diff --git a/lib/src/androidTest/assets/issue_215/bbb_720p_1sec.mp4 b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec.mp4 new file mode 100644 index 00000000..9d2ead42 Binary files /dev/null and b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec.mp4 differ diff --git a/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r180.mp4 b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r180.mp4 new file mode 100644 index 00000000..126f5301 Binary files /dev/null and b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r180.mp4 differ diff --git a/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r270.mp4 b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r270.mp4 new file mode 100644 index 00000000..df44f9e1 Binary files /dev/null and b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r270.mp4 differ diff --git a/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r90.mp4 b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r90.mp4 new file mode 100644 index 00000000..2727c129 Binary files /dev/null and b/lib/src/androidTest/assets/issue_215/bbb_720p_1sec_r90.mp4 differ diff --git a/lib/src/androidTest/java/com/otaliastudios/transcoder/integration/IssuesTests.kt b/lib/src/androidTest/java/com/otaliastudios/transcoder/integration/IssuesTests.kt index 1ed497a8..028c9348 100644 --- a/lib/src/androidTest/java/com/otaliastudios/transcoder/integration/IssuesTests.kt +++ b/lib/src/androidTest/java/com/otaliastudios/transcoder/integration/IssuesTests.kt @@ -10,10 +10,12 @@ import com.otaliastudios.transcoder.TranscoderListener import com.otaliastudios.transcoder.TranscoderOptions import com.otaliastudios.transcoder.common.TrackType import com.otaliastudios.transcoder.internal.utils.Logger +import com.otaliastudios.transcoder.resize.AspectRatioResizer import com.otaliastudios.transcoder.source.AssetFileDescriptorDataSource import com.otaliastudios.transcoder.source.BlankAudioDataSource import com.otaliastudios.transcoder.source.ClipDataSource import com.otaliastudios.transcoder.source.FileDescriptorDataSource +import com.otaliastudios.transcoder.source.FilePathDataSource import com.otaliastudios.transcoder.strategy.DefaultAudioStrategy import com.otaliastudios.transcoder.strategy.DefaultVideoStrategy import com.otaliastudios.transcoder.validator.WriteAlwaysValidator @@ -22,6 +24,7 @@ import org.junit.AssumptionViolatedException import org.junit.Test import org.junit.runner.RunWith import java.io.File +import kotlin.math.roundToInt @RunWith(AndroidJUnit4::class) class IssuesTests { @@ -76,6 +79,64 @@ class IssuesTests { } throw it } + fun getRotation(file:File) : Int { + val outputDataSource = FilePathDataSource(file.absolutePath) + var displayRotation = 0 + try{ + outputDataSource.initialize() + val mediaFormat = outputDataSource.getTrackFormat(TrackType.VIDEO) ?: throw NullPointerException("MediaFormat is null") + displayRotation = mediaFormat.getInteger(MediaFormat.KEY_ROTATION) + }catch (_:Exception){ + + }finally { + outputDataSource.deinitialize() + } + return displayRotation + } + fun getRotation(fd:AssetFileDescriptorDataSource) : Int { + var displayRotation = 0 + try{ + fd.initialize() + val mediaFormat = fd.getTrackFormat(TrackType.VIDEO) ?: throw NullPointerException("MediaFormat is null") + displayRotation = mediaFormat.getInteger(MediaFormat.KEY_ROTATION) + }catch (_:Exception){ + + }finally { + fd.deinitialize() + } + return displayRotation + } + fun getFrameSize(fd:AssetFileDescriptorDataSource): Pair{ + var outputWidth = 0 + var outputHeight = 0 + try{ + fd.initialize() + val mediaFormat = fd.getTrackFormat(TrackType.VIDEO) ?: throw NullPointerException("MediaFormat is null") + outputWidth = mediaFormat.getInteger(MediaFormat.KEY_WIDTH) + outputHeight = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT) + }catch (ex:Exception){ + throw Exception("Get video size\n${ex.localizedMessage}") + }finally { + fd.deinitialize() + } + return Pair(outputWidth, outputHeight) + } + fun getFrameSize(file:File) : Pair { + val outputDataSource = FilePathDataSource(file.absolutePath) + var outputWidth = 0 + var outputHeight = 0 + try{ + outputDataSource.initialize() + val mediaFormat = outputDataSource.getTrackFormat(TrackType.VIDEO) ?: throw NullPointerException("MediaFormat is null") + outputWidth = mediaFormat.getInteger(MediaFormat.KEY_WIDTH) + outputHeight = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT) + }catch (ex:Exception){ + throw Exception("Get video size\n${ex.localizedMessage}") + }finally { + outputDataSource.deinitialize() + } + return Pair(outputWidth, outputHeight) + } } @@ -151,4 +212,31 @@ class IssuesTests { } Unit } + @Test + fun issue215() = with(Helper(215)){ + //Display rotation 0, 90, 180, 270 + val rotations = listOf(0,270,180,90) + val videoNames = listOf("bbb_720p_1sec.mp4", "bbb_720p_1sec_r90.mp4", "bbb_720p_1sec_r180.mp4", "bbb_720p_1sec_r270.mp4") + videoNames.forEachIndexed { i, videoName -> + val inputVideoSize = getFrameSize(input(videoName)) + val inputRatio = inputVideoSize.first.toFloat() / inputVideoSize.second.toFloat() + check(inputRatio > 1f){"Input video ($videoName) ratio is: $inputRatio but expected: greater then 1"} + val inputRotation = getRotation(input(videoName)) + check(inputRotation == rotations[i]) {"Input video ($videoName) display rotation is: $inputRotation but expected: ${rotations[i]}"} + val expectedOutputRatio = 0.5f + val outputVideo = transcode { + val vds = input(videoName) + addDataSource(vds) + val videoTrackStrategy = DefaultVideoStrategy.Builder() + videoTrackStrategy.addResizer(AspectRatioResizer(expectedOutputRatio)) + setVideoTrackStrategy(videoTrackStrategy.build()) + } + val outputRotation = getRotation(outputVideo) + val outputVideoSize = getFrameSize(outputVideo) + val outputRatio = ((outputVideoSize.first.toFloat() / outputVideoSize.second.toFloat()) * 10).roundToInt() / 10f + check(outputRatio == expectedOutputRatio) {"Output ratio is: $outputRatio but expects: $expectedOutputRatio (input video[$i]: $videoName)"} + check(outputRotation == 0) {"Output video display rotation is: $outputRotation but expected: 0 (input video[$i]: $videoName)"} + println("$videoName (rotation: $outputRotation expected: 0), inputRatio: $inputRatio (${inputVideoSize.first}x${inputVideoSize.second}) expectedOutputRatio: $expectedOutputRatio (${outputVideoSize.first}x${outputVideoSize.second}) OK") + } + } } \ No newline at end of file diff --git a/lib/src/main/java/com/otaliastudios/transcoder/common/Size.java b/lib/src/main/java/com/otaliastudios/transcoder/common/Size.java index e17f9f31..f5c395f9 100644 --- a/lib/src/main/java/com/otaliastudios/transcoder/common/Size.java +++ b/lib/src/main/java/com/otaliastudios/transcoder/common/Size.java @@ -9,6 +9,8 @@ public class Size { private final int mMajor; private final int mMinor; + private final int mFirst; + private final int mSecond; /** * The order does not matter. @@ -19,6 +21,8 @@ public class Size { public Size(int firstSize, int secondSize) { mMajor = Math.max(firstSize, secondSize); mMinor = Math.min(firstSize, secondSize); + mFirst = firstSize; + mSecond = secondSize; } public int getMinor() { @@ -28,4 +32,12 @@ public int getMinor() { public int getMajor() { return mMajor; } + public int getFirst() { + return mFirst; + } + + public int getSecond() { + return mSecond; + } + } diff --git a/lib/src/main/java/com/otaliastudios/transcoder/resize/AspectRatioResizer.java b/lib/src/main/java/com/otaliastudios/transcoder/resize/AspectRatioResizer.java index ee0f3250..9a03b008 100644 --- a/lib/src/main/java/com/otaliastudios/transcoder/resize/AspectRatioResizer.java +++ b/lib/src/main/java/com/otaliastudios/transcoder/resize/AspectRatioResizer.java @@ -2,6 +2,7 @@ import androidx.annotation.NonNull; +import com.otaliastudios.transcoder.common.ExactSize; import com.otaliastudios.transcoder.common.Size; import com.otaliastudios.transcoder.resize.Resizer; @@ -24,17 +25,15 @@ public AspectRatioResizer(float aspectRatio) { @NonNull @Override public Size getOutputSize(@NonNull Size inputSize) { - float inputRatio = (float) inputSize.getMajor() / inputSize.getMinor(); - float outputRatio = aspectRatio > 1 ? aspectRatio : 1F / aspectRatio; - // now both are greater than 1 (major / minor). - if (inputRatio > outputRatio) { - // input is "wider". We must reduce the input major dimension. - return new Size(inputSize.getMinor(), (int) (outputRatio * inputSize.getMinor())); - } else if (inputRatio < outputRatio) { - // input is more square. We must reduce the input minor dimension. - return new Size(inputSize.getMajor(), (int) (inputSize.getMajor() / outputRatio)); - } else { - return inputSize; + float inputRatio = (float) inputSize.getFirst() / inputSize.getSecond(); + if(inputRatio > aspectRatio){ + int outputFirst = (int)(aspectRatio * ((float) inputSize.getSecond())); + return new ExactSize(outputFirst, inputSize.getSecond()); + }else if(inputRatio < aspectRatio){ + int outputSecond = (int)(((float) inputSize.getFirst()) / aspectRatio); + return new ExactSize(inputSize.getFirst(), outputSecond); + }else{ + return new ExactSize(inputSize.getFirst(), inputSize.getSecond()); } } }