www.pudn.com > jm50g.zip > image.c
/* *********************************************************************** * COPYRIGHT AND WARRANTY INFORMATION * * Copyright 2001, International Telecommunications Union, Geneva * * DISCLAIMER OF WARRANTY * * These software programs are available to the user without any * license fee or royalty on an "as is" basis. The ITU disclaims * any and all warranties, whether express, implied, or * statutory, including any implied warranties of merchantability * or of fitness for a particular purpose. In no event shall the * contributor or the ITU be liable for any incidental, punitive, or * consequential damages of any kind whatsoever arising from the * use of these programs. * * This disclaimer of warranty extends to the user of these programs * and user's customers, employees, agents, transferees, successors, * and assigns. * * The ITU does not represent or warrant that the programs furnished * hereunder are free of infringement of any third-party patents. * Commercial implementations of ITU-T Recommendations, including * shareware, may be subject to royalty fees to patent holders. * Information regarding the ITU-T patent policy is available from * the ITU Web site at http://www.itu.int. * * THIS IS NOT A GRANT OF PATENT RIGHTS - SEE THE ITU-T PATENT POLICY. ************************************************************************ */ /*! *********************************************************************** * \file image.c * * \brief * Decode a Slice * * \author * Main contributors (see contributors.h for copyright, address and affiliation details) * - Inge Lille-Langøy* - Rickard Sjoberg * - Jani Lainema * - Sebastian Purreiter * - Byeong-Moon Jeon * - Thomas Wedi * - Gabi Blaettermann * - Ye-Kui Wang * - Antti Hallapuro *********************************************************************** */ #include "contributors.h" #include #include #include #include #include #include #include "global.h" #include "errorconcealment.h" #include "image.h" #include "mbuffer.h" #include "decodeiff.h" #include "fmo.h" #if _ERROR_CONCEALMENT_ #include "erc_api.h" extern objectBuffer_t *erc_object_list; extern ercVariables_t *erc_errorVar; extern frame erc_recfr; extern int erc_mvperMB; extern struct img_par *erc_img; #endif #ifdef _ADAPT_LAST_GROUP_ int *last_P_no; int *last_P_no_frm; int *last_P_no_fld; #endif /*! *********************************************************************** * \brief * decodes one I- or P-frame * *********************************************************************** */ int decode_one_frame(struct img_par *img,struct inp_par *inp, struct snr_par *snr) { int current_header; Slice *currSlice = img->currentSlice; extern FILE* bits; int Firstcall; #if _ERROR_CONCEALMENT_ int ercStartMB; int ercSegment; frame recfr; int i; #endif time_t ltime1; // for time measurement time_t ltime2; #ifdef WIN32 struct _timeb tstruct1; struct _timeb tstruct2; #else struct timeb tstruct1; struct timeb tstruct2; #endif int tmp_time; // time used by decoding the last frame if ( inp->of_mode == PAR_OF_IFF ) // for Interim File Format rdPictureInfo( bits ); #ifdef WIN32 _ftime (&tstruct1); // start time ms #else ftime (&tstruct1); // start time ms #endif time( <ime1 ); // start time s FmoStartPicture(); img->current_slice_nr = 0; img->current_mb_nr = -4711; // initialized to an impossible value for debugging -- correct value is taken from slice header currSlice->next_header = -8888; // initialized to an impossible value for debugging -- correct value is taken from slice header currSlice->next_eiflag = 0; while ((currSlice->next_header != EOS && currSlice->next_header != SOP)) { // printf ("decode_one_frame: currSlice->next_header %d\n", currSlice->next_header); // set the corresponding read functions start_slice(img, inp); // read new slice Firstcall = (img->max_mb_nr == 0); // A hack for the current byte string format. In the current format, // the picture size is part of the slice header and unknown before // the first slice is read. FMO needs to be initialized with the // picture format. Hence, test the picture size for initialization // and initialize FMO in case of the first slice. current_header = read_new_slice(img, inp); if (Firstcall && (inp->of_mode == PAR_OF_26L || inp->of_mode == PAR_OF_IFF)) { if (currSlice->structure!=0 && currSlice->structure!=3) { FmoInit (img, inp, img->width/16, img->height/8, NULL, 0); // force a default MBAmap } else { FmoInit (img, inp, img->width/16, img->height/16, NULL, 0); // force a default MBAmap } } img->current_mb_nr = img->map_mb_nr = currSlice->start_mb_nr;//GB #ifdef _ABT_FLAG_IN_SLICE_HEADER_ USEABT = currSlice->abt; #endif // printf ("Now processing mb %d\n", img->current_mb_nr); if (current_header == EOS) return EOS; if (img->structure == FRAME) decode_frame_slice(img, inp, current_header); else decode_field_slice(img, inp, current_header); img->current_slice_nr++; } FmoEndPicture(); //deblocking for frame or top/bottom field DeblockFrame( img, imgY, imgUV ) ; if(img->structure != FRAME) //if the previous pict is top or bottom field, { FmoStartPicture(); img->current_slice_nr = 0; currSlice->next_header = -8889; currSlice->next_eiflag = 0; while ((currSlice->next_header != EOS && currSlice->next_header != SOP)) { // set the corresponding read functions start_slice(img, inp); // read new slice current_header = read_new_slice(img, inp); img->current_mb_nr = currSlice->start_mb_nr; if (current_header == EOS) return EOS; decode_field_slice(img, inp, current_header); img->current_slice_nr++; } FmoEndPicture(); //deblocking bottom/top DeblockFrame( img, imgY, imgUV ) ; } #if _ERROR_CONCEALMENT_ recfr.yptr = &imgY[0][0]; recfr.uptr = &imgUV[0][0][0]; recfr.vptr = &imgUV[1][0][0]; //! this is always true at the beginning of a frame ercStartMB = 0; ercSegment = 0; //! mark the start of the first segment ercStartSegment(0, ercSegment, 0 , erc_errorVar); //! generate the segments according to the macroblock map for(i = 1; i max_mb_nr; i++) { if(img->mb_data[i].ei_flag != img->mb_data[i-1].ei_flag) { ercStopSegment(i-1, ercSegment, 0, erc_errorVar); //! stop current segment //! mark current segment as lost or OK if(img->mb_data[i-1].ei_flag) ercMarkCurrSegmentLost(img->width, erc_errorVar); else ercMarkCurrSegmentOK(img->width, erc_errorVar); ercSegment++; //! next segment ercStartSegment(i, ercSegment, 0 , erc_errorVar); //! start new segment ercStartMB = i;//! save start MB for this segment } } //! mark end of the last segent ercStopSegment(img->max_mb_nr-1, ercSegment, 0, erc_errorVar); if(img->mb_data[i-1].ei_flag) ercMarkCurrSegmentLost(img->width, erc_errorVar); else ercMarkCurrSegmentOK(img->width, erc_errorVar); //! call the right error concealment function depending on the frame type. erc_mvperMB /= img->max_mb_nr; erc_img = img; if(img->type == INTRA_IMG || img->type == SI_IMG) // I-frame ercConcealIntraFrame(&recfr, img->width, img->height, erc_errorVar); else ercConcealInterFrame(&recfr, erc_object_list, img->width, img->height, erc_errorVar); #endif if (img->structure == FRAME) // buffer mgt. for frame mode frame_postprocessing(img, inp); else field_postprocessing(img, inp); // reset all interlaced variables if((img->type==B_IMG_1 || img->type==B_IMG_MULT) && !img->disposable_flag) copy_stored_B_motion_info(img); store_field_MV(img); store_field_colB8mode(img); if (p_ref) find_snr(snr,img,p_ref,inp->postfilter); // if ref sequence exist #ifdef WIN32 _ftime (&tstruct2); // end time ms #else ftime (&tstruct2); // end time ms #endif time( <ime2 ); // end time sec tmp_time=(ltime2*1000+tstruct2.millitm) - (ltime1*1000+tstruct1.millitm); tot_time=tot_time + tmp_time; if(img->type == INTRA_IMG) // I picture fprintf(stdout,"%3d(I) %3d %5d %7.4f %7.4f %7.4f %5d\n", frame_no, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time); else if(img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT) // P pictures fprintf(stdout,"%3d(P) %3d %5d %7.4f %7.4f %7.4f %5d\n", frame_no, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time); else if(img->type == SP_IMG_1 || img->type == SP_IMG_MULT) // SP pictures fprintf(stdout,"%3d(SP) %3d %5d %7.4f %7.4f %7.4f %5d\n", frame_no, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time); else if (img->type == SI_IMG) fprintf(stdout,"%3d(SI) %3d %5d %7.4f %7.4f %7.4f %5d\n", frame_no, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time); else if(!img->disposable_flag) // stored B pictures fprintf(stdout,"%3d(BS) %3d %5d %7.4f %7.4f %7.4f %5d\n", frame_no, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time); else // B pictures fprintf(stdout,"%3d(B) %3d %5d %7.4f %7.4f %7.4f %5d\n", frame_no, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time); fflush(stdout); if(img->type == INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT) // I or P pictures copy_Pframe(img, inp->postfilter); // imgY-->imgY_prev, imgUV-->imgUV_prev else if(img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG) // SP pictures copy_Pframe(img, inp->postfilter); // imgY-->imgY_prev, imgUV-->imgUV_prev else if(!img->disposable_flag) // stored B pictures copy_Pframe(img, inp->postfilter); // imgY-->imgY_prev, imgUV-->imgUV_prev else // B pictures write_frame(img,inp->postfilter,p_out); // write image to output YUV file //! TO 19.11.2001 Known Problem: for init_frame we have to know the picture type of the actual frame //! in case the first slice of the P-Frame following the I-Frame was lost we decode this P-Frame but //! do not write it because it was assumed to be an I-Frame in init_frame. So we force the decoder to //! guess the right picture type. This is a hack a should be removed by the time there is a clean //! solution where we do not have to know the picture type for the function init_frame. if(img->type == INTRA_IMG) img->type = INTER_IMG_1; //! End TO 19.11.2001 if(img->type <= INTRA_IMG || img->type >= SI_IMG || !img->disposable_flag) // I or P pictures img->number++; else Bframe_ctr++; // B pictures exit_frame(img, inp); if (img->structure != FRAME) { img->height /= 2; img->height_cr /= 2; } img->current_mb_nr = -4712; // impossible value for debugging, StW img->current_slice_nr = 0; img->last_decoded_pic_id = img->tr; // JVT-D101 return (SOP); } /*! ************************************************************************ * \brief * Find PSNR for all three components.Compare decoded frame with * the original sequence. Read inp->jumpd frames to reflect frame skipping. ************************************************************************ */ void find_snr( struct snr_par *snr, //!< pointer to snr parameters struct img_par *img, //!< pointer to image parameters FILE *p_ref, //!< filestream to reference YUV file int postfilter) //!< postfilterin on (=1) or off (=1) { int i,j; int diff_y,diff_u,diff_v; int uv; int status; static int modulo_ctr_frm=0,modulo_ctr_fld=0,pic_id_old_frm=0,pic_id_old_fld=0; static int modulo_ctr_frm_b=0,modulo_ctr_fld_b=0,pic_id_old_frm_b=0,pic_id_old_fld_b=0; // static int modulo_ctr = 0; // static int modulo_ctr_b = 0; // static int modulo_flag = 0; // static int modulo_flag_b = 0; // static int pic_id_old = 0, pic_id_old_b = 0; Slice *currSlice = img->currentSlice; #ifndef _ADAPT_LAST_GROUP_ byte diff; #endif #ifndef _ADAPT_LAST_GROUP_ if(img->type<=INTRA_IMG || img->type >= SI_IMG || !img->disposable_flag) // I, P pictures frame_no=img->number*P_interval; else // B pictures { diff=nextP_tr-img->tr; frame_no=(img->number-1)*P_interval-diff; } #else // TO 5.11.2001 We do have some problems finding the correct frame in the original sequence // if errors appear. In this case the method of using this p_frame_no, nextP_tr, prevP_tr // variables does not work. So I use the picture_id instead. //calculate frame number if (img->type <= INTRA_IMG || img->type >= SI_IMG || !img->disposable_flag) { if (img->structure == FRAME) { if (currSlice->picture_id < pic_id_old_frm) modulo_ctr_frm++; pic_id_old_frm = currSlice->picture_id; frame_no = currSlice->picture_id + (256*modulo_ctr_frm); } else { if (currSlice->picture_id < pic_id_old_fld) modulo_ctr_fld++; pic_id_old_fld = currSlice->picture_id; frame_no = (currSlice->picture_id + (256*modulo_ctr_fld))/2; } } else { if (img->structure == FRAME) { if (currSlice->picture_id < pic_id_old_frm_b) modulo_ctr_frm_b++; pic_id_old_frm_b = currSlice->picture_id; frame_no = currSlice->picture_id + (256*modulo_ctr_frm_b); } else { if (currSlice->picture_id < pic_id_old_fld_b) modulo_ctr_fld_b++; pic_id_old_fld_b = currSlice->picture_id; frame_no = (currSlice->picture_id + (256*modulo_ctr_fld_b))/2; } } #endif rewind(p_ref); status = fseek (p_ref, frame_no*img->height*img->width*3/2, 0); if (status != 0) { snprintf(errortext, ET_SIZE, "Error in seeking img->tr: %d", img->tr); error(errortext, 500); } for (j=0; j < img->height; j++) for (i=0; i < img->width; i++) imgY_ref[j][i]=fgetc(p_ref); for (uv=0; uv < 2; uv++) for (j=0; j < img->height_cr ; j++) for (i=0; i < img->width_cr; i++) imgUV_ref[uv][j][i]=fgetc(p_ref); img->quad[0]=0; diff_y=0; for (j=0; j < img->height; ++j) { for (i=0; i < img->width; ++i) { diff_y += img->quad[abs(imgY[j][i]-imgY_ref[j][i])]; } } // Chroma diff_u=0; diff_v=0; for (j=0; j < img->height_cr; ++j) { for (i=0; i < img->width_cr; ++i) { diff_u += img->quad[abs(imgUV_ref[0][j][i]-imgUV[0][j][i])]; diff_v += img->quad[abs(imgUV_ref[1][j][i]-imgUV[1][j][i])]; } } // Collecting SNR statistics if (diff_y != 0) snr->snr_y=(float)(10*log10(65025*(float)(img->width)*(img->height)/(float)diff_y)); // luma snr for current frame if (diff_u != 0) snr->snr_u=(float)(10*log10(65025*(float)(img->width)*(img->height)/(float)(4*diff_u))); // chroma snr for current frame if (diff_v != 0) snr->snr_v=(float)(10*log10(65025*(float)(img->width)*(img->height)/(float)(4*diff_v))); // chroma snr for current frame if (img->number == 0) // first { snr->snr_y1=(float)(10*log10(65025*(float)(img->width)*(img->height)/(float)diff_y)); // keep luma snr for first frame snr->snr_u1=(float)(10*log10(65025*(float)(img->width)*(img->height)/(float)(4*diff_u))); // keep chroma snr for first frame snr->snr_v1=(float)(10*log10(65025*(float)(img->width)*(img->height)/(float)(4*diff_v))); // keep chroma snr for first frame snr->snr_ya=snr->snr_y1; snr->snr_ua=snr->snr_u1; snr->snr_va=snr->snr_v1; if (diff_y == 0) snr->snr_ya=50; // need to assign a reasonable large number so avg snr of entire sequece isn't infinite if (diff_u == 0) snr->snr_ua=50; if (diff_v == 0) snr->snr_va=50; } else { snr->snr_ya=(float)(snr->snr_ya*(img->number+Bframe_ctr)+snr->snr_y)/(img->number+Bframe_ctr+1); // average snr chroma for all frames snr->snr_ua=(float)(snr->snr_ua*(img->number+Bframe_ctr)+snr->snr_u)/(img->number+Bframe_ctr+1); // average snr luma for all frames snr->snr_va=(float)(snr->snr_va*(img->number+Bframe_ctr)+snr->snr_v)/(img->number+Bframe_ctr+1); // average snr luma for all frames } } /*! ************************************************************************ * \brief * Interpolation of 1/4 subpixel ************************************************************************ */ void get_block(int ref_frame,int x_pos, int y_pos, struct img_par *img, int block[BLOCK_SIZE][BLOCK_SIZE]) { int dx, dy; int x, y; int i, j; int maxold_x,maxold_y; int result; int pres_x; int pres_y; int tmp_res[4][9]; static const int COEF[6] = { 1, -5, 20, 20, -5, 1 }; dx = x_pos&3; dy = y_pos&3; x_pos = (x_pos-dx)/4; y_pos = (y_pos-dy)/4; maxold_x = img->width-1; maxold_y = img->height-1; if (img->structure==FRAME && img->mb_field) maxold_y = img->height/2 - 1; if (dx == 0 && dy == 0) { /* fullpel position */ for (j = 0; j < BLOCK_SIZE; j++) for (i = 0; i < BLOCK_SIZE; i++) block[i][j] = mref[ref_frame][max(0,min(maxold_y,y_pos+j))][max(0,min(maxold_x,x_pos+i))]; } else { /* other positions */ if (dy == 0) { /* No vertical interpolation */ for (j = 0; j < BLOCK_SIZE; j++) { for (i = 0; i < BLOCK_SIZE; i++) { for (result = 0, x = -2; x < 4; x++) result += mref[ref_frame][max(0,min(maxold_y,y_pos+j))][max(0,min(maxold_x,x_pos+i+x))]*COEF[x+2]; block[i][j] = max(0, min(255, (result+16)/32)); } } if ((dx&1) == 1) { for (j = 0; j < BLOCK_SIZE; j++) for (i = 0; i < BLOCK_SIZE; i++) block[i][j] = (block[i][j] + mref[ref_frame][max(0,min(maxold_y,y_pos+j))][max(0,min(maxold_x,x_pos+i+dx/2))])/2; } } else if (dx == 0) { /* No horizontal interpolation */ for (j = 0; j < BLOCK_SIZE; j++) { for (i = 0; i < BLOCK_SIZE; i++) { for (result = 0, y = -2; y < 4; y++) result += mref[ref_frame][max(0,min(maxold_y,y_pos+j+y))][max(0,min(maxold_x,x_pos+i))]*COEF[y+2]; block[i][j] = max(0, min(255, (result+16)/32)); } } if ((dy&1) == 1) { for (j = 0; j < BLOCK_SIZE; j++) for (i = 0; i < BLOCK_SIZE; i++) block[i][j] = (block[i][j] + mref[ref_frame][max(0,min(maxold_y,y_pos+j+dy/2))][max(0,min(maxold_x,x_pos+i))])/2; } } else if (dx == 2) { /* Vertical & horizontal interpolation */ for (j = -2; j < BLOCK_SIZE+3; j++) { for (i = 0; i < BLOCK_SIZE; i++) for (tmp_res[i][j+2] = 0, x = -2; x < 4; x++) tmp_res[i][j+2] += mref[ref_frame][max(0,min(maxold_y,y_pos+j))][max(0,min(maxold_x,x_pos+i+x))]*COEF[x+2]; } for (j = 0; j < BLOCK_SIZE; j++) { for (i = 0; i < BLOCK_SIZE; i++) { for (result = 0, y = -2; y < 4; y++) result += tmp_res[i][j+y+2]*COEF[y+2]; block[i][j] = max(0, min(255, (result+512)/1024)); } } if ((dy&1) == 1) { for (j = 0; j < BLOCK_SIZE; j++) for (i = 0; i < BLOCK_SIZE; i++) block[i][j] = (block[i][j] + max(0, min(255, (tmp_res[i][j+2+dy/2]+16)/32)))/2; } } else if (dy == 2) { /* Horizontal & vertical interpolation */ for (j = 0; j < BLOCK_SIZE; j++) { for (i = -2; i < BLOCK_SIZE+3; i++) for (tmp_res[j][i+2] = 0, y = -2; y < 4; y++) tmp_res[j][i+2] += mref[ref_frame][max(0,min(maxold_y,y_pos+j+y))][max(0,min(maxold_x,x_pos+i))]*COEF[y+2]; } for (j = 0; j < BLOCK_SIZE; j++) { for (i = 0; i < BLOCK_SIZE; i++) { for (result = 0, x = -2; x < 4; x++) result += tmp_res[j][i+x+2]*COEF[x+2]; block[i][j] = max(0, min(255, (result+512)/1024)); } } if ((dx&1) == 1) { for (j = 0; j < BLOCK_SIZE; j++) for (i = 0; i < BLOCK_SIZE; i++) block[i][j] = (block[i][j] + max(0, min(255, (tmp_res[j][i+2+dx/2]+16)/32)))/2; } } else { /* Diagonal interpolation */ for (j = 0; j < BLOCK_SIZE; j++) { for (i = 0; i < BLOCK_SIZE; i++) { pres_y = dy == 1 ? y_pos+j : y_pos+j+1; pres_y = max(0,min(maxold_y,pres_y)); for (result = 0, x = -2; x < 4; x++) result += mref[ref_frame][pres_y][max(0,min(maxold_x,x_pos+i+x))]*COEF[x+2]; block[i][j] = max(0, min(255, (result+16)/32)); } } for (j = 0; j < BLOCK_SIZE; j++) { for (i = 0; i < BLOCK_SIZE; i++) { pres_x = dx == 1 ? x_pos+i : x_pos+i+1; pres_x = max(0,min(maxold_x,pres_x)); for (result = 0, y = -2; y < 4; y++) result += mref[ref_frame][max(0,min(maxold_y,y_pos+j+y))][pres_x]*COEF[y+2]; block[i][j] = (block[i][j] + max(0, min(255, (result+16)/32))) / 2; } } } } } /*! ************************************************************************ * \brief * Reads new slice (picture) from bit_stream ************************************************************************ */ int read_new_slice(struct img_par *img, struct inp_par *inp) { int current_header; Slice *currSlice = img->currentSlice; // read new slice current_header = currSlice->readSlice(img,inp); return current_header; } /*! ************************************************************************ * \brief * Initializes the parameters for a new frame ************************************************************************ */ void init_frame(struct img_par *img, struct inp_par *inp) { static int first_P = TRUE; int i,j,k,l; // printf ("init_frame: img->tr %d, img->number %d, img->current_mb_nr %d\n", img->tr, img->number, img->current_mb_nr); // img->current_mb_nr=-4713; // don't know why this should make sense. // First MB may be in a lost slcie, slices // may be out-of-order... STW img->current_slice_nr=0; // img->mb_y = img->mb_x = 0; // img->block_y = img->pix_y = img->pix_c_y = 0; // define vertical positions // img->block_x = img->pix_x = img->pix_c_x = 0; // define horizontal positions last_P_no = last_P_no_frm; nextP_tr = nextP_tr_frm; //WYK: When entire non-B frames are lost, adjust the reference buffers //! TO 4.11.2001 Yes, but only for Bitstream mode! We do not loose anything in bitstream mode! //! Should remove this one time! #ifndef AFF //to be fixed later if(inp->of_mode == PAR_OF_26L) //! TO 4.11.2001 just to make sure that this piece of code { //! does not affect any other input mode where this refPicID is not supported j = img->refPicID-img->refPicID_old; if(j<0) j += 16; // img->refPicID is 4 bit, wrapps at 15 if(j > 1) //at least one non-B frame has been lost { for(i=1; i number++; copy2fb(img); } } } #endif if (img->number == 0) // first picture { nextP_tr=prevP_tr=img->tr; } else if(img->type == INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) { #ifdef _ADAPT_LAST_GROUP_ for (i = img->buf_cycle-1; i > 0; i--) last_P_no[i] = last_P_no[i-1]; last_P_no[0] = nextP_tr; #endif nextP_tr=img->tr; if(first_P) // first P picture { first_P = FALSE; P_interval=nextP_tr-prevP_tr; //! TO 4.11.2001 we get problems here in case the first P-Frame was lost } write_prev_Pframe(img, p_out); // imgY_prev, imgUV_prev -> file } if (img->type > SI_IMG) { set_ec_flag(SE_PTYPE); img->type = INTER_IMG_1; // concealed element } img->max_mb_nr = (img->width * img->height) / (MB_BLOCK_SIZE * MB_BLOCK_SIZE); // allocate memory for frame buffers if (img->number == 0) { init_frame_buffers(inp, img); init_global_buffers(inp, img); } for(i=0;i width/BLOCK_SIZE+1;i++) // set edge to -1, indicate nothing to predict from { img->ipredmode[i+1][0]=-1; img->ipredmode[i+1][img->height/BLOCK_SIZE+1]=-1; } for(j=0;j height/BLOCK_SIZE+1;j++) { img->ipredmode[0][j+1]=-1; img->ipredmode[img->width/BLOCK_SIZE+1][j+1]=-1; } for(i=0;i width/BLOCK_SIZE+1;i++) // set edge to -1, indicate nothing to predict from img->ipredmode_frm[i+1][0]=-1; for(j=0;j height/BLOCK_SIZE+1;j++) img->ipredmode_frm[0][j+1]=-1; for(i=0;i width/BLOCK_SIZE+1;i++) // set edge to -1, indicate nothing to predict from img->ipredmode_top[i+1][0]=-1; for(j=0;j<(img->height /2)/BLOCK_SIZE+1;j++) img->ipredmode_top[0][j+1]=-1; for(i=0;i width/BLOCK_SIZE+1;i++) // set edge to -1, indicate nothing to predict from img->ipredmode_bot[i+1][0]=-1; for(j=0;j<(img->height /2)/BLOCK_SIZE+1;j++) img->ipredmode_bot[0][j+1]=-1; for (i=0;i < img->width/MB_BLOCK_SIZE; i++) for (j=0; j < img->height/MB_BLOCK_SIZE; j++) for (k=0;k<4;k++) for (l=0;l<6;l++) img->nz_coeff[i][j][k][l]=-1; // CAVLC if(img->UseConstrainedIntraPred) { for (i=0; i width/MB_BLOCK_SIZE*img->height/MB_BLOCK_SIZE; i++) { img->intra_block[i][0] =img->intra_block[i][1] = img->intra_block[i][2] = img->intra_block[i][3] = 1; } } // WYK: Oct. 8, 2001. Set the slice_nr member of each MB to -1, to ensure correct when packet loss occurs // TO set Macroblock Map (mark all MBs as 'have to be concealed') for(i=0; i max_mb_nr; i++) { img->mb_data[i].slice_nr = -1; img->mb_data[i].ei_flag = 1; } fb = frm; imgY = imgY_frm; imgUV = imgUV_frm; mref = mref_frm; mcef = mcef_frm; img->mv = img->mv_frm; refFrArr = refFrArr_frm; moving_block = moving_block_frm; img->fw_refFrArr = img->fw_refFrArr_frm; img->bw_refFrArr = img->bw_refFrArr_frm; // printf("short size, used, (%d, %d)\n", frm->short_size, frm->short_used ); // JVT-D097 if (img->type!=B_IMG_1 && img->type!=B_IMG_MULT && img->num_slice_groups_minus1 == 1 && img->mb_allocation_map_type > 3) FmoUpdateEvolvingMBAmap (img, inp, MBAmap); // End JVT-D097 } /*! ************************************************************************ * \brief * exit a frame ************************************************************************ */ void exit_frame(struct img_par *img, struct inp_par *inp) { if(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) copy2fb(img); if (img->structure == FRAME) { fld->short_used = frm->short_used * 2; fld->short_size = frm->short_size * 2; } } /*! ************************************************************************ * \brief * write the encoding mode and motion vectors of current * MB to the buffer of the error concealment module. ************************************************************************ */ #if _ERROR_CONCEALMENT_ void ercWriteMBMODEandMV(struct img_par *img,struct inp_par *inp) { extern objectBuffer_t *erc_object_list; int i, ii, jj, currMBNum = img->current_mb_nr; int mbx = xPosMB(currMBNum,img->width), mby = yPosMB(currMBNum,img->width); objectBuffer_t *currRegion, *pRegion; Macroblock *currMB = &img->mb_data[currMBNum]; int*** mv; currRegion = erc_object_list + (currMBNum<<2); if(img->type != B_IMG_1 && img->type != B_IMG_MULT) //non-B frame { for (i=0; i<4; i++) { pRegion = currRegion + i; pRegion->regionMode = (currMB->mb_type ==I16MB ? REGMODE_INTRA : currMB->b8mode[i]==IBLOCK ? REGMODE_INTRA_8x8 : currMB->b8mode[i]==0 ? REGMODE_INTER_COPY : currMB->b8mode[i]==1 ? REGMODE_INTER_PRED : REGMODE_INTER_PRED_8x8); if (currMB->b8mode[i]==0 || currMB->b8mode[i]==IBLOCK) // INTRA OR COPY { pRegion->mv[0] = 0; pRegion->mv[1] = 0; pRegion->mv[2] = 0; } else { if (currMB->b8mode[i]>=5 && currMB->b8mode[i]<=7) // SMALL BLOCKS { ii = 4*mbx + (i%2)*2 + BLOCK_SIZE; jj = 4*mby + (i/2)*2; pRegion->mv[0] = (img->mv[ii][jj][0] + img->mv[ii+1][jj][0] + img->mv[ii][jj+1][0] + img->mv[ii+1][jj+1][0] + 2)/4; pRegion->mv[1] = (img->mv[ii][jj][1] + img->mv[ii+1][jj][1] + img->mv[ii][jj+1][1] + img->mv[ii+1][jj+1][1] + 2)/4; } else // 16x16, 16x8, 8x16, 8x8 { pRegion->mv[0] = img->mv[4*mbx+(i%2)*2+BLOCK_SIZE][4*mby+(i/2)*2][0]; pRegion->mv[1] = img->mv[4*mbx+(i%2)*2+BLOCK_SIZE][4*mby+(i/2)*2][1]; } erc_mvperMB += mabs(pRegion->mv[0]) + mabs(pRegion->mv[1]); pRegion->mv[2] = refFrArr[4*mby+(i/2)*2][4*mbx+(i%2)*2]; } } } else //B-frame { for (i=0; i<4; i++) { ii = 4*mbx + (i%2)*2 + BLOCK_SIZE; jj = 4*mby + (i/2)*2; pRegion = currRegion + i; pRegion->regionMode = (currMB->mb_type ==I16MB ? REGMODE_INTRA : currMB->b8mode[i]==IBLOCK ? REGMODE_INTRA_8x8 : REGMODE_INTER_PRED_8x8); if (currMB->mb_type==I16MB || currMB->b8mode[i]==IBLOCK) // INTRA { pRegion->mv[0] = 0; pRegion->mv[1] = 0; pRegion->mv[2] = 0; } else { mv = (currMB->b8mode[i]==0 && currMB->b8pdir[i]==2 ? img->dbMV : currMB->b8pdir[i]==1 ? img->bw_mv : img->fw_mv); pRegion->mv[0] = (mv[ii][jj][0] + mv[ii+1][jj][0] + mv[ii][jj+1][0] + mv[ii+1][jj+1][0] + 2)/4; pRegion->mv[1] = (mv[ii][jj][1] + mv[ii+1][jj][1] + mv[ii][jj+1][1] + mv[ii+1][jj+1][1] + 2)/4; erc_mvperMB += mabs(pRegion->mv[0]) + mabs(pRegion->mv[1]); if (currMB->b8pdir[i]==0 || (currMB->b8pdir[i]==2 && currMB->b8mode[i]!=0)) // forward or bidirect { pRegion->mv[2] = (img->fw_refFrArr[jj][ii-4]-1+img->buf_cycle) % img->buf_cycle; ///???? is it right, not only "img->fw_refFrArr[jj][ii-4]" } else { pRegion->mv[2] = 0; } } } } } #endif /*! ************************************************************************ * \brief * decodes one slice ************************************************************************ */ void decode_one_slice(struct img_par *img,struct inp_par *inp) { Boolean end_of_slice = FALSE; int read_flag; img->cod_counter=-1; reset_ec_flags(); while (end_of_slice == FALSE) // loop over macroblocks { setRealMB_nr (img); //GB #if TRACE fprintf(p_trace,"\n*********** Pic: %i (I/P) MB: %i Slice: %i Type %d **********\n", img->tr, img->map_mb_nr, img->mb_data[img->map_mb_nr].slice_nr, img->type); #endif // Initializes the current macroblock start_macroblock(img,inp, img->current_mb_nr); // Get the syntax elements from the NAL read_flag = read_one_macroblock(img,inp); if (img->mb_frame_field_flag) init_super_macroblock(img,inp); // decode one macroblock if (img->mb_field) decode_super_macroblock(img,inp); else decode_one_macroblock(img,inp); if (img->mb_frame_field_flag) exit_super_macroblock(img,inp); if(img->mb_frame_field_flag && img->mb_field) img->num_ref_pic_active_fwd >>= 1; #if _ERROR_CONCEALMENT_ ercWriteMBMODEandMV(img,inp); #endif end_of_slice=exit_macroblock(img,inp,(!img->mb_frame_field_flag||img->current_mb_nr%2)); } reset_ec_flags(); if(img->mb_frame_field_flag) img->buf_cycle = inp->buf_cycle+1; // reset the img->buf_cycle, otherwise free will cause problems } void decode_frame_slice(struct img_par *img,struct inp_par *inp, int current_header) { Slice *currSlice = img->currentSlice; if (inp->symbol_mode == CABAC) { init_contexts_MotionInfo (img, currSlice->mot_ctx); init_contexts_TextureInfo(img, currSlice->tex_ctx); } // init new frame if (current_header == SOP) init_frame(img, inp); // do reference frame buffer reordering reorder_mref(img); fill_wp_params(img); #if _ERROR_CONCEALMENT_ if (current_header == SOP) { if (img->number == 0) ercInit(img->width, img->height, 1); // reset all variables of the error concealmnet instance before decoding of every frame. // here the third parameter should, if perfectly, be equal to the number of slices per frame. // using little value is ok, the code will alloc more memory if the slice number is larger ercReset(erc_errorVar, img->max_mb_nr, img->max_mb_nr, img->width); erc_mvperMB = 0; } // decode main slice information if ((current_header == SOP || current_header == SOS) && currSlice->ei_flag == 0) decode_one_slice(img,inp); // setMB-Nr in case this slice was lost if(currSlice->ei_flag) img->current_mb_nr = currSlice->last_mb_nr + 1; #else // decode main slice information if (current_header == SOP || current_header == SOS) decode_one_slice(img,inp); #endif //! This code doesn't workj with FMO or a slice-lossy environment! // if(currSlice->next_eiflag && img->current_mb_nr != img->max_mb_nr) // currSlice->next_header = SOS; } void decode_field_slice(struct img_par *img,struct inp_par *inp, int current_header) { Slice *currSlice = img->currentSlice; if (inp->symbol_mode == CABAC) { init_contexts_MotionInfo (img, currSlice->mot_ctx); init_contexts_TextureInfo(img, currSlice->tex_ctx); } // init new frame if (current_header == SOP) { if (img->structure == TOP_FIELD) init_top(img, inp); // set up field buffer in this function else { init_bottom(img, inp); } } // do reference frame buffer reordering reorder_mref(img); fill_wp_params(img); #if _ERROR_CONCEALMENT_ if (current_header == SOP) { if (img->number == 0) ercInit(img->width, 2*img->height, 1); // reset all variables of the error concealmnet instance before decoding of every frame. // here the third parameter should, if perfectly, be equal to the number of slices per frame. // using little value is ok, the code will alloc more memory if the slice number is larger ercReset(erc_errorVar, img->max_mb_nr, img->max_mb_nr, img->width); erc_mvperMB = 0; } // decode main slice information if ((current_header == SOP || current_header == SOS) && currSlice->ei_flag == 0) decode_one_slice(img,inp); // setMB-Nr in case this slice was lost // if(currSlice->ei_flag) // img->current_mb_nr = currSlice->last_mb_nr + 1; #else // decode main slice information if (current_header == SOP || current_header == SOS) decode_one_slice(img,inp); #endif //! This code doesn't work with FMO or a slice lossy environment or out-of-order slices // if(currSlice->next_eiflag && img->current_mb_nr != img->max_mb_nr) // currSlice->next_header = SOS; } /*! ************************************************************************ * \brief * Initializes the parameters for a new field ************************************************************************ */ void init_top(struct img_par *img, struct inp_par *inp) { static int first_P = TRUE; int i,j; img->buf_cycle *= 2; img->number *= 2; // img->current_mb_nr=-4714; // impossible value, StW img->current_slice_nr=0; img->mb_y = img->mb_x = 0; img->block_y = img->pix_y = img->pix_c_y = 0; // define vertical positions img->block_x = img->pix_x = img->pix_c_x = 0; // define horizontal positions last_P_no = last_P_no_fld; nextP_tr = nextP_tr_fld; //WYK: When entire non-B frames are lost, adjust the reference buffers //! TO 4.11.2001 Yes, but only for Bitstream mode! We do not loose anything in bitstream mode! //! Should remove this one time! #ifndef AFF //to be fixed if(inp->of_mode == PAR_OF_26L) //! TO 4.11.2001 just to make sure that this piece of code { //! does not affect any other input mode where this refPicID is not supported j = img->refPicID-img->refPicID_old; if(j<0) j += 16; // img->refPicID is 4 bit, wrapps at 15 if(j > 1) //at least one non-B frame has been lost { for(i=1; i number++; copy2fb(img); } } } #endif if (img->number == 0) // first picture { nextP_tr=prevP_tr=img->tr; } else if(img->type == INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) // I or P pictures { #ifdef _ADAPT_LAST_GROUP_ for (i = img->buf_cycle; i > 0; i--) last_P_no[i] = last_P_no[i-1]; last_P_no[0] = nextP_tr; #endif nextP_tr=img->tr; if(first_P) // first P picture { first_P = FALSE; P_interval=nextP_tr-prevP_tr; //! TO 4.11.2001 we get problems here in case the first P-Frame was lost } write_prev_Pframe(img, p_out); // imgY_prev, imgUV_prev -> file } if (img->type > SI_IMG) { set_ec_flag(SE_PTYPE); img->type = INTER_IMG_1; // concealed element } img->max_mb_nr = (img->width * img->height) / (MB_BLOCK_SIZE * MB_BLOCK_SIZE); // allocate memory for frame buffers if (img->number == 0) { init_frame_buffers(inp, img); init_global_buffers(inp, img); img->buf_cycle *= 2; } for(i=0;i width/BLOCK_SIZE+1;i++) // set edge to -1, indicate nothing to predict from { img->ipredmode[i+1][0]=-1; img->ipredmode[i+1][img->height/BLOCK_SIZE+1]=-1; } for(j=0;j height/BLOCK_SIZE+1;j++) { img->ipredmode[0][j+1]=-1; img->ipredmode[img->width/BLOCK_SIZE+1][j+1]=-1; } if(img->UseConstrainedIntraPred) { for (i=0; i width/MB_BLOCK_SIZE*img->height/MB_BLOCK_SIZE; i++) { img->intra_block[i][0] =img->intra_block[i][1] = img->intra_block[i][2] = img->intra_block[i][3] = 1; } } // WYK: Oct. 8, 2001. Set the slice_nr member of each MB to -1, to ensure correct when packet loss occurs for(i=0; i max_mb_nr; i++) img->mb_data[i].slice_nr = -1; fb = fld; imgY = imgY_top; imgUV = imgUV_top; mref = mref_fld; mcef = mcef_fld; img->mv = img->mv_top; refFrArr = refFrArr_top; moving_block = moving_block_top; img->fw_refFrArr = img->fw_refFrArr_top; img->bw_refFrArr = img->bw_refFrArr_top; // JVT-D097 if (img->type!=B_IMG_1 && img->type!=B_IMG_MULT && img->num_slice_groups_minus1 == 1 && img->mb_allocation_map_type > 3) FmoUpdateEvolvingMBAmap (img, inp, MBAmap); // End JVT-D097 } /*! ************************************************************************ * \brief * Initializes the parameters for a new field ************************************************************************ */ void init_bottom(struct img_par *img, struct inp_par *inp) { static int first_P = TRUE; int i,j; img->number++; // img->current_mb_nr=-4715; // impossible value, StW img->current_slice_nr=0; img->buf_cycle *= 2; img->mb_y = img->mb_x = 0; img->block_y = img->pix_y = img->pix_c_y = 0; // define vertical positions img->block_x = img->pix_x = img->pix_c_x = 0; // define horizontal positions last_P_no = last_P_no_fld; //WYK: When entire non-B frames are lost, adjust the reference buffers //! TO 4.11.2001 Yes, but only for Bitstream mode! We do not loose anything in bitstream mode! //! Should remove this one time! #ifndef AFF //to be fixed if(inp->of_mode == PAR_OF_26L) //! TO 4.11.2001 just to make sure that this piece of code { //! does not affect any other input mode where this refPicID is not supported j = img->refPicID-img->refPicID_old; if(j<0) j += 16; // img->refPicID is 4 bit, wrapps at 15 if(j > 1) //at least one non-B frame has been lost { for(i=1; i number++; copy2fb(img); } } } #endif if(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) copy2fb(img); // trying to match exit_frame() in frame mode if (!img->mb_frame_field_flag) { if((img->type==B_IMG_1 || img->type==B_IMG_MULT) && !img->disposable_flag) { // copy motion information of stored B-picture for direct mode for (i=0 ; i width/4+4 ; i++) { for (j=0 ; j height/4 ; j++) { img->mv_top[i][j][0] = img->fw_mv[i][j][0]; img->mv_top[i][j][1] = img->fw_mv[i][j][1]; if (i width/4) { refFrArr_top[j][i] = img->fw_refFrArr[j][i]; } } } } } if (img->number == 0) // first picture { nextP_tr=prevP_tr=img->tr; } else if (img->type == INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) // I or P pictures { #ifdef _ADAPT_LAST_GROUP_ if (img->number==1) { for (i = img->buf_cycle; i > 0; i--) last_P_no[i] = last_P_no[i-1]; last_P_no[0] = nextP_tr; } #endif nextP_tr=img->tr; if(first_P) // first P picture { first_P = FALSE; P_interval=nextP_tr-prevP_tr; //! TO 4.11.2001 we get problems here in case the first P-Frame was lost } } if (img->type > SI_IMG) { set_ec_flag(SE_PTYPE); img->type = INTER_IMG_1; // concealed element } img->max_mb_nr = (img->width * img->height) / (MB_BLOCK_SIZE * MB_BLOCK_SIZE); for(i=0;i width/BLOCK_SIZE+1;i++) // set edge to -1, indicate nothing to predict from { img->ipredmode[i+1][0]=-1; img->ipredmode[i+1][img->height/BLOCK_SIZE+1]=-1; } for(j=0;j height/BLOCK_SIZE+1;j++) { img->ipredmode[0][j+1]=-1; img->ipredmode[img->width/BLOCK_SIZE+1][j+1]=-1; } if(img->UseConstrainedIntraPred) { for (i=0; i width/MB_BLOCK_SIZE*img->height/MB_BLOCK_SIZE; i++) { img->intra_block[i][0] =img->intra_block[i][1] = img->intra_block[i][2] = img->intra_block[i][3] = 1; } } // WYK: Oct. 8, 2001. Set the slice_nr member of each MB to -1, to ensure correct when packet loss occurs for(i=0; i max_mb_nr; i++) img->mb_data[i].slice_nr = -1; imgY = imgY_bot; imgUV = imgUV_bot; img->mv = img->mv_bot; moving_block = moving_block_bot; refFrArr = refFrArr_bot; mref = mref_fld; mcef = mcef_fld; img->fw_refFrArr = img->fw_refFrArr_bot; img->bw_refFrArr = img->bw_refFrArr_bot; // JVT-D097 if (img->type!=B_IMG_1 && img->type!=B_IMG_MULT && img->num_slice_groups_minus1 == 1 && img->mb_allocation_map_type > 3) FmoUpdateEvolvingMBAmap (img, inp, MBAmap); // End JVT-D097 } /*! ************************************************************************ * \brief * Prepare field and frame buffer after frame decoding ************************************************************************ */ void frame_postprocessing(struct img_par *img, struct inp_par *inp) { int i; img->height = img->height/2; img->height_cr = img->height_cr/2; img->number *= 2; img->buf_cycle *= 2; fb = fld; mref = mref_fld; mcef = mcef_fld; imgY = imgY_top; imgUV = imgUV_top; if (img->type == INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) // I or P pictures { split_field_top(img); copy2fb(img); } img->number++; imgY = imgY_bot; imgUV = imgUV_bot; if (img->type == INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) // I or P pictures { split_field_bot(img); copy2fb(img); } fb = frm; mref = mref_frm; mcef = mcef_frm; imgY = imgY_frm; imgUV = imgUV_frm; img->height *= 2; img->height_cr *= 2; img->buf_cycle /= 2; img->number /= 2; if((img->number)&&(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag)) { for (i = img->buf_cycle; i > 2; i--) { last_P_no_fld[i] = last_P_no_fld[i-2]; last_P_no_fld[i-1] = last_P_no_fld[i-3]; } last_P_no_fld[0] = nextP_tr_fld+1; last_P_no_fld[1] = nextP_tr_fld; nextP_tr_fld = nextP_tr * 2; nextP_tr_frm = nextP_tr; } } /*! ************************************************************************ * \brief * Extract top field from a frame ************************************************************************ */ void split_field_top(struct img_par *img) { int i; for (i=0; i height; i++) { memcpy(imgY[i], imgY_frm[i*2], img->width); } for (i=0; i height_cr; i++) { memcpy(imgUV[0][i], imgUV_frm[0][i*2], img->width_cr); memcpy(imgUV[1][i], imgUV_frm[1][i*2], img->width_cr); } } /*! ************************************************************************ * \brief * Extract bottom field from a frame ************************************************************************ */ void split_field_bot(struct img_par *img) { int i; for (i=0; i height; i++) { memcpy(imgY[i], imgY_frm[i*2 + 1], img->width); } for (i=0; i height_cr; i++) { memcpy(imgUV[0][i], imgUV_frm[0][i*2 + 1], img->width_cr); memcpy(imgUV[1][i], imgUV_frm[1][i*2 + 1], img->width_cr); } } /*! ************************************************************************ * \brief * Prepare field and frame buffer after field decoding ************************************************************************ */ void field_postprocessing(struct img_par *img, struct inp_par *inp) { int i; combine_field(img); if(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) { img->number++; imgY = imgY_bot; imgUV = imgUV_bot; copy2fb(img); // bottom field img->number--; } fb = frm; mref = mref_frm; imgY = imgY_frm; imgUV = imgUV_frm; if((img->number>1)&&(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag)) { for (i = img->buf_cycle-1; i > 0; i--) last_P_no_frm[i] = last_P_no_frm[i-1]; last_P_no_frm[0] = nextP_tr_frm; nextP_tr_frm = nextP_tr / 2; nextP_tr_fld = nextP_tr; } img->height *= 2; img->height_cr *= 2; img->buf_cycle /= 2; img->number /= 2; img->max_mb_nr = (img->width * img->height) / (MB_BLOCK_SIZE * MB_BLOCK_SIZE); } /*! ************************************************************************ * \brief * Generate a frame from top and bottom fields ************************************************************************ */ void combine_field(struct img_par *img) { int i; for (i=0; i height; i++) { memcpy(imgY_frm[i*2], imgY_top[i], img->width); // top field memcpy(imgY_frm[i*2 + 1], imgY_bot[i], img->width); // bottom field } for (i=0; i height_cr; i++) { memcpy(imgUV_frm[0][i*2], imgUV_top[0][i], img->width_cr); memcpy(imgUV_frm[0][i*2 + 1], imgUV_bot[0][i], img->width_cr); memcpy(imgUV_frm[1][i*2], imgUV_top[1][i], img->width_cr); memcpy(imgUV_frm[1][i*2 + 1], imgUV_bot[1][i], img->width_cr); } } /*! ************************************************************************ * \brief * Store information for use in B picture ************************************************************************ */ void store_field_MV(struct img_par *img) { int i, j; if(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) { if (img->structure != FRAME) { for (i=0 ; i width/4+4 ; i++) { for (j=0 ; j height/8 ; j++) { img->mv_frm[i][2*j][0] = img->mv_frm[i][2*j+1][0] = img->mv_top[i][j][0]; img->mv_frm[i][2*j][0] = img->mv_frm[i][2*j+1][0] = img->mv_top[i][j][0]; img->mv_frm[i][2*j][1] = img->mv_frm[i][2*j+1][1] = img->mv_top[i][j][1]*2; img->mv_frm[i][2*j][1] = img->mv_frm[i][2*j+1][1] = img->mv_top[i][j][1]*2; if (i width/4) { moving_block_frm[2*j+1][i]=moving_block_frm[2*j][i]= ((refFrArr_top[j][i]!=0) || (refFrArr_bot[j][i]!=0) || (abs(img->mv_top[i+4][j][0])>>1) || (abs(img->mv_top[i+4][j][1])>>1) || (abs(img->mv_bot[i+4][j][0])>>1) || (abs(img->mv_bot[i+4][j][1])>>1)); moving_block_top[j][i]=((refFrArr_top[j][i]!=0) || (abs(img->mv_top[i+4][j][0])>>1) || (abs(img->mv_top[i+4][j][1])>>1)); moving_block_bot[j][i]=((refFrArr_bot[j][i]!=0) || (abs(img->mv_bot[i+4][j][0])>>1) || (abs(img->mv_bot[i+4][j][1])>>1)); } if ((i%2 == 0) && (j%2 == 0) && (i width/4)) { if (refFrArr_top[j][i] == -1) { refFrArr_frm[2*j][i] = refFrArr_frm[2*j+1][i] = -1; refFrArr_frm[2*(j+1)][i] = refFrArr_frm[2*(j+1)+1][i] = -1; refFrArr_frm[2*j][i+1] = refFrArr_frm[2*j+1][i+1] = -1; refFrArr_frm[2*(j+1)][i+1] = refFrArr_frm[2*(j+1)+1][i+1] = -1; } else { refFrArr_frm[2*j][i] = refFrArr_frm[2*j+1][i] = (int)(refFrArr_top[j][i]/2); refFrArr_frm[2*(j+1)][i] = refFrArr_frm[2*(j+1)+1][i] = (int)(refFrArr_top[j][i]/2); refFrArr_frm[2*j][i+1] = refFrArr_frm[2*j+1][i+1] = (int)(refFrArr_top[j][i]/2); refFrArr_frm[2*(j+1)][i+1] = refFrArr_frm[2*(j+1)+1][i+1] = (int)(refFrArr_top[j][i]/2); } } } } } else { for (i=0 ; i width/4+4 ; i++) { for (j=0 ; j height/8 ; j++) { img->mv_top[i][j][0] = img->mv_bot[i][j][0] = (int)(img->mv_frm[i][2*j][0]); img->mv_top[i][j][1] = img->mv_bot[i][j][1] = (int)((img->mv_frm[i][2*j][1])/2); if (i width/4) { moving_block_top[j][i]=moving_block_bot[j][i]= ((refFrArr_frm[2*j][i]!=0) || (refFrArr_frm[2*j + 1][i]!=0) || (abs(img->mv_frm[i+4][2*j][0])>>1) || (abs(img->mv_frm[i+4][2*j][1])>>1) || (abs(img->mv_frm[i+4][2*j+1][0])>>1) || (abs(img->mv_frm[i+4][2*j+1][1])>>1)); moving_block_frm[2*j][i]=((refFrArr_frm[2*j][i]!=0) || (abs(img->mv_frm[i+4][2*j][0])>>1) || (abs(img->mv_frm[i+4][2*j][1])>>1) ); moving_block_frm[2*j+1][i]=((refFrArr_frm[2*j+1][i]!=0) || (abs(img->mv_frm[i+4][2*j+1][0])>>1) || (abs(img->mv_frm[i+4][2*j+1][1])>>1)); } if ((i%2 == 0) && (j%2 == 0) && (i width/4)) { if (refFrArr_frm[2*j][i] == -1) { refFrArr_top[j][i] = refFrArr_bot[j][i] = -1; refFrArr_top[j+1][i] = refFrArr_bot[j+1][i] = -1; refFrArr_top[j][i+1] = refFrArr_bot[j][i+1] = -1; refFrArr_top[j+1][i+1] = refFrArr_bot[j+1][i+1] = -1; } else { refFrArr_top[j][i] = refFrArr_bot[j][i] = refFrArr_frm[2*j][i]*2; refFrArr_top[j+1][i] = refFrArr_bot[j+1][i] = refFrArr_frm[2*j][i]*2; refFrArr_top[j][i+1] = refFrArr_bot[j][i+1] = refFrArr_frm[2*j][i]*2; refFrArr_top[j+1][i+1] = refFrArr_bot[j+1][i+1] = refFrArr_frm[2*j][i]*2; } } } } } } } /* void store_direct_moving_flag(struct img par *img) { int i, j; if(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG) for (i=0 ; i width/4 ; i++) for (j=0 ; j height/8 ; j++) { moving_block_frm[2*j][i]=((refFrArr_frm[2*j][i]!=0) || (abs(img->mv_frm[i+4][2*j][0])>>1) || (abs(img->mv_frm[i+4][2*j][1])>>1) ); moving_block_frm[2*j+1][i]=((refFrArr_frm[2*j+1][i]!=0) || (abs(img->mv_frm[i+4][2*j+1][0])>>1) || (abs(img->mv_frm[i+4][2*j+1][1])>>1)); } } */ // ABT int field2frame_mode(int fld_mode) { int frm_mode; static const int field2frame_map[MAXMODE] = {-1, 1,1,3,3,4,6,6, -1, 7,1, -1, -1}; frm_mode = field2frame_map[fld_mode]; assert(frm_mode>0); return frm_mode; } int frame2field_mode(int frm_mode) { int fld_mode; static const int frame2field_map[MAXMODE] = {-1, 2,5,4,5,5,7,7, -1, 7,2, -1, -1}; fld_mode = frame2field_map[frm_mode]; assert(fld_mode>0); return fld_mode; } void store_field_colB8mode(struct img_par *img) { int i, j; if (USEABT) { if(img->type==INTRA_IMG || img->type == INTER_IMG_1 || img->type == INTER_IMG_MULT || img->type == SP_IMG_1 || img->type == SP_IMG_MULT || img->type == SI_IMG || !img->disposable_flag) { if (img->structure != FRAME) { for (i=0 ; i width/B8_SIZE ; i++) for (j=0 ; j height/MB_BLOCK_SIZE ; j++) colB8mode[FRAME][2*j][i] = colB8mode[FRAME][2*j+1][i] = field2frame_mode(colB8mode[TOP_FIELD][j][i]); } else { for (i=0 ; i width/B8_SIZE ; i++) for (j=0 ; j height/MB_BLOCK_SIZE ; j++) colB8mode[TOP_FIELD][j][i] = colB8mode[BOTTOM_FIELD][j][i] = frame2field_mode(colB8mode[FRAME][2*j][i]); } } } } void copy_stored_B_motion_info(struct img_par *img) { int i,j; // copy motion information of stored B-picture for direct mode if (img->structure != FRAME) { if (img->mb_frame_field_flag) { for (i=0 ; i width/4+4 ; i++) { for (j=0 ; j height/8 ; j++) { img->mv_top[i][j][0] = img->fw_mv_top[i][j][0]; img->mv_top[i][j][1] = img->fw_mv_top[i][j][1]; img->mv_bot[i][j][0] = img->fw_mv_bot[i][j][0]; img->mv_bot[i][j][1] = img->fw_mv_bot[i][j][1]; if (i width/4) { refFrArr_top[j][i] = img->fw_refFrArr_top[j][i]; refFrArr_bot[j][i] = img->fw_refFrArr_bot[j][i]; } } } } else { for (i=0 ; i width/4+4 ; i++) { for (j=0 ; j height/8 ; j++) { img->mv_bot[i][j][0] = img->fw_mv[i][j][0]; img->mv_bot[i][j][1] = img->fw_mv[i][j][1]; if (i width/4) { refFrArr_bot[j][i] = img->fw_refFrArr[j][i]; } } } } } else { for (i=0 ; i width/4+4 ; i++) { for (j=0 ; j height/4 ; j++) { img->mv_frm[i][j][0] = img->fw_mv[i][j][0]; img->mv_frm[i][j][1] = img->fw_mv[i][j][1]; if (i width/4) { refFrArr_frm[j][i] = img->fw_refFrArr[j][i]; } } } } } void reset_wp_params(struct img_par *img) { int i,comp; int log_weight_denom; for (i=0; i luma_log_weight_denom : img->chroma_log_weight_denom; img->wp_weight[0][i][comp] = 1< wp_weight[1][i][comp] = 1< currentSlice; int i, j, n; int comp; int log_weight_denom; int p0, p1, pt; int bframe = (img->type==B_IMG_1 || img->type==B_IMG_MULT); int current_tr; int fwd_refframe_offset; int bwd_refframe_offset; int fwd_ref[MAX_REFERENCE_PICTURES], bwd_ref[MAX_REFERENCE_PICTURES]; int index; int max_bwd_ref, max_fwd_ref; #if 0 if(bframe) { int current_tr = (img->structure==TOP_FIELD || img->structure==BOTTOM_FIELD)?img->tr_fld:2*img->tr_frm; if(img->imgtr_next_P <= current_tr) fwd_refframe_offset = 0; else if (img->structure==FRAME) fwd_refframe_offset = 1; else fwd_refframe_offset = 2; } else { fwd_refframe_offset = 0; } if (bframe && img->disposable_flag) { if(img->structure == TOP_FIELD) bwd_refframe_offset = 1; else bwd_refframe_offset = 0; } else { bwd_refframe_offset = 0; } #define fwd_ref_idx_to_refframe(idx) ((idx)+fwd_refframe_offset) #define bwd_ref_idx_to_refframe(idx) ((idx)+bwd_refframe_offset) #endif if ((img->weighted_bipred_explicit_flag || img->weighted_bipred_implicit_flag) && (img->type == B_IMG_1 || img->type == B_IMG_MULT)) { if (!img->disposable_flag ) { max_bwd_ref = MAX_REFERENCE_PICTURES; max_fwd_ref = MAX_REFERENCE_PICTURES; for (index = 0; index < MAX_REFERENCE_PICTURES; index++) { fwd_ref[index] = index; if (index == 0) n = 1; else if (index == 1) n = 0; else n = index; bwd_ref[index] = n; } } else { max_bwd_ref = 1; max_fwd_ref = MAX_REFERENCE_PICTURES - 1; for (index = 0; index < MAX_REFERENCE_PICTURES - 1; index++) { fwd_ref[index] = index+1; } bwd_ref[0] = 0; // only one possible backwards ref for traditional B picture in current software } } if (img->weighted_bipred_implicit_flag && bframe) { img->luma_log_weight_denom = 7; img->chroma_log_weight_denom = 7; img->wp_round_luma = 64; img->wp_round_chroma = 64; for (i=0; i luma_log_weight_denom : img->chroma_log_weight_denom; img->wp_weight[0][i][comp] = 1< wp_weight[1][i][comp] = 1< luma_log_weight_denom : img->chroma_log_weight_denom; if (img->weighted_bipred_explicit_flag) { img->wbp_weight[0][i][j][comp] = img->wp_weight[0][i][comp]; img->wbp_weight[1][i][j][comp] = img->wp_weight[1][j][comp]; } else if (img->weighted_bipred_implicit_flag) { pt = poc_distance (fwd_ref[i], bwd_ref[j]); if (pt == 0) { img->wbp_weight[0][i][j][comp] = 1< wbp_weight[1][i][j][comp] = 1< wbp_weight[0][i][j][comp] = (p1 << (log_weight_denom+1)) / pt; img->wbp_weight[1][i][j][comp] = (p0 << (log_weight_denom+1)) / pt; // if (comp == 0) // printf ("bpw weight[%d] = %d, %d\n", n, // img->wbp_weight[0][i][j][0], img->wbp_weight[1][i][j][0]); } } } } } } } int poc_distance( int refa, int refb) { return toprefpoc[refb + 1] - toprefpoc[refa + 1]; }