AVFoundation合并多個音視頻文件(七)

前言

從本文開始逐漸學習iOS自帶的多媒體處理框架断楷,例如AVFoundation,VideoToolbox,CoreMedia衣厘,CoreVideo實現多媒體的處理,并且將實現方式以及效果和ffmpeg的方式做對比

給一個視頻添加音樂,將多段音視頻文件合并為一個文件是很常見的需求影暴,AVFoundation就提供了這樣的接口错邦。

本文的目的:
合并兩個MP4文件為一個

音視頻合并相關流程

image.png

上圖介紹了AVFoundation框架中關于合并音視頻文件的相關的對象關系圖,可以看到使用AVFoundation合并音視頻還是相對比較簡單的型宙。

相關對象及函數介紹

  • 1撬呢、AVURLAsset
    容器對象,代表了要操作的容器妆兑。封裝魂拦,解封裝,音視頻播放搁嗓,以及音視頻合并等等操作的基礎都涉及到這個對象芯勘。

  • 2、AVAssetTrack
    音視頻軌道對象腺逛,代表了文件中的一路音頻流或者一路視頻流荷愕,它作為每一個要被合并的音頻或者視頻流被添加到組合對象中最終進行合并

  • 3、AVMutableCompositionTrack
    組合軌道對象棍矛,它作為音視頻合并的基礎安疗,通過它添加要合并的音頻流或者視頻流,分為兩種類型:音頻組合軌道對象和視頻組合軌道對象够委,音頻組合軌道對象只能添加音頻流荐类,視頻組合軌道對象只能添加視頻流

  • 4、AVMutableComposition
    組合對象慨绳,通過它構建組合軌道對象

  • 5掉冶、AVAssetExportSession
    執(zhí)行合并操作并導出為文件對象,該對象內部應該是封裝了合并多個音頻流或者視頻流的操作和封裝操作

實現代碼

#import <Foundation/Foundation.h>

@interface AVMYComposition : NSObject

/** 合并任意兩個相同容器類型容器文件的功能脐雪;合并后的文件分辨率取最低的文件分辨率厌小,像素格式及顏色范圍取第一文件的。編碼方式則
 */
- (void)mergeFile:(NSURL*)filstURL twoURL:(NSURL*)twoURL dst:(NSURL*)dsturl;
@end
import "AVMYComposition.h"
#import <AVFoundation/AVFoundation.h>

