AV Foundation提供了直接處理媒體樣本的低級功能,其中需要使用的兩個重要的類,AVAssetReader和AVAssetWrite,AVAssetReader用於從AVAsset資源讀取媒體樣本,AVAssetWrite用於對媒體資源進行編碼並寫入到容器文件中。下面簡單的使用一下:
初始化AVAssetReader
-(void)configAssetReader { NSURL *videoUrl = [NSURL fileURLWithPath:[self resoucePath]]; _asset = [AVAsset assetWithURL:videoUrl]; //獲取資源的一個視頻軌道 AVAssetTrack *track = [[_asset tracksWithMediaType:AVMediaTypeVideo] firstObject]; _assetReader = [[AVAssetReader alloc] initWithAsset:_asset error:nil]; //指定將讀取的樣本數據壓縮為BGRA格式 NSDictionary *setting = @{(id)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32BGRA)}; //初始化輸出,指定從track軌道中讀取樣本數據 _assetOutPut = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:setting]; //添加輸出 [_assetReader addOutput:_assetOutPut]; //開始讀取過程 [_assetReader startReading]; }
初始化AVAssetWrite
-(void)configWriteInput { NSString *storePath = nil; NSString *path = [self resoucePath]; NSRange range = [path rangeOfString:@"/" options:NSBackwardsSearch]; if (range.location != NSNotFound) { NSString *pathRoot = [path substringToIndex:range.location]; storePath = [pathRoot stringByAppendingPathComponent:@"copy.mp4"]; } if (storePath) { _assetWrite = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:storePath] fileType:AVFileTypeQuickTimeMovie error:nil]; //指定編碼格式,像素寬高等信息 NSDictionary *setting = @{ AVVideoCodecKey:AVVideoCodecH264, AVVideoWidthKey:@1280, AVVideoHeightKey:@720, AVVideoCompressionPropertiesKey:@{ AVVideoMaxKeyFrameIntervalKey:@1, AVVideoAverageBitRateKey:@10500000, AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31 } }; 初始化寫入器,並制定了媒體格式 _assetInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:setting]; //添加寫入器 [_assetWrite addInput:_assetInput]; [_assetWrite startWriting]; } }
將讀取的數據寫入到_assetInput寫入器中
-(void)assertReadToAssetInput { dispatch_queue_t queue = dispatch_queue_create("com.writequeue", DISPATCH_QUEUE_CONCURRENT); if (_assetInput) { __block NSInteger count = 0; __block BOOL isComplete = NO; //開啟寫入會話,並指定樣本的開始時間 [_assetWrite startSessionAtSourceTime:kCMTimeZero]; [_assetInput requestMediaDataWhenReadyOnQueue:queue usingBlock:^{ if (!isComplete && _assetInput.readyForMoreMediaData) { //樣本數據 CMSampleBufferRef buffer = [_assetOutPut copyNextSampleBuffer]; if (buffer) { [_assetInput appendSampleBuffer:buffer]; count++; // 展示第2000幀數據 if (count == 2000) { CGImageRef imgref = [UIImage imageFromSampleBufferRef:buffer]; //讀取CMSampleBuffer中的數據,將其轉化為CGImageRef 參考代碼見:http://www.jianshu.com/p/3d5ccbde0de1 UIImage *img = [UIImage imageWithCGImage:imgref]; dispatch_sync(dispatch_get_main_queue(), ^{ _imageView.image = img; }); } } else { isComplete = YES; } if(isComplete) { //關閉寫入會話 [_assetWrite finishWritingWithCompletionHandler:^{ AVAssetWriterStatus status = self.assetWrite.status; if (status == AVAssetWriterStatusCompleted) { NSLog(@"finsished"); } else { NSLog(@"failure"); } }]; } } }]; } }
-(void)assertReadToAssetInput { dispatch_queue_t queue = dispatch_queue_create("com.writequeue", DISPATCH_QUEUE_CONCURRENT); if (_assetInput) { __block NSInteger count = 0; __block BOOL isComplete = NO; //開啟寫入會話,並指定樣本的開始時間 [_assetWrite startSessionAtSourceTime:kCMTimeZero]; [_assetInput requestMediaDataWhenReadyOnQueue:queue usingBlock:^{ if (!isComplete && _assetInput.readyForMoreMediaData) { //樣本數據 CMSampleBufferRef buffer = [_assetOutPut copyNextSampleBuffer]; if (buffer) { [_assetInput appendSampleBuffer:buffer]; count++; // 展示第2000幀數據 if (count == 2000) { CGImageRef imgref = [UIImage imageFromSampleBufferRef:buffer]; //讀取CMSampleBuffer中的數據,將其轉化為CGImageRef 參考代碼見:http://www.jianshu.com/p/3d5ccbde0de1 UIImage *img = [UIImage imageWithCGImage:imgref]; dispatch_sync(dispatch_get_main_queue(), ^{ _imageView.image = img; }); } } else { isComplete = YES; } if(isComplete) { //關閉寫入會話 [_assetWrite finishWritingWithCompletionHandler:^{ AVAssetWriterStatus status = self.assetWrite.status; if (status == AVAssetWriterStatusCompleted) { NSLog(@"finsished"); } else { NSLog(@"failure"); } }]; } } }]; } }
