/* * * Copyright 2010 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. */ #include #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_debug.h" #include "mpp_bitread.h" #include "h263d_parser.h" #include "h263d_syntax.h" RK_U32 h263d_debug = 0; #define h263d_dbg(flag, fmt, ...) _mpp_dbg(h263d_debug, flag, fmt, ## __VA_ARGS__) #define h263d_dbg_f(flag, fmt, ...) _mpp_dbg_f(h263d_debug, flag, fmt, ## __VA_ARGS__) #define h263d_dbg_func(fmt, ...) h263d_dbg_f(H263D_DBG_FUNCTION, fmt, ## __VA_ARGS__) #define h263d_dbg_bit(fmt, ...) h263d_dbg(H263D_DBG_BITS, fmt, ## __VA_ARGS__) #define h263d_dbg_status(fmt, ...) h263d_dbg(H263D_DBG_STATUS, fmt, ## __VA_ARGS__) #define H263_STARTCODE 0x00000080 /* 17 zero and 1 one */ #define H263_STARTCODE_MASK 0x00FFFF80 #define H263_GOB_ZERO 0x00000000 #define H263_GOB_ZERO_MASK 0x0000007C #define H263_SF_SQCIF 1 /* 001 */ #define H263_SF_QCIF 2 /* 010 */ #define H263_SF_CIF 3 /* 011 */ #define H263_SF_4CIF 4 /* 100 */ #define H263_SF_16CIF 5 /* 101 */ #define H263_SF_CUSTOM 6 /* 110 */ #define H263_EXTENDED_PTYPE 7 /* 111 */ #define H263_EXTENDED_PAR 15 /* 1111 */ typedef struct H263Hdr_t { H263VOPType pict_type; RK_S32 width; RK_S32 height; RK_U32 TR; RK_U32 quant; // frame related parameter RK_S64 pts; RK_S32 slot_idx; RK_U32 enqueued; RK_U32 hdr_bits; } H263Hdr; typedef struct { // global paramter MppBufSlots frame_slots; RK_U32 use_internal_pts; RK_U32 found_i_vop; // frame size parameter RK_S32 width; RK_S32 height; RK_S32 hor_stride; RK_S32 ver_stride; RK_U32 info_change; RK_U32 eos; // spliter parameter RK_S32 pos_frm_start; // negtive - not found; non-negtive - position of frame start RK_S32 pos_frm_end; // negtive - not found; non-negtive - position of frame end // bit read context BitReadCtx_t *bit_ctx; // decoding parameter H263Hdr hdr_curr; H263Hdr hdr_ref0; // dpb/output information RK_S32 output; RK_S64 pts; // syntax for hal h263d_dxva2_picture_context_t *syntax; } H263dParserImpl; static RK_U32 h263d_fmt_to_dimension[8][2] = { { 0, 0 }, /* invalid */ { 128, 96 }, /* SQCIF */ { 176, 144 }, /* QCIF */ { 352, 288 }, /* CIF */ { 704, 576 }, /* 4CIF */ { 1408, 1152 }, /* 16CIF */ { 0, 0 }, /* custorm */ { 0, 0 }, /* extend */ }; static void h263d_fill_picture_parameters(const H263dParserImpl *p, DXVA_PicParams_H263 *pp) { const H263Hdr *hdr_curr = &p->hdr_curr; const H263Hdr *hdr_ref0 = &p->hdr_ref0; pp->short_video_header = 1; pp->vop_coding_type = hdr_curr->pict_type; pp->vop_quant = hdr_curr->quant; pp->wDecodedPictureIndex = hdr_curr->slot_idx; pp->wForwardRefPictureIndex = hdr_ref0->slot_idx; pp->vop_time_increment_resolution = 30000; pp->vop_width = hdr_curr->width; pp->vop_height = hdr_curr->height; // Rockchip special data pp->prev_coding_type = hdr_ref0->pict_type; pp->header_bits = hdr_curr->hdr_bits; } static void h263_syntax_init(h263d_dxva2_picture_context_t *syntax) { DXVA2_DecodeBufferDesc *data = &syntax->desc[0]; //!< commit picture paramters memset(data, 0, sizeof(*data)); data->CompressedBufferType = DXVA2_PictureParametersBufferType; data->pvPVPState = (void *)&syntax->pp; data->DataSize = sizeof(syntax->pp); syntax->data[0] = data; //!< commit bitstream data = &syntax->desc[1]; memset(data, 0, sizeof(*data)); data->CompressedBufferType = DXVA2_BitStreamDateBufferType; syntax->data[1] = data; } static MPP_RET h263_parse_picture_header(H263dParserImpl *p, BitReadCtx_t *gb) { RK_U32 val = 0; H263Hdr *hdr_curr = &p->hdr_curr; H263VOPType pict_type = H263_INVALID_VOP; /* start code */ READ_BITS(gb, 17, &val); /* start code */ mpp_assert(val == 1); /* gob */ READ_BITS(gb, 5, &val); /* gob */ mpp_assert(val == 0); /* time reference */ READ_BITS(gb, 8, &hdr_curr->TR); /* first 5 bit of PTYPE */ SKIP_BITS(gb, 5); /* source format */ READ_BITS(gb, 3, &val); /* source format */ hdr_curr->width = h263d_fmt_to_dimension[val][0]; hdr_curr->height = h263d_fmt_to_dimension[val][1]; if (!hdr_curr->width && !hdr_curr->height) { mpp_err_f("unsupport source format %d\n", val); return MPP_NOK; } /* picture coding type: 0 - INTRA, 1 - INTER */ READ_BITS(gb, 1, &val); pict_type = val; /* last 4 bit for PTYPE: UMV, AP mode, PB frame */ READ_BITS(gb, 4, &val); if (val) { mpp_err_f("unsupport PTYPE mode %x\n", val); return MPP_NOK; } READ_BITS(gb, 5, &val); hdr_curr->quant = val; SKIP_BITS(gb, 1); READ_BITS(gb, 1, &val); while (val) { SKIP_BITS(gb, 8); READ_BITS(gb, 1, &val); } if (!p->found_i_vop) p->found_i_vop = (pict_type == H263_I_VOP); if (!p->found_i_vop) return MPP_NOK; hdr_curr->hdr_bits = gb->used_bits; hdr_curr->pict_type = pict_type; return MPP_OK; __BITREAD_ERR: mpp_err_f("found error stream\n"); return MPP_ERR_STREAM; } MPP_RET mpp_h263_parser_init(H263dParser *ctx, MppBufSlots frame_slots) { BitReadCtx_t *bit_ctx = mpp_calloc(BitReadCtx_t, 1); H263dParserImpl *p = mpp_calloc(H263dParserImpl, 1); h263d_dxva2_picture_context_t *syntax = mpp_calloc(h263d_dxva2_picture_context_t, 1); if (NULL == p || NULL == bit_ctx || NULL == syntax) { mpp_err_f("malloc context failed\n"); if (p) mpp_free(p); if (bit_ctx) mpp_free(bit_ctx); if (syntax) mpp_free(syntax); return MPP_NOK; } mpp_buf_slot_setup(frame_slots, 4); p->frame_slots = frame_slots; p->pos_frm_start = -1; p->pos_frm_end = -1; p->bit_ctx = bit_ctx; p->hdr_curr.slot_idx = H263_INVALID_VOP; p->hdr_ref0.slot_idx = H263_INVALID_VOP; h263_syntax_init(syntax); p->syntax = syntax; mpp_env_get_u32("h263d_debug", &h263d_debug, 0); *ctx = p; return MPP_OK; } MPP_RET mpp_h263_parser_deinit(H263dParser ctx) { H263dParserImpl *p = (H263dParserImpl *)ctx; if (p) { if (p->bit_ctx) { mpp_free(p->bit_ctx); p->bit_ctx = NULL; } if (p->syntax) { mpp_free(p->syntax); p->syntax = NULL; } mpp_free(p); } return MPP_OK; } MPP_RET mpp_h263_parser_flush(H263dParser ctx) { H263dParserImpl *p = (H263dParserImpl *)ctx; MppBufSlots slots = p->frame_slots; H263Hdr *hdr_curr = &p->hdr_ref0; RK_S32 index = hdr_curr->slot_idx; h263d_dbg_func("in\n"); if (!hdr_curr->enqueued && index >= 0) { mpp_buf_slot_set_flag(slots, index, SLOT_QUEUE_USE); mpp_buf_slot_enqueue(slots, index, QUEUE_DISPLAY); hdr_curr->enqueued = 1; } h263d_dbg_func("out\n"); return MPP_OK; } MPP_RET mpp_h263_parser_reset(H263dParser ctx) { H263dParserImpl *p = (H263dParserImpl *)ctx; MppBufSlots slots = p->frame_slots; H263Hdr *hdr_curr = &p->hdr_ref0; H263Hdr *hdr_ref0 = &p->hdr_ref0; RK_S32 index = hdr_curr->slot_idx; h263d_dbg_func("in\n"); if (index >= 0) { mpp_buf_slot_clr_flag(slots, index, SLOT_CODEC_USE); hdr_curr->slot_idx = -1; } index = hdr_ref0->slot_idx; if (index >= 0) { mpp_buf_slot_clr_flag(slots, index, SLOT_CODEC_USE); hdr_ref0->slot_idx = -1; } p->found_i_vop = 0; h263d_dbg_func("out\n"); return MPP_OK; } MPP_RET mpp_h263_parser_split(H263dParser ctx, MppPacket dst, MppPacket src) { MPP_RET ret = MPP_NOK; H263dParserImpl *p = (H263dParserImpl *)ctx; RK_U8 *dst_buf = mpp_packet_get_data(dst); size_t dst_len = mpp_packet_get_length(dst); RK_U8 *src_buf = mpp_packet_get_pos(src); RK_S32 src_len = (RK_S32)mpp_packet_get_length(src); RK_S32 pos_frm_start = p->pos_frm_start; RK_S32 pos_frm_end = p->pos_frm_end; RK_U32 src_eos = mpp_packet_get_eos(src); RK_S32 src_pos = 0; RK_U32 state = (RK_U32) - 1; h263d_dbg_func("in\n"); mpp_assert(src_len); if (dst_len) { mpp_assert(dst_len >= 4); state = ((RK_U32)(dst_buf[dst_len - 1]) << 0) | ((RK_U32)(dst_buf[dst_len - 2]) << 8) | ((RK_U32)(dst_buf[dst_len - 3]) << 16) | ((RK_U32)(dst_buf[dst_len - 4]) << 24); } if (pos_frm_start < 0) { // scan for frame start for (src_pos = 0; src_pos < src_len; src_pos++) { state = (state << 8) | src_buf[src_pos]; if ((state & H263_STARTCODE_MASK) == H263_STARTCODE && (state & H263_GOB_ZERO_MASK) == H263_GOB_ZERO) { pos_frm_start = src_pos - 3; src_pos++; break; } } } if (pos_frm_start >= 0) { // scan for frame end for (; src_pos < src_len; src_pos++) { state = (state << 8) | src_buf[src_pos]; if ((state & H263_STARTCODE_MASK) == H263_STARTCODE && (state & H263_GOB_ZERO_MASK) == H263_GOB_ZERO) { pos_frm_end = src_pos - 3; break; } } if (src_eos && src_pos == src_len) { pos_frm_end = src_len; mpp_packet_set_eos(dst); } } //mpp_log("pkt pos: start %d end %d len: left %d in %d\n", // pos_frm_start, pos_frm_end, dst_len, src_len); if (pos_frm_start < 0 || pos_frm_end < 0) { // do not found frame start or do not found frame end, just copy the hold buffer to dst memcpy(dst_buf + dst_len, src_buf, src_len); // update dst buffer length mpp_packet_set_length(dst, dst_len + src_len); // set src buffer pos to end to src buffer mpp_packet_set_pos(src, src_buf + src_len); } else { // found both frame start and frame end - only copy frame memcpy(dst_buf + dst_len, src_buf, pos_frm_end); mpp_packet_set_length(dst, dst_len + pos_frm_end); // set src buffer pos to end to src buffer mpp_packet_set_pos(src, src_buf + pos_frm_end); mpp_assert((RK_S32)mpp_packet_get_length(src) == (src_len - pos_frm_end)); mpp_packet_set_length(src, src_len - pos_frm_end); // return ok indicate the frame is ready and reset frame start/end position ret = MPP_OK; pos_frm_start = -1; pos_frm_end = -1; } p->pos_frm_start = pos_frm_start; p->pos_frm_end = pos_frm_end; h263d_dbg_func("out\n"); return ret; } MPP_RET mpp_h263_parser_decode(H263dParser ctx, MppPacket pkt) { MPP_RET ret = MPP_NOK; H263dParserImpl *p = (H263dParserImpl *)ctx; BitReadCtx_t *gb = p->bit_ctx; RK_U8 *buf = mpp_packet_get_data(pkt); RK_S32 len = (RK_S32)mpp_packet_get_length(pkt); RK_U32 startcode = 0xff; RK_S32 i = 0; h263d_dbg_func("in\n"); while (i < len) { startcode = (startcode << 8) | buf[i++]; if (startcode >> (32 - 22) == 0x20) { i -= 4; h263d_dbg_bit("found startcode at byte %d\n", i); break; } } if (i == len) { mpp_err_f("can not found start code in len %d packet\n", len); goto __BITREAD_ERR; } // setup bit read context mpp_set_bitread_ctx(gb, buf + i, len - i); ret = h263_parse_picture_header(p, gb); if (ret) goto __BITREAD_ERR; p->width = p->hdr_curr.width; p->height = p->hdr_curr.height; p->pts = mpp_packet_get_pts(pkt); __BITREAD_ERR: h263d_dbg_status("found i_frame %d frame_type %d ret %d\n", p->found_i_vop, p->hdr_curr.pict_type, ret); mpp_packet_set_pos(pkt, buf); mpp_packet_set_length(pkt, 0); p->eos = mpp_packet_get_eos(pkt); h263d_dbg_func("out\n"); return ret; } MPP_RET mpp_h263_parser_setup_syntax(H263dParser ctx, MppSyntax *syntax) { H263dParserImpl *p = (H263dParserImpl *)ctx; h263d_dxva2_picture_context_t *syn = p->syntax; h263d_dbg_func("in\n"); h263d_fill_picture_parameters(p, &syn->pp); // fill bit stream parameter syn->data[1]->DataSize = p->bit_ctx->buf_len; syn->data[1]->DataOffset = p->hdr_curr.hdr_bits; syn->data[1]->pvPVPState = p->bit_ctx->buf; syntax->number = 2; syntax->data = syn->data; h263d_dbg_func("out\n"); return MPP_OK; } MPP_RET mpp_h263_parser_setup_hal_output(H263dParser ctx, RK_S32 *output) { H263dParserImpl *p = (H263dParserImpl *)ctx; RK_S32 index = -1; h263d_dbg_func("in\n"); if (p->found_i_vop) { H263Hdr *hdr_curr = &p->hdr_curr; MppBufSlots slots = p->frame_slots; MppFrame frame = NULL; mpp_frame_init(&frame); mpp_frame_set_width(frame, p->width); mpp_frame_set_height(frame, p->height); mpp_frame_set_hor_stride(frame, MPP_ALIGN(p->width, 16)); mpp_frame_set_ver_stride(frame, MPP_ALIGN(p->height, 16)); /* * set slots information * 1. output index MUST be set * 2. get unused index for output if needed * 3. set output index as hal_input * 4. set frame information to output index * 5. if one frame can be display, it SHOULD be enqueued to display queue */ mpp_buf_slot_get_unused(slots, &index); mpp_buf_slot_set_flag(slots, index, SLOT_HAL_OUTPUT); mpp_frame_set_pts(frame, p->pts); mpp_frame_set_mode(frame, MPP_FRAME_FLAG_FRAME); mpp_buf_slot_set_prop(slots, index, SLOT_FRAME, frame); mpp_frame_deinit(&frame); mpp_assert(NULL == frame); hdr_curr->slot_idx = index; } p->output = index; *output = index; h263d_dbg_func("out\n"); return MPP_OK; } MPP_RET mpp_h263_parser_setup_refer(H263dParser ctx, RK_S32 *refer, RK_S32 max_ref) { H263dParserImpl *p = (H263dParserImpl *)ctx; H263Hdr *hdr_curr = &p->hdr_curr; MppBufSlots slots = p->frame_slots; RK_S32 index; h263d_dbg_func("in\n"); memset(refer, -1, sizeof(max_ref * sizeof(*refer))); if (hdr_curr->pict_type == H263_P_VOP) { index = p->hdr_ref0.slot_idx; if (index >= 0) { mpp_buf_slot_set_flag(slots, index, SLOT_HAL_INPUT); refer[0] = index; } } h263d_dbg_func("out\n"); return MPP_OK; } MPP_RET mpp_h263_parser_update_dpb(H263dParser ctx) { H263dParserImpl *p = (H263dParserImpl *)ctx; MppBufSlots slots = p->frame_slots; H263Hdr *hdr_curr = &p->hdr_curr; H263Hdr *hdr_ref0 = &p->hdr_ref0; RK_S32 index = hdr_curr->slot_idx; h263d_dbg_func("in\n"); mpp_assert(index >= 0); mpp_buf_slot_set_flag(slots, index, SLOT_CODEC_USE); mpp_buf_slot_set_flag(slots, index, SLOT_QUEUE_USE); mpp_buf_slot_enqueue(slots, index, QUEUE_DISPLAY); hdr_curr->enqueued = 1; index = hdr_ref0->slot_idx; if (index >= 0) { mpp_buf_slot_clr_flag(slots, index, SLOT_CODEC_USE); hdr_ref0->slot_idx = -1; } // swap current to ref0 *hdr_ref0 = *hdr_curr; hdr_curr->slot_idx = H263_INVALID_VOP; hdr_curr->pts = 0; hdr_curr->enqueued = 0; h263d_dbg_func("out\n"); return MPP_OK; }