Add Dolby Vision Transcoding and Editing Support

This commit is contained in:
ybai001 2024-04-02 12:59:06 +08:00
parent 563f4d845a
commit a5524c09c5
3 changed files with 73 additions and 0 deletions

View File

@ -135,6 +135,9 @@ public final class DefaultDecoderFactory implements Codec.DecoderFactory {
if (SDK_INT >= 31 && requestSdrToneMapping) { if (SDK_INT >= 31 && requestSdrToneMapping) {
mediaFormat.setInteger( mediaFormat.setInteger(
MediaFormat.KEY_COLOR_TRANSFER_REQUEST, MediaFormat.COLOR_TRANSFER_SDR_VIDEO); MediaFormat.KEY_COLOR_TRANSFER_REQUEST, MediaFormat.COLOR_TRANSFER_SDR_VIDEO);
} else if (SDK_INT >= 31 && MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
mediaFormat.setInteger(
MediaFormat.KEY_COLOR_TRANSFER_REQUEST, MediaFormat.COLOR_TRANSFER_HLG);
} }
@Nullable @Nullable

View File

@ -150,6 +150,13 @@ public final class EncoderUtil {
return ImmutableList.of(MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10); return ImmutableList.of(MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10);
} }
break; break;
case MimeTypes.VIDEO_DOLBY_VISION:
if (colorTransfer == C.COLOR_TRANSFER_HLG) {
return ImmutableList.of(
MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt);
}
// CodecProfileLevel does not support PQ for Dolby Vision.
break;
default: default:
break; break;
} }

View File

@ -22,9 +22,12 @@ import static androidx.media3.common.util.Util.castNonNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.media.MediaMuxer; import android.media.MediaMuxer;
import android.os.Build;
import android.util.SparseLongArray; import android.util.SparseLongArray;
import androidx.annotation.RequiresApi;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
@ -108,6 +111,11 @@ import java.nio.ByteBuffer;
if (isVideo) { if (isVideo) {
mediaFormat = MediaFormat.createVideoFormat(sampleMimeType, format.width, format.height); mediaFormat = MediaFormat.createVideoFormat(sampleMimeType, format.width, format.height);
MediaFormatUtil.maybeSetColorInfo(mediaFormat, format.colorInfo); MediaFormatUtil.maybeSetColorInfo(mediaFormat, format.colorInfo);
if (sampleMimeType.equals(MimeTypes.VIDEO_DOLBY_VISION) &&
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
mediaFormat.setInteger(MediaFormat.KEY_PROFILE, getDvProfile(format));
mediaFormat.setInteger(MediaFormat.KEY_LEVEL, getDvLevel(format));
}
try { try {
mediaMuxer.setOrientationHint(format.rotationDegrees); mediaMuxer.setOrientationHint(format.rotationDegrees);
} catch (RuntimeException e) { } catch (RuntimeException e) {
@ -276,9 +284,64 @@ import java.nio.ByteBuffer;
if (SDK_INT >= 24) { if (SDK_INT >= 24) {
supportedMimeTypes.add(MimeTypes.VIDEO_H265); supportedMimeTypes.add(MimeTypes.VIDEO_H265);
} }
if (SDK_INT >= 33) {
supportedMimeTypes.add(MimeTypes.VIDEO_DOLBY_VISION);
}
if (SDK_INT >= 34) { if (SDK_INT >= 34) {
supportedMimeTypes.add(MimeTypes.VIDEO_AV1); supportedMimeTypes.add(MimeTypes.VIDEO_AV1);
} }
return supportedMimeTypes.build(); return supportedMimeTypes.build();
} }
// Get Dolby Vision profile
// Refer to https://professionalsupport.dolby.com/s/article/What-is-Dolby-Vision-Profile
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
private static int getDvProfile(Format format) {
// Currently, only profile 8 is supported for encoding
// TODO: set profile ID based on format.
return MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheSt;
}
// Get Dolby Vision level
// Refer to https://professionalsupport.dolby.com/s/article/What-is-Dolby-Vision-Profile
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
private static int getDvLevel(Format format) {
int level = -1;
int maxWidthHeight = Math.max(format.width, format.height);
float pps = format.width * format.height * format.frameRate;
if (maxWidthHeight <= 1280) {
if (pps <= 22118400) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelHd24; // Level 01
} else if (pps <= 27648000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelHd30; // Level 02
}
} else if (maxWidthHeight <= 1920 && pps <= 49766400) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd24; // Level 03
} else if (maxWidthHeight <= 2560 && pps <= 62208000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd30; // Level 04
} else if (maxWidthHeight <= 3840) {
if (pps <= 124416000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60; // Level 05
} else if (pps <= 199065600) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd24; // Level 06
} else if (pps <= 248832000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd30; // Level 07
} else if (pps <= 398131200) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd48; // Level 08
} else if (pps <= 497664000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd60; // Level 09
} else if (pps <= 995328000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelUhd120; // Level 10
}
} else if (maxWidthHeight <= 7680) {
if (pps <= 995328000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevel8k30; // Level 11
} else if (pps <= 1990656000) {
level = MediaCodecInfo.CodecProfileLevel.DolbyVisionLevel8k60; // Level 12
}
}
return level;
}
} }