diff mbox

[FFmpeg-devel] Added the interface for the Turing codec

Message ID 1479482749-9868-1-git-send-email-matteo.naccari@bbc.co.uk
State New
Headers show

Commit Message

Matteo Naccari Nov. 18, 2016, 3:25 p.m. UTC
- The Turing codec is an open source HEVC encoder licensed under GPLv2
- More information at http://turingcodec.org/
---
 LICENSE.md             |   1 +
 configure              |   5 ++
 libavcodec/Makefile    |   1 +
 libavcodec/allcodecs.c |   1 +
 libavcodec/libturing.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 237 insertions(+)
 create mode 100644 libavcodec/libturing.c

Comments

Josh Dekker Nov. 18, 2016, 4:45 p.m. UTC | #1
On 18/11/2016 15:25, Matteo Naccari wrote:
> - The Turing codec is an open source HEVC encoder licensed under GPLv2
> - More information at http://turingcodec.org/
> ---
>  LICENSE.md             |   1 +
>  configure              |   5 ++
>  libavcodec/Makefile    |   1 +
>  libavcodec/allcodecs.c |   1 +
>  libavcodec/libturing.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 237 insertions(+)
>  create mode 100644 libavcodec/libturing.c
>
> diff --git a/LICENSE.md b/LICENSE.md
> index a384fa0..6f9fab8 100644
> --- a/LICENSE.md
> +++ b/LICENSE.md
> @@ -86,6 +86,7 @@ The following libraries are under GPL:
>  - frei0r
>  - libcdio
>  - librubberband
> +- libturing
>  - libvidstab
>  - libx264
>  - libx265
> diff --git a/configure b/configure
> index b5bfad6..47d6b93 100755
> --- a/configure
> +++ b/configure
> @@ -255,6 +255,7 @@ External library support:
>    --enable-libssh          enable SFTP protocol via libssh [no]
>    --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
>    --enable-libtheora       enable Theora encoding via libtheora [no]
> +  --enable-libturing       enable HEVC encoding via libturing [no]
>    --enable-libtwolame      enable MP2 encoding via libtwolame [no]
>    --enable-libv4l2         enable libv4l2/v4l-utils [no]
>    --enable-libvidstab      enable video stabilization using vid.stab [no]
> @@ -1521,6 +1522,7 @@ EXTERNAL_LIBRARY_LIST="
>      libssh
>      libtesseract
>      libtheora
> +    libturing
>      libtwolame
>      libv4l2
>      libvidstab
> @@ -2814,6 +2816,7 @@ libspeex_decoder_deps="libspeex"
>  libspeex_encoder_deps="libspeex"
>  libspeex_encoder_select="audio_frame_queue"
>  libtheora_encoder_deps="libtheora"
> +libturing_encoder_deps="libturing"
>  libtwolame_encoder_deps="libtwolame"
>  libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
>  libvorbis_decoder_deps="libvorbis"
> @@ -5072,6 +5075,7 @@ die_license_disabled gpl frei0r
>  die_license_disabled gpl libcdio
>  die_license_disabled gpl librubberband
>  die_license_disabled gpl libsmbclient
> +die_license_disabled gpl libturing
>  die_license_disabled gpl libvidstab
>  die_license_disabled gpl libx264
>  die_license_disabled gpl libx265
> @@ -5735,6 +5739,7 @@ enabled libssh            && require_pkg_config libssh libssh/sftp.h sftp_init
>  enabled libspeex          && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex
>  enabled libtesseract      && require_pkg_config tesseract tesseract/capi.h TessBaseAPICreate
>  enabled libtheora         && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
> +enabled libturing         && require libturing turing.h turing_version -lturing -lstdc++ -lboost_chrono -lboost_program_options -lboost_timer -lboost_system -lboost_filesystem -lhavoc
>  enabled libtwolame        && require libtwolame twolame.h twolame_init -ltwolame &&
>                               { check_lib twolame.h twolame_encode_buffer_float32_interleaved -ltwolame ||
>                                 die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; }
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 82f7fa2..cadefdc 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -880,6 +880,7 @@ OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
>  OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
>  OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
>  OBJS-$(CONFIG_LIBTWOLAME_ENCODER)         += libtwolame.o
> +OBJS-$(CONFIG_LIBTURING_ENCODER)          += libturing.o
>  OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER)     += libvo-amrwbenc.o
>  OBJS-$(CONFIG_LIBVORBIS_DECODER)          += libvorbisdec.o
>  OBJS-$(CONFIG_LIBVORBIS_ENCODER)          += libvorbisenc.o \
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index ada9481..0e61a4a 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -610,6 +610,7 @@ void avcodec_register_all(void)
>      REGISTER_ENCDEC (LIBSPEEX,          libspeex);
>      REGISTER_ENCODER(LIBTHEORA,         libtheora);
>      REGISTER_ENCODER(LIBTWOLAME,        libtwolame);
> +    REGISTER_ENCODER(LIBTURING,         libturing);
>      REGISTER_ENCODER(LIBVO_AMRWBENC,    libvo_amrwbenc);
>      REGISTER_ENCDEC (LIBVORBIS,         libvorbis);
>      REGISTER_ENCDEC (LIBVPX_VP8,        libvpx_vp8);
> diff --git a/libavcodec/libturing.c b/libavcodec/libturing.c
> new file mode 100644
> index 0000000..3191a41
> --- /dev/null
> +++ b/libavcodec/libturing.c
> @@ -0,0 +1,229 @@
> +/*
> + * libturing encoder
> + *
> + * Copyright (c) 2016 Turing Codec contributors
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <turing.h>
> +#include <float.h>
> +#include "libavutil/internal.h"
> +#include "libavutil/common.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/pixdesc.h"
> +#include "avcodec.h"
> +#include "internal.h"
> +
> +typedef struct libturingEncodeContext {
> +    const AVClass *class;
> +    turing_encoder *encoder;
> +    const char *options;
> +} libturingEncodeContext;
> +
> +static av_cold int libturing_encode_close(AVCodecContext *avctx)
> +{
> +    libturingEncodeContext *ctx = avctx->priv_data;
> +
> +    if (ctx->encoder)
> +        turing_destroy_encoder(ctx->encoder);
> +
> +    return 0;
> +}
> +
> +static av_cold int libturing_encode_init(AVCodecContext *avctx)
> +{
> +    libturingEncodeContext *ctx = avctx->priv_data;
> +
> +    char options[1024];
> +    char* s = options;
> +    char *end = &options[sizeof(options)];
> +
> +    char const* argv[32];
> +    char const** p = argv;
> +    turing_encoder_settings settings;
> +
> +    *p++ = s;
> +    *p++ = s += 1 + snprintf(s, end - s, "turing");
> +    *p++ = s += 1 + snprintf(s, end - s, "--input-res=%dx%d", avctx->width, avctx->height);
> +    *p++ = s += 1 + snprintf(s, end - s, "--frame-rate=%f", (double)avctx->time_base.den / (avctx->time_base.num * avctx->ticks_per_frame));
> +    *p++ = s += 1 + snprintf(s, end - s, "--frames=0");
> +
> +    {
> +        int const bit_depth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
> +        if (bit_depth != 8 && bit_depth != 10) {
> +            av_log(avctx, AV_LOG_ERROR, "Encoder input must be 8- or 10-bit.\n");
> +            turing_destroy_encoder(ctx->encoder);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        *p++ = s += 1 + snprintf(s, end - s, "--bit-depth=%d", bit_depth);
> +        *p++ = s += 1 + snprintf(s, end - s, "--internal-bit-depth=%d", bit_depth);
> +    }
> +
> +    if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
> +        int sar_num, sar_den;
> +
> +        av_reduce(&sar_num, &sar_den,
> +            avctx->sample_aspect_ratio.num,
> +            avctx->sample_aspect_ratio.den, 65535);
> +
> +        *p++ = s += 1 + snprintf(s, end - s, "--sar=%d:%d", sar_num, sar_den);
> +    }
> +
> +    if (ctx->options) {
> +        AVDictionary *dict = NULL;
> +        AVDictionaryEntry *en = NULL;
> +
> +        if (!av_dict_parse_string(&dict, ctx->options, "=", ":", 0)) {
> +            while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) {
> +                int const illegal_option =
> +                    !strcmp("input-res", en->key) ||
> +                    !strcmp("frame-rate", en->key) ||
> +                    !strcmp("f", en->key) ||
> +                    !strcmp("frames", en->key) ||
> +                    !strcmp("sar", en->key) ||
> +                    !strcmp("bit-depth", en->key) ||
> +                    !strcmp("internal-bit-depth", en->key);
> +                if (illegal_option)
> +                    av_log(avctx, AV_LOG_WARNING, "%s=%s ignored.\n", en->key, en->value);
> +                else
> +                    *p++ = s += 1 + snprintf(s, end - s, "--%s=%s", en->key, en->value);
> +            }
> +            av_dict_free(&dict);
> +        }
> +    }
> +
> +    *p++ = s += 1 + snprintf(s, end - s, "dummy-input-filename");
> +
> +    settings.argv = argv;
> +    settings.argc = p - argv - 1;
> +
> +    for (int i=0; i<settings.argc; ++i)
> +        av_log(avctx, AV_LOG_INFO, "arg %d: %s\n", i, settings.argv[i]);
> +
> +    ctx->encoder = turing_create_encoder(settings);
> +
> +    if (!ctx->encoder) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to create libturing encoder.\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
> +        turing_bitstream const *bitstream;
> +        bitstream = turing_encode_headers(ctx->encoder);
> +        if (bitstream->size <= 0) {
> +            av_log(avctx, AV_LOG_ERROR, "Failed to encode headers.\n");
> +            turing_destroy_encoder(ctx->encoder);
> +            return AVERROR_INVALIDDATA;
> +        }
> +
> +        avctx->extradata_size = bitstream->size;
> +
> +        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
> +        if (!avctx->extradata) {
> +            av_log(avctx, AV_LOG_ERROR, "Failed to allocate HEVC extradata %d bytes\n", avctx->extradata_size);
> +            turing_destroy_encoder(ctx->encoder);
> +            return AVERROR(ENOMEM);
> +        }
> +
> +        memcpy(avctx->extradata, bitstream->p, bitstream->size);
> +    }
> +
> +    return 0;
> +}
> +
> +static int libturing_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic, int *got_packet)
> +{
> +    libturingEncodeContext *ctx = avctx->priv_data;
> +    turing_encoder_output const *output;
> +    int ret = 0;
> +
> +    if (pic) {
> +        turing_picture picture;
> +
> +        picture.image[0].p = pic->data[0];
> +        picture.image[1].p = pic->data[1];
> +        picture.image[2].p = pic->data[2];
> +        picture.image[0].stride = pic->linesize[0];
> +        picture.image[1].stride = pic->linesize[1];
> +        picture.image[2].stride = pic->linesize[2];
> +    picture.pts = pic->pts;
> +
> +        output = turing_encode_picture(ctx->encoder, &picture);
> +    } else {
> +        output = turing_encode_picture(ctx->encoder, 0);
> +    }
> +
> +    if (output->bitstream.size < 0)
> +        return AVERROR_EXTERNAL;
> +
> +    if (output->bitstream.size ==0)
> +        return 0;
> +
> +    ret = ff_alloc_packet(pkt, output->bitstream.size);
> +    if (ret < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
> +        return ret;
> +    }
> +
> +    memcpy(pkt->data, output->bitstream.p, output->bitstream.size);
> +
> +    pkt->pts = output->pts;
> +    pkt->dts = output->dts;
> +    if (output->keyframe)
> +        pkt->flags |= AV_PKT_FLAG_KEY;
> +
> +    *got_packet = 1;
> +    return 0;
> +}
> +
> +static const enum AVPixelFormat turing_csp[] = {
> +    AV_PIX_FMT_YUV420P10,
> +    AV_PIX_FMT_YUV420P,
> +    AV_PIX_FMT_NONE
> +};
> +
> +static av_cold void libturing_encode_init_csp(AVCodec *codec)
> +{
> +    codec->pix_fmts = turing_csp;
> +}
> +
> +static const AVOption options[] = {
> +    { "turing-params", "configure additional turing encoder paremeters", offsetof(libturingEncodeContext, options), AV_OPT_TYPE_STRING,{ 0 }, 0, 0, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
> +    { NULL }
> +};
> +
> +static const AVClass class = {
> +    .class_name = "libturing",
> +    .item_name = av_default_item_name,
> +    .option = options,
> +    .version = LIBAVUTIL_VERSION_INT,
> +};
> +
> +AVCodec ff_libturing_encoder = {
> +    .name = "libturing",
> +    .long_name = NULL_IF_CONFIG_SMALL("libturing HEVC"),
> +    .type = AVMEDIA_TYPE_VIDEO,
> +    .id = AV_CODEC_ID_HEVC,
> +    .init = libturing_encode_init,
> +    .init_static_data = libturing_encode_init_csp,
> +    .encode2 = libturing_encode_frame,
> +    .close = libturing_encode_close,
> +    .priv_data_size = sizeof(libturingEncodeContext),
> +    .priv_class = &class,
> +    .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
> +};
>

Can't currently test on macOS as libturing doesn't have macOS support 
(https://github.com/bbc/turingcodec/issues/5), but it is being worked on 
(supposedly), so it may make sense to wait until then before this is 
applied.
Matteo Naccari Nov. 18, 2016, 5:55 p.m. UTC | #2
> Can't currently test on macOS as libturing doesn't have macOS support

> (https://github.com/bbc/turingcodec/issues/5), but it is being worked on

> (supposedly), so it may make sense to wait until then before this is applied.

>


Ok we'll try to get this sorted out and then get back to you. Thanks for your reply.

Best regards,
Matteo



-----------------------------
http://www.bbc.co.uk
This e-mail (and any attachments) is confidential and
may contain personal views which are not the views of the BBC unless specifically stated.
If you have received it in
error, please delete it from your system.
Do not use, copy or disclose the
information in any way nor act in reliance on it and notify the sender
immediately.
Please note that the BBC monitors e-mails
sent or received.
Further communication will signify your consent to
this.
-----------------------------
Hendrik Leppkes Nov. 18, 2016, 6:51 p.m. UTC | #3
On Fri, Nov 18, 2016 at 4:25 PM, Matteo Naccari
<matteo.naccari@bbc.co.uk> wrote:
> - The Turing codec is an open source HEVC encoder licensed under GPLv2
> - More information at http://turingcodec.org/
> ---
>  LICENSE.md             |   1 +
>  configure              |   5 ++
>  libavcodec/Makefile    |   1 +
>  libavcodec/allcodecs.c |   1 +
>  libavcodec/libturing.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 237 insertions(+)
>  create mode 100644 libavcodec/libturing.c
>
> diff --git a/LICENSE.md b/LICENSE.md
> index a384fa0..6f9fab8 100644
> --- a/LICENSE.md
> +++ b/LICENSE.md
> @@ -86,6 +86,7 @@ The following libraries are under GPL:
>  - frei0r
>  - libcdio
>  - librubberband
> +- libturing
>  - libvidstab
>  - libx264
>  - libx265
> diff --git a/configure b/configure
> index b5bfad6..47d6b93 100755
> --- a/configure
> +++ b/configure
> @@ -255,6 +255,7 @@ External library support:
>    --enable-libssh          enable SFTP protocol via libssh [no]
>    --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
>    --enable-libtheora       enable Theora encoding via libtheora [no]
> +  --enable-libturing       enable HEVC encoding via libturing [no]
>    --enable-libtwolame      enable MP2 encoding via libtwolame [no]
>    --enable-libv4l2         enable libv4l2/v4l-utils [no]
>    --enable-libvidstab      enable video stabilization using vid.stab [no]
> @@ -1521,6 +1522,7 @@ EXTERNAL_LIBRARY_LIST="
>      libssh
>      libtesseract
>      libtheora
> +    libturing
>      libtwolame
>      libv4l2
>      libvidstab
> @@ -2814,6 +2816,7 @@ libspeex_decoder_deps="libspeex"
>  libspeex_encoder_deps="libspeex"
>  libspeex_encoder_select="audio_frame_queue"
>  libtheora_encoder_deps="libtheora"
> +libturing_encoder_deps="libturing"
>  libtwolame_encoder_deps="libtwolame"
>  libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
>  libvorbis_decoder_deps="libvorbis"
> @@ -5072,6 +5075,7 @@ die_license_disabled gpl frei0r
>  die_license_disabled gpl libcdio
>  die_license_disabled gpl librubberband
>  die_license_disabled gpl libsmbclient
> +die_license_disabled gpl libturing
>  die_license_disabled gpl libvidstab
>  die_license_disabled gpl libx264
>  die_license_disabled gpl libx265
> @@ -5735,6 +5739,7 @@ enabled libssh            && require_pkg_config libssh libssh/sftp.h sftp_init
>  enabled libspeex          && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex
>  enabled libtesseract      && require_pkg_config tesseract tesseract/capi.h TessBaseAPICreate
>  enabled libtheora         && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
> +enabled libturing         && require libturing turing.h turing_version -lturing -lstdc++ -lboost_chrono -lboost_program_options -lboost_timer -lboost_system -lboost_filesystem -lhavoc

These dependencies are kind of a mess. Maybe you can make libturning
include a pkg_config file so we don't have to maintain your library
list here?

- Hendrik
wm4 Nov. 18, 2016, 7:15 p.m. UTC | #4
On Fri, 18 Nov 2016 15:25:49 +0000
Matteo Naccari <matteo.naccari@bbc.co.uk> wrote:

> - The Turing codec is an open source HEVC encoder licensed under GPLv2
> - More information at http://turingcodec.org/
> ---
>  LICENSE.md             |   1 +
>  configure              |   5 ++
>  libavcodec/Makefile    |   1 +
>  libavcodec/allcodecs.c |   1 +
>  libavcodec/libturing.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 237 insertions(+)
>  create mode 100644 libavcodec/libturing.c
> 
> diff --git a/LICENSE.md b/LICENSE.md
> index a384fa0..6f9fab8 100644
> --- a/LICENSE.md
> +++ b/LICENSE.md
> @@ -86,6 +86,7 @@ The following libraries are under GPL:
>  - frei0r
>  - libcdio
>  - librubberband
> +- libturing
>  - libvidstab
>  - libx264
>  - libx265
> diff --git a/configure b/configure
> index b5bfad6..47d6b93 100755
> --- a/configure
> +++ b/configure
> @@ -255,6 +255,7 @@ External library support:
>    --enable-libssh          enable SFTP protocol via libssh [no]
>    --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
>    --enable-libtheora       enable Theora encoding via libtheora [no]
> +  --enable-libturing       enable HEVC encoding via libturing [no]
>    --enable-libtwolame      enable MP2 encoding via libtwolame [no]
>    --enable-libv4l2         enable libv4l2/v4l-utils [no]
>    --enable-libvidstab      enable video stabilization using vid.stab [no]
> @@ -1521,6 +1522,7 @@ EXTERNAL_LIBRARY_LIST="
>      libssh
>      libtesseract
>      libtheora
> +    libturing
>      libtwolame
>      libv4l2
>      libvidstab
> @@ -2814,6 +2816,7 @@ libspeex_decoder_deps="libspeex"
>  libspeex_encoder_deps="libspeex"
>  libspeex_encoder_select="audio_frame_queue"
>  libtheora_encoder_deps="libtheora"
> +libturing_encoder_deps="libturing"
>  libtwolame_encoder_deps="libtwolame"
>  libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
>  libvorbis_decoder_deps="libvorbis"
> @@ -5072,6 +5075,7 @@ die_license_disabled gpl frei0r
>  die_license_disabled gpl libcdio
>  die_license_disabled gpl librubberband
>  die_license_disabled gpl libsmbclient
> +die_license_disabled gpl libturing
>  die_license_disabled gpl libvidstab
>  die_license_disabled gpl libx264
>  die_license_disabled gpl libx265
> @@ -5735,6 +5739,7 @@ enabled libssh            && require_pkg_config libssh libssh/sftp.h sftp_init
>  enabled libspeex          && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex
>  enabled libtesseract      && require_pkg_config tesseract tesseract/capi.h TessBaseAPICreate
>  enabled libtheora         && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
> +enabled libturing         && require libturing turing.h turing_version -lturing -lstdc++ -lboost_chrono -lboost_program_options -lboost_timer -lboost_system -lboost_filesystem -lhavoc
>  enabled libtwolame        && require libtwolame twolame.h twolame_init -ltwolame &&
>                               { check_lib twolame.h twolame_encode_buffer_float32_interleaved -ltwolame ||
>                                 die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; }
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 82f7fa2..cadefdc 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -880,6 +880,7 @@ OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
>  OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
>  OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
>  OBJS-$(CONFIG_LIBTWOLAME_ENCODER)         += libtwolame.o
> +OBJS-$(CONFIG_LIBTURING_ENCODER)          += libturing.o
>  OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER)     += libvo-amrwbenc.o
>  OBJS-$(CONFIG_LIBVORBIS_DECODER)          += libvorbisdec.o
>  OBJS-$(CONFIG_LIBVORBIS_ENCODER)          += libvorbisenc.o \
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index ada9481..0e61a4a 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -610,6 +610,7 @@ void avcodec_register_all(void)
>      REGISTER_ENCDEC (LIBSPEEX,          libspeex);
>      REGISTER_ENCODER(LIBTHEORA,         libtheora);
>      REGISTER_ENCODER(LIBTWOLAME,        libtwolame);
> +    REGISTER_ENCODER(LIBTURING,         libturing);
>      REGISTER_ENCODER(LIBVO_AMRWBENC,    libvo_amrwbenc);
>      REGISTER_ENCDEC (LIBVORBIS,         libvorbis);
>      REGISTER_ENCDEC (LIBVPX_VP8,        libvpx_vp8);
> diff --git a/libavcodec/libturing.c b/libavcodec/libturing.c
> new file mode 100644
> index 0000000..3191a41
> --- /dev/null
> +++ b/libavcodec/libturing.c
> @@ -0,0 +1,229 @@
> +/*
> + * libturing encoder
> + *
> + * Copyright (c) 2016 Turing Codec contributors
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <turing.h>
> +#include <float.h>
> +#include "libavutil/internal.h"
> +#include "libavutil/common.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/pixdesc.h"
> +#include "avcodec.h"
> +#include "internal.h"
> +
> +typedef struct libturingEncodeContext {
> +    const AVClass *class;
> +    turing_encoder *encoder;
> +    const char *options;
> +} libturingEncodeContext;
> +
> +static av_cold int libturing_encode_close(AVCodecContext *avctx)
> +{
> +    libturingEncodeContext *ctx = avctx->priv_data;
> +
> +    if (ctx->encoder)
> +        turing_destroy_encoder(ctx->encoder);
> +
> +    return 0;
> +}
> +
> +static av_cold int libturing_encode_init(AVCodecContext *avctx)
> +{
> +    libturingEncodeContext *ctx = avctx->priv_data;
> +
> +    char options[1024];
> +    char* s = options;
> +    char *end = &options[sizeof(options)];
> +
> +    char const* argv[32];
> +    char const** p = argv;
> +    turing_encoder_settings settings;
> +
> +    *p++ = s;
> +    *p++ = s += 1 + snprintf(s, end - s, "turing");
> +    *p++ = s += 1 + snprintf(s, end - s, "--input-res=%dx%d", avctx->width, avctx->height);
> +    *p++ = s += 1 + snprintf(s, end - s, "--frame-rate=%f", (double)avctx->time_base.den / (avctx->time_base.num * avctx->ticks_per_frame));
> +    *p++ = s += 1 + snprintf(s, end - s, "--frames=0");
> +
> +    {
> +        int const bit_depth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
> +        if (bit_depth != 8 && bit_depth != 10) {
> +            av_log(avctx, AV_LOG_ERROR, "Encoder input must be 8- or 10-bit.\n");
> +            turing_destroy_encoder(ctx->encoder);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        *p++ = s += 1 + snprintf(s, end - s, "--bit-depth=%d", bit_depth);
> +        *p++ = s += 1 + snprintf(s, end - s, "--internal-bit-depth=%d", bit_depth);
> +    }
> +
> +    if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
> +        int sar_num, sar_den;
> +
> +        av_reduce(&sar_num, &sar_den,
> +            avctx->sample_aspect_ratio.num,
> +            avctx->sample_aspect_ratio.den, 65535);
> +
> +        *p++ = s += 1 + snprintf(s, end - s, "--sar=%d:%d", sar_num, sar_den);
> +    }
> +
> +    if (ctx->options) {
> +        AVDictionary *dict = NULL;
> +        AVDictionaryEntry *en = NULL;
> +
> +        if (!av_dict_parse_string(&dict, ctx->options, "=", ":", 0)) {
> +            while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) {
> +                int const illegal_option =
> +                    !strcmp("input-res", en->key) ||
> +                    !strcmp("frame-rate", en->key) ||
> +                    !strcmp("f", en->key) ||
> +                    !strcmp("frames", en->key) ||
> +                    !strcmp("sar", en->key) ||
> +                    !strcmp("bit-depth", en->key) ||
> +                    !strcmp("internal-bit-depth", en->key);
> +                if (illegal_option)
> +                    av_log(avctx, AV_LOG_WARNING, "%s=%s ignored.\n", en->key, en->value);
> +                else
> +                    *p++ = s += 1 + snprintf(s, end - s, "--%s=%s", en->key, en->value);
> +            }
> +            av_dict_free(&dict);
> +        }
> +    }

This lib has a really weird API... Anyway, access to p++ seems
unbounded and could go past the argv array. The string overflow checks
also look questionable. snprintf() returns the size the string would
have had and isn't limited by the buffer passed to it, so the s pointer
can go out of bounds (which is undefined behavior). Also, "end - s"
will underflow, making the attempt to avoid a buffer overflow pointless.
Moritz Barsnick Nov. 19, 2016, 1:29 p.m. UTC | #5
On Fri, Nov 18, 2016 at 20:15:30 +0100, wm4 wrote:
> This lib has a really weird API...

I can't judge the algorithms or the development direction and stuff -
I'm sure it's all state of the art. But the API sure gives me
goosebumps, and I don't mean the sexy feelgood type.

Sure, it has all the flexibility, but also almost all the disadvantages
of calling an external program. This makes it look so much like a proof
of concept.

But I'm sure that's not the point. If it turns out to be here to stay,
to compete with x265 in one or the other way, it's probably worth
integrating.

Back to the review: From first glance, the libturing codec/library (or
the executable only???) seems to have speed presets. Why are these not
exposed to the libavcodec user?

Furthermore: Documentation is missing.

£0.02,
Moritz
Alexander Strasser Nov. 19, 2016, 11:21 p.m. UTC | #6
On 2016-11-19 14:29 +0100, Moritz Barsnick wrote:
> On Fri, Nov 18, 2016 at 20:15:30 +0100, wm4 wrote:
> > This lib has a really weird API...
> 
> I can't judge the algorithms or the development direction and stuff -
> I'm sure it's all state of the art. But the API sure gives me
> goosebumps, and I don't mean the sexy feelgood type.
> 
> Sure, it has all the flexibility, but also almost all the disadvantages
> of calling an external program. This makes it look so much like a proof
> of concept.

  I looked at the source for fun yesterday to find out what
that was about.

  IMHO it is that the real encoder class takes C++ arguments 
(boost variables map) and they have a CLI program which also
needs to create that variables map for the encoder. Thus it
seems the quickest way to make a C interface was to use that
argument parsing code for initializing the encoder.

  I hope it copes well with multiple definitions of the same
option, like the last overwriting the previous ones.


[...]


  Alexander
Carl Eugen Hoyos Nov. 20, 2016, 12:48 p.m. UTC | #7
2016-11-18 17:45 GMT+01:00 Josh de Kock <josh@itanimul.li>:

> Can't currently test on macOS as libturing doesn't have macOS
> support (https://github.com/bbc/turingcodec/issues/5), but it is
> being worked on (supposedly), so it may make sense to wait until
> then before this is applied.

I don't know if we should add support for libturing or not but I wonder
why this is related to libturing working on osx or not...

Or to say it differently: If libturing really is better than libx265 at least
in some situations (this is claimed afaiu), it should imo be added no
matter if it works on osx or not.

Carl Eugen
Matteo Naccari Nov. 28, 2016, 4:30 p.m. UTC | #8
> These dependencies are kind of a mess. Maybe you can make libturning
> include a pkg_config file so we don't have to maintain your library list here?


The new patch we just submitted addresses this point: the Turing codec will install a pkg-config file to list the dependencies as suggested

Matteo Naccari

> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> Of Hendrik Leppkes

> Sent: 18 November 2016 18:51

> To: FFmpeg development discussions and patches <ffmpeg-

> devel@ffmpeg.org>

> Subject: Re: [FFmpeg-devel] [PATCH] Added the interface for the Turing

> codec

> 

> On Fri, Nov 18, 2016 at 4:25 PM, Matteo Naccari <matteo.naccari@bbc.co.uk>

> wrote:

> > - The Turing codec is an open source HEVC encoder licensed under GPLv2

> > - More information at http://turingcodec.org/

> > ---

> >  LICENSE.md             |   1 +

> >  configure              |   5 ++

> >  libavcodec/Makefile    |   1 +

> >  libavcodec/allcodecs.c |   1 +

> >  libavcodec/libturing.c | 229

> > +++++++++++++++++++++++++++++++++++++++++++++++++

> >  5 files changed, 237 insertions(+)

> >  create mode 100644 libavcodec/libturing.c

> >

> > diff --git a/LICENSE.md b/LICENSE.md

> > index a384fa0..6f9fab8 100644

> > --- a/LICENSE.md

> > +++ b/LICENSE.md

> > @@ -86,6 +86,7 @@ The following libraries are under GPL:

> >  - frei0r

> >  - libcdio

> >  - librubberband

> > +- libturing

> >  - libvidstab

> >  - libx264

> >  - libx265

> > diff --git a/configure b/configure

> > index b5bfad6..47d6b93 100755

> > --- a/configure

> > +++ b/configure

> > @@ -255,6 +255,7 @@ External library support:

> >    --enable-libssh          enable SFTP protocol via libssh [no]

> >    --enable-libtesseract    enable Tesseract, needed for ocr filter [no]

> >    --enable-libtheora       enable Theora encoding via libtheora [no]

> > +  --enable-libturing       enable HEVC encoding via libturing [no]

> >    --enable-libtwolame      enable MP2 encoding via libtwolame [no]

> >    --enable-libv4l2         enable libv4l2/v4l-utils [no]

> >    --enable-libvidstab      enable video stabilization using vid.stab [no]

> > @@ -1521,6 +1522,7 @@ EXTERNAL_LIBRARY_LIST="

> >      libssh

> >      libtesseract

> >      libtheora

> > +    libturing

> >      libtwolame

> >      libv4l2

> >      libvidstab

> > @@ -2814,6 +2816,7 @@ libspeex_decoder_deps="libspeex"

> >  libspeex_encoder_deps="libspeex"

> >  libspeex_encoder_select="audio_frame_queue"

> >  libtheora_encoder_deps="libtheora"

> > +libturing_encoder_deps="libturing"

> >  libtwolame_encoder_deps="libtwolame"

> >  libvo_amrwbenc_encoder_deps="libvo_amrwbenc"

> >  libvorbis_decoder_deps="libvorbis"

> > @@ -5072,6 +5075,7 @@ die_license_disabled gpl frei0r

> > die_license_disabled gpl libcdio  die_license_disabled gpl

> > librubberband  die_license_disabled gpl libsmbclient

> > +die_license_disabled gpl libturing

> >  die_license_disabled gpl libvidstab

> >  die_license_disabled gpl libx264

> >  die_license_disabled gpl libx265

> > @@ -5735,6 +5739,7 @@ enabled libssh            && require_pkg_config libssh

> libssh/sftp.h sftp_init

> >  enabled libspeex          && require_pkg_config speex speex/speex.h

> speex_decoder_init -lspeex

> >  enabled libtesseract      && require_pkg_config tesseract tesseract/capi.h

> TessBaseAPICreate

> >  enabled libtheora         && require libtheora theora/theoraenc.h

> th_info_init -ltheoraenc -ltheoradec -logg

> > +enabled libturing         && require libturing turing.h turing_version -lturing -

> lstdc++ -lboost_chrono -lboost_program_options -lboost_timer -

> lboost_system -lboost_filesystem -lhavoc

> 

> These dependencies are kind of a mess. Maybe you can make libturning

> include a pkg_config file so we don't have to maintain your library list here?

> 

> - Hendrik

> _______________________________________________

> ffmpeg-devel mailing list

> ffmpeg-devel@ffmpeg.org

> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel



-----------------------------
http://www.bbc.co.uk
This e-mail (and any attachments) is confidential and 
may contain personal views which are not the views of the BBC unless specifically stated.
If you have received it in 
error, please delete it from your system.
Do not use, copy or disclose the 
information in any way nor act in reliance on it and notify the sender 
immediately.
Please note that the BBC monitors e-mails 
sent or received.
Further communication will signify your consent to 
this.
-----------------------------
Matteo Naccari Nov. 28, 2016, 4:31 p.m. UTC | #9
> This lib has a really weird API... Anyway, access to p++ seems unbounded and

> could go past the argv array. The string overflow checks also look

> questionable. snprintf() returns the size the string would have had and isn't

> limited by the buffer passed to it, so the s pointer can go out of bounds

> (which is undefined behavior). Also, "end - s"

> will underflow, making the attempt to avoid a buffer overflow pointless.


The patch we just submitted should address this point: now the buffer size for the command line option depends on the actual number of options passed by the user for the Turing codec.

Matteo Naccari


-----------------------------
http://www.bbc.co.uk
This e-mail (and any attachments) is confidential and
may contain personal views which are not the views of the BBC unless specifically stated.
If you have received it in
error, please delete it from your system.
Do not use, copy or disclose the
information in any way nor act in reliance on it and notify the sender
immediately.
Please note that the BBC monitors e-mails
sent or received.
Further communication will signify your consent to
this.
-----------------------------
Matteo Naccari Nov. 28, 2016, 4:36 p.m. UTC | #10
> Back to the review: From first glance, the libturing codec/library (or the

> executable only???) seems to have speed presets. Why are these not

> exposed to the libavcodec user?


All options, including the speed presets, can be specified using -turing-params (e.g. -turing-params speed=value). The reason why we decided to go for this option is because we want to be as less invasive as possible so that if we decide to change the name for a given option the changes will be transparent to FFmpeg.

Matteo Naccari

> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> Of Moritz Barsnick

> Sent: 19 November 2016 13:29

> To: FFmpeg development discussions and patches <ffmpeg-

> devel@ffmpeg.org>

> Subject: Re: [FFmpeg-devel] [PATCH] Added the interface for the Turing

> codec

> 

> On Fri, Nov 18, 2016 at 20:15:30 +0100, wm4 wrote:

> > This lib has a really weird API...

> 

> I can't judge the algorithms or the development direction and stuff - I'm sure

> it's all state of the art. But the API sure gives me goosebumps, and I don't

> mean the sexy feelgood type.

> 

> Sure, it has all the flexibility, but also almost all the disadvantages of calling an

> external program. This makes it look so much like a proof of concept.

> 

> But I'm sure that's not the point. If it turns out to be here to stay, to compete

> with x265 in one or the other way, it's probably worth integrating.

> 

> Back to the review: From first glance, the libturing codec/library (or the

> executable only???) seems to have speed presets. Why are these not

> exposed to the libavcodec user?

> 

> Furthermore: Documentation is missing.

> 

> £0.02,

> Moritz

> _______________________________________________

> ffmpeg-devel mailing list

> ffmpeg-devel@ffmpeg.org

> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Matteo Naccari Nov. 28, 2016, 4:38 p.m. UTC | #11
>   I hope it copes well with multiple definitions of the same option, like the last

> overwriting the previous ones.


The latest stable version of the Turing codec deals correctly with multiple definitions of the same option.

Matteo Naccari
diff mbox

Patch

diff --git a/LICENSE.md b/LICENSE.md
index a384fa0..6f9fab8 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -86,6 +86,7 @@  The following libraries are under GPL:
 - frei0r
 - libcdio
 - librubberband
+- libturing
 - libvidstab
 - libx264
 - libx265
diff --git a/configure b/configure
index b5bfad6..47d6b93 100755
--- a/configure
+++ b/configure
@@ -255,6 +255,7 @@  External library support:
   --enable-libssh          enable SFTP protocol via libssh [no]
   --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
   --enable-libtheora       enable Theora encoding via libtheora [no]
+  --enable-libturing       enable HEVC encoding via libturing [no]
   --enable-libtwolame      enable MP2 encoding via libtwolame [no]
   --enable-libv4l2         enable libv4l2/v4l-utils [no]
   --enable-libvidstab      enable video stabilization using vid.stab [no]
@@ -1521,6 +1522,7 @@  EXTERNAL_LIBRARY_LIST="
     libssh
     libtesseract
     libtheora
+    libturing
     libtwolame
     libv4l2
     libvidstab
@@ -2814,6 +2816,7 @@  libspeex_decoder_deps="libspeex"
 libspeex_encoder_deps="libspeex"
 libspeex_encoder_select="audio_frame_queue"
 libtheora_encoder_deps="libtheora"
+libturing_encoder_deps="libturing"
 libtwolame_encoder_deps="libtwolame"
 libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
 libvorbis_decoder_deps="libvorbis"
@@ -5072,6 +5075,7 @@  die_license_disabled gpl frei0r
 die_license_disabled gpl libcdio
 die_license_disabled gpl librubberband
 die_license_disabled gpl libsmbclient
+die_license_disabled gpl libturing
 die_license_disabled gpl libvidstab
 die_license_disabled gpl libx264
 die_license_disabled gpl libx265
@@ -5735,6 +5739,7 @@  enabled libssh            && require_pkg_config libssh libssh/sftp.h sftp_init
 enabled libspeex          && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex
 enabled libtesseract      && require_pkg_config tesseract tesseract/capi.h TessBaseAPICreate
 enabled libtheora         && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
+enabled libturing         && require libturing turing.h turing_version -lturing -lstdc++ -lboost_chrono -lboost_program_options -lboost_timer -lboost_system -lboost_filesystem -lhavoc
 enabled libtwolame        && require libtwolame twolame.h twolame_init -ltwolame &&
                              { check_lib twolame.h twolame_encode_buffer_float32_interleaved -ltwolame ||
                                die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; }
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 82f7fa2..cadefdc 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -880,6 +880,7 @@  OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
 OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
 OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
 OBJS-$(CONFIG_LIBTWOLAME_ENCODER)         += libtwolame.o
+OBJS-$(CONFIG_LIBTURING_ENCODER)          += libturing.o
 OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER)     += libvo-amrwbenc.o
 OBJS-$(CONFIG_LIBVORBIS_DECODER)          += libvorbisdec.o
 OBJS-$(CONFIG_LIBVORBIS_ENCODER)          += libvorbisenc.o \
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index ada9481..0e61a4a 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -610,6 +610,7 @@  void avcodec_register_all(void)
     REGISTER_ENCDEC (LIBSPEEX,          libspeex);
     REGISTER_ENCODER(LIBTHEORA,         libtheora);
     REGISTER_ENCODER(LIBTWOLAME,        libtwolame);
+    REGISTER_ENCODER(LIBTURING,         libturing);
     REGISTER_ENCODER(LIBVO_AMRWBENC,    libvo_amrwbenc);
     REGISTER_ENCDEC (LIBVORBIS,         libvorbis);
     REGISTER_ENCDEC (LIBVPX_VP8,        libvpx_vp8);
diff --git a/libavcodec/libturing.c b/libavcodec/libturing.c
new file mode 100644
index 0000000..3191a41
--- /dev/null
+++ b/libavcodec/libturing.c
@@ -0,0 +1,229 @@ 
+/*
+ * libturing encoder
+ *
+ * Copyright (c) 2016 Turing Codec contributors
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <turing.h>
+#include <float.h>
+#include "libavutil/internal.h"
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avcodec.h"
+#include "internal.h"
+
+typedef struct libturingEncodeContext {
+    const AVClass *class;
+    turing_encoder *encoder;
+    const char *options;
+} libturingEncodeContext;
+
+static av_cold int libturing_encode_close(AVCodecContext *avctx)
+{
+    libturingEncodeContext *ctx = avctx->priv_data;
+
+    if (ctx->encoder)
+        turing_destroy_encoder(ctx->encoder);
+
+    return 0;
+}
+
+static av_cold int libturing_encode_init(AVCodecContext *avctx)
+{
+    libturingEncodeContext *ctx = avctx->priv_data;
+
+    char options[1024];
+    char* s = options;
+    char *end = &options[sizeof(options)];
+
+    char const* argv[32];
+    char const** p = argv;
+    turing_encoder_settings settings;
+
+    *p++ = s;
+    *p++ = s += 1 + snprintf(s, end - s, "turing");
+    *p++ = s += 1 + snprintf(s, end - s, "--input-res=%dx%d", avctx->width, avctx->height);
+    *p++ = s += 1 + snprintf(s, end - s, "--frame-rate=%f", (double)avctx->time_base.den / (avctx->time_base.num * avctx->ticks_per_frame));
+    *p++ = s += 1 + snprintf(s, end - s, "--frames=0");
+
+    {
+        int const bit_depth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
+        if (bit_depth != 8 && bit_depth != 10) {
+            av_log(avctx, AV_LOG_ERROR, "Encoder input must be 8- or 10-bit.\n");
+            turing_destroy_encoder(ctx->encoder);
+            return AVERROR_INVALIDDATA;
+        }
+        *p++ = s += 1 + snprintf(s, end - s, "--bit-depth=%d", bit_depth);
+        *p++ = s += 1 + snprintf(s, end - s, "--internal-bit-depth=%d", bit_depth);
+    }
+
+    if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
+        int sar_num, sar_den;
+
+        av_reduce(&sar_num, &sar_den,
+            avctx->sample_aspect_ratio.num,
+            avctx->sample_aspect_ratio.den, 65535);
+
+        *p++ = s += 1 + snprintf(s, end - s, "--sar=%d:%d", sar_num, sar_den);
+    }
+
+    if (ctx->options) {
+        AVDictionary *dict = NULL;
+        AVDictionaryEntry *en = NULL;
+
+        if (!av_dict_parse_string(&dict, ctx->options, "=", ":", 0)) {
+            while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) {
+                int const illegal_option =
+                    !strcmp("input-res", en->key) ||
+                    !strcmp("frame-rate", en->key) ||
+                    !strcmp("f", en->key) ||
+                    !strcmp("frames", en->key) ||
+                    !strcmp("sar", en->key) ||
+                    !strcmp("bit-depth", en->key) ||
+                    !strcmp("internal-bit-depth", en->key);
+                if (illegal_option)
+                    av_log(avctx, AV_LOG_WARNING, "%s=%s ignored.\n", en->key, en->value);
+                else
+                    *p++ = s += 1 + snprintf(s, end - s, "--%s=%s", en->key, en->value);
+            }
+            av_dict_free(&dict);
+        }
+    }
+
+    *p++ = s += 1 + snprintf(s, end - s, "dummy-input-filename");
+
+    settings.argv = argv;
+    settings.argc = p - argv - 1;
+
+    for (int i=0; i<settings.argc; ++i)
+        av_log(avctx, AV_LOG_INFO, "arg %d: %s\n", i, settings.argv[i]);
+
+    ctx->encoder = turing_create_encoder(settings);
+
+    if (!ctx->encoder) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to create libturing encoder.\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
+        turing_bitstream const *bitstream;
+        bitstream = turing_encode_headers(ctx->encoder);
+        if (bitstream->size <= 0) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to encode headers.\n");
+            turing_destroy_encoder(ctx->encoder);
+            return AVERROR_INVALIDDATA;
+        }
+
+        avctx->extradata_size = bitstream->size;
+
+        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!avctx->extradata) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to allocate HEVC extradata %d bytes\n", avctx->extradata_size);
+            turing_destroy_encoder(ctx->encoder);
+            return AVERROR(ENOMEM);
+        }
+
+        memcpy(avctx->extradata, bitstream->p, bitstream->size);
+    }
+
+    return 0;
+}
+
+static int libturing_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic, int *got_packet)
+{
+    libturingEncodeContext *ctx = avctx->priv_data;
+    turing_encoder_output const *output;
+    int ret = 0;
+
+    if (pic) {
+        turing_picture picture;
+
+        picture.image[0].p = pic->data[0];
+        picture.image[1].p = pic->data[1];
+        picture.image[2].p = pic->data[2];
+        picture.image[0].stride = pic->linesize[0];
+        picture.image[1].stride = pic->linesize[1];
+        picture.image[2].stride = pic->linesize[2];
+    picture.pts = pic->pts;
+
+        output = turing_encode_picture(ctx->encoder, &picture);
+    } else {
+        output = turing_encode_picture(ctx->encoder, 0);
+    }
+
+    if (output->bitstream.size < 0)
+        return AVERROR_EXTERNAL;
+
+    if (output->bitstream.size ==0)
+        return 0;
+
+    ret = ff_alloc_packet(pkt, output->bitstream.size);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+        return ret;
+    }
+
+    memcpy(pkt->data, output->bitstream.p, output->bitstream.size);
+
+    pkt->pts = output->pts;
+    pkt->dts = output->dts;
+    if (output->keyframe)
+        pkt->flags |= AV_PKT_FLAG_KEY;
+
+    *got_packet = 1;
+    return 0;
+}
+
+static const enum AVPixelFormat turing_csp[] = {
+    AV_PIX_FMT_YUV420P10,
+    AV_PIX_FMT_YUV420P,
+    AV_PIX_FMT_NONE
+};
+
+static av_cold void libturing_encode_init_csp(AVCodec *codec)
+{
+    codec->pix_fmts = turing_csp;
+}
+
+static const AVOption options[] = {
+    { "turing-params", "configure additional turing encoder paremeters", offsetof(libturingEncodeContext, options), AV_OPT_TYPE_STRING,{ 0 }, 0, 0, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
+    { NULL }
+};
+
+static const AVClass class = {
+    .class_name = "libturing",
+    .item_name = av_default_item_name,
+    .option = options,
+    .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_libturing_encoder = {
+    .name = "libturing",
+    .long_name = NULL_IF_CONFIG_SMALL("libturing HEVC"),
+    .type = AVMEDIA_TYPE_VIDEO,
+    .id = AV_CODEC_ID_HEVC,
+    .init = libturing_encode_init,
+    .init_static_data = libturing_encode_init_csp,
+    .encode2 = libturing_encode_frame,
+    .close = libturing_encode_close,
+    .priv_data_size = sizeof(libturingEncodeContext),
+    .priv_class = &class,
+    .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
+};