相册视频转码MP4格式 iOS

本地已转码时,直接上传;本地无转码时,先转码再上传

/// 视频处理通过本地沙盒文件路径判断此视频文件是否已经转码
/// @param asset 视频资源
/// @param callBack 回调
- (void)dealWithVidioAsset:(PHAsset *)asset
                  callBack:(void (^)(NSString *))callBack
{
    /// 转码操作
    PHImageManager *manager = [PHImageManager defaultManager];
    [manager requestAVAssetForVideo:asset
                          
                            options:nil
                      resultHandler:^(AVAsset * _Nullable aVsset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
        
        ///判断此视频是否已经转码
         NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingFormat:@"/VideoCacheData/%@.mp4",[((AVURLAsset*)aVsset).URL.path MD5String]];
        
         NSFileManager *fileManager = [NSFileManager defaultManager];
         BOOL isDirExist = [fileManager fileExistsAtPath:path];
        if (isDirExist) {
            // 已经转码成功 直接上传
            [self uploadMpa4WithUrl:[NSURL URLWithString:path] callBack:^(NSString *str) {
                if (callBack) {
                    callBack(str);
                }
            }];
            return;
        }
        [self convertMovToMp4FromAVURLAsset:(AVURLAsset*)aVsset andCompeleteHandler:^(NSURL *fileUrl) {
            if (!fileUrl) {
                [HUDManager hideHUDView];
                [self.view showMessageWithText:@"上传错误请重试!"];
                self.navigationItem.rightBarButtonItem.enabled = YES;

            }else
            {
                [self uploadMpa4WithUrl:fileUrl callBack:^(NSString *str) {
                    if (callBack) {
                        callBack(str);
                    }
                }];
            }
        }];
    }];
}

转码MP4

- (void)convertMovToMp4FromAVURLAsset:(AVURLAsset*)urlAsset andCompeleteHandler:(void(^)(NSURL *fileUrl))fileUrlHandler{

    AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:urlAsset.URL options:nil];
    
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
    
    if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {
       
        //  在Documents目录下创建一个名为FileData的文件夹
        NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"VideoCacheData"];
       
        NSFileManager *fileManager = [NSFileManager defaultManager];
        BOOL isDir = FALSE;
        BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
        if(!(isDirExist && isDir)) {
            BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
            if(!bCreateDir){
                NSLog(@"创建文件夹失败!%@",path);
            }
            NSLog(@"创建文件夹成功,文件路径%@",path);
        }
        /// 文件名为本地相册路径的Md5
        NSString *resultPath = [path stringByAppendingFormat:@"/%@.mp4",[urlAsset.URL.path MD5String]];
        NSLog(@"file path:%@",resultPath);
        
        NSLog(@"resultPath = %@",resultPath);
        
        AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset
                                                                               presetName:AVAssetExportPresetMediumQuality];
        exportSession.outputURL = [NSURL fileURLWithPath:resultPath];
        exportSession.outputFileType = AVFileTypeMPEG4;
        exportSession.shouldOptimizeForNetworkUse = YES;
        exportSession.videoComposition = [self getVideoComposition:avAsset];  //修正某些播放器不识别视频Rotation的问题

        [exportSession exportAsynchronouslyWithCompletionHandler:^(void)
         {
            dispatch_async(dispatch_get_main_queue(), ^{
                switch (exportSession.status) {
                    case AVAssetExportSessionStatusUnknown:
                        NSLog(@"AVAssetExportSessionStatusUnknown");
                        fileUrlHandler(nil);
                        break;
                    case AVAssetExportSessionStatusWaiting:
                        NSLog(@"AVAssetExportSessionStatusWaiting");
                        fileUrlHandler(nil);
                        break;
                    case AVAssetExportSessionStatusExporting:
                        NSLog(@"AVAssetExportSessionStatusExporting");
                        fileUrlHandler(nil);
                        break;
                    case AVAssetExportSessionStatusCompleted:
                        NSLog(@"AVAssetExportSessionStatusCompleted");
                        fileUrlHandler(exportSession.outputURL);
                        break;
                    case AVAssetExportSessionStatusFailed:
                        NSLog(@"AVAssetExportSessionStatusFailed");
                        fileUrlHandler(nil);
                        break;
                        
                    case AVAssetExportSessionStatusCancelled:
                        NSLog(@"AVAssetExportSessionStatusCancelled");
                        fileUrlHandler(nil);
                        break;
                }
            });
         }];
    }
}

修正视频位置

/// 修正位置信息
- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset
{
    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVMutableComposition *composition = [AVMutableComposition composition];
    AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
    CGSize videoSize = videoTrack.naturalSize;
    BOOL isPortrait_ = [self isVideoPortrait:asset];
    if(isPortrait_) {
        videoSize = CGSizeMake(videoSize.height, videoSize.width);
    }
    composition.naturalSize     = videoSize;
    videoComposition.renderSize = videoSize;
    
    videoComposition.frameDuration = CMTimeMakeWithSeconds( 1 / videoTrack.nominalFrameRate, 600);
    AVMutableCompositionTrack *compositionVideoTrack;
    compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil];
    AVMutableVideoCompositionLayerInstruction *layerInst;
    layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
    [layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero];
    AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
    inst.layerInstructions = [NSArray arrayWithObject:layerInst];
    videoComposition.instructions = [NSArray arrayWithObject:inst];
    return videoComposition;
}

- (BOOL) isVideoPortrait:(AVAsset *)asset
{
    BOOL isPortrait = NO;
    NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
    if([tracks    count] > 0) {
        AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
        
        CGAffineTransform t = videoTrack.preferredTransform;
        // Portrait
        if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0)
        {
            isPortrait = YES;
        }
        // PortraitUpsideDown
        if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0)  {
            
            isPortrait = YES;
        }
        // LandscapeRight
        if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0)
        {
            isPortrait = NO;
        }
        // LandscapeLeft
        if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0)
        {
            isPortrait = NO;
        }
    }
    return isPortrait;
}
在北京的灯中,有一盏是我家的。这个梦何时可以实现?哪怕微微亮。北京就像魔鬼训练营,有能力的留,没能力的走……
原文地址:https://www.cnblogs.com/huangzs/p/15234902.html