FFMPEG 解码过程初步学习

news2024/11/16 7:52:53

1. 视频文件解码过程

解码过程

在这里插入图片描述

步骤如下:

  1. 视频文件(封装格式,MP4/FLV/AVI 等)获取视频格式信息等
  2. 解复用为Stream 流, 准备解码用的Codec
  3. 将Stream 流 使用解码器解为Raw 格式针

1.1 音视频格式填充:

int ret = avformat_open_input(&format_ctx, filename, nullptr, nullptr);  // 打开输入文件并将格式上下文赋给 format_ctx
// 填充stream 信息
if (avformat_find_stream_info(format_ctx, NULL) < 0) {
    std::cout << "no stream in files : " << std::endl;
    return -1;
}


// find the video stream information
ret = av_find_best_stream(format_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (ret < 0) {
    fprintf(stderr, "Cannot find a video stream in the input file\n");
    return -1;
}
video_stream_index = ret;
video_stream = format_ctx->streams[video_stream_index];

 ret = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
if (ret < 0) {
    std::cout<< "no audio stream " << ret << std::endl;
} else {
    audio_stream_index = ret;
    audio_stream = format_ctx->streams[audio_stream_index];
}

1.2 准备解码用的codec

const AVCodec * video_codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
if (video_codec == nullptr) {
    std::cout << "we not found the code: " << video_decoder->id << std::endl;
} else {
    std::cout << "we found the video codec: " << video_codec->name << std::endl;
}
const AVCodec * audio_codec = avcodec_find_decoder(audio_stream->codecpar->codec_id);
if (audio_codec == nullptr) {
    std::cout << "we not found the code: " << audio_decoder->id << std::endl;
} else {
    std::cout << "we found the audio codec: " << audio_codec->name << std::endl;
}

// codec context for decoder 
AVCodecContext* video_dec_context = avcodec_alloc_context3(video_codec);
if (!video_dec_context) {
    std::cout << "video dec context alloc failed" << std::endl;
}
if ((ret = avcodec_parameters_to_context(video_dec_context, video_stream->codecpar)) < 0) {
    std::cerr << "codec copy failed" << std::endl;
}
std::cout<< "video format width: " << video_dec_context->width << std::endl;
std::cout<< "video format height: " << video_dec_context->height << std::endl;
std::cout << "video pixel format: " << video_dec_context->pix_fmt << std::endl;
video_width = video_dec_context->width;
video_height = video_dec_context->height;
video_fmt = video_dec_context->pix_fmt;
// open codec
ret = avcodec_open2(video_dec_context, video_codec, NULL);
if (ret < 0) {
    std::cerr << "video codec open failed" << std::endl;
}

Audio 的流程和video 的流程相近:
通过stream 信息->AVCodec->AVCodecContext , 再通过AVCodecContext 打开解码器(avcodec_open2)

1.3 解码过程:

在打开解码器后,创建AVPacket AVFrame
AVPacket 是解码前的包, AVFrame 是解码后的帧

AVPacket *packet;
packet = av_packet_alloc();

AVFrame* frame = av_frame_alloc();

while(1) {
  // 从里面获取一个packet
  ret1 = av_read_frame(format_ctx, packet);
  if (ret1 < 0) {
      break;
  } else {
      /*
      if (packet->stream_index == video_stream_index) {
          std::cout << "Video: pts: " << packet->pts << " dts: " << packet->dts <<" duration: " << packet->duration << std::endl;
      } else {
          if (packet->stream_index != -1 && audio_stream_index == packet->stream_index) {
              std::cout << "Audio: pts: " << packet->pts << " dts: " << packet->dts <<" duration: " << packet->duration << std::endl;
          }
      }
      */
      if (packet->stream_index == video_stream_index) {
          int result = decode_packet(video_dec_context, packet);
          if (result == 0) {
              //video_frame_count++;
               

          }

      } else {
          decode_packet(audio_dec_context, packet);
          av_frame_unref(frame);
      }

  }
  av_packet_unref(packet);

}
// 解包过程
static int decode_packet(AVCodecContext *dec, const AVPacket *pkt)
{
  int ret = 0;

  // submit the packet to the decoder
  ret = avcodec_send_packet(dec, pkt);
  if (ret < 0) {
      fprintf(stderr, "Error submitting a packet for decoding (%d)\n", ret);
      return ret;
  }

  // get all the available frames from the decoder
  while (ret >= 0) {
      ret = avcodec_receive_frame(dec, frame);
      if (ret < 0) {
          // those two return values are special and mean there is no output
          // frame available, but there were no errors during decoding
          if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
              return 0;

          // fprintf(stderr, "Error during decoding (%s)\n", av_err2str(ret));
          std::cerr << "Error during decoding " << ret << std::endl;
          return ret;
      }

      // // write the frame data to output file
      if (dec->codec->type == AVMEDIA_TYPE_VIDEO) {
          static int video_frame_count = 0;
          /* copy decoded frame to destination buffer:
          * this is required since rawvideo expects non aligned data */
          // std::cout << "frame size: " << frame->linesize << std::endl;
          av_image_copy2(video_dst_data, video_dst_linesize,
                      frame->data, frame->linesize,
                      video_fmt, video_width, video_height);

          /* write to rawvideo file */
          size_t size =  fwrite(video_dst_data[0], 1, video_dst_bufsize, video_dst_file);
          if (size == 0) {
              std::cerr << "write failed" << std::endl;
              return -1;
          } else {
              
              video_frame_count++;
              std::cout << " write to video frame count: " << video_frame_count << std::endl;
          }
          
      }
           //ret = output_video_frame(frame);
      // else
      //     ret = output_audio_frame(frame);

      av_frame_unref(frame);
  }

  return ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1693319.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

升级版网创教程wordpress插件自动采集并发布

主要功能&#xff1a; wordpress 插件主题系列支持自动采集并发布。 主要采集: 福缘&#xff0c;中创&#xff0c;冒泡 自动采集各大项目网进行整合发布到自己个人网站 插件话更新&#xff0c;减少网络请求&#xff0c;提升稳定性 代码完美开源 傻瓜式操作&#xff0c;一…

第 398 场 LeetCode 周赛题解

A 特殊数组 I 模拟&#xff1a;遍历数组判断是否是一个特殊数组 class Solution { public:bool isArraySpecial(vector<int>& nums) {int r 0;while (r 1 < nums.size() && nums[r 1] % 2 ! nums[r] % 2)r;return r nums.size() - 1;} };B 特殊数组 I…

Aiseesoft iPhone Unlocker for Mac激活版:一键解锁工具

在数字时代&#xff0c;手机解锁问题时常困扰着我们。Aiseesoft iPhone Unlocker for Mac作为一款专为Mac用户打造的解锁工具&#xff0c;以其简洁易用的界面和强大的功能&#xff0c;成为了解决iPhone解锁问题的最佳选择。 Aiseesoft iPhone Unlocker for Mac激活版下载 Aisee…

Mysql之InnoDB索引

1.索引简介 官网介绍:MySQL :: MySQL 8.0 Reference Manual :: 10.3.1 How MySQL Uses Indexes 索引用于快速查找具有特定列值的行。如果没有索引&#xff0c; MySQL 必须从第一行开始&#xff0c;然后读取整个表以找到相关的行。表越大&#xff0c;花费就越多。如果表中有相关…

java项目之视频网站系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的视频网站系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 视频网站系统的主要使用者管…

Java进阶学习笔记15——接口概述

认识接口&#xff1a; Java提供了一个关键字Interface&#xff0c;用这个关键字我们可以定义一个特殊的结构&#xff1a;接口。 接口不能创建对象。 注意&#xff1a;接口不能创建对象&#xff0c;接口是用来被类实现&#xff08;implements&#xff09;的&#xff0c;实现接口…

意外发现openGauss兼容Oracle的几个条件表达式

意外发现openGauss兼容Oracle的几个条件表达式 最近工作中发现openGauss在兼容oracle模式下&#xff0c;可以兼容常用的两个表达式&#xff0c;因此就随手测试了一下。 查看数据库版本 [ommopenGauss ~]$ gsql -r gsql ((openGauss 6.0.0-RC1 build ed7f8e37) compiled at 2…

idea使用鼠标滚轮进行字体大小缩放

idea使用鼠标滚轮进行字体大小缩放 使用快捷键CtrlAltS进入到设置页面 在左上角搜索框输入“increase”&#xff0c;在左侧的Keymap中右击“Increase Fort Size”&#xff0c;点击“add mouse shortcut”&#xff0c;然后录入我们要设置的快捷键&#xff0c;比如我是点击ctrl鼠…

Unity Assembly Definition Dotween 引用

原理&#xff1a; 具体Unity程序集原理用法&#xff0c;暂时留坑&#xff0c;不介绍了&#xff0c;相信有很多人也写过了 这里简单放个官方API链接 https://docs.unity3d.com/cn/current/Manual/ScriptCompilationAssemblyDefinitionFiles.html 现象 &#xff1a;Dotween引用…

CATIA入门操作——为什么大佬的工具栏是水平的?如何把工具栏变水平?

目录 引出工具栏怎么变成水平&#xff1f;总结发生肾么事了&#xff1f;&#xff1f;鼠标中键旋转不了解决&#xff1a;特征树不显示参数关系 我的窗口去哪了&#xff1f;插曲&#xff1a;草图工具的调出插曲&#xff1a;颜色工具栏显示 弹窗警告警告&#xff1a;创建约束是临时…

bootstrap实现九宫格效果(猫捉老鼠游戏)

最近&#xff0c;孩子的幼儿园让家长体验“半日助教活动”&#xff0c;每个家长需要讲授15-20分钟的课程。作为一名程序员&#xff0c;实在没有能教的课程&#xff0c;只能做了一个小游戏&#xff0c;带着小朋友们熟悉数字。 效果大致是这样的。九宫格的左上角是一只小猫图片&…

VirtualBox+Ubuntu22.10+Docker+ROS2

Docker 拉取ros2镜像 docker pull osrf/ros:foxy-desktop 运行 docker run -it --nameros2 -p 50022:22 osrf/ros:foxy-desktop 进入容器安装组件 apt-get update apt-get install vim apt-get install git apt-get install net-tools # 安装ssh apt-get install openssh…

企业如何防止数据泄密?大型企业必备的文件加密软件

随着信息化建设的大步推进&#xff0c;越来越多的企业资料以电子文件的形式保存&#xff0c;企业内部和企业之间的信息交流也主要依靠电子文件。近年来的泄密事件层出不穷&#xff0c;比如东软泄密案、HTC窃密案、力拓案等&#xff0c;给企业带来灾难性的经济损失及信誉重创。如…

Redis(十三) 事务

文章目录 前言事务的特性Redis事务的执行原理Redis中使用事务WATCH UNWATCH实现乐观锁 前言 前面我们学习 MySQL 的时候&#xff0c;肯定也学习了事务。事务是什么&#xff1f;给大家举个例子&#xff1a;假如我给朋友微信转账&#xff0c;我给他转了 100 块钱&#xff0c;当我…

ArcGIS中分割与按属性分割的区别

1、分割ArcGIS批量导出各个市的县级行政边界 视频教学&#xff1a; ArcGIS批量导出各个市的县级行政边界002 2、ArcGIS批量导出全国各省的边界 视频教学&#xff1a; ArcGIS导出全国各省的边界003 推荐学习&#xff1a; ArcGIS全系列实战视频教程——9个单一课程组合系列直播回…

RAG技术综述

RAG的基本架构。&#xff0c;生成器和检索器。 参考paper&#xff1a;https://arxiv.org/html/2402.19473v4 文中将rag的内容从文本扩展至多模态&#xff0c;打开了思路。 生成器&#xff1a;transformer&#xff0c;LSTM&#xff0c;扩散模型&#xff0c;gan 检索器&#xf…

怎么一键消除路人?教你三个消除方法

怎么一键消除路人&#xff1f;在数字时代&#xff0c;摄影已成为我们记录生活、表达情感的重要方式。然而&#xff0c;完美的照片背后往往隐藏着一些不那么完美的元素——比如那些不经意间闯入镜头的路人。他们或许只是匆匆过客&#xff0c;但却足以破坏你精心构图的美好瞬间。…

香农信息量/自信息、信息熵、相对熵/KL散度/信息散度、交叉熵

诸神缄默不语-个人CSDN博文目录 文章目录 1. 引言2. 什么是熵&#xff1f;3. 香农信息量/自信息香农信息量的定义香农信息量的含义香农信息量计算示例香农信息量与信息熵的关系 4. 信息熵信息熵的定义信息熵的计算公式信息熵计算示例 5. 衡量两个分布间的差异&#xff1a;相对熵…

Excel工作簿/表的合并/拆分全集(一文通关)

概述 在工作中&#xff0c;我们常会用到到Excel拆分/合并为多个工作表/簿&#xff0c;如全国的订单表&#xff0c;需要根据省份列拆分下发至对应的省、各省份数据需要汇总、...... 应该如何操作呢&#xff1f; 1. 传统方法&#xff08;借助透视表、Power Query编辑器、VBA实现…

Alienware外星人笔记本m17 R3原厂OEM预装Win10系统包下载,恢复开箱状态电脑自带系统

适用型号&#xff1a;Alienware M17 R3 链接&#xff1a;https://pan.baidu.com/s/1m3RwLmIlih3iPn5AclpptQ?pwdmsef 提取码&#xff1a;msef 外星人原装W10系统自带所有驱动、出厂专用主题壁纸、系统属性专属联机支持标志、系统属性专属LOGO标志、Office办公软件、MyAlie…