播放器系列3——解码

FFmpeg解码过程详解

解码流程

avformat_open_input
avformat_find_stream_info
avcodec_find_decoder
avcodec_alloc_context3
avcodec_parameters_to_context
avcodec_open2
av_read_frame
avcodec_send_packet
avcodec_receive_frame
处理解码帧

API文档

avcodec_find_decoder

AVCodec *avcodec_find_decoder(enum AVCodecID id);
  • 功能: 根据编解码器ID查找解码器
  • 参数:
    • id: 编解码器ID
  • 返回值: 成功返回AVCodec指针,失败返回NULL
  • 示例:
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {fprintf(stderr, "未找到H264解码器\n");return -1;
}

avcodec_alloc_context3

AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
  • 功能: 分配并初始化AVCodecContext
  • 参数:
    • codec: 关联的编解码器,可以为NULL
  • 返回值: 成功返回AVCodecContext指针,失败返回NULL
  • 示例:
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {fprintf(stderr, "无法分配编解码器上下文\n");return -1;
}

avcodec_parameters_to_context

int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *par);
  • 功能: 将AVCodecParameters中的参数填充到AVCodecContext
  • 参数:
    • codec: 目标AVCodecContext
    • par: 源AVCodecParameters
  • 返回值: 成功返回0,失败返回负值错误码
  • 示例:
if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {fprintf(stderr, "无法填充编解码器参数\n");return -1;
}

avcodec_open2

int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
  • 功能: 使用指定解码器初始化AVCodecContext
  • 参数:
    • avctx: 要初始化的AVCodecContext
    • codec: 要使用的解码器
    • options: 额外的选项字典
  • 返回值: 成功返回0,失败返回负值错误码
  • 示例:
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {fprintf(stderr, "无法打开解码器\n");return -1;
}

avcodec_send_packet

int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
  • 功能: 将数据包发送给解码器
  • 参数:
    • avctx: AVCodecContext指针
    • avpkt: 要解码的数据包
  • 返回值: 成功返回0,失败返回负值错误码
  • 示例:
if (avcodec_send_packet(codec_ctx, &pkt) < 0) {fprintf(stderr, "发送数据包失败\n");continue;
}

avcodec_receive_frame

int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
  • 功能: 从解码器获取解码后的帧
  • 参数:
    • avctx: AVCodecContext指针
    • frame: 用于存储解码后的帧
  • 返回值: 成功返回0,失败返回负值错误码
  • 示例:
AVFrame *frame = av_frame_alloc();
while (avcodec_receive_frame(codec_ctx, frame) >= 0) {// 处理解码帧
}

Audio编码格式介绍

1. 音频编码格式概述

音频编码格式是将音频数据转换为可存储或传输的格式的过程。在音频领域,常见的编码格式包括PCM(脉冲编码调制)、MP3、AAC等。每种格式都有其特定的特点和应用场景。

2.常见音频编码格式

2.1 PCM(脉冲编码调制)

PCM(Pulse Code Modulation,脉冲编码调制)是一种将模拟信号转换为数字信号的标准方法。其核心过程包括采样、量化和编码,最终生成未经压缩的音频数据。PCM数据由如下六个参数来描述:

  • 采样率:每秒钟采集的样本数,例如44.1kHz表示每秒采集44100个样本。
    位深度:每个样本的量化位数,常见的有8位、16位、24位等。位深度越高,表示的动态范围越大,音质越好。
  • 声道数:单声道或双声道等。双声道音频通常采用LRLR或RLRL的方式存储。
  • 符号性:有符号或无符号。有符号数据可以表示负值,适用于更广泛的音频范围。
  • 字节序:大端模式或小端模式。字节序决定了数据在存储或传输时的排列顺序。
  • 数据类型:整型或浮点型。整型数据通常用于存储离散的量化值,而浮点型数据可能用于某些特殊应用。

PCM数据的存储方式:

  • 单声道PCM:采样数据按时间顺序存储,例如16位单声道音频,每个样本占用2个字节。
  • 双声道PCM:采样数据交错存储(Packed)或分开存储(Planar)。交错存储将左右声道的数据混合在一起,而分开存储则将左右声道的数据分别存储。

2.1.2 PCM数据的操作

在dump pcm数据的时候要关注当前数据是Packed还是Planar。通常pcm文件格式为Packed,那么也就是说如果按照Planar的方式来dump数据,那么dump出来的文件是不可以播放的。下面分别提供两种格式dump代码。

void FileDump::WritePcmPlanarData(uint8_t *data[], int size_per_sample) {/**P表示Planar(平面),其数据格式排列方式为 :LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)注意planar格式通常是ffmpeg内部使用格式而不带P的数据格式(即交错排列)排列方式为:LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)播放范例:   `*/
// 解析出来的是32bit float planar 小端数据for (int i = 0; i < audio_info_.samples; i++) {for (int ch = 0; ch < audio_info_.channels;ch++) // 交错的方式写入, 大部分float的格式输出fwrite(data[ch] + size_per_sample * i, 1, size_per_sample, file_);fflush(file_);}
}
void FileDump::WritePcmData(uint8_t *data[], int pcm_size) {fwrite(data[0], 1, pcm_size, file_);fflush(file_);
}

注意使用avcodec_receive_frame 获取到的数据是planar的,因此解码后的数据在dump的时候应该注意。
在使用sox 添加音效时也要注意,输入给API的数据需要是int32_t类型的planar数据。

2.1.2 PCM文件大小与播放时长的关系

假如一个PCM文件大小为100MB,采样率为44.1kHz,采样深度为16位,双声道。那么这个PCM文件的时长为:

时长 = 文件大小 / (采样率 * 采样深度 * 声道数 / 8)
时长 = 100MB / (44.1kHz * 16位 * 2声道 / 8)
2.1.3 PCM sample与播放时长的关系

如果当前解析出来的一段PCM数据sample个数是1024,并且采样率为44.1kHz,采样深度为16位,双声道。那么这个PCM文件的时长为:

时长 = sample个数 / 采样率 
时长 = 1024 / 44.1kHz  约等于23ms左右

2.2 AAC

AAC(高级音频编码,Advanced Audio Coding)是一种高压缩比的音频编码技术,最初基于MPEG-2标准开发,并在2000年随着MPEG-4标准的推出进一步发展为MPEG-4 AAC。AAC的设计目标是取代MP3格式,提供更高的音质和更低的比特率。
AAC编码封装格式分为两种:ADTS(Audio Data Transport Stream)和ADIF(Audio Data Interchange Format)。ADTS是一种流式封装格式,适用于实时传输和存储;ADIF是一种文件封装格式,适用于存储。

2.2.1 ADTS格式

在这里插入图片描述

上图可以看出以ADTS格式的AAC文件包含了多个adts_frame。
在这里插入图片描述

解析 ADTS 帧头:

  • adts_fixed_header():解析 ADTS 帧的固定头部,包含同步字、帧长度、采样率等信息。
  • adts_variable_header():解析 ADTS 帧的可变头部,包含声道配置、帧类型等信息。
    处理音频数据块:
  • adts_error_check():检查帧头部的错误。
  • raw_data_block():提取并处理音频数据块。
    如果 number_of_raw_data_blocks_in_frame == 0,表示帧中只有一个音频数据块。
    注意一个adts_frame中包含了1到16个raw_data_block,一个raw_data_block包含了1024个采样点。

2.2.2 ADIF格式

在这里插入图片描述

从图可以看出ADIF格式类型的AAC文件只有一个adif_header。

  • aif_header()
    作用: 定义位于 adif_sequence 开头的 ADIF 头。
    描述: 包含音频数据交换格式的基本信息,如版权标识、比特率类型、比特率等。具体字段包括 adif_id, copyright_id_present, copyright_id, original_copy, home, bitstream_type, bitrate, num_program_config_elements, 和 adif_buffer_fullness。
  • byte_alignment()
    作用: 对齐到头部的第一个比特。
    描述: 确保数据流在内存中的对齐,以便后续的数据处理更加高效。
  • raw_data_stream()
    作用: 包含实际的音频数据流。
    描述: 这是音频数据的核心部分,包含了经过编码的音频数据。
    好了,aac我们就介绍这些,毕竟较为复杂,在日常的开发中,解析aac head一般使用开源库,如果需要自己解析,也是边看spec边code.具体的aac格式请参照ISO/IEC
    13818-7 Part 7: Advanced Audio Coding (AAC)

Video 编码格式介绍

视频编码格式是将视频数据压缩成更小的数据块,以便于存储和传输。常见的视频编码格式包括H.264、H.265、VP8、VP9等。这些格式在压缩效率和视频质量之间取得了平衡。

1.H.264 (AVC)

H.264是一种广泛使用的视频编码格式,由ITU-T和ISO/IEC联合开发。H.264采用了基于帧的编码方式,将视频数据分割成多个帧,并对每个帧进行压缩。H.264的压缩算法包括帧内编码和帧间编码。

1.H264数据组织形式

在这里插入图片描述

1.帧的分类

1.1 I帧
  • I帧(Intra Frame)
    定义:I帧采用帧内压缩技术,不依赖于其他帧进行解码。I帧通过预测当前帧内的像素差异来减少数据量,通常用于场景切换或图像变化较大的时刻。
    特点:
    解码时不需要参考其他帧。
    压缩率较低(约7%),但提供高质量的画面。
    在GOP(Group of Picture)中作为起始帧,用于重同步解码过程。
    应用场景:I帧通常用于关键帧的插入,例如在检测到丢包或需要重新同步时立即插入一个I帧。
1.2 P帧
  • P帧(Predictive Frame)
    定义:P帧是前向参考帧,采用帧间压缩技术,仅参考前一帧(P帧或I帧)进行解码。
    特点:
    解码时需要参考前一帧。
    压缩率较高(约20%),适合变化较小的场景。
    可以进一步分为P1帧和P2帧,分别依赖前一帧和前两帧。
    应用场景:P帧常用于连续变化的场景,例如缓慢移动的物体或背景。
1.3 B帧
  • B帧(Bi-Directional Frame)
    定义:B帧是双向参考帧,采用帧间压缩技术,同时参考前后两帧(P帧或I帧)进行解码。
    特点:
    解码时需要参考前后两帧。
    压缩率最高(约50%),适合快速变化的场景。
    提高了压缩效率,但增加了解码复杂度。
    应用场景:B帧更适合运动较平缓的场景、静态北背景变化
帧大小对比

在这里插入图片描述

从图中可以看出I>P>B,而且大小相差很多。

参考链接

由于本人对视频编码格式不是很了解,因此这里给出一个参考链接,供大家学习。
https://www.nxrte.com/jishu/16413.html
注意

特性I 帧IDR 帧
定义独立编码的帧,不依赖其他帧特殊的 I 帧,用于重置参考帧列表
参考关系可能被后续 P/B 帧参考之后的所有帧都不能参考之前的帧考
作用提供随机访问点提供更强的随机访问能力

2.YUV编码介绍

YUV编码是一种广泛应用于数字视频和图像处理中的颜色编码方式,其核心思想是将图像的颜色信息分解为亮度(Y)和色度(U和V)两个部分。这种编码方式基于人类视觉对亮度和色度敏感度的不同,通过减少色度信息的采样率来降低数据传输和存储的带宽需求,从而实现高效的视频压缩和传输。

2.YUV原理

2.1亮度与色度分离:

Y(亮度)表示图像的明暗程度,是灰度值。

  • U和V(色度)分别表示蓝色差分信号和红色差分信号,用于描述颜色的饱和度和色调。
  • 在YUV编码中,亮度信息占据主要带宽,而色度信息则通过采样率降低来减少存储空间。
2.2 人眼特性:
  • 人类视觉对亮度变化比对颜色变化更敏感,因此在YUV编码中,亮度信息被赋予更高的带宽,而色度信息则通过采样率降低来减少数据量。
  • 这种设计使得YUV编码在保持图像质量的同时,能够有效减少数据传输和存储的带宽需求。
    数学表达:
2.3 YUV可以通过以下公式从RGB转换而来:
2.3.1 YUV 分量定义
  • Y:亮度(Luma)
  • U:蓝色色差(Cb)
  • V:红色色差(Cr)
2.3.2. 转换公式
  • Y = 0.299 * R + 0.587 * G + 0.114 * B
  • U = -0.14713 * R - 0.28886 * G + 0.436 * B
  • V = 0.615 * R - 0.51499 * G - 0.10001 * B
2.3.3. 公式说明
  • R, G, B 的取值范围为 [0, 255]
  • Y 的取值范围为 [0, 255]
  • U 和 V 的取值范围为 [-128, 127]
2.3.4. 示例

假设 R = 100, G = 150, B = 200:

  • Y = 0.299 * 100 + 0.587 * 150 + 0.114 * 200 ≈ 146.45
  • U = -0.14713 * 100 - 0.28886 * 150 + 0.436 * 200 ≈ 33.565
  • V = 0.615 * 100 - 0.51499 * 150 - 0.10001 * 200 ≈ -10.7485
    其中,R、G、B分别表示红色、绿色和蓝色分量。

2.4 YUV编码的采样格式

根据YUV的原理主要是改变UV的个数因此有如下格式
在这里插入图片描述

举个例子YUV4:4:4 代表什么意思:

  • 第一个"4"代表4列像素信息
  • 第二个"4"代表第一行像素信息
  • 第三个"4"代表第二行像素信息
    先记住下面这段话,以后提取每个像素的YUV分量会用到。
  • YUV 4:4:4采样,每一个Y对应一组UV分量。
  • YUV 4:2:2采样,每两个Y共用一组UV分量。
  • YUV 4:2:0采样,每四个Y共用一组UV分量。
    注意YUV存在Packed与Planar的概念,下面给出YUV420P如何dump code.
void FileDump::WriteVideoYUV420PData(AVFrame* videoFrame) {for (int j = 0; j < videoFrame->height; j++)fwrite(videoFrame->data[0] + j * videoFrame->linesize[0], 1, videoFrame->width, file_);for (int j = 0; j < videoFrame->height / 2; j++)fwrite(videoFrame->data[1] + j * videoFrame->linesize[1], 1, videoFrame->width / 2, file_);for (int j = 0; j < videoFrame->height / 2; j++)fwrite(videoFrame->data[2] + j * videoFrame->linesize[2], 1, videoFrame->width / 2, file_);
}

大多数播放器支持PCM packeted 与YUVPlanar ,因此我们在开发的时候也要注意,设置给驱动的format和输入给驱动的data 要符合驱动的要求。

2.4 YUV编码的采样格式

yuv420p原图
在这里插入图片描述

Y图
在这里插入图片描述

U图
在这里插入图片描述

V图
在这里插入图片描述

从上面三幅图片可以看出来,人眼灰度图片(Y图)敏感度最高,感官上可以感觉出来Y图反馈的信息最多

总结

可以看出不论是Audio还是Video,编码的最终目的都是在尽可能保证原始数据质量的同时,减少冗余信息,提高传输效率。

源码地址

https://github.com/OrangeKitten/VideoPlayer

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

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

相关文章

SimPO算法-Simple Preference Optimizationwith a Reference-Free Reward

偏好优化&#xff08;preference optimization &#xff09;算法大全&#xff1a; 本篇介绍下SimPO SimPO&#xff08;Simple Preference Optimization&#xff09;的设计核心在于简化偏好优化过程&#xff0c;同时提升模型的表现。其设计主要围绕两个关键点展开&#xff1a;长…

AIGC时代:如何快速搞定Spring Boot+Vue全栈开发

文章目录 一、Spring Boot基础二、Vue.js基础三、Spring Boot与Vue.js集成四、性能优化与最佳实践《快速搞定Spring BootVue全栈开发》 内容简介作者简介目录前言/序言本书内容本书特点读者对象 随着人工智能生成内容&#xff08;AIGC&#xff09;技术的迅速发展&#xff0c;…

探秘基带算法:从原理到5G时代的通信变革【六】CRC 校验

文章目录 2.5 CRC 校验2.5.1 前言2.5.2 CRC算法简介2.5.3 CRC计算的详细过程2.5.4 CRC校验的两种方法详解**分离比较法****整体运算法****不同位出错与余数的关系****总结** 2.5.5 CRC计算的C实现及工具介绍**C实现CRC计算****CRC计算工具推荐** **2.5.6 总结&#xff1a;CRC校…

AUTOSAR微控制器抽象层(MCAL)详解及综合实例

目录 1. 微控制器抽象层(MCAL)概述 1.1 MCAL的核心功能 1.2 MCAL的模块划分 1.3 MCAL的工作流程 2. MCAL的详细功能解析 2.1 微控制器驱动 2.1.1 时钟配置 2.1.2 电源管理 2.1.3 实例:时钟配置 2.2 通信驱动 2.2.1 CAN驱动 2.2.2 实例:CAN通信的实现 2.3 I/O驱…

探究高空视频全景AR技术的实现原理

1. 引言 笔者认为现阶段AR技术的应用是还是比较坑爹的&#xff0c;大都是噱头多但是实用的成分少&#xff0c;拿出来做做DEMO是可以&#xff0c;但是难以在实际的项目中落地产生实际的经济价值。一方面是很难在业务上难以找到合适的应用场景&#xff08;可能管线相关的项目算一…

深度解析 | 2025 AI新突破,物理信息神经网络(PINN):Nature级顶刊的「科研加速器」,70份源码论文速取!

&#x1f525; 为什么全球顶尖实验室都在押注PINN&#xff1f; 过去一年&#xff0c;物理信息神经网络&#xff08;PINN&#xff0c;Physics-Informed Neural Networks&#xff09;以「现象级」姿态席卷科研圈&#xff1a;不仅在NeurIPS、ICML等顶会横扫15%相关论文&#xff0c…

0基础学前端---品优购项目Day14

0基础学前端—品优购项目Day14 视频参考&#xff1a;B站Pink老师 本节重点&#xff1a;all 项目链接&#xff1a;完整的项目已放到 品优购完整项目 大家可以自行下载 强调内容 这里主要强调两个知识点&#xff1a; (1) 网站TDK三个标签SEO优化 (2) logo SEO优化 网站TDK三个…

LeetCode热题100JS(37/100)第七天|排序链表|合并K个升序链表|LRU缓存|二叉树的中序遍历|二叉树的最大深度|对称二叉树

148. 排序链表 题目链接&#xff1a;​​​​​​​148. 排序链表 难度&#xff1a;中等 刷题状态&#xff1a;1刷 新知识&#xff1a; - dic.reduceRight((t,c)>(c.nextt,c),null) 方法从数组的末尾开始执行 解题过程 思考 示例 1&#xff1a; 输入&#xff1a;head […

课程2. 机器学习方法论

课程2. 机器学习方法论 训练算法并评估其质量将样本分成训练和测试。分层 交叉验证方法sklearn 接口算法模型训练模型的应用质量评估 数据预处理标准缩放Violinplot 数据集使用模型Pipeline 在上一讲中&#xff0c;我们讨论了机器学习专家面临的挑战。无论解决的问题类型和解决…

六足仿生机器人地形自适应步态规划研究

六足仿生机器人地形自适应步态规划研究 第1章 绪论第2章 机器人系统建模第3章 地形感知与建模第4章 自适应步态生成算法第5章 动力学仿真与实验第6章 驱动代码设计与实现源码&文档链接 第1章 绪论 1.1 研究背景与意义 1.2 国内外研究现状 1.2.1 多足机器人步态规划 1.2.2 …

mysql表分区

本文简述了mysql表分区的作用和特点&#xff0c;又演示了mysql表分区的创建过程&#xff0c;详细演示了指定不同分区目录时的处理办法。由于表分区对crud操作是透明的&#xff0c;对于普通开发同学其实不用过多关注&#xff0c;但是本着学习的态度&#xff0c;在分库分表等高大…

Nessus安装

Nessus&#xff1a;https://pan.quark.cn/s/f5fb09b6d4fb 1.软件安装 点击安装&#xff0c;剩下的下一步即可。 直接下一步安装即可 2.Web端安装 会弹出一个web窗口 开始初始化 创建用户 开始初始化 3.Cracker 会弹一个黑窗口 运行完&#xff0c;回车即可。访问https://loc…

26-小迪安全-模块引用,mvc框架,渲染,数据联动0-rce安全

先创建一个新闻需要的库 这样id值可以逐级递增 然后随便写个值&#xff0c;让他输出一下看看 模板引入 但是这样不够美观&#xff0c;这就涉及到了引入html模板 模板引入是html有一个的地方值可以通过php代码去传入过去&#xff0c;其他的html界面直接调用&#xff0c;这样页…

第十三届蓝桥杯大赛软件赛决赛C/C++ 大学 B 组

A 【2022——暴力DP / 优雅背包】-CSDN博客 B 【钟表——类日期问题】-CSDN博客 C 【卡牌——二分】-CSDN博客 D 【最大数字——DFS】-CSDN博客 E 【出差——Dijkstra】-CSDN博客 F 【费用报销——01背包】-CSDN博客 G 【故障——条件概率】-CSDN博客 H 【机房—…

树莓集团最新现状更新:南京园区业务的创新与突破

树莓集团在南京的园区业务呈现出蓬勃发展的态势&#xff0c;不断实现创新与突破。 在产业布局方面&#xff0c;南京园区进一步优化了产业结构。除了继续巩固数字影像、数字娱乐等传统优势领域外&#xff0c;还积极拓展了数字金融、数字教育等新兴领域。吸引了一批知名的数字金融…

Linux网络编程(20250301)

网络通信&#xff1a;进行不同主机的进程间通信 解决硬件与软件的互联互通 主机-->交换机-->路由器-->广域网-->路由器-->交换机-->主机 IP地址&#xff1a;区分不同主机 MAC地址&#xff1a;计算机硬件地址 端口号&#xff1a;区分主机上的不同进程 1…

【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-附录B-严格模式

附录B、严格模式 严格模式 ECMAScript 5 首次引入严格模式的概念。严格模式用于选择以更严格的条件检查 JavaScript 代码错误&#xff0c;可以应用到全局&#xff0c;也可以应用到函数内部。严格模式的好处是可以提早发现错误&#xff0c;因此可以捕获某些 ECMAScript 问题导致…

蓝桥试题:混境之地(记忆化搜索)

一、问题描述 小蓝有一天误入了一个混境之地。 好消息是&#xff1a;他误打误撞拿到了一张地图&#xff0c;并从中获取到以下信息&#xff1a; 混境之地是一个n⋅m 大小的矩阵&#xff0c;其中第 i 行第 j 列的的点 h i j​ 表示第 i 行第 j 列的高度。他现在所在位置的坐标…

CC++链接数据库(MySQL)超级详细指南

C/C链接数据库&#xff08;MySQL&#xff09;超级详细指南 在C/C编程中&#xff0c;与数据库进行交互是一项常见的任务。MySQL作为一个广泛使用的开源关系型数据库管理系统&#xff0c;提供了丰富的API供C/C开发者使用。本文将详细介绍如何在C/C程序中链接MySQL数据库&#xf…

基于EM期望最大化算法的GMM参数估计与三维数据分类系统python源码

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 EM算法 E步:期望步 M步:最大化步 4.2 GMM模型 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 程序运行配置环境&#xff1a; 人工智能算法…