【问题标题】:Fixing orientation when stitching (merging) videos using AVMutableComposition使用 AVMutableComposition 拼接(合并)视频时修复方向
【发布时间】:2016-04-16 12:02:32
【问题描述】:

TLDR - 查看编辑

我正在 Swift 中创建一个测试应用程序,我想使用 AVMutableComposition 将我的应用程序文档目录中的多个视频拼接在一起。

我在某种程度上成功地做到了这一点,我所有的视频都被拼接在一起,所有的东西都显示了正确大小的纵向和横向。

然而,我的问题是,所有视频都以汇编中最后一个视频的方向显示

我知道要解决这个问题,我需要为我添加的每个轨道添加图层说明,但是我似乎无法正确解决这个问题,我发现整个编译似乎都是纵向的横向视频只是缩放以适合纵向视图,因此当我将手机侧放观看横向视频时,它们仍然很小,因为它们已缩放为纵向尺寸。

这不是我想要的结果,我想要预期的功能,即如果视频是横向的,它会在纵向模式下显示缩放但如果手机旋转,我希望横向视频填满屏幕(因为它会当只是在照片中观看横向视频时)和纵向相同,因此当以纵向观看时它是全屏的,而当侧身观看时,视频会缩放到横向尺寸(就像在照片中观看纵向视频时一样)。

总而言之,我想要的结果是,在查看包含横向和纵向视频的合辑时,我可以将手机侧放观看整个合辑,并且横向视频是全屏的并且纵向是缩放的,或者在查看纵向相同的视频,纵向视频是全屏的,横向视频是按比例缩放的。

根据所有答案,我发现情况并非如此,当从照片导入视频以添加到编辑中时,它们似乎都有非常意外的行为,在添加正面拍摄的视频时,它们似乎都有相同的随机行为相机(要清楚我当前从库导入的实现视频和“自拍”视频以正确的大小显示,没有这些问题)。

我正在寻找一种方法来旋转/缩放这些视频,以便它们始终以正确的方向和比例显示,具体取决于用户拿着手机的方向。

编辑:我现在知道我不能在一个视频中同时包含横向和纵向,所以我正在寻找的预期结果是让最终视频为横向方向。我已经想出了如何切换所有方向和比例以使所有内容都以相同的方式进行,但是如果有人可以帮助我更改它,我的输出是纵向视频,因此我的输出是横向的,将不胜感激。

下面是我获取每个视频指令的函数:

func videoTransformForTrack(asset: AVAsset) -> CGAffineTransform
{
    var return_value:CGAffineTransform?

    let assetTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0]

    let transform = assetTrack.preferredTransform
    let assetInfo = orientationFromTransform(transform)

    var scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.width
    if assetInfo.isPortrait
    {
        scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.height
        let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
        return_value = CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor)
    }
    else
    {
        let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
        var concat = CGAffineTransformConcat(CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor), CGAffineTransformMakeTranslation(0, UIScreen.mainScreen().bounds.width / 2))
        if assetInfo.orientation == .Down
        {
            let fixUpsideDown = CGAffineTransformMakeRotation(CGFloat(M_PI))
            let windowBounds = UIScreen.mainScreen().bounds
            let yFix = assetTrack.naturalSize.height + windowBounds.height
            let centerFix = CGAffineTransformMakeTranslation(assetTrack.naturalSize.width, yFix)
            concat = CGAffineTransformConcat(CGAffineTransformConcat(fixUpsideDown, centerFix), scaleFactor)
        }
        return_value = concat
    }
    return return_value!
}

