diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1bc205f33..5aa1dc982 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -119,7 +119,6 @@
-
{
- // should be safe run the following code without "getActivity().runOnUiThread()"
if (listed) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.download_dialog_title)
@@ -511,11 +510,11 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
if (secondaryStream != null) {
secondaryStreamUrl = secondaryStream.getStream().getUrl();
- psName = selectedStream.getFormat() == MediaFormat.MPEG_4 ? Postprocessing.ALGORITHM_MP4_DASH_MUXER : Postprocessing.ALGORITHM_WEBM_MUXER;
+ psName = selectedStream.getFormat() == MediaFormat.MPEG_4 ? Postprocessing.ALGORITHM_MP4_MUXER : Postprocessing.ALGORITHM_WEBM_MUXER;
psArgs = null;
long videoSize = wrappedVideoStreams.getSizeInBytes((VideoStream) selectedStream);
- // set nearLength, only, if both sizes are fetched or known. this probably does not work on weak internet connections
+ // set nearLength, only, if both sizes are fetched or known. this probably does not work on slow networks
if (secondaryStream.getSizeInBytes() > 0 && videoSize > 0) {
nearLength = secondaryStream.getSizeInBytes() + videoSize;
}
diff --git a/app/src/main/java/org/schabi/newpipe/download/ExtSDDownloadFailedActivity.java b/app/src/main/java/org/schabi/newpipe/download/ExtSDDownloadFailedActivity.java
deleted file mode 100644
index c02ef92eb..000000000
--- a/app/src/main/java/org/schabi/newpipe/download/ExtSDDownloadFailedActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.schabi.newpipe.download;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-
-import org.schabi.newpipe.R;
-import org.schabi.newpipe.settings.NewPipeSettings;
-import org.schabi.newpipe.util.ServiceHelper;
-import org.schabi.newpipe.util.ThemeHelper;
-
-public class ExtSDDownloadFailedActivity extends AppCompatActivity {
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this));
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- new AlertDialog.Builder(this)
- .setTitle(R.string.download_to_sdcard_error_title)
- .setMessage(R.string.download_to_sdcard_error_message)
- .setPositiveButton(R.string.yes, (DialogInterface dialogInterface, int i) -> {
- NewPipeSettings.resetDownloadFolders(this);
- finish();
- })
- .setNegativeButton(R.string.cancel, (DialogInterface dialogInterface, int i) -> {
- dialogInterface.dismiss();
- finish();
- })
- .create()
- .show();
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/util/SecondaryStreamHelper.java b/app/src/main/java/org/schabi/newpipe/util/SecondaryStreamHelper.java
index a5d3ea3eb..b3522aea0 100644
--- a/app/src/main/java/org/schabi/newpipe/util/SecondaryStreamHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/SecondaryStreamHelper.java
@@ -36,7 +36,6 @@ public class SecondaryStreamHelper {
* @return selected audio stream or null if a candidate was not found
*/
public static AudioStream getAudioStreamFor(@NonNull List audioStreams, @NonNull VideoStream videoStream) {
- // TODO: check if m4v and m4a selected streams are DASH compliant
switch (videoStream.getFormat()) {
case WEBM:
case MPEG_4:
diff --git a/app/src/main/java/us/shandian/giga/get/DownloadInitializer.java b/app/src/main/java/us/shandian/giga/get/DownloadInitializer.java
index ce7ae267c..b864cf4fb 100644
--- a/app/src/main/java/us/shandian/giga/get/DownloadInitializer.java
+++ b/app/src/main/java/us/shandian/giga/get/DownloadInitializer.java
@@ -156,7 +156,6 @@ public class DownloadInitializer extends Thread {
if (retryCount++ > mMission.maxRetry) {
Log.e(TAG, "initializer failed", e);
- mMission.running = false;
mMission.notifyError(e);
return;
}
diff --git a/app/src/main/java/us/shandian/giga/get/DownloadMission.java b/app/src/main/java/us/shandian/giga/get/DownloadMission.java
index c25d517f1..243a8585a 100644
--- a/app/src/main/java/us/shandian/giga/get/DownloadMission.java
+++ b/app/src/main/java/us/shandian/giga/get/DownloadMission.java
@@ -39,7 +39,7 @@ public class DownloadMission extends Mission {
public static final int ERROR_SSL_EXCEPTION = 1004;
public static final int ERROR_UNKNOWN_HOST = 1005;
public static final int ERROR_CONNECT_HOST = 1006;
- public static final int ERROR_POSTPROCESSING_FAILED = 1007;
+ public static final int ERROR_POSTPROCESSING = 1007;
public static final int ERROR_HTTP_NO_CONTENT = 204;
public static final int ERROR_HTTP_UNSUPPORTED_RANGE = 206;
@@ -79,9 +79,12 @@ public class DownloadMission extends Mission {
public String postprocessingName;
/**
- * Indicates if the post-processing algorithm is actually running, used to detect corrupt downloads
+ * Indicates if the post-processing state:
+ * 0: ready
+ * 1: running
+ * 2: completed
*/
- public boolean postprocessingRunning;
+ public int postprocessingState;
/**
* Indicate if the post-processing algorithm works on the same file
@@ -356,7 +359,7 @@ public class DownloadMission extends Mission {
finishCount++;
if (finishCount == currentThreadCount) {
- if (errCode > ERROR_NOTHING) return;
+ if (errCode != ERROR_NOTHING) return;
if (DEBUG) {
Log.d(TAG, "onFinish" + (current + 1) + "/" + urls.length);
@@ -382,19 +385,26 @@ public class DownloadMission extends Mission {
}
}
- private void notifyPostProcessing(boolean processing) {
+ private void notifyPostProcessing(int state) {
if (DEBUG) {
- Log.d(TAG, (processing ? "enter" : "exit") + " postprocessing on " + location + File.separator + name);
+ String action;
+ switch (state) {
+ case 1:
+ action = "Running";
+ break;
+ case 2:
+ action = "Completed";
+ break;
+ default:
+ action = "Failed";
+ }
+
+ Log.d(TAG, action + " postprocessing on " + location + File.separator + name);
}
synchronized (blockState) {
- if (!processing) {
- postprocessingName = null;
- postprocessingArgs = null;
- }
-
// don't return without fully write the current state
- postprocessingRunning = processing;
+ postprocessingState = state;
Utility.writeToFile(metadata, DownloadMission.this);
}
}
@@ -403,16 +413,30 @@ public class DownloadMission extends Mission {
* Start downloading with multiple threads.
*/
public void start() {
- if (running || current >= urls.length) return;
+ if (running || isFinished()) return;
// ensure that the previous state is completely paused.
joinForThread(init);
- for (Thread thread : threads) joinForThread(thread);
+ if (threads != null)
+ for (Thread thread : threads) joinForThread(thread);
enqueued = false;
running = true;
errCode = ERROR_NOTHING;
+ if (current >= urls.length && postprocessingName != null) {
+ runAsync(1, () -> {
+ if (doPostprocessing()) {
+ running = false;
+ deleteThisFromFile();
+
+ notify(DownloadManagerService.MESSAGE_FINISHED);
+ }
+ });
+
+ return;
+ }
+
if (blocks < 0) {
initializer();
return;
@@ -420,7 +444,7 @@ public class DownloadMission extends Mission {
init = null;
- if (threads.length < 1) {
+ if (threads == null || threads.length < 1) {
threads = new Thread[currentThreadCount];
}
@@ -444,18 +468,18 @@ public class DownloadMission extends Mission {
public synchronized void pause() {
if (!running) return;
- running = false;
- recovered = true;
- enqueued = false;
-
- if (postprocessingRunning) {
+ if (isPsRunning()) {
if (DEBUG) {
Log.w(TAG, "pause during post-processing is not applicable.");
}
return;
}
- if (init != null && init.isAlive()) {
+ running = false;
+ recovered = true;
+ enqueued = false;
+
+ if (init != null && Thread.currentThread() != init && init.isAlive()) {
init.interrupt();
synchronized (blockState) {
resetState();
@@ -532,13 +556,36 @@ public class DownloadMission extends Mission {
mWritingToFile = false;
}
+ /**
+ * Indicates if the download if fully finished
+ *
+ * @return true, otherwise, false
+ */
public boolean isFinished() {
- return current >= urls.length && postprocessingName == null;
+ return current >= urls.length && (postprocessingName == null || postprocessingState == 2);
+ }
+
+ /**
+ * Indicates if the download file is corrupt due a failed post-processing
+ *
+ * @return {@code true} if this mission is unrecoverable
+ */
+ public boolean isPsFailed() {
+ return postprocessingName != null && errCode == DownloadMission.ERROR_POSTPROCESSING && postprocessingThis;
+ }
+
+ /**
+ * Indicates if a post-processing algorithm is running
+ *
+ * @return true, otherwise, false
+ */
+ public boolean isPsRunning() {
+ return postprocessingName != null && postprocessingState == 1;
}
public long getLength() {
long calculated;
- if (postprocessingRunning) {
+ if (postprocessingState == 1) {
calculated = length;
} else {
calculated = offsets[current < offsets.length ? current : (offsets.length - 1)] + length;
@@ -550,16 +597,19 @@ public class DownloadMission extends Mission {
}
private boolean doPostprocessing() {
- if (postprocessingName == null) return true;
+ if (postprocessingName == null || postprocessingState == 2) return true;
+
+ notifyPostProcessing(1);
+ notifyProgress(0);
+
+ Thread.currentThread().setName("[" + TAG + "] post-processing = " + postprocessingName + " filename = " + name);
+
+ Exception exception = null;
try {
- notifyPostProcessing(true);
- notifyProgress(0);
-
- Thread.currentThread().setName("[" + TAG + "] post-processing = " + postprocessingName + " filename = " + name);
-
- Postprocessing algorithm = Postprocessing.getAlgorithm(postprocessingName, this);
- algorithm.run();
+ Postprocessing
+ .getAlgorithm(postprocessingName, this)
+ .run();
} catch (Exception err) {
StringBuilder args = new StringBuilder(" ");
if (postprocessingArgs != null) {
@@ -571,15 +621,21 @@ public class DownloadMission extends Mission {
}
Log.e(TAG, String.format("Post-processing failed. algorithm = %s args = [%s]", postprocessingName, args), err);
- notifyError(ERROR_POSTPROCESSING_FAILED, err);
- return false;
+ if (errCode == ERROR_NOTHING) errCode = ERROR_POSTPROCESSING;
+
+ exception = err;
} finally {
- notifyPostProcessing(false);
+ notifyPostProcessing(errCode == ERROR_NOTHING ? 2 : 0);
}
- if (errCode != ERROR_NOTHING) notify(DownloadManagerService.MESSAGE_ERROR);
+ if (errCode != ERROR_NOTHING) {
+ if (exception == null) exception = errObject;
+ notifyError(ERROR_POSTPROCESSING, exception);
- return errCode == ERROR_NOTHING;
+ return false;
+ }
+
+ return true;
}
private boolean deleteThisFromFile() {
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Mp4DashMuxer.java b/app/src/main/java/us/shandian/giga/postprocessing/Mp4DashMuxer.java
index b303b66cd..45c06dd4b 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/Mp4DashMuxer.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Mp4DashMuxer.java
@@ -13,9 +13,7 @@ import us.shandian.giga.get.DownloadMission;
class Mp4DashMuxer extends Postprocessing {
Mp4DashMuxer(DownloadMission mission) {
- super(mission);
- recommendedReserve = 15360 * 1024;// 15 MiB
- worksOnSameFile = true;
+ super(mission, 15360 * 1024/* 15 MiB */, true);
}
@Override
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Mp4Muxer.java b/app/src/main/java/us/shandian/giga/postprocessing/Mp4Muxer.java
new file mode 100644
index 000000000..bf932d5c1
--- /dev/null
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Mp4Muxer.java
@@ -0,0 +1,136 @@
+package us.shandian.giga.postprocessing;
+
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaExtractor;
+import android.media.MediaMuxer;
+import android.media.MediaMuxer.OutputFormat;
+import android.util.Log;
+
+import static org.schabi.newpipe.BuildConfig.DEBUG;
+
+import org.schabi.newpipe.streams.io.SharpStream;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import us.shandian.giga.get.DownloadMission;
+
+
+class Mp4Muxer extends Postprocessing {
+ private static final String TAG = "Mp4Muxer";
+ private static final int NOTIFY_BYTES_INTERVAL = 128 * 1024;// 128 KiB
+
+ Mp4Muxer(DownloadMission mission) {
+ super(mission, 0, false);
+ }
+
+ @Override
+ int process(SharpStream out, SharpStream... sources) throws IOException {
+ File dlFile = mission.getDownloadedFile();
+ File tmpFile = new File(mission.location, mission.name.concat(".tmp"));
+
+ if (tmpFile.exists())
+ if (!tmpFile.delete()) return DownloadMission.ERROR_FILE_CREATION;
+
+ if (!tmpFile.createNewFile()) return DownloadMission.ERROR_FILE_CREATION;
+
+ FileInputStream source = null;
+ MediaMuxer muxer = null;
+
+ //noinspection TryFinallyCanBeTryWithResources
+ try {
+ source = new FileInputStream(dlFile);
+ MediaExtractor tracks[] = {
+ getMediaExtractor(source, mission.offsets[0], mission.offsets[1] - mission.offsets[0]),
+ getMediaExtractor(source, mission.offsets[1], mission.length - mission.offsets[1])
+ };
+
+ muxer = new MediaMuxer(tmpFile.getAbsolutePath(), OutputFormat.MUXER_OUTPUT_MPEG_4);
+
+ int tracksIndex[] = {
+ muxer.addTrack(tracks[0].getTrackFormat(0)),
+ muxer.addTrack(tracks[1].getTrackFormat(0))
+ };
+
+ ByteBuffer buffer = ByteBuffer.allocate(512 * 1024);// 512 KiB
+ BufferInfo info = new BufferInfo();
+
+ long written = 0;
+ long nextReport = NOTIFY_BYTES_INTERVAL;
+
+ muxer.start();
+
+ while (true) {
+ int done = 0;
+
+ for (int i = 0; i < tracks.length; i++) {
+ if (tracksIndex[i] < 0) continue;
+
+ info.set(0,
+ tracks[i].readSampleData(buffer, 0),
+ tracks[i].getSampleTime(),
+ tracks[i].getSampleFlags()
+ );
+
+ if (info.size >= 0) {
+ muxer.writeSampleData(tracksIndex[i], buffer, info);
+ written += info.size;
+ done++;
+ }
+ if (!tracks[i].advance()) {
+ // EOF reached
+ tracks[i].release();
+ tracksIndex[i] = -1;
+ }
+
+ if (written > nextReport) {
+ nextReport = written + NOTIFY_BYTES_INTERVAL;
+ super.progressReport(written);
+ }
+ }
+
+ if (done < 1) break;
+ }
+
+ // this part should not fail
+ if (!dlFile.delete()) return DownloadMission.ERROR_FILE_CREATION;
+ if (!tmpFile.renameTo(dlFile)) return DownloadMission.ERROR_FILE_CREATION;
+
+ return OK_RESULT;
+ } finally {
+ try {
+ if (muxer != null) {
+ muxer.stop();
+ muxer.release();
+ }
+ } catch (Exception err) {
+ if (DEBUG)
+ Log.e(TAG, "muxer stop/release failed", err);
+ }
+
+ if (source != null) {
+ try {
+ source.close();
+ } catch (IOException e) {
+ // nothing to do
+ }
+ }
+
+ // if the operation fails, delete the temporal file
+ if (tmpFile.exists()) {
+ //noinspection ResultOfMethodCallIgnored
+ tmpFile.delete();
+ }
+ }
+ }
+
+ private MediaExtractor getMediaExtractor(FileInputStream source, long offset, long length) throws IOException {
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(source.getFD(), offset, length);
+ extractor.selectTrack(0);
+
+ return extractor;
+ }
+}
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
index 80726f705..635140bd3 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
@@ -18,21 +18,21 @@ public abstract class Postprocessing {
public static final String ALGORITHM_TTML_CONVERTER = "ttml";
public static final String ALGORITHM_MP4_DASH_MUXER = "mp4D";
+ public static final String ALGORITHM_MP4_MUXER = "mp4";
public static final String ALGORITHM_WEBM_MUXER = "webm";
- private static final String ALGORITHM_TEST_ALGO = "test";
public static Postprocessing getAlgorithm(String algorithmName, DownloadMission mission) {
if (null == algorithmName) {
throw new NullPointerException("algorithmName");
} else switch (algorithmName) {
case ALGORITHM_TTML_CONVERTER:
- return new TttmlConverter(mission);
+ return new TtmlConverter(mission);
case ALGORITHM_MP4_DASH_MUXER:
return new Mp4DashMuxer(mission);
+ case ALGORITHM_MP4_MUXER:
+ return new Mp4Muxer(mission);
case ALGORITHM_WEBM_MUXER:
return new WebMMuxer(mission);
- case ALGORITHM_TEST_ALGO:
- return new TestAlgo(mission);
/*case "example-algorithm":
return new ExampleAlgorithm(mission);*/
default:
@@ -52,71 +52,84 @@ public abstract class Postprocessing {
*/
public int recommendedReserve;
+ /**
+ * the download to post-process
+ */
protected DownloadMission mission;
- Postprocessing(DownloadMission mission) {
+ Postprocessing(DownloadMission mission, int recommendedReserve, boolean worksOnSameFile) {
this.mission = mission;
+ this.recommendedReserve = recommendedReserve;
+ this.worksOnSameFile = worksOnSameFile;
}
public void run() throws IOException {
File file = mission.getDownloadedFile();
CircularFile out = null;
- ChunkFileInputStream[] sources = new ChunkFileInputStream[mission.urls.length];
+ int result;
+ long finalLength = -1;
- try {
- int i = 0;
- for (; i < sources.length - 1; i++) {
- sources[i] = new ChunkFileInputStream(file, mission.offsets[i], mission.offsets[i + 1], "rw");
- }
- sources[i] = new ChunkFileInputStream(file, mission.offsets[i], mission.getDownloadedFile().length(), "rw");
+ mission.done = 0;
+ mission.length = file.length();
- int[] idx = {0};
- CircularFile.OffsetChecker checker = () -> {
- while (idx[0] < sources.length) {
- /*
- * WARNING: never use rewind() in any chunk after any writing (especially on first chunks)
- * or the CircularFile can lead to unexpected results
- */
- if (sources[idx[0]].isDisposed() || sources[idx[0]].available() < 1) {
- idx[0]++;
- continue;// the selected source is not used anymore
+ if (worksOnSameFile) {
+ ChunkFileInputStream[] sources = new ChunkFileInputStream[mission.urls.length];
+ try {
+ int i = 0;
+ for (; i < sources.length - 1; i++) {
+ sources[i] = new ChunkFileInputStream(file, mission.offsets[i], mission.offsets[i + 1], "rw");
+ }
+ sources[i] = new ChunkFileInputStream(file, mission.offsets[i], mission.getDownloadedFile().length(), "rw");
+
+ int[] idx = {0};
+ CircularFile.OffsetChecker checker = () -> {
+ while (idx[0] < sources.length) {
+ /*
+ * WARNING: never use rewind() in any chunk after any writing (especially on first chunks)
+ * or the CircularFile can lead to unexpected results
+ */
+ if (sources[idx[0]].isDisposed() || sources[idx[0]].available() < 1) {
+ idx[0]++;
+ continue;// the selected source is not used anymore
+ }
+
+ return sources[idx[0]].getFilePointer() - 1;
}
- return sources[idx[0]].getFilePointer() - 1;
+ return -1;
+ };
+ out = new CircularFile(file, 0, this::progressReport, checker);
+
+ result = process(out, sources);
+
+ if (result == OK_RESULT)
+ finalLength = out.finalizeFile();
+ } finally {
+ for (SharpStream source : sources) {
+ if (source != null && !source.isDisposed()) {
+ source.dispose();
+ }
}
-
- return -1;
- };
-
- out = new CircularFile(file, 0, this::progressReport, checker);
-
- mission.done = 0;
- mission.length = file.length();
-
- int result = process(out, sources);
-
- if (result == OK_RESULT) {
- long finalLength = out.finalizeFile();
- mission.done = finalLength;
- mission.length = finalLength;
- } else {
- mission.errCode = DownloadMission.ERROR_UNKNOWN_EXCEPTION;
- mission.errObject = new RuntimeException("post-processing algorithm returned " + result);
- }
-
- if (result != OK_RESULT && worksOnSameFile) {
- //noinspection ResultOfMethodCallIgnored
- new File(mission.location, mission.name).delete();
- }
- } finally {
- for (SharpStream source : sources) {
- if (source != null && !source.isDisposed()) {
- source.dispose();
+ if (out != null) {
+ out.dispose();
}
}
- if (out != null) {
- out.dispose();
- }
+ } else {
+ result = process(null);
+ }
+
+ if (result == OK_RESULT) {
+ if (finalLength < 0) finalLength = file.length();
+ mission.done = finalLength;
+ mission.length = finalLength;
+ } else {
+ mission.errCode = DownloadMission.ERROR_UNKNOWN_EXCEPTION;
+ mission.errObject = new RuntimeException("post-processing algorithm returned " + result);
+ }
+
+ if (result != OK_RESULT && worksOnSameFile) {
+ //noinspection ResultOfMethodCallIgnored
+ file.delete();
}
}
@@ -138,7 +151,7 @@ public abstract class Postprocessing {
return mission.postprocessingArgs[index];
}
- private void progressReport(long done) {
+ void progressReport(long done) {
mission.done = done;
if (mission.length < mission.done) mission.length = mission.done;
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/TestAlgo.java b/app/src/main/java/us/shandian/giga/postprocessing/TestAlgo.java
deleted file mode 100644
index 66b235d7c..000000000
--- a/app/src/main/java/us/shandian/giga/postprocessing/TestAlgo.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package us.shandian.giga.postprocessing;
-
-import android.util.Log;
-
-import org.schabi.newpipe.streams.io.SharpStream;
-
-import java.io.IOException;
-import java.util.Random;
-
-import us.shandian.giga.get.DownloadMission;
-
-/**
- * Algorithm for testing proposes
- */
-class TestAlgo extends Postprocessing {
-
- public TestAlgo(DownloadMission mission) {
- super(mission);
-
- worksOnSameFile = true;
- recommendedReserve = 4096 * 1024;// 4 KiB
- }
-
- @Override
- int process(SharpStream out, SharpStream... sources) throws IOException {
-
- int written = 0;
- int size = 5 * 1024 * 1024;// 5 MiB
- byte[] buffer = new byte[8 * 1024];//8 KiB
- mission.length = size;
-
- Random rnd = new Random();
-
- // only write random data
- sources[0].dispose();
-
- while (written < size) {
- rnd.nextBytes(buffer);
-
- int read = Math.min(buffer.length, size - written);
- out.write(buffer, 0, read);
-
- try {
- Thread.sleep((int) (Math.random() * 10));
- } catch (InterruptedException e) {
- return -1;
- }
-
- written += read;
- }
-
- return Postprocessing.OK_RESULT;
- }
-}
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/TttmlConverter.java b/app/src/main/java/us/shandian/giga/postprocessing/TtmlConverter.java
similarity index 83%
rename from app/src/main/java/us/shandian/giga/postprocessing/TttmlConverter.java
rename to app/src/main/java/us/shandian/giga/postprocessing/TtmlConverter.java
index 4c9d44548..390061840 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/TttmlConverter.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/TtmlConverter.java
@@ -18,13 +18,12 @@ import us.shandian.giga.postprocessing.io.SharpInputStream;
/**
* @author kapodamy
*/
-class TttmlConverter extends Postprocessing {
- private static final String TAG = "TttmlConverter";
+class TtmlConverter extends Postprocessing {
+ private static final String TAG = "TtmlConverter";
- TttmlConverter(DownloadMission mission) {
- super(mission);
- recommendedReserve = 0;// due how XmlPullParser works, the xml is fully loaded on the ram
- worksOnSameFile = true;
+ TtmlConverter(DownloadMission mission) {
+ // due how XmlPullParser works, the xml is fully loaded on the ram
+ super(mission, 0, true);
}
@Override
@@ -41,7 +40,7 @@ class TttmlConverter extends Postprocessing {
out,
getArgumentAt(1, "true").equals("true"),
getArgumentAt(2, "true").equals("true")
- );
+ );
} catch (Exception err) {
Log.e(TAG, "subtitle parse failed", err);
@@ -56,7 +55,7 @@ class TttmlConverter extends Postprocessing {
} else if (err instanceof XPathExpressionException) {
return 7;
}
-
+
return 8;
}
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/WebMMuxer.java b/app/src/main/java/us/shandian/giga/postprocessing/WebMMuxer.java
index 009a9a66b..2ffb0f08d 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/WebMMuxer.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/WebMMuxer.java
@@ -15,9 +15,7 @@ import us.shandian.giga.get.DownloadMission;
class WebMMuxer extends Postprocessing {
WebMMuxer(DownloadMission mission) {
- super(mission);
- recommendedReserve = 2048 * 1024;// 2 MiB
- worksOnSameFile = true;
+ super(mission, 2048 * 1024/* 2 MiB */, true);
}
@Override
diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManager.java b/app/src/main/java/us/shandian/giga/service/DownloadManager.java
index 6bcf84745..883c26850 100644
--- a/app/src/main/java/us/shandian/giga/service/DownloadManager.java
+++ b/app/src/main/java/us/shandian/giga/service/DownloadManager.java
@@ -141,15 +141,18 @@ public class DownloadManager {
File dl = mis.getDownloadedFile();
boolean exists = dl.exists();
- if (mis.postprocessingRunning && mis.postprocessingThis) {
- // Incomplete post-processing results in a corrupted download file
- // because the selected algorithm works on the same file to save space.
- if (!dl.delete()) {
- Log.w(TAG, "Unable to delete incomplete download file: " + sub.getPath());
+ if (mis.isPsRunning()) {
+ if (mis.postprocessingThis) {
+ // Incomplete post-processing results in a corrupted download file
+ // because the selected algorithm works on the same file to save space.
+ if (exists && dl.isFile() && !dl.delete())
+ Log.w(TAG, "Unable to delete incomplete download file: " + sub.getPath());
+
+ exists = true;
}
- exists = true;
- mis.postprocessingRunning = false;
- mis.errCode = DownloadMission.ERROR_POSTPROCESSING_FAILED;
+
+ mis.postprocessingState = 0;
+ mis.errCode = DownloadMission.ERROR_POSTPROCESSING;
mis.errObject = new RuntimeException("stopped unexpectedly");
} else if (exists && !dl.isFile()) {
// probably a folder, this should never happens
@@ -332,7 +335,7 @@ public class DownloadManager {
int count = 0;
synchronized (this) {
for (DownloadMission mission : mMissionsPending) {
- if (mission.running && mission.errCode != DownloadMission.ERROR_POSTPROCESSING_FAILED && !mission.isFinished())
+ if (mission.running && !mission.isFinished() && !mission.isPsFailed())
count++;
}
}
@@ -471,7 +474,7 @@ public class DownloadManager {
boolean flag = false;
synchronized (this) {
for (DownloadMission mission : mMissionsPending) {
- if (mission.running && mission.isFinished() && !mission.postprocessingRunning) {
+ if (mission.running && !mission.isFinished() && !mission.isPsRunning()) {
flag = true;
mission.pause();
}
@@ -528,6 +531,8 @@ public class DownloadManager {
ArrayList