Android 音视频深入 十八 FFmpeg播放视频,有声音(附源码下载)

Android音视频 同时被 2 个专栏收录
23 篇文章 3 订阅
21 篇文章 132 订阅
项目地址
https://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpegv%E6%92%AD%E6%94%BE%E8%A7%86%E9%A2%91%E6%9C%89%E5%A3%B0%E9%9F%B3%EF%BC%8C%E6%9A%82%E5%81%9C%EF%BC%8C%E9%87%8A%E6%94%BE%E3%80%81%E5%BF%AB%E8%BF%9B%E3%80%81%E9%80%80%E5%90%8E

这个项目是简书2012lc大神写的,播放没问题就是其他功能都有点卡过头了。。。
哎,自己也没能写出一个优秀的播放器,

回到正题

首先这个代码是生产者和消费者的模式,生成者就是不断地解码mp4将一帧的数据给消费者,消费者就是音频播放类和视频播放类,也就说生成者一个,消费者两个,都是通过pthread开启线程,通过互斥锁和条件信息来维持这个关系链

1.生产者—输出一帧帧的数据


开始就是初始化各类组件和测试视频文件是否能够打开,并获得视频相关信息为后来代码做准备工作

void init() {
    LOGE("开启解码线程")
    //1.注册组件
    av_register_all();
    avformat_network_init();
    //封装格式上下文
    pFormatCtx = avformat_alloc_context();

    //2.打开输入视频文件
    if (avformat_open_input(&pFormatCtx, inputPath, NULL, NULL) != 0) {
        LOGE("%s", "打开输入视频文件失败");
    }
    //3.获取视频信息
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        LOGE("%s", "获取视频信息失败");
    }

    //得到播放总时间
    if (pFormatCtx->duration != AV_NOPTS_VALUE) {
        duration = pFormatCtx->duration;//微秒
    }
}

初始化音频类和视频类,并将SurfaceView给视频类

    ffmpegVideo = new FFmpegVideo;
    ffmpegMusic = new FFmpegMusic;
    ffmpegVideo->setPlayCall(call_video_play);

开启生成者线程

pthread_create(&p_tid, NULL, begin, NULL);//开启begin线程

从视频信息里获取视屏流和音频流,将各自的解码器上下文复制分别给与两个消费者类,并将流在哪个位置、还有时间单位给与两个消费者类

    //找到视频流和音频流
    for (int i = 0; i < pFormatCtx->nb_streams; ++i) {
        //获取解码器
        AVCodecContext *avCodecContext = pFormatCtx->streams[i]->codec;
        AVCodec *avCodec = avcodec_find_decoder(avCodecContext->codec_id);

        //copy一个解码器,
        AVCodecContext *codecContext = avcodec_alloc_context3(avCodec);
        avcodec_copy_context(codecContext, avCodecContext);
        if (avcodec_open2(codecContext, avCodec, NULL) < 0) {
            LOGE("打开失败")
            continue;
        }
        //如果是视频流
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            ffmpegVideo->index = i;
            ffmpegVideo->setAvCodecContext(codecContext);
            ffmpegVideo->time_base = pFormatCtx->streams[i]->time_base;
            if (window) {
                ANativeWindow_setBuffersGeometry(window, ffmpegVideo->codec->width,
                                                 ffmpegVideo->codec->height,
                                                 WINDOW_FORMAT_RGBA_8888);
            }
        }//如果是音频流
        else if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            ffmpegMusic->index = i;
            ffmpegMusic->setAvCodecContext(codecContext);
            ffmpegMusic->time_base = pFormatCtx->streams[i]->time_base;
        }
    }

开启两个消费者类的线程

    ffmpegVideo->setFFmepegMusic(ffmpegMusic);
    ffmpegMusic->play();
    ffmpegVideo->play();

然后开始一帧一帧的解码出数据给两个消费者类的用来存储数据的矢量,如果矢量里的数据还有那就没有播放玩,继续播放

    while (isPlay) {
        //
        ret = av_read_frame(pFormatCtx, packet);
        if (ret == 0) {
            if (ffmpegVideo && ffmpegVideo->isPlay && packet->stream_index == ffmpegVideo->index
               ) {
                //将视频packet压入队列
                ffmpegVideo->put(packet);
            } else if (ffmpegMusic && ffmpegMusic->isPlay &&
                       packet->stream_index == ffmpegMusic->index) {
                ffmpegMusic->put(packet);
            }
            av_packet_unref(packet);
        } else if (ret == AVERROR_EOF) {
            // 读完了
            //读取完毕 但是不一定播放完毕
            while (isPlay) {
                if (ffmpegVideo->queue.empty() && ffmpegMusic->queue.empty()) {
                    break;
                }
                // LOGE("等待播放完成");
                av_usleep(10000);
            }
        }
    }

播放完了就停止两个消费者类的线程,并释放资源

    isPlay = 0;
    if (ffmpegMusic && ffmpegMusic->isPlay) {
        ffmpegMusic->stop();
    }
    if (ffmpegVideo && ffmpegVideo->isPlay) {
        ffmpegVideo->stop();
    }
    //释放
    av_free_packet(packet);
    avformat_free_context(pFormatCtx);
    pthread_exit(0);

