【备战秋招】C++音视频开发经典面试题整理

发布于:2025-05-27 ⋅ 阅读:(19) ⋅ 点赞:(0)

1、简要介绍一下对 H.264 的了解?

1)基础描述

H.264 是由国际标准组织机构(ISO)下属的运动图象专家组(MPEG)和国际电传视讯联盟远程通信标准化组织(ITU-T)开发的系列编码标准之一。

2)码流结构

H.264 原始码流(裸流)是由一个接一个 NALU 组成,它的功能分为两层:VCL(视频编码层)和 NAL(网络抽象层)。

  • 视频编码层 VCL(Video Coding Layer):是对视频编码核心算法过程、子宏块、宏块、片等概念的定义。这层主要是为了尽可能的独立于网络来高效的对视频内容进行编码。

  • 网路抽象层 NAL(Network Abstract Layer):负责将 VCL 产生的比特字符串适配到各种各样的网络和多元环境中,覆盖了所有片级以上的语法级别。

3)两种封装

H.264 的两种封装:AnnexB 模式和 AVCC 模式。

AnnexB 模式:

  • 传统模式

  • 有 startcode,startcode 码是:00 00 01 或 00 00 00 01 (3 字节或 4 字节)

  • SPS 和 PPS 在码流中分别作为一个 NALU

AVCC 模式:

  • 没有 startcode,SPS 和 PPS 以及其它信息被封装在 container 中,每一个 frame 前面 4 个字节是这个 frame 的长度

  • 一般在 mp4、mkv 格式中常用 AVCC 模式

很多解码器只支持 AnnexB 这种模式,因此需要将 AVCC 模式做转换,在 ffmpeg 中⽤ h264_mp4toannexb_filter 可以做转换,实现如下:

const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb"); 

AVBSFContext *bsf_ctx = NULL; 
// 初始化过滤器上下⽂ 
av_bsf_alloc(bsfilter, &bsf_ctx); 
// 添加解码器属性
avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->cod ecpar);
av_bsf_init(bsf_ctx);

2、H.264 编码框架分层目的是什么?

对 H.264 编码框架进行分层的主要目标是为了有高的视频压缩比和良好的网络亲和性。

VCL 层负责视频的信号处理,包含压缩,量化等处理,NAL 层则负责解决编码后数据的网络传输。

这样可以将 VCL 和 NAL 的处理放到不同平台来处理,可以减少因为网络环境不同对 VCL 的比特流进行重构和重编码。

这样将编码和网络传输进行隔离,使功能单一、便于维护。

3、介绍一下 I、P、B 帧编码、解码、显示顺序?

我们以下图为例来介绍一下 I、P、B 帧的编码过程:

编码器编码一个 I 帧,然后向后跳过几个帧,用这个 I 帧作为基准帧对一个未来 P 帧进行编码,然后跳回到这个 I 帧之后的下一个帧。I 帧和 P 帧之间的帧可以被编码为 B 帧。之后,编码器会再次跳过几个帧,使用第一个 P 帧作为基准帧,编码另外一个 P 帧,然后再次跳回,用 B 帧填充显示序列中的空隙。这个过程不断持续,然后每间隔一定的帧数后插入一个新的 I 帧。

由于帧之间存在依赖关系,所以各帧的解码顺序和编码顺序是一致的,先被编码的帧在解码时就会先被解码。为了实现这一点,编码的时候需要根据每帧的编码顺序会为其记录上一个 DTS(Decoding Time Stamp)用于解码时按此顺序进行解码。

如上面介绍的编码过程,P 帧由前一个 I 帧或 P 帧来预测,而 B 帧由前后的两个 P 帧或一个 I 帧和一个 P 帧来预测,因而当存在 B 帧时,帧的编解码顺序和帧的显示顺序会有所不同,这时候就需要为每帧记录上一个 PTS(Presentation Time Stamp)用于解码后按顺序显示。

4、H.264 与 H.265 有什么区别?

