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
38bc7355
authored
Jan 16, 2020
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Merge pull request #6678 from phhusson:feature/enable-multi-metadata-tracks
PiperOrigin-RevId: 290032841
parent
5bdcb5fd
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
135 additions
and
57 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java
library/core/src/test/java/com/google/android/exoplayer2/trackselection/MappingTrackSelectorTest.java
RELEASENOTES.md
View file @
38bc7355
...
...
@@ -44,6 +44,8 @@
media segment has been established.
*
Reduce startup latency for on-demand DASH playbacks by allowing codec
initialization to occur before the sidx box has been loaded.
*
Select multiple metadata tracks if multiple metadata renderers are available
(
[
#6676
](
https://github.com/google/ExoPlayer/issues/6676
)
).
### 2.11.1 (2019-12-20) ###
...
...
library/core/src/main/java/com/google/android/exoplayer2/trackselection/MappingTrackSelector.java
View file @
38bc7355
...
...
@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.Timeline;
import
com.google.android.exoplayer2.source.MediaSource.MediaPeriodId
;
import
com.google.android.exoplayer2.source.TrackGroup
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.Util
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
...
...
@@ -359,7 +360,11 @@ public abstract class MappingTrackSelector extends TrackSelector {
for
(
int
groupIndex
=
0
;
groupIndex
<
trackGroups
.
length
;
groupIndex
++)
{
TrackGroup
group
=
trackGroups
.
get
(
groupIndex
);
// Associate the group to a preferred renderer.
int
rendererIndex
=
findRenderer
(
rendererCapabilities
,
group
);
boolean
preferUnassociatedRenderer
=
MimeTypes
.
getTrackType
(
group
.
getFormat
(
0
).
sampleMimeType
)
==
C
.
TRACK_TYPE_METADATA
;
int
rendererIndex
=
findRenderer
(
rendererCapabilities
,
group
,
rendererTrackGroupCounts
,
preferUnassociatedRenderer
);
// Evaluate the support that the renderer provides for each track in the group.
@Capabilities
int
[]
rendererFormatSupport
=
...
...
@@ -431,43 +436,65 @@ public abstract class MappingTrackSelector extends TrackSelector {
/**
* Finds the renderer to which the provided {@link TrackGroup} should be mapped.
* <p>
* A {@link TrackGroup} is mapped to the renderer that reports the highest of (listed in
* decreasing order of support) {@link RendererCapabilities#FORMAT_HANDLED},
* {@link RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES},
* {@link RendererCapabilities#FORMAT_UNSUPPORTED_DRM} and
* {@link RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE}. In the case that two or more renderers
* report the same level of support, the renderer with the lowest index is associated.
* <p>
* If all renderers report {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} for all of the
*
* <p>A {@link TrackGroup} is mapped to the renderer that reports the highest of (listed in
* decreasing order of support) {@link RendererCapabilities#FORMAT_HANDLED}, {@link
* RendererCapabilities#FORMAT_EXCEEDS_CAPABILITIES}, {@link
* RendererCapabilities#FORMAT_UNSUPPORTED_DRM} and {@link
* RendererCapabilities#FORMAT_UNSUPPORTED_SUBTYPE}.
*
* <p>In the case that two or more renderers report the same level of support, the assignment
* depends on {@code preferUnassociatedRenderer}.
*
* <ul>
* <li>If {@code preferUnassociatedRenderer} is false, the renderer with the lowest index is
* chosen regardless of how many other track groups are already mapped to this renderer.
* <li>If {@code preferUnassociatedRenderer} is true, the renderer with the lowest index and no
* other mapped track group is chosen, or the renderer with the lowest index if all
* available renderers have already mapped track groups.
* </ul>
*
* <p>If all renderers report {@link RendererCapabilities#FORMAT_UNSUPPORTED_TYPE} for all of the
* tracks in the group, then {@code renderers.length} is returned to indicate that the group was
* not mapped to any renderer.
*
* @param rendererCapabilities The {@link RendererCapabilities} of the renderers.
* @param group The track group to map to a renderer.
* @return The index of the renderer to which the track group was mapped, or
* {@code renderers.length} if it was not mapped to any renderer.
* @param rendererTrackGroupCounts The number of already mapped track groups for each renderer.
* @param preferUnassociatedRenderer Whether renderers unassociated to any track group should be
* preferred.
* @return The index of the renderer to which the track group was mapped, or {@code
* renderers.length} if it was not mapped to any renderer.
* @throws ExoPlaybackException If an error occurs finding a renderer.
*/
private
static
int
findRenderer
(
RendererCapabilities
[]
rendererCapabilities
,
TrackGroup
group
)
private
static
int
findRenderer
(
RendererCapabilities
[]
rendererCapabilities
,
TrackGroup
group
,
int
[]
rendererTrackGroupCounts
,
boolean
preferUnassociatedRenderer
)
throws
ExoPlaybackException
{
int
bestRendererIndex
=
rendererCapabilities
.
length
;
@FormatSupport
int
bestFormatSupportLevel
=
RendererCapabilities
.
FORMAT_UNSUPPORTED_TYPE
;
boolean
bestRendererIsUnassociated
=
true
;
for
(
int
rendererIndex
=
0
;
rendererIndex
<
rendererCapabilities
.
length
;
rendererIndex
++)
{
RendererCapabilities
rendererCapability
=
rendererCapabilities
[
rendererIndex
];
@FormatSupport
int
formatSupportLevel
=
RendererCapabilities
.
FORMAT_UNSUPPORTED_TYPE
;
for
(
int
trackIndex
=
0
;
trackIndex
<
group
.
length
;
trackIndex
++)
{
@FormatSupport
int
f
ormatSupportLevel
=
int
trackF
ormatSupportLevel
=
RendererCapabilities
.
getFormatSupport
(
rendererCapability
.
supportsFormat
(
group
.
getFormat
(
trackIndex
)));
if
(
formatSupportLevel
>
bestFormatSupportLevel
)
{
formatSupportLevel
=
Math
.
max
(
formatSupportLevel
,
trackFormatSupportLevel
);
}
boolean
rendererIsUnassociated
=
rendererTrackGroupCounts
[
rendererIndex
]
==
0
;
if
(
formatSupportLevel
>
bestFormatSupportLevel
||
(
formatSupportLevel
==
bestFormatSupportLevel
&&
preferUnassociatedRenderer
&&
!
bestRendererIsUnassociated
&&
rendererIsUnassociated
))
{
bestRendererIndex
=
rendererIndex
;
bestFormatSupportLevel
=
formatSupportLevel
;
if
(
bestFormatSupportLevel
==
RendererCapabilities
.
FORMAT_HANDLED
)
{
// We can't do better.
return
bestRendererIndex
;
}
}
bestRendererIsUnassociated
=
rendererIsUnassociated
;
}
}
return
bestRendererIndex
;
...
...
library/core/src/test/java/com/google/android/exoplayer2/trackselection/MappingTrackSelectorTest.java
View file @
38bc7355
...
...
@@ -44,17 +44,41 @@ public final class MappingTrackSelectorTest {
new
FakeRendererCapabilities
(
C
.
TRACK_TYPE_VIDEO
);
private
static
final
RendererCapabilities
AUDIO_CAPABILITIES
=
new
FakeRendererCapabilities
(
C
.
TRACK_TYPE_AUDIO
);
private
static
final
RendererCapabilities
[]
RENDERER_CAPABILITIES
=
new
RendererCapabilities
[]
{
VIDEO_CAPABILITIES
,
AUDIO_CAPABILITIES
};
private
static
final
TrackGroup
VIDEO_TRACK_GROUP
=
new
TrackGroup
(
Format
.
createVideoSampleFormat
(
"video"
,
MimeTypes
.
VIDEO_H264
,
null
,
Format
.
NO_VALUE
,
Format
.
NO_VALUE
,
1024
,
768
,
Format
.
NO_VALUE
,
null
,
null
));
private
static
final
TrackGroup
AUDIO_TRACK_GROUP
=
new
TrackGroup
(
Format
.
createAudioSampleFormat
(
"audio"
,
MimeTypes
.
AUDIO_AAC
,
null
,
Format
.
NO_VALUE
,
Format
.
NO_VALUE
,
2
,
44100
,
null
,
null
,
0
,
null
));
private
static
final
TrackGroupArray
TRACK_GROUPS
=
new
TrackGroupArray
(
VIDEO_TRACK_GROUP
,
AUDIO_TRACK_GROUP
);
private
static
final
RendererCapabilities
METADATA_CAPABILITIES
=
new
FakeRendererCapabilities
(
C
.
TRACK_TYPE_METADATA
);
private
static
final
TrackGroup
VIDEO_TRACK_GROUP
=
new
TrackGroup
(
Format
.
createVideoSampleFormat
(
"video"
,
MimeTypes
.
VIDEO_H264
,
/* codecs= */
null
,
/* bitrate= */
Format
.
NO_VALUE
,
/* maxInputSize= */
Format
.
NO_VALUE
,
/* width= */
1024
,
/* height= */
768
,
/* frameRate= */
Format
.
NO_VALUE
,
/* initializationData= */
null
,
/* drmInitData= */
null
));
private
static
final
TrackGroup
AUDIO_TRACK_GROUP
=
new
TrackGroup
(
Format
.
createAudioSampleFormat
(
"audio"
,
MimeTypes
.
AUDIO_AAC
,
/* codecs= */
null
,
/* bitrate= */
Format
.
NO_VALUE
,
/* maxInputSize= */
Format
.
NO_VALUE
,
/* channelCount= */
2
,
/* sampleRate= */
44100
,
/* initializationData= */
null
,
/* drmInitData= */
null
,
/* selectionFlags= */
0
,
/* language= */
null
));
private
static
final
TrackGroup
METADATA_TRACK_GROUP
=
new
TrackGroup
(
Format
.
createSampleFormat
(
"metadata"
,
MimeTypes
.
APPLICATION_ID3
,
/* subsampleOffsetUs= */
0
));
private
static
final
Timeline
TIMELINE
=
new
FakeTimeline
(
/* windowCount= */
1
);
private
static
MediaPeriodId
periodId
;
...
...
@@ -64,43 +88,68 @@ public final class MappingTrackSelectorTest {
periodId
=
new
MediaPeriodId
(
TIMELINE
.
getUidOfPeriod
(
/* periodIndex= */
0
));
}
/**
* Tests that the video and audio track groups are mapped onto the correct renderers.
*/
@Test
public
void
testMapping
()
throws
ExoPlaybackException
{
public
void
selectTracks_audioAndVideo_sameOrderAsRenderers_mappedToCorectRenderer
()
throws
ExoPlaybackException
{
FakeMappingTrackSelector
trackSelector
=
new
FakeMappingTrackSelector
();
trackSelector
.
selectTracks
(
RENDERER_CAPABILITIES
,
TRACK_GROUPS
,
periodId
,
TIMELINE
);
trackSelector
.
assertMappedTrackGroups
(
0
,
VIDEO_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
1
,
AUDIO_TRACK_GROUP
);
RendererCapabilities
[]
rendererCapabilities
=
new
RendererCapabilities
[]
{
VIDEO_CAPABILITIES
,
AUDIO_CAPABILITIES
};
TrackGroupArray
trackGroups
=
new
TrackGroupArray
(
VIDEO_TRACK_GROUP
,
AUDIO_TRACK_GROUP
);
trackSelector
.
selectTracks
(
rendererCapabilities
,
trackGroups
,
periodId
,
TIMELINE
);
trackSelector
.
assertMappedTrackGroups
(
/* rendererIndex= */
0
,
VIDEO_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
/* rendererIndex= */
1
,
AUDIO_TRACK_GROUP
);
}
/**
* Tests that the video and audio track groups are mapped onto the correct renderers when the
* renderer ordering is reversed.
*/
@Test
public
void
testMappingReverseOrder
()
throws
ExoPlaybackException
{
public
void
selectTracks_audioAndVideo_reverseOrderToRenderers_mappedToCorectRenderer
()
throws
ExoPlaybackException
{
FakeMappingTrackSelector
trackSelector
=
new
FakeMappingTrackSelector
();
RendererCapabilities
[]
reverseOrderRendererCapabilities
=
new
RendererCapabilities
[]
{
AUDIO_CAPABILITIES
,
VIDEO_CAPABILITIES
};
trackSelector
.
selectTracks
(
reverseOrderRendererCapabilities
,
TRACK_GROUPS
,
periodId
,
TIMELINE
);
trackSelector
.
assertMappedTrackGroups
(
0
,
AUDIO_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
1
,
VIDEO_TRACK_GROUP
);
TrackGroupArray
trackGroups
=
new
TrackGroupArray
(
VIDEO_TRACK_GROUP
,
AUDIO_TRACK_GROUP
);
RendererCapabilities
[]
reverseOrderRendererCapabilities
=
new
RendererCapabilities
[]
{
AUDIO_CAPABILITIES
,
VIDEO_CAPABILITIES
};
trackSelector
.
selectTracks
(
reverseOrderRendererCapabilities
,
trackGroups
,
periodId
,
TIMELINE
);
trackSelector
.
assertMappedTrackGroups
(
/* rendererIndex= */
0
,
AUDIO_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
/* rendererIndex= */
1
,
VIDEO_TRACK_GROUP
);
}
/**
* Tests video and audio track groups are mapped onto the correct renderers when there are
* multiple track groups of the same type.
*/
@Test
public
void
testMappingMulti
()
throws
ExoPlaybackException
{
public
void
selectTracks_multipleVideoAndAudioTracks_mappedToSameRenderer
()
throws
ExoPlaybackException
{
FakeMappingTrackSelector
trackSelector
=
new
FakeMappingTrackSelector
();
TrackGroupArray
multiTrackGroups
=
new
TrackGroupArray
(
VIDEO_TRACK_GROUP
,
AUDIO_TRACK_GROUP
,
VIDEO_TRACK_GROUP
);
trackSelector
.
selectTracks
(
RENDERER_CAPABILITIES
,
multiTrackGroups
,
periodId
,
TIMELINE
);
TrackGroupArray
trackGroups
=
new
TrackGroupArray
(
VIDEO_TRACK_GROUP
,
AUDIO_TRACK_GROUP
,
AUDIO_TRACK_GROUP
,
VIDEO_TRACK_GROUP
);
RendererCapabilities
[]
rendererCapabilities
=
new
RendererCapabilities
[]
{
VIDEO_CAPABILITIES
,
AUDIO_CAPABILITIES
,
VIDEO_CAPABILITIES
,
AUDIO_CAPABILITIES
};
trackSelector
.
selectTracks
(
rendererCapabilities
,
trackGroups
,
periodId
,
TIMELINE
);
trackSelector
.
assertMappedTrackGroups
(
0
,
VIDEO_TRACK_GROUP
,
VIDEO_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
1
,
AUDIO_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
1
,
AUDIO_TRACK_GROUP
,
AUDIO_TRACK_GROUP
);
}
@Test
public
void
selectTracks_multipleMetadataTracks_mappedToDifferentRenderers
()
throws
ExoPlaybackException
{
FakeMappingTrackSelector
trackSelector
=
new
FakeMappingTrackSelector
();
TrackGroupArray
trackGroups
=
new
TrackGroupArray
(
VIDEO_TRACK_GROUP
,
METADATA_TRACK_GROUP
,
METADATA_TRACK_GROUP
);
RendererCapabilities
[]
rendererCapabilities
=
new
RendererCapabilities
[]
{
VIDEO_CAPABILITIES
,
METADATA_CAPABILITIES
,
METADATA_CAPABILITIES
};
trackSelector
.
selectTracks
(
rendererCapabilities
,
trackGroups
,
periodId
,
TIMELINE
);
trackSelector
.
assertMappedTrackGroups
(
0
,
VIDEO_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
1
,
METADATA_TRACK_GROUP
);
trackSelector
.
assertMappedTrackGroups
(
2
,
METADATA_TRACK_GROUP
);
}
/**
...
...
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