2.消费者—音频类


开启线程

      pthread_create(&playId, NULL, MusicPlay, this);//开启begin线程

就下来就是配置OpenSL ES来播放音频,而这个数据的来源是这一段代码决定的

    (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);

我们再来看看bqPlayerCallback,数据是从getPcm函数得到的

    FFmpegMusic *musicplay = (FFmpegMusic *) context;
    int datasize = getPcm(musicplay);
    if(datasize>0){
        //第一针所需要时间采样字节/采样率
        double time = datasize/(44100*2*2);
        //
        musicplay->clock=time+musicplay->clock;
        LOGE("当前一帧声音时间%f   播放时间%f",time,musicplay->clock);

        (*bq)->Enqueue(bq,musicplay->out_buffer,datasize);
        LOGE("播放 %d ",musicplay->queue.size());
    }

然后这个getPcm函数里,通过get函数来完成获取一帧数据

agrs->get(avPacket);

如果有矢量里有数据它将矢量里的数据取出,如果没有就等待生产者通过条件变量

//将packet弹出队列
int FFmpegMusic::get(AVPacket *avPacket) {
    LOGE("取出队列")
    pthread_mutex_lock(&mutex);
    while (isPlay){
        LOGE("取出对垒 xxxxxx")
        if(!queue.empty()&&isPause){
            LOGE("ispause %d",isPause);
            //如果队列中有数据可以拿出来
            if(av_packet_ref(avPacket,queue.front())){
                break;
            }
            //取成功了,弹出队列,销毁packet
            AVPacket *packet2 = queue.front();
            queue.erase(queue.begin());
            av_free(packet2);
            break;
        } else{
            LOGE("音频执行wait")
            LOGE("ispause %d",isPause);
            pthread_cond_wait(&cond,&mutex);

        }
    }
    pthread_mutex_unlock(&mutex);
    return 0;
}

注意这个获取的数据是AVPacket,我们需要将他解码为AVFrame才行

        if (avPacket->pts != AV_NOPTS_VALUE) {
            agrs->clock = av_q2d(agrs->time_base) * avPacket->pts;
        }
        //            解码  mp3   编码格式frame----pcm   frame
        LOGE("解码")
        avcodec_decode_audio4(agrs->codec, avFrame, &gotframe, avPacket);
        if (gotframe) {

            swr_convert(agrs->swrContext, &agrs->out_buffer, 44100 * 2, (const uint8_t **) avFrame->data, avFrame->nb_samples);
//                缓冲区的大小
            size = av_samples_get_buffer_size(NULL, agrs->out_channer_nb, avFrame->nb_samples,
                                              AV_SAMPLE_FMT_S16, 1);
            break;
        }

回到OpenSL ES的回调函数,取到数据后将数据压入播放器里让他播放

        //第一针所需要时间采样字节/采样率
        double time = datasize/(44100*2*2);
        //
        musicplay->clock=time+musicplay->clock;
        LOGE("当前一帧声音时间%f   播放时间%f",time,musicplay->clock);

        (*bq)->Enqueue(bq,musicplay->out_buffer,datasize);
        LOGE("播放 %d ",musicplay->queue.size());

3.消费者—视频类


这两者的运行过程很像,我这里就省略的说说

开启线程

    //申请AVFrame
    AVFrame *frame = av_frame_alloc();//分配一个AVFrame结构体,AVFrame结构体一般用于存储原始数据,指向解码后的原始帧
    AVFrame *rgb_frame = av_frame_alloc();//分配一个AVFrame结构体,指向存放转换成rgb后的帧
    AVPacket *packet = (AVPacket *) av_mallocz(sizeof(AVPacket));
    //输出文件
    //FILE *fp = fopen(outputPath,"wb");


    //缓存区
    uint8_t  *out_buffer= (uint8_t *)av_mallocz(avpicture_get_size(AV_PIX_FMT_RGBA,
                                                                  ffmpegVideo->codec->width,ffmpegVideo->codec->height));
    //与缓存区相关联,设置rgb_frame缓存区
    avpicture_fill((AVPicture *)rgb_frame,out_buffer,AV_PIX_FMT_RGBA,ffmpegVideo->codec->width,ffmpegVideo->codec->height);


    LOGE("转换成rgba格式")
    ffmpegVideo->swsContext = sws_getContext(ffmpegVideo->codec->width,ffmpegVideo->codec->height,ffmpegVideo->codec->pix_fmt,
                                            ffmpegVideo->codec->width,ffmpegVideo->codec->height,AV_PIX_FMT_RGBA,
                                            SWS_BICUBIC,NULL,NULL,NULL);

获取一帧数据

ffmpegVideo->get(packet);

然后从矢量里得到数据

调节视频和音频的播放速度

        diff = ffmpegVideo->clock - audio_clock;
