Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
3db703a9
authored
May 18, 2020
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #7370 from jruesga:embedded-cea-708-support
PiperOrigin-RevId: 312090461
parents
23f58b11
43563997
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
132 additions
and
37 deletions
RELEASENOTES.md
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java
RELEASENOTES.md
View file @
3db703a9
...
...
@@ -156,6 +156,7 @@
`http://dashif.org/guidelines/trickmode`
) into the same
`TrackGroup`
as
the main adaptation sets to which they refer. Trick play tracks are
marked with the
`C.ROLE_FLAG_TRICK_PLAY`
flag.
*
Enable support for embedded CEA-708.
*
Fix assertion failure in
`SampleQueue`
when playing DASH streams with
EMSG tracks (
[
#7273
](
https://github.com/google/ExoPlayer/issues/7273
)
).
*
MP3:
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaPeriod.java
View file @
3db703a9
...
...
@@ -69,7 +69,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
SequenceableLoader
.
Callback
<
ChunkSampleStream
<
DashChunkSource
>>,
ChunkSampleStream
.
ReleaseCallback
<
DashChunkSource
>
{
// Defined by ANSI/SCTE 214-1 2016 7.2.3.
private
static
final
Pattern
CEA608_SERVICE_DESCRIPTOR_REGEX
=
Pattern
.
compile
(
"CC([1-4])=(.+)"
);
// Defined by ANSI/SCTE 214-1 2016 7.2.2.
private
static
final
Pattern
CEA708_SERVICE_DESCRIPTOR_REGEX
=
Pattern
.
compile
(
"([1-4])=lang:(\\w+)(,.+)?"
);
/* package */
final
int
id
;
private
final
DashChunkSource
.
Factory
chunkSourceFactory
;
...
...
@@ -835,49 +839,52 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
for
(
int
j
=
0
;
j
<
descriptors
.
size
();
j
++)
{
Descriptor
descriptor
=
descriptors
.
get
(
j
);
if
(
"urn:scte:dash:cc:cea-608:2015"
.
equals
(
descriptor
.
schemeIdUri
))
{
@Nullable
String
value
=
descriptor
.
value
;
if
(
value
==
null
)
{
// There are embedded CEA-608 tracks, but service information is not declared.
return
new
Format
[]
{
buildCea608TrackFormat
(
adaptationSet
.
id
)};
}
String
[]
services
=
Util
.
split
(
value
,
";"
);
Format
[]
formats
=
new
Format
[
services
.
length
];
for
(
int
k
=
0
;
k
<
services
.
length
;
k
++)
{
Matcher
matcher
=
CEA608_SERVICE_DESCRIPTOR_REGEX
.
matcher
(
services
[
k
]);
if
(!
matcher
.
matches
())
{
// If we can't parse service information for all services, assume a single track.
return
new
Format
[]
{
buildCea608TrackFormat
(
adaptationSet
.
id
)};
}
formats
[
k
]
=
buildCea608TrackFormat
(
adaptationSet
.
id
,
/* language= */
matcher
.
group
(
2
),
/* accessibilityChannel= */
Integer
.
parseInt
(
matcher
.
group
(
1
)));
}
return
formats
;
Format
cea608Format
=
new
Format
.
Builder
()
.
setSampleMimeType
(
MimeTypes
.
APPLICATION_CEA608
)
.
setId
(
adaptationSet
.
id
+
":cea608"
)
.
build
();
return
parseClosedCaptionDescriptor
(
descriptor
,
CEA608_SERVICE_DESCRIPTOR_REGEX
,
cea608Format
);
}
else
if
(
"urn:scte:dash:cc:cea-708:2015"
.
equals
(
descriptor
.
schemeIdUri
))
{
Format
cea708Format
=
new
Format
.
Builder
()
.
setSampleMimeType
(
MimeTypes
.
APPLICATION_CEA708
)
.
setId
(
adaptationSet
.
id
+
":cea708"
)
.
build
();
return
parseClosedCaptionDescriptor
(
descriptor
,
CEA708_SERVICE_DESCRIPTOR_REGEX
,
cea708Format
);
}
}
}
return
new
Format
[
0
];
}
private
static
Format
buildCea608TrackFormat
(
int
adaptationSetId
)
{
return
buildCea608TrackFormat
(
adaptationSetId
,
/* language= */
null
,
/* accessibilityChannel= */
Format
.
NO_VALUE
);
}
private
static
Format
buildCea608TrackFormat
(
int
adaptationSetId
,
@Nullable
String
language
,
int
accessibilityChannel
)
{
String
id
=
adaptationSetId
+
":cea608"
+
(
accessibilityChannel
!=
Format
.
NO_VALUE
?
":"
+
accessibilityChannel
:
""
);
return
new
Format
.
Builder
()
.
setId
(
id
)
.
setSampleMimeType
(
MimeTypes
.
APPLICATION_CEA608
)
.
setLanguage
(
language
)
.
setAccessibilityChannel
(
accessibilityChannel
)
.
build
();
private
static
Format
[]
parseClosedCaptionDescriptor
(
Descriptor
descriptor
,
Pattern
serviceDescriptorRegex
,
Format
baseFormat
)
{
@Nullable
String
value
=
descriptor
.
value
;
if
(
value
==
null
)
{
// There are embedded closed caption tracks, but service information is not declared.
return
new
Format
[]
{
baseFormat
};
}
String
[]
services
=
Util
.
split
(
value
,
";"
);
Format
[]
formats
=
new
Format
[
services
.
length
];
for
(
int
i
=
0
;
i
<
services
.
length
;
i
++)
{
Matcher
matcher
=
serviceDescriptorRegex
.
matcher
(
services
[
i
]);
if
(!
matcher
.
matches
())
{
// If we can't parse service information for all services, assume a single track.
return
new
Format
[]
{
baseFormat
};
}
int
accessibilityChannel
=
Integer
.
parseInt
(
matcher
.
group
(
1
));
formats
[
i
]
=
baseFormat
.
buildUpon
()
.
setId
(
baseFormat
.
id
+
":"
+
accessibilityChannel
)
.
setAccessibilityChannel
(
accessibilityChannel
)
.
setLanguage
(
matcher
.
group
(
2
))
.
build
();
}
return
formats
;
}
// We won't assign the array to a variable that erases the generic type, and then write into it.
...
...
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java
View file @
3db703a9
...
...
@@ -256,6 +256,93 @@ public final class DashMediaPeriodTest {
MediaPeriodAsserts
.
assertTrackGroups
(
dashMediaPeriod
,
expectedTrackGroups
);
}
@Test
public
void
cea608AccessibilityDescriptor_createsCea608TrackGroup
()
{
Descriptor
descriptor
=
new
Descriptor
(
"urn:scte:dash:cc:cea-608:2015"
,
"CC1=eng;CC3=deu"
,
/* id= */
null
);
DashManifest
manifest
=
createDashManifest
(
createPeriod
(
new
AdaptationSet
(
/* id= */
123
,
C
.
TRACK_TYPE_VIDEO
,
Arrays
.
asList
(
createVideoRepresentation
(
/* bitrate= */
0
),
createVideoRepresentation
(
/* bitrate= */
1
)),
/* accessibilityDescriptors= */
Collections
.
singletonList
(
descriptor
),
/* essentialProperties= */
Collections
.
emptyList
(),
/* supplementalProperties= */
Collections
.
emptyList
())));
DashMediaPeriod
dashMediaPeriod
=
createDashMediaPeriod
(
manifest
,
0
);
List
<
AdaptationSet
>
adaptationSets
=
manifest
.
getPeriod
(
0
).
adaptationSets
;
// We expect two adaptation sets. The first containing the video representations, and the second
// containing the embedded CEA-608 tracks.
Format
.
Builder
cea608FormatBuilder
=
new
Format
.
Builder
().
setSampleMimeType
(
MimeTypes
.
APPLICATION_CEA608
);
TrackGroupArray
expectedTrackGroups
=
new
TrackGroupArray
(
new
TrackGroup
(
adaptationSets
.
get
(
0
).
representations
.
get
(
0
).
format
,
adaptationSets
.
get
(
0
).
representations
.
get
(
1
).
format
),
new
TrackGroup
(
cea608FormatBuilder
.
setId
(
"123:cea608:1"
)
.
setLanguage
(
"eng"
)
.
setAccessibilityChannel
(
1
)
.
build
(),
cea608FormatBuilder
.
setId
(
"123:cea608:3"
)
.
setLanguage
(
"deu"
)
.
setAccessibilityChannel
(
3
)
.
build
()));
MediaPeriodAsserts
.
assertTrackGroups
(
dashMediaPeriod
,
expectedTrackGroups
);
}
@Test
public
void
cea708AccessibilityDescriptor_createsCea708TrackGroup
()
{
Descriptor
descriptor
=
new
Descriptor
(
"urn:scte:dash:cc:cea-708:2015"
,
"1=lang:eng;2=lang:deu,war:1,er:1"
,
/* id= */
null
);
DashManifest
manifest
=
createDashManifest
(
createPeriod
(
new
AdaptationSet
(
/* id= */
123
,
C
.
TRACK_TYPE_VIDEO
,
Arrays
.
asList
(
createVideoRepresentation
(
/* bitrate= */
0
),
createVideoRepresentation
(
/* bitrate= */
1
)),
/* accessibilityDescriptors= */
Collections
.
singletonList
(
descriptor
),
/* essentialProperties= */
Collections
.
emptyList
(),
/* supplementalProperties= */
Collections
.
emptyList
())));
DashMediaPeriod
dashMediaPeriod
=
createDashMediaPeriod
(
manifest
,
0
);
List
<
AdaptationSet
>
adaptationSets
=
manifest
.
getPeriod
(
0
).
adaptationSets
;
// We expect two adaptation sets. The first containing the video representations, and the second
// containing the embedded CEA-708 tracks.
Format
.
Builder
cea608FormatBuilder
=
new
Format
.
Builder
().
setSampleMimeType
(
MimeTypes
.
APPLICATION_CEA708
);
TrackGroupArray
expectedTrackGroups
=
new
TrackGroupArray
(
new
TrackGroup
(
adaptationSets
.
get
(
0
).
representations
.
get
(
0
).
format
,
adaptationSets
.
get
(
0
).
representations
.
get
(
1
).
format
),
new
TrackGroup
(
cea608FormatBuilder
.
setId
(
"123:cea708:1"
)
.
setLanguage
(
"eng"
)
.
setAccessibilityChannel
(
1
)
.
build
(),
cea608FormatBuilder
.
setId
(
"123:cea708:2"
)
.
setLanguage
(
"deu"
)
.
setAccessibilityChannel
(
2
)
.
build
()));
MediaPeriodAsserts
.
assertTrackGroups
(
dashMediaPeriod
,
expectedTrackGroups
);
}
private
static
DashMediaPeriod
createDashMediaPeriod
(
DashManifest
manifest
,
int
periodIndex
)
{
return
new
DashMediaPeriod
(
/* id= */
periodIndex
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment