FFMPEG + GPL

Just to make things clear

0) yes I agree I violated GLP and I feel sorry, but I didnt do it on purpose (and to be fair I didnt know much licensing details till the week I was noticed about my violation)

1) After Kieran left the comment about violation I made repo private (to spend some time to understand all details) and today I fully removed the repo

2) To be fair its easy to see it wasn’t done on purpose as I never posted updates even though the posted version had interlaced coding bug. I was asked a couple of times privately to make a custom build with my encoder and I rejected it as the only purpose I persued was to show encoder exists and performs well

3) Why dont I disclose source codes?

3.1) I was going to re-work prores_ks or add one more encoder and I had an exact plan on how to do it and I started with it. I sent couple patches 1st was approved 2nd still under review. I decided to not wait forever and Im not the one to ping every day/week to make it pushed (I believe if the community needs something it will be pushed, and its easy to prove with my mxf op1b research when my changes were pushed even though Ive never sent that patch)

3.2) I still was interested to finish my Prores encoder so I continued to work on it. And now when encoder done I plan to make a product based on it. It will be free but probably close-sourced.

3.3) Even if I want one day to make it part of ffmpeg it wont be easy to do, as my implementation done in C++ and ffmpeg is C

3.4) so the build I shared (and later removed) literally a bag of tricks.

3.5) so when Kieran/Martin/Carl or whoever says I should share prores_amcdx_encoder I can easily do it, but what will you see here? as its basically skeleton copied from prores_anatoly with whole logic replaced by calling functions from private static library

#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "profiles.h"
#include "prores_defs.hpp"

#define DEFAULT_SLICE_MB_WIDTH 8

static const AVProfile profiles[] = {
    { FF_PROFILE_PRORES_PROXY,    "apco"},
    { FF_PROFILE_PRORES_LT,       "apcs"},
    { FF_PROFILE_PRORES_STANDARD, "apcn"},
    { FF_PROFILE_PRORES_HQ,       "apch"},
    { FF_PROFILE_PRORES_4444,     "ap4h"},
    { FF_PROFILE_PRORES_XQ,       "ap4x"},
    { FF_PROFILE_UNKNOWN }
};

static const int valid_primaries[9]  = { AVCOL_PRI_RESERVED0, AVCOL_PRI_BT709, AVCOL_PRI_UNSPECIFIED, AVCOL_PRI_BT470BG,
                                         AVCOL_PRI_SMPTE170M, AVCOL_PRI_BT2020, AVCOL_PRI_SMPTE431, AVCOL_PRI_SMPTE432,INT_MAX };
static const int valid_trc[4]        = { AVCOL_TRC_RESERVED0, AVCOL_TRC_BT709, AVCOL_TRC_UNSPECIFIED, INT_MAX };
static const int valid_colorspace[5] = { AVCOL_SPC_BT709, AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_SMPTE170M,
                                         AVCOL_SPC_BT2020_NCL, INT_MAX };

typedef struct {
    AVClass *class;
    void *encoder;
    int cs;
    int qual;
    int field_order;
    int planes;
    int target_size;
} ProresContext;

static int prores_encode_frame2(AVCodecContext *avctx, AVPacket *pkt,
                               const AVFrame *pict, int *got_packet)
{
    ProresContext *ctx = avctx->priv_data;
    int ret;
    int frame_size = amcdx_pr_encoder_encode(ctx->encoder, (void **)pict->data, (int *)pict->linesize, ctx->planes); //for the time being


    if ((ret = ff_alloc_packet2(avctx, pkt, frame_size, 0)) < 0)
        return ret;

    amcdx_pr_encoder_read(ctx->encoder, pkt->data, &pkt->size);


    pkt->flags |= AV_PKT_FLAG_KEY;

    *got_packet = 1;
    return 0;
}

static av_cold int prores_encode_init2(AVCodecContext *avctx)
{
    ProresContext* ctx = avctx->priv_data;

    avctx->bits_per_raw_sample = 10;

    if (avctx->width & 0x1) {
        av_log(avctx, AV_LOG_ERROR,
                "frame width needs to be multiple of 2\n");
        return AVERROR(EINVAL);
    }

    if (avctx->width > 65534 || avctx->height > 65535) {
        av_log(avctx, AV_LOG_ERROR, "The maximum dimensions are 65534x65535\n");
        return AVERROR(EINVAL);
    }

    switch (avctx->profile) {
    case FF_PROFILE_UNKNOWN:
    case FF_PROFILE_PRORES_STANDARD:
        ctx->qual = Quality_422;
        break;
    case FF_PROFILE_PRORES_4444:
        ctx->qual = Quality_4444;
        break;
    case FF_PROFILE_PRORES_HQ:
        ctx->qual = Quality_422HQ;
        break;
    case FF_PROFILE_PRORES_LT:
        ctx->qual = Quality_422LT;
        break;
    case FF_PROFILE_PRORES_PROXY:
        ctx->qual = Quality_422Proxy;
        break;
    case FF_PROFILE_PRORES_XQ:
        ctx->qual = Quality_4444XQ;
        break;
    default:
        return -1;
        break;
    }

    switch (avctx->pix_fmt) {
    case AV_PIX_FMT_UYVY422:
        ctx->cs = ColorSpace_uyvy;
        ctx->planes = 1;
        break;
    case AV_PIX_FMT_YUV422P10:
        ctx->cs = ColorSpace_yuv10_422_planar;
        ctx->planes = 3;
        break;
    case AV_PIX_FMT_YUV422P12:
        ctx->cs = ColorSpace_yuv12_422_planar;
        ctx->planes = 3;
        break;
    case AV_PIX_FMT_YUV444P12:
        ctx->cs = ColorSpace_yuv12_444_planar;
        ctx->planes = 3;
        break;
    default:
        break;
    }

     //for the time being

    switch (avctx->field_order)
    {
    case AV_FIELD_BT:
        avctx->field_order = FieldOrder_BottomFieldFirst;
        break;
    case AV_FIELD_TB:
        avctx->field_order = FieldOrder_TopFieldFirst;
        break;
    case AV_FIELD_PROGRESSIVE:
    default: //otherwise we think its progressive
        avctx->field_order = FieldOrder_Progressive;
        break;
    }

    ctx->encoder = amcdx_pr_encoder_create();

    if (ctx->target_size != 0) {
        amcdx_pr_encoder_set_frame_size(ctx->encoder, ctx->target_size);
    }

    avctx->codec_tag = MKTAG(profiles[avctx->profile].name[0], profiles[avctx->profile].name[1], profiles[avctx->profile].name[2], profiles[avctx->profile].name[3]);// AV_RL32((const uint8_t*)profiles[avctx->profile].name);

    return amcdx_pr_encoder_init(ctx->encoder, avctx->width, avctx->height, ctx->cs, ctx->qual, ctx->field_order) - 1;
}

static av_cold int prores_encode_close2(AVCodecContext *avctx)
{
    ProresContext* ctx = avctx->priv_data;
    amcdx_pr_encoder_destroy(ctx->encoder);

    return 0;
}

#define OFFSET(x) offsetof(ProresContext, x)
#define VE     AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM

static const AVOption options[] = {
    { "target_size", "force frame size", OFFSET(target_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
    { NULL }
};

static const AVClass proresamcdx_enc_class = {
    .class_name = "ProRes amcdx encoder",
    .item_name  = av_default_item_name,
    .option     = options,
    .version    = LIBAVUTIL_VERSION_INT,
};

AVCodec ff_prores_amcdx_encoder = {
    .name           = "prores_amcdx",
    .long_name      = NULL_IF_CONFIG_SMALL("Apple ProRes"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_PRORES,
    .priv_data_size = sizeof(ProresContext),
    .init           = prores_encode_init2,
    .close          = prores_encode_close2,
    .encode2        = prores_encode_frame2,
    .pix_fmts       = (const enum AVPixelFormat[]){AV_PIX_FMT_UYVY422, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_NONE},
    .capabilities   = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY,
    .priv_class     = &proresamcdx_enc_class,
    .profiles       = NULL_IF_CONFIG_SMALL(ff_prores_profiles),
};

14 thoughts on “FFMPEG + GPL”

  1. Not sure I understand:
    As long as you post your patches somewhere (visible), be it the ffmpeg-devel mailing list or your github repository, you may of course distribute binaries. Kieran asked you to provide the patches, why couldn’t you do it?

    Note that we are literally dealing with hundreds of copyright violators. Sorry if you feel that we didn’t treat you nicely but I don’t see what else we could have done apart from asking you to provide the source code / patches – which was done.

    1. 1) you could easily ask me directly instead of reporting the violation to github 🙂
      2) you can always say thanks when you copy code from a blog post and make a patch out of it 🙂

      nevertheless, FFmpeg is an awesome project just too much bureaucracy as for me

    1. Carl, yes now I more or less understand GPL and as you can see there are no binaries or repo as it, so no more violation, Im not sure what we are arguing about

  2. The GPL says you should share all the source code to your application, not just the FFmpeg stub. You are reaping the benefits of FFmpeg without giving anything back.

      1. You get the benefits of having your test application support virtual every video format as input. This saves you having to implement hundreds of video formats.

        1. Technically you are right, but in real world for Prores I need just MOV, MXF Op1a and MXF Op Atom and I have own parser/muxer for each of listed above.
          I still not sure why we are arguing… I agreed I violated GPL, I also removed binaries. I disagree I made it on purpose but it doesn’t really matter as binaries already removed, right?

    1. BTW, Kieran, I can show you case when FFmpeg dev made the patch out of my blog post (literally copied source codes) and as I can see changes pushed to the main repo. Is it benefiting without giving nothing back?

  3. I’ve been keeping an eye on this thing, and I have a suggestion if you want to make some money while still contributing to the free software sphere: do what x264 does and pick a stricter free software license like GPL or AGPL. Then you can sell exceptions to it to proprietary vendors (dual licensing).

    You should submit your patches to the mailing list again, or perhaps bump the thread. It’s not so strange that they don’t attract much attention around the holidays 🙂

    1. Thanks, Tomas,
      I dont think its about money… Its not easy to have fun coding (at least I easily can get bored), it was fun though to reverse Prores and if I disclose the source codes I have a chance to have negative feedback or community will finish my work faster than me, both cases steal the fun I have now doing what I do.

      Regarding my patch, I dont think patch I sent that critical, it was more preparation for the next patch (was going to add 12-bit encoding so had to replace 10 integer fdct)

Leave a Reply

Your email address will not be published. Required fields are marked *