diff mbox

[FFmpeg-devel,ticket,#5522] lavc/cfhd: interlaced frame decoding added

Message ID 20180522154021.16763-1-deepgagan231197@gmail.com
State Accepted
Commit 9cefb9e7ec508900ba147e6977590f03456aa15c
Headers show

Commit Message

Gagandeep Singh May 22, 2018, 3:40 p.m. UTC
ticket #5522 output of given samples significantly improved
---
 libavcodec/cfhd.c | 181 +++++++++++++++++++++++++++++++++++++++++++-----------
 libavcodec/cfhd.h |   9 +++
 2 files changed, 155 insertions(+), 35 deletions(-)

Comments

Carl Eugen Hoyos May 22, 2018, 8:35 p.m. UTC | #1
2018-05-22 17:40 GMT+02:00, Gagandeep Singh <deepgagan231197@gmail.com>:

> +            low    = s->plane[plane].subband[0];
> +            high   = s->plane[plane].subband[8];
> +            output = s->plane[plane].l_h[6];
> +            for (i = 0; i < lowpass_width; i++) {
> +                vert_filter(output, lowpass_width, low, lowpass_width,
> high, highpass_stride, lowpass_height);
> +                low++;
> +                high++;
> +                output++;
> +            }
>
> -        low    = s->plane[plane].subband[0];
> -        high   = s->plane[plane].subband[8];
> -        output = s->plane[plane].l_h[6];
> -        for (i = 0; i < lowpass_width; i++) {
> -            vert_filter(output, lowpass_width, low, lowpass_width, high,
> highpass_stride, lowpass_height);
> -            low++;
> -            high++;
> -            output++;
> -        }

The patch will get much more readable (and easier to review)
if you do not re-indent, instead send a second patch with the
cosmetic changes only.

Carl Eugen
Hendrik Leppkes May 22, 2018, 10:21 p.m. UTC | #2
On Tue, May 22, 2018 at 10:35 PM, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
> 2018-05-22 17:40 GMT+02:00, Gagandeep Singh <deepgagan231197@gmail.com>:
>
>> +            low    = s->plane[plane].subband[0];
>> +            high   = s->plane[plane].subband[8];
>> +            output = s->plane[plane].l_h[6];
>> +            for (i = 0; i < lowpass_width; i++) {
>> +                vert_filter(output, lowpass_width, low, lowpass_width,
>> high, highpass_stride, lowpass_height);
>> +                low++;
>> +                high++;
>> +                output++;
>> +            }
>>
>> -        low    = s->plane[plane].subband[0];
>> -        high   = s->plane[plane].subband[8];
>> -        output = s->plane[plane].l_h[6];
>> -        for (i = 0; i < lowpass_width; i++) {
>> -            vert_filter(output, lowpass_width, low, lowpass_width, high,
>> highpass_stride, lowpass_height);
>> -            low++;
>> -            high++;
>> -            output++;
>> -        }
>
> The patch will get much more readable (and easier to review)
> if you do not re-indent, instead send a second patch with the
> cosmetic changes only.
>

Except, no sane developer works like that. In fact many editors will
even indent for you automatically if you add new blocks, so splitting
this is a really annoying task to perform.
Instead, may I suggest a proper patch viewer which can ignore
whitespace changes? It makes reading patches with indent changes
trivial.

- Hendrik
Carl Eugen Hoyos May 22, 2018, 10:35 p.m. UTC | #3
2018-05-23 0:21 GMT+02:00, Hendrik Leppkes <h.leppkes@gmail.com>:
> On Tue, May 22, 2018 at 10:35 PM, Carl Eugen Hoyos <ceffmpeg@gmail.com>
> wrote:
>> 2018-05-22 17:40 GMT+02:00, Gagandeep Singh <deepgagan231197@gmail.com>:
>>
>>> +            low    = s->plane[plane].subband[0];
>>> +            high   = s->plane[plane].subband[8];
>>> +            output = s->plane[plane].l_h[6];
>>> +            for (i = 0; i < lowpass_width; i++) {
>>> +                vert_filter(output, lowpass_width, low, lowpass_width,
>>> high, highpass_stride, lowpass_height);
>>> +                low++;
>>> +                high++;
>>> +                output++;
>>> +            }
>>>
>>> -        low    = s->plane[plane].subband[0];
>>> -        high   = s->plane[plane].subband[8];
>>> -        output = s->plane[plane].l_h[6];
>>> -        for (i = 0; i < lowpass_width; i++) {
>>> -            vert_filter(output, lowpass_width, low, lowpass_width, high,
>>> highpass_stride, lowpass_height);
>>> -            low++;
>>> -            high++;
>>> -            output++;
>>> -        }
>>
>> The patch will get much more readable (and easier to review)
>> if you do not re-indent, instead send a second patch with the
>> cosmetic changes only.
>>
>
> Except, no sane developer works like that.

It's great to know that you are so much smarter than most developers,
I will forward the next regression directly to you to fix it.

Thank you, Carl Eugen
Gagandeep Singh May 23, 2018, 1:46 a.m. UTC | #4
On Wed, 23 May 2018, 04:05 Carl Eugen Hoyos, <ceffmpeg@gmail.com> wrote:

> 2018-05-23 0:21 GMT+02:00, Hendrik Leppkes <h.leppkes@gmail.com>:
> > On Tue, May 22, 2018 at 10:35 PM, Carl Eugen Hoyos <ceffmpeg@gmail.com>
> > wrote:
> >> 2018-05-22 17:40 GMT+02:00, Gagandeep Singh <deepgagan231197@gmail.com
> >:
> >>
> >>> +            low    = s->plane[plane].subband[0];
> >>> +            high   = s->plane[plane].subband[8];
> >>> +            output = s->plane[plane].l_h[6];
> >>> +            for (i = 0; i < lowpass_width; i++) {
> >>> +                vert_filter(output, lowpass_width, low, lowpass_width,
> >>> high, highpass_stride, lowpass_height);
> >>> +                low++;
> >>> +                high++;
> >>> +                output++;
> >>> +            }
> >>>
> >>> -        low    = s->plane[plane].subband[0];
> >>> -        high   = s->plane[plane].subband[8];
> >>> -        output = s->plane[plane].l_h[6];
> >>> -        for (i = 0; i < lowpass_width; i++) {
> >>> -            vert_filter(output, lowpass_width, low, lowpass_width,
> high,
> >>> highpass_stride, lowpass_height);
> >>> -            low++;
> >>> -            high++;
> >>> -            output++;
> >>> -        }
> >>
> >> The patch will get much more readable (and easier to review)
> >> if you do not re-indent, instead send a second patch with the
> >> cosmetic changes only.
> >>
> >
> > Except, no sane developer works like that.
>
> It's great to know that you are so much smarter than most developers,
> I will forward the next regression directly to you to fix it.
>
> Thank you, Carl Eugen
>

I will keep the cosmetic patch also in mind next time

Gagandeep Singh

> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
wm4 May 23, 2018, 3:08 p.m. UTC | #5
On Wed, 23 May 2018 00:21:56 +0200
Hendrik Leppkes <h.leppkes@gmail.com> wrote:

> On Tue, May 22, 2018 at 10:35 PM, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
> > 2018-05-22 17:40 GMT+02:00, Gagandeep Singh <deepgagan231197@gmail.com>:
> >  
> >> +            low    = s->plane[plane].subband[0];
> >> +            high   = s->plane[plane].subband[8];
> >> +            output = s->plane[plane].l_h[6];
> >> +            for (i = 0; i < lowpass_width; i++) {
> >> +                vert_filter(output, lowpass_width, low, lowpass_width,
> >> high, highpass_stride, lowpass_height);
> >> +                low++;
> >> +                high++;
> >> +                output++;
> >> +            }
> >>
> >> -        low    = s->plane[plane].subband[0];
> >> -        high   = s->plane[plane].subband[8];
> >> -        output = s->plane[plane].l_h[6];
> >> -        for (i = 0; i < lowpass_width; i++) {
> >> -            vert_filter(output, lowpass_width, low, lowpass_width, high,
> >> highpass_stride, lowpass_height);
> >> -            low++;
> >> -            high++;
> >> -            output++;
> >> -        }  
> >
> > The patch will get much more readable (and easier to review)
> > if you do not re-indent, instead send a second patch with the
> > cosmetic changes only.
> >  
> 
> Except, no sane developer works like that. In fact many editors will
> even indent for you automatically if you add new blocks, so splitting
> this is a really annoying task to perform.
> Instead, may I suggest a proper patch viewer which can ignore
> whitespace changes? It makes reading patches with indent changes
> trivial.

+1

We could add instructions to the docs how to make patches with
whitespace changes ignored.
Paul B Mahol May 23, 2018, 3:20 p.m. UTC | #6
On 5/23/18, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
> 2018-05-23 0:21 GMT+02:00, Hendrik Leppkes <h.leppkes@gmail.com>:
>> On Tue, May 22, 2018 at 10:35 PM, Carl Eugen Hoyos <ceffmpeg@gmail.com>
>> wrote:
>>> 2018-05-22 17:40 GMT+02:00, Gagandeep Singh <deepgagan231197@gmail.com>:
>>>
>>>> +            low    = s->plane[plane].subband[0];
>>>> +            high   = s->plane[plane].subband[8];
>>>> +            output = s->plane[plane].l_h[6];
>>>> +            for (i = 0; i < lowpass_width; i++) {
>>>> +                vert_filter(output, lowpass_width, low, lowpass_width,
>>>> high, highpass_stride, lowpass_height);
>>>> +                low++;
>>>> +                high++;
>>>> +                output++;
>>>> +            }
>>>>
>>>> -        low    = s->plane[plane].subband[0];
>>>> -        high   = s->plane[plane].subband[8];
>>>> -        output = s->plane[plane].l_h[6];
>>>> -        for (i = 0; i < lowpass_width; i++) {
>>>> -            vert_filter(output, lowpass_width, low, lowpass_width,
>>>> high,
>>>> highpass_stride, lowpass_height);
>>>> -            low++;
>>>> -            high++;
>>>> -            output++;
>>>> -        }
>>>
>>> The patch will get much more readable (and easier to review)
>>> if you do not re-indent, instead send a second patch with the
>>> cosmetic changes only.
>>>
>>
>> Except, no sane developer works like that.
>
> It's great to know that you are so much smarter than most developers,
> I will forward the next regression directly to you to fix it.

CoC violation. First warning given.
Michael Niedermayer June 23, 2018, 10:34 p.m. UTC | #7
Hi

On Tue, May 22, 2018 at 09:10:21PM +0530, Gagandeep Singh wrote:
> ticket #5522 output of given samples significantly improved
> ---
>  libavcodec/cfhd.c | 181 +++++++++++++++++++++++++++++++++++++++++++-----------
>  libavcodec/cfhd.h |   9 +++
>  2 files changed, 155 insertions(+), 35 deletions(-)
> 
> diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c
> index 7ceb803595..051d210355 100644
> --- a/libavcodec/cfhd.c
> +++ b/libavcodec/cfhd.c
> @@ -49,12 +49,15 @@ enum CFHDParam {
>      SubbandNumber    =  48,
>      Quantization     =  53,
>      ChannelNumber    =  62,
> +    SampleFlags      =  68,
>      BitsPerComponent = 101,
>      ChannelWidth     = 104,
>      ChannelHeight    = 105,
>      PrescaleShift    = 109,
>  };
>  
> +
> +
>  static av_cold int cfhd_init(AVCodecContext *avctx)
>  {
>      CFHDContext *s = avctx->priv_data;
> @@ -72,6 +75,13 @@ static void init_plane_defaults(CFHDContext *s)
>      s->subband_num_actual = 0;
>  }
>  
> +static void init_peak_table_defaults(CFHDContext *s)
> +{
> +    s->peak.level  = 0;
> +    s->peak.offset = 0;
> +    s->peak.base   = NULL;
> +}
> +
>  static void init_frame_defaults(CFHDContext *s)
>  {
>      s->coded_width       = 0;
> @@ -86,15 +96,44 @@ static void init_frame_defaults(CFHDContext *s)
>      s->wavelet_depth     = 3;
>      s->pshift            = 1;
>      s->codebook          = 0;
> +    s->difference_coding = 0;
> +    s->progressive       = 0;
>      init_plane_defaults(s);
> +    init_peak_table_defaults(s);
>  }
>  
>  /* TODO: merge with VLC tables or use LUT */
> -static inline int dequant_and_decompand(int level, int quantisation)
> +static inline int dequant_and_decompand(int level, int quantisation, int codebook)
> +{
> +    if (codebook == 0 || codebook == 1) {
> +        int64_t abslevel = abs(level);
> +        if (level < 264)
> +            return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) *
> +               FFSIGN(level) * quantisation;
> +        else
> +            return level * quantisation;
> +    } else
> +        return level * quantisation;
> +}
> +
> +static inline void difference_coding(int16_t *band, int width, int height)
> +{
> +
> +    int i,j;
> +    for (i = 0; i < height; i++) {
> +        for (j = 1; j < width; j++) {
> +          band[j] += band[j-1];
> +        }
> +        band += width;
> +    }
> +}
> +

> +static inline void peak_table(int16_t *band, Peak *peak, int length)
>  {
> -    int64_t abslevel = abs(level);
> -    return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) *
> -           FFSIGN(level) * quantisation;
> +    int i;
> +    for (i = 0; i < length; i++)
> +        if (abs(band[i]) > peak->level)
> +            band[i] = *(peak->base++);

This directly reads from the bytestream cast to int16.
This is likely wrong for bigendian


>  }
>  
>  static inline void process_alpha(int16_t *alpha, int width)
> @@ -154,6 +193,18 @@ static inline void filter(int16_t *output, ptrdiff_t out_stride,
>      }
>  }
>  
> +static inline void interlaced_vertical_filter(int16_t *output, int16_t *low, int16_t *high,
> +                         int width, int linesize, int plane)
> +{
> +    int i;
> +    int16_t even, odd;
> +    for (i = 0; i < width; i++) {
> +        even = (low[i] - high[i])/2;
> +        odd  = (low[i] + high[i])/2;
> +        output[i]            = av_clip_uintp2(even, 10);
> +        output[i + linesize] = av_clip_uintp2(odd, 10);
> +    }
> +}
>  static void horiz_filter(int16_t *output, int16_t *low, int16_t *high,
>                           int width)
>  {
> @@ -295,6 +346,9 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
>          uint16_t data   = bytestream2_get_be16(&gb);
>          if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) {
>              av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data);
> +        } else if (tag == SampleFlags) {
> +            av_log(avctx, AV_LOG_DEBUG, "Progressive?%"PRIu16"\n", data);
> +            s->progressive = data & 0x0001;
>          } else if (tag == ImageWidth) {
>              av_log(avctx, AV_LOG_DEBUG, "Width %"PRIu16"\n", data);
>              s->coded_width = data;
> @@ -393,6 +447,8 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
>              }
>              av_log(avctx, AV_LOG_DEBUG, "Transform-type? %"PRIu16"\n", data);
>          } else if (abstag >= 0x4000 && abstag <= 0x40ff) {
> +            if (abstag == 0x4001)
> +                s->peak.level = 0;
>              av_log(avctx, AV_LOG_DEBUG, "Small chunk length %d %s\n", data * 4, tag < 0 ? "optional" : "required");
>              bytestream2_skipu(&gb, data * 4);
>          } else if (tag == 23) {
> @@ -450,7 +506,8 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
>              s->codebook = data;
>              av_log(avctx, AV_LOG_DEBUG, "Codebook %i\n", s->codebook);
>          } else if (tag == 72) {
> -            s->codebook = data;
> +            s->codebook = data & 0xf;
> +            s->difference_coding = (data >> 4) & 1;
>              av_log(avctx, AV_LOG_DEBUG, "Other codebook? %i\n", s->codebook);
>          } else if (tag == 70) {
>              av_log(avctx, AV_LOG_DEBUG, "Subsampling or bit-depth flag? %i\n", data);

> @@ -477,6 +534,19 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
>          } else if (tag == -85) {
>              av_log(avctx, AV_LOG_DEBUG, "Cropped height %"PRIu16"\n", data);
>              s->cropped_height = data;
> +        } else if (tag == -75) {
> +            s->peak.offset &= ~0xffff;
> +            s->peak.offset |= (data & 0xffff);
> +            s->peak.base    = (int16_t *) gb.buffer;
> +            s->peak.level   = 0;
> +        } else if (tag == -76) {
> +            s->peak.offset &= 0xffff;
> +            s->peak.offset |= (data & 0xffff)<<16;

Undefined shift, Issue 8695 in oss-fuzz
If you fix this please add "Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg"


> +            s->peak.base    = (int16_t *) gb.buffer;
> +            s->peak.level   = 0;
> +        } else if (tag == -74 && s->peak.offset) {
> +            s->peak.level = data;
> +            s->peak.base += s->peak.offset / 2 - 2;

Is the offset checked anywhere ?
adding a unchecked value to a pointer is a undefined operation
but more so i do not see anything checking the offst or pointer
before it is dereferenced. If so this would allow one to crash the
decoder with an out of array read
All input data has to be checked if some value could cause undefined
behavior, crashes, or worse.
The fuzzers did not find this one yet. This was just spotted by me when
looking at the undefined shift.

Also, why are people attacking each other over spliting this?
Split or not split, i think more energy should be put into reviewing
patches than attacking each other

Thanks

PS: for reference this was pushed to master in 9cefb9e7ec508900ba147e6977590f03456aa15c

[...]
diff mbox

Patch

diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c
index 7ceb803595..051d210355 100644
--- a/libavcodec/cfhd.c
+++ b/libavcodec/cfhd.c
@@ -49,12 +49,15 @@  enum CFHDParam {
     SubbandNumber    =  48,
     Quantization     =  53,
     ChannelNumber    =  62,
+    SampleFlags      =  68,
     BitsPerComponent = 101,
     ChannelWidth     = 104,
     ChannelHeight    = 105,
     PrescaleShift    = 109,
 };
 
+
+
 static av_cold int cfhd_init(AVCodecContext *avctx)
 {
     CFHDContext *s = avctx->priv_data;
@@ -72,6 +75,13 @@  static void init_plane_defaults(CFHDContext *s)
     s->subband_num_actual = 0;
 }
 
+static void init_peak_table_defaults(CFHDContext *s)
+{
+    s->peak.level  = 0;
+    s->peak.offset = 0;
+    s->peak.base   = NULL;
+}
+
 static void init_frame_defaults(CFHDContext *s)
 {
     s->coded_width       = 0;
@@ -86,15 +96,44 @@  static void init_frame_defaults(CFHDContext *s)
     s->wavelet_depth     = 3;
     s->pshift            = 1;
     s->codebook          = 0;
+    s->difference_coding = 0;
+    s->progressive       = 0;
     init_plane_defaults(s);
+    init_peak_table_defaults(s);
 }
 
 /* TODO: merge with VLC tables or use LUT */
-static inline int dequant_and_decompand(int level, int quantisation)
+static inline int dequant_and_decompand(int level, int quantisation, int codebook)
+{
+    if (codebook == 0 || codebook == 1) {
+        int64_t abslevel = abs(level);
+        if (level < 264)
+            return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) *
+               FFSIGN(level) * quantisation;
+        else
+            return level * quantisation;
+    } else
+        return level * quantisation;
+}
+
+static inline void difference_coding(int16_t *band, int width, int height)
+{
+
+    int i,j;
+    for (i = 0; i < height; i++) {
+        for (j = 1; j < width; j++) {
+          band[j] += band[j-1];
+        }
+        band += width;
+    }
+}
+
+static inline void peak_table(int16_t *band, Peak *peak, int length)
 {
-    int64_t abslevel = abs(level);
-    return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) *
-           FFSIGN(level) * quantisation;
+    int i;
+    for (i = 0; i < length; i++)
+        if (abs(band[i]) > peak->level)
+            band[i] = *(peak->base++);
 }
 
 static inline void process_alpha(int16_t *alpha, int width)
@@ -154,6 +193,18 @@  static inline void filter(int16_t *output, ptrdiff_t out_stride,
     }
 }
 
+static inline void interlaced_vertical_filter(int16_t *output, int16_t *low, int16_t *high,
+                         int width, int linesize, int plane)
+{
+    int i;
+    int16_t even, odd;
+    for (i = 0; i < width; i++) {
+        even = (low[i] - high[i])/2;
+        odd  = (low[i] + high[i])/2;
+        output[i]            = av_clip_uintp2(even, 10);
+        output[i + linesize] = av_clip_uintp2(odd, 10);
+    }
+}
 static void horiz_filter(int16_t *output, int16_t *low, int16_t *high,
                          int width)
 {
@@ -295,6 +346,9 @@  static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
         uint16_t data   = bytestream2_get_be16(&gb);
         if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) {
             av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data);
+        } else if (tag == SampleFlags) {
+            av_log(avctx, AV_LOG_DEBUG, "Progressive?%"PRIu16"\n", data);
+            s->progressive = data & 0x0001;
         } else if (tag == ImageWidth) {
             av_log(avctx, AV_LOG_DEBUG, "Width %"PRIu16"\n", data);
             s->coded_width = data;
@@ -393,6 +447,8 @@  static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
             }
             av_log(avctx, AV_LOG_DEBUG, "Transform-type? %"PRIu16"\n", data);
         } else if (abstag >= 0x4000 && abstag <= 0x40ff) {
+            if (abstag == 0x4001)
+                s->peak.level = 0;
             av_log(avctx, AV_LOG_DEBUG, "Small chunk length %d %s\n", data * 4, tag < 0 ? "optional" : "required");
             bytestream2_skipu(&gb, data * 4);
         } else if (tag == 23) {
@@ -450,7 +506,8 @@  static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
             s->codebook = data;
             av_log(avctx, AV_LOG_DEBUG, "Codebook %i\n", s->codebook);
         } else if (tag == 72) {
-            s->codebook = data;
+            s->codebook = data & 0xf;
+            s->difference_coding = (data >> 4) & 1;
             av_log(avctx, AV_LOG_DEBUG, "Other codebook? %i\n", s->codebook);
         } else if (tag == 70) {
             av_log(avctx, AV_LOG_DEBUG, "Subsampling or bit-depth flag? %i\n", data);
@@ -477,6 +534,19 @@  static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
         } else if (tag == -85) {
             av_log(avctx, AV_LOG_DEBUG, "Cropped height %"PRIu16"\n", data);
             s->cropped_height = data;
+        } else if (tag == -75) {
+            s->peak.offset &= ~0xffff;
+            s->peak.offset |= (data & 0xffff);
+            s->peak.base    = (int16_t *) gb.buffer;
+            s->peak.level   = 0;
+        } else if (tag == -76) {
+            s->peak.offset &= 0xffff;
+            s->peak.offset |= (data & 0xffff)<<16;
+            s->peak.base    = (int16_t *) gb.buffer;
+            s->peak.level   = 0;
+        } else if (tag == -74 && s->peak.offset) {
+            s->peak.level = data;
+            s->peak.base += s->peak.offset / 2 - 2;
         } else
             av_log(avctx, AV_LOG_DEBUG,  "Unknown tag %i data %x\n", tag, data);
 
@@ -594,10 +664,15 @@  static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
                         if (count > expected)
                             break;
 
-                        coeff = dequant_and_decompand(level, s->quantisation);
+                        coeff = dequant_and_decompand(level, s->quantisation, 0);
                         for (i = 0; i < run; i++)
                             *coeff_data++ = coeff;
                     }
+                    if (s->peak.level)
+                        peak_table(coeff_data - expected, &s->peak, expected);
+                    if (s->difference_coding)
+                        difference_coding(s->plane[s->channel_num].subband[s->subband_num_actual], highpass_width, highpass_height);
+
                 } else {
                     while (1) {
                         UPDATE_CACHE(re, &s->gb);
@@ -613,10 +688,15 @@  static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
                         if (count > expected)
                             break;
 
-                        coeff = dequant_and_decompand(level, s->quantisation);
+                        coeff = dequant_and_decompand(level, s->quantisation, s->codebook);
                         for (i = 0; i < run; i++)
                             *coeff_data++ = coeff;
                     }
+                    if (s->peak.level)
+                        peak_table(coeff_data - expected, &s->peak, expected);
+                    if (s->difference_coding)
+                        difference_coding(s->plane[s->channel_num].subband[s->subband_num_actual], highpass_width, highpass_height);
+
                 }
                 CLOSE_READER(re, &s->gb);
             }
