[xiph-commits] r8895 - experimental/derf/theora-exp/lib

tterribe at motherfish-iii.xiph.org tterribe at motherfish-iii.xiph.org
Wed Feb 9 18:06:58 PST 2005


Author: tterribe
Date: 2005-02-09 18:06:56 -0800 (Wed, 09 Feb 2005)
New Revision: 8895

Modified:
   experimental/derf/theora-exp/lib/decode.c
   experimental/derf/theora-exp/lib/state.c
Log:
Continued pipelined decode to include loop filter and border filling.
All that's left is out-of-loop post-processing.


Modified: experimental/derf/theora-exp/lib/decode.c
===================================================================
--- experimental/derf/theora-exp/lib/decode.c	2005-02-09 09:13:37 UTC (rev 8894)
+++ experimental/derf/theora-exp/lib/decode.c	2005-02-10 02:06:56 UTC (rev 8895)
@@ -1181,15 +1181,120 @@
 
 
 
+static int oc_dec_postprocess_init(oc_dec_ctx *_dec){
+  /*pp_level 0: disabled; free any memory used and return*/
+  if(_dec->pp_level<=OC_PP_LEVEL_DISABLED){
+    if(_dec->dc_qis!=NULL){
+      _ogg_free(_dec->dc_qis);
+      _dec->dc_qis=NULL;
+      _ogg_free(_dec->variances);
+      _dec->variances=NULL;
+      _ogg_free(_dec->pp_frame_data);
+      _dec->pp_frame_data=NULL;
+    }
+    return 1;
+  }
+  if(_dec->dc_qis==NULL){
+    /*If we haven't been tracking DC quantization indices, there's no point in
+       starting now.*/
+    if(_dec->state.frame_type!=OC_INTRA_FRAME)return 1;
+    _dec->dc_qis=(unsigned char *)_ogg_malloc(
+     _dec->state.nfrags*sizeof(_dec->dc_qis[0]));
+    memset(_dec->dc_qis,_dec->state.qis[0],_dec->state.nfrags);
+  }
+  else{
+    int           *coded_fragi;
+    int           *coded_fragi_end;
+    unsigned char  qi0;
+    /*Update the DC quantization index of each coded block.*/
+    qi0=(unsigned char)_dec->state.qis[0];
+    coded_fragi_end=_dec->state.coded_fragis+_dec->state.ncoded_fragis[0]+
+     _dec->state.ncoded_fragis[1]+_dec->state.ncoded_fragis[2];
+    for(coded_fragi=_dec->state.coded_fragis;coded_fragi<coded_fragi_end;
+     coded_fragi++){
+      _dec->dc_qis[*coded_fragi]=qi0;
+    }
+  }
+  /*pp_level 1: Stop after updating DC quantization indices.*/
+  if(_dec->pp_level<=OC_PP_LEVEL_TRACKDCQI){
+    if(_dec->variances!=NULL){
+      _ogg_free(_dec->variances);
+      _dec->variances=NULL;
+      _ogg_free(_dec->pp_frame_data);
+      _dec->pp_frame_data=NULL;
+    }
+    return 1;
+  }
+  if(_dec->variances==NULL||
+   _dec->pp_frame_has_chroma!=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC)){
+    size_t frame_sz;
+    frame_sz=_dec->state.info.frame_width*_dec->state.info.frame_height;
+    if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
+      _dec->variances=(ogg_uint32_t *)_ogg_realloc(_dec->variances,
+       _dec->state.fplanes[0].nfrags*sizeof(_dec->variances[0]));
+      _dec->pp_frame_data=(unsigned char *)_ogg_realloc( 
+       _dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
+      _dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
+      _dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
+      _dec->pp_frame_buf[0].ystride=-_dec->pp_frame_buf[0].width;
+      _dec->pp_frame_buf[0].data=_dec->pp_frame_data+
+       (1-_dec->pp_frame_buf[0].height)*_dec->pp_frame_buf[0].ystride;
+    }
+    else{
+      size_t y_sz;
+      size_t c_sz;
+      int    c_w;
+      int    c_h;
+      _dec->variances=(int *)_ogg_realloc(_dec->variances,
+       _dec->state.nfrags*sizeof(_dec->variances[0]));
+      y_sz=frame_sz;
+      c_w=_dec->state.info.frame_width>>!(_dec->state.info.pixel_fmt&1);
+      c_h=_dec->state.info.frame_height>>!(_dec->state.info.pixel_fmt&2);
+      c_sz=c_w*c_h;
+      frame_sz+=c_sz<<1;
+      _dec->pp_frame_data=(unsigned char *)_ogg_realloc( 
+       _dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
+      _dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
+      _dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
+      _dec->pp_frame_buf[0].ystride=_dec->pp_frame_buf[0].width;
+      _dec->pp_frame_buf[0].data=_dec->pp_frame_data;
+      _dec->pp_frame_buf[1].width=c_w;
+      _dec->pp_frame_buf[1].height=c_h;
+      _dec->pp_frame_buf[1].ystride=_dec->pp_frame_buf[1].width;
+      _dec->pp_frame_buf[1].data=_dec->pp_frame_buf[0].data+y_sz;
+      _dec->pp_frame_buf[2].width=c_w;
+      _dec->pp_frame_buf[2].height=c_h;
+      _dec->pp_frame_buf[2].ystride=_dec->pp_frame_buf[2].width;
+      _dec->pp_frame_buf[2].data=_dec->pp_frame_buf[1].data+c_sz;
+      oc_ycbcr_buffer_flip(_dec->pp_frame_buf,_dec->pp_frame_buf);
+    }
+    _dec->pp_frame_has_chroma=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC);
+  }
+  /*If we're not processing chroma, copy the reference frame's chroma planes.*/
+  if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
+    memcpy(_dec->pp_frame_buf+1,
+     _dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]]+1,
+     sizeof(_dec->pp_frame_buf[1])*2);
+  }
+  return 0;
+}
+
+
+
 typedef struct{
   int  ti[3][64];
   int  ebi[3][64];
   int  eob_runs[3][64];
+  int  bounding_values[512];
   int *coded_fragis[3];
   int *uncoded_fragis[3];
+  int  fragy0[3];
+  int  fragy_end[3];
   int  pred_last[3][3];
   int  mcu_nvfrags;
   int  cur_fragy;
+  int  loop_filter;
+  int  pp_level;
 }oc_dec_pipeline_state;
 
 
