diff --git a/demo/src/main/java/com/otaliastudios/transcoder/demo/TranscoderActivity.java b/demo/src/main/java/com/otaliastudios/transcoder/demo/TranscoderActivity.java index f5e70b86..6702624c 100644 --- a/demo/src/main/java/com/otaliastudios/transcoder/demo/TranscoderActivity.java +++ b/demo/src/main/java/com/otaliastudios/transcoder/demo/TranscoderActivity.java @@ -20,6 +20,10 @@ import com.otaliastudios.transcoder.engine.TrackStatus; import com.otaliastudios.transcoder.engine.TrackType; import com.otaliastudios.transcoder.internal.Logger; +import com.otaliastudios.transcoder.scale.DownVideoScaler; +import com.otaliastudios.transcoder.scale.StretchVideoScaler; +import com.otaliastudios.transcoder.scale.UpVideoScaler; +import com.otaliastudios.transcoder.scale.VideoScaler; import com.otaliastudios.transcoder.sink.DataSink; import com.otaliastudios.transcoder.sink.DefaultDataSink; import com.otaliastudios.transcoder.source.DataSource; @@ -59,6 +63,7 @@ public class TranscoderActivity extends AppCompatActivity implements private RadioGroup mVideoFramesGroup; private RadioGroup mVideoResolutionGroup; private RadioGroup mVideoAspectGroup; + private RadioGroup mVideoScalingGroup; private RadioGroup mVideoRotationGroup; private RadioGroup mSpeedGroup; private RadioGroup mAudioReplaceGroup; @@ -134,6 +139,7 @@ protected void onCreate(Bundle savedInstanceState) { mVideoFramesGroup = findViewById(R.id.frames); mVideoResolutionGroup = findViewById(R.id.resolution); mVideoAspectGroup = findViewById(R.id.aspect); + mVideoScalingGroup = findViewById(R.id.scale); mVideoRotationGroup = findViewById(R.id.rotation); mSpeedGroup = findViewById(R.id.speed); mAudioSampleRateGroup = findViewById(R.id.sampleRate); @@ -143,6 +149,7 @@ protected void onCreate(Bundle savedInstanceState) { mVideoFramesGroup.setOnCheckedChangeListener(mRadioGroupListener); mVideoResolutionGroup.setOnCheckedChangeListener(mRadioGroupListener); mVideoAspectGroup.setOnCheckedChangeListener(mRadioGroupListener); + mVideoScalingGroup.setOnCheckedChangeListener(mRadioGroupListener); mAudioSampleRateGroup.setOnCheckedChangeListener(mRadioGroupListener); mTrimStartView.addTextChangedListener(mTextListener); mTrimEndView.addTextChangedListener(mTextListener); @@ -296,11 +303,18 @@ private void transcode() { default: speed = 1F; } + VideoScaler videoScaler; + switch (mVideoScalingGroup.getCheckedRadioButtonId()) { + case R.id.scale_down: videoScaler = new DownVideoScaler(); break; + case R.id.scale_stretch: videoScaler = new StretchVideoScaler(); break; + default: videoScaler = new UpVideoScaler(); break; + } + // Launch the transcoding operation. mTranscodeStartTime = SystemClock.uptimeMillis(); setIsTranscoding(true); DataSink sink = new DefaultDataSink(mTranscodeOutputFile.getAbsolutePath()); - TranscoderOptions.Builder builder = Transcoder.into(sink); + TranscoderOptions.Builder builder = Transcoder.into(sink).setVideoScaler(videoScaler); if (mAudioReplacementUri == null) { if (mTranscodeInputUri1 != null) { DataSource source = new UriDataSource(this, mTranscodeInputUri1); diff --git a/demo/src/main/res/layout/activity_transcoder.xml b/demo/src/main/res/layout/activity_transcoder.xml index 8034a75c..87ccda03 100644 --- a/demo/src/main/res/layout/activity_transcoder.xml +++ b/demo/src/main/res/layout/activity_transcoder.xml @@ -205,6 +205,42 @@ android:layout_height="wrap_content" /> + + + + + + + + audioDataSources = new ArrayList<>(); @@ -117,6 +125,7 @@ public static class Builder { private TimeInterpolator timeInterpolator; private AudioStretcher audioStretcher; private AudioResampler audioResampler; + private VideoScaler videoScaler; Builder(@NonNull String outPath) { this.dataSink = new DefaultDataSink(outPath); @@ -199,13 +208,13 @@ public Builder setAudioTrackStrategy(@Nullable TrackStrategy trackStrategy) { * Sets the video output strategy. If absent, this defaults to the 16:9 * strategy returned by {@link DefaultVideoStrategies#for720x1280()}. * - * @param trackStrategy the desired strategy + * @param videoTrackStrategy the desired strategy * @return this for chaining */ @NonNull @SuppressWarnings("unused") - public Builder setVideoTrackStrategy(@Nullable TrackStrategy trackStrategy) { - this.videoTrackStrategy = trackStrategy; + public Builder setVideoTrackStrategy(@Nullable TrackStrategy videoTrackStrategy) { + this.videoTrackStrategy = videoTrackStrategy; return this; } @@ -318,6 +327,18 @@ public Builder setAudioResampler(@NonNull AudioResampler audioResampler) { return this; } + /** + * Set an {@link VideoScaler} to change the resolution of the video frames + * so that they fit the new resolution + * + */ + @NonNull + @SuppressWarnings("unused") + public Builder setVideoScaler(@NonNull VideoScaler videoScaler) { + this.videoScaler = videoScaler; + return this; + } + /** * Generates muted audio data sources if needed * @return The list of audio data sources including the muted sources @@ -389,6 +410,9 @@ public TranscoderOptions build() { if (audioResampler == null) { audioResampler = new DefaultAudioResampler(); } + if (videoScaler == null) { + videoScaler = new UpVideoScaler(); + } TranscoderOptions options = new TranscoderOptions(); options.listener = listener; options.audioDataSources = buildAudioDataSources(); @@ -402,6 +426,7 @@ public TranscoderOptions build() { options.timeInterpolator = timeInterpolator; options.audioStretcher = audioStretcher; options.audioResampler = audioResampler; + options.videoScaler = videoScaler; return options; } diff --git a/lib/src/main/java/com/otaliastudios/transcoder/engine/Engine.java b/lib/src/main/java/com/otaliastudios/transcoder/engine/Engine.java index 742fd1cf..18e2e683 100644 --- a/lib/src/main/java/com/otaliastudios/transcoder/engine/Engine.java +++ b/lib/src/main/java/com/otaliastudios/transcoder/engine/Engine.java @@ -171,6 +171,7 @@ private void openCurrentStep(@NonNull TrackType type, @NonNull TranscoderOptions case VIDEO: transcoder = new VideoTrackTranscoder(dataSource, mDataSink, interpolator, + options.getVideoScaler(), options.getVideoRotation()); break; case AUDIO: diff --git a/lib/src/main/java/com/otaliastudios/transcoder/scale/DownVideoScaler.java b/lib/src/main/java/com/otaliastudios/transcoder/scale/DownVideoScaler.java new file mode 100644 index 00000000..b239dc23 --- /dev/null +++ b/lib/src/main/java/com/otaliastudios/transcoder/scale/DownVideoScaler.java @@ -0,0 +1,20 @@ +package com.otaliastudios.transcoder.scale; + +import androidx.annotation.NonNull; + +import com.otaliastudios.transcoder.transcode.internal.VideoDecoderOutput; + +/** + * An {@link VideoScaler} that scale the video down so that no side exceed the new resolution + * Sides that are too small will have black borders + */ +public class DownVideoScaler implements VideoScaler { + @Override + public void scaleOutput(@NonNull VideoDecoderOutput videoDecoderOutput, float scaleX, float scaleY, boolean flipped) { + if (flipped) { // The drawable is not affected by the flip so we need to reverse it + videoDecoderOutput.setDrawableScale(1.0F / scaleX, 1.0F / scaleY); + } else { + videoDecoderOutput.setDrawableScale(1.0F / scaleY, 1.0F / scaleX); + } + } +} \ No newline at end of file diff --git a/lib/src/main/java/com/otaliastudios/transcoder/scale/StretchVideoScaler.java b/lib/src/main/java/com/otaliastudios/transcoder/scale/StretchVideoScaler.java new file mode 100644 index 00000000..8862f229 --- /dev/null +++ b/lib/src/main/java/com/otaliastudios/transcoder/scale/StretchVideoScaler.java @@ -0,0 +1,16 @@ +package com.otaliastudios.transcoder.scale; + +import androidx.annotation.NonNull; + +import com.otaliastudios.transcoder.transcode.internal.VideoDecoderOutput; + +/** + * An {@link VideoScaler} that strech the video so that they match the video resolution + * at the cost of deforming the images + */ +public class StretchVideoScaler implements VideoScaler { + @Override + public void scaleOutput(@NonNull VideoDecoderOutput videoDecoderOutput, float scaleX, float scaleY, boolean flipped) { + //No scaling will automatically stretch the frames to fill all the drawable space + } +} \ No newline at end of file diff --git a/lib/src/main/java/com/otaliastudios/transcoder/scale/UpVideoScaler.java b/lib/src/main/java/com/otaliastudios/transcoder/scale/UpVideoScaler.java new file mode 100644 index 00000000..444eab65 --- /dev/null +++ b/lib/src/main/java/com/otaliastudios/transcoder/scale/UpVideoScaler.java @@ -0,0 +1,16 @@ +package com.otaliastudios.transcoder.scale; + +import androidx.annotation.NonNull; + +import com.otaliastudios.transcoder.transcode.internal.VideoDecoderOutput; + +/** + * An {@link VideoScaler} that scale the video up so that it touches all sides + * of the new resolution and exceeding parts will be truncated + */ +public class UpVideoScaler implements VideoScaler { + @Override + public void scaleOutput(@NonNull VideoDecoderOutput videoDecoderOutput, float scaleX, float scaleY, boolean flipped) { + videoDecoderOutput.setScale(scaleX, scaleY); + } +} diff --git a/lib/src/main/java/com/otaliastudios/transcoder/scale/VideoScaler.java b/lib/src/main/java/com/otaliastudios/transcoder/scale/VideoScaler.java new file mode 100644 index 00000000..b012361f --- /dev/null +++ b/lib/src/main/java/com/otaliastudios/transcoder/scale/VideoScaler.java @@ -0,0 +1,22 @@ +package com.otaliastudios.transcoder.scale; + +import androidx.annotation.NonNull; + +import com.otaliastudios.transcoder.transcode.internal.VideoDecoderOutput; + +/** + * Scale the frames when they are not of the expected resolution + */ +public interface VideoScaler { + /** + * Apply the scaling to the video decoder output + * + * It can be done using VideoDecoderOutput.setScale or VideoDecoderOutput.setDrawableScale + * + * @param videoDecoderOutput the video decoder output + * @param scaleX the input width/height + * @param scaleY the output width/height + * @param flipped whether or not the frame was rotated by 90 degrees + */ + void scaleOutput(@NonNull VideoDecoderOutput videoDecoderOutput, float scaleX, float scaleY, boolean flipped); +} diff --git a/lib/src/main/java/com/otaliastudios/transcoder/strategy/DefaultVideoStrategy.java b/lib/src/main/java/com/otaliastudios/transcoder/strategy/DefaultVideoStrategy.java index bbab7255..5335b3ed 100644 --- a/lib/src/main/java/com/otaliastudios/transcoder/strategy/DefaultVideoStrategy.java +++ b/lib/src/main/java/com/otaliastudios/transcoder/strategy/DefaultVideoStrategy.java @@ -16,6 +16,7 @@ import com.otaliastudios.transcoder.strategy.size.Resizer; import com.otaliastudios.transcoder.internal.Logger; import com.otaliastudios.transcoder.internal.MediaFormatConstants; +import com.otaliastudios.transcoder.transcode.internal.VideoDecoderOutput; import androidx.annotation.NonNull; diff --git a/lib/src/main/java/com/otaliastudios/transcoder/strategy/TrackStrategy.java b/lib/src/main/java/com/otaliastudios/transcoder/strategy/TrackStrategy.java index fa2df2a4..a2210e51 100644 --- a/lib/src/main/java/com/otaliastudios/transcoder/strategy/TrackStrategy.java +++ b/lib/src/main/java/com/otaliastudios/transcoder/strategy/TrackStrategy.java @@ -2,12 +2,11 @@ import android.media.MediaFormat; +import androidx.annotation.NonNull; + import com.otaliastudios.transcoder.engine.TrackStatus; import com.otaliastudios.transcoder.strategy.size.Resizer; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - import java.util.List; /** diff --git a/lib/src/main/java/com/otaliastudios/transcoder/transcode/VideoTrackTranscoder.java b/lib/src/main/java/com/otaliastudios/transcoder/transcode/VideoTrackTranscoder.java index 1f782566..c4e1e573 100644 --- a/lib/src/main/java/com/otaliastudios/transcoder/transcode/VideoTrackTranscoder.java +++ b/lib/src/main/java/com/otaliastudios/transcoder/transcode/VideoTrackTranscoder.java @@ -16,20 +16,20 @@ package com.otaliastudios.transcoder.transcode; import android.media.MediaCodec; -import android.media.MediaExtractor; import android.media.MediaFormat; import androidx.annotation.NonNull; import com.otaliastudios.transcoder.engine.TrackType; +import com.otaliastudios.transcoder.internal.Logger; import com.otaliastudios.transcoder.internal.MediaCodecBuffers; +import com.otaliastudios.transcoder.internal.MediaFormatConstants; +import com.otaliastudios.transcoder.scale.VideoScaler; import com.otaliastudios.transcoder.sink.DataSink; import com.otaliastudios.transcoder.source.DataSource; import com.otaliastudios.transcoder.time.TimeInterpolator; import com.otaliastudios.transcoder.transcode.internal.VideoDecoderOutput; import com.otaliastudios.transcoder.transcode.internal.VideoEncoderInput; -import com.otaliastudios.transcoder.internal.Logger; -import com.otaliastudios.transcoder.internal.MediaFormatConstants; import com.otaliastudios.transcoder.transcode.internal.VideoFrameDropper; import java.nio.ByteBuffer; @@ -46,6 +46,7 @@ public class VideoTrackTranscoder extends BaseTrackTranscoder { private MediaCodec mEncoder; // Keep this since we want to signal EOS on it. private VideoFrameDropper mFrameDropper; private final TimeInterpolator mTimeInterpolator; + private final VideoScaler mVideoScaler; private final int mSourceRotation; private final int mExtraRotation; @@ -53,9 +54,11 @@ public VideoTrackTranscoder( @NonNull DataSource dataSource, @NonNull DataSink dataSink, @NonNull TimeInterpolator timeInterpolator, + @NonNull VideoScaler videoScaler, int rotation) { super(dataSource, dataSink, TrackType.VIDEO); mTimeInterpolator = timeInterpolator; + mVideoScaler = videoScaler; mSourceRotation = dataSource.getOrientation(); mExtraRotation = rotation; } @@ -130,7 +133,7 @@ protected void onCodecsStarted(@NonNull MediaFormat inputFormat, @NonNull MediaF } else if (inputRatio < outputRatio) { // Input taller. We have a scaleY. scaleY = outputRatio / inputRatio; } - mDecoderOutputSurface.setScale(scaleX, scaleY); + mVideoScaler.scaleOutput(mDecoderOutputSurface, scaleX, scaleY, flip); } @Override diff --git a/lib/src/main/java/com/otaliastudios/transcoder/transcode/internal/VideoDecoderOutput.java b/lib/src/main/java/com/otaliastudios/transcoder/transcode/internal/VideoDecoderOutput.java index 7f052561..efa20220 100644 --- a/lib/src/main/java/com/otaliastudios/transcoder/transcode/internal/VideoDecoderOutput.java +++ b/lib/src/main/java/com/otaliastudios/transcoder/transcode/internal/VideoDecoderOutput.java @@ -87,6 +87,21 @@ public void setScale(float scaleX, float scaleY) { mScaleY = scaleY; } + /** + * Scale the canvas along the two axes. + * @param scaleX x scale + * @param scaleY y scale + */ + @SuppressWarnings("unused") + public void setDrawableScale(float scaleX, float scaleY) { + mDrawable.setRect( + -1.0F * scaleX, + -1.0F * scaleY, + 1.0F * scaleX, + 1.0F * scaleY + ); + } + /** * Sets the desired frame rotation with respect * to its natural orientation. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy