diff --git a/app/src/main/java/protect/videotranscoder/activity/MainActivity.java b/app/src/main/java/protect/videotranscoder/activity/MainActivity.java
index 707db3eb..1a51b421 100644
--- a/app/src/main/java/protect/videotranscoder/activity/MainActivity.java
+++ b/app/src/main/java/protect/videotranscoder/activity/MainActivity.java
@@ -31,6 +31,7 @@
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
@@ -75,6 +76,7 @@ public class MainActivity extends AppCompatActivity
public static final String MESSENGER_INTENT_KEY = BuildConfig.APPLICATION_ID + ".MESSENGER_INTENT_KEY";
public static final String FFMPEG_ENCODE_ARGS = BuildConfig.APPLICATION_ID + ".FFMPEG_ENCODE_ARGS";
public static final String FFMPEG_OUTPUT_FILE = BuildConfig.APPLICATION_ID + ".FFMPEG_OUTPUT_FILE";
+ public static final String FFMPEG_FAILURE_MSG = BuildConfig.APPLICATION_ID + ".FFMPEG_FAILURE_MSG";
public static final String OUTPUT_MIMETYPE = BuildConfig.APPLICATION_ID + ".OUTPUT_MIMETYPE";
public static final String OUTPUT_DURATION_MS = BuildConfig.APPLICATION_ID + ".OUTPUT_DURATION_MS";
@@ -128,6 +130,10 @@ public class MainActivity extends AppCompatActivity
private Button selectVideoButton;
private Button encodeButton;
private Button cancelButton;
+ private ImageView startJumpBack;
+ private ImageView startJumpForward;
+ private ImageView endJumpBack;
+ private ImageView endJumpForward;
private MediaInfo videoInfo;
private JobScheduler schedulerService;
@@ -145,6 +151,11 @@ protected void onCreate(Bundle savedInstanceState)
encodeButton = findViewById(R.id.encode);
cancelButton = findViewById(R.id.cancel);
+ startJumpBack = findViewById(R.id.startJumpBack);
+ startJumpForward = findViewById(R.id.startJumpForward);
+ endJumpBack = findViewById(R.id.endJumpBack);
+ endJumpForward = findViewById(R.id.endJumpForward);
+
tvLeft = findViewById(R.id.tvLeft);
tvRight = findViewById(R.id.tvRight);
@@ -520,10 +531,28 @@ private void updateUiForEncoding()
selectVideoButton.setVisibility(View.GONE);
encodeButton.setVisibility(View.GONE);
+ startJumpBack.setVisibility(View.GONE);
+ startJumpForward.setVisibility(View.GONE);
+ endJumpBack.setVisibility(View.GONE);
+ endJumpForward.setVisibility(View.GONE);
+
cancelButton.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.VISIBLE);
}
+ private void updateUiForVideoSettings()
+ {
+ selectVideoButton.setVisibility(View.VISIBLE);
+ encodeButton.setVisibility(View.VISIBLE);
+ startJumpBack.setVisibility(View.VISIBLE);
+ startJumpForward.setVisibility(View.VISIBLE);
+ endJumpBack.setVisibility(View.VISIBLE);
+ endJumpForward.setVisibility(View.VISIBLE);
+
+ cancelButton.setVisibility(View.GONE);
+ progressBar.setVisibility(View.GONE);
+ }
+
private void cancelEncode()
{
FFmpegUtil.cancelCall();
@@ -536,6 +565,8 @@ private void cancelEncode()
}
scheduler.cancelAll();
+
+ updateUiForVideoSettings();
}
private boolean isEncoding()
@@ -553,15 +584,21 @@ private void stopVideoPlayback()
}
}
- private void startVideoPlayback()
+ private void startVideoPlayback(Integer positionSec)
{
stopVideoPlayback();
int startTimeSec = rangeSeekBar.getSelectedMinValue().intValue();
int stopTimeSec = rangeSeekBar.getSelectedMaxValue().intValue();
- int durationSec = stopTimeSec - startTimeSec;
- videoView.seekTo(startTimeSec * 1000);
+ if(positionSec == null)
+ {
+ positionSec = startTimeSec;
+ }
+
+ int durationSec = stopTimeSec - positionSec;
+
+ videoView.seekTo(positionSec * 1000);
videoView.start();
videoTimer = new Timer();
@@ -570,7 +607,7 @@ private void startVideoPlayback()
@Override
public void run()
{
- startVideoPlayback();
+ startVideoPlayback(null);
}
}, durationSec * 1000);
}
@@ -600,7 +637,7 @@ protected void onResume()
if(isEncoding() == false)
{
- startVideoPlayback();
+ startVideoPlayback(null);
}
}
@@ -656,6 +693,10 @@ private void populateOptionDefaults()
}
encodeButton.setVisibility(View.VISIBLE);
+ startJumpBack.setVisibility(View.VISIBLE);
+ startJumpForward.setVisibility(View.VISIBLE);
+ endJumpBack.setVisibility(View.VISIBLE);
+ endJumpForward.setVisibility(View.VISIBLE);
containerSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.spinner_textview, MediaContainer.values()));
containerSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
@@ -866,7 +907,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data)
@Override
public void onPrepared(MediaPlayer mp)
{
- int durationMs = mp.getDuration();
+ final int durationMs = mp.getDuration();
tvLeft.setVisibility(View.VISIBLE);
tvLeft.setText(getTime(0));
tvRight.setVisibility(View.VISIBLE);
@@ -880,18 +921,75 @@ public void onPrepared(MediaPlayer mp)
rangeSeekBar.setOnRangeSeekbarChangeListener(new OnRangeSeekbarChangeListener()
{
+ Number prevMinValueSec = 0;
+ Number prevMaxValueSec = (int)(durationMs / 1000f);
+
+ // If the end time slider was moved, resume the playback
+ // this may seconds before the end
+ static final int END_PLAYBACK_HEADROOM_SEC = 3;
+
@Override
public void valueChanged(Number minValue, Number maxValue)
{
+ Integer playStartSec = null;
+
+ if(prevMaxValueSec.intValue() != maxValue.intValue())
+ {
+ // End time was changed
+ prevMaxValueSec = maxValue;
+ playStartSec = prevMaxValueSec.intValue();
+
+ // Resume playback a few seconds before the end
+ int headroom = Math.min(maxValue.intValue()-minValue.intValue(), END_PLAYBACK_HEADROOM_SEC);
+ playStartSec -= headroom;
+ }
+
+ if(prevMinValueSec.intValue() != minValue.intValue())
+ {
+ // Start time was changed
+ prevMinValueSec = minValue;
+ playStartSec = prevMinValueSec.intValue();
+ }
+
tvLeft.setText(getTime(minValue.intValue()));
tvRight.setText(getTime(maxValue.intValue()));
- if(isEncoding() == false)
+ if(isEncoding() == false && playStartSec != null)
{
- startVideoPlayback();
+ startVideoPlayback(playStartSec);
}
}
});
+
+ class RangeSeekChanger implements View.OnClickListener
+ {
+ private final int startOffset;
+ private final int endOffset;
+ RangeSeekChanger(int startOffset, int endOffset)
+ {
+ this.startOffset = startOffset;
+ this.endOffset = endOffset;
+ }
+
+ @Override
+ public void onClick(View v)
+ {
+ rangeSeekBar.setMinValue(0);
+ rangeSeekBar.setMaxValue(durationMs / 1000f);
+
+ int selectedStart = rangeSeekBar.getSelectedMinValue().intValue();
+ int selectedEnd = rangeSeekBar.getSelectedMaxValue().intValue();
+
+ rangeSeekBar.setMinStartValue(selectedStart + startOffset);
+ rangeSeekBar.setMaxStartValue(selectedEnd + endOffset);
+ rangeSeekBar.apply();
+ }
+ }
+
+ startJumpForward.setOnClickListener(new RangeSeekChanger(1, 0));
+ startJumpBack.setOnClickListener(new RangeSeekChanger(-1, 0));
+ endJumpForward.setOnClickListener(new RangeSeekChanger(0, 1));
+ endJumpBack.setOnClickListener(new RangeSeekChanger(0, -1));
}
});
@@ -992,6 +1090,7 @@ public void handleMessage(Message msg)
boolean result = false;
String outputFile = null;
String mimetype = null;
+ String message = null;
if(messageId == MessageId.JOB_SUCCEDED_MSG)
{
@@ -999,9 +1098,13 @@ public void handleMessage(Message msg)
outputFile = ((Bundle)msg.obj).getString(FFMPEG_OUTPUT_FILE);
mimetype = ((Bundle)msg.obj).getString(OUTPUT_MIMETYPE);
}
+ else
+ {
+ message = ((Bundle)msg.obj).getString(FFMPEG_FAILURE_MSG);
+ }
Log.d(TAG, "Job complete, result: " + result);
- showEncodeCompleteDialog(mainActivity, result, outputFile, mimetype);
+ showEncodeCompleteDialog(mainActivity, result, message, outputFile, mimetype);
break;
case FFMPEG_UNSUPPORTED_MSG:
@@ -1015,13 +1118,9 @@ public void handleMessage(Message msg)
}
private void showEncodeCompleteDialog(final MainActivity mainActivity, final boolean result,
- final String outputFile, final String mimetype)
+ final String ffmpegMessage, final String outputFile,
+ final String mimetype)
{
- ProgressBar progressBar = mainActivity.findViewById(R.id.encodeProgress);
- Button selectVideoButton = mainActivity.findViewById(R.id.selectVideo);
- Button encodeButton = mainActivity.findViewById(R.id.encode);
- Button cancelButton = mainActivity.findViewById(R.id.cancel);
-
Log.d(TAG, "Encode result: " + result);
String message;
@@ -1032,12 +1131,20 @@ private void showEncodeCompleteDialog(final MainActivity mainActivity, final boo
}
else
{
- message = mainActivity.getResources().getString(R.string.transcodeFailed);
+ message = mainActivity.getResources().getString(R.string.transcodeFailed, ffmpegMessage);
}
AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity)
.setMessage(message)
.setCancelable(true)
+ .setOnDismissListener(new DialogInterface.OnDismissListener()
+ {
+ @Override
+ public void onDismiss(DialogInterface dialog)
+ {
+ mainActivity.startVideoPlayback(null);
+ }
+ })
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
@@ -1070,12 +1177,7 @@ public void onClick(DialogInterface dialog, int which)
builder.show();
- //startVideoPlayback();
-
- selectVideoButton.setVisibility(View.VISIBLE);
- encodeButton.setVisibility(View.VISIBLE);
- cancelButton.setVisibility(View.GONE);
- progressBar.setVisibility(View.GONE);
+ mainActivity.updateUiForVideoSettings();
}
}
diff --git a/app/src/main/java/protect/videotranscoder/service/FFmpegProcessService.java b/app/src/main/java/protect/videotranscoder/service/FFmpegProcessService.java
index e2052147..7bcae049 100644
--- a/app/src/main/java/protect/videotranscoder/service/FFmpegProcessService.java
+++ b/app/src/main/java/protect/videotranscoder/service/FFmpegProcessService.java
@@ -13,9 +13,11 @@
import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler;
import protect.videotranscoder.FFmpegUtil;
+import protect.videotranscoder.R;
import protect.videotranscoder.ResultCallbackHandler;
import static protect.videotranscoder.activity.MainActivity.FFMPEG_ENCODE_ARGS;
+import static protect.videotranscoder.activity.MainActivity.FFMPEG_FAILURE_MSG;
import static protect.videotranscoder.activity.MainActivity.FFMPEG_OUTPUT_FILE;
import static protect.videotranscoder.activity.MainActivity.MESSENGER_INTENT_KEY;
import static protect.videotranscoder.activity.MainActivity.OUTPUT_DURATION_MS;
@@ -77,7 +79,13 @@ public void onFailure(String s)
Log.d(TAG, "Failed with output : " + s);
jobFinished(params, false);
- sendMessage(MessageId.JOB_FAILED_MSG, params.getJobId());
+ // The last line of the output should be the failure message
+ String [] lines = s.split("\n");
+ String failureMg = lines[lines.length-1].trim();
+
+ Bundle bundle = new Bundle();
+ bundle.putString(FFMPEG_FAILURE_MSG, failureMg);
+ sendMessage(MessageId.JOB_FAILED_MSG, bundle);
}
@Override
@@ -142,7 +150,9 @@ public boolean onStopJob(JobParameters params)
FFmpegUtil.cancelCall();
- sendMessage(MessageId.JOB_FAILED_MSG, params.getJobId());
+ Bundle bundle = new Bundle();
+ bundle.putString(FFMPEG_FAILURE_MSG, getResources().getString(R.string.encodeCanceled));
+ sendMessage(MessageId.JOB_FAILED_MSG, bundle);
// Return false to drop the job.
return false;
diff --git a/app/src/main/res/drawable-hdpi/ic_fast_forward_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_fast_forward_black_24dp.png
new file mode 100644
index 00000000..3cd2adea
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fast_forward_black_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_fast_rewind_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_fast_rewind_black_24dp.png
new file mode 100644
index 00000000..c5a902db
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fast_rewind_black_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_fast_forward_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_fast_forward_black_24dp.png
new file mode 100644
index 00000000..70a4bbcf
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fast_forward_black_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_fast_rewind_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_fast_rewind_black_24dp.png
new file mode 100644
index 00000000..7dc7471e
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fast_rewind_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_fast_forward_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_fast_forward_black_24dp.png
new file mode 100644
index 00000000..6f26faa6
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fast_forward_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_fast_rewind_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_fast_rewind_black_24dp.png
new file mode 100644
index 00000000..78c67476
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fast_rewind_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_fast_forward_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_fast_forward_black_24dp.png
new file mode 100644
index 00000000..abd54533
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fast_forward_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_fast_rewind_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_fast_rewind_black_24dp.png
new file mode 100644
index 00000000..72c70c45
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fast_rewind_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fast_forward_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_fast_forward_black_24dp.png
new file mode 100644
index 00000000..35017177
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_fast_forward_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fast_rewind_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_fast_rewind_black_24dp.png
new file mode 100644
index 00000000..8839147e
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_fast_rewind_black_24dp.png differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 60180dd2..f004fa5e 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -54,19 +54,35 @@
android:id="@+id/buttonContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
+ android:layout_below="@id/tvRight"
android:orientation="horizontal">
+
+
@@ -74,9 +90,24 @@
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
android:visibility="gone"
android:text="@string/cancel"
/>
+
+
20dip
15sp
15sp
+
+ 35dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 466a63d9..6e845ffc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -27,12 +27,13 @@
You must select a file to encode first.
Video bitrate value is invalid, could not encode.
Encoding completed successfully. The file was written to:\n%s
- Encoding failed, see logs for details.
+ Encoding failed: %s
This application needs access to storage in order to read and write media files. Without this access, the application cannot transcode.
Request again
Failed to resolve the location of the media file
+ Encoding was canceled
Slow, Quality excellent
Fast, Quality good