1)主要区别

  • H.265 也称为高效视频编码 (HEVC),是 H.264 的升级和更高级的版本;

  • H.265 的编码架构大致上 和 H.264 的架构相似,主要也包含:帧内预测(intra prediction)、帧间预测(inter prediction)、转换(transform)、量化(quantization)、去区块滤波器(deblocking filter)、熵编码(entropy coding)等模块。但在 H.265 编码架构中,整体被分为了三个基本单位,分别是编码单位(coding unit, CU)、预测单位(predict unit, PU)和转换单位(transform unit, TU);

  • 比起 H.264,H.265 提供了更多不同的工具来降低码率,以编码单位来说,H.264 中每个宏块(macroblock/MB)大小最大为 16x16 像素,而 H.265 的编码单位最大为 64x64;

  • H.265 的帧内预测模式支持 35 种方向(而 H.264 只支持 8 种),并且提供了更好的运动补偿处理和矢量预测方法。

5、RTMP 和 RTSP 有什么区别?使用 RTSP 是基于 UDP 传输的话,我们怎样进行乱序重排?

RTMP 和 RTSP 的区别:

RTMP 使用 TCP 作为传输层协议,能保证不丢包和接收顺序,传输质量高。

RTSP 使用 RTP 格式协议和 RTCP 控制协议,命令与数据分离。传输层协议一般会选择 UDP,延迟比较低,传输效率高。

RTSP 中的 RTP 格式头中有 SequenceNumber 字段,可以通过这个序号实现排序。

6、假如给你一堆乱序的 RTP 包,应该怎样实现乱序重排?

可以利用接收 RTP 包缓冲队列使用包的序号进行排序。

在丢包情况下为保证传输质量会引入 NACK 和 FEC 机制。

NACK 表示接收端通知发送端一些包丢失,发送 NACK 包请求重传;FEC 前向纠错值的是每个包携带一些冗余信息可以在部分包丢失的时候利用其他包进行重建。

如果重传次数过多,包无法重建,或者丢的包过多,此时可以丢帧直接跳过丢失的部分。

7、对 YUV 格式有了解吗?YUV 数据做转换是怎样实现的,比如说 YUV422 转为 YUV420?

YUV 格式是传输视频常用的格式,因为相对于 RGB 格式它可以节省更多空间。

YUV 的格式有很多,例如:YUV444、YUV422、YUV420,常用的 YUV 格式是 YUV420 格式。Y 表示亮度信息,是人眼最敏感的分量,UV 则表示色度信息。

YUV420 表示采样方式:UV 分量具有 2:1 的水平采样,2:1 的垂直采样,这里并不是指只有 U,没有 V,而是对于每一行,只有一个 U 或者 V 分量,如果第一行是 4:2:0,那么下一行就是 4:0:2。

可以用工具 YUVView 直接打开 YUV 格式的数据。

YUV 数据因为计算量大和数据量大可以都放到 GPU 存储和计算,YUV422 转 YUV420 可以利用 OpenGL 将 YUV422 的 UV 数据转换成 texture 纹理,编写 shader 做格式转换逻辑继而生成 YUV420 的 UV texture,再通过 readPixel 将显存的 UV 数据读取出来。转换逻辑即将纹理 UV 分量隔行采样。

8、你在项目中是怎么降低端到端的延时的?

面是直播走 RTMP 推流、HTTP-FLV 播放方案降低端到端延迟的思路:

  • 推流端的延迟包含编码延迟和发送缓存队列引入的延迟。可以通过调节编码参数(B 帧、码率、帧率)减小编码延迟但会影响画质。另外可以提高上传的传输性能来减小传输时长。

  • CDN 链路上的传输延迟。包括推流的链路和播放回源的链路,这部分延迟不是太大,但依旧会引入几百 ms 的延迟。

  • CDN 拉流边缘节点的吐流策略会直接影响延迟的大小。直播流编码的 GOP 的长度,CDN 在客户端拉流时吐几秒的数据、按照 GOP 分隔如何丢数据,这些策略都会影响延时。

  • 播放端可以通过对当前已下载的 buffer 进行倍速播放和跳帧来降低缓存从而达到降低延迟。注意如果倍速过大,声音是会明显变调的,需要通过算法来调整。跳帧一定要注意视频跳到 I 帧,音频对齐视频进行丢弃。

9、如何监控视频播放黑屏、花屏、绿屏等异常?

视频播放时如果遇到黑屏、花屏、绿屏通常会伴有解码器的报错或异常信息,我们可以上报这些异常信息来实现对这些情况的监控。

但是也有一些情况,即使出现黑屏、花屏、绿屏的情况了,解码器也没有报错或异常,这时候就需要我们对解码后的画面进行检测来识别这些问题。一般可以这样:

  • 用传统的图像处理算法来识别。对于黑屏、绿屏可以用传统图像处理算法来进行识别,但这里也会有一些误识别的问题,比如视频本身就有些亮度较低、正常全黑帧、正常全绿帧的情况,可能也会被识别为异常。

  • 训练 AI 模型类识别。对于花屏,可以训练 AI 模型来进行识别。训练过程可以通过人工构造丢帧视频的方法来生成花屏样本,同时筛选出无花屏问题的正常样本,基于这两类样本来做二分类模型的训练。

10、介绍一下 FFmpeg 中关于 timebase 的基础知识与应用?

1)timebase 定义

在 FFmpeg 中,time_base 是一个关键概念,它用于表示时间单位。在处理音频或视频流时,time_base 可以根据不同的采样频率或帧率来定义。timebase 在 FFmpeg 的定义是一个 AVRational 结构体:

typedef struct AVRational{
    int num; ///< numerator  
    int den; ///< denominator  
} AVRational;

2)timebase 的使用

在某些情况下,time_base 是根据采样频率来定义的。例如:对于视频采样频率为 90KHz(90000Hz)的情况,time_base 就相当于 1/90000 秒。另一种定义 time_base 的方式是根据帧率。例如:对于视频帧率为 24fps 的情况,time_base 就相当于 1/24 秒。在 FFmpeg 的分层结构中,原始数据层、编解码层和封装层都有对应的 time_base。原始数据层和封装层都通过 AVStream 进行处理,而编解码层则对应 AVCodec。

3)封装层 timebase,视频流/音频流 timebase 和现实时间戳的的关系和转换

封装层 tbn、视频 tbc 和音频 tbc 可以各不相同,相互不影响。现实时间基我们一般选用 1us 即 (1/1000000)s。因为每一层用的时间基不同,在函数参数传递上只会使用时间基前面的倍数值,timebase 是统一的,因此时间在不同的时间基上面需要做一层转换。 例如:现实时间 1s 转换到音频流时间实现为 1000000 * (1/1000000) = 44100 * (1/44100),那么现实时间 1000000 在音频流时间值则为 44100。举一个开发中的实例:如果想 seek 视频到现实时间的 X ms。

int64_t seekTime = (int64_t)(( X / 1000 )  / av_q2d(videoStream->time_base)); 
av_seek_frame(videoFormatCtx_, video_index_, seekTime, AVSEEK_FLAG_BACKWARD);

因为 av_seek_frame 是在视频流层面,时间基与现实时间不同,需要转换并将转换后的值作为参数才能得到正确的结果。

4)转换函数解析

double av_q2d(AVRational a) //将AVRational 对象转换为小数,便于转换
// 将一个时间戳a从时基bq转换到时基cq下
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)

例如,将视频流的一帧 pts(a * atbr) 转换到封装层打包成 AVPacket,封装层 timebase 为 tbn,此时需要转换 int64 t = av_rescale_q_rnd(a, atbr, tbn);。

如果还不知道音视频开发需要学习哪些内容的同学,可以参考程序员老廖的学习路线,主页也分享了很多音视频的面试题和项目供大家学习参考

最全音视频学习路线-互联网音视频-嵌入式音视频https://www.bilibili.com/video/BV138DoY7E74/

11、I 帧和 IDR 帧有什么区别?在什么情况下 I 帧不是 IDR 帧?

I 帧:I 帧是视频序列中的关键帧,它是一个完整的图像帧,类似于 JPEG 或 BMP 图像文件。I 帧不依赖于其他帧,因此可以独立解码和显示。在视频序列中,I 帧通常用于随机访问点,也作为其他帧解码的参考。

IDR 帧:IDR 帧是一种特殊的 I 帧,它具有刷新解码器缓冲区的功能。当解码器接收到 IDR 帧时,它会清除之前的解码状态,确保从该帧开始解码,从而避免错误传播。IDR 帧通常用于视频序列的随机访问点,以及在视频传输或存储中用于错误恢复。

因此 IDR 帧一定是 I 帧,但是 I 帧则不一定是 IDR 帧。在遇到 OpenGOP 的情况下,就会出现 I 帧为非 IDR 帧的情况。

OpenGOP

如上图所示右数第一个 I 帧就是一个非 IDR 的 I 帧,前一个 GOP 中的 B 帧依赖了当前 GOP 的 I 帧。所以右数第一个 I 帧接受时,不能刷新解码器,否则上一个 GOP 中的 B 帧无法被成功解码,可能会出现花屏或者报错。

12、如果让你设计一个播放器的架构,你会分哪几层?

我们可以分下面几层来设计播放器的架构:

  • 音视频核心层:职责在于处理网络协议、音视频解封装(Demuxer)、音视频解码(Decoder)、音视频数据结构封装等等,通常基于 FFmpeg 来实现。

  • 播放器内核层:基于音视频核心层的能力来封装播放器内核能力,包括使用多线程、多缓冲区串联网络、解封装、解码、渲染等节点;支持播放、暂停、seek、刷新数据源等控制能力;提供播放状态获取、播放事件回调、播放器错误上报等接口。

  • 播放器封装层:基于平台开发语言对播放器内核进行封装,提供高内聚低耦合的播放器接口。

  • 播放器工具层:在播放器核心能力的基础上组装和扩展其他播放相关的其他能力,比如:边下边播视频缓存能力、播放远程配置能力、播放数据埋点上报能力等等。

  • 播放业务控制层:基于业务属性进行播放策略控制,比如:码率选档、解码方式选择、网络链路优选等策略。

13、如何降低处理音视频链路中的内存峰值?

音视频处理链路中的内存峰值一般是视频数据导致的,要降低内存峰值一般可以从两个方面入手:

降低采集参数:

  • 降低采集视频分辨率

  • 降低采集视频帧率

降低并发任务数量:

  • 将任务分优先级,按照优先级串行执行,这样既能降低内存峰值,也会降低 CPU 峰值

14、聊聊对音视频同步的理解?

音视频对齐方式有三种:

  • 以音频时钟为基准

  • 以视频时钟为基准

  • 以第三方时钟为基准

由于音频播放都是硬件来驱动的,相对比较稳定,另外音频 pts 通常是单调递增的,所以一般是按照音视时钟为准。

以一个 44.1KHz 的 AAC 音频流和 24 FPS 的视频流为例,理想情况下,音视频完全同步,音视频播放过程如下图所示:

音视频同步

但实际情况下,如果用上面那种简单的方式,慢慢的就会出现音视频不同步的情况,主要原因是同步时,时间粒度太大了,难以精准控制。所以需要引入一个参考时钟(要求参考时钟上的时间是恒定线性递增的)来提高音频时钟的时间粒度,比如:系统时间,进而进行精准时钟对齐。最后以音频时钟为准,视频放快了就减慢播放速度,播放快了就丢帧或加快播放的速度。

15、为什么在 YUV 转 RGB 转换中 UV 分量要减去 0.5?

在 YUV 到 RGB 的转换公式中,U 和 V 分量减去 0.5 的原因与 YUV 颜色空间的编码方式有关。YUV 格式通常用于视频压缩,其中 Y 代表亮度(luminance),而 U 和 V 代表色度(chrominance),也就是颜色信息。在某些 YUV 格式中,U 和 V 的取值范围是标准化的,例如在 8 位颜色深度中,U 和 V 的取值范围是从 -128 到 127。这种表示方法将色度的中心点设在了 0,使得色度信号可以表示正负偏差。

在进行 YUV 到 RGB 的转换时,为了将 U 和 V 的取值范围从对称的 -128 到 127 归一化为非对称的 0 到 255,并且将中心点从 128 移动到 0,需要对 U 和 V 进行偏移量的减法操作。具体来说,通过减去 0.5(或 128 对应的小数形式),可以将 U 和 V 的取值范围转换为 0 到 255,从而与 RGB 的取值范围相匹配。

例如,如果使用如下的转换公式:

[ R = Y + 1.4075 * (V - 128) ]
[ G = Y - 0.34414 * (U - 128) - 0.71414 * (V - 128) ]
[ B = Y + 1.772 * (U - 128) ]

在这个公式中,U 和 V 减去 128 实际上就是将色度信号的中心从 128 移动到 0,然后再进行缩放操作以匹配 RGB 的取值范围。如果不进行这个减法操作,色度信号将不会正确地转换为 RGB 颜色空间,导致颜色失真。

总结来说,U 和 V 分量后面减去 0.5 是为了将色度信号的表示方式从 YUV 颜色空间转换为 RGB 颜色空间,确保颜色信息的准确传递。

16、如何获取视频流中的 QP 值?

在 H.264 中,量化参数(QP)的获取涉及到几个层级:

  • 图像参数集(PPS):包含初始量化参数 pic_init_qp_minus26,其取值范围是 -26 到 +25。

  • 片头(Slice Header):每个片(Slice)都有自己的片头,其中包含 slice_qp_delta,表示当前片所有宏块的量化参数初始值 QPy Slice,计算公式为:QPy Slice = 26 + pic_init_qp_minus26 + slice_qp_delta,其取值范围是 0 到 51。

  • 宏块(Macroblock, MB):宏块是编码的基本单元,宏块量化参数偏移值 mb_qp_delta 表示前后两个宏块之间的偏移,取值范围是 -26 到 +25。第一个宏块的 QP 值等于片头的 QP 值,后续宏块的 QP 值计算方式为 QP = (QPprev + mb_qp_delta + 52) % 52。

要从 H.264 码流中提取 QP 值,需要执行以下步骤:

  • 1、解析 NALU:首先需要定位并提取 NALU,因为 QP 值信息分布在 PPS 和 Slice Header 中。

  • 2、解析 PPS:找到 PPS NALU 并解析出 pic_init_qp_minus26。

  • 3、解析 Slice Header:对于每个 Slice,解析 Slice Header 以获取 slice_qp_delta。

  • 4、计算 QP 值:根据上述解析出的参数和宏块信息,计算每个宏块的 QP 值。

使用工具:可以使用如 ffmpeg 等工具来辅助解析码流和提取 QP 值。例如,ffmpeg 提供了 -showqp 选项来显示量化参数。

编程实现:也可以通过编程方式,如使用 Python 结合相关库来解析 H.264 码流并提取 QP 值。

在实际应用中,可能需要结合具体的编码场景和需求来选择合适的工具和方法,以实现对 H.264 码流中 QP 值的提取。

17、视频编码对 QP 值的控制有哪些?

在视频编码中,QP(Quantization Parameter)值是一个重要的概念,它对编码后视频的质量和码率有着直接的影响。视频编码中的量化步骤是将像素值映射到一个较小的数值范围内,这一步骤会损失一些图像细节,但可以显著减少编码后视频的数据量。

QP 值决定了量化过程中的量化步长,从而影响量化的精度。较小的 QP 值意味着量化步长较小,量化过程更精细,编码后的视频质量更高,但同时也会导致码率增加; 较大的 QP 值意味着量化步长较大,量化过程更粗糙,编码后的视频质量较低,但码率会减少。

对于部分软编库来说是可以设置平均/最大/最小 QP 值的。下面我们重点说下客户端如何设置 QP。

  • 在 iOS 中使用 VideoToolbox 编码视频时通过属性值设置最大 QP 和最小 QP 值。属性 key 为 kVTCompressionPropertyKey_MinAllowedFrameQP、kVTCompressionPropertyKey_MaxAllowedFrameQP。 这样编码器就会保证是编码出来的文件 QP 值在这个范围。其次如果你设置了码率,他也会在这个范围内尽量使用你设置的码率。但是如果你设置的码率过高或者过低,QP 值无法满足时,编码器则根据优先以 QP 值自动调整码率。

  • Android 部分机型的编码器可以开启质量编码模式,即 KEY_BITRATE_MODE 为 BITRATE_MODE_CQ。质量可以通过设置参数 KEY_VIDEO_QP_MAX、KEY_VIDEO_QP_MIN、KEY_VIDEO_QP_P_MAX、KEY_VIDEO_QP_P_MIN、KEY_VIDEO_QP_B_MAX、KEY_VIDEO_QP_B_MIN 等一系列参数来控制帧的 QP 值。

18、纹理有哪些环绕方式(wrapping)?

  • 重复(GL_Repeat):纹理在每个纹理坐标轴上重复出现,当纹理坐标超出 [0,1] 范围时,纹理会在该轴上重复出现。这种方式适用于创建无缝平铺效果。这是对纹理的默认行为。

  • 镜像重复(GL_MIRRORED_REPEAT):与重复(GL_Repeat)方式相似,但当纹理坐标超出 [0,1] 范围时,会将其镜像翻转后再重复出现。这可以有效减少纹理重复造成的视觉疲劳。

  • 夹取到边缘(GL_CLAMP_TO_EDGE):与夹取方式类似,但在超出范围时,会使用边缘纹素的颜色,产生一种边缘被拉伸的效果。

  • 夹取到边框(GL_CLAMP_TO_BORDER):超出范围时,使用指定的边框颜色。这种方式通常用于在超出纹理范围时填充边框颜色,避免黑边。

19、为什么视频会议用 UDP?如果用 TCP 实现音视频,需要建立几次连接?用 UDP 实现音视频,有什么方法可以保证通话质量?

1)为什么视频会议用 UDP?

视频会议场景最重要的体验指标一般是『通话延时』和『语音音质』两方面。

在传输层使用 UDP 的主要考虑是为了降低通话延时。因为 UDP 的不需要 TCP 那样的面向连接、可靠传输、拥塞控制等机制,这些机制(比如三次握手建连、丢包重传等)通常都会带来相对 UDP 更高的延时。

当然,另外一方面原因是人们对视频会议中图像信息的损失容忍度是比较高的,这样即使 UDP 无法保证可靠性,有时候还是可以接受的。

2)如果用 TCP 实现音视频,需要建立几次连接?

可以做到只建连一次,多路复用。 也可以音频和视频各使用一路连接。

3)用 UDP 实现音视频,有什么方法可以保证通话质量?

使用 UDP 享受了低延时,牺牲了可靠性。但可靠性牺牲太多导致不可用也是不可接受的,所以还需要做一些机制来保证一定的可靠性,比如我们可以参考 WebRTC 的机制:

  • NACK:通过丢包重传解决丢包问题,会增加延时。

  • FEC:通过冗余数据解决丢包问题,会增加带宽占用。

  • JitterBuffer:通过队列对接收到的数据进行缓冲,出队时将数据包均匀平滑的取出,解决视频的乱序与抖动。

  • NetEQ:类似 JitterBuffer,解决音频的乱序与抖动。

20、为什么会有 YUV 这种数据?它相比 RGB 数据有什么优点?

RGB 工业显示器要求一幅彩色图像由分开的 R、G、B 信号组成,而电视显示器则需要混合信号输入,为了实现对这两种标准的兼容,NTSC(美国国家电视系统委员会)制定了 YIQ 颜色模型,它的主要优点是可以实现对彩色电视和黑白电视的兼容,即可以用黑白电视收看彩色电视信号。YUV 颜色模型则是在 YIQ 的基础上发展而来。

