decoder.cpp

来自「gaca源码」· C++ 代码 · 共 1,447 行 · 第 1/4 页

CPP
1,447
字号
         MACROBLOCK *mb = &mbs[y * mb_width + x];
         MACROBLOCK *last_mb = &last_mbs[y * mb_width + x];
         const int fcode_max = (fcode_forward>fcode_backward) ? fcode_forward : fcode_backward;

         if(bs->check_resync_marker(fcode_max  - 1)){
            dword intra_dc_threshold; /* fake variable */
            int bound = read_video_packet_header(bs, fcode_max - 1, &quant, &fcode_forward, &fcode_backward, (int*)&intra_dc_threshold);
            x = bound % mb_width;
            y = bound / mb_width;
                              //reset predicted macroblocks
            p_fmv = p_bmv = zeromv;
         }

         mv = mb->b_mvs[0] = mb->b_mvs[1] = mb->b_mvs[2] = mb->b_mvs[3] = mb->mvs[0] = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] = zeromv;
         mb->quant = quant;

         /*
          * skip if the co-located P_VOP macroblock is not coded
          * if not codec in co-located S_VOP macroblock is _not_
          * automatically skipped
          */

         if(last_mb->mode == MODE_NOT_CODED){
            mb->cbp = 0;
            mb->mode = MODE_FORWARD;
            DecodeInterMacroBlock(mb, x, y, mb->cbp, bs, 0, 0, 1);
            continue;
         }

         if(!bs->GetBit()){
                              //modb=='0'
            const byte modb2 = bs->GetBit();

            mb->mode = get_mbtype(bs);

            if (!modb2)    /* modb=='00' */
               mb->cbp = bs->GetBits(6);
            else
               mb->cbp = 0;

            if (mb->mode && mb->cbp) {
               quant += get_dbquant(bs);
               if (quant > 31)
                  quant = 31;
               else if (quant < 1)
                  quant = 1;
            }
            mb->quant = quant;

            if(interlacing){
               if (mb->cbp) {
                  mb->field_dct = bs->GetBit();
                  DPRINTF(XVID_DEBUG_MB,"decp: field_dct: %i\n", mb->field_dct);
               }

               if (mb->mode) {
                  mb->field_pred = bs->GetBit();
                  DPRINTF(XVID_DEBUG_MB, "decp: field_pred: %i\n", mb->field_pred);

                  if (mb->field_pred) {
                     mb->field_for_top = bs->GetBit();
                     DPRINTF(XVID_DEBUG_MB,"decp: field_for_top: %i\n", mb->field_for_top);
                     mb->field_for_bot = bs->GetBit();
                     DPRINTF(XVID_DEBUG_MB,"decp: field_for_bot: %i\n", mb->field_for_bot);
                  }
               }
            }

         }else{
            mb->mode = MODE_DIRECT_NONE_MV;
            mb->cbp = 0;
         }

         switch(mb->mode){
         case MODE_DIRECT:
            get_b_motion_vector(bs, &mv, 1, zeromv);
                              //flow...
         case MODE_DIRECT_NONE_MV:
            for(i=0; i<4; i++){
               mb->mvs[i].x = (int)((int(TRB) * last_mb->mvs[i].x) / (int)TRD + mv.x);
               mb->b_mvs[i].x = (int) ((mv.x == 0) ?
                  (int(TRB - TRD) * last_mb->mvs[i].x) / (int)TRD :
                  mb->mvs[i].x - last_mb->mvs[i].x);
               mb->mvs[i].y = (int) ((int(TRB) * last_mb->mvs[i].y) / (int)TRD + mv.y);
               mb->b_mvs[i].y = (int) ((mv.y == 0) ?
                  (int(TRB - TRD) * last_mb->mvs[i].y) / int(TRD) :
                  int(mb->mvs[i].y - last_mb->mvs[i].y));
            }
            BFrameInterpolateMBInter(refn[1], refn[0], mb, x, y, bs, 1);
            break;

         case MODE_INTERPOLATE:
            get_b_motion_vector(bs, &mb->mvs[0], fcode_forward, p_fmv);
            p_fmv = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] =   mb->mvs[0];

            get_b_motion_vector(bs, &mb->b_mvs[0], fcode_backward, p_bmv);
            p_bmv = mb->b_mvs[1] = mb->b_mvs[2] = mb->b_mvs[3] = mb->b_mvs[0];

            BFrameInterpolateMBInter(refn[1], refn[0], mb, x, y, bs, 0);
            break;

         case MODE_BACKWARD:
            get_b_motion_vector(bs, &mb->mvs[0], fcode_backward, p_bmv);
            p_bmv = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] =   mb->mvs[0];

            DecodeInterMacroBlock(mb, x, y, mb->cbp, bs, 0, 0, 0);
            break;

         case MODE_FORWARD:
            get_b_motion_vector(bs, &mb->mvs[0], fcode_forward, p_fmv);
            p_fmv = mb->mvs[1] = mb->mvs[2] = mb->mvs[3] =   mb->mvs[0];

            DecodeInterMacroBlock(mb, x, y, mb->cbp, bs, 0, 0, 1);
            break;

         default:
            DPRINTF(XVID_DEBUG_ERROR,"Not supported B-frame mb_type = %i\n", mb->mode);
         }
      }
   }
   PROF_E(PROF_FRM_B);
}

