AVFounction學習筆記之--音視訊的編輯
阿新 • • 發佈:2019-01-22
AVFounction學習筆記之–音視訊的編輯
媒體資料的讀取和寫入
- AVAssetReader
AVAssetReader用於從AVAsset例項中讀取媒體樣本。通常會配置一個或多個AVAssetReaderOutput例項,並通過copyNextSampleBuffer方法訪問音訊樣本和視訊幀。它只針對帶有一個資源的媒體樣本。
- AVAssetWriter
AVAssetWriter用於對媒體資源進行編碼並將其寫入到容器檔案中。它由一個或多個AVAssetWriterInput物件配置,用於附加將包含寫入容器的媒體樣本的CMSampleBuffer物件。AVAssetWriter可以自動支援交叉媒體樣本。可用於實時操作和離線操作兩種情況。
- Demo例子
// 配置AVAssetReader NSURL * url = [[NSBundle mainBundle] URLForResource:@"Test" withExtension:@"mov"]; AVAsset * asset = [AVAsset assetWithURL:url]; AVAssetTrack * track = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject]; self.assetReader = [[AVAssetReader alloc] initWithAsset:asset error:nil]; NSDictionary * readerOutputSettings = @{(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA)}; AVAssetReaderTrackOutput * trackOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:readerOutputSettings]; [self.assetReader addOutput:trackOutput]; [self.assetReader startReading]; // 配置AVAssetWriter NSURL * outputURL = [[NSURL alloc] initFileURLWithPath:@"/Users/mac/Desktop/T/T/Writer.h264"]; NSError * error = nil; self.assetWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error]; if (error) { NSLog(@"assetWriter error = %@", error.localizedDescription); return; } NSDictionary * writeOutputSettings = @{ AVVideoCodecKey: AVVideoCodecTypeH264, AVVideoWidthKey: @1280, AVVideoHeightKey: @720, AVVideoCompressionPropertiesKey: @{ AVVideoMaxKeyFrameIntervalKey: @1, AVVideoAverageBitRateKey: @10500000, AVVideoProfileLevelKey: AVVideoProfileLevelH264Main31 } }; AVAssetWriterInput * writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings: writeOutputSettings]; [self.assetWriter addInput:writerInput]; [self.assetWriter startWriting]; // 開始寫入容器 [self.assetWriter startSessionAtSourceTime:kCMTimeZero]; [writerInput requestMediaDataWhenReadyOnQueue:dispatch_queue_create("com.writerQueue", NULL) usingBlock:^{ BOOL complete = NO; while ([writerInput isReadyForMoreMediaData] && !complete) { CMSampleBufferRef sampleBuffer = [trackOutput copyNextSampleBuffer]; if (sampleBuffer) { BOOL result = [writerInput appendSampleBuffer:sampleBuffer]; CFRelease(sampleBuffer); complete = !result; } else { [writerInput markAsFinished]; complete = YES; } } if (complete) { [self.assetWriter finishWritingWithCompletionHandler:^{ AVAssetWriterStatus status = self.assetWriter.status; if (status == AVAssetWriterStatusCompleted) { NSLog(@"success"); } else { NSLog(@"error - %@", self.assetWriter.error.localizedDescription); } }]; } }];
媒體的組合和編輯
通過AVFounction框架實現媒體的組合和編輯,包括音訊與音訊、音訊與視訊、視訊與視訊等的組合和剪下等。
涉及到的類
AVAssetTrack
AVMutableComposition
AVMutableCompositionTrack
AVURLAsset
實現步驟:
1、建立需要編輯的音視訊資源
2、建立媒體組合容器,新增音視訊軌道
3、獲取原音視訊的軌道資料
4、向容器中新增需要的軌道資料
5、建立匯出Session,配置引數匯出到目標位置
let videoMov = Bundle.main.url(forResource: "Test", withExtension: "mov") let videoMovAsset = AVURLAsset.init(url: videoMov!) let audioMp3 = Bundle.main.url(forResource: "test", withExtension: "mp3") let audioMp3Asset = AVURLAsset.init(url: audioMp3!) let composition = AVMutableComposition() // video let videoTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid) // audio let audioTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid) // 視訊 let cursorTime = kCMTimeZero let videoDurtion = CMTimeMake(10, 1) let videoTimeRange = CMTimeRangeMake(kCMTimeZero, videoDurtion) var assetTrack = videoMovAsset.tracks(withMediaType: AVMediaType.video).first do { try videoTrack?.insertTimeRange(videoTimeRange, of: assetTrack!, at: cursorTime) } catch let error { print(" video error = \(error.localizedDescription)") } // 音訊 let audioDurtion = CMTimeMake(10, 1) let range = CMTimeRangeMake(kCMTimeZero, audioDurtion) assetTrack = audioMp3Asset.tracks(withMediaType: AVMediaType.audio).first do { try audioTrack?.insertTimeRange(range, of: assetTrack!, at: cursorTime) } catch let error { print("audio error = \(error.localizedDescription)") } let outputUrl = URL(fileURLWithPath: "/Users/mac/Documents/iOSProject/AVFounctionStudy/AVFounctionStudy/edit.mp4") let session = AVAssetExportSession(asset: composition, presetName: AVAssetExportPreset640x480) session?.outputFileType = AVFileType.mp4 session?.outputURL = outputUrl session?.exportAsynchronously(completionHandler: { if AVAssetExportSessionStatus.completed == session?.status { print("匯出成功") } else { print("匯出失敗 = \(session?.error?.localizedDescription ?? "nil")") } })