FFMPEG 解码过程初步学习

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) {// 从里面获取一个packetret1 = 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 decoderret = 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 decoderwhile (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 decodingif (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 fileif (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.mzph.cn/web/15199.shtml

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

相关文章

找不到msvcr110.dll无法继续执行代码的原因分析及解决方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是找不到msvcr110.dll文件。这个错误通常发生在运行某些程序或游戏时&#xff0c;系统无法找到所需的动态链接库文件。为了解决这个问题&#xff0c;下面我将介绍5种常见的解决方法。 一&#…

Vue3实现上传照片以及回显

Vue3实现上传照片以及回显 一、安装Element Plus二、案例1、基本示例 三、进阶案例1、代码2、代码解释1、上传接口展示2、查询接口展示组件属性 3、效果展示 一、安装Element Plus 使用 Element Plus 组件库来实现上传照片和回显同样很简单&#xff0c;你可以按照以下步骤进行…

用栈实现队列(C语言)

目录 题目题目分析 代码栈的实现结构体。栈的初始化栈的销毁 入栈删除查找顶部数据判空 答案结构体初始化插入数据删除数据获取队列开头元素判空销毁栈 题目 题目分析 链接: 题目 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、po…

pyside6下没有designer.exe、pyside6-uic.exe等

使用conda安装的pyside6&#xff08;conda install pyside6&#xff09;&#xff0c;发现pyside6目录下没有designer.exe、pyside6-uic.exe等&#xff1b;designer.exe在Miniconda3/Library/bin下 pyside6-uic.exe、pyside6-rcc.exe在Miniconda3\Scripts下 但是 使用pip安装…

【MyBatis】MyBatis解析全局配置文件源码详解

目录 一、前言 思维导图概括 二、配置文件解析过程分析 2.1 配置文件解析入口 2.2 初始化XMLConfigBuilder 2.3 XMLConfigBuilder#parse()方法&#xff1a;解析全局配置文件 2.3.1 解析properties配置 2.3.2 解析settings配置 2.3.2.1 元信息对象&#xff08;MetaClas…

解决移植Metasploitable3到VM虚拟机无网络的问题

第一步 导入后不要开机&#xff0c;先在虚拟机设置里面将原有的两个网络适配器移除。 第二步 接着在选项里面&#xff0c;在客户机操作系统里面&#xff0c;选择Microsoft Windwos(W)&#xff0c; 版本选择Windows Server 2008 R2 x64 第三步 先打开虚拟机&#xff0c;然后…

Python_文件操作_学习

目录 一、关于文件的打开和关闭 1. 文件的打开 2.文件的关闭 二、文件的读取 1. 文件的读_r 2. 使用readline 3.使用readlines 三、文件的写入 1. 文本的新建写入 2.文本的追加写入 四、文件的删除和重命名 1.文件的重命名 2.文件的删除 五、文件的定位读写 1.t…

Unity Miscellaneous入门

概述 在Unity中有非常多好用的组件&#xff0c;也是Unity为我们提供的方便的开发工具&#xff0c;它的功能可能不是主流的内容&#xff0c;比如渲染&#xff0c;音乐&#xff0c;视频等等&#xff0c;所有Unity把这些内容统一归到了一个杂项文件组中。 Unity组件入门篇总目录-…

Python线程

Python线程 1. 进程和线程 先来了解下进程和线程。 类比&#xff1a; 一个工厂&#xff0c;至少有一个车间&#xff0c;一个车间中至少有一个工人&#xff0c;最终是工人在工作。 一个程序&#xff0c;至少有一个进程&#xff0c;一个进程中至少有一个线程&#xff0c;最终…

langchain实战-从0到1搭建ai聊天机器人

介绍 当前&#xff0c;人工智能大模型公司如雨后春笋般迅速涌现&#xff0c;例如 OpenAI、文心一言、通义千问等&#xff0c;它们提供了成熟的 API 调用服务。然而&#xff0c;随之而来的是不同公司的繁琐协议接入过程&#xff0c;这让许多开发者感到头疼不已。有没有一种统一…

SpringBoot + Redis实现对接口的限流

目录 前言 什么是限流&#xff1f; 实现限流 创建一个注解类 接着创建一个切面类 前言 在项目中&#xff0c;对于接口的限流&#xff0c;是任何项目都必不可少的一部分&#xff0c;主要是为了防止用户频繁的发送请求&#xff0c;对服务器造成压力。 另外一点就是防止外来攻…

C++之第八课

课程列表 今天我们来学一学C里的一些实用的东西。 1.域宽 说到域宽setw&#xff0c;就叒要加头文件了。 #include<iomanip> 使用格式是&#xff1a; cout<<setw(5)<<"123"; setw括号里面可以改数字&#xff0c;后面就是输出内容了&#xff…

COD论文笔记 Boundary-Guided Camouflaged Object Detection

动机 挑战性任务&#xff1a;伪装物体检测&#xff08;COD&#xff09;是一个重要且具有挑战性的任务&#xff0c;因为伪装物体往往与背景高度相似&#xff0c;使得准确识别和分割非常困难。现有方法的不足&#xff1a;现有的深度学习方法难以有效识别伪装物体的结构和细节&am…

MySQL索引、视图练习

素材 1.学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 2.课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 3.学生选课表&#xff1a;SC (Sno…

Home Credit - Credit Risk Model Stability

本篇是对Kaggle上Home Credit - Credit Risk Model Stability竞赛中的开源代码VotingClassifier Home Credit的解读。原链接在VotingClassifier Home Credit (kaggle.com)。 %%writefile script.py import sys from pathlib import Path import subprocess import os import g…

浅谈JMeter运行原理

浅谈JMeter运行原理 JMeter架构基础 JMeter基于Java平台开发&#xff0c;运行于Java虚拟机&#xff08;JVM&#xff09;之上。这意味着它可以在任何支持JVM的操作系统上运行&#xff0c;包括Windows、Linux、macOS等。其核心架构设计围绕着多线程执行机制&#xff0c;这使得它…

AI大模型探索之路-实战篇6: Function Calling技术调研之详细流程剖析

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;DB-GPT数据应用开发框架调研实践 AI大模型探索之路-实战篇5&#xff1a; Open Interpreter开放代码解释器调研实践 目录 系列篇章&#x1f4a5;一、前言二、Function Calling详细流程剖析1、创建OpenAI客户端2、定…

PCL 法向量加权的RANSAC拟合分割平面

目录 一、算法原理1、原理概述2、主要函数二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、原理概述

鸿蒙布局List简介

鸿蒙布局List简介 List--常见的布局容器List 创建方式创建方式一&#xff0c;通过Listitem创建方式二&#xff0c;通过ForEach和Listitem创建方式三&#xff0c;通过ListItemGroup List–常见的布局容器 List是在app开发中最常见的一种布局方式&#xff0c;例如通讯录、新闻列…