Keep video rotation metadata when transcoding (#5008)
This commit is contained in:
parent
7fdbd4c24b
commit
fb318ad6fe
2 changed files with 39 additions and 16 deletions
|
|
@ -90,6 +90,7 @@ class VideoCompressor @Inject constructor(
|
||||||
val height = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toIntOrNull() ?: -1
|
val height = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toIntOrNull() ?: -1
|
||||||
val bitrate = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE)?.toLongOrNull() ?: -1
|
val bitrate = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE)?.toLongOrNull() ?: -1
|
||||||
val framerate = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE)?.toIntOrNull() ?: -1
|
val framerate = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE)?.toIntOrNull() ?: -1
|
||||||
|
val rotation = it.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)?.toIntOrNull() ?: 0
|
||||||
|
|
||||||
val (actualWidth, actualHeight) = if (width == -1 || height == -1) {
|
val (actualWidth, actualHeight) = if (width == -1 || height == -1) {
|
||||||
// Try getting the first frame instead
|
// Try getting the first frame instead
|
||||||
|
|
@ -103,7 +104,8 @@ class VideoCompressor @Inject constructor(
|
||||||
width = actualWidth,
|
width = actualWidth,
|
||||||
height = actualHeight,
|
height = actualHeight,
|
||||||
bitrate = bitrate,
|
bitrate = bitrate,
|
||||||
frameRate = framerate
|
frameRate = framerate,
|
||||||
|
rotation = rotation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
|
@ -113,10 +115,11 @@ class VideoCompressor @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class VideoFileMetadata(
|
internal data class VideoFileMetadata(
|
||||||
val width: Int?,
|
val width: Int,
|
||||||
val height: Int?,
|
val height: Int,
|
||||||
val bitrate: Long?,
|
val bitrate: Long,
|
||||||
val frameRate: Int?,
|
val frameRate: Int,
|
||||||
|
val rotation: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed interface VideoTranscodingEvent {
|
sealed interface VideoTranscodingEvent {
|
||||||
|
|
@ -136,10 +139,11 @@ internal object VideoStrategyFactory {
|
||||||
metadata: VideoFileMetadata?,
|
metadata: VideoFileMetadata?,
|
||||||
shouldBeCompressed: Boolean,
|
shouldBeCompressed: Boolean,
|
||||||
): TrackStrategy {
|
): TrackStrategy {
|
||||||
val width = metadata?.width ?: Int.MAX_VALUE
|
val width = metadata?.width?.takeIf { it >= 0 } ?: Int.MAX_VALUE
|
||||||
val height = metadata?.height ?: Int.MAX_VALUE
|
val height = metadata?.height?.takeIf { it >= 0 } ?: Int.MAX_VALUE
|
||||||
val bitrate = metadata?.bitrate
|
val bitrate = metadata?.bitrate?.takeIf { it >= 0 }
|
||||||
val frameRate = metadata?.frameRate
|
val frameRate = metadata?.frameRate?.takeIf { it >= 0 }
|
||||||
|
val rotation = metadata?.rotation?.takeIf { it >= 0 }
|
||||||
|
|
||||||
// We only create a resizer if needed
|
// We only create a resizer if needed
|
||||||
val resizer = when {
|
val resizer = when {
|
||||||
|
|
@ -148,8 +152,9 @@ internal object VideoStrategyFactory {
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (resizer == null && expectedExtension == MP4_EXTENSION) {
|
return if (resizer == null && rotation == 0 && expectedExtension == MP4_EXTENSION) {
|
||||||
// If there's no transcoding or resizing needed for the video file, just create a new file with the same contents but no metadata
|
// If there's no transcoding or resizing needed for the video file, just create a new file with the same contents but no metadata
|
||||||
|
// Rotation is not kept by the PassThroughTrackStrategy, so we need to ensure the video is not rotated
|
||||||
PassThroughTrackStrategy()
|
PassThroughTrackStrategy()
|
||||||
} else {
|
} else {
|
||||||
DefaultVideoStrategy.Builder()
|
DefaultVideoStrategy.Builder()
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class VideoStrategyFactoryTest {
|
||||||
fun `if the video should be compressed and is larger than 720p it will be transcoded`() {
|
fun `if the video should be compressed and is larger than 720p it will be transcoded`() {
|
||||||
// Given
|
// Given
|
||||||
val expectedExtension = "mp4"
|
val expectedExtension = "mp4"
|
||||||
val metadata = VideoFileMetadata(width = 1920, height = 1080, bitrate = 1_000_000, frameRate = 50)
|
val metadata = VideoFileMetadata(width = 1920, height = 1080, bitrate = 1_000_000, frameRate = 50, rotation = 0)
|
||||||
val shouldBeCompressed = true
|
val shouldBeCompressed = true
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
@ -57,7 +57,7 @@ class VideoStrategyFactoryTest {
|
||||||
fun `if the video should be compressed, has the right format and is smaller or equal to 720p it will not be transcoded`() {
|
fun `if the video should be compressed, has the right format and is smaller or equal to 720p it will not be transcoded`() {
|
||||||
// Given
|
// Given
|
||||||
val expectedExtension = "mp4"
|
val expectedExtension = "mp4"
|
||||||
val metadata = VideoFileMetadata(width = 1280, height = 720, bitrate = 1_000_000, frameRate = 50)
|
val metadata = VideoFileMetadata(width = 1280, height = 720, bitrate = 1_000_000, frameRate = 50, rotation = 0)
|
||||||
val shouldBeCompressed = true
|
val shouldBeCompressed = true
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
@ -75,7 +75,7 @@ class VideoStrategyFactoryTest {
|
||||||
fun `if the video should not be compressed and is larger than 1080p it will be transcoded`() {
|
fun `if the video should not be compressed and is larger than 1080p it will be transcoded`() {
|
||||||
// Given
|
// Given
|
||||||
val expectedExtension = "mp4"
|
val expectedExtension = "mp4"
|
||||||
val metadata = VideoFileMetadata(width = 2560, height = 1440, bitrate = 1_000_000, frameRate = 50)
|
val metadata = VideoFileMetadata(width = 2560, height = 1440, bitrate = 1_000_000, frameRate = 50, rotation = 0)
|
||||||
val shouldBeCompressed = false
|
val shouldBeCompressed = false
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
@ -93,7 +93,7 @@ class VideoStrategyFactoryTest {
|
||||||
fun `if the video should not be compressed, has the right format and is smaller or equal than 1080p it will not be transcoded`() {
|
fun `if the video should not be compressed, has the right format and is smaller or equal than 1080p it will not be transcoded`() {
|
||||||
// Given
|
// Given
|
||||||
val expectedExtension = "mp4"
|
val expectedExtension = "mp4"
|
||||||
val metadata = VideoFileMetadata(width = 1920, height = 1080, bitrate = 1_000_000, frameRate = 50)
|
val metadata = VideoFileMetadata(width = 1920, height = 1080, bitrate = 1_000_000, frameRate = 50, rotation = 0)
|
||||||
val shouldBeCompressed = false
|
val shouldBeCompressed = false
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
@ -111,7 +111,7 @@ class VideoStrategyFactoryTest {
|
||||||
fun `if the video should not be compressed but has a wrong format it will be transcoded`() {
|
fun `if the video should not be compressed but has a wrong format it will be transcoded`() {
|
||||||
// Given
|
// Given
|
||||||
val expectedExtension = "mkv"
|
val expectedExtension = "mkv"
|
||||||
val metadata = VideoFileMetadata(width = 320, height = 240, bitrate = 1_000_000, frameRate = 50)
|
val metadata = VideoFileMetadata(width = 320, height = 240, bitrate = 1_000_000, frameRate = 50, rotation = 0)
|
||||||
val shouldBeCompressed = false
|
val shouldBeCompressed = false
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
@ -129,7 +129,7 @@ class VideoStrategyFactoryTest {
|
||||||
fun `if the video should be compressed and has a wrong format it will be transcoded`() {
|
fun `if the video should be compressed and has a wrong format it will be transcoded`() {
|
||||||
// Given
|
// Given
|
||||||
val expectedExtension = "mkv"
|
val expectedExtension = "mkv"
|
||||||
val metadata = VideoFileMetadata(width = 320, height = 240, bitrate = 1_000_000, frameRate = 50)
|
val metadata = VideoFileMetadata(width = 320, height = 240, bitrate = 1_000_000, frameRate = 50, rotation = 0)
|
||||||
val shouldBeCompressed = true
|
val shouldBeCompressed = true
|
||||||
|
|
||||||
// When
|
// When
|
||||||
|
|
@ -143,6 +143,24 @@ class VideoStrategyFactoryTest {
|
||||||
assertIsTranscoded(videoStrategy)
|
assertIsTranscoded(videoStrategy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `if the video should not be compressed but has a rotation not zero it will be transcoded`() {
|
||||||
|
// Given
|
||||||
|
val expectedExtension = "mp4"
|
||||||
|
val metadata = VideoFileMetadata(width = 320, height = 240, bitrate = 1_000_000, frameRate = 50, rotation = 90)
|
||||||
|
val shouldBeCompressed = false
|
||||||
|
|
||||||
|
// When
|
||||||
|
val videoStrategy = VideoStrategyFactory.create(
|
||||||
|
expectedExtension = expectedExtension,
|
||||||
|
metadata = metadata,
|
||||||
|
shouldBeCompressed = shouldBeCompressed
|
||||||
|
)
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertIsTranscoded(videoStrategy)
|
||||||
|
}
|
||||||
|
|
||||||
private inline fun assertIsTranscoded(videoStrategy: TrackStrategy) {
|
private inline fun assertIsTranscoded(videoStrategy: TrackStrategy) {
|
||||||
assert(videoStrategy is DefaultVideoStrategy)
|
assert(videoStrategy is DefaultVideoStrategy)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue