莫奈《睡莲》
iOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对音视频基础概念知识有一定了解后,再借助 iOS/Android 平台的音视频能力上手去实践音视频的采集 → 编码 → 封装 → 解封装 → 解码 → 渲染
过程,并借助音视频工具来分析和理解对应的音视频数据。
在音视频工程示例这个栏目的 13 篇 AVDemo 文章中,我们拆解了音频和视频的采集 → 编码 → 封装 → 解封装 → 解码 → 渲染
流程并基于 iOS 系统 API 实现了 Demo:
如果你看完这些 Demo,对 iOS 平台的音视频开发多多少少会有一些认识了。在《iOS 音频处理框架及重点 API 合集》一文中,我们总结了一下 iOS 音频处理框架以及音频相关的 Demo 中用到的主要 API 和数据结构。
接下来,我们再来总结一下 iOS 视频处理框架以及视频相关的 Demo 中用到的主要 API 和数据结构。
当我们想要了解 iOS 的视频处理框架时,以下是我们能比较容易找到的两张官方架构图。它们出自 AVFoundation Programming Guide[1] 这篇已经过陈旧过时的文档。
AVFoundation Stack on iOS
AVFoundation Stack on OS X
时至今日,iOS 平台的视频处理框架已经有了很多更新,上图中很多在 OS X 上的模块也有了 iOS 版本的实现。虽然有变化,但是上面的架构图,对我们了解现在 iOS 平台的视频处理框架还是有参考价值的。
根据我们的视频 Demo 中涉及的系统 API,我们这里挑选介绍几个相关的 Framework:
Video Toolbox Framework[2] 主要用于支持视频硬编码和硬解码。这里我们主要介绍一下编码和解码相关的 API:
1)Data Compression[3]:通过一个编码 Session 来管理对输入视频数据的压缩操作。
VTCompressionSessionEncodeFrame(...)
时做。CVPixelBuffer
。VTCompressionSessionEncodeFrame(...)
等编码接口时传入,也会在编码数据回调中收到。有如下值:2)Data Decompression[16]:通过一个解码 Session 来管理对输入视频数据的解压缩操作。
kVTDecodeFrame_EnableTemporalProcessing
这个 VTDecodeFrameFlags。这个方法会在所有延迟的帧解码输出后返回,要等待它们,则需要调用 VTDecompressionSessionWaitForAsynchronousFrames(...)
。VTDecompressionSessionFinishDelayedFrames(...)
,所以使用方不用自己调。VTDecompressionSessionDecodeFrame(...)
等解码接口时传入,也会在解码数据回调中收到。有如下值:在前面介绍 iOS 音频处理框架时,我们已经介绍过 Core Media Framework[34] 了,这个 Framework 中定义和封装了 AVFoundation 等更上层的媒体框架需要的媒体处理流水线(包含时间信息)以及其中使用的接口和数据类型。使用 Core Media 层的接口和数据类型可以高效的处理媒体采样数据、管理采样数据队列。这里,我们着重介绍一下其中跟视频处理相关的部分。
1)Sample Processing[35]:采样数据处理。常用的数据类型:
kCMSampleAttachmentKey_PartialSync
和 kCMSampleAttachmentKey_NotSync
两个属性为 kCFBooleanTrue(可以认为是 I 帧,但是又区别于 IDR 帧)。这个属性会被写入媒体文件或从媒体文件中读取。AVSampleBufferDisplayLayer
就可能用到。这个属性不会被写入媒体文件。AVSampleBufferDisplayLayer
就可能用到。这个属性不会被写入媒体文件。typedef FourCharCode CMVideoCodecType
,视频编码类型。typedef FourCharCode CMMediaType
,媒体类型。typedef CMFormatDescriptionRef CMVideoFormatDescriptionRef;
CMVideoFormatDescription 是一种 CMFormatDescriptionRef。CMVideoDimensions
。2)Time Representation[59]:时间信息表示。常用的数据类型:
3)Queues[63]:数据容器。常用的数据类型:
(void *)
元素,元素不能是 NULL 或 0,如果元素是指向分配内存的指针,其内存生命周期要在外面自己管理。可以用作音视频采样数据(CMSampleBufferRef)的队列,不过要自己加锁。Core Video Framework[67] 主要用于支持数字视频及数字图像帧的处理,提供基于处理 Pipeline 的 API,并且同时支持 Metal 和 OpenGL。
这里我们主要介绍 CoreVideo Framework 中的几种数据类型:
typedef CVImageBufferRef CVPixelBufferRef
,像素缓冲区。这是 iOS 平台进行视频编解码及图像处理相关最重要的数据结构之一。它是在 CVImageBuffer
的基础上实现了内存存储。并且,CVPixelBuffer 还可以实现 CPU 和 GPU 共享内存,为图像处理提供更高的效率。kCVPixelBufferLock_ReadOnly
的 lockFlags,解锁时也要带上。但是,如果使用 GPU 读取 Pixel 数据时,则没有必要锁定,反而会影响性能。CVPixelBufferGetBaseAddressOfPlane(...)
和 CVPixelBufferGetBytesPerRowOfPlane(...)
来获取其中数据。获取 Pixel Buffer 的基地址时,需要先用 CVPixelBufferLockBaseAddress(...)
加锁。CVPixelBufferLockBaseAddress(...)
加锁。怎么理解 Plane 呢?其实主要跟颜色模型有关,比如:存储 YUV420P 时,有 Y、U、V 这 3 个 Plane;存储 NV12 时,有 Y、UV 这 2 个 Plane;存储 RGBA 时,有 R、G、B、A 这 4 个 Plane;而在 Packed 存储模式中,因为所有分量的像素是交织存储的,所以只有 1 个 Plane。AVFoundation Framework[81] 是更上层的面向对象的一个音视频处理框架。它提供了音视频资源管理、相机设备管理、音视频处理、系统级音频交互管理的能力,功能非常强大。如果对其功能进行细分,可以分为如下几个模块:
在我们前面的 Demo 中封装 Video Capture、Muxer、Demuxer 及设置 AudioSession 时会用到 AVFoundation Framework 的一些能力,我们这里对应地介绍一下。
1)Video Capture
关于 iOS 视频采集相关的架构,可以参考下面两张图:
AVCaptureSession 配置多组输入输出
AVCaptureConnection 连接单或多输入和单输出
-captureOutput:didOutputSampleBuffer:fromConnection:
回调获取采集的数据。-captureOutput:didOutputSampleBuffer:fromConnection:
更多时间处理帧,但是这时候内存占用可能会更大。2)Muxer
startSessionAtSourceTime:
开始写入会话,此后就可以使用对应的 AVAssetWriterInput 来写入媒体采样数据。startWriting
后调用,在写入媒体采样数据之前调用。finishWritingWithCompletionHandler:
结束写入时自动调用。readyForMoreMediaData
的状态。3)Demuxer
AVAssetReaderTrackOutput
、AVAssetReaderVideoCompositionOutput
等具体的实现类。以上这些框架及 API 基本上可以覆盖我们在前面的 Demo 中用到的能力了。
[1]
AVFoundation Programming Guide: https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/00_Introduction.html
[2]
Video Toolbox Framework: https://developer.apple.com/documentation/videotoolbox?language=objc
[3]
Data Compression: https://developer.apple.com/documentation/videotoolbox?language=objc
[4]
VTCompressionSession: https://developer.apple.com/documentation/videotoolbox/vtcompressionsession?language=objc
[5]
VTCompressionSessionCreate(...): https://developer.apple.com/documentation/videotoolbox/1428285-vtcompressionsessioncreate?language=objc
[6]
VTSessionSetProperty(...): https://developer.apple.com/documentation/videotoolbox/1536144-vtsessionsetproperty?language=objc
[7]
VTCompressionSessionPrepareToEncodeFrames(...): https://developer.apple.com/documentation/videotoolbox/1428283-vtcompressionsessionpreparetoenc?language=objc
[8]
VTCompressionSessionEncodeFrame(...): https://developer.apple.com/documentation/videotoolbox/1428287-vtcompressionsessionencodeframe?language=objc
[9]
VTCompressionOutputCallback: https://developer.apple.com/documentation/videotoolbox/vtcompressionoutputcallback?language=objc
[10]
VTCompressionSessionCompleteFrames(...): https://developer.apple.com/documentation/videotoolbox/1428303-vtcompressionsessioncompletefram?language=objc
[11]
VTCompressionSessionInvalidate(...): https://developer.apple.com/documentation/videotoolbox/1428295-vtcompressionsessioninvalidate?language=objc
[12]
VTEncodeInfoFlags: https://developer.apple.com/documentation/videotoolbox/vtencodeinfoflags?language=objc
[13]
kVTEncodeInfo_Asynchronous: https://developer.apple.com/documentation/videotoolbox/vtencodeinfoflags/kvtencodeinfo_asynchronous?language=objc
[14]
kVTEncodeInfo_FrameDropped: https://developer.apple.com/documentation/videotoolbox/vtencodeinfoflags/kvtencodeinfo_framedropped?language=objc
[15]
VTIsHardwareDecodeSupported(...): https://developer.apple.com/documentation/videotoolbox/2887343-vtishardwaredecodesupported?language=objc
[16]
Data Decompression: https://developer.apple.com/documentation/videotoolbox?language=objc
[17]
VTDecompressionSession: https://developer.apple.com/documentation/videotoolbox/vtdecompressionsession?language=objc
[18]
VTDecompressionSessionCreate(...): https://developer.apple.com/documentation/videotoolbox/1536134-vtdecompressionsessioncreate?language=objc
[19]
VTSessionSetProperty(...): https://developer.apple.com/documentation/videotoolbox/1536144-vtsessionsetproperty?language=objc
[20]
VTDecompressionSessionDecodeFrame(...): https://developer.apple.com/documentation/videotoolbox/1536071-vtdecompressionsessiondecodefram?language=objc
[21]
VTDecompressionOutputCallbackRecord: https://developer.apple.com/documentation/videotoolbox/vtdecompressionoutputcallbackrecord?language=objc
[22]
VTDecompressionSessionFinishDelayedFrames(...): https://developer.apple.com/documentation/videotoolbox/1536101-vtdecompressionsessionfinishdela?language=objc
[23]
VTDecompressionSessionWaitForAsynchronousFrames(...): https://developer.apple.com/documentation/videotoolbox/1536066-vtdecompressionsessionwaitforasy?language=objc
[24]
VTDecompressionSessionInvalidate(...): https://developer.apple.com/documentation/videotoolbox/1536093-vtdecompressionsessioninvalidate?language=objc
[25]
VTDecodeInfoFlags: https://developer.apple.com/documentation/videotoolbox/vtdecodeinfoflags?language=objc
[26]
kVTDecodeInfo_Asynchronous: https://developer.apple.com/documentation/videotoolbox/vtdecodeinfoflags/kvtdecodeinfo_asynchronous?language=objc
[27]
kVTDecodeInfo_FrameDropped: https://developer.apple.com/documentation/videotoolbox/vtdecodeinfoflags/kvtdecodeinfo_framedropped?language=objc
[28]
kVTDecodeInfo_ImageBufferModifiable: https://developer.apple.com/documentation/videotoolbox/vtdecodeinfoflags/kvtdecodeinfo_imagebuffermodifiable?language=objc
[29]
VTDecodeFrameFlags: https://developer.apple.com/documentation/videotoolbox/vtdecodeframeflags?language=objc
[30]
kVTDecodeFrame_EnableAsynchronousDecompression: https://developer.apple.com/documentation/videotoolbox/vtdecodeframeflags/kvtdecodeframe_enableasynchronousdecompression?language=objc
[31]
kVTDecodeFrame_DoNotOutputFrame: https://developer.apple.com/documentation/videotoolbox/vtdecodeframeflags/kvtdecodeframe_donotoutputframe?language=objc
[32]
kVTDecodeFrame_1xRealTimePlayback(...): https://developer.apple.com/documentation/videotoolbox/vtdecodeframeflags/kvtdecodeframe_1xrealtimeplayback?language=objc
[33]
kVTDecodeFrame_EnableTemporalProcessing(...): https://developer.apple.com/documentation/videotoolbox/vtdecodeframeflags/kvtdecodeframe_enabletemporalprocessing?language=objc
[34]
Core Media: https://developer.apple.com/documentation/coremedia?language=objc
[35]
Sample Processing: https://developer.apple.com/documentation/coremedia?language=objc
[36]
CMSampleBuffer: https://developer.apple.com/documentation/coremedia/cmsamplebuffer-u71?language=objc
[37]
CMSampleBufferGetFormatDescription(...): https://developer.apple.com/documentation/coremedia/1489185-cmsamplebuffergetformatdescripti?language=objc
[38]
CMSampleBufferGetDataBuffer(...): https://developer.apple.com/documentation/coremedia/1489629-cmsamplebuffergetdatabuffer?language=objc
[39]
CMSampleBufferGetPresentationTimeStamp(...): https://developer.apple.com/documentation/coremedia/1489252-cmsamplebuffergetpresentationtim?language=objc
[40]
CMSampleBufferGetDecodeTimeStamp(...): https://developer.apple.com/documentation/coremedia/1489404-cmsamplebuffergetdecodetimestamp?language=objc
[41]
CMSampleBufferGetSampleAttachmentsArray(...): https://developer.apple.com/documentation/coremedia/1489189-cmsamplebuffergetsampleattachmen?language=objc
[42]
kCMSampleAttachmentKey_NotSync: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_notsync?language=objc
[43]
kCMSampleAttachmentKey_PartialSync: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_partialsync?language=objc
[44]
kCMSampleAttachmentKey_DependsOnOthers: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_dependsonothers?language=objc
[45]
kCMSampleAttachmentKey_IsDependedOnByOthers: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_isdependedonbyothers?language=objc
[46]
kCMSampleAttachmentKey_DisplayImmediately: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_displayimmediately?language=objc
[47]
kCMSampleAttachmentKey_DoNotDisplay: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_donotdisplay?language=objc
[48]
kCMSampleAttachmentKey_EarlierDisplayTimesAllowed: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_earlierdisplaytimesallowed?language=objc
[49]
kCMSampleAttachmentKey_HasRedundantCoding: https://developer.apple.com/documentation/coremedia/kcmsampleattachmentkey_hasredundantcoding?language=objc
[50]
CMBlockBuffer: https://developer.apple.com/documentation/coremedia/cmblockbuffer-u9i?language=objc
[51]
CMBlockBufferGetDataPointer(...): https://developer.apple.com/documentation/coremedia/1489264-cmblockbuffergetdatapointer?language=objc
[52]
CMFormatDescription: https://developer.apple.com/documentation/coremedia/cmformatdescription-u8g?language=objc
[53]
CMFormatDescriptionCreate(...): https://developer.apple.com/documentation/coremedia/1489182-cmformatdescriptioncreate?language=objc
[54]
CMVideoCodecType: https://developer.apple.com/documentation/coremedia/cmvideocodectype?language=objc
[55]
CMMediaType: https://developer.apple.com/documentation/coremedia/1564193-cmmediatype/
[56]
CMVideoFormatDescription: https://developer.apple.com/documentation/coremedia/cmvideoformatdescription?language=objc
[57]
CMVideoFormatDescriptionCreate(...): https://developer.apple.com/documentation/coremedia/1489743-cmvideoformatdescriptioncreate?language=objc
[58]
CMVideoFormatDescriptionGetDimensions(...): https://developer.apple.com/documentation/coremedia/1489287-cmvideoformatdescriptiongetdimen?language=objc
[59]
Time Representation: https://developer.apple.com/documentation/coremedia?language=objc
[60]
CMTime: https://developer.apple.com/documentation/coremedia/cmtime-u58?language=objc
[61]
CMTimeRange: https://developer.apple.com/documentation/coremedia/cmtimerange-qts?language=objc
[62]
CMSampleTimingInfo: https://developer.apple.com/documentation/coremedia/cmsampletiminginfo?language=objc
[63]
Queues: https://developer.apple.com/documentation/coremedia?language=objc
[64]
CMSimpleQueue: https://developer.apple.com/documentation/coremedia/cmsimplequeue?language=objc
[65]
CMBufferQueue: https://developer.apple.com/documentation/coremedia/cmbufferqueue?language=objc
[66]
CMMemoryPool: https://developer.apple.com/documentation/coremedia/cmmemorypool-u89?language=objc
[67]
Core Video Framework: https://developer.apple.com/documentation/corevideo?language=objc
[68]
CVImageBuffer: https://developer.apple.com/documentation/corevideo/cvimagebuffer-q40
[69]
CVPixelBuffer: https://developer.apple.com/documentation/corevideo/cvpixelbuffer?language=objc
[70]
CVPixelBufferLockBaseAddress(...): https://developer.apple.com/documentation/corevideo/1457128-cvpixelbufferlockbaseaddress?language=objc
[71]
CVPixelBufferUnlockBaseAddress(...): https://developer.apple.com/documentation/corevideo/1456843-cvpixelbufferunlockbaseaddress?language=objc
[72]
CVPixelBufferLockBaseAddress(...): https://developer.apple.com/documentation/corevideo/1457115-cvpixelbuffergetbaseaddress?language=objc
[73]
CVPixelBufferGetHeight(...): https://developer.apple.com/documentation/corevideo/1456666-cvpixelbuffergetheight?language=objc
[74]
CVPixelBufferGetWidth(...): https://developer.apple.com/documentation/corevideo/1457241-cvpixelbuffergetwidth?language=objc
[75]
CVPixelBufferIsPlanar(...): https://developer.apple.com/documentation/corevideo/1456805-cvpixelbufferisplanar?language=objc
[76]
CVPixelBufferGetBaseAddressOfPlane(...): https://developer.apple.com/documentation/corevideo/1456821-cvpixelbuffergetbaseaddressofpla?language=objc
[77]
CVPixelBufferGetPlaneCount(...): https://developer.apple.com/documentation/corevideo/1456976-cvpixelbuffergetplanecount?language=objc
[78]
CVPixelBufferGetBytesPerRowOfPlane(...): https://developer.apple.com/documentation/corevideo/1456711-cvpixelbuffergetbytesperrowofpla?language=objc
[79]
CVPixelBufferGetHeightOfPlane(...): https://developer.apple.com/documentation/corevideo/1456698-cvpixelbuffergetheightofplane?language=objc
[80]
CVPixelBufferGetWidthOfPlane(...): https://developer.apple.com/documentation/corevideo/1456830-cvpixelbuffergetwidthofplane?language=objc
[81]
AVFoundation Framework: https://developer.apple.com/documentation/avfoundation?language=objc
[82]
AVCaptureDevice: https://developer.apple.com/documentation/avfoundation/avcapturedevice?language=objc
[83]
-lockForConfiguration:: https://developer.apple.com/documentation/avfoundation/avcapturedevice/1387810-lockforconfiguration?language=objc
[84]
-unlockForConfiguration:: https://developer.apple.com/documentation/avfoundation/avcapturedevice/1387917-unlockforconfiguration?language=objc
[85]
-activeFormat: https://developer.apple.com/documentation/avfoundation/avcapturedevice/1389221-activeformat?language=objc
[86]
-activeVideoMinFrameDuration: https://developer.apple.com/documentation/avfoundation/avcapturedevice/1389290-activevideominframeduration?language=objc
[87]
AVCaptureDeviceInput: https://developer.apple.com/documentation/avfoundation/avcapturedeviceinput?language=objc
[88]
AVCaptureDeviceFormat: https://developer.apple.com/documentation/avfoundation/avcapturedeviceformat?language=objc
[89]
AVCaptureDevicePosition: https://developer.apple.com/documentation/avfoundation/avcapturedeviceposition?language=objc
[90]
AVCaptureSession: https://developer.apple.com/documentation/avfoundation/avcapturesession?language=objc
[91]
-sessionPreset: https://developer.apple.com/documentation/avfoundation/avcapturesession/1389696-sessionpreset?language=objc
[92]
-addInput:: https://developer.apple.com/documentation/avfoundation/avcapturesession/1387239-addinput?language=objc
[93]
-addOutput:: https://developer.apple.com/documentation/avfoundation/avcapturesession/1387325-addoutput?language=objc
[94]
-addConnection:: https://developer.apple.com/documentation/avfoundation/avcapturesession/1389687-addconnection?language=objc
[95]
AVCaptureSessionPreset: https://developer.apple.com/documentation/avfoundation/avcapturesessionpreset?language=objc
[96]
AVCaptureSessionRuntimeErrorNotification: https://developer.apple.com/documentation/avfoundation/avcapturesessionruntimeerrornotification?language=objc
[97]
AVCaptureConnection: https://developer.apple.com/documentation/avfoundation/avcaptureconnection?language=objc
[98]
-videoMirrored: https://developer.apple.com/documentation/avfoundation/avcaptureconnection/1389172-videomirrored?language=objc
[99]
preferredVideoStabilizationMode: https://developer.apple.com/documentation/avfoundation/avcaptureconnection/1620484-preferredvideostabilizationmode?language=objc
[100]
AVCaptureVideoDataOutput: https://developer.apple.com/documentation/avfoundation/avcapturevideodataoutput?language=objc
[101]
-setSampleBufferDelegate:queue:: https://developer.apple.com/documentation/avfoundation/avcapturevideodataoutput/1389008-setsamplebufferdelegate?language=objc
[102]
-alwaysDiscardsLateVideoFrames: https://developer.apple.com/documentation/avfoundation/avcapturevideodataoutput/1385780-alwaysdiscardslatevideoframes?language=objc
[103]
AVCaptureVideoPreviewLayer: https://developer.apple.com/documentation/avfoundation/avcapturevideopreviewlayer?language=objc
[104]
-setVideoGravity:: https://developer.apple.com/documentation/watchkit/wkinterfacemovie/1628130-setvideogravity?language=objc
[105]
AVAssetWriter: https://developer.apple.com/documentation/avfoundation/avassetwriter?language=objc
[106]
canAddInput:: https://developer.apple.com/documentation/avfoundation/avassetwriter/1387863-canaddinput?language=objc
[107]
addInput:: https://developer.apple.com/documentation/avfoundation/avassetwriter/1390389-addinput?language=objc
[108]
startWriting: https://developer.apple.com/documentation/avfoundation/avassetwriter/1386724-startwriting?language=objc
[109]
startSession(atSourceTime:): https://developer.apple.com/documentation/avfoundation/avassetwriter/1389908-startsessionatsourcetime?language=objc
[110]
endSessionAtSourceTime:: https://developer.apple.com/documentation/avfoundation/avassetwriter/1389921-endsessionatsourcetime?language=objc
[111]
finishWritingWithCompletionHandler:: https://developer.apple.com/documentation/avfoundation/avassetwriter/1390432-finishwriting?language=objc
[112]
cancelWriting: https://developer.apple.com/documentation/avfoundation/avassetwriter/1387234-cancelwriting?language=objc
[113]
AVAssetWriterInput: https://developer.apple.com/documentation/avfoundation/avassetwriterinput?language=objc
[114]
expectsMediaDataInRealTime: https://developer.apple.com/documentation/avfoundation/avassetwriterinput/1387827-expectsmediadatainrealtime?language=objc
[115]
readyForMoreMediaData: https://developer.apple.com/documentation/avfoundation/avassetwriterinput/1389084-readyformoremediadata?language=objc
[116]
requestMediaDataWhenReadyOnQueue:usingBlock:: https://developer.apple.com/documentation/avfoundation/avassetwriterinput?language=objc
[117]
appendSampleBuffer:: https://developer.apple.com/documentation/avfoundation/avassetwriterinput/1389566-appendsamplebuffer?language=objc
[118]
markAsFinished: https://developer.apple.com/documentation/avfoundation/avassetwriterinput/1390122-markasfinished?language=objc
[119]
AVAssetReader: https://developer.apple.com/documentation/avfoundation/avassetreader?language=objc
[120]
canAddOutput:: https://developer.apple.com/documentation/avfoundation/avassetreader/1387485-canaddoutput?language=objc
[121]
addOutput:: https://developer.apple.com/documentation/avfoundation/avassetreader/1390110-addoutput?language=objc
[122]
startReading: https://developer.apple.com/documentation/avfoundation/avassetreader/1390286-startreading?language=objc
[123]
cancelReading: https://developer.apple.com/documentation/avfoundation/avassetreader/1390258-cancelreading?language=objc
[124]
AVAssetReaderOutput: https://developer.apple.com/documentation/avfoundation/avassetreaderoutput?language=objc
[125]
AVAssetReaderTrackOutput: https://developer.apple.com/documentation/avfoundation/avassetreadertrackoutput?language=objc
[126]
alwaysCopiesSampleData: https://developer.apple.com/documentation/avfoundation/avassetreaderoutput/1389189-alwayscopiessampledata?language=objc
[127]
copyNextSampleBuffer: https://developer.apple.com/documentation/avfoundation/avassetreaderoutput/1385732-copynextsamplebuffer?language=objc
[128]
AVAudioSession: https://developer.apple.com/documentation/avfaudio/avaudiosession?language=objc
[129]
setCategory:withOptions:error:: https://developer.apple.com/documentation/avfaudio/avaudiosession/1616442-setcategory?language=objc
[130]
setMode:error:: https://developer.apple.com/documentation/avfaudio/avaudiosession/1616614-setmode?language=objc
[131]
setActive:withOptions:error:: https://developer.apple.com/documentation/avfaudio/avaudiosession?language=objc