diff options
author | sahara <keun-o.park@windriver.com> | 2010-01-22 17:50:43 +0900 |
---|---|---|
committer | Patrick Tjin <pattjin@google.com> | 2014-07-21 22:03:35 -0700 |
commit | 983ae58ba31d37e90bca2933ed67331021f7c775 (patch) | |
tree | b67feee10f73d8d87dffbe5331015752d4cc1482 /utils | |
parent | e7660662764bf407dcd3c569bc52b170c5753391 (diff) | |
download | wrs_omxil_core-983ae58ba31d37e90bca2933ed67331021f7c775.tar.gz |
add h.264 sps nal parser for libmix api
Signed-off-by: sahara <keun-o.park@windriver.com>
Diffstat (limited to 'utils')
-rw-r--r-- | utils/inc/h264_parser.h | 181 | ||||
-rw-r--r-- | utils/src/Android.mk | 3 | ||||
-rw-r--r-- | utils/src/h264_parser.c | 604 |
3 files changed, 787 insertions, 1 deletions
diff --git a/utils/inc/h264_parser.h b/utils/inc/h264_parser.h new file mode 100644 index 0000000..5f45d46 --- /dev/null +++ b/utils/inc/h264_parser.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * + * The right to copy, distribute, modify, or otherwise make use + * of this software may be licensed only pursuant to the terms + * of an applicable Wind River license agreement. + */ + +#ifndef __WRS_OMXIL_H264_PARSER +#define ___WRS_OMXIL_H264_PARSER + +#ifdef __cplusplus +extern "C" { +#endif + +#define USE_PV_BITOPS 1 +#define USE_MIXVBP_DEF 1 + +#if USE_PV_BITOPS +/* Port from PV OpenCORE 2.02 */ +typedef struct _nal_stream_t { + unsigned char *data; + unsigned int numbytes; + unsigned int bytepos; + unsigned int bitbuf; + unsigned int databitpos; + unsigned int bitpos; +} nal_stream; +#endif + +#if USE_MIXVBP_DEF +/* Import from MI-X VBP header */ +#define MAX_NUM_SPS 32 +/* status codes */ +typedef enum _h264_Status +{ + H264_STATUS_EOF = 1, // end of file + H264_STATUS_OK = 0, // no error + H264_STATUS_NO_MEM = 2, // out of memory + H264_STATUS_FILE_ERROR = 3, // file error + H264_STATUS_NOTSUPPORT = 4, // not supported mode + H264_STATUS_PARSE_ERROR = 5, // fail in parse MPEG-4 stream + H264_STATUS_ERROR = 6, // unknown/unspecified error + H264_NAL_ERROR, + H264_SPS_INVALID_PROFILE, + H264_SPS_INVALID_LEVEL, + H264_SPS_INVALID_SEQ_PARAM_ID, + H264_SPS_ERROR, + H264_PPS_INVALID_PIC_ID, + H264_PPS_INVALID_SEQ_ID, + H264_PPS_ERROR, + H264_SliceHeader_INVALID_MB, + H264_SliceHeader_ERROR, + H264_FRAME_DONE, + H264_SLICE_DONE, + H264_STATUS_POLL_ONCE_ERROR, + H264_STATUS_DEC_MEMINIT_ERROR, + H264_STATUS_NAL_UNIT_TYPE_ERROR, + H264_STATUS_SEI_ERROR, + H264_STATUS_SEI_DONE, +} h264_Status; + +typedef enum _h264_Profile +{ + h264_ProfileBaseline = 66, /** Baseline profile */ + h264_ProfileMain = 77, /** Main profile */ + h264_ProfileExtended = 88, /** Extended profile */ + h264_ProfileHigh = 100 , /** High profile */ + h264_ProfileHigh10 = 110, /** High 10 profile */ + h264_ProfileHigh422 = 122, /** High profile 4:2:2 */ + h264_ProfileHigh444 = 144, /** High profile 4:4:4 */ +} h264_Profile; + +typedef enum _h264_Level +{ + h264_Level1b = 9, /** Level 1b */ + h264_Level1 = 10, /** Level 1 */ + h264_Level11 = 11, /** Level 1.1 */ + h264_Level12 = 12, /** Level 1.2 */ + h264_Level13 = 13, /** Level 1.3 */ + h264_Level2 = 20, /** Level 2 */ + h264_Level21 = 21, /** Level 2.1 */ + h264_Level22 = 22, /** Level 2.2 */ + h264_Level3 = 30, /** Level 3 */ + h264_Level31 = 31, /** Level 3.1 */ + h264_Level32 = 32, /** Level 3.2 */ + h264_Level4 = 40, /** Level 4 */ + h264_Level41 = 41, /** Level 4.1 */ + h264_Level42 = 42, /** Level 4.2 */ + h264_Level5 = 50, /** Level 5 */ + h264_Level51 = 51, /** Level 5.1 */ + h264_LevelReserved = 255 /** Unknown profile */ +} h264_Level; + +#endif + +/* + * VUI + */ + +#define Extended_SAR 255 + +typedef struct _VUI_t { + unsigned char aspect_ratio_info_present_flag; + unsigned char aspect_ratio_idc; + unsigned short sar_width; + unsigned short sar_height; + unsigned char overscan_info_present_flag; + unsigned char overscan_appropriate_flag; + unsigned char video_signal_type_present_flag; + unsigned char video_format; + unsigned char video_full_range_flag; + unsigned char colour_description_present_flag; + unsigned char colour_primaries; + unsigned char transfer_characteristics; + unsigned char matrix_coefficients; + unsigned char chroma_loc_info_present_flag; + unsigned int chroma_sample_loc_type_top_field; + unsigned int chroma_sample_loc_type_bottom_field; + unsigned int timing_info_present_flag; + unsigned int num_units_in_tick; + unsigned int time_scale; + unsigned int fixed_frame_rate_flag; + /* TBD */ +} VUI; + +int nal_sps_vui_parse(const unsigned char *buffer, int *framerate); + +/* + * SPS + */ + +typedef struct _SPS_t { + unsigned char profile_idc; + unsigned char constraint_flags; + unsigned short level_idc; + unsigned int seq_parameter_set_id; + unsigned int chroma_format_idc; + unsigned int separate_colour_plane_flag; + unsigned int bit_depth_luma_minus8; + unsigned int bit_depth_chroma_minus8; + unsigned short qpprime_y_zero_transform_bypass_flag; + unsigned short seq_scaling_matrix_present_flag; + unsigned char *seq_scaling_list_present_flag; + unsigned char scaling_list_4x4[6][16]; + unsigned char scaling_list_8x8[2][64]; + unsigned char use_default_scaling_matrix_4x4_flag[6]; + unsigned char use_default_scaling_matrix_8x8_flag[6]; + unsigned int log2_max_frame_num_minus4; + unsigned int pic_order_cnt_type; + unsigned int log2_max_pic_order_cnt_lsb_minus4; + unsigned int delta_pic_order_always_zero_flag; + int offset_for_non_ref_pic; + int offset_for_top_to_bottom_field; + unsigned int num_ref_frames_in_pic_order_cnt_cycle; + int *offset_for_ref_frame; + unsigned int max_num_ref_frames; + unsigned int gaps_in_frame_num_value_allowed_flag; + unsigned int pic_width_in_mbs_minus1; + unsigned int pic_height_in_map_units_minus1; + unsigned char frame_mbs_only_flag; + unsigned char mb_adaptive_frame_field_flag; + unsigned char direct_8x8_inference_flag; + unsigned char frame_cropping_flag; + unsigned int frame_crop_left_offset; + unsigned int frame_crop_right_offset; + unsigned int frame_crop_top_offset; + unsigned int frame_crop_bottom_offset; + unsigned int vui_parameters_present_flag; + VUI *vui; +} SPS; + +int nal_sps_parse(unsigned char *buffer, unsigned int len, + unsigned int *width, unsigned int *height, + unsigned int *framerate); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ___WRS_OMXIL_H264_PARSER */ diff --git a/utils/src/Android.mk b/utils/src/Android.mk index 1f3fec2..799c2c6 100644 --- a/utils/src/Android.mk +++ b/utils/src/Android.mk @@ -15,7 +15,8 @@ LOCAL_SRC_FILES := \ module.c \ thread.cpp \ workqueue.cpp \ - audio_parser.c + audio_parser.c \ + h264_parser.c LOCAL_MODULE := libwrs_omxil_utils diff --git a/utils/src/h264_parser.c b/utils/src/h264_parser.c new file mode 100644 index 0000000..e90da4a --- /dev/null +++ b/utils/src/h264_parser.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * + * The right to copy, distribute, modify, or otherwise make use + * of this software may be licensed only pursuant to the terms + * of an applicable Wind River license agreement. + */ + +#include <h264_parser.h> + +//#define LOG_NDEBUG 0 + +#define LOG_TAG "h264_parser" +#include <log.h> + +#if USE_PV_BITOPS +/* + * NOTE: The original idea of this code for bit operation is from PV's OpenCORE 2.02 + * Wind River Systems modified PV source for se(v) operation. + * + */ + +#define PV_CLZ(A,B) while (((B) & 0x8000) == 0) {(B) <<=1; A++;} + +static const unsigned int mask[33] = +{ + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, + 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, + 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; + +static int read_bits(nal_stream *pstream, unsigned char nbits, unsigned int *outdata) +{ + unsigned char *bits; + unsigned int databitpos = pstream->databitpos; + unsigned int bitpos = pstream->bitpos; + unsigned int databytepos; + + if ((databitpos + nbits) > (pstream->numbytes << 3)) + { + *outdata = 0; + // buffer over run + LOGE("%s: buffer over run",__func__); + return -1; + } + + // databitpos += nbits; + + if (nbits > (32 - bitpos)) /* not enough bits */ + { + databytepos = databitpos >> 3; /* byte aligned position */ + bitpos = databitpos & 7; /* update bit position */ + bits = &pstream->data[databytepos]; + pstream->bitbuf = (bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | bits[3]; + } + + pstream->databitpos += nbits; + pstream->bitpos = (unsigned char)(bitpos + nbits); + + *outdata = (pstream->bitbuf >> (32 - pstream->bitpos)) & mask[(unsigned short)nbits]; + return 0; +} + +static void show_bits(nal_stream *pstream, unsigned char nbits, unsigned int *outdata) +{ + unsigned char *bits; + unsigned int databitpos = pstream->databitpos; + unsigned int bitpos = pstream->bitpos; + unsigned int databytepos; + + uint i; + + if (nbits > (32 - bitpos)) /* not enough bits */ + { + databytepos = databitpos >> 3; /* byte aligned position */ + bitpos = databitpos & 7; /* update bit position */ + if (databytepos > pstream->numbytes - 4) + { + pstream->bitbuf = 0; + for (i = 0; i < pstream->numbytes - databytepos; i++) + { + pstream->bitbuf |= pstream->data[databytepos+i]; + pstream->bitbuf <<= 8; + } + pstream->bitbuf <<= 8 * (3 - i); + } + else + { + bits = &pstream->data[databytepos]; + pstream->bitbuf = (bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | bits[3]; + } + pstream->bitpos = bitpos; + } + + bitpos += nbits; + + *outdata = (pstream->bitbuf >> (32 - bitpos)) & mask[(unsigned short)nbits]; +} + +static void flush_bits(nal_stream *pstream, unsigned char nbits) +{ + unsigned char *bits; + unsigned int databitpos = pstream->databitpos; + unsigned int bitpos = pstream->bitpos; + unsigned int databytepos; + + if ((databitpos + nbits) > (unsigned int)(pstream->numbytes << 3)) { + // buffer over run + LOGE("%s: buffer over run",__func__); + } + + databitpos += nbits; + bitpos += nbits; + + if (bitpos > 32) + { + databytepos = databitpos >> 3; /* byte aligned position */ + bitpos = databitpos & 7; /* update bit position */ + bits = &pstream->data[databytepos]; + pstream->bitbuf = (bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | bits[3]; + } + + pstream->databitpos = databitpos; + pstream->bitpos = bitpos; +} + +static void read_ue_bits(nal_stream *pstream, unsigned int *coded_val) +{ + unsigned int temp; + unsigned int tmp_cnt; + int leading_zeros = 0; + + show_bits(pstream, 16, &temp); + tmp_cnt = temp | 0x1; + + PV_CLZ(leading_zeros, tmp_cnt) + + if (leading_zeros < 8) + { + *coded_val = (temp >> (15 - (leading_zeros << 1))) - 1; + flush_bits(pstream, (leading_zeros << 1) + 1); + } + else + { + read_bits(pstream, (leading_zeros << 1) + 1, &temp); + *coded_val = temp - 1; + } +} + +static void read_se_bits(nal_stream *pstream, int *coded_val) +{ + int leading_zeros = 0; + unsigned int temp; + + read_bits(pstream, 1, &temp); + while (!temp) + { + leading_zeros++; + if (read_bits(pstream, 1, &temp)) + { + break; + } + } + read_bits(pstream, leading_zeros, &temp); +} +#endif /* USE_PV_BITOPS */ + +#if USE_MIXVBP_DEF +static h264_Status h264_scaling_list(nal_stream *pstream, + unsigned char *scaling_list, + int sizeof_scaling_list, + unsigned char *use_default_scaling_matrix) +{ + int j, scanj; + int delta_scale, last_scale, next_scale; + + last_scale = 8; + next_scale = 8; + scanj = 0; + + for(j=0; j<sizeof_scaling_list; j++) { + if(next_scale!=0) { + read_se_bits(pstream, &delta_scale); + next_scale = (last_scale + delta_scale + 256) % 256; + *use_default_scaling_matrix = (unsigned char) (scanj==0 && next_scale==0); + } + + scaling_list[scanj] = (next_scale==0) ? last_scale:next_scale; + last_scale = scaling_list[scanj]; + scanj ++; + } + + return H264_STATUS_OK; +} +#endif + +static int _sps_parse(nal_stream *pstream, SPS *sps) +{ + h264_Status status = H264_SPS_ERROR; + unsigned int val; + int sval; + + read_bits(pstream, 8, &val); + sps->profile_idc = (unsigned char)val; + LOGV("%s: sps->profile_idc = %d", __func__, val); + + switch(sps->profile_idc) { + case h264_ProfileBaseline: + case h264_ProfileMain: + case h264_ProfileExtended: + case h264_ProfileHigh10: + case h264_ProfileHigh422: + case h264_ProfileHigh444: + case h264_ProfileHigh: + break; + default: + return H264_SPS_INVALID_PROFILE; + } + + read_bits(pstream, 8, &val); + sps->constraint_flags = (unsigned char)val; + LOGV("%s: sps->constraint_flags = %d", __func__, val); + + read_bits(pstream, 8, &val); + sps->level_idc = (unsigned short)val; + LOGV("%s: sps->level_idc = %d", __func__, val); + + switch(sps->level_idc) + { + case h264_Level1b: + case h264_Level1: + case h264_Level11: + case h264_Level12: + case h264_Level13: + case h264_Level2: + case h264_Level21: + case h264_Level22: + case h264_Level3: + case h264_Level31: + case h264_Level32: + case h264_Level4: + case h264_Level41: + case h264_Level42: + case h264_Level5: + case h264_Level51: + break; + default: + return H264_SPS_INVALID_LEVEL; + } + + do { + read_ue_bits(pstream, &val); + sps->seq_parameter_set_id = val; + LOGV("%s: sps->seq_parameter_set_id = %d", __func__, val); + if (val > MAX_NUM_SPS - 1) break; + + if((sps->profile_idc == h264_ProfileHigh) || + (sps->profile_idc == h264_ProfileHigh10) || + (sps->profile_idc == h264_ProfileHigh422) || + (sps->profile_idc == h264_ProfileHigh444)) + { + + read_ue_bits(pstream, &val); + sps->chroma_format_idc = val; + LOGV("%s: sps->chroma_format_idc = %d", __func__, val); + + if (val == 3) { + read_bits(pstream, 1, &val); + sps->separate_colour_plane_flag = val; + LOGV("%s: sps->separate_colour_plane_flag = %d", __func__, val); + } + + read_ue_bits(pstream, &val); + sps->bit_depth_luma_minus8 = val; + LOGV("%s: sps->bit_depth_luma_minus8 = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->bit_depth_chroma_minus8 = val; + LOGV("%s: sps->bit_depth_chroma_minus8 = %d", __func__, val); + + read_bits(pstream, 1, &val); + sps->qpprime_y_zero_transform_bypass_flag = (unsigned short)val; + LOGV("%s: sps->qpprime_y_zero_transform_bypass_flag = %d", __func__, val); + + read_bits(pstream, 1, &val); + sps->seq_scaling_matrix_present_flag = (unsigned short)val; + LOGV("%s: sps->seq_scaling_matrix_present_flag = %d", __func__, val); + + if (val) { + unsigned int i; + unsigned int _count_i = (sps->chroma_format_idc != 3)?8:12; + sps->seq_scaling_list_present_flag = malloc(sizeof(unsigned char)*_count_i); + for(i=0; i<_count_i; i++) { + read_bits(pstream, 1, &val); + sps->seq_scaling_list_present_flag[i] = (unsigned char)val; + if (val) { + if (i<6) { + h264_scaling_list(pstream, + sps->scaling_list_4x4[i], 16, + &sps->use_default_scaling_matrix_4x4_flag[i]); + } else { + h264_scaling_list(pstream, + sps->scaling_list_8x8[i-6], 64, + &sps->use_default_scaling_matrix_8x8_flag[i-6]); + } + } + } + } + } else { + sps->chroma_format_idc = 1; + sps->seq_scaling_matrix_present_flag = 0; + + sps->bit_depth_luma_minus8 = 0; + sps->bit_depth_chroma_minus8 = 0; + } + + read_ue_bits(pstream, &val); + sps->log2_max_frame_num_minus4 = val; + LOGV("%s: sps->log2_max_frame_num_minus4 = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->pic_order_cnt_type = val; + LOGV("%s: sps->pic_order_cnt_type = %d", __func__, val); + + if (val == 0) { + read_ue_bits(pstream, &val); + sps->log2_max_pic_order_cnt_lsb_minus4 = val; + LOGV("%s: sps->log2_max_pic_order_cnt_lsb_minus4 = %d", __func__, val); + } else if (val == 1) { + unsigned int i; + + read_bits(pstream, 1, &val); + sps->delta_pic_order_always_zero_flag = val; + LOGV("%s: sps->delta_pic_order_always_zero_flag = %d", __func__, val); + + read_se_bits(pstream, &sval); + sps->offset_for_non_ref_pic = sval; + LOGV("%s: sps->offset_for_non_ref_pic = %d", __func__, val); + + read_se_bits(pstream, &sval); + sps->offset_for_top_to_bottom_field = sval; + LOGV("%s: sps->offset_for_top_to_bottom_field = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->num_ref_frames_in_pic_order_cnt_cycle = val; + LOGV("%s: sps->num_ref_frames_in_pic_order_cnt_cycle = %d", __func__, val); + + sps->offset_for_ref_frame = malloc(sizeof(int)*val); + for (i=0; i<sps->num_ref_frames_in_pic_order_cnt_cycle; i++) { + read_se_bits(pstream, &sval); + sps->offset_for_ref_frame[i] = sval; + } + + } + + read_ue_bits(pstream, &val); + sps->max_num_ref_frames = val; + LOGV("%s: sps->max_num_ref_frames = %d", __func__, val); + + read_bits(pstream, 1, &val); + sps->gaps_in_frame_num_value_allowed_flag = val; + LOGV("%s: sps->gaps_in_frame_num_value_allowed_flag = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->pic_width_in_mbs_minus1 = val; + LOGV("%s: sps->pic_width_in_mbs_minus1 = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->pic_height_in_map_units_minus1 = val; + LOGV("%s: sps->pic_height_in_map_units_minus1 = %d", __func__, val); + + read_bits(pstream, 1, &val); + sps->frame_mbs_only_flag = (unsigned char)val; + LOGV("%s: sps->frame_mbs_only_flag = %d", __func__, val); + + if (!val) { + read_bits(pstream, 1, &val); + sps->mb_adaptive_frame_field_flag = (unsigned char)val; + LOGV("%s: sps->mb_adaptive_frame_field_flag = %d", __func__, val); + } + + read_bits(pstream, 1, &val); + sps->direct_8x8_inference_flag = (unsigned char)val; + LOGV("%s: sps->direct_8x8_inference_flag = %d", __func__, val); + + read_bits(pstream, 1, &val); + sps->frame_cropping_flag = (unsigned char)val; + LOGV("%s: sps->frame_cropping_flag = %d", __func__, val); + + if (val) { + read_ue_bits(pstream, &val); + sps->frame_crop_left_offset = val; + LOGV("%s: sps->frame_crop_left_offset = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->frame_crop_right_offset = val; + LOGV("%s: sps->frame_crop_right_offset = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->frame_crop_top_offset = val; + LOGV("%s: sps->frame_crop_top_offset = %d", __func__, val); + + read_ue_bits(pstream, &val); + sps->frame_crop_bottom_offset = val; + LOGV("%s: sps->frame_crop_bottom_offset = %d", __func__, val); + } + + read_bits(pstream, 1, &val); + sps->vui_parameters_present_flag = val; + LOGV("%s: sps->vui_parameters_present_flag = %d", __func__, val); + + status = H264_STATUS_OK; + } while(0); + + return status; +} + +static int _vui_parse(nal_stream *pstream, SPS *sps) +{ + unsigned int val; + int sval; + h264_Status status = H264_SPS_ERROR; + VUI* vui = sps->vui; + + if (!vui) { + LOGE("%s: Invalid VUI", __func__); + return status; + } + + read_bits(pstream, 1, &val); + vui->aspect_ratio_info_present_flag = (unsigned char)val; + LOGV("%s: vui->aspect_ratio_info_present_flag = %d", __func__, val); + + if (val) { + read_bits(pstream, 8, &val); + vui->aspect_ratio_idc = (unsigned char)val; + LOGV("%s: vui->aspect_ratio_idc = %d", __func__, val); + + if (val == Extended_SAR) { + read_bits(pstream, 16, &val); + vui->sar_width = (unsigned short)val; + LOGV("%s: vui->sar_width = %d", __func__, val); + + read_bits(pstream, 16, &val); + vui->sar_height = (unsigned short)val; + LOGV("%s: vui->sar_height = %d", __func__, val); + } + } + + read_bits(pstream, 1, &val); + vui->overscan_info_present_flag = (unsigned char)val; + LOGV("%s: vui->overscan_info_present_flag = %d", __func__, val); + + if (val) { + read_bits(pstream, 1, &val); + vui->overscan_appropriate_flag = (unsigned char)val; + LOGV("%s: vui->overscan_appropriate_flag = %d", __func__, val); + } + + read_bits(pstream, 1, &val); + vui->video_signal_type_present_flag = (unsigned char)val; + LOGV("%s: vui->video_signal_type_present_flag = %d", __func__, val); + + if (val) { + read_bits(pstream, 3, &val); + vui->video_format = (unsigned char)val; + LOGV("%s: vui->video_format = %d", __func__, val); + + read_bits(pstream, 1, &val); + vui->video_full_range_flag = (unsigned char)val; + LOGV("%s: vui->video_full_range_flag = %d", __func__, val); + + read_bits(pstream, 1, &val); + vui->colour_description_present_flag = (unsigned char)val; + LOGV("%s: vui->colour_description_present_flag = %d", __func__, val); + + if (val) { + read_bits(pstream, 8, &val); + vui->colour_primaries = (unsigned char)val; + LOGV("%s: vui->colour_primaries = %d", __func__, val); + + read_bits(pstream, 8, &val); + vui->transfer_characteristics = (unsigned char)val; + LOGV("%s: vui->transfer_characteristics = %d", __func__, val); + + read_bits(pstream, 8, &val); + vui->matrix_coefficients = (unsigned char)val; + LOGV("%s: vui->matrix_coefficients = %d", __func__, val); + } + } + + read_bits(pstream, 1, &val); + vui->chroma_loc_info_present_flag = (unsigned char)val; + LOGV("%s: vui->chroma_loc_info_present_flag = %d", __func__, val); + + if (val) { + read_ue_bits(pstream, &val); + vui->chroma_sample_loc_type_top_field = val; + LOGV("%s: vui->chroma_sample_loc_type_top_field = %d", __func__, val); + + read_ue_bits(pstream, &val); + vui->chroma_sample_loc_type_bottom_field = val; + LOGV("%s: vui->chroma_sample_loc_type_bottom_field = %d", __func__, val); + } + + read_bits(pstream, 1, &val); + vui->timing_info_present_flag = val; + LOGV("%s: vui->timing_info_present_flag = %d", __func__, vui->timing_info_present_flag); + + if (val) { + read_bits(pstream, 32, &val); + vui->num_units_in_tick = val; + LOGV("%s: vui->num_units_in_tick = %d", __func__, vui->num_units_in_tick); + + read_bits(pstream, 32, &val); + vui->time_scale = val; + LOGV("%s: vui->time_scale = %d", __func__, vui->time_scale); + + read_bits(pstream, 1, &val); + vui->fixed_frame_rate_flag = val; + LOGV("%s: vui->fixed_frame_rate_flag = %d", __func__, vui->fixed_frame_rate_flag); + } + + /* TBD */ + + return H264_STATUS_OK; +} + +int nal_sps_parse(unsigned char *buffer, unsigned int len, + unsigned int *width, unsigned int *height, + unsigned int *framerate) +{ + SPS sps; + VUI vui; + nal_stream nalst; + unsigned int val; + int status = H264_SPS_ERROR; + + nalst.data = buffer; + nalst.numbytes = len; + nalst.bitbuf = 0; + nalst.bitpos = 32; + nalst.bytepos = 0; + nalst.databitpos = 0; + + memset(&sps, 0, sizeof(sps)); + memset(&vui, 0, sizeof(vui)); + sps.vui = &vui; + + read_bits(&nalst, 8, &val); + if ((val & 0x1F) != 7) { + LOGE("%s: NAL type is not SPS. ERROR", __func__); + goto init_error; + } + + /* parse SPS */ + status = _sps_parse(&nalst, &sps); + if (status) goto sps_error; + + if (sps.vui_parameters_present_flag) { + /* parse VUI */ + status = _vui_parse(&nalst, &sps); + if (status) goto vui_error; + } else { + LOGE("%s: VUI parameters present flag is OFF from SPS", __func__); + goto vui_error; + } + + /* calculate width, height, framerate */ + *width = (sps.pic_width_in_mbs_minus1 + 1) * 16; + *height = (sps.pic_height_in_map_units_minus1 + 1) * 16; + LOGV("%s: frame width = %d", __func__, *width); + LOGV("%s: frame height = %d", __func__, *height); + + /* FIXME: Generally framerate is in container header */ + if (vui.fixed_frame_rate_flag) { + *framerate = 30; + LOGV("%s: frame rate = %d", __func__, *framerate); + } else { + *framerate = 30; + //*framerate = 0; + LOGV("%s: fixed_frame_rate_flag = 0 framerate=%d", __func__, *framerate); + } + return H264_STATUS_OK; + + sps_error: + *width = 0; + *height = 0; + vui_error: + *framerate = 0; + if (sps.seq_scaling_list_present_flag) + free(sps.seq_scaling_list_present_flag); + if (sps.offset_for_ref_frame) + free(sps.offset_for_ref_frame); + init_error: + return status; +} + |