AVFoundation - 为什么我不能正确地获得视频

her*_*son 5 objective-c avfoundation

AVCaptureSession用来从设备摄像头捕获视频,然后使用AVAssetWriterInputAVAssetTrack压缩/调整视频大小,然后再将其上传到服务器.最终视频将通过html5视频元素在网上观看.

我遇到了多个问题,试图让视频的方向正确.我的应用程序仅支持横向,所有捕获的视频都应横向显示.但是,我想允许用户将设备保持在横向方向(即左侧或右侧的主页按钮).

我可以使用以下代码行以正确的方向显示视频预览

_previewLayer.connection.videoOrientation = UIDevice.currentDevice.orientation;
Run Code Online (Sandbox Code Playgroud)

通过AVAssetWriterInput和朋友处理视频时问题就开始了.结果似乎并未考虑视频捕获的左右横向模式.IOW,有时视频会颠倒过来.经过一些谷歌搜索后,我发现许多人建议以下代码行可以解决这个问题

writerInput.transform = videoTrack.preferredTransform;
Run Code Online (Sandbox Code Playgroud)

......但这似乎不起作用.经过一些调试后videoTrack.preferredTransform,无论视频被捕获的方向如何,我都发现它始终是相同的值.

我试图手动跟踪什么方位的视频在拍摄和设置writerInput.transform,以CGAffineTransformMakeRotation(M_PI)根据需要.哪解决了问题!!!

...八九不离十

当我在设备上查看结果时,此解决方案按预期工作.录制时,无论左右方向如何,视频都是正面向上的.不幸的是,当我在另一个浏览器中观看完全相同的视频时(Mac书上的chrome),它们都是颠倒的!?!?!?

我究竟做错了什么?

编辑

这是一些代码,万一它有用...

-(void)compressFile:(NSURL*)inUrl;
{                
    NSString* fileName = [@"compressed." stringByAppendingString:inUrl.lastPathComponent];
    NSError* error;
    NSURL* outUrl = [PlatformHelper getFilePath:fileName error:&error];

    NSDictionary* compressionSettings = @{ AVVideoProfileLevelKey: AVVideoProfileLevelH264Main31,
                                           AVVideoAverageBitRateKey: [NSNumber numberWithInt:2500000],
                                           AVVideoMaxKeyFrameIntervalKey: [NSNumber numberWithInt: 30] };

    NSDictionary* videoSettings = @{ AVVideoCodecKey: AVVideoCodecH264,
                                     AVVideoWidthKey: [NSNumber numberWithInt:1280],
                                     AVVideoHeightKey: [NSNumber numberWithInt:720],
                                     AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill,
                                     AVVideoCompressionPropertiesKey: compressionSettings };

    NSDictionary* videoOptions = @{ (id)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] };


    AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
    writerInput.expectsMediaDataInRealTime = YES;

    AVAssetWriter* assetWriter = [AVAssetWriter assetWriterWithURL:outUrl fileType:AVFileTypeMPEG4 error:&error];
    assetWriter.shouldOptimizeForNetworkUse = YES;

    [assetWriter addInput:writerInput];

    AVURLAsset* asset = [AVURLAsset URLAssetWithURL:inUrl options:nil];
    AVAssetTrack* videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    // !!! this line does not work as expected and causes all sorts of issues (videos display sideways in some cases) !!!
    //writerInput.transform = videoTrack.preferredTransform;

    AVAssetReaderTrackOutput* readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:videoOptions];
    AVAssetReader* assetReader = [AVAssetReader assetReaderWithAsset:asset error:&error];

    [assetReader addOutput:readerOutput];

    [assetWriter startWriting];
    [assetWriter startSessionAtSourceTime:kCMTimeZero];
    [assetReader startReading];

    [writerInput requestMediaDataWhenReadyOnQueue:_processingQueue usingBlock:
     ^{
         /* snip */
     }];
}
Run Code Online (Sandbox Code Playgroud)

小智 8

问题是修改writerInput.transform属性只会在视频文件元数据中添加一个标记,指示视频播放器在播放期间旋转文件.这就是为什么视频在你的设备上以正确的方向播放的原因(我猜他们也可以在Quicktime播放器中正确播放).

相机捕获的像素缓冲区仍然以捕获它们的方向布局.许多视频播放器不会检查首选方向元数据标签,只会以原始像素方向播放文件.

如果您希望用户能够以横向模式录制持有手机的视频,则需要AVCaptureSession在压缩前通过对每个视频帧的CVPixelBuffer执行变换来纠正此问题.这个Apple Q&A涵盖了它(查看AVCaptureVideoOutput文档):https: //developer.apple.com/library/ios/qa/qa1744/_index.html

调查上面的链接是解决问题的正确方法.解决相同问题的另一种快速解决方法是将应用程序的录制UI锁定为仅一个横向,然后使用ffmpeg旋转服务器端的所有视频.