Prioritize object-based audio in DefaultTrackSelector
Object-based audio is more efficient and flexible than channel-based audio, supporting a broader range of devices. This update makes `DefaultTrackSelector` prefer object-based audio when other factors are equal, ensuring its use whenever possible. #cherrypick PiperOrigin-RevId: 683990051
This commit is contained in:
parent
5e5d486ef1
commit
4df7216bc0
@ -53,6 +53,8 @@
|
|||||||
`MediaItem.Builder.setImageDurationMs` mandatory for image export.
|
`MediaItem.Builder.setImageDurationMs` mandatory for image export.
|
||||||
* Add export support for gaps in sequences of audio EditedMediaItems.
|
* Add export support for gaps in sequences of audio EditedMediaItems.
|
||||||
* Track Selection:
|
* Track Selection:
|
||||||
|
* `DefaultTrackSelector`: Prefer object-based audio over channel-based
|
||||||
|
audio when other factors are equal.
|
||||||
* Extractors:
|
* Extractors:
|
||||||
* Fix preroll sample handling for non-keyframe media start positions when
|
* Fix preroll sample handling for non-keyframe media start positions when
|
||||||
processing edit lists in MP4 files
|
processing edit lists in MP4 files
|
||||||
|
@ -3406,6 +3406,20 @@ public class DefaultTrackSelector extends MappingTrackSelector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isObjectBasedAudio(Format format) {
|
||||||
|
if (format.sampleMimeType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (format.sampleMimeType) {
|
||||||
|
case MimeTypes.AUDIO_E_AC3_JOC:
|
||||||
|
case MimeTypes.AUDIO_AC4:
|
||||||
|
case MimeTypes.AUDIO_IAMF:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isDolbyAudio(Format format) {
|
private static boolean isDolbyAudio(Format format) {
|
||||||
if (format.sampleMimeType == null) {
|
if (format.sampleMimeType == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -3726,6 +3740,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
|
|||||||
private final int preferredMimeTypeMatchIndex;
|
private final int preferredMimeTypeMatchIndex;
|
||||||
private final boolean usesPrimaryDecoder;
|
private final boolean usesPrimaryDecoder;
|
||||||
private final boolean usesHardwareAcceleration;
|
private final boolean usesHardwareAcceleration;
|
||||||
|
private final boolean isObjectBasedAudio;
|
||||||
|
|
||||||
public AudioTrackInfo(
|
public AudioTrackInfo(
|
||||||
int rendererIndex,
|
int rendererIndex,
|
||||||
@ -3770,6 +3785,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
|
|||||||
getRoleFlagMatchScore(format.roleFlags, parameters.preferredAudioRoleFlags);
|
getRoleFlagMatchScore(format.roleFlags, parameters.preferredAudioRoleFlags);
|
||||||
hasMainOrNoRoleFlag = format.roleFlags == 0 || (format.roleFlags & C.ROLE_FLAG_MAIN) != 0;
|
hasMainOrNoRoleFlag = format.roleFlags == 0 || (format.roleFlags & C.ROLE_FLAG_MAIN) != 0;
|
||||||
isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
|
isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
|
||||||
|
isObjectBasedAudio = isObjectBasedAudio(format);
|
||||||
channelCount = format.channelCount;
|
channelCount = format.channelCount;
|
||||||
sampleRate = format.sampleRate;
|
sampleRate = format.sampleRate;
|
||||||
bitrate = format.bitrate;
|
bitrate = format.bitrate;
|
||||||
@ -3877,6 +3893,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
|
|||||||
.compareFalseFirst(this.usesPrimaryDecoder, other.usesPrimaryDecoder)
|
.compareFalseFirst(this.usesPrimaryDecoder, other.usesPrimaryDecoder)
|
||||||
.compareFalseFirst(this.usesHardwareAcceleration, other.usesHardwareAcceleration)
|
.compareFalseFirst(this.usesHardwareAcceleration, other.usesHardwareAcceleration)
|
||||||
// 5. Compare technical quality.
|
// 5. Compare technical quality.
|
||||||
|
.compareFalseFirst(this.isObjectBasedAudio, other.isObjectBasedAudio)
|
||||||
.compare(this.channelCount, other.channelCount, qualityOrdering)
|
.compare(this.channelCount, other.channelCount, qualityOrdering)
|
||||||
.compare(this.sampleRate, other.sampleRate, qualityOrdering);
|
.compare(this.sampleRate, other.sampleRate, qualityOrdering);
|
||||||
if (Util.areEqual(this.language, other.language)) {
|
if (Util.areEqual(this.language, other.language)) {
|
||||||
|
@ -988,6 +988,39 @@ public final class DefaultTrackSelectorTest {
|
|||||||
assertFixedSelection(result.selections[0], trackGroups, firstLanguageFormat);
|
assertFixedSelection(result.selections[0], trackGroups, firstLanguageFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that track selector will prefer audio tracks with object based audio over tracks with
|
||||||
|
* higher channel count when other factors are the same, and tracks are within renderer's
|
||||||
|
* capabilities.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
selectTracks_audioChannelCountConstraintsDisabled_preferObjectBasedAudioBeforeChannelCount()
|
||||||
|
throws Exception {
|
||||||
|
Format channelBasedAudioWithHigherChannelCountFormat =
|
||||||
|
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AC3).setChannelCount(6).build();
|
||||||
|
Format objectBasedAudioWithLowerChannelCountFormat =
|
||||||
|
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AC4).setChannelCount(2).build();
|
||||||
|
TrackGroupArray trackGroups =
|
||||||
|
wrapFormats(
|
||||||
|
channelBasedAudioWithHigherChannelCountFormat,
|
||||||
|
objectBasedAudioWithLowerChannelCountFormat);
|
||||||
|
trackSelector.setParameters(
|
||||||
|
trackSelector
|
||||||
|
.buildUponParameters()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
TrackSelectorResult result =
|
||||||
|
trackSelector.selectTracks(
|
||||||
|
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
|
||||||
|
trackGroups,
|
||||||
|
periodId,
|
||||||
|
TIMELINE);
|
||||||
|
assertFixedSelection(
|
||||||
|
result.selections[0], trackGroups, objectBasedAudioWithLowerChannelCountFormat);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that track selector will prefer audio tracks with higher channel count over tracks with
|
* Tests that track selector will prefer audio tracks with higher channel count over tracks with
|
||||||
* higher sample rate when audio channel count constraints are disabled, other factors are the
|
* higher sample rate when audio channel count constraints are disabled, other factors are the
|
||||||
@ -2779,37 +2812,37 @@ public final class DefaultTrackSelectorTest {
|
|||||||
public void selectTracks_withPreferredAudioMimeTypes_selectsTrackWithPreferredMimeType()
|
public void selectTracks_withPreferredAudioMimeTypes_selectsTrackWithPreferredMimeType()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Format formatAac = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).build();
|
Format formatAac = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).build();
|
||||||
Format formatAc4 = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AC4).build();
|
Format formatOpus = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_OPUS).build();
|
||||||
Format formatEAc3 = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_E_AC3).build();
|
Format formatFlac = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_FLAC).build();
|
||||||
TrackGroupArray trackGroups = wrapFormats(formatAac, formatAc4, formatEAc3);
|
TrackGroupArray trackGroups = wrapFormats(formatAac, formatOpus, formatFlac);
|
||||||
|
|
||||||
trackSelector.setParameters(
|
trackSelector.setParameters(
|
||||||
trackSelector.buildUponParameters().setPreferredAudioMimeType(MimeTypes.AUDIO_AC4));
|
trackSelector.buildUponParameters().setPreferredAudioMimeType(MimeTypes.AUDIO_OPUS));
|
||||||
TrackSelectorResult result =
|
TrackSelectorResult result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
assertThat(result.length).isEqualTo(1);
|
assertThat(result.length).isEqualTo(1);
|
||||||
assertFixedSelection(result.selections[0], trackGroups, formatAc4);
|
assertFixedSelection(result.selections[0], trackGroups, formatOpus);
|
||||||
|
|
||||||
trackSelector.setParameters(
|
trackSelector.setParameters(
|
||||||
trackSelector
|
trackSelector
|
||||||
.buildUponParameters()
|
.buildUponParameters()
|
||||||
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AC4, MimeTypes.AUDIO_AAC));
|
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_OPUS, MimeTypes.AUDIO_AAC));
|
||||||
result =
|
result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
assertThat(result.length).isEqualTo(1);
|
assertThat(result.length).isEqualTo(1);
|
||||||
assertFixedSelection(result.selections[0], trackGroups, formatAc4);
|
assertFixedSelection(result.selections[0], trackGroups, formatOpus);
|
||||||
|
|
||||||
trackSelector.setParameters(
|
trackSelector.setParameters(
|
||||||
trackSelector
|
trackSelector
|
||||||
.buildUponParameters()
|
.buildUponParameters()
|
||||||
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AMR, MimeTypes.AUDIO_E_AC3));
|
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AMR, MimeTypes.AUDIO_FLAC));
|
||||||
result =
|
result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
assertThat(result.length).isEqualTo(1);
|
assertThat(result.length).isEqualTo(1);
|
||||||
assertFixedSelection(result.selections[0], trackGroups, formatEAc3);
|
assertFixedSelection(result.selections[0], trackGroups, formatFlac);
|
||||||
|
|
||||||
// Select first in the list if no preference is specified.
|
// Select first in the list if no preference is specified.
|
||||||
trackSelector.setParameters(
|
trackSelector.setParameters(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user