Commit 0a7011b3 by tonihei Committed by Oliver Woodman

Support default style in Tx3g decoder.

The track initialization data of Tx3g includes default style values for
font styles, colour, and font family. Additionally the decoder now supports
vertical subtitle placements other than the Tx3g default of 85% video height.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=152930057
parent 1a22a4be
...@@ -82,6 +82,16 @@ public final class C { ...@@ -82,6 +82,16 @@ public final class C {
public static final String UTF16_NAME = "UTF-16"; public static final String UTF16_NAME = "UTF-16";
/** /**
* * The name of the serif font family.
*/
public static final String SERIF_NAME = "serif";
/**
* * The name of the sans-serif font family.
*/
public static final String SANS_SERIF_NAME = "sans-serif";
/**
* Crypto modes for a codec. * Crypto modes for a codec.
*/ */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
......
...@@ -283,30 +283,31 @@ public final class Format implements Parcelable { ...@@ -283,30 +283,31 @@ public final class Format implements Parcelable {
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs,
int bitrate, @C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData) { int bitrate, @C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData) {
return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language,
NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE); NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.<byte[]>emptyList());
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs,
int bitrate, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel, int bitrate, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel,
DrmInitData drmInitData) { DrmInitData drmInitData) {
return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language,
accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE); accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE, Collections.<byte[]>emptyList());
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs,
int bitrate, @C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData, int bitrate, @C.SelectionFlags int selectionFlags, String language, DrmInitData drmInitData,
long subsampleOffsetUs) { long subsampleOffsetUs) {
return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language, return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language,
NO_VALUE, drmInitData, subsampleOffsetUs); NO_VALUE, drmInitData, subsampleOffsetUs, Collections.<byte[]>emptyList());
} }
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs, public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs,
int bitrate, @C.SelectionFlags int selectionFlags, String language, int bitrate, @C.SelectionFlags int selectionFlags, String language,
int accessibilityChannel, DrmInitData drmInitData, long subsampleOffsetUs) { int accessibilityChannel, DrmInitData drmInitData, long subsampleOffsetUs,
List<byte[]> initializationData) {
return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE, return new Format(id, null, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
NO_VALUE, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, null, NO_VALUE, selectionFlags, language, accessibilityChannel, subsampleOffsetUs,
drmInitData, null); initializationData, drmInitData, null);
} }
// Image. // Image.
...@@ -438,6 +439,7 @@ public final class Format implements Parcelable { ...@@ -438,6 +439,7 @@ public final class Format implements Parcelable {
drmInitData, metadata); drmInitData, metadata);
} }
@SuppressWarnings("ReferenceEquality")
public Format copyWithManifestFormatInfo(Format manifestFormat) { public Format copyWithManifestFormatInfo(Format manifestFormat) {
if (this == manifestFormat) { if (this == manifestFormat) {
// No need to copy from ourselves. // No need to copy from ourselves.
......
...@@ -611,24 +611,11 @@ import java.util.List; ...@@ -611,24 +611,11 @@ import java.util.List;
|| childAtomType == Atom.TYPE__mp3 || childAtomType == Atom.TYPE_alac) { || childAtomType == Atom.TYPE__mp3 || childAtomType == Atom.TYPE_alac) {
parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId, parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId,
language, isQuickTime, drmInitData, out, i); language, isQuickTime, drmInitData, out, i);
} else if (childAtomType == Atom.TYPE_TTML) { } else if (childAtomType == Atom.TYPE_TTML || childAtomType == Atom.TYPE_tx3g
out.format = Format.createTextSampleFormat(Integer.toString(trackId), || childAtomType == Atom.TYPE_wvtt || childAtomType == Atom.TYPE_stpp
MimeTypes.APPLICATION_TTML, null, Format.NO_VALUE, 0, language, drmInitData); || childAtomType == Atom.TYPE_c608) {
} else if (childAtomType == Atom.TYPE_tx3g) { parseTextSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId,
out.format = Format.createTextSampleFormat(Integer.toString(trackId), language, drmInitData, out);
MimeTypes.APPLICATION_TX3G, null, Format.NO_VALUE, 0, language, drmInitData);
} else if (childAtomType == Atom.TYPE_wvtt) {
out.format = Format.createTextSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_MP4VTT, null, Format.NO_VALUE, 0, language, drmInitData);
} else if (childAtomType == Atom.TYPE_stpp) {
out.format = Format.createTextSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_TTML, null, Format.NO_VALUE, 0, language, drmInitData,
0 /* subsample timing is absolute */);
} else if (childAtomType == Atom.TYPE_c608) {
// Defined by the QuickTime File Format specification.
out.format = Format.createTextSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_MP4CEA608, null, Format.NO_VALUE, 0, language, drmInitData);
out.requiredSampleTransformation = Track.TRANSFORMATION_CEA608_CDAT;
} else if (childAtomType == Atom.TYPE_camm) { } else if (childAtomType == Atom.TYPE_camm) {
out.format = Format.createSampleFormat(Integer.toString(trackId), out.format = Format.createSampleFormat(Integer.toString(trackId),
MimeTypes.APPLICATION_CAMERA_MOTION, null, Format.NO_VALUE, drmInitData); MimeTypes.APPLICATION_CAMERA_MOTION, null, Format.NO_VALUE, drmInitData);
...@@ -638,12 +625,49 @@ import java.util.List; ...@@ -638,12 +625,49 @@ import java.util.List;
return out; return out;
} }
private static void parseTextSampleEntry(ParsableByteArray parent, int atomType, int position,
int atomSize, int trackId, String language, DrmInitData drmInitData, StsdData out)
throws ParserException {
parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE);
// Default values.
List<byte[]> initializationData = null;
long subsampleOffsetUs = Format.OFFSET_SAMPLE_RELATIVE;
String mimeType;
if (atomType == Atom.TYPE_TTML) {
mimeType = MimeTypes.APPLICATION_TTML;
} else if (atomType == Atom.TYPE_tx3g) {
mimeType = MimeTypes.APPLICATION_TX3G;
int sampleDescriptionLength = atomSize - Atom.HEADER_SIZE - 8;
byte[] sampleDescriptionData = new byte[sampleDescriptionLength];
parent.readBytes(sampleDescriptionData, 0, sampleDescriptionLength);
initializationData = Collections.singletonList(sampleDescriptionData);
} else if (atomType == Atom.TYPE_wvtt) {
mimeType = MimeTypes.APPLICATION_MP4VTT;
} else if (atomType == Atom.TYPE_stpp) {
mimeType = MimeTypes.APPLICATION_TTML;
subsampleOffsetUs = 0; // Subsample timing is absolute.
} else if (atomType == Atom.TYPE_c608) {
// Defined by the QuickTime File Format specification.
mimeType = MimeTypes.APPLICATION_MP4CEA608;
out.requiredSampleTransformation = Track.TRANSFORMATION_CEA608_CDAT;
} else {
// Never happens.
throw new IllegalStateException();
}
out.format = Format.createTextSampleFormat(Integer.toString(trackId), mimeType, null,
Format.NO_VALUE, 0, language, Format.NO_VALUE, drmInitData, subsampleOffsetUs,
initializationData);
}
private static void parseVideoSampleEntry(ParsableByteArray parent, int atomType, int position, private static void parseVideoSampleEntry(ParsableByteArray parent, int atomType, int position,
int size, int trackId, int rotationDegrees, DrmInitData drmInitData, StsdData out, int size, int trackId, int rotationDegrees, DrmInitData drmInitData, StsdData out,
int entryIndex) throws ParserException { int entryIndex) throws ParserException {
parent.setPosition(position + Atom.HEADER_SIZE); parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE);
parent.skipBytes(24); parent.skipBytes(16);
int width = parent.readUnsignedShort(); int width = parent.readUnsignedShort();
int height = parent.readUnsignedShort(); int height = parent.readUnsignedShort();
boolean pixelWidthHeightRatioFromPasp = false; boolean pixelWidthHeightRatioFromPasp = false;
...@@ -784,15 +808,14 @@ import java.util.List; ...@@ -784,15 +808,14 @@ import java.util.List;
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position, private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position,
int size, int trackId, String language, boolean isQuickTime, DrmInitData drmInitData, int size, int trackId, String language, boolean isQuickTime, DrmInitData drmInitData,
StsdData out, int entryIndex) { StsdData out, int entryIndex) {
parent.setPosition(position + Atom.HEADER_SIZE); parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE);
int quickTimeSoundDescriptionVersion = 0; int quickTimeSoundDescriptionVersion = 0;
if (isQuickTime) { if (isQuickTime) {
parent.skipBytes(8);
quickTimeSoundDescriptionVersion = parent.readUnsignedShort(); quickTimeSoundDescriptionVersion = parent.readUnsignedShort();
parent.skipBytes(6); parent.skipBytes(6);
} else { } else {
parent.skipBytes(16); parent.skipBytes(8);
} }
int channelCount; int channelCount;
...@@ -1177,6 +1200,8 @@ import java.util.List; ...@@ -1177,6 +1200,8 @@ import java.util.List;
*/ */
private static final class StsdData { private static final class StsdData {
public static final int STSD_HEADER_SIZE = 8;
public final TrackEncryptionBox[] trackEncryptionBoxes; public final TrackEncryptionBox[] trackEncryptionBoxes;
public Format format; public Format format;
......
...@@ -92,7 +92,7 @@ public interface SubtitleDecoderFactory { ...@@ -92,7 +92,7 @@ public interface SubtitleDecoderFactory {
case MimeTypes.APPLICATION_SUBRIP: case MimeTypes.APPLICATION_SUBRIP:
return new SubripDecoder(); return new SubripDecoder();
case MimeTypes.APPLICATION_TX3G: case MimeTypes.APPLICATION_TX3G:
return new Tx3gDecoder(); return new Tx3gDecoder(format.initializationData);
case MimeTypes.APPLICATION_CEA608: case MimeTypes.APPLICATION_CEA608:
case MimeTypes.APPLICATION_MP4CEA608: case MimeTypes.APPLICATION_MP4CEA608:
return new Cea608Decoder(format.sampleMimeType, format.accessibilityChannel); return new Cea608Decoder(format.sampleMimeType, format.accessibilityChannel);
......
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