YUV 颜色模型中用亮度、色度来表示颜色。它的亮度信息和色度信息是分离的,其中 Y 表示亮度通道,U 和 V 则表示色度通道。如果只有 Y 信息,没有 U、V 信息,那么表示的图像就是灰度图像。YUV 常用在各种影像处理场景中。YUV 在对照片或视频编码时,考虑到人眼对亮度信息的敏感度高于色度信息,允许降低色度的带宽。这样一来就可以对色度信息进行压缩,所以 YUV 可以相对 RGB 使用更少的数据带宽。比如常见的采样格式有:4:2:1、4:1:1、4:2:0 等,它们分别相对 RGB 压缩了 33.3%、50%、50% 的数据量。

21、RTMP 消息分优先级的设计有什么好处?

RTMP 的消息优先级是:控制消息 > 音频消息 > 视频消息。当网络传输能力受限时,优先传输高优先级消息的数据。

要使优先级能够有效执行,分块也很关键:将大消息切割成小块,可以避免大的低优先级的消息(如视频消息)堵塞了发送缓冲从而阻塞了小的高优先级的消息(如音频消息或控制消息)。

22、iOS 中如何判断一个视频帧是不是关键帧?

在 VideoToolbox 中,可以通过检查给定的 CMSampleBuffer 是否是视频帧,并且是否是关键帧。通过检查 kCMSampleAttachmentKey_NotSync 键的值,如果它为 false ,则说明这是一个关键帧。以下是示例代码

#import <VideoToolbox/VideoToolbox.h>

BOOL isKeyFrame(CMSampleBufferRef sampleBuffer) {
    CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
    if (!formatDescription) {
        return NO;
    }
    
    CMMediaType mediaType = CMFormatDescriptionGetMediaType(formatDescription);
    if (mediaType != kCMMediaType_Video) {
        return NO;
    }
    
    CFArrayRef sampleAttachmentsArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, true);
    CFDictionaryRef sampleAttachments = (CFDictionaryRef)CFArrayGetValueAtIndex(sampleAttachmentsArray, 0);
    BOOL isKeyFrame = !CFDictionaryContainsKey(sampleAttachments, kCMSampleAttachmentKey_NotSync);
    return isKeyFrame;
}

23、iOS 中系统 API 提供了哪些视频编码的方式?

在 iOS 中,实现视频编码的方式主要包括以下两种:

  • AVFoundation 框架:AVFoundation 是苹果提供的一个用于处理音视频数据的框架,它提供了一系列用于捕获、处理和输出音视频数据的类和方法。通过 AVFoundation 框架,可以使用 AVAssetWriter 和 AVAssetWriterInput 类来实现编码视频。

  • VideoToolbox 框架:VideoToolbox 是苹果提供的一个专门用于处理视频数据的框架,它提供了硬件加速的视频编码和解码功能。使用 VideoToolbox,可以利用 iOS 设备上的硬件编码器来实现高效的视频编码。

相比而言,AVFoundation 框架则提供了更加上层的接口,更简单易用,但因此对于一些特殊需求和高级功能,可能无法满足。VideoToolbox 则提供了更直接的对硬件编码器的访问,允许开发者能更细致的控制编码器的配置和参数,并且可以直接操作编码器的输入和输出数据,灵活性更好。

24、VideoToolbox 视频帧解码失败以后应该如何重试?

  • 1、重新初始化解码器:尝试重新初始化 Videotoolbox 解码器,有时候重新初始化可以解决解码过程中的一些临时问题。

  • 2、检查视频文件:确保视频文件没有损坏或者格式不正确。有时候解码失败是因为视频文件本身的问题,可以尝试使用其他工具或者重新获取视频文件。

  • 3、检查当前内存:在解码过程中如果 CMSampleBuffer 不及时释放,可能会导致内存过高导致解码器报 -11800 通用错误。

  • 4、尝试重新解码当前帧:将当前帧以及当前 gop 内前序帧都重新输入给解码器。

来源:关键帧 - 个人中心


网站公告

今日签到

点亮在社区的每一天
去签到