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();
|
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
|
* Returns whether it's possible to read {@code n} bits starting from the current offset. The
|
||||||
* offset is not modified.
|
* offset is not modified.
|
||||||
|
@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -37,6 +38,58 @@ public final class NalUnitUtilTest {
|
|||||||
0x91, 0x00, 0x00, 0x7E, 0xA0);
|
0x91, 0x00, 0x00, 0x7E, 0xA0);
|
||||||
private static final int SPS_TEST_DATA_OFFSET = 3;
|
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
|
@Test
|
||||||
public void findNalUnit() {
|
public void findNalUnit() {
|
||||||
byte[] data = buildTestData();
|
byte[] data = buildTestData();
|
||||||
@ -143,6 +196,172 @@ public final class NalUnitUtilTest {
|
|||||||
assertThat(data.maxNumReorderFrames).isEqualTo(1);
|
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
|
@Test
|
||||||
public void unescapeDoesNotModifyBuffersWithoutStartCodes() {
|
public void unescapeDoesNotModifyBuffersWithoutStartCodes() {
|
||||||
assertUnescapeDoesNotModify("");
|
assertUnescapeDoesNotModify("");
|
||||||
@ -185,15 +404,18 @@ public final class NalUnitUtilTest {
|
|||||||
-128, 28, 120, 1, -57, 0, 56, -15
|
-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.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.profileTierLevel.constraintBytes).isEqualTo(new int[] {144, 0, 0, 0, 0, 0});
|
||||||
assertThat(spsData.generalLevelIdc).isEqualTo(150);
|
assertThat(spsData.profileTierLevel.generalLevelIdc).isEqualTo(150);
|
||||||
assertThat(spsData.generalProfileCompatibilityFlags).isEqualTo(4);
|
assertThat(spsData.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(4);
|
||||||
assertThat(spsData.generalProfileIdc).isEqualTo(2);
|
assertThat(spsData.profileTierLevel.generalProfileIdc).isEqualTo(2);
|
||||||
assertThat(spsData.generalProfileSpace).isEqualTo(0);
|
assertThat(spsData.profileTierLevel.generalProfileSpace).isEqualTo(0);
|
||||||
assertThat(spsData.generalTierFlag).isFalse();
|
assertThat(spsData.profileTierLevel.generalTierFlag).isFalse();
|
||||||
assertThat(spsData.height).isEqualTo(2160);
|
assertThat(spsData.height).isEqualTo(2160);
|
||||||
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
|
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
|
||||||
assertThat(spsData.seqParameterSetId).isEqualTo(0);
|
assertThat(spsData.seqParameterSetId).isEqualTo(0);
|
||||||
@ -214,15 +436,18 @@ public final class NalUnitUtilTest {
|
|||||||
8
|
8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NalUnitUtil.H265NalHeader nalHeader =
|
||||||
|
new NalUnitUtil.H265NalHeader(NalUnitUtil.H265_NAL_UNIT_TYPE_SPS, 0, 0);
|
||||||
NalUnitUtil.H265SpsData spsData =
|
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.profileTierLevel.constraintBytes).isEqualTo(new int[] {0, 0, 0, 0, 0, 0});
|
||||||
assertThat(spsData.generalLevelIdc).isEqualTo(150);
|
assertThat(spsData.profileTierLevel.generalLevelIdc).isEqualTo(150);
|
||||||
assertThat(spsData.generalProfileCompatibilityFlags).isEqualTo(6);
|
assertThat(spsData.profileTierLevel.generalProfileCompatibilityFlags).isEqualTo(6);
|
||||||
assertThat(spsData.generalProfileIdc).isEqualTo(2);
|
assertThat(spsData.profileTierLevel.generalProfileIdc).isEqualTo(2);
|
||||||
assertThat(spsData.generalProfileSpace).isEqualTo(0);
|
assertThat(spsData.profileTierLevel.generalProfileSpace).isEqualTo(0);
|
||||||
assertThat(spsData.generalTierFlag).isFalse();
|
assertThat(spsData.profileTierLevel.generalTierFlag).isFalse();
|
||||||
assertThat(spsData.width).isEqualTo(1080);
|
assertThat(spsData.width).isEqualTo(1080);
|
||||||
assertThat(spsData.height).isEqualTo(1920);
|
assertThat(spsData.height).isEqualTo(1920);
|
||||||
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
|
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
|
||||||
|
@ -467,7 +467,10 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
byte[] spsNalDataWithStartCode = initializationData.get(1);
|
byte[] spsNalDataWithStartCode = initializationData.get(1);
|
||||||
NalUnitUtil.H265SpsData spsData =
|
NalUnitUtil.H265SpsData spsData =
|
||||||
NalUnitUtil.parseH265SpsNalUnit(
|
NalUnitUtil.parseH265SpsNalUnit(
|
||||||
spsNalDataWithStartCode, NAL_START_CODE.length, spsNalDataWithStartCode.length);
|
spsNalDataWithStartCode,
|
||||||
|
NAL_START_CODE.length,
|
||||||
|
spsNalDataWithStartCode.length,
|
||||||
|
/* vpsData= */ null);
|
||||||
formatBuilder.setPixelWidthHeightRatio(spsData.pixelWidthHeightRatio);
|
formatBuilder.setPixelWidthHeightRatio(spsData.pixelWidthHeightRatio);
|
||||||
formatBuilder.setHeight(spsData.height).setWidth(spsData.width);
|
formatBuilder.setHeight(spsData.height).setWidth(spsData.width);
|
||||||
formatBuilder.setColorInfo(
|
formatBuilder.setColorInfo(
|
||||||
@ -479,14 +482,16 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
.setChromaBitdepth(spsData.bitDepthChromaMinus8 + 8)
|
.setChromaBitdepth(spsData.bitDepthChromaMinus8 + 8)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
formatBuilder.setCodecs(
|
if (spsData.profileTierLevel != null) {
|
||||||
CodecSpecificDataUtil.buildHevcCodecString(
|
formatBuilder.setCodecs(
|
||||||
spsData.generalProfileSpace,
|
CodecSpecificDataUtil.buildHevcCodecString(
|
||||||
spsData.generalTierFlag,
|
spsData.profileTierLevel.generalProfileSpace,
|
||||||
spsData.generalProfileIdc,
|
spsData.profileTierLevel.generalTierFlag,
|
||||||
spsData.generalProfileCompatibilityFlags,
|
spsData.profileTierLevel.generalProfileIdc,
|
||||||
spsData.constraintBytes,
|
spsData.profileTierLevel.generalProfileCompatibilityFlags,
|
||||||
spsData.generalLevelIdc));
|
spsData.profileTierLevel.constraintBytes,
|
||||||
|
spsData.profileTierLevel.generalLevelIdc));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +89,7 @@ public final class HevcConfig {
|
|||||||
if (nalUnitType == SPS_NAL_UNIT_TYPE && j == 0) {
|
if (nalUnitType == SPS_NAL_UNIT_TYPE && j == 0) {
|
||||||
NalUnitUtil.H265SpsData spsData =
|
NalUnitUtil.H265SpsData spsData =
|
||||||
NalUnitUtil.parseH265SpsNalUnit(
|
NalUnitUtil.parseH265SpsNalUnit(
|
||||||
buffer, bufferPosition, bufferPosition + nalUnitLength);
|
buffer, bufferPosition, bufferPosition + nalUnitLength, null);
|
||||||
width = spsData.width;
|
width = spsData.width;
|
||||||
height = spsData.height;
|
height = spsData.height;
|
||||||
bitdepthLuma = spsData.bitDepthLumaMinus8 + 8;
|
bitdepthLuma = spsData.bitDepthLumaMinus8 + 8;
|
||||||
@ -100,14 +100,16 @@ public final class HevcConfig {
|
|||||||
pixelWidthHeightRatio = spsData.pixelWidthHeightRatio;
|
pixelWidthHeightRatio = spsData.pixelWidthHeightRatio;
|
||||||
maxNumReorderPics = spsData.maxNumReorderPics;
|
maxNumReorderPics = spsData.maxNumReorderPics;
|
||||||
|
|
||||||
codecs =
|
if (spsData.profileTierLevel != null) {
|
||||||
CodecSpecificDataUtil.buildHevcCodecString(
|
codecs =
|
||||||
spsData.generalProfileSpace,
|
CodecSpecificDataUtil.buildHevcCodecString(
|
||||||
spsData.generalTierFlag,
|
spsData.profileTierLevel.generalProfileSpace,
|
||||||
spsData.generalProfileIdc,
|
spsData.profileTierLevel.generalTierFlag,
|
||||||
spsData.generalProfileCompatibilityFlags,
|
spsData.profileTierLevel.generalProfileIdc,
|
||||||
spsData.constraintBytes,
|
spsData.profileTierLevel.generalProfileCompatibilityFlags,
|
||||||
spsData.generalLevelIdc);
|
spsData.profileTierLevel.constraintBytes,
|
||||||
|
spsData.profileTierLevel.generalLevelIdc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bufferPosition += nalUnitLength;
|
bufferPosition += nalUnitLength;
|
||||||
data.skipBytes(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.
|
// Skip the 3-byte NAL unit start code synthesised by the NalUnitTargetBuffer constructor.
|
||||||
NalUnitUtil.H265SpsData spsData =
|
NalUnitUtil.H265SpsData spsData =
|
||||||
NalUnitUtil.parseH265SpsNalUnit(sps.nalData, /* nalOffset= */ 3, sps.nalLength);
|
NalUnitUtil.parseH265SpsNalUnit(
|
||||||
|
sps.nalData, /* nalOffset= */ 3, sps.nalLength, /* vpsData= */ null);
|
||||||
String codecs =
|
|
||||||
CodecSpecificDataUtil.buildHevcCodecString(
|
|
||||||
spsData.generalProfileSpace,
|
|
||||||
spsData.generalTierFlag,
|
|
||||||
spsData.generalProfileIdc,
|
|
||||||
spsData.generalProfileCompatibilityFlags,
|
|
||||||
spsData.constraintBytes,
|
|
||||||
spsData.generalLevelIdc);
|
|
||||||
|
|
||||||
|
@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()
|
return new Format.Builder()
|
||||||
.setId(formatId)
|
.setId(formatId)
|
||||||
.setSampleMimeType(MimeTypes.VIDEO_H265)
|
.setSampleMimeType(MimeTypes.VIDEO_H265)
|
||||||
|
@ -1202,7 +1202,7 @@ import java.util.List;
|
|||||||
|
|
||||||
NalUnitUtil.H265SpsData h265SpsData =
|
NalUnitUtil.H265SpsData h265SpsData =
|
||||||
NalUnitUtil.parseH265SpsNalUnit(
|
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 chromaFormat = (byte) (0xFC | h265SpsData.chromaFormatIdc); // First 6 bits reserved
|
||||||
byte bitDepthLumaMinus8 =
|
byte bitDepthLumaMinus8 =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user