Skip to content

Commit 01255c7

Browse files
microkatzcopybara-github
authored andcommitted
Remove supply of init data for AV1-based Dolby Vision codecs
The initialization data it is not required by MediaCodec for these encodings and some codec implementations fail if it's present. Issue: #3153 #cherrypick PiperOrigin-RevId: 897164714
1 parent 6e8ac29 commit 01255c7

5 files changed

Lines changed: 105 additions & 1 deletion

File tree

RELEASENOTES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
deprecated method with custom implementation will still be called by
4343
default though, it is recommended to implement the new method and use
4444
`BandwidthMeter.getTransferListener()` to get parity to the old method.
45+
* Fix issue where video artifacts were caused by supplying initialization
46+
data when using an AV1-based Dolby Vision codec
47+
([#3153](https://github.com/androidx/media/pull/3153)).
4548
* CompositionPlayer:
4649
* Transformer:
4750
* Fix an issue where `ExportResult.fileSizeBytes` may be over-reported.

libraries/common/src/main/java/androidx/media3/common/util/CodecSpecificDataUtil.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.Arrays;
3939
import java.util.Collections;
4040
import java.util.List;
41+
import java.util.Objects;
4142
import java.util.regex.Matcher;
4243
import java.util.regex.Pattern;
4344

@@ -1322,6 +1323,36 @@ private static MediaCodecProfileAndLevel getDolbyVisionProfileAndLevel(
13221323
return new MediaCodecProfileAndLevel(profile, level);
13231324
}
13241325

1326+
/**
1327+
* Returns a Dolby Vision base layer codec MIME type of the provided {@link Format}.
1328+
*
1329+
* @param format The media format.
1330+
* @return A Dolby Vision base layer MIME type, or {@code null} if a Dolby Vision profile is not
1331+
* identified.
1332+
*/
1333+
@Nullable
1334+
public static String getDolbyVisionBaseLayerMimeType(Format format) {
1335+
if (!Objects.equals(format.sampleMimeType, MimeTypes.VIDEO_DOLBY_VISION)) {
1336+
return null;
1337+
}
1338+
@Nullable Pair<Integer, Integer> codecProfileAndLevel = getCodecProfileAndLevel(format);
1339+
if (codecProfileAndLevel == null) {
1340+
return null;
1341+
}
1342+
switch (codecProfileAndLevel.first) {
1343+
case CodecProfileLevel.DolbyVisionProfileDvheDtr: // profile 4
1344+
case CodecProfileLevel.DolbyVisionProfileDvheStn: // profile 5
1345+
case CodecProfileLevel.DolbyVisionProfileDvheSt: // profile 8
1346+
return MimeTypes.VIDEO_H265;
1347+
case CodecProfileLevel.DolbyVisionProfileDvavSe: // profile 9
1348+
return MimeTypes.VIDEO_H264;
1349+
case CodecProfileLevel.DolbyVisionProfileDvav110: // profile 10
1350+
return MimeTypes.VIDEO_AV1;
1351+
default:
1352+
return null;
1353+
}
1354+
}
1355+
13251356
/** Returns H263 profile and level from codec string. */
13261357
@Nullable
13271358
private static MediaCodecProfileAndLevel getH263ProfileAndLevel(String codec, String[] parts) {

libraries/common/src/test/java/androidx/media3/common/util/CodecSpecificDataUtilTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,40 @@ public void getMediaCodecProfileAndLevel_mvHevcWithNoMatchingMediaCodecConstant_
334334
assertThat(getMediaCodecProfileAndLevel(format).isSupportableByMediaCodec()).isFalse();
335335
}
336336

337+
@Test
338+
public void
339+
getDolbyVisionBaseLayerMimeType_withNonFallbackCompatibleFormat_returnsBaseEncoding() {
340+
// Profile 10.0 (Full Range PQ) which does NOT allow fallback.
341+
Format formatDav1NoFallbackPossible =
342+
new Format.Builder()
343+
.setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION)
344+
.setCodecs("dav1.10.01")
345+
.setColorInfo(
346+
new ColorInfo.Builder()
347+
.setColorSpace(C.COLOR_SPACE_BT2020)
348+
.setColorTransfer(C.COLOR_TRANSFER_ST2084)
349+
.setColorRange(C.COLOR_RANGE_FULL)
350+
.build())
351+
.build();
352+
// Profile 10.1 (Limited Range PQ) which allows fallback to AV1.
353+
Format formatDav1FallbackToAv1 =
354+
new Format.Builder()
355+
.setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION)
356+
.setCodecs("dav1.10.01")
357+
.setColorInfo(
358+
new ColorInfo.Builder()
359+
.setColorSpace(C.COLOR_SPACE_BT2020)
360+
.setColorTransfer(C.COLOR_TRANSFER_ST2084)
361+
.setColorRange(C.COLOR_RANGE_LIMITED)
362+
.build())
363+
.build();
364+
365+
assertThat(CodecSpecificDataUtil.getDolbyVisionBaseLayerMimeType(formatDav1NoFallbackPossible))
366+
.isEqualTo(MimeTypes.VIDEO_AV1);
367+
assertThat(CodecSpecificDataUtil.getDolbyVisionBaseLayerMimeType(formatDav1FallbackToAv1))
368+
.isEqualTo(MimeTypes.VIDEO_AV1);
369+
}
370+
337371
private static void assertCodecProfileAndLevelForCodecsString(
338372
String sampleMimeType, String codecs, int profile, int level) {
339373
Format format =

libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import androidx.media3.common.MimeTypes;
5353
import androidx.media3.common.PlaybackException;
5454
import androidx.media3.common.Timeline;
55+
import androidx.media3.common.util.CodecSpecificDataUtil;
5556
import androidx.media3.common.util.ExperimentalApi;
5657
import androidx.media3.common.util.Log;
5758
import androidx.media3.common.util.TimedValueQueue;
@@ -1813,7 +1814,8 @@ protected DecoderReuseEvaluation onInputFormatChanged(FormatHolder formatHolder)
18131814
|| Objects.equals(newFormat.sampleMimeType, MimeTypes.VIDEO_VP9)
18141815
|| (Objects.equals(newFormat.sampleMimeType, MimeTypes.VIDEO_DOLBY_VISION)
18151816
&& Objects.equals(
1816-
MediaCodecUtil.getAlternativeCodecMimeType(newFormat), MimeTypes.VIDEO_AV1)))
1817+
CodecSpecificDataUtil.getDolbyVisionBaseLayerMimeType(newFormat),
1818+
MimeTypes.VIDEO_AV1)))
18171819
&& !newFormat.initializationData.isEmpty()) {
18181820
newFormat = newFormat.buildUpon().setInitializationData(null).build();
18191821
}

libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecUtilTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import static com.google.common.truth.Truth.assertThat;
1919

2020
import android.media.MediaCodecInfo;
21+
import androidx.media3.common.C;
22+
import androidx.media3.common.ColorInfo;
2123
import androidx.media3.common.Format;
2224
import androidx.media3.common.MimeTypes;
2325
import androidx.media3.common.util.CodecSpecificDataUtil.MediaCodecProfileAndLevel;
@@ -225,6 +227,38 @@ public void getHevcBaseLayerCodecProfileAndLevel_rejectsFormatWithNoInitializati
225227
assertThat(MediaCodecUtil.getHevcBaseLayerCodecProfileAndLevel(format)).isNull();
226228
}
227229

230+
@Test
231+
public void getAlternativeCodecMimeType_withNonFallbackCompatibleFormat_returnsNull() {
232+
// Profile 10.0 (Full Range PQ) which does NOT allow fallback.
233+
Format formatDav1NoFallbackPossible =
234+
new Format.Builder()
235+
.setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION)
236+
.setCodecs("dav1.10.01")
237+
.setColorInfo(
238+
new ColorInfo.Builder()
239+
.setColorSpace(C.COLOR_SPACE_BT2020)
240+
.setColorTransfer(C.COLOR_TRANSFER_ST2084)
241+
.setColorRange(C.COLOR_RANGE_FULL)
242+
.build())
243+
.build();
244+
// Profile 10.1 (Limited Range PQ) which allows fallback to AV1.
245+
Format formatDav1FallbackToAv1 =
246+
new Format.Builder()
247+
.setSampleMimeType(MimeTypes.VIDEO_DOLBY_VISION)
248+
.setCodecs("dav1.10.01")
249+
.setColorInfo(
250+
new ColorInfo.Builder()
251+
.setColorSpace(C.COLOR_SPACE_BT2020)
252+
.setColorTransfer(C.COLOR_TRANSFER_ST2084)
253+
.setColorRange(C.COLOR_RANGE_LIMITED)
254+
.build())
255+
.build();
256+
257+
assertThat(MediaCodecUtil.getAlternativeCodecMimeType(formatDav1NoFallbackPossible)).isNull();
258+
assertThat(MediaCodecUtil.getAlternativeCodecMimeType(formatDav1FallbackToAv1))
259+
.isEqualTo(MimeTypes.VIDEO_AV1);
260+
}
261+
228262
private static void assertHevcBaseLayerCodecProfileAndLevelForFormat(
229263
Format format, int profile, int level) {
230264
MediaCodecProfileAndLevel codecProfileAndLevel =

0 commit comments

Comments
 (0)