4 * Copyright (c) 2015 Tampere University of Technology
6 * This file is part of FFmpeg.
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.
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.
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
26 #include "libavutil/avassert.h"
27 #include "libavutil/imgutils.h"
28 #include "libavutil/dict.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/pixdesc.h"
34 typedef struct LibkvazaarContext {
44 static av_cold int libkvazaar_init(AVCodecContext *avctx)
47 kvz_config *cfg = NULL;
48 kvz_encoder *enc = NULL;
49 const kvz_api *const api = kvz_api_get(8);
51 LibkvazaarContext *const ctx = avctx->priv_data;
53 // Kvazaar requires width and height to be multiples of eight.
54 if (avctx->width % 8 || avctx->height % 8) {
55 av_log(avctx, AV_LOG_ERROR, "Video dimensions are not a multiple of 8.\n");
56 retval = AVERROR_INVALIDDATA;
60 cfg = api->config_alloc();
62 av_log(avctx, AV_LOG_ERROR, "Could not allocate kvazaar config structure.\n");
63 retval = AVERROR(ENOMEM);
67 if (!api->config_init(cfg)) {
68 av_log(avctx, AV_LOG_ERROR, "Could not initialize kvazaar config structure.\n");
69 retval = AVERROR_EXTERNAL;
73 cfg->width = avctx->width;
74 cfg->height = avctx->height;
76 avctx->time_base.den / (double)(avctx->time_base.num * avctx->ticks_per_frame);
77 cfg->target_bitrate = avctx->bit_rate;
78 cfg->vui.sar_width = avctx->sample_aspect_ratio.num;
79 cfg->vui.sar_height = avctx->sample_aspect_ratio.den;
81 if (ctx->kvz_params) {
82 AVDictionary *dict = NULL;
83 if (!av_dict_parse_string(&dict, ctx->kvz_params, "=", ",", 0)) {
84 AVDictionaryEntry *entry = NULL;
85 while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) {
86 if (!api->config_parse(cfg, entry->key, entry->value)) {
87 av_log(avctx, AV_LOG_WARNING,
88 "Invalid option: %s=%s.\n",
89 entry->key, entry->value);
96 enc = api->encoder_open(cfg);
98 av_log(avctx, AV_LOG_ERROR, "Could not open kvazaar encoder.\n");
99 retval = AVERROR_EXTERNAL;
110 api->config_destroy(cfg);
111 api->encoder_close(enc);
116 static av_cold int libkvazaar_close(AVCodecContext *avctx)
118 LibkvazaarContext *ctx = avctx->priv_data;
119 if (!ctx->api) return 0;
122 ctx->api->encoder_close(ctx->encoder);
127 ctx->api->config_destroy(ctx->config);
134 static int libkvazaar_encode(AVCodecContext *avctx,
136 const AVFrame *frame,
140 kvz_picture *img_in = NULL;
142 kvz_data_chunk *data_out = NULL;
143 uint32_t len_out = 0;
144 kvz_picture *recon_pic = NULL;
145 kvz_frame_info frame_info;
147 LibkvazaarContext *ctx = avctx->priv_data;
152 if (frame->width != ctx->config->width ||
153 frame->height != ctx->config->height) {
154 av_log(avctx, AV_LOG_ERROR,
155 "Changing video dimensions during encoding is not supported. "
156 "(changed from %dx%d to %dx%d)\n",
157 ctx->config->width, ctx->config->height,
158 frame->width, frame->height);
159 retval = AVERROR_INVALIDDATA;
163 if (frame->format != avctx->pix_fmt) {
164 av_log(avctx, AV_LOG_ERROR,
165 "Changing pixel format during encoding is not supported. "
166 "(changed from %s to %s)\n",
167 av_get_pix_fmt_name(avctx->pix_fmt),
168 av_get_pix_fmt_name(frame->format));
169 retval = AVERROR_INVALIDDATA;
173 // Allocate input picture for kvazaar.
174 img_in = ctx->api->picture_alloc(frame->width, frame->height);
176 av_log(avctx, AV_LOG_ERROR, "Failed to allocate picture.\n");
177 retval = AVERROR(ENOMEM);
181 // Copy pixels from frame to img_in.
183 int dst_linesizes[4] = {
189 av_image_copy(img_in->data, dst_linesizes,
190 frame->data, frame->linesize,
191 frame->format, frame->width, frame->height);
194 img_in->pts = frame->pts;
197 if (!ctx->api->encoder_encode(ctx->encoder, img_in,
201 av_log(avctx, AV_LOG_ERROR, "Failed to encode frame.\n");
202 retval = AVERROR_EXTERNAL;
207 kvz_data_chunk *chunk = NULL;
208 uint64_t written = 0;
210 retval = ff_alloc_packet(avpkt, len_out);
212 av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n");
216 for (chunk = data_out; chunk != NULL; chunk = chunk->next) {
217 av_assert0(written + chunk->len <= len_out);
218 memcpy(avpkt->data + written, chunk->data, chunk->len);
219 written += chunk->len;
223 ctx->api->chunk_free(data_out);
226 avpkt->pts = recon_pic->pts;
227 avpkt->dts = recon_pic->dts;
230 // IRAP VCL NAL unit types span the range
231 // [BLA_W_LP (16), RSV_IRAP_VCL23 (23)].
232 if (frame_info.nal_unit_type >= KVZ_NAL_BLA_W_LP &&
233 frame_info.nal_unit_type <= KVZ_NAL_RSV_IRAP_VCL23) {
234 avpkt->flags |= AV_PKT_FLAG_KEY;
239 ctx->api->picture_free(img_in);
240 ctx->api->picture_free(recon_pic);
241 ctx->api->chunk_free(data_out);
245 static const enum AVPixelFormat pix_fmts[] = {
250 static const AVOption options[] = {
251 { "kvazaar-params", "Set kvazaar parameters as a comma-separated list of name=value pairs.",
252 offsetof(LibkvazaarContext, kvz_params), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0,
253 AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
257 static const AVClass class = {
258 .class_name = "libkvazaar",
259 .item_name = av_default_item_name,
261 .version = LIBAVUTIL_VERSION_INT,
264 static const AVCodecDefault defaults[] = {
269 AVCodec ff_libkvazaar_encoder = {
270 .name = "libkvazaar",
271 .long_name = NULL_IF_CONFIG_SMALL("libkvazaar H.265 / HEVC"),
272 .type = AVMEDIA_TYPE_VIDEO,
273 .id = AV_CODEC_ID_HEVC,
274 .capabilities = AV_CODEC_CAP_DELAY,
275 .pix_fmts = pix_fmts,
277 .priv_class = &class,
278 .priv_data_size = sizeof(LibkvazaarContext),
279 .defaults = defaults,
281 .init = libkvazaar_init,
282 .encode2 = libkvazaar_encode,
283 .close = libkvazaar_close,