@@ -1225,6 +1330,21 @@
   }
   /*Set the previous DC predictor to 0 for all color planes and frame types.*/
   memset(_pipe->pred_last,0,sizeof(_pipe->pred_last));
+  /*Initialize the bounding value array for the loop filter.*/
+  _pipe->loop_filter=!oc_state_loop_filter_init(&_dec->state,
+   _pipe->bounding_values+256);
+  /*Initialize any buffers needed for post-processing.
+    We also save the current post-processing level, to guard against the user
+     changing it from a callback.*/
+  if(!oc_dec_postprocess_init(_dec))_pipe->pp_level=_dec->pp_level;
+  /*If we don't have enough information to post-process, disable it, regardless
+     of the user-requested level.*/
+  else{
+    _pipe->pp_level=OC_PP_LEVEL_DISABLED;
+    memcpy(_dec->pp_frame_buf,
+     _dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]],
+     sizeof(_dec->pp_frame_buf[0])*3);
+  }
 }
 
 /*Reconstructs all coded fragments in a single MCU (one or two super block
@@ -1253,8 +1373,9 @@
     /*Compute the first and last fragment row of the current MCU for this
        plane.*/
     frag_shift=pli!=0&&!(_dec->state.info.pixel_fmt&2);
-    fragy0=_pipe->cur_fragy>>frag_shift;
-    fragy_end=OC_MINI(fragy0+(_pipe->mcu_nvfrags>>frag_shift),fplane->nvfrags);
+    _pipe->fragy0[pli]=fragy0=_pipe->cur_fragy>>frag_shift;
+    _pipe->fragy_end[pli]=fragy_end=
+     OC_MINI(fragy0+(_pipe->mcu_nvfrags>>frag_shift),fplane->nvfrags);
     ncoded_fragis[pli]=0;
     pred_last=_pipe->pred_last[pli];
     frag=_dec->state.frags+fplane->froffset+(fragy0*fplane->nhfrags);
@@ -1664,117 +1785,24 @@
   }
 }
 
-static int oc_dec_postprocess(oc_dec_ctx *_dec){
-  /*pp_level 0: disabled; free any memory used and return*/
-  if(_dec->pp_level<=OC_PP_LEVEL_DISABLED){
-    if(_dec->dc_qis!=NULL){
-      _ogg_free(_dec->dc_qis);
-      _dec->dc_qis=NULL;
-      _ogg_free(_dec->variances);
-      _dec->variances=NULL;
-      _ogg_free(_dec->pp_frame_data);
-      _dec->pp_frame_data=NULL;
-    }
-    return 1;
-  }
-  if(_dec->dc_qis==NULL){
-    /*If we haven't been tracking DC quantization indices, there's no point in
-       starting now.*/
-    if(_dec->state.frame_type!=OC_INTRA_FRAME)return 1;
-    _dec->dc_qis=(unsigned char *)_ogg_malloc(
-     _dec->state.nfrags*sizeof(_dec->dc_qis[0]));
-    memset(_dec->dc_qis,_dec->state.qis[0],_dec->state.nfrags);
-  }
-  else{
-    int           *coded_fragi;
-    int           *coded_fragi_end;
-    unsigned char  qi0;
-    /*Update the DC quantization index of each coded block.*/
-    qi0=(unsigned char)_dec->state.qis[0];
-    coded_fragi_end=_dec->state.coded_fragis+_dec->state.ncoded_fragis[0]+
-     _dec->state.ncoded_fragis[1]+_dec->state.ncoded_fragis[2];
-    for(coded_fragi=_dec->state.coded_fragis;coded_fragi<coded_fragi_end;
-     coded_fragi++){
-      _dec->dc_qis[*coded_fragi]=qi0;
-    }
-  }
+static void oc_dec_postprocess(oc_dec_ctx *_dec,int _pp_level){
   /*pp_level 1: Stop after updating DC quantization indices.*/
-  if(_dec->pp_level<=OC_PP_LEVEL_TRACKDCQI){
-    if(_dec->variances!=NULL){
-      _ogg_free(_dec->variances);
-      _dec->variances=NULL;
-      _ogg_free(_dec->pp_frame_data);
-      _dec->pp_frame_data=NULL;
-    }
-    return 1;
-  }
-  if(_dec->variances==NULL||
-   _dec->pp_frame_has_chroma!=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC)){
-    size_t frame_sz;
-    frame_sz=_dec->state.info.frame_width*_dec->state.info.frame_height;
-    if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
-      _dec->variances=(ogg_uint32_t *)_ogg_realloc(_dec->variances,
-       _dec->state.fplanes[0].nfrags*sizeof(_dec->variances[0]));
-      _dec->pp_frame_data=(unsigned char *)_ogg_realloc( 
-       _dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
-      _dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
-      _dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
-      _dec->pp_frame_buf[0].ystride=-_dec->pp_frame_buf[0].width;
-      _dec->pp_frame_buf[0].data=_dec->pp_frame_data+
-       (1-_dec->pp_frame_buf[0].height)*_dec->pp_frame_buf[0].ystride;
-    }
-    else{
-      size_t y_sz;
-      size_t c_sz;
-      int    c_w;
-      int    c_h;
-      _dec->variances=(int *)_ogg_realloc(_dec->variances,
-       _dec->state.nfrags*sizeof(_dec->variances[0]));
-      y_sz=frame_sz;
-      c_w=_dec->state.info.frame_width>>!(_dec->state.info.pixel_fmt&1);
-      c_h=_dec->state.info.frame_height>>!(_dec->state.info.pixel_fmt&2);
-      c_sz=c_w*c_h;
-      frame_sz+=c_sz<<1;
-      _dec->pp_frame_data=(unsigned char *)_ogg_realloc( 
-       _dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
-      _dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
-      _dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
-      _dec->pp_frame_buf[0].ystride=_dec->pp_frame_buf[0].width;
-      _dec->pp_frame_buf[0].data=_dec->pp_frame_data;
-      _dec->pp_frame_buf[1].width=c_w;
-      _dec->pp_frame_buf[1].height=c_h;
-      _dec->pp_frame_buf[1].ystride=_dec->pp_frame_buf[1].width;
-      _dec->pp_frame_buf[1].data=_dec->pp_frame_buf[0].data+y_sz;
-      _dec->pp_frame_buf[2].width=c_w;
-      _dec->pp_frame_buf[2].height=c_h;
-      _dec->pp_frame_buf[2].ystride=_dec->pp_frame_buf[2].width;
-      _dec->pp_frame_buf[2].data=_dec->pp_frame_buf[1].data+c_sz;
-      oc_ycbcr_buffer_flip(_dec->pp_frame_buf,_dec->pp_frame_buf);
-    }
-    _dec->pp_frame_has_chroma=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC);
-  }
+  if(_pp_level<=OC_PP_LEVEL_TRACKDCQI)return;
   /*Perform de-blocking in the Y plane.*/
   oc_dec_deblock_plane(_dec,0,_dec->pp_frame_buf,
    _dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]]);
-  if(_dec->pp_level>=OC_PP_LEVEL_DERINGY){
+  if(_pp_level>=OC_PP_LEVEL_DERINGY){
     oc_dec_dering_plane(_dec,0,_dec->pp_frame_buf);
   }
-  /*If we're not processing chroma, copy the reference frame's chroma planes
-     and return.*/
-  if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
-    memcpy(_dec->pp_frame_buf+1,
-     _dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]]+1,
-     sizeof(_dec->pp_frame_buf[1])*2);
-    return 0;
-  }
+  /*If we're not processing chroma, return.*/
+  if(_pp_level<OC_PP_LEVEL_DEBLOCKC)return;
   oc_dec_deblock_plane(_dec,1,_dec->pp_frame_buf,
    _dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]]);
   oc_dec_deblock_plane(_dec,2,_dec->pp_frame_buf,
    _dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]]);
-  if(_dec->pp_level<=OC_PP_LEVEL_DEBLOCKC)return 0;
+  if(_pp_level<=OC_PP_LEVEL_DEBLOCKC)return;
   oc_dec_dering_plane(_dec,1,_dec->pp_frame_buf);
   oc_dec_dering_plane(_dec,2,_dec->pp_frame_buf);
-  return 0;
 }
 
 
@@ -1840,6 +1868,9 @@
     Only proceed if we have a non-empty packet.*/
   if(_op->bytes!=0){
     oc_dec_pipeline_state pipe;
+    int                   refi;
+    int                   pli;
+    int                   notdone;
     oggpackB_readinit(&_dec->opb,_op->packet,_op->bytes);
     ret=oc_dec_frame_header_unpack(_dec);
     if(ret<0)return ret;
@@ -1860,7 +1891,7 @@
         We initialize them to a solid gray here.*/
       _dec->state.ref_frame_idx[OC_FRAME_GOLD]=0;
       _dec->state.ref_frame_idx[OC_FRAME_PREV]=0;
-      _dec->state.ref_frame_idx[OC_FRAME_SELF]=1;
+      _dec->state.ref_frame_idx[OC_FRAME_SELF]=refi=1;
       info=&_dec->state.info;
       yhstride=info->frame_width+2*OC_UMV_PADDING;
       yvstride=info->frame_height+2*OC_UMV_PADDING;
@@ -1871,10 +1902,9 @@
       memset(_dec->state.ref_frame_data,0x80,yplane_sz+2*cplane_sz);
     }
     else{
-      int rfi;
-      for(rfi=0;rfi==_dec->state.ref_frame_idx[OC_FRAME_GOLD]||
-       rfi==_dec->state.ref_frame_idx[OC_FRAME_PREV];rfi++);
-      _dec->state.ref_frame_idx[OC_FRAME_SELF]=rfi;
+      for(refi=0;refi==_dec->state.ref_frame_idx[OC_FRAME_GOLD]||
+       refi==_dec->state.ref_frame_idx[OC_FRAME_PREV];refi++);
+      _dec->state.ref_frame_idx[OC_FRAME_SELF]=refi;
     }
     if(_dec->state.frame_type==OC_INTRA_FRAME){
       oc_dec_mark_all_intra(_dec);
@@ -1899,14 +1929,34 @@
        is decoded is also a good idea.*/
     oc_dec_pipeline_init(_dec,&pipe);
     do{
+      int notstart;
+      int sdelay;
+      int edelay;
       oc_dec_frags_recon_mcu(_dec,&pipe);
-      /*TODO: Loop filter.*/
-      /*TODO: Fill borders.*/
-      /*TODO: Out-of-loop post-processing.
-        What is the required latency of this?*/
+      notstart=pipe.cur_fragy>0;
       pipe.cur_fragy+=pipe.mcu_nvfrags;
+      notdone=pipe.cur_fragy<_dec->state.fplanes[0].nvfrags;
+      for(pli=0;pli<3;pli++){
+        sdelay=edelay=0;
+        if(pipe.loop_filter){
+          sdelay+=notstart;
+          edelay+=notdone;
+          oc_state_loop_filter_frag_rows(&_dec->state,pipe.bounding_values+256,
+           refi,pli,pipe.fragy0[pli]-sdelay,pipe.fragy_end[pli]-edelay);
+        }
+        /*To fill the borders, we have an additional two pixel delay, since a
+           fragment in the next row could filter its top edge, using two pixels
+           from a fragment in this row.
+          But there's no reason to delay a full fragment.*/
+        oc_state_borders_fill_rows(&_dec->state,refi,pli,
+         (pipe.fragy0[pli]-sdelay<<3)-(sdelay<<1),
+         (pipe.fragy_end[pli]-edelay<<3)-(edelay<<1));
+      }
+      /*TODO: Out-of-loop post-processing.*/
     }
-    while(pipe.cur_fragy<_dec->state.fplanes[0].nvfrags);
+    while(notdone);
+    /*Finish filling in the reference frame borders.*/
+    for(pli=0;pli<3;pli++)oc_state_borders_fill_caps(&_dec->state,refi,pli);
     /*Update the reference frame indices.*/
     if(_dec->state.frame_type==OC_INTRA_FRAME){
       /*The new frame becomes both the previous and gold reference frames.*/
@@ -1920,19 +1970,9 @@
       _dec->state.ref_frame_idx[OC_FRAME_PREV]=
        _dec->state.ref_frame_idx[OC_FRAME_SELF];
     }
-    /*Filter block edges.*/
-    oc_state_loop_filter(&_dec->state,OC_FRAME_PREV);
-    /*Fill in the borders from the reconstructed version of the last encoded
-       frame.*/
-    if(_dec->state.ref_frame_idx[OC_FRAME_PREV]>=0){
-      oc_state_borders_fill(&_dec->state,
-       _dec->state.ref_frame_idx[OC_FRAME_PREV]);
-    }
     /*Perform out-of-loop post-processing, if enabled.*/
-    if(oc_dec_postprocess(_dec)){
-      memcpy(_dec->pp_frame_buf,
-       _dec->state.ref_frame_bufs[_dec->state.ref_frame_idx[OC_FRAME_SELF]],
-       sizeof(_dec->pp_frame_buf[0])*3);
+    if(pipe.pp_level>OC_PP_LEVEL_TRACKDCQI){
+      oc_dec_postprocess(_dec,pipe.pp_level);
     }
   }
   /*Update granule position.*/

Modified: experimental/derf/theora-exp/lib/state.c
===================================================================
--- experimental/derf/theora-exp/lib/state.c	2005-02-09 09:13:37 UTC (rev 8894)
+++ experimental/derf/theora-exp/lib/state.c	2005-02-10 02:06:56 UTC (rev 8895)
@@ -545,36 +545,59 @@
 
 /*Duplicates the pixels on the border of the image plane out into the
    surrounding padding for use by unrestricted motion vectors.
-  _iplane:   The image plane to fill the borders of.
-  _hpadding: The amount of padding on each side in the horizontal direction.
-  _vpadding: The amount of padding on each side in the vertical direction.*/
-static void oc_iplane_borders_fill(theora_img_plane *_iplane,
- int _hpadding,int _vpadding){
-  unsigned char *apix;
-  unsigned char *bpix;
-  unsigned char *epix;
-  int            fullw;
-  /*First extend the vertical edges.*/
-  apix=_iplane->data;
-  bpix=_iplane->data+_iplane->width-1;
-  epix=_iplane->data+_iplane->height*_iplane->ystride;
+  This function only adds the left and right borders, and only for the fragment
+   rows specified.
+  _refi: The index of the reference buffer to pad.
+  _pli:  The color plane.
+  _y0:   The Y coordinate of the first row to pad.
+  _yend: The Y coordinate of the row to stop padding at.*/
+void oc_state_borders_fill_rows(oc_theora_state *_state,int _refi,int _pli,
+ int _y0,int _yend){
+  theora_img_plane *iplane;
+  unsigned char    *apix;
+  unsigned char    *bpix;
+  unsigned char    *epix;
+  int               hpadding;
+  hpadding=OC_UMV_PADDING>>(_pli!=0&&!(_state->info.pixel_fmt&1));
+  iplane=_state->ref_frame_bufs[_refi]+_pli;
+  apix=iplane->data+_y0*iplane->ystride;
+  bpix=apix+iplane->width-1;
+  epix=iplane->data+_yend*iplane->ystride;
   /*Note the use of != instead of <, which allows ystride to be negative.*/
   while(apix!=epix){
-    memset(apix-_hpadding,apix[0],_hpadding);
-    memset(bpix+1,bpix[0],_hpadding);
-    apix+=_iplane->ystride;
-    bpix+=_iplane->ystride;
+    memset(apix-hpadding,apix[0],hpadding);
+    memset(bpix+1,bpix[0],hpadding);
+    apix+=iplane->ystride;
+    bpix+=iplane->ystride;
   }
-  /*Next extend the horizontal edges.*/
-  fullw=_iplane->width+(_hpadding<<1);
-  apix=_iplane->data-_hpadding;
-  bpix=_iplane->data+(_iplane->height-1)*_iplane->ystride;
-  epix=apix-_iplane->ystride*_vpadding;
+}
+
+/*Duplicates the pixels on the border of the image plane out into the
+   surrounding padding for use by unrestricted motion vectors.
+  This function only adds the top and bottom borders, and must be called after
+   the left and right borders are added.
+  _refi:      The index of the reference buffer to pad.
+  _pli:       The color plane.*/
+void oc_state_borders_fill_caps(oc_theora_state *_state,int _refi,int _pli){
+  theora_img_plane *iplane;
+  unsigned char    *apix;
+  unsigned char    *bpix;
+  unsigned char    *epix;
+  int               hpadding;
+  int               vpadding;
+  int               fullw;
+  hpadding=OC_UMV_PADDING>>(_pli!=0&&!(_state->info.pixel_fmt&1));
+  vpadding=OC_UMV_PADDING>>(_pli!=0&&!(_state->info.pixel_fmt&2));
+  iplane=_state->ref_frame_bufs[_refi]+_pli;
+  fullw=iplane->width+(hpadding<<1);
+  apix=iplane->data-hpadding;
+  bpix=iplane->data+(iplane->height-1)*iplane->ystride;
+  epix=apix-iplane->ystride*vpadding;
   while(apix!=epix){
-    memcpy(apix-_iplane->ystride,apix,fullw);
-    memcpy(bpix+_iplane->ystride,bpix,fullw);
-    apix-=_iplane->ystride;
-    bpix+=_iplane->ystride;
+    memcpy(apix-iplane->ystride,apix,fullw);
+    memcpy(bpix+iplane->ystride,bpix,fullw);
+    apix-=iplane->ystride;
+    bpix+=iplane->ystride;
   }
 }
 
@@ -583,16 +606,11 @@
   _state: The context containing the reference buffers.
   _refi:  The index of the reference buffer to pad.*/
 void oc_state_borders_fill(oc_theora_state *_state,int _refi){
-  static const int PL_PADDING[3][2]={
-    {OC_UMV_PADDING,OC_UMV_PADDING},
-    {OC_UMV_PADDING/2,OC_UMV_PADDING},
-    {OC_UMV_PADDING/2,OC_UMV_PADDING}
-  };
   int pli;
   for(pli=0;pli<3;pli++){
-    oc_iplane_borders_fill(&_state->ref_frame_bufs[_refi][pli],
-     PL_PADDING[pli][_state->info.pixel_fmt&1],
-     PL_PADDING[pli][_state->info.pixel_fmt>>1]);
+    oc_state_borders_fill_rows(_state,_refi,pli,0,
+     _state->ref_frame_bufs[_refi][pli].height);
+    oc_state_borders_fill_caps(_state,_refi,pli);
   }
 }
 
@@ -890,68 +908,96 @@
   }
 }
 