//----------------------------
/* perform post processing if necessary, and output the image */
/*
void S_decoder::Output(IMAGE *img, xvid_dec_frame_t *frame, xvid_dec_stats_t *stats, int coding_type){

   //image_output(img, width, height, edged_width, (byte**)frame->output.plane, (unsigned int*)frame->output.stride, frame->output.csp, interlacing);
   yv12_to_bgr((byte*)frame->output.plane, frame->output.stride, img->y, img->u, img->v, edged_width, edged_width/2, width, height, false);

   if(stats){
      stats->type = coding2type(coding_type);
      stats->data.vop.time_base = (int)time_base;
      stats->data.vop.time_increment = 0; //XXX: todo
   }
}
*/

//----------------------------

int S_decoder::Decode(xvid_dec_frame_t *frame, xvid_dec_stats_t *stats){

   PROF_S(PROF_DECODE);

   Bitstream bs;
   bool rounding;
   bool reduced_resolution;
   dword quant;
   dword fcode_forward;
   dword fcode_backward;
   dword intra_dc_threshold;
   WARPPOINTS gmc_warp;
   int coding_type;

   frame->img_out = NULL;

   if(XVID_VERSION_MAJOR(frame->version) != 1 || (stats && XVID_VERSION_MAJOR(stats->version) != 1)){ //v1.x.x
      PROF_E(PROF_DECODE);
      return XVID_ERR_VERSION;
   }

   //start_global_timer();

   low_delay_default = (frame->general & XVID_LOWDELAY);
   if((frame->general & XVID_DISCONTINUITY))
      frames = 0;
   /*
#ifdef XVID_CSP_SLICE
   out_frm = (frame->output.csp == XVID_CSP_SLICE) ? &frame->output : NULL;
#endif
   */

   if(frame->length < 0){
                              //decoder flush
      int ret;
                              //if not decoding "low_delay/packed", and this isn't low_delay and
                              // we have a reference frame, then outout the reference frame
      if(!(low_delay_default && packed_mode) && !low_delay && frames>0){
         //Output(&refn[0], frame, stats, last_coding_type);
         frame->img_out = &refn[0];
         frames = 0;
         ret = 0;
      } else {
         if (stats) stats->type = XVID_TYPE_NOTHING;
         ret = XVID_ERR_END;
      }
      //stop_global_timer();
      PROF_E(PROF_DECODE);
      return ret;
   }

   bs.Init(frame->bitstream, frame->length);

                              //XXX: 0x7f is only valid whilst decoding vfw xvid/divx5 avi's
   if(low_delay_default && frame->length == 1 && bs.ShowBits(8) == 0x7f){
      //image_output(&refn[0], width, height, edged_width, (byte**)frame->output.plane, (unsigned int*)frame->output.stride, frame->output.csp, interlacing);
      if(stats)
         stats->type = XVID_TYPE_NOTHING;
      PROF_E(PROF_DECODE);
      return 1;               //one byte consumed
   }

   bool success = false;
   bool output = false;
   bool seen_something = false;

   /*
   cur.Clear(width, height, edged_width, 0, 0, 0);
   refn[0].Clear(width, height, edged_width, 0, 0, 0);
   refn[1].Clear(width, height, edged_width, 0, 0, 0);
   */

repeat:

   coding_type = BitstreamReadHeaders(&bs, rounding, &reduced_resolution, &quant, &fcode_forward, &fcode_backward, &intra_dc_threshold, &gmc_warp);

   //DPRINTF(XVID_DEBUG_HEADER, "coding_type=%i, packed=%i, time=%lli, time_pp=%i, time_bp=%i\n", coding_type, packed_mode, time, time_pp, time_bp);

   if(coding_type == -1){
                              //nothing
      if(success)
         goto done;
      if(stats)
         stats->type = XVID_TYPE_NOTHING;
      PROF_E(PROF_DECODE);
      return bs.Pos()/8;
   }

   if(coding_type == -2 || coding_type == -3){
                              //vol and/or resize

      if(coding_type == -3)
         Resize();
      /*
      if(stats){
         stats->type = XVID_TYPE_VOL;
         stats->data.vol.general = 0;
         //XXX: if (interlacing) stats->data.vol.general |= ++INTERLACING;
         stats->data.vol.width = width;
         stats->data.vol.height = height;
         stats->data.vol.par = aspect_ratio;
         stats->data.vol.par_width = par_width;
         stats->data.vol.par_height = par_height;
         return bs.Pos()/8;   //number of bytes consumed
      }
      */
      goto repeat;
   }
   p_bmv.x = p_bmv.y = p_fmv.y = p_fmv.y = 0;

                              //packed_mode: special-N_VOP treament
   if(packed_mode && coding_type == N_VOP){
      if(low_delay_default && frames > 0){
         //Output(&refn[0], frame, stats, last_coding_type);
         frame->img_out = &refn[0];
         output = true;
      }
                              //ignore otherwise
   }else
   if(coding_type != B_VOP){
      switch(coding_type){
      case I_VOP:
         PROF_S(PROF_FRM_I);
         I_Frame(&bs, reduced_resolution, quant, intra_dc_threshold);
         PROF_E(PROF_FRM_I);
         break;
      case P_VOP:
         P_Frame(&bs, rounding, reduced_resolution, quant, fcode_forward, intra_dc_threshold, NULL);
         break;
      case S_VOP:
                              //not called (or very rare)
         P_Frame(&bs, rounding, reduced_resolution, quant, fcode_forward, intra_dc_threshold, &gmc_warp);
         break;
      case N_VOP:
                              //XXX: not_coded vops are not used for forward prediction we should not swap(last_mbs,mbs)
         cur.Copy(&refn[0], edged_width, height);
         break;
      }
      if(reduced_resolution)
         cur.deblock_rrv(edged_width, mbs, (width + 31) / 32, (height + 31) / 32, mb_width, 16, 0);

                              //note: for packed_mode, output is performed when the special-N_VOP is decoded
      if(!(low_delay_default && packed_mode)){
         if(low_delay){
            //Output(&cur, frame, stats, coding_type);
            frame->img_out = &cur;
            output = true;
         }else
         if(frames > 0){
                              //is the reference frame valid?
                              // output the reference frame
            //Output(&refn[0], frame, stats, last_coding_type);
            frame->img_out = &refn[1];
            output = true;
         }
      }
      refn[0].Swap(&refn[1]);
      cur.Swap(&refn[0]);
      Swap(mbs, last_mbs);
      last_reduced_resolution = reduced_resolution;
      last_coding_type = coding_type;

      frames++;
      seen_something = true;
   }else{
                              //B_VOP
      if(low_delay){
         DPRINTF(XVID_DEBUG_ERROR, "warning: bvop found in low_delay==1 stream\n");
         low_delay = true;
      }

      if(frames < 2){
         /* attemping to decode a bvop without atleast 2 reference frames */
         cur.Print(edged_width, height, 16, 16, "broken b-frame, mising ref frames");
      }else
      if(time_pp <= time_bp){
                              //this occurs when dx50_bvop_compatibility==0 sequences are decoded in vfw
         cur.Print(edged_width, height, 16, 16, "broken b-frame");
      }else{
         B_Frame(&bs, quant, fcode_forward, fcode_backward);
      }
      //Output(&cur, frame, stats, coding_type);
      frame->img_out = &cur;
      output = true;
      frames++;
   }

   bs.ByteAlign();

                              //low_delay_default mode: repeat in packed_mode
   if(low_delay_default && packed_mode && !output && !success){
      success = true;
      goto repeat;
   }
done:
                              //low_delay_default mode: if we've gotten here without outputting anything,
                              // then output the recently decoded frame, or print an error message
   if(low_delay_default && !output){
      if(packed_mode && seen_something){
                              //output the recently decoded frame
         //Output(&refn[0], frame, stats, last_coding_type);
         frame->img_out = &refn[0];
      }else{
         cur.Clear(width, height, edged_width, 0, 128, 128);
         cur.Print(edged_width, height, 16, 16, "warning: nothing to output");
         cur.Print(edged_width, height, 16, 64, "bframe decoder lag");

         //Output(&cur, frame, stats, P_VOP);
         frame->img_out = &cur;
         if(stats)
            stats->type = XVID_TYPE_NOTHING;
      }
   }

   PROF_E(PROF_DECODE);
                              //number of bytes consumed
   return bs.Pos() / 8;
}

//----------------------------

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?