AVAssetReader和AVAssetWriter

来源:互联网 发布:java游戏服务端开发 编辑:程序博客网 时间:2024/05/13 05:03

AVAssetReader和AVAssetWriter

AVAssetReader和AVAssetWriter类可以让开发者直接处理媒体样本

这里写图片描述

AVAssetReader

AVAssetReader用于从AVAssert实例中读取媒体样本。每个AVAssetReader对象在某个时刻只能和单个asset关联,但这个asset可包含多个tracks。所以,在开始读取之前,必须给asset reader指定一个AVAssetReaderOutput 的具体子类,来配置media data怎样读取。

可通过copyNextSampleBuffer方法可以访问音频样本和视频帧。

AVAssetReaderOutput是一个抽象类,其有3个具体子类:

  • AVAssetReaderTrackOutput从指定的AVAssetTrack中读取解码的媒体样本
  • AVAssetReaderAudioMixOutput从多音频轨道中读取混合输出
  • AVAssetReaderVideoCompositionOutput从多视频轨道中读取组合输出

注意:AVAssetReader只针对带有一个资源的媒体样本。如果需要同时从多个基于文件的资源中读取样本,可将它们组合到一个AVAsset子类AVComposition

创建Asset Reader

NSError *outError;AVAsset *someAsset = <#AVAsset that you want to read#>;AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:someAsset error:&outError];BOOL success = (assetReader != nil);

注意:始终要检查返回的asset reader不为nil,确保asset reader初始化成功。否则,参数error将会包含对应的错误信息

设置Asset ReaderOutputs

在创建asset reader之后,至少设置一个output来接收读取的媒体数据。在设置outputs时,要确保设置alwaysCopiesSampleData为NO,这样的话,有改进性能的好处。

如果你仅仅想从一个或多个tracks中读取媒体数据,并可能会把数据转换成另一种格式,就使用AVAssetReaderTrackOutput类,为你想要从asset中读取的每个AVAssetTrack对象,使用一个单独的track ouput对象。

使用asset readeraudio track解压缩为Linear PCM,按如下方式设置track output

AVAsset *localAsset = assetReader.asset;// 获取读取的audio trackAVAssetTrack *audioTrack = [[localAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];//Linear PCM解压缩设置NSDictionary *decompressionAudioSettings = @{ AVFormatIDKey : [NSNumber numberWithUnsignedInt:kAudioFormatLinearPCM] };//使用audio track 和 解压缩设置创建outputAVAssetReaderOutput *trackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:decompressionAudioSettings];// 添加output到readerif ([assetReader canAddOutput:trackOutput])    [assetReader addOutput:trackOutput];

注意:要以本身存储的格式从特定的asset track中读取媒体数据,给outputSettings参数传递nil

实际运用

音频波形图

《AV Foundation开发秘籍》中例子
读取资源的音频样本,返回NSData数据,如下:

//从资源轨道中读取样本+ (NSData *)readAudioSamplesFromAsset:(AVAsset *)asset {    NSError *error = nil;    AVAssetReader *assetReader = [[AVAssetReader alloc] initWithAsset:asset error:&error];    if (!assetReader) {        NSLog(@"Error creating asset reader: %@", [error localizedDescription]);        return nil;    }    //获取资源中找到的第一个音频轨道    AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];    /*     *从资源轨道读取音频样本时使用的解压设置     *kAudioFormatLinearPCM 样本需要以未压缩的格式被读取     *little-endian字节序(小端序)     *有符号整型     *16位     */    NSDictionary *outputSettings = @{        AVFormatIDKey               : @(kAudioFormatLinearPCM),        AVLinearPCMIsBigEndianKey   : @NO,        AVLinearPCMIsFloatKey       : @NO,        AVLinearPCMBitDepthKey      : @(16)    };    //创建trackOutput,作为AVAssetReader的输出    AVAssetReaderTrackOutput *trackOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:outputSettings];    [assetReader addOutput:trackOutput];    //开始预收取样本数据    [assetReader startReading];    NSMutableData *sampleData = [NSMutableData data];    while (assetReader.status == AVAssetReaderStatusReading) {        CMSampleBufferRef sampleBuffer = [trackOutput copyNextSampleBuffer];        if (sampleBuffer) {            //获取音频样本            CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sampleBuffer);            //确定长度,并创建一个16位的带符号的整型数组来保存音频赝本            size_t length = CMBlockBufferGetDataLength(blockBufferRef);            SInt16 sampleBytes[length];            CMBlockBufferCopyDataBytes(blockBufferRef, 0, length, sampleBytes);            //数组内容附加在NSData实例后            [sampleData appendBytes:sampleBytes length:length];            //指定样本buffer已经处理和不可再继续使用            CMSampleBufferInvalidate(sampleBuffer);            CFRelease(sampleBuffer);        }    }    //数据读取成功    if (assetReader.status == AVAssetReaderStatusCompleted) {        return sampleData;    } else {        NSLog(@"Failed to read audio samples from asset");        return nil;    }}

效果如下:

这里写图片描述

AVAssetWriter

AVAssetWriter类将媒体数据从多个源写入指定文件格式的单个文件。不需要将asset writer对象与特定的asset相关联,但必须为要创建的每个输出文件使用单独的asset writer。由于asset writer可以从多个源写入媒体数据,因此必须要为写入文件的每个track创建一个AVAssetWriterInput对象,每个AVAssetWriterInput期望以CMSampleBufferRef对象形式接收数据,但如果你想要将CVPixelBufferRef类型对象添加到asset writer input,就使用AVAssetWriterInputPixelBufferAdaptor类。

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

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

创建Asset Writer

创建Asset Writer,需指定输出文件的URL和要求的文件类型(file type)。
下面的代码展示了如何创建一个asset writer来创建一个QuickTime movie

NSError *outError;NSURL *outputURL = <#NSURL object representing the URL where you want to save the video#>;AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:outputURL                                                      fileType:AVFileTypeQuickTimeMovie                                                         error:&outError];BOOL success = (assetWriter != nil);

设置Asset Writer Inputs

为了asset writer能够写入media数据,必须设置至少一个asset writer input

例如,添加AVAssetWriterInput

        self.assetWriterVideoInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:self.videoSettings];        self.assetWriterVideoInput.expectsMediaDataInRealTime = YES;        if ([self.assetWriter canAddInput:self.assetWriterVideoInput]) {            [self.assetWriter addInput:self.assetWriterVideoInput];        } else {            NSLog(@"Unable to add video input.");            return;        }

AVAssetWriter的例子

objcn 在 iOS 上捕获视频一节有介绍使用AVAssetWriter来捕捉写入视频

资源

  • Export
阅读全文
0 0