mpegvideo.c
资源名称:tcpmp.rar [点击查看]
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:238k
源码类别:
Windows CE
开发平台:
C/C++
- }
- #endif
- #ifdef CONFIG_ENCODERS static int get_sae(uint8_t *src, int ref, int stride){ int x,y; int acc=0; for(y=0; y<16; y++){ for(x=0; x<16; x++){ acc+= ABS(src[x+y*stride] - ref); } } return acc; } static int get_intra_count(MpegEncContext *s, uint8_t *src, uint8_t *ref, int stride){ int x, y, w, h; int acc=0; w= s->width &~15; h= s->height&~15; for(y=0; y<h; y+=16){ for(x=0; x<w; x+=16){ int offset= x + y*stride; int sad = s->dsp.sad[0](NULL, src + offset, ref + offset, stride, 16); int mean= (s->dsp.pix_sum(src + offset, stride) + 128)>>8; int sae = get_sae(src + offset, mean, stride); acc+= sae + 500 < sad; } } return acc; } static int load_input_picture(MpegEncContext *s, AVFrame *pic_arg){ AVFrame *pic=NULL; int64_t pts; int i; const int encoding_delay= s->max_b_frames; int direct=1; if(pic_arg){ pts= pic_arg->pts; pic_arg->display_picture_number= s->input_picture_number++; if(pts != AV_NOPTS_VALUE){ if(s->user_specified_pts != AV_NOPTS_VALUE){ int64_t time= pts; int64_t last= s->user_specified_pts; if(time <= last){ av_log(s->avctx, AV_LOG_ERROR, "Error, Invalid timestamp=%Ld, last=%Ldn", pts, s->user_specified_pts); return -1; } } s->user_specified_pts= pts; }else{ if(s->user_specified_pts != AV_NOPTS_VALUE){ s->user_specified_pts= pts= s->user_specified_pts + 1; av_log(s->avctx, AV_LOG_INFO, "Warning: AVFrame.pts=? trying to guess (%Ld)n", pts); }else{ pts= pic_arg->display_picture_number; } } } if(pic_arg){ if(encoding_delay && !(s->flags&CODEC_FLAG_INPUT_PRESERVED)) direct=0; if(pic_arg->linesize[0] != s->linesize) direct=0; if(pic_arg->linesize[1] != s->uvlinesize) direct=0; if(pic_arg->linesize[2] != s->uvlinesize) direct=0; // av_log(AV_LOG_DEBUG, "%d %d %d %dn",pic_arg->linesize[0], pic_arg->linesize[1], s->linesize, s->uvlinesize); if(direct){ i= ff_find_unused_picture(s, 1); pic= (AVFrame*)&s->picture[i]; pic->reference= 3; for(i=0; i<4; i++){ pic->data[i]= pic_arg->data[i]; pic->linesize[i]= pic_arg->linesize[i]; } alloc_picture(s, (Picture*)pic, 1); }else{ int offset= 16; i= ff_find_unused_picture(s, 0); pic= (AVFrame*)&s->picture[i]; pic->reference= 3; alloc_picture(s, (Picture*)pic, 0); if( pic->data[0] + offset == pic_arg->data[0] && pic->data[1] + offset == pic_arg->data[1] && pic->data[2] + offset == pic_arg->data[2]){ // empty }else{ int h_chroma_shift, v_chroma_shift; avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift); for(i=0; i<3; i++){ int src_stride= pic_arg->linesize[i]; int dst_stride= i ? s->uvlinesize : s->linesize; int h_shift= i ? h_chroma_shift : 0; int v_shift= i ? v_chroma_shift : 0; int w= s->width >>h_shift; int h= s->height>>v_shift; uint8_t *src= pic_arg->data[i]; uint8_t *dst= pic->data[i] + offset; if(src_stride==dst_stride) memcpy(dst, src, src_stride*h); else{ while(h--){ memcpy(dst, src, w); dst += dst_stride; src += src_stride; } } } } } copy_picture_attributes(s, pic, pic_arg); pic->pts= pts; //we set this here to avoid modifiying pic_arg } /* shift buffer entries */ for(i=1; i<MAX_PICTURE_COUNT /*s->encoding_delay+1*/; i++) s->input_picture[i-1]= s->input_picture[i]; s->input_picture[encoding_delay]= (Picture*)pic; return 0; } static int skip_check(MpegEncContext *s, Picture *p, Picture *ref){ int x, y, plane; int score=0; int64_t score64=0; for(plane=0; plane<3; plane++){ const int stride= p->linesize[plane]; const int bw= plane ? 1 : 2; for(y=0; y<s->mb_height*bw; y++){ for(x=0; x<s->mb_width*bw; x++){ int v= s->dsp.frame_skip_cmp[1](s, p->data[plane] + 8*(x + y*stride), ref->data[plane] + 8*(x + y*stride), stride, 8); switch(s->avctx->frame_skip_exp){ case 0: score= FFMAX(score, v); break; case 1: score+= ABS(v);break; case 2: score+= v*v;break; case 3: score64+= ABS(v*v*(int64_t)v);break; case 4: score64+= v*v*(int64_t)(v*v);break; } } } } if(score) score64= score; if(score64 < s->avctx->frame_skip_threshold) return 1; if(score64 < ((s->avctx->frame_skip_factor * (int64_t)s->lambda)>>8)) return 1; return 0; } static void select_input_picture(MpegEncContext *s){ int i; for(i=1; i<MAX_PICTURE_COUNT; i++) s->reordered_input_picture[i-1]= s->reordered_input_picture[i]; s->reordered_input_picture[MAX_PICTURE_COUNT-1]= NULL; /* set next picture type & ordering */ if(s->reordered_input_picture[0]==NULL && s->input_picture[0]){ if(/*s->picture_in_gop_number >= s->gop_size ||*/ s->next_picture_ptr==NULL || s->intra_only){ s->reordered_input_picture[0]= s->input_picture[0]; s->reordered_input_picture[0]->pict_type= I_TYPE; s->reordered_input_picture[0]->coded_picture_number= s->coded_picture_number++; }else{ int b_frames; if(s->avctx->frame_skip_threshold || s->avctx->frame_skip_factor){ if(skip_check(s, s->input_picture[0], s->next_picture_ptr)){ //av_log(NULL, AV_LOG_DEBUG, "skip %p %Ldn", s->input_picture[0]->data[0], s->input_picture[0]->pts); if(s->input_picture[0]->type == FF_BUFFER_TYPE_SHARED){ for(i=0; i<4; i++) s->input_picture[0]->data[i]= NULL; s->input_picture[0]->type= 0; }else{ assert( s->input_picture[0]->type==FF_BUFFER_TYPE_USER || s->input_picture[0]->type==FF_BUFFER_TYPE_INTERNAL); s->avctx->release_buffer(s->avctx, (AVFrame*)s->input_picture[0]); } goto no_output_pic; } } if(s->flags&CODEC_FLAG_PASS2){ for(i=0; i<s->max_b_frames+1; i++){ int pict_num= s->input_picture[0]->display_picture_number + i; if(pict_num >= s->rc_context.num_entries) break; if(!s->input_picture[i]){ s->rc_context.entry[pict_num-1].new_pict_type = P_TYPE; break; } s->input_picture[i]->pict_type= s->rc_context.entry[pict_num].new_pict_type; } } if(s->avctx->b_frame_strategy==0){ b_frames= s->max_b_frames; while(b_frames && !s->input_picture[b_frames]) b_frames--; }else if(s->avctx->b_frame_strategy==1){ for(i=1; i<s->max_b_frames+1; i++){ if(s->input_picture[i] && s->input_picture[i]->b_frame_score==0){ s->input_picture[i]->b_frame_score= get_intra_count(s, s->input_picture[i ]->data[0], s->input_picture[i-1]->data[0], s->linesize) + 1; } } for(i=0; i<s->max_b_frames+1; i++){ if(s->input_picture[i]==NULL || s->input_picture[i]->b_frame_score - 1 > s->mb_num/40) break; } b_frames= FFMAX(0, i-1); /* reset scores */ for(i=0; i<b_frames+1; i++){ s->input_picture[i]->b_frame_score=0; } }else{ av_log(s->avctx, AV_LOG_ERROR, "illegal b frame strategyn"); b_frames=0; } emms_c(); //static int b_count=0; //b_count+= b_frames; //av_log(s->avctx, AV_LOG_DEBUG, "b_frames: %dn", b_count); for(i= b_frames - 1; i>=0; i--){ int type= s->input_picture[i]->pict_type; if(type && type != B_TYPE) b_frames= i; } if(s->input_picture[b_frames]->pict_type == B_TYPE && b_frames == s->max_b_frames){ av_log(s->avctx, AV_LOG_ERROR, "warning, too many b frames in a rown"); } if(s->picture_in_gop_number + b_frames >= s->gop_size){ if((s->flags2 & CODEC_FLAG2_STRICT_GOP) && s->gop_size > s->picture_in_gop_number){ b_frames= s->gop_size - s->picture_in_gop_number - 1; }else{ if(s->flags & CODEC_FLAG_CLOSED_GOP) b_frames=0; s->input_picture[b_frames]->pict_type= I_TYPE; } } if( (s->flags & CODEC_FLAG_CLOSED_GOP) && b_frames && s->input_picture[b_frames]->pict_type== I_TYPE) b_frames--; s->reordered_input_picture[0]= s->input_picture[b_frames]; if(s->reordered_input_picture[0]->pict_type != I_TYPE) s->reordered_input_picture[0]->pict_type= P_TYPE; s->reordered_input_picture[0]->coded_picture_number= s->coded_picture_number++; for(i=0; i<b_frames; i++){ s->reordered_input_picture[i+1]= s->input_picture[i]; s->reordered_input_picture[i+1]->pict_type= B_TYPE; s->reordered_input_picture[i+1]->coded_picture_number= s->coded_picture_number++; } } } no_output_pic: if(s->reordered_input_picture[0]){ s->reordered_input_picture[0]->reference= s->reordered_input_picture[0]->pict_type!=B_TYPE ? 3 : 0; copy_picture(&s->new_picture, s->reordered_input_picture[0]); if(s->reordered_input_picture[0]->type == FF_BUFFER_TYPE_SHARED){ // input is a shared pix, so we can't modifiy it -> alloc a new one & ensure that the shared one is reuseable int i= ff_find_unused_picture(s, 0); Picture *pic= &s->picture[i]; /* mark us unused / free shared pic */ for(i=0; i<4; i++) s->reordered_input_picture[0]->data[i]= NULL; s->reordered_input_picture[0]->type= 0; pic->reference = s->reordered_input_picture[0]->reference; alloc_picture(s, pic, 0); copy_picture_attributes(s, (AVFrame*)pic, (AVFrame*)s->reordered_input_picture[0]); s->current_picture_ptr= pic; }else{ // input is not a shared pix -> reuse buffer for current_pix assert( s->reordered_input_picture[0]->type==FF_BUFFER_TYPE_USER || s->reordered_input_picture[0]->type==FF_BUFFER_TYPE_INTERNAL); s->current_picture_ptr= s->reordered_input_picture[0]; for(i=0; i<4; i++){ s->new_picture.data[i]+=16; } } copy_picture(&s->current_picture, s->current_picture_ptr); s->picture_number= s->new_picture.display_picture_number; //printf("dpn:%dn", s->picture_number); }else{ memset(&s->new_picture, 0, sizeof(Picture)); } } int MPV_encode_picture(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data) { MpegEncContext *s = avctx->priv_data; AVFrame *pic_arg = data; int i, stuffing_count; if(avctx->pix_fmt != PIX_FMT_YUV420P && avctx->pix_fmt != PIX_FMT_YUVJ420P){ av_log(avctx, AV_LOG_ERROR, "this codec supports only YUV420Pn"); return -1; } for(i=0; i<avctx->thread_count; i++){ int start_y= s->thread_context[i]->start_mb_y; int end_y= s->thread_context[i]-> end_mb_y; int h= s->mb_height; uint8_t *start= buf + (size_t)(((int64_t) buf_size)*start_y/h); uint8_t *end = buf + (size_t)(((int64_t) buf_size)* end_y/h); init_put_bits(&s->thread_context[i]->pb, start, end - start); } s->picture_in_gop_number++; if(load_input_picture(s, pic_arg) < 0) return -1; select_input_picture(s); /* output? */ if(s->new_picture.data[0]){ s->pict_type= s->new_picture.pict_type; //emms_c(); //printf("qs:%f %f %dn", s->new_picture.quality, s->current_picture.quality, s->qscale); MPV_frame_start(s, avctx); encode_picture(s, s->picture_number); avctx->real_pict_num = s->picture_number; avctx->header_bits = s->header_bits; avctx->mv_bits = s->mv_bits; avctx->misc_bits = s->misc_bits; avctx->i_tex_bits = s->i_tex_bits; avctx->p_tex_bits = s->p_tex_bits; avctx->i_count = s->i_count; avctx->p_count = s->mb_num - s->i_count - s->skip_count; //FIXME f/b_count in avctx avctx->skip_count = s->skip_count; MPV_frame_end(s); if (s->out_format == FMT_MJPEG) mjpeg_picture_trailer(s); if(s->flags&CODEC_FLAG_PASS1) ff_write_pass1_stats(s); for(i=0; i<4; i++){ avctx->error[i] += s->current_picture_ptr->error[i]; } if(s->flags&CODEC_FLAG_PASS1) assert(avctx->header_bits + avctx->mv_bits + avctx->misc_bits + avctx->i_tex_bits + avctx->p_tex_bits == put_bits_count(&s->pb)); flush_put_bits(&s->pb); s->frame_bits = put_bits_count(&s->pb); stuffing_count= ff_vbv_update(s, s->frame_bits); if(stuffing_count){ if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < stuffing_count + 50){ av_log(s->avctx, AV_LOG_ERROR, "stuffing too largen"); return -1; } switch(s->codec_id){ case CODEC_ID_MPEG1VIDEO: case CODEC_ID_MPEG2VIDEO: while(stuffing_count--){ put_bits(&s->pb, 8, 0); } break; case CODEC_ID_MPEG4: put_bits(&s->pb, 16, 0); put_bits(&s->pb, 16, 0x1C3); stuffing_count -= 4; while(stuffing_count--){ put_bits(&s->pb, 8, 0xFF); } break; default: av_log(s->avctx, AV_LOG_ERROR, "vbv buffer overflown"); } flush_put_bits(&s->pb); s->frame_bits = put_bits_count(&s->pb); } /* update mpeg1/2 vbv_delay for CBR */ if(s->avctx->rc_max_rate && s->avctx->rc_min_rate == s->avctx->rc_max_rate && s->out_format == FMT_MPEG1 && 90000LL * (avctx->rc_buffer_size-1) <= s->avctx->rc_max_rate*0xFFFFLL){ int vbv_delay; assert(s->repeat_first_field==0); vbv_delay= lrintf(90000 * s->rc_context.buffer_index / s->avctx->rc_max_rate); assert(vbv_delay < 0xFFFF); s->vbv_delay_ptr[0] &= 0xF8; s->vbv_delay_ptr[0] |= vbv_delay>>13; s->vbv_delay_ptr[1] = vbv_delay>>5; s->vbv_delay_ptr[2] &= 0x07; s->vbv_delay_ptr[2] |= vbv_delay<<3; } s->total_bits += s->frame_bits; avctx->frame_bits = s->frame_bits; }else{ assert((pbBufPtr(&s->pb) == s->pb.buf)); s->frame_bits=0; } assert((s->frame_bits&7)==0); return s->frame_bits/8; } #endif //CONFIG_ENCODERS static inline void gmc1_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t **ref_picture) { uint8_t *ptr; int offset, src_x, src_y, linesize, uvlinesize; int motion_x, motion_y; int emu=0; motion_x= s->sprite_offset[0][0]; motion_y= s->sprite_offset[0][1]; src_x = s->mb_x * 16 + (motion_x >> (s->sprite_warping_accuracy+1)); src_y = s->mb_y * 16 + (motion_y >> (s->sprite_warping_accuracy+1)); motion_x<<=(3-s->sprite_warping_accuracy); motion_y<<=(3-s->sprite_warping_accuracy); src_x = clip(src_x, -16, s->width); if (src_x == s->width) motion_x =0; src_y = clip(src_y, -16, s->height); if (src_y == s->height) motion_y =0; linesize = s->linesize; uvlinesize = s->uvlinesize; ptr = ref_picture[0] + (src_y * linesize) + src_x; if(s->flags&CODEC_FLAG_EMU_EDGE){ if( (unsigned)src_x >= s->h_edge_pos - 17 || (unsigned)src_y >= s->v_edge_pos - 17){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, linesize, 17, 17, src_x, src_y, s->h_edge_pos, s->v_edge_pos); ptr= s->edge_emu_buffer; } } if((motion_x|motion_y)&7){ s->dsp.gmc1(dest_y , ptr , linesize, 16, motion_x&15, motion_y&15, 128 - s->no_rounding); s->dsp.gmc1(dest_y+8, ptr+8, linesize, 16, motion_x&15, motion_y&15, 128 - s->no_rounding); }else{ int dxy; dxy= ((motion_x>>3)&1) | ((motion_y>>2)&2); if (s->no_rounding){ s->dsp.put_no_rnd_pixels_tab[0][dxy](dest_y, ptr, linesize, 16); }else{ s->dsp.put_pixels_tab [0][dxy](dest_y, ptr, linesize, 16); } } if(s->flags&CODEC_FLAG_GRAY) return; motion_x= s->sprite_offset[1][0]; motion_y= s->sprite_offset[1][1]; src_x = s->mb_x * 8 + (motion_x >> (s->sprite_warping_accuracy+1)); src_y = s->mb_y * 8 + (motion_y >> (s->sprite_warping_accuracy+1)); motion_x<<=(3-s->sprite_warping_accuracy); motion_y<<=(3-s->sprite_warping_accuracy); src_x = clip(src_x, -8, s->width>>1); if (src_x == s->width>>1) motion_x =0; src_y = clip(src_y, -8, s->height>>1); if (src_y == s->height>>1) motion_y =0; offset = (src_y * uvlinesize) + src_x; ptr = ref_picture[1] + offset; if(s->flags&CODEC_FLAG_EMU_EDGE){ if( (unsigned)src_x >= (s->h_edge_pos>>1) - 9 || (unsigned)src_y >= (s->v_edge_pos>>1) - 9){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, uvlinesize, 9, 9, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1); ptr= s->edge_emu_buffer; emu=1; } } s->dsp.gmc1(dest_cb, ptr, uvlinesize, 8, motion_x&15, motion_y&15, 128 - s->no_rounding); ptr = ref_picture[2] + offset; if(emu){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, uvlinesize, 9, 9, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1); ptr= s->edge_emu_buffer; } s->dsp.gmc1(dest_cr, ptr, uvlinesize, 8, motion_x&15, motion_y&15, 128 - s->no_rounding); return; } static inline void gmc_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t **ref_picture) { uint8_t *ptr; int linesize, uvlinesize; const int a= s->sprite_warping_accuracy; int ox, oy; linesize = s->linesize; uvlinesize = s->uvlinesize; ptr = ref_picture[0]; ox= s->sprite_offset[0][0] + s->sprite_delta[0][0]*s->mb_x*16 + s->sprite_delta[0][1]*s->mb_y*16; oy= s->sprite_offset[0][1] + s->sprite_delta[1][0]*s->mb_x*16 + s->sprite_delta[1][1]*s->mb_y*16; s->dsp.gmc(dest_y, ptr, linesize, 16, ox, oy, s->sprite_delta[0][0], s->sprite_delta[0][1], s->sprite_delta[1][0], s->sprite_delta[1][1], a+1, (1<<(2*a+1)) - s->no_rounding, s->h_edge_pos, s->v_edge_pos); s->dsp.gmc(dest_y+8, ptr, linesize, 16, ox + s->sprite_delta[0][0]*8, oy + s->sprite_delta[1][0]*8, s->sprite_delta[0][0], s->sprite_delta[0][1], s->sprite_delta[1][0], s->sprite_delta[1][1], a+1, (1<<(2*a+1)) - s->no_rounding, s->h_edge_pos, s->v_edge_pos); if(s->flags&CODEC_FLAG_GRAY) return; ox= s->sprite_offset[1][0] + s->sprite_delta[0][0]*s->mb_x*8 + s->sprite_delta[0][1]*s->mb_y*8; oy= s->sprite_offset[1][1] + s->sprite_delta[1][0]*s->mb_x*8 + s->sprite_delta[1][1]*s->mb_y*8; ptr = ref_picture[1]; s->dsp.gmc(dest_cb, ptr, uvlinesize, 8, ox, oy, s->sprite_delta[0][0], s->sprite_delta[0][1], s->sprite_delta[1][0], s->sprite_delta[1][1], a+1, (1<<(2*a+1)) - s->no_rounding, s->h_edge_pos>>1, s->v_edge_pos>>1); ptr = ref_picture[2]; s->dsp.gmc(dest_cr, ptr, uvlinesize, 8, ox, oy, s->sprite_delta[0][0], s->sprite_delta[0][1], s->sprite_delta[1][0], s->sprite_delta[1][1], a+1, (1<<(2*a+1)) - s->no_rounding, s->h_edge_pos>>1, s->v_edge_pos>>1); } /** * Copies a rectangular area of samples to a temporary buffer and replicates the boarder samples. * @param buf destination buffer * @param src source buffer * @param linesize number of bytes between 2 vertically adjacent samples in both the source and destination buffers * @param block_w width of block * @param block_h height of block * @param src_x x coordinate of the top left sample of the block in the source buffer * @param src_y y coordinate of the top left sample of the block in the source buffer * @param w width of the source buffer * @param h height of the source buffer */ void ff_emulated_edge_mc(uint8_t *buf, uint8_t *src, int linesize, int block_w, int block_h, int src_x, int src_y, int w, int h){ int x, y; int start_y, start_x, end_y, end_x; if(src_y>= h){ src+= (h-1-src_y)*linesize; src_y=h-1; }else if(src_y<=-block_h){ src+= (1-block_h-src_y)*linesize; src_y=1-block_h; } if(src_x>= w){ src+= (w-1-src_x); src_x=w-1; }else if(src_x<=-block_w){ src+= (1-block_w-src_x); src_x=1-block_w; } start_y= FFMAX(0, -src_y); start_x= FFMAX(0, -src_x); end_y= FFMIN(block_h, h-src_y); end_x= FFMIN(block_w, w-src_x); // copy existing part for(y=start_y; y<end_y; y++){ for(x=start_x; x<end_x; x++){ buf[x + y*linesize]= src[x + y*linesize]; } } //top for(y=0; y<start_y; y++){ for(x=start_x; x<end_x; x++){ buf[x + y*linesize]= buf[x + start_y*linesize]; } } //bottom for(y=end_y; y<block_h; y++){ for(x=start_x; x<end_x; x++){ buf[x + y*linesize]= buf[x + (end_y-1)*linesize]; } } for(y=0; y<block_h; y++){ //left for(x=0; x<start_x; x++){ buf[x + y*linesize]= buf[start_x + y*linesize]; } //right for(x=end_x; x<block_w; x++){ buf[x + y*linesize]= buf[end_x - 1 + y*linesize]; } } } static inline int hpel_motion(MpegEncContext *s, uint8_t *dest, uint8_t *src, int field_based, int field_select, int src_x, int src_y, int width, int height, int stride, int h_edge_pos, int v_edge_pos, int w, int h, op_pixels_func *pix_op, int motion_x, int motion_y) { int dxy; int emu=0; dxy = ((motion_y & 1) << 1) | (motion_x & 1); src_x += motion_x >> 1; src_y += motion_y >> 1; /* WARNING: do no forget half pels */ src_x = clip(src_x, -16, width); //FIXME unneeded for emu? if (src_x == width) dxy &= ~1; src_y = clip(src_y, -16, height); if (src_y == height) dxy &= ~2; src += src_y * stride + src_x; if(s->unrestricted_mv && (s->flags&CODEC_FLAG_EMU_EDGE)){ if( (unsigned)src_x > h_edge_pos - (motion_x&1) - w || (unsigned)src_y > v_edge_pos - (motion_y&1) - h){ ff_emulated_edge_mc(s->edge_emu_buffer, src, s->linesize, w+1, (h+1)<<field_based, src_x, src_y<<field_based, h_edge_pos, s->v_edge_pos); src= s->edge_emu_buffer; emu=1; } } if(field_select) src += s->linesize; pix_op[dxy](dest, src, stride, h); return emu; } static inline int hpel_motion_lowres(MpegEncContext *s, uint8_t *dest, uint8_t *src, int field_based, int field_select, int src_x, int src_y, int width, int height, int stride, int h_edge_pos, int v_edge_pos, int w, int h, h264_chroma_mc_func *pix_op, int motion_x, int motion_y) { const int lowres= s->avctx->lowres; const int s_mask= (2<<lowres)-1; int emu=0; int sx, sy; if(s->quarter_sample){ motion_x/=2; motion_y/=2; } sx= motion_x & s_mask; sy= motion_y & s_mask; src_x += motion_x >> (lowres+1); src_y += motion_y >> (lowres+1); src += src_y * stride + src_x; if( (unsigned)src_x > h_edge_pos - (!!sx) - w || (unsigned)src_y >(v_edge_pos >> field_based) - (!!sy) - h){ ff_emulated_edge_mc(s->edge_emu_buffer, src, s->linesize, w+1, (h+1)<<field_based, src_x, src_y<<field_based, h_edge_pos, v_edge_pos); src= s->edge_emu_buffer; emu=1; } sx <<= 2 - lowres; sy <<= 2 - lowres; if(field_select) src += s->linesize; pix_op[lowres](dest, src, stride, h, sx, sy); return emu; } /* apply one mpeg motion vector to the three components */ static always_inline void mpeg_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int field_based, int bottom_field, int field_select, uint8_t **ref_picture, op_pixels_func (*pix_op)[4], int motion_x, int motion_y, int h) { uint8_t *ptr_y, *ptr_cb, *ptr_cr; int dxy, uvdxy, mx, my, src_x, src_y, uvsrc_x, uvsrc_y, v_edge_pos, uvlinesize, linesize; #if 0 if(s->quarter_sample) { motion_x>>=1; motion_y>>=1; } #endif v_edge_pos = s->v_edge_pos >> field_based; linesize = s->current_picture.linesize[0] << field_based; uvlinesize = s->current_picture.linesize[1] << field_based; dxy = ((motion_y & 1) << 1) | (motion_x & 1); src_x = s->mb_x* 16 + (motion_x >> 1); src_y =(s->mb_y<<(4-field_based)) + (motion_y >> 1); if (s->out_format == FMT_H263) { if((s->workaround_bugs & FF_BUG_HPEL_CHROMA) && field_based){ mx = (motion_x>>1)|(motion_x&1); my = motion_y >>1; uvdxy = ((my & 1) << 1) | (mx & 1); uvsrc_x = s->mb_x* 8 + (mx >> 1); uvsrc_y = (s->mb_y<<(3-field_based)) + (my >> 1); }else{ uvdxy = dxy | (motion_y & 2) | ((motion_x & 2) >> 1); uvsrc_x = src_x>>1; uvsrc_y = src_y>>1; } }else if(s->out_format == FMT_H261){//even chroma mv's are full pel in H261 mx = motion_x / 4; my = motion_y / 4; uvdxy = 0; uvsrc_x = s->mb_x*8 + mx; uvsrc_y = s->mb_y*8 + my; } else { if(s->chroma_y_shift){ mx = motion_x / 2; my = motion_y / 2; uvdxy = ((my & 1) << 1) | (mx & 1); uvsrc_x = s->mb_x* 8 + (mx >> 1); uvsrc_y = (s->mb_y<<(3-field_based)) + (my >> 1); } else { if(s->chroma_x_shift){ //Chroma422 mx = motion_x / 2; uvdxy = ((motion_y & 1) << 1) | (mx & 1); uvsrc_x = s->mb_x* 8 + (mx >> 1); uvsrc_y = src_y; } else { //Chroma444 uvdxy = dxy; uvsrc_x = src_x; uvsrc_y = src_y; } } } ptr_y = ref_picture[0] + src_y * linesize + src_x; ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x; ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x; if( (unsigned)src_x > s->h_edge_pos - (motion_x&1) - 16 || (unsigned)src_y > v_edge_pos - (motion_y&1) - h){ if(s->codec_id == CODEC_ID_MPEG2VIDEO || s->codec_id == CODEC_ID_MPEG1VIDEO){ av_log(s->avctx,AV_LOG_DEBUG,"MPEG motion vector out of boundaryn"); return ; } ff_emulated_edge_mc(s->edge_emu_buffer, ptr_y, s->linesize, 17, 17+field_based, src_x, src_y<<field_based, s->h_edge_pos, s->v_edge_pos); ptr_y = s->edge_emu_buffer; if(!(s->flags&CODEC_FLAG_GRAY)){ uint8_t *uvbuf= s->edge_emu_buffer+18*s->linesize; ff_emulated_edge_mc(uvbuf , ptr_cb, s->uvlinesize, 9, 9+field_based, uvsrc_x, uvsrc_y<<field_based, s->h_edge_pos>>1, s->v_edge_pos>>1); ff_emulated_edge_mc(uvbuf+16, ptr_cr, s->uvlinesize, 9, 9+field_based, uvsrc_x, uvsrc_y<<field_based, s->h_edge_pos>>1, s->v_edge_pos>>1); ptr_cb= uvbuf; ptr_cr= uvbuf+16; } } if(bottom_field){ //FIXME use this for field pix too instead of the obnoxious hack which changes picture.data dest_y += s->linesize; dest_cb+= s->uvlinesize; dest_cr+= s->uvlinesize; } if(field_select){ ptr_y += s->linesize; ptr_cb+= s->uvlinesize; ptr_cr+= s->uvlinesize; } pix_op[0][dxy](dest_y, ptr_y, linesize, h); if(!(s->flags&CODEC_FLAG_GRAY)){ pix_op[s->chroma_x_shift][uvdxy](dest_cb, ptr_cb, uvlinesize, h >> s->chroma_y_shift); pix_op[s->chroma_x_shift][uvdxy](dest_cr, ptr_cr, uvlinesize, h >> s->chroma_y_shift); } #if defined(CONFIG_H261_ENCODER) || defined(CONFIG_H261_DECODER) if(s->out_format == FMT_H261){ ff_h261_loop_filter(s); } #endif } /* apply one mpeg motion vector to the three components */ static always_inline void mpeg_motion_lowres(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int field_based, int bottom_field, int field_select, uint8_t **ref_picture, h264_chroma_mc_func *pix_op, int motion_x, int motion_y, int h) { uint8_t *ptr_y, *ptr_cb, *ptr_cr; int mx, my, src_x, src_y, uvsrc_x, uvsrc_y, uvlinesize, linesize, sx, sy, uvsx, uvsy; const int lowres= s->avctx->lowres; const int block_s= 8>>lowres; const int s_mask= (2<<lowres)-1; const int h_edge_pos = s->h_edge_pos >> lowres; const int v_edge_pos = s->v_edge_pos >> lowres; linesize = s->current_picture.linesize[0] << field_based; uvlinesize = s->current_picture.linesize[1] << field_based; if(s->quarter_sample){ //FIXME obviously not perfect but qpel wont work in lowres anyway motion_x/=2; motion_y/=2; } if(field_based){ motion_y += (bottom_field - field_select)*((1<<lowres)-1); } sx= motion_x & s_mask; sy= motion_y & s_mask; src_x = s->mb_x*2*block_s + (motion_x >> (lowres+1)); src_y =(s->mb_y*2*block_s>>field_based) + (motion_y >> (lowres+1)); if (s->out_format == FMT_H263) { uvsx = ((motion_x>>1) & s_mask) | (sx&1); uvsy = ((motion_y>>1) & s_mask) | (sy&1); uvsrc_x = src_x>>1; uvsrc_y = src_y>>1; }else if(s->out_format == FMT_H261){//even chroma mv's are full pel in H261 mx = motion_x / 4; my = motion_y / 4; uvsx = (2*mx) & s_mask; uvsy = (2*my) & s_mask; uvsrc_x = s->mb_x*block_s + (mx >> lowres); uvsrc_y = s->mb_y*block_s + (my >> lowres); } else { mx = motion_x / 2; my = motion_y / 2; uvsx = mx & s_mask; uvsy = my & s_mask; uvsrc_x = s->mb_x*block_s + (mx >> (lowres+1)); uvsrc_y =(s->mb_y*block_s>>field_based) + (my >> (lowres+1)); } ptr_y = ref_picture[0] + src_y * linesize + src_x; ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x; ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x; if( (unsigned)src_x > h_edge_pos - (!!sx) - 2*block_s || (unsigned)src_y >(v_edge_pos >> field_based) - (!!sy) - h){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr_y, s->linesize, 17, 17+field_based, src_x, src_y<<field_based, h_edge_pos, v_edge_pos); ptr_y = s->edge_emu_buffer; if(!(s->flags&CODEC_FLAG_GRAY)){ uint8_t *uvbuf= s->edge_emu_buffer+18*s->linesize; ff_emulated_edge_mc(uvbuf , ptr_cb, s->uvlinesize, 9, 9+field_based, uvsrc_x, uvsrc_y<<field_based, h_edge_pos>>1, v_edge_pos>>1); ff_emulated_edge_mc(uvbuf+16, ptr_cr, s->uvlinesize, 9, 9+field_based, uvsrc_x, uvsrc_y<<field_based, h_edge_pos>>1, v_edge_pos>>1); ptr_cb= uvbuf; ptr_cr= uvbuf+16; } } if(bottom_field){ //FIXME use this for field pix too instead of the obnoxious hack which changes picture.data dest_y += s->linesize; dest_cb+= s->uvlinesize; dest_cr+= s->uvlinesize; } if(field_select){ ptr_y += s->linesize; ptr_cb+= s->uvlinesize; ptr_cr+= s->uvlinesize; } sx <<= 2 - lowres; sy <<= 2 - lowres; pix_op[lowres-1](dest_y, ptr_y, linesize, h, sx, sy); if(!(s->flags&CODEC_FLAG_GRAY)){ uvsx <<= 2 - lowres; uvsy <<= 2 - lowres; pix_op[lowres](dest_cb, ptr_cb, uvlinesize, h >> s->chroma_y_shift, uvsx, uvsy); pix_op[lowres](dest_cr, ptr_cr, uvlinesize, h >> s->chroma_y_shift, uvsx, uvsy); } //FIXME h261 lowres loop filter } //FIXME move to dsputil, avg variant, 16x16 version static inline void put_obmc(uint8_t *dst, uint8_t *src[5], int stride){ int x; uint8_t * const top = src[1]; uint8_t * const left = src[2]; uint8_t * const mid = src[0]; uint8_t * const right = src[3]; uint8_t * const bottom= src[4]; #define OBMC_FILTER(x, t, l, m, r, b) dst[x]= (t*top[x] + l*left[x] + m*mid[x] + r*right[x] + b*bottom[x] + 4)>>3 #define OBMC_FILTER4(x, t, l, m, r, b) OBMC_FILTER(x , t, l, m, r, b); OBMC_FILTER(x+1 , t, l, m, r, b); OBMC_FILTER(x +stride, t, l, m, r, b); OBMC_FILTER(x+1+stride, t, l, m, r, b); x=0; OBMC_FILTER (x , 2, 2, 4, 0, 0); OBMC_FILTER (x+1, 2, 1, 5, 0, 0); OBMC_FILTER4(x+2, 2, 1, 5, 0, 0); OBMC_FILTER4(x+4, 2, 0, 5, 1, 0); OBMC_FILTER (x+6, 2, 0, 5, 1, 0); OBMC_FILTER (x+7, 2, 0, 4, 2, 0); x+= stride; OBMC_FILTER (x , 1, 2, 5, 0, 0); OBMC_FILTER (x+1, 1, 2, 5, 0, 0); OBMC_FILTER (x+6, 1, 0, 5, 2, 0); OBMC_FILTER (x+7, 1, 0, 5, 2, 0); x+= stride; OBMC_FILTER4(x , 1, 2, 5, 0, 0); OBMC_FILTER4(x+2, 1, 1, 6, 0, 0); OBMC_FILTER4(x+4, 1, 0, 6, 1, 0); OBMC_FILTER4(x+6, 1, 0, 5, 2, 0); x+= 2*stride; OBMC_FILTER4(x , 0, 2, 5, 0, 1); OBMC_FILTER4(x+2, 0, 1, 6, 0, 1); OBMC_FILTER4(x+4, 0, 0, 6, 1, 1); OBMC_FILTER4(x+6, 0, 0, 5, 2, 1); x+= 2*stride; OBMC_FILTER (x , 0, 2, 5, 0, 1); OBMC_FILTER (x+1, 0, 2, 5, 0, 1); OBMC_FILTER4(x+2, 0, 1, 5, 0, 2); OBMC_FILTER4(x+4, 0, 0, 5, 1, 2); OBMC_FILTER (x+6, 0, 0, 5, 2, 1); OBMC_FILTER (x+7, 0, 0, 5, 2, 1); x+= stride; OBMC_FILTER (x , 0, 2, 4, 0, 2); OBMC_FILTER (x+1, 0, 1, 5, 0, 2); OBMC_FILTER (x+6, 0, 0, 5, 1, 2); OBMC_FILTER (x+7, 0, 0, 4, 2, 2); } /* obmc for 1 8x8 luma block */ static inline void obmc_motion(MpegEncContext *s, uint8_t *dest, uint8_t *src, int src_x, int src_y, op_pixels_func *pix_op, int16_t mv[5][2]/* mid top left right bottom*/) #define MID 0 { int i; uint8_t *ptr[5]; assert(s->quarter_sample==0); for(i=0; i<5; i++){ if(i && mv[i][0]==mv[MID][0] && mv[i][1]==mv[MID][1]){ ptr[i]= ptr[MID]; }else{ ptr[i]= s->obmc_scratchpad + 8*(i&1) + s->linesize*8*(i>>1); hpel_motion(s, ptr[i], src, 0, 0, src_x, src_y, s->width, s->height, s->linesize, s->h_edge_pos, s->v_edge_pos, 8, 8, pix_op, mv[i][0], mv[i][1]); } } put_obmc(dest, ptr, s->linesize); } static inline void qpel_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int field_based, int bottom_field, int field_select, uint8_t **ref_picture, op_pixels_func (*pix_op)[4], qpel_mc_func (*qpix_op)[16], int motion_x, int motion_y, int h) { uint8_t *ptr_y, *ptr_cb, *ptr_cr; int dxy, uvdxy, mx, my, src_x, src_y, uvsrc_x, uvsrc_y, v_edge_pos, linesize, uvlinesize; dxy = ((motion_y & 3) << 2) | (motion_x & 3); src_x = s->mb_x * 16 + (motion_x >> 2); src_y = s->mb_y * (16 >> field_based) + (motion_y >> 2); v_edge_pos = s->v_edge_pos >> field_based; linesize = s->linesize << field_based; uvlinesize = s->uvlinesize << field_based; if(field_based){ mx= motion_x/2; my= motion_y>>1; }else if(s->workaround_bugs&FF_BUG_QPEL_CHROMA2){ static const int rtab[8]= {0,0,1,1,0,0,0,1}; mx= (motion_x>>1) + rtab[motion_x&7]; my= (motion_y>>1) + rtab[motion_y&7]; }else if(s->workaround_bugs&FF_BUG_QPEL_CHROMA){ mx= (motion_x>>1)|(motion_x&1); my= (motion_y>>1)|(motion_y&1); }else{ mx= motion_x/2; my= motion_y/2; } mx= (mx>>1)|(mx&1); my= (my>>1)|(my&1); uvdxy= (mx&1) | ((my&1)<<1); mx>>=1; my>>=1; uvsrc_x = s->mb_x * 8 + mx; uvsrc_y = s->mb_y * (8 >> field_based) + my; ptr_y = ref_picture[0] + src_y * linesize + src_x; ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x; ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x; if( (unsigned)src_x > s->h_edge_pos - (motion_x&3) - 16 || (unsigned)src_y > v_edge_pos - (motion_y&3) - h ){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr_y, s->linesize, 17, 17+field_based, src_x, src_y<<field_based, s->h_edge_pos, s->v_edge_pos); ptr_y= s->edge_emu_buffer; if(!(s->flags&CODEC_FLAG_GRAY)){ uint8_t *uvbuf= s->edge_emu_buffer + 18*s->linesize; ff_emulated_edge_mc(uvbuf, ptr_cb, s->uvlinesize, 9, 9 + field_based, uvsrc_x, uvsrc_y<<field_based, s->h_edge_pos>>1, s->v_edge_pos>>1); ff_emulated_edge_mc(uvbuf + 16, ptr_cr, s->uvlinesize, 9, 9 + field_based, uvsrc_x, uvsrc_y<<field_based, s->h_edge_pos>>1, s->v_edge_pos>>1); ptr_cb= uvbuf; ptr_cr= uvbuf + 16; } } if(!field_based) qpix_op[0][dxy](dest_y, ptr_y, linesize); else{ if(bottom_field){ dest_y += s->linesize; dest_cb+= s->uvlinesize; dest_cr+= s->uvlinesize; } if(field_select){ ptr_y += s->linesize; ptr_cb += s->uvlinesize; ptr_cr += s->uvlinesize; } //damn interlaced mode //FIXME boundary mirroring is not exactly correct here qpix_op[1][dxy](dest_y , ptr_y , linesize); qpix_op[1][dxy](dest_y+8, ptr_y+8, linesize); } if(!(s->flags&CODEC_FLAG_GRAY)){ pix_op[1][uvdxy](dest_cr, ptr_cr, uvlinesize, h >> 1); pix_op[1][uvdxy](dest_cb, ptr_cb, uvlinesize, h >> 1); } } inline int ff_h263_round_chroma(int x){ if (x >= 0) return (h263_chroma_roundtab[x & 0xf] + ((x >> 3) & ~1)); else { x = -x; return -(h263_chroma_roundtab[x & 0xf] + ((x >> 3) & ~1)); } } /** * h263 chorma 4mv motion compensation. */ static inline void chroma_4mv_motion(MpegEncContext *s, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t **ref_picture, op_pixels_func *pix_op, int mx, int my){ int dxy, emu=0, src_x, src_y, offset; uint8_t *ptr; /* In case of 8X8, we construct a single chroma motion vector with a special rounding */ mx= ff_h263_round_chroma(mx); my= ff_h263_round_chroma(my); dxy = ((my & 1) << 1) | (mx & 1); mx >>= 1; my >>= 1; src_x = s->mb_x * 8 + mx; src_y = s->mb_y * 8 + my; src_x = clip(src_x, -8, s->width/2); if (src_x == s->width/2) dxy &= ~1; src_y = clip(src_y, -8, s->height/2); if (src_y == s->height/2) dxy &= ~2; offset = (src_y * (s->uvlinesize)) + src_x; ptr = ref_picture[1] + offset; if(s->flags&CODEC_FLAG_EMU_EDGE){ if( (unsigned)src_x > (s->h_edge_pos>>1) - (dxy &1) - 8 || (unsigned)src_y > (s->v_edge_pos>>1) - (dxy>>1) - 8){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1); ptr= s->edge_emu_buffer; emu=1; } } pix_op[dxy](dest_cb, ptr, s->uvlinesize, 8); ptr = ref_picture[2] + offset; if(emu){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9, src_x, src_y, s->h_edge_pos>>1, s->v_edge_pos>>1); ptr= s->edge_emu_buffer; } pix_op[dxy](dest_cr, ptr, s->uvlinesize, 8); } static inline void chroma_4mv_motion_lowres(MpegEncContext *s, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t **ref_picture, h264_chroma_mc_func *pix_op, int mx, int my){ const int lowres= s->avctx->lowres; const int block_s= 8>>lowres; const int s_mask= (2<<lowres)-1; const int h_edge_pos = s->h_edge_pos >> (lowres+1); const int v_edge_pos = s->v_edge_pos >> (lowres+1); int emu=0, src_x, src_y, offset, sx, sy; uint8_t *ptr; if(s->quarter_sample){ mx/=2; my/=2; } /* In case of 8X8, we construct a single chroma motion vector with a special rounding */ mx= ff_h263_round_chroma(mx); my= ff_h263_round_chroma(my); sx= mx & s_mask; sy= my & s_mask; src_x = s->mb_x*block_s + (mx >> (lowres+1)); src_y = s->mb_y*block_s + (my >> (lowres+1)); offset = src_y * s->uvlinesize + src_x; ptr = ref_picture[1] + offset; if(s->flags&CODEC_FLAG_EMU_EDGE){ if( (unsigned)src_x > h_edge_pos - (!!sx) - block_s || (unsigned)src_y > v_edge_pos - (!!sy) - block_s){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9, src_x, src_y, h_edge_pos, v_edge_pos); ptr= s->edge_emu_buffer; emu=1; } } sx <<= 2 - lowres; sy <<= 2 - lowres; pix_op[lowres](dest_cb, ptr, s->uvlinesize, block_s, sx, sy); ptr = ref_picture[2] + offset; if(emu){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, s->uvlinesize, 9, 9, src_x, src_y, h_edge_pos, v_edge_pos); ptr= s->edge_emu_buffer; } pix_op[lowres](dest_cr, ptr, s->uvlinesize, block_s, sx, sy); } /** * motion compensation of a single macroblock * @param s context * @param dest_y luma destination pointer * @param dest_cb chroma cb/u destination pointer * @param dest_cr chroma cr/v destination pointer * @param dir direction (0->forward, 1->backward) * @param ref_picture array[3] of pointers to the 3 planes of the reference picture * @param pic_op halfpel motion compensation function (average or put normally) * @param pic_op qpel motion compensation function (average or put normally) * the motion vectors are taken from s->mv and the MV type from s->mv_type */ static inline void MPV_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int dir, uint8_t **ref_picture, op_pixels_func (*pix_op)[4], qpel_mc_func (*qpix_op)[16]) { int dxy, mx, my, src_x, src_y, motion_x, motion_y; int mb_x, mb_y, i; uint8_t *ptr, *dest; mb_x = s->mb_x; mb_y = s->mb_y; if(s->obmc && s->pict_type != B_TYPE){ int16_t mv_cache[4][4][2]; const int xy= s->mb_x + s->mb_y*s->mb_stride; const int mot_stride= s->b8_stride; const int mot_xy= mb_x*2 + mb_y*2*mot_stride; assert(!s->mb_skipped); memcpy(mv_cache[1][1], s->current_picture.motion_val[0][mot_xy ], sizeof(int16_t)*4); memcpy(mv_cache[2][1], s->current_picture.motion_val[0][mot_xy+mot_stride], sizeof(int16_t)*4); memcpy(mv_cache[3][1], s->current_picture.motion_val[0][mot_xy+mot_stride], sizeof(int16_t)*4); if(mb_y==0 || IS_INTRA(s->current_picture.mb_type[xy-s->mb_stride])){ memcpy(mv_cache[0][1], mv_cache[1][1], sizeof(int16_t)*4); }else{ memcpy(mv_cache[0][1], s->current_picture.motion_val[0][mot_xy-mot_stride], sizeof(int16_t)*4); } if(mb_x==0 || IS_INTRA(s->current_picture.mb_type[xy-1])){ *(int32_t*)mv_cache[1][0]= *(int32_t*)mv_cache[1][1]; *(int32_t*)mv_cache[2][0]= *(int32_t*)mv_cache[2][1]; }else{ *(int32_t*)mv_cache[1][0]= *(int32_t*)s->current_picture.motion_val[0][mot_xy-1]; *(int32_t*)mv_cache[2][0]= *(int32_t*)s->current_picture.motion_val[0][mot_xy-1+mot_stride]; } if(mb_x+1>=s->mb_width || IS_INTRA(s->current_picture.mb_type[xy+1])){ *(int32_t*)mv_cache[1][3]= *(int32_t*)mv_cache[1][2]; *(int32_t*)mv_cache[2][3]= *(int32_t*)mv_cache[2][2]; }else{ *(int32_t*)mv_cache[1][3]= *(int32_t*)s->current_picture.motion_val[0][mot_xy+2]; *(int32_t*)mv_cache[2][3]= *(int32_t*)s->current_picture.motion_val[0][mot_xy+2+mot_stride]; } mx = 0; my = 0; for(i=0;i<4;i++) { const int x= (i&1)+1; const int y= (i>>1)+1; int16_t mv[5][2]= { {mv_cache[y][x ][0], mv_cache[y][x ][1]}, {mv_cache[y-1][x][0], mv_cache[y-1][x][1]}, {mv_cache[y][x-1][0], mv_cache[y][x-1][1]}, {mv_cache[y][x+1][0], mv_cache[y][x+1][1]}, {mv_cache[y+1][x][0], mv_cache[y+1][x][1]}}; //FIXME cleanup obmc_motion(s, dest_y + ((i & 1) * 8) + (i >> 1) * 8 * s->linesize, ref_picture[0], mb_x * 16 + (i & 1) * 8, mb_y * 16 + (i >>1) * 8, pix_op[1], mv); mx += mv[0][0]; my += mv[0][1]; } if(!(s->flags&CODEC_FLAG_GRAY)) chroma_4mv_motion(s, dest_cb, dest_cr, ref_picture, pix_op[1], mx, my); return; } switch(s->mv_type) { case MV_TYPE_16X16: if(s->mcsel){ if(s->real_sprite_warping_points==1){ gmc1_motion(s, dest_y, dest_cb, dest_cr, ref_picture); }else{ gmc_motion(s, dest_y, dest_cb, dest_cr, ref_picture); } }else if(s->quarter_sample){ qpel_motion(s, dest_y, dest_cb, dest_cr, 0, 0, 0, ref_picture, pix_op, qpix_op, s->mv[dir][0][0], s->mv[dir][0][1], 16); }else if(s->mspel){ ff_mspel_motion(s, dest_y, dest_cb, dest_cr, ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], 16); }else { mpeg_motion(s, dest_y, dest_cb, dest_cr, 0, 0, 0, ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], 16); } break; case MV_TYPE_8X8: mx = 0; my = 0; if(s->quarter_sample){ for(i=0;i<4;i++) { motion_x = s->mv[dir][i][0]; motion_y = s->mv[dir][i][1]; dxy = ((motion_y & 3) << 2) | (motion_x & 3); src_x = mb_x * 16 + (motion_x >> 2) + (i & 1) * 8; src_y = mb_y * 16 + (motion_y >> 2) + (i >>1) * 8; /* WARNING: do no forget half pels */ src_x = clip(src_x, -16, s->width); if (src_x == s->width) dxy &= ~3; src_y = clip(src_y, -16, s->height); if (src_y == s->height) dxy &= ~12; ptr = ref_picture[0] + (src_y * s->linesize) + (src_x); if(s->flags&CODEC_FLAG_EMU_EDGE){ if( (unsigned)src_x > s->h_edge_pos - (motion_x&3) - 8 || (unsigned)src_y > s->v_edge_pos - (motion_y&3) - 8 ){ ff_emulated_edge_mc(s->edge_emu_buffer, ptr, s->linesize, 9, 9, src_x, src_y, s->h_edge_pos, s->v_edge_pos); ptr= s->edge_emu_buffer; } } dest = dest_y + ((i & 1) * 8) + (i >> 1) * 8 * s->linesize; qpix_op[1][dxy](dest, ptr, s->linesize); mx += s->mv[dir][i][0]/2; my += s->mv[dir][i][1]/2; } }else{ for(i=0;i<4;i++) { hpel_motion(s, dest_y + ((i & 1) * 8) + (i >> 1) * 8 * s->linesize, ref_picture[0], 0, 0, mb_x * 16 + (i & 1) * 8, mb_y * 16 + (i >>1) * 8, s->width, s->height, s->linesize, s->h_edge_pos, s->v_edge_pos, 8, 8, pix_op[1], s->mv[dir][i][0], s->mv[dir][i][1]); mx += s->mv[dir][i][0]; my += s->mv[dir][i][1]; } } if(!(s->flags&CODEC_FLAG_GRAY)) chroma_4mv_motion(s, dest_cb, dest_cr, ref_picture, pix_op[1], mx, my); break; case MV_TYPE_FIELD: if (s->picture_structure == PICT_FRAME) { if(s->quarter_sample){ for(i=0; i<2; i++){ qpel_motion(s, dest_y, dest_cb, dest_cr, 1, i, s->field_select[dir][i], ref_picture, pix_op, qpix_op, s->mv[dir][i][0], s->mv[dir][i][1], 8); } }else{ /* top field */ mpeg_motion(s, dest_y, dest_cb, dest_cr, 1, 0, s->field_select[dir][0], ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], 8); /* bottom field */ mpeg_motion(s, dest_y, dest_cb, dest_cr, 1, 1, s->field_select[dir][1], ref_picture, pix_op, s->mv[dir][1][0], s->mv[dir][1][1], 8); } } else { if(s->picture_structure != s->field_select[dir][0] + 1 && s->pict_type != B_TYPE && !s->first_field){ ref_picture= s->current_picture_ptr->data; } mpeg_motion(s, dest_y, dest_cb, dest_cr, 0, 0, s->field_select[dir][0], ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], 16); } break; case MV_TYPE_16X8: for(i=0; i<2; i++){ uint8_t ** ref2picture; if(s->picture_structure == s->field_select[dir][i] + 1 || s->pict_type == B_TYPE || s->first_field){ ref2picture= ref_picture; }else{ ref2picture= s->current_picture_ptr->data; } mpeg_motion(s, dest_y, dest_cb, dest_cr, 0, 0, s->field_select[dir][i], ref2picture, pix_op, s->mv[dir][i][0], s->mv[dir][i][1] + 16*i, 8); dest_y += 16*s->linesize; dest_cb+= (16>>s->chroma_y_shift)*s->uvlinesize; dest_cr+= (16>>s->chroma_y_shift)*s->uvlinesize; } break; case MV_TYPE_DMV: if(s->picture_structure == PICT_FRAME){ for(i=0; i<2; i++){ int j; for(j=0; j<2; j++){ mpeg_motion(s, dest_y, dest_cb, dest_cr, 1, j, j^i, ref_picture, pix_op, s->mv[dir][2*i + j][0], s->mv[dir][2*i + j][1], 8); } pix_op = s->dsp.avg_pixels_tab; } }else{ for(i=0; i<2; i++){ mpeg_motion(s, dest_y, dest_cb, dest_cr, 0, 0, s->picture_structure != i+1, ref_picture, pix_op, s->mv[dir][2*i][0],s->mv[dir][2*i][1],16); // after put we make avg of the same block pix_op=s->dsp.avg_pixels_tab; //opposite parity is always in the same frame if this is second field if(!s->first_field){ ref_picture = s->current_picture_ptr->data; } } } break; default: assert(0); } } /** * motion compensation of a single macroblock * @param s context * @param dest_y luma destination pointer * @param dest_cb chroma cb/u destination pointer * @param dest_cr chroma cr/v destination pointer * @param dir direction (0->forward, 1->backward) * @param ref_picture array[3] of pointers to the 3 planes of the reference picture * @param pic_op halfpel motion compensation function (average or put normally) * the motion vectors are taken from s->mv and the MV type from s->mv_type */ static inline void MPV_motion_lowres(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int dir, uint8_t **ref_picture, h264_chroma_mc_func *pix_op) { int mx, my; int mb_x, mb_y, i; const int lowres= s->avctx->lowres; const int block_s= 8>>lowres; mb_x = s->mb_x; mb_y = s->mb_y; switch(s->mv_type) { case MV_TYPE_16X16: mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, 0, 0, ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], 2*block_s); break; case MV_TYPE_8X8: mx = 0; my = 0; for(i=0;i<4;i++) { hpel_motion_lowres(s, dest_y + ((i & 1) + (i >> 1) * s->linesize)*block_s, ref_picture[0], 0, 0, (2*mb_x + (i & 1))*block_s, (2*mb_y + (i >>1))*block_s, s->width, s->height, s->linesize, s->h_edge_pos >> lowres, s->v_edge_pos >> lowres, block_s, block_s, pix_op, s->mv[dir][i][0], s->mv[dir][i][1]); mx += s->mv[dir][i][0]; my += s->mv[dir][i][1]; } if(!(s->flags&CODEC_FLAG_GRAY)) chroma_4mv_motion_lowres(s, dest_cb, dest_cr, ref_picture, pix_op, mx, my); break; case MV_TYPE_FIELD: if (s->picture_structure == PICT_FRAME) { /* top field */ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, 0, s->field_select[dir][0], ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], block_s); /* bottom field */ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, 1, s->field_select[dir][1], ref_picture, pix_op, s->mv[dir][1][0], s->mv[dir][1][1], block_s); } else { if(s->picture_structure != s->field_select[dir][0] + 1 && s->pict_type != B_TYPE && !s->first_field){ ref_picture= s->current_picture_ptr->data; } mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, 0, s->field_select[dir][0], ref_picture, pix_op, s->mv[dir][0][0], s->mv[dir][0][1], 2*block_s); } break; case MV_TYPE_16X8: for(i=0; i<2; i++){ uint8_t ** ref2picture; if(s->picture_structure == s->field_select[dir][i] + 1 || s->pict_type == B_TYPE || s->first_field){ ref2picture= ref_picture; }else{ ref2picture= s->current_picture_ptr->data; } mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, 0, s->field_select[dir][i], ref2picture, pix_op, s->mv[dir][i][0], s->mv[dir][i][1] + 2*block_s*i, block_s); dest_y += 2*block_s*s->linesize; dest_cb+= (2*block_s>>s->chroma_y_shift)*s->uvlinesize; dest_cr+= (2*block_s>>s->chroma_y_shift)*s->uvlinesize; } break; case MV_TYPE_DMV: if(s->picture_structure == PICT_FRAME){ for(i=0; i<2; i++){ int j; for(j=0; j<2; j++){ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, j, j^i, ref_picture, pix_op, s->mv[dir][2*i + j][0], s->mv[dir][2*i + j][1], block_s); } pix_op = s->dsp.avg_h264_chroma_pixels_tab; } }else{ for(i=0; i<2; i++){ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, 0, s->picture_structure != i+1, ref_picture, pix_op, s->mv[dir][2*i][0],s->mv[dir][2*i][1],2*block_s); // after put we make avg of the same block pix_op = s->dsp.avg_h264_chroma_pixels_tab; //opposite parity is always in the same frame if this is second field if(!s->first_field){ ref_picture = s->current_picture_ptr->data; } } } break; default: assert(0); } } /* put block[] to dest[] */ static inline void put_dct(MpegEncContext *s, DCTELEM *block, int i, uint8_t *dest, int line_size, int qscale) { s->dct_unquantize_intra(s, block, i, qscale); s->dsp.idct_put (dest, line_size, block); } /* add block[] to dest[] */ static inline void add_dct(MpegEncContext *s, DCTELEM *block, int i, uint8_t *dest, int line_size) { if (s->block_last_index[i] >= 0) { s->dsp.idct_add (dest, line_size, block); } } static inline void add_dequant_dct(MpegEncContext *s, DCTELEM *block, int i, uint8_t *dest, int line_size, int qscale) { if (s->block_last_index[i] >= 0) { s->dct_unquantize_inter(s, block, i, qscale); s->dsp.idct_add (dest, line_size, block); } } /** * cleans dc, ac, coded_block for the current non intra MB */ void ff_clean_intra_table_entries(MpegEncContext *s) { int wrap = s->b8_stride; int xy = s->block_index[0]; s->dc_val[0][xy ] = s->dc_val[0][xy + 1 ] = s->dc_val[0][xy + wrap] = s->dc_val[0][xy + 1 + wrap] = 1024; /* ac pred */ memset(s->ac_val[0][xy ], 0, 32 * sizeof(int16_t)); memset(s->ac_val[0][xy + wrap], 0, 32 * sizeof(int16_t)); if (s->msmpeg4_version>=3) { s->coded_block[xy ] = s->coded_block[xy + 1 ] = s->coded_block[xy + wrap] = s->coded_block[xy + 1 + wrap] = 0; } /* chroma */ wrap = s->mb_stride; xy = s->mb_x + s->mb_y * wrap; s->dc_val[1][xy] = s->dc_val[2][xy] = 1024; /* ac pred */ memset(s->ac_val[1][xy], 0, 16 * sizeof(int16_t)); memset(s->ac_val[2][xy], 0, 16 * sizeof(int16_t)); s->mbintra_table[xy]= 0; } /* generic function called after a macroblock has been parsed by the decoder or after it has been encoded by the encoder. Important variables used: s->mb_intra : true if intra macroblock s->mv_dir : motion vector direction s->mv_type : motion vector type s->mv : motion vector s->interlaced_dct : true if interlaced dct used (mpeg2) */ static always_inline void MPV_decode_mb_internal(MpegEncContext *s, DCTELEM block[12][64], int lowres_flag) { int mb_x, mb_y; const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; #ifdef HAVE_XVMC if(s->avctx->xvmc_acceleration){ XVMC_decode_mb(s);//xvmc uses pblocks return; } #endif mb_x = s->mb_x; mb_y = s->mb_y; if(s->avctx->debug&FF_DEBUG_DCT_COEFF) { /* save DCT coefficients */ int i,j; DCTELEM *dct = &s->current_picture.dct_coeff[mb_xy*64*6]; for(i=0; i<6; i++) for(j=0; j<64; j++) *dct++ = block[i][s->dsp.idct_permutation[j]]; } s->current_picture.qscale_table[mb_xy]= s->qscale; /* update DC predictors for P macroblocks */ if (!s->mb_intra) { if (s->h263_pred || s->h263_aic) { if(s->mbintra_table[mb_xy]) ff_clean_intra_table_entries(s); } else { s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 128 << s->intra_dc_precision; } } else if (s->h263_pred || s->h263_aic) s->mbintra_table[mb_xy]=1; if ((s->flags&CODEC_FLAG_PSNR) || !(s->encoding && (s->intra_only || s->pict_type==B_TYPE))) { //FIXME precalc uint8_t *dest_y, *dest_cb, *dest_cr; int dct_linesize, dct_offset; op_pixels_func (*op_pix)[4]; qpel_mc_func (*op_qpix)[16]; const int linesize= s->current_picture.linesize[0]; //not s->linesize as this would be wrong for field pics const int uvlinesize= s->current_picture.linesize[1]; const int readable= s->pict_type != B_TYPE || s->encoding || s->avctx->draw_horiz_band || lowres_flag; const int block_size= lowres_flag ? 8>>s->avctx->lowres : 8; /* avoid copy if macroblock skipped in last frame too */ /* skip only during decoding as we might trash the buffers during encoding a bit */ if(!s->encoding){ uint8_t *mbskip_ptr = &s->mbskip_table[mb_xy]; const int age= s->current_picture.age; assert(age); if (s->mb_skipped) { s->mb_skipped= 0; assert(s->pict_type!=I_TYPE); (*mbskip_ptr) ++; /* indicate that this time we skipped it */ if(*mbskip_ptr >99) *mbskip_ptr= 99; /* if previous was skipped too, then nothing to do ! */ if (*mbskip_ptr >= age && s->current_picture.reference){ return; } } else if(!s->current_picture.reference){ (*mbskip_ptr) ++; /* increase counter so the age can be compared cleanly */ if(*mbskip_ptr >99) *mbskip_ptr= 99; } else{ *mbskip_ptr = 0; /* not skipped */ } } dct_linesize = linesize << s->interlaced_dct; dct_offset =(s->interlaced_dct)? linesize : linesize*block_size; if(readable){ dest_y= s->dest[0]; dest_cb= s->dest[1]; dest_cr= s->dest[2]; }else{ dest_y = s->b_scratchpad; dest_cb= s->b_scratchpad+16*linesize; dest_cr= s->b_scratchpad+32*linesize; } if (!s->mb_intra) { /* motion handling */ /* decoding or more than one mb_type (MC was already done otherwise) */ if(!s->encoding){ if(lowres_flag){ h264_chroma_mc_func *op_pix = s->dsp.put_h264_chroma_pixels_tab; if (s->mv_dir & MV_DIR_FORWARD) { MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, s->last_picture.data, op_pix); op_pix = s->dsp.avg_h264_chroma_pixels_tab; } if (s->mv_dir & MV_DIR_BACKWARD) { MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, s->next_picture.data, op_pix); } }else{ if ((!s->no_rounding) || s->pict_type==B_TYPE){ op_pix = s->dsp.put_pixels_tab; op_qpix= s->dsp.put_qpel_pixels_tab; }else{ op_pix = s->dsp.put_no_rnd_pixels_tab; op_qpix= s->dsp.put_no_rnd_qpel_pixels_tab; } if (s->mv_dir & MV_DIR_FORWARD) { MPV_motion(s, dest_y, dest_cb, dest_cr, 0, s->last_picture.data, op_pix, op_qpix); op_pix = s->dsp.avg_pixels_tab; op_qpix= s->dsp.avg_qpel_pixels_tab; } if (s->mv_dir & MV_DIR_BACKWARD) { MPV_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_picture.data, op_pix, op_qpix); } } } /* skip dequant / idct if we are really late ;) */ if(s->hurry_up>1) goto skip_idct; if(s->avctx->skip_idct){ if( (s->avctx->skip_idct >= AVDISCARD_NONREF && s->pict_type == B_TYPE) ||(s->avctx->skip_idct >= AVDISCARD_NONKEY && s->pict_type != I_TYPE) || s->avctx->skip_idct >= AVDISCARD_ALL) goto skip_idct; } /* add dct residue */ if(s->encoding || !( s->h263_msmpeg4 || s->codec_id==CODEC_ID_MPEG1VIDEO || s->codec_id==CODEC_ID_MPEG2VIDEO || (s->codec_id==CODEC_ID_MPEG4 && !s->mpeg_quant))){ add_dequant_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); add_dequant_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); add_dequant_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); add_dequant_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); if(!(s->flags&CODEC_FLAG_GRAY)){ add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); } } else if(s->codec_id != CODEC_ID_WMV2){ add_dct(s, block[0], 0, dest_y , dct_linesize); add_dct(s, block[1], 1, dest_y + block_size, dct_linesize); add_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize); add_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize); if(!(s->flags&CODEC_FLAG_GRAY)){ if(s->chroma_y_shift){//Chroma420 add_dct(s, block[4], 4, dest_cb, uvlinesize); add_dct(s, block[5], 5, dest_cr, uvlinesize); }else{ //chroma422 dct_linesize = uvlinesize << s->interlaced_dct; dct_offset =(s->interlaced_dct)? uvlinesize : uvlinesize*8; add_dct(s, block[4], 4, dest_cb, dct_linesize); add_dct(s, block[5], 5, dest_cr, dct_linesize); add_dct(s, block[6], 6, dest_cb+dct_offset, dct_linesize); add_dct(s, block[7], 7, dest_cr+dct_offset, dct_linesize); if(!s->chroma_x_shift){//Chroma444 add_dct(s, block[8], 8, dest_cb+8, dct_linesize); add_dct(s, block[9], 9, dest_cr+8, dct_linesize); add_dct(s, block[10], 10, dest_cb+8+dct_offset, dct_linesize); add_dct(s, block[11], 11, dest_cr+8+dct_offset, dct_linesize); } } }//fi gray } else{ ff_wmv2_add_mb(s, block, dest_y, dest_cb, dest_cr); } } else { /* dct only in intra block */ if(s->encoding || !(s->codec_id==CODEC_ID_MPEG1VIDEO || s->codec_id==CODEC_ID_MPEG2VIDEO)){ put_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); if(!(s->flags&CODEC_FLAG_GRAY)){ put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); } }else{ s->dsp.idct_put(dest_y , dct_linesize, block[0]); s->dsp.idct_put(dest_y + block_size, dct_linesize, block[1]); s->dsp.idct_put(dest_y + dct_offset , dct_linesize, block[2]); s->dsp.idct_put(dest_y + dct_offset + block_size, dct_linesize, block[3]); if(!(s->flags&CODEC_FLAG_GRAY)){ if(s->chroma_y_shift){ s->dsp.idct_put(dest_cb, uvlinesize, block[4]); s->dsp.idct_put(dest_cr, uvlinesize, block[5]); }else{ dct_linesize = uvlinesize << s->interlaced_dct; dct_offset =(s->interlaced_dct)? uvlinesize : uvlinesize*8; s->dsp.idct_put(dest_cb, dct_linesize, block[4]); s->dsp.idct_put(dest_cr, dct_linesize, block[5]); s->dsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]); s->dsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]); if(!s->chroma_x_shift){//Chroma444 s->dsp.idct_put(dest_cb + 8, dct_linesize, block[8]); s->dsp.idct_put(dest_cr + 8, dct_linesize, block[9]); s->dsp.idct_put(dest_cb + 8 + dct_offset, dct_linesize, block[10]); s->dsp.idct_put(dest_cr + 8 + dct_offset, dct_linesize, block[11]); } } }//gray } } skip_idct: if(!readable){ s->dsp.put_pixels_tab[0][0](s->dest[0], dest_y , linesize,16); s->dsp.put_pixels_tab[s->chroma_x_shift][0](s->dest[1], dest_cb, uvlinesize,16 >> s->chroma_y_shift); s->dsp.put_pixels_tab[s->chroma_x_shift][0](s->dest[2], dest_cr, uvlinesize,16 >> s->chroma_y_shift); } } } void MPV_decode_mb(MpegEncContext *s, DCTELEM block[12][64]){ if(s->avctx->lowres) MPV_decode_mb_internal(s, block, 1); else MPV_decode_mb_internal(s, block, 0); } #ifdef CONFIG_ENCODERS static inline void dct_single_coeff_elimination(MpegEncContext *s, int n, int threshold) { static const char tab[64]= {3,2,2,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; int score=0; int run=0; int i; DCTELEM *block= s->block[n]; const int last_index= s->block_last_index[n]; int skip_dc; if(threshold<0){ skip_dc=0; threshold= -threshold; }else skip_dc=1; /* are all which we could set to zero are allready zero? */ if(last_index<=skip_dc - 1) return; for(i=0; i<=last_index; i++){ const int j = s->intra_scantable.permutated[i]; const int level = ABS(block[j]); if(level==1){ if(skip_dc && i==0) continue; score+= tab[run]; run=0; }else if(level>1){ return; }else{ run++; } } if(score >= threshold) return; for(i=skip_dc; i<=last_index; i++){ const int j = s->intra_scantable.permutated[i]; block[j]=0; } if(block[0]) s->block_last_index[n]= 0; else s->block_last_index[n]= -1; } static inline void clip_coeffs(MpegEncContext *s, DCTELEM *block, int last_index) { int i; const int maxlevel= s->max_qcoeff; const int minlevel= s->min_qcoeff; int overflow=0; if(s->mb_intra){ i=1; //skip clipping of intra dc }else i=0; for(;i<=last_index; i++){ const int j= s->intra_scantable.permutated[i]; int level = block[j]; if (level>maxlevel){ level=maxlevel; overflow++; }else if(level<minlevel){ level=minlevel; overflow++; } block[j]= level; } if(overflow && s->avctx->mb_decision == FF_MB_DECISION_SIMPLE) av_log(s->avctx, AV_LOG_INFO, "warning, clipping %d dct coefficients to %d..%dn", overflow, minlevel, maxlevel); } #endif //CONFIG_ENCODERS /** * * @param h is the normal height, this will be reduced automatically if needed for the last row */ void ff_draw_horiz_band(MpegEncContext *s, int y, int h){ if (s->avctx->draw_horiz_band) { AVFrame *src; int offset[4]; if(s->picture_structure != PICT_FRAME){ h <<= 1; y <<= 1; if(s->first_field && !(s->avctx->slice_flags&SLICE_FLAG_ALLOW_FIELD)) return; } h= FFMIN(h, s->avctx->height - y); if(s->pict_type==B_TYPE || s->low_delay || (s->avctx->slice_flags&SLICE_FLAG_CODED_ORDER)) src= (AVFrame*)s->current_picture_ptr; else if(s->last_picture_ptr) src= (AVFrame*)s->last_picture_ptr; else return; if(s->pict_type==B_TYPE && s->picture_structure == PICT_FRAME && s->out_format != FMT_H264){ offset[0]= offset[1]= offset[2]= offset[3]= 0; }else{ offset[0]= y * s->linesize;; offset[1]= offset[2]= (y >> s->chroma_y_shift) * s->uvlinesize; offset[3]= 0; } emms_c(); s->avctx->draw_horiz_band(s->avctx, src, offset, y, s->picture_structure, h); } } void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename const int linesize= s->current_picture.linesize[0]; //not s->linesize as this would be wrong for field pics const int uvlinesize= s->current_picture.linesize[1]; const int mb_size= 4 - s->avctx->lowres; s->block_index[0]= s->b8_stride*(s->mb_y*2 ) - 2 + s->mb_x*2; s->block_index[1]= s->b8_stride*(s->mb_y*2 ) - 1 + s->mb_x*2; s->block_index[2]= s->b8_stride*(s->mb_y*2 + 1) - 2 + s->mb_x*2; s->block_index[3]= s->b8_stride*(s->mb_y*2 + 1) - 1 + s->mb_x*2; s->block_index[4]= s->mb_stride*(s->mb_y + 1) + s->b8_stride*s->mb_height*2 + s->mb_x - 1; s->block_index[5]= s->mb_stride*(s->mb_y + s->mb_height + 2) + s->b8_stride*s->mb_height*2 + s->mb_x - 1; //block_index is not used by mpeg2, so it is not affected by chroma_format s->dest[0] = s->current_picture.data[0] + ((s->mb_x - 1) << mb_size); s->dest[1] = s->current_picture.data[1] + ((s->mb_x - 1) << (mb_size - s->chroma_x_shift)); s->dest[2] = s->current_picture.data[2] + ((s->mb_x - 1) << (mb_size - s->chroma_x_shift)); if(!(s->pict_type==B_TYPE && s->avctx->draw_horiz_band && s->picture_structure==PICT_FRAME)) { s->dest[0] += s->mb_y * linesize << mb_size; s->dest[1] += s->mb_y * uvlinesize << (mb_size - s->chroma_y_shift); s->dest[2] += s->mb_y * uvlinesize << (mb_size - s->chroma_y_shift); } } #ifdef CONFIG_ENCODERS static void get_vissual_weight(int16_t *weight, uint8_t *ptr, int stride){ int x, y; //FIXME optimize for(y=0; y<8; y++){ for(x=0; x<8; x++){ int x2, y2; int sum=0; int sqr=0; int count=0; for(y2= FFMAX(y-1, 0); y2 < FFMIN(8, y+2); y2++){ for(x2= FFMAX(x-1, 0); x2 < FFMIN(8, x+2); x2++){ int v= ptr[x2 + y2*stride]; sum += v; sqr += v*v; count++; } } weight[x + 8*y]= (36*ff_sqrt(count*sqr - sum*sum)) / count; } } } static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) { int16_t weight[6][64]; DCTELEM orig[6][64]; const int mb_x= s->mb_x; const int mb_y= s->mb_y; int i; int skip_dct[6]; int dct_offset = s->linesize*8; //default for progressive frames uint8_t *ptr_y, *ptr_cb, *ptr_cr; int wrap_y, wrap_c; for(i=0; i<6; i++) skip_dct[i]=0; if(s->adaptive_quant){ const int last_qp= s->qscale; const int mb_xy= mb_x + mb_y*s->mb_stride; s->lambda= s->lambda_table[mb_xy]; update_qscale(s); if(!(s->flags&CODEC_FLAG_QP_RD)){ s->dquant= s->qscale - last_qp; if(s->out_format==FMT_H263){ s->dquant= clip(s->dquant, -2, 2); //FIXME RD if(s->codec_id==CODEC_ID_MPEG4){ if(!s->mb_intra){ if(s->pict_type == B_TYPE){ if(s->dquant&1) s->dquant= (s->dquant/2)*2; if(s->mv_dir&MV_DIRECT) s->dquant= 0; } if(s->mv_type==MV_TYPE_8X8) s->dquant=0; } } } } ff_set_qscale(s, last_qp + s->dquant); }else if(s->flags&CODEC_FLAG_QP_RD) ff_set_qscale(s, s->qscale + s->dquant); wrap_y = s->linesize; wrap_c = s->uvlinesize; ptr_y = s->new_picture.data[0] + (mb_y * 16 * wrap_y) + mb_x * 16; ptr_cb = s->new_picture.data[1] + (mb_y * 8 * wrap_c) + mb_x * 8; ptr_cr = s->new_picture.data[2] + (mb_y * 8 * wrap_c) + mb_x * 8; if(mb_x*16+16 > s->width || mb_y*16+16 > s->height){ uint8_t *ebuf= s->edge_emu_buffer + 32; ff_emulated_edge_mc(ebuf , ptr_y , wrap_y,16,16,mb_x*16,mb_y*16, s->width , s->height); ptr_y= ebuf; ff_emulated_edge_mc(ebuf+18*wrap_y , ptr_cb, wrap_c, 8, 8, mb_x*8, mb_y*8, s->width>>1, s->height>>1); ptr_cb= ebuf+18*wrap_y; ff_emulated_edge_mc(ebuf+18*wrap_y+8, ptr_cr, wrap_c, 8, 8, mb_x*8, mb_y*8, s->width>>1, s->height>>1); ptr_cr= ebuf+18*wrap_y+8; } if (s->mb_intra) { if(s->flags&CODEC_FLAG_INTERLACED_DCT){ int progressive_score, interlaced_score; s->interlaced_dct=0; progressive_score= s->dsp.ildct_cmp[4](s, ptr_y , NULL, wrap_y, 8) +s->dsp.ildct_cmp[4](s, ptr_y + wrap_y*8, NULL, wrap_y, 8) - 400; if(progressive_score > 0){ interlaced_score = s->dsp.ildct_cmp[4](s, ptr_y , NULL, wrap_y*2, 8) +s->dsp.ildct_cmp[4](s, ptr_y + wrap_y , NULL, wrap_y*2, 8); if(progressive_score > interlaced_score){ s->interlaced_dct=1; dct_offset= wrap_y; wrap_y<<=1; } } } s->dsp.get_pixels(s->block[0], ptr_y , wrap_y); s->dsp.get_pixels(s->block[1], ptr_y + 8, wrap_y); s->dsp.get_pixels(s->block[2], ptr_y + dct_offset , wrap_y); s->dsp.get_pixels(s->block[3], ptr_y + dct_offset + 8, wrap_y); if(s->flags&CODEC_FLAG_GRAY){ skip_dct[4]= 1; skip_dct[5]= 1; }else{ s->dsp.get_pixels(s->block[4], ptr_cb, wrap_c); s->dsp.get_pixels(s->block[5], ptr_cr, wrap_c); } }else{ op_pixels_func (*op_pix)[4]; qpel_mc_func (*op_qpix)[16]; uint8_t *dest_y, *dest_cb, *dest_cr; dest_y = s->dest[0]; dest_cb = s->dest[1]; dest_cr = s->dest[2]; if ((!s->no_rounding) || s->pict_type==B_TYPE){ op_pix = s->dsp.put_pixels_tab; op_qpix= s->dsp.put_qpel_pixels_tab; }else{ op_pix = s->dsp.put_no_rnd_pixels_tab; op_qpix= s->dsp.put_no_rnd_qpel_pixels_tab; } if (s->mv_dir & MV_DIR_FORWARD) { MPV_motion(s, dest_y, dest_cb, dest_cr, 0, s->last_picture.data, op_pix, op_qpix); op_pix = s->dsp.avg_pixels_tab; op_qpix= s->dsp.avg_qpel_pixels_tab; } if (s->mv_dir & MV_DIR_BACKWARD) { MPV_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_picture.data, op_pix, op_qpix); } if(s->flags&CODEC_FLAG_INTERLACED_DCT){ int progressive_score, interlaced_score; s->interlaced_dct=0; progressive_score= s->dsp.ildct_cmp[0](s, dest_y , ptr_y , wrap_y, 8) +s->dsp.ildct_cmp[0](s, dest_y + wrap_y*8, ptr_y + wrap_y*8, wrap_y, 8) - 400; if(s->avctx->ildct_cmp == FF_CMP_VSSE) progressive_score -= 400; if(progressive_score>0){ interlaced_score = s->dsp.ildct_cmp[0](s, dest_y , ptr_y , wrap_y*2, 8) +s->dsp.ildct_cmp[0](s, dest_y + wrap_y , ptr_y + wrap_y , wrap_y*2, 8); if(progressive_score > interlaced_score){ s->interlaced_dct=1; dct_offset= wrap_y; wrap_y<<=1; } } } s->dsp.diff_pixels(s->block[0], ptr_y , dest_y , wrap_y); s->dsp.diff_pixels(s->block[1], ptr_y + 8, dest_y + 8, wrap_y); s->dsp.diff_pixels(s->block[2], ptr_y + dct_offset , dest_y + dct_offset , wrap_y); s->dsp.diff_pixels(s->block[3], ptr_y + dct_offset + 8, dest_y + dct_offset + 8, wrap_y); if(s->flags&CODEC_FLAG_GRAY){ skip_dct[4]= 1; skip_dct[5]= 1; }else{ s->dsp.diff_pixels(s->block[4], ptr_cb, dest_cb, wrap_c); s->dsp.diff_pixels(s->block[5], ptr_cr, dest_cr, wrap_c); } /* pre quantization */ if(s->current_picture.mc_mb_var[s->mb_stride*mb_y+ mb_x]<2*s->qscale*s->qscale){ //FIXME optimize if(s->dsp.sad[1](NULL, ptr_y , dest_y , wrap_y, 8) < 20*s->qscale) skip_dct[0]= 1; if(s->dsp.sad[1](NULL, ptr_y + 8, dest_y + 8, wrap_y, 8) < 20*s->qscale) skip_dct[1]= 1; if(s->dsp.sad[1](NULL, ptr_y +dct_offset , dest_y +dct_offset , wrap_y, 8) < 20*s->qscale) skip_dct[2]= 1; if(s->dsp.sad[1](NULL, ptr_y +dct_offset+ 8, dest_y +dct_offset+ 8, wrap_y, 8) < 20*s->qscale) skip_dct[3]= 1; if(s->dsp.sad[1](NULL, ptr_cb , dest_cb , wrap_c, 8) < 20*s->qscale) skip_dct[4]= 1; if(s->dsp.sad[1](NULL, ptr_cr , dest_cr , wrap_c, 8) < 20*s->qscale) skip_dct[5]= 1; } } if(s->avctx->quantizer_noise_shaping){ if(!skip_dct[0]) get_vissual_weight(weight[0], ptr_y , wrap_y); if(!skip_dct[1]) get_vissual_weight(weight[1], ptr_y + 8, wrap_y); if(!skip_dct[2]) get_vissual_weight(weight[2], ptr_y + dct_offset , wrap_y); if(!skip_dct[3]) get_vissual_weight(weight[3], ptr_y + dct_offset + 8, wrap_y); if(!skip_dct[4]) get_vissual_weight(weight[4], ptr_cb , wrap_c); if(!skip_dct[5]) get_vissual_weight(weight[5], ptr_cr , wrap_c); memcpy(orig[0], s->block[0], sizeof(DCTELEM)*64*6); } /* DCT & quantize */ assert(s->out_format!=FMT_MJPEG || s->qscale==8); { for(i=0;i<6;i++) { if(!skip_dct[i]){ int overflow; s->block_last_index[i] = s->dct_quantize(s, s->block[i], i, s->qscale, &overflow); // FIXME we could decide to change to quantizer instead of clipping // JS: I don't think that would be a good idea it could lower quality instead // of improve it. Just INTRADC clipping deserves changes in quantizer if (overflow) clip_coeffs(s, s->block[i], s->block_last_index[i]); }else s->block_last_index[i]= -1; } if(s->avctx->quantizer_noise_shaping){ for(i=0;i<6;i++) { if(!skip_dct[i]){ s->block_last_index[i] = dct_quantize_refine(s, s->block[i], weight[i], orig[i], i, s->qscale); } } } if(s->luma_elim_threshold && !s->mb_intra) for(i=0; i<4; i++) dct_single_coeff_elimination(s, i, s->luma_elim_threshold); if(s->chroma_elim_threshold && !s->mb_intra) for(i=4; i<6; i++) dct_single_coeff_elimination(s, i, s->chroma_elim_threshold); if(s->flags & CODEC_FLAG_CBP_RD){ for(i=0;i<6;i++) { if(s->block_last_index[i] == -1) s->coded_score[i]= INT_MAX/256; } } } if((s->flags&CODEC_FLAG_GRAY) && s->mb_intra){ s->block_last_index[4]= s->block_last_index[5]= 0; s->block[4][0]= s->block[5][0]= (1024 + s->c_dc_scale/2)/ s->c_dc_scale; } //non c quantize code returns incorrect block_last_index FIXME if(s->alternate_scan && s->dct_quantize != dct_quantize_c){ for(i=0; i<6; i++){ int j; if(s->block_last_index[i]>0){ for(j=63; j>0; j--){ if(s->block[i][ s->intra_scantable.permutated[j] ]) break; } s->block_last_index[i]= j; } } } /* huffman encode */ switch(s->codec_id){ //FIXME funct ptr could be slightly faster case CODEC_ID_MPEG1VIDEO: case CODEC_ID_MPEG2VIDEO: mpeg1_encode_mb(s, s->block, motion_x, motion_y); break; case CODEC_ID_MPEG4: mpeg4_encode_mb(s, s->block, motion_x, motion_y); break; case CODEC_ID_MSMPEG4V2: case CODEC_ID_MSMPEG4V3: case CODEC_ID_WMV1: msmpeg4_encode_mb(s, s->block, motion_x, motion_y); break; case CODEC_ID_WMV2: ff_wmv2_encode_mb(s, s->block, motion_x, motion_y); break; #ifdef CONFIG_H261_ENCODER case CODEC_ID_H261: ff_h261_encode_mb(s, s->block, motion_x, motion_y); break; #endif case CODEC_ID_H263: case CODEC_ID_H263P: case CODEC_ID_FLV1: case CODEC_ID_RV10: case CODEC_ID_RV20: h263_encode_mb(s, s->block, motion_x, motion_y); break; case CODEC_ID_MJPEG: mjpeg_encode_mb(s, s->block); break; default: assert(0); } } #endif //CONFIG_ENCODERS void ff_mpeg_flush(AVCodecContext *avctx){ int i; MpegEncContext *s = avctx->priv_data; if(s==NULL || s->picture==NULL) return; for(i=0; i<MAX_PICTURE_COUNT; i++){ if(s->picture[i].data[0] && ( s->picture[i].type == FF_BUFFER_TYPE_INTERNAL || s->picture[i].type == FF_BUFFER_TYPE_USER)) avctx->release_buffer(avctx, (AVFrame*)&s->picture[i]); } s->current_picture_ptr = s->last_picture_ptr = s->next_picture_ptr = NULL; s->mb_x= s->mb_y= 0; s->parse_context.state= -1; s->parse_context.frame_start_found= 0; s->parse_context.overread= 0; s->parse_context.overread_index= 0; s->parse_context.index= 0; s->parse_context.last_index= 0; s->bitstream_buffer_size=0; } #ifdef CONFIG_ENCODERS void ff_copy_bits(PutBitContext *pb, uint8_t *src, int length) { const uint16_t *srcw= (uint16_t*)src; int words= length>>4; int bits= length&15; int i; if(length==0) return; if(words < 16){ for(i=0; i<words; i++) put_bits(pb, 16, be2me_16(srcw[i])); }else if(put_bits_count(pb)&7){ for(i=0; i<words; i++) put_bits(pb, 16, be2me_16(srcw[i])); }else{ for(i=0; put_bits_count(pb)&31; i++) put_bits(pb, 8, src[i]); flush_put_bits(pb); memcpy(pbBufPtr(pb), src+i, 2*words-i); skip_put_bytes(pb, 2*words-i); } put_bits(pb, bits, be2me_16(srcw[words])>>(16-bits)); } static inline void copy_context_before_encode(MpegEncContext *d, MpegEncContext *s, int type){ int i; memcpy(d->last_mv, s->last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster then a loop? /* mpeg1 */ d->mb_skip_run= s->mb_skip_run; for(i=0; i<3; i++) d->last_dc[i]= s->last_dc[i]; /* statistics */ d->mv_bits= s->mv_bits; d->i_tex_bits= s->i_tex_bits; d->p_tex_bits= s->p_tex_bits; d->i_count= s->i_count; d->f_count= s->f_count; d->b_count= s->b_count; d->skip_count= s->skip_count; d->misc_bits= s->misc_bits; d->last_bits= 0; d->mb_skipped= 0; d->qscale= s->qscale; d->dquant= s->dquant; } static inline void copy_context_after_encode(MpegEncContext *d, MpegEncContext *s, int type){ int i; memcpy(d->mv, s->mv, 2*4*2*sizeof(int)); memcpy(d->last_mv, s->last_mv, 2*2*2*sizeof(int)); //FIXME is memcpy faster then a loop? /* mpeg1 */ d->mb_skip_run= s->mb_skip_run; for(i=0; i<3; i++) d->last_dc[i]= s->last_dc[i]; /* statistics */ d->mv_bits= s->mv_bits; d->i_tex_bits= s->i_tex_bits; d->p_tex_bits= s->p_tex_bits; d->i_count= s->i_count; d->f_count= s->f_count; d->b_count= s->b_count; d->skip_count= s->skip_count; d->misc_bits= s->misc_bits; d->mb_intra= s->mb_intra; d->mb_skipped= s->mb_skipped; d->mv_type= s->mv_type; d->mv_dir= s->mv_dir; d->pb= s->pb; if(s->data_partitioning){ d->pb2= s->pb2; d->tex_pb= s->tex_pb; } d->block= s->block; for(i=0; i<6; i++) d->block_last_index[i]= s->block_last_index[i]; d->interlaced_dct= s->interlaced_dct; d->qscale= s->qscale; } static inline void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegEncContext *best, int type, PutBitContext pb[2], PutBitContext pb2[2], PutBitContext tex_pb[2], int *dmin, int *next_block, int motion_x, int motion_y) { int score; uint8_t *dest_backup[3]; copy_context_before_encode(s, backup, type); s->block= s->blocks[*next_block]; s->pb= pb[*next_block]; if(s->data_partitioning){ s->pb2 = pb2 [*next_block]; s->tex_pb= tex_pb[*next_block]; } if(*next_block){ memcpy(dest_backup, s->dest, sizeof(s->dest)); s->dest[0] = s->rd_scratchpad; s->dest[1] = s->rd_scratchpad + 16*s->linesize; s->dest[2] = s->rd_scratchpad + 16*s->linesize + 8; assert(s->linesize >= 32); //FIXME } encode_mb(s, motion_x, motion_y); score= put_bits_count(&s->pb); if(s->data_partitioning){ score+= put_bits_count(&s->pb2); score+= put_bits_count(&s->tex_pb); } if(s->avctx->mb_decision == FF_MB_DECISION_RD){ MPV_decode_mb(s, s->block); score *= s->lambda2; score += sse_mb(s) << FF_LAMBDA_SHIFT; } if(*next_block){ memcpy(s->dest, dest_backup, sizeof(s->dest)); } if(score<*dmin){ *dmin= score; *next_block^=1; copy_context_after_encode(best, s, type); } } static int sse(MpegEncContext *s, uint8_t *src1, uint8_t *src2, int w, int h, int stride){ uint32_t *sq = squareTbl + 256; int acc=0; int x,y; if(w==16 && h==16) return s->dsp.sse[0](NULL, src1, src2, stride, 16); else if(w==8 && h==8) return s->dsp.sse[1](NULL, src1, src2, stride, 8); for(y=0; y<h; y++){ for(x=0; x<w; x++){ acc+= sq[src1[x + y*stride] - src2[x + y*stride]]; } } assert(acc>=0); return acc; } static int sse_mb(MpegEncContext *s){ int w= 16; int h= 16; if(s->mb_x*16 + 16 > s->width ) w= s->width - s->mb_x*16; if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; if(w==16 && h==16) if(s->avctx->mb_cmp == FF_CMP_NSSE){ return s->dsp.nsse[0](s, s->new_picture.data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, s->dest[0], s->linesize, 16) +s->dsp.nsse[1](s, s->new_picture.data[1] + s->mb_x*8 + s->mb_y*s->uvlinesize*8,s->dest[1], s->uvlinesize, 8) +s->dsp.nsse[1](s, s->new_picture.data[2] + s->mb_x*8 + s->mb_y*s->uvlinesize*8,s->dest[2], s->uvlinesize, 8); }else{ return s->dsp.sse[0](NULL, s->new_picture.data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, s->dest[0], s->linesize, 16) +s->dsp.sse[1](NULL, s->new_picture.data[1] + s->mb_x*8 + s->mb_y*s->uvlinesize*8,s->dest[1], s->uvlinesize, 8) +s->dsp.sse[1](NULL, s->new_picture.data[2] + s->mb_x*8 + s->mb_y*s->uvlinesize*8,s->dest[2], s->uvlinesize, 8); } else return sse(s, s->new_picture.data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, s->dest[0], w, h, s->linesize) +sse(s, s->new_picture.data[1] + s->mb_x*8 + s->mb_y*s->uvlinesize*8,s->dest[1], w>>1, h>>1, s->uvlinesize) +sse(s, s->new_picture.data[2] + s->mb_x*8 + s->mb_y*s->uvlinesize*8,s->dest[2], w>>1, h>>1, s->uvlinesize); } static int pre_estimate_motion_thread(AVCodecContext *c, void *arg){ MpegEncContext *s= arg; s->me.pre_pass=1; s->me.dia_size= s->avctx->pre_dia_size; s->first_slice_line=1; for(s->mb_y= s->end_mb_y-1; s->mb_y >= s->start_mb_y; s->mb_y--) { for(s->mb_x=s->mb_width-1; s->mb_x >=0 ;s->mb_x--) { ff_pre_estimate_p_frame_motion(s, s->mb_x, s->mb_y); } s->first_slice_line=0; } s->me.pre_pass=0; return 0; } static int estimate_motion_thread(AVCodecContext *c, void *arg){ MpegEncContext *s= arg; s->me.dia_size= s->avctx->dia_size; s->first_slice_line=1; for(s->mb_y= s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) { s->mb_x=0; //for block init below ff_init_block_index(s); for(s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) { s->block_index[0]+=2; s->block_index[1]+=2; s->block_index[2]+=2; s->block_index[3]+=2; /* compute motion vector & mb_type and store in context */ if(s->pict_type==B_TYPE) ff_estimate_b_frame_motion(s, s->mb_x, s->mb_y); else ff_estimate_p_frame_motion(s, s->mb_x, s->mb_y); } s->first_slice_line=0; } return 0; } static int mb_var_thread(AVCodecContext *c, void *arg){ MpegEncContext *s= arg; int mb_x, mb_y; for(mb_y=s->start_mb_y; mb_y < s->end_mb_y; mb_y++) { for(mb_x=0; mb_x < s->mb_width; mb_x++) { int xx = mb_x * 16; int yy = mb_y * 16; uint8_t *pix = s->new_picture.data[0] + (yy * s->linesize) + xx; int varc; int sum = s->dsp.pix_sum(pix, s->linesize); varc = (s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500 + 128)>>8; s->current_picture.mb_var [s->mb_stride * mb_y + mb_x] = varc; s->current_picture.mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8; s->me.mb_var_sum_temp += varc; } } return 0; } static void write_slice_end(MpegEncContext *s){ if(s->codec_id==CODEC_ID_MPEG4){ if(s->partitioned_frame){ ff_mpeg4_merge_partitions(s); } ff_mpeg4_stuffing(&s->pb); }else if(s->out_format == FMT_MJPEG){ ff_mjpeg_stuffing(&s->pb); } align_put_bits(&s->pb); flush_put_bits(&s->pb); if((s->flags&CODEC_FLAG_PASS1) && !s->partitioned_frame) s->misc_bits+= get_bits_diff(s); } static int encode_thread(AVCodecContext *c, void *arg){ MpegEncContext *s= arg; int mb_x, mb_y, pdif = 0; int i, j; MpegEncContext best_s, backup_s; uint8_t bit_buf[2][MAX_MB_BYTES]; uint8_t bit_buf2[2][MAX_MB_BYTES]; uint8_t bit_buf_tex[2][MAX_MB_BYTES]; PutBitContext pb[2], pb2[2], tex_pb[2]; //printf("%d->%dn", s->resync_mb_y, s->end_mb_y); for(i=0; i<2; i++){ init_put_bits(&pb [i], bit_buf [i], MAX_MB_BYTES); init_put_bits(&pb2 [i], bit_buf2 [i], MAX_MB_BYTES); init_put_bits(&tex_pb[i], bit_buf_tex[i], MAX_MB_BYTES); } s->last_bits= put_bits_count(&s->pb); s->mv_bits=0; s->misc_bits=0; s->i_tex_bits=0; s->p_tex_bits=0; s->i_count=0; s->f_count=0; s->b_count=0; s->skip_count=0; for(i=0; i<3; i++){ /* init last dc values */ /* note: quant matrix value (8) is implied here */ s->last_dc[i] = 128 << s->intra_dc_precision; s->current_picture_ptr->error[i] = 0; } s->mb_skip_run = 0; memset(s->last_mv, 0, sizeof(s->last_mv)); s->last_mv_dir = 0; switch(s->codec_id){ case CODEC_ID_H263: case CODEC_ID_H263P: case CODEC_ID_FLV1: s->gob_index = ff_h263_get_gob_height(s); break; case CODEC_ID_MPEG4: if(s->partitioned_frame) ff_mpeg4_init_partitions(s); break; } s->resync_mb_x=0; s->resync_mb_y=0; s->first_slice_line = 1; s->ptr_lastgob = s->pb.buf; for(mb_y= s->start_mb_y; mb_y < s->end_mb_y; mb_y++) { // printf("row %d at %Xn", s->mb_y, (int)s); s->mb_x=0; s->mb_y= mb_y; ff_set_qscale(s, s->qscale); ff_init_block_index(s); for(mb_x=0; mb_x < s->mb_width; mb_x++) { int xy= mb_y*s->mb_stride + mb_x; // removed const, H261 needs to adjust this int mb_type= s->mb_type[xy]; // int d; int dmin= INT_MAX; int dir; if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < MAX_MB_BYTES){ av_log(s->avctx, AV_LOG_ERROR, "encoded frame too largen"); return -1; } if(s->data_partitioning){ if( s->pb2 .buf_end - s->pb2 .buf - (put_bits_count(&s-> pb2)>>3) < MAX_MB_BYTES || s->tex_pb.buf_end - s->tex_pb.buf - (put_bits_count(&s->tex_pb )>>3) < MAX_MB_BYTES){ av_log(s->avctx, AV_LOG_ERROR, "encoded frame too largen"); return -1; } } s->mb_x = mb_x; s->mb_y = mb_y; // moved into loop, can get changed by H.261 ff_update_block_index(s); #ifdef CONFIG_H261_ENCODER if(s->codec_id == CODEC_ID_H261){ ff_h261_reorder_mb_index(s); xy= s->mb_y*s->mb_stride + s->mb_x; mb_type= s->mb_type[xy]; } #endif /* write gob / video packet header */ if(s->rtp_mode){ int current_packet_size, is_gob_start; current_packet_size= ((put_bits_count(&s->pb)+7)>>3) - (s->ptr_lastgob - s->pb.buf); is_gob_start= s->avctx->rtp_payload_size && current_packet_size >= s->avctx->rtp_payload_size && mb_y + mb_x>0; if(s->start_mb_y == mb_y && mb_y > 0 && mb_x==0) is_gob_start=1; switch(s->codec_id){ case CODEC_ID_H263: case CODEC_ID_H263P: if(!s->h263_slice_structured) if(s->mb_x || s->mb_y%s->gob_index) is_gob_start=0; break; case CODEC_ID_MPEG2VIDEO: if(s->mb_x==0 && s->mb_y!=0) is_gob_start=1; case CODEC_ID_MPEG1VIDEO: if(s->mb_skip_run) is_gob_start=0; break; } if(is_gob_start){ if(s->start_mb_y != mb_y || mb_x!=0){ write_slice_end(s); if(s->codec_id==CODEC_ID_MPEG4 && s->partitioned_frame){ ff_mpeg4_init_partitions(s); } } assert((put_bits_count(&s->pb)&7) == 0); current_packet_size= pbBufPtr(&s->pb) - s->ptr_lastgob; if(s->avctx->error_rate && s->resync_mb_x + s->resync_mb_y > 0){ int r= put_bits_count(&s->pb)/8 + s->picture_number + 16 + s->mb_x + s->mb_y; int d= 100 / s->avctx->error_rate; if(r % d == 0){ current_packet_size=0; #ifndef ALT_BITSTREAM_WRITER s->pb.buf_ptr= s->ptr_lastgob; #endif assert(pbBufPtr(&s->pb) == s->ptr_lastgob); } } if (s->avctx->rtp_callback){ int number_mb = (mb_y - s->resync_mb_y)*s->mb_width + mb_x - s->resync_mb_x; s->avctx->rtp_callback(s->avctx, s->ptr_lastgob, current_packet_size, number_mb); } switch(s->codec_id){ case CODEC_ID_MPEG4: ff_mpeg4_encode_video_packet_header(s); ff_mpeg4_clean_buffers(s); break; case CODEC_ID_MPEG1VIDEO: case CODEC_ID_MPEG2VIDEO: ff_mpeg1_encode_slice_header(s); ff_mpeg1_clean_buffers(s); break; case CODEC_ID_H263: case CODEC_ID_H263P: h263_encode_gob_header(s, mb_y); break; } if(s->flags&CODEC_FLAG_PASS1){ int bits= put_bits_count(&s->pb); s->misc_bits+= bits - s->last_bits; s->last_bits= bits; } s->ptr_lastgob += current_packet_size; s->first_slice_line=1; s->resync_mb_x=mb_x; s->resync_mb_y=mb_y; } } if( (s->resync_mb_x == s->mb_x) && s->resync_mb_y+1 == s->mb_y){ s->first_slice_line=0; } s->mb_skipped=0; s->dquant=0; //only for QP_RD if(mb_type & (mb_type-1) || (s->flags & CODEC_FLAG_QP_RD)){ // more than 1 MB type possible or CODEC_FLAG_QP_RD int next_block=0; int pb_bits_count, pb2_bits_count, tex_pb_bits_count; copy_context_before_encode(&backup_s, s, -1); backup_s.pb= s->pb; best_s.data_partitioning= s->data_partitioning; best_s.partitioned_frame= s->partitioned_frame; if(s->data_partitioning){ backup_s.pb2= s->pb2; backup_s.tex_pb= s->tex_pb; } if(mb_type&CANDIDATE_MB_TYPE_INTER){ s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_16X16; s->mb_intra= 0; s->mv[0][0][0] = s->p_mv_table[xy][0]; s->mv[0][0][1] = s->p_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_INTER, pb, pb2, tex_pb, &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_INTER_I){ s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(i=0; i<2; i++){ j= s->field_select[0][i] = s->p_field_select_table[i][xy]; s->mv[0][i][0] = s->p_field_mv_table[i][j][xy][0]; s->mv[0][i][1] = s->p_field_mv_table[i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_INTER_I, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_SKIPPED){ s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_16X16; s->mb_intra= 0; s->mv[0][0][0] = 0; s->mv[0][0][1] = 0; encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_SKIPPED, pb, pb2, tex_pb, &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_INTER4V){ s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_8X8; s->mb_intra= 0; for(i=0; i<4; i++){ s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0]; s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1]; } encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_INTER4V, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_FORWARD){ s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_16X16; s->mb_intra= 0; s->mv[0][0][0] = s->b_forw_mv_table[xy][0]; s->mv[0][0][1] = s->b_forw_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_FORWARD, pb, pb2, tex_pb, &dmin, &next_block, s->mv[0][0][0], s->mv[0][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_BACKWARD){ s->mv_dir = MV_DIR_BACKWARD; s->mv_type = MV_TYPE_16X16; s->mb_intra= 0; s->mv[1][0][0] = s->b_back_mv_table[xy][0]; s->mv[1][0][1] = s->b_back_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_BACKWARD, pb, pb2, tex_pb, &dmin, &next_block, s->mv[1][0][0], s->mv[1][0][1]); } if(mb_type&CANDIDATE_MB_TYPE_BIDIR){ s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; s->mv_type = MV_TYPE_16X16; s->mb_intra= 0; s->mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; s->mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; s->mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; s->mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_BIDIR, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_DIRECT){ int mx= s->b_direct_mv_table[xy][0]; int my= s->b_direct_mv_table[xy][1]; s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; s->mb_intra= 0; ff_mpeg4_set_direct_mv(s, mx, my); encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_DIRECT, pb, pb2, tex_pb, &dmin, &next_block, mx, my); } if(mb_type&CANDIDATE_MB_TYPE_FORWARD_I){ s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(i=0; i<2; i++){ j= s->field_select[0][i] = s->b_field_select_table[0][i][xy]; s->mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; s->mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_FORWARD_I, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_BACKWARD_I){ s->mv_dir = MV_DIR_BACKWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(i=0; i<2; i++){ j= s->field_select[1][i] = s->b_field_select_table[1][i][xy]; s->mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; s->mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; } encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_BACKWARD_I, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_BIDIR_I){ s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ j= s->field_select[dir][i] = s->b_field_select_table[dir][i][xy]; s->mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; s->mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; } } encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_BIDIR_I, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } if(mb_type&CANDIDATE_MB_TYPE_INTRA){ s->mv_dir = 0; s->mv_type = MV_TYPE_16X16; s->mb_intra= 1; s->mv[0][0][0] = 0; s->mv[0][0][1] = 0; encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_INTRA, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); if(s->h263_pred || s->h263_aic){ if(best_s.mb_intra) s->mbintra_table[mb_x + mb_y*s->mb_stride]=1; else ff_clean_intra_table_entries(s); //old mode? } } if(s->flags & CODEC_FLAG_QP_RD){ if(best_s.mv_type==MV_TYPE_16X16 && !(best_s.mv_dir&MV_DIRECT)){ const int last_qp= backup_s.qscale; int dquant, dir, qp, dc[6]; DCTELEM ac[6][16]; const int mvdir= (best_s.mv_dir&MV_DIR_BACKWARD) ? 1 : 0; assert(backup_s.dquant == 0); //FIXME intra s->mv_dir= best_s.mv_dir; s->mv_type = MV_TYPE_16X16; s->mb_intra= best_s.mb_intra; s->mv[0][0][0] = best_s.mv[0][0][0]; s->mv[0][0][1] = best_s.mv[0][0][1]; s->mv[1][0][0] = best_s.mv[1][0][0]; s->mv[1][0][1] = best_s.mv[1][0][1]; dir= s->pict_type == B_TYPE ? 2 : 1; if(last_qp + dir > s->avctx->qmax) dir= -dir; for(dquant= dir; dquant<=2 && dquant>=-2; dquant += dir){ qp= last_qp + dquant; if(qp < s->avctx->qmin || qp > s->avctx->qmax) break; backup_s.dquant= dquant; if(s->mb_intra && s->dc_val[0]){ for(i=0; i<6; i++){ dc[i]= s->dc_val[0][ s->block_index[i] ]; memcpy(ac[i], s->ac_val[0][s->block_index[i]], sizeof(DCTELEM)*16); } } encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_INTER /* wrong but unused */, pb, pb2, tex_pb, &dmin, &next_block, s->mv[mvdir][0][0], s->mv[mvdir][0][1]); if(best_s.qscale != qp){ if(s->mb_intra && s->dc_val[0]){ for(i=0; i<6; i++){ s->dc_val[0][ s->block_index[i] ]= dc[i]; memcpy(s->ac_val[0][s->block_index[i]], ac[i], sizeof(DCTELEM)*16); } } if(dir > 0 && dquant==dir){ dquant= 0; dir= -dir; }else break; } } qp= best_s.qscale; s->current_picture.qscale_table[xy]= qp; } } copy_context_after_encode(s, &best_s, -1); pb_bits_count= put_bits_count(&s->pb); flush_put_bits(&s->pb); ff_copy_bits(&backup_s.pb, bit_buf[next_block^1], pb_bits_count); s->pb= backup_s.pb; if(s->data_partitioning){ pb2_bits_count= put_bits_count(&s->pb2); flush_put_bits(&s->pb2); ff_copy_bits(&backup_s.pb2, bit_buf2[next_block^1], pb2_bits_count); s->pb2= backup_s.pb2; tex_pb_bits_count= put_bits_count(&s->tex_pb); flush_put_bits(&s->tex_pb); ff_copy_bits(&backup_s.tex_pb, bit_buf_tex[next_block^1], tex_pb_bits_count); s->tex_pb= backup_s.tex_pb; } s->last_bits= put_bits_count(&s->pb); if (s->out_format == FMT_H263 && s->pict_type!=B_TYPE) ff_h263_update_motion_val(s); if(next_block==0){ //FIXME 16 vs linesize16 s->dsp.put_pixels_tab[0][0](s->dest[0], s->rd_scratchpad , s->linesize ,16); s->dsp.put_pixels_tab[1][0](s->dest[1], s->rd_scratchpad + 16*s->linesize , s->uvlinesize, 8); s->dsp.put_pixels_tab[1][0](s->dest[2], s->rd_scratchpad + 16*s->linesize + 8, s->uvlinesize, 8); } if(s->avctx->mb_decision == FF_MB_DECISION_BITS) MPV_decode_mb(s, s->block); } else { int motion_x, motion_y; s->mv_type=MV_TYPE_16X16; // only one MB-Type possible switch(mb_type){ case CANDIDATE_MB_TYPE_INTRA: s->mv_dir = 0; s->mb_intra= 1; motion_x= s->mv[0][0][0] = 0; motion_y= s->mv[0][0][1] = 0; break; case CANDIDATE_MB_TYPE_INTER: s->mv_dir = MV_DIR_FORWARD; s->mb_intra= 0; motion_x= s->mv[0][0][0] = s->p_mv_table[xy][0]; motion_y= s->mv[0][0][1] = s->p_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_INTER_I: s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(i=0; i<2; i++){ j= s->field_select[0][i] = s->p_field_select_table[i][xy]; s->mv[0][i][0] = s->p_field_mv_table[i][j][xy][0]; s->mv[0][i][1] = s->p_field_mv_table[i][j][xy][1]; } motion_x = motion_y = 0; break; case CANDIDATE_MB_TYPE_INTER4V: s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_8X8; s->mb_intra= 0; for(i=0; i<4; i++){ s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0]; s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1]; } motion_x= motion_y= 0; break; case CANDIDATE_MB_TYPE_DIRECT: s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; s->mb_intra= 0; motion_x=s->b_direct_mv_table[xy][0]; motion_y=s->b_direct_mv_table[xy][1]; ff_mpeg4_set_direct_mv(s, motion_x, motion_y); break; case CANDIDATE_MB_TYPE_BIDIR: s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; s->mb_intra= 0; motion_x=0; motion_y=0; s->mv[0][0][0] = s->b_bidir_forw_mv_table[xy][0]; s->mv[0][0][1] = s->b_bidir_forw_mv_table[xy][1]; s->mv[1][0][0] = s->b_bidir_back_mv_table[xy][0]; s->mv[1][0][1] = s->b_bidir_back_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_BACKWARD: s->mv_dir = MV_DIR_BACKWARD; s->mb_intra= 0; motion_x= s->mv[1][0][0] = s->b_back_mv_table[xy][0]; motion_y= s->mv[1][0][1] = s->b_back_mv_table[xy][1]; break; case CANDIDATE_MB_TYPE_FORWARD: s->mv_dir = MV_DIR_FORWARD; s->mb_intra= 0; motion_x= s->mv[0][0][0] = s->b_forw_mv_table[xy][0]; motion_y= s->mv[0][0][1] = s->b_forw_mv_table[xy][1]; // printf(" %d %d ", motion_x, motion_y); break; case CANDIDATE_MB_TYPE_FORWARD_I: s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(i=0; i<2; i++){ j= s->field_select[0][i] = s->b_field_select_table[0][i][xy]; s->mv[0][i][0] = s->b_field_mv_table[0][i][j][xy][0]; s->mv[0][i][1] = s->b_field_mv_table[0][i][j][xy][1]; } motion_x=motion_y=0; break; case CANDIDATE_MB_TYPE_BACKWARD_I: s->mv_dir = MV_DIR_BACKWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(i=0; i<2; i++){ j= s->field_select[1][i] = s->b_field_select_table[1][i][xy]; s->mv[1][i][0] = s->b_field_mv_table[1][i][j][xy][0]; s->mv[1][i][1] = s->b_field_mv_table[1][i][j][xy][1]; } motion_x=motion_y=0; break; case CANDIDATE_MB_TYPE_BIDIR_I: s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; s->mv_type = MV_TYPE_FIELD; s->mb_intra= 0; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ j= s->field_select[dir][i] = s->b_field_select_table[dir][i][xy]; s->mv[dir][i][0] = s->b_field_mv_table[dir][i][j][xy][0]; s->mv[dir][i][1] = s->b_field_mv_table[dir][i][j][xy][1]; } } motion_x=motion_y=0; break; default: motion_x=motion_y=0; //gcc warning fix av_log(s->avctx, AV_LOG_ERROR, "illegal MB typen"); } encode_mb(s, motion_x, motion_y); // RAL: Update last macroblock type s->last_mv_dir = s->mv_dir; if (s->out_format == FMT_H263 && s->pict_type!=B_TYPE) ff_h263_update_motion_val(s); MPV_decode_mb(s, s->block); } /* clean the MV table in IPS frames for direct mode in B frames */ if(s->mb_intra /* && I,P,S_TYPE */){ s->p_mv_table[xy][0]=0; s->p_mv_table[xy][1]=0; } if(s->flags&CODEC_FLAG_PSNR){ int w= 16; int h= 16; if(s->mb_x*16 + 16 > s->width ) w= s->width - s->mb_x*16; if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; s->current_picture_ptr->error[0] += sse( s, s->new_picture.data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, s->dest[0], w, h, s->linesize); s->current_picture_ptr->error[1] += sse( s, s->new_picture.data[1] + s->mb_x*8 + s->mb_y*s->uvlinesize*8, s->dest[1], w>>1, h>>1, s->uvlinesize); s->current_picture_ptr->error[2] += sse( s, s->new_picture .data[2] + s->mb_x*8 + s->mb_y*s->uvlinesize*8, s->dest[2], w>>1, h>>1, s->uvlinesize); } if(s->loop_filter){ if(s->out_format == FMT_H263) ff_h263_loop_filter(s); } //printf("MB %d %d bitsn", s->mb_x+s->mb_y*s->mb_stride, put_bits_count(&s->pb)); } } //not beautiful here but we must write it before flushing so it has to be here if (s->msmpeg4_version && s->msmpeg4_version<4 && s->pict_type == I_TYPE) msmpeg4_encode_ext_header(s); write_slice_end(s); /* Send the last GOB if RTP */ if (s->avctx->rtp_callback) { int number_mb = (mb_y - s->resync_mb_y)*s->mb_width - s->resync_mb_x; pdif = pbBufPtr(&s->pb) - s->ptr_lastgob; /* Call the RTP callback to send the last GOB */ emms_c(); s->avctx->rtp_callback(s->avctx, s->ptr_lastgob, pdif, number_mb); } return 0; } #define MERGE(field) dst->field += src->field; src->field=0 static void merge_context_after_me(MpegEncContext *dst, MpegEncContext *src){ MERGE(me.scene_change_score); MERGE(me.mc_mb_var_sum_temp); MERGE(me.mb_var_sum_temp); } static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src){ int i; MERGE(dct_count[0]); //note, the other dct vars are not part of the context MERGE(dct_count[1]); MERGE(mv_bits); MERGE(i_tex_bits); MERGE(p_tex_bits); MERGE(i_count); MERGE(f_count); MERGE(b_count); MERGE(skip_count); MERGE(misc_bits); MERGE(error_count); MERGE(padding_bug_score); if(dst->avctx->noise_reduction){ for(i=0; i<64; i++){ MERGE(dct_error_sum[0][i]); MERGE(dct_error_sum[1][i]); } } assert(put_bits_count(&src->pb) % 8 ==0); assert(put_bits_count(&dst->pb) % 8 ==0); ff_copy_bits(&dst->pb, src->pb.buf, put_bits_count(&src->pb)); flush_put_bits(&dst->pb); } static void encode_picture(MpegEncContext *s, int picture_number) { int i; int bits; s->picture_number = picture_number; /* Reset the average MB variance */ s->me.mb_var_sum_temp = s->me.mc_mb_var_sum_temp = 0; /* we need to initialize some time vars before we can encode b-frames */ // RAL: Condition added for MPEG1VIDEO if (s->codec_id == CODEC_ID_MPEG1VIDEO || s->codec_id == CODEC_ID_MPEG2VIDEO || (s->h263_pred && !s->h263_msmpeg4)) ff_set_mpeg4_time(s, s->picture_number); //FIXME rename and use has_b_frames or similar s->me.scene_change_score=0; // s->lambda= s->current_picture_ptr->quality; //FIXME qscale / ... stuff for ME ratedistoration if(s->pict_type==I_TYPE){ if(s->msmpeg4_version >= 3) s->no_rounding=1; else s->no_rounding=0; }else if(s->pict_type!=B_TYPE){ if(s->flipflop_rounding || s->codec_id == CODEC_ID_H263P || s->codec_id == CODEC_ID_MPEG4) s->no_rounding ^= 1; } s->mb_intra=0; //for the rate distortion & bit compare functions for(i=1; i<s->avctx->thread_count; i++){ ff_update_duplicate_context(s->thread_context[i], s); } ff_init_me(s); /* Estimate motion for every MB */ if(s->pict_type != I_TYPE){ s->lambda = (s->lambda * s->avctx->me_penalty_compensation + 128)>>8; s->lambda2= (s->lambda2* s->avctx->me_penalty_compensation + 128)>>8; if(s->pict_type != B_TYPE && s->avctx->me_threshold==0){ if((s->avctx->pre_me && s->last_non_b_pict_type==I_TYPE) || s->avctx->pre_me==2){ s->avctx->execute(s->avctx, pre_estimate_motion_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count); } } s->avctx->execute(s->avctx, estimate_motion_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count); }else /* if(s->pict_type == I_TYPE) */{ /* I-Frame */ for(i=0; i<s->mb_stride*s->mb_height; i++) s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA; if(!s->fixed_qscale){ /* finding spatial complexity for I-frame rate control */ s->avctx->execute(s->avctx, mb_var_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count); } } for(i=1; i<s->avctx->thread_count; i++){ merge_context_after_me(s, s->thread_context[i]); } s->current_picture.mc_mb_var_sum= s->current_picture_ptr->mc_mb_var_sum= s->me.mc_mb_var_sum_temp; s->current_picture. mb_var_sum= s->current_picture_ptr-> mb_var_sum= s->me. mb_var_sum_temp; emms_c(); if(s->me.scene_change_score > s->avctx->scenechange_threshold && s->pict_type == P_TYPE){ s->pict_type= I_TYPE; for(i=0; i<s->mb_stride*s->mb_height; i++) s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA; //printf("Scene change detected, encoding as I Frame %d %dn", s->current_picture.mb_var_sum, s->current_picture.mc_mb_var_sum); } if(!s->umvplus){ if(s->pict_type==P_TYPE || s->pict_type==S_TYPE) { s->f_code= ff_get_best_fcode(s, s->p_mv_table, CANDIDATE_MB_TYPE_INTER); if(s->flags & CODEC_FLAG_INTERLACED_ME){ int a,b; a= ff_get_best_fcode(s, s->p_field_mv_table[0][0], CANDIDATE_MB_TYPE_INTER_I); //FIXME field_select b= ff_get_best_fcode(s, s->p_field_mv_table[1][1], CANDIDATE_MB_TYPE_INTER_I); s->f_code= FFMAX(s->f_code, FFMAX(a,b)); } ff_fix_long_p_mvs(s); ff_fix_long_mvs(s, NULL, 0, s->p_mv_table, s->f_code, CANDIDATE_MB_TYPE_INTER, 0); if(s->flags & CODEC_FLAG_INTERLACED_ME){ int j; for(i=0; i<2; i++){ for(j=0; j<2; j++) ff_fix_long_mvs(s, s->p_field_select_table[i], j, s->p_field_mv_table[i][j], s->f_code, CANDIDATE_MB_TYPE_INTER_I, 0); } } } if(s->pict_type==B_TYPE){ int a, b; a = ff_get_best_fcode(s, s->b_forw_mv_table, CANDIDATE_MB_TYPE_FORWARD); b = ff_get_best_fcode(s, s->b_bidir_forw_mv_table, CANDIDATE_MB_TYPE_BIDIR); s->f_code = FFMAX(a, b); a = ff_get_best_fcode(s, s->b_back_mv_table, CANDIDATE_MB_TYPE_BACKWARD); b = ff_get_best_fcode(s, s->b_bidir_back_mv_table, CANDIDATE_MB_TYPE_BIDIR); s->b_code = FFMAX(a, b); ff_fix_long_mvs(s, NULL, 0, s->b_forw_mv_table, s->f_code, CANDIDATE_MB_TYPE_FORWARD, 1); ff_fix_long_mvs(s, NULL, 0, s->b_back_mv_table, s->b_code, CANDIDATE_MB_TYPE_BACKWARD, 1); ff_fix_long_mvs(s, NULL, 0, s->b_bidir_forw_mv_table, s->f_code, CANDIDATE_MB_TYPE_BIDIR, 1); ff_fix_long_mvs(s, NULL, 0, s->b_bidir_back_mv_table, s->b_code, CANDIDATE_MB_TYPE_BIDIR, 1); if(s->flags & CODEC_FLAG_INTERLACED_ME){ int dir, j; for(dir=0; dir<2; dir++){ for(i=0; i<2; i++){ for(j=0; j<2; j++){ int type= dir ? (CANDIDATE_MB_TYPE_BACKWARD_I|CANDIDATE_MB_TYPE_BIDIR_I) : (CANDIDATE_MB_TYPE_FORWARD_I |CANDIDATE_MB_TYPE_BIDIR_I); ff_fix_long_mvs(s, s->b_field_select_table[dir][i], j, s->b_field_mv_table[dir][i][j], dir ? s->b_code : s->f_code, type, 1); } } } } } } if (!s->fixed_qscale) s->current_picture.quality = ff_rate_estimate_qscale(s); //FIXME pic_ptr if(s->adaptive_quant){ switch(s->codec_id){ case CODEC_ID_MPEG4: ff_clean_mpeg4_qscales(s); break; case CODEC_ID_H263: case CODEC_ID_H263P: case CODEC_ID_FLV1: ff_clean_h263_qscales(s); break; } s->lambda= s->lambda_table[0]; //FIXME broken }else s->lambda= s->current_picture.quality; //printf("%d %dn", s->avctx->global_quality, s->current_picture.quality); update_qscale(s); if(s->qscale < 3 && s->max_qcoeff<=128 && s->pict_type==I_TYPE && !(s->flags & CODEC_FLAG_QSCALE)) s->qscale= 3; //reduce clipping problems if (s->out_format == FMT_MJPEG) { /* for mjpeg, we do include qscale in the matrix */ s->intra_matrix[0] = ff_mpeg1_default_intra_matrix[0]; for(i=1;i<64;i++){ int j= s->dsp.idct_permutation[i]; s->intra_matrix[j] = clip_uint8((ff_mpeg1_default_intra_matrix[i] * s->qscale) >> 3) & 0xFF; } convert_matrix(&s->dsp, s->q_intra_matrix, s->q_intra_matrix16, s->intra_matrix, s->intra_quant_bias, 8, 8, 1); s->qscale= 8; } //FIXME var duplication s->current_picture_ptr->key_frame= s->current_picture.key_frame= s->pict_type == I_TYPE; //FIXME pic_ptr s->current_picture_ptr->pict_type= s->current_picture.pict_type= s->pict_type; if(s->current_picture.key_frame) s->picture_in_gop_number=0; s->last_bits= put_bits_count(&s->pb); switch(s->out_format) { case FMT_MJPEG: mjpeg_picture_header(s); break; #ifdef CONFIG_H261_ENCODER case FMT_H261: ff_h261_encode_picture_header(s, picture_number); break; #endif case FMT_H263: if (s->codec_id == CODEC_ID_WMV2) ff_wmv2_encode_picture_header(s, picture_number); else if (s->h263_msmpeg4) msmpeg4_encode_picture_header(s, picture_number); else if (s->h263_pred) mpeg4_encode_picture_header(s, picture_number); #ifdef CONFIG_RV10_ENCODER else if (s->codec_id == CODEC_ID_RV10) rv10_encode_picture_header(s, picture_number); #endif #ifdef CONFIG_RV20_ENCODER else if (s->codec_id == CODEC_ID_RV20) rv20_encode_picture_header(s, picture_number); #endif else if (s->codec_id == CODEC_ID_FLV1) ff_flv_encode_picture_header(s, picture_number); else h263_encode_picture_header(s, picture_number); break; case FMT_MPEG1: mpeg1_encode_picture_header(s, picture_number); break; case FMT_H264: break; default: assert(0); } bits= put_bits_count(&s->pb); s->header_bits= bits - s->last_bits; for(i=1; i<s->avctx->thread_count; i++){ update_duplicate_context_after_me(s->thread_context[i], s); } s->avctx->execute(s->avctx, encode_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count); for(i=1; i<s->avctx->thread_count; i++){ merge_context_after_encode(s, s->thread_context[i]); } emms_c(); } #endif //CONFIG_ENCODERS static void denoise_dct_c(MpegEncContext *s, DCTELEM *block){ const int intra= s->mb_intra; int i; s->dct_count[intra]++; for(i=0; i<64; i++){ int level= block[i]; if(level){ if(level>0){ s->dct_error_sum[intra][i] += level; level -= s->dct_offset[intra][i]; if(level<0) level=0; }else{ s->dct_error_sum[intra][i] -= level; level += s->dct_offset[intra][i]; if(level>0) level=0; } block[i]= level; } } } #ifdef CONFIG_ENCODERS static int dct_quantize_trellis_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, int *overflow){ const int *qmat; const uint8_t *scantable= s->intra_scantable.scantable; const uint8_t *perm_scantable= s->intra_scantable.permutated; int max=0; unsigned int threshold1, threshold2; int bias=0; int run_tab[65]; int level_tab[65]; int score_tab[65]; int survivor[65]; int survivor_count; int last_run=0; int last_level=0; int last_score= 0; int last_i; int coeff[2][64]; int coeff_count[64]; int qmul, qadd, start_i, last_non_zero, i, dc; const int esc_length= s->ac_esc_length; uint8_t * length; uint8_t * last_length; const int lambda= s->lambda2 >> (FF_LAMBDA_SHIFT - 6); s->dsp.fdct (block); if(s->dct_error_sum) s->denoise_dct(s, block); qmul= qscale*16; qadd= ((qscale-1)|1)*8; if (s->mb_intra) { int q; if (!s->h263_aic) { if (n < 4) q = s->y_dc_scale; else q = s->c_dc_scale; q = q << 3; } else{ /* For AIC we skip quant/dequant of INTRADC */ q = 1 << 3; qadd=0; } /* note: block[0] is assumed to be positive */ block[0] = (block[0] + (q >> 1)) / q; start_i = 1; last_non_zero = 0; qmat = s->q_intra_matrix[qscale]; if(s->mpeg_quant || s->out_format == FMT_MPEG1) bias= 1<<(QMAT_SHIFT-1); length = s->intra_ac_vlc_length; last_length= s->intra_ac_vlc_last_length; } else { start_i = 0; last_non_zero = -1; qmat = s->q_inter_matrix[qscale]; length = s->inter_ac_vlc_length; last_length= s->inter_ac_vlc_last_length; } last_i= start_i; threshold1= (1<<QMAT_SHIFT) - bias - 1; threshold2= (threshold1<<1); for(i=63; i>=start_i; i--) { const int j = scantable[i]; int level = block[j] * qmat[j]; if(((unsigned)(level+threshold1))>threshold2){ last_non_zero = i; break; } } for(i=start_i; i<=last_non_zero; i++) { const int j = scantable[i]; int level = block[j] * qmat[j]; // if( bias+level >= (1<<(QMAT_SHIFT - 3)) // || bias-level >= (1<<(QMAT_SHIFT - 3))){ if(((unsigned)(level+threshold1))>threshold2){ if(level>0){ level= (bias + level)>>QMAT_SHIFT; coeff[0][i]= level; coeff[1][i]= level-1; // coeff[2][k]= level-2; }else{ level= (bias - level)>>QMAT_SHIFT; coeff[0][i]= -level; coeff[1][i]= -level+1; // coeff[2][k]= -level+2; } coeff_count[i]= FFMIN(level, 2); assert(coeff_count[i]); max |=level; }else{ coeff[0][i]= (level>>31)|1; coeff_count[i]= 1; } } *overflow= s->max_qcoeff < max; //overflow might have happened if(last_non_zero < start_i){ memset(block + start_i, 0, (64-start_i)*sizeof(DCTELEM)); return last_non_zero; } score_tab[start_i]= 0; survivor[0]= start_i; survivor_count= 1; for(i=start_i; i<=last_non_zero; i++){ int level_index, j; const int dct_coeff= ABS(block[ scantable[i] ]); const int zero_distoration= dct_coeff*dct_coeff; int best_score=256*256*256*120; for(level_index=0; level_index < coeff_count[i]; level_index++){ int distoration; int level= coeff[level_index][i]; const int alevel= ABS(level); int unquant_coeff; assert(level); if(s->out_format == FMT_H263){ unquant_coeff= alevel*qmul + qadd; }else{ //MPEG1 j= s->dsp.idct_permutation[ scantable[i] ]; //FIXME optimize if(s->mb_intra){ unquant_coeff = (int)( alevel * qscale * s->intra_matrix[j]) >> 3; unquant_coeff = (unquant_coeff - 1) | 1; }else{ unquant_coeff = ((( alevel << 1) + 1) * qscale * ((int) s->inter_matrix[j])) >> 4; unquant_coeff = (unquant_coeff - 1) | 1; } unquant_coeff<<= 3; } distoration= (unquant_coeff - dct_coeff) * (unquant_coeff - dct_coeff) - zero_distoration; level+=64; if((level&(~127)) == 0){ for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distoration + length[UNI_AC_ENC_INDEX(run, level)]*lambda; score += score_tab[i-run]; if(score < best_score){ best_score= score; run_tab[i+1]= run; level_tab[i+1]= level-64; } } if(s->out_format == FMT_H263){ for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distoration + last_length[UNI_AC_ENC_INDEX(run, level)]*lambda; score += score_tab[i-run]; if(score < last_score){ last_score= score; last_run= run; last_level= level-64; last_i= i+1; } } } }else{ distoration += esc_length*lambda; for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distoration + score_tab[i-run]; if(score < best_score){ best_score= score; run_tab[i+1]= run; level_tab[i+1]= level-64; } } if(s->out_format == FMT_H263){ for(j=survivor_count-1; j>=0; j--){ int run= i - survivor[j]; int score= distoration + score_tab[i-run]; if(score < last_score){ last_score= score; last_run= run; last_level= level-64; last_i= i+1; } } } } } score_tab[i+1]= best_score; //Note: there is a vlc code in mpeg4 which is 1 bit shorter then another one with a shorter run and the same level if(last_non_zero <= 27){ for(; survivor_count; survivor_count--){ if(score_tab[ survivor[survivor_count-1] ] <= best_score) break; } }else{ for(; survivor_count; survivor_count--){ if(score_tab[ survivor[survivor_count-1] ] <= best_score + lambda) break; } } survivor[ survivor_count++ ]= i+1; } if(s->out_format != FMT_H263){ last_score= 256*256*256*120; for(i= survivor[0]; i<=last_non_zero + 1; i++){ int score= score_tab[i]; if(i) score += lambda*2; //FIXME exacter? if(score < last_score){ last_score= score; last_i= i; last_level= level_tab[i]; last_run= run_tab[i]; } } } s->coded_score[n] = last_score; dc= ABS(block[0]); last_non_zero= last_i - 1; memset(block + start_i, 0, (64-start_i)*sizeof(DCTELEM)); if(last_non_zero < start_i) return last_non_zero; if(last_non_zero == 0 && start_i == 0){ int best_level= 0; int best_score= dc * dc; for(i=0; i<coeff_count[0]; i++){ int level= coeff[i][0]; int alevel= ABS(level); int unquant_coeff, score, distortion; if(s->out_format == FMT_H263){ unquant_coeff= (alevel*qmul + qadd)>>3; }else{ //MPEG1 unquant_coeff = ((( alevel << 1) + 1) * qscale * ((int) s->inter_matrix[0])) >> 4; unquant_coeff = (unquant_coeff - 1) | 1; } unquant_coeff = (unquant_coeff + 4) >> 3; unquant_coeff<<= 3 + 3; distortion= (unquant_coeff - dc) * (unquant_coeff - dc); level+=64; if((level&(~127)) == 0) score= distortion + last_length[UNI_AC_ENC_INDEX(0, level)]*lambda; else score= distortion + esc_length*lambda; if(score < best_score){ best_score= score; best_level= level - 64; } } block[0]= best_level; s->coded_score[n] = best_score - dc*dc; if(best_level == 0) return -1; else return last_non_zero; } i= last_i; assert(last_level); block[ perm_scantable[last_non_zero] ]= last_level; i -= last_run + 1; for(; i>start_i; i -= run_tab[i] + 1){ block[ perm_scantable[i-1] ]= level_tab[i]; } return last_non_zero; } //#define REFINE_STATS 1 static int16_t basis[64][64]; static void build_basis(uint8_t *perm){ int i, j, x, y; emms_c(); for(i=0; i<8; i++){ for(j=0; j<8; j++){ for(y=0; y<8; y++){ for(x=0; x<8; x++){ double s= 0.25*(1<<BASIS_SHIFT); int index= 8*i + j; int perm_index= perm[index]; if(i==0) s*= sqrt(0.5); if(j==0) s*= sqrt(0.5); basis[perm_index][8*x + y]= lrintf(s * cos((M_PI/8.0)*i*(x+0.5)) * cos((M_PI/8.0)*j*(y+0.5))); } } } } } static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? DCTELEM *block, int16_t *weight, DCTELEM *orig, int n, int qscale){ int16_t rem[64]; DCTELEM d1[64] __align16; const int *qmat; const uint8_t *scantable= s->intra_scantable.scantable; const uint8_t *perm_scantable= s->intra_scantable.permutated; // unsigned int threshold1, threshold2; // int bias=0; int run_tab[65]; int prev_run=0; int prev_level=0; int qmul, qadd, start_i, last_non_zero, i, dc; uint8_t * length; uint8_t * last_length; int lambda; int rle_index, run, q, sum; #ifdef REFINE_STATS static int count=0; static int after_last=0; static int to_zero=0; static int from_zero=0; static int raise=0; static int lower=0; static int messed_sign=0; #endif if(basis[0][0] == 0) build_basis(s->dsp.idct_permutation); qmul= qscale*2; qadd= (qscale-1)|1; if (s->mb_intra) { if (!s->h263_aic) { if (n < 4) q = s->y_dc_scale; else q = s->c_dc_scale; } else{ /* For AIC we skip quant/dequant of INTRADC */ q = 1; qadd=0; } q <<= RECON_SHIFT-3; /* note: block[0] is assumed to be positive */ dc= block[0]*q; // block[0] = (block[0] + (q >> 1)) / q; start_i = 1; qmat = s->q_intra_matrix[qscale]; // if(s->mpeg_quant || s->out_format == FMT_MPEG1) // bias= 1<<(QMAT_SHIFT-1); length = s->intra_ac_vlc_length; last_length= s->intra_ac_vlc_last_length; } else { dc= 0; start_i = 0; qmat = s->q_inter_matrix[qscale]; length = s->inter_ac_vlc_length; last_length= s->inter_ac_vlc_last_length; } last_non_zero = s->block_last_index[n]; #ifdef REFINE_STATS {START_TIMER #endif dc += (1<<(RECON_SHIFT-1)); for(i=0; i<64; i++){ rem[i]= dc - (orig[i]<<RECON_SHIFT); //FIXME use orig dirrectly instead of copying to rem[] } #ifdef REFINE_STATS STOP_TIMER("memset rem[]")} #endif sum=0; for(i=0; i<64; i++){ int one= 36; int qns=4; int w; w= ABS(weight[i]) + qns*one; w= 15 + (48*qns*one + w/2)/w; // 16 .. 63 weight[i] = w; // w=weight[i] = (63*qns + (w/2)) / w; assert(w>0); assert(w<(1<<6)); sum += w*w; } lambda= sum*(uint64_t)s->lambda2 >> (FF_LAMBDA_SHIFT - 6 + 6 + 6 + 6); #ifdef REFINE_STATS {START_TIMER #endif run=0; rle_index=0; for(i=start_i; i<=last_non_zero; i++){ int j= perm_scantable[i]; const int level= block[j]; int coeff; if(level){ if(level<0) coeff= qmul*level - qadd; else coeff= qmul*level + qadd; run_tab[rle_index++]=run; run=0; s->dsp.add_8x8basis(rem, basis[j], coeff); }else{ run++; } } #ifdef REFINE_STATS if(last_non_zero>0){ STOP_TIMER("init rem[]") } } {START_TIMER #endif for(;;){ int best_score=s->dsp.try_8x8basis(rem, weight, basis[0], 0); int best_coeff=0; int best_change=0; int run2, best_unquant_change=0, analyze_gradient; #ifdef REFINE_STATS {START_TIMER #endif analyze_gradient = last_non_zero > 2 || s->avctx->quantizer_noise_shaping >= 3; if(analyze_gradient){ #ifdef REFINE_STATS {START_TIMER #endif for(i=0; i<64; i++){ int w= weight[i]; d1[i] = (rem[i]*w*w + (1<<(RECON_SHIFT+12-1)))>>(RECON_SHIFT+12); } #ifdef REFINE_STATS STOP_TIMER("rem*w*w")} {START_TIMER #endif s->dsp.fdct(d1); #ifdef REFINE_STATS STOP_TIMER("dct")} #endif } if(start_i){ const int level= block[0]; int change, old_coeff; assert(s->mb_intra); old_coeff= q*level; for(change=-1; change<=1; change+=2){ int new_level= level + change; int score, new_coeff; new_coeff= q*new_level; if(new_coeff >= 2048 || new_coeff < 0) continue; score= s->dsp.try_8x8basis(rem, weight, basis[0], new_coeff - old_coeff); if(score<best_score){ best_score= score; best_coeff= 0; best_change= change; best_unquant_change= new_coeff - old_coeff; } } } run=0; rle_index=0; run2= run_tab[rle_index++]; prev_level=0; prev_run=0; for(i=start_i; i<64; i++){ int j= perm_scantable[i]; const int level= block[j]; int change, old_coeff; if(s->avctx->quantizer_noise_shaping < 3 && i > last_non_zero + 1) break; if(level){ if(level<0) old_coeff= qmul*level - qadd; else old_coeff= qmul*level + qadd; run2= run_tab[rle_index++]; //FIXME ! maybe after last }else{ old_coeff=0; run2--; assert(run2>=0 || i >= last_non_zero ); } for(change=-1; change<=1; change+=2){ int new_level= level + change; int score, new_coeff, unquant_change; score=0; if(s->avctx->quantizer_noise_shaping < 2 && ABS(new_level) > ABS(level)) continue; if(new_level){ if(new_level<0) new_coeff= qmul*new_level - qadd; else new_coeff= qmul*new_level + qadd; if(new_coeff >= 2048 || new_coeff <= -2048) continue; //FIXME check for overflow if(level){ if(level < 63 && level > -63){ if(i < last_non_zero) score += length[UNI_AC_ENC_INDEX(run, new_level+64)] - length[UNI_AC_ENC_INDEX(run, level+64)]; else score += last_length[UNI_AC_ENC_INDEX(run, new_level+64)] - last_length[UNI_AC_ENC_INDEX(run, level+64)]; } }else{ assert(ABS(new_level)==1); if(analyze_gradient){ int g= d1[ scantable[i] ]; if(g && (g^new_level) >= 0) continue; } if(i < last_non_zero){ int next_i= i + run2 + 1; int next_level= block[ perm_scantable[next_i] ] + 64; if(next_level&(~127)) next_level= 0; if(next_i < last_non_zero) score += length[UNI_AC_ENC_INDEX(run, 65)] + length[UNI_AC_ENC_INDEX(run2, next_level)] - length[UNI_AC_ENC_INDEX(run + run2 + 1, next_level)]; else score += length[UNI_AC_ENC_INDEX(run, 65)] + last_length[UNI_AC_ENC_INDEX(run2, next_level)] - last_length[UNI_AC_ENC_INDEX(run + run2 + 1, next_level)]; }else{ score += last_length[UNI_AC_ENC_INDEX(run, 65)]; if(prev_level){ score += length[UNI_AC_ENC_INDEX(prev_run, prev_level)] - last_length[UNI_AC_ENC_INDEX(prev_run, prev_level)]; } } } }else{ new_coeff=0; assert(ABS(level)==1); if(i < last_non_zero){ int next_i= i + run2 + 1; int next_level= block[ perm_scantable[next_i] ] + 64; if(next_level&(~127)) next_level= 0; if(next_i < last_non_zero) score += length[UNI_AC_ENC_INDEX(run + run2 + 1, next_level)] - length[UNI_AC_ENC_INDEX(run2, next_level)] - length[UNI_AC_ENC_INDEX(run, 65)]; else score += last_length[UNI_AC_ENC_INDEX(run + run2 + 1, next_level)] - last_length[UNI_AC_ENC_INDEX(run2, next_level)] - length[UNI_AC_ENC_INDEX(run, 65)]; }else{ score += -last_length[UNI_AC_ENC_INDEX(run, 65)]; if(prev_level){ score += last_length[UNI_AC_ENC_INDEX(prev_run, prev_level)] - length[UNI_AC_ENC_INDEX(prev_run, prev_level)]; } } } score *= lambda; unquant_change= new_coeff - old_coeff; assert((score < 100*lambda && score > -100*lambda) || lambda==0); score+= s->dsp.try_8x8basis(rem, weight, basis[j], unquant_change); if(score<best_score){ best_score= score; best_coeff= i; best_change= change; best_unquant_change= unquant_change; } } if(level){ prev_level= level + 64; if(prev_level&(~127)) prev_level= 0; prev_run= run; run=0; }else{ run++; } } #ifdef REFINE_STATS STOP_TIMER("iterative step")} #endif if(best_change){ int j= perm_scantable[ best_coeff ]; block[j] += best_change; if(best_coeff > last_non_zero){ last_non_zero= best_coeff; assert(block[j]); #ifdef REFINE_STATS after_last++; #endif }else{ #ifdef REFINE_STATS if(block[j]){ if(block[j] - best_change){ if(ABS(block[j]) > ABS(block[j] - best_change)){ raise++; }else{ lower++; } }else{ from_zero++; } }else{ to_zero++; } #endif for(; last_non_zero>=start_i; last_non_zero--){ if(block[perm_scantable[last_non_zero]]) break; } } #ifdef REFINE_STATS count++; if(256*256*256*64 % count == 0){ printf("after_last:%d to_zero:%d from_zero:%d raise:%d lower:%d sign:%d xyp:%d/%d/%dn", after_last, to_zero, from_zero, raise, lower, messed_sign, s->mb_x, s->mb_y, s->picture_number); } #endif run=0; rle_index=0; for(i=start_i; i<=last_non_zero; i++){ int j= perm_scantable[i]; const int level= block[j]; if(level){ run_tab[rle_index++]=run; run=0; }else{ run++; } } s->dsp.add_8x8basis(rem, basis[j], best_unquant_change); }else{ break; } } #ifdef REFINE_STATS if(last_non_zero>0){ STOP_TIMER("iterative search") } } #endif return last_non_zero; } static int dct_quantize_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, int *overflow) { int i, j, level, last_non_zero, q, start_i; const int *qmat; const uint8_t *scantable= s->intra_scantable.scantable; int bias; int max=0; unsigned int threshold1, threshold2; s->dsp.fdct (block); if(s->dct_error_sum) s->denoise_dct(s, block); if (s->mb_intra) { if (!s->h263_aic) { if (n < 4) q = s->y_dc_scale; else q = s->c_dc_scale; q = q << 3; } else /* For AIC we skip quant/dequant of INTRADC */ q = 1 << 3; /* note: block[0] is assumed to be positive */ block[0] = (block[0] + (q >> 1)) / q; start_i = 1; last_non_zero = 0; qmat = s->q_intra_matrix[qscale]; bias= s->intra_quant_bias<<(QMAT_SHIFT - QUANT_BIAS_SHIFT); } else { start_i = 0; last_non_zero = -1; qmat = s->q_inter_matrix[qscale]; bias= s->inter_quant_bias<<(QMAT_SHIFT - QUANT_BIAS_SHIFT); } threshold1= (1<<QMAT_SHIFT) - bias - 1; threshold2= (threshold1<<1); for(i=63;i>=start_i;i--) { j = scantable[i]; level = block[j] * qmat[j]; if(((unsigned)(level+threshold1))>threshold2){ last_non_zero = i; break; }else{ block[j]=0; } } for(i=start_i; i<=last_non_zero; i++) { j = scantable[i]; level = block[j] * qmat[j]; // if( bias+level >= (1<<QMAT_SHIFT) // || bias-level >= (1<<QMAT_SHIFT)){ if(((unsigned)(level+threshold1))>threshold2){ if(level>0){ level= (bias + level)>>QMAT_SHIFT; block[j]= level; }else{ level= (bias - level)>>QMAT_SHIFT; block[j]= -level; } max |=level; }else{ block[j]=0; } } *overflow= s->max_qcoeff < max; //overflow might have happened /* we need this permutation so that we correct the IDCT, we only permute the !=0 elements */ if (s->dsp.idct_permutation_type != FF_NO_IDCT_PERM) ff_block_permute(block, s->dsp.idct_permutation, scantable, last_non_zero); return last_non_zero; } #endif //CONFIG_ENCODERS static void dct_unquantize_mpeg1_intra_c(MpegEncContext *s, DCTELEM *block, int n, int qscale) { int i, level, nCoeffs; const uint16_t *quant_matrix; nCoeffs= s->block_last_index[n]; if (n < 4) block[0] = block[0] * s->y_dc_scale; else block[0] = block[0] * s->c_dc_scale; /* XXX: only mpeg1 */ quant_matrix = s->intra_matrix; for(i=1;i<=nCoeffs;i++) { int j= s->intra_scantable.permutated[i]; level = block[j]; if (level) { if (level < 0) { level = -level; level = (int)(level * qscale * quant_matrix[j]) >> 3; level = (level - 1) | 1; level = -level; } else { level = (int)(level * qscale * quant_matrix[j]) >> 3; level = (level - 1) | 1; } block[j] = level; } } } static void dct_unquantize_mpeg1_inter_c(MpegEncContext *s, DCTELEM *block, int n, int qscale) { int i, level, nCoeffs; const uint16_t *quant_matrix; nCoeffs= s->block_last_index[n]; quant_matrix = s->inter_matrix; for(i=0; i<=nCoeffs; i++) { int j= s->intra_scantable.permutated[i]; level = block[j]; if (level) { if (level < 0) { level = -level; level = (((level << 1) + 1) * qscale * ((int) (quant_matrix[j]))) >> 4; level = (level - 1) | 1; level = -level; } else { level = (((level << 1) + 1) * qscale * ((int) (quant_matrix[j]))) >> 4; level = (level - 1) | 1; } block[j] = level; } } } static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s, DCTELEM *block, int n, int qscale) { int i, level, nCoeffs; const uint16_t *quant_matrix; if(s->alternate_scan) nCoeffs= 63; else nCoeffs= s->block_last_index[n]; if (n < 4) block[0] = block[0] * s->y_dc_scale; else block[0] = block[0] * s->c_dc_scale; quant_matrix = s->intra_matrix; for(i=1;i<=nCoeffs;i++) { int j= s->intra_scantable.permutated[i]; level = block[j]; if (level) { if (level < 0) { level = -level; level = (int)(level * qscale * quant_matrix[j]) >> 3; level = -level; } else { level = (int)(level * qscale * quant_matrix[j]) >> 3; } block[j] = level; } } } static void dct_unquantize_mpeg2_inter_c(MpegEncContext *s, DCTELEM *block, int n, int qscale) { int i, level, nCoeffs; const uint16_t *quant_matrix; int sum=-1; if(s->alternate_scan) nCoeffs= 63; else nCoeffs= s->block_last_index[n]; quant_matrix = s->inter_matrix; for(i=0; i<=nCoeffs; i++) { int j= s->intra_scantable.permutated[i]; level = block[j]; if (level) { if (level < 0) { level = -level; level = (((level << 1) + 1) * qscale * ((int) (quant_matrix[j]))) >> 4; level = -level; } else { level = (((level << 1) + 1) * qscale * ((int) (quant_matrix[j]))) >> 4; } block[j] = level; sum+=level; } } block[63]^=sum&1; } static void dct_unquantize_h263_intra_c(MpegEncContext *s, DCTELEM *block, int n, int qscale) { int i, level, qmul, qadd; int nCoeffs; assert(s->block_last_index[n]>=0); qmul = qscale << 1; if (!s->h263_aic) { if (n < 4) block[0] = block[0] * s->y_dc_scale; else block[0] = block[0] * s->c_dc_scale; qadd = (qscale - 1) | 1; }else{ qadd = 0; } if(s->ac_pred) nCoeffs=63; else nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; for(i=1; i<=nCoeffs; i++) { level = block[i]; if (level) { if (level < 0) { level = level * qmul - qadd; } else { level = level * qmul + qadd; } block[i] = level; } } } static void dct_unquantize_h263_inter_c(MpegEncContext *s, DCTELEM *block, int n, int qscale) { int i, level, qmul, qadd; int nCoeffs; assert(s->block_last_index[n]>=0); qadd = (qscale - 1) | 1; qmul = qscale << 1; nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; for(i=0; i<=nCoeffs; i++) { level = block[i]; if (level) { if (level < 0) { level = level * qmul - qadd; } else { level = level * qmul + qadd; } block[i] = level; } } } #ifdef CONFIG_ENCODERS AVCodec h263_encoder = { "h263", CODEC_TYPE_VIDEO, CODEC_ID_H263, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec h263p_encoder = { "h263p", CODEC_TYPE_VIDEO, CODEC_ID_H263P, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec flv_encoder = { "flv", CODEC_TYPE_VIDEO, CODEC_ID_FLV1, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec rv10_encoder = { "rv10", CODEC_TYPE_VIDEO, CODEC_ID_RV10, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec rv20_encoder = { "rv20", CODEC_TYPE_VIDEO, CODEC_ID_RV20, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec mpeg4_encoder = { "mpeg4", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, .capabilities= CODEC_CAP_DELAY, }; AVCodec msmpeg4v1_encoder = { "msmpeg4v1", CODEC_TYPE_VIDEO, CODEC_ID_MSMPEG4V1, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec msmpeg4v2_encoder = { "msmpeg4v2", CODEC_TYPE_VIDEO, CODEC_ID_MSMPEG4V2, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec msmpeg4v3_encoder = { "msmpeg4", CODEC_TYPE_VIDEO, CODEC_ID_MSMPEG4V3, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec wmv1_encoder = { "wmv1", CODEC_TYPE_VIDEO, CODEC_ID_WMV1, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, }; AVCodec mjpeg_encoder = { "mjpeg", CODEC_TYPE_VIDEO, CODEC_ID_MJPEG, sizeof(MpegEncContext), MPV_encode_init, MPV_encode_picture, MPV_encode_end, .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUVJ420P, -1}, }; #endif //CONFIG_ENCODERS