compatibleBrands = new ArrayList<>(5);
private final StreamInfo streamInfo;
+ private final Bitmap thumbnail;
public Mp4FromDashWriter(final StreamInfo streamInfo,
+ final Bitmap thumbnail,
final SharpStream... sources) throws IOException {
for (final SharpStream src : sources) {
if (!src.canRewind() && !src.canRead()) {
@@ -63,6 +74,7 @@ public class Mp4FromDashWriter {
}
this.streamInfo = streamInfo;
+ this.thumbnail = thumbnail;
sourceTracks = sources;
readers = new Mp4DashReader[sourceTracks.length];
readersChunks = new Mp4DashChunk[readers.length];
@@ -946,10 +958,23 @@ public class Mp4FromDashWriter {
writeMetaItem("©day", date);
}
+
+
+ if (thumbnail != null) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ thumbnail.compress(Bitmap.CompressFormat.PNG, 100, baos);
+ final byte[] imgBytes = baos.toByteArray();
+ baos.close();
+ // 0x0000000E = PNG type indicator for 'data' box (0x0D = JPEG)
+ writeMetaCover(imgBytes, 0x0000000E);
+
+ }
+
// fix lengths
lengthFor(startIlst);
lengthFor(startMeta);
lengthFor(startUdta);
+
}
/**
@@ -997,9 +1022,9 @@ public class Mp4FromDashWriter {
/**
* Create a minimal hdlr box for the meta container.
* The boxsize is fixed (33 bytes) as no name is provided.
+ * @return byte array with the hdlr box
*/
private byte[] makeMetaHdlr() {
-
final ByteBuffer buf = ByteBuffer.allocate(33);
buf.putInt(33);
buf.putInt(0x68646C72); // "hdlr"
@@ -1011,6 +1036,52 @@ public class Mp4FromDashWriter {
return buf.array();
}
+ /**
+ * Helper to write cover image inside the 'udta' box.
+ *
+ *
+ * [size][key] [data_box]
+ * data_box = [size]["data"][type(4bytes)][locale(4bytes)=0][payload]
+ *
+ *
+ * @param imageData image byte data
+ * @param dataType type indicator: 0x0000000E = PNG, 0x0000000D = JPEG
+ * @throws IOException
+ */
+ private void writeMetaCover(final byte[] imageData, final int dataType) throws IOException {
+ if (imageData == null || imageData.length == 0) {
+ return;
+ }
+
+ final byte[] keyBytes = "covr".getBytes(StandardCharsets.ISO_8859_1);
+
+ // data box: 4(size) + 4("data") + 4(type) + 4(locale) + payload
+ final int dataBoxSize = 16 + imageData.length;
+ final int itemBoxSize = 8 + dataBoxSize;
+
+ final ByteBuffer buf = ByteBuffer.allocate(itemBoxSize);
+ buf.putInt(itemBoxSize);
+
+ // key (4 chars)
+ if (keyBytes.length == 4) {
+ buf.put(keyBytes);
+ } else {
+ final byte[] kb = new byte[4];
+ System.arraycopy(keyBytes, 0, kb, 0, Math.min(keyBytes.length, 4));
+ buf.put(kb);
+ }
+
+ // data box
+ buf.putInt(dataBoxSize);
+ buf.putInt(0x64617461); // "data"
+ buf.putInt(dataType); // type indicator: 0x0000000E = PNG, 0x0000000D = JPEG
+ buf.putInt(0x00000000); // locale
+ buf.put(imageData);
+
+ auxWrite(buf.array());
+ }
+
+
static class TablesInfo {
int stts;
int stsc;
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/M4aNoDash.java b/app/src/main/java/us/shandian/giga/postprocessing/M4aNoDash.java
index ec59b93a7..ec57ed491 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/M4aNoDash.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/M4aNoDash.java
@@ -30,7 +30,8 @@ class M4aNoDash extends Postprocessing {
@Override
int process(SharpStream out, SharpStream... sources) throws IOException {
- Mp4FromDashWriter muxer = new Mp4FromDashWriter(this.streamInfo, sources[0]);
+ Mp4FromDashWriter muxer = new Mp4FromDashWriter(
+ this.streamInfo, this.thumbnail, sources[0]);
muxer.setMainBrand(0x4D344120);// binary string "M4A "
muxer.parseSources();
muxer.selectTracks(0);
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Mp4FromDashMuxer.java b/app/src/main/java/us/shandian/giga/postprocessing/Mp4FromDashMuxer.java
index 9f530ffc9..887ba1bf5 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/Mp4FromDashMuxer.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Mp4FromDashMuxer.java
@@ -16,7 +16,7 @@ class Mp4FromDashMuxer extends Postprocessing {
@Override
int process(SharpStream out, SharpStream... sources) throws IOException {
- Mp4FromDashWriter muxer = new Mp4FromDashWriter(this.streamInfo, sources);
+ Mp4FromDashWriter muxer = new Mp4FromDashWriter(this.streamInfo, this.thumbnail, sources);
muxer.parseSources();
muxer.selectTracks(0, 0);
muxer.build(out);