/* * * 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 "vp8d_parser" #include #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_debug.h" #include "mpp_frame.h" #include "vp8d_parser.h" #include "vp8d_codec.h" #define FUN_T(tag) \ do {\ if (VP8D_DBG_FUNCTION & vp8d_debug)\ { mpp_log("%s: line(%d), func(%s)", tag, __LINE__, __FUNCTION__); }\ } while (0) static RK_U32 vp8d_debug = 0x0; static void vp8hwdBoolStart(vpBoolCoder_t *bit_ctx, RK_U8 *buffer, RK_U32 len) { FUN_T("FUN_IN"); bit_ctx->lowvalue = 0; bit_ctx->range = 255; bit_ctx->count = 8; bit_ctx->buffer = buffer; bit_ctx->pos = 0; bit_ctx->value = (bit_ctx->buffer[0] << 24) + (bit_ctx->buffer[1] << 16) + (bit_ctx->buffer[2] << 8) + (bit_ctx->buffer[3]); bit_ctx->pos += 4; bit_ctx->streamEndPos = len; bit_ctx->strmError = bit_ctx->pos > bit_ctx->streamEndPos; FUN_T("FUN_OUT"); } static RK_U32 vp8hwdDecodeBool(vpBoolCoder_t *bit_ctx, RK_S32 probability) { RK_U32 bit = 0; RK_U32 split; RK_U32 bigsplit; RK_U32 count = bit_ctx->count; RK_U32 range = bit_ctx->range; RK_U32 value = bit_ctx->value; FUN_T("FUN_IN"); split = 1 + (((range - 1) * probability) >> 8); bigsplit = (split << 24); range = split; if (value >= bigsplit) { range = bit_ctx->range - split; value = value - bigsplit; bit = 1; } if (range >= 0x80) { bit_ctx->value = value; bit_ctx->range = range; return bit; } else { do { range += range; value += value; if (!--count) { /* no more stream to read? */ if (bit_ctx->pos >= bit_ctx->streamEndPos) { bit_ctx->strmError = 1; mpp_log("vp8hwdDecodeBool read end"); break; } count = 8; value |= bit_ctx->buffer[bit_ctx->pos]; bit_ctx->pos++; } } while (range < 0x80); } bit_ctx->count = count; bit_ctx->value = value; bit_ctx->range = range; FUN_T("FUN_OUT"); return bit; } static RK_U32 vp8hwdDecodeBool128(vpBoolCoder_t *bit_ctx) { RK_U32 bit = 0; RK_U32 split; RK_U32 bigsplit; RK_U32 count = bit_ctx->count; RK_U32 range = bit_ctx->range; RK_U32 value = bit_ctx->value; FUN_T("FUN_IN"); split = (range + 1) >> 1; bigsplit = (split << 24); range = split; if (value >= bigsplit) { range = (bit_ctx->range - split); value = (value - bigsplit); bit = 1; } if (range >= 0x80) { bit_ctx->value = value; bit_ctx->range = range; FUN_T("FUN_OUT"); return bit; } else { range <<= 1; value <<= 1; if (!--count) { /* no more stream to read? */ if (bit_ctx->pos >= bit_ctx->streamEndPos) { bit_ctx->strmError = 1; mpp_log("vp8hwdDecodeBool128 read end"); return 0; /* any value, not valid */ } count = 8; value |= bit_ctx->buffer[bit_ctx->pos]; bit_ctx->pos++; } } bit_ctx->count = count; bit_ctx->value = value; bit_ctx->range = range; FUN_T("FUN_OUT"); return bit; } static RK_U32 vp8hwdReadBits(vpBoolCoder_t *bit_ctx, RK_S32 bits) { RK_U32 z = 0; RK_S32 bit; FUN_T("FUN_IN"); for (bit = bits - 1; bit >= 0; bit--) { z |= (vp8hwdDecodeBool128(bit_ctx) << bit); } FUN_T("FUN_OUT"); return z; } static RK_U32 ScaleDimension( RK_U32 orig, RK_U32 scale ) { FUN_T("FUN_IN"); switch (scale) { case 0: return orig; break; case 1: /* 5/4 */ return (5 * orig) / 4; break; case 2: /* 5/3 */ return (5 * orig) / 3; break; case 3: /* 2 */ return 2 * orig; break; } FUN_T("FUN_OUT"); return orig; } static RK_S32 DecodeQuantizerDelta(vpBoolCoder_t *bit_ctx) { RK_S32 result = 0; FUN_T("FUN_IN"); if (vp8hwdDecodeBool128(bit_ctx)) { result = vp8hwdReadBits(bit_ctx, 4); if (vp8hwdDecodeBool128(bit_ctx)) result = -result; } FUN_T("FUN_OUT"); return result; } MPP_RET vp8d_parser_init(void *ctx, ParserCfg *parser_cfg) { MPP_RET ret = MPP_OK; VP8DContext *c = (VP8DContext *)ctx; VP8DParserContext_t *p = (VP8DParserContext_t *)c->parse_ctx; FUN_T("FUN_IN"); if (p == NULL) { p = (VP8DParserContext_t*)mpp_calloc(VP8DParserContext_t, 1); if (NULL == p) { mpp_err("vp8d malloc VP8DParserContext_t fail"); FUN_T("FUN_OUT"); return MPP_ERR_NOMEM; } c->parse_ctx = p; } p->packet_slots = parser_cfg->packet_slots; p->frame_slots = parser_cfg->frame_slots; mpp_buf_slot_setup(p->frame_slots, 15); p->dxva_ctx = mpp_calloc(DXVA_PicParams_VP8, 1); if (NULL == p->dxva_ctx) { mpp_err("vp8d malloc dxva_ctx fail"); FUN_T("FUN_OUT"); return MPP_ERR_NOMEM; } p->decMode = VP8HWD_VP8; p->bitstream_sw_buf = mpp_malloc(RK_U8, VP8D_BUF_SIZE_BITMEM); mpp_packet_init(&p->input_packet, p->bitstream_sw_buf, VP8D_BUF_SIZE_BITMEM); p->max_stream_size = VP8D_BUF_SIZE_BITMEM; FUN_T("FUN_OUT"); return ret; } static void vp8d_unref_frame(VP8DParserContext_t *p, VP8Frame *frame) { FUN_T("FUN_IN"); if (NULL == frame || frame->ref_count <= 0 || frame->slot_index >= 0x7f) { mpp_err("ref count alreay is zero"); FUN_T("FUN_OUT"); return; } frame->ref_count--; if (!frame->ref_count) { if (frame->slot_index < 0x7f) { MppBuffer framebuf = NULL; if (frame->invisible) { mpp_buf_slot_get_prop(p->frame_slots, frame->slot_index, SLOT_BUFFER, &framebuf); mpp_buffer_put(framebuf); frame->invisible = 0; } mpp_buf_slot_clr_flag(p->frame_slots, frame->slot_index, SLOT_CODEC_USE); } frame->slot_index = 0xff; mpp_frame_deinit(&frame->f); mpp_free(frame); frame = NULL; } FUN_T("FUN_OUT"); return; } static void vp8d_unref_allframe(VP8DParserContext_t *p) { FUN_T("FUN_IN"); if (NULL != p->frame_out) { vp8d_unref_frame(p, p->frame_out); p->frame_out = NULL; } if (NULL != p->frame_ref) { vp8d_unref_frame(p, p->frame_ref); p->frame_ref = NULL; } if (NULL != p->frame_golden) { vp8d_unref_frame(p, p->frame_golden); p->frame_golden = NULL; } if (NULL != p->frame_alternate) { vp8d_unref_frame(p, p->frame_alternate); p->frame_alternate = NULL; } FUN_T("FUN_OUT"); return; } MPP_RET vp8d_parser_deinit(void *ctx) { MPP_RET ret = MPP_OK; VP8DContext *c = (VP8DContext *)ctx; VP8DParserContext_t *p = (VP8DParserContext_t *)c->parse_ctx; FUN_T("FUN_IN"); if (NULL != p->bitstream_sw_buf) { mpp_free(p->bitstream_sw_buf); p->bitstream_sw_buf = NULL; } if (NULL != p->dxva_ctx) { mpp_free(p->dxva_ctx); p->dxva_ctx = NULL; } vp8d_unref_allframe(p); if (p->input_packet) { mpp_packet_deinit(&p->input_packet); p->input_packet = NULL; } if ( NULL != p) { mpp_free(p); } FUN_T("FUN_OUT"); return ret; } /*! *********************************************************************** * \brief * reset *********************************************************************** */ MPP_RET vp8d_parser_reset(void *ctx) { MPP_RET ret = MPP_OK; VP8DContext *c = (VP8DContext *)ctx; VP8DParserContext_t *p = (VP8DParserContext_t *)c->parse_ctx; FUN_T("FUN_IN"); vp8d_unref_allframe(p); p->needKeyFrame = 0; p->eos = 0; FUN_T("FUN_OUT"); return ret; } /*! *********************************************************************** * \brief * flush *********************************************************************** */ MPP_RET vp8d_parser_flush(void *ctx) { MPP_RET ret = MPP_OK; FUN_T("FUN_IN"); (void) ctx; FUN_T("FUN_OUT"); return ret; } /*! *********************************************************************** * \brief * control/perform *********************************************************************** */ MPP_RET vp8d_parser_control(void *ctx, MpiCmd cmd_type, void *param) { MPP_RET ret = MPP_OK; FUN_T("FUN_IN"); (void)ctx; (void)cmd_type; (void)param; FUN_T("FUN_OUT"); return ret; } /*! *********************************************************************** * \brief * prepare *********************************************************************** */ static MPP_RET vp8d_parser_split_frame(RK_U8 *src, RK_U32 src_size, RK_U8 *dst, RK_U32 *dst_size) { MPP_RET ret = MPP_OK; FUN_T("FUN_IN"); memcpy(dst, src, src_size);; *dst_size = src_size; (void)dst; FUN_T("FUN_OUT"); return ret; } MPP_RET vp8d_parser_prepare(void *ctx, MppPacket pkt, HalDecTask *task) { MPP_RET ret = MPP_OK; RK_U32 out_size = 0, len_in = 0; RK_U8 * pos = NULL; RK_U8 *buf = NULL; VP8DContext *c = (VP8DContext *)ctx; VP8DParserContext_t *p = (VP8DParserContext_t *)c->parse_ctx; MppPacket input_packet = p->input_packet; FUN_T("FUN_IN"); task->valid = 0; buf = pos = mpp_packet_get_pos(pkt); p->pts = mpp_packet_get_pts(pkt); len_in = (RK_U32)mpp_packet_get_length(pkt), p->eos = mpp_packet_get_eos(pkt); // mpp_log("len_in = %d",len_in); if (len_in > p->max_stream_size) { mpp_free(p->bitstream_sw_buf); p->bitstream_sw_buf = NULL; p->bitstream_sw_buf = mpp_malloc(RK_U8, (len_in + 1024)); if (NULL == p->bitstream_sw_buf) { mpp_err("vp8d_parser realloc fail"); return MPP_ERR_NOMEM; } p->max_stream_size = len_in + 1024; } vp8d_parser_split_frame(buf, len_in, p->bitstream_sw_buf, &out_size); pos += out_size; mpp_packet_set_pos(pkt, pos); if (out_size == 0 && p->eos) { task->flags.eos = p->eos; return ret; } // mpp_log("p->bitstream_sw_buf = 0x%x", p->bitstream_sw_buf); // mpp_log("out_size = 0x%x", out_size); mpp_packet_set_data(input_packet, p->bitstream_sw_buf); mpp_packet_set_size(input_packet, p->max_stream_size); mpp_packet_set_length(input_packet, out_size); p->stream_size = out_size; task->input_packet = input_packet; task->valid = 1; FUN_T("FUN_OUT"); return ret; } static MPP_RET vp8d_convert_to_syntx( VP8DParserContext_t *p, HalDecTask *in_task) { MPP_RET ret = MPP_OK; RK_U32 i, tmp; RK_U32 byteOffset = 0, extraBytesPacked = 0; DXVA_PicParams_VP8 *pic_param = p->dxva_ctx; FUN_T("FUN_IN"); tmp = (p->bitstr.pos) * 8 + (8 - p->bitstr.count); if (p->frameTagSize == 4) tmp += 8; if (p->decMode == VP8HWD_VP8 && p->keyFrame) extraBytesPacked += 7; tmp += extraBytesPacked * 8; byteOffset = tmp / 8; pic_param->stream_start_bit = (byteOffset & 0x07U) * 8; byteOffset &= (~0x07U); /* align the base */ pic_param->stream_start_offset = byteOffset; pic_param->stream_start_bit += (tmp & 0x7); pic_param->frame_type = !p->keyFrame; pic_param->stVP8Segments.segmentation_enabled = p->segmentationEnabled; pic_param->stVP8Segments.update_mb_segmentation_map = p->segmentationMapUpdate; pic_param->mode_ref_lf_delta_enabled = p->modeRefLfEnabled; pic_param->mb_no_coeff_skip = p->coeffSkipMode; pic_param->width = p->width; pic_param->height = p->height; pic_param->decMode = p->decMode; pic_param->filter_type = p->loopFilterType; pic_param->sharpness = p->loopFilterSharpness; pic_param->filter_level = p->loopFilterLevel; pic_param->stVP8Segments.update_mb_segmentation_data = p->segmentFeatureMode; pic_param->version = p->vpVersion; pic_param->bool_value = ((p->bitstr.value >> 24) & (0xFFU)); pic_param->bool_range = (p->bitstr.range & (0xFFU)); pic_param->frameTagSize = p->frameTagSize; pic_param->streamEndPos = p->bitstr.streamEndPos; pic_param->log2_nbr_of_dct_partitions = p->nbrDctPartitions; pic_param->offsetToDctParts = p->offsetToDctParts; pic_param->y1ac_delta_q = p->qpYAc; pic_param->y1dc_delta_q = p->qpYDc; pic_param->y2ac_delta_q = p->qpY2Ac; pic_param->y2dc_delta_q = p->qpY2Dc; pic_param->uvac_delta_q = p->qpChAc; pic_param->uvdc_delta_q = p->qpChDc; pic_param->probe_skip_false = p->probMbSkipFalse; pic_param->prob_intra = p->probIntra; pic_param->prob_last = p->probRefLast; pic_param->prob_golden = p->probRefGolden; memcpy(pic_param->vp8_coef_update_probs, p->entropy.probCoeffs, sizeof(pic_param->vp8_coef_update_probs)); memcpy(pic_param->vp8_mv_update_probs, p->entropy.probMvContext, sizeof(pic_param->vp8_mv_update_probs)); for ( i = 0; i < 3; i++) { pic_param->intra_chroma_prob[i] = p->entropy.probChromaPredMode[i]; pic_param->stVP8Segments.mb_segment_tree_probs[i] = p->probSegment[i]; } pic_param->ref_frame_sign_bias_golden = p->refFrameSignBias[0]; pic_param->ref_frame_sign_bias_altref = p->refFrameSignBias[1]; for (i = 0; i < 4; i++) { pic_param->stVP8Segments.segment_feature_data[0][i] = p->segmentQp[i]; pic_param->ref_lf_deltas[i] = p->mbRefLfDelta[i]; pic_param->mode_lf_deltas[i] = p->mbModeLfDelta[i]; pic_param->stVP8Segments.segment_feature_data[1][i] = p->segmentLoopfilter[i]; pic_param->intra_16x16_prob[i] = p->entropy.probLuma16x16PredMode[i]; } p->dxva_ctx->CurrPic.Index7Bits = p->frame_out->slot_index; memset(in_task->refer, -1, sizeof(in_task->refer)); if (p->frame_ref != NULL) { pic_param->lst_fb_idx.Index7Bits = p->frame_ref->slot_index; mpp_buf_slot_set_flag(p->frame_slots, p->frame_ref->slot_index, SLOT_HAL_INPUT); in_task->refer[0] = p->frame_ref->slot_index; } else { pic_param->lst_fb_idx.Index7Bits = 0x7f; } if (p->frame_golden != NULL) { pic_param->gld_fb_idx.Index7Bits = p->frame_golden->slot_index; mpp_buf_slot_set_flag(p->frame_slots, p->frame_golden->slot_index, SLOT_HAL_INPUT); in_task->refer[1] = p->frame_golden->slot_index; } else { pic_param->gld_fb_idx.Index7Bits = 0x7f; } if (p->frame_alternate != NULL) { pic_param->alt_fb_idx.Index7Bits = p->frame_alternate->slot_index; mpp_buf_slot_set_flag(p->frame_slots, p->frame_alternate->slot_index, SLOT_HAL_INPUT); in_task->refer[2] = p->frame_alternate->slot_index; } else { pic_param->alt_fb_idx.Index7Bits = 0x7f; } memcpy(pic_param->dctPartitionOffsets, p->dctPartitionOffsets, sizeof(p->dctPartitionOffsets)); FUN_T("FUN_OUT"); return ret; } static MPP_RET vp8d_alloc_frame(VP8DParserContext_t *p) { MPP_RET ret = MPP_OK; FUN_T("FUN_IN"); if (NULL == p->frame_out) { p->frame_out = mpp_calloc(VP8Frame, 1); if (NULL == p->frame_out) { mpp_err("alloc vp8 frame fail"); return MPP_ERR_NOMEM; } if (NULL == p->frame_out->f) { mpp_frame_init(&p->frame_out->f); if (NULL == p->frame_out->f) { mpp_err("alloc vp8 mpp frame fail"); return MPP_ERR_NOMEM; } } p->frame_out->slot_index = 0xff; p->frame_out->invisible = !p->showFrame; } if (p->frame_out->slot_index == 0xff) { mpp_frame_set_width(p->frame_out->f, p->width); mpp_frame_set_height(p->frame_out->f, p->height); mpp_frame_set_hor_stride(p->frame_out->f, p->width); mpp_frame_set_ver_stride(p->frame_out->f, p->height); mpp_frame_set_errinfo(p->frame_out->f, 0); mpp_frame_set_pts(p->frame_out->f, p->pts); ret = mpp_buf_slot_get_unused(p->frame_slots, &p->frame_out->slot_index); if (MPP_OK != ret) { mpp_err("vp8 buf_slot_get_unused get fail"); return ret; } mpp_buf_slot_set_prop(p->frame_slots, p->frame_out->slot_index, SLOT_FRAME, p->frame_out->f); mpp_buf_slot_set_flag(p->frame_slots, p->frame_out->slot_index, SLOT_CODEC_USE); mpp_buf_slot_set_flag(p->frame_slots, p->frame_out->slot_index, SLOT_HAL_OUTPUT); mpp_frame_set_mode(p->frame_out->f, 0); if (p->showFrame) { mpp_buf_slot_set_flag(p->frame_slots, p->frame_out->slot_index, SLOT_QUEUE_USE); mpp_buf_slot_enqueue(p->frame_slots, p->frame_out->slot_index, QUEUE_DISPLAY); } p->frame_out->ref_count++; } FUN_T("FUN_OUT"); return ret; } static void vp8d_ref_frame(VP8Frame *frame) { FUN_T("FUN_IN"); if ((NULL == frame) || (frame->slot_index >= 0x7f)) { mpp_err("frame is null or slot_index is no valid"); return; } frame->ref_count++; FUN_T("FUN_OUT"); } static MPP_RET vp8d_ref_update(VP8DParserContext_t *p) { FUN_T("FUN_IN"); if (p->decMode != VP8HWD_WEBP) { if (p->copyBufferToAlternate == 1) { if (NULL != p->frame_alternate) { vp8d_unref_frame(p, p->frame_alternate); p->frame_alternate = NULL; } p->frame_alternate = p->frame_ref; vp8d_ref_frame(p->frame_alternate); } else if (p->copyBufferToAlternate == 2) { if (NULL != p->frame_alternate) { vp8d_unref_frame(p, p->frame_alternate); p->frame_alternate = NULL; } p->frame_alternate = p->frame_golden; vp8d_ref_frame(p->frame_alternate); } if (p->copyBufferToGolden == 1) { if (NULL != p->frame_golden) { vp8d_unref_frame(p, p->frame_golden); p->frame_golden = NULL; } p->frame_golden = p->frame_ref; vp8d_ref_frame(p->frame_golden); } else if (p->copyBufferToGolden == 2) { if (NULL != p->frame_golden) { vp8d_unref_frame(p, p->frame_golden); p->frame_golden = NULL; } p->frame_golden = p->frame_alternate; vp8d_ref_frame(p->frame_golden); } if (p->refreshGolden) { if (NULL != p->frame_golden) { vp8d_unref_frame(p, p->frame_golden); p->frame_golden = NULL; } p->frame_golden = p->frame_out; vp8d_ref_frame(p->frame_golden); } if (p->refreshAlternate) { if (NULL != p->frame_alternate) { vp8d_unref_frame(p, p->frame_alternate); p->frame_alternate = NULL; } p->frame_alternate = p->frame_out; vp8d_ref_frame(p->frame_out); } if (p->refreshLast) { if (NULL != p->frame_ref) { vp8d_unref_frame(p, p->frame_ref); p->frame_ref = NULL; } p->frame_ref = p->frame_out; vp8d_ref_frame(p->frame_ref); } vp8d_unref_frame(p, p->frame_out); p->frame_out = NULL; } FUN_T("FUN_OUT"); return 0; } static void vp8hwdResetProbs(VP8DParserContext_t *p) { RK_U32 i, j, k, l; static const RK_U32 Vp7DefaultScan[] = { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15, }; FUN_T("FUN_IN"); for ( i = 0 ; i < 16 ; ++i ) p->vp7ScanOrder[i] = Vp7DefaultScan[i]; /* Intra-prediction modes */ p->entropy.probLuma16x16PredMode[0] = 112; p->entropy.probLuma16x16PredMode[1] = 86; p->entropy.probLuma16x16PredMode[2] = 140; p->entropy.probLuma16x16PredMode[3] = 37; p->entropy.probChromaPredMode[0] = 162; p->entropy.probChromaPredMode[1] = 101; p->entropy.probChromaPredMode[2] = 204; for (i = 0; i < MAX_NBR_OF_MB_REF_LF_DELTAS; i++) p->mbRefLfDelta[i] = 0; for (i = 0; i < MAX_NBR_OF_MB_MODE_LF_DELTAS; i++) p->mbModeLfDelta[i] = 0; /* MV context */ k = 0; if (p->decMode == VP8HWD_VP8) { for ( i = 0 ; i < 2 ; ++i ) for ( j = 0 ; j < VP8_MV_PROBS_PER_COMPONENT ; ++j, ++k ) p->entropy.probMvContext[i][j] = Vp8DefaultMvProbs[i][j]; } else { for ( i = 0 ; i < 2 ; ++i ) for ( j = 0 ; j < VP7_MV_PROBS_PER_COMPONENT ; ++j, ++k ) p->entropy.probMvContext[i][j] = Vp7DefaultMvProbs[i][j]; } /* Coefficients */ for ( i = 0 ; i < 4 ; ++i ) for ( j = 0 ; j < 8 ; ++j ) for ( k = 0 ; k < 3 ; ++k ) for ( l = 0 ; l < 11 ; ++l ) p->entropy.probCoeffs[i][j][k][l] = DefaultCoeffProbs[i][j][k][l]; FUN_T("FUN_OUT"); } static void vp8hwdDecodeCoeffUpdate(VP8DParserContext_t *p) { RK_U32 i, j, k, l; FUN_T("FUN_IN"); for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 8; j++ ) { for ( k = 0; k < 3; k++ ) { for ( l = 0; l < 11; l++ ) { if (vp8hwdDecodeBool(&p->bitstr, CoeffUpdateProbs[i][j][k][l])) p->entropy.probCoeffs[i][j][k][l] = vp8hwdReadBits(&p->bitstr, 8); } } } } FUN_T("FUN_OUT"); } static MPP_RET vp8_header_parser(VP8DParserContext_t *p, RK_U8 *pbase, RK_U32 size) { RK_U32 tmp; int i, j; vpBoolCoder_t *bit_ctx = &p->bitstr; FUN_T("FUN_IN"); if (p->keyFrame) { tmp = (pbase[0] << 16) | (pbase[1] << 8) | (pbase[2] << 0); if (tmp != VP8_KEY_FRAME_START_CODE) return MPP_ERR_PROTOL; tmp = (pbase[3] << 0) | (pbase[4] << 8); p->width = tmp & 0x3fff; p->scaledWidth = ScaleDimension(p->width, tmp >> 14); tmp = (pbase[5] << 0) | (pbase[6] << 8); p->height = tmp & 0x3fff; p->scaledHeight = ScaleDimension(p->height, tmp >> 14); pbase += 7; size -= 7; } vp8hwdBoolStart(bit_ctx, pbase, size); if (p->keyFrame) { p->colorSpace = (vpColorSpace_e)vp8hwdDecodeBool128(bit_ctx); p->clamping = vp8hwdDecodeBool128(bit_ctx); } p->segmentationEnabled = vp8hwdDecodeBool128(bit_ctx); p->segmentationMapUpdate = 0; if (p->segmentationEnabled) { p->segmentationMapUpdate = vp8hwdDecodeBool128(bit_ctx); if (vp8hwdDecodeBool128(bit_ctx)) { /* Segmentation map update */ p->segmentFeatureMode = vp8hwdDecodeBool128(bit_ctx); memset(&p->segmentQp[0], 0, MAX_NBR_OF_SEGMENTS * sizeof(RK_S32)); memset(&p->segmentLoopfilter[0], 0, MAX_NBR_OF_SEGMENTS * sizeof(RK_S32)); for (i = 0; i < MAX_NBR_OF_SEGMENTS; i++) { if (vp8hwdDecodeBool128(bit_ctx)) { p->segmentQp[i] = vp8hwdReadBits(bit_ctx, 7); if (vp8hwdDecodeBool128(bit_ctx)) p->segmentQp[i] = -p->segmentQp[i]; } } for (i = 0; i < MAX_NBR_OF_SEGMENTS; i++) { if (vp8hwdDecodeBool128(bit_ctx)) { p->segmentLoopfilter[i] = vp8hwdReadBits(bit_ctx, 6); if (vp8hwdDecodeBool128(bit_ctx)) p->segmentLoopfilter[i] = -p->segmentLoopfilter[i]; } } } if (p->segmentationMapUpdate) { p->probSegment[0] = 255; p->probSegment[1] = 255; p->probSegment[2] = 255; for (i = 0; i < 3; i++) { if (vp8hwdDecodeBool128(bit_ctx)) { p->probSegment[i] = vp8hwdReadBits(bit_ctx, 8); } } } if (bit_ctx->strmError) { mpp_err_f("paser header stream no enough"); FUN_T("FUN_OUT"); return MPP_ERR_STREAM; } } p->loopFilterType = vp8hwdDecodeBool128(bit_ctx); p->loopFilterLevel = vp8hwdReadBits(bit_ctx, 6); p->loopFilterSharpness = vp8hwdReadBits(bit_ctx, 3); p->modeRefLfEnabled = vp8hwdDecodeBool128(bit_ctx); if (p->modeRefLfEnabled) { if (vp8hwdDecodeBool128(bit_ctx)) { for (i = 0; i < MAX_NBR_OF_MB_REF_LF_DELTAS; i++) { if (vp8hwdDecodeBool128(bit_ctx)) { p->mbRefLfDelta[i] = vp8hwdReadBits(bit_ctx, 6); if (vp8hwdDecodeBool128(bit_ctx)) p->mbRefLfDelta[i] = -p->mbRefLfDelta[i]; } } for (i = 0; i < MAX_NBR_OF_MB_MODE_LF_DELTAS; i++) { if (vp8hwdDecodeBool128(&p->bitstr)) { p->mbModeLfDelta[i] = vp8hwdReadBits(bit_ctx, 6); if (vp8hwdDecodeBool128(bit_ctx)) p->mbModeLfDelta[i] = -p->mbModeLfDelta[i]; } } } } if (bit_ctx->strmError) { mpp_err_f("paser header stream no enough"); FUN_T("FUN_OUT"); return MPP_ERR_STREAM; } p->nbrDctPartitions = vp8hwdReadBits(bit_ctx, 2); p->qpYAc = vp8hwdReadBits(bit_ctx, 7); p->qpYDc = DecodeQuantizerDelta(bit_ctx); p->qpY2Dc = DecodeQuantizerDelta(bit_ctx); p->qpY2Ac = DecodeQuantizerDelta(bit_ctx); p->qpChDc = DecodeQuantizerDelta(bit_ctx); p->qpChAc = DecodeQuantizerDelta(bit_ctx); if (p->keyFrame) { p->refreshGolden = 1; p->refreshAlternate = 1; p->copyBufferToGolden = 0; p->copyBufferToAlternate = 0; /* Refresh entropy probs */ p->refreshEntropyProbs = vp8hwdDecodeBool128(bit_ctx); p->refFrameSignBias[0] = 0; p->refFrameSignBias[1] = 0; p->refreshLast = 1; } else { /* Refresh golden */ p->refreshGolden = vp8hwdDecodeBool128(bit_ctx); /* Refresh alternate */ p->refreshAlternate = vp8hwdDecodeBool128(bit_ctx); if ( p->refreshGolden == 0 ) { /* Copy to golden */ p->copyBufferToGolden = vp8hwdReadBits(bit_ctx, 2); } else p->copyBufferToGolden = 0; if ( p->refreshAlternate == 0 ) { /* Copy to alternate */ p->copyBufferToAlternate = vp8hwdReadBits(bit_ctx, 2); } else p->copyBufferToAlternate = 0; /* Sign bias for golden frame */ p->refFrameSignBias[0] = vp8hwdDecodeBool128(bit_ctx); /* Sign bias for alternate frame */ p->refFrameSignBias[1] = vp8hwdDecodeBool128(bit_ctx); /* Refresh entropy probs */ p->refreshEntropyProbs = vp8hwdDecodeBool128(bit_ctx); /* Refresh last */ p->refreshLast = vp8hwdDecodeBool128(bit_ctx); } /* Make a "backup" of current entropy probabilities if refresh is not set */ if (p->refreshEntropyProbs == 0) { memcpy((void*)&p->entropyLast, (void*)&p->entropy, (unsigned long)sizeof(vp8EntropyProbs_t)); memcpy( (void*)p->vp7PrevScanOrder, (void*)p->vp7ScanOrder, (unsigned long)sizeof(p->vp7ScanOrder)); } vp8hwdDecodeCoeffUpdate(p); p->coeffSkipMode = vp8hwdDecodeBool128(bit_ctx); if (!p->keyFrame) { RK_U32 mvProbs; if (p->coeffSkipMode) p->probMbSkipFalse = vp8hwdReadBits(bit_ctx, 8); p->probIntra = vp8hwdReadBits(bit_ctx, 8); p->probRefLast = vp8hwdReadBits(bit_ctx, 8); p->probRefGolden = vp8hwdReadBits(bit_ctx, 8); if (vp8hwdDecodeBool128(bit_ctx)) { for (i = 0; i < 4; i++) p->entropy.probLuma16x16PredMode[i] = vp8hwdReadBits(bit_ctx, 8); } if (vp8hwdDecodeBool128(bit_ctx)) { for (i = 0; i < 3; i++) p->entropy.probChromaPredMode[i] = vp8hwdReadBits(bit_ctx, 8); } mvProbs = VP8_MV_PROBS_PER_COMPONENT; for ( i = 0 ; i < 2 ; ++i ) { for ( j = 0 ; j < (RK_S32)mvProbs ; ++j ) { if (vp8hwdDecodeBool(bit_ctx, MvUpdateProbs[i][j]) == 1) { tmp = vp8hwdReadBits(bit_ctx, 7); if ( tmp ) tmp = tmp << 1; else tmp = 1; p->entropy.probMvContext[i][j] = tmp; } } } } else { if (p->coeffSkipMode) p->probMbSkipFalse = vp8hwdReadBits(bit_ctx, 8); } if (bit_ctx->strmError) { mpp_err_f("paser header stream no enough"); FUN_T("FUN_OUT"); return MPP_ERR_STREAM; } FUN_T("FUN_OUT"); return MPP_OK; } static MPP_RET vp7_header_parser(VP8DParserContext_t *p, RK_U8 *pbase, RK_U32 size) { RK_U32 tmp; int i, j; FUN_T("FUN_IN"); vpBoolCoder_t *bit_ctx = &p->bitstr; vp8hwdBoolStart(bit_ctx, pbase, size); if (p->keyFrame) { p->width = vp8hwdReadBits(bit_ctx, 12); p->height = vp8hwdReadBits(bit_ctx, 12); tmp = vp8hwdReadBits(bit_ctx, 2); p->scaledWidth = ScaleDimension(p->width, tmp); tmp = vp8hwdReadBits(bit_ctx, 2); p->scaledHeight = ScaleDimension(p->height, tmp); } { const RK_U32 vp70FeatureBits[4] = { 7, 6, 0, 8 }; const RK_U32 vp71FeatureBits[4] = { 7, 6, 0, 5 }; const RK_U32 *featureBits; if (p->vpVersion == 0) featureBits = vp70FeatureBits; else featureBits = vp71FeatureBits; for (i = 0; i < MAX_NBR_OF_VP7_MB_FEATURES; i++) { if (vp8hwdDecodeBool128(bit_ctx)) { tmp = vp8hwdReadBits(bit_ctx, 8); for (j = 0; j < 3; j++) { if (vp8hwdDecodeBool128(bit_ctx)) tmp = vp8hwdReadBits(bit_ctx, 8); } if (featureBits[i]) { for (j = 0; j < 4; j++) { if (vp8hwdDecodeBool128(bit_ctx)) tmp = vp8hwdReadBits(bit_ctx, featureBits[i]); } } FUN_T("FUN_OUT"); return MPP_ERR_PROTOL; } } p->nbrDctPartitions = 0; } p->qpYAc = (RK_S32)vp8hwdReadBits(bit_ctx, 7 ); p->qpYDc = vp8hwdReadBits(bit_ctx, 1 ) ? (RK_S32)vp8hwdReadBits(bit_ctx, 7 ) : p->qpYAc; p->qpY2Dc = vp8hwdReadBits(bit_ctx, 1 ) ? (RK_S32)vp8hwdReadBits(bit_ctx, 7 ) : p->qpYAc; p->qpY2Ac = vp8hwdReadBits(bit_ctx, 1 ) ? (RK_S32)vp8hwdReadBits(bit_ctx, 7 ) : p->qpYAc; p->qpChDc = vp8hwdReadBits(bit_ctx, 1 ) ? (RK_S32)vp8hwdReadBits(bit_ctx, 7 ) : p->qpYAc; p->qpChAc = vp8hwdReadBits(bit_ctx, 1 ) ? (RK_S32)vp8hwdReadBits(bit_ctx, 7 ) : p->qpYAc; if (!p->keyFrame) { p->refreshGolden = vp8hwdDecodeBool128(bit_ctx); if (p->vpVersion >= 1) { p->refreshEntropyProbs = vp8hwdDecodeBool128(bit_ctx); p->refreshLast = vp8hwdDecodeBool128(bit_ctx); } else { p->refreshEntropyProbs = 1; p->refreshLast = 1; } } else { p->refreshGolden = 1; p->refreshAlternate = 1; p->copyBufferToGolden = 0; p->copyBufferToAlternate = 0; if (p->vpVersion >= 1) p->refreshEntropyProbs = vp8hwdDecodeBool128(bit_ctx); else p->refreshEntropyProbs = 1; p->refFrameSignBias[0] = 0; p->refFrameSignBias[1] = 0; p->refreshLast = 1; } if (!p->refreshEntropyProbs) { memcpy(&p->entropyLast, &p->entropy, (unsigned long)sizeof(vp8EntropyProbs_t)); memcpy(p->vp7PrevScanOrder, p->vp7ScanOrder, (unsigned long)sizeof(p->vp7ScanOrder)); } if (p->refreshLast) { if (vp8hwdDecodeBool128(bit_ctx)) { tmp = vp8hwdReadBits(bit_ctx, 8); tmp = vp8hwdReadBits(bit_ctx, 8); FUN_T("FUN_OUT"); return MPP_ERR_STREAM; } } if (p->vpVersion == 0) { p->loopFilterType = vp8hwdDecodeBool128(bit_ctx); } if (vp8hwdDecodeBool128(bit_ctx)) { static const RK_U32 Vp7DefaultScan[] = { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15, }; p->vp7ScanOrder[0] = 0; for (i = 1; i < 16; i++) p->vp7ScanOrder[i] = Vp7DefaultScan[vp8hwdReadBits(bit_ctx, 4)]; } if (p->vpVersion >= 1) p->loopFilterType = vp8hwdDecodeBool128(bit_ctx); p->loopFilterLevel = vp8hwdReadBits(bit_ctx, 6); p->loopFilterSharpness = vp8hwdReadBits(bit_ctx, 3); vp8hwdDecodeCoeffUpdate(p); if (!p->keyFrame) { p->probIntra = vp8hwdReadBits(bit_ctx, 8); p->probRefLast = vp8hwdReadBits(bit_ctx, 8); if (vp8hwdDecodeBool128(bit_ctx)) { for (i = 0; i < 4; i++) p->entropy.probLuma16x16PredMode[i] = vp8hwdReadBits(bit_ctx, 8); } if (vp8hwdDecodeBool128(bit_ctx)) { for (i = 0; i < 3; i++) p->entropy.probChromaPredMode[i] = vp8hwdReadBits(bit_ctx, 8); } for ( i = 0 ; i < 2 ; ++i ) { for ( j = 0 ; j < VP7_MV_PROBS_PER_COMPONENT ; ++j ) { if (vp8hwdDecodeBool(bit_ctx, MvUpdateProbs[i][j])) { tmp = vp8hwdReadBits(bit_ctx, 7); if ( tmp ) tmp = tmp << 1; else tmp = 1; p->entropy.probMvContext[i][j] = tmp; } } } } if (bit_ctx->strmError) { FUN_T("FUN_OUT"); return MPP_ERR_PROTOL; } FUN_T("FUN_OUT"); return MPP_OK; } static MPP_RET vp8hwdSetPartitionOffsets(VP8DParserContext_t *p, RK_U8 *stream, RK_U32 len) { RK_U32 i = 0; RK_U32 offset = 0; RK_U32 baseOffset; RK_U32 extraBytesPacked = 0; FUN_T("FUN_IN"); if (p->decMode == VP8HWD_VP8 && p->keyFrame) extraBytesPacked += 7; stream += p->frameTagSize; baseOffset = p->frameTagSize + p->offsetToDctParts + 3 * ( (1 << p->nbrDctPartitions) - 1); stream += p->offsetToDctParts + extraBytesPacked; for ( i = 0 ; i < (RK_U32)(1 << p->nbrDctPartitions) - 1 ; ++i ) { RK_U32 tmp; p->dctPartitionOffsets[i] = baseOffset + offset; tmp = stream[0] | (stream[1] << 8) | (stream[2] << 16); offset += tmp; stream += 3; } p->dctPartitionOffsets[i] = baseOffset + offset; return (p->dctPartitionOffsets[i] < len ? MPP_OK : MPP_ERR_STREAM); } static MPP_RET decoder_frame_header(VP8DParserContext_t *p, RK_U8 *pbase, RK_U32 size) { MPP_RET ret; FUN_T("FUN_IN"); p->keyFrame = !(pbase[0] & 1); p->vpVersion = (pbase[0] >> 1) & 7; p->showFrame = 1; if (p->keyFrame && !p->needKeyFrame) { p->needKeyFrame = 1; } else { if (!p->needKeyFrame) { mpp_err("no found key frame"); return MPP_NOK; } } if (p->decMode == VP8HWD_VP7) { p->offsetToDctParts = (pbase[0] >> 4) | (pbase[1] << 4) | (pbase[2] << 12); p->frameTagSize = p->vpVersion >= 1 ? 3 : 4; } else { p->offsetToDctParts = (pbase[0] >> 5) | (pbase[1] << 3) | (pbase[2] << 11); #if 0 mpp_log("offsetToDctParts %d pbase[0] = 0x%x pbase[1] = 0x%x pbase[2] = 0x%x ", p->offsetToDctParts, pbase[0], pbase[1], pbase[2]); #endif p->showFrame = (pbase[0] >> 4) & 1; p->frameTagSize = 3; } pbase += p->frameTagSize; size -= p->frameTagSize; if (p->keyFrame) vp8hwdResetProbs(p); //mpp_log_f("p->decMode = %d", p->decMode); if (p->decMode == VP8HWD_VP8) { ret = vp8_header_parser(p, pbase, size); } else { ret = vp7_header_parser(p, pbase, size); } if (ret != MPP_OK) { return ret; } return MPP_OK; } MPP_RET vp8d_parser_parse(void *ctx, HalDecTask *in_task) { MPP_RET ret = MPP_OK; VP8DContext *c = (VP8DContext *)ctx; VP8DParserContext_t *p = (VP8DParserContext_t *)c->parse_ctx; FUN_T("FUN_IN"); ret = decoder_frame_header(p, p->bitstream_sw_buf, p->stream_size); if (MPP_OK != ret) { mpp_err("decoder_frame_header err ret %d", ret); FUN_T("FUN_OUT"); return ret; } vp8hwdSetPartitionOffsets(p, p->bitstream_sw_buf, p->stream_size); ret = vp8d_alloc_frame(p); if (MPP_OK != ret) { mpp_err("vp8d_alloc_frame err ret %d", ret); FUN_T("FUN_OUT"); return ret; } vp8d_convert_to_syntx(p, in_task); /* Rollback entropy probabilities if refresh is not set */ if (p->refreshEntropyProbs == 0) { memcpy((void*)&p->entropy, (void*)&p->entropyLast, (unsigned long)sizeof(vp8EntropyProbs_t)); memcpy((void*)p->vp7ScanOrder, (void*)p->vp7PrevScanOrder, (unsigned long)sizeof(p->vp7ScanOrder)); } in_task->syntax.data = (void *)p->dxva_ctx; in_task->syntax.number = 1; in_task->output = p->frame_out->slot_index; in_task->valid = 1; if (p->eos) { in_task->flags.eos = p->eos; } vp8d_ref_update(p); FUN_T("FUN_OUT"); return ret; } MPP_RET vp8d_parser_callback(void *ctx, void *hal_info) { MPP_RET ret = MPP_OK; FUN_T("FUN_IN"); (void)ctx; (void)hal_info; FUN_T("FUN_OUT"); return ret; }