libkvazaar: Remove unnecessary NULL checks
[ffmpeg.git] / libavcodec / libkvazaar.c
1 /*
2  * libkvazaar encoder
3  *
4  * Copyright (c) 2015 Tampere University of Technology
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include <kvazaar.h>
24 #include <string.h>
25
26 #include "libavutil/avassert.h"
27 #include "libavutil/dict.h"
28 #include "libavutil/opt.h"
29 #include "avcodec.h"
30 #include "internal.h"
31
32 typedef struct LibkvazaarContext {
33     const AVClass *class;
34
35     const kvz_api *api;
36     kvz_encoder *encoder;
37     kvz_config *config;
38
39     char *kvz_params;
40 } LibkvazaarContext;
41
42 static av_cold int libkvazaar_init(AVCodecContext *avctx)
43 {
44     int retval = 0;
45     kvz_config *cfg = NULL;
46     kvz_encoder *enc = NULL;
47     const kvz_api *const api = kvz_api_get(8);
48
49     LibkvazaarContext *const ctx = avctx->priv_data;
50
51     // Kvazaar requires width and height to be multiples of eight.
52     if (avctx->width % 8 || avctx->height % 8) {
53         av_log(avctx, AV_LOG_ERROR, "Video dimensions are not a multiple of 8.\n");
54         retval = AVERROR_INVALIDDATA;
55         goto done;
56     }
57
58     cfg = api->config_alloc();
59     if (!cfg) {
60         av_log(avctx, AV_LOG_ERROR, "Could not allocate kvazaar config structure.\n");
61         retval = AVERROR(ENOMEM);
62         goto done;
63     }
64
65     if (!api->config_init(cfg)) {
66         av_log(avctx, AV_LOG_ERROR, "Could not initialize kvazaar config structure.\n");
67         retval = AVERROR_EXTERNAL;
68         goto done;
69     }
70
71     cfg->width = avctx->width;
72     cfg->height = avctx->height;
73     cfg->framerate =
74       (double)(avctx->time_base.num * avctx->ticks_per_frame) / avctx->time_base.den;
75     cfg->threads = avctx->thread_count;
76     cfg->target_bitrate = avctx->bit_rate;
77     cfg->vui.sar_width = avctx->sample_aspect_ratio.num;
78     cfg->vui.sar_height = avctx->sample_aspect_ratio.den;
79
80     if (ctx->kvz_params) {
81         AVDictionary *dict = NULL;
82         if (!av_dict_parse_string(&dict, ctx->kvz_params, "=", ",", 0)) {
83             AVDictionaryEntry *entry = NULL;
84             while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) {
85                 if (!api->config_parse(cfg, entry->key, entry->value)) {
86                     av_log(avctx, AV_LOG_WARNING,
87                            "Invalid option: %s=%s.\n",
88                            entry->key, entry->value);
89                 }
90             }
91             av_dict_free(&dict);
92         }
93     }
94
95     enc = api->encoder_open(cfg);
96     if (!enc) {
97         av_log(avctx, AV_LOG_ERROR, "Could not open kvazaar encoder.\n");
98         retval = AVERROR_EXTERNAL;
99         goto done;
100     }
101
102     ctx->api = api;
103     ctx->encoder = enc;
104     ctx->config = cfg;
105     enc = NULL;
106     cfg = NULL;
107
108 done:
109     api->config_destroy(cfg);
110     api->encoder_close(enc);
111
112     return retval;
113 }
114
115 static av_cold int libkvazaar_close(AVCodecContext *avctx)
116 {
117     LibkvazaarContext *ctx = avctx->priv_data;
118     if (!ctx->api) return 0;
119
120     if (ctx->encoder) {
121         ctx->api->encoder_close(ctx->encoder);
122         ctx->encoder = NULL;
123     }
124
125     if (ctx->config) {
126         ctx->api->config_destroy(ctx->config);
127         ctx->config = NULL;
128     }
129
130     return 0;
131 }
132
133 static int libkvazaar_encode(AVCodecContext *avctx,
134                              AVPacket *avpkt,
135                              const AVFrame *frame,
136                              int *got_packet_ptr)
137 {
138     int retval = 0;
139     kvz_picture *img_in = NULL;
140
141     kvz_data_chunk *data_out = NULL;
142     uint32_t len_out = 0;
143     kvz_frame_info frame_info;
144
145     LibkvazaarContext *ctx = avctx->priv_data;
146
147     *got_packet_ptr = 0;
148
149     if (frame) {
150         int i = 0;
151
152         av_assert0(frame->width == ctx->config->width);
153         av_assert0(frame->height == ctx->config->height);
154         av_assert0(frame->format == avctx->pix_fmt);
155
156         // Allocate input picture for kvazaar.
157         img_in = ctx->api->picture_alloc(frame->width, frame->height);
158         if (!img_in) {
159             av_log(avctx, AV_LOG_ERROR, "Failed to allocate picture.\n");
160             retval = AVERROR(ENOMEM);
161             goto done;
162         }
163
164         // Copy pixels from frame to img_in.
165         for (i = 0; i < 3; ++i) {
166             uint8_t *dst = img_in->data[i];
167             uint8_t *src = frame->data[i];
168             int width = (i == 0) ? frame->width : (frame->width / 2);
169             int height = (i == 0) ? frame->height : (frame->height / 2);
170             int y = 0;
171             for (y = 0; y < height; ++y) {
172                 memcpy(dst, src, width);
173                 src += frame->linesize[i];
174                 dst += width;
175             }
176         }
177     }
178
179     if (!ctx->api->encoder_encode(ctx->encoder, img_in,
180                                   &data_out, &len_out,
181                                   NULL, NULL,
182                                   &frame_info)) {
183         av_log(avctx, AV_LOG_ERROR, "Failed to encode frame.\n");
184         retval = AVERROR_EXTERNAL;
185         goto done;
186     }
187
188     if (data_out) {
189         kvz_data_chunk *chunk = NULL;
190         uint64_t written = 0;
191
192         retval = ff_alloc_packet(avpkt, len_out);
193         if (retval < 0) {
194             av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n");
195             goto done;
196         }
197
198         for (chunk = data_out; chunk != NULL; chunk = chunk->next) {
199             av_assert0(written + chunk->len <= len_out);
200             memcpy(avpkt->data + written, chunk->data, chunk->len);
201             written += chunk->len;
202         }
203         *got_packet_ptr = 1;
204
205         ctx->api->chunk_free(data_out);
206         data_out = NULL;
207
208         avpkt->flags = 0;
209         // IRAP VCL NAL unit types span the range
210         // [BLA_W_LP (16), RSV_IRAP_VCL23 (23)].
211         if (frame_info.nal_unit_type >= KVZ_NAL_BLA_W_LP &&
212                 frame_info.nal_unit_type <= KVZ_NAL_RSV_IRAP_VCL23) {
213             avpkt->flags |= AV_PKT_FLAG_KEY;
214         }
215     }
216
217 done:
218     ctx->api->picture_free(img_in);
219     ctx->api->chunk_free(data_out);
220     return retval;
221 }
222
223 static const enum AVPixelFormat pix_fmts[] = {
224     AV_PIX_FMT_YUV420P,
225     AV_PIX_FMT_NONE
226 };
227
228 static const AVOption options[] = {
229     { "kvazaar-params", "Set kvazaar parameters as a comma-separated list of name=value pairs.",
230       offsetof(LibkvazaarContext, kvz_params), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0,
231       AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
232     { NULL },
233 };
234
235 static const AVClass class = {
236     .class_name = "libkvazaar",
237     .item_name  = av_default_item_name,
238     .option     = options,
239     .version    = LIBAVUTIL_VERSION_INT,
240 };
241
242 static const AVCodecDefault defaults[] = {
243     { "b", "0" },
244     { NULL },
245 };
246
247 AVCodec ff_libkvazaar_encoder = {
248     .name             = "libkvazaar",
249     .long_name        = NULL_IF_CONFIG_SMALL("libkvazaar H.265 / HEVC"),
250     .type             = AVMEDIA_TYPE_VIDEO,
251     .id               = AV_CODEC_ID_HEVC,
252     .capabilities     = AV_CODEC_CAP_DELAY,
253     .pix_fmts         = pix_fmts,
254
255     .priv_class       = &class,
256     .priv_data_size   = sizeof(LibkvazaarContext),
257     .defaults         = defaults,
258
259     .init             = libkvazaar_init,
260     .encode2          = libkvazaar_encode,
261     .close            = libkvazaar_close,
262 };