Add NAL unit parsing needed for stereo MV-HEVC playback.
Add the following NAL unit parsing utility functions that will be needed for the MV-HEVC support as proposed in Apple's HEVC stereo video interoperability profile: - NAL unit header parsing to get the layer information needed for MV-HEVC support. - VPS parsing, including vps_extension() needed for MV-HEVC support. - SPS parsing modifications to support MV-HEVC. PiperOrigin-RevId: 647329211
This commit is contained in:
parent
304bcfc852
commit
3da63eeaa7
File diff suppressed because it is too large
Load Diff
@ -92,6 +92,13 @@ public final class ParsableNalUnitBitArray {
|
||||
assertValidOffset();
|
||||
}
|
||||
|
||||
/** Skips bits until at a byte alignment; if already byte aligned, then simply returns. */
|
||||
public void byteAlign() {
|
||||
if (bitOffset > 0) {
|
||||
skipBits(8 - bitOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether it's possible to read {@code n} bits starting from the current offset. The
|
||||
* offset is not modified.
|
||||
|
@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import org.junit.Test;
|
||||
@ -37,6 +38,58 @@ public final class NalUnitUtilTest {
|
||||
0x91, 0x00, 0x00, 0x7E, 0xA0);
|
||||
private static final int SPS_TEST_DATA_OFFSET = 3;
|
||||
|
||||
// Below are H.265 VPS and SPS samples obtained from the "24-bit big endian raw audio LPCM
|
||||
// (MP4,H265,raw)" clip in the ExoPlayer sample.
|
||||
private static final byte[] H265_VPS_TEST_DATA =
|
||||
createByteArray(
|
||||
0x40, 0x01, 0x0C, 0x01, 0xFF, 0xFF, 0x22, 0x20, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x99, 0x2C, 0x09);
|
||||
private static final byte[] H265_SPS_TEST_DATA =
|
||||
createByteArray(
|
||||
0x42, 0x01, 0x01, 0x22, 0x20, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x99, 0xA0, 0x01, 0xE0, 0x20, 0x02, 0x1C, 0x4D, 0x94, 0xBB, 0xB4, 0xA3, 0x32,
|
||||
0xAA, 0xC0, 0x5A, 0x84, 0x89, 0x04, 0x8A, 0x00, 0x00, 0x07, 0xD2, 0x00, 0x00, 0xBB, 0x80,
|
||||
0xE4, 0x68, 0x7C, 0x9C, 0x00, 0x01, 0x2E, 0x1F, 0x80, 0x00, 0x21, 0xFD, 0x30, 0x00, 0x02,
|
||||
0x5C, 0x3F, 0x00, 0x00, 0x43, 0xFA, 0x62);
|
||||
|
||||
// Below are MV-HEVC VPS and SPS samples obtained from the two sample clips in b/40937818.
|
||||
private static final byte[] H265_VPS_TEST_DATA_2VIEWS =
|
||||
createByteArray(
|
||||
0x40, 0x01, 0x0C, 0x11, 0xFF, 0xFF, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x15, 0xC1, 0x5B, 0x00, 0x20, 0x00, 0x28, 0x24, 0xC1,
|
||||
0x97, 0x06, 0x02, 0x00, 0x00, 0x03, 0x00, 0xBF, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x78,
|
||||
0x8D, 0x07, 0x80, 0x04, 0x40, 0xA0, 0x1E, 0x5C, 0x52, 0xBF, 0x48);
|
||||
private static final byte[] H265_SPS_TEST_DATA_2VIEWS_VIEW_0 =
|
||||
createByteArray(
|
||||
0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x78, 0xA0, 0x03, 0xC0, 0x80, 0x11, 0x07, 0xCB, 0x88, 0x15, 0xEE, 0x45, 0x95,
|
||||
0x4D, 0x40, 0x40, 0x40, 0x40, 0x20);
|
||||
private static final byte[] H265_SPS_TEST_DATA_2VIEWS_VIEW_1 =
|
||||
createByteArray(0x42, 0x09, 0x0E, 0x82, 0x2E, 0x45, 0x8A, 0xA0, 0x05, 0x01);
|
||||
|
||||
private static final byte[] H265_VPS_TEST_DATA_2VIEWS_HDR =
|
||||
createByteArray(
|
||||
0x40, 0x01, 0x0C, 0x11, 0xFF, 0xFF, 0x02, 0x20, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x99, 0x98, 0xA3, 0x41, 0x5C, 0x00, 0x00, 0x0F, 0xA4, 0x00,
|
||||
0x03, 0xA9, 0x83, 0xFF, 0x99, 0x20, 0x00, 0x21, 0x16, 0x93, 0x93, 0x11, 0x00, 0x00, 0x03,
|
||||
0x00, 0x5E, 0xC4, 0x00, 0x00, 0x03, 0x00, 0x00, 0x4C, 0xC6, 0x87, 0x80, 0x04, 0x38, 0x52,
|
||||
0x24, 0x31, 0x8A, 0x3B, 0xA4, 0x80);
|
||||
private static final byte[] H265_SPS_TEST_DATA_2VIEWS_HDR_VIEW_0 =
|
||||
createByteArray(
|
||||
0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x99, 0xA0, 0x01, 0xE0, 0x20, 0x02, 0x1C, 0x4D, 0x94, 0x62, 0x8D, 0x92, 0x42,
|
||||
0x97, 0x55, 0x58, 0x43, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x18, 0x82, 0x8D,
|
||||
0x08, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x91, 0x88, 0x28, 0xD0, 0x87, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x2B, 0xC0, 0x41, 0x40, 0x00, 0x00, 0xFA, 0x40,
|
||||
0x00, 0x3A, 0x98, 0x3C, 0x24, 0x82, 0x4D, 0xC0, 0x00, 0x26, 0x25, 0xA0, 0x00, 0x13, 0x12,
|
||||
0xDF, 0xC4, 0xC7, 0x8F, 0x40);
|
||||
private static final byte[] H265_SPS_TEST_DATA_2VIEWS_HDR_VIEW_1 =
|
||||
createByteArray(
|
||||
0x42, 0x09, 0x0E, 0x85, 0x92, 0x42, 0x96, 0xAA, 0xAC, 0x21, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFC, 0x8C, 0x41, 0x46, 0x84, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC8, 0xC4, 0x14, 0x68, 0x43, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x95, 0xA8,
|
||||
0x18);
|
||||
|
||||
@Test
|
||||
public void findNalUnit() {
|
||||
byte[] data = buildTestData();
|
||||
@ -143,6 +196,172 @@ public final class NalUnitUtilTest {
|
||||
assertThat(data.maxNumReorderFrames).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseH265VpsAndSpsNalUnits() {
|
||||
NalUnitUtil.H265VpsData vpsData =
|
||||
NalUnitUtil.parseH265VpsNalUnit(
|
||||
H265_VPS_TEST_DATA, /* nalOffset= */ 0, H265_VPS_TEST_DATA.length);
|
||||
assertThat(vpsData.nalHeader.layerId).isEqualTo(0);
|
||||
assertThat(vpsData.layerInfos).isEmpty();
|
||||
ImmutableList<NalUnitUtil.H265ProfileTierLevel> profileTierLevels =
|
||||
vpsData.profileTierLevelsAndIndices.profileTierLevels;
|
||||
assertThat(profileTierLevels).hasSize(1);
|
||||
assertThat(profileTierLevels.get(0).generalProfileIdc).isEqualTo(2);
|
||||
assertThat(profileTierLevels.get(0).generalProfileCompatibilityFlags).isEqualTo(4);
|
||||
assertThat(profileTierLevels.get(0).generalLevelIdc).isEqualTo(153);
|
||||
|
||||
NalUnitUtil.H265SpsData spsData =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
H265_SPS_TEST_DATA, /* nalOffset= */ 0, H265_SPS_TEST_DATA.length, vpsData);
|
||||
assertThat(spsData.nalHeader.layerId).isEqualTo(0);
|
||||
assertThat(spsData.profileTierLevel.generalProfileIdc).isEqualTo(2);
|
||||
assertThat(spsData.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(4);
|
||||
assertThat(spsData.profileTierLevel.generalLevelIdc).isEqualTo(153);
|
||||
assertThat(spsData.chromaFormatIdc).isEqualTo(1);
|
||||
assertThat(spsData.width).isEqualTo(3840);
|
||||
assertThat(spsData.height).isEqualTo(2160);
|
||||
assertThat(spsData.bitDepthLumaMinus8).isEqualTo(2);
|
||||
assertThat(spsData.bitDepthChromaMinus8).isEqualTo(2);
|
||||
assertThat(spsData.colorSpace).isEqualTo(6);
|
||||
assertThat(spsData.colorRange).isEqualTo(2);
|
||||
assertThat(spsData.colorTransfer).isEqualTo(7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseH265VpsAndSpsNalUnits2Views() {
|
||||
NalUnitUtil.H265VpsData vpsData =
|
||||
NalUnitUtil.parseH265VpsNalUnit(
|
||||
H265_VPS_TEST_DATA_2VIEWS, /* nalOffset= */ 0, H265_VPS_TEST_DATA_2VIEWS.length);
|
||||
assertThat(vpsData.nalHeader.layerId).isEqualTo(0);
|
||||
ImmutableList<NalUnitUtil.H265LayerInfo> layerInfos = vpsData.layerInfos;
|
||||
assertThat(layerInfos).hasSize(2);
|
||||
assertThat(layerInfos.get(0).layerIdInVps).isEqualTo(0);
|
||||
assertThat(layerInfos.get(0).viewId).isEqualTo(0);
|
||||
assertThat(layerInfos.get(1).layerIdInVps).isEqualTo(1);
|
||||
assertThat(layerInfos.get(1).viewId).isEqualTo(1);
|
||||
ImmutableList<NalUnitUtil.H265ProfileTierLevel> profileTierLevels =
|
||||
vpsData.profileTierLevelsAndIndices.profileTierLevels;
|
||||
assertThat(profileTierLevels).hasSize(3);
|
||||
assertThat(profileTierLevels.get(0).generalProfileIdc).isEqualTo(1);
|
||||
assertThat(profileTierLevels.get(0).generalProfileCompatibilityFlags).isEqualTo(6);
|
||||
assertThat(profileTierLevels.get(0).generalLevelIdc).isEqualTo(120);
|
||||
assertThat(profileTierLevels.get(1).generalProfileIdc).isEqualTo(1);
|
||||
assertThat(profileTierLevels.get(1).generalProfileCompatibilityFlags).isEqualTo(6);
|
||||
assertThat(profileTierLevels.get(1).generalLevelIdc).isEqualTo(0);
|
||||
assertThat(profileTierLevels.get(2).generalProfileIdc).isEqualTo(6);
|
||||
assertThat(profileTierLevels.get(2).generalProfileCompatibilityFlags).isEqualTo(64);
|
||||
assertThat(profileTierLevels.get(2).generalLevelIdc).isEqualTo(120);
|
||||
ImmutableList<NalUnitUtil.H265RepFormat> repFormats = vpsData.repFormatsAndIndices.repFormats;
|
||||
assertThat(repFormats).hasSize(1);
|
||||
assertThat(repFormats.get(0).chromaFormatIdc).isEqualTo(1);
|
||||
assertThat(repFormats.get(0).width).isEqualTo(1920);
|
||||
assertThat(repFormats.get(0).height).isEqualTo(1080);
|
||||
assertThat(repFormats.get(0).bitDepthLumaMinus8).isEqualTo(0);
|
||||
assertThat(repFormats.get(0).bitDepthChromaMinus8).isEqualTo(0);
|
||||
|
||||
NalUnitUtil.H265SpsData spsDataView0 =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
H265_SPS_TEST_DATA_2VIEWS_VIEW_0,
|
||||
/* nalOffset= */ 0,
|
||||
H265_SPS_TEST_DATA_2VIEWS_VIEW_0.length,
|
||||
vpsData);
|
||||
assertThat(spsDataView0.nalHeader.layerId).isEqualTo(0);
|
||||
assertThat(spsDataView0.profileTierLevel.generalProfileIdc).isEqualTo(1);
|
||||
assertThat(spsDataView0.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(6);
|
||||
assertThat(spsDataView0.profileTierLevel.generalLevelIdc).isEqualTo(120);
|
||||
assertThat(spsDataView0.chromaFormatIdc).isEqualTo(1);
|
||||
assertThat(spsDataView0.width).isEqualTo(1920);
|
||||
assertThat(spsDataView0.height).isEqualTo(1080);
|
||||
assertThat(spsDataView0.bitDepthLumaMinus8).isEqualTo(0);
|
||||
assertThat(spsDataView0.bitDepthChromaMinus8).isEqualTo(0);
|
||||
assertThat(spsDataView0.colorSpace).isEqualTo(1);
|
||||
assertThat(spsDataView0.colorRange).isEqualTo(2);
|
||||
assertThat(spsDataView0.colorTransfer).isEqualTo(3);
|
||||
|
||||
NalUnitUtil.H265SpsData spsDataView1 =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
H265_SPS_TEST_DATA_2VIEWS_VIEW_1,
|
||||
/* nalOffset= */ 0,
|
||||
H265_SPS_TEST_DATA_2VIEWS_VIEW_1.length,
|
||||
vpsData);
|
||||
assertThat(spsDataView1.nalHeader.layerId).isEqualTo(1);
|
||||
assertThat(spsDataView1.profileTierLevel.generalProfileIdc).isEqualTo(6);
|
||||
assertThat(spsDataView1.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(64);
|
||||
assertThat(spsDataView1.profileTierLevel.generalLevelIdc).isEqualTo(120);
|
||||
assertThat(spsDataView1.chromaFormatIdc).isEqualTo(1);
|
||||
assertThat(spsDataView1.width).isEqualTo(1920);
|
||||
assertThat(spsDataView1.height).isEqualTo(1080);
|
||||
assertThat(spsDataView1.bitDepthLumaMinus8).isEqualTo(0);
|
||||
assertThat(spsDataView1.bitDepthChromaMinus8).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseH265VpsAndSpsNalUnits2ViewsHdr() {
|
||||
NalUnitUtil.H265VpsData vpsData =
|
||||
NalUnitUtil.parseH265VpsNalUnit(
|
||||
H265_VPS_TEST_DATA_2VIEWS_HDR,
|
||||
/* nalOffset= */ 0,
|
||||
H265_VPS_TEST_DATA_2VIEWS_HDR.length);
|
||||
assertThat(vpsData.nalHeader.layerId).isEqualTo(0);
|
||||
ImmutableList<NalUnitUtil.H265LayerInfo> layerInfos = vpsData.layerInfos;
|
||||
assertThat(layerInfos).hasSize(2);
|
||||
assertThat(layerInfos.get(0).layerIdInVps).isEqualTo(0);
|
||||
assertThat(layerInfos.get(0).viewId).isEqualTo(0);
|
||||
assertThat(layerInfos.get(1).layerIdInVps).isEqualTo(1);
|
||||
assertThat(layerInfos.get(1).viewId).isEqualTo(1);
|
||||
ImmutableList<NalUnitUtil.H265ProfileTierLevel> profileTierLevels =
|
||||
vpsData.profileTierLevelsAndIndices.profileTierLevels;
|
||||
assertThat(profileTierLevels).hasSize(3);
|
||||
assertThat(profileTierLevels.get(0).generalProfileIdc).isEqualTo(2);
|
||||
assertThat(profileTierLevels.get(0).generalProfileCompatibilityFlags).isEqualTo(4);
|
||||
assertThat(profileTierLevels.get(0).generalLevelIdc).isEqualTo(153);
|
||||
assertThat(profileTierLevels.get(1).generalProfileIdc).isEqualTo(2);
|
||||
assertThat(profileTierLevels.get(1).generalProfileCompatibilityFlags).isEqualTo(4);
|
||||
assertThat(profileTierLevels.get(1).generalLevelIdc).isEqualTo(153);
|
||||
assertThat(profileTierLevels.get(2).generalProfileIdc).isEqualTo(6);
|
||||
assertThat(profileTierLevels.get(2).generalProfileCompatibilityFlags).isEqualTo(68);
|
||||
assertThat(profileTierLevels.get(2).generalLevelIdc).isEqualTo(153);
|
||||
ImmutableList<NalUnitUtil.H265RepFormat> repFormats = vpsData.repFormatsAndIndices.repFormats;
|
||||
assertThat(repFormats).hasSize(1);
|
||||
assertThat(repFormats.get(0).chromaFormatIdc).isEqualTo(1);
|
||||
assertThat(repFormats.get(0).width).isEqualTo(3840);
|
||||
assertThat(repFormats.get(0).height).isEqualTo(2160);
|
||||
assertThat(repFormats.get(0).bitDepthLumaMinus8).isEqualTo(2);
|
||||
assertThat(repFormats.get(0).bitDepthChromaMinus8).isEqualTo(2);
|
||||
|
||||
NalUnitUtil.H265SpsData spsDataView0 =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
H265_SPS_TEST_DATA_2VIEWS_HDR_VIEW_0,
|
||||
/* nalOffset= */ 0,
|
||||
H265_SPS_TEST_DATA_2VIEWS_HDR_VIEW_0.length,
|
||||
vpsData);
|
||||
assertThat(spsDataView0.nalHeader.layerId).isEqualTo(0);
|
||||
assertThat(spsDataView0.profileTierLevel.generalProfileIdc).isEqualTo(2);
|
||||
assertThat(spsDataView0.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(4);
|
||||
assertThat(spsDataView0.profileTierLevel.generalLevelIdc).isEqualTo(153);
|
||||
assertThat(spsDataView0.chromaFormatIdc).isEqualTo(1);
|
||||
assertThat(spsDataView0.width).isEqualTo(3840);
|
||||
assertThat(spsDataView0.height).isEqualTo(2160);
|
||||
assertThat(spsDataView0.bitDepthLumaMinus8).isEqualTo(2);
|
||||
assertThat(spsDataView0.bitDepthChromaMinus8).isEqualTo(2);
|
||||
|
||||
NalUnitUtil.H265SpsData spsDataView1 =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
H265_SPS_TEST_DATA_2VIEWS_HDR_VIEW_1,
|
||||
/* nalOffset= */ 0,
|
||||
H265_SPS_TEST_DATA_2VIEWS_HDR_VIEW_1.length,
|
||||
vpsData);
|
||||
assertThat(spsDataView1.nalHeader.layerId).isEqualTo(1);
|
||||
assertThat(spsDataView1.profileTierLevel.generalProfileIdc).isEqualTo(6);
|
||||
assertThat(spsDataView1.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(68);
|
||||
assertThat(spsDataView1.profileTierLevel.generalLevelIdc).isEqualTo(153);
|
||||
assertThat(spsDataView1.chromaFormatIdc).isEqualTo(1);
|
||||
assertThat(spsDataView1.width).isEqualTo(3840);
|
||||
assertThat(spsDataView1.height).isEqualTo(2160);
|
||||
assertThat(spsDataView1.bitDepthLumaMinus8).isEqualTo(2);
|
||||
assertThat(spsDataView1.bitDepthChromaMinus8).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unescapeDoesNotModifyBuffersWithoutStartCodes() {
|
||||
assertUnescapeDoesNotModify("");
|
||||
@ -185,15 +404,18 @@ public final class NalUnitUtilTest {
|
||||
-128, 28, 120, 1, -57, 0, 56, -15
|
||||
};
|
||||
|
||||
NalUnitUtil.H265NalHeader nalHeader =
|
||||
new NalUnitUtil.H265NalHeader(NalUnitUtil.H265_NAL_UNIT_TYPE_SPS, 0, 0);
|
||||
NalUnitUtil.H265SpsData spsData =
|
||||
NalUnitUtil.parseH265SpsNalUnitPayload(spsNalUnitPayload, 0, spsNalUnitPayload.length);
|
||||
NalUnitUtil.parseH265SpsNalUnitPayload(
|
||||
spsNalUnitPayload, 0, spsNalUnitPayload.length, nalHeader, null);
|
||||
|
||||
assertThat(spsData.constraintBytes).isEqualTo(new int[] {144, 0, 0, 0, 0, 0});
|
||||
assertThat(spsData.generalLevelIdc).isEqualTo(150);
|
||||
assertThat(spsData.generalProfileCompatibilityFlags).isEqualTo(4);
|
||||
assertThat(spsData.generalProfileIdc).isEqualTo(2);
|
||||
assertThat(spsData.generalProfileSpace).isEqualTo(0);
|
||||
assertThat(spsData.generalTierFlag).isFalse();
|
||||
assertThat(spsData.profileTierLevel.constraintBytes).isEqualTo(new int[] {144, 0, 0, 0, 0, 0});
|
||||
assertThat(spsData.profileTierLevel.generalLevelIdc).isEqualTo(150);
|
||||
assertThat(spsData.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(4);
|
||||
assertThat(spsData.profileTierLevel.generalProfileIdc).isEqualTo(2);
|
||||
assertThat(spsData.profileTierLevel.generalProfileSpace).isEqualTo(0);
|
||||
assertThat(spsData.profileTierLevel.generalTierFlag).isFalse();
|
||||
assertThat(spsData.height).isEqualTo(2160);
|
||||
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
|
||||
assertThat(spsData.seqParameterSetId).isEqualTo(0);
|
||||
@ -214,15 +436,18 @@ public final class NalUnitUtilTest {
|
||||
8
|
||||
};
|
||||
|
||||
NalUnitUtil.H265NalHeader nalHeader =
|
||||
new NalUnitUtil.H265NalHeader(NalUnitUtil.H265_NAL_UNIT_TYPE_SPS, 0, 0);
|
||||
NalUnitUtil.H265SpsData spsData =
|
||||
NalUnitUtil.parseH265SpsNalUnitPayload(spsNalUnitPayload, 0, spsNalUnitPayload.length);
|
||||
NalUnitUtil.parseH265SpsNalUnitPayload(
|
||||
spsNalUnitPayload, 0, spsNalUnitPayload.length, nalHeader, null);
|
||||
|
||||
assertThat(spsData.constraintBytes).isEqualTo(new int[] {0, 0, 0, 0, 0, 0});
|
||||
assertThat(spsData.generalLevelIdc).isEqualTo(150);
|
||||
assertThat(spsData.generalProfileCompatibilityFlags).isEqualTo(6);
|
||||
assertThat(spsData.generalProfileIdc).isEqualTo(2);
|
||||
assertThat(spsData.generalProfileSpace).isEqualTo(0);
|
||||
assertThat(spsData.generalTierFlag).isFalse();
|
||||
assertThat(spsData.profileTierLevel.constraintBytes).isEqualTo(new int[] {0, 0, 0, 0, 0, 0});
|
||||
assertThat(spsData.profileTierLevel.generalLevelIdc).isEqualTo(150);
|
||||
assertThat(spsData.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(6);
|
||||
assertThat(spsData.profileTierLevel.generalProfileIdc).isEqualTo(2);
|
||||
assertThat(spsData.profileTierLevel.generalProfileSpace).isEqualTo(0);
|
||||
assertThat(spsData.profileTierLevel.generalTierFlag).isFalse();
|
||||
assertThat(spsData.width).isEqualTo(1080);
|
||||
assertThat(spsData.height).isEqualTo(1920);
|
||||
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
|
||||
|
@ -467,7 +467,10 @@ import com.google.common.collect.ImmutableMap;
|
||||
byte[] spsNalDataWithStartCode = initializationData.get(1);
|
||||
NalUnitUtil.H265SpsData spsData =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
spsNalDataWithStartCode, NAL_START_CODE.length, spsNalDataWithStartCode.length);
|
||||
spsNalDataWithStartCode,
|
||||
NAL_START_CODE.length,
|
||||
spsNalDataWithStartCode.length,
|
||||
/* vpsData= */ null);
|
||||
formatBuilder.setPixelWidthHeightRatio(spsData.pixelWidthHeightRatio);
|
||||
formatBuilder.setHeight(spsData.height).setWidth(spsData.width);
|
||||
formatBuilder.setColorInfo(
|
||||
@ -479,14 +482,16 @@ import com.google.common.collect.ImmutableMap;
|
||||
.setChromaBitdepth(spsData.bitDepthChromaMinus8 + 8)
|
||||
.build());
|
||||
|
||||
formatBuilder.setCodecs(
|
||||
CodecSpecificDataUtil.buildHevcCodecString(
|
||||
spsData.generalProfileSpace,
|
||||
spsData.generalTierFlag,
|
||||
spsData.generalProfileIdc,
|
||||
spsData.generalProfileCompatibilityFlags,
|
||||
spsData.constraintBytes,
|
||||
spsData.generalLevelIdc));
|
||||
if (spsData.profileTierLevel != null) {
|
||||
formatBuilder.setCodecs(
|
||||
CodecSpecificDataUtil.buildHevcCodecString(
|
||||
spsData.profileTierLevel.generalProfileSpace,
|
||||
spsData.profileTierLevel.generalTierFlag,
|
||||
spsData.profileTierLevel.generalProfileIdc,
|
||||
spsData.profileTierLevel.generalProfileCompatibilityFlags,
|
||||
spsData.profileTierLevel.constraintBytes,
|
||||
spsData.profileTierLevel.generalLevelIdc));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +89,7 @@ public final class HevcConfig {
|
||||
if (nalUnitType == SPS_NAL_UNIT_TYPE && j == 0) {
|
||||
NalUnitUtil.H265SpsData spsData =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
buffer, bufferPosition, bufferPosition + nalUnitLength);
|
||||
buffer, bufferPosition, bufferPosition + nalUnitLength, null);
|
||||
width = spsData.width;
|
||||
height = spsData.height;
|
||||
bitdepthLuma = spsData.bitDepthLumaMinus8 + 8;
|
||||
@ -100,14 +100,16 @@ public final class HevcConfig {
|
||||
pixelWidthHeightRatio = spsData.pixelWidthHeightRatio;
|
||||
maxNumReorderPics = spsData.maxNumReorderPics;
|
||||
|
||||
codecs =
|
||||
CodecSpecificDataUtil.buildHevcCodecString(
|
||||
spsData.generalProfileSpace,
|
||||
spsData.generalTierFlag,
|
||||
spsData.generalProfileIdc,
|
||||
spsData.generalProfileCompatibilityFlags,
|
||||
spsData.constraintBytes,
|
||||
spsData.generalLevelIdc);
|
||||
if (spsData.profileTierLevel != null) {
|
||||
codecs =
|
||||
CodecSpecificDataUtil.buildHevcCodecString(
|
||||
spsData.profileTierLevel.generalProfileSpace,
|
||||
spsData.profileTierLevel.generalTierFlag,
|
||||
spsData.profileTierLevel.generalProfileIdc,
|
||||
spsData.profileTierLevel.generalProfileCompatibilityFlags,
|
||||
spsData.profileTierLevel.constraintBytes,
|
||||
spsData.profileTierLevel.generalLevelIdc);
|
||||
}
|
||||
}
|
||||
bufferPosition += nalUnitLength;
|
||||
data.skipBytes(nalUnitLength);
|
||||
|
@ -246,17 +246,20 @@ public final class H265Reader implements ElementaryStreamReader {
|
||||
|
||||
// Skip the 3-byte NAL unit start code synthesised by the NalUnitTargetBuffer constructor.
|
||||
NalUnitUtil.H265SpsData spsData =
|
||||
NalUnitUtil.parseH265SpsNalUnit(sps.nalData, /* nalOffset= */ 3, sps.nalLength);
|
||||
|
||||
String codecs =
|
||||
CodecSpecificDataUtil.buildHevcCodecString(
|
||||
spsData.generalProfileSpace,
|
||||
spsData.generalTierFlag,
|
||||
spsData.generalProfileIdc,
|
||||
spsData.generalProfileCompatibilityFlags,
|
||||
spsData.constraintBytes,
|
||||
spsData.generalLevelIdc);
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
sps.nalData, /* nalOffset= */ 3, sps.nalLength, /* vpsData= */ null);
|
||||
|
||||
@Nullable String codecs = null;
|
||||
if (spsData.profileTierLevel != null) {
|
||||
codecs =
|
||||
CodecSpecificDataUtil.buildHevcCodecString(
|
||||
spsData.profileTierLevel.generalProfileSpace,
|
||||
spsData.profileTierLevel.generalTierFlag,
|
||||
spsData.profileTierLevel.generalProfileIdc,
|
||||
spsData.profileTierLevel.generalProfileCompatibilityFlags,
|
||||
spsData.profileTierLevel.constraintBytes,
|
||||
spsData.profileTierLevel.generalLevelIdc);
|
||||
}
|
||||
return new Format.Builder()
|
||||
.setId(formatId)
|
||||
.setSampleMimeType(MimeTypes.VIDEO_H265)
|
||||
|
@ -1202,7 +1202,7 @@ import java.util.List;
|
||||
|
||||
NalUnitUtil.H265SpsData h265SpsData =
|
||||
NalUnitUtil.parseH265SpsNalUnit(
|
||||
spsArray, /* nalOffset= */ 0, /* nalLimit= */ spsArray.length);
|
||||
spsArray, /* nalOffset= */ 0, /* nalLimit= */ spsArray.length, /* vpsData= */ null);
|
||||
|
||||
byte chromaFormat = (byte) (0xFC | h265SpsData.chromaFormatIdc); // First 6 bits reserved
|
||||
byte bitDepthLumaMinus8 =
|
||||
|
Loading…
x
Reference in New Issue
Block a user