Files
Bento4/Source/C++/Codecs/Ap4AvcParser.cpp
Gilles Boccon-Gibod 2fe0cb251d making some progress...
2017-09-24 19:06:52 -07:00

1145 lines
46 KiB
C++

/*****************************************************************
|
| AP4 - AVC Parser
|
| Copyright 2002-2008 Axiomatic Systems, LLC
|
|
| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
|
| Unless you have obtained Bento4 under a difference license,
| this version of Bento4 is Bento4|GPL.
| Bento4|GPL is free software; you can redistribute it and/or modify
| it under the terms of the GNU General Public License as published by
| the Free Software Foundation; either version 2, or (at your option)
| any later version.
|
| Bento4|GPL is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with Bento4|GPL; see the file COPYING. If not, write to the
| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
| 02111-1307, USA.
|
****************************************************************/
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
#include "Ap4AvcParser.h"
#include "Ap4Utils.h"
/*----------------------------------------------------------------------
| debugging
+---------------------------------------------------------------------*/
//#define AP4_AVC_PARSER_ENABLE_DEBUG
#if defined(AP4_AVC_PARSER_ENABLE_DEBUG)
#define DBG_PRINTF_0(_x0) printf(_x0)
#define DBG_PRINTF_1(_x0, _x1) printf(_x0, _x1)
#define DBG_PRINTF_2(_x0, _x1, _x2) printf(_x0, _x1, _x2)
#define DBG_PRINTF_3(_x0, _x1, _x2, _x3) printf(_x0, _x1, _x2, _x3)
#define DBG_PRINTF_4(_x0, _x1, _x2, _x3, _x4) printf(_x0, _x1, _x2, _x3, _x4)
#define DBG_PRINTF_5(_x0, _x1, _x2, _x3, _x4, _x5) printf(_x0, _x1, _x2, _x3, _x4, _x5)
#else
#define DBG_PRINTF_0(_x0)
#define DBG_PRINTF_1(_x0, _x1)
#define DBG_PRINTF_2(_x0, _x1, _x2)
#define DBG_PRINTF_3(_x0, _x1, _x2, _x3)
#define DBG_PRINTF_4(_x0, _x1, _x2, _x3, _x4)
#define DBG_PRINTF_5(_x0, _x1, _x2, _x3, _x4, _x5)
#endif
/*----------------------------------------------------------------------
| AP4_AvcNalParser::NaluTypeName
+---------------------------------------------------------------------*/
const char*
AP4_AvcNalParser::NaluTypeName(unsigned int nalu_type)
{
switch (nalu_type) {
case 0: return "Unspecified";
case 1: return "Coded slice of a non-IDR picture";
case 2: return "Coded slice data partition A";
case 3: return "Coded slice data partition B";
case 4: return "Coded slice data partition C";
case 5: return "Coded slice of an IDR picture";
case 6: return "Supplemental enhancement information (SEI)";
case 7: return "Sequence parameter set";
case 8: return "Picture parameter set";
case 9: return "Access unit delimiter";
case 10: return "End of sequence";
case 11: return "End of stream";
case 12: return "Filler data";
case 13: return "Sequence parameter set extension";
case 14: return "Prefix NAL unit in scalable extension";
case 15: return "Subset sequence parameter set";
case 19: return "Coded slice of an auxiliary coded picture without partitioning";
case 20: return "Coded slice in scalable extension";
default: return NULL;
}
}
/*----------------------------------------------------------------------
| AP4_AvcNalParser::PrimaryPicTypeName
+---------------------------------------------------------------------*/
const char*
AP4_AvcNalParser::PrimaryPicTypeName(unsigned int primary_pic_type)
{
switch (primary_pic_type) {
case 0: return "I";
case 1: return "I, P";
case 2: return "I, P, B";
case 3: return "SI";
case 4: return "SI, SP";
case 5: return "I, SI";
case 6: return "I, SI, P, SP";
case 7: return "I, SI, P, SP, B";
default: return NULL;
}
}
/*----------------------------------------------------------------------
| AP4_AvcNalParser::SliceTypeName
+---------------------------------------------------------------------*/
const char*
AP4_AvcNalParser::SliceTypeName(unsigned int slice_type)
{
switch (slice_type) {
case 0: return "P";
case 1: return "B";
case 2: return "I";
case 3: return "SP";
case 4: return "SI";
case 5: return "P";
case 6: return "B";
case 7: return "I";
case 8: return "SP";
case 9: return "SI";
default: return NULL;
}
}
/*----------------------------------------------------------------------
| AP4_AvcNalParser::AP4_AvcNalParser
+---------------------------------------------------------------------*/
AP4_AvcNalParser::AP4_AvcNalParser() :
AP4_NalParser()
{
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::AP4_AvcFrameParser
+---------------------------------------------------------------------*/
AP4_AvcFrameParser::AP4_AvcFrameParser() :
m_NalUnitType(0),
m_NalRefIdc(0),
m_SliceHeader(NULL),
m_AccessUnitVclNalUnitCount(0),
m_TotalNalUnitCount(0),
m_TotalAccessUnitCount(0),
m_PrevFrameNum(0),
m_PrevFrameNumOffset(0),
m_PrevPicOrderCntMsb(0),
m_PrevPicOrderCntLsb(0)
{
for (unsigned int i=0; i<256; i++) {
m_PPS[i] = NULL;
m_SPS[i] = NULL;
}
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::~AP4_AvcFrameParser
+---------------------------------------------------------------------*/
AP4_AvcFrameParser::~AP4_AvcFrameParser()
{
for (unsigned int i=0; i<256; i++) {
delete m_PPS[i];
delete m_SPS[i];
}
delete m_SliceHeader;
// cleanup any un-transfered buffers
for (unsigned int i=0; i<m_AccessUnitData.ItemCount(); i++) {
delete m_AccessUnitData[i];
}
}
/*----------------------------------------------------------------------
| ReadGolomb
+---------------------------------------------------------------------*/
static unsigned int
ReadGolomb(AP4_BitReader& bits)
{
unsigned int leading_zeros = 0;
while (bits.ReadBit() == 0) {
leading_zeros++;
if (leading_zeros > 32) return 0; // safeguard
}
if (leading_zeros) {
return (1<<leading_zeros)-1+bits.ReadBits(leading_zeros);
} else {
return 0;
}
}
/*----------------------------------------------------------------------
| SignedGolomb
+---------------------------------------------------------------------*/
static int
SignedGolomb(unsigned int code_num)
{
if (code_num % 2) {
return (code_num+1)/2;
} else {
return -((int)code_num/2);
}
}
/*----------------------------------------------------------------------
| AP4_AvcSequenceParameterSet::AP4_AvcSequenceParameterSet
+---------------------------------------------------------------------*/
AP4_AvcSequenceParameterSet::AP4_AvcSequenceParameterSet() :
profile_idc(0),
constraint_set0_flag(0),
constraint_set1_flag(0),
constraint_set2_flag(0),
constraint_set3_flag(0),
level_idc(0),
seq_parameter_set_id(0),
chroma_format_idc(0),
separate_colour_plane_flag(0),
bit_depth_luma_minus8(0),
bit_depth_chroma_minus8(0),
qpprime_y_zero_transform_bypass_flag(0),
seq_scaling_matrix_present_flag(0),
log2_max_frame_num_minus4(0),
pic_order_cnt_type(0),
log2_max_pic_order_cnt_lsb_minus4(0),
delta_pic_order_always_zero_flags(0),
offset_for_non_ref_pic(0),
offset_for_top_to_bottom_field(0),
num_ref_frames_in_pic_order_cnt_cycle(0),
num_ref_frames(0),
gaps_in_frame_num_value_allowed_flag(0),
pic_width_in_mbs_minus1(0),
pic_height_in_map_units_minus1(0),
frame_mbs_only_flag(0),
mb_adaptive_frame_field_flag(0),
direct_8x8_inference_flag(0),
frame_cropping_flag(0),
frame_crop_left_offset(0),
frame_crop_right_offset(0),
frame_crop_top_offset(0),
frame_crop_bottom_offset(0)
{
AP4_SetMemory(scaling_list_4x4, 0, sizeof(scaling_list_4x4));
AP4_SetMemory(use_default_scaling_matrix_4x4, 0, sizeof(use_default_scaling_matrix_4x4));
AP4_SetMemory(scaling_list_8x8, 0, sizeof(scaling_list_8x8));
AP4_SetMemory(use_default_scaling_matrix_8x8, 0, sizeof(use_default_scaling_matrix_8x8));
AP4_SetMemory(offset_for_ref_frame, 0, sizeof(offset_for_ref_frame));
}
/*----------------------------------------------------------------------
| AP4_AvcSequenceParameterSet::GetInfo
+---------------------------------------------------------------------*/
void
AP4_AvcSequenceParameterSet::GetInfo(unsigned int& width, unsigned int& height)
{
width = (pic_width_in_mbs_minus1+1) * 16;
height = (2-frame_mbs_only_flag) * (pic_height_in_map_units_minus1+1) * 16;
if (frame_cropping_flag) {
unsigned int crop_h = 2*(frame_crop_left_offset+frame_crop_right_offset);
unsigned int crop_v = 2*(frame_crop_top_offset+frame_crop_bottom_offset)*(2-frame_mbs_only_flag);
if (crop_h < width) width -= crop_h;
if (crop_v < height) height -= crop_v;
}
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::ParseSPS
+---------------------------------------------------------------------*/
AP4_Result
AP4_AvcFrameParser::ParseSPS(const unsigned char* data,
unsigned int data_size,
AP4_AvcSequenceParameterSet& sps)
{
sps.raw_bytes.SetData(data, data_size);
AP4_DataBuffer unescaped(data, data_size);
AP4_NalParser::Unescape(unescaped);
AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
bits.SkipBits(8); // NAL Unit Type
sps.profile_idc = bits.ReadBits(8);
sps.constraint_set0_flag = bits.ReadBit();
sps.constraint_set1_flag = bits.ReadBit();
sps.constraint_set2_flag = bits.ReadBit();
sps.constraint_set3_flag = bits.ReadBit();
bits.SkipBits(4);
sps.level_idc = bits.ReadBits(8);
sps.seq_parameter_set_id = ReadGolomb(bits);
if (sps.seq_parameter_set_id > AP4_AVC_SPS_MAX_ID) {
return AP4_ERROR_INVALID_FORMAT;
}
if (sps.profile_idc == 100 ||
sps.profile_idc == 110 ||
sps.profile_idc == 122 ||
sps.profile_idc == 244 ||
sps.profile_idc == 44 ||
sps.profile_idc == 83 ||
sps.profile_idc == 86) {
sps.chroma_format_idc = ReadGolomb(bits);
sps.separate_colour_plane_flag = 0;
if (sps.chroma_format_idc == 3) {
sps.separate_colour_plane_flag = bits.ReadBit();
}
sps.bit_depth_luma_minus8 = ReadGolomb(bits);
sps.bit_depth_chroma_minus8 = ReadGolomb(bits);
sps.qpprime_y_zero_transform_bypass_flag = bits.ReadBit();
sps.seq_scaling_matrix_present_flag = bits.ReadBit();
if (sps.seq_scaling_matrix_present_flag) {
for (int i=0; i<(sps.chroma_format_idc != 3 ? 8 : 12); i++) {
unsigned int seq_scaling_list_present_flag = bits.ReadBit();
if (seq_scaling_list_present_flag) {
if (i<6) {
int last_scale = 8;
int next_scale = 8;
for (unsigned int j=0; j<16; j++) {
if (next_scale) {
int delta_scale = SignedGolomb(ReadGolomb(bits));
next_scale = (last_scale + delta_scale + 256) % 256;
sps.use_default_scaling_matrix_4x4[i] = (j == 0 && next_scale == 0);
}
sps.scaling_list_4x4[i].scale[j] = (next_scale == 0 ? last_scale : next_scale);
last_scale = sps.scaling_list_4x4[i].scale[j];
}
} else {
int last_scale = 8;
int next_scale = 8;
for (unsigned int j=0; j<64; j++) {
if (next_scale) {
int delta_scale = SignedGolomb(ReadGolomb(bits));
next_scale = (last_scale + delta_scale + 256) % 256;
sps.use_default_scaling_matrix_8x8[i-6] = (j == 0 && next_scale == 0);
}
sps.scaling_list_8x8[i-6].scale[j] = (next_scale == 0 ? last_scale : next_scale);
last_scale = sps.scaling_list_8x8[i-6].scale[j];
}
}
}
}
}
}
sps.log2_max_frame_num_minus4 = ReadGolomb(bits);
sps.pic_order_cnt_type = ReadGolomb(bits);
if (sps.pic_order_cnt_type > 2) {
return AP4_ERROR_INVALID_FORMAT;
}
if (sps.pic_order_cnt_type == 0) {
sps.log2_max_pic_order_cnt_lsb_minus4 = ReadGolomb(bits);
} else if (sps.pic_order_cnt_type == 1) {
sps.delta_pic_order_always_zero_flags = bits.ReadBit();
sps.offset_for_non_ref_pic = SignedGolomb(ReadGolomb(bits));
sps.offset_for_top_to_bottom_field = SignedGolomb(ReadGolomb(bits));
sps.num_ref_frames_in_pic_order_cnt_cycle = ReadGolomb(bits);
if (sps.num_ref_frames_in_pic_order_cnt_cycle > AP4_AVC_SPS_MAX_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE) {
return AP4_ERROR_INVALID_FORMAT;
}
for (unsigned int i=0; i<sps.num_ref_frames_in_pic_order_cnt_cycle; i++) {
sps.offset_for_ref_frame[i] = SignedGolomb(ReadGolomb(bits));
}
}
sps.num_ref_frames = ReadGolomb(bits);
sps.gaps_in_frame_num_value_allowed_flag = bits.ReadBit();
sps.pic_width_in_mbs_minus1 = ReadGolomb(bits);
sps.pic_height_in_map_units_minus1 = ReadGolomb(bits);
sps.frame_mbs_only_flag = bits.ReadBit();
if (!sps.frame_mbs_only_flag) {
sps.mb_adaptive_frame_field_flag = bits.ReadBit();
}
sps.direct_8x8_inference_flag = bits.ReadBit();
sps.frame_cropping_flag = bits.ReadBit();
if (sps.frame_cropping_flag) {
sps.frame_crop_left_offset = ReadGolomb(bits);
sps.frame_crop_right_offset = ReadGolomb(bits);
sps.frame_crop_top_offset = ReadGolomb(bits);
sps.frame_crop_bottom_offset = ReadGolomb(bits);
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_AvcPictureParameterSet::AP4_PictureParameterSet
+---------------------------------------------------------------------*/
AP4_AvcPictureParameterSet::AP4_AvcPictureParameterSet() :
pic_parameter_set_id(0),
seq_parameter_set_id(0),
entropy_coding_mode_flag(0),
pic_order_present_flag(0),
num_slice_groups_minus1(0),
slice_group_map_type(0),
slice_group_change_direction_flag(0),
slice_group_change_rate_minus1(0),
pic_size_in_map_units_minus1(0),
num_ref_idx_10_active_minus1(0),
num_ref_idx_11_active_minus1(0),
weighted_pred_flag(0),
weighted_bipred_idc(0),
pic_init_qp_minus26(0),
pic_init_qs_minus26(0),
chroma_qp_index_offset(0),
deblocking_filter_control_present_flag(0),
constrained_intra_pred_flag(0),
redundant_pic_cnt_present_flag(0)
{
AP4_SetMemory(run_length_minus1, 0, sizeof(run_length_minus1));
AP4_SetMemory(top_left, 0, sizeof(top_left));
AP4_SetMemory(bottom_right, 0, sizeof(bottom_right));
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::ParsePPS
+---------------------------------------------------------------------*/
AP4_Result
AP4_AvcFrameParser::ParsePPS(const unsigned char* data,
unsigned int data_size,
AP4_AvcPictureParameterSet& pps)
{
pps.raw_bytes.SetData(data, data_size);
AP4_DataBuffer unescaped(data, data_size);
AP4_NalParser::Unescape(unescaped);
AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
bits.SkipBits(8); // NAL Unit Type
pps.pic_parameter_set_id = ReadGolomb(bits);
if (pps.pic_parameter_set_id > AP4_AVC_PPS_MAX_ID) {
return AP4_ERROR_INVALID_FORMAT;
}
pps.seq_parameter_set_id = ReadGolomb(bits);
if (pps.seq_parameter_set_id > AP4_AVC_SPS_MAX_ID) {
return AP4_ERROR_INVALID_FORMAT;
}
pps.entropy_coding_mode_flag = bits.ReadBit();
pps.pic_order_present_flag = bits.ReadBit();
pps.num_slice_groups_minus1 = ReadGolomb(bits);
if (pps.num_slice_groups_minus1 >= AP4_AVC_PPS_MAX_SLICE_GROUPS) {
return AP4_ERROR_INVALID_FORMAT;
}
if (pps.num_slice_groups_minus1 > 0) {
pps.slice_group_map_type = ReadGolomb(bits);
if (pps.slice_group_map_type == 0) {
for (unsigned int i=0; i<=pps.num_slice_groups_minus1; i++) {
pps.run_length_minus1[i] = ReadGolomb(bits);
}
} else if (pps.slice_group_map_type == 2) {
for (unsigned int i=0; i<pps.num_slice_groups_minus1; i++) {
pps.top_left[i] = ReadGolomb(bits);
pps.bottom_right[i] = ReadGolomb(bits);
}
} else if (pps.slice_group_map_type == 3 ||
pps.slice_group_map_type == 4 ||
pps.slice_group_map_type == 5) {
pps.slice_group_change_direction_flag = bits.ReadBit();
pps.slice_group_change_rate_minus1 = ReadGolomb(bits);
} else if (pps.slice_group_map_type == 6) {
pps.pic_size_in_map_units_minus1 = ReadGolomb(bits);
if (pps.pic_size_in_map_units_minus1 >= AP4_AVC_PPS_MAX_PIC_SIZE_IN_MAP_UNITS) {
return AP4_ERROR_INVALID_FORMAT;
}
unsigned int num_bits_per_slice_group_id;
if (pps.num_slice_groups_minus1 + 1 > 4) {
num_bits_per_slice_group_id = 3;
} else if (pps.num_slice_groups_minus1 + 1 > 2) {
num_bits_per_slice_group_id = 2;
} else {
num_bits_per_slice_group_id = 1;
}
for (unsigned int i=0; i<=pps.pic_size_in_map_units_minus1; i++) {
/*pps.slice_group_id[i] =*/ bits.ReadBits(num_bits_per_slice_group_id);
}
}
}
pps.num_ref_idx_10_active_minus1 = ReadGolomb(bits);
pps.num_ref_idx_11_active_minus1 = ReadGolomb(bits);
pps.weighted_pred_flag = bits.ReadBit();
pps.weighted_bipred_idc = bits.ReadBits(2);
pps.pic_init_qp_minus26 = SignedGolomb(ReadGolomb(bits));
pps.pic_init_qs_minus26 = SignedGolomb(ReadGolomb(bits));
pps.chroma_qp_index_offset = SignedGolomb(ReadGolomb(bits));
pps.deblocking_filter_control_present_flag = bits.ReadBit();
pps.constrained_intra_pred_flag = bits.ReadBit();
pps.redundant_pic_cnt_present_flag = bits.ReadBit();
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_AvcSliceHeader::AP4_AvcSliceHeader
+---------------------------------------------------------------------*/
AP4_AvcSliceHeader::AP4_AvcSliceHeader() :
size(0),
first_mb_in_slice(0),
slice_type(0),
pic_parameter_set_id(0),
colour_plane_id(0),
frame_num(0),
field_pic_flag(0),
bottom_field_flag(0),
idr_pic_id(0),
pic_order_cnt_lsb(0),
redundant_pic_cnt(0),
direct_spatial_mv_pred_flag(0),
num_ref_idx_active_override_flag(0),
num_ref_idx_l0_active_minus1(0),
num_ref_idx_l1_active_minus1(0),
ref_pic_list_reordering_flag_l0(0),
reordering_of_pic_nums_idc(0),
abs_diff_pic_num_minus1(0),
long_term_pic_num(0),
ref_pic_list_reordering_flag_l1(0),
luma_log2_weight_denom(0),
chroma_log2_weight_denom(0),
cabac_init_idc(0),
slice_qp_delta(0),
sp_for_switch_flag(0),
slice_qs_delta(0),
disable_deblocking_filter_idc(0),
slice_alpha_c0_offset_div2(0),
slice_beta_offset_div2(0),
slice_group_change_cycle(0),
no_output_of_prior_pics_flag(0),
long_term_reference_flag(0),
difference_of_pic_nums_minus1(0),
long_term_frame_idx(0),
max_long_term_frame_idx_plus1(0)
{
delta_pic_order_cnt[0] = delta_pic_order_cnt[1] = 0;
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::ParseSliceHeader
+---------------------------------------------------------------------*/
AP4_Result
AP4_AvcFrameParser::ParseSliceHeader(const AP4_UI08* data,
unsigned int data_size,
unsigned int nal_unit_type,
unsigned int nal_ref_idc,
AP4_AvcSliceHeader& slice_header)
{
AP4_DataBuffer unescaped(data, data_size);
AP4_NalParser::Unescape(unescaped);
AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());
// init the computer fields
slice_header.size = 0;
slice_header.first_mb_in_slice = ReadGolomb(bits);
slice_header.slice_type = ReadGolomb(bits);
slice_header.pic_parameter_set_id = ReadGolomb(bits);
if (slice_header.pic_parameter_set_id > AP4_AVC_PPS_MAX_ID) {
return AP4_ERROR_INVALID_FORMAT;
}
const AP4_AvcPictureParameterSet* pps = m_PPS[slice_header.pic_parameter_set_id];
if (pps == NULL) {
return AP4_ERROR_INVALID_FORMAT;
}
const AP4_AvcSequenceParameterSet* sps = m_SPS[pps->seq_parameter_set_id];
if (sps == NULL) {
return AP4_ERROR_INVALID_FORMAT;
}
if (sps->separate_colour_plane_flag) {
slice_header.colour_plane_id = bits.ReadBits(2);
}
slice_header.frame_num = bits.ReadBits(sps->log2_max_frame_num_minus4 + 4);
if (!sps->frame_mbs_only_flag) {
slice_header.field_pic_flag = bits.ReadBit();
if (slice_header.field_pic_flag) {
slice_header.bottom_field_flag = bits.ReadBit();
}
}
if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
slice_header.idr_pic_id = ReadGolomb(bits);
}
if (sps->pic_order_cnt_type == 0) {
slice_header.pic_order_cnt_lsb = bits.ReadBits(sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
if (pps->pic_order_present_flag && !slice_header.field_pic_flag) {
slice_header.delta_pic_order_cnt[0] = SignedGolomb(ReadGolomb(bits));
}
}
if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flags) {
slice_header.delta_pic_order_cnt[0] = SignedGolomb(ReadGolomb(bits));
if (pps->pic_order_present_flag && !slice_header.field_pic_flag) {
slice_header.delta_pic_order_cnt[1] = SignedGolomb(ReadGolomb(bits));
}
}
if (pps->redundant_pic_cnt_present_flag) {
slice_header.redundant_pic_cnt = ReadGolomb(bits);
}
unsigned int slice_type = slice_header.slice_type % 5; // this seems to be implicit in the spec
if (slice_type == AP4_AVC_SLICE_TYPE_B) {
slice_header.direct_spatial_mv_pred_flag = bits.ReadBit();
}
if (slice_type == AP4_AVC_SLICE_TYPE_P ||
slice_type == AP4_AVC_SLICE_TYPE_SP ||
slice_type == AP4_AVC_SLICE_TYPE_B) {
slice_header.num_ref_idx_active_override_flag = bits.ReadBit();
if (slice_header.num_ref_idx_active_override_flag) {
slice_header.num_ref_idx_l0_active_minus1 = ReadGolomb(bits);
if ((slice_header.slice_type % 5) == AP4_AVC_SLICE_TYPE_B) {
slice_header.num_ref_idx_l1_active_minus1 = ReadGolomb(bits);
}
} else {
slice_header.num_ref_idx_l0_active_minus1 = pps->num_ref_idx_10_active_minus1;
slice_header.num_ref_idx_l1_active_minus1 = pps->num_ref_idx_11_active_minus1;
}
}
// ref_pic_list_reordering
if ((slice_header.slice_type % 5) != 2 && (slice_header.slice_type % 5) != 4) {
slice_header.ref_pic_list_reordering_flag_l0 = bits.ReadBit();
if (slice_header.ref_pic_list_reordering_flag_l0) {
do {
slice_header.reordering_of_pic_nums_idc = ReadGolomb(bits);
if (slice_header.reordering_of_pic_nums_idc == 0 ||
slice_header.reordering_of_pic_nums_idc == 1) {
slice_header.abs_diff_pic_num_minus1 = ReadGolomb(bits);
} else if (slice_header.reordering_of_pic_nums_idc == 2) {
slice_header.long_term_pic_num = ReadGolomb(bits);
}
} while (slice_header.reordering_of_pic_nums_idc != 3);
}
}
if ((slice_header.slice_type % 5) == 1) {
slice_header.ref_pic_list_reordering_flag_l1 = bits.ReadBit();
if (slice_header.ref_pic_list_reordering_flag_l1) {
do {
slice_header.reordering_of_pic_nums_idc = ReadGolomb(bits);
if (slice_header.reordering_of_pic_nums_idc == 0 ||
slice_header.reordering_of_pic_nums_idc == 1) {
slice_header.abs_diff_pic_num_minus1 = ReadGolomb(bits);
} else if (slice_header.reordering_of_pic_nums_idc == 2) {
slice_header.long_term_pic_num = ReadGolomb(bits);
}
} while (slice_header.reordering_of_pic_nums_idc != 3);
}
}
if ((pps->weighted_pred_flag &&
(slice_type == AP4_AVC_SLICE_TYPE_P || slice_type == AP4_AVC_SLICE_TYPE_SP)) ||
(pps->weighted_bipred_idc == 1 && slice_type == AP4_AVC_SLICE_TYPE_B)) {
// pred_weight_table
slice_header.luma_log2_weight_denom = ReadGolomb(bits);
if (sps->chroma_format_idc != 0) {
slice_header.chroma_log2_weight_denom = ReadGolomb(bits);
}
for (unsigned int i=0; i<=slice_header.num_ref_idx_l0_active_minus1; i++) {
unsigned int luma_weight_l0_flag = bits.ReadBit();
if (luma_weight_l0_flag) {
/* slice_header.luma_weight_l0[i] = SignedGolomb( */ ReadGolomb(bits);
/* slice_header.luma_offset_l0[i] = SignedGolomb( */ ReadGolomb(bits);
}
if (sps->chroma_format_idc != 0) {
unsigned int chroma_weight_l0_flag = bits.ReadBit();
if (chroma_weight_l0_flag) {
for (unsigned int j=0; j<2; j++) {
/* slice_header.chroma_weight_l0[i][j] = SignedGolomb( */ ReadGolomb(bits);
/* slice_header.chroma_offset_l0[i][j] = SignedGolomb( */ ReadGolomb(bits);
}
}
}
}
if ((slice_header.slice_type % 5) == 1) {
for (unsigned int i=0; i<=slice_header.num_ref_idx_l1_active_minus1; i++) {
unsigned int luma_weight_l1_flag = bits.ReadBit();
if (luma_weight_l1_flag) {
/* slice_header.luma_weight_l1[i] = SignedGolomb( */ ReadGolomb(bits);
/* slice_header.luma_offset_l1[i] = SignedGolomb( */ ReadGolomb(bits);
}
if (sps->chroma_format_idc != 0) {
unsigned int chroma_weight_l1_flag = bits.ReadBit();
if (chroma_weight_l1_flag) {
for (unsigned int j=0; j<2; j++) {
/* slice_header.chroma_weight_l1[i][j] = SignedGolomb( */ ReadGolomb(bits);
/* slice_header.chroma_offset_l1[i][j] = SignedGolomb( */ ReadGolomb(bits);
}
}
}
}
}
}
if (nal_ref_idc != 0) {
// dec_ref_pic_marking
if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
slice_header.no_output_of_prior_pics_flag = bits.ReadBit();
slice_header.long_term_reference_flag = bits.ReadBit();
} else {
unsigned int adaptive_ref_pic_marking_mode_flag = bits.ReadBit();
if (adaptive_ref_pic_marking_mode_flag) {
unsigned int memory_management_control_operation = 0;
do {
memory_management_control_operation = ReadGolomb(bits);
if (memory_management_control_operation == 1 || memory_management_control_operation == 3) {
slice_header.difference_of_pic_nums_minus1 = ReadGolomb(bits);
}
if (memory_management_control_operation == 2) {
slice_header.long_term_pic_num = ReadGolomb(bits);
}
if (memory_management_control_operation == 3 || memory_management_control_operation == 6) {
slice_header.long_term_frame_idx = ReadGolomb(bits);
}
if (memory_management_control_operation == 4) {
slice_header.max_long_term_frame_idx_plus1 = ReadGolomb(bits);
}
} while (memory_management_control_operation != 0);
}
}
}
if (pps->entropy_coding_mode_flag && slice_type != AP4_AVC_SLICE_TYPE_I && slice_type != AP4_AVC_SLICE_TYPE_SI) {
slice_header.cabac_init_idc = ReadGolomb(bits);
}
slice_header.slice_qp_delta = ReadGolomb(bits);
if (slice_type == AP4_AVC_SLICE_TYPE_SP || slice_type == AP4_AVC_SLICE_TYPE_SI) {
if (slice_type == AP4_AVC_SLICE_TYPE_SP) {
slice_header.sp_for_switch_flag = bits.ReadBit();
}
slice_header.slice_qs_delta = SignedGolomb(ReadGolomb(bits));
}
if (pps->deblocking_filter_control_present_flag) {
slice_header.disable_deblocking_filter_idc = ReadGolomb(bits);
if (slice_header.disable_deblocking_filter_idc != 1) {
slice_header.slice_alpha_c0_offset_div2 = SignedGolomb(ReadGolomb(bits));
slice_header.slice_beta_offset_div2 = SignedGolomb(ReadGolomb(bits));
}
}
if (pps->num_slice_groups_minus1 > 0 &&
pps->slice_group_map_type >= 3 &&
pps->slice_group_map_type <= 5) {
slice_header.slice_group_change_cycle = ReadGolomb(bits);
}
/* compute the size */
slice_header.size = bits.GetBitsRead();
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::GetSliceSPS
+---------------------------------------------------------------------*/
AP4_AvcSequenceParameterSet*
AP4_AvcFrameParser::GetSliceSPS(AP4_AvcSliceHeader& sh)
{
// lookup the SPS
AP4_AvcPictureParameterSet* pps = m_PPS[sh.pic_parameter_set_id];
if (pps == NULL) return NULL;
return m_SPS[pps->seq_parameter_set_id];
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::SameFrame
| 14496-10 7.4.1.2.4 Detection of the first VCL NAL unit of a primary coded picture
+---------------------------------------------------------------------*/
bool
AP4_AvcFrameParser::SameFrame(unsigned int nal_unit_type_1, unsigned int nal_ref_idc_1, AP4_AvcSliceHeader& sh1,
unsigned int nal_unit_type_2, unsigned int nal_ref_idc_2, AP4_AvcSliceHeader& sh2)
{
if (sh1.frame_num != sh2.frame_num) {
return false;
}
if (sh1.pic_parameter_set_id != sh2.pic_parameter_set_id) {
return false;
}
if (sh1.field_pic_flag != sh2.field_pic_flag) {
return false;
}
if (sh1.field_pic_flag) {
if (sh1.bottom_field_flag != sh2.bottom_field_flag) {
return false;
}
}
if ((nal_ref_idc_1 == 0 || nal_ref_idc_2 == 0) && (nal_ref_idc_1 != nal_ref_idc_2)) {
return false;
}
// lookup the SPS
AP4_AvcSequenceParameterSet* sps = GetSliceSPS(sh1);
if (sps == NULL) return false;
if (sps->pic_order_cnt_type == 0) {
if (sh1.pic_order_cnt_lsb != sh2.pic_order_cnt_lsb ||
sh1.delta_pic_order_cnt[0] != sh2.delta_pic_order_cnt[0]) {
return false;
}
}
if (sps->pic_order_cnt_type == 1) {
if (sh1.delta_pic_order_cnt[0] != sh2.delta_pic_order_cnt[0] ||
sh1.delta_pic_order_cnt[1] != sh2.delta_pic_order_cnt[1]) {
return false;
}
}
if (nal_unit_type_1 == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE ||
nal_unit_type_2 == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
if (nal_unit_type_1 != nal_unit_type_2) {
return false;
}
}
if (nal_unit_type_1 == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE &&
nal_unit_type_2 == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
if (sh1.idr_pic_id != sh2.idr_pic_id) {
return false;
}
}
return true;
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::CheckIfAccessUnitIsCompleted
+---------------------------------------------------------------------*/
void
AP4_AvcFrameParser::CheckIfAccessUnitIsCompleted(AccessUnitInfo& access_unit_info)
{
if (m_SliceHeader == NULL) {
return;
}
if (!m_AccessUnitVclNalUnitCount) {
return;
}
DBG_PRINTF_0(">>>>>>> New Access Unit\n");
m_AccessUnitVclNalUnitCount = 0;
AP4_AvcSequenceParameterSet* sps = GetSliceSPS(*m_SliceHeader);
if (sps == NULL) return;
int max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
// compute the picture type
enum {
AP4_AVC_PIC_TYPE_FRAME,
AP4_AVC_PIC_TYPE_TOP_FIELD,
AP4_AVC_PIC_TYPE_BOTTOM_FIELD
} pic_type;
if (sps->frame_mbs_only_flag || !m_SliceHeader->field_pic_flag) {
pic_type = AP4_AVC_PIC_TYPE_FRAME;
} else if (m_SliceHeader->bottom_field_flag) {
pic_type = AP4_AVC_PIC_TYPE_BOTTOM_FIELD;
} else {
pic_type = AP4_AVC_PIC_TYPE_TOP_FIELD;
}
// prepare to compute the picture order count
int top_field_pic_order_cnt = 0;
int bottom_field_pic_order_cnt = 0;
unsigned int frame_num_offset = 0;
unsigned int frame_num = m_SliceHeader->frame_num;
if (m_NalUnitType == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
m_PrevPicOrderCntMsb = 0;
m_PrevPicOrderCntLsb = 0;
} else {
if (frame_num < m_PrevFrameNum) {
// wrap around
frame_num_offset = m_PrevFrameNumOffset + max_frame_num;
} else {
frame_num_offset = m_PrevFrameNumOffset;
}
}
// compute the picture order count
int pic_order_cnt_msb = 0;
if (sps->pic_order_cnt_type == 0) {
unsigned int max_pic_order_cnt_lsb = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
if (m_SliceHeader->pic_order_cnt_lsb < m_PrevPicOrderCntLsb &&
m_PrevPicOrderCntLsb - m_SliceHeader->pic_order_cnt_lsb >= max_pic_order_cnt_lsb/2) {
pic_order_cnt_msb = m_PrevPicOrderCntMsb + max_pic_order_cnt_lsb;
} else if (m_SliceHeader->pic_order_cnt_lsb > m_PrevPicOrderCntLsb &&
m_SliceHeader->pic_order_cnt_lsb - m_PrevPicOrderCntLsb > max_pic_order_cnt_lsb/2) {
pic_order_cnt_msb = m_PrevPicOrderCntMsb - max_pic_order_cnt_lsb;
} else {
pic_order_cnt_msb = m_PrevPicOrderCntMsb;
}
if (pic_type != AP4_AVC_PIC_TYPE_BOTTOM_FIELD) {
top_field_pic_order_cnt = pic_order_cnt_msb+m_SliceHeader->pic_order_cnt_lsb;
}
if (pic_type != AP4_AVC_PIC_TYPE_TOP_FIELD) {
if (!m_SliceHeader->field_pic_flag) {
bottom_field_pic_order_cnt = top_field_pic_order_cnt + m_SliceHeader->delta_pic_order_cnt[0];
} else {
bottom_field_pic_order_cnt = pic_order_cnt_msb + m_SliceHeader->pic_order_cnt_lsb;
}
}
} else if (sps->pic_order_cnt_type == 1) {
unsigned int abs_frame_num = 0;
if (sps->num_ref_frames_in_pic_order_cnt_cycle) {
abs_frame_num = frame_num_offset + frame_num;
}
if (m_NalRefIdc == 0 && abs_frame_num > 0) {
--abs_frame_num;
}
int expected_pic_order_cnt = 0;
if (abs_frame_num >0) {
unsigned int pic_order_cnt_cycle_cnt = (abs_frame_num-1)/sps->num_ref_frames_in_pic_order_cnt_cycle;
unsigned int frame_num_in_pic_order_cnt_cycle = (abs_frame_num-1)%sps->num_ref_frames_in_pic_order_cnt_cycle;
int expected_delta_per_pic_order_cnt_cycle = 0;
for (unsigned int i=0; i<sps->num_ref_frames_in_pic_order_cnt_cycle; i++) {
expected_delta_per_pic_order_cnt_cycle += sps->offset_for_ref_frame[i];
}
expected_pic_order_cnt = pic_order_cnt_cycle_cnt * expected_delta_per_pic_order_cnt_cycle;
for (unsigned int i=0; i<frame_num_in_pic_order_cnt_cycle; i++) {
expected_pic_order_cnt += sps->offset_for_ref_frame[i];
}
}
if (m_NalRefIdc == 0) {
expected_pic_order_cnt += sps->offset_for_non_ref_pic;
}
if (!m_SliceHeader->field_pic_flag) {
top_field_pic_order_cnt = expected_pic_order_cnt + m_SliceHeader->delta_pic_order_cnt[0];
bottom_field_pic_order_cnt = top_field_pic_order_cnt + sps->offset_for_top_to_bottom_field + m_SliceHeader->delta_pic_order_cnt[1];
} else if (!m_SliceHeader->bottom_field_flag) {
top_field_pic_order_cnt = expected_pic_order_cnt + m_SliceHeader->delta_pic_order_cnt[0];
} else {
bottom_field_pic_order_cnt = expected_pic_order_cnt + sps->offset_for_top_to_bottom_field + m_SliceHeader->delta_pic_order_cnt[0];
}
} else if (sps->pic_order_cnt_type == 2) {
int pic_order_cnt;
if (m_NalUnitType == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE) {
pic_order_cnt = 0;
} else if (m_NalRefIdc == 0) {
pic_order_cnt = 2*(frame_num_offset+frame_num)-1;
} else {
pic_order_cnt = 2*(frame_num_offset+frame_num);
}
if (!m_SliceHeader->field_pic_flag) {
top_field_pic_order_cnt = pic_order_cnt;
bottom_field_pic_order_cnt = pic_order_cnt;
} else if (m_SliceHeader->bottom_field_flag) {
bottom_field_pic_order_cnt = pic_order_cnt;
} else {
top_field_pic_order_cnt = pic_order_cnt;
}
}
unsigned int pic_order_cnt;
if (pic_type == AP4_AVC_PIC_TYPE_FRAME) {
pic_order_cnt = top_field_pic_order_cnt < bottom_field_pic_order_cnt ? top_field_pic_order_cnt : bottom_field_pic_order_cnt;
} else if (pic_type == AP4_AVC_PIC_TYPE_TOP_FIELD) {
pic_order_cnt = top_field_pic_order_cnt;
} else {
pic_order_cnt = bottom_field_pic_order_cnt;
}
// emit the access unit (transfer ownership)
access_unit_info.nal_units = m_AccessUnitData;
access_unit_info.is_idr = (m_NalUnitType == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE);
access_unit_info.decode_order = m_TotalAccessUnitCount;
access_unit_info.display_order = pic_order_cnt;
m_AccessUnitData.Clear();
++m_TotalAccessUnitCount;
// update state
m_PrevFrameNum = frame_num;
m_PrevFrameNumOffset = frame_num_offset;
if (m_NalRefIdc) {
m_PrevPicOrderCntMsb = pic_order_cnt_msb;
m_PrevPicOrderCntLsb = m_SliceHeader->pic_order_cnt_lsb;
}
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::AppendNalUnitData
+---------------------------------------------------------------------*/
void
AP4_AvcFrameParser::AppendNalUnitData(const unsigned char* data, unsigned int data_size)
{
m_AccessUnitData.Append(new AP4_DataBuffer(data, data_size));
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::Feed
+---------------------------------------------------------------------*/
AP4_Result
AP4_AvcFrameParser::Feed(const void* data,
AP4_Size data_size,
AP4_Size& bytes_consumed,
AccessUnitInfo& access_unit_info,
bool eos)
{
const AP4_DataBuffer* nal_unit = NULL;
// feed the NAL unit parser
AP4_Result result = m_NalParser.Feed(data, data_size, bytes_consumed, nal_unit, eos);
if (AP4_FAILED(result)) {
return result;
}
if (bytes_consumed < data_size) {
// there will be more to parse
eos = false;
}
return Feed(nal_unit ? nal_unit->GetData() : NULL,
nal_unit ? nal_unit->GetDataSize() : 0,
access_unit_info,
eos);
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::Feed
+---------------------------------------------------------------------*/
AP4_Result
AP4_AvcFrameParser::Feed(const AP4_UI08* nal_unit,
AP4_Size nal_unit_size,
AccessUnitInfo& access_unit_info,
bool last_unit)
{
AP4_Result result;
// default return values
access_unit_info.Reset();
if (nal_unit && nal_unit_size) {
unsigned int nal_unit_type = nal_unit[0]&0x1F;
const char* nal_unit_type_name = AP4_AvcNalParser::NaluTypeName(nal_unit_type);
unsigned int nal_ref_idc = (nal_unit[0]>>5)&3;
if (nal_unit_type_name == NULL) nal_unit_type_name = "UNKNOWN";
DBG_PRINTF_5("NALU %5d: ref=%d, size=%5d, type=%02d (%s) ",
m_TotalNalUnitCount,
nal_ref_idc,
nal_unit_size,
nal_unit_type,
nal_unit_type_name);
if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_ACCESS_UNIT_DELIMITER) {
unsigned int primary_pic_type = (nal_unit[1]>>5);
const char* primary_pic_type_name = AP4_AvcNalParser::PrimaryPicTypeName(primary_pic_type);
if (primary_pic_type_name == NULL) primary_pic_type_name = "UNKNOWN";
DBG_PRINTF_2("[%d:%s]\n", primary_pic_type, primary_pic_type_name);
CheckIfAccessUnitIsCompleted(access_unit_info);
} else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_NON_IDR_PICTURE ||
nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE ||
nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A) {
AP4_AvcSliceHeader* slice_header = new AP4_AvcSliceHeader;
result = ParseSliceHeader(nal_unit+1,
nal_unit_size-1,
nal_unit_type,
nal_ref_idc,
*slice_header);
if (AP4_FAILED(result)) {
return AP4_ERROR_INVALID_FORMAT;
}
const char* slice_type_name = AP4_AvcNalParser::SliceTypeName(slice_header->slice_type);
if (slice_type_name == NULL) slice_type_name = "?";
DBG_PRINTF_5(" pps_id=%d, header_size=%d, frame_num=%d, slice_type=%d (%s), ",
slice_header->pic_parameter_set_id,
slice_header->size,
slice_header->frame_num,
slice_header->slice_type,
slice_type_name);
DBG_PRINTF_0("\n");
if (slice_header) {
if (m_SliceHeader &&
!SameFrame(m_NalUnitType, m_NalRefIdc, *m_SliceHeader,
nal_unit_type, nal_ref_idc, *slice_header)) {
CheckIfAccessUnitIsCompleted(access_unit_info);
m_AccessUnitVclNalUnitCount = 1;
} else {
// continuation of an access unit
++m_AccessUnitVclNalUnitCount;
}
}
// buffer this NAL unit
AppendNalUnitData(nal_unit, nal_unit_size);
delete m_SliceHeader;
m_SliceHeader = slice_header;
m_NalUnitType = nal_unit_type;
m_NalRefIdc = nal_ref_idc;
} else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_PPS) {
AP4_AvcPictureParameterSet* pps = new AP4_AvcPictureParameterSet;
result = ParsePPS(nal_unit, nal_unit_size, *pps);
if (AP4_FAILED(result)) {
DBG_PRINTF_0("PPS ERROR!!!\n");
delete pps;
} else {
delete m_PPS[pps->pic_parameter_set_id];
m_PPS[pps->pic_parameter_set_id] = pps;
DBG_PRINTF_2("PPS sps_id=%d, pps_id=%d\n", pps->seq_parameter_set_id, pps->pic_parameter_set_id);
// keep the PPS with the NAL unit (this is optional)
AppendNalUnitData(nal_unit, nal_unit_size);
CheckIfAccessUnitIsCompleted(access_unit_info);
}
} else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_SPS) {
AP4_AvcSequenceParameterSet* sps = new AP4_AvcSequenceParameterSet;
result = ParseSPS(nal_unit, nal_unit_size, *sps);
if (AP4_FAILED(result)) {
DBG_PRINTF_0("SPS ERROR!!!\n");
delete sps;
} else {
delete m_SPS[sps->seq_parameter_set_id];
m_SPS[sps->seq_parameter_set_id] = sps;
DBG_PRINTF_1("SPS sps_id=%d\n", sps->seq_parameter_set_id);
CheckIfAccessUnitIsCompleted(access_unit_info);
}
} else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_SEI) {
AppendNalUnitData(nal_unit, nal_unit_size);
CheckIfAccessUnitIsCompleted(access_unit_info);
DBG_PRINTF_0("\n");
} else if (nal_unit_type >= 14 && nal_unit_type <= 18) {
CheckIfAccessUnitIsCompleted(access_unit_info);
DBG_PRINTF_0("\n");
} else {
DBG_PRINTF_0("\n");
}
m_TotalNalUnitCount++;
}
// flush if needed
if (last_unit && access_unit_info.nal_units.ItemCount() == 0) {
DBG_PRINTF_0("------ last unit\n");
CheckIfAccessUnitIsCompleted(access_unit_info);
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_AvcFrameParser::AccessUnitInfo::Reset
+---------------------------------------------------------------------*/
void
AP4_AvcFrameParser::AccessUnitInfo::Reset()
{
for (unsigned int i=0; i<nal_units.ItemCount(); i++) {
delete nal_units[i];
}
nal_units.Clear();
is_idr = false;
decode_order = 0;
display_order = 0;
}