肖像视频以黑屏播放

时间:2017-02-17 10:48:10

标签: ios objective-c video avfoundation avassetexportsession

更新

  

不要使用模拟器测试视频翻译。但我有编解码器问题   在另一个问题here中提出。任何帮助表示赞赏。

我正在使用AVURLAsset创建我的视频,只要从图库中挑选的视频处于横向模式,它们就可以正常工作。但是当我使用肖像视频时,它可以在黑屏(音频播放)中播放,或者帧被扭曲(见图像)。

更新 我尝试使用CGAffineTransform仍然没有运气。

以下是代码:

-(void) createVideo{

    AVMutableComposition* mixComposition = [AVMutableComposition composition];
    NSDictionary *options = @{AVURLAssetPreferPreciseDurationAndTimingKey:@YES};


    _videoAsset = [[AVURLAsset alloc]initWithURL:video_url options:options];

    CMTime startTimeV=CMTimeMakeWithSeconds(videoStartTime.floatValue, 1);
    CMTime endTimeV=CMTimeMakeWithSeconds(videoEndTime.floatValue, 1);

    CMTimeRange video_timeRange = CMTimeRangeMake(startTimeV,endTimeV);



    AVMutableCompositionTrack *a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    [a_compositionVideoTrack insertTimeRange:video_timeRange ofTrack:[[_videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];

    AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, self.videoAsset.duration);

    AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:a_compositionVideoTrack];
    AVAssetTrack *videoAssetTrack = [[self.videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    CGSize trackDimensions = {
        .width = 0.0,
        .height = 0.0,
    };
    trackDimensions = [videoAssetTrack naturalSize];

    int width = trackDimensions.width;
    int height = trackDimensions.height;


    UIImageOrientation videoAssetOrientation_  = UIImageOrientationUp;
    BOOL isVideoAssetPortrait_  = NO;
    CGAffineTransform videoTransform = videoAssetTrack.preferredTransform;
    if (videoTransform.a == 0 && videoTransform.b == 1.0 && videoTransform.c == -1.0 && videoTransform.d == 0) {
        videoAssetOrientation_ = UIImageOrientationRight;
        isVideoAssetPortrait_ = YES;
    }
    if (videoTransform.a == 0 && videoTransform.b == -1.0 && videoTransform.c == 1.0 && videoTransform.d == 0) {
        videoAssetOrientation_ =  UIImageOrientationLeft;
        isVideoAssetPortrait_ = YES;
    }
    if (videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0) {
        videoAssetOrientation_ =  UIImageOrientationUp;
    }
    if (videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0) {
        videoAssetOrientation_ = UIImageOrientationDown;
    }
//    CGAffineTransform transformToApply=CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90.0));

    [videolayerInstruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero];
    [videolayerInstruction setOpacity:0.0 atTime:self.videoAsset.duration];

    mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil];

    AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];

    CGSize naturalSize;
    if(isVideoAssetPortrait_){
        naturalSize = CGSizeMake(videoAssetTrack.naturalSize.height, videoAssetTrack.naturalSize.width);
    } else {
        naturalSize = videoAssetTrack.naturalSize;
    }

    float renderWidth, renderHeight;
    renderWidth = naturalSize.width;
    renderHeight = naturalSize.height;
    mainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight);
    mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
    mainCompositionInst.frameDuration = CMTimeMake(1, 30);

出口:

    -(void)export{

        NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docsDir = [dirPaths objectAtIndex:0];
        NSString* fileName=[NSString stringWithFormat:@"myvideo%lld.mp4",[@(floor([[NSDate date] timeIntervalSince1970])) longLongValue]+1];

        NSString *outputFilePath = [docsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@",fileName]];

        NSURL *outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
        if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
            [[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];


        AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
        _assetExport.outputFileType = AVFileTypeMPEG4;
        _assetExport.outputURL = outputFileUrl;
        _assetExport.videoComposition = mainCompositionInst;

        ShareViewController *newViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"vidShare"];

        [_assetExport exportAsynchronouslyWithCompletionHandler:
         ^(void ) {
             dispatch_async(dispatch_get_main_queue(), ^{

                 newViewController.videoFilePath=outputFileUrl;
[self.navigationController pushViewController:newViewController animated:YES];

             });
         }
         ];
    }

风景=确定

Landscape Video = OK

人像=失败

Portrait Video = FAIL

1 个答案:

答案 0 :(得分:1)

我以前遇到过这个问题。在大多数情况下,使用videoAssetTrack.preferredTransform设置videolayerInstruction的变换。但有时preferredTransform可能缺乏tx(ty)的值(你应该检查CGAffineTransform在Apple API参考中,如果你不知道什么是tx(ty))或tx(ty)有不准确的值导致错误的视频定位(如在黑屏中玩。) 所以重点是:你应该使用preferredTransform来确定原始视频方向并进行自己的转换 这是获取轨道方向的代码:

- (UIInterfaceOrientation)orientationForTrack:(AVAsset *)asset {
    UIInterfaceOrientation orientation = UIInterfaceOrientationPortrait;
    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) {
            orientation = UIInterfaceOrientationPortrait;
        }
        // PortraitUpsideDown
        if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0) {
            orientation = UIInterfaceOrientationPortraitUpsideDown;
        }
        // LandscapeRight
        if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0) {
            orientation = UIInterfaceOrientationLandscapeRight;
        }
        // LandscapeLeft
        if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0) {
            orientation = UIInterfaceOrientationLandscapeLeft;
        }
    }
    return orientation;
}

用于获取所需变换以应用于videolayerInstruction的转换的代码:

- (CGAffineTransform)transformBasedOnAsset:(AVAsset *)asset {
    UIInterfaceOrientation orientation = [AVUtilities orientationForTrack:asset];
    AVAssetTrack *assetTrack = [asset tracksWithMediaType:AVMediaTypeVideo][0];
    CGSize naturalSize = assetTrack.naturalSize;
    CGAffineTransform finalTranform;
    switch (orientation) {
        case UIInterfaceOrientationLandscapeLeft:
            finalTranform = CGAffineTransformMake(-1, 0, 0, -1, naturalSize.width, naturalSize.height);
            break;
        case UIInterfaceOrientationLandscapeRight:
            finalTranform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
            break;
        case UIInterfaceOrientationPortrait:
            finalTranform = CGAffineTransformMake(0, 1, -1, 0, naturalSize.height, 0);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            finalTranform = CGAffineTransformMake(0, -1, 1, 0, 0, naturalSize.width);
            break;
        default:
            break;
    }
    return finalTranform;
}

希望它适合你。