mirror of https://github.com/TeamNewPipe/NewPipe
165 lines
5.8 KiB
Java
165 lines
5.8 KiB
Java
package us.shandian.giga.postprocessing;
|
|
|
|
import android.os.Message;
|
|
|
|
import org.schabi.newpipe.streams.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_MP4_MUXER = "mp4";
|
|
public static final String ALGORITHM_WEBM_MUXER = "webm";
|
|
|
|
public static Postprocessing getAlgorithm(String algorithmName, DownloadMission mission) {
|
|
if (null == algorithmName) {
|
|
throw new NullPointerException("algorithmName");
|
|
} else switch (algorithmName) {
|
|
case ALGORITHM_TTML_CONVERTER:
|
|
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 "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;
|
|
|
|
/**
|
|
* the download to post-process
|
|
*/
|
|
protected 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;
|
|
int result;
|
|
long finalLength = -1;
|
|
|
|
mission.done = 0;
|
|
mission.length = file.length();
|
|
|
|
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 -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();
|
|
}
|
|
}
|
|
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();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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];
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|