AVFoundation音視頻精準(zhǔn)截取(九)

前言

從本文開始逐漸學(xué)習(xí)iOS自帶的多媒體處理框架踱阿,例如AVFoundation透罢,VideoToolbox,CoreMedia虏肾,CoreVideo實現(xiàn)多媒體的處理廓啊,并且將實現(xiàn)方式以及效果和ffmpeg的方式做對比

截取一個音視頻文件中的某個時間段的音視頻然后保存是很常見的需求,AVFoundation就提供了這樣的接口封豪,它其實也是利用AVMutableComposition來實現(xiàn)的

本文的目的:
截取一個音視頻文件中的某個時間段的音視頻然后保存到本地

音視頻截取相關(guān)流程

image.png

上圖介紹了AVFoundation框架中關(guān)于音視頻截取的相關(guān)的對象關(guān)系圖谴轮,可以看到使用AVFoundation截取音視頻中某一段還是相對比較簡單的。

相關(guān)對象及函數(shù)介紹

  • 1吹埠、AVURLAsset
    容器對象第步,代表了要操作的容器。封裝缘琅,解封裝粘都,音視頻播放,以及音視頻合并等等操作的基礎(chǔ)都涉及到這個對象刷袍。

  • 2翩隧、AVAssetTrack
    音視頻軌道對象,代表了文件中的一路音頻流或者一路視頻流呻纹,它作為每一個要被合并的音頻或者視頻流被添加到組合對象中最終進(jìn)行合并

  • 3鸽心、AVMutableCompositionTrack
    組合軌道對象,它作為音視頻合并的基礎(chǔ)居暖,通過它添加要合并的音頻流或者視頻流顽频,分為兩種類型:音頻組合軌道對象和視頻組合軌道對象,音頻組合軌道對象只能添加音頻流太闺,視頻組合軌道對象只能添加視頻流
    通過此對象定義要截取的時間段即可實現(xiàn)音視頻內(nèi)容的截取

  • 4糯景、AVMutableComposition
    組合對象,通過它構(gòu)建組合軌道對象

  • 5省骂、AVAssetExportSession
    執(zhí)行合并操作并導(dǎo)出為文件對象蟀淮,該對象內(nèi)部應(yīng)該是封裝了合并多個音頻流或者視頻流的操作和封裝操作

實現(xiàn)代碼

這里例子中為截取源音視頻中中5-15秒的內(nèi)容然后保存為MP4

#import <Foundation/Foundation.h>

@interface AVVideoCut : NSObject

/** 實現(xiàn)功能:截取音視頻文件中指定范圍段的內(nèi)容
 */
- (void)cutVideo:(NSURL*)srcURL dst:(NSURL*)dstURL;
@end
#import "AVVideoCut.h"
#import <AVFoundation/AVFoundation.h>

@implementation AVVideoCut
{
    dispatch_semaphore_t processSemaphore;
}

- (void)cutVideo:(NSURL*)srcURL dst:(NSURL*)dstURL
{
    processSemaphore = dispatch_semaphore_create(0);
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:srcURL options:nil];
    [asset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:^{
        NSError *error = nil;
        AVKeyValueStatus status = [asset statusOfValueForKey:@"tracks" error:&error];
        if (status != AVKeyValueStatusLoaded) {
            NSLog(@"loaded error %@",error);
            return;
        }
        
        [self processAsset:asset dst:dstURL];
        
        
    }];
    dispatch_semaphore_wait(processSemaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"結(jié)束了");
}

- (void)processAsset:(AVAsset*)asset dst:(NSURL*)dstURL
{
    // 獲取容器中的音視頻軌道對象
    NSArray *videotracks = [asset tracksWithMediaType:AVMediaTypeVideo];
    NSArray *audiotracks = [asset tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *videoTrack = videotracks?videotracks[0]:nil;
    AVAssetTrack *audioTrack = audiotracks?audiotracks[0]:nil;
    
    // 劃定要截取的時間;這里選擇的時間為5-15秒的視頻
    CMTime start = CMTimeMake(5*1000, 1000);
    CMTime time = CMTimeMake(10*1000, 1000);
    CMTimeRange range = CMTimeRangeMake(start, time);
    
    // 創(chuàng)建組合對象
    AVMutableComposition *compostion = [AVMutableComposition composition];
    if (audioTrack) {
        // 添加組合音頻軌道
        AVMutableCompositionTrack *audiocomtrack = [compostion addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
        NSError *error = nil;
        // 在音頻軌道中選取指定的時間范圍的音頻插入到組合音頻軌道中
        [audiocomtrack insertTimeRange:range ofTrack:audioTrack atTime:kCMTimeZero error:&error];
    }
    
    if (videoTrack) {
        AVMutableCompositionTrack *videocomtrack = [compostion addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
        NSError *error = nil;
        [videocomtrack insertTimeRange:range ofTrack:videoTrack atTime:kCMTimeZero error:&error];
    }
    
    // 執(zhí)行合并
    if ([[NSFileManager defaultManager] fileExistsAtPath:dstURL.path]) {
        [[NSFileManager defaultManager] removeItemAtURL:dstURL error:nil];
    }
    
    // 執(zhí)行組合對象中組合軌道的編輯任務(wù)
    AVAssetExportSession *extSession = [[AVAssetExportSession alloc] initWithAsset:compostion presetName:AVAssetExportPresetHighestQuality];
    extSession.outputURL = dstURL;
    extSession.outputFileType = AVFileTypeMPEG4;
    NSLog(@"開始編輯");
    [extSession exportAsynchronouslyWithCompletionHandler:^{
        if (extSession.status != AVAssetExportSessionStatusCompleted) {
            NSLog(@"編輯 error %@",extSession.error);
        }
        NSLog(@"編輯完畢");
        
        dispatch_semaphore_signal(self->processSemaphore);
    }];
}
@end

遇到問題

項目地址

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钞澳,隨后出現(xiàn)的幾起案子怠惶,更是在濱河造成了極大的恐慌,老刑警劉巖轧粟,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件策治,死亡現(xiàn)場離奇詭異脓魏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)通惫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門茂翔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人履腋,你說我怎么就攤上這事珊燎。” “怎么了遵湖?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵悔政,是天一觀的道長。 經(jīng)常有香客問我延旧,道長卓箫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任垄潮,我火速辦了婚禮烹卒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弯洗。我一直安慰自己旅急,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布牡整。 她就那樣靜靜地躺著藐吮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逃贝。 梳的紋絲不亂的頭發(fā)上谣辞,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機(jī)與錄音沐扳,去河邊找鬼泥从。 笑死,一個胖子當(dāng)著我的面吹牛沪摄,可吹牛的內(nèi)容都是我干的躯嫉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼杨拐,長吁一口氣:“原來是場噩夢啊……” “哼祈餐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哄陶,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤帆阳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后屋吨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜒谤,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡山宾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了芭逝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡渊胸,死狀恐怖旬盯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翎猛,我是刑警寧澤胖翰,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站切厘,受9級特大地震影響萨咳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疫稿,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一培他、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遗座,春花似錦舀凛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至号坡,卻和暖如春懊烤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宽堆。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工腌紧, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畜隶。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓寄啼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親代箭。 傳聞我的和親對象是個殘疾皇子墩划,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360