mirror of
https://github.com/androidx/media.git
synced 2025-05-15 11:39:56 +08:00
Added support for multiple RawCC (CEA-608/CEA-708) tracks in DASH.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=138392065
This commit is contained in:
parent
0354ef24d4
commit
a4935a9ba0
@ -64,8 +64,8 @@ public final class FormatTest extends TestCase {
|
|||||||
|
|
||||||
Format formatToParcel = new Format("id", MimeTypes.VIDEO_MP4, MimeTypes.VIDEO_H264, null,
|
Format formatToParcel = new Format("id", MimeTypes.VIDEO_MP4, MimeTypes.VIDEO_H264, null,
|
||||||
1024, 2048, 1920, 1080, 24, 90, 2, projectionData, C.STEREO_MODE_TOP_BOTTOM, 6, 44100,
|
1024, 2048, 1920, 1080, 24, 90, 2, projectionData, C.STEREO_MODE_TOP_BOTTOM, 6, 44100,
|
||||||
C.ENCODING_PCM_24BIT, 1001, 1002, 0, "und", Format.OFFSET_SAMPLE_RELATIVE, INIT_DATA,
|
C.ENCODING_PCM_24BIT, 1001, 1002, 0, "und", Format.NO_VALUE, Format.OFFSET_SAMPLE_RELATIVE,
|
||||||
drmInitData, metadata);
|
INIT_DATA, drmInitData, metadata);
|
||||||
|
|
||||||
Parcel parcel = Parcel.obtain();
|
Parcel parcel = Parcel.obtain();
|
||||||
formatToParcel.writeToParcel(parcel, 0);
|
formatToParcel.writeToParcel(parcel, 0);
|
||||||
|
@ -17,8 +17,10 @@ package com.google.android.exoplayer2.extractor.rawcc;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.test.InstrumentationTestCase;
|
import android.test.InstrumentationTestCase;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.extractor.Extractor;
|
import com.google.android.exoplayer2.extractor.Extractor;
|
||||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||||
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link RawCcExtractor}.
|
* Tests for {@link RawCcExtractor}.
|
||||||
@ -27,12 +29,15 @@ import com.google.android.exoplayer2.testutil.TestUtil;
|
|||||||
public final class RawCcExtractorTest extends InstrumentationTestCase {
|
public final class RawCcExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
public void testRawCcSample() throws Exception {
|
public void testRawCcSample() throws Exception {
|
||||||
TestUtil.assertOutput(new TestUtil.ExtractorFactory() {
|
TestUtil.assertOutput(
|
||||||
@Override
|
new TestUtil.ExtractorFactory() {
|
||||||
public Extractor create() {
|
@Override
|
||||||
return new RawCcExtractor();
|
public Extractor create() {
|
||||||
}
|
return new RawCcExtractor(
|
||||||
}, "rawcc/sample.rawcc", getInstrumentation());
|
Format.createTextContainerFormat(null, null, MimeTypes.APPLICATION_CEA608,
|
||||||
|
"cea608", Format.NO_VALUE, 0, null, 1));
|
||||||
|
}
|
||||||
|
}, "rawcc/sample.rawcc", getInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.dash.manifest;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.test.InstrumentationTestCase;
|
import android.test.InstrumentationTestCase;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -68,4 +69,35 @@ public class DashManifestParserTest extends InstrumentationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testParseCea608AccessibilityChannel() {
|
||||||
|
assertEquals(1, DashManifestParser.parseCea608AccessibilityChannel("CC1=eng"));
|
||||||
|
assertEquals(2, DashManifestParser.parseCea608AccessibilityChannel("CC2=eng"));
|
||||||
|
assertEquals(3, DashManifestParser.parseCea608AccessibilityChannel("CC3=eng"));
|
||||||
|
assertEquals(4, DashManifestParser.parseCea608AccessibilityChannel("CC4=eng"));
|
||||||
|
|
||||||
|
assertEquals(Format.NO_VALUE, DashManifestParser.parseCea608AccessibilityChannel(null));
|
||||||
|
assertEquals(Format.NO_VALUE, DashManifestParser.parseCea608AccessibilityChannel(""));
|
||||||
|
assertEquals(Format.NO_VALUE, DashManifestParser.parseCea608AccessibilityChannel("CC0=eng"));
|
||||||
|
assertEquals(Format.NO_VALUE, DashManifestParser.parseCea608AccessibilityChannel("CC5=eng"));
|
||||||
|
assertEquals(Format.NO_VALUE,
|
||||||
|
DashManifestParser.parseCea608AccessibilityChannel("Wrong format"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testParseCea708AccessibilityChannel() {
|
||||||
|
assertEquals(1, DashManifestParser.parseCea708AccessibilityChannel("1=lang:eng"));
|
||||||
|
assertEquals(2, DashManifestParser.parseCea708AccessibilityChannel("2=lang:eng"));
|
||||||
|
assertEquals(3, DashManifestParser.parseCea708AccessibilityChannel("3=lang:eng"));
|
||||||
|
assertEquals(62, DashManifestParser.parseCea708AccessibilityChannel("62=lang:eng"));
|
||||||
|
assertEquals(63, DashManifestParser.parseCea708AccessibilityChannel("63=lang:eng"));
|
||||||
|
|
||||||
|
assertEquals(Format.NO_VALUE, DashManifestParser.parseCea708AccessibilityChannel(null));
|
||||||
|
assertEquals(Format.NO_VALUE, DashManifestParser.parseCea708AccessibilityChannel(""));
|
||||||
|
assertEquals(Format.NO_VALUE,
|
||||||
|
DashManifestParser.parseCea708AccessibilityChannel("0=lang:eng"));
|
||||||
|
assertEquals(Format.NO_VALUE,
|
||||||
|
DashManifestParser.parseCea708AccessibilityChannel("64=lang:eng"));
|
||||||
|
assertEquals(Format.NO_VALUE,
|
||||||
|
DashManifestParser.parseCea708AccessibilityChannel("Wrong format"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,11 @@ public final class Format implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public final String language;
|
public final String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Accessibility channel, or {@link #NO_VALUE} if not known or applicable.
|
||||||
|
*/
|
||||||
|
public final int accessibilityChannel;
|
||||||
|
|
||||||
// Lazily initialized hashcode and framework media format.
|
// Lazily initialized hashcode and framework media format.
|
||||||
|
|
||||||
private int hashCode;
|
private int hashCode;
|
||||||
@ -190,7 +195,8 @@ public final class Format implements Parcelable {
|
|||||||
float frameRate, List<byte[]> initializationData) {
|
float frameRate, List<byte[]> initializationData) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, width,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, width,
|
||||||
height, frameRate, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
|
height, frameRate, NO_VALUE, NO_VALUE, null, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, 0, null, OFFSET_SAMPLE_RELATIVE, initializationData, null, null);
|
NO_VALUE, NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, null,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Format createVideoSampleFormat(String id, String sampleMimeType, String codecs,
|
public static Format createVideoSampleFormat(String id, String sampleMimeType, String codecs,
|
||||||
@ -215,8 +221,8 @@ public final class Format implements Parcelable {
|
|||||||
byte[] projectionData, @C.StereoMode int stereoMode, DrmInitData drmInitData) {
|
byte[] projectionData, @C.StereoMode int stereoMode, DrmInitData drmInitData) {
|
||||||
return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, width, height,
|
return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, width, height,
|
||||||
frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, NO_VALUE,
|
frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, 0, null, OFFSET_SAMPLE_RELATIVE, initializationData,
|
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE,
|
||||||
drmInitData, null);
|
initializationData, drmInitData, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio.
|
// Audio.
|
||||||
@ -226,8 +232,8 @@ public final class Format implements Parcelable {
|
|||||||
List<byte[]> initializationData, @C.SelectionFlags int selectionFlags, String language) {
|
List<byte[]> initializationData, @C.SelectionFlags int selectionFlags, String language) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, channelCount, sampleRate, NO_VALUE,
|
NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, channelCount, sampleRate, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, selectionFlags, language, OFFSET_SAMPLE_RELATIVE, initializationData,
|
NO_VALUE, NO_VALUE, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE,
|
||||||
null, null);
|
initializationData, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Format createAudioSampleFormat(String id, String sampleMimeType, String codecs,
|
public static Format createAudioSampleFormat(String id, String sampleMimeType, String codecs,
|
||||||
@ -254,7 +260,7 @@ public final class Format implements Parcelable {
|
|||||||
@C.SelectionFlags int selectionFlags, String language, Metadata metadata) {
|
@C.SelectionFlags int selectionFlags, String language, Metadata metadata) {
|
||||||
return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, NO_VALUE, NO_VALUE,
|
return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, channelCount, sampleRate, pcmEncoding,
|
NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, channelCount, sampleRate, pcmEncoding,
|
||||||
encoderDelay, encoderPadding, selectionFlags, language, OFFSET_SAMPLE_RELATIVE,
|
encoderDelay, encoderPadding, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE,
|
||||||
initializationData, drmInitData, metadata);
|
initializationData, drmInitData, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,23 +269,46 @@ public final class Format implements Parcelable {
|
|||||||
public static Format createTextContainerFormat(String id, String containerMimeType,
|
public static Format createTextContainerFormat(String id, String containerMimeType,
|
||||||
String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags,
|
String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags,
|
||||||
String language) {
|
String language) {
|
||||||
|
return createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs, bitrate,
|
||||||
|
selectionFlags, language, NO_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Format createTextContainerFormat(String id, String containerMimeType,
|
||||||
|
String sampleMimeType, String codecs, int bitrate, @C.SelectionFlags int selectionFlags,
|
||||||
|
String language, int accessibilityChannel) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
|
return new Format(id, containerMimeType, 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, OFFSET_SAMPLE_RELATIVE, null, null, null);
|
NO_VALUE, NO_VALUE, selectionFlags, language, accessibilityChannel,
|
||||||
|
OFFSET_SAMPLE_RELATIVE, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
drmInitData, OFFSET_SAMPLE_RELATIVE);
|
NO_VALUE, drmInitData, OFFSET_SAMPLE_RELATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs,
|
||||||
|
int bitrate, @C.SelectionFlags int selectionFlags, String language,
|
||||||
|
int accessibilityChannel, DrmInitData drmInitData) {
|
||||||
|
return createTextSampleFormat(id, sampleMimeType, codecs, bitrate, selectionFlags, language,
|
||||||
|
accessibilityChannel, drmInitData, OFFSET_SAMPLE_RELATIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
NO_VALUE, drmInitData, subsampleOffsetUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Format createTextSampleFormat(String id, String sampleMimeType, String codecs,
|
||||||
|
int bitrate, @C.SelectionFlags int selectionFlags, String language,
|
||||||
|
int accessibilityChannel, DrmInitData drmInitData, long subsampleOffsetUs) {
|
||||||
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, subsampleOffsetUs, null, drmInitData, null);
|
NO_VALUE, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, null,
|
||||||
|
drmInitData, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image.
|
// Image.
|
||||||
@ -288,7 +317,8 @@ public final class Format implements Parcelable {
|
|||||||
int bitrate, List<byte[]> initializationData, String language, DrmInitData drmInitData) {
|
int bitrate, List<byte[]> initializationData, String language, DrmInitData drmInitData) {
|
||||||
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, 0, language, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, null);
|
NO_VALUE, 0, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic.
|
// Generic.
|
||||||
@ -297,14 +327,14 @@ public final class Format implements Parcelable {
|
|||||||
String sampleMimeType, int bitrate) {
|
String sampleMimeType, int bitrate) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, NO_VALUE, NO_VALUE,
|
return new Format(id, containerMimeType, 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, 0, null, OFFSET_SAMPLE_RELATIVE, null, null, null);
|
NO_VALUE, NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Format createSampleFormat(String id, String sampleMimeType, String codecs,
|
public static Format createSampleFormat(String id, String sampleMimeType, String codecs,
|
||||||
int bitrate, DrmInitData drmInitData) {
|
int bitrate, DrmInitData drmInitData) {
|
||||||
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, 0, null, OFFSET_SAMPLE_RELATIVE, null, drmInitData, null);
|
NO_VALUE, 0, null, NO_VALUE, OFFSET_SAMPLE_RELATIVE, null, drmInitData, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ Format(String id, String containerMimeType, String sampleMimeType, String codecs,
|
/* package */ Format(String id, String containerMimeType, String sampleMimeType, String codecs,
|
||||||
@ -312,8 +342,8 @@ public final class Format implements Parcelable {
|
|||||||
float pixelWidthHeightRatio, byte[] projectionData, @C.StereoMode int stereoMode,
|
float pixelWidthHeightRatio, byte[] projectionData, @C.StereoMode int stereoMode,
|
||||||
int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay,
|
int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay,
|
||||||
int encoderPadding, @C.SelectionFlags int selectionFlags, String language,
|
int encoderPadding, @C.SelectionFlags int selectionFlags, String language,
|
||||||
long subsampleOffsetUs, List<byte[]> initializationData, DrmInitData drmInitData,
|
int accessibilityChannel, long subsampleOffsetUs, List<byte[]> initializationData,
|
||||||
Metadata metadata) {
|
DrmInitData drmInitData, Metadata metadata) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.containerMimeType = containerMimeType;
|
this.containerMimeType = containerMimeType;
|
||||||
this.sampleMimeType = sampleMimeType;
|
this.sampleMimeType = sampleMimeType;
|
||||||
@ -334,6 +364,7 @@ public final class Format implements Parcelable {
|
|||||||
this.encoderPadding = encoderPadding;
|
this.encoderPadding = encoderPadding;
|
||||||
this.selectionFlags = selectionFlags;
|
this.selectionFlags = selectionFlags;
|
||||||
this.language = language;
|
this.language = language;
|
||||||
|
this.accessibilityChannel = accessibilityChannel;
|
||||||
this.subsampleOffsetUs = subsampleOffsetUs;
|
this.subsampleOffsetUs = subsampleOffsetUs;
|
||||||
this.initializationData = initializationData == null ? Collections.<byte[]>emptyList()
|
this.initializationData = initializationData == null ? Collections.<byte[]>emptyList()
|
||||||
: initializationData;
|
: initializationData;
|
||||||
@ -364,6 +395,7 @@ public final class Format implements Parcelable {
|
|||||||
encoderPadding = in.readInt();
|
encoderPadding = in.readInt();
|
||||||
selectionFlags = in.readInt();
|
selectionFlags = in.readInt();
|
||||||
language = in.readString();
|
language = in.readString();
|
||||||
|
accessibilityChannel = in.readInt();
|
||||||
subsampleOffsetUs = in.readLong();
|
subsampleOffsetUs = in.readLong();
|
||||||
int initializationDataSize = in.readInt();
|
int initializationDataSize = in.readInt();
|
||||||
initializationData = new ArrayList<>(initializationDataSize);
|
initializationData = new ArrayList<>(initializationDataSize);
|
||||||
@ -378,14 +410,16 @@ public final class Format implements Parcelable {
|
|||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
||||||
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
||||||
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
||||||
selectionFlags, language, subsampleOffsetUs, initializationData, drmInitData, metadata);
|
selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData,
|
||||||
|
drmInitData, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithSubsampleOffsetUs(long subsampleOffsetUs) {
|
public Format copyWithSubsampleOffsetUs(long subsampleOffsetUs) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
||||||
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
||||||
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
||||||
selectionFlags, language, subsampleOffsetUs, initializationData, drmInitData, metadata);
|
selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData,
|
||||||
|
drmInitData, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithContainerInfo(String id, String codecs, int bitrate, int width, int height,
|
public Format copyWithContainerInfo(String id, String codecs, int bitrate, int width, int height,
|
||||||
@ -393,7 +427,8 @@ public final class Format implements Parcelable {
|
|||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
||||||
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
||||||
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
||||||
selectionFlags, language, subsampleOffsetUs, initializationData, drmInitData, metadata);
|
selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData,
|
||||||
|
drmInitData, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithManifestFormatInfo(Format manifestFormat,
|
public Format copyWithManifestFormatInfo(Format manifestFormat,
|
||||||
@ -409,28 +444,32 @@ public final class Format implements Parcelable {
|
|||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width,
|
||||||
height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode,
|
height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode,
|
||||||
channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags,
|
channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags,
|
||||||
language, subsampleOffsetUs, initializationData, drmInitData, metadata);
|
language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData,
|
||||||
|
metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) {
|
public Format copyWithGaplessInfo(int encoderDelay, int encoderPadding) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
||||||
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
||||||
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
||||||
selectionFlags, language, subsampleOffsetUs, initializationData, drmInitData, metadata);
|
selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData,
|
||||||
|
drmInitData, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithDrmInitData(DrmInitData drmInitData) {
|
public Format copyWithDrmInitData(DrmInitData drmInitData) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
||||||
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
||||||
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
||||||
selectionFlags, language, subsampleOffsetUs, initializationData, drmInitData, metadata);
|
selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData,
|
||||||
|
drmInitData, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Format copyWithMetadata(Metadata metadata) {
|
public Format copyWithMetadata(Metadata metadata) {
|
||||||
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize,
|
||||||
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData,
|
||||||
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding,
|
||||||
selectionFlags, language, subsampleOffsetUs, initializationData, drmInitData, metadata);
|
selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData,
|
||||||
|
drmInitData, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -489,6 +528,7 @@ public final class Format implements Parcelable {
|
|||||||
result = 31 * result + channelCount;
|
result = 31 * result + channelCount;
|
||||||
result = 31 * result + sampleRate;
|
result = 31 * result + sampleRate;
|
||||||
result = 31 * result + (language == null ? 0 : language.hashCode());
|
result = 31 * result + (language == null ? 0 : language.hashCode());
|
||||||
|
result = 31 * result + accessibilityChannel;
|
||||||
result = 31 * result + (drmInitData == null ? 0 : drmInitData.hashCode());
|
result = 31 * result + (drmInitData == null ? 0 : drmInitData.hashCode());
|
||||||
result = 31 * result + (metadata == null ? 0 : metadata.hashCode());
|
result = 31 * result + (metadata == null ? 0 : metadata.hashCode());
|
||||||
hashCode = result;
|
hashCode = result;
|
||||||
@ -514,6 +554,7 @@ public final class Format implements Parcelable {
|
|||||||
|| encoderPadding != other.encoderPadding || subsampleOffsetUs != other.subsampleOffsetUs
|
|| encoderPadding != other.encoderPadding || subsampleOffsetUs != other.subsampleOffsetUs
|
||||||
|| selectionFlags != other.selectionFlags || !Util.areEqual(id, other.id)
|
|| selectionFlags != other.selectionFlags || !Util.areEqual(id, other.id)
|
||||||
|| !Util.areEqual(language, other.language)
|
|| !Util.areEqual(language, other.language)
|
||||||
|
|| accessibilityChannel != other.accessibilityChannel
|
||||||
|| !Util.areEqual(containerMimeType, other.containerMimeType)
|
|| !Util.areEqual(containerMimeType, other.containerMimeType)
|
||||||
|| !Util.areEqual(sampleMimeType, other.sampleMimeType)
|
|| !Util.areEqual(sampleMimeType, other.sampleMimeType)
|
||||||
|| !Util.areEqual(codecs, other.codecs)
|
|| !Util.areEqual(codecs, other.codecs)
|
||||||
@ -584,6 +625,7 @@ public final class Format implements Parcelable {
|
|||||||
dest.writeInt(encoderPadding);
|
dest.writeInt(encoderPadding);
|
||||||
dest.writeInt(selectionFlags);
|
dest.writeInt(selectionFlags);
|
||||||
dest.writeString(language);
|
dest.writeString(language);
|
||||||
|
dest.writeInt(accessibilityChannel);
|
||||||
dest.writeLong(subsampleOffsetUs);
|
dest.writeLong(subsampleOffsetUs);
|
||||||
int initializationDataSize = initializationData.size();
|
int initializationDataSize = initializationData.size();
|
||||||
dest.writeInt(initializationDataSize);
|
dest.writeInt(initializationDataSize);
|
||||||
|
@ -24,7 +24,6 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
|||||||
import com.google.android.exoplayer2.extractor.PositionHolder;
|
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.util.MimeTypes;
|
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -45,6 +44,8 @@ public final class RawCcExtractor implements Extractor {
|
|||||||
private static final int STATE_READING_TIMESTAMP_AND_COUNT = 1;
|
private static final int STATE_READING_TIMESTAMP_AND_COUNT = 1;
|
||||||
private static final int STATE_READING_SAMPLES = 2;
|
private static final int STATE_READING_SAMPLES = 2;
|
||||||
|
|
||||||
|
private final Format format;
|
||||||
|
|
||||||
private final ParsableByteArray dataScratch;
|
private final ParsableByteArray dataScratch;
|
||||||
|
|
||||||
private TrackOutput trackOutput;
|
private TrackOutput trackOutput;
|
||||||
@ -55,7 +56,8 @@ public final class RawCcExtractor implements Extractor {
|
|||||||
private int remainingSampleCount;
|
private int remainingSampleCount;
|
||||||
private int sampleBytesWritten;
|
private int sampleBytesWritten;
|
||||||
|
|
||||||
public RawCcExtractor() {
|
public RawCcExtractor(Format format) {
|
||||||
|
this.format = format;
|
||||||
dataScratch = new ParsableByteArray(SCRATCH_SIZE);
|
dataScratch = new ParsableByteArray(SCRATCH_SIZE);
|
||||||
parserState = STATE_READING_HEADER;
|
parserState = STATE_READING_HEADER;
|
||||||
}
|
}
|
||||||
@ -65,9 +67,7 @@ public final class RawCcExtractor implements Extractor {
|
|||||||
output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET));
|
output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET));
|
||||||
trackOutput = output.track(0);
|
trackOutput = output.track(0);
|
||||||
output.endTracks();
|
output.endTracks();
|
||||||
|
trackOutput.format(format);
|
||||||
trackOutput.format(Format.createTextSampleFormat(null, MimeTypes.APPLICATION_CEA608,
|
|
||||||
null, Format.NO_VALUE, 0, null, null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -349,7 +349,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
boolean resendFormatOnInit = false;
|
boolean resendFormatOnInit = false;
|
||||||
Extractor extractor;
|
Extractor extractor;
|
||||||
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
|
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
|
||||||
extractor = new RawCcExtractor();
|
extractor = new RawCcExtractor(representation.format);
|
||||||
resendFormatOnInit = true;
|
resendFormatOnInit = true;
|
||||||
} else if (mimeTypeIsWebm(containerMimeType)) {
|
} else if (mimeTypeIsWebm(containerMimeType)) {
|
||||||
extractor = new MatroskaExtractor();
|
extractor = new MatroskaExtractor();
|
||||||
|
@ -59,6 +59,10 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
|
|
||||||
private static final Pattern FRAME_RATE_PATTERN = Pattern.compile("(\\d+)(?:/(\\d+))?");
|
private static final Pattern FRAME_RATE_PATTERN = Pattern.compile("(\\d+)(?:/(\\d+))?");
|
||||||
|
|
||||||
|
private static final Pattern CEA_608_ACCESSIBILITY_PATTERN = Pattern.compile("CC([1-4])=.*");
|
||||||
|
private static final Pattern CEA_708_ACCESSIBILITY_PATTERN =
|
||||||
|
Pattern.compile("([1-9]|[1-5][0-9]|6[0-3])=.*");
|
||||||
|
|
||||||
private final String contentId;
|
private final String contentId;
|
||||||
private final XmlPullParserFactory xmlParserFactory;
|
private final XmlPullParserFactory xmlParserFactory;
|
||||||
|
|
||||||
@ -235,6 +239,7 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
int audioChannels = Format.NO_VALUE;
|
int audioChannels = Format.NO_VALUE;
|
||||||
int audioSamplingRate = parseInt(xpp, "audioSamplingRate", Format.NO_VALUE);
|
int audioSamplingRate = parseInt(xpp, "audioSamplingRate", Format.NO_VALUE);
|
||||||
String language = xpp.getAttributeValue(null, "lang");
|
String language = xpp.getAttributeValue(null, "lang");
|
||||||
|
int accessibilityChannel = Format.NO_VALUE;
|
||||||
ArrayList<SchemeData> drmSchemeDatas = new ArrayList<>();
|
ArrayList<SchemeData> drmSchemeDatas = new ArrayList<>();
|
||||||
List<RepresentationInfo> representationInfos = new ArrayList<>();
|
List<RepresentationInfo> representationInfos = new ArrayList<>();
|
||||||
|
|
||||||
@ -256,12 +261,15 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
contentType = checkContentTypeConsistency(contentType, parseContentType(xpp));
|
contentType = checkContentTypeConsistency(contentType, parseContentType(xpp));
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "Representation")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "Representation")) {
|
||||||
RepresentationInfo representationInfo = parseRepresentation(xpp, baseUrl, mimeType, codecs,
|
RepresentationInfo representationInfo = parseRepresentation(xpp, baseUrl, mimeType, codecs,
|
||||||
width, height, frameRate, audioChannels, audioSamplingRate, language, segmentBase);
|
width, height, frameRate, audioChannels, audioSamplingRate, language,
|
||||||
|
accessibilityChannel, segmentBase);
|
||||||
contentType = checkContentTypeConsistency(contentType,
|
contentType = checkContentTypeConsistency(contentType,
|
||||||
getContentType(representationInfo.format));
|
getContentType(representationInfo.format));
|
||||||
representationInfos.add(representationInfo);
|
representationInfos.add(representationInfo);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
|
||||||
audioChannels = parseAudioChannelConfiguration(xpp);
|
audioChannels = parseAudioChannelConfiguration(xpp);
|
||||||
|
} else if (XmlPullParserUtil.isStartTag(xpp, "Accessibility")) {
|
||||||
|
accessibilityChannel = parseAccessibilityValue(xpp);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
|
||||||
segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase);
|
segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
||||||
@ -365,7 +373,8 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
protected RepresentationInfo parseRepresentation(XmlPullParser xpp, String baseUrl,
|
protected RepresentationInfo parseRepresentation(XmlPullParser xpp, String baseUrl,
|
||||||
String adaptationSetMimeType, String adaptationSetCodecs, int adaptationSetWidth,
|
String adaptationSetMimeType, String adaptationSetCodecs, int adaptationSetWidth,
|
||||||
int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels,
|
int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels,
|
||||||
int adaptationSetAudioSamplingRate, String adaptationSetLanguage, SegmentBase segmentBase)
|
int adaptationSetAudioSamplingRate, String adaptationSetLanguage,
|
||||||
|
int adaptationSetAccessibilityChannel, SegmentBase segmentBase)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
String id = xpp.getAttributeValue(null, "id");
|
String id = xpp.getAttributeValue(null, "id");
|
||||||
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
|
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
|
||||||
@ -404,7 +413,8 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
} while (!XmlPullParserUtil.isEndTag(xpp, "Representation"));
|
} while (!XmlPullParserUtil.isEndTag(xpp, "Representation"));
|
||||||
|
|
||||||
Format format = buildFormat(id, mimeType, width, height, frameRate, audioChannels,
|
Format format = buildFormat(id, mimeType, width, height, frameRate, audioChannels,
|
||||||
audioSamplingRate, bandwidth, adaptationSetLanguage, codecs);
|
audioSamplingRate, bandwidth, adaptationSetLanguage, adaptationSetAccessibilityChannel,
|
||||||
|
codecs);
|
||||||
segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase(baseUrl);
|
segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase(baseUrl);
|
||||||
|
|
||||||
return new RepresentationInfo(format, baseUrl, segmentBase, drmSchemeDatas);
|
return new RepresentationInfo(format, baseUrl, segmentBase, drmSchemeDatas);
|
||||||
@ -412,7 +422,7 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
|
|
||||||
protected Format buildFormat(String id, String containerMimeType, int width, int height,
|
protected Format buildFormat(String id, String containerMimeType, int width, int height,
|
||||||
float frameRate, int audioChannels, int audioSamplingRate, int bitrate, String language,
|
float frameRate, int audioChannels, int audioSamplingRate, int bitrate, String language,
|
||||||
String codecs) {
|
int accessiblityChannel, String codecs) {
|
||||||
String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
|
String sampleMimeType = getSampleMimeType(containerMimeType, codecs);
|
||||||
if (sampleMimeType != null) {
|
if (sampleMimeType != null) {
|
||||||
if (MimeTypes.isVideo(sampleMimeType)) {
|
if (MimeTypes.isVideo(sampleMimeType)) {
|
||||||
@ -423,7 +433,10 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
bitrate, audioChannels, audioSamplingRate, null, 0, language);
|
bitrate, audioChannels, audioSamplingRate, null, 0, language);
|
||||||
} else if (mimeTypeIsRawText(sampleMimeType)) {
|
} else if (mimeTypeIsRawText(sampleMimeType)) {
|
||||||
return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs,
|
return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs,
|
||||||
bitrate, 0, language);
|
bitrate, 0, language, accessiblityChannel);
|
||||||
|
} else if (containerMimeType.equals(MimeTypes.APPLICATION_RAWCC)) {
|
||||||
|
return Format.createTextContainerFormat(id, containerMimeType, sampleMimeType, codecs,
|
||||||
|
bitrate, 0, language, accessiblityChannel);
|
||||||
} else {
|
} else {
|
||||||
return Format.createContainerFormat(id, containerMimeType, codecs, sampleMimeType, bitrate);
|
return Format.createContainerFormat(id, containerMimeType, codecs, sampleMimeType, bitrate);
|
||||||
}
|
}
|
||||||
@ -726,6 +739,54 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int parseAccessibilityValue(XmlPullParser xpp)
|
||||||
|
throws IOException, XmlPullParserException {
|
||||||
|
String schemeIdUri = parseString(xpp, "schemeIdUri", null);
|
||||||
|
String valueString = parseString(xpp, "value", null);
|
||||||
|
int accessibilityValue;
|
||||||
|
if (schemeIdUri == null || valueString == null) {
|
||||||
|
accessibilityValue = Format.NO_VALUE;
|
||||||
|
} else if ("urn:scte:dash:cc:cea-608:2015".equals(schemeIdUri)) {
|
||||||
|
accessibilityValue = parseCea608AccessibilityChannel(valueString);
|
||||||
|
} else if ("urn:scte:dash:cc:cea-708:2015".equals(schemeIdUri)) {
|
||||||
|
accessibilityValue = parseCea708AccessibilityChannel(valueString);
|
||||||
|
} else {
|
||||||
|
accessibilityValue = Format.NO_VALUE;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
xpp.next();
|
||||||
|
} while (!XmlPullParserUtil.isEndTag(xpp, "Accessibility"));
|
||||||
|
return accessibilityValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseCea608AccessibilityChannel(String accessibilityValueString) {
|
||||||
|
if (accessibilityValueString == null) {
|
||||||
|
return Format.NO_VALUE;
|
||||||
|
}
|
||||||
|
Matcher accessibilityValueMatcher =
|
||||||
|
CEA_608_ACCESSIBILITY_PATTERN.matcher(accessibilityValueString);
|
||||||
|
if (accessibilityValueMatcher.matches()) {
|
||||||
|
return Integer.parseInt(accessibilityValueMatcher.group(1));
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Unable to parse channel number from " + accessibilityValueString);
|
||||||
|
return Format.NO_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseCea708AccessibilityChannel(String accessibilityValueString) {
|
||||||
|
if (accessibilityValueString == null) {
|
||||||
|
return Format.NO_VALUE;
|
||||||
|
}
|
||||||
|
Matcher accessibilityValueMatcher =
|
||||||
|
CEA_708_ACCESSIBILITY_PATTERN.matcher(accessibilityValueString);
|
||||||
|
if (accessibilityValueMatcher.matches()) {
|
||||||
|
return Integer.parseInt(accessibilityValueMatcher.group(1));
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Unable to parse service block number from " + accessibilityValueString);
|
||||||
|
return Format.NO_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static float parseFrameRate(XmlPullParser xpp, float defaultValue) {
|
protected static float parseFrameRate(XmlPullParser xpp, float defaultValue) {
|
||||||
float frameRate = defaultValue;
|
float frameRate = defaultValue;
|
||||||
String frameRateAttribute = xpp.getAttributeValue(null, "frameRate");
|
String frameRateAttribute = xpp.getAttributeValue(null, "frameRate");
|
||||||
|
@ -74,7 +74,12 @@ public interface SubtitleDecoderFactory {
|
|||||||
if (clazz == null) {
|
if (clazz == null) {
|
||||||
throw new IllegalArgumentException("Attempted to create decoder for unsupported format");
|
throw new IllegalArgumentException("Attempted to create decoder for unsupported format");
|
||||||
}
|
}
|
||||||
return clazz.asSubclass(SubtitleDecoder.class).getConstructor().newInstance();
|
if (clazz == Cea608Decoder.class) {
|
||||||
|
return clazz.asSubclass(SubtitleDecoder.class)
|
||||||
|
.getConstructor(Integer.TYPE).newInstance(format.accessibilityChannel);
|
||||||
|
} else {
|
||||||
|
return clazz.asSubclass(SubtitleDecoder.class).getConstructor().newInstance();
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException("Unexpected error instantiating decoder", e);
|
throw new IllegalStateException("Unexpected error instantiating decoder", e);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.text.cea;
|
package com.google.android.exoplayer2.text.cea;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.text.Cue;
|
import com.google.android.exoplayer2.text.Cue;
|
||||||
import com.google.android.exoplayer2.text.Subtitle;
|
import com.google.android.exoplayer2.text.Subtitle;
|
||||||
import com.google.android.exoplayer2.text.SubtitleDecoder;
|
import com.google.android.exoplayer2.text.SubtitleDecoder;
|
||||||
@ -27,9 +28,15 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
|
|||||||
*/
|
*/
|
||||||
public final class Cea608Decoder extends CeaDecoder {
|
public final class Cea608Decoder extends CeaDecoder {
|
||||||
|
|
||||||
private static final int NTSC_CC_FIELD_1 = 0x00;
|
private static final String TAG = "Cea608Decoder";
|
||||||
private static final int CC_TYPE_MASK = 0x03;
|
|
||||||
private static final int CC_VALID_FLAG = 0x04;
|
private static final int CC_VALID_FLAG = 0x04;
|
||||||
|
private static final int CC_TYPE_FLAG = 0x02;
|
||||||
|
private static final int CC_FIELD_FLAG = 0x01;
|
||||||
|
|
||||||
|
private static final int NTSC_CC_FIELD_1 = 0x00;
|
||||||
|
private static final int NTSC_CC_FIELD_2 = 0x01;
|
||||||
|
private static final int CC_VALID_608_ID = 0x04;
|
||||||
|
|
||||||
private static final int PAYLOAD_TYPE_CC = 4;
|
private static final int PAYLOAD_TYPE_CC = 4;
|
||||||
private static final int COUNTRY_CODE = 0xB5;
|
private static final int COUNTRY_CODE = 0xB5;
|
||||||
@ -160,6 +167,8 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
|
|
||||||
private final StringBuilder captionStringBuilder;
|
private final StringBuilder captionStringBuilder;
|
||||||
|
|
||||||
|
private final int selectedField;
|
||||||
|
|
||||||
private int captionMode;
|
private int captionMode;
|
||||||
private int captionRowCount;
|
private int captionRowCount;
|
||||||
private String captionString;
|
private String captionString;
|
||||||
@ -170,10 +179,21 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
private byte repeatableControlCc1;
|
private byte repeatableControlCc1;
|
||||||
private byte repeatableControlCc2;
|
private byte repeatableControlCc2;
|
||||||
|
|
||||||
public Cea608Decoder() {
|
public Cea608Decoder(int accessibilityChannel) {
|
||||||
ccData = new ParsableByteArray();
|
ccData = new ParsableByteArray();
|
||||||
|
|
||||||
captionStringBuilder = new StringBuilder();
|
captionStringBuilder = new StringBuilder();
|
||||||
|
switch (accessibilityChannel) {
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
selectedField = 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case Format.NO_VALUE:
|
||||||
|
default:
|
||||||
|
selectedField = 1;
|
||||||
|
}
|
||||||
|
|
||||||
setCaptionMode(CC_MODE_UNKNOWN);
|
setCaptionMode(CC_MODE_UNKNOWN);
|
||||||
captionRowCount = DEFAULT_CAPTIONS_ROW_COUNT;
|
captionRowCount = DEFAULT_CAPTIONS_ROW_COUNT;
|
||||||
@ -219,14 +239,18 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
boolean captionDataProcessed = false;
|
boolean captionDataProcessed = false;
|
||||||
boolean isRepeatableControl = false;
|
boolean isRepeatableControl = false;
|
||||||
while (ccData.bytesLeft() > 0) {
|
while (ccData.bytesLeft() > 0) {
|
||||||
byte ccTypeAndValid = (byte) (ccData.readUnsignedByte() & 0x07);
|
byte ccDataHeader = (byte) ccData.readUnsignedByte();
|
||||||
byte ccData1 = (byte) (ccData.readUnsignedByte() & 0x7F);
|
byte ccData1 = (byte) (ccData.readUnsignedByte() & 0x7F);
|
||||||
byte ccData2 = (byte) (ccData.readUnsignedByte() & 0x7F);
|
byte ccData2 = (byte) (ccData.readUnsignedByte() & 0x7F);
|
||||||
|
|
||||||
// Only examine valid NTSC_CC_FIELD_1 packets
|
// Only examine valid CEA-608 packets
|
||||||
if ((ccTypeAndValid & CC_VALID_FLAG) == 0
|
if ((ccDataHeader & (CC_VALID_FLAG | CC_TYPE_FLAG)) != CC_VALID_608_ID) {
|
||||||
|| (ccTypeAndValid & CC_TYPE_MASK) != NTSC_CC_FIELD_1) {
|
continue;
|
||||||
// TODO: Add support for NTSC_CC_FIELD_2 packets
|
}
|
||||||
|
|
||||||
|
// Only examine packets within the selected field
|
||||||
|
if ((selectedField == 1 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_1)
|
||||||
|
|| (selectedField == 2 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_2)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user