fix videos with an orientation
This commit is contained in:
+22
-14
@@ -168,11 +168,16 @@ class VideoCompressor(
|
|||||||
encoder.start()
|
encoder.start()
|
||||||
|
|
||||||
// Set up video decoder
|
// Set up video decoder
|
||||||
val decoderFormat = videoFormat
|
// Strip rotation from decoder format so the decoder outputs frames in storage
|
||||||
|
// orientation. Some decoders apply rotation themselves when KEY_ROTATION is set,
|
||||||
|
// which double-rotates since we handle it via muxer.setOrientationHint().
|
||||||
|
if (videoFormat.containsKey(MediaFormat.KEY_ROTATION)) {
|
||||||
|
videoFormat.setInteger(MediaFormat.KEY_ROTATION, 0)
|
||||||
|
}
|
||||||
val decoder = MediaCodec.createDecoderByType(
|
val decoder = MediaCodec.createDecoderByType(
|
||||||
videoFormat.getString(MediaFormat.KEY_MIME) ?: "video/avc"
|
videoFormat.getString(MediaFormat.KEY_MIME) ?: "video/avc"
|
||||||
)
|
)
|
||||||
decoder.configure(decoderFormat, outputSurface.surface, null, 0)
|
decoder.configure(videoFormat, outputSurface.surface, null, 0)
|
||||||
decoder.start()
|
decoder.start()
|
||||||
|
|
||||||
extractor.selectTrack(videoTrackIndex)
|
extractor.selectTrack(videoTrackIndex)
|
||||||
@@ -411,26 +416,29 @@ class VideoCompressor(
|
|||||||
rotation: Int,
|
rotation: Int,
|
||||||
maxSize: Int
|
maxSize: Int
|
||||||
): Pair<Int, Int> {
|
): Pair<Int, Int> {
|
||||||
// Apply rotation to get display dimensions
|
// Use display dimensions (rotated) to determine the scale factor,
|
||||||
|
// but return storage dimensions (unrotated) for the encoder.
|
||||||
|
// The muxer's orientationHint handles rotation separately.
|
||||||
val isRotated = rotation == 90 || rotation == 270
|
val isRotated = rotation == 90 || rotation == 270
|
||||||
val sourceWidth = if (isRotated) height else width
|
val displayWidth = if (isRotated) height else width
|
||||||
val sourceHeight = if (isRotated) width else height
|
val displayHeight = if (isRotated) width else height
|
||||||
|
|
||||||
// If within bounds, keep original (rounded to even)
|
// If display dimensions within bounds, keep original storage size (rounded to even)
|
||||||
if (sourceWidth <= maxSize && sourceHeight <= maxSize) {
|
if (displayWidth <= maxSize && displayHeight <= maxSize) {
|
||||||
return Pair(roundToEven(sourceWidth), roundToEven(sourceHeight))
|
return Pair(roundToEven(width), roundToEven(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale down maintaining aspect ratio
|
// Scale based on display dimensions
|
||||||
val scale = if (sourceWidth > sourceHeight) {
|
val scale = if (displayWidth > displayHeight) {
|
||||||
maxSize.toFloat() / sourceWidth.toFloat()
|
maxSize.toFloat() / displayWidth.toFloat()
|
||||||
} else {
|
} else {
|
||||||
maxSize.toFloat() / sourceHeight.toFloat()
|
maxSize.toFloat() / displayHeight.toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return storage dimensions (unrotated)
|
||||||
return Pair(
|
return Pair(
|
||||||
roundToEven((sourceWidth * scale).toInt()),
|
roundToEven((width * scale).toInt()),
|
||||||
roundToEven((sourceHeight * scale).toInt())
|
roundToEven((height * scale).toInt())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -316,32 +316,35 @@ class VideoCompressor {
|
|||||||
transform: CGAffineTransform,
|
transform: CGAffineTransform,
|
||||||
maxSize: Int
|
maxSize: Int
|
||||||
) -> (width: Int, height: Int) {
|
) -> (width: Int, height: Int) {
|
||||||
// Apply transform to get actual display dimensions
|
// Use display dimensions (rotated) to determine the scale factor,
|
||||||
|
// but return storage dimensions (unrotated) for the encoder.
|
||||||
|
// The writer's transform handles rotation separately.
|
||||||
let isRotated = abs(transform.b) == 1.0 && abs(transform.c) == 1.0
|
let isRotated = abs(transform.b) == 1.0 && abs(transform.c) == 1.0
|
||||||
let sourceWidth = isRotated ? naturalSize.height : naturalSize.width
|
let displayWidth = isRotated ? naturalSize.height : naturalSize.width
|
||||||
let sourceHeight = isRotated ? naturalSize.width : naturalSize.height
|
let displayHeight = isRotated ? naturalSize.width : naturalSize.height
|
||||||
|
|
||||||
let maxDimension = CGFloat(maxSize)
|
let maxDimension = CGFloat(maxSize)
|
||||||
|
|
||||||
// If already within bounds, keep original size (rounded to even)
|
// If display dimensions within bounds, keep original storage size (rounded to even)
|
||||||
if sourceWidth <= maxDimension && sourceHeight <= maxDimension {
|
if displayWidth <= maxDimension && displayHeight <= maxDimension {
|
||||||
return (
|
return (
|
||||||
width: roundToEven(Int(sourceWidth)),
|
width: roundToEven(Int(naturalSize.width)),
|
||||||
height: roundToEven(Int(sourceHeight))
|
height: roundToEven(Int(naturalSize.height))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale down maintaining aspect ratio
|
// Scale based on display dimensions
|
||||||
let scale: CGFloat
|
let scale: CGFloat
|
||||||
if sourceWidth > sourceHeight {
|
if displayWidth > displayHeight {
|
||||||
scale = maxDimension / sourceWidth
|
scale = maxDimension / displayWidth
|
||||||
} else {
|
} else {
|
||||||
scale = maxDimension / sourceHeight
|
scale = maxDimension / displayHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return storage dimensions (unrotated)
|
||||||
return (
|
return (
|
||||||
width: roundToEven(Int(sourceWidth * scale)),
|
width: roundToEven(Int(naturalSize.width * scale)),
|
||||||
height: roundToEven(Int(sourceHeight * scale))
|
height: roundToEven(Int(naturalSize.height * scale))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user