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 478fd41e..40b7f995 100644 --- a/demo/src/main/java/com/otaliastudios/transcoder/demo/TranscoderActivity.java +++ b/demo/src/main/java/com/otaliastudios/transcoder/demo/TranscoderActivity.java @@ -3,10 +3,12 @@ import android.annotation.SuppressLint; import android.content.ClipData; import android.content.Intent; -import android.media.MediaMuxer; import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; +import android.text.Editable; +import android.text.TextWatcher; +import android.widget.EditText; import android.widget.ProgressBar; import android.widget.RadioGroup; import android.widget.TextView; @@ -61,6 +63,8 @@ public class TranscoderActivity extends AppCompatActivity implements private ProgressBar mProgressView; private TextView mButtonView; + private EditText mTrimStartView; + private EditText mTrimEndView; private TextView mAudioReplaceView; private boolean mIsTranscoding; @@ -74,6 +78,52 @@ public class TranscoderActivity extends AppCompatActivity implements private long mTranscodeStartTime; private TrackStrategy mTranscodeVideoStrategy; private TrackStrategy mTranscodeAudioStrategy; + private long mTrimStartUs = 0; + private long mTrimEndUs = 0; + + private TextWatcher mTrimStartTextWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + try { + mTrimStartUs = Long.valueOf(s.toString()) * 1000000; + } catch (NumberFormatException e) { + mTrimStartUs = 0; + LOG.w("Failed to read trimStart value."); + } + } + } + }; + private TextWatcher mTrimEndTextWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + try { + mTrimEndUs = Long.valueOf(s.toString()) * 1000000; + } catch (NumberFormatException e) { + mTrimEndUs = 0; + LOG.w("Failed to read trimEnd value."); + } + } + } + }; + @SuppressLint("SetTextI18n") @Override @@ -97,6 +147,8 @@ protected void onCreate(Bundle savedInstanceState) { mProgressView = findViewById(R.id.progress); mProgressView.setMax(PROGRESS_BAR_MAX); + mTrimStartView = findViewById(R.id.trim_start); + mTrimEndView = findViewById(R.id.trim_end); mAudioReplaceView = findViewById(R.id.replace_info); mAudioChannelsGroup = findViewById(R.id.channels); @@ -113,6 +165,8 @@ protected void onCreate(Bundle savedInstanceState) { mVideoResolutionGroup.setOnCheckedChangeListener(this); mVideoAspectGroup.setOnCheckedChangeListener(this); mAudioSampleRateGroup.setOnCheckedChangeListener(this); + mTrimStartView.addTextChangedListener(mTrimStartTextWatcher); + mTrimEndView.addTextChangedListener(mTrimEndTextWatcher); syncParameters(); mAudioReplaceGroup.setOnCheckedChangeListener((group, checkedId) -> { @@ -257,13 +311,27 @@ private void transcode() { DataSink sink = new DefaultDataSink(mTranscodeOutputFile.getAbsolutePath()); TranscoderOptions.Builder builder = Transcoder.into(sink); if (mAudioReplacementUri == null) { - if (mTranscodeInputUri1 != null) builder.addDataSource(this, mTranscodeInputUri1); - if (mTranscodeInputUri2 != null) builder.addDataSource(this, mTranscodeInputUri2); - if (mTranscodeInputUri3 != null) builder.addDataSource(this, mTranscodeInputUri3); + if (mTrimStartUs > 0 || mTrimEndUs > 0) { + if (mTranscodeInputUri1 != null) builder.addDataSource(this, mTranscodeInputUri1, mTrimStartUs, mTrimEndUs); + if (mTranscodeInputUri2 != null) builder.addDataSource(this, mTranscodeInputUri2, mTrimStartUs, mTrimEndUs); + if (mTranscodeInputUri3 != null) builder.addDataSource(this, mTranscodeInputUri3, mTrimStartUs, mTrimEndUs); + } + else { + if (mTranscodeInputUri1 != null) builder.addDataSource(this, mTranscodeInputUri1); + if (mTranscodeInputUri2 != null) builder.addDataSource(this, mTranscodeInputUri2); + if (mTranscodeInputUri3 != null) builder.addDataSource(this, mTranscodeInputUri3); + } } else { - if (mTranscodeInputUri1 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri1); - if (mTranscodeInputUri2 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri2); - if (mTranscodeInputUri3 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri3); + if (mTrimStartUs > 0 || mTrimEndUs > 0) { + if (mTranscodeInputUri1 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri1, mTrimStartUs, mTrimEndUs); + if (mTranscodeInputUri2 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri2, mTrimStartUs, mTrimEndUs); + if (mTranscodeInputUri3 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri3, mTrimStartUs, mTrimEndUs); + } + else { + if (mTranscodeInputUri1 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri1); + if (mTranscodeInputUri2 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri2); + if (mTranscodeInputUri3 != null) builder.addDataSource(TrackType.VIDEO, this, mTranscodeInputUri3); + } builder.addDataSource(TrackType.AUDIO, this, mAudioReplacementUri); } mTranscodeFuture = builder.setListener(this) diff --git a/demo/src/main/res/layout/activity_transcoder.xml b/demo/src/main/res/layout/activity_transcoder.xml index e142c221..9cbcafb7 100644 --- a/demo/src/main/res/layout/activity_transcoder.xml +++ b/demo/src/main/res/layout/activity_transcoder.xml @@ -285,6 +285,55 @@ android:layout_height="wrap_content" /> + + + + + + + + + + + + + + duration) { + throw new IllegalArgumentException("Trim values cannot be greater than media duration."); + } + return duration - trimStart - trimEnd; + } + + @Override + public int getOrientation() { + return source.getOrientation(); + } + + @Nullable + @Override + public double[] getLocation() { + return source.getLocation(); + } + + @Override + public long getDurationUs() { + return trimDurationUs; + } + + @Nullable + @Override + public MediaFormat getTrackFormat(@NonNull TrackType type) { + return source.getTrackFormat(type); + } + + @Override + public void selectTrack(@NonNull TrackType type) { + source.selectTrack(type); + } + + @Override + public long seekBy(long durationUs) { + return source.seekBy(durationUs); + } + + @Override + public boolean canReadTrack(@NonNull TrackType type) { + if (!didSeekTracks) { + final long sampleTimeUs = seekBy(trimStartUs); + updateTrimValues(sampleTimeUs); + didSeekTracks = true; + } + return source.canReadTrack(type); + } + + private void updateTrimValues(long timestampUs) { + trimDurationUs += trimStartUs - timestampUs; + trimStartUs = timestampUs; + } + + @Override + public void readTrack(@NonNull Chunk chunk) { + source.readTrack(chunk); + } + + @Override + public long getReadUs() { + return source.getReadUs(); + } + + @Override + public boolean isDrained() { + return source.isDrained() || getReadUs() >= getDurationUs(); + } + + @Override + public void releaseTrack(@NonNull TrackType type) { + source.releaseTrack(type); + } + + @Override + public void rewind() { + didSeekTracks = false; + source.rewind(); + } +}