美文网首页
ffmpeg 解封装/封装 流程

ffmpeg 解封装/封装 流程

作者: LF_Lufei | 来源:发表于2022-02-13 15:06 被阅读0次

    ffmpeg解封装流程

    设置参数

    打开url之前可以选择设置参数

    AVDictionary *opts = nullptr;
    av_dict_set(&opts,"rtsp_transport","tcp",0);//传输媒体流协议为tcp,默认为udp 可不设置
    av_dict_set(&opts,"stimeout","1000000",0);//链接超时1秒, -stimeout 设置在你要解析的url之后是没有作用的
    
    打开解封装上下文
    //打开封装上下文
    AVFormatContext *c = nullptr;
    auto re = avformat_open_input(&c,url,
                                      nullptr,//封装器的格式 可以根据后缀或者文件头 自动探测
                                      &opts//参数设置 ,rtsp 需要设置
                                      );
    

    url 为本地文件地址或者网络地址 如 海康摄像头的地址:
    rtsp://test:x12345678@192.168.2.64/h264/ch1/main/av_stream
    如果设置了opts 别忘了释放

    if(opts){
            av_dict_free(&opts);
        }
    
    获取媒体信息
    re = avformat_find_stream_info(c,nullptr);
    //可以打印媒体信息
    av_dump_format(c,0,url,0);
    
    获取音频流和视频流相关信息
    for(int i = 0;i< c->nb_streams;i++){
            //音频
            if( c->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){
    
                audio_index_ = i;
                //也可以直接复制  因为内存完全一样 audio_time_base =  streams[i]->time_base;
                audio_time_base_.den =  c->streams[i]->time_base.den;
                audio_time_base_.num =  c->streams[i]->time_base.num;
            }else if( c->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
                video_index_ = i;
                video_time_base_.den =  c->streams[i]->time_base.den;
                video_time_base_.num =  c->streams[i]->time_base.num;
                video_codec_id_ =  c->streams[i]->codecpar->codec_id;
            }
        }
    
    创建视频解码上下文
    AVCodec *dcodec = nullptr;
    dcodec = avcodec_find_decoder(video_codec_id_);
    auto decodeContext = avcodec_alloc_context3(dcodec);
    

    可以设置一下参数默认值

    decodeContext->time_base = {1,25};
    decodeContext->pix_fmt = AV_PIX_FMT_YUV420P;
    decodeContext->thread_count = 16;
    
    复制视频参数给解码上下文
    video_index_为视频流索引
    avcodec_parameters_to_context(decodeContext,c->streams[video_index_]->codecpar);
    
    打开视频解码器
    auto re = avcodec_open2(decodeContext,NULL,NULL);
    
    创建音频解码上下文同视频一样
    audio_index_为音频流索引
    AVCodec *dacodec = nullptr;
    dacodec = avcodec_find_decoder(c->streams[audio_index_]->codecpar->codec_id);
    auto audioDecodeContext = avcodec_alloc_context3(dacodec);
    avcodec_parameters_to_context(audioDecodeContext,c->streams[audio_index_]->codecpar);
    auto re = avcodec_open2(decodeContext,NULL,NULL);
    
    解封装开始
     AVPacket pkt;
    while (true) {
             //读出来完整一帧  一般这里在没连接成功时会有阻塞
        auto re = av_read_frame(con_,&pkt);
    //这里一般使用数组把解封装出来的pkt 保存起来,因为解封装和解码是线程并发执行的 要注意 线程之间的资源调用 一般使用锁来解决
         pkt_list_.Push(pkt);
    }
    
    解码过程
    分配AVFrame
    AVFrame  frame_ = av_frame_alloc();
    

    从数组里面取出pkt

    auto pkt = pkt_list_.Pop(); 
    //con_ 区别为音视频解码上下文
    auto re = avcodec_send_packet(con_,pkt);
    av_packet_free(&pkt);
     auto re = avcodec_receive_frame(con_,frame_);
    
    解码出来的frame 如果是音频的话建议放到数组中缓存起来,因为音频播放速度可能会赶不上解码的速度
     auto f = av_frame_alloc();
     av_frame_ref(f,frame_);
     frames_.push_back(f);
    //如果用数组存储的话  记得释放frame_
    if(frame_){
          av_frame_free(&frame_);
    }
    

    至此解封装完成 音频播放可以用sdl 或者其他的库

    封装 待更新

    demo 地址

    相关文章

      网友评论

          本文标题:ffmpeg 解封装/封装 流程

          本文链接:https://www.haomeiwen.com/subject/ncpflrtx.html