From e4a2d6598fd19b068f3c628401d8474897db2f49 Mon Sep 17 00:00:00 2001
From: Mashiat Sarker Shakkhar <shahriman_ams@yahoo.com>
Date: Sat, 15 Oct 2011 13:55:12 +0500
Subject: [PATCH] VC1: Implement range mapping

---
 libavcodec/vc1.h    |    2 +
 libavcodec/vc1dec.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h
index ac65348..5089675 100644
--- a/libavcodec/vc1.h
+++ b/libavcodec/vc1.h
@@ -172,6 +172,8 @@ typedef struct VC1Context{
     VC1DSPContext vc1dsp;
 
     int bits;
+    uint8_t *data_out_base, *data_out[3];
+    uint8_t *data_out_last[3];
 
     /** Simple/Main Profile sequence header */
     //@{
diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c
index 6ca7585..dba2ebd 100644
--- a/libavcodec/vc1dec.c
+++ b/libavcodec/vc1dec.c
@@ -5406,6 +5406,8 @@ static av_cold int vc1_decode_end(AVCodecContext *avctx)
         avctx->release_buffer(avctx, &v->sprite_output_frame);
     for (i = 0; i < 4; i++)
         av_freep(&v->sr_rows[i >> 1][i & 1]);
+    if (v->data_out_base)
+        av_freep(&v->data_out_base);
     av_freep(&v->hrd_rate);
     av_freep(&v->hrd_buffer);
     MPV_common_end(&v->s);
@@ -5456,6 +5458,12 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
         /* special case for last picture */
         if (s->low_delay == 0 && s->next_picture_ptr) {
             *pict = *(AVFrame*)s->next_picture_ptr;
+            if (v->range_mapy_flag)
+                pict->data[0] = v->data_out_last[0];
+            if (v->range_mapuv_flag) {
+                pict->data[1] = v->data_out_last[1];
+                pict->data[2] = v->data_out_last[2];
+            }
             s->next_picture_ptr = NULL;
 
             *data_size = sizeof(AVFrame);
@@ -5654,6 +5662,17 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
         goto err;
     }
 
+    if (!v->data_out_base) {
+        /* Allocate temporary data buffers for range mapped pictures */
+        v->data_out_base = av_malloc((avctx->coded_height * s->linesize + avctx->coded_height * s->uvlinesize) << 1);
+        v->data_out[0] = v->data_out_base;
+        v->data_out[1] = v->data_out[0] + avctx->coded_height * s->linesize;
+        v->data_out[2] = v->data_out[1] + (avctx->coded_height * s->uvlinesize >> 1);
+        v->data_out_last[0] = v->data_out_base + avctx->coded_height * s->linesize + avctx->coded_height * s->uvlinesize;
+        v->data_out_last[1] = v->data_out_last[0] + avctx->coded_height * s->linesize;
+        v->data_out_last[2] = v->data_out_last[1] + (avctx->coded_height * s->uvlinesize >> 1);
+    }
+
     s->me.qpel_put = s->dsp.put_qpel_pixels_tab;
     s->me.qpel_avg = s->dsp.avg_qpel_pixels_tab;
 
@@ -5731,6 +5750,39 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
             s->linesize                      >>= 1;
             s->uvlinesize                    >>= 1;
         }
+
+        /* Apply range mapping if flags are present */
+        if (v->range_mapy_flag) {
+            int j, k;
+            uint8_t *srcy, *desty;
+            srcy  = s->current_picture_ptr->f.data[0];
+            desty = v->data_out[0];
+            for (k = 0; k < avctx->coded_height; k++) {
+                for (j = 0; j < s->linesize; j++)
+                    desty[j] = av_clip((((srcy[j] - 128) * (v->range_mapy + 9) + 4) >> 3) + 128, 0, 255);
+                srcy  += s->linesize;
+                desty += s->linesize;
+            }
+        }
+        if (v->range_mapuv_flag) {
+            int j, k;
+            uint8_t *srcu, *srcv;
+            uint8_t *destu, *destv;
+            srcu  = s->current_picture_ptr->f.data[1];
+            srcv  = s->current_picture_ptr->f.data[2];
+            destu = v->data_out[1];
+            destv = v->data_out[2];
+            for (k = 0; k < (avctx->coded_height >> 1); k++) {
+                for (j = 0; j < s->uvlinesize; j++) {
+                    destu[j] = av_clip((((srcu[j] - 128) * (v->range_mapuv + 9) + 4) >> 3) + 128, 0, 255);
+                    destv[j] = av_clip((((srcv[j] - 128) * (v->range_mapuv + 9) + 4) >> 3) + 128, 0, 255);
+                }
+                srcu  += s->uvlinesize;
+                srcv  += s->uvlinesize;
+                destu += s->uvlinesize;
+                destv += s->uvlinesize;
+            }
+        }
 //av_log(s->avctx, AV_LOG_INFO, "Consumed %i/%i bits\n", get_bits_count(&s->gb), s->gb.size_in_bits);
 //  if (get_bits_count(&s->gb) > buf_size * 8)
 //      return -1;
@@ -5754,8 +5806,29 @@ image:
     } else {
         if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
             *pict = *(AVFrame*)s->current_picture_ptr;
+            /* Output range mapped frame instead of decoded frame if flags are present */
+            if (v->range_mapy_flag)
+                pict->data[0] = v->data_out[0];
+            if (v->range_mapuv_flag) {
+                pict->data[1] = v->data_out[1];
+                pict->data[2] = v->data_out[2];
+            }
         } else if (s->last_picture_ptr != NULL) {
             *pict = *(AVFrame*)s->last_picture_ptr;
+            if (v->range_mapy_flag)
+                pict->data[0] = v->data_out_last[0];
+            if (v->range_mapuv_flag) {
+                pict->data[1] = v->data_out_last[1];
+                pict->data[2] = v->data_out_last[2];
+            }
+        }
+        if (s->pict_type != AV_PICTURE_TYPE_B && !s->low_delay) {
+            if (v->range_mapy_flag)
+                FFSWAP(uint8_t*, v->data_out_last[0], v->data_out[0]);
+            if (v->range_mapuv_flag) {
+                FFSWAP(uint8_t*, v->data_out_last[1], v->data_out[1]);
+                FFSWAP(uint8_t*, v->data_out_last[2], v->data_out[2]);
+            }
         }
         if (s->last_picture_ptr || s->low_delay) {
             *data_size = sizeof(AVFrame);
-- 
1.7.4.1

