Bug 1321164 - part1 : handle multiple SPS/PPS. r=jya

Implement the data structure for multuple SPS/PPS, and decode the multiple SPS/PPS from the extra data.

MozReview-Commit-ID: E90fdH1pvlA

--HG--
extra : rebase_source : 4b9c3229b92ec5d1d43ce14a72b8e96da516c59d
This commit is contained in:
Alastor Wu 2016-12-02 14:52:48 +08:00
parent 8eec8fa630
commit 1a51e913a5
2 changed files with 136 additions and 57 deletions

View File

@ -211,6 +211,10 @@ H264::DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest)
br.ReadBits(2); // reserved_zero_2bits
aDest.level_idc = br.ReadBits(8);
aDest.seq_parameter_set_id = br.ReadUE();
if (aDest.seq_parameter_set_id >= MAX_SPS_COUNT) {
return false;
}
if (aDest.profile_idc == 100 || aDest.profile_idc == 110 ||
aDest.profile_idc == 122 || aDest.profile_idc == 244 ||
aDest.profile_idc == 44 || aDest.profile_idc == 83 ||
@ -532,6 +536,26 @@ H264::vui_parameters(BitReader& aBr, SPSData& aDest)
/* static */ bool
H264::DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSData& aDest)
{
H264ParametersSet ps;
if (!DecodeSPSDataSetFromExtraData(aExtraData, ps.SPSes)) {
return false;
}
uint16_t spsId = 0;
if (DecodePPSDataSetFromExtraData(aExtraData, ps.SPSes, ps.PPSes)) {
// We can't know which PPS is in use without parsing slice header if we
// have multiple PPSes, so we always use the first one.
spsId = ps.PPSes[0].seq_parameter_set_id;
}
aDest = Move(ps.SPSes[spsId]);
return true;
}
/* static */ bool
H264::DecodeSPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSDataSet& aDest)
{
if (!AnnexB::HasSPS(aExtraData)) {
return false;
@ -547,29 +571,36 @@ H264::DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
// No SPS.
return false;
}
NS_ASSERTION(numSps == 1, "More than one SPS in extradata");
NS_ASSERTION(numSps <= MAX_SPS_COUNT, "Exceed the maximum SPS counts!");
uint16_t length = reader.ReadU16();
for (uint32_t idx = 0; idx < numSps; idx++) {
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != 7) {
// Not a SPS NAL type.
return false;
if ((reader.PeekU8() & 0x1f) != 7) {
// Not a SPS NAL type.
return false;
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
rawNAL->AppendElements(ptr, length);
RefPtr<mozilla::MediaByteBuffer> sps = DecodeNALUnit(rawNAL);
if (!sps) {
return false;
}
SPSData spsData;
if (!DecodeSPS(sps, spsData)) {
return false;
}
aDest.AppendElement(spsData);
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
rawNAL->AppendElements(ptr, length);
RefPtr<mozilla::MediaByteBuffer> sps = DecodeNALUnit(rawNAL);
if (!sps) {
return false;
}
return DecodeSPS(sps, aDest);
return true;
}
/* static */ bool
@ -595,8 +626,8 @@ H264::EnsureSPSIsSane(SPSData& aSPS)
}
/* static */ bool
H264::DecodePPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
const SPSData& aSPS, PPSData& aDest)
H264::DecodePPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
const SPSDataSet& aSPSes, PPSDataSet& aDest)
{
if (!AnnexB::HasPPS(aExtraData)) {
return false;
@ -630,47 +661,67 @@ H264::DecodePPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
// No PPs.
return false;
}
NS_ASSERTION(numPps == 1, "More than one PPS in extradata");
uint16_t length = reader.ReadU16();
NS_ASSERTION(numPps <= MAX_PPS_COUNT, "Exceed the maximum PPS counts!");
if ((reader.PeekU8() & 0x1f) != 8) {
// Not a PPS NAL type.
return false;
for (uint32_t idx = 0; idx < numPps; idx++) {
uint16_t length = reader.ReadU16();
if ((reader.PeekU8() & 0x1f) != 8) {
// Not a PPS NAL type.
return false;
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
rawNAL->AppendElements(ptr, length);
RefPtr<mozilla::MediaByteBuffer> pps = DecodeNALUnit(rawNAL);
if (!pps) {
return false;
}
PPSData ppsData;
if(DecodePPS(pps, aSPSes, ppsData)) {
return false;
}
aDest[ppsData.pic_parameter_set_id] = Move(ppsData);
}
const uint8_t* ptr = reader.Read(length);
if (!ptr) {
return false;
}
RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
rawNAL->AppendElements(ptr, length);
RefPtr<mozilla::MediaByteBuffer> pps = DecodeNALUnit(rawNAL);
if (!pps) {
return false;
}
return DecodePPS(pps, aSPS, aDest);
return true;
}
/* static */ bool
H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS,const SPSData& aSPS,
H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS, const SPSDataSet& aSPSes,
PPSData& aDest)
{
if (!aPPS) {
return false;
}
memcpy(aDest.scaling_matrix4x4, aSPS.scaling_matrix4x4,
sizeof(aDest.scaling_matrix4x4));
memcpy(aDest.scaling_matrix8x8, aSPS.scaling_matrix8x8,
sizeof(aDest.scaling_matrix8x8));
if (aSPSes.IsEmpty()) {
return false;
}
BitReader br(aPPS);
aDest.pic_parameter_set_id = br.ReadUE();
aDest.seq_parameter_set_id = br.ReadUE();
if (aDest.pic_parameter_set_id >= MAX_PPS_COUNT ||
aDest.seq_parameter_set_id >= MAX_SPS_COUNT) {
return false;
}
const SPSData& sps = aSPSes[aDest.seq_parameter_set_id];
memcpy(aDest.scaling_matrix4x4, sps.scaling_matrix4x4,
sizeof(aDest.scaling_matrix4x4));
memcpy(aDest.scaling_matrix8x8, sps.scaling_matrix8x8,
sizeof(aDest.scaling_matrix8x8));
aDest.entropy_coding_mode_flag = br.ReadBit();
aDest.bottom_field_pic_order_in_frame_present_flag = br.ReadBit();
aDest.num_slice_groups_minus1 = br.ReadUE();
@ -729,7 +780,7 @@ H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS,const SPSData& aSPS,
if (br.BitsLeft()) {
aDest.transform_8x8_mode_flag = br.ReadBit();
if (br.ReadBit()) { // pic_scaling_matrix_present_flag
if (aSPS.seq_scaling_matrix_present_flag) {
if (sps.seq_scaling_matrix_present_flag) {
scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra);
scaling_list(br, aDest.scaling_matrix4x4[1], Default_4x4_Intra,
aDest.scaling_matrix4x4[0]);
@ -751,7 +802,7 @@ H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS,const SPSData& aSPS,
scaling_list(br, aDest.scaling_matrix4x4[5], Default_4x4_Inter,
aDest.scaling_matrix4x4[4]);
if (aDest.transform_8x8_mode_flag) {
if (aSPS.seq_scaling_matrix_present_flag) {
if (sps.seq_scaling_matrix_present_flag) {
scaling_list(br, aDest.scaling_matrix8x8[0], Default_8x8_Intra);
scaling_list(br, aDest.scaling_matrix8x8[1], Default_8x8_Inter);
} else {
@ -760,7 +811,7 @@ H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS,const SPSData& aSPS,
scaling_list(br, aDest.scaling_matrix8x8[1], Default_8x8_Inter,
Default_8x8_Inter);
}
if (aSPS.chroma_format_idc == 3) {
if (sps.chroma_format_idc == 3) {
scaling_list(br, aDest.scaling_matrix8x8[2], Default_8x8_Intra,
aDest.scaling_matrix8x8[0]);
scaling_list(br, aDest.scaling_matrix8x8[3], Default_8x8_Inter,
@ -777,6 +828,14 @@ H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS,const SPSData& aSPS,
return true;
}
/* static */ bool
H264::DecodeParametersSet(const mozilla::MediaByteBuffer* aExtraData,
H264ParametersSet& aDest)
{
return DecodeSPSDataSetFromExtraData(aExtraData, aDest.SPSes) &&
DecodePPSDataSetFromExtraData(aExtraData, aDest.SPSes, aDest.PPSes);
}
/* static */ uint32_t
H264::ComputeMaxRefFrames(const mozilla::MediaByteBuffer* aExtraData)
{

View File

@ -9,6 +9,10 @@
namespace mp4_demuxer {
// Spec 7.4.2.1
#define MAX_SPS_COUNT 32
#define MAX_PPS_COUNT 256
class BitReader;
struct SPSData
@ -560,12 +564,18 @@ struct PPSData
PPSData();
};
typedef AutoTArray<SPSData, MAX_SPS_COUNT> SPSDataSet;
typedef AutoTArray<PPSData, MAX_PPS_COUNT> PPSDataSet;
struct H264ParametersSet
{
SPSDataSet SPSes;
PPSDataSet PPSes;
};
class H264
{
public:
static bool DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSData& aDest);
/* Extract RAW BYTE SEQUENCE PAYLOAD from NAL content.
Returns nullptr if invalid content.
This is compliant to ITU H.264 7.3.1 Syntax in tabular form NAL unit syntax
@ -577,8 +587,11 @@ public:
// otherwise. If false, then content will be adjusted accordingly.
static bool EnsureSPSIsSane(SPSData& aSPS);
static bool DecodePPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
const SPSData& aSPS, PPSData& aDest);
static bool DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSData& aDest);
static bool DecodeParametersSet(const mozilla::MediaByteBuffer* aExtraData,
H264ParametersSet& aDest);
// If the given aExtraData is valid, return the aExtraData.max_num_ref_frames
// clamped to be in the range of [4, 16]; otherwise return 4.
@ -605,11 +618,18 @@ public:
static const uint8_t ZZ_SCAN8[64];
private:
static bool DecodeSPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
SPSDataSet& aDest);
static bool DecodePPSDataSetFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
const SPSDataSet& aPS,
PPSDataSet& aDest);
/* Decode SPS NAL RBSP and fill SPSData structure */
static bool DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest);
/* Decode PPS NAL RBSP and fill PPSData structure */
static bool DecodePPS(const mozilla::MediaByteBuffer* aPPS, const SPSData& aSPS,
PPSData& aDest);
static bool DecodePPS(const mozilla::MediaByteBuffer* aPPS,
const SPSDataSet& aSPSs, PPSData& aDest);
static void vui_parameters(BitReader& aBr, SPSData& aDest);
// Read HRD parameters, all data is ignored.
static void hrd_parameters(BitReader& aBr);