Commit 08e1d356 by Julian Cable

add changed files for SSA from branch

parent 246a0dc8
...@@ -188,6 +188,8 @@ public final class Format implements Parcelable { ...@@ -188,6 +188,8 @@ public final class Format implements Parcelable {
private int hashCode; private int hashCode;
private MediaFormat frameworkMediaFormat; private MediaFormat frameworkMediaFormat;
private byte[] header = new byte[0];
// Video. // Video.
public static Format createVideoContainerFormat(String id, String containerMimeType, public static Format createVideoContainerFormat(String id, String containerMimeType,
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.extractor.mkv; package com.google.android.exoplayer2.extractor.mkv;
import android.content.Intent;
import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
...@@ -30,6 +32,8 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader; ...@@ -30,6 +32,8 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.mp4.Track;
import com.google.android.exoplayer2.text.ssa.SSADecoder;
import com.google.android.exoplayer2.util.LongArray; import com.google.android.exoplayer2.util.LongArray;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.NalUnitUtil; import com.google.android.exoplayer2.util.NalUnitUtil;
...@@ -38,8 +42,13 @@ import com.google.android.exoplayer2.util.Util; ...@@ -38,8 +42,13 @@ import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.AvcConfig; import com.google.android.exoplayer2.video.AvcConfig;
import com.google.android.exoplayer2.video.HevcConfig; import com.google.android.exoplayer2.video.HevcConfig;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
...@@ -47,6 +56,12 @@ import java.util.List; ...@@ -47,6 +56,12 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.UUID; import java.util.UUID;
import static android.R.attr.format;
import static android.R.attr.longClickable;
import static android.R.attr.mimeType;
import static android.R.attr.track;
import static android.R.id.input;
/** /**
* Extracts data from a Matroska or WebM file. * Extracts data from a Matroska or WebM file.
*/ */
...@@ -97,6 +112,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -97,6 +112,7 @@ public final class MatroskaExtractor implements Extractor {
private static final String CODEC_ID_ACM = "A_MS/ACM"; private static final String CODEC_ID_ACM = "A_MS/ACM";
private static final String CODEC_ID_PCM_INT_LIT = "A_PCM/INT/LIT"; private static final String CODEC_ID_PCM_INT_LIT = "A_PCM/INT/LIT";
private static final String CODEC_ID_SUBRIP = "S_TEXT/UTF8"; private static final String CODEC_ID_SUBRIP = "S_TEXT/UTF8";
private static final String CODEC_ID_ASS = "S_TEXT/ASS";
private static final String CODEC_ID_VOBSUB = "S_VOBSUB"; private static final String CODEC_ID_VOBSUB = "S_VOBSUB";
private static final String CODEC_ID_PGS = "S_HDMV/PGS"; private static final String CODEC_ID_PGS = "S_HDMV/PGS";
...@@ -861,9 +877,9 @@ public final class MatroskaExtractor implements Extractor { ...@@ -861,9 +877,9 @@ public final class MatroskaExtractor implements Extractor {
if (id == ID_SIMPLE_BLOCK) { if (id == ID_SIMPLE_BLOCK) {
// For SimpleBlock, we have metadata for each sample here. // For SimpleBlock, we have metadata for each sample here.
while (blockLacingSampleIndex < blockLacingSampleCount) { while (blockLacingSampleIndex < blockLacingSampleCount) {
writeSampleData(input, track, blockLacingSampleSizes[blockLacingSampleIndex]);
long sampleTimeUs = this.blockTimeUs long sampleTimeUs = this.blockTimeUs
+ (blockLacingSampleIndex * track.defaultSampleDurationNs) / 1000; + (blockLacingSampleIndex * track.defaultSampleDurationNs) / 1000;
writeSampleData(input, track, blockLacingSampleSizes[blockLacingSampleIndex]);
commitSampleToOutput(track, sampleTimeUs); commitSampleToOutput(track, sampleTimeUs);
blockLacingSampleIndex++; blockLacingSampleIndex++;
} }
...@@ -884,6 +900,9 @@ public final class MatroskaExtractor implements Extractor { ...@@ -884,6 +900,9 @@ public final class MatroskaExtractor implements Extractor {
if (CODEC_ID_SUBRIP.equals(track.codecId)) { if (CODEC_ID_SUBRIP.equals(track.codecId)) {
writeSubripSample(track); writeSubripSample(track);
} }
if (CODEC_ID_ASS.equals(track.codecId)) {
writeSSASample(track);
}
track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.encryptionKeyId); track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.encryptionKeyId);
sampleRead = true; sampleRead = true;
resetSample(); resetSample();
...@@ -935,6 +954,12 @@ public final class MatroskaExtractor implements Extractor { ...@@ -935,6 +954,12 @@ public final class MatroskaExtractor implements Extractor {
// the correct end timecode, which we might not have yet. // the correct end timecode, which we might not have yet.
return; return;
} }
if (CODEC_ID_ASS.equals(track.codecId)) {
// Defer writing the data to the track output. We need to modify the sample data by setting
// the correct end timecode, which we might not have yet.
cacheSSASampleData(input, track, size);
return;
}
TrackOutput output = track.output; TrackOutput output = track.output;
if (!sampleEncodingHandled) { if (!sampleEncodingHandled) {
...@@ -1076,6 +1101,26 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1076,6 +1101,26 @@ public final class MatroskaExtractor implements Extractor {
} }
} }
private void cacheSSASampleData(ExtractorInput input, Track track, int size) throws IOException,
InterruptedException
{
ParsableByteArray ssaSample = new ParsableByteArray(size);
input.readFully(ssaSample.data, 0, size);
track.ssaSample = ssaSample.readString(size);
}
private void writeSSASample(Track track) {
StringBuffer s = new StringBuffer();
if(track.ssaHeader != null) {
// header contains the original format but the Matroska encoder changes this.
SSADecoder.writeMangledHeader(s, track.ssaHeader);
}
SSADecoder.buildDialogue(s, track.ssaSample, blockDurationUs);
ParsableByteArray out = new ParsableByteArray(s.toString().getBytes());
track.output.sampleData(out, out.limit());
sampleBytesWritten += out.limit();
}
private void writeSubripSample(Track track) { private void writeSubripSample(Track track) {
setSubripSampleEndTimecode(subripSample.data, blockDurationUs); setSubripSampleEndTimecode(subripSample.data, blockDurationUs);
// Note: If we ever want to support DRM protected subtitles then we'll need to output the // Note: If we ever want to support DRM protected subtitles then we'll need to output the
...@@ -1103,6 +1148,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1103,6 +1148,7 @@ public final class MatroskaExtractor implements Extractor {
SUBRIP_TIMECODE_LENGTH); SUBRIP_TIMECODE_LENGTH);
} }
/** /**
* Writes {@code length} bytes of sample data into {@code target} at {@code offset}, consisting of * Writes {@code length} bytes of sample data into {@code target} at {@code offset}, consisting of
* pending {@link #sampleStrippedBytes} and any remaining data read from {@code input}. * pending {@link #sampleStrippedBytes} and any remaining data read from {@code input}.
...@@ -1231,6 +1277,7 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1231,6 +1277,7 @@ public final class MatroskaExtractor implements Extractor {
|| CODEC_ID_ACM.equals(codecId) || CODEC_ID_ACM.equals(codecId)
|| CODEC_ID_PCM_INT_LIT.equals(codecId) || CODEC_ID_PCM_INT_LIT.equals(codecId)
|| CODEC_ID_SUBRIP.equals(codecId) || CODEC_ID_SUBRIP.equals(codecId)
|| CODEC_ID_ASS.equals(codecId)
|| CODEC_ID_VOBSUB.equals(codecId) || CODEC_ID_VOBSUB.equals(codecId)
|| CODEC_ID_PGS.equals(codecId); || CODEC_ID_PGS.equals(codecId);
} }
...@@ -1335,6 +1382,8 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1335,6 +1382,8 @@ public final class MatroskaExtractor implements Extractor {
public boolean flagForced; public boolean flagForced;
public boolean flagDefault = true; public boolean flagDefault = true;
private String language = "eng"; private String language = "eng";
public byte[] ssaHeader = null;
public String ssaSample = null;
// Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265. // Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265.
public TrackOutput output; public TrackOutput output;
...@@ -1453,6 +1502,10 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1453,6 +1502,10 @@ public final class MatroskaExtractor implements Extractor {
case CODEC_ID_SUBRIP: case CODEC_ID_SUBRIP:
mimeType = MimeTypes.APPLICATION_SUBRIP; mimeType = MimeTypes.APPLICATION_SUBRIP;
break; break;
case CODEC_ID_ASS:
mimeType = MimeTypes.TEXT_SSA;
ssaHeader = codecPrivate;
break;
case CODEC_ID_VOBSUB: case CODEC_ID_VOBSUB:
mimeType = MimeTypes.APPLICATION_VOBSUB; mimeType = MimeTypes.APPLICATION_VOBSUB;
initializationData = Collections.singletonList(codecPrivate); initializationData = Collections.singletonList(codecPrivate);
...@@ -1493,6 +1546,10 @@ public final class MatroskaExtractor implements Extractor { ...@@ -1493,6 +1546,10 @@ public final class MatroskaExtractor implements Extractor {
|| MimeTypes.APPLICATION_PGS.equals(mimeType)) { || MimeTypes.APPLICATION_PGS.equals(mimeType)) {
format = Format.createImageSampleFormat(Integer.toString(trackId), mimeType, null, format = Format.createImageSampleFormat(Integer.toString(trackId), mimeType, null,
Format.NO_VALUE, initializationData, language, drmInitData); Format.NO_VALUE, initializationData, language, drmInitData);
} else if (MimeTypes.TEXT_SSA.equals(mimeType)) {
format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, null,
Format.NO_VALUE, selectionFlags, language, drmInitData);
output.track(number).sampleData(new ParsableByteArray(codecPrivate), codecPrivate.length);
} else { } else {
throw new ParserException("Unexpected MIME type."); throw new ParserException("Unexpected MIME type.");
} }
......
...@@ -56,6 +56,7 @@ public interface SubtitleDecoderFactory { ...@@ -56,6 +56,7 @@ public interface SubtitleDecoderFactory {
* <li>WebVTT (MP4) ({@link Mp4WebvttDecoder})</li> * <li>WebVTT (MP4) ({@link Mp4WebvttDecoder})</li>
* <li>TTML ({@link TtmlDecoder})</li> * <li>TTML ({@link TtmlDecoder})</li>
* <li>SubRip ({@link SubripDecoder})</li> * <li>SubRip ({@link SubripDecoder})</li>
* <li>AAS/SSA ({@link SSADecoder})</li>
* <li>TX3G ({@link Tx3gDecoder})</li> * <li>TX3G ({@link Tx3gDecoder})</li>
* <li>Cea608 ({@link Cea608Decoder})</li> * <li>Cea608 ({@link Cea608Decoder})</li>
* </ul> * </ul>
...@@ -99,6 +100,8 @@ public interface SubtitleDecoderFactory { ...@@ -99,6 +100,8 @@ public interface SubtitleDecoderFactory {
return Class.forName("com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder"); return Class.forName("com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder");
case MimeTypes.APPLICATION_SUBRIP: case MimeTypes.APPLICATION_SUBRIP:
return Class.forName("com.google.android.exoplayer2.text.subrip.SubripDecoder"); return Class.forName("com.google.android.exoplayer2.text.subrip.SubripDecoder");
case MimeTypes.TEXT_SSA:
return Class.forName("com.google.android.exoplayer2.text.ssa.SSADecoder");
case MimeTypes.APPLICATION_TX3G: case MimeTypes.APPLICATION_TX3G:
return Class.forName("com.google.android.exoplayer2.text.tx3g.Tx3gDecoder"); return Class.forName("com.google.android.exoplayer2.text.tx3g.Tx3gDecoder");
case MimeTypes.APPLICATION_CEA608: case MimeTypes.APPLICATION_CEA608:
......
...@@ -62,6 +62,7 @@ public final class MimeTypes { ...@@ -62,6 +62,7 @@ public final class MimeTypes {
public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/x-flac"; public static final String AUDIO_FLAC = BASE_TYPE_AUDIO + "/x-flac";
public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt"; public static final String TEXT_VTT = BASE_TYPE_TEXT + "/vtt";
public static final String TEXT_SSA = BASE_TYPE_TEXT + "/x-ssa";
public static final String APPLICATION_MP4 = BASE_TYPE_APPLICATION + "/mp4"; public static final String APPLICATION_MP4 = BASE_TYPE_APPLICATION + "/mp4";
public static final String APPLICATION_WEBM = BASE_TYPE_APPLICATION + "/webm"; public static final String APPLICATION_WEBM = BASE_TYPE_APPLICATION + "/webm";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment