一文搞懂IOS音视频编解码器VideoToolbox

打印 上一主题 下一主题

主题 762|帖子 762|积分 2301

在 IOS 平台上,我们经常必要处理音视频数据,比如播放视频、录制音频等。为了高效处理这些数据,IOS 提供了 VideoToolbox 类,它允许我们对音视频进行编解码操作。
什么是 VideoToolbox?

IOS 8.0之后,苹果开放了硬编解码API,即 VideoToolbox.framework的API。VideoToolbox是一套纯C语言API,可以直接访问硬件编解码器。它提供视频压缩和解压缩以及存储在像素缓存区中的数据转换服务。

下面以编码器为例进行说明:
先介绍VideoToolbox相关的几种数据布局
(1)CVPixelBuffer:存储编码前或解码后的视频帧,包罗了图像的像素数据以及有关像素格式、巨细和颜色空间等信息。
(2)CMBlockBuffer:存储压缩后的视频数据,比方H.264视频流中的NAL单元。
(3)CMSampleBuffer:包罗时间戳和持续时间等元数据的样本数据。它可以包罗一个CVPixelBuffer或者CMBlockBuffer,相称于存放视频图像的容器数据布局。
H.264编码整体流程:


  • CVPixelBuffer → CMSampleBuffer → H.264
VideoToolbox用法

1. 创建 VideoToolbox 会话

要使用 VideoToolbox,首先必要创建一个 VTCompressionSessionRef 实例作为编码器的句柄。以下是创建编码器实例的基本步调:
  1. VTCompressionSessionRef compressionSession;
  2. OSStatus status = VTCompressionSessionCreate(NULL, width, height, kCMVideoCodecType_H264, NULL, NULL, NULL, compressionCallback, NULL, &compressionSession);
  3. if (status != noErr) {
  4.     NSLog(@"Failed to create compression session: %d", (int)status);
  5.     return;
  6. }
复制代码
其中,width 和 height 是要编码的视频帧的宽度和高度,kCMVideoCodecType_H264 是视频编码器范例。compressionCallback 是一个回调函数,用于处理编码后的数据。
2. 配置 VideoToolbox

配置编码器的参数,包括码率、帧率、关键帧隔断等
  1. NSDictionary *compressionProperties = @{
  2.     (__bridge NSString *)kVTCompressionPropertyKey_RealTime: @YES, // 开启实时编码,降低延迟
  3.     (__bridge NSString *)kVTCompressionPropertyKey_ProfileLevel: (__bridge NSString *)kVTProfileLevel_H264_Baseline_AutoLevel, // BaseLine等级
  4.     (__bridge NSString *)kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration: @(10), // 关键帧间隔
  5.     (__bridge NSString *)kVTCompressionPropertyKey_AverageBitRate: @(500000), // 平均码率,单位bps
  6.     (__bridge NSString *)kVTCompressionPropertyKey_DataRateLimits: @(600000/8), // 最高码率,单位byte/s
  7. };
  8. VTSessionSetProperties(compressionSession, (__bridge CFDictionaryRef)compressionProperties);
复制代码
IOS只支持ABR码控模式:
ABR:恒定平均目的码率,简朴场景分配较低bit,复杂场景分配充足bit,使得有限的bit数能够在不同场景下合理分配,这类似VBR。同时肯定时间内,平均码率又靠近设置的目的码率,如许可以控制输出文件的巨细,这又类似CBR。可以认为是CBR和VBR的折中方案
3. 处理输入数据

将必要编码的原始视频帧通报给编码器进行处理。首先将原始数据放入 CMSampleBufferRef 中,然后将其通报给 VideoToolbox:
  1. CVPixelBufferRef pixelBuffer;   // 存放原始视频帧数据
  2. CFDictionaryRef frameProperties;    // 设置编码帧属性,如是否为关键帧
  3. CMTime presentationTimeStamp = CMTimeMake(value, timescale); // 显示时间戳
  4. VTCompressionSessionEncodeFrame(compressionSession, pixelBuffer, presentationTimeStamp, kCMTimeInvalid, frameProperties, NULL, NULL);
复制代码
注意事项:
CMTime是IOS专门描述视频时间的一种数据范例
官网注释 /*@field value the value of the CMTime. value/timescale = seconds*/
举个例子说明,假设以下情况:
A视频15帧,播放速率5fps,持续时间=15/5=3s
B视频60帧,播放速率20fps,持续时间60/20=3s
由此可知,timesclae应设置为帧率
4. 处理输出数据

编码器处理完数据后,会通过上述界说的回调函数返回编码后的数据。在回调函数中可以处理编码后的数据,比如将其写入文件或传输到网络上。
  1. void compressionCallback(void *outputCallbackRefCon, void *sourceFrameRefCon, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer) {
  2.     if (status != noErr) {
  3.         NSLog(@"Failed to encode frame: %d", (int)status);
  4.         return;
  5.     }
  6.     // 从sampleBuffer中取出编码后的数据
  7.     CMBlockBufferRef dataBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
  8.     size_t length, totalLength;
  9.     char *dataPointer;
  10.     // 处理编码后的数据,比如将其写入文件或传输到网络上
  11.     OSStatus statusCodeRet = CMBlockBufferGetDataPointer(dataBuffer, 0, &length, &totalLength, &dataPointer);
  12.     if (statusCodeRet == noErr) {
  13.         size_t bufferOffset = 0;
  14.         static const int AVCCHeaderLength = 4; // 返回的NALU数据前四个字节是大端模式的帧长度
  15.         // 循环获取NALU数据
  16.         while (bufferOffset < totalLength - AVCCHeaderLength) {
  17.             uint32_t NALUnitLength = 0;
  18.             // 读取NALU长度的数据
  19.             memcpy(&NALUnitLength, dataPointer + bufferOffset, AVCCHeaderLength);
  20.             // 从大端转系统端
  21.             NALUnitLength = CFSwapInt32BigToHost(NALUnitLength);
  22.             NSData* data = [[NSData alloc] initWithBytes:(dataPointer + bufferOffset + AVCCHeaderLength) length:NALUnitLength];
  23.             // 移动到下一个NALU单元
  24.             bufferOffset += AVCCHeaderLength+NALUnitLength;
  25.         }
  26.     }
  27. }
复制代码
注意事项:
VideoToolbox编码以AVCC格式(头四个字节表现NALU长度)存储数据,且字节次序是反的,在转换为H.264格式时需取出头四个字节并替换为Annex B格式(头四个字节是0001),并将字节次序反转得到H.264数据。
5. 销毁编码器

  1. VTCompressionSessionCompleteFrames(compressionSession, kCMTimeInvalid);
  2. VTCompressionSessionInvalidate(compressionSession);
复制代码
相关系列



  • 一文搞懂 Android 音视频编解码器 MediaCodec

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大连全瓷种植牙齿制作中心

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表