]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/libkvazaar.c
Merge commit '4dfbc7a7559ccab666a8fd39de4224eb4b02c768'
[ffmpeg] / libavcodec / libkvazaar.c
index 3000f6ac6e7045568a997e8e98e2816b0db9c41a..e58405d27e4f7efc3f0a2360b64f4a3d2bf0d0ee 100644 (file)
 #include <string.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/pixdesc.h"
+#include "libavutil/opt.h"
+
 #include "avcodec.h"
 #include "internal.h"
 
@@ -43,39 +46,39 @@ 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->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) {
@@ -84,8 +87,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);
                 }
             }
@@ -93,40 +95,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;
 }
@@ -136,15 +149,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;
 
@@ -171,14 +182,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,
@@ -186,22 +197,26 @@ 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;
@@ -218,14 +233,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)].
@@ -233,10 +243,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;
@@ -247,10 +259,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 },
 };
 
@@ -281,4 +294,6 @@ 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,
 };