avfilter/vf_framerate: change blend factor precision
[ffmpeg.git] / libavcodec / libkvazaar.c
index 0cf890f..41a1bbb 100644 (file)
  */
 
 #include <kvazaar.h>
+#include <stdint.h>
 #include <string.h>
 
+#include "libavutil/attributes.h"
 #include "libavutil/avassert.h"
-#include "libavutil/imgutils.h"
 #include "libavutil/dict.h"
-#include "libavutil/opt.h"
+#include "libavutil/error.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/internal.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+
 #include "avcodec.h"
 #include "internal.h"
 
@@ -43,40 +50,44 @@ typedef struct LibkvazaarContext {
 
 static av_cold int libkvazaar_init(AVCodecContext *avctx)
 {
-    int retval = 0;
+    LibkvazaarContext *const ctx = avctx->priv_data;
+    const kvz_api *const api = ctx->api = kvz_api_get(8);
     kvz_config *cfg = NULL;
     kvz_encoder *enc = NULL;
-    const kvz_api *const api = kvz_api_get(8);
 
-    LibkvazaarContext *const ctx = avctx->priv_data;
-
-    // Kvazaar requires width and height to be multiples of eight.
+    /* Kvazaar requires width and height to be multiples of eight. */
     if (avctx->width % 8 || avctx->height % 8) {
-        av_log(avctx, AV_LOG_ERROR, "Video dimensions are not a multiple of 8.\n");
-        retval = AVERROR_INVALIDDATA;
-        goto done;
+        av_log(avctx, AV_LOG_ERROR,
+               "Video dimensions are not a multiple of 8 (%dx%d).\n",
+               avctx->width, avctx->height);
+        return AVERROR(ENOSYS);
     }
 
-    cfg = api->config_alloc();
+    ctx->config = cfg = api->config_alloc();
     if (!cfg) {
-        av_log(avctx, AV_LOG_ERROR, "Could not allocate kvazaar config structure.\n");
-        retval = AVERROR(ENOMEM);
-        goto done;
+        av_log(avctx, AV_LOG_ERROR,
+               "Could not allocate kvazaar config structure.\n");
+        return AVERROR(ENOMEM);
     }
 
     if (!api->config_init(cfg)) {
-        av_log(avctx, AV_LOG_ERROR, "Could not initialize kvazaar config structure.\n");
-        retval = AVERROR_EXTERNAL;
-        goto done;
+        av_log(avctx, AV_LOG_ERROR,
+               "Could not initialize kvazaar config structure.\n");
+        return AVERROR_BUG;
     }
 
-    cfg->width = avctx->width;
+    cfg->width  = avctx->width;
     cfg->height = avctx->height;
-    cfg->framerate =
-      avctx->time_base.den / (double)(avctx->time_base.num * avctx->ticks_per_frame);
-    cfg->threads = avctx->thread_count;
+
+    if (avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Could not set framerate for kvazaar: integer overflow\n");
+        return AVERROR(EINVAL);
+    }
+    cfg->framerate_num   = avctx->time_base.den;
+    cfg->framerate_denom = avctx->time_base.num * avctx->ticks_per_frame;
     cfg->target_bitrate = avctx->bit_rate;
-    cfg->vui.sar_width = avctx->sample_aspect_ratio.num;
+    cfg->vui.sar_width  = avctx->sample_aspect_ratio.num;
     cfg->vui.sar_height = avctx->sample_aspect_ratio.den;
 
     if (ctx->kvz_params) {
@@ -85,8 +96,7 @@ static av_cold int libkvazaar_init(AVCodecContext *avctx)
             AVDictionaryEntry *entry = NULL;
             while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) {
                 if (!api->config_parse(cfg, entry->key, entry->value)) {
-                    av_log(avctx, AV_LOG_WARNING,
-                           "Invalid option: %s=%s.\n",
+                    av_log(avctx, AV_LOG_WARNING, "Invalid option: %s=%s.\n",
                            entry->key, entry->value);
                 }
             }
@@ -94,40 +104,51 @@ static av_cold int libkvazaar_init(AVCodecContext *avctx)
         }
     }
 
-    enc = api->encoder_open(cfg);
+    ctx->encoder = enc = api->encoder_open(cfg);
     if (!enc) {
         av_log(avctx, AV_LOG_ERROR, "Could not open kvazaar encoder.\n");
-        retval = AVERROR_EXTERNAL;
-        goto done;
+        return AVERROR_BUG;
     }
 
-    ctx->api = api;
-    ctx->encoder = enc;
-    ctx->config = cfg;
-    enc = NULL;
-    cfg = NULL;
+    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+        kvz_data_chunk *data_out = NULL;
+        kvz_data_chunk *chunk = NULL;
+        uint32_t len_out;
+        uint8_t *p;
 
-done:
-    api->config_destroy(cfg);
-    api->encoder_close(enc);
+        if (!api->encoder_headers(enc, &data_out, &len_out))
+            return AVERROR(ENOMEM);
 
-    return retval;
+        avctx->extradata = p = av_mallocz(len_out + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!p) {
+            ctx->api->chunk_free(data_out);
+            return AVERROR(ENOMEM);
+        }
+
+        avctx->extradata_size = len_out;
+
+        for (chunk = data_out; chunk != NULL; chunk = chunk->next) {
+            memcpy(p, chunk->data, chunk->len);
+            p += chunk->len;
+        }
+
+        ctx->api->chunk_free(data_out);
+    }
+
+    return 0;
 }
 
 static av_cold int libkvazaar_close(AVCodecContext *avctx)
 {
     LibkvazaarContext *ctx = avctx->priv_data;
-    if (!ctx->api) return 0;
 
-    if (ctx->encoder) {
-        ctx->api->encoder_close(ctx->encoder);
-        ctx->encoder = NULL;
+    if (ctx->api) {
+      ctx->api->encoder_close(ctx->encoder);
+      ctx->api->config_destroy(ctx->config);
     }
 
-    if (ctx->config) {
-        ctx->api->config_destroy(ctx->config);
-        ctx->config = NULL;
-    }
+    if (avctx->extradata)
+        av_freep(&avctx->extradata);
 
     return 0;
 }
@@ -137,15 +158,13 @@ static int libkvazaar_encode(AVCodecContext *avctx,
                              const AVFrame *frame,
                              int *got_packet_ptr)
 {
-    int retval = 0;
-    kvz_picture *img_in = NULL;
-
-    kvz_data_chunk *data_out = NULL;
-    uint32_t len_out = 0;
+    LibkvazaarContext *ctx = avctx->priv_data;
+    kvz_picture *input_pic = NULL;
     kvz_picture *recon_pic = NULL;
     kvz_frame_info frame_info;
-
-    LibkvazaarContext *ctx = avctx->priv_data;
+    kvz_data_chunk *data_out = NULL;
+    uint32_t len_out = 0;
+    int retval = 0;
 
     *got_packet_ptr = 0;
 
@@ -172,14 +191,14 @@ static int libkvazaar_encode(AVCodecContext *avctx,
         }
 
         // Allocate input picture for kvazaar.
-        img_in = ctx->api->picture_alloc(frame->width, frame->height);
-        if (!img_in) {
+        input_pic = ctx->api->picture_alloc(frame->width, frame->height);
+        if (!input_pic) {
             av_log(avctx, AV_LOG_ERROR, "Failed to allocate picture.\n");
             retval = AVERROR(ENOMEM);
             goto done;
         }
 
-        // Copy pixels from frame to img_in.
+        // Copy pixels from frame to input_pic.
         {
             int dst_linesizes[4] = {
               frame->width,
@@ -187,28 +206,32 @@ static int libkvazaar_encode(AVCodecContext *avctx,
               frame->width / 2,
               0
             };
-            av_image_copy(img_in->data, dst_linesizes,
+            av_image_copy(input_pic->data, dst_linesizes,
                           frame->data, frame->linesize,
                           frame->format, frame->width, frame->height);
         }
 
-        img_in->pts = frame->pts;
+        input_pic->pts = frame->pts;
     }
 
-    if (!ctx->api->encoder_encode(ctx->encoder, img_in,
-                                  &data_out, &len_out,
-                                  &recon_pic, NULL,
-                                  &frame_info)) {
+    retval = ctx->api->encoder_encode(ctx->encoder,
+                                      input_pic,
+                                      &data_out, &len_out,
+                                      &recon_pic, NULL,
+                                      &frame_info);
+    if (!retval) {
         av_log(avctx, AV_LOG_ERROR, "Failed to encode frame.\n");
-        retval = AVERROR_EXTERNAL;
+        retval = AVERROR_INVALIDDATA;
         goto done;
     }
+    else
+        retval = 0; /* kvazaar returns 1 on success */
 
     if (data_out) {
         kvz_data_chunk *chunk = NULL;
         uint64_t written = 0;
 
-        retval = ff_alloc_packet(avpkt, len_out);
+        retval = ff_alloc_packet2(avctx, avpkt, len_out, len_out);
         if (retval < 0) {
             av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n");
             goto done;
@@ -219,14 +242,9 @@ static int libkvazaar_encode(AVCodecContext *avctx,
             memcpy(avpkt->data + written, chunk->data, chunk->len);
             written += chunk->len;
         }
-        *got_packet_ptr = 1;
-
-        ctx->api->chunk_free(data_out);
-        data_out = NULL;
 
         avpkt->pts = recon_pic->pts;
         avpkt->dts = recon_pic->dts;
-
         avpkt->flags = 0;
         // IRAP VCL NAL unit types span the range
         // [BLA_W_LP (16), RSV_IRAP_VCL23 (23)].
@@ -234,10 +252,12 @@ static int libkvazaar_encode(AVCodecContext *avctx,
                 frame_info.nal_unit_type <= KVZ_NAL_RSV_IRAP_VCL23) {
             avpkt->flags |= AV_PKT_FLAG_KEY;
         }
+
+        *got_packet_ptr = 1;
     }
 
 done:
-    ctx->api->picture_free(img_in);
+    ctx->api->picture_free(input_pic);
     ctx->api->picture_free(recon_pic);
     ctx->api->chunk_free(data_out);
     return retval;
@@ -248,10 +268,11 @@ static const enum AVPixelFormat pix_fmts[] = {
     AV_PIX_FMT_NONE
 };
 
+#define OFFSET(x) offsetof(LibkvazaarContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
-    { "kvazaar-params", "Set kvazaar parameters as a comma-separated list of name=value pairs.",
-      offsetof(LibkvazaarContext, kvz_params), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0,
-      AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
+    { "kvazaar-params", "Set kvazaar parameters as a comma-separated list of key=value pairs.",
+        OFFSET(kvz_params), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE },
     { NULL },
 };
 
@@ -282,4 +303,8 @@ AVCodec ff_libkvazaar_encoder = {
     .init             = libkvazaar_init,
     .encode2          = libkvazaar_encode,
     .close            = libkvazaar_close,
+
+    .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
+
+    .wrapper_name     = "libkvazaar",
 };