add changed files for SSA from branch

This commit is contained in:
Julian Cable 2017-01-02 14:20:14 +00:00
parent 246a0dc86e
commit 08e1d356ad
4 changed files with 65 additions and 2 deletions

View file

@ -188,6 +188,8 @@ public final class Format implements Parcelable {
private int hashCode;
private MediaFormat frameworkMediaFormat;
private byte[] header = new byte[0];
// Video.
public static Format createVideoContainerFormat(String id, String containerMimeType,

View file

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.extractor.mkv;
import android.content.Intent;
import android.util.Log;
import android.util.SparseArray;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
@ -30,6 +32,8 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader;
import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap;
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.MimeTypes;
import com.google.android.exoplayer2.util.NalUnitUtil;
@ -38,8 +42,13 @@ import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.AvcConfig;
import com.google.android.exoplayer2.video.HevcConfig;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -47,6 +56,12 @@ import java.util.List;
import java.util.Locale;
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.
*/
@ -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_PCM_INT_LIT = "A_PCM/INT/LIT";
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_PGS = "S_HDMV/PGS";
@ -861,9 +877,9 @@ public final class MatroskaExtractor implements Extractor {
if (id == ID_SIMPLE_BLOCK) {
// For SimpleBlock, we have metadata for each sample here.
while (blockLacingSampleIndex < blockLacingSampleCount) {
writeSampleData(input, track, blockLacingSampleSizes[blockLacingSampleIndex]);
long sampleTimeUs = this.blockTimeUs
+ (blockLacingSampleIndex * track.defaultSampleDurationNs) / 1000;
+ (blockLacingSampleIndex * track.defaultSampleDurationNs) / 1000;
writeSampleData(input, track, blockLacingSampleSizes[blockLacingSampleIndex]);
commitSampleToOutput(track, sampleTimeUs);
blockLacingSampleIndex++;
}
@ -884,6 +900,9 @@ public final class MatroskaExtractor implements Extractor {
if (CODEC_ID_SUBRIP.equals(track.codecId)) {
writeSubripSample(track);
}
if (CODEC_ID_ASS.equals(track.codecId)) {
writeSSASample(track);
}
track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, track.encryptionKeyId);
sampleRead = true;
resetSample();
@ -935,6 +954,12 @@ public final class MatroskaExtractor implements Extractor {
// the correct end timecode, which we might not have yet.
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;
if (!sampleEncodingHandled) {
@ -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) {
setSubripSampleEndTimecode(subripSample.data, blockDurationUs);
// 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 {
SUBRIP_TIMECODE_LENGTH);
}
/**
* 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}.
@ -1231,6 +1277,7 @@ public final class MatroskaExtractor implements Extractor {
|| CODEC_ID_ACM.equals(codecId)
|| CODEC_ID_PCM_INT_LIT.equals(codecId)
|| CODEC_ID_SUBRIP.equals(codecId)
|| CODEC_ID_ASS.equals(codecId)
|| CODEC_ID_VOBSUB.equals(codecId)
|| CODEC_ID_PGS.equals(codecId);
}
@ -1335,6 +1382,8 @@ public final class MatroskaExtractor implements Extractor {
public boolean flagForced;
public boolean flagDefault = true;
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.
public TrackOutput output;
@ -1453,6 +1502,10 @@ public final class MatroskaExtractor implements Extractor {
case CODEC_ID_SUBRIP:
mimeType = MimeTypes.APPLICATION_SUBRIP;
break;
case CODEC_ID_ASS:
mimeType = MimeTypes.TEXT_SSA;
ssaHeader = codecPrivate;
break;
case CODEC_ID_VOBSUB:
mimeType = MimeTypes.APPLICATION_VOBSUB;
initializationData = Collections.singletonList(codecPrivate);
@ -1493,6 +1546,10 @@ public final class MatroskaExtractor implements Extractor {
|| MimeTypes.APPLICATION_PGS.equals(mimeType)) {
format = Format.createImageSampleFormat(Integer.toString(trackId), mimeType, null,
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 {
throw new ParserException("Unexpected MIME type.");
}

View file

@ -56,6 +56,7 @@ public interface SubtitleDecoderFactory {
* <li>WebVTT (MP4) ({@link Mp4WebvttDecoder})</li>
* <li>TTML ({@link TtmlDecoder})</li>
* <li>SubRip ({@link SubripDecoder})</li>
* <li>AAS/SSA ({@link SSADecoder})</li>
* <li>TX3G ({@link Tx3gDecoder})</li>
* <li>Cea608 ({@link Cea608Decoder})</li>
* </ul>
@ -99,6 +100,8 @@ public interface SubtitleDecoderFactory {
return Class.forName("com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder");
case MimeTypes.APPLICATION_SUBRIP:
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:
return Class.forName("com.google.android.exoplayer2.text.tx3g.Tx3gDecoder");
case MimeTypes.APPLICATION_CEA608:

View file

@ -62,6 +62,7 @@ public final class MimeTypes {
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_SSA = BASE_TYPE_TEXT + "/x-ssa";
public static final String APPLICATION_MP4 = BASE_TYPE_APPLICATION + "/mp4";
public static final String APPLICATION_WEBM = BASE_TYPE_APPLICATION + "/webm";