美文网首页
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