[FFmpeg-devel] [PATCH] Rl2 Video decoder

Sascha Sommer saschasommer
Thu Mar 20 19:44:39 CET 2008


Hi,

On Montag, 17. M?rz 2008, Reimar D?ffinger wrote:
> On Mon, Mar 17, 2008 at 01:56:08PM +0100, Sascha Sommer wrote:
> > +/**
> > + * Run Length Decode a single 320x200 frame
> > + * @param s rl2 context
> > + * @param buf input buffer
> > + * @param size input buffer size
> > + * @param out ouput buffer
> > + * @param stride stride of the output buffer
> > + */
> > +static void rl2_rle_decode(Rl2Context *s,const unsigned char* in,int
> > size, +                               unsigned char* out,int stride){
> > +     int row_inc = stride - s->avctx->width;
> > +     unsigned char* back_frame = s->back_frame;
> > +     const unsigned char* in_end = in + size;
> > +     unsigned char* out_end = out + stride*s->avctx->height;
>
> Btw. I do not really like using "unsigned char", first because it is
> much longer that just "uint8_t" and secondly because (almost?) all other
> FFmpeg code uses uint8_t.
>

I did not change this but I can if it is needed.

> > +     int x = s->video_base % s->avctx->width;
> > +     out += s->video_base + (s->video_base / s->avctx->width) * row_inc;
>
> I think it would be better to split video_base into x and y already in
> rl2_decode_init
>

Done.

> > +     while(in < in_end){
> > +         unsigned char tag = *in++;
> > +         int len = 1;
> > +         unsigned char val;
> > +         if(tag >= 0x80){
> > +             if(in >= in_end)
> > +                 break;
> > +             len = *in++;
> > +             if(!len)
> > +                 break;
> > +         }
> > +         if(s->back_frame)
> > +             val = tag | 0x80;
> > +         else
> > +             val = tag & ~0x80;
> > +
> > +         if(out + len >= out_end)
> > +             break;
>
> I think this is wrong in many ways, e.g. out + len could overflow,
> and this does not take into account the row_inc that will be added in
> the while loop.

Should be fixed now...

>
> > +         while(len--){
> > +             if(s->back_frame){
> > +                 if(!tag || tag == 0x80)
> > +                     val = *back_frame;
> > +                 ++back_frame;
> > +             }
>
> The order of these ifs and the while really should be swapped, also
> since you do "tag | 0x80" above already, you should just compare
> that result against 0x80 instead of comparing tag both against 0 and
> 0x80.
>

I'm only checking for one value now. Swapping the if and while does not lead 
to faster decoding with gcc 4.2.1 and that way there is no code duplication.

> > +             *out++ = val;
> > +             if(++x == s->avctx->width){
> > +                  out += row_inc;
> > +                  x = 0;
> > +             }
>
> I have the feeling this whole stride-handling will be easier if you use
> uint8_t *cur_line and int x (pointer to start of line and current
> offset in that line) and then reuse memset/memcpy (using them in 2
> places, first process till end of current line and process full lines
> (needs incrementing stride) and then partial last line if any).
> In case of s->back_frame I even wonder if it wouldn't be both faster and
> simpler to just copy the whole back frame first and then just overwrite
> some parts...

The memcpy and memset would still need checks for len and calulation of the 
arguments. I also noticed that one of the samples did not decode properly. 
Therefore some more fixes were in order. Copying the whole back frame is 
simpler but not faster (for the 3 samples that exist for that format...)

Regards

Sascha





More information about the ffmpeg-devel mailing list