main commit
Post-processing infrastructure * remove interfaces with one implementation * fix download resources with unknow length * marquee style for ProgressDrawable * "view details" option in mission context menu * notification for finished downloads * postprocessing infrastructure: sub-missions, circular file, layers for layers of abstractions for Java IO streams * Mp4 muxing (only DASH brand) * WebM muxing * Captions downloading * alert dialog for overwrite existing downloads finished or not. Misc changes * delete SQLiteDownloadDataSource.java * delete DownloadMissionSQLiteHelper.java * implement Localization from #114 Misc fixes (this branch) * restore old mission listeners variables. Prevents registered listeners get de-referenced on low-end devices * DownloadManagerService.checkForRunningMission() now return false if the mission has a error. * use Intent.FLAG_ACTIVITY_NEW_TASK when launching an activity from gigaget threads (apparently it is required in old versions of android) More changes * proper error handling "infrastructure" * queue instead of multiple downloads * move serialized pending downloads (.giga files) to app data * stop downloads when swicthing to mobile network (never works, see 2nd point) * save the thread count for next downloads * a lot of incoherences fixed * delete DownloadManagerTest.java (too many changes to keep this file updated)
This commit is contained in:
parent
45fea983b9
commit
5825843f68
48 changed files with 4379 additions and 1119 deletions
|
|
@ -0,0 +1,149 @@
|
|||
package us.shandian.giga.postprocessing;
|
||||
|
||||
import android.os.Message;
|
||||
|
||||
import org.schabi.newpipe.extractor.utils.io.SharpStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import us.shandian.giga.get.DownloadMission;
|
||||
import us.shandian.giga.postprocessing.io.ChunkFileInputStream;
|
||||
import us.shandian.giga.postprocessing.io.CircularFile;
|
||||
import us.shandian.giga.service.DownloadManagerService;
|
||||
|
||||
public abstract class Postprocessing {
|
||||
|
||||
static final byte OK_RESULT = DownloadMission.ERROR_NOTHING;
|
||||
|
||||
public static final String ALGORITHM_TTML_CONVERTER = "ttml";
|
||||
public static final String ALGORITHM_MP4_DASH_MUXER = "mp4D";
|
||||
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);
|
||||
case ALGORITHM_MP4_DASH_MUXER:
|
||||
return new Mp4DashMuxer(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:
|
||||
throw new RuntimeException("Unimplemented post-processing algorithm: " + algorithmName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value that indicate if the given algorithm work on the same
|
||||
* file
|
||||
*/
|
||||
public boolean worksOnSameFile;
|
||||
|
||||
/**
|
||||
* Get the recommended space to reserve for the given algorithm. The amount
|
||||
* is in bytes
|
||||
*/
|
||||
public int recommendedReserve;
|
||||
|
||||
protected DownloadMission mission;
|
||||
|
||||
Postprocessing(DownloadMission mission) {
|
||||
this.mission = mission;
|
||||
}
|
||||
|
||||
public void run() throws IOException {
|
||||
File file = mission.getDownloadedFile();
|
||||
CircularFile out = null;
|
||||
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 -1;
|
||||
};
|
||||
|
||||
out = new CircularFile(file, 0, this::progressReport, checker);
|
||||
|
||||
mission.done = 0;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method to execute the pos-processing algorithm
|
||||
*
|
||||
* @param out output stream
|
||||
* @param sources files to be processed
|
||||
* @return a error code, 0 means the operation was successful
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
abstract int process(SharpStream out, SharpStream... sources) throws IOException;
|
||||
|
||||
String getArgumentAt(int index, String defaultValue) {
|
||||
if (mission.postprocessingArgs == null || index >= mission.postprocessingArgs.length) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return mission.postprocessingArgs[index];
|
||||
}
|
||||
|
||||
private void progressReport(long done) {
|
||||
mission.done = done;
|
||||
if (mission.length < mission.done) mission.length = mission.done;
|
||||
|
||||
Message m = new Message();
|
||||
m.what = DownloadManagerService.MESSAGE_PROGRESS;
|
||||
m.obj = mission;
|
||||
|
||||
mission.mHandler.sendMessage(m);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue