blob: 8568ddc10090f7f9d038c120e3aafb62feb899d5 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.media;
import android.annotation.TargetApi;
import android.media.MediaFormat;
import android.os.Build;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.Log;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex;
import org.chromium.base.annotations.NativeMethods;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@JNINamespace("media")
@MainDex
class HdrMetadata {
private static final String TAG = "HdrMetadata";
private static final int MAX_CHROMATICITY = 50000; // Defined in CTA-861.3.
private long mNativeJniHdrMetadata;
private final Object mLock = new Object();
@CalledByNative
private static HdrMetadata create(long nativeRef) {
return new HdrMetadata(nativeRef);
}
@VisibleForTesting
HdrMetadata() {
// Used for testing only.
mNativeJniHdrMetadata = 0;
}
private HdrMetadata(long nativeRef) {
assert nativeRef != 0;
mNativeJniHdrMetadata = nativeRef;
}
@CalledByNative
private void close() {
synchronized (mLock) {
mNativeJniHdrMetadata = 0;
}
}
@TargetApi(Build.VERSION_CODES.N)
public void addMetadataToFormat(MediaFormat format) {
synchronized (mLock) {
assert mNativeJniHdrMetadata != 0;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.e(TAG, "HDR not supported before Android N");
return;
}
// TODO(sandv): Use color space matrix when android has support for it.
int colorStandard = getColorStandard();
if (colorStandard != -1) {
format.setInteger(MediaFormat.KEY_COLOR_STANDARD, colorStandard);
}
int colorTransfer = getColorTransfer();
if (colorTransfer != -1) {
format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, colorTransfer);
}
int colorRange = getColorRange();
if (colorRange != -1) format.setInteger(MediaFormat.KEY_COLOR_RANGE, colorRange);
ByteBuffer hdrStaticInfo = ByteBuffer.wrap(new byte[25]);
hdrStaticInfo.order(ByteOrder.LITTLE_ENDIAN);
hdrStaticInfo.put((byte) 0); // Type.
hdrStaticInfo.putShort((short) ((primaryRChromaticityX() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((primaryRChromaticityY() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((primaryGChromaticityX() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((primaryGChromaticityY() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((primaryBChromaticityX() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((primaryBChromaticityY() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((whitePointChromaticityX() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) ((whitePointChromaticityY() * MAX_CHROMATICITY) + 0.5f));
hdrStaticInfo.putShort((short) (maxColorVolumeLuminance() + 0.5f));
hdrStaticInfo.putShort((short) (minColorVolumeLuminance() + 0.5f));
hdrStaticInfo.putShort((short) maxContentLuminance());
hdrStaticInfo.putShort((short) maxFrameAverageLuminance());
hdrStaticInfo.rewind();
format.setByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, hdrStaticInfo);
}
}
private int getColorStandard() {
// media/base/video_color_space.h
switch (HdrMetadataJni.get().primaries(mNativeJniHdrMetadata, HdrMetadata.this)) {
case 1:
return MediaFormat.COLOR_STANDARD_BT709;
case 4: // BT.470M.
case 5: // BT.470BG.
case 6: // SMPTE 170M.
case 7: // SMPTE 240M.
return MediaFormat.COLOR_STANDARD_BT601_NTSC;
case 9:
return MediaFormat.COLOR_STANDARD_BT2020;
default:
return -1;
}
}
private int getColorTransfer() {
// media/base/video_color_space.h
switch (HdrMetadataJni.get().colorTransfer(mNativeJniHdrMetadata, HdrMetadata.this)) {
case 1: // BT.709.
case 6: // SMPTE 170M.
case 7: // SMPTE 240M.
return MediaFormat.COLOR_TRANSFER_SDR_VIDEO;
case 8:
return MediaFormat.COLOR_TRANSFER_LINEAR;
case 16:
return MediaFormat.COLOR_TRANSFER_ST2084;
case 18:
return MediaFormat.COLOR_TRANSFER_HLG;
default:
return -1;
}
}
private int getColorRange() {
// media/base/video_color_space.h
switch (HdrMetadataJni.get().range(mNativeJniHdrMetadata, HdrMetadata.this)) {
case 1:
return MediaFormat.COLOR_RANGE_LIMITED;
case 2:
return MediaFormat.COLOR_RANGE_FULL;
default:
return -1;
}
}
private float primaryRChromaticityX() {
return HdrMetadataJni.get().primaryRChromaticityX(mNativeJniHdrMetadata, HdrMetadata.this);
}
private float primaryRChromaticityY() {
return HdrMetadataJni.get().primaryRChromaticityY(mNativeJniHdrMetadata, HdrMetadata.this);
}
private float primaryGChromaticityX() {
return HdrMetadataJni.get().primaryGChromaticityX(mNativeJniHdrMetadata, HdrMetadata.this);
}
private float primaryGChromaticityY() {
return HdrMetadataJni.get().primaryGChromaticityY(mNativeJniHdrMetadata, HdrMetadata.this);
}
private float primaryBChromaticityX() {
return HdrMetadataJni.get().primaryBChromaticityX(mNativeJniHdrMetadata, HdrMetadata.this);
}
private float primaryBChromaticityY() {
return HdrMetadataJni.get().primaryBChromaticityY(mNativeJniHdrMetadata, HdrMetadata.this);
}
private float whitePointChromaticityX() {
return HdrMetadataJni.get().whitePointChromaticityX(
mNativeJniHdrMetadata, HdrMetadata.this);
}
private float whitePointChromaticityY() {
return HdrMetadataJni.get().whitePointChromaticityY(
mNativeJniHdrMetadata, HdrMetadata.this);
}
private float maxColorVolumeLuminance() {
return HdrMetadataJni.get().maxColorVolumeLuminance(
mNativeJniHdrMetadata, HdrMetadata.this);
}
private float minColorVolumeLuminance() {
return HdrMetadataJni.get().minColorVolumeLuminance(
mNativeJniHdrMetadata, HdrMetadata.this);
}
private int maxContentLuminance() {
return HdrMetadataJni.get().maxContentLuminance(mNativeJniHdrMetadata, HdrMetadata.this);
}
private int maxFrameAverageLuminance() {
return HdrMetadataJni.get().maxFrameAverageLuminance(
mNativeJniHdrMetadata, HdrMetadata.this);
}
@NativeMethods
interface Natives {
int primaries(long nativeJniHdrMetadata, HdrMetadata caller);
int colorTransfer(long nativeJniHdrMetadata, HdrMetadata caller);
int range(long nativeJniHdrMetadata, HdrMetadata caller);
float primaryRChromaticityX(long nativeJniHdrMetadata, HdrMetadata caller);
float primaryRChromaticityY(long nativeJniHdrMetadata, HdrMetadata caller);
float primaryGChromaticityX(long nativeJniHdrMetadata, HdrMetadata caller);
float primaryGChromaticityY(long nativeJniHdrMetadata, HdrMetadata caller);
float primaryBChromaticityX(long nativeJniHdrMetadata, HdrMetadata caller);
float primaryBChromaticityY(long nativeJniHdrMetadata, HdrMetadata caller);
float whitePointChromaticityX(long nativeJniHdrMetadata, HdrMetadata caller);
float whitePointChromaticityY(long nativeJniHdrMetadata, HdrMetadata caller);
float maxColorVolumeLuminance(long nativeJniHdrMetadata, HdrMetadata caller);
float minColorVolumeLuminance(long nativeJniHdrMetadata, HdrMetadata caller);
int maxContentLuminance(long nativeJniHdrMetadata, HdrMetadata caller);
int maxFrameAverageLuminance(long nativeJniHdrMetadata, HdrMetadata caller);
}
}