Index: libavcodec/h264.c =================================================================== --- libavcodec/h264.c (revision 12665) +++ libavcodec/h264.c (working copy) @@ -3826,7 +3826,7 @@ /** * Replicates H264 "master" context to thread contexts. */ -static void clone_slice(H264Context *dst, H264Context *src) +static void clone_slice(H264Context *dst, H264Context *src, int full) { memcpy(dst->block_offset, src->block_offset, sizeof(dst->block_offset)); dst->s.current_picture_ptr = src->s.current_picture_ptr; @@ -3848,6 +3848,47 @@ memcpy(dst->dequant4_coeff, src->dequant4_coeff, sizeof(src->dequant4_coeff)); memcpy(dst->dequant8_coeff, src->dequant8_coeff, sizeof(src->dequant8_coeff)); + + if(!full) + return; + + dst->slice_type = src->slice_type; + + dst->mb_linesize = src->mb_linesize; + + dst->sps = src->sps; + dst->pps = src->pps; + + dst->mb_mbaff = src->mb_mbaff; + dst->mb_aff_frame = src->mb_aff_frame; + + dst->s.me.qpel_put = src->s.me.qpel_put; + dst->s.me.qpel_avg = src->s.me.qpel_avg; + + /* weighted motion pred */ + + dst->use_weight = src->use_weight; + if(dst->use_weight != 0) { + dst->use_weight_chroma = src->use_weight_chroma; + dst->luma_log2_weight_denom = src->luma_log2_weight_denom; + dst->chroma_log2_weight_denom = src->chroma_log2_weight_denom; + + memcpy(dst->luma_weight, src->luma_weight, sizeof(src->luma_weight)); + memcpy(dst->luma_offset, src->luma_offset, sizeof(src->luma_offset)); + memcpy(dst->chroma_weight, src->chroma_weight, sizeof(src->chroma_weight)); + memcpy(dst->chroma_offset, src->chroma_offset, sizeof(src->chroma_offset)); + + memcpy(dst->implicit_weight, src->implicit_weight, sizeof(src->implicit_weight)); + } + + + /* deblocking */ + + dst->deblocking_filter = src->deblocking_filter; + dst->slice_alpha_c0_offset = src->slice_alpha_c0_offset; + dst->slice_beta_offset = src->slice_beta_offset; + + } /** @@ -4057,7 +4098,7 @@ } } if(h != h0) - clone_slice(h, h0); + clone_slice(h, h0, 0); s->current_picture_ptr->frame_num= h->frame_num; //FIXME frame_num cleanup @@ -6921,6 +6962,182 @@ return -1; //not reached } +static void copy_context_to_mb(H264mb *dst, H264Context *src) +{ + dst->mb_x = src->s.mb_x; + dst->mb_y = src->s.mb_y; + dst->qscale = src->s.qscale; + dst->chroma_qp[0] = src->chroma_qp[0]; + dst->chroma_qp[1] = src->chroma_qp[1]; + dst->chroma_pred_mode = src->chroma_pred_mode; + dst->intra16x16_pred_mode = src->intra16x16_pred_mode; + dst->topleft_samples_available = src->topleft_samples_available; + dst->topright_samples_available = src->topright_samples_available; + + memcpy(dst->mb, src->mb, sizeof(src->mb)); + memcpy(dst->intra4x4_pred_mode_cache, src->intra4x4_pred_mode_cache, sizeof(src->intra4x4_pred_mode_cache)); + memcpy(dst->non_zero_count_cache, src->non_zero_count_cache, sizeof(src->non_zero_count_cache)); + + + if(src->slice_type != FF_I_TYPE && src->slice_type != FF_SI_TYPE) { + memcpy(dst->sub_mb_type, src->sub_mb_type, sizeof(src->sub_mb_type)); + memcpy(dst->mv_cache, src->mv_cache, sizeof(src->mv_cache)); + memcpy(dst->ref_cache, src->ref_cache, sizeof(src->ref_cache)); + } + + dst->top_mb_xy = src->top_mb_xy; + dst->left_mb_xy[0] = src->left_mb_xy[0]; + dst->left_mb_xy[1] = src->left_mb_xy[1]; + dst->cbp = src->cbp; + +} + +static void copy_mb_to_context(H264Context *dst, H264mb *src) +{ + dst->s.mb_x = src->mb_x; + dst->s.mb_y = src->mb_y; + dst->s.qscale = src->qscale; + dst->chroma_qp[0] = src->chroma_qp[0]; + dst->chroma_qp[1] = src->chroma_qp[1]; + dst->chroma_pred_mode = src->chroma_pred_mode; + dst->intra16x16_pred_mode = src->intra16x16_pred_mode; + dst->topleft_samples_available = src->topleft_samples_available; + dst->topright_samples_available = src->topright_samples_available; + + memcpy(dst->mb, src->mb, sizeof(src->mb)); + memcpy(dst->intra4x4_pred_mode_cache, src->intra4x4_pred_mode_cache, sizeof(src->intra4x4_pred_mode_cache)); + memcpy(dst->non_zero_count_cache, src->non_zero_count_cache, sizeof(src->non_zero_count_cache)); + + + if(dst->slice_type != FF_I_TYPE && dst->slice_type != FF_SI_TYPE) { + memcpy(dst->sub_mb_type, src->sub_mb_type, sizeof(src->sub_mb_type)); + memcpy(dst->mv_cache, src->mv_cache, sizeof(src->mv_cache)); + memcpy(dst->ref_cache, src->ref_cache, sizeof(src->ref_cache)); + } + + /* Needed for deblocking */ + + dst->top_mb_xy = src->top_mb_xy; + dst->left_mb_xy[0] = src->left_mb_xy[0]; + dst->left_mb_xy[1] = src->left_mb_xy[1]; + dst->cbp = src->cbp; + +} + + + + +#define MAXBLOCKS 128 + +static int decode_mb_parallelized(struct AVCodecContext *avctx, H264Context *h) +{ + H264Context *h0 = avctx->priv_data; + MpegEncContext * const s = &h->s; + const int part_mask= s->partitioned_frame ? (AC_END|AC_ERROR) : 0x7F; + int i, ret; + + if(h0 == h) { + /* first thread does entropy decode */ + + for(i = 0; i < MAXBLOCKS; i++) { + ret = decode_mb_cabac(h); + if(ret < 0 || h->cabac.bytestream > h->cabac.bytestream_end + 2) { + av_log(h->s.avctx, AV_LOG_ERROR, + "error while decoding MB %d %d, bytestream (%td)\n", + s->mb_x, s->mb_y, h->cabac.bytestream_end - h->cabac.bytestream); + ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, + (AC_ERROR|DC_ERROR|MV_ERROR)&part_mask); + return -1; + } + + copy_context_to_mb(h->blocks[h->phaze] + i, h); + if(++s->mb_x >= s->mb_width) { + s->mb_x = 0; + ++s->mb_y; + } + + if(get_cabac_terminate(&h->cabac) || s->mb_y >= s->mb_height) + return i + 1; + } + return 0; + + } else { + /* second thread does hl decode */ + + for(i = 0; i < h0->todecode; i++) { + copy_mb_to_context(h, h0->blocks[!h0->phaze] + i); + hl_decode_mb(h); + } + return 0; + } +} + + + + +static int decode_slice2(struct AVCodecContext *avctx, H264Context *h){ + MpegEncContext * const s = &h->s; + const int part_mask= s->partitioned_frame ? (AC_END|AC_ERROR) : 0x7F; + H264Context *h2 = h->thread_context[1]; + int i, rv[2]; + + clone_slice(h2, h, 1); + + if(!h->blocks[0]) { + h->blocks[0] = av_malloc(sizeof(H264mb) * MAXBLOCKS); + h->blocks[1] = av_malloc(sizeof(H264mb) * MAXBLOCKS); + } + + s->mb_skip_run= -1; + + /* realign */ + align_get_bits( &s->gb ); + + /* init cabac */ + ff_init_cabac_states( &h->cabac); + ff_init_cabac_decoder( &h->cabac, + s->gb.buffer + get_bits_count(&s->gb)/8, + ( s->gb.size_in_bits - get_bits_count(&s->gb) + 7)/8); + /* calculate pre-state */ + for( i= 0; i < 460; i++ ) { + int pre; + if( h->slice_type == FF_I_TYPE ) + pre = av_clip( ((cabac_context_init_I[i][0] * s->qscale) >>4 ) + cabac_context_init_I[i][1], 1, 126 ); + else + pre = av_clip( ((cabac_context_init_PB[h->cabac_init_idc][i][0] * s->qscale) >>4 ) + cabac_context_init_PB[h->cabac_init_idc][i][1], 1, 126 ); + + if( pre <= 63 ) + h->cabac_state[i] = 2 * ( 63 - pre ) + 0; + else + h->cabac_state[i] = 2 * ( pre - 64 ) + 1; + } + + h->todecode = 0; + + while(1) { + avctx->execute(avctx, (void *)decode_mb_parallelized, + (void **)h->thread_context, rv, 2); + + h->phaze = !h->phaze; + + if(rv[0] == -1) + return -1; + else if(rv[0] == 0) + h->todecode = MAXBLOCKS; + else + break; + } + + for(i = 0; i < rv[0]; i++) { + copy_mb_to_context(h2, h->blocks[!h->phaze] + i); + hl_decode_mb(h2); + } + + tprintf(s->avctx, "slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits); + ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x-1, s->mb_y, (AC_END|DC_END|MV_END)&part_mask); + return 0; +} + static int decode_unregistered_user_data(H264Context *h, int size){ MpegEncContext * const s = &h->s; uint8_t user_data[16+256]; @@ -7403,7 +7620,10 @@ int i; if(context_count == 1) { - decode_slice(avctx, h); + if(avctx->thread_count > 1 && h->pps.cabac) + decode_slice2(avctx, h); + else + decode_slice(avctx, h); } else { for(i = 1; i < context_count; i++) { hx = h->thread_context[i]; Index: libavcodec/h264.h =================================================================== --- libavcodec/h264.h (revision 12665) +++ libavcodec/h264.h (working copy) @@ -159,6 +159,35 @@ } MMCO; /** + * + */ + +typedef struct H264mb { + int mb_x, mb_y; + int qscale; + int chroma_qp[2]; //QPc + int chroma_pred_mode; + int intra16x16_pred_mode; + unsigned int topleft_samples_available; + unsigned int topright_samples_available; + int8_t intra4x4_pred_mode_cache[5*8]; + + uint8_t non_zero_count_cache[6*8]; + + int16_t mv_cache[2][5*8][2]; + int8_t ref_cache[2][5*8]; + + int cbp; + int top_mb_xy; + int left_mb_xy[2]; + + unsigned int sub_mb_type[4]; + + DCTELEM mb[16*24]; +} H264mb; + + +/** * H264Context */ typedef struct H264Context{ @@ -414,6 +443,12 @@ int last_slice_type; /** @} */ + /* experimental */ + + int phaze; + int todecode; + H264mb *blocks[2]; + }H264Context; #endif /* FFMPEG_H264_H */