1. 程式人生 > >AVFounction學習筆記之--音視訊的編輯

AVFounction學習筆記之--音視訊的編輯

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")")
    }
})