还有出口商:

    // Create AVMutableComposition to contain all AVMutableComposition tracks
    let mix_composition = AVMutableComposition()
    var total_time = kCMTimeZero

    // Loop over videos and create tracks, keep incrementing total duration
    let video_track = mix_composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())

    var instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: video_track)
    for video in videos
    {
        let shortened_duration = CMTimeSubtract(video.duration, CMTimeMake(1,10));
        let videoAssetTrack = video.tracksWithMediaType(AVMediaTypeVideo)[0]

        do
        {
            try video_track.insertTimeRange(CMTimeRangeMake(kCMTimeZero, shortened_duration),
                ofTrack: videoAssetTrack ,
                atTime: total_time)

            video_track.preferredTransform = videoAssetTrack.preferredTransform

        }
        catch _
        {
        }

        instruction.setTransform(videoTransformForTrack(video), atTime: total_time)

        // Add video duration to total time
        total_time = CMTimeAdd(total_time, shortened_duration)
    }

    // Create main instrcution for video composition
    let main_instruction = AVMutableVideoCompositionInstruction()
    main_instruction.timeRange = CMTimeRangeMake(kCMTimeZero, total_time)
    main_instruction.layerInstructions = [instruction]
    main_composition.instructions = [main_instruction]
    main_composition.frameDuration = CMTimeMake(1, 30)
    main_composition.renderSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: UIScreen.mainScreen().bounds.height)

    let exporter = AVAssetExportSession(asset: mix_composition, presetName: AVAssetExportPreset640x480)
    exporter!.outputURL = final_url
    exporter!.outputFileType = AVFileTypeMPEG4
    exporter!.shouldOptimizeForNetworkUse = true
    exporter!.videoComposition = main_composition

    // 6 - Perform the Export
    exporter!.exportAsynchronouslyWithCompletionHandler()
    {
        // Assign return values based on success of export
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.exportDidFinish(exporter!)
        })
    }

很抱歉,我只是想确保我对所问的问题非常清楚,因为其他答案对我不起作用。

【问题讨论】:

  • 关于我提到的编辑,我发布了一个赏金让某人知道即使在前 2 天内没有发布任何赏金,我也会奖励正确答案的分数。我现在添加了赏金,但除了编辑之外,对这个问题的关注度仍然为零????
  • 对于像这样一个依赖于外部数据的问题,如果您可以发布整个项目(包括示例视频)将会很有帮助,这样很容易重现。
  • 这是一个完整的最小示例,它将显示您只需要 2 个视频作为 AVAsset 在视频阵列中的问题,一个是横向的,一个是纵向的,您就会看到问题
  • 再读一遍,我不确定你能不能达到你想要的。视频是固定大小的;它不能在视频期间改变大小。您希望结果是比屏幕大的方形视频吗?
  • 在看了其他一些事情之后,您似乎是正确的,我真正想要的预期结果是最终视频是横向的,我使用合成层指令找到的所有示例最终都是纵向的视频。我有实现这一点的代码,我会在我在家的一个小时内发布,然后看看是否有人可以帮助我更改它,以便最终视频是横向而不是纵向

标签: ios swift video avmutablecomposition


【解决方案1】:

我不确定您的 orientationFromTransform() 是否为您提供正确的方向。

我认为您尝试修改它或尝试类似的方法:

extension AVAsset {

    func videoOrientation() -> (orientation: UIInterfaceOrientation, device: AVCaptureDevicePosition) {
        var orientation: UIInterfaceOrientation = .Unknown
        var device: AVCaptureDevicePosition = .Unspecified

        let tracks :[AVAssetTrack] = self.tracksWithMediaType(AVMediaTypeVideo)
        if let videoTrack = tracks.first {

            let t = videoTrack.preferredTransform

            if (t.a == 0 && t.b == 1.0 && t.d == 0) {
                orientation = .Portrait

                if t.c == 1.0 {
                    device = .Front
                } else if t.c == -1.0 {
                    device = .Back
                }
            }
            else if (t.a == 0 && t.b == -1.0 && t.d == 0) {
                orientation = .PortraitUpsideDown

                if t.c == -1.0 {
                    device = .Front
                } else if t.c == 1.0 {
                    device = .Back
                }
            }
            else if (t.a == 1.0 && t.b == 0 && t.c == 0) {
                orientation = .LandscapeRight

                if t.d == -1.0 {
                    device = .Front
                } else if t.d == 1.0 {
                    device = .Back
                }
            }
            else if (t.a == -1.0 && t.b == 0 && t.c == 0) {
                orientation = .LandscapeLeft

                if t.d == 1.0 {
                    device = .Front
                } else if t.d == -1.0 {
                    device = .Back
                }
            }
        }

        return (orientation, device)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多