avfilter/vsrc_testsrc: fix a preprocessor check
[ffmpeg.git] / libavfilter / vf_uspp.c
index c96df42..da4029f 100644 (file)
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 #include "internal.h"
-#include "libavcodec/avcodec.h"
 #include "avfilter.h"
 
 #define MAX_LEVEL 8 /* quality levels */
 #define BLOCK 16
 
-typedef struct {
+typedef struct USPPContext {
     const AVClass *av_class;
     int log2_count;
+    int hsub, vsub;
     int qp;
     int qscale_type;
     int temp_stride[3];
     uint8_t *src[3];
-    int16_t *temp[3];
+    uint16_t *temp[3];
     int outbuf_size;
     uint8_t *outbuf;
     AVCodecContext *avctx_enc[BLOCK*BLOCK];
@@ -54,27 +54,19 @@ typedef struct {
     uint8_t *non_b_qp_table;
     int non_b_qp_alloc_size;
     int use_bframe_qp;
-
 } USPPContext;
 
 #define OFFSET(x) offsetof(USPPContext, x)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 static const AVOption uspp_options[] = {
-    { "quality" , "set quality" , OFFSET(log2_count) , AV_OPT_TYPE_INT , {.i64 = 3} , 0 , MAX_LEVEL , FLAGS },
-    { "qp" , "force a constant quantizer parameter" , OFFSET(qp) , AV_OPT_TYPE_INT , {.i64 = 0} , 0 , 63 , FLAGS },
-    { "use_bframe_qp" , "use B-frames' QP" , OFFSET(use_bframe_qp) , AV_OPT_TYPE_INT , {.i64 = 0} , 0 , 1 , FLAGS },
+    { "quality",       "set quality",                          OFFSET(log2_count),    AV_OPT_TYPE_INT, {.i64 = 3}, 0, MAX_LEVEL, FLAGS },
+    { "qp",            "force a constant quantizer parameter", OFFSET(qp),            AV_OPT_TYPE_INT, {.i64 = 0}, 0, 63,        FLAGS },
+    { "use_bframe_qp", "use B-frames' QP",                     OFFSET(use_bframe_qp), AV_OPT_TYPE_BOOL,{.i64 = 0}, 0, 1,         FLAGS },
     { NULL }
 };
 
-static const AVClass uspp_class = {
-    .class_name       = "uspp",
-    .item_name        = av_default_item_name,
-    .option           = uspp_options,
-    .version          = LIBAVUTIL_VERSION_INT,
-    .category         = AV_CLASS_CATEGORY_FILTER,
-};
+AVFILTER_DEFINE_CLASS(uspp);
 
-//===========================================================================//
 DECLARE_ALIGNED(8, static const uint8_t, dither)[8][8] = {
     {  0*4,  48*4,  12*4,  60*4,   3*4,  51*4,  15*4,  63*4, },
     { 32*4,  16*4,  44*4,  28*4,  35*4,  19*4,  47*4,  31*4, },
@@ -86,7 +78,7 @@ DECLARE_ALIGNED(8, static const uint8_t, dither)[8][8] = {
     { 42*4,  26*4,  38*4,  22*4,  41*4,  25*4,  37*4,  21*4, },
 };
 
-static const uint8_t offset[511][2]= {
+static const uint8_t offset[511][2] = {
     { 0, 0},
     { 0, 0}, { 8, 8},                                                              // quality 1
     { 0, 0}, { 4, 4}, {12, 8}, { 8,12},                                            // quality 2
@@ -160,21 +152,21 @@ static const uint8_t offset[511][2]= {
     { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
 };
 
-static void store_slice_c(uint8_t *dst, int16_t *src,
-                         int dst_stride, int src_stride,
-                         int width, int height, int log2_scale )
+static void store_slice_c(uint8_t *dst, const uint16_t *src,
+                          int dst_stride, int src_stride,
+                          int width, int height, int log2_scale)
 {
     int y, x;
 
-#define STORE(pos) do {                                                  \
-    temp = ((src[x + y * src_stride + pos] << log2_scale) + d[pos]) >> 8;  \
-    if (temp & 0x100) temp = ~(temp >> 31);                              \
-    dst[x + y * dst_stride + pos] = temp;                                  \
-} while (0);
+#define STORE(pos) do {                                                     \
+    temp = ((src[x + y * src_stride + pos] << log2_scale) + d[pos]) >> 8;   \
+    if (temp & 0x100) temp = ~(temp >> 31);                                 \
+    dst[x + y * dst_stride + pos] = temp;                                   \
+} while (0)
 
-    for (y = 0 ; y < height ; y++) {
-    const uint8_t *d = dither[y&7];
-        for (x = 0 ; x < width ; x += 8) {
+    for (y = 0; y < height; y++) {
+        const uint8_t *d = dither[y&7];
+        for (x = 0; x < width; x += 8) {
             int temp;
             STORE(0);
             STORE(1);
@@ -188,62 +180,65 @@ static void store_slice_c(uint8_t *dst, int16_t *src,
     }
 }
 
-static inline int norm_qscale(int qscale, int type)
-{
-    switch (type) {
-    case FF_QSCALE_TYPE_MPEG1: return qscale;
-    case FF_QSCALE_TYPE_MPEG2: return qscale >> 1;
-    case FF_QSCALE_TYPE_H264:  return qscale >> 2;
-    case FF_QSCALE_TYPE_VP56:  return (63 - qscale + 2) >> 2;
-    }
-    return qscale;
-}
-
 static void filter(USPPContext *p, uint8_t *dst[3], uint8_t *src[3],
-                 int dst_stride[3], int src_stride[3], int width,
-                 int height, uint8_t *qp_store, int qp_stride)
+                   int dst_stride[3], int src_stride[3], int width,
+                   int height, uint8_t *qp_store, int qp_stride)
 {
     int x, y, i, j;
     const int count = 1<<p->log2_count;
-    for (i = 0 ; i < 3 ; i++) {
+    int ret;
+
+    for (i = 0; i < 3; i++) {
         int is_chroma = !!i;
-        int w = width  >> is_chroma;
-        int h = height >> is_chroma;
+        int w = AV_CEIL_RSHIFT(width,  is_chroma ? p->hsub : 0);
+        int h = AV_CEIL_RSHIFT(height, is_chroma ? p->vsub : 0);
         int stride = p->temp_stride[i];
-        int block = BLOCK >> is_chroma;
+        int block = BLOCK >> (is_chroma ? p->hsub : 0);
 
         if (!src[i] || !dst[i])
             continue;
-        for (y = 0 ; y < h ; y++) {
+        for (y = 0; y < h; y++) {
             int index = block + block * stride + y * stride;
-            memcpy( p->src[i] + index , src[i] + y * src_stride[i] , w );
-            for (x = 0 ; x < block ; x++) {
-                p->src[i][index     - x - 1]= p->src[i][index +     x    ];
-                p->src[i][index + w + x    ]= p->src[i][index + w - x - 1];
+
+            memcpy(p->src[i] + index, src[i] + y * src_stride[i], w );
+            for (x = 0; x < block; x++) {
+                p->src[i][index     - x - 1] = p->src[i][index +     x    ];
+                p->src[i][index + w + x    ] = p->src[i][index + w - x - 1];
             }
         }
-        for (y = 0 ; y < block ; y++){
-            memcpy(p->src[i] + (  block-1-y) * stride , p->src[i] + (  y+block  ) * stride , stride);
-            memcpy(p->src[i] + (h+block  +y) * stride , p->src[i] + (h-y+block-1) * stride , stride);
+        for (y = 0; y < block; y++) {
+            memcpy(p->src[i] + (  block-1-y) * stride, p->src[i] + (  y+block  ) * stride, stride);
+            memcpy(p->src[i] + (h+block  +y) * stride, p->src[i] + (h-y+block-1) * stride, stride);
         }
 
         p->frame->linesize[i] = stride;
-        memset(p->temp[i] , 0 , (h + 2 * block) * stride * sizeof(int16_t));
+        memset(p->temp[i], 0, (h + 2 * block) * stride * sizeof(int16_t));
     }
 
     if (p->qp)
         p->frame->quality = p->qp * FF_QP2LAMBDA;
-    else
-        p->frame->quality = norm_qscale(qp_store[0] , p->qscale_type) * FF_QP2LAMBDA;
+    else {
+        int qpsum=0;
+        int qpcount = (height>>4) * (height>>4);
+
+        for (y = 0; y < (height>>4); y++) {
+            for (x = 0; x < (width>>4); x++)
+                qpsum += qp_store[x + y * qp_stride];
+        }
+        p->frame->quality = ff_norm_qscale((qpsum + qpcount/2) / qpcount, p->qscale_type) * FF_QP2LAMBDA;
+    }
 //    init per MB qscale stuff FIXME
-    p->frame->height = height;
-    p->frame->width  = width;
+    p->frame->height = height + BLOCK;
+    p->frame->width  = width + BLOCK;
 
-    for (i = 0 ; i < count ; i++) {
+    for (i = 0; i < count; i++) {
         const int x1 = offset[i+count-1][0];
         const int y1 = offset[i+count-1][1];
+        const int x1c = x1 >> p->hsub;
+        const int y1c = y1 >> p->vsub;
+        const int BLOCKc = BLOCK >> p->hsub;
         int offset;
-        AVPacket pkt;
+        AVPacket pkt = {0};
         int got_pkt_ptr;
 
         av_init_packet(&pkt);
@@ -251,50 +246,64 @@ static void filter(USPPContext *p, uint8_t *dst[3], uint8_t *src[3],
         pkt.size = p->outbuf_size;
 
         p->frame->data[0] = p->src[0] + x1   + y1   * p->frame->linesize[0];
-        p->frame->data[1] = p->src[1] + x1/2 + y1/2 * p->frame->linesize[1];
-        p->frame->data[2] = p->src[2] + x1/2 + y1/2 * p->frame->linesize[2];
+        p->frame->data[1] = p->src[1] + x1c  + y1c  * p->frame->linesize[1];
+        p->frame->data[2] = p->src[2] + x1c  + y1c  * p->frame->linesize[2];
         p->frame->format  = p->avctx_enc[i]->pix_fmt;
 
-        avcodec_encode_video2(p->avctx_enc[i] , &pkt , p->frame , &got_pkt_ptr);
+        ret = avcodec_encode_video2(p->avctx_enc[i], &pkt, p->frame, &got_pkt_ptr);
+        if (ret < 0) {
+            av_log(p->avctx_enc[i], AV_LOG_ERROR, "Encoding failed\n");
+            continue;
+        }
+
         p->frame_dec = p->avctx_enc[i]->coded_frame;
 
         offset = (BLOCK-x1) + (BLOCK-y1) * p->frame_dec->linesize[0];
 
-        for (y = 0 ; y < height ; y++)
-            for (x = 0 ; x < width ; x++)
-                p->temp[0][ x + y * p->temp_stride[0] ] += p->frame_dec->data[0][ x + y * p->frame_dec->linesize[0] + offset ];
+        for (y = 0; y < height; y++)
+            for (x = 0; x < width; x++)
+                p->temp[0][x + y * p->temp_stride[0]] += p->frame_dec->data[0][x + y * p->frame_dec->linesize[0] + offset];
+
+        if (!src[2] || !dst[2])
+            continue;
 
-        offset = (BLOCK/2-x1/2) + (BLOCK/2-y1/2) * p->frame_dec->linesize[1];
+        offset = (BLOCKc-x1c) + (BLOCKc-y1c) * p->frame_dec->linesize[1];
 
-        for (y = 0 ; y < height/2 ; y++) {
-            for (x = 0; x < width/2 ; x++) {
-                p->temp[1][ x + y * p->temp_stride[1] ] += p->frame_dec->data[1][ x + y * p->frame_dec->linesize[1] + offset ];
-                p->temp[2][ x + y * p->temp_stride[2] ] += p->frame_dec->data[2][ x + y * p->frame_dec->linesize[2] + offset ];
+        for (y = 0; y < AV_CEIL_RSHIFT(height, p->vsub); y++) {
+            for (x = 0; x < AV_CEIL_RSHIFT(width, p->hsub); x++) {
+                p->temp[1][x + y * p->temp_stride[1]] += p->frame_dec->data[1][x + y * p->frame_dec->linesize[1] + offset];
+                p->temp[2][x + y * p->temp_stride[2]] += p->frame_dec->data[2][x + y * p->frame_dec->linesize[2] + offset];
             }
         }
     }
 
-    for (j = 0 ; j < 3 ; j++) {
+    for (j = 0; j < 3; j++) {
         int is_chroma = !!j;
         if (!dst[j])
             continue;
-        store_slice_c(dst[j] , p->temp[j] , dst_stride[j] , p->temp_stride[j] ,
-             width >> is_chroma , height >> is_chroma , 8-p->log2_count);
+        store_slice_c(dst[j], p->temp[j], dst_stride[j], p->temp_stride[j],
+                      AV_CEIL_RSHIFT(width,  is_chroma ? p->hsub : 0),
+                      AV_CEIL_RSHIFT(height, is_chroma ? p->vsub : 0),
+                      8-p->log2_count);
     }
 }
 
 static int query_formats(AVFilterContext *ctx)
 {
-    static const enum PixelFormat pix_fmts[] = {
-        AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV422P,
-        AV_PIX_FMT_YUV420P,  AV_PIX_FMT_YUV411P,
-        AV_PIX_FMT_YUV410P,  AV_PIX_FMT_YUV440P,
-        AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P,
-        AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
+    static const enum AVPixelFormat pix_fmts[] = {
+        AV_PIX_FMT_YUV444P,
+        AV_PIX_FMT_YUV420P,
+        AV_PIX_FMT_YUV410P,
+        AV_PIX_FMT_YUVJ444P,
+        AV_PIX_FMT_YUVJ420P,
+        AV_PIX_FMT_GRAY8,
         AV_PIX_FMT_NONE
     };
-    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
-    return 0;
+
+    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+    if (!fmts_list)
+        return AVERROR(ENOMEM);
+    return ff_set_common_formats(ctx, fmts_list);
 }
 
 static int config_input(AVFilterLink *inlink)
@@ -304,37 +313,36 @@ static int config_input(AVFilterLink *inlink)
     USPPContext *uspp = ctx->priv;
     const int height = inlink->h;
     const int width  = inlink->w;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     int i;
 
     AVCodec *enc = avcodec_find_encoder(AV_CODEC_ID_SNOW);
-    if(!enc)
-    {
+    if (!enc) {
         av_log(ctx, AV_LOG_ERROR, "SNOW encoder not found.\n");
         return AVERROR(EINVAL);
     }
 
-    if (!uspp->use_bframe_qp) {
-        /* we are assuming here the qp blocks will not be smaller that 16x16 */
-        uspp->non_b_qp_alloc_size = FF_CEIL_RSHIFT(width, 4) * FF_CEIL_RSHIFT(height, 4);
-        uspp->non_b_qp_table = av_calloc(uspp->non_b_qp_alloc_size, sizeof(*uspp->non_b_qp_table));
+    uspp->hsub = desc->log2_chroma_w;
+    uspp->vsub = desc->log2_chroma_h;
 
-        if (!uspp->non_b_qp_table)
-            return AVERROR(ENOMEM);
-    }
-
-    for (i = 0 ; i < 3; i++) {
+    for (i = 0; i < 3; i++) {
         int is_chroma = !!i;
-        int w = ((width  + 4 * BLOCK-1) & (~(2 * BLOCK-1))) >> is_chroma;
-        int h = ((height + 4 * BLOCK-1) & (~(2 * BLOCK-1))) >> is_chroma;
+        int w = (width  + 4 * BLOCK-1) & (~(2 * BLOCK-1));
+        int h = (height + 4 * BLOCK-1) & (~(2 * BLOCK-1));
+
+        if (is_chroma) {
+            w = AV_CEIL_RSHIFT(w, uspp->hsub);
+            h = AV_CEIL_RSHIFT(h, uspp->vsub);
+        }
 
         uspp->temp_stride[i] = w;
-        if (!(uspp->temp[i] = av_malloc(uspp->temp_stride[i] * h * sizeof(int16_t))))
+        if (!(uspp->temp[i] = av_malloc_array(uspp->temp_stride[i], h * sizeof(int16_t))))
             return AVERROR(ENOMEM);
-        if (!(uspp->src [i] = av_malloc(uspp->temp_stride[i] * h * sizeof(uint8_t))))
+        if (!(uspp->src [i] = av_malloc_array(uspp->temp_stride[i], h * sizeof(uint8_t))))
             return AVERROR(ENOMEM);
     }
 
-    for (i = 0 ; i < (1<<uspp->log2_count) ; i++) {
+    for (i = 0; i < (1<<uspp->log2_count); i++) {
         AVCodecContext *avctx_enc;
         AVDictionary *opts = NULL;
         int ret;
@@ -346,10 +354,10 @@ static int config_input(AVFilterLink *inlink)
         avctx_enc->width = width + BLOCK;
         avctx_enc->height = height + BLOCK;
         avctx_enc->time_base = (AVRational){1,25};  // meaningless
-        avctx_enc->gop_size = 300;
+        avctx_enc->gop_size = INT_MAX;
         avctx_enc->max_b_frames = 0;
-        avctx_enc->pix_fmt = AV_PIX_FMT_YUV420P;
-        avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
+        avctx_enc->pix_fmt = inlink->format;
+        avctx_enc->flags = AV_CODEC_FLAG_QSCALE | AV_CODEC_FLAG_LOW_DELAY;
         avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
         avctx_enc->global_quality = 123;
         av_dict_set(&opts, "no_bitstream", "1", 0);
@@ -362,9 +370,9 @@ static int config_input(AVFilterLink *inlink)
 
     uspp->outbuf_size = (width + BLOCK) * (height + BLOCK) * 10;
     if (!(uspp->frame = av_frame_alloc()))
-            return AVERROR(ENOMEM);
+        return AVERROR(ENOMEM);
     if (!(uspp->outbuf = av_malloc(uspp->outbuf_size)))
-            return AVERROR(ENOMEM);
+        return AVERROR(ENOMEM);
 
     return 0;
 }
@@ -392,14 +400,24 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             /* if the qp stride is not set, it means the QP are only defined on
              * a line basis */
             if (!qp_stride) {
-                w = FF_CEIL_RSHIFT(inlink->w, 4);
+                w = AV_CEIL_RSHIFT(inlink->w, 4);
                 h = 1;
             } else {
-                w = FF_CEIL_RSHIFT(qp_stride, 4);
-                h = FF_CEIL_RSHIFT(inlink->h, 4);
+                w = qp_stride;
+                h = AV_CEIL_RSHIFT(inlink->h, 4);
             }
+
+            if (w * h > uspp->non_b_qp_alloc_size) {
+                int ret = av_reallocp_array(&uspp->non_b_qp_table, w, h);
+                if (ret < 0) {
+                    uspp->non_b_qp_alloc_size = 0;
+                    return ret;
+                }
+                uspp->non_b_qp_alloc_size = w * h;
+            }
+
             av_assert0(w * h <= uspp->non_b_qp_alloc_size);
-            memcpy(uspp->non_b_qp_table , qp_table , w * h);
+            memcpy(uspp->non_b_qp_table, qp_table, w * h);
         }
     }
 
@@ -425,7 +443,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
                 out->height = in->height;
             }
 
-            filter(uspp , out->data , in->data , out->linesize , in->linesize , inlink->w , inlink->h , qp_table , qp_stride);
+            filter(uspp, out->data, in->data, out->linesize, in->linesize,
+                   inlink->w, inlink->h, qp_table, qp_stride);
         }
     }
 
@@ -444,12 +463,12 @@ static av_cold void uninit(AVFilterContext *ctx)
     USPPContext *uspp = ctx->priv;
     int i;
 
-    for (i = 0 ; i < 3 ; i++) {
+    for (i = 0; i < 3; i++) {
         av_freep(&uspp->temp[i]);
         av_freep(&uspp->src[i]);
     }
 
-    for (i = 0 ; i < (1 << uspp->log2_count) ; i++) {
+    for (i = 0; i < (1 << uspp->log2_count); i++) {
         avcodec_close(uspp->avctx_enc[i]);
         av_freep(&uspp->avctx_enc[i]);
     }