mirror of
https://github.com/androidx/media.git
synced 2025-05-17 12:39:52 +08:00
Clarify SSA and SubRip docs in MatroskaExtractor
The handling of times wasn't really clear to me, hopefully this more exhaustive documentation helps a bit. Also assert the end timecode is the 'correct' length for the format. PiperOrigin-RevId: 279922369
This commit is contained in:
parent
2faef48302
commit
b43db3bceb
@ -236,14 +236,21 @@ public class MatroskaExtractor implements Extractor {
|
|||||||
private static final int FOURCC_COMPRESSION_VC1 = 0x31435657;
|
private static final int FOURCC_COMPRESSION_VC1 = 0x31435657;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A template for the prefix that must be added to each subrip sample. The 12 byte end timecode
|
* A template for the prefix that must be added to each subrip sample.
|
||||||
* starting at {@link #SUBRIP_PREFIX_END_TIMECODE_OFFSET} is set to a dummy value, and must be
|
*
|
||||||
* replaced with the duration of the subtitle.
|
* <p>The display time of each subtitle is passed as {@code timeUs} to {@link
|
||||||
* <p>
|
* TrackOutput#sampleMetadata}. The start and end timecodes in this template are relative to
|
||||||
* Equivalent to the UTF-8 string: "1\n00:00:00,000 --> 00:00:00,000\n".
|
* {@code timeUs}. Hence the start timecode is always zero. The 12 byte end timecode starting at
|
||||||
|
* {@link #SUBRIP_PREFIX_END_TIMECODE_OFFSET} is set to a dummy value, and must be replaced with
|
||||||
|
* the duration of the subtitle.
|
||||||
|
*
|
||||||
|
* <p>Equivalent to the UTF-8 string: "1\n00:00:00,000 --> 00:00:00,000\n".
|
||||||
*/
|
*/
|
||||||
private static final byte[] SUBRIP_PREFIX = new byte[] {49, 10, 48, 48, 58, 48, 48, 58, 48, 48,
|
private static final byte[] SUBRIP_PREFIX =
|
||||||
44, 48, 48, 48, 32, 45, 45, 62, 32, 48, 48, 58, 48, 48, 58, 48, 48, 44, 48, 48, 48, 10};
|
new byte[] {
|
||||||
|
49, 10, 48, 48, 58, 48, 48, 58, 48, 48, 44, 48, 48, 48, 32, 45, 45, 62, 32, 48, 48, 58, 48,
|
||||||
|
48, 58, 48, 48, 44, 48, 48, 48, 10
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* The byte offset of the end timecode in {@link #SUBRIP_PREFIX}.
|
* The byte offset of the end timecode in {@link #SUBRIP_PREFIX}.
|
||||||
*/
|
*/
|
||||||
@ -272,14 +279,21 @@ public class MatroskaExtractor implements Extractor {
|
|||||||
private static final byte[] SSA_DIALOGUE_FORMAT = Util.getUtf8Bytes("Format: Start, End, "
|
private static final byte[] SSA_DIALOGUE_FORMAT = Util.getUtf8Bytes("Format: Start, End, "
|
||||||
+ "ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text");
|
+ "ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text");
|
||||||
/**
|
/**
|
||||||
* A template for the prefix that must be added to each SSA sample. The 10 byte end timecode
|
* A template for the prefix that must be added to each SSA sample.
|
||||||
* starting at {@link #SSA_PREFIX_END_TIMECODE_OFFSET} is set to a dummy value, and must be
|
*
|
||||||
* replaced with the duration of the subtitle.
|
* <p>The display time of each subtitle is passed as {@code timeUs} to {@link
|
||||||
* <p>
|
* TrackOutput#sampleMetadata}. The start and end timecodes in this template are relative to
|
||||||
* Equivalent to the UTF-8 string: "Dialogue: 0:00:00:00,0:00:00:00,".
|
* {@code timeUs}. Hence the start timecode is always zero. The 12 byte end timecode starting at
|
||||||
|
* {@link #SUBRIP_PREFIX_END_TIMECODE_OFFSET} is set to a dummy value, and must be replaced with
|
||||||
|
* the duration of the subtitle.
|
||||||
|
*
|
||||||
|
* <p>Equivalent to the UTF-8 string: "Dialogue: 0:00:00:00,0:00:00:00,".
|
||||||
*/
|
*/
|
||||||
private static final byte[] SSA_PREFIX = new byte[] {68, 105, 97, 108, 111, 103, 117, 101, 58, 32,
|
private static final byte[] SSA_PREFIX =
|
||||||
48, 58, 48, 48, 58, 48, 48, 58, 48, 48, 44, 48, 58, 48, 48, 58, 48, 48, 58, 48, 48, 44};
|
new byte[] {
|
||||||
|
68, 105, 97, 108, 111, 103, 117, 101, 58, 32, 48, 58, 48, 48, 58, 48, 48, 58, 48, 48, 44,
|
||||||
|
48, 58, 48, 48, 58, 48, 48, 58, 48, 48, 44
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* The byte offset of the end timecode in {@link #SSA_PREFIX}.
|
* The byte offset of the end timecode in {@link #SSA_PREFIX}.
|
||||||
*/
|
*/
|
||||||
@ -1468,16 +1482,32 @@ public class MatroskaExtractor implements Extractor {
|
|||||||
|
|
||||||
private void commitSubtitleSample(Track track, String timecodeFormat, int endTimecodeOffset,
|
private void commitSubtitleSample(Track track, String timecodeFormat, int endTimecodeOffset,
|
||||||
long lastTimecodeValueScalingFactor, byte[] emptyTimecode) {
|
long lastTimecodeValueScalingFactor, byte[] emptyTimecode) {
|
||||||
setSampleDuration(subtitleSample.data, blockDurationUs, timecodeFormat, endTimecodeOffset,
|
setSubtitleSampleDuration(
|
||||||
lastTimecodeValueScalingFactor, emptyTimecode);
|
subtitleSample.data,
|
||||||
|
blockDurationUs,
|
||||||
|
timecodeFormat,
|
||||||
|
endTimecodeOffset,
|
||||||
|
lastTimecodeValueScalingFactor,
|
||||||
|
emptyTimecode);
|
||||||
// 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
|
||||||
// appropriate encryption data here.
|
// appropriate encryption data here.
|
||||||
track.output.sampleData(subtitleSample, subtitleSample.limit());
|
track.output.sampleData(subtitleSample, subtitleSample.limit());
|
||||||
sampleBytesWritten += subtitleSample.limit();
|
sampleBytesWritten += subtitleSample.limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setSampleDuration(byte[] subripSampleData, long durationUs,
|
/**
|
||||||
String timecodeFormat, int endTimecodeOffset, long lastTimecodeValueScalingFactor,
|
* Formats {@code durationUs} using {@code timecodeFormat}, and sets it as the end timecode in
|
||||||
|
* {@code subtitleSampleData}.
|
||||||
|
*
|
||||||
|
* <p>See documentation on {@link #SSA_DIALOGUE_FORMAT} and {@link #SUBRIP_PREFIX} for why we use
|
||||||
|
* the duration as the end timecode.
|
||||||
|
*/
|
||||||
|
private static void setSubtitleSampleDuration(
|
||||||
|
byte[] subtitleSampleData,
|
||||||
|
long durationUs,
|
||||||
|
String timecodeFormat,
|
||||||
|
int endTimecodeOffset,
|
||||||
|
long lastTimecodeValueScalingFactor,
|
||||||
byte[] emptyTimecode) {
|
byte[] emptyTimecode) {
|
||||||
byte[] timeCodeData;
|
byte[] timeCodeData;
|
||||||
if (durationUs == C.TIME_UNSET) {
|
if (durationUs == C.TIME_UNSET) {
|
||||||
@ -1493,7 +1523,8 @@ public class MatroskaExtractor implements Extractor {
|
|||||||
timeCodeData = Util.getUtf8Bytes(String.format(Locale.US, timecodeFormat, hours, minutes,
|
timeCodeData = Util.getUtf8Bytes(String.format(Locale.US, timecodeFormat, hours, minutes,
|
||||||
seconds, lastValue));
|
seconds, lastValue));
|
||||||
}
|
}
|
||||||
System.arraycopy(timeCodeData, 0, subripSampleData, endTimecodeOffset, emptyTimecode.length);
|
Assertions.checkState(timeCodeData.length == emptyTimecode.length);
|
||||||
|
System.arraycopy(timeCodeData, 0, subtitleSampleData, endTimecodeOffset, timeCodeData.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user