短視頻從無(wú)到有 (六)視頻合成及壓縮、轉(zhuǎn)換格式

視頻合成

視頻合成中依然用到了AVMutableComposition,思路依然很簡(jiǎn)單,取出視頻軌和音頻軌數(shù)據(jù)加入到可變軌道之中。不多說(shuō),還是貼代碼吧:

 NSArray *videosPathArray =@[@"",
                                @""];
 
  
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
    
    
    AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    CMTime totalDuration = kCMTimeZero;
    for (int i = 0; i < videosPathArray.count; i++) {
        
        NSDictionary* options = @{AVURLAssetPreferPreciseDurationAndTimingKey:@YES
                                  
                                  };
   //網(wǎng)絡(luò)視頻 URLWithString: 本地視頻 fileURLWithPath:     
        AVURLAsset *asset =[AVURLAsset URLAssetWithURL:[NSURL URLWithString:videosPathArray[i]] options:options];
        
        NSError *erroraudio = nil;
        
        //獲取AVAsset中的音頻 或者視頻
        AVAssetTrack *assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
        //向通道內(nèi)加入音頻或者視頻
        BOOL ba = [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                                      ofTrack:assetAudioTrack
                                       atTime:totalDuration
                                        error:&erroraudio];
        
        NSLog(@"erroraudio:%@%d",erroraudio,ba);
        
        NSError *errorVideo = nil;
        AVAssetTrack *assetVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
        BOOL bl = [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                                      ofTrack:assetVideoTrack
                                       atTime:totalDuration
                                        error:&errorVideo];
        
        NSLog(@"errorVideo:%@%d",errorVideo,bl);
        totalDuration = CMTimeAdd(totalDuration, asset.duration);
    }
    
    
    
    LYAVPlayerView *playerView =[[LYAVPlayerView alloc]init];
  //  CGFloat scale =_composition.naturalSize.width/_composition.naturalSize.height;
    playerView.frame =CGRectMake(0,100,ScreenWidth,ScreenHeight-160);
    playerView.videoGravity =AVLayerVideoGravityResizeAspect;
    [playerView setPlayerItem:[[AVPlayerItem alloc]initWithAsset:mixComposition]];
    [self.view addSubview:playerView];
    [playerView play];
    

注:創(chuàng)建AVURLAsset時(shí),如果是本地視頻則用fileURLWithPath:函數(shù),如果是網(wǎng)絡(luò)視頻,則調(diào)用URLWithString函數(shù)。多個(gè)網(wǎng)絡(luò)視頻合成后,效果就跟播放一個(gè)視頻一樣,用戶體驗(yàn)非常不錯(cuò)。CMTimeAdd的用法參考另一篇文章短視頻從無(wú)到有 (三)CMTime詳解。

視頻壓縮和轉(zhuǎn)換

視頻合成后即可導(dǎo)出到本地或者手機(jī)相冊(cè),思路依然很簡(jiǎn)單,使用AVAssetExportSession即可。代碼如下:

  unlink([outPath UTF8String]);
    NSURL *compressionFileURL = [NSURL fileURLWithPath:outPath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:outPath]) {
        
        [[NSFileManager defaultManager] removeItemAtPath:outPath error:nil];
        
    }
    
    
    
    // 創(chuàng)建AVAsset對(duì)象
    AVAsset* asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:videoPath]];
    // 創(chuàng)建AVAssetExportSession對(duì)象
    AVAssetExportSession * exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:presetName];
    //優(yōu)化網(wǎng)絡(luò)
    exporter.shouldOptimizeForNetworkUse = YES;
    //設(shè)置輸出路徑
    exporter.outputURL =compressionFileURL;
    //設(shè)置輸出類型
    exporter.outputFileType = outputFileType;
    [exporter exportAsynchronouslyWithCompletionHandler:^{
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            switch (exporter.status) {
                case AVAssetExportSessionStatusFailed:{
                    
                    if (completeBlock) {
                        
                        completeBlock(exporter.error,compressionFileURL);
                    }
                    
                    
                    
                    break;
                }
                case AVAssetExportSessionStatusCancelled:{
                    
                    NSLog(@"Export Status: Cancell");
                    
                    break;
                }
                case AVAssetExportSessionStatusCompleted: {
                    
                    if (completeBlock) {
                        
                        completeBlock(nil,compressionFileURL);
                    }
                    
                    
                    break;
                }
                case AVAssetExportSessionStatusUnknown: {
                    
                    NSLog(@"Export Status: Unknown");
                    break;
                }
                case AVAssetExportSessionStatusExporting : {
                    
                    NSLog(@"Export Status: Exporting");
                    break;
                }
                case AVAssetExportSessionStatusWaiting: {
                    
                    NSLog(@"Export Status: Wating");
                    break;
                }
                    
            };
            
        });
        
    }];

注:導(dǎo)出過(guò)程中設(shè)置exporterpresetName(分辨率)outputFileType(視頻封裝格式)即可完成視頻轉(zhuǎn)換和壓縮。當(dāng)然,更深層次的處理靠這些是遠(yuǎn)遠(yuǎn)不夠的,還要依靠更多的框架來(lái)處理,譬如ffmpeg等,這些以后再做討論,今兒就先到這。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容