Plumb SubtitleParser.Factory into TsExtractor
PiperOrigin-RevId: 597578122
This commit is contained in:
parent
c59711f592
commit
a728ec8e67
@ -16,6 +16,7 @@
|
|||||||
package androidx.media3.exoplayer.hls;
|
package androidx.media3.exoplayer.hls;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
|
import static androidx.media3.extractor.ts.TsExtractor.DEFAULT_TIMESTAMP_SEARCH_BYTES;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -205,16 +206,13 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
return createFragmentedMp4Extractor(
|
return createFragmentedMp4Extractor(
|
||||||
subtitleParserFactory, timestampAdjuster, format, muxedCaptionFormats);
|
subtitleParserFactory, timestampAdjuster, format, muxedCaptionFormats);
|
||||||
case FileTypes.TS:
|
case FileTypes.TS:
|
||||||
Extractor tsExtractor =
|
return createTsExtractor(
|
||||||
createTsExtractor(
|
payloadReaderFactoryFlags,
|
||||||
payloadReaderFactoryFlags,
|
exposeCea608WhenMissingDeclarations,
|
||||||
exposeCea608WhenMissingDeclarations,
|
format,
|
||||||
format,
|
muxedCaptionFormats,
|
||||||
muxedCaptionFormats,
|
timestampAdjuster,
|
||||||
timestampAdjuster);
|
subtitleParserFactory);
|
||||||
return subtitleParserFactory != null
|
|
||||||
? new SubtitleTranscodingExtractor(tsExtractor, subtitleParserFactory)
|
|
||||||
: tsExtractor;
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -225,7 +223,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
boolean exposeCea608WhenMissingDeclarations,
|
boolean exposeCea608WhenMissingDeclarations,
|
||||||
Format format,
|
Format format,
|
||||||
@Nullable List<Format> muxedCaptionFormats,
|
@Nullable List<Format> muxedCaptionFormats,
|
||||||
TimestampAdjuster timestampAdjuster) {
|
TimestampAdjuster timestampAdjuster,
|
||||||
|
@Nullable SubtitleParser.Factory subtitleParserFactory) {
|
||||||
@DefaultTsPayloadReaderFactory.Flags
|
@DefaultTsPayloadReaderFactory.Flags
|
||||||
int payloadReaderFactoryFlags =
|
int payloadReaderFactoryFlags =
|
||||||
DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM
|
DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM
|
||||||
@ -254,11 +253,18 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
payloadReaderFactoryFlags |= DefaultTsPayloadReaderFactory.FLAG_IGNORE_H264_STREAM;
|
payloadReaderFactoryFlags |= DefaultTsPayloadReaderFactory.FLAG_IGNORE_H264_STREAM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@TsExtractor.Flags int extractorFlags = 0;
|
||||||
|
if (subtitleParserFactory == null) {
|
||||||
|
subtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
||||||
|
extractorFlags |= TsExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
|
}
|
||||||
return new TsExtractor(
|
return new TsExtractor(
|
||||||
TsExtractor.MODE_HLS,
|
TsExtractor.MODE_HLS,
|
||||||
|
extractorFlags,
|
||||||
|
subtitleParserFactory,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
new DefaultTsPayloadReaderFactory(payloadReaderFactoryFlags, muxedCaptionFormats));
|
new DefaultTsPayloadReaderFactory(payloadReaderFactoryFlags, muxedCaptionFormats),
|
||||||
|
DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FragmentedMp4Extractor createFragmentedMp4Extractor(
|
private static FragmentedMp4Extractor createFragmentedMp4Extractor(
|
||||||
|
@ -440,6 +440,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
textTrackTranscodingEnabled
|
textTrackTranscodingEnabled
|
||||||
&& !(extractor.getUnderlyingImplementation() instanceof FragmentedMp4Extractor)
|
&& !(extractor.getUnderlyingImplementation() instanceof FragmentedMp4Extractor)
|
||||||
&& !(extractor.getUnderlyingImplementation() instanceof Mp4Extractor)
|
&& !(extractor.getUnderlyingImplementation() instanceof Mp4Extractor)
|
||||||
|
&& !(extractor.getUnderlyingImplementation() instanceof TsExtractor)
|
||||||
? new SubtitleTranscodingExtractor(extractor, subtitleParserFactory)
|
? new SubtitleTranscodingExtractor(extractor, subtitleParserFactory)
|
||||||
: extractor;
|
: extractor;
|
||||||
}
|
}
|
||||||
@ -530,6 +531,8 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
|||||||
extractors.add(
|
extractors.add(
|
||||||
new TsExtractor(
|
new TsExtractor(
|
||||||
tsMode,
|
tsMode,
|
||||||
|
(textTrackTranscodingEnabled ? 0 : TsExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA),
|
||||||
|
subtitleParserFactory,
|
||||||
new TimestampAdjuster(0),
|
new TimestampAdjuster(0),
|
||||||
new DefaultTsPayloadReaderFactory(tsFlags, tsSubtitleFormats),
|
new DefaultTsPayloadReaderFactory(tsFlags, tsSubtitleFormats),
|
||||||
tsTimestampSearchBytes));
|
tsTimestampSearchBytes));
|
||||||
|
@ -24,6 +24,7 @@ import android.util.SparseIntArray;
|
|||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.ParserException;
|
import androidx.media3.common.ParserException;
|
||||||
import androidx.media3.common.util.Assertions;
|
import androidx.media3.common.util.Assertions;
|
||||||
import androidx.media3.common.util.NullableType;
|
import androidx.media3.common.util.NullableType;
|
||||||
@ -39,7 +40,8 @@ import androidx.media3.extractor.ExtractorsFactory;
|
|||||||
import androidx.media3.extractor.PositionHolder;
|
import androidx.media3.extractor.PositionHolder;
|
||||||
import androidx.media3.extractor.SeekMap;
|
import androidx.media3.extractor.SeekMap;
|
||||||
import androidx.media3.extractor.TrackOutput;
|
import androidx.media3.extractor.TrackOutput;
|
||||||
import androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory.Flags;
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
|
import androidx.media3.extractor.text.SubtitleTranscodingExtractorOutput;
|
||||||
import androidx.media3.extractor.ts.TsPayloadReader.DvbSubtitleInfo;
|
import androidx.media3.extractor.ts.TsPayloadReader.DvbSubtitleInfo;
|
||||||
import androidx.media3.extractor.ts.TsPayloadReader.EsInfo;
|
import androidx.media3.extractor.ts.TsPayloadReader.EsInfo;
|
||||||
import androidx.media3.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
import androidx.media3.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||||
@ -58,9 +60,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
@UnstableApi
|
@UnstableApi
|
||||||
public final class TsExtractor implements Extractor {
|
public final class TsExtractor implements Extractor {
|
||||||
|
|
||||||
/** Factory for {@link TsExtractor} instances. */
|
/**
|
||||||
|
* @deprecated Use {@link #newFactory(SubtitleParser.Factory)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new TsExtractor()};
|
public static final ExtractorsFactory FACTORY = () -> new Extractor[] {new TsExtractor()};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a factory for {@link TsExtractor} instances with the provided {@link
|
||||||
|
* SubtitleParser.Factory}.
|
||||||
|
*/
|
||||||
|
public static ExtractorsFactory newFactory(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
|
return () -> new Extractor[] {new TsExtractor(subtitleParserFactory)};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modes for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT} or {@link
|
* Modes for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT} or {@link
|
||||||
* #MODE_HLS}.
|
* #MODE_HLS}.
|
||||||
@ -83,6 +96,24 @@ public final class TsExtractor implements Extractor {
|
|||||||
*/
|
*/
|
||||||
public static final int MODE_HLS = 2;
|
public static final int MODE_HLS = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags controlling the behavior of the extractor. Possible flag value is {@link
|
||||||
|
* #FLAG_EMIT_RAW_SUBTITLE_DATA}.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@Target(TYPE_USE)
|
||||||
|
@IntDef(
|
||||||
|
flag = true,
|
||||||
|
value = {FLAG_EMIT_RAW_SUBTITLE_DATA})
|
||||||
|
public @interface Flags {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to use the source subtitle formats without modification. If unset, subtitles will be
|
||||||
|
* transcoded to {@link MimeTypes#APPLICATION_MEDIA3_CUES} during extraction.
|
||||||
|
*/
|
||||||
|
public static final int FLAG_EMIT_RAW_SUBTITLE_DATA = 1;
|
||||||
|
|
||||||
public static final int TS_PACKET_SIZE = 188;
|
public static final int TS_PACKET_SIZE = 188;
|
||||||
public static final int DEFAULT_TIMESTAMP_SEARCH_BYTES = 600 * TS_PACKET_SIZE;
|
public static final int DEFAULT_TIMESTAMP_SEARCH_BYTES = 600 * TS_PACKET_SIZE;
|
||||||
|
|
||||||
@ -121,11 +152,13 @@ public final class TsExtractor implements Extractor {
|
|||||||
private static final int SNIFF_TS_PACKET_COUNT = 5;
|
private static final int SNIFF_TS_PACKET_COUNT = 5;
|
||||||
|
|
||||||
private final @Mode int mode;
|
private final @Mode int mode;
|
||||||
|
private final @Flags int extractorFlags;
|
||||||
private final int timestampSearchBytes;
|
private final int timestampSearchBytes;
|
||||||
private final List<TimestampAdjuster> timestampAdjusters;
|
private final List<TimestampAdjuster> timestampAdjusters;
|
||||||
private final ParsableByteArray tsPacketBuffer;
|
private final ParsableByteArray tsPacketBuffer;
|
||||||
private final SparseIntArray continuityCounters;
|
private final SparseIntArray continuityCounters;
|
||||||
private final TsPayloadReader.Factory payloadReaderFactory;
|
private final TsPayloadReader.Factory payloadReaderFactory;
|
||||||
|
private final SubtitleParser.Factory subtitleParserFactory;
|
||||||
private final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid
|
private final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid
|
||||||
private final SparseBooleanArray trackIds;
|
private final SparseBooleanArray trackIds;
|
||||||
private final SparseBooleanArray trackPids;
|
private final SparseBooleanArray trackPids;
|
||||||
@ -142,57 +175,131 @@ public final class TsExtractor implements Extractor {
|
|||||||
private int bytesSinceLastSync;
|
private int bytesSinceLastSync;
|
||||||
private int pcrPid;
|
private int pcrPid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #TsExtractor(SubtitleParser.Factory)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public TsExtractor() {
|
public TsExtractor() {
|
||||||
this(/* defaultTsPayloadReaderFlags= */ 0);
|
this(
|
||||||
|
MODE_SINGLE_PMT,
|
||||||
|
/* extractorFlags= */ FLAG_EMIT_RAW_SUBTITLE_DATA,
|
||||||
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
new DefaultTsPayloadReaderFactory(/* defaultTsPayloadReaderFlags= */ 0),
|
||||||
|
DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param defaultTsPayloadReaderFlags A combination of {@link DefaultTsPayloadReaderFactory}
|
* Constructs an instance.
|
||||||
* {@code FLAG_*} values that control the behavior of the payload readers.
|
*
|
||||||
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
|
* extraction.
|
||||||
*/
|
*/
|
||||||
public TsExtractor(@Flags int defaultTsPayloadReaderFlags) {
|
public TsExtractor(SubtitleParser.Factory subtitleParserFactory) {
|
||||||
this(MODE_SINGLE_PMT, defaultTsPayloadReaderFlags, DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
this(
|
||||||
|
MODE_SINGLE_PMT,
|
||||||
|
/* extractorFlags= */ 0,
|
||||||
|
subtitleParserFactory,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
new DefaultTsPayloadReaderFactory(/* defaultTsPayloadReaderFlags= */ 0),
|
||||||
|
DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mode Mode for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT}
|
* Constructs an instance.
|
||||||
* and {@link #MODE_HLS}.
|
*
|
||||||
* @param defaultTsPayloadReaderFlags A combination of {@link DefaultTsPayloadReaderFactory}
|
* @param extractorFlags Flags that control the extractor's behavior.
|
||||||
* {@code FLAG_*} values that control the behavior of the payload readers.
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
* @param timestampSearchBytes The number of bytes searched from a given position in the stream to
|
* extraction.
|
||||||
* find a PCR timestamp. If this value is too small, the duration might be unknown and seeking
|
|
||||||
* might not be supported for high bitrate progressive streams. Setting a large value for this
|
|
||||||
* field might be inefficient though because the extractor stores a buffer of {@code
|
|
||||||
* timestampSearchBytes} bytes when determining the duration or when performing a seek
|
|
||||||
* operation. The default value is {@link #DEFAULT_TIMESTAMP_SEARCH_BYTES}. If the number of
|
|
||||||
* bytes left in the stream from the current position is less than {@code
|
|
||||||
* timestampSearchBytes}, the search is performed on the bytes left.
|
|
||||||
*/
|
*/
|
||||||
|
public TsExtractor(@Flags int extractorFlags, SubtitleParser.Factory subtitleParserFactory) {
|
||||||
|
this(
|
||||||
|
MODE_SINGLE_PMT,
|
||||||
|
extractorFlags,
|
||||||
|
subtitleParserFactory,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
new DefaultTsPayloadReaderFactory(/* defaultTsPayloadReaderFlags= */ 0),
|
||||||
|
DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #TsExtractor(int, int, SubtitleParser.Factory, TimestampAdjuster,
|
||||||
|
* TsPayloadReader.Factory, int)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public TsExtractor(@DefaultTsPayloadReaderFactory.Flags int defaultTsPayloadReaderFlags) {
|
||||||
|
this(
|
||||||
|
MODE_SINGLE_PMT,
|
||||||
|
FLAG_EMIT_RAW_SUBTITLE_DATA,
|
||||||
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
new DefaultTsPayloadReaderFactory(defaultTsPayloadReaderFlags),
|
||||||
|
DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #TsExtractor(int, int, SubtitleParser.Factory, TimestampAdjuster,
|
||||||
|
* TsPayloadReader.Factory, int)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public TsExtractor(
|
public TsExtractor(
|
||||||
@Mode int mode, @Flags int defaultTsPayloadReaderFlags, int timestampSearchBytes) {
|
@Mode int mode,
|
||||||
|
@DefaultTsPayloadReaderFactory.Flags int defaultTsPayloadReaderFlags,
|
||||||
|
int timestampSearchBytes) {
|
||||||
this(
|
this(
|
||||||
mode,
|
mode,
|
||||||
|
FLAG_EMIT_RAW_SUBTITLE_DATA,
|
||||||
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
new TimestampAdjuster(0),
|
new TimestampAdjuster(0),
|
||||||
new DefaultTsPayloadReaderFactory(defaultTsPayloadReaderFlags),
|
new DefaultTsPayloadReaderFactory(defaultTsPayloadReaderFlags),
|
||||||
timestampSearchBytes);
|
timestampSearchBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mode Mode for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT}
|
* @deprecated Use {@link #TsExtractor(int, int, SubtitleParser.Factory, TimestampAdjuster,
|
||||||
* and {@link #MODE_HLS}.
|
* TsPayloadReader.Factory, int)} instead.
|
||||||
* @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps.
|
|
||||||
* @param payloadReaderFactory Factory for injecting a custom set of payload readers.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public TsExtractor(
|
public TsExtractor(
|
||||||
@Mode int mode,
|
@Mode int mode,
|
||||||
TimestampAdjuster timestampAdjuster,
|
TimestampAdjuster timestampAdjuster,
|
||||||
TsPayloadReader.Factory payloadReaderFactory) {
|
TsPayloadReader.Factory payloadReaderFactory) {
|
||||||
this(mode, timestampAdjuster, payloadReaderFactory, DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
this(
|
||||||
|
mode,
|
||||||
|
FLAG_EMIT_RAW_SUBTITLE_DATA,
|
||||||
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
|
timestampAdjuster,
|
||||||
|
payloadReaderFactory,
|
||||||
|
DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated Use {@link #TsExtractor(int, int, SubtitleParser.Factory, TimestampAdjuster,
|
||||||
|
* TsPayloadReader.Factory, int)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public TsExtractor(
|
||||||
|
@Mode int mode,
|
||||||
|
TimestampAdjuster timestampAdjuster,
|
||||||
|
TsPayloadReader.Factory payloadReaderFactory,
|
||||||
|
int timestampSearchBytes) {
|
||||||
|
this(
|
||||||
|
mode,
|
||||||
|
FLAG_EMIT_RAW_SUBTITLE_DATA,
|
||||||
|
SubtitleParser.Factory.UNSUPPORTED,
|
||||||
|
timestampAdjuster,
|
||||||
|
payloadReaderFactory,
|
||||||
|
timestampSearchBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance.
|
||||||
|
*
|
||||||
* @param mode Mode for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT}
|
* @param mode Mode for the extractor. One of {@link #MODE_MULTI_PMT}, {@link #MODE_SINGLE_PMT}
|
||||||
* and {@link #MODE_HLS}.
|
* and {@link #MODE_HLS}.
|
||||||
|
* @param extractorFlags Flags that control the extractor's behavior.
|
||||||
|
* @param subtitleParserFactory The {@link SubtitleParser.Factory} for parsing subtitles during
|
||||||
|
* extraction.
|
||||||
* @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps.
|
* @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps.
|
||||||
* @param payloadReaderFactory Factory for injecting a custom set of payload readers.
|
* @param payloadReaderFactory Factory for injecting a custom set of payload readers.
|
||||||
* @param timestampSearchBytes The number of bytes searched from a given position in the stream to
|
* @param timestampSearchBytes The number of bytes searched from a given position in the stream to
|
||||||
@ -206,12 +313,16 @@ public final class TsExtractor implements Extractor {
|
|||||||
*/
|
*/
|
||||||
public TsExtractor(
|
public TsExtractor(
|
||||||
@Mode int mode,
|
@Mode int mode,
|
||||||
|
@Flags int extractorFlags,
|
||||||
|
SubtitleParser.Factory subtitleParserFactory,
|
||||||
TimestampAdjuster timestampAdjuster,
|
TimestampAdjuster timestampAdjuster,
|
||||||
TsPayloadReader.Factory payloadReaderFactory,
|
TsPayloadReader.Factory payloadReaderFactory,
|
||||||
int timestampSearchBytes) {
|
int timestampSearchBytes) {
|
||||||
this.payloadReaderFactory = Assertions.checkNotNull(payloadReaderFactory);
|
this.payloadReaderFactory = Assertions.checkNotNull(payloadReaderFactory);
|
||||||
this.timestampSearchBytes = timestampSearchBytes;
|
this.timestampSearchBytes = timestampSearchBytes;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
this.extractorFlags = extractorFlags;
|
||||||
|
this.subtitleParserFactory = subtitleParserFactory;
|
||||||
if (mode == MODE_SINGLE_PMT || mode == MODE_HLS) {
|
if (mode == MODE_SINGLE_PMT || mode == MODE_HLS) {
|
||||||
timestampAdjusters = Collections.singletonList(timestampAdjuster);
|
timestampAdjusters = Collections.singletonList(timestampAdjuster);
|
||||||
} else {
|
} else {
|
||||||
@ -254,7 +365,10 @@ public final class TsExtractor implements Extractor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(ExtractorOutput output) {
|
public void init(ExtractorOutput output) {
|
||||||
this.output = output;
|
this.output =
|
||||||
|
(extractorFlags & FLAG_EMIT_RAW_SUBTITLE_DATA) == 0
|
||||||
|
? new SubtitleTranscodingExtractorOutput(output, subtitleParserFactory)
|
||||||
|
: output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -179,7 +179,7 @@ public final class DefaultExtractorsFactoryTest {
|
|||||||
assertThat(matroskaExtractor).isInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(matroskaExtractor).isInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
assertThat(mp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(mp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
assertThat(fragmentedMp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(fragmentedMp4Extractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
assertThat(tsExtractor).isInstanceOf(SubtitleTranscodingExtractor.class);
|
assertThat(tsExtractor).isNotInstanceOf(SubtitleTranscodingExtractor.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Class<? extends Extractor>> getUnderlyingExtractorClasses(
|
private static List<Class<? extends Extractor>> getUnderlyingExtractorClasses(
|
||||||
|
@ -24,6 +24,7 @@ import androidx.media3.extractor.Extractor;
|
|||||||
import androidx.media3.extractor.ExtractorInput;
|
import androidx.media3.extractor.ExtractorInput;
|
||||||
import androidx.media3.extractor.PositionHolder;
|
import androidx.media3.extractor.PositionHolder;
|
||||||
import androidx.media3.extractor.SeekMap;
|
import androidx.media3.extractor.SeekMap;
|
||||||
|
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||||
import androidx.media3.test.utils.FakeExtractorOutput;
|
import androidx.media3.test.utils.FakeExtractorOutput;
|
||||||
import androidx.media3.test.utils.FakeTrackOutput;
|
import androidx.media3.test.utils.FakeTrackOutput;
|
||||||
import androidx.media3.test.utils.TestUtil;
|
import androidx.media3.test.utils.TestUtil;
|
||||||
@ -56,7 +57,9 @@ public final class TsExtractorSeekTest {
|
|||||||
positionHolder = new PositionHolder();
|
positionHolder = new PositionHolder();
|
||||||
expectedTrackOutput =
|
expectedTrackOutput =
|
||||||
TestUtil.extractAllSamplesFromFile(
|
TestUtil.extractAllSamplesFromFile(
|
||||||
new TsExtractor(), ApplicationProvider.getApplicationContext(), TEST_FILE)
|
new TsExtractor(new DefaultSubtitleParserFactory()),
|
||||||
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
TEST_FILE)
|
||||||
.trackOutputs
|
.trackOutputs
|
||||||
.get(AUDIO_TRACK_ID);
|
.get(AUDIO_TRACK_ID);
|
||||||
|
|
||||||
@ -68,7 +71,7 @@ public final class TsExtractorSeekTest {
|
|||||||
@Test
|
@Test
|
||||||
public void tsExtractorReads_nonSeekTableFile_returnSeekableSeekMap() throws IOException {
|
public void tsExtractorReads_nonSeekTableFile_returnSeekableSeekMap() throws IOException {
|
||||||
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
||||||
TsExtractor extractor = new TsExtractor();
|
TsExtractor extractor = new TsExtractor(new DefaultSubtitleParserFactory());
|
||||||
|
|
||||||
SeekMap seekMap =
|
SeekMap seekMap =
|
||||||
TestUtil.extractSeekMap(extractor, new FakeExtractorOutput(), dataSource, fileUri);
|
TestUtil.extractSeekMap(extractor, new FakeExtractorOutput(), dataSource, fileUri);
|
||||||
@ -81,7 +84,7 @@ public final class TsExtractorSeekTest {
|
|||||||
@Test
|
@Test
|
||||||
public void handlePendingSeek_handlesSeekingToPositionInFile_extractsCorrectFrame()
|
public void handlePendingSeek_handlesSeekingToPositionInFile_extractsCorrectFrame()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
TsExtractor extractor = new TsExtractor();
|
TsExtractor extractor = new TsExtractor(new DefaultSubtitleParserFactory());
|
||||||
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
||||||
|
|
||||||
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
||||||
@ -100,7 +103,7 @@ public final class TsExtractorSeekTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlePendingSeek_handlesSeekToEoF_extractsLastFrame() throws IOException {
|
public void handlePendingSeek_handlesSeekToEoF_extractsLastFrame() throws IOException {
|
||||||
TsExtractor extractor = new TsExtractor();
|
TsExtractor extractor = new TsExtractor(new DefaultSubtitleParserFactory());
|
||||||
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
||||||
|
|
||||||
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
||||||
@ -120,7 +123,7 @@ public final class TsExtractorSeekTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlePendingSeek_handlesSeekingBackward_extractsCorrectFrame() throws IOException {
|
public void handlePendingSeek_handlesSeekingBackward_extractsCorrectFrame() throws IOException {
|
||||||
TsExtractor extractor = new TsExtractor();
|
TsExtractor extractor = new TsExtractor(new DefaultSubtitleParserFactory());
|
||||||
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
||||||
|
|
||||||
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
||||||
@ -142,7 +145,7 @@ public final class TsExtractorSeekTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlePendingSeek_handlesSeekingForward_extractsCorrectFrame() throws IOException {
|
public void handlePendingSeek_handlesSeekingForward_extractsCorrectFrame() throws IOException {
|
||||||
TsExtractor extractor = new TsExtractor();
|
TsExtractor extractor = new TsExtractor(new DefaultSubtitleParserFactory());
|
||||||
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
||||||
|
|
||||||
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
||||||
@ -164,7 +167,7 @@ public final class TsExtractorSeekTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlePendingSeek_handlesRandomSeeks_extractsCorrectFrame() throws IOException {
|
public void handlePendingSeek_handlesRandomSeeks_extractsCorrectFrame() throws IOException {
|
||||||
TsExtractor extractor = new TsExtractor();
|
TsExtractor extractor = new TsExtractor(new DefaultSubtitleParserFactory());
|
||||||
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
||||||
|
|
||||||
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
||||||
@ -187,7 +190,7 @@ public final class TsExtractorSeekTest {
|
|||||||
@Test
|
@Test
|
||||||
public void handlePendingSeek_handlesRandomSeeksAfterReadingFileOnce_extractsCorrectFrame()
|
public void handlePendingSeek_handlesRandomSeeksAfterReadingFileOnce_extractsCorrectFrame()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
TsExtractor extractor = new TsExtractor();
|
TsExtractor extractor = new TsExtractor(new DefaultSubtitleParserFactory());
|
||||||
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
Uri fileUri = TestUtil.buildAssetUri(TEST_FILE);
|
||||||
|
|
||||||
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
FakeExtractorOutput extractorOutput = new FakeExtractorOutput();
|
||||||
|
@ -15,7 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.extractor.ts;
|
package androidx.media3.extractor.ts;
|
||||||
|
|
||||||
|
import static androidx.media3.extractor.mp4.FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
import static androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS;
|
import static androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS;
|
||||||
|
import static androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory.FLAG_ENABLE_HDMV_DTS_AUDIO_STREAMS;
|
||||||
|
import static androidx.media3.extractor.ts.TsExtractor.DEFAULT_TIMESTAMP_SEARCH_BYTES;
|
||||||
|
import static androidx.media3.extractor.ts.TsExtractor.MODE_MULTI_PMT;
|
||||||
|
import static androidx.media3.extractor.ts.TsExtractor.MODE_SINGLE_PMT;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@ -28,6 +33,8 @@ import androidx.media3.extractor.Extractor;
|
|||||||
import androidx.media3.extractor.ExtractorOutput;
|
import androidx.media3.extractor.ExtractorOutput;
|
||||||
import androidx.media3.extractor.PositionHolder;
|
import androidx.media3.extractor.PositionHolder;
|
||||||
import androidx.media3.extractor.TrackOutput;
|
import androidx.media3.extractor.TrackOutput;
|
||||||
|
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||||
|
import androidx.media3.extractor.text.SubtitleParser;
|
||||||
import androidx.media3.extractor.ts.TsPayloadReader.EsInfo;
|
import androidx.media3.extractor.ts.TsPayloadReader.EsInfo;
|
||||||
import androidx.media3.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
import androidx.media3.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||||
import androidx.media3.test.utils.ExtractorAsserts;
|
import androidx.media3.test.utils.ExtractorAsserts;
|
||||||
@ -36,7 +43,8 @@ import androidx.media3.test.utils.FakeExtractorOutput;
|
|||||||
import androidx.media3.test.utils.FakeTrackOutput;
|
import androidx.media3.test.utils.FakeTrackOutput;
|
||||||
import androidx.media3.test.utils.TestUtil;
|
import androidx.media3.test.utils.TestUtil;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import com.google.common.collect.ImmutableList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.ParameterizedRobolectricTestRunner;
|
import org.robolectric.ParameterizedRobolectricTestRunner;
|
||||||
@ -47,39 +55,62 @@ import org.robolectric.ParameterizedRobolectricTestRunner.Parameters;
|
|||||||
@RunWith(ParameterizedRobolectricTestRunner.class)
|
@RunWith(ParameterizedRobolectricTestRunner.class)
|
||||||
public final class TsExtractorTest {
|
public final class TsExtractorTest {
|
||||||
|
|
||||||
@Parameters(name = "{0}")
|
@Parameters(name = "{0},subtitlesParsedDuringExtraction={1}")
|
||||||
public static ImmutableList<ExtractorAsserts.SimulationConfig> params() {
|
public static List<Object[]> params() {
|
||||||
return ExtractorAsserts.configs();
|
List<Object[]> parameterList = new ArrayList<>();
|
||||||
|
for (ExtractorAsserts.SimulationConfig config : ExtractorAsserts.configs()) {
|
||||||
|
parameterList.add(new Object[] {config, /* subtitlesParsedDuringExtraction */ true});
|
||||||
|
parameterList.add(new Object[] {config, /* subtitlesParsedDuringExtraction */ false});
|
||||||
|
}
|
||||||
|
return parameterList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parameter public ExtractorAsserts.SimulationConfig simulationConfig;
|
@Parameter(0)
|
||||||
|
public ExtractorAsserts.SimulationConfig simulationConfig;
|
||||||
|
|
||||||
|
@Parameter(1)
|
||||||
|
public boolean subtitlesParsedDuringExtraction;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithH262AndMpegAudio() throws Exception {
|
public void sampleWithH262AndMpegAudio() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
TsExtractor::new, "media/ts/sample_h262_mpeg_audio.ts", simulationConfig);
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_h262_mpeg_audio.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithH263() throws Exception {
|
public void sampleWithH263() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_h263.ts", simulationConfig);
|
ExtractorAsserts.assertBehavior(
|
||||||
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_h263.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithH264() throws Exception {
|
public void sampleWithH264() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_h264.ts", simulationConfig);
|
ExtractorAsserts.assertBehavior(
|
||||||
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_h264.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithH264AndMpegAudio() throws Exception {
|
public void sampleWithH264AndMpegAudio() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
TsExtractor::new, "media/ts/sample_h264_mpeg_audio.ts", simulationConfig);
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_h264_mpeg_audio.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithH264NoAccessUnitDelimiters() throws Exception {
|
public void sampleWithH264NoAccessUnitDelimiters() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
() -> new TsExtractor(FLAG_DETECT_ACCESS_UNITS),
|
getExtractorFactory(
|
||||||
|
subtitlesParsedDuringExtraction,
|
||||||
|
MODE_SINGLE_PMT,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
new DefaultTsPayloadReaderFactory(FLAG_DETECT_ACCESS_UNITS)),
|
||||||
"media/ts/sample_h264_no_access_unit_delimiters.ts",
|
"media/ts/sample_h264_no_access_unit_delimiters.ts",
|
||||||
simulationConfig);
|
simulationConfig);
|
||||||
}
|
}
|
||||||
@ -87,26 +118,35 @@ public final class TsExtractorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void sampleWithH264AndDtsAudio() throws Exception {
|
public void sampleWithH264AndDtsAudio() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
() -> new TsExtractor(DefaultTsPayloadReaderFactory.FLAG_ENABLE_HDMV_DTS_AUDIO_STREAMS),
|
getExtractorFactory(
|
||||||
|
subtitlesParsedDuringExtraction,
|
||||||
|
MODE_SINGLE_PMT,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
new DefaultTsPayloadReaderFactory(FLAG_ENABLE_HDMV_DTS_AUDIO_STREAMS)),
|
||||||
"media/ts/sample_h264_dts_audio.ts",
|
"media/ts/sample_h264_dts_audio.ts",
|
||||||
simulationConfig);
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithH265() throws Exception {
|
public void sampleWithH265() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_h265.ts", simulationConfig);
|
ExtractorAsserts.assertBehavior(
|
||||||
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_h265.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithH265RpsPred() throws Exception {
|
public void sampleWithH265RpsPred() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
TsExtractor::new, "media/ts/sample_h265_rps_pred.ts", simulationConfig);
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_h265_rps_pred.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithScte35() throws Exception {
|
public void sampleWithScte35() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
TsExtractor::new,
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
"media/ts/sample_scte35.ts",
|
"media/ts/sample_scte35.ts",
|
||||||
new ExtractorAsserts.AssertionConfig.Builder()
|
new ExtractorAsserts.AssertionConfig.Builder()
|
||||||
.setDeduplicateConsecutiveFormats(true)
|
.setDeduplicateConsecutiveFormats(true)
|
||||||
@ -117,7 +157,7 @@ public final class TsExtractorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void sampleWithAit() throws Exception {
|
public void sampleWithAit() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
TsExtractor::new,
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
"media/ts/sample_ait.ts",
|
"media/ts/sample_ait.ts",
|
||||||
new ExtractorAsserts.AssertionConfig.Builder()
|
new ExtractorAsserts.AssertionConfig.Builder()
|
||||||
.setDeduplicateConsecutiveFormats(true)
|
.setDeduplicateConsecutiveFormats(true)
|
||||||
@ -127,41 +167,63 @@ public final class TsExtractorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithAc3() throws Exception {
|
public void sampleWithAc3() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_ac3.ts", simulationConfig);
|
ExtractorAsserts.assertBehavior(
|
||||||
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_ac3.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithAc4() throws Exception {
|
public void sampleWithAc4() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_ac4.ts", simulationConfig);
|
ExtractorAsserts.assertBehavior(
|
||||||
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_ac4.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithEac3() throws Exception {
|
public void sampleWithEac3() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_eac3.ts", simulationConfig);
|
ExtractorAsserts.assertBehavior(
|
||||||
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_eac3.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithEac3joc() throws Exception {
|
public void sampleWithEac3joc() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
TsExtractor::new, "media/ts/sample_eac3joc.ts", simulationConfig);
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_eac3joc.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sampleWithLatm() throws Exception {
|
public void sampleWithLatm() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(TsExtractor::new, "media/ts/sample_latm.ts", simulationConfig);
|
ExtractorAsserts.assertBehavior(
|
||||||
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_latm.ts",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void streamWithJunkData() throws Exception {
|
public void streamWithJunkData() throws Exception {
|
||||||
ExtractorAsserts.assertBehavior(
|
ExtractorAsserts.assertBehavior(
|
||||||
TsExtractor::new, "media/ts/sample_with_junk", simulationConfig);
|
getExtractorFactory(subtitlesParsedDuringExtraction),
|
||||||
|
"media/ts/sample_with_junk",
|
||||||
|
simulationConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void customPesReader() throws Exception {
|
public void customPesReader() throws Exception {
|
||||||
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false);
|
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false);
|
||||||
TsExtractor tsExtractor =
|
TsExtractor tsExtractor =
|
||||||
new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory);
|
(TsExtractor)
|
||||||
|
getExtractorFactory(
|
||||||
|
subtitlesParsedDuringExtraction,
|
||||||
|
MODE_MULTI_PMT,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
factory)
|
||||||
|
.create();
|
||||||
FakeExtractorInput input =
|
FakeExtractorInput input =
|
||||||
new FakeExtractorInput.Builder()
|
new FakeExtractorInput.Builder()
|
||||||
.setData(
|
.setData(
|
||||||
@ -199,7 +261,13 @@ public final class TsExtractorTest {
|
|||||||
public void customInitialSectionReader() throws Exception {
|
public void customInitialSectionReader() throws Exception {
|
||||||
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true);
|
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true);
|
||||||
TsExtractor tsExtractor =
|
TsExtractor tsExtractor =
|
||||||
new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory);
|
(TsExtractor)
|
||||||
|
getExtractorFactory(
|
||||||
|
subtitlesParsedDuringExtraction,
|
||||||
|
MODE_MULTI_PMT,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
factory)
|
||||||
|
.create();
|
||||||
FakeExtractorInput input =
|
FakeExtractorInput input =
|
||||||
new FakeExtractorInput.Builder()
|
new FakeExtractorInput.Builder()
|
||||||
.setData(
|
.setData(
|
||||||
@ -221,6 +289,39 @@ public final class TsExtractorTest {
|
|||||||
assertThat(factory.sdtReader.consumedSdts).isEqualTo(2);
|
assertThat(factory.sdtReader.consumedSdts).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ExtractorAsserts.ExtractorFactory getExtractorFactory(
|
||||||
|
boolean subtitlesParsedDuringExtraction) {
|
||||||
|
return getExtractorFactory(
|
||||||
|
subtitlesParsedDuringExtraction,
|
||||||
|
MODE_SINGLE_PMT,
|
||||||
|
new TimestampAdjuster(0),
|
||||||
|
new DefaultTsPayloadReaderFactory(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExtractorAsserts.ExtractorFactory getExtractorFactory(
|
||||||
|
boolean subtitlesParsedDuringExtraction,
|
||||||
|
@TsExtractor.Mode int mode,
|
||||||
|
TimestampAdjuster timestampAdjuster,
|
||||||
|
TsPayloadReader.Factory payloadReaderFactory) {
|
||||||
|
SubtitleParser.Factory subtitleParserFactory;
|
||||||
|
@TsExtractor.Flags int flags;
|
||||||
|
if (subtitlesParsedDuringExtraction) {
|
||||||
|
subtitleParserFactory = new DefaultSubtitleParserFactory();
|
||||||
|
flags = 0;
|
||||||
|
} else {
|
||||||
|
subtitleParserFactory = SubtitleParser.Factory.UNSUPPORTED;
|
||||||
|
flags = FLAG_EMIT_RAW_SUBTITLE_DATA;
|
||||||
|
}
|
||||||
|
return () ->
|
||||||
|
new TsExtractor(
|
||||||
|
mode,
|
||||||
|
flags,
|
||||||
|
subtitleParserFactory,
|
||||||
|
timestampAdjuster,
|
||||||
|
payloadReaderFactory,
|
||||||
|
DEFAULT_TIMESTAMP_SEARCH_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
private static final class CustomTsPayloadReaderFactory implements TsPayloadReader.Factory {
|
private static final class CustomTsPayloadReaderFactory implements TsPayloadReader.Factory {
|
||||||
|
|
||||||
private final boolean provideSdtReader;
|
private final boolean provideSdtReader;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user