@@ -784,37 +864,68 @@  static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame,
         }
 
         av_log(avctx, AV_LOG_DEBUG, "Level 3 plane %i %i %i %i\n", plane, lowpass_height, lowpass_width, highpass_stride);
+        if (s->progressive) {
+            low    = s->plane[plane].subband[0];
+            high   = s->plane[plane].subband[8];
+            output = s->plane[plane].l_h[6];
+            for (i = 0; i < lowpass_width; i++) {
+                vert_filter(output, lowpass_width, low, lowpass_width, high, highpass_stride, lowpass_height);
+                low++;
+                high++;
+                output++;
+            }
 
-        low    = s->plane[plane].subband[0];
-        high   = s->plane[plane].subband[8];
-        output = s->plane[plane].l_h[6];
-        for (i = 0; i < lowpass_width; i++) {
-            vert_filter(output, lowpass_width, low, lowpass_width, high, highpass_stride, lowpass_height);
-            low++;
-            high++;
-            output++;
-        }
+            low    = s->plane[plane].subband[7];
+            high   = s->plane[plane].subband[9];
+            output = s->plane[plane].l_h[7];
+            for (i = 0; i < lowpass_width; i++) {
+                vert_filter(output, lowpass_width, low, highpass_stride, high, highpass_stride, lowpass_height);
+                low++;
+                high++;
+                output++;
+            }
 
-        low    = s->plane[plane].subband[7];
-        high   = s->plane[plane].subband[9];
-        output = s->plane[plane].l_h[7];
-        for (i = 0; i < lowpass_width; i++) {
-            vert_filter(output, lowpass_width, low, highpass_stride, high, highpass_stride, lowpass_height);
-            low++;
-            high++;
-            output++;
-        }
+            dst = (int16_t *)pic->data[act_plane];
+            low  = s->plane[plane].l_h[6];
+            high = s->plane[plane].l_h[7];
+            for (i = 0; i < lowpass_height * 2; i++) {
+                horiz_filter_clip(dst, low, high, lowpass_width, s->bpc);
+                low  += lowpass_width;
+                high += lowpass_width;
+                dst  += pic->linesize[act_plane] / 2;
+            }
+        } else {
+            av_log(avctx, AV_LOG_DEBUG, "interlaced frame ? %d", pic->interlaced_frame);
+            pic->interlaced_frame = 1;
+            low    = s->plane[plane].subband[0];
+            high   = s->plane[plane].subband[7];
+            output = s->plane[plane].l_h[6];
+            for (i = 0; i < lowpass_height; i++) {
+                horiz_filter(output, low, high, lowpass_width);
+                low    += lowpass_width;
+                high   += lowpass_width;
+                output += lowpass_width * 2;
+            }
 
-        dst = (int16_t *)pic->data[act_plane];
-        low  = s->plane[plane].l_h[6];
-        high = s->plane[plane].l_h[7];
-        for (i = 0; i < lowpass_height * 2; i++) {
-            horiz_filter_clip(dst, low, high, lowpass_width, s->bpc);
-            if (act_plane == 3)
-                process_alpha(dst, lowpass_width * 2);
-            low  += lowpass_width;
-            high += lowpass_width;
-            dst  += pic->linesize[act_plane] / 2;
+            low    = s->plane[plane].subband[8];
+            high   = s->plane[plane].subband[9];
+            output = s->plane[plane].l_h[7];
+            for (i = 0; i < lowpass_height; i++) {
+                horiz_filter(output, low, high, lowpass_width);
+                low    += lowpass_width;
+                high   += lowpass_width;
+                output += lowpass_width * 2;
+            }
+
+            dst  = (int16_t *)pic->data[act_plane];
+            low  = s->plane[plane].l_h[6];
+            high = s->plane[plane].l_h[7];
+            for (i = 0; i < lowpass_height; i++) {
+                interlaced_vertical_filter(dst, low, high, lowpass_width * 2,  pic->linesize[act_plane]/2, act_plane);
+                low  += lowpass_width * 2;
+                high += lowpass_width * 2;
+                dst  += pic->linesize[act_plane];
+            }
         }
     }
 
diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h
index 2573e750a6..7cd251fca7 100644
--- a/libavcodec/cfhd.h
+++ b/libavcodec/cfhd.h
@@ -68,6 +68,12 @@  typedef struct Plane {
     SubBand band[DWT_LEVELS][4];
 } Plane;
 
+typedef struct Peak {
+    int level;
+    int offset;
+    const int16_t *base;
+} Peak;
+
 typedef struct CFHDContext {
     AVCodecContext *avctx;
 
@@ -83,6 +89,7 @@  typedef struct CFHDContext {
     int coded_height;
     int cropped_height;
     enum AVPixelFormat coded_format;
+    int progressive;
 
     int a_width;
     int a_height;
@@ -98,12 +105,14 @@  typedef struct CFHDContext {
     int pshift;
 
     int codebook;
+    int difference_coding;
     int subband_num;
     int level;
     int subband_num_actual;
 
     uint8_t prescale_shift[3];
     Plane plane[4];
+    Peak peak;
 } CFHDContext;
 
 int ff_cfhd_init_vlcs(CFHDContext *s);