-void oc_state_loop_filter(oc_theora_state *_state,int _frame){
-  int bounding_values[512];
+/*Initialize the bounding values array used by the loop filter.
+  _bv: Storage for the array.
+       The total array size should be 512, but this pointer should point to the
+         256th entry, as that is more convenient for the filter functions.
+  Return: 0 on success, or a non-zero value if no filtering need be applied.*/
+int oc_state_loop_filter_init(oc_theora_state *_state,
+ int *_bv){
   int flimit;
-  int framei;
-  int pli;
   int i;
   flimit=_state->loop_filter_limits[_state->qis[0]];
-  if(flimit==0)return;
-  framei=_state->ref_frame_idx[_frame];
-  memset(bounding_values,0,sizeof(bounding_values));
+  if(flimit==0)return 1;
+  _bv-=256;
+  memset(_bv,0,sizeof(_bv[0])*512);
   for(i=0;i<flimit;i++){
-    bounding_values[256-i-flimit]=i-flimit;
-    bounding_values[256-i]=-i;
-    bounding_values[256+i]=i;
-    bounding_values[256+i+flimit]=flimit-i;
+    _bv[256-i-flimit]=i-flimit;
+    _bv[256-i]=-i;
+    _bv[256+i]=i;
+    _bv[256+i+flimit]=flimit-i;
   }
+  return 0;
+}
+
+/*Apply the loop filter to a given set of fragment rows in the given plane.
+  The filter may be run on the bottom edge, affecting pixels in the next row of
+   fragments, so this row also needs to be available.
+  _bv:        The bounding values array.
+  _refi:      The index of the frame buffer to filter.
+  _pli:       The color plane to filter.
+  _fragy0:    The Y coordinate of the first fragment row to filter.
+  _fragy_end: The Y coordinate of the fragment row to stop filtering at.*/
+void oc_state_loop_filter_frag_rows(oc_theora_state *_state,int *_bv,
+ int _refi,int _pli,int _fragy0,int _fragy_end){
+  theora_img_plane  *iplane;
+  oc_fragment_plane *fplane;
+  oc_fragment       *frag_top;
+  oc_fragment       *frag0;
+  oc_fragment       *frag;
+  oc_fragment       *frag_end;
+  oc_fragment       *frag0_end;
+  oc_fragment       *frag_bot;
+  iplane=_state->ref_frame_bufs[_refi]+_pli;
+  fplane=_state->fplanes+_pli;
   /*The following loops are constructed somewhat non-intuitively on purpose.
     The main idea is: if a block boundary has at least one coded fragment on
      it, the filter is applied to it.
     However, the order that the filters are applied in matters, and VP3 chose
      the somewhat strange ordering used below.*/
-  for(pli=0;pli<3;pli++){
-    theora_img_plane  *iplane;
-    oc_fragment_plane *fplane;
-    oc_fragment       *frag00;
-    oc_fragment       *frag0;
-    oc_fragment       *frag;
-    oc_fragment       *frag_end;
-    oc_fragment       *frag0_end;
-    iplane=_state->ref_frame_bufs[framei]+pli;
-    fplane=_state->fplanes+pli;
-    frag00=frag0=_state->frags+fplane->froffset;
-    frag0_end=frag0+fplane->nfrags;
-    while(frag0<frag0_end){
-      frag=frag0;
-      frag_end=frag+fplane->nhfrags;
-      while(frag<frag_end){
-        if(frag->coded){
-          if(frag>frag0){
-            loop_filter_h(frag->buffer[framei],iplane->ystride,
-             bounding_values+256);
-          }
-          if(frag0>frag00){
-            loop_filter_v(frag->buffer[framei],iplane->ystride,
-             bounding_values+256);
-          }
-          if(frag+1<frag_end&&!(frag+1)->coded){
-            loop_filter_h(frag->buffer[framei]+8,iplane->ystride,
-             bounding_values+256);
-          }
-          if(frag+fplane->nhfrags<frag0_end&&!(frag+fplane->nhfrags)->coded){
-            loop_filter_v((frag+fplane->nhfrags)->buffer[framei],
-             iplane->ystride,bounding_values+256);
-          }
+  frag_top=_state->frags+fplane->froffset;
+  frag0=frag_top+_fragy0*fplane->nhfrags;
+  frag0_end=frag0+(_fragy_end-_fragy0)*fplane->nhfrags;
+  frag_bot=_state->frags+fplane->froffset+fplane->nfrags;
+  while(frag0<frag0_end){
+    frag=frag0;
+    frag_end=frag+fplane->nhfrags;
+    while(frag<frag_end){
+      if(frag->coded){
+        if(frag>frag0){
+          loop_filter_h(frag->buffer[_refi],iplane->ystride,_bv);
         }
-        frag++;
+        if(frag0>frag_top){
+          loop_filter_v(frag->buffer[_refi],iplane->ystride,_bv);
+        }
+        if(frag+1<frag_end&&!(frag+1)->coded){
+          loop_filter_h(frag->buffer[_refi]+8,iplane->ystride,_bv);
+        }
+        if(frag+fplane->nhfrags<frag_bot&&!(frag+fplane->nhfrags)->coded){
+          loop_filter_v((frag+fplane->nhfrags)->buffer[_refi],
+           iplane->ystride,_bv);
+        }
       }
-      frag0+=fplane->nhfrags;
+      frag++;
     }
+    frag0+=fplane->nhfrags;
   }
 }
 
+/*Apply the complete loop filter to the given frame.*/
+void oc_state_loop_filter(oc_theora_state *_state,int _frame){
+  int bounding_values[512];
+  int framei;
+  int pli;
+  int i;
+  framei=_state->ref_frame_idx[_frame];
+  if(oc_state_loop_filter_init(_state,bounding_values+256))return;
+  for(pli=0;pli<3;pli++){
+    oc_state_loop_filter_frag_rows(_state,bounding_values+256,
+     framei,pli,0,_state->fplanes[pli].nvfrags);
+  }
+}
+
 #if defined(OC_DUMP_IMAGES)
 int oc_state_dump_frame(const oc_theora_state *_state,int _frame,
  const char *_suf){



More information about the commits mailing list