📄 h263dec.c
字号:
/* * H263 decoder * Copyright (c) 2001 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "avcodec.h"#include "dsputil.h"#include "mpegvideo.h"#if 1#define PRINT_QP(a, b) {}#else#define PRINT_QP(a, b) printf(a, b)#endif//#define DEBUG//#define PRINT_FRAME_TIME#ifdef PRINT_FRAME_TIMEstatic inline long long rdtsc(){ long long l; asm volatile( "rdtsc\n\t" : "=A" (l) );// printf("%d\n", int(l/1000)); return l;}#endifstatic int h263_decode_init(AVCodecContext *avctx){ MpegEncContext *s = avctx->priv_data; s->avctx = avctx; s->out_format = FMT_H263; s->width = avctx->width; s->height = avctx->height; s->workaround_bugs= avctx->workaround_bugs; // set defaults s->quant_precision=5; s->progressive_sequence=1; s->decode_mb= ff_h263_decode_mb; /* select sub codec */ switch(avctx->codec->id) { case CODEC_ID_H263: s->gob_number = 0; break; case CODEC_ID_MPEG4: s->time_increment_bits = 4; /* default value for broken headers */ s->h263_pred = 1; s->has_b_frames = 1; //default, might be overriden in the vol header during header parsing break; case CODEC_ID_MSMPEG4V1: s->h263_msmpeg4 = 1; s->h263_pred = 1; s->msmpeg4_version=1; break; case CODEC_ID_MSMPEG4V2: s->h263_msmpeg4 = 1; s->h263_pred = 1; s->msmpeg4_version=2; break; case CODEC_ID_MSMPEG4V3: s->h263_msmpeg4 = 1; s->h263_pred = 1; s->msmpeg4_version=3; break; case CODEC_ID_WMV1: s->h263_msmpeg4 = 1; s->h263_pred = 1; s->msmpeg4_version=4; break; case CODEC_ID_WMV2: s->h263_msmpeg4 = 1; s->h263_pred = 1; s->msmpeg4_version=5; break; case CODEC_ID_H263I: s->h263_intel = 1; break; default: return -1; } s->codec_id= avctx->codec->id; /* for h263, we allocate the images after having read the header */ if (avctx->codec->id != CODEC_ID_H263 && avctx->codec->id != CODEC_ID_MPEG4) if (MPV_common_init(s) < 0) return -1; if (s->h263_msmpeg4) ff_msmpeg4_decode_init(s); else h263_decode_init_vlc(s); return 0;}static int h263_decode_end(AVCodecContext *avctx){ MpegEncContext *s = avctx->priv_data; MPV_common_end(s); return 0;}/** * retunrs the number of bytes consumed for building the current frame */static int get_consumed_bytes(MpegEncContext *s, int buf_size){ int pos= (get_bits_count(&s->gb)+7)>>3; if(s->divx_version>=500){ //we would have to scan through the whole buf to handle the weird reordering ... return buf_size; }else if(s->flags&CODEC_FLAG_TRUNCATED){ pos -= s->parse_context.last_index; if(pos<0) pos=0; // padding is not really read so this might be -1 return pos; }else{ if(pos==0) pos=1; //avoid infinite loops (i doubt thats needed but ...) if(pos+10>buf_size) pos=buf_size; // oops ;) return pos; }}static int decode_slice(MpegEncContext *s){ s->last_resync_gb= s->gb; s->first_slice_line= 1; s->resync_mb_x= s->mb_x; s->resync_mb_y= s->mb_y; s->y_dc_scale= s->y_dc_scale_table[ s->qscale ]; s->c_dc_scale= s->c_dc_scale_table[ s->qscale ]; if(s->partitioned_frame){ const int qscale= s->qscale; if(s->codec_id==CODEC_ID_MPEG4){ if(ff_mpeg4_decode_partitions(s) < 0) return -1; } /* restore variables which where modified */ s->first_slice_line=1; s->mb_x= s->resync_mb_x; s->mb_y= s->resync_mb_y; s->qscale= qscale; s->y_dc_scale= s->y_dc_scale_table[ s->qscale ]; s->c_dc_scale= s->c_dc_scale_table[ s->qscale ]; } for(; s->mb_y < s->mb_height; s->mb_y++) { /* per-row end of slice checks */ if(s->msmpeg4_version){ if(s->resync_mb_y + s->slice_height == s->mb_y){ const int xy= s->mb_x + s->mb_y*s->mb_width; s->error_status_table[xy-1]|= AC_END|DC_END|MV_END; return 0; } } if(s->msmpeg4_version==1){ s->last_dc[0]= s->last_dc[1]= s->last_dc[2]= 128; } ff_init_block_index(s); for(; s->mb_x < s->mb_width; s->mb_x++) { int ret; ff_update_block_index(s); if(s->resync_mb_x == s->mb_x && s->resync_mb_y+1 == s->mb_y){ s->first_slice_line=0; } /* DCT & quantize */ s->dsp.clear_blocks(s->block[0]); s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_16X16;//printf("%d %d %06X\n", ret, get_bits_count(&s->gb), show_bits(&s->gb, 24)); ret= s->decode_mb(s, s->block); PRINT_QP("%2d", s->qscale); MPV_decode_mb(s, s->block); if(ret<0){ const int xy= s->mb_x + s->mb_y*s->mb_width; if(ret==SLICE_END){//printf("%d %d %d %06X\n", s->mb_x, s->mb_y, s->gb.size*8 - get_bits_count(&s->gb), show_bits(&s->gb, 24)); s->error_status_table[xy]|= AC_END; if(!s->partitioned_frame) s->error_status_table[xy]|= MV_END|DC_END; s->padding_bug_score--; if(++s->mb_x >= s->mb_width){ s->mb_x=0; ff_draw_horiz_band(s); s->mb_y++; } return 0; }else if(ret==SLICE_NOEND){ fprintf(stderr,"Slice mismatch at MB: %d\n", xy); return -1; } fprintf(stderr,"Error at MB: %d\n", xy); s->error_status_table[xy]|= AC_ERROR; if(!s->partitioned_frame) s->error_status_table[xy]|= DC_ERROR|MV_ERROR; return -1; } } ff_draw_horiz_band(s); PRINT_QP("%s", "\n"); s->mb_x= 0; } assert(s->mb_x==0 && s->mb_y==s->mb_height); /* try to detect the padding bug */ if( s->codec_id==CODEC_ID_MPEG4 && (s->workaround_bugs&FF_BUG_AUTODETECT) && s->gb.size*8 - get_bits_count(&s->gb) >=0 && s->gb.size*8 - get_bits_count(&s->gb) < 48 && !s->resync_marker && !s->data_partitioning){ const int bits_count= get_bits_count(&s->gb); const int bits_left = s->gb.size*8 - bits_count; if(bits_left==0 || bits_left>8){ s->padding_bug_score++; } else if(bits_left != 1){ int v= show_bits(&s->gb, 8); v|= 0x7F >> (7-(bits_count&7)); if(v==0x7F) s->padding_bug_score--; else s->padding_bug_score++; } if(s->padding_bug_score > -2) s->workaround_bugs |= FF_BUG_NO_PADDING; else s->workaround_bugs &= ~FF_BUG_NO_PADDING; } // handle formats which dont have unique end markers if(s->msmpeg4_version || (s->workaround_bugs&FF_BUG_NO_PADDING)){ //FIXME perhaps solve this more cleanly int left= s->gb.size*8 - get_bits_count(&s->gb); int max_extra=7; /* no markers in M$ crap */ if(s->msmpeg4_version && s->pict_type==I_TYPE) max_extra+= 17; /* buggy padding but the frame should still end approximately at the bitstream end */ if((s->workaround_bugs&FF_BUG_NO_PADDING) && s->error_resilience>=3) max_extra+= 48; else if((s->workaround_bugs&FF_BUG_NO_PADDING)) max_extra+= 256*256*256*64; if(left>max_extra){ fprintf(stderr, "discarding %d junk bits at end, next would be %X\n", left, show_bits(&s->gb, 24)); } else if(left<0){ fprintf(stderr, "overreading %d bits\n", -left); }else s->error_status_table[s->mb_num-1]|= AC_END|MV_END|DC_END; return 0; } fprintf(stderr, "slice end not reached but screenspace end (%d left %06X)\n", s->gb.size*8 - get_bits_count(&s->gb), show_bits(&s->gb, 24)); return -1;}/** * finds the end of the current frame in the bitstream. * @return the position of the first byte of the next frame, or -1 */static int mpeg4_find_frame_end(MpegEncContext *s, UINT8 *buf, int buf_size){ ParseContext *pc= &s->parse_context; int vop_found, i; uint32_t state; vop_found= pc->frame_start_found; state= pc->state; i=0; if(!vop_found){ for(i=0; i<buf_size; i++){ state= (state<<8) | buf[i]; if(state == 0x1B6){ i++; vop_found=1; break; } } } for(; i<buf_size; i++){ state= (state<<8) | buf[i]; if((state&0xFFFFFF00) == 0x100){ pc->frame_start_found=0; pc->state=-1; return i-3; } } pc->frame_start_found= vop_found; pc->state= state; return -1;}static int h263_decode_frame(AVCodecContext *avctx, void *data, int *data_size, UINT8 *buf, int buf_size){ MpegEncContext *s = avctx->priv_data; int ret,i; AVPicture *pict = data; float new_aspect; #ifdef PRINT_FRAME_TIMEuint64_t time= rdtsc();#endif#ifdef DEBUG printf("*****frame %d size=%d\n", avctx->frame_number, buf_size); printf("bytes=%x %x %x %x\n", buf[0], buf[1], buf[2], buf[3]);#endif s->hurry_up= avctx->hurry_up; s->error_resilience= avctx->error_resilience; s->flags= avctx->flags; *data_size = 0; /* no supplementary picture */ if (buf_size == 0) { return 0; } if(s->flags&CODEC_FLAG_TRUNCATED){ int next; ParseContext *pc= &s->parse_context; pc->last_index= pc->index; if(s->codec_id==CODEC_ID_MPEG4){ next= mpeg4_find_frame_end(s, buf, buf_size); }else{ fprintf(stderr, "this codec doesnt support truncated bitstreams\n"); return -1; } if(next==-1){ if(buf_size + FF_INPUT_BUFFER_PADDING_SIZE + pc->index > pc->buffer_size){ pc->buffer_size= buf_size + pc->index + 10*1024; pc->buffer= realloc(pc->buffer, pc->buffer_size); } memcpy(&pc->buffer[pc->index], buf, buf_size); pc->index += buf_size; return buf_size; } if(pc->index){ if(next + FF_INPUT_BUFFER_PADDING_SIZE + pc->index > pc->buffer_size){ pc->buffer_size= next + pc->index + 10*1024; pc->buffer= realloc(pc->buffer, pc->buffer_size); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -