如何使用AVFoundation设置逐帧生成的视频的方向?

时间:2011-10-08 13:11:38

标签: iphone ios camera orientation avfoundation

我正在编写一个iPhone应用程序,它从相机中获取视频,通过一些OpenGL着色器代码运行它,然后使用AVFoundation将输出写入视频文件。该应用程序以lanscape方向运行(或者),因此所有录制的视频都应该是横向的。

我开始录制之前使用的当前代码是以正确的方式获取视频:

[[self videoWriterInput] setTransform:CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI), -1.0, 1.0)];

其中videoWriterInput是AVAssetWriterInput的一个实例,目的是补偿横向模式和OpenGL的尊重方向。

这会生成在Quicktime播放器上下载和播放时正常播放的视频。但是,如果我将录制的视频添加到iPhone照片库中,缩略图会正确显示,但如果手机是横向拍摄的,则视频会旋转90度。如果手机处于纵向状态,则视频可以正常播放,但会水平裁剪以适合纵向尺寸。

根据this Apple tech note我用于处理视频帧的AVCaptureVideoDataOutput的捕获输出不支持设置视频方向。

有没有人成功录制了横向生成的视频,可以将其添加到iPhone库并在风景中正确播放,如果是这样的话?

2 个答案:

答案 0 :(得分:11)

您的帖子让我看到了苹果视频应用播放视频的方式。我用我的应用程序在四个方向上记录了几个项目。他们都回放得恰到好处。我刚注意到视频应用不支持像照片相册应用中的播放器那样的旋转。视频应用程序希望您保持设备(至少我的iPod touch)的横向。我做了一些肖像录制,将它们添加到iTunes,所有这些,包括用Apple的相机应用创建的,在将设备旋转为纵向时都没有旋转。

总之...

我的应用程序是一个时间推移的应用程序,不会像你一样对框架进行任何额外的处理,所以YMMV在下面。我设置了我的应用程序,以便在设备旋转时不会旋转窗口。这样我总是处理设备的一个方向。我使用AVFoundation从视频流中抓取每个第N帧并将其写出来。

在我开始录制时,我会执行以下操作。

inputWriterBuffer = [AVAssetWriterInput assetWriterInputWithMediaType: AVMediaTypeVideo outputSettings: outputSettings];
    // I call this explicitly before recording starts. Video plays back the right way up.
[self detectOrientation];
inputWriterBuffer.transform = playbackTransform;

detectOrientation调用以下方法。为了清晰起见,我已经减少了实际代码。在我的应用程序中,我还旋转了一些按钮,因此请注意它们没有得到相同的转换。需要注意的是我如何设置playbackTransform ivar。

-(void) detectOrientation {
CGAffineTransform buttonTransform;

switch ([[UIDevice currentDevice] orientation]) {
    case UIDeviceOrientationUnknown:
        NULL;
    case UIDeviceOrientationFaceUp:
        NULL;
    case UIDeviceOrientationFaceDown:
        NULL;
        break;
    case UIDeviceOrientationPortrait:
        [UIButton beginAnimations: @"myButtonTwist" context: nil];
        [UIButton setAnimationDuration: 0.25];
        buttonTransform = CGAffineTransformMakeRotation( ( 0 * M_PI ) / 180 );
        recordingStarStop.transform = buttonTransform;
        [UIButton commitAnimations];            

        playbackTransform = CGAffineTransformMakeRotation( ( 90 * M_PI ) / 180 );
        break;
    case UIDeviceOrientationLandscapeLeft:
        [UIButton beginAnimations: @"myButtonTwist" context: nil];
        [UIButton setAnimationDuration: 0.25];
        buttonTransform = CGAffineTransformMakeRotation( ( 90 * M_PI ) / 180 );
        recordingStarStop.transform = buttonTransform;
        [UIButton commitAnimations];            

        // Transform depends on which camera is supplying video
        if (theProject.backCamera == YES) playbackTransform = CGAffineTransformMakeRotation( 0 / 180 );
        else playbackTransform = CGAffineTransformMakeRotation( ( -180 * M_PI ) / 180 );

        break;
    case UIDeviceOrientationLandscapeRight:
        [UIButton beginAnimations: @"myButtonTwist" context: nil];
        [UIButton setAnimationDuration: 0.25];
        buttonTransform = CGAffineTransformMakeRotation( ( -90 * M_PI ) / 180 );
        recordingStarStop.transform = buttonTransform;
        [UIButton commitAnimations];

        // Transform depends on which camera is supplying video
        if (theProject.backCamera == YES) playbackTransform = CGAffineTransformMakeRotation( ( -180 * M_PI ) / 180 );
        else playbackTransform = CGAffineTransformMakeRotation( 0 / 180 );

        break;
    case UIDeviceOrientationPortraitUpsideDown:
        [UIButton beginAnimations: @"myButtonTwist" context: nil];
        [UIButton setAnimationDuration: 0.25];
        buttonTransform = CGAffineTransformMakeRotation( ( 180 * M_PI ) / 180 );
        recordingStarStop.transform = buttonTransform;
        [UIButton commitAnimations];

        playbackTransform = CGAffineTransformMakeRotation( ( -90 * M_PI ) / 180 );
        break;
    default:
        playbackTransform = CGAffineTransformMakeRotation( 0 / 180 ); // Use the default, although there are likely other issues if we get here.
        break;
}
}

作为旁注,因为我想要旋转设备时调用的方法,并且我关闭了自动旋转,我的viewDidLoad方法中有以下内容。

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(detectOrientation) name:@"UIDeviceOrientationDidChangeNotification" object:nil];

这是我在this SOF Q&A中找到的提示。

答案 1 :(得分:0)

更简单......

在你的顶点着色器中:

统一浮动preferredRotation; 。 。 。 mat4 rotationMatrix = mat4(cos(preferredRotation), - sin(preferredRotation),0.0,0.0,                                 sin(preferredRotation),cos(preferredRotation),0.0,0.0,                                                    0.0,0.0,1.0,0.0,                                                    0.0,0.0,0.0,1.0);

/* 90-degrees
mat4 rotationMatrix = mat4( cos(preferredRotation), -sin(preferredRotation), (1.0 - cos(preferredRotation)) - sin(preferredRotation), 0.0,
                           -sin(preferredRotation),  cos(preferredRotation), 0.0, 0.0,
                           0.0,                     0.0, 1.0, 0.0,
                           0.0,                     0.0, 0.0, 1.0);

在调用着色器的视图或视图控制器中:

if([videoTrack statusOfValueForKey:@“preferredTransform”error:nil] == AVKeyValueStatusLoaded){                         CGAffineTransform preferredTransform = [videoTrack preferredTransform];                         self.playerView.preferredRotation = -1 * atan2(preferredTransform.b,preferredTransform.a);

......等等......