• ios 视频拼接/合成


    上面的图说明的是这个混合的过程,下面放代码:

    - (void)mergeAndExportVideos:(NSArray*)videosPathArray withOutPath:(NSString*)outpath{
        if (videosPathArray.count == 0) {
            return;
        }
        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++) {
            AVURLAsset *asset = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:videosPathArray[i]]];
            NSError *erroraudio = nil;
         //获取AVAsset中的音频 或者视频 AVAssetTrack
    *assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
         //向通道内加入音频或者视频 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); } NSLog(@"%@",NSHomeDirectory()); NSURL *mergeFileURL = [NSURL fileURLWithPath:outpath]; AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPreset640x480]; exporter.outputURL = mergeFileURL; exporter.outputFileType = AVFileTypeMPEG4; exporter.shouldOptimizeForNetworkUse = YES; [exporter exportAsynchronouslyWithCompletionHandler:^{ NSLog(@"exporter%@",exporter.error); }];

    下面是方法详解:

    - (AVMutableCompositionTrack *)addMutableTrackWithMediaType:(NSString *)mediaType preferredTrackID:(CMPersistentTrackID)preferredTrackID;

    参数:

    mediaType          :数据类型  AVMediaTypeVideo 视频   AVMediaTypeAudio  音频

    preferredTrackID :可自由设定 但建议kCMPersistentTrackID_Invalid也就是0

    //向通道内加入音频或者视频
    - (BOOL)insertTimeRange:(CMTimeRange)timeRange ofTrack:(AVAssetTrack *)track atTime:(CMTime)startTime error:(NSError * __nullable * __nullable)outError;

    参数:

    timeRange:  插入视频/音频的的时间段

    track        :插入的视频/音频

    补充调整视频方向的方法,个人感觉不是很好,希望大家给点建议: 从stackoverflow查到的具体网址忘了

    代码如下:

    - (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset completion:(void (^)(NSString *outputPath))completion {

        AVAssetExportSession *session = [[AVAssetExportSession alloc]initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality];
        //
        AVMutableVideoComposition *videoComposition = [self fixedCompositionWithAsset:videoAsset];
        if (videoComposition.renderSize.width) {
            // 修正视频转向
            session.videoComposition = videoComposition;
        }
        //
        NSDateFormatter *formater = [[NSDateFormatter alloc] init];
        [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss"];
        NSString *outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]];
        session.outputURL = [NSURL fileURLWithPath:outputPath];
        
        // Optimize for network use.
        session.shouldOptimizeForNetworkUse = true;
        
        NSArray *supportedTypeArray = session.supportedFileTypes;
        if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
            session.outputFileType = AVFileTypeMPEG4;
        } else if (supportedTypeArray.count == 0) {
            NSLog(@"No supported file types 视频类型暂不支持导出");
            return;
        } else {
            session.outputFileType = [supportedTypeArray firstObject];
        }
        
        if (![[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"]]) {
            [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"] withIntermediateDirectories:YES attributes:nil error:nil];
        }
        // Begin to export video to the output path asynchronously.
        [session exportAsynchronouslyWithCompletionHandler:^(void) {
            NSLog(@"%@",[session.error description]);
            switch (session.status) {
                case AVAssetExportSessionStatusUnknown:
                    NSLog(@"AVAssetExportSessionStatusUnknown"); break;
                case AVAssetExportSessionStatusWaiting:
                    NSLog(@"AVAssetExportSessionStatusWaiting"); break;
                case AVAssetExportSessionStatusExporting:
                    NSLog(@"AVAssetExportSessionStatusExporting"); break;
                case AVAssetExportSessionStatusCompleted: {
                    NSLog(@"AVAssetExportSessionStatusCompleted");
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (completion) {
                            completion(outputPath);
                        }
                    });
                }  break;
                case AVAssetExportSessionStatusFailed:{
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (completion) {
                            completion(nil);
                        }
                    });
                    NSLog(@"AVAssetExportSessionStatusFailed"); break;
                }
                default: break;
            }
        }];
    //    }
    }

    /// 获取优化后的视频转向信息
    - (AVMutableVideoComposition *)fixedCompositionWithAsset:(AVAsset *)videoAsset {
        AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
        // 视频转向
        int degrees = [self degressFromVideoFileWithAsset:videoAsset];
        if (degrees != 0) {
            CGAffineTransform translateToCenter;
            CGAffineTransform mixedTransform;
            videoComposition.frameDuration = CMTimeMake(1, 30);
            
            NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeVideo];
            AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
            
            if (degrees == 90) {
                // 顺时针旋转90°
                translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.height, 0.0);
                mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2);
                videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
            } else if(degrees == 180){
                // 顺时针旋转180°
                translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.width, videoTrack.naturalSize.height);
                mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI);
                videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height);
            } else if(degrees == 270){
                // 顺时针旋转270°
                translateToCenter = CGAffineTransformMakeTranslation(0.0, videoTrack.naturalSize.width);
                mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0);
                videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
            }
            
            AVMutableVideoCompositionInstruction *roateInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
            roateInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]);
            AVMutableVideoCompositionLayerInstruction *roateLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
            
            [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
            
            roateInstruction.layerInstructions = @[roateLayerInstruction];
            // 加入视频方向信息
            videoComposition.instructions = @[roateInstruction];
        }
        return videoComposition;
    }
    /// 获取视频角度
    - (int)degressFromVideoFileWithAsset:(AVAsset *)asset {
        int degress = 0;
        NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
        if([tracks count] > 0) {
            AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
            CGAffineTransform t = videoTrack.preferredTransform;
            if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
                // Portrait
                degress = 90;
            } else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
                // PortraitUpsideDown
                degress = 270;
            } else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
                // LandscapeRight
                degress = 0;
            } else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
                // LandscapeLeft
                degress = 180;
            }
        }
        return degress;
    }
  • 相关阅读:
    Python使用requirements.txt安装类库
    virtualenv -- python虚拟沙盒(linux版本)
    linux下导入、导出mysql数据库命令
    linux中mysql基本操作
    aspx.cs方法设置webmenthod特性接收ajax请求
    vue高级路由
    浅析JS模块规范:AMD,CMD,CommonJS
    当前不会命中断点还未为文档加载任何符号——问题探究
    Node.js安装及环境配置之Windows篇
    NewtonSoft.Json NULL转空字符串
  • 原文地址:https://www.cnblogs.com/chaochaobuhuifei55/p/5581291.html
Copyright © 2020-2023  润新知