首页 > 其他分享 >libavcodec视频解码

libavcodec视频解码

时间:2023-06-17 11:46:14浏览次数:40  
标签:视频 int32 libavcodec 解码 file input data frame size

一.打开和关闭输入文件和输出文件

//io_data.cpp
static FILE* input_file= nullptr;
static FILE* output_file= nullptr;

int32_t open_input_output_files(const char* input_name,const char* output_name){
    if(strlen(input_name)==0||strlen(output_name)==0){
        cout<<"Error:empty input or output file name."<<endl;
        return -1;
    }
    close_input_output_files();
    input_file=fopen(input_name,"rb");//rb:读取一个二进制文件,该文件必须存在
    if(input_file==nullptr){
        cerr<<"Error:failed to open input file."<<endl;
        return -1;
    }
    output_file=fopen(output_name,"wb");//wb:打开或新建一个二进制文件,只允许写
    if(output_file== nullptr){
        cout<<"Error:failed to open output file."<<endl;
        return -1;
    }
    return 0;
}
void close_input_output_files(){
    if(input_file!= nullptr){
        fclose(input_file);
        input_file= nullptr;
    }
    if(output_file!= nullptr){
        fclose(output_file);
        output_file= nullptr;
    }
}

二.视频解码器的初始化

  解码器的初始化和编码器初始化类似,区别仅在于需要多创建一个AVCodecParserContext类型对象。AVCodecParserContext是码流解析器的句柄,其作用是从一串二进制数据流中解析出

符合某种编码标准的码流包。

//video_decoder_core.cpp
static const AVCodec* codec= nullptr;
static AVCodecContext* codec_ctx= nullptr;
static AVCodecParserContext* parser= nullptr;
static AVFrame* frame= nullptr;
static AVPacket* pkt= nullptr;
int32_t init_video_decoder(){
    codec= avcodec_find_decoder(AV_CODEC_ID_H264);
    if(!codec){
        cerr<<"Error:could not find codec."<<endl;
        return -1;
    }
    parser= av_parser_init(codec->id);
    if(!parser){
        cerr<<"Error:could not init parser."<<endl;
        return -1;
    }
    codec_ctx= avcodec_alloc_context3(codec);
    if(!codec_ctx){
        cerr<<"Error:could not alloc codec_ctx."<<endl;
        return -1;
    }
    int32_t result= avcodec_open2(codec_ctx,codec, nullptr);
    if(result<0){
        cerr<<"Error:could not open codec."<<endl;
        return -1;
    }
    frame=av_frame_alloc();
    if(!frame){
        cerr<<"Error:could not alloc frame."<<endl;
        return -1;
    }
    pkt=av_packet_alloc();
    if(!pkt){
        cerr<<"Error:could not alloc packet."<<endl;
        return -1;
    }
    return 0;
}

三.解码循环体

  解码循环体至少需要实现以下三个功能:

    1.从输入源中循环获取码流包

    2.将当前帧传入解码器,获取输出的图像帧

    3.输出解码获取的图像帧到输出文件

  从输入文件中读取数据添加到缓存,并判断输入文件是否到达结尾:

io_data.cpp
int32_t end_of_input_file(){
    return feof(input_file);
}
int32_t read_data_to_buf(uint8_t* buf,int32_t size,int32_t& out_size){
    int32_t read_size=fread(buf,1,size,input_file);
    if(read_size==0){
        cerr<<"Error:read_data_to_buf failed."<<endl;
        return -1;
    }
    out_size=read_size;
    return 0;
}

  解码循环体:在解码循环体中,有一个核心函数av_parser_parse2(),它的作用是从数据缓冲区中解析出AVPacket结构。当调用av_parser_parse2()函数时,首先通过参数指定保存

某一段码流数据的缓存区及其长度,然后通过输出poutbuf指针或poutbuf_size的值来判断是否读取了一个完整的AVPacket结构,只有当poutbuf指针为非空或

poutbuf_size值为正时,才表示解析出一个完整的AVPacket

//video_decoder_core.cpp
int32_t decoding(){
    uint8_t inbuf[INBUF_SIZE]={0};
    int32_t result=0;
    uint8_t* data= nullptr;
    int32_t data_size=0;
    while(!end_of_input_file()){
        result=read_data_to_buf(inbuf,INBUF_SIZE,data_size);
        if(result<0){
            cerr<<"Error:read_data_to_buf failed."<<endl;
            return -1;
        }
        data=inbuf;
        while(data_size>0){
            result= av_parser_parse2(parser,codec_ctx,&pkt->data,&pkt->size,data,data_size,AV_NOPTS_VALUE,AV_NOPTS_VALUE,0);
            if(result<0){
                cerr<<"Error:av_parser_parse2 failed."<<endl;
                return -1;
            }
            data+=result;
            data_size-=result;
            if(pkt->size){
                cout<<"Parsed packet size:"<<pkt->size<<endl;
                decode_packet(false);
            }
        }
    }
    decode_packet(true);
    return 0;
}
static int32_t decode_packet(bool flushing){
    int32_t result=0;
    result= avcodec_send_packet(codec_ctx,flushing? nullptr:pkt);
    if(result<0){
        cerr<<"Error:failed to send packet,result:"<<result<<endl;
        return -1;
    }
    while(result>=0){
        result= avcodec_receive_frame(codec_ctx,frame);
        if(result==AVERROR(EAGAIN)||result==AVERROR_EOF){
            return 1;
        }
        else if(result<0){
            cerr<<"Error:failed to receive frame,result:"<<result<<endl;
            return -1;
        }
        if(flushing){
            cout<<"Flushing:";
        }
        cout<<"Write frame pic_num:"<<frame->coded_picture_number<<endl;
        write_frame_to_yuv(frame);
    }
    return 0;
}

  输出解码图像数据:

//io_data.cpp
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;j<height;j++){
            fwrite(pBuf[i],1,width,output_file);
            pBuf[i]+= pStride[i];
        }
    }
    return 0;
}

  关闭解码器:

//video_decoder_core.cpp
void destroy_video_decoder(){
    av_parser_close(parser);
    avcodec_free_context(&codec_ctx);
    av_frame_free(&frame);
    av_packet_free(&pkt);
}

  最终,main函数的实现如下:

int main(){
    const char* input_file_name="../input.h264";
    const char* output_file_name="../output.yuv";
    int32_t result= open_input_output_files(input_file_name,output_file_name);
    if(result<0){
        return result;
    }
    result=init_video_decoder();
    if(result<0){
        return result;
    }
    result=decoding();
    if(result<0){
        return result;
    }
    destroy_video_decoder();
    close_input_output_files();
    return 0;
}

  解码完成后,可以使用ffplay播放输出的.yuv图像文件:

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

  

  

 

      

    

标签:视频,int32,libavcodec,解码,file,input,data,frame,size
From: https://www.cnblogs.com/luqman/p/decode.html

相关文章

  • AI智能视频技术在安防监控领域的场景应用
    AI智能视频技术是一种基于人工智能、深度学习和计算机视觉等技术的视频处理技术。它可以通过对视频进行分析和识别,实现各种智能化应用,如视频监控、智能家居、自动驾驶等。目前,AI智能视频技术已经实现了人脸识别、行为分析、智能跟踪、场景分析、目标检测、图像增强等多种功能,可以......
  • RTSP/Onvif安防视频平台EasyNVR设备在线但通道无法播放的原因排查
    EasyNVR是基于RTSP/Onvif协议的视频平台,可支持将接入的视频流进行全平台、全终端的分发,分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。为了满足用户的集成与二次开发需求,我们也提供了丰富的API接口供用户调用。有需要的用户可参照官方接口文档进行操作。有用......
  • 成为Spring Boot大师:推荐一门精选视频课程
    SpringBoot是Java生态系统中备受追捧的开发框架之一,它简化了Java应用程序的搭建和配置过程,使开发者能够更快速、高效地构建强大的应用程序。如果你希望在SpringBoot领域中迈向专家级水平,并且想要通过一门优质的视频课程来加速你的学习过程,我们向你推荐以下精选课程:链接:https://w......
  • 成为Spring Boot大师:推荐一门精选视频课程
    SpringBoot是Java生态系统中备受追捧的开发框架之一,它简化了Java应用程序的搭建和配置过程,使开发者能够更快速、高效地构建强大的应用程序。如果你希望在SpringBoot领域中迈向专家级水平,并且想要通过一门优质的视频课程来加速你的学习过程,我们向你推荐以下精选课程:链接:https://......
  • 音视频网络传输协议,RTSP/RTMP/SRT/NDI协议之间特点
    网络视频传输协议有哪些,RTSP/RTMP/SRT/RTP之间特点下面详细介绍:有兴趣的小伙伴可加qq群一起交流384170753RTP协议(Real-timeTransportProtocol)是一个网络传输协议,是一种实时传输协议技术,RTP协议常用于流媒体系统(配合RTSP协议)视频会议和一键通(PushtoTalk)系统(配合H.323或SIP),使它成为IP......
  • 视频直播源码,html2canvas 前端保存页面为图片
    视频直播源码,html2canvas前端保存页面为图片转换方法如下: /***将页面指定节点内容转为图片*1.拿到想要转换为图片的内容节点DOM;*2.转换,拿到转换后的canvas*3.转换为图片*///生成局部图片GenerateImg(){ letelement=this.$refs.canvasImgObj; //console.warn(el......
  • 中视频如何准确的定位账号
    在账号的经营过程中,必须要确立良好的账号定位。账号定位,简单来说,就是确定账号的经营方向。具体而言,账号定位可以从行业、内容、用户、角色和产品这五个维度进行考虑。只要账号的定位准确,运营者就能准确地把握账号的发展方向,从而获得更好的效果。(腾讯|课堂搜|索“如何运营视频才能......
  • Adobe Prelude CC2022【Pl视频编辑软件】中文直装版安装教程
    dobePrelude是一个很好的视频编辑软件。该软件结合了优异的性能、优美的改进用户界面和许多奇妙的创意功能,包括WarpStabilizer、动态时间轴切割、扩展多机编辑、调整图层等。该专业视频捕获程序允许转换任何文件格式和设置标记。该应用程序提供了对文件准备过程的有效管理,并立即......
  • Adobe Media Encoder CC2022【视频与音频编码工具】安装教程
    新款AdobeMediaencoder2022正式上线,又称Me2022,该软件不仅为用户提供了转换视频、音频格式等功能,使用户能够转换各种视频或音频格式,或为不同的应用程序开发和各种格式编码音视频文件。还提供了各种专业的硬件设备编码格式设置和设计预设设置,包括视频渲染、剪切、摄取、转码等。更......
  • 中视频为什么要做好的账号定位?
    为什么要正确定位中视频账号呢?主要有以下3个理由:一是通过账号定位可以找到适合的运营方向,确定自身的运营目标;二是良好的账号定位可以为未来的内容策划提供指导;三是进行账号定位的过程也是对自己的审视,定位好账号后,运营者的优势将得以凸显。(腾讯|课堂搜|索“如何运营视频才能获得......