/* * * Copyright 2015 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MODULE_TAG "h264d_sei" #include #include #include "h264d_global.h" #include "h264d_sps.h" #include "h264d_sei.h" static MPP_RET interpret_picture_timing_info( BitReadCtx_t *p_bitctx, H264_SEI_t *sei_msg, H264dVideoCtx_t *p_videoctx) { RK_S32 cpb_removal_delay_length = 0; RK_S32 dpb_output_delay_length = 0; RK_S32 time_offset_length = 0; RK_S32 cpb_dpb_delays_present_flag = 0; RK_U32 i = 0; H264_SEI_PIC_TIMING_t *pic_timing = NULL; RK_U32 num_clock_ts[9] = {1, 1, 1, 2, 2, 3, 3, 2, 3}; struct h264_vui_t *vui_seq_parameters = NULL; RK_S32 seq_parameter_set_id = sei_msg->seq_parameter_set_id; if (seq_parameter_set_id >= MAXSPS || !p_videoctx->spsSet[seq_parameter_set_id]) { H264D_ERR("seq_parameter_set_id %d may be invalid\n", seq_parameter_set_id); goto __BITREAD_ERR; } vui_seq_parameters = &(p_videoctx->spsSet[sei_msg->seq_parameter_set_id]->vui_seq_parameters); pic_timing = &(sei_msg->pic_timing); if (vui_seq_parameters->nal_hrd_parameters_present_flag) { cpb_removal_delay_length = vui_seq_parameters->nal_hrd_parameters.cpb_removal_delay_length_minus1; dpb_output_delay_length = vui_seq_parameters->nal_hrd_parameters.dpb_output_delay_length_minus1; time_offset_length = vui_seq_parameters->nal_hrd_parameters.time_offset_length; cpb_dpb_delays_present_flag = 1; } else if (vui_seq_parameters->vcl_hrd_parameters_present_flag) { cpb_removal_delay_length = vui_seq_parameters->vcl_hrd_parameters.cpb_removal_delay_length_minus1; dpb_output_delay_length = vui_seq_parameters->vcl_hrd_parameters.dpb_output_delay_length_minus1; time_offset_length = vui_seq_parameters->vcl_hrd_parameters.time_offset_length; cpb_dpb_delays_present_flag = 1; } if (cpb_dpb_delays_present_flag) { READ_BITS(p_bitctx, cpb_removal_delay_length, &pic_timing->cpb_removal_delay); READ_BITS(p_bitctx, dpb_output_delay_length, &pic_timing->dpb_output_delay); } if (vui_seq_parameters->pic_struct_present_flag) { READ_BITS(p_bitctx, 4, &pic_timing->pic_struct); if (pic_timing->pic_struct > 8 || pic_timing->pic_struct < 0) { goto __BITREAD_ERR; } for (i = 0; i < num_clock_ts[pic_timing->pic_struct]; i++) { READ_BITS(p_bitctx, 1, &pic_timing->clock_timestamp_flag[i]); if (pic_timing->clock_timestamp_flag[i]) { READ_BITS(p_bitctx, 2, &pic_timing->ct_type[i]); READ_BITS(p_bitctx, 1, &pic_timing->nuit_field_based_flag[i]); READ_BITS(p_bitctx, 5, &pic_timing->counting_type[i]); if (pic_timing->counting_type[i] > 6 || pic_timing->counting_type[i] < 0) { goto __BITREAD_ERR; } READ_BITS(p_bitctx, 1, &pic_timing->full_timestamp_flag[i]); READ_BITS(p_bitctx, 1, &pic_timing->discontinuity_flag[i]); READ_BITS(p_bitctx, 1, &pic_timing->cnt_dropped_flag[i]); READ_BITS(p_bitctx, 8, &pic_timing->n_frames[i]); if (pic_timing->full_timestamp_flag[i]) { READ_BITS(p_bitctx, 6, &pic_timing->seconds_value[i]); if (pic_timing->seconds_value[i] > 59) { goto __BITREAD_ERR; } READ_BITS(p_bitctx, 6, &pic_timing->minutes_value[i]); if (pic_timing->minutes_value[i] > 59) { goto __BITREAD_ERR; } READ_BITS(p_bitctx, 5, &pic_timing->hours_value[i]); if (pic_timing->hours_value[i] > 23) { goto __BITREAD_ERR; } } else { READ_BITS(p_bitctx, 1, &pic_timing->seconds_flag[i]); if (pic_timing->seconds_flag[i]) { READ_BITS(p_bitctx, 6, &pic_timing->seconds_value[i]); if (pic_timing->seconds_value[i] > 59) { goto __BITREAD_ERR; } READ_BITS(p_bitctx, 1, &pic_timing->minutes_flag[i]); if (pic_timing->minutes_flag[i]) { READ_BITS(p_bitctx, 6, &pic_timing->minutes_value[i]); if (pic_timing->minutes_value[i] > 59) { goto __BITREAD_ERR; } READ_BITS(p_bitctx, 1, &pic_timing->hours_flag[i]); if (pic_timing->hours_flag[i]) { READ_BITS(p_bitctx, 5, &pic_timing->hours_value[i]); if (pic_timing->hours_value[i] > 23) { goto __BITREAD_ERR; } } } } } if (time_offset_length) { RK_S32 tmp; READ_BITS(p_bitctx, time_offset_length, &tmp); /* following "converts" timeOffsetLength-bit signed * integer into i32 */ /*lint -save -e701 -e702 */ tmp <<= (32 - time_offset_length); tmp >>= (32 - time_offset_length); /*lint -restore */ pic_timing->time_offset[i] = tmp; } else pic_timing->time_offset[i] = 0; } } } return MPP_OK; __BITREAD_ERR: return MPP_ERR_STREAM; } static MPP_RET interpret_buffering_period_info( BitReadCtx_t *p_bitctx, H264_SEI_t *sei_msg, H264dVideoCtx_t *p_videoctx) { MPP_RET ret = MPP_ERR_UNKNOW; RK_U32 i = 0; RK_S32 seq_parameter_set_id = sei_msg->seq_parameter_set_id; struct h264_vui_t *vui_seq_parameters = NULL; READ_UE(p_bitctx, &seq_parameter_set_id); if (seq_parameter_set_id >= MAXSPS || !p_videoctx->spsSet[seq_parameter_set_id]) { H264D_ERR("seq_parameter_set_id %d may be invalid\n", seq_parameter_set_id); goto __BITREAD_ERR; } sei_msg->seq_parameter_set_id = seq_parameter_set_id; vui_seq_parameters = &(p_videoctx->spsSet[sei_msg->seq_parameter_set_id]->vui_seq_parameters); if (vui_seq_parameters->nal_hrd_parameters_present_flag) { for (i = 0; i <= vui_seq_parameters->vcl_hrd_parameters.cpb_cnt_minus1; i++) { SKIP_BITS(p_bitctx, vui_seq_parameters->nal_hrd_parameters.initial_cpb_removal_delay_length_minus1); //initial_cpb_removal_delay SKIP_BITS(p_bitctx, vui_seq_parameters->nal_hrd_parameters.initial_cpb_removal_delay_length_minus1); //initial_cpb_removal_delay_offset } } if (vui_seq_parameters->vcl_hrd_parameters_present_flag) { for (i = 0; i <= vui_seq_parameters->vcl_hrd_parameters.cpb_cnt_minus1; i++) { SKIP_BITS(p_bitctx, vui_seq_parameters->vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1); //initial_cpb_removal_delay SKIP_BITS(p_bitctx, vui_seq_parameters->vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1); //initial_cpb_removal_delay_offset } } return ret = MPP_OK; __BITREAD_ERR: ret = p_bitctx->ret; return ret; } static MPP_RET interpret_reserved_info(RK_S32 size, BitReadCtx_t *p_bitctx, H264_SEI_t *sei_msg) { RK_U8 payload_byte = 0; RK_S32 i = 0; for (i = 0; i < size; i++) { SKIP_BITS(p_bitctx, 8); } (void)p_bitctx; (void)sei_msg; (void)payload_byte; __BITREAD_ERR: return p_bitctx->ret; } static MPP_RET parserSEI(H264_SLICE_t *cur_slice, BitReadCtx_t *p_bitctx, H264_SEI_t *sei_msg, RK_U8 *msg) { (void)msg; MPP_RET ret = MPP_ERR_UNKNOW; H264dVideoCtx_t *p_Vid = cur_slice->p_Vid; #if 0 H264_SPS_t *sps = NULL; H264_subSPS_t *subset_sps = NULL; if (sei_msg->mvc_scalable_nesting_flag) { p_Vid->active_mvc_sps_flag = 1; sps = NULL; subset_sps = &p_Vid->subspsSet[sei_msg->seq_parameter_set_id]; } else { p_Vid->active_mvc_sps_flag = 0; sps = &p_Vid->spsSet[sei_msg->seq_parameter_set_id]; subset_sps = NULL; } p_Vid->exit_picture_flag = 1; FUN_CHECK(ret = activate_sps(p_Vid, sps, subset_sps)); #endif H264D_DBG(H264D_DBG_SEI, "[SEI_info] type=%d size: %d\n", sei_msg->type, sei_msg->payload_size); switch (sei_msg->type) { case H264_SEI_BUFFERING_PERIOD: { FUN_CHECK(ret = interpret_buffering_period_info(p_bitctx, sei_msg, p_Vid)); } break; case H264_SEI_PIC_TIMING: { FUN_CHECK(interpret_picture_timing_info(p_bitctx, sei_msg, p_Vid)); } break; case H264_SEI_USER_DATA_UNREGISTERED: break; default: { interpret_reserved_info(sei_msg->payload_size, p_bitctx, sei_msg); } break; } return ret = MPP_OK; __FAILED: return ret; } /*! *********************************************************************** * \brief * parse SEI information *********************************************************************** */ //extern "C" MPP_RET process_sei(H264_SLICE_t *currSlice) { RK_S32 tmp_byte = 0; MPP_RET ret = MPP_ERR_UNKNOW; H264_SEI_t *sei_msg = NULL; BitReadCtx_t *p_bitctx = &currSlice->p_Cur->bitctx; RK_U32 next; if (!currSlice->p_Cur->sei) currSlice->p_Cur->sei = mpp_calloc(H264_SEI_t, 1); sei_msg = currSlice->p_Cur->sei; sei_msg->mvc_scalable_nesting_flag = 0; //init to false sei_msg->p_Dec = currSlice->p_Dec; do { tmp_byte = 0xFF; sei_msg->type = 0; while (tmp_byte == 0xFF) { READ_BITS(p_bitctx, 8, &tmp_byte); sei_msg->type += tmp_byte; } tmp_byte = 0xFF; sei_msg->payload_size = 0; while (tmp_byte == 0xFF) { READ_BITS(p_bitctx, 8, &tmp_byte); sei_msg->payload_size += tmp_byte; } next = p_bitctx->used_bits + 8 * sei_msg->payload_size; //--- read sei info FUN_CHECK(ret = parserSEI(currSlice, p_bitctx, sei_msg, p_bitctx->data_)); //--- set offset to read next sei nal if (H264_SEI_MVC_SCALABLE_NESTING == sei_msg->type) { sei_msg->payload_size = ((p_bitctx->used_bits + 0x07) >> 3); } SKIP_BITS(p_bitctx, next - p_bitctx->used_bits); } while (mpp_has_more_rbsp_data(p_bitctx)); // more_rbsp_data() msg[offset] != 0x80 return ret = MPP_OK; __BITREAD_ERR: __FAILED: return ret; }