读取和写入媒体-音频波形绘制

一、AVAssetReader

AVAssetReader用于从AVAsset实例中读取媒体样本。通常会配置一个或多个AVAssetReaderOutput实例,并通过copyNextSampleBuffer可以访问音频样本和视频帧。AVAssetReaderOutput是一个抽象类。不过框架定义了3个具体实例来从指定的AVAssetTrack中读取解码的媒体样本,从多音轨轨道中读取混合输出,或者从多视频轨道中读取组合输出。一个资源读取器的内部都是以多线程的方式不断提取下一个可用样本的,这样可以在系统请求资源时最小化时延。尽管提供了低延时的检索操作,还是不倾向于实时操作,比如播放。

二、AVAssetWriter

AVAssetWriter用于对媒体资源进行编码并将其写入到容器文件中。它由一个或多个AVAssetWriterInput对象配置,用于附加将包含要写入容器的媒体样本的CMSampleBuffer对象。AVAssetWriterInput被配置为可以处理指定的媒体类型,比如音频或视频,并且附加在其后的样本会在最终输出时生成一个独立的AVAssetTrack。当使用了一个配置处理视频样本的AVAssetWriterInput时,会用到一个专门的适配器对象AVAssetWriterInputPixelBufferAdaptor。这个类在附加被包装为CVPixelBuffer对象的视频样本时,提供最优性能。输入信息也可以通过使用AVAssetWriterInputGroup组成互斥的参数。这就让开发者能够创建特定资源,其中包含在播放时使用AVMediaSelectionGroup和AVMediaSelectionOption类选择指定语言媒体轨道。

AVAssetWriter可以自动支持交叉媒体样本。

将样本写入的一种方式是按照顺序写入。特点:需要将所有的媒体样本捕捉好,不过这会导致数据的低效率排列,因为本应该整体呈现的样本数据可能会彼此分开。这就使得存储设备更难有效的读取数据,并在播放和寻找资源时产生负面效果和性能问题。

另一种是使用交错方式。AVAssetWriterInput提供一个readyForMoreMediaData属性来指示在保持所需的交错情况下输入信息是否还可以附加更多数据。只有在这个属性值为YES时才可以将一个新的样本添加到写入输入信息中。

AVAssetWriter可用于实时操作和离线操作两种情况。

实时:当处理实时资源时,比如从AVCaptureVideoDataOutput写入捕捉的样本时,AVAssetWriterInput应该令expectsMediaDataInRealTime属性为YES来确保readyForMoreMediaData值被正确计算。从实时资源写入数据优化了写入器,这样以来,与维持理想交错效果相比,快速写入样本具有更高的优先级。这一优化效果不错,视频和音频样本以大致相同的速率捕捉,传入数据自然交错。

离线:当从离线资源中读取媒体资源时,比如从AVAssetReader读取样本buffer,在附加样本前仍然需要观察写入器输入的readyForMoreMediaData属性的状态,不过可以使用requestMediaDataWhenReadyOnQueue:usingBlock方法控制数据的提供。传到这个方法中的代码块会随写入器输入准备附加更多的样本而不被调用,添加样本时开发者需要检索数据并从资源中找到下一个样本进行添加。

与AVAssetExportSession相比,AVAssetWriter明显的优势就是它对输出进行编码时能够进行更加细致的压缩设置控制。可以让开发者指定诸如关键帧间隔、视频比特率、H264配置文件、像素宽高比和纯净光圈等设置。

三、音频波形图

绘制一个波形图的基本技巧包括以下三个步骤:

(1)读取:第一步是读取音频样本进行渲染,需要读取或可能解压音频数据。

(2)缩减:实际读取到的样本数量远比我们在屏幕上渲染的多。考虑到单声道音频文件是以44.1kHz比率进行采样的,所得到的样本要比我们具有的像素多得多。缩减的过程必须作用于这个样本集。这一过程通常包括将样本总量分为小的样本块,并在每个样本块上找到最大的样本,所有样本的平均值或min/max值。

(3)渲染:将缩减后的样本呈现在屏幕上。通常会用到Quartz框架,不过也可以使用任何苹果公司支持的绘图框架。如何绘制这些数据的类型取决于开发者是如何缩减这些样本的。若果采用min/max,则为它的每一对绘制一条垂线。若果使用每个样本块的平均值,会发现使用Quartz Bezier路径绘制波形是最合适的。

之前讨论了用CMSampleBuffer访问AVCaptureVideoDataOutput对象渲染的视频帧。当我们处理未压缩的视频数据时,可以使用CMSampleBufferGetImageBuffer函数检索包含有帧的像素信息的CMSampleBufferRef。

从一个资源中读取音频样本时,会再次用到CMSampleBuffer,不过本例基础数据将会以core media类型CMBlockBuffer的形式提供。BlockBuffer用于在core media通道中传送任意字节的数据。根据开发者对音频样本的使用目的,有多种方法可以访问带有音频数据的BlockBuffer。使用CMSampleBufferGetDataBuffer函数得到一个到BlockBuffer的不可保留引用,这个方法适用于只需要访问数据而不进行后续处理的情况。相反可以使用:CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer函数将数据作为AudioBufferList访问。

你可能感兴趣的:(读取和写入媒体-音频波形绘制)