Portrait video rendered as landscape after exporting with AVMutableVideoComposition
Asked Answered
T

1

2

hello i'm combining two videos with AVMutableVideoComposition() and it works good with landscape videos and portrait videos downloaded from youtube but when try portrait video recorded in iPhone or android the exported video comes as landscape/horizontal instead of original portrait/ vertical.

if researched lot on stack overflow and google but couldn't find any working solution.

this raywenderlich's article explains very well why video is in landscape mode and provides solution mathod in Orienting Video section of article, that first checks if video is portrait and then sets it's height width and preferredOrientation. but it doesn't work anymore.

i tried manually setting AVAssetTrack's .preferredTransform to CGAffineTransform(a: 0.0, b: 1.0, c: -1.0, d: 0.0, tx: 0.0, ty: 0.0) but doesn't work.

many old answer suggest setting AVAssetTrack's .preferredTransform to AvAsset's preferredTransform but it doesn't work.

from AVAssetTrack's .preferredTransform i'm able to know if video is portrait or not but not able to change it, any help will be really appreciated, thank you.

Tiddlywinks answered 14/2, 2022 at 8:51 Comment(2)
trying to solve this, any solutions?Misanthropy
@Misanthropy this is how i solved it.Tiddlywinks
T
5

After searching and trying many things i did this to solve the problem, first i check orientation with this function from raywenderlich article.

  func orientationFromTransform(
  _ transform: CGAffineTransform
) -> (orientation: UIImage.Orientation, isPortrait: Bool) {
  var assetOrientation = UIImage.Orientation.up
  var isPortrait = false
  let tfA = transform.a
  let tfB = transform.b
  let tfC = transform.c
  let tfD = transform.d

  if tfA == 0 && tfB == 1.0 && tfC == -1.0 && tfD == 0 {
    assetOrientation = .right
    isPortrait = true
  } else if tfA == 0 && tfB == -1.0 && tfC == 1.0 && tfD == 0 {
    assetOrientation = .left
    isPortrait = true
  } else if tfA == 1.0 && tfB == 0 && tfC == 0 && tfD == 1.0 {
    assetOrientation = .up
  } else if tfA == -1.0 && tfB == 0 && tfC == 0 && tfD == -1.0 {
    assetOrientation = .down
  }
  return (assetOrientation, isPortrait)
}

and store it

let firstAssetInfo = orientationFromTransform(firstVideoTrack!.preferredTransform)

then before adding transform instructions i check if it is portrait then transform it to portrait manually and set it's scaling according to and use it's width as height and height as width, and if it's not portrait then do what i was doing before.

    let firstLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
    
    if firstAssetInfo.isPortrait {
        
        let rotate = __CGAffineTransformMake(0.0, 1.0, -1.0, 0.0, 0.0, 0.0)
        let scale = CGAffineTransform(scaleX: firstPosScale.videoScale.x, y: firstPosScale.videoScale.y)
        let move = CGAffineTransform(translationX: firstPosScale.videoLocation.x, y: firstPosScale.videoLocation.y)
        let transform = rotate.concatenating(scale).concatenating(move)
        firstLayerInstruction.setTransform(transform, at: .zero)
        
    } else {
        
        let scale = CGAffineTransform(scaleX: firstPosScale.videoScale.x, y: firstPosScale.videoScale.y)
        let move = CGAffineTransform(translationX: firstPosScale.videoLocation.x, y: firstPosScale.videoLocation.y)
        let transform = scale.concatenating(move)
        firstLayerInstruction.setTransform(transform, at: .zero)
    }
Tiddlywinks answered 24/2, 2022 at 10:6 Comment(2)
hey Ramesh what is firstPosScale is your code? facing the same problemHyperbaton
@Hyperbaton yes it's custom scale value returned according to user selected option, you can just add your scaling value if you want to change scaling.Tiddlywinks

© 2022 - 2024 — McMap. All rights reserved.