//        在合理范围外  才会延迟  加快
        sync_threshold = (delay > 0.01 ? 0.01 : delay);

        if (fabs(diff) < 10) {
            if (diff <= -sync_threshold) {
                delay = 0;
            } else if (diff >=sync_threshold) {
                delay = 2 * delay;
            }
        }
        start_time += delay;
        actual_delay=start_time-av_gettime()/1000000.0;
        if (actual_delay < 0.01) {
            actual_delay = 0.01;
        }
        av_usleep(actual_delay*1000000.0+6000);

播放视频

video_call(rgb_frame);

释放资源并退出线程

    LOGE("free packet");
    av_free(packet);
    LOGE("free packet ok");
    LOGE("free packet");
    av_frame_free(&frame);
    av_frame_free(&rgb_frame);
    sws_freeContext(ffmpegVideo->swsContext);
    size_t size = ffmpegVideo->queue.size();
    for (int i = 0; i < size; ++i) {
        AVPacket *pkt = ffmpegVideo->queue.front();
        av_free(pkt);
        ffmpegVideo->queue.erase(ffmpegVideo->queue.begin());
    }
    LOGE("VIDEO EXIT");
    pthread_exit(0);

结束了,以后哎,尽量自己写出一个播放器,要那种暂停不卡的


  • 2
    点赞
  • 1
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
<p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; color: #333333;"><span style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box;"><strong style="margin: 0px; padding: 0px;"><strong style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #ff0000;"><span style="margin: 0px; padding: 0px; font-size: 24px;"><strong style="margin: 0px; padding: 0px; color: #333333;">敬告:</strong></span></span></strong><span style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box; color: #ff0000; font-size: 24px;">该系列的课程在抓紧录制更新中敬请大家关注。</span></strong></span></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box;"><strong style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #ff0000;"><span style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box;"><strong style="margin: 0px; padding: 0px; color: #333333;"><strong style="margin: 0px; padding: 0px;"><strong style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #ff0000; font-size: 24px;"><strong style="margin: 0px; padding: 0px; color: #333333;">敬告:</strong></span></strong></strong><span style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box; color: #00b050;">本课程项目仅供学习参考请不要直接商用概不负责任何法律责任</span><span style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box; color: #ff0000;">。</span></strong></span></span></strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; color: #333333;"> </span><span style="margin: 0px; padding: 0px; color: #333333; max-width: 100%; box-sizing: border-box;"><strong style="margin: 0px; padding: 0px;">该系列的课程涉及:FFmpeg,WebRTC,SRS,Nginx,Darwin,Live555,等。包括:音视频、流媒体、直播、Android、视频监控28181、等。</strong></span><br style="margin: 0px; padding: 0px;" /></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; color: #e36c09; font-size: 20px;"><strong style="margin: 0px; padding: 0px;">我将带领大家一起来学习使用FFmpeg开发视频监控项目<span style="margin: 0px; padding: 0px; color: #00b050;">并动手操练</span>。</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #000000;"><strong style="margin: 0px; padding: 0px;">具体内容包括:</strong></span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">一、视频监控的架构和流程</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">二、FFmpeg4.3+SDL2+Qt5开发环境的搭建</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">三、FFmpeg的SDK编程回顾总结并操练</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">四、SDL2.0的编程回顾总结并操练</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">五、颜色空间转换RGB和YUV的原理与实战</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">六、Qt5+FFmpeg本地摄像头采集预览实战</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">七、代码封装:摄像头h264/5编码并存储</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">八、Qt5+FFmpeg单路网络摄像头采集预览</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">九、Qt5+FFmpeg单路网络摄像头</span><span style="margin: 0px; padding: 0px; font-size: 20px; color: #ff0000;">采集预览录制会看</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-size: 20px; color: #7030a0;">十、onvif与GB/T-28181的简介</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><img src="https://img-bss.csdnimg.cn/202101130753276832.jpg" alt="" /></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><strong><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;">音视频与流媒体是一门很复杂的技术涉及的概念、原理、理论非常多很多初学者不学 基础理论而是直接做项目往往会看到c/c++的代码时一头雾水不知道代码到底是什么意思这是为什么呢?</span></strong></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;">因为没学习音视频和流媒体的基础理论就比如学习英语不学习基本单词而是天天听英语新闻总也听不懂。</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;">所以呢一定要认真学习基础理论然后再学习播放器、转码器、非编、流媒体直播、视频监控、等等。</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><strong><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;">梅老师从事音视频与流媒体行业18年;曾在永新视博、中科大洋、百度、美国Harris广播事业部等公司就职经验丰富;曾亲手主导广电直播全套项目精通h.264/h.265/aac曾亲自参与百度app上的网页播放器等实战产品。</span></strong></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;">目前全身心自主创业主要聚焦音视频+流媒体行业精通音视频加密、流媒体在线转码快编等热门产品。</span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"><span style="color: #313d54; font-family: Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;"> </span></p> <p style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; color: #313d54; font-size: 16px; background-color: #ffffff;"> </p>
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值