@implementation AVMYComposition
{
    dispatch_semaphore_t processSemaphore;
}
- (void)mergeFile:(NSURL*)filstURL twoURL:(NSURL*)twoURL dst:(NSURL*)dsturl
{
    NSLog(@"開始");
    processSemaphore = dispatch_semaphore_create(0);
    
    // 創(chuàng)建組合對象
    AVMutableComposition *composition = [AVMutableComposition composition];
    
    // 為組合對象添加組合對象音頻軌道战秋,用于合并所有音頻
    AVMutableCompositionTrack *audioComTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    // 為組合對象添加組合對象視頻軌道璧亚,用于合并所有視頻
    AVMutableCompositionTrack *videoComTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    
    // 準備第一個容器文件的所有音頻和視頻軌道
    AVURLAsset *asset1 = [[AVURLAsset alloc] initWithURL:filstURL options:nil];
    NSArray *audioTracks1 = [asset1 tracksWithMediaType:AVMediaTypeAudio];
    NSArray *videoTracks1 = [asset1 tracksWithMediaType:AVMediaTypeVideo];
    AVAssetTrack *audioTrack1 = audioTracks1?audioTracks1[0]:nil;
    AVAssetTrack *videoTrack1 = videoTracks1?videoTracks1[0]:nil;
    
    
    // 準備第二個文件的所有音頻和視頻軌道
    AVURLAsset *asset2 = [[AVURLAsset alloc] initWithURL:twoURL options:nil];
    NSArray *audioTracks2 = [asset2 tracksWithMediaType:AVMediaTypeAudio];
    NSArray *videoTracks2 = [asset2 tracksWithMediaType:AVMediaTypeVideo];
    AVAssetTrack *audioTrack2 = audioTracks2?audioTracks2[0]:nil;
    AVAssetTrack *videoTrack2 = videoTracks2?videoTracks2[0]:nil;
    
    // 將解析出的每個文件的各個軌道添加到組合對象的對應的用于編輯的音視頻軌道對象中
    CMTimeRange audioTmeRange1 = kCMTimeRangeZero;
    CMTimeRange videoTmeRange1 = kCMTimeRangeZero;
    NSError *error = nil;
    if (audioTrack1) {
        audioTmeRange1 = CMTimeRangeMake(kCMTimeZero, asset1.duration);
        // 組合對象音頻軌道添加音頻軌道
        [audioComTrack insertTimeRange:audioTmeRange1 ofTrack:audioTrack1 atTime:kCMTimeZero error:&error];
        if (error) {
            NSLog(@"audio1 error %@",error);
            return;;
        }
    }
    
    if (videoTrack1) {
        videoTmeRange1 = CMTimeRangeMake(kCMTimeZero, asset1.duration);
        // 組合對象音頻軌道添加音頻軌道
        [videoComTrack insertTimeRange:videoTmeRange1 ofTrack:videoTrack1 atTime:kCMTimeZero error:&error];
        if (error) {
            NSLog(@"video1 error %@",error);
            return;;
        }
    }
    
    // 處理第二個文件
    CMTimeRange audioTmeRange2 = kCMTimeRangeZero;
    CMTimeRange videoTmeRange2 = kCMTimeRangeZero;
    if (audioTrack2) {
        audioTmeRange2 = CMTimeRangeMake(kCMTimeZero, asset2.duration);
        [audioComTrack insertTimeRange:audioTmeRange2 ofTrack:audioTrack2 atTime:asset1.duration error:&error];
        if (error) {
            NSLog(@"audio2 error %@",error);
            return;;
        }
    }
    if (videoTrack2) {
        videoTmeRange2 = CMTimeRangeMake(kCMTimeZero, asset2.duration);
        [videoComTrack insertTimeRange:videoTmeRange2 ofTrack:videoTrack2 atTime:asset1.duration error:&error];
        if (error) {
            NSLog(@"video2 error %@",error);
            return;;
        }
    }
    
    // 執(zhí)行合并
    if ([[NSFileManager defaultManager] fileExistsAtPath:dsturl.path]) {
        [[NSFileManager defaultManager] removeItemAtURL:dsturl error:nil];
    }
    
    // 執(zhí)行合并軌道對象會話
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetHighestQuality];
    exportSession.outputURL = dsturl;
    exportSession.outputFileType = AVFileTypeMPEG4;
    
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        NSLog(@"over");
        if (exportSession.status != AVAssetExportSessionStatusCompleted) {
            NSLog(@"error %@",exportSession.error);
        }
        
        dispatch_semaphore_signal(self->processSemaphore);
    }];
    
    dispatch_semaphore_wait(self->processSemaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"結束了");
}

遇到問題

項目地址

https://github.com/nldzsz/ffmpeg-demo

位于AVFoundation目錄下文件AVMYComposition.h/AVMYComposition.m中

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脂信,隨后出現的幾起案子癣蟋,更是在濱河造成了極大的恐慌呵晨,老刑警劉巖闽坡,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件音诫,死亡現場離奇詭異雄驹,居然都是意外死亡,警方通過查閱死者的電腦和手機留夜,發(fā)現死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門真椿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娜遵,“玉大人,你說我怎么就攤上這事礁蔗【跻澹” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵浴井,是天一觀的道長晒骇。 經常有香客問我,道長磺浙,這世上最難降的妖魔是什么洪囤? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮屠缭,結果婚禮上箍鼓,老公的妹妹穿的比我還像新娘。我一直安慰自己呵曹,他們只是感情好,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布何暮。 她就那樣靜靜地躺著奄喂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪海洼。 梳的紋絲不亂的頭發(fā)上跨新,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機與錄音坏逢,去河邊找鬼域帐。 笑死,一個胖子當著我的面吹牛是整,可吹牛的內容都是我干的肖揣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼浮入,長吁一口氣:“原來是場噩夢啊……” “哼龙优!你這毒婦竟也來了?” 一聲冷哼從身側響起事秀,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤彤断,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后易迹,有當地人在樹林里發(fā)現了一具尸體宰衙,經...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年睹欲,在試婚紗的時候發(fā)現自己被綠了供炼。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劲蜻,靈堂內的尸體忽然破棺而出陆淀,到底是詐尸還是另有隱情,我是刑警寧澤先嬉,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布轧苫,位于F島的核電站,受9級特大地震影響疫蔓,放射性物質發(fā)生泄漏含懊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一衅胀、第九天 我趴在偏房一處隱蔽的房頂上張望岔乔。 院中可真熱鬧,春花似錦滚躯、人聲如沸雏门。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茁影。三九已至,卻和暖如春丧凤,著一層夾襖步出監(jiān)牢的瞬間募闲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工愿待, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浩螺,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓仍侥,卻偏偏與公主長得像要出,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子访圃,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360