Commit 51de6e53 by Oliver Woodman

Clean up multiple DVB subtitles per PID support

parent 68ff7e0f
...@@ -156,7 +156,7 @@ public final class TsExtractorTest extends InstrumentationTestCase { ...@@ -156,7 +156,7 @@ public final class TsExtractorTest extends InstrumentationTestCase {
@Override @Override
public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) { public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) {
if (provideCustomEsReader && streamType == 3) { if (provideCustomEsReader && streamType == 3) {
esReader = new CustomEsReader(esInfo.languagesInfo.get(0).languageCode); esReader = new CustomEsReader(esInfo.language);
return new PesReader(esReader); return new PesReader(esReader);
} else { } else {
return defaultFactory.createPayloadReader(streamType, esInfo); return defaultFactory.createPayloadReader(streamType, esInfo);
......
...@@ -93,16 +93,16 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact ...@@ -93,16 +93,16 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact
switch (streamType) { switch (streamType) {
case TsExtractor.TS_STREAM_TYPE_MPA: case TsExtractor.TS_STREAM_TYPE_MPA:
case TsExtractor.TS_STREAM_TYPE_MPA_LSF: case TsExtractor.TS_STREAM_TYPE_MPA_LSF:
return new PesReader(new MpegAudioReader(esInfo.languagesInfo.get(0).languageCode)); return new PesReader(new MpegAudioReader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_AAC: case TsExtractor.TS_STREAM_TYPE_AAC:
return isSet(FLAG_IGNORE_AAC_STREAM) return isSet(FLAG_IGNORE_AAC_STREAM)
? null : new PesReader(new AdtsReader(false, esInfo.languagesInfo.get(0).languageCode)); ? null : new PesReader(new AdtsReader(false, esInfo.language));
case TsExtractor.TS_STREAM_TYPE_AC3: case TsExtractor.TS_STREAM_TYPE_AC3:
case TsExtractor.TS_STREAM_TYPE_E_AC3: case TsExtractor.TS_STREAM_TYPE_E_AC3:
return new PesReader(new Ac3Reader(esInfo.languagesInfo.get(0).languageCode)); return new PesReader(new Ac3Reader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_DTS: case TsExtractor.TS_STREAM_TYPE_DTS:
case TsExtractor.TS_STREAM_TYPE_HDMV_DTS: case TsExtractor.TS_STREAM_TYPE_HDMV_DTS:
return new PesReader(new DtsReader(esInfo.languagesInfo.get(0).languageCode)); return new PesReader(new DtsReader(esInfo.language));
case TsExtractor.TS_STREAM_TYPE_H262: case TsExtractor.TS_STREAM_TYPE_H262:
return new PesReader(new H262Reader()); return new PesReader(new H262Reader());
case TsExtractor.TS_STREAM_TYPE_H264: case TsExtractor.TS_STREAM_TYPE_H264:
...@@ -118,7 +118,7 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact ...@@ -118,7 +118,7 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact
return new PesReader(new Id3Reader()); return new PesReader(new Id3Reader());
case TsExtractor.TS_STREAM_TYPE_DVBSUBS: case TsExtractor.TS_STREAM_TYPE_DVBSUBS:
return new PesReader( return new PesReader(
new DvbSubtitleReader(esInfo)); new DvbSubtitleReader(esInfo.dvbSubtitleInfos));
default: default:
return null; return null;
} }
......
...@@ -19,13 +19,10 @@ import com.google.android.exoplayer2.C; ...@@ -19,13 +19,10 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.DvbSubtitleInfo;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.LanguageInfo;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
...@@ -33,8 +30,8 @@ import java.util.List; ...@@ -33,8 +30,8 @@ import java.util.List;
*/ */
public final class DvbSubtitleReader implements ElementaryStreamReader { public final class DvbSubtitleReader implements ElementaryStreamReader {
private final List<LanguageInfo> languages; private final List<DvbSubtitleInfo> subtitleInfos;
private List<TrackOutput> outputTracks = new ArrayList<>(); private final TrackOutput[] outputs;
private boolean writingSample; private boolean writingSample;
private int bytesToCheck; private int bytesToCheck;
...@@ -42,10 +39,11 @@ public final class DvbSubtitleReader implements ElementaryStreamReader { ...@@ -42,10 +39,11 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
private long sampleTimeUs; private long sampleTimeUs;
/** /**
* @param esInfo Information associated to the elementary stream. * @param subtitleInfos Information about the DVB subtitles associated to the stream.
*/ */
public DvbSubtitleReader(EsInfo esInfo) { public DvbSubtitleReader(List<DvbSubtitleInfo> subtitleInfos) {
this.languages = esInfo.languagesInfo; this.subtitleInfos = subtitleInfos;
outputs = new TrackOutput[subtitleInfos.size()];
} }
@Override @Override
...@@ -55,24 +53,14 @@ public final class DvbSubtitleReader implements ElementaryStreamReader { ...@@ -55,24 +53,14 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
@Override @Override
public void createTracks(ExtractorOutput extractorOutput, TrackIdGenerator idGenerator) { public void createTracks(ExtractorOutput extractorOutput, TrackIdGenerator idGenerator) {
for (int i = 0; i < outputs.length; i++) {
DvbSubtitleInfo subtitleInfo = subtitleInfos.get(i);
idGenerator.generateNewId(); idGenerator.generateNewId();
TrackOutput output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT);
TrackOutput output;
LanguageInfo language;
for (int i = 0; i < languages.size(); i++) {
language = languages.get(i);
idGenerator.generateNewId();
if (((language.programElementType & 0xF0 ) >> 4 ) == 2 ) {
language.languageCode += " for hard of hearing";
}
output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT);
output.format(Format.createImageSampleFormat(idGenerator.getFormatId(), output.format(Format.createImageSampleFormat(idGenerator.getFormatId(),
MimeTypes.APPLICATION_DVBSUBS, null, Format.NO_VALUE, MimeTypes.APPLICATION_DVBSUBS, null, Format.NO_VALUE, subtitleInfo.initializationData,
language.initializationData, language.languageCode, null)); subtitleInfo.language, null));
outputTracks.add(output); outputs[i] = output;
} }
} }
...@@ -90,10 +78,7 @@ public final class DvbSubtitleReader implements ElementaryStreamReader { ...@@ -90,10 +78,7 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
@Override @Override
public void packetFinished() { public void packetFinished() {
if (writingSample) { if (writingSample) {
TrackOutput output; for (TrackOutput output : outputs) {
for (int i = 0; i < outputTracks.size(); i++) {
output = outputTracks.get(i);
output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null); output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null);
} }
writingSample = false; writingSample = false;
...@@ -111,12 +96,10 @@ public final class DvbSubtitleReader implements ElementaryStreamReader { ...@@ -111,12 +96,10 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
// Check and discard the subtitle_stream_id // Check and discard the subtitle_stream_id
return; return;
} }
int bytesAvailable = data.bytesLeft();
TrackOutput output;
int dataPosition = data.getPosition(); int dataPosition = data.getPosition();
for (int i = 0; i < outputTracks.size(); i++) { int bytesAvailable = data.bytesLeft();
for (TrackOutput output : outputs) {
data.setPosition(dataPosition); data.setPosition(dataPosition);
output = outputTracks.get(i);
output.sampleData(data, bytesAvailable); output.sampleData(data, bytesAvailable);
} }
sampleBytesWritten += bytesAvailable; sampleBytesWritten += bytesAvailable;
......
...@@ -28,8 +28,8 @@ import com.google.android.exoplayer2.extractor.PositionHolder; ...@@ -28,8 +28,8 @@ 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.ts.DefaultTsPayloadReaderFactory.Flags; import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory.Flags;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.DvbSubtitleInfo;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.LanguageInfo;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ParsableBitArray; import com.google.android.exoplayer2.util.ParsableBitArray;
...@@ -419,7 +419,7 @@ public final class TsExtractor implements Extractor { ...@@ -419,7 +419,7 @@ public final class TsExtractor implements Extractor {
if (mode == MODE_HLS && id3Reader == null) { if (mode == MODE_HLS && id3Reader == null) {
// Setup an ID3 track regardless of whether there's a corresponding entry, in case one // Setup an ID3 track regardless of whether there's a corresponding entry, in case one
// appears intermittently during playback. See [Internal: b/20261500]. // appears intermittently during playback. See [Internal: b/20261500].
EsInfo dummyEsInfo = new EsInfo(TS_STREAM_TYPE_ID3, null, new byte[0]); EsInfo dummyEsInfo = new EsInfo(TS_STREAM_TYPE_ID3, null, null, new byte[0]);
id3Reader = payloadReaderFactory.createPayloadReader(TS_STREAM_TYPE_ID3, dummyEsInfo); id3Reader = payloadReaderFactory.createPayloadReader(TS_STREAM_TYPE_ID3, dummyEsInfo);
id3Reader.init(timestampAdjuster, output, id3Reader.init(timestampAdjuster, output,
new TrackIdGenerator(programNumber, TS_STREAM_TYPE_ID3, MAX_PID_PLUS_ONE)); new TrackIdGenerator(programNumber, TS_STREAM_TYPE_ID3, MAX_PID_PLUS_ONE));
...@@ -488,7 +488,8 @@ public final class TsExtractor implements Extractor { ...@@ -488,7 +488,8 @@ public final class TsExtractor implements Extractor {
int descriptorsStartPosition = data.getPosition(); int descriptorsStartPosition = data.getPosition();
int descriptorsEndPosition = descriptorsStartPosition + length; int descriptorsEndPosition = descriptorsStartPosition + length;
int streamType = -1; int streamType = -1;
List<LanguageInfo> languages = null; String language = null;
List<DvbSubtitleInfo> dvbSubtitleInfos = null;
while (data.getPosition() < descriptorsEndPosition) { while (data.getPosition() < descriptorsEndPosition) {
int descriptorTag = data.readUnsignedByte(); int descriptorTag = data.readUnsignedByte();
int descriptorLength = data.readUnsignedByte(); int descriptorLength = data.readUnsignedByte();
...@@ -509,35 +510,25 @@ public final class TsExtractor implements Extractor { ...@@ -509,35 +510,25 @@ public final class TsExtractor implements Extractor {
} else if (descriptorTag == TS_PMT_DESC_DTS) { // DTS_descriptor } else if (descriptorTag == TS_PMT_DESC_DTS) { // DTS_descriptor
streamType = TS_STREAM_TYPE_DTS; streamType = TS_STREAM_TYPE_DTS;
} else if (descriptorTag == TS_PMT_DESC_ISO639_LANG) { } else if (descriptorTag == TS_PMT_DESC_ISO639_LANG) {
int position = data.getPosition(); language = data.readString(3).trim();
languages = Collections.singletonList( // Audio type is ignored.
new LanguageInfo(new String(new byte[]
{data.data[position++], data.data[position++], data.data[position++]}).trim(),
data.data[position], null));
} else if (descriptorTag == TS_PMT_DESC_DVBSUBS) { } else if (descriptorTag == TS_PMT_DESC_DVBSUBS) {
streamType = TS_STREAM_TYPE_DVBSUBS; streamType = TS_STREAM_TYPE_DVBSUBS;
int position = data.getPosition(); dvbSubtitleInfos = new ArrayList<>();
String language; while (data.getPosition() < positionOfNextDescriptor) {
byte programElementType; String dvbLanguage = data.readString(3).trim();
byte[] buffer; int dvbProgramElementType = data.readUnsignedByte();
languages = new ArrayList<>(); byte[] initializationData = new byte[4];
while (position < positionOfNextDescriptor) { data.readBytes(initializationData, 0, 4);
buffer = new byte[4]; dvbSubtitleInfos.add(new DvbSubtitleInfo(dvbLanguage, dvbProgramElementType,
language = new String(new byte[] Collections.singletonList(initializationData)));
{data.data[position++], data.data[position++], data.data[position++]}).trim();
programElementType = data.data[position++];
data.setPosition(position);
data.readBytes(buffer, 0,4);
languages.add(
new LanguageInfo(language, programElementType, Collections.singletonList(buffer)));
position += 4;
} }
} }
// Skip unused bytes of current descriptor. // Skip unused bytes of current descriptor.
data.skipBytes(positionOfNextDescriptor - data.getPosition()); data.skipBytes(positionOfNextDescriptor - data.getPosition());
} }
data.setPosition(descriptorsEndPosition); data.setPosition(descriptorsEndPosition);
return new EsInfo(streamType, languages, return new EsInfo(streamType, language, dvbSubtitleInfos,
Arrays.copyOfRange(data.data, descriptorsStartPosition, descriptorsEndPosition)); Arrays.copyOfRange(data.data, descriptorsStartPosition, descriptorsEndPosition));
} }
......
...@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.extractor.TrackOutput; ...@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.TimestampAdjuster;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
...@@ -61,33 +62,44 @@ public interface TsPayloadReader { ...@@ -61,33 +62,44 @@ public interface TsPayloadReader {
final class EsInfo { final class EsInfo {
public final int streamType; public final int streamType;
public final List<LanguageInfo> languagesInfo; public final String language;
public final List<DvbSubtitleInfo> dvbSubtitleInfos;
public final byte[] descriptorBytes; public final byte[] descriptorBytes;
/** /**
* @param streamType The type of the stream as defined by the * @param streamType The type of the stream as defined by the
* {@link TsExtractor}{@code .TS_STREAM_TYPE_*}. * {@link TsExtractor}{@code .TS_STREAM_TYPE_*}.
* @param languagesInfo Language or languages info of the associated program element * @param language The language of the stream, as defined by ISO/IEC 13818-1, section 2.6.18.
* @param dvbSubtitleInfos Information about DVB subtitles associated to the stream.
* @param descriptorBytes The descriptor bytes associated to the stream. * @param descriptorBytes The descriptor bytes associated to the stream.
*/ */
public EsInfo(int streamType, List<LanguageInfo> languagesInfo, byte[] descriptorBytes) { public EsInfo(int streamType, String language, List<DvbSubtitleInfo> dvbSubtitleInfos,
byte[] descriptorBytes) {
this.streamType = streamType; this.streamType = streamType;
this.languagesInfo = languagesInfo; this.language = language;
this.dvbSubtitleInfos = dvbSubtitleInfos == null ? Collections.<DvbSubtitleInfo>emptyList()
: Collections.unmodifiableList(dvbSubtitleInfos);
this.descriptorBytes = descriptorBytes; this.descriptorBytes = descriptorBytes;
} }
} }
final class LanguageInfo { /**
* Holds information about a DVB subtitle.
*/
final class DvbSubtitleInfo {
public String languageCode; public final String language;
public final byte programElementType; public final int programElementType;
public final List<byte[]> initializationData; public final List<byte[]> initializationData;
LanguageInfo (String languageCode, byte programElementType, List<byte[]> initializationData) { public DvbSubtitleInfo(String language, int programElementType,
this.languageCode = languageCode; List<byte[]> initializationData) {
this.language = language;
this.programElementType = programElementType; this.programElementType = programElementType;
this.initializationData = initializationData; this.initializationData = initializationData;
} }
} }
/** /**
......
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