1. 程式人生 > 其它 >相簿視訊轉碼MP4格式 iOS

相簿視訊轉碼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;
}
在北京的燈中,有一盞是我家的。這個夢何時可以實現?哪怕微微亮。北京就像魔鬼訓練營,有能力的留,沒能力的走……