首页 滚动 > > 正文

如何将mp4文件解复用并且解码为单独的.yuv图像序列以及.pcm音频采样数据? 环球新视野

来源:博客园 发布日期:2023-06-28 10:27:44 分享到:

一.初始化解复用器

在音视频的解复用的过程中,有一个非常重要的结构体AVFormatContext,即输入文件的上下文句柄结构,代表当前打开的输入文件或流。我们可以将输入文件的路径以及AVFormatContext **format_ctx 传入函数avformat_open_input(),就可以打开对应的音视频文件或流。接下来再调用avformat_find_stream_info()函数去解析输入文件中的音视频流信息,打开对应的解码器,读取文件头的信息进行解码, 然后在解码过程中将一些参数的信息保存到AVStream结构对应的成员中。之后,我们便可以通过AVStream去初始化编解码器的上下文结构,下面给出代码:


【资料图】

static AVFormatContext *format_ctx= nullptr;static AVCodecContext *video_dec_ctx= nullptr,*audio_dec_ctx= nullptr;static int32_t video_stream_index=-1;static int32_t audio_stream_index=-1;static AVStream *video_stream= nullptr,*audio_stream= nullptr;static FILE *output_video_file= nullptr,*output_audio_file= nullptr;static AVPacket *pkt= nullptr;static AVFrame *frame= nullptr;static int open_codec_context(int32_t *stream_idx,AVCodecContext **dec_ctx,AVFormatContext *fmt_ctx,enum AVMediaType type){    int ret,stream_index;    AVStream *st= nullptr;    const AVCodec *dec= nullptr;    ret= av_find_best_stream(fmt_ctx,type,-1,-1, nullptr,0);    if(ret<0){        cerr<<"Error:Could not find "<streams[stream_index];        //find decoder for the stream        dec= avcodec_find_decoder(st->codecpar->codec_id);        if(!dec){            cerr<<"Error:Failed to find codec:"<codecpar))<0){            cerr<<"Error:Failed to copy codec parameters to decoder context."<=0){        video_stream=format_ctx->streams[video_stream_index];        output_video_file=fopen(video_output_name,"wb");        if(!output_video_file){            cerr<<"Error:failed to open video output file."<=0){        audio_stream=format_ctx->streams[audio_stream_index];        output_audio_file=fopen(audio_output_name,"wb");        if(!output_audio_file){            cerr<<"Error:failed to open audio output file."<

二.循环读取码流包数据进行解码

在这里,我们需要调用一个非常重要的函数av_read_frame(),它可以从打开的音视频文件或流中依次读取下一个码流包结构,然后我们将码流包传入解码器进行解码即可,代码如下:

static int32_t decode_packet(AVCodecContext *dec,const AVPacket *pkt,bool flushing){    int32_t result=0;    result= avcodec_send_packet(dec,pkt);    if(result<0){        cerr<<"Error:avcodec_send_packet failed."<=0){        result=avcodec_receive_frame(dec,frame);        if(result<0){            if(result==AVERROR_EOF||result==AVERROR(EAGAIN)){                return 0;            }            cerr<<"Error:Error during decoding,result="<codec->type==AVMEDIA_TYPE_VIDEO){            write_frame_to_yuv(frame);        }        else{            write_samples_to_pcm(frame,audio_dec_ctx);        }        if(flushing){            cout<<"flushing"<=0){        cout<<"Read packet,pts:"<pts<<",stream:"<stream_index<<",size:"<size<stream_index==audio_stream_index){            result= decode_packet(audio_dec_ctx,pkt,false);        }        else if(pkt->stream_index==video_stream_index){            result= decode_packet(video_dec_ctx,pkt,false);        }        av_packet_unref(pkt);        if(result<0){            break;        }    }    if(video_dec_ctx){        decode_packet(video_dec_ctx, nullptr,true);    }    if(audio_dec_ctx){        decode_packet(audio_dec_ctx, nullptr,true);    }    cout<<"Demuxing succeeded."<

三.将解码后的图像序列以及音频采样数据写入相应的文件

这个步骤比较简单,不解释,直接上代码:

int32_t write_frame_to_yuv(AVFrame* frame){    uint8_t** pBuf=frame->data;    int* pStride=frame->linesize;    for(size_t i=0;i<3;i++){        int32_t width=(i==0?frame->width:frame->width/2);        int32_t height=(i==0?frame->height:frame->height/2);        for(size_t j=0;jsample_fmt);    if(data_size<0){        cerr<<"Error:failed to calculate data size."<channels;ch++){            fwrite(frame->data[ch]+i*data_size,1,data_size,output_audio_file);        }    }    return 0;}

四.销毁资源,释放内存

void destroy_demuxer(){    avcodec_free_context(&video_dec_ctx);    avcodec_free_context(&audio_dec_ctx);    avformat_close_input(&format_ctx);    if(output_audio_file!= nullptr){        fclose(output_audio_file);        output_audio_file= nullptr;    }    if(output_video_file!= nullptr){        fclose(output_video_file);        output_video_file= nullptr;    }}

五.main函数

int main(){    int32_t result=init_demuxer("../input.mp4","../output.yuv","../output.pcm");    if(result<0){        return -1;    }    result=demuxing();    if(result<0){        return -1;    }    destroy_demuxer();    return 0;}

到这里,就大功告成了,可以使用以下的命令去播放输出的音视频文件:

ffplay -ac 2 -ar 44100 -f f32le -i output.pcm

ffplay -f rawvideo -video_size 1920x1080 -i output.yuv

关键词:

x 广告

复原民国旧菜单 一批“消失的名菜”重现羊城

  中新网广州12月5日电 (记者 程景伟)“粤宴中国·消失的名菜”活动4日晚在广州博物馆镇海楼广场举行,一批业已失传或十分罕见的传统粤

青海再度“双清零”:战“疫”催生定点救治医院反思与成长

  中新网西宁12月5日电 题:青海再度“双清零”:战“疫”催生定点救治医院反思与成长  作者 潘雨洁  全面停诊、四下无人;火线冲

世界海拔最高高铁客运站山丹马场站运营

  中新网兰州12月5日电 (记者 杨艳敏)记者从中国铁路兰州局集团有限公司获悉,12月5日10时29分随着嘉峪关南至西安北D2696次动车组列车

千年古都洛阳为何要建青年友好型城市?

  中新网洛阳12月5日电 题:千年古都洛阳为何要建青年友好型城市?  记者 肖开霖 李贵刚  千年古都洛阳日前公布《洛阳市建设青年

甘肃万余河长公示牌拥有“电子身份证” 局地启“千里眼”治水

  中新网兰州12月5日电 (记者 冯志军)记者5日从甘肃省水利厅获悉,今年以来,甘肃全面推动河长公示牌信息化建设,为全省河流换发“电子

满洲里市向呼伦贝尔市“手递手”异地转运3批次隔离人员

  (抗击新冠肺炎)满洲里市向呼伦贝尔市“手递手”异地转运3批次隔离人员  中新网呼伦贝尔12月5日电 (记者 张玮)5日,内蒙古自治区呼

2021年度法治人物沈云如:让群众过上“有身份的生活”

  中新网杭州12月5日电 题:2021年度法治人物沈云如:让群众过上“有身份的生活”  作者 郭其钰 张先登  行程10余万公里,为辖区3

全国妇联在北京组织巾帼志愿者服务社区“一老一小”

  中新网北京12月5日电 (记者 余湛奕)在12月5日国际志愿者日前夕,全国妇联4日在北京组织机关党员干部以巾帼志愿者身份,聚焦“一老一

x 广告

Copyright   2015-2022 人人海洋网版权所有  备案号:粤ICP备18023326号-36   联系邮箱:8557298@qq.com