从零到一学FFmpeg:AVCodecContext 结构体详析与实战

2024-06-23 1593阅读

文章目录

  • 前言
  • 一、结构体原型
  • 二、使用场景
    • 1、编码流程:
    • 2、解码流程:
    • 三、编码使用实例
    • 四、解码使用实例

      前言

      AVCodecContext是FFmpeg库中的一个核心结构体,它代表了编解码器的上下文信息,是进行音频或视频编解码操作时必不可少的组件。

      从零到一学FFmpeg:AVCodecContext 结构体详析与实战
      (图片来源网络,侵删)

      AVCodecContext存储了编解码器的配置参数、状态信息以及与编解码过程相关的资源。

      无论是在编码还是解码过程中,都需要一个相应的AVCodecContext实例来管理和控制编解码过程。


      提示:以下是本篇文章正文内容,下面案例可供参考

      一、结构体原型

      typedef struct AVCodecContext {
          const AVClass *av_class;
          AVMediaType codec_type; //编解码器处理的媒体类型,如AVMEDIA_TYPE_VIDEO或AVMEDIA_TYPE_AUDIO
          const AVCodec *codec; // 指向当前编解码器的指针
          AVCodecID codec_id; // 编解码器的ID,例如CODEC_ID_H264
          int width, height; // 视频的情况下,宽和高
          AVRational time_base; // 时间基,用于计算时间戳
          int bit_rate; // 编码时的目标比特率
          /* 更多编解码相关的参数... */
          AVFrame *frame; // 可选的,用于存储原始数据的帧
          AVFrame *coded_frame; // 编码后的帧,解码时使用
          /* 更多功能性、控制和状态字段... */
      } AVCodecContext;
      

      参数说明

      *const AVClass av_class:
      同AVFormatContext中的av_class,用于日志记录和运行时类型信息。
      AVMediaType codec_type:
      指定编解码器处理的媒体类型,如音频或视频。
      *const AVCodec codec:
      指向已初始化的编解码器结构体,这个编解码器用于执行实际的编解码操作。
      AVCodecID codec_id:
      编解码器的唯一标识符,例如对于H.264视频编码器,其值为AV_CODEC_ID_H264。
      int width, height:
      视频编解码时,指定帧的宽度和高度。
      AVRational time_base:
      定义时间戳的单位,例如1/1000表示每毫秒一个时间单位。
      int bit_rate:
      编码时的目标比特率,单位通常是比特每秒。
      **AVFrame frame, coded_frame:
      frame通常用于存放原始数据,coded_frame用于存放编码或解码后的数据。在编码时,原始数据放入frame,编码后数据转移到coded_frame;解码时相反。
      

      返回值

      如果ts_a小于ts_b,返回负数。
      如果ts_a等于ts_b,返回0。
      如果ts_a大于ts_b,返回正数
      

      二、使用场景

      1、编码流程:

      1、查找并分配编解码器:使用avcodec_find_encoder(codec_id)查找编解码器,然后通过avcodec_alloc_context3(codec)分配并初始化AVCodecContext。

      2、配置编解码器上下文:设置AVCodecContext的参数,如分辨率、比特率、时间基等。

      3、打开编解码器:调用avcodec_open2(context, codec, NULL)来初始化编解码器。

      4、编码循环:准备数据帧,调用avcodec_send_frame送入编码器,再通过avcodec_receive_packet获取编码后的数据包。

      2、解码流程:

      1、查找并分配解码器:与编码流程相似,使用avcodec_find_decoder(codec_id)和avcodec_alloc_context3(codec)。

      2、配置解码器上下文:根据输入流的参数配置AVCodecContext。

      3、打开解码器:调用avcodec_open2。

      4、解码循环:接收数据包通过avcodec_send_packet送入解码器,然后使用avcodec_receive_frame获取解码后的帧。

      三、编码使用实例

      这个例子将展示如何使用AVCodecContext和其他相关结构体来编码一帧原始图像数据为H.264视频流。

      1、首先,我们初始化FFmpeg库,找到H.264编码器,并为编码器创建和配置AVCodecContext。

      2、接着,我们创建输出文件的AVFormatContext,添加一个视频流,并打开输出文件。

      3、之后,我们为一帧原始图像数据创建AVFrame结构体,并简单地填充一些测试数据。

      4、利用avcodec_encode_video2()函数尝试编码这一帧数据,得到的编码数据包通过av_interleaved_write_frame()写入输出文件。

      5、最后,我们完成编码后清理资源,关闭编码器和输出文件。

      #include 
      #include 
      #include 
      int main() {
          const char *out_filename = "output.h264";
          const AVCodecID codec_id = AV_CODEC_ID_H264;
          // 初始化FFmpeg库
          av_register_all();
          avcodec_register_all();
          // 找到编码器
          AVCodec *codec = avcodec_find_encoder(codec_id);
          if (!codec) {
              printf("Codec not found\n");
              return -1;
          }
          // 创建并初始化编码上下文
          AVCodecContext *c = avcodec_alloc_context3(codec);
          if (!c) {
              printf("Could not allocate video codec context\n");
              return -1;
          }
          // 设置编码参数
          c->bit_rate = 400000; // 比特率
          c->width = 640;       // 宽度
          c->height = 480;      // 高度
          c->time_base = (AVRational){1, 25}; // 25帧每秒
          c->gop_size = 12;     // I帧间隔
          c->max_b_frames = 1;  // 最大B帧数
          c->pix_fmt = AV_PIX_FMT_YUV420P; // 像素格式
          // 打开编码器
          if (avcodec_open2(c, codec, NULL) codecpar, c);
          // 打开输出文件
          if (avio_open(&fmt_ctx->pb, out_filename, AVIO_FLAG_WRITE) format = c->pix_fmt;
          frame->width = c->width;
          frame->height = c->height;
          av_frame_get_buffer(frame, 0);
          // 填充帧数据(此处仅为演示,实际应用中应根据真实图像数据填充)
          uint8_t *image_data = frame->data[0];
          size_t image_size = c->width * c->height;
          memset(image_data, 128, image_size); // 简单地填充灰阶数据
          // 编码循环(简化版,实际应用中需要循环处理多帧)
          AVPacket pkt = {0};
          av_init_packet(&pkt);
          pkt.data = NULL; // packet data will be allocated by the encoder
          pkt.size = 0;
          // 将帧送入编码器
          int got_packet = 0;
          if (avcodec_encode_video2(c, &pkt, frame, &got_packet) time_base, stream->time_base);
              pkt.stream_index = stream->index;
              if (av_interleaved_write_frame(fmt_ctx, &pkt)  
      

      四、解码使用实例

      这个例子将会使用FFmpeg库来打开一个视频文件,找到解码器,初始化AVCodecContext,并进行基本的解码流程。

      1、首先,通过av_register_all()和avformat_network_init()注册FFmpeg的所有组件并初始化网络支持。

      2、使用avformat_open_input()打开视频文件,并通过avformat_find_stream_info()获取流信息。

      3、查找视频流,并根据视频流的编解码器ID查找解码器。

      4、为找到的解码器创建AVCodecContext实例,并使用avcodec_parameters_to_context()从流的AVCodecParameters复制参数到解码器上下文中。

      5、通过avcodec_open2()打开解码器,准备进行解码操作。

      #include 
      #include 
      int main(int argc, char **argv) {
          const char *filename = "example.mp4"; // 待解码的视频文件名
          if (argc > 1) filename = argv[1];
          av_register_all(); // 注册所有组件
          avformat_network_init(); // 初始化网络组件,如果视频来源于网络
          
          AVFormatContext *fmt_ctx = NULL;
          if (avformat_open_input(&fmt_ctx, filename, NULL, NULL) != 0) {
              printf("Could not open input file.\n");
              return -1;
          }
          if (avformat_find_stream_info(fmt_ctx, NULL) nb_streams; i++) {
              if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
                  video_stream_index = i;
                  break;
              }
          }
          if (video_stream_index == -1) {
              printf("Didn't find a video stream.\n");
              return -1;
          }
          dec = avcodec_find_decoder(fmt_ctx->streams[video_stream_index]->codecpar->codec_id);
          if (!dec) {
              printf("Decoder not found.\n");
              return -1;
          }
          
          dec_ctx = avcodec_alloc_context3(dec);
          if (avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar) 
                      
                      
                      
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]