Merge commit 'd6604b29ef544793479d7fb4e05ef6622bb3e534'
authorMichael Niedermayer <michael@niedermayer.cc>
Mon, 20 Jul 2015 20:59:45 +0000 (22:59 +0200)
committerMichael Niedermayer <michael@niedermayer.cc>
Mon, 20 Jul 2015 21:43:05 +0000 (23:43 +0200)
* commit 'd6604b29ef544793479d7fb4e05ef6622bb3e534':
  Gather all coded_frame allocations and free functions to a single place

Conflicts:
libavcodec/a64multienc.c
libavcodec/asvenc.c
libavcodec/cljrenc.c
libavcodec/dpxenc.c
libavcodec/dvenc.c
libavcodec/gif.c
libavcodec/huffyuvenc.c
libavcodec/jpeglsenc.c
libavcodec/libopenjpegenc.c
libavcodec/libtheoraenc.c
libavcodec/libvpxenc.c
libavcodec/mpegvideo_enc.c
libavcodec/nvenc.c
libavcodec/pngenc.c
libavcodec/proresenc_kostya.c
libavcodec/sunrastenc.c
libavcodec/tiffenc.c
libavcodec/utils.c
libavcodec/utvideoenc.c
libavcodec/v210enc.c
libavcodec/v410enc.c
libavcodec/xbmenc.c

Merged-by: Michael Niedermayer <michael@niedermayer.cc>
52 files changed:
1  2 
libavcodec/aliaspixenc.c
libavcodec/asvenc.c
libavcodec/avuienc.c
libavcodec/bmpenc.c
libavcodec/dnxhdenc.c
libavcodec/dvenc.c
libavcodec/ffv1enc.c
libavcodec/flashsvenc.c
libavcodec/gif.c
libavcodec/huffyuvenc.c
libavcodec/jpeglsenc.c
libavcodec/lclenc.c
libavcodec/libopenjpegenc.c
libavcodec/libschroedingerenc.c
libavcodec/libspeexenc.c
libavcodec/libtheoraenc.c
libavcodec/libutvideoenc.cpp
libavcodec/libvpxenc.c
libavcodec/libx264.c
libavcodec/libx265.c
libavcodec/libxavs.c
libavcodec/libxvid.c
libavcodec/ljpegenc.c
libavcodec/mpegvideo_enc.c
libavcodec/nvenc.c
libavcodec/pamenc.c
libavcodec/pcxenc.c
libavcodec/pngenc.c
libavcodec/pnmenc.c
libavcodec/proresenc_anatoliy.c
libavcodec/proresenc_kostya.c
libavcodec/qsvenc.c
libavcodec/qtrleenc.c
libavcodec/r210enc.c
libavcodec/rawenc.c
libavcodec/roqvideoenc.c
libavcodec/sgienc.c
libavcodec/snowenc.c
libavcodec/sunrastenc.c
libavcodec/svq1enc.c
libavcodec/targaenc.c
libavcodec/tiffenc.c
libavcodec/utils.c
libavcodec/utvideoenc.c
libavcodec/v210enc.c
libavcodec/v308enc.c
libavcodec/v408enc.c
libavcodec/v410enc.c
libavcodec/xfaceenc.c
libavcodec/y41penc.c
libavcodec/yuv4enc.c
libavcodec/zmbvenc.c

Simple merge
Simple merge
index b32f433,0000000..acfe7bc
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,106 @@@
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
-         return AVERROR(ENOMEM);
-     }
 +/*
 + * AVID Meridien encoder
 + *
 + * Copyright (c) 2012 Carl Eugen Hoyos
 + *
 + * 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 "avcodec.h"
 +#include "internal.h"
 +#include "libavutil/intreadwrite.h"
 +
 +static av_cold int avui_encode_init(AVCodecContext *avctx)
 +{
 +    if (avctx->width != 720 || avctx->height != 486 && avctx->height != 576) {
 +        av_log(avctx, AV_LOG_ERROR, "Only 720x486 and 720x576 are supported.\n");
 +        return AVERROR(EINVAL);
 +    }
 +    if (!(avctx->extradata = av_mallocz(144 + FF_INPUT_BUFFER_PADDING_SIZE)))
 +        return AVERROR(ENOMEM);
 +    avctx->extradata_size = 144;
 +    memcpy(avctx->extradata, "\0\0\0\x18""APRGAPRG0001", 16);
 +    if (avctx->field_order > AV_FIELD_PROGRESSIVE) {
 +        avctx->extradata[19] = 2;
 +    } else {
 +        avctx->extradata[19] = 1;
 +    }
 +    memcpy(avctx->extradata + 24, "\0\0\0\x78""ARESARES0001""\0\0\0\x98", 20);
 +    AV_WB32(avctx->extradata + 44, avctx->width);
 +    AV_WB32(avctx->extradata + 48, avctx->height);
 +    memcpy(avctx->extradata + 52, "\0\0\0\x1\0\0\0\x20\0\0\0\x2", 12);
 +
- static av_cold int avui_encode_close(AVCodecContext *avctx)
- {
-     av_frame_free(&avctx->coded_frame);
-     return 0;
- }
 +
 +    return 0;
 +}
 +
 +static int avui_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                             const AVFrame *pic, int *got_packet)
 +{
 +    uint8_t *dst;
 +    int i, j, skip, ret, size, interlaced;
 +
 +    interlaced = avctx->field_order > AV_FIELD_PROGRESSIVE;
 +
 +    if (avctx->height == 486) {
 +        skip = 10;
 +    } else {
 +        skip = 16;
 +    }
 +    size = 2 * avctx->width * (avctx->height + skip) + 8 * interlaced;
 +    if ((ret = ff_alloc_packet(pkt, size)) < 0)
 +        return ret;
 +    dst = pkt->data;
 +    if (!interlaced) {
 +        memset(dst, 0, avctx->width * skip);
 +        dst += avctx->width * skip;
 +    }
 +
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +
 +    for (i = 0; i <= interlaced; i++) {
 +        uint8_t *src;
 +        if (interlaced && avctx->height == 486) {
 +            src = pic->data[0] + (1 - i) * pic->linesize[0];
 +        } else {
 +            src = pic->data[0] + i * pic->linesize[0];
 +        }
 +        memset(dst, 0, avctx->width * skip + 4 * i);
 +        dst += avctx->width * skip + 4 * i;
 +        for (j = 0; j < avctx->height; j += interlaced + 1) {
 +            memcpy(dst, src, avctx->width * 2);
 +            src += (interlaced + 1) * pic->linesize[0];
 +            dst += avctx->width * 2;
 +        }
 +    }
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +    return 0;
 +}
 +
-     .close        = avui_encode_close,
 +AVCodec ff_avui_encoder = {
 +    .name         = "avui",
 +    .long_name    = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"),
 +    .type         = AVMEDIA_TYPE_VIDEO,
 +    .id           = AV_CODEC_ID_AVUI,
 +    .init         = avui_encode_init,
 +    .encode2      = avui_encode_frame,
 +    .capabilities = CODEC_CAP_EXPERIMENTAL,
 +    .pix_fmts     = (const enum AVPixelFormat[]){ AV_PIX_FMT_UYVY422, AV_PIX_FMT_NONE },
 +};
@@@ -57,13 -53,9 +57,9 @@@ static av_cold int bmp_encode_init(AVCo
          break;
      default:
          av_log(avctx, AV_LOG_INFO, "unsupported pixel format\n");
 -        return -1;
 +        return AVERROR(EINVAL);
      }
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
      return 0;
  }
  
@@@ -176,10 -160,9 +166,9 @@@ AVCodec ff_bmp_encoder = 
      .id             = AV_CODEC_ID_BMP,
      .init           = bmp_encode_init,
      .encode2        = bmp_encode_frame,
-     .close          = bmp_encode_close,
      .pix_fmts       = (const enum AVPixelFormat[]){
 -        AV_PIX_FMT_BGR24,
 -        AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, AV_PIX_FMT_RGB565,
 +        AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24,
 +        AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444,
          AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8,
          AV_PIX_FMT_MONOBLACK,
          AV_PIX_FMT_NONE
Simple merge
@@@ -65,15 -61,8 +65,11 @@@ static av_cold int dvvideo_encode_init(
          return ret;
      }
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
      dv_vlc_map_tableinit();
  
 +    memset(&fdsp,0, sizeof(fdsp));
 +    memset(&mecc,0, sizeof(mecc));
 +    memset(&pdsp,0, sizeof(pdsp));
      ff_fdctdsp_init(&fdsp, avctx);
      ff_me_cmp_init(&mecc, avctx);
      ff_pixblockdsp_init(&pdsp, avctx);
@@@ -757,8 -741,7 +747,7 @@@ AVCodec ff_dvvideo_encoder = 
      .priv_data_size = sizeof(DVVideoContext),
      .init           = dvvideo_encode_init,
      .encode2        = dvvideo_encode_frame,
-     .close          = dvvideo_encode_close,
 -    .capabilities   = CODEC_CAP_SLICE_THREADS,
 +    .capabilities   = CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
      .pix_fmts       = (const enum AVPixelFormat[]) {
          AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P,
          AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
@@@ -1330,9 -1055,8 +1326,8 @@@ static int encode_frame(AVCodecContext 
      return 0;
  }
  
 -static av_cold int ffv1_encode_close(AVCodecContext *avctx)
 +static av_cold int encode_close(AVCodecContext *avctx)
  {
-     av_frame_free(&avctx->coded_frame);
      ffv1_close(avctx);
      return 0;
  }
@@@ -94,12 -94,10 +94,10 @@@ static av_cold int flashsv_encode_end(A
  
      deflateEnd(&s->zstream);
  
 -    av_free(s->encbuffer);
 -    av_free(s->previous_frame);
 -    av_free(s->tmpblock);
 +    av_freep(&s->encbuffer);
 +    av_freep(&s->previous_frame);
 +    av_freep(&s->tmpblock);
  
-     av_frame_free(&avctx->coded_frame);
      return 0;
  }
  
@@@ -217,15 -130,6 +217,10 @@@ static av_cold int gif_encode_init(AVCo
  {
      GIFContext *s = avctx->priv_data;
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
 +    if (avctx->width > 65535 || avctx->height > 65535) {
 +        av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n");
 +        return AVERROR(EINVAL);
 +    }
      avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
      avctx->coded_frame->key_frame = 1;
  
@@@ -320,12 -170,8 +315,10 @@@ static int gif_encode_close(AVCodecCont
  {
      GIFContext *s = avctx->priv_data;
  
-     av_frame_free(&avctx->coded_frame);
      av_freep(&s->lzw);
      av_freep(&s->buf);
 +    av_frame_free(&s->last_frame);
 +    av_freep(&s->tmpl);
      return 0;
  }
  
@@@ -219,17 -150,11 +219,16 @@@ static av_cold int encode_init(AVCodecC
      ff_huffyuv_common_init(avctx);
      ff_huffyuvencdsp_init(&s->hencdsp);
  
 -    avctx->extradata = av_mallocz(1024*30); // 256*3+4 == 772
 -    avctx->stats_out = av_mallocz(1024*30); // 21*256*3(%llu ) + 3(\n) + 1(0) = 16132
 +    avctx->extradata = av_mallocz(3*MAX_N + 4);
 +    if (s->flags&CODEC_FLAG_PASS1) {
 +#define STATS_OUT_SIZE 21*MAX_N*3 + 4
 +        avctx->stats_out = av_mallocz(STATS_OUT_SIZE); // 21*256*3(%llu ) + 3(\n) + 1(0) = 16132
 +        if (!avctx->stats_out)
 +            return AVERROR(ENOMEM);
 +    }
      s->version = 2;
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->extradata || !avctx->coded_frame)
 -    if (!avctx->extradata || !avctx->stats_out)
++    if (!avctx->extradata)
          return AVERROR(ENOMEM);
  
      avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
@@@ -444,8 -435,6 +434,7 @@@ AVCodec ff_jpegls_encoder = 
      .type           = AVMEDIA_TYPE_VIDEO,
      .id             = AV_CODEC_ID_JPEGLS,
      .init           = encode_init_ls,
-     .close          = encode_close,
 +    .capabilities   = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
      .encode2        = encode_picture_ls,
      .pix_fmts       = (const enum AVPixelFormat[]) {
          AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24,
Simple merge
@@@ -242,18 -176,15 +242,11 @@@ static av_cold int libopenjpeg_encode_i
          goto fail;
      }
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
-         goto fail;
-     }
 -    ctx->event_mgr.info_handler    = info_callback;
 -    ctx->event_mgr.error_handler   = error_callback;
 -    ctx->event_mgr.warning_handler = warning_callback;
 -    opj_set_event_mgr((opj_common_ptr) ctx->compress, &ctx->event_mgr, avctx);
--
      return 0;
  
  fail:
 -    av_freep(&ctx->compress);
 +    opj_image_destroy(ctx->image);
 +    ctx->image = NULL;
-     av_frame_free(&avctx->coded_frame);
      return err;
  }
  
@@@ -606,9 -362,8 +599,8 @@@ static av_cold int libopenjpeg_encode_c
  {
      LibOpenJPEGContext *ctx = avctx->priv_data;
  
 -    opj_destroy_compress(ctx->compress);
      opj_image_destroy(ctx->image);
-     av_frame_free(&avctx->coded_frame);
 +    ctx->image = NULL;
      return 0;
  }
  
Simple merge
Simple merge
Simple merge
index cf669d2,0000000..38d019b
mode 100644,000000..100644
--- /dev/null
@@@ -1,253 -1,0 +1,251 @@@
-     avctx->coded_frame = av_frame_alloc();
 +/*
 + * Copyright (c) 2012 Derek Buitenhuis
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public
 + * License as published by the Free Software Foundation;
 + * version 2 of the License.
 + *
 + * 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
 + * General Public License for more details.
 + *
 + * You should have received a copy of the GNU 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
 + */
 +
 +/**
 + * @file
 + * Known FOURCCs:
 + *     'ULY0' (YCbCr 4:2:0), 'ULY2' (YCbCr 4:2:2), 'ULRG' (RGB), 'ULRA' (RGBA),
 + *     'ULH0' (YCbCr 4:2:0 BT.709), 'ULH2' (YCbCr 4:2:2 BT.709)
 + */
 +
 +extern "C" {
 +#include "libavutil/avassert.h"
 +#include "avcodec.h"
 +#include "internal.h"
 +}
 +
 +#include "libutvideo.h"
 +#include "put_bits.h"
 +
 +static av_cold int utvideo_encode_init(AVCodecContext *avctx)
 +{
 +    UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
 +    UtVideoExtra *info;
 +    uint32_t flags, in_format;
 +    int ret;
 +
 +    switch (avctx->pix_fmt) {
 +    case AV_PIX_FMT_YUV420P:
 +        in_format = UTVF_YV12;
 +        avctx->bits_per_coded_sample = 12;
 +        if (avctx->colorspace == AVCOL_SPC_BT709)
 +            avctx->codec_tag = MKTAG('U', 'L', 'H', '0');
 +        else
 +            avctx->codec_tag = MKTAG('U', 'L', 'Y', '0');
 +        break;
 +    case AV_PIX_FMT_YUYV422:
 +        in_format = UTVF_YUYV;
 +        avctx->bits_per_coded_sample = 16;
 +        if (avctx->colorspace == AVCOL_SPC_BT709)
 +            avctx->codec_tag = MKTAG('U', 'L', 'H', '2');
 +        else
 +            avctx->codec_tag = MKTAG('U', 'L', 'Y', '2');
 +        break;
 +    case AV_PIX_FMT_BGR24:
 +        in_format = UTVF_NFCC_BGR_BU;
 +        avctx->bits_per_coded_sample = 24;
 +        avctx->codec_tag = MKTAG('U', 'L', 'R', 'G');
 +        break;
 +    case AV_PIX_FMT_RGB32:
 +        in_format = UTVF_NFCC_BGRA_BU;
 +        avctx->bits_per_coded_sample = 32;
 +        avctx->codec_tag = MKTAG('U', 'L', 'R', 'A');
 +        break;
 +    default:
 +        return AVERROR(EINVAL);
 +    }
 +
 +    /* Check before we alloc anything */
 +    if (avctx->prediction_method != 0 && avctx->prediction_method != 2) {
 +        av_log(avctx, AV_LOG_ERROR, "Invalid prediction method.\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    flags = ((avctx->prediction_method + 1) << 8) | (avctx->thread_count - 1);
 +
 +    avctx->priv_data = utv;
-     av_frame_free(&avctx->coded_frame);
 +
 +    /* Alloc extradata buffer */
 +    info = (UtVideoExtra *)av_malloc(sizeof(*info));
 +
 +    if (!info) {
 +        av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata buffer.\n");
 +        return AVERROR(ENOMEM);
 +    }
 +
 +    /*
 +     * We use this buffer to hold the data that Ut Video returns,
 +     * since we cannot decode planes separately with it.
 +     */
 +    ret = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
 +    if (ret < 0) {
 +        av_free(info);
 +        return ret;
 +    }
 +    utv->buf_size = ret;
 +
 +    utv->buffer = (uint8_t *)av_malloc(utv->buf_size);
 +
 +    if (utv->buffer == NULL) {
 +        av_log(avctx, AV_LOG_ERROR, "Could not allocate output buffer.\n");
 +        av_free(info);
 +        return AVERROR(ENOMEM);
 +    }
 +
 +    /*
 +     * Create a Ut Video instance. Since the function wants
 +     * an "interface name" string, pass it the name of the lib.
 +     */
 +    utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec");
 +
 +    /* Initialize encoder */
 +    utv->codec->EncodeBegin(in_format, avctx->width, avctx->height,
 +                            CBGROSSWIDTH_WINDOWS);
 +
 +    /* Get extradata from encoder */
 +    avctx->extradata_size = utv->codec->EncodeGetExtraDataSize();
 +    utv->codec->EncodeGetExtraData(info, avctx->extradata_size, in_format,
 +                                   avctx->width, avctx->height,
 +                                   CBGROSSWIDTH_WINDOWS);
 +    avctx->extradata = (uint8_t *)info;
 +
 +    /* Set flags */
 +    utv->codec->SetState(&flags, sizeof(flags));
 +
 +    return 0;
 +}
 +
 +static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                                const AVFrame *pic, int *got_packet)
 +{
 +    UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
 +    int w = avctx->width, h = avctx->height;
 +    int ret, rgb_size, i;
 +    bool keyframe;
 +    uint8_t *y, *u, *v;
 +    uint8_t *dst;
 +
 +    /* Alloc buffer */
 +    if ((ret = ff_alloc_packet2(avctx, pkt, utv->buf_size)) < 0)
 +        return ret;
 +
 +    dst = pkt->data;
 +
 +    /* Move input if needed data into Ut Video friendly buffer */
 +    switch (avctx->pix_fmt) {
 +    case AV_PIX_FMT_YUV420P:
 +        y = utv->buffer;
 +        u = y + w * h;
 +        v = u + w * h / 4;
 +        for (i = 0; i < h; i++) {
 +            memcpy(y, pic->data[0] + i * pic->linesize[0], w);
 +            y += w;
 +        }
 +        for (i = 0; i < h / 2; i++) {
 +            memcpy(u, pic->data[2] + i * pic->linesize[2], w >> 1);
 +            memcpy(v, pic->data[1] + i * pic->linesize[1], w >> 1);
 +            u += w >> 1;
 +            v += w >> 1;
 +        }
 +        break;
 +    case AV_PIX_FMT_YUYV422:
 +        for (i = 0; i < h; i++)
 +            memcpy(utv->buffer + i * (w << 1),
 +                   pic->data[0] + i * pic->linesize[0], w << 1);
 +        break;
 +    case AV_PIX_FMT_BGR24:
 +    case AV_PIX_FMT_RGB32:
 +        /* Ut Video takes bottom-up BGR */
 +        rgb_size = avctx->pix_fmt == AV_PIX_FMT_BGR24 ? 3 : 4;
 +        for (i = 0; i < h; i++)
 +            memcpy(utv->buffer + (h - i - 1) * w * rgb_size,
 +                   pic->data[0] + i * pic->linesize[0],
 +                   w * rgb_size);
 +        break;
 +    default:
 +        return AVERROR(EINVAL);
 +    }
 +
 +    /* Encode frame */
 +    pkt->size = utv->codec->EncodeFrame(dst, &keyframe, utv->buffer);
 +
 +    if (!pkt->size) {
 +        av_log(avctx, AV_LOG_ERROR, "EncodeFrame failed!\n");
 +        return AVERROR_INVALIDDATA;
 +    }
 +
 +    /*
 +     * Ut Video is intra-only and every frame is a keyframe,
 +     * and the API always returns true. In case something
 +     * durastic changes in the future, such as inter support,
 +     * assert that this is true.
 +     */
 +    av_assert2(keyframe == true);
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +    return 0;
 +}
 +
 +static av_cold int utvideo_encode_close(AVCodecContext *avctx)
 +{
 +    UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
 +
 +    av_freep(&avctx->extradata);
 +    av_freep(&utv->buffer);
 +
 +    utv->codec->EncodeEnd();
 +    CCodec::DeleteInstance(utv->codec);
 +
 +    return 0;
 +}
 +
 +AVCodec ff_libutvideo_encoder = {
 +    "libutvideo",
 +    NULL_IF_CONFIG_SMALL("Ut Video"),
 +    AVMEDIA_TYPE_VIDEO,
 +    AV_CODEC_ID_UTVIDEO,
 +    CODEC_CAP_AUTO_THREADS | CODEC_CAP_LOSSLESS,
 +    NULL, /* supported_framerates */
 +    (const enum AVPixelFormat[]) {
 +        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_BGR24,
 +        AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
 +    },
 +    NULL, /* supported_samplerates */
 +    NULL, /* sample_fmts */
 +    NULL, /* channel_layouts */
 +    0,    /* max_lowres */
 +    NULL, /* priv_class */
 +    NULL, /* profiles */
 +    sizeof(UtVideoContext),
 +    NULL, /* next */
 +    NULL, /* init_thread_copy */
 +    NULL, /* update_thread_context */
 +    NULL, /* defaults */
 +    NULL, /* init_static_data */
 +    utvideo_encode_init,
 +    NULL, /* encode */
 +    utvideo_encode_frame,
 +    NULL, /* decode */
 +    utvideo_encode_close,
 +    NULL, /* flush */
 +};
@@@ -262,10 -209,7 +262,9 @@@ static av_cold int vp8_free(AVCodecCont
      VP8Context *ctx = avctx->priv_data;
  
      vpx_codec_destroy(&ctx->encoder);
 +    if (ctx->is_alpha)
 +        vpx_codec_destroy(&ctx->encoder_alpha);
      av_freep(&ctx->twopass_stats.buf);
-     av_frame_free(&avctx->coded_frame);
      av_freep(&avctx->stats_out);
      free_frame_list(ctx->coded_frame_list);
      return 0;
@@@ -603,49 -364,12 +602,43 @@@ static av_cold int vpx_init(AVCodecCont
      FF_ENABLE_DEPRECATION_WARNINGS
  #endif
      codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD,  ctx->static_thresh);
 -    codecctl_int(avctx, VP8E_SET_CQ_LEVEL,          ctx->crf);
 +    if (ctx->crf >= 0)
 +        codecctl_int(avctx, VP8E_SET_CQ_LEVEL,          ctx->crf);
 +    if (ctx->max_intra_rate >= 0)
 +        codecctl_int(avctx, VP8E_SET_MAX_INTRA_BITRATE_PCT, ctx->max_intra_rate);
 +
 +#if CONFIG_LIBVPX_VP9_ENCODER
 +    if (avctx->codec_id == AV_CODEC_ID_VP9) {
 +        if (ctx->lossless >= 0)
 +            codecctl_int(avctx, VP9E_SET_LOSSLESS, ctx->lossless);
 +        if (ctx->tile_columns >= 0)
 +            codecctl_int(avctx, VP9E_SET_TILE_COLUMNS, ctx->tile_columns);
 +        if (ctx->tile_rows >= 0)
 +            codecctl_int(avctx, VP9E_SET_TILE_ROWS, ctx->tile_rows);
 +        if (ctx->frame_parallel >= 0)
 +            codecctl_int(avctx, VP9E_SET_FRAME_PARALLEL_DECODING, ctx->frame_parallel);
 +        if (ctx->aq_mode >= 0)
 +            codecctl_int(avctx, VP9E_SET_AQ_MODE, ctx->aq_mode);
 +#if VPX_ENCODER_ABI_VERSION > 8
 +        set_colorspace(avctx);
 +#endif
 +    }
 +#endif
 +
 +    av_log(avctx, AV_LOG_DEBUG, "Using deadline: %d\n", ctx->deadline);
  
      //provide dummy value to initialize wrapper, values will be updated each _encode()
 -    vpx_img_wrap(&ctx->rawimg, ff_vpx_pixfmt_to_imgfmt(avctx->pix_fmt),
 -                 avctx->width, avctx->height, 1, (unsigned char *)1);
 +    vpx_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1,
 +                 (unsigned char*)1);
 +#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
 +    if (avctx->codec_id == AV_CODEC_ID_VP9 && (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH))
 +        ctx->rawimg.bit_depth = enccfg.g_bit_depth;
 +#endif
 +
 +    if (ctx->is_alpha)
 +        vpx_img_wrap(&ctx->rawimg_alpha, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
 +                     (unsigned char*)1);
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
-         vp8_free(avctx);
-         return AVERROR(ENOMEM);
-     }
      return 0;
  }
  
@@@ -706,12 -542,8 +704,8 @@@ static av_cold int X264_init(AVCodecCon
  
      x4->enc = x264_encoder_open(&x4->params);
      if (!x4->enc)
 -        return AVERROR_UNKNOWN;
 +        return AVERROR_EXTERNAL;
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
      if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
          x264_nal_t *nal;
          uint8_t *p;
Simple merge
@@@ -354,16 -353,12 +352,12 @@@ static av_cold int XAVS_init(AVCodecCon
      if (!x4->enc)
          return -1;
  
 -    if (!(x4->pts_buffer = av_mallocz((avctx->max_b_frames+1) * sizeof(*x4->pts_buffer))))
 +    if (!(x4->pts_buffer = av_mallocz_array((avctx->max_b_frames+1), sizeof(*x4->pts_buffer))))
          return AVERROR(ENOMEM);
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
      /* TAG: Do we have GLOBAL HEADER in AVS */
      /* We Have PPS and SPS in AVS */
 -    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
 +    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER && 0) {
          xavs_nal_t *nal;
          int nnal, s, i, size;
          uint8_t *p;
@@@ -818,21 -787,14 +815,20 @@@ static av_cold int xvid_encode_close(AV
          x->encoder_handle = NULL;
      }
  
-     av_frame_free(&avctx->coded_frame);
      av_freep(&avctx->extradata);
      if (x->twopassbuffer) {
 -        av_free(x->twopassbuffer);
 -        av_free(x->old_twopassbuffer);
 +        av_freep(&x->twopassbuffer);
 +        av_freep(&x->old_twopassbuffer);
 +        avctx->stats_out = NULL;
 +    }
 +    if (x->twopassfd>=0) {
 +        unlink(x->twopassfile);
 +        close(x->twopassfd);
 +        x->twopassfd = -1;
      }
 -    av_free(x->twopassfile);
 -    av_free(x->intra_matrix);
 -    av_free(x->inter_matrix);
 +    av_freep(&x->twopassfile);
 +    av_freep(&x->intra_matrix);
 +    av_freep(&x->inter_matrix);
  
      return 0;
  }
Simple merge
@@@ -1617,8 -1467,15 +1617,7 @@@ static void frame_end(MpegEncContext *s
      if (s->pict_type!= AV_PICTURE_TYPE_B)
          s->last_non_b_pict_type = s->pict_type;
  
-     s->avctx->coded_frame = s->current_picture_ptr->f;
 -    if (s->encoding) {
 -        /* release non-reference frames */
 -        for (i = 0; i < MAX_PICTURE_COUNT; i++) {
 -            if (!s->picture[i].reference)
 -                ff_mpeg_unref_picture(s->avctx, &s->picture[i]);
 -        }
 -    }
--
+     av_frame_copy_props(s->avctx->coded_frame, s->current_picture.f);
  }
  
  static void update_noise_reduction(MpegEncContext *s)
@@@ -457,696 -515,529 +457,686 @@@ error
      return 0;
  }
  
 -static int nvenc_setup_hevc_config(AVCodecContext *avctx)
 +static av_cold int nvenc_dyload_nvenc(AVCodecContext *avctx)
  {
 -    NVENCContext *ctx                      = avctx->priv_data;
 -    NV_ENC_CONFIG *cc                      = &ctx->config;
 -    NV_ENC_CONFIG_HEVC *hevc               = &cc->encodeCodecConfig.hevcConfig;
 +    PNVENCODEAPICREATEINSTANCE nvEncodeAPICreateInstance = 0;
 +    NVENCSTATUS nvstatus;
  
 -    hevc->disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
 -    hevc->repeatSPSPPS  = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
 +    NvencContext *ctx = avctx->priv_data;
 +    NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
  
 -    hevc->maxNumRefFramesInDPB = avctx->refs;
 -    hevc->idrPeriod            = cc->gopLength;
 +    if (!nvenc_check_cuda(avctx))
 +        return 0;
  
 -    /* No other profile is supported in the current SDK version 5 */
 -    cc->profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
 -    avctx->profile  = FF_PROFILE_HEVC_MAIN;
 +    if (dl_fn->nvenc_lib)
 +        return 1;
  
 -    if (ctx->level) {
 -        hevc->level = ctx->level;
 +#if defined(_WIN32)
 +    if (sizeof(void*) == 8) {
 +        dl_fn->nvenc_lib = LoadLibrary(TEXT("nvEncodeAPI64.dll"));
      } else {
 -        hevc->level = NV_ENC_LEVEL_AUTOSELECT;
 +        dl_fn->nvenc_lib = LoadLibrary(TEXT("nvEncodeAPI.dll"));
      }
 +#else
 +    dl_fn->nvenc_lib = dlopen("libnvidia-encode.so.1", RTLD_LAZY);
 +#endif
  
 -    if (ctx->tier) {
 -        hevc->tier = ctx->tier;
 +    if (!dl_fn->nvenc_lib) {
 +        av_log(avctx, AV_LOG_FATAL, "Failed loading the nvenc library\n");
 +        goto error;
      }
  
 -    return 0;
 -}
 -static int nvenc_setup_codec_config(AVCodecContext *avctx)
 -{
 -    switch (avctx->codec->id) {
 -    case AV_CODEC_ID_H264:
 -        return nvenc_setup_h264_config(avctx);
 -    case AV_CODEC_ID_HEVC:
 -        return nvenc_setup_hevc_config(avctx);
 +    nvEncodeAPICreateInstance = (PNVENCODEAPICREATEINSTANCE)LOAD_FUNC(dl_fn->nvenc_lib, "NvEncodeAPICreateInstance");
 +
 +    if (!nvEncodeAPICreateInstance) {
 +        av_log(avctx, AV_LOG_FATAL, "Failed to load nvenc entrypoint\n");
 +        goto error;
      }
 -    return 0;
 -}
  
 -static int nvenc_setup_encoder(AVCodecContext *avctx)
 -{
 -    NVENCContext *ctx               = avctx->priv_data;
 -    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
 -    NV_ENC_PRESET_CONFIG preset_cfg = { 0 };
 -    int ret;
 -
 -    ctx->params.version = NV_ENC_INITIALIZE_PARAMS_VER;
 -
 -    ctx->params.encodeHeight = avctx->height;
 -    ctx->params.encodeWidth  = avctx->width;
 -
 -    if (avctx->sample_aspect_ratio.num &&
 -        avctx->sample_aspect_ratio.den &&
 -        (avctx->sample_aspect_ratio.num != 1 ||
 -         avctx->sample_aspect_ratio.den != 1)) {
 -        av_reduce(&ctx->params.darWidth,
 -                  &ctx->params.darHeight,
 -                  avctx->width * avctx->sample_aspect_ratio.num,
 -                  avctx->height * avctx->sample_aspect_ratio.den,
 -                  INT_MAX / 8);
 -    } else {
 -        ctx->params.darHeight = avctx->height;
 -        ctx->params.darWidth  = avctx->width;
 +    dl_fn->nvenc_funcs.version = NV_ENCODE_API_FUNCTION_LIST_VER;
 +
 +    nvstatus = nvEncodeAPICreateInstance(&dl_fn->nvenc_funcs);
 +
 +    if (nvstatus != NV_ENC_SUCCESS) {
 +        av_log(avctx, AV_LOG_FATAL, "Failed to create nvenc instance\n");
 +        goto error;
      }
  
 -    ctx->params.frameRateNum = avctx->time_base.den;
 -    ctx->params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
 +    av_log(avctx, AV_LOG_VERBOSE, "Nvenc initialized successfully\n");
  
 -    ctx->params.enableEncodeAsync = 0;
 -    ctx->params.enablePTD         = 1;
 +    return 1;
  
 -    ctx->params.encodeConfig = &ctx->config;
 +error:
 +    if (dl_fn->nvenc_lib)
 +        DL_CLOSE_FUNC(dl_fn->nvenc_lib);
  
 -    nvec_map_preset(ctx);
 +    dl_fn->nvenc_lib = NULL;
  
 -    preset_cfg.version           = NV_ENC_PRESET_CONFIG_VER;
 -    preset_cfg.presetCfg.version = NV_ENC_CONFIG_VER;
 +    return 0;
 +}
  
 -    ret = nv->nvEncGetEncodePresetConfig(ctx->nvenc_ctx,
 -                                         ctx->params.encodeGUID,
 -                                         ctx->params.presetGUID,
 -                                         &preset_cfg);
 -    if (ret != NV_ENC_SUCCESS) {
 -        av_log(avctx, AV_LOG_ERROR,
 -               "Cannot get the preset configuration\n");
 -        return AVERROR_UNKNOWN;
 -    }
 +static av_cold void nvenc_unload_nvenc(AVCodecContext *avctx)
 +{
 +    NvencContext *ctx = avctx->priv_data;
 +    NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
  
 -    memcpy(&ctx->config, &preset_cfg.presetCfg, sizeof(ctx->config));
 +    DL_CLOSE_FUNC(dl_fn->nvenc_lib);
 +    dl_fn->nvenc_lib = NULL;
  
 -    ctx->config.version = NV_ENC_CONFIG_VER;
 +    dl_fn->nvenc_device_count = 0;
  
 -    if (avctx->gop_size > 0) {
 -        if (avctx->max_b_frames > 0) {
 -            ctx->last_dts = -2;
 -            /* 0 is intra-only,
 -             * 1 is I/P only,
 -             * 2 is one B Frame,
 -             * 3 two B frames, and so on. */
 -            ctx->config.frameIntervalP = avctx->max_b_frames + 1;
 -        } else if (avctx->max_b_frames == 0) {
 -            ctx->config.frameIntervalP = 1;
 -        }
 -        ctx->config.gopLength = avctx->gop_size;
 -    } else if (avctx->gop_size == 0) {
 -        ctx->config.frameIntervalP = 0;
 -        ctx->config.gopLength      = 1;
 -    }
 +    DL_CLOSE_FUNC(dl_fn->cuda_lib);
 +    dl_fn->cuda_lib = NULL;
  
 -    if (ctx->config.frameIntervalP > 1)
 -        avctx->max_b_frames = ctx->config.frameIntervalP - 1;
 +    dl_fn->cu_init = NULL;
 +    dl_fn->cu_device_get_count = NULL;
 +    dl_fn->cu_device_get = NULL;
 +    dl_fn->cu_device_get_name = NULL;
 +    dl_fn->cu_device_compute_capability = NULL;
 +    dl_fn->cu_ctx_create = NULL;
 +    dl_fn->cu_ctx_pop_current = NULL;
 +    dl_fn->cu_ctx_destroy = NULL;
  
 -    nvenc_setup_rate_control(avctx);
 +    av_log(avctx, AV_LOG_VERBOSE, "Nvenc unloaded\n");
 +}
  
 -    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
 -        ctx->config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
 -    } else {
 -        ctx->config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
 +static av_cold int nvenc_encode_init(AVCodecContext *avctx)
 +{
 +    NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS encode_session_params = { 0 };
 +    NV_ENC_PRESET_CONFIG preset_config = { 0 };
 +    CUcontext cu_context_curr;
 +    CUresult cu_res;
 +    GUID encoder_preset = NV_ENC_PRESET_HQ_GUID;
 +    GUID codec;
 +    NVENCSTATUS nv_status = NV_ENC_SUCCESS;
 +    int surfaceCount = 0;
 +    int i, num_mbs;
 +    int isLL = 0;
 +    int lossless = 0;
 +    int res = 0;
 +    int dw, dh;
 +
 +    NvencContext *ctx = avctx->priv_data;
 +    NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
 +    NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs;
 +
 +    if (!nvenc_dyload_nvenc(avctx))
 +        return AVERROR_EXTERNAL;
 +
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         res = AVERROR(ENOMEM);
-         goto error;
-     }
 +    ctx->last_dts = AV_NOPTS_VALUE;
 +
 +    ctx->encode_config.version = NV_ENC_CONFIG_VER;
 +    ctx->init_encode_params.version = NV_ENC_INITIALIZE_PARAMS_VER;
 +    preset_config.version = NV_ENC_PRESET_CONFIG_VER;
 +    preset_config.presetCfg.version = NV_ENC_CONFIG_VER;
 +    encode_session_params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
 +    encode_session_params.apiVersion = NVENCAPI_VERSION;
 +
 +    if (ctx->gpu >= dl_fn->nvenc_device_count) {
 +        av_log(avctx, AV_LOG_FATAL, "Requested GPU %d, but only %d GPUs are available!\n", ctx->gpu, dl_fn->nvenc_device_count);
 +        res = AVERROR(EINVAL);
 +        goto error;
      }
  
 -    if ((ret = nvenc_setup_codec_config(avctx)) < 0)
 -        return ret;
 +    ctx->cu_context = NULL;
 +    cu_res = dl_fn->cu_ctx_create(&ctx->cu_context, 0, dl_fn->nvenc_devices[ctx->gpu]);
  
 -    ret = nv->nvEncInitializeEncoder(ctx->nvenc_ctx, &ctx->params);
 -    if (ret != NV_ENC_SUCCESS) {
 -        av_log(avctx, AV_LOG_ERROR, "Cannot initialize the decoder");
 -        return AVERROR_UNKNOWN;
 +    if (cu_res != CUDA_SUCCESS) {
 +        av_log(avctx, AV_LOG_FATAL, "Failed creating CUDA context for NVENC: 0x%x\n", (int)cu_res);
 +        res = AVERROR_EXTERNAL;
 +        goto error;
      }
  
 -    return 0;
 -}
 +    cu_res = dl_fn->cu_ctx_pop_current(&cu_context_curr);
  
 -static int nvenc_alloc_surface(AVCodecContext *avctx, int idx)
 -{
 -    NVENCContext *ctx               = avctx->priv_data;
 -    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
 -    int ret;
 -    NV_ENC_CREATE_INPUT_BUFFER in_buffer      = { 0 };
 -    NV_ENC_CREATE_BITSTREAM_BUFFER out_buffer = { 0 };
 +    if (cu_res != CUDA_SUCCESS) {
 +        av_log(avctx, AV_LOG_FATAL, "Failed popping CUDA context: 0x%x\n", (int)cu_res);
 +        res = AVERROR_EXTERNAL;
 +        goto error;
 +    }
  
 -    in_buffer.version  = NV_ENC_CREATE_INPUT_BUFFER_VER;
 -    out_buffer.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
 +    encode_session_params.device = ctx->cu_context;
 +    encode_session_params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
  
 -    in_buffer.width  = avctx->width;
 -    in_buffer.height = avctx->height;
 +    nv_status = p_nvenc->nvEncOpenEncodeSessionEx(&encode_session_params, &ctx->nvencoder);
 +    if (nv_status != NV_ENC_SUCCESS) {
 +        ctx->nvencoder = NULL;
 +        av_log(avctx, AV_LOG_FATAL, "OpenEncodeSessionEx failed: 0x%x - invalid license key?\n", (int)nv_status);
 +        res = AVERROR_EXTERNAL;
 +        goto error;
 +    }
  
 -    in_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED;
 +    if (ctx->preset) {
 +        if (!strcmp(ctx->preset, "hp")) {
 +            encoder_preset = NV_ENC_PRESET_HP_GUID;
 +        } else if (!strcmp(ctx->preset, "hq")) {
 +            encoder_preset = NV_ENC_PRESET_HQ_GUID;
 +        } else if (!strcmp(ctx->preset, "bd")) {
 +            encoder_preset = NV_ENC_PRESET_BD_GUID;
 +        } else if (!strcmp(ctx->preset, "ll")) {
 +            encoder_preset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
 +            isLL = 1;
 +        } else if (!strcmp(ctx->preset, "llhp")) {
 +            encoder_preset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
 +            isLL = 1;
 +        } else if (!strcmp(ctx->preset, "llhq")) {
 +            encoder_preset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
 +            isLL = 1;
 +        } else if (!strcmp(ctx->preset, "lossless")) {
 +            encoder_preset = NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID;
 +            lossless = 1;
 +        } else if (!strcmp(ctx->preset, "losslesshp")) {
 +            encoder_preset = NV_ENC_PRESET_LOSSLESS_HP_GUID;
 +            lossless = 1;
 +        } else if (!strcmp(ctx->preset, "default")) {
 +            encoder_preset = NV_ENC_PRESET_DEFAULT_GUID;
 +        } else {
 +            av_log(avctx, AV_LOG_FATAL, "Preset \"%s\" is unknown! Supported presets: hp, hq, bd, ll, llhp, llhq, lossless, losslesshp, default\n", ctx->preset);
 +            res = AVERROR(EINVAL);
 +            goto error;
 +        }
 +    }
  
 -    switch (avctx->pix_fmt) {
 -    case AV_PIX_FMT_YUV420P:
 -        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_YV12_PL;
 -        break;
 -    case AV_PIX_FMT_NV12:
 -        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12_PL;
 +    switch (avctx->codec->id) {
 +    case AV_CODEC_ID_H264:
 +        codec = NV_ENC_CODEC_H264_GUID;
          break;
 -    case AV_PIX_FMT_YUV444P:
 -        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_YUV444_PL;
 +    case AV_CODEC_ID_H265:
 +        codec = NV_ENC_CODEC_HEVC_GUID;
          break;
      default:
 -        return AVERROR_BUG;
 +        av_log(avctx, AV_LOG_ERROR, "nvenc: Unknown codec name\n");
 +        res = AVERROR(EINVAL);
 +        goto error;
      }
  
 -    ret = nv->nvEncCreateInputBuffer(ctx->nvenc_ctx, &in_buffer);
 -    if (ret != NV_ENC_SUCCESS) {
 -        av_log(avctx, AV_LOG_ERROR, "CreateInputBuffer failed\n");
 -        return AVERROR_UNKNOWN;
 +    nv_status = p_nvenc->nvEncGetEncodePresetConfig(ctx->nvencoder, codec, encoder_preset, &preset_config);
 +    if (nv_status != NV_ENC_SUCCESS) {
 +        av_log(avctx, AV_LOG_FATAL, "GetEncodePresetConfig failed: 0x%x\n", (int)nv_status);
 +        res = AVERROR_EXTERNAL;
 +        goto error;
      }
  
 -    ctx->in[idx].in        = in_buffer.inputBuffer;
 -    ctx->in[idx].format    = in_buffer.bufferFmt;
 -
 -    /* 1MB is large enough to hold most output frames.
 -     * NVENC increases this automaticaly if it's not enough. */
 -    out_buffer.size = BITSTREAM_BUFFER_SIZE;
 +    ctx->init_encode_params.encodeGUID = codec;
 +    ctx->init_encode_params.encodeHeight = avctx->height;
 +    ctx->init_encode_params.encodeWidth = avctx->width;
  
 -    out_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED;
 +    if (avctx->sample_aspect_ratio.num && avctx->sample_aspect_ratio.den &&
 +        (avctx->sample_aspect_ratio.num != 1 || avctx->sample_aspect_ratio.num != 1)) {
 +        av_reduce(&dw, &dh,
 +                  avctx->width * avctx->sample_aspect_ratio.num,
 +                  avctx->height * avctx->sample_aspect_ratio.den,
 +                  1024 * 1024);
 +        ctx->init_encode_params.darHeight = dh;
 +        ctx->init_encode_params.darWidth = dw;
 +    } else {
 +        ctx->init_encode_params.darHeight = avctx->height;
 +        ctx->init_encode_params.darWidth = avctx->width;
 +    }
  
 -    ret = nv->nvEncCreateBitstreamBuffer(ctx->nvenc_ctx, &out_buffer);
 -    if (ret != NV_ENC_SUCCESS) {
 -        av_log(avctx, AV_LOG_ERROR, "CreateBitstreamBuffer failed\n");
 -        return AVERROR_UNKNOWN;
 +    // De-compensate for hardware, dubiously, trying to compensate for
 +    // playback at 704 pixel width.
 +    if (avctx->width == 720 &&
 +        (avctx->height == 480 || avctx->height == 576)) {
 +        av_reduce(&dw, &dh,
 +                  ctx->init_encode_params.darWidth * 44,
 +                  ctx->init_encode_params.darHeight * 45,
 +                  1024 * 1024);
 +        ctx->init_encode_params.darHeight = dh;
 +        ctx->init_encode_params.darWidth = dw;
      }
  
 -    ctx->out[idx].out  = out_buffer.bitstreamBuffer;
 -    ctx->out[idx].busy = 0;
 +    ctx->init_encode_params.frameRateNum = avctx->time_base.den;
 +    ctx->init_encode_params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
  
 -    return 0;
 -}
 +    num_mbs = ((avctx->width + 15) >> 4) * ((avctx->height + 15) >> 4);
 +    ctx->max_surface_count = (num_mbs >= 8160) ? 32 : 48;
  
 -static int nvenc_setup_surfaces(AVCodecContext *avctx)
 -{
 -    NVENCContext *ctx = avctx->priv_data;
 -    int i, ret;
 +    ctx->init_encode_params.enableEncodeAsync = 0;
 +    ctx->init_encode_params.enablePTD = 1;
  
 -    ctx->nb_surfaces = FFMAX(4 + avctx->max_b_frames,
 -                             ctx->nb_surfaces);
 +    ctx->init_encode_params.presetGUID = encoder_preset;
  
 -    ctx->in = av_mallocz(ctx->nb_surfaces * sizeof(*ctx->in));
 -    if (!ctx->in)
 -        return AVERROR(ENOMEM);
 +    ctx->init_encode_params.encodeConfig = &ctx->encode_config;
 +    memcpy(&ctx->encode_config, &preset_config.presetCfg, sizeof(ctx->encode_config));
 +    ctx->encode_config.version = NV_ENC_CONFIG_VER;
  
 -    ctx->out = av_mallocz(ctx->nb_surfaces * sizeof(*ctx->out));
 -    if (!ctx->out)
 -        return AVERROR(ENOMEM);
 +    if (avctx->refs >= 0) {
 +        /* 0 means "let the hardware decide" */
 +        switch (avctx->codec->id) {
 +        case AV_CODEC_ID_H264:
 +            ctx->encode_config.encodeCodecConfig.h264Config.maxNumRefFrames = avctx->refs;
 +            break;
 +        case AV_CODEC_ID_H265:
 +            ctx->encode_config.encodeCodecConfig.hevcConfig.maxNumRefFramesInDPB = avctx->refs;
 +            break;
 +        /* Earlier switch/case will return if unknown codec is passed. */
 +        }
 +    }
  
 -    ctx->timestamps = av_fifo_alloc(ctx->nb_surfaces * sizeof(int64_t));
 -    if (!ctx->timestamps)
 -        return AVERROR(ENOMEM);
 -    ctx->pending = av_fifo_alloc(ctx->nb_surfaces * sizeof(ctx->out));
 -    if (!ctx->pending)
 -        return AVERROR(ENOMEM);
 -    ctx->ready = av_fifo_alloc(ctx->nb_surfaces * sizeof(ctx->out));
 -    if (!ctx->ready)
 -        return AVERROR(ENOMEM);
 +    if (avctx->gop_size > 0) {
 +        if (avctx->max_b_frames >= 0) {
 +            /* 0 is intra-only, 1 is I/P only, 2 is one B Frame, 3 two B frames, and so on. */
 +            ctx->encode_config.frameIntervalP = avctx->max_b_frames + 1;
 +        }
  
 -    for (i = 0; i < ctx->nb_surfaces; i++) {
 -        if ((ret = nvenc_alloc_surface(avctx, i)) < 0)
 -            return ret;
 +        ctx->encode_config.gopLength = avctx->gop_size;
 +        switch (avctx->codec->id) {
 +        case AV_CODEC_ID_H264:
 +            ctx->encode_config.encodeCodecConfig.h264Config.idrPeriod = avctx->gop_size;
 +            break;
 +        case AV_CODEC_ID_H265:
 +            ctx->encode_config.encodeCodecConfig.hevcConfig.idrPeriod = avctx->gop_size;
 +            break;
 +        /* Earlier switch/case will return if unknown codec is passed. */
 +        }
 +    } else if (avctx->gop_size == 0) {
 +        ctx->encode_config.frameIntervalP = 0;
 +        ctx->encode_config.gopLength = 1;
 +        switch (avctx->codec->id) {
 +        case AV_CODEC_ID_H264:
 +            ctx->encode_config.encodeCodecConfig.h264Config.idrPeriod = 1;
 +            break;
 +        case AV_CODEC_ID_H265:
 +            ctx->encode_config.encodeCodecConfig.hevcConfig.idrPeriod = 1;
 +            break;
 +        /* Earlier switch/case will return if unknown codec is passed. */
 +        }
      }
  
 -    return 0;
 -}
 +    /* when there're b frames, set dts offset */
 +    if (ctx->encode_config.frameIntervalP >= 2)
 +        ctx->last_dts = -2;
  
 -#define EXTRADATA_SIZE 512
 +    if (avctx->bit_rate > 0)
 +        ctx->encode_config.rcParams.averageBitRate = avctx->bit_rate;
  
 -static int nvenc_setup_extradata(AVCodecContext *avctx)
 -{
 -    NVENCContext *ctx                     = avctx->priv_data;
 -    NV_ENCODE_API_FUNCTION_LIST *nv       = &ctx->nvel.nvenc_funcs;
 -    NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = { 0 };
 -    int ret;
 +    if (avctx->rc_max_rate > 0)
 +        ctx->encode_config.rcParams.maxBitRate = avctx->rc_max_rate;
 +
 +    if (lossless) {
 +      ctx->encode_config.encodeCodecConfig.h264Config.qpPrimeYZeroTransformBypassFlag = 1;
 +      ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
 +      ctx->encode_config.rcParams.constQP.qpInterB = 0;
 +      ctx->encode_config.rcParams.constQP.qpInterP = 0;
 +      ctx->encode_config.rcParams.constQP.qpIntra = 0;
 +
 +      avctx->qmin = -1;
 +      avctx->qmax = -1;
 +    } else if (ctx->cbr) {
 +        if (!ctx->twopass) {
 +            ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
 +        } else if (ctx->twopass == 1 || isLL) {
 +            ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_2_PASS_QUALITY;
 +
 +            if (avctx->codec->id == AV_CODEC_ID_H264) {
 +                ctx->encode_config.encodeCodecConfig.h264Config.adaptiveTransformMode = NV_ENC_H264_ADAPTIVE_TRANSFORM_ENABLE;
 +                ctx->encode_config.encodeCodecConfig.h264Config.fmoMode = NV_ENC_H264_FMO_DISABLE;
 +            }
 +
 +            if (!isLL)
 +                av_log(avctx, AV_LOG_WARNING, "Twopass mode is only known to work with low latency (ll, llhq, llhp) presets.\n");
 +        } else {
 +            ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
 +        }
 +    } else if (avctx->global_quality > 0) {
 +        ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
 +        ctx->encode_config.rcParams.constQP.qpInterB = avctx->global_quality;
 +        ctx->encode_config.rcParams.constQP.qpInterP = avctx->global_quality;
 +        ctx->encode_config.rcParams.constQP.qpIntra = avctx->global_quality;
  
 -    avctx->extradata = av_mallocz(EXTRADATA_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
 -    if (!avctx->extradata)
 -        return AVERROR(ENOMEM);
 +        avctx->qmin = -1;
 +        avctx->qmax = -1;
 +    } else if (avctx->qmin >= 0 && avctx->qmax >= 0) {
 +        ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_VBR;
  
 -    payload.version              = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER;
 -    payload.spsppsBuffer         = avctx->extradata;
 -    payload.inBufferSize         = EXTRADATA_SIZE;
 -    payload.outSPSPPSPayloadSize = &avctx->extradata_size;
 +        ctx->encode_config.rcParams.enableMinQP = 1;
 +        ctx->encode_config.rcParams.enableMaxQP = 1;
  
 -    ret = nv->nvEncGetSequenceParams(ctx->nvenc_ctx, &payload);
 -    if (ret != NV_ENC_SUCCESS) {
 -        av_log(avctx, AV_LOG_ERROR, "Cannot get the extradata\n");
 -        return AVERROR_UNKNOWN;
 +        ctx->encode_config.rcParams.minQP.qpInterB = avctx->qmin;
 +        ctx->encode_config.rcParams.minQP.qpInterP = avctx->qmin;
 +        ctx->encode_config.rcParams.minQP.qpIntra = avctx->qmin;
 +
 +        ctx->encode_config.rcParams.maxQP.qpInterB = avctx->qmax;
 +        ctx->encode_config.rcParams.maxQP.qpInterP = avctx->qmax;
 +        ctx->encode_config.rcParams.maxQP.qpIntra = avctx->qmax;
      }
  
 -    return 0;
 -}
 +    if (avctx->rc_buffer_size > 0)
 +        ctx->encode_config.rcParams.vbvBufferSize = avctx->rc_buffer_size;
  
 -av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
 -{
 -    NVENCContext *ctx               = avctx->priv_data;
 -    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
 -    int i;
 +    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
 +        ctx->encode_config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
 +    } else {
 +        ctx->encode_config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
 +    }
  
 -    if (ctx->in) {
 -        for (i = 0; i < ctx->nb_surfaces; ++i) {
 -            nv->nvEncDestroyInputBuffer(ctx->nvenc_ctx, ctx->in[i].in);
 -            nv->nvEncDestroyBitstreamBuffer(ctx->nvenc_ctx, ctx->out[i].out);
 +    switch (avctx->codec->id) {
 +    case AV_CODEC_ID_H264:
 +        ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.colourDescriptionPresentFlag = 1;
 +        ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.videoSignalTypePresentFlag = 1;
 +
 +        ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.colourMatrix = avctx->colorspace;
 +        ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.colourPrimaries = avctx->color_primaries;
 +        ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.transferCharacteristics = avctx->color_trc;
 +
 +        ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.videoFullRangeFlag = avctx->color_range == AVCOL_RANGE_JPEG;
 +
 +        ctx->encode_config.encodeCodecConfig.h264Config.disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
 +        ctx->encode_config.encodeCodecConfig.h264Config.repeatSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
 +
 +        if (!ctx->profile) {
 +            switch (avctx->profile) {
 +            case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
 +                break;
 +            case FF_PROFILE_H264_BASELINE:
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
 +                break;
 +            case FF_PROFILE_H264_MAIN:
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
 +                break;
 +            case FF_PROFILE_H264_HIGH:
 +            case FF_PROFILE_UNKNOWN:
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
 +                break;
 +            default:
 +                av_log(avctx, AV_LOG_WARNING, "Unsupported profile requested, falling back to high\n");
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
 +                break;
 +            }
 +        } else {
 +            if (!strcmp(ctx->profile, "high")) {
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
 +                avctx->profile = FF_PROFILE_H264_HIGH;
 +            } else if (!strcmp(ctx->profile, "main")) {
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
 +                avctx->profile = FF_PROFILE_H264_MAIN;
 +            } else if (!strcmp(ctx->profile, "baseline")) {
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
 +                avctx->profile = FF_PROFILE_H264_BASELINE;
 +            } else if (!strcmp(ctx->profile, "high444p")) {
 +                ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID;
 +                avctx->profile = FF_PROFILE_H264_HIGH_444_PREDICTIVE;
 +            } else {
 +                av_log(avctx, AV_LOG_FATAL, "Profile \"%s\" is unknown! Supported profiles: high, main, baseline\n", ctx->profile);
 +                res = AVERROR(EINVAL);
 +                goto error;
 +            }
          }
 -    }
  
 -    av_freep(&ctx->in);
 -    av_freep(&ctx->out);
 +        ctx->encode_config.encodeCodecConfig.h264Config.chromaFormatIDC = avctx->profile == FF_PROFILE_H264_HIGH_444_PREDICTIVE ? 3 : 1;
  
 -    if (ctx->nvenc_ctx)
 -        nv->nvEncDestroyEncoder(ctx->nvenc_ctx);
 +        if (ctx->level) {
 +            res = input_string_to_uint32(avctx, nvenc_h264_level_pairs, ctx->level, &ctx->encode_config.encodeCodecConfig.h264Config.level);
  
 -    if (ctx->cu_context)
 -        ctx->nvel.cu_ctx_destroy(ctx->cu_context);
 +            if (res) {
 +                av_log(avctx, AV_LOG_FATAL, "Level \"%s\" is unknown! Supported levels: auto, 1, 1b, 1.1, 1.2, 1.3, 2, 2.1, 2.2, 3, 3.1, 3.2, 4, 4.1, 4.2, 5, 5.1\n", ctx->level);
 +                goto error;
 +            }
 +        } else {
 +            ctx->encode_config.encodeCodecConfig.h264Config.level = NV_ENC_LEVEL_AUTOSELECT;
 +        }
  
 -    if (ctx->nvel.nvenc)
 -        dlclose(ctx->nvel.nvenc);
 +        break;
 +    case AV_CODEC_ID_H265:
 +        ctx->encode_config.encodeCodecConfig.hevcConfig.disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
 +        ctx->encode_config.encodeCodecConfig.hevcConfig.repeatSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
  
 -    if (ctx->nvel.cuda)
 -        dlclose(ctx->nvel.cuda);
 +        /* No other profile is supported in the current SDK version 5 */
 +        ctx->encode_config.profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
 +        avctx->profile = FF_PROFILE_HEVC_MAIN;
  
 -    return 0;
 -}
 +        if (ctx->level) {
 +            res = input_string_to_uint32(avctx, nvenc_hevc_level_pairs, ctx->level, &ctx->encode_config.encodeCodecConfig.hevcConfig.level);
  
 -av_cold int ff_nvenc_encode_init(AVCodecContext *avctx)
 -{
 -    int ret;
 +            if (res) {
 +                av_log(avctx, AV_LOG_FATAL, "Level \"%s\" is unknown! Supported levels: auto, 1, 2, 2.1, 3, 3.1, 4, 4.1, 5, 5.1, 5.2, 6, 6.1, 6.2\n", ctx->level);
 +                goto error;
 +            }
 +        } else {
 +            ctx->encode_config.encodeCodecConfig.hevcConfig.level = NV_ENC_LEVEL_AUTOSELECT;
 +        }
 +
 +        if (ctx->tier) {
 +            if (!strcmp(ctx->tier, "main")) {
 +                ctx->encode_config.encodeCodecConfig.hevcConfig.tier = NV_ENC_TIER_HEVC_MAIN;
 +            } else if (!strcmp(ctx->tier, "high")) {
 +                ctx->encode_config.encodeCodecConfig.hevcConfig.tier = NV_ENC_TIER_HEVC_HIGH;
 +            } else {
 +                av_log(avctx, AV_LOG_FATAL, "Tier \"%s\" is unknown! Supported tiers: main, high\n", ctx->tier);
 +                res = AVERROR(EINVAL);
 +                goto error;
 +            }
 +        }
 +
 +        break;
 +    /* Earlier switch/case will return if unknown codec is passed. */
 +    }
  
 -    if ((ret = nvenc_load_libraries(avctx)) < 0)
 -        return ret;
 +    nv_status = p_nvenc->nvEncInitializeEncoder(ctx->nvencoder, &ctx->init_encode_params);
 +    if (nv_status != NV_ENC_SUCCESS) {
 +        av_log(avctx, AV_LOG_FATAL, "InitializeEncoder failed: 0x%x\n", (int)nv_status);
 +        res = AVERROR_EXTERNAL;
 +        goto error;
 +    }
  
 -    if ((ret = nvenc_setup_device(avctx)) < 0)
 -        return ret;
 +    ctx->input_surfaces = av_malloc(ctx->max_surface_count * sizeof(*ctx->input_surfaces));
  
 -    if ((ret = nvenc_setup_encoder(avctx)) < 0)
 -        return ret;
 +    if (!ctx->input_surfaces) {
 +        res = AVERROR(ENOMEM);
 +        goto error;
 +    }
  
 -    if ((ret = nvenc_setup_surfaces(avctx)) < 0)
 -        return ret;
 +    ctx->output_surfaces = av_malloc(ctx->max_surface_count * sizeof(*ctx->output_surfaces));
  
 -    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
 -        if ((ret = nvenc_setup_extradata(avctx)) < 0)
 -            return ret;
 +    if (!ctx->output_surfaces) {
 +        res = AVERROR(ENOMEM);
 +        goto error;
      }
  
 -    return 0;
 -}
 +    for (surfaceCount = 0; surfaceCount < ctx->max_surface_count; ++surfaceCount) {
 +        NV_ENC_CREATE_INPUT_BUFFER allocSurf = { 0 };
 +        NV_ENC_CREATE_BITSTREAM_BUFFER allocOut = { 0 };
 +        allocSurf.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
 +        allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
  
 -static NVENCInputSurface *get_input_surface(NVENCContext *ctx)
 -{
 -    int i;
 +        allocSurf.width = (avctx->width + 31) & ~31;
 +        allocSurf.height = (avctx->height + 31) & ~31;
  
 -    for (i = 0; i < ctx->nb_surfaces; i++) {
 -        if (!ctx->in[i].locked) {
 -            ctx->in[i].locked = 1;
 -            return &ctx->in[i];
 -        }
 -    }
 +        allocSurf.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
  
 -    return NULL;
 -}
 +        switch (avctx->pix_fmt) {
 +        case AV_PIX_FMT_YUV420P:
 +            allocSurf.bufferFmt = NV_ENC_BUFFER_FORMAT_YV12_PL;
 +            break;
  
 -static NVENCOutputSurface *get_output_surface(NVENCContext *ctx)
 -{
 -    int i;
 +        case AV_PIX_FMT_NV12:
 +            allocSurf.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12_PL;
 +            break;
 +
 +        case AV_PIX_FMT_YUV444P:
 +            allocSurf.bufferFmt = NV_ENC_BUFFER_FORMAT_YUV444_PL;
 +            break;
  
 -    for (i = 0; i < ctx->nb_surfaces; i++) {
 -        if (!ctx->out[i].busy) {
 -            return &ctx->out[i];
 +        default:
 +            av_log(avctx, AV_LOG_FATAL, "Invalid input pixel format\n");
 +            res = AVERROR(EINVAL);
 +            goto error;
          }
 -    }
  
 -    return NULL;
 -}
 +        nv_status = p_nvenc->nvEncCreateInputBuffer(ctx->nvencoder, &allocSurf);
 +        if (nv_status != NV_ENC_SUCCESS) {
 +            av_log(avctx, AV_LOG_FATAL, "CreateInputBuffer failed\n");
 +            res = AVERROR_EXTERNAL;
 +            goto error;
 +        }
  
 -static int nvenc_copy_frame(NV_ENC_LOCK_INPUT_BUFFER *in, const AVFrame *frame)
 -{
 -    uint8_t *buf = in->bufferDataPtr;
 -    int off      = frame->height * in->pitch;
 +        ctx->input_surfaces[surfaceCount].lockCount = 0;
 +        ctx->input_surfaces[surfaceCount].input_surface = allocSurf.inputBuffer;
 +        ctx->input_surfaces[surfaceCount].format = allocSurf.bufferFmt;
 +        ctx->input_surfaces[surfaceCount].width = allocSurf.width;
 +        ctx->input_surfaces[surfaceCount].height = allocSurf.height;
  
 -    switch (frame->format) {
 -    case AV_PIX_FMT_YUV420P:
 -        av_image_copy_plane(buf, in->pitch,
 -                            frame->data[0], frame->linesize[0],
 -                            frame->width, frame->height);
 -        buf += off;
 +        /* 1MB is large enough to hold most output frames. NVENC increases this automaticaly if it's not enough. */
 +        allocOut.size = 1024 * 1024;
  
 -        av_image_copy_plane(buf, in->pitch >> 1,
 -                            frame->data[2], frame->linesize[2],
 -                            frame->width >> 1, frame->height >> 1);
 +        allocOut.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
  
 -        buf += off >> 2;
 +        nv_status = p_nvenc->nvEncCreateBitstreamBuffer(ctx->nvencoder, &allocOut);
 +        if (nv_status != NV_ENC_SUCCESS) {
 +            av_log(avctx, AV_LOG_FATAL, "CreateBitstreamBuffer failed\n");
 +            ctx->output_surfaces[surfaceCount++].output_surface = NULL;
 +            res = AVERROR_EXTERNAL;
 +            goto error;
 +        }
  
 -        av_image_copy_plane(buf, in->pitch >> 1,
 -                            frame->data[1], frame->linesize[1],
 -                            frame->width >> 1, frame->height >> 1);
 -        break;
 -    case AV_PIX_FMT_NV12:
 -        av_image_copy_plane(buf, in->pitch,
 -                            frame->data[0], frame->linesize[0],
 -                            frame->width, frame->height);
 -        buf += off;
 -
 -        av_image_copy_plane(buf, in->pitch,
 -                            frame->data[1], frame->linesize[1],
 -                            frame->width, frame->height >> 1);
 -        break;
 -    case AV_PIX_FMT_YUV444P:
 -        av_image_copy_plane(buf, in->pitch,
 -                            frame->data[0], frame->linesize[0],
 -                            frame->width, frame->height);
 -        buf += off;
 -
 -        av_image_copy_plane(buf, in->pitch,
 -                            frame->data[1], frame->linesize[1],
 -                            frame->width, frame->height);
 -        buf += off;
 -
 -        av_image_copy_plane(buf, in->pitch,
 -                            frame->data[2], frame->linesize[2],
 -                            frame->width, frame->height);
 -        break;
 -    default:
 -        return AVERROR_BUG;
 +        ctx->output_surfaces[surfaceCount].output_surface = allocOut.bitstreamBuffer;
 +        ctx->output_surfaces[surfaceCount].size = allocOut.size;
 +        ctx->output_surfaces[surfaceCount].busy = 0;
      }
  
 -    return 0;
 -}
 +    if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
 +        uint32_t outSize = 0;
 +        char tmpHeader[256];
 +        NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = { 0 };
 +        payload.version = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER;
 +
 +        payload.spsppsBuffer = tmpHeader;
 +        payload.inBufferSize = sizeof(tmpHeader);
 +        payload.outSPSPPSPayloadSize = &outSize;
 +
 +        nv_status = p_nvenc->nvEncGetSequenceParams(ctx->nvencoder, &payload);
 +        if (nv_status != NV_ENC_SUCCESS) {
 +            av_log(avctx, AV_LOG_FATAL, "GetSequenceParams failed\n");
 +            goto error;
 +        }
  
 -static int nvenc_enqueue_frame(AVCodecContext *avctx, const AVFrame *frame,
 -                               NVENCInputSurface **in_surf)
 -{
 -    NVENCContext *ctx               = avctx->priv_data;
 -    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
 -    NV_ENC_LOCK_INPUT_BUFFER params = { 0 };
 -    NVENCInputSurface *in           = get_input_surface(ctx);
 -    int ret;
 +        avctx->extradata_size = outSize;
 +        avctx->extradata = av_mallocz(outSize + FF_INPUT_BUFFER_PADDING_SIZE);
  
 -    if (!in)
 -        return AVERROR_BUG;
 +        if (!avctx->extradata) {
 +            res = AVERROR(ENOMEM);
 +            goto error;
 +        }
  
 -    params.version     = NV_ENC_LOCK_INPUT_BUFFER_VER;
 -    params.inputBuffer = in->in;
 +        memcpy(avctx->extradata, tmpHeader, outSize);
 +    }
  
 +    if (ctx->encode_config.frameIntervalP > 1)
 +        avctx->has_b_frames = 2;
  
 -    ret = nv->nvEncLockInputBuffer(ctx->nvenc_ctx, &params);
 -    if (ret != NV_ENC_SUCCESS) {
 -        av_log(avctx, AV_LOG_ERROR, "Cannot lock the buffer %p.\n",
 -               in);
 -        return AVERROR_UNKNOWN;
 -    }
 +    if (ctx->encode_config.rcParams.averageBitRate > 0)
 +        avctx->bit_rate = ctx->encode_config.rcParams.averageBitRate;
 +
 +    return 0;
  
 -    ret = nvenc_copy_frame(&params, frame);
 -    if (ret < 0)
 -        goto fail;
 +error:
  
 -    ret = nv->nvEncUnlockInputBuffer(ctx->nvenc_ctx, in->in);
 -    if (ret != NV_ENC_SUCCESS) {
 -        av_log(avctx, AV_LOG_ERROR, "Cannot unlock the buffer %p.\n",
 -               in);
 -        return AVERROR_UNKNOWN;
 +    for (i = 0; i < surfaceCount; ++i) {
 +        p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->input_surfaces[i].input_surface);
 +        if (ctx->output_surfaces[i].output_surface)
 +            p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->output_surfaces[i].output_surface);
      }
  
 -    *in_surf = in;
 +    if (ctx->nvencoder)
 +        p_nvenc->nvEncDestroyEncoder(ctx->nvencoder);
  
 -    return 0;
 +    if (ctx->cu_context)
 +        dl_fn->cu_ctx_destroy(ctx->cu_context);
  
-     av_frame_free(&avctx->coded_frame);
 -fail:
 -    nv->nvEncUnlockInputBuffer(ctx->nvenc_ctx, in->in);
 +    nvenc_unload_nvenc(avctx);
  
 -    return ret;
 +    ctx->nvencoder = NULL;
 +    ctx->cu_context = NULL;
 +
 +    return res;
  }
  
 -static void nvenc_codec_specific_pic_params(AVCodecContext *avctx,
 -                                            NV_ENC_PIC_PARAMS *params)
 +static av_cold int nvenc_encode_close(AVCodecContext *avctx)
  {
 -    NVENCContext *ctx = avctx->priv_data;
 +    NvencContext *ctx = avctx->priv_data;
 +    NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
 +    NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs;
 +    int i;
  
 -    switch (avctx->codec->id) {
 -    case AV_CODEC_ID_H264:
 -        params->codecPicParams.h264PicParams.sliceMode =
 -            ctx->config.encodeCodecConfig.h264Config.sliceMode;
 -        params->codecPicParams.h264PicParams.sliceModeData =
 -            ctx->config.encodeCodecConfig.h264Config.sliceModeData;
 -        break;
 -    case AV_CODEC_ID_HEVC:
 -        params->codecPicParams.hevcPicParams.sliceMode =
 -            ctx->config.encodeCodecConfig.hevcConfig.sliceMode;
 -        params->codecPicParams.hevcPicParams.sliceModeData =
 -            ctx->config.encodeCodecConfig.hevcConfig.sliceModeData;
 -        break;
 +    av_freep(&ctx->timestamp_list.data);
 +    av_freep(&ctx->output_surface_ready_queue.data);
 +    av_freep(&ctx->output_surface_queue.data);
 +
 +    for (i = 0; i < ctx->max_surface_count; ++i) {
 +        p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->input_surfaces[i].input_surface);
 +        p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->output_surfaces[i].output_surface);
      }
 -}
 +    ctx->max_surface_count = 0;
  
 -static inline int nvenc_enqueue_timestamp(AVFifoBuffer *f, int64_t pts)
 -{
 -    return av_fifo_generic_write(f, &pts, sizeof(pts), NULL);
 -}
 +    p_nvenc->nvEncDestroyEncoder(ctx->nvencoder);
 +    ctx->nvencoder = NULL;
  
 -static inline int nvenc_dequeue_timestamp(AVFifoBuffer *f, int64_t *pts)
 -{
 -    return av_fifo_generic_read(f, pts, sizeof(*pts), NULL);
 -}
 +    dl_fn->cu_ctx_destroy(ctx->cu_context);
 +    ctx->cu_context = NULL;
  
 -static inline int nvenc_enqueue_surface(AVFifoBuffer *f,
 -                                        NVENCOutputSurface *surf)
 -{
 -    surf->busy = 1;
 -    return av_fifo_generic_write(f, &surf, sizeof(surf), NULL);
 -}
 +    nvenc_unload_nvenc(avctx);
  
-     av_frame_free(&avctx->coded_frame);
 -static inline int nvenc_dequeue_surface(AVFifoBuffer *f,
 -                                        NVENCOutputSurface **surf)
 -{
 -    return av_fifo_generic_read(f, surf, sizeof(*surf), NULL);
 +    return 0;
  }
  
 -static int nvenc_set_timestamp(NVENCContext *ctx,
 -                               NV_ENC_LOCK_BITSTREAM *params,
 -                               AVPacket *pkt)
 +static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, AVFrame *coded_frame, NvencOutputSurface *tmpoutsurf)
  {
 -    pkt->pts      = params->outputTimeStamp;
 -    pkt->duration = params->outputDuration;
 -
 -    return nvenc_dequeue_timestamp(ctx->timestamps, &pkt->dts);
 -}
 +    NvencContext *ctx = avctx->priv_data;
 +    NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
 +    NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs;
  
 -static int nvenc_get_frame(AVCodecContext *avctx, AVPacket *pkt)
 -{
 -    NVENCContext *ctx               = avctx->priv_data;
 -    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
 -    NV_ENC_LOCK_BITSTREAM params    = { 0 };
 -    NVENCOutputSurface *out         = NULL;
 -    int ret;
 +    uint32_t slice_mode_data;
 +    uint32_t *slice_offsets;
 +    NV_ENC_LOCK_BITSTREAM lock_params = { 0 };
 +    NVENCSTATUS nv_status;
 +    int res = 0;
  
 -    ret = nvenc_dequeue_surface(ctx->pending, &out);
 -    if (ret)
 -        return ret;
 +    switch (avctx->codec->id) {
 +    case AV_CODEC_ID_H264:
 +      slice_mode_data = ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData;
 +      break;
 +    case AV_CODEC_ID_H265:
 +      slice_mode_data = ctx->encode_config.encodeCodecConfig.hevcConfig.sliceModeData;
 +      break;
 +    default:
 +      av_log(avctx, AV_LOG_ERROR, "nvenc: Unknown codec name\n");
 +      res = AVERROR(EINVAL);
 +      goto error;
 +    }
 +    slice_offsets = av_mallocz(slice_mode_data * sizeof(*slice_offsets));
  
 -    params.version         = NV_ENC_LOCK_BITSTREAM_VER;
 -    params.outputBitstream = out->out;
 +    if (!slice_offsets)
 +        return AVERROR(ENOMEM);
  
 -    ret = nv->nvEncLockBitstream(ctx->nvenc_ctx, &params);
 -    if (ret < 0)
 -        return AVERROR_UNKNOWN;
 +    lock_params.version = NV_ENC_LOCK_BITSTREAM_VER;
  
 -    ret = ff_alloc_packet(pkt, params.bitstreamSizeInBytes);
 -    if (ret < 0)
 -        return ret;
 +    lock_params.doNotWait = 0;
 +    lock_params.outputBitstream = tmpoutsurf->output_surface;
 +    lock_params.sliceOffsets = slice_offsets;
  
 -    memcpy(pkt->data, params.bitstreamBufferPtr, pkt->size);
 +    nv_status = p_nvenc->nvEncLockBitstream(ctx->nvencoder, &lock_params);
 +    if (nv_status != NV_ENC_SUCCESS) {
 +        av_log(avctx, AV_LOG_ERROR, "Failed locking bitstream buffer\n");
 +        res = AVERROR_EXTERNAL;
 +        goto error;
 +    }
  
 -    ret = nv->nvEncUnlockBitstream(ctx->nvenc_ctx, out->out);
 -    if (ret < 0)
 -        return AVERROR_UNKNOWN;
 +    if (res = ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes)) {
 +        p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
 +        goto error;
 +    }
  
 -    out->busy = out->in->locked = 0;
 +    memcpy(pkt->data, lock_params.bitstreamBufferPtr, lock_params.bitstreamSizeInBytes);
  
 -    ret = nvenc_set_timestamp(ctx, &params, pkt);
 -    if (ret < 0)
 -        return ret;
 +    nv_status = p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
 +    if (nv_status != NV_ENC_SUCCESS)
 +        av_log(avctx, AV_LOG_ERROR, "Failed unlocking bitstream buffer, expect the gates of mordor to open\n");
  
 -    switch (params.pictureType) {
 +    switch (lock_params.pictureType) {
      case NV_ENC_PIC_TYPE_IDR:
          pkt->flags |= AV_PKT_FLAG_KEY;
 -    case NV_ENC_PIC_TYPE_INTRA_REFRESH:
      case NV_ENC_PIC_TYPE_I:
          avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
          break;
@@@ -151,13 -121,9 +141,12 @@@ AVCodec ff_pam_encoder = 
      .type           = AVMEDIA_TYPE_VIDEO,
      .id             = AV_CODEC_ID_PAM,
      .init           = pam_encode_init,
-     .close          = pam_encode_close,
      .encode2        = pam_encode_frame,
      .pix_fmts       = (const enum AVPixelFormat[]){
 -        AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_GRAY8, AV_PIX_FMT_MONOWHITE,
 -        AV_PIX_FMT_NONE
 +        AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
 +        AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
 +        AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
 +        AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
 +        AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
      },
  };
Simple merge
@@@ -608,29 -454,7 +608,25 @@@ static int encode_apng(AVCodecContext *
  static av_cold int png_enc_init(AVCodecContext *avctx)
  {
      PNGEncContext *s = avctx->priv_data;
 +    int compression_level;
 +
 +    switch (avctx->pix_fmt) {
 +    case AV_PIX_FMT_RGBA:
 +        avctx->bits_per_coded_sample = 32;
 +        break;
 +    case AV_PIX_FMT_RGB24:
 +        avctx->bits_per_coded_sample = 24;
 +        break;
 +    case AV_PIX_FMT_GRAY8:
 +        avctx->bits_per_coded_sample = 0x28;
 +        break;
 +    case AV_PIX_FMT_MONOBLACK:
 +        avctx->bits_per_coded_sample = 1;
 +        break;
 +    case AV_PIX_FMT_PAL8:
 +        avctx->bits_per_coded_sample = 8;
 +    }
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
      avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
      avctx->coded_frame->key_frame = 1;
  
      if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK)
          s->filter_type = PNG_FILTER_VALUE_NONE;
  
-     av_frame_free(&avctx->coded_frame);
 +    if (s->dpi && s->dpm) {
 +      av_log(avctx, AV_LOG_ERROR, "Only one of 'dpi' or 'dpm' options should be set\n");
 +      return AVERROR(EINVAL);
 +    } else if (s->dpi) {
 +      s->dpm = s->dpi * 10000 / 254;
 +    }
 +
 +    s->is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
 +    switch (avctx->pix_fmt) {
 +    case AV_PIX_FMT_RGBA64BE:
 +        s->bit_depth = 16;
 +        s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 +        break;
 +    case AV_PIX_FMT_RGB48BE:
 +        s->bit_depth = 16;
 +        s->color_type = PNG_COLOR_TYPE_RGB;
 +        break;
 +    case AV_PIX_FMT_RGBA:
 +        s->bit_depth  = 8;
 +        s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 +        break;
 +    case AV_PIX_FMT_RGB24:
 +        s->bit_depth  = 8;
 +        s->color_type = PNG_COLOR_TYPE_RGB;
 +        break;
 +    case AV_PIX_FMT_GRAY16BE:
 +        s->bit_depth  = 16;
 +        s->color_type = PNG_COLOR_TYPE_GRAY;
 +        break;
 +    case AV_PIX_FMT_GRAY8:
 +        s->bit_depth  = 8;
 +        s->color_type = PNG_COLOR_TYPE_GRAY;
 +        break;
 +    case AV_PIX_FMT_GRAY8A:
 +        s->bit_depth = 8;
 +        s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
 +        break;
 +    case AV_PIX_FMT_YA16BE:
 +        s->bit_depth = 16;
 +        s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
 +        break;
 +    case AV_PIX_FMT_MONOBLACK:
 +        s->bit_depth  = 1;
 +        s->color_type = PNG_COLOR_TYPE_GRAY;
 +        break;
 +    case AV_PIX_FMT_PAL8:
 +        s->bit_depth  = 8;
 +        s->color_type = PNG_COLOR_TYPE_PALETTE;
 +        break;
 +    default:
 +        return -1;
 +    }
 +    s->bits_per_pixel = ff_png_get_nb_channels(s->color_type) * s->bit_depth;
 +
 +    s->zstream.zalloc = ff_png_zalloc;
 +    s->zstream.zfree  = ff_png_zfree;
 +    s->zstream.opaque = NULL;
 +    compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT
 +                      ? Z_DEFAULT_COMPRESSION
 +                      : av_clip(avctx->compression_level, 0, 9);
 +    if (deflateInit2(&s->zstream, compression_level, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY) != Z_OK)
 +        return -1;
 +
 +    return 0;
 +}
 +
 +static av_cold int png_enc_close(AVCodecContext *avctx)
 +{
 +    PNGEncContext *s = avctx->priv_data;
 +
 +    deflateEnd(&s->zstream);
      return 0;
  }
  
Simple merge
index 48eb44e,0000000..6070534
mode 100644,000000..100644
--- /dev/null
@@@ -1,637 -1,0 +1,633 @@@
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
 +/*
 + * Apple ProRes encoder
 + *
 + * Copyright (c) 2011 Anatoliy Wasserman
 + *
 + * 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
 + */
 +
 +/**
 + * @file
 + * Apple ProRes encoder (Anatoliy Wasserman version)
 + * Known FOURCCs: 'apch' (HQ), 'apcn' (SD), 'apcs' (LT), 'acpo' (Proxy)
 + */
 +
 +#include "avcodec.h"
 +#include "dct.h"
 +#include "internal.h"
 +#include "put_bits.h"
 +#include "bytestream.h"
 +#include "fdctdsp.h"
 +
 +#define DEFAULT_SLICE_MB_WIDTH 8
 +
 +#define FF_PROFILE_PRORES_PROXY     0
 +#define FF_PROFILE_PRORES_LT        1
 +#define FF_PROFILE_PRORES_STANDARD  2
 +#define FF_PROFILE_PRORES_HQ        3
 +
 +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_UNKNOWN }
 +};
 +
 +static const int qp_start_table[4] = { 4, 1, 1, 1 };
 +static const int qp_end_table[4]   = { 8, 9, 6, 6 };
 +static const int bitrate_table[5]  = { 1000, 2100, 3500, 5400 };
 +
 +static const uint8_t progressive_scan[64] = {
 +     0,  1,  8,  9,  2,  3, 10, 11,
 +    16, 17, 24, 25, 18, 19, 26, 27,
 +     4,  5, 12, 20, 13,  6,  7, 14,
 +    21, 28, 29, 22, 15, 23, 30, 31,
 +    32, 33, 40, 48, 41, 34, 35, 42,
 +    49, 56, 57, 50, 43, 36, 37, 44,
 +    51, 58, 59, 52, 45, 38, 39, 46,
 +    53, 60, 61, 54, 47, 55, 62, 63
 +};
 +
 +static const uint8_t QMAT_LUMA[4][64] = {
 +    {
 +         4,  7,  9, 11, 13, 14, 15, 63,
 +         7,  7, 11, 12, 14, 15, 63, 63,
 +         9, 11, 13, 14, 15, 63, 63, 63,
 +        11, 11, 13, 14, 63, 63, 63, 63,
 +        11, 13, 14, 63, 63, 63, 63, 63,
 +        13, 14, 63, 63, 63, 63, 63, 63,
 +        13, 63, 63, 63, 63, 63, 63, 63,
 +        63, 63, 63, 63, 63, 63, 63, 63
 +    }, {
 +         4,  5,  6,  7,  9, 11, 13, 15,
 +         5,  5,  7,  8, 11, 13, 15, 17,
 +         6,  7,  9, 11, 13, 15, 15, 17,
 +         7,  7,  9, 11, 13, 15, 17, 19,
 +         7,  9, 11, 13, 14, 16, 19, 23,
 +         9, 11, 13, 14, 16, 19, 23, 29,
 +         9, 11, 13, 15, 17, 21, 28, 35,
 +        11, 13, 16, 17, 21, 28, 35, 41
 +    }, {
 +         4,  4,  5,  5,  6,  7,  7,  9,
 +         4,  4,  5,  6,  7,  7,  9,  9,
 +         5,  5,  6,  7,  7,  9,  9, 10,
 +         5,  5,  6,  7,  7,  9,  9, 10,
 +         5,  6,  7,  7,  8,  9, 10, 12,
 +         6,  7,  7,  8,  9, 10, 12, 15,
 +         6,  7,  7,  9, 10, 11, 14, 17,
 +         7,  7,  9, 10, 11, 14, 17, 21
 +    }, {
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  5,
 +         4,  4,  4,  4,  4,  4,  5,  5,
 +         4,  4,  4,  4,  4,  5,  5,  6,
 +         4,  4,  4,  4,  5,  5,  6,  7,
 +         4,  4,  4,  4,  5,  6,  7,  7
 +    }
 +};
 +
 +static const uint8_t QMAT_CHROMA[4][64] = {
 +    {
 +         4,  7,  9, 11, 13, 14, 63, 63,
 +         7,  7, 11, 12, 14, 63, 63, 63,
 +         9, 11, 13, 14, 63, 63, 63, 63,
 +        11, 11, 13, 14, 63, 63, 63, 63,
 +        11, 13, 14, 63, 63, 63, 63, 63,
 +        13, 14, 63, 63, 63, 63, 63, 63,
 +        13, 63, 63, 63, 63, 63, 63, 63,
 +        63, 63, 63, 63, 63, 63, 63, 63
 +    }, {
 +         4,  5,  6,  7,  9, 11, 13, 15,
 +         5,  5,  7,  8, 11, 13, 15, 17,
 +         6,  7,  9, 11, 13, 15, 15, 17,
 +         7,  7,  9, 11, 13, 15, 17, 19,
 +         7,  9, 11, 13, 14, 16, 19, 23,
 +         9, 11, 13, 14, 16, 19, 23, 29,
 +         9, 11, 13, 15, 17, 21, 28, 35,
 +        11, 13, 16, 17, 21, 28, 35, 41
 +    }, {
 +         4,  4,  5,  5,  6,  7,  7,  9,
 +         4,  4,  5,  6,  7,  7,  9,  9,
 +         5,  5,  6,  7,  7,  9,  9, 10,
 +         5,  5,  6,  7,  7,  9,  9, 10,
 +         5,  6,  7,  7,  8,  9, 10, 12,
 +         6,  7,  7,  8,  9, 10, 12, 15,
 +         6,  7,  7,  9, 10, 11, 14, 17,
 +         7,  7,  9, 10, 11, 14, 17, 21
 +    }, {
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  5,
 +         4,  4,  4,  4,  4,  4,  5,  5,
 +         4,  4,  4,  4,  4,  5,  5,  6,
 +         4,  4,  4,  4,  5,  5,  6,  7,
 +         4,  4,  4,  4,  5,  6,  7,  7
 +    }
 +};
 +
 +
 +typedef struct {
 +    FDCTDSPContext fdsp;
 +    uint8_t* fill_y;
 +    uint8_t* fill_u;
 +    uint8_t* fill_v;
 +
 +    int qmat_luma[16][64];
 +    int qmat_chroma[16][64];
 +} ProresContext;
 +
 +static void encode_codeword(PutBitContext *pb, int val, int codebook)
 +{
 +    unsigned int rice_order, exp_order, switch_bits, first_exp, exp, zeros;
 +
 +    /* number of bits to switch between rice and exp golomb */
 +    switch_bits = codebook & 3;
 +    rice_order  = codebook >> 5;
 +    exp_order   = (codebook >> 2) & 7;
 +
 +    first_exp = ((switch_bits + 1) << rice_order);
 +
 +    if (val >= first_exp) { /* exp golomb */
 +        val -= first_exp;
 +        val += (1 << exp_order);
 +        exp = av_log2(val);
 +        zeros = exp - exp_order + switch_bits + 1;
 +        put_bits(pb, zeros, 0);
 +        put_bits(pb, exp + 1, val);
 +    } else if (rice_order) {
 +        put_bits(pb, (val >> rice_order), 0);
 +        put_bits(pb, 1, 1);
 +        put_sbits(pb, rice_order, val);
 +    } else {
 +        put_bits(pb, val, 0);
 +        put_bits(pb, 1, 1);
 +    }
 +}
 +
 +#define QSCALE(qmat,ind,val) ((val) / ((qmat)[ind]))
 +#define TO_GOLOMB(val) (((val) << 1) ^ ((val) >> 31))
 +#define DIFF_SIGN(val, sign) (((val) >> 31) ^ (sign))
 +#define IS_NEGATIVE(val) ((((val) >> 31) ^ -1) + 1)
 +#define TO_GOLOMB2(val,sign) ((val)==0 ? 0 : ((val) << 1) + (sign))
 +
 +static av_always_inline int get_level(int val)
 +{
 +    int sign = (val >> 31);
 +    return (val ^ sign) - sign;
 +}
 +
 +#define FIRST_DC_CB 0xB8
 +
 +static const uint8_t dc_codebook[7] = { 0x04, 0x28, 0x28, 0x4D, 0x4D, 0x70, 0x70};
 +
 +static void encode_dc_coeffs(PutBitContext *pb, int16_t *in,
 +        int blocks_per_slice, int *qmat)
 +{
 +    int prev_dc, code;
 +    int i, sign, idx;
 +    int new_dc, delta, diff_sign, new_code;
 +
 +    prev_dc = QSCALE(qmat, 0, in[0] - 16384);
 +    code = TO_GOLOMB(prev_dc);
 +    encode_codeword(pb, code, FIRST_DC_CB);
 +
 +    code = 5; sign = 0; idx = 64;
 +    for (i = 1; i < blocks_per_slice; i++, idx += 64) {
 +        new_dc    = QSCALE(qmat, 0, in[idx] - 16384);
 +        delta     = new_dc - prev_dc;
 +        diff_sign = DIFF_SIGN(delta, sign);
 +        new_code  = TO_GOLOMB2(get_level(delta), diff_sign);
 +
 +        encode_codeword(pb, new_code, dc_codebook[FFMIN(code, 6)]);
 +
 +        code      = new_code;
 +        sign      = delta >> 31;
 +        prev_dc   = new_dc;
 +    }
 +}
 +
 +static const uint8_t run_to_cb[16] = { 0x06, 0x06, 0x05, 0x05, 0x04, 0x29,
 +        0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x4C };
 +static const uint8_t lev_to_cb[10] = { 0x04, 0x0A, 0x05, 0x06, 0x04, 0x28,
 +        0x28, 0x28, 0x28, 0x4C };
 +
 +static void encode_ac_coeffs(AVCodecContext *avctx, PutBitContext *pb,
 +        int16_t *in, int blocks_per_slice, int *qmat)
 +{
 +    int prev_run = 4;
 +    int prev_level = 2;
 +
 +    int run = 0, level, code, i, j;
 +    for (i = 1; i < 64; i++) {
 +        int indp = progressive_scan[i];
 +        for (j = 0; j < blocks_per_slice; j++) {
 +            int val = QSCALE(qmat, indp, in[(j << 6) + indp]);
 +            if (val) {
 +                encode_codeword(pb, run, run_to_cb[FFMIN(prev_run, 15)]);
 +
 +                prev_run   = run;
 +                run        = 0;
 +                level      = get_level(val);
 +                code       = level - 1;
 +
 +                encode_codeword(pb, code, lev_to_cb[FFMIN(prev_level, 9)]);
 +
 +                prev_level = level;
 +
 +                put_bits(pb, 1, IS_NEGATIVE(val));
 +            } else {
 +                ++run;
 +            }
 +        }
 +    }
 +}
 +
 +static void get(uint8_t *pixels, int stride, int16_t* block)
 +{
 +    int i;
 +
 +    for (i = 0; i < 8; i++) {
 +        AV_WN64(block, AV_RN64(pixels));
 +        AV_WN64(block+4, AV_RN64(pixels+8));
 +        pixels += stride;
 +        block += 8;
 +    }
 +}
 +
 +static void fdct_get(FDCTDSPContext *fdsp, uint8_t *pixels, int stride, int16_t* block)
 +{
 +    get(pixels, stride, block);
 +    fdsp->fdct(block);
 +}
 +
 +static int encode_slice_plane(AVCodecContext *avctx, int mb_count,
 +        uint8_t *src, int src_stride, uint8_t *buf, unsigned buf_size,
 +        int *qmat, int chroma)
 +{
 +    ProresContext* ctx = avctx->priv_data;
 +    FDCTDSPContext *fdsp = &ctx->fdsp;
 +    LOCAL_ALIGNED(16, int16_t, blocks, [DEFAULT_SLICE_MB_WIDTH << 8]);
 +    int16_t *block;
 +    int i, blocks_per_slice;
 +    PutBitContext pb;
 +
 +    block = blocks;
 +    for (i = 0; i < mb_count; i++) {
 +        fdct_get(fdsp, src,                  src_stride, block + (0 << 6));
 +        fdct_get(fdsp, src + 8 * src_stride, src_stride, block + ((2 - chroma) << 6));
 +        if (!chroma) {
 +            fdct_get(fdsp, src + 16,                  src_stride, block + (1 << 6));
 +            fdct_get(fdsp, src + 16 + 8 * src_stride, src_stride, block + (3 << 6));
 +        }
 +
 +        block += (256 >> chroma);
 +        src   += (32  >> chroma);
 +    }
 +
 +    blocks_per_slice = mb_count << (2 - chroma);
 +    init_put_bits(&pb, buf, buf_size);
 +
 +    encode_dc_coeffs(&pb, blocks, blocks_per_slice, qmat);
 +    encode_ac_coeffs(avctx, &pb, blocks, blocks_per_slice, qmat);
 +
 +    flush_put_bits(&pb);
 +    return put_bits_ptr(&pb) - pb.buf;
 +}
 +
 +static av_always_inline unsigned encode_slice_data(AVCodecContext *avctx,
 +        uint8_t *dest_y, uint8_t *dest_u, uint8_t *dest_v, int luma_stride,
 +        int chroma_stride, unsigned mb_count, uint8_t *buf, unsigned data_size,
 +        unsigned* y_data_size, unsigned* u_data_size, unsigned* v_data_size,
 +        int qp)
 +{
 +    ProresContext* ctx = avctx->priv_data;
 +
 +    *y_data_size = encode_slice_plane(avctx, mb_count, dest_y, luma_stride,
 +            buf, data_size, ctx->qmat_luma[qp - 1], 0);
 +
 +    if (!(avctx->flags & CODEC_FLAG_GRAY)) {
 +        *u_data_size = encode_slice_plane(avctx, mb_count, dest_u,
 +                chroma_stride, buf + *y_data_size, data_size - *y_data_size,
 +                ctx->qmat_chroma[qp - 1], 1);
 +
 +        *v_data_size = encode_slice_plane(avctx, mb_count, dest_v,
 +                chroma_stride, buf + *y_data_size + *u_data_size,
 +                data_size - *y_data_size - *u_data_size,
 +                ctx->qmat_chroma[qp - 1], 1);
 +    }
 +
 +    return *y_data_size + *u_data_size + *v_data_size;
 +}
 +
 +static void subimage_with_fill(uint16_t *src, unsigned x, unsigned y,
 +        unsigned stride, unsigned width, unsigned height, uint16_t *dst,
 +        unsigned dst_width, unsigned dst_height)
 +{
 +
 +    int box_width = FFMIN(width - x, dst_width);
 +    int box_height = FFMIN(height - y, dst_height);
 +    int i, j, src_stride = stride >> 1;
 +    uint16_t last_pix, *last_line;
 +
 +    src += y * src_stride + x;
 +    for (i = 0; i < box_height; ++i) {
 +        for (j = 0; j < box_width; ++j) {
 +            dst[j] = src[j];
 +        }
 +        last_pix = dst[j - 1];
 +        for (; j < dst_width; j++)
 +            dst[j] = last_pix;
 +        src += src_stride;
 +        dst += dst_width;
 +    }
 +    last_line = dst - dst_width;
 +    for (; i < dst_height; i++) {
 +        for (j = 0; j < dst_width; ++j) {
 +            dst[j] = last_line[j];
 +        }
 +        dst += dst_width;
 +    }
 +}
 +
 +static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, int mb_x,
 +        int mb_y, unsigned mb_count, uint8_t *buf, unsigned data_size,
 +        int unsafe, int *qp)
 +{
 +    int luma_stride, chroma_stride;
 +    int hdr_size = 6, slice_size;
 +    uint8_t *dest_y, *dest_u, *dest_v;
 +    unsigned y_data_size = 0, u_data_size = 0, v_data_size = 0;
 +    ProresContext* ctx = avctx->priv_data;
 +    int tgt_bits   = (mb_count * bitrate_table[avctx->profile]) >> 2;
 +    int low_bytes  = (tgt_bits - (tgt_bits >> 3)) >> 3; // 12% bitrate fluctuation
 +    int high_bytes = (tgt_bits + (tgt_bits >> 3)) >> 3;
 +
 +    luma_stride   = pic->linesize[0];
 +    chroma_stride = pic->linesize[1];
 +
 +    dest_y = pic->data[0] + (mb_y << 4) * luma_stride   + (mb_x << 5);
 +    dest_u = pic->data[1] + (mb_y << 4) * chroma_stride + (mb_x << 4);
 +    dest_v = pic->data[2] + (mb_y << 4) * chroma_stride + (mb_x << 4);
 +
 +    if (unsafe) {
 +
 +        subimage_with_fill((uint16_t *) pic->data[0], mb_x << 4, mb_y << 4,
 +                luma_stride, avctx->width, avctx->height,
 +                (uint16_t *) ctx->fill_y, mb_count << 4, 16);
 +        subimage_with_fill((uint16_t *) pic->data[1], mb_x << 3, mb_y << 4,
 +                chroma_stride, avctx->width >> 1, avctx->height,
 +                (uint16_t *) ctx->fill_u, mb_count << 3, 16);
 +        subimage_with_fill((uint16_t *) pic->data[2], mb_x << 3, mb_y << 4,
 +                chroma_stride, avctx->width >> 1, avctx->height,
 +                (uint16_t *) ctx->fill_v, mb_count << 3, 16);
 +
 +        encode_slice_data(avctx, ctx->fill_y, ctx->fill_u, ctx->fill_v,
 +                mb_count << 5, mb_count << 4, mb_count, buf + hdr_size,
 +                data_size - hdr_size, &y_data_size, &u_data_size, &v_data_size,
 +                *qp);
 +    } else {
 +        slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v,
 +                luma_stride, chroma_stride, mb_count, buf + hdr_size,
 +                data_size - hdr_size, &y_data_size, &u_data_size, &v_data_size,
 +                *qp);
 +
 +        if (slice_size > high_bytes && *qp < qp_end_table[avctx->profile]) {
 +            do {
 +                *qp += 1;
 +                slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v,
 +                        luma_stride, chroma_stride, mb_count, buf + hdr_size,
 +                        data_size - hdr_size, &y_data_size, &u_data_size,
 +                        &v_data_size, *qp);
 +            } while (slice_size > high_bytes && *qp < qp_end_table[avctx->profile]);
 +        } else if (slice_size < low_bytes && *qp
 +                > qp_start_table[avctx->profile]) {
 +            do {
 +                *qp -= 1;
 +                slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v,
 +                        luma_stride, chroma_stride, mb_count, buf + hdr_size,
 +                        data_size - hdr_size, &y_data_size, &u_data_size,
 +                        &v_data_size, *qp);
 +            } while (slice_size < low_bytes && *qp > qp_start_table[avctx->profile]);
 +        }
 +    }
 +
 +    buf[0] = hdr_size << 3;
 +    buf[1] = *qp;
 +    AV_WB16(buf + 2, y_data_size);
 +    AV_WB16(buf + 4, u_data_size);
 +
 +    return hdr_size + y_data_size + u_data_size + v_data_size;
 +}
 +
 +static int prores_encode_picture(AVCodecContext *avctx, const AVFrame *pic,
 +        uint8_t *buf, const int buf_size)
 +{
 +    int mb_width = (avctx->width + 15) >> 4;
 +    int mb_height = (avctx->height + 15) >> 4;
 +    int hdr_size, sl_size, i;
 +    int mb_y, sl_data_size, qp;
 +    int unsafe_bot, unsafe_right;
 +    uint8_t *sl_data, *sl_data_sizes;
 +    int slice_per_line = 0, rem = mb_width;
 +
 +    for (i = av_log2(DEFAULT_SLICE_MB_WIDTH); i >= 0; --i) {
 +        slice_per_line += rem >> i;
 +        rem &= (1 << i) - 1;
 +    }
 +
 +    qp = qp_start_table[avctx->profile];
 +    hdr_size = 8; sl_data_size = buf_size - hdr_size;
 +    sl_data_sizes = buf + hdr_size;
 +    sl_data = sl_data_sizes + (slice_per_line * mb_height * 2);
 +    for (mb_y = 0; mb_y < mb_height; mb_y++) {
 +        int mb_x = 0;
 +        int slice_mb_count = DEFAULT_SLICE_MB_WIDTH;
 +        while (mb_x < mb_width) {
 +            while (mb_width - mb_x < slice_mb_count)
 +                slice_mb_count >>= 1;
 +
 +            unsafe_bot = (avctx->height & 0xf) && (mb_y == mb_height - 1);
 +            unsafe_right = (avctx->width & 0xf) && (mb_x + slice_mb_count == mb_width);
 +
 +            sl_size = encode_slice(avctx, pic, mb_x, mb_y, slice_mb_count,
 +                    sl_data, sl_data_size, unsafe_bot || unsafe_right, &qp);
 +
 +            bytestream_put_be16(&sl_data_sizes, sl_size);
 +            sl_data           += sl_size;
 +            sl_data_size      -= sl_size;
 +            mb_x              += slice_mb_count;
 +        }
 +    }
 +
 +    buf[0] = hdr_size << 3;
 +    AV_WB32(buf + 1, sl_data - buf);
 +    AV_WB16(buf + 5, slice_per_line * mb_height);
 +    buf[7] = av_log2(DEFAULT_SLICE_MB_WIDTH) << 4;
 +
 +    return sl_data - buf;
 +}
 +
 +static int prores_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                               const AVFrame *pict, int *got_packet)
 +{
 +    int header_size = 148;
 +    uint8_t *buf;
 +    int pic_size, ret;
 +    int frame_size = FFALIGN(avctx->width, 16) * FFALIGN(avctx->height, 16)*16 + 500 + FF_MIN_BUFFER_SIZE; //FIXME choose tighter limit
 +
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, frame_size + FF_MIN_BUFFER_SIZE)) < 0)
 +        return ret;
 +
 +    buf = pkt->data;
 +    pic_size = prores_encode_picture(avctx, pict, buf + header_size + 8,
 +            pkt->size - header_size - 8);
 +
 +    bytestream_put_be32(&buf, pic_size + 8 + header_size);
 +    bytestream_put_buffer(&buf, "icpf", 4);
 +
 +    bytestream_put_be16(&buf, header_size);
 +    bytestream_put_be16(&buf, 0);
 +    bytestream_put_buffer(&buf, "fmpg", 4);
 +    bytestream_put_be16(&buf, avctx->width);
 +    bytestream_put_be16(&buf, avctx->height);
 +    *buf++ = 0x83; // {10}(422){00}{00}(frame){11}
 +    *buf++ = 0;
 +    *buf++ = 2;
 +    *buf++ = 2;
 +    *buf++ = 6;
 +    *buf++ = 32;
 +    *buf++ = 0;
 +    *buf++ = 3;
 +
 +    bytestream_put_buffer(&buf, QMAT_LUMA[avctx->profile],   64);
 +    bytestream_put_buffer(&buf, QMAT_CHROMA[avctx->profile], 64);
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    pkt->size = pic_size + 8 + header_size;
 +    *got_packet = 1;
 +
 +    return 0;
 +}
 +
 +static void scale_mat(const uint8_t* src, int* dst, int scale)
 +{
 +    int i;
 +    for (i = 0; i < 64; i++)
 +        dst[i] = src[i] * scale;
 +}
 +
 +static av_cold int prores_encode_init(AVCodecContext *avctx)
 +{
 +    int i;
 +    ProresContext* ctx = avctx->priv_data;
 +
 +    if (avctx->pix_fmt != AV_PIX_FMT_YUV422P10) {
 +        av_log(avctx, AV_LOG_ERROR, "need YUV422P10\n");
 +        return AVERROR_PATCHWELCOME;
 +    }
 +    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);
 +    }
 +
 +    if ((avctx->height & 0xf) || (avctx->width & 0xf)) {
 +        ctx->fill_y = av_malloc(4 * (DEFAULT_SLICE_MB_WIDTH << 8));
 +        if (!ctx->fill_y)
 +            return AVERROR(ENOMEM);
 +        ctx->fill_u = ctx->fill_y + (DEFAULT_SLICE_MB_WIDTH << 9);
 +        ctx->fill_v = ctx->fill_u + (DEFAULT_SLICE_MB_WIDTH << 8);
 +    }
 +
 +    if (avctx->profile == FF_PROFILE_UNKNOWN) {
 +        avctx->profile = FF_PROFILE_PRORES_STANDARD;
 +        av_log(avctx, AV_LOG_INFO,
 +                "encoding with ProRes standard (apcn) profile\n");
 +
 +    } else if (avctx->profile < FF_PROFILE_PRORES_PROXY
 +            || avctx->profile > FF_PROFILE_PRORES_HQ) {
 +        av_log(
 +                avctx,
 +                AV_LOG_ERROR,
 +                "unknown profile %d, use [0 - apco, 1 - apcs, 2 - apcn (default), 3 - apch]\n",
 +                avctx->profile);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    ff_fdctdsp_init(&ctx->fdsp, avctx);
 +
 +    avctx->codec_tag = AV_RL32((const uint8_t*)profiles[avctx->profile].name);
 +
 +    for (i = 1; i <= 16; i++) {
 +        scale_mat(QMAT_LUMA[avctx->profile]  , ctx->qmat_luma[i - 1]  , i);
 +        scale_mat(QMAT_CHROMA[avctx->profile], ctx->qmat_chroma[i - 1], i);
 +    }
 +
-     av_frame_free(&avctx->coded_frame);
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +
 +    return 0;
 +}
 +
 +static av_cold int prores_encode_close(AVCodecContext *avctx)
 +{
 +    ProresContext* ctx = avctx->priv_data;
 +    av_freep(&ctx->fill_y);
 +
 +    return 0;
 +}
 +
 +AVCodec ff_prores_aw_encoder = {
 +    .name           = "prores_aw",
 +    .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_init,
 +    .close          = prores_encode_close,
 +    .encode2        = prores_encode_frame,
 +    .pix_fmts       = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE},
 +    .capabilities   = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
 +    .profiles       = profiles
 +};
 +
 +AVCodec ff_prores_encoder = {
 +    .name           = "prores",
 +    .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_init,
 +    .close          = prores_encode_close,
 +    .encode2        = prores_encode_frame,
 +    .pix_fmts       = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE},
 +    .capabilities   = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
 +    .profiles       = profiles
 +};
index 1abc496,0000000..46f932f
mode 100644,000000..100644
--- /dev/null
@@@ -1,1357 -1,0 +1,1352 @@@
-     av_frame_free(&avctx->coded_frame);
 +/*
 + * Apple ProRes encoder
 + *
 + * Copyright (c) 2012 Konstantin Shishkov
 + *
 + * This encoder appears to be based on Anatoliy Wassermans considering
 + * similarities in the bugs.
 + *
 + * 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 "libavutil/opt.h"
 +#include "libavutil/pixdesc.h"
 +#include "avcodec.h"
 +#include "fdctdsp.h"
 +#include "put_bits.h"
 +#include "bytestream.h"
 +#include "internal.h"
 +#include "proresdata.h"
 +
 +#define CFACTOR_Y422 2
 +#define CFACTOR_Y444 3
 +
 +#define MAX_MBS_PER_SLICE 8
 +
 +#define MAX_PLANES 4
 +
 +enum {
 +    PRORES_PROFILE_AUTO  = -1,
 +    PRORES_PROFILE_PROXY = 0,
 +    PRORES_PROFILE_LT,
 +    PRORES_PROFILE_STANDARD,
 +    PRORES_PROFILE_HQ,
 +    PRORES_PROFILE_4444,
 +};
 +
 +enum {
 +    QUANT_MAT_PROXY = 0,
 +    QUANT_MAT_LT,
 +    QUANT_MAT_STANDARD,
 +    QUANT_MAT_HQ,
 +    QUANT_MAT_DEFAULT,
 +};
 +
 +static const uint8_t prores_quant_matrices[][64] = {
 +    { // proxy
 +         4,  7,  9, 11, 13, 14, 15, 63,
 +         7,  7, 11, 12, 14, 15, 63, 63,
 +         9, 11, 13, 14, 15, 63, 63, 63,
 +        11, 11, 13, 14, 63, 63, 63, 63,
 +        11, 13, 14, 63, 63, 63, 63, 63,
 +        13, 14, 63, 63, 63, 63, 63, 63,
 +        13, 63, 63, 63, 63, 63, 63, 63,
 +        63, 63, 63, 63, 63, 63, 63, 63,
 +    },
 +    { // LT
 +         4,  5,  6,  7,  9, 11, 13, 15,
 +         5,  5,  7,  8, 11, 13, 15, 17,
 +         6,  7,  9, 11, 13, 15, 15, 17,
 +         7,  7,  9, 11, 13, 15, 17, 19,
 +         7,  9, 11, 13, 14, 16, 19, 23,
 +         9, 11, 13, 14, 16, 19, 23, 29,
 +         9, 11, 13, 15, 17, 21, 28, 35,
 +        11, 13, 16, 17, 21, 28, 35, 41,
 +    },
 +    { // standard
 +         4,  4,  5,  5,  6,  7,  7,  9,
 +         4,  4,  5,  6,  7,  7,  9,  9,
 +         5,  5,  6,  7,  7,  9,  9, 10,
 +         5,  5,  6,  7,  7,  9,  9, 10,
 +         5,  6,  7,  7,  8,  9, 10, 12,
 +         6,  7,  7,  8,  9, 10, 12, 15,
 +         6,  7,  7,  9, 10, 11, 14, 17,
 +         7,  7,  9, 10, 11, 14, 17, 21,
 +    },
 +    { // high quality
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  5,
 +         4,  4,  4,  4,  4,  4,  5,  5,
 +         4,  4,  4,  4,  4,  5,  5,  6,
 +         4,  4,  4,  4,  5,  5,  6,  7,
 +         4,  4,  4,  4,  5,  6,  7,  7,
 +    },
 +    { // codec default
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +         4,  4,  4,  4,  4,  4,  4,  4,
 +    },
 +};
 +
 +#define NUM_MB_LIMITS 4
 +static const int prores_mb_limits[NUM_MB_LIMITS] = {
 +    1620, // up to 720x576
 +    2700, // up to 960x720
 +    6075, // up to 1440x1080
 +    9216, // up to 2048x1152
 +};
 +
 +static const struct prores_profile {
 +    const char *full_name;
 +    uint32_t    tag;
 +    int         min_quant;
 +    int         max_quant;
 +    int         br_tab[NUM_MB_LIMITS];
 +    int         quant;
 +} prores_profile_info[5] = {
 +    {
 +        .full_name = "proxy",
 +        .tag       = MKTAG('a', 'p', 'c', 'o'),
 +        .min_quant = 4,
 +        .max_quant = 8,
 +        .br_tab    = { 300, 242, 220, 194 },
 +        .quant     = QUANT_MAT_PROXY,
 +    },
 +    {
 +        .full_name = "LT",
 +        .tag       = MKTAG('a', 'p', 'c', 's'),
 +        .min_quant = 1,
 +        .max_quant = 9,
 +        .br_tab    = { 720, 560, 490, 440 },
 +        .quant     = QUANT_MAT_LT,
 +    },
 +    {
 +        .full_name = "standard",
 +        .tag       = MKTAG('a', 'p', 'c', 'n'),
 +        .min_quant = 1,
 +        .max_quant = 6,
 +        .br_tab    = { 1050, 808, 710, 632 },
 +        .quant     = QUANT_MAT_STANDARD,
 +    },
 +    {
 +        .full_name = "high quality",
 +        .tag       = MKTAG('a', 'p', 'c', 'h'),
 +        .min_quant = 1,
 +        .max_quant = 6,
 +        .br_tab    = { 1566, 1216, 1070, 950 },
 +        .quant     = QUANT_MAT_HQ,
 +    },
 +    {
 +        .full_name = "4444",
 +        .tag       = MKTAG('a', 'p', '4', 'h'),
 +        .min_quant = 1,
 +        .max_quant = 6,
 +        .br_tab    = { 2350, 1828, 1600, 1425 },
 +        .quant     = QUANT_MAT_HQ,
 +    }
 +};
 +
 +#define TRELLIS_WIDTH 16
 +#define SCORE_LIMIT   INT_MAX / 2
 +
 +struct TrellisNode {
 +    int prev_node;
 +    int quant;
 +    int bits;
 +    int score;
 +};
 +
 +#define MAX_STORED_Q 16
 +
 +typedef struct ProresThreadData {
 +    DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
 +    DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16];
 +    int16_t custom_q[64];
 +    struct TrellisNode *nodes;
 +} ProresThreadData;
 +
 +typedef struct ProresContext {
 +    AVClass *class;
 +    DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
 +    DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
 +    int16_t quants[MAX_STORED_Q][64];
 +    int16_t custom_q[64];
 +    const uint8_t *quant_mat;
 +    const uint8_t *scantable;
 +
 +    void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src,
 +                 int linesize, int16_t *block);
 +    FDCTDSPContext fdsp;
 +
 +    const AVFrame *pic;
 +    int mb_width, mb_height;
 +    int mbs_per_slice;
 +    int num_chroma_blocks, chroma_factor;
 +    int slices_width;
 +    int slices_per_picture;
 +    int pictures_per_frame; // 1 for progressive, 2 for interlaced
 +    int cur_picture_idx;
 +    int num_planes;
 +    int bits_per_mb;
 +    int force_quant;
 +    int alpha_bits;
 +    int warn;
 +
 +    char *vendor;
 +    int quant_sel;
 +
 +    int frame_size_upper_bound;
 +
 +    int profile;
 +    const struct prores_profile *profile_info;
 +
 +    int *slice_q;
 +
 +    ProresThreadData *tdata;
 +} ProresContext;
 +
 +static void get_slice_data(ProresContext *ctx, const uint16_t *src,
 +                           int linesize, int x, int y, int w, int h,
 +                           int16_t *blocks, uint16_t *emu_buf,
 +                           int mbs_per_slice, int blocks_per_mb, int is_chroma)
 +{
 +    const uint16_t *esrc;
 +    const int mb_width = 4 * blocks_per_mb;
 +    int elinesize;
 +    int i, j, k;
 +
 +    for (i = 0; i < mbs_per_slice; i++, src += mb_width) {
 +        if (x >= w) {
 +            memset(blocks, 0, 64 * (mbs_per_slice - i) * blocks_per_mb
 +                              * sizeof(*blocks));
 +            return;
 +        }
 +        if (x + mb_width <= w && y + 16 <= h) {
 +            esrc      = src;
 +            elinesize = linesize;
 +        } else {
 +            int bw, bh, pix;
 +
 +            esrc      = emu_buf;
 +            elinesize = 16 * sizeof(*emu_buf);
 +
 +            bw = FFMIN(w - x, mb_width);
 +            bh = FFMIN(h - y, 16);
 +
 +            for (j = 0; j < bh; j++) {
 +                memcpy(emu_buf + j * 16,
 +                       (const uint8_t*)src + j * linesize,
 +                       bw * sizeof(*src));
 +                pix = emu_buf[j * 16 + bw - 1];
 +                for (k = bw; k < mb_width; k++)
 +                    emu_buf[j * 16 + k] = pix;
 +            }
 +            for (; j < 16; j++)
 +                memcpy(emu_buf + j * 16,
 +                       emu_buf + (bh - 1) * 16,
 +                       mb_width * sizeof(*emu_buf));
 +        }
 +        if (!is_chroma) {
 +            ctx->fdct(&ctx->fdsp, esrc, elinesize, blocks);
 +            blocks += 64;
 +            if (blocks_per_mb > 2) {
 +                ctx->fdct(&ctx->fdsp, esrc + 8, elinesize, blocks);
 +                blocks += 64;
 +            }
 +            ctx->fdct(&ctx->fdsp, esrc + elinesize * 4, elinesize, blocks);
 +            blocks += 64;
 +            if (blocks_per_mb > 2) {
 +                ctx->fdct(&ctx->fdsp, esrc + elinesize * 4 + 8, elinesize, blocks);
 +                blocks += 64;
 +            }
 +        } else {
 +            ctx->fdct(&ctx->fdsp, esrc, elinesize, blocks);
 +            blocks += 64;
 +            ctx->fdct(&ctx->fdsp, esrc + elinesize * 4, elinesize, blocks);
 +            blocks += 64;
 +            if (blocks_per_mb > 2) {
 +                ctx->fdct(&ctx->fdsp, esrc + 8, elinesize, blocks);
 +                blocks += 64;
 +                ctx->fdct(&ctx->fdsp, esrc + elinesize * 4 + 8, elinesize, blocks);
 +                blocks += 64;
 +            }
 +        }
 +
 +        x += mb_width;
 +    }
 +}
 +
 +static void get_alpha_data(ProresContext *ctx, const uint16_t *src,
 +                           int linesize, int x, int y, int w, int h,
 +                           int16_t *blocks, int mbs_per_slice, int abits)
 +{
 +    const int slice_width = 16 * mbs_per_slice;
 +    int i, j, copy_w, copy_h;
 +
 +    copy_w = FFMIN(w - x, slice_width);
 +    copy_h = FFMIN(h - y, 16);
 +    for (i = 0; i < copy_h; i++) {
 +        memcpy(blocks, src, copy_w * sizeof(*src));
 +        if (abits == 8)
 +            for (j = 0; j < copy_w; j++)
 +                blocks[j] >>= 2;
 +        else
 +            for (j = 0; j < copy_w; j++)
 +                blocks[j] = (blocks[j] << 6) | (blocks[j] >> 4);
 +        for (j = copy_w; j < slice_width; j++)
 +            blocks[j] = blocks[copy_w - 1];
 +        blocks += slice_width;
 +        src    += linesize >> 1;
 +    }
 +    for (; i < 16; i++) {
 +        memcpy(blocks, blocks - slice_width, slice_width * sizeof(*blocks));
 +        blocks += slice_width;
 +    }
 +}
 +
 +/**
 + * Write an unsigned rice/exp golomb codeword.
 + */
 +static inline void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
 +{
 +    unsigned int rice_order, exp_order, switch_bits, switch_val;
 +    int exponent;
 +
 +    /* number of prefix bits to switch between Rice and expGolomb */
 +    switch_bits = (codebook & 3) + 1;
 +    rice_order  =  codebook >> 5;       /* rice code order */
 +    exp_order   = (codebook >> 2) & 7;  /* exp golomb code order */
 +
 +    switch_val  = switch_bits << rice_order;
 +
 +    if (val >= switch_val) {
 +        val -= switch_val - (1 << exp_order);
 +        exponent = av_log2(val);
 +
 +        put_bits(pb, exponent - exp_order + switch_bits, 0);
 +        put_bits(pb, exponent + 1, val);
 +    } else {
 +        exponent = val >> rice_order;
 +
 +        if (exponent)
 +            put_bits(pb, exponent, 0);
 +        put_bits(pb, 1, 1);
 +        if (rice_order)
 +            put_sbits(pb, rice_order, val);
 +    }
 +}
 +
 +#define GET_SIGN(x)  ((x) >> 31)
 +#define MAKE_CODE(x) (((x) << 1) ^ GET_SIGN(x))
 +
 +static void encode_dcs(PutBitContext *pb, int16_t *blocks,
 +                       int blocks_per_slice, int scale)
 +{
 +    int i;
 +    int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
 +
 +    prev_dc = (blocks[0] - 0x4000) / scale;
 +    encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
 +    sign     = 0;
 +    codebook = 3;
 +    blocks  += 64;
 +
 +    for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
 +        dc       = (blocks[0] - 0x4000) / scale;
 +        delta    = dc - prev_dc;
 +        new_sign = GET_SIGN(delta);
 +        delta    = (delta ^ sign) - sign;
 +        code     = MAKE_CODE(delta);
 +        encode_vlc_codeword(pb, ff_prores_dc_codebook[codebook], code);
 +        codebook = (code + (code & 1)) >> 1;
 +        codebook = FFMIN(codebook, 3);
 +        sign     = new_sign;
 +        prev_dc  = dc;
 +    }
 +}
 +
 +static void encode_acs(PutBitContext *pb, int16_t *blocks,
 +                       int blocks_per_slice,
 +                       int plane_size_factor,
 +                       const uint8_t *scan, const int16_t *qmat)
 +{
 +    int idx, i;
 +    int run, level, run_cb, lev_cb;
 +    int max_coeffs, abs_level;
 +
 +    max_coeffs = blocks_per_slice << 6;
 +    run_cb     = ff_prores_run_to_cb_index[4];
 +    lev_cb     = ff_prores_lev_to_cb_index[2];
 +    run        = 0;
 +
 +    for (i = 1; i < 64; i++) {
 +        for (idx = scan[i]; idx < max_coeffs; idx += 64) {
 +            level = blocks[idx] / qmat[scan[i]];
 +            if (level) {
 +                abs_level = FFABS(level);
 +                encode_vlc_codeword(pb, ff_prores_ac_codebook[run_cb], run);
 +                encode_vlc_codeword(pb, ff_prores_ac_codebook[lev_cb],
 +                                    abs_level - 1);
 +                put_sbits(pb, 1, GET_SIGN(level));
 +
 +                run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
 +                lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
 +                run    = 0;
 +            } else {
 +                run++;
 +            }
 +        }
 +    }
 +}
 +
 +static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
 +                              const uint16_t *src, int linesize,
 +                              int mbs_per_slice, int16_t *blocks,
 +                              int blocks_per_mb, int plane_size_factor,
 +                              const int16_t *qmat)
 +{
 +    int blocks_per_slice, saved_pos;
 +
 +    saved_pos = put_bits_count(pb);
 +    blocks_per_slice = mbs_per_slice * blocks_per_mb;
 +
 +    encode_dcs(pb, blocks, blocks_per_slice, qmat[0]);
 +    encode_acs(pb, blocks, blocks_per_slice, plane_size_factor,
 +               ctx->scantable, qmat);
 +    flush_put_bits(pb);
 +
 +    return (put_bits_count(pb) - saved_pos) >> 3;
 +}
 +
 +static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits)
 +{
 +    const int dbits = (abits == 8) ? 4 : 7;
 +    const int dsize = 1 << dbits - 1;
 +    int diff = cur - prev;
 +
 +    diff = av_mod_uintp2(diff, abits);
 +    if (diff >= (1 << abits) - dsize)
 +        diff -= 1 << abits;
 +    if (diff < -dsize || diff > dsize || !diff) {
 +        put_bits(pb, 1, 1);
 +        put_bits(pb, abits, diff);
 +    } else {
 +        put_bits(pb, 1, 0);
 +        put_bits(pb, dbits - 1, FFABS(diff) - 1);
 +        put_bits(pb, 1, diff < 0);
 +    }
 +}
 +
 +static void put_alpha_run(PutBitContext *pb, int run)
 +{
 +    if (run) {
 +        put_bits(pb, 1, 0);
 +        if (run < 0x10)
 +            put_bits(pb, 4, run);
 +        else
 +            put_bits(pb, 15, run);
 +    } else {
 +        put_bits(pb, 1, 1);
 +    }
 +}
 +
 +// todo alpha quantisation for high quants
 +static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
 +                              int mbs_per_slice, uint16_t *blocks,
 +                              int quant)
 +{
 +    const int abits = ctx->alpha_bits;
 +    const int mask  = (1 << abits) - 1;
 +    const int num_coeffs = mbs_per_slice * 256;
 +    int saved_pos = put_bits_count(pb);
 +    int prev = mask, cur;
 +    int idx = 0;
 +    int run = 0;
 +
 +    cur = blocks[idx++];
 +    put_alpha_diff(pb, cur, prev, abits);
 +    prev = cur;
 +    do {
 +        cur = blocks[idx++];
 +        if (cur != prev) {
 +            put_alpha_run (pb, run);
 +            put_alpha_diff(pb, cur, prev, abits);
 +            prev = cur;
 +            run  = 0;
 +        } else {
 +            run++;
 +        }
 +    } while (idx < num_coeffs);
 +    if (run)
 +        put_alpha_run(pb, run);
 +    flush_put_bits(pb);
 +    return (put_bits_count(pb) - saved_pos) >> 3;
 +}
 +
 +static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
 +                        PutBitContext *pb,
 +                        int sizes[4], int x, int y, int quant,
 +                        int mbs_per_slice)
 +{
 +    ProresContext *ctx = avctx->priv_data;
 +    int i, xp, yp;
 +    int total_size = 0;
 +    const uint16_t *src;
 +    int slice_width_factor = av_log2(mbs_per_slice);
 +    int num_cblocks, pwidth, linesize, line_add;
 +    int plane_factor, is_chroma;
 +    uint16_t *qmat;
 +
 +    if (ctx->pictures_per_frame == 1)
 +        line_add = 0;
 +    else
 +        line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
 +
 +    if (ctx->force_quant) {
 +        qmat = ctx->quants[0];
 +    } else if (quant < MAX_STORED_Q) {
 +        qmat = ctx->quants[quant];
 +    } else {
 +        qmat = ctx->custom_q;
 +        for (i = 0; i < 64; i++)
 +            qmat[i] = ctx->quant_mat[i] * quant;
 +    }
 +
 +    for (i = 0; i < ctx->num_planes; i++) {
 +        is_chroma    = (i == 1 || i == 2);
 +        plane_factor = slice_width_factor + 2;
 +        if (is_chroma)
 +            plane_factor += ctx->chroma_factor - 3;
 +        if (!is_chroma || ctx->chroma_factor == CFACTOR_Y444) {
 +            xp          = x << 4;
 +            yp          = y << 4;
 +            num_cblocks = 4;
 +            pwidth      = avctx->width;
 +        } else {
 +            xp          = x << 3;
 +            yp          = y << 4;
 +            num_cblocks = 2;
 +            pwidth      = avctx->width >> 1;
 +        }
 +
 +        linesize = pic->linesize[i] * ctx->pictures_per_frame;
 +        src = (const uint16_t*)(pic->data[i] + yp * linesize +
 +                                line_add * pic->linesize[i]) + xp;
 +
 +        if (i < 3) {
 +            get_slice_data(ctx, src, linesize, xp, yp,
 +                           pwidth, avctx->height / ctx->pictures_per_frame,
 +                           ctx->blocks[0], ctx->emu_buf,
 +                           mbs_per_slice, num_cblocks, is_chroma);
 +            sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
 +                                          mbs_per_slice, ctx->blocks[0],
 +                                          num_cblocks, plane_factor,
 +                                          qmat);
 +        } else {
 +            get_alpha_data(ctx, src, linesize, xp, yp,
 +                           pwidth, avctx->height / ctx->pictures_per_frame,
 +                           ctx->blocks[0], mbs_per_slice, ctx->alpha_bits);
 +            sizes[i] = encode_alpha_plane(ctx, pb, mbs_per_slice,
 +                                          ctx->blocks[0], quant);
 +        }
 +        total_size += sizes[i];
 +        if (put_bits_left(pb) < 0) {
 +            av_log(avctx, AV_LOG_ERROR,
 +                   "Underestimated required buffer size.\n");
 +            return AVERROR_BUG;
 +        }
 +    }
 +    return total_size;
 +}
 +
 +static inline int estimate_vlc(unsigned codebook, int val)
 +{
 +    unsigned int rice_order, exp_order, switch_bits, switch_val;
 +    int exponent;
 +
 +    /* number of prefix bits to switch between Rice and expGolomb */
 +    switch_bits = (codebook & 3) + 1;
 +    rice_order  =  codebook >> 5;       /* rice code order */
 +    exp_order   = (codebook >> 2) & 7;  /* exp golomb code order */
 +
 +    switch_val  = switch_bits << rice_order;
 +
 +    if (val >= switch_val) {
 +        val -= switch_val - (1 << exp_order);
 +        exponent = av_log2(val);
 +
 +        return exponent * 2 - exp_order + switch_bits + 1;
 +    } else {
 +        return (val >> rice_order) + rice_order + 1;
 +    }
 +}
 +
 +static int estimate_dcs(int *error, int16_t *blocks, int blocks_per_slice,
 +                        int scale)
 +{
 +    int i;
 +    int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
 +    int bits;
 +
 +    prev_dc  = (blocks[0] - 0x4000) / scale;
 +    bits     = estimate_vlc(FIRST_DC_CB, MAKE_CODE(prev_dc));
 +    sign     = 0;
 +    codebook = 3;
 +    blocks  += 64;
 +    *error  += FFABS(blocks[0] - 0x4000) % scale;
 +
 +    for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
 +        dc       = (blocks[0] - 0x4000) / scale;
 +        *error  += FFABS(blocks[0] - 0x4000) % scale;
 +        delta    = dc - prev_dc;
 +        new_sign = GET_SIGN(delta);
 +        delta    = (delta ^ sign) - sign;
 +        code     = MAKE_CODE(delta);
 +        bits    += estimate_vlc(ff_prores_dc_codebook[codebook], code);
 +        codebook = (code + (code & 1)) >> 1;
 +        codebook = FFMIN(codebook, 3);
 +        sign     = new_sign;
 +        prev_dc  = dc;
 +    }
 +
 +    return bits;
 +}
 +
 +static int estimate_acs(int *error, int16_t *blocks, int blocks_per_slice,
 +                        int plane_size_factor,
 +                        const uint8_t *scan, const int16_t *qmat)
 +{
 +    int idx, i;
 +    int run, level, run_cb, lev_cb;
 +    int max_coeffs, abs_level;
 +    int bits = 0;
 +
 +    max_coeffs = blocks_per_slice << 6;
 +    run_cb     = ff_prores_run_to_cb_index[4];
 +    lev_cb     = ff_prores_lev_to_cb_index[2];
 +    run        = 0;
 +
 +    for (i = 1; i < 64; i++) {
 +        for (idx = scan[i]; idx < max_coeffs; idx += 64) {
 +            level   = blocks[idx] / qmat[scan[i]];
 +            *error += FFABS(blocks[idx]) % qmat[scan[i]];
 +            if (level) {
 +                abs_level = FFABS(level);
 +                bits += estimate_vlc(ff_prores_ac_codebook[run_cb], run);
 +                bits += estimate_vlc(ff_prores_ac_codebook[lev_cb],
 +                                     abs_level - 1) + 1;
 +
 +                run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
 +                lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
 +                run    = 0;
 +            } else {
 +                run++;
 +            }
 +        }
 +    }
 +
 +    return bits;
 +}
 +
 +static int estimate_slice_plane(ProresContext *ctx, int *error, int plane,
 +                                const uint16_t *src, int linesize,
 +                                int mbs_per_slice,
 +                                int blocks_per_mb, int plane_size_factor,
 +                                const int16_t *qmat, ProresThreadData *td)
 +{
 +    int blocks_per_slice;
 +    int bits;
 +
 +    blocks_per_slice = mbs_per_slice * blocks_per_mb;
 +
 +    bits  = estimate_dcs(error, td->blocks[plane], blocks_per_slice, qmat[0]);
 +    bits += estimate_acs(error, td->blocks[plane], blocks_per_slice,
 +                         plane_size_factor, ctx->scantable, qmat);
 +
 +    return FFALIGN(bits, 8);
 +}
 +
 +static int est_alpha_diff(int cur, int prev, int abits)
 +{
 +    const int dbits = (abits == 8) ? 4 : 7;
 +    const int dsize = 1 << dbits - 1;
 +    int diff = cur - prev;
 +
 +    diff = av_mod_uintp2(diff, abits);
 +    if (diff >= (1 << abits) - dsize)
 +        diff -= 1 << abits;
 +    if (diff < -dsize || diff > dsize || !diff)
 +        return abits + 1;
 +    else
 +        return dbits + 1;
 +}
 +
 +static int estimate_alpha_plane(ProresContext *ctx, int *error,
 +                                const uint16_t *src, int linesize,
 +                                int mbs_per_slice, int quant,
 +                                int16_t *blocks)
 +{
 +    const int abits = ctx->alpha_bits;
 +    const int mask  = (1 << abits) - 1;
 +    const int num_coeffs = mbs_per_slice * 256;
 +    int prev = mask, cur;
 +    int idx = 0;
 +    int run = 0;
 +    int bits;
 +
 +    *error = 0;
 +    cur = blocks[idx++];
 +    bits = est_alpha_diff(cur, prev, abits);
 +    prev = cur;
 +    do {
 +        cur = blocks[idx++];
 +        if (cur != prev) {
 +            if (!run)
 +                bits++;
 +            else if (run < 0x10)
 +                bits += 4;
 +            else
 +                bits += 15;
 +            bits += est_alpha_diff(cur, prev, abits);
 +            prev = cur;
 +            run  = 0;
 +        } else {
 +            run++;
 +        }
 +    } while (idx < num_coeffs);
 +
 +    if (run) {
 +        if (run < 0x10)
 +            bits += 4;
 +        else
 +            bits += 15;
 +    }
 +
 +    return bits;
 +}
 +
 +static int find_slice_quant(AVCodecContext *avctx,
 +                            int trellis_node, int x, int y, int mbs_per_slice,
 +                            ProresThreadData *td)
 +{
 +    ProresContext *ctx = avctx->priv_data;
 +    int i, q, pq, xp, yp;
 +    const uint16_t *src;
 +    int slice_width_factor = av_log2(mbs_per_slice);
 +    int num_cblocks[MAX_PLANES], pwidth;
 +    int plane_factor[MAX_PLANES], is_chroma[MAX_PLANES];
 +    const int min_quant = ctx->profile_info->min_quant;
 +    const int max_quant = ctx->profile_info->max_quant;
 +    int error, bits, bits_limit;
 +    int mbs, prev, cur, new_score;
 +    int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
 +    int overquant;
 +    uint16_t *qmat;
 +    int linesize[4], line_add;
 +
 +    if (ctx->pictures_per_frame == 1)
 +        line_add = 0;
 +    else
 +        line_add = ctx->cur_picture_idx ^ !ctx->pic->top_field_first;
 +    mbs = x + mbs_per_slice;
 +
 +    for (i = 0; i < ctx->num_planes; i++) {
 +        is_chroma[i]    = (i == 1 || i == 2);
 +        plane_factor[i] = slice_width_factor + 2;
 +        if (is_chroma[i])
 +            plane_factor[i] += ctx->chroma_factor - 3;
 +        if (!is_chroma[i] || ctx->chroma_factor == CFACTOR_Y444) {
 +            xp             = x << 4;
 +            yp             = y << 4;
 +            num_cblocks[i] = 4;
 +            pwidth         = avctx->width;
 +        } else {
 +            xp             = x << 3;
 +            yp             = y << 4;
 +            num_cblocks[i] = 2;
 +            pwidth         = avctx->width >> 1;
 +        }
 +
 +        linesize[i] = ctx->pic->linesize[i] * ctx->pictures_per_frame;
 +        src = (const uint16_t *)(ctx->pic->data[i] + yp * linesize[i] +
 +                                 line_add * ctx->pic->linesize[i]) + xp;
 +
 +        if (i < 3) {
 +            get_slice_data(ctx, src, linesize[i], xp, yp,
 +                           pwidth, avctx->height / ctx->pictures_per_frame,
 +                           td->blocks[i], td->emu_buf,
 +                           mbs_per_slice, num_cblocks[i], is_chroma[i]);
 +        } else {
 +            get_alpha_data(ctx, src, linesize[i], xp, yp,
 +                           pwidth, avctx->height / ctx->pictures_per_frame,
 +                           td->blocks[i], mbs_per_slice, ctx->alpha_bits);
 +        }
 +    }
 +
 +    for (q = min_quant; q < max_quant + 2; q++) {
 +        td->nodes[trellis_node + q].prev_node = -1;
 +        td->nodes[trellis_node + q].quant     = q;
 +    }
 +
 +    // todo: maybe perform coarser quantising to fit into frame size when needed
 +    for (q = min_quant; q <= max_quant; q++) {
 +        bits  = 0;
 +        error = 0;
 +        for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
 +            bits += estimate_slice_plane(ctx, &error, i,
 +                                         src, linesize[i],
 +                                         mbs_per_slice,
 +                                         num_cblocks[i], plane_factor[i],
 +                                         ctx->quants[q], td);
 +        }
 +        if (ctx->alpha_bits)
 +            bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
 +                                         mbs_per_slice, q, td->blocks[3]);
 +        if (bits > 65000 * 8)
 +            error = SCORE_LIMIT;
 +
 +        slice_bits[q]  = bits;
 +        slice_score[q] = error;
 +    }
 +    if (slice_bits[max_quant] <= ctx->bits_per_mb * mbs_per_slice) {
 +        slice_bits[max_quant + 1]  = slice_bits[max_quant];
 +        slice_score[max_quant + 1] = slice_score[max_quant] + 1;
 +        overquant = max_quant;
 +    } else {
 +        for (q = max_quant + 1; q < 128; q++) {
 +            bits  = 0;
 +            error = 0;
 +            if (q < MAX_STORED_Q) {
 +                qmat = ctx->quants[q];
 +            } else {
 +                qmat = td->custom_q;
 +                for (i = 0; i < 64; i++)
 +                    qmat[i] = ctx->quant_mat[i] * q;
 +            }
 +            for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
 +                bits += estimate_slice_plane(ctx, &error, i,
 +                                             src, linesize[i],
 +                                             mbs_per_slice,
 +                                             num_cblocks[i], plane_factor[i],
 +                                             qmat, td);
 +            }
 +            if (ctx->alpha_bits)
 +                bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
 +                                             mbs_per_slice, q, td->blocks[3]);
 +            if (bits <= ctx->bits_per_mb * mbs_per_slice)
 +                break;
 +        }
 +
 +        slice_bits[max_quant + 1]  = bits;
 +        slice_score[max_quant + 1] = error;
 +        overquant = q;
 +    }
 +    td->nodes[trellis_node + max_quant + 1].quant = overquant;
 +
 +    bits_limit = mbs * ctx->bits_per_mb;
 +    for (pq = min_quant; pq < max_quant + 2; pq++) {
 +        prev = trellis_node - TRELLIS_WIDTH + pq;
 +
 +        for (q = min_quant; q < max_quant + 2; q++) {
 +            cur = trellis_node + q;
 +
 +            bits  = td->nodes[prev].bits + slice_bits[q];
 +            error = slice_score[q];
 +            if (bits > bits_limit)
 +                error = SCORE_LIMIT;
 +
 +            if (td->nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT)
 +                new_score = td->nodes[prev].score + error;
 +            else
 +                new_score = SCORE_LIMIT;
 +            if (td->nodes[cur].prev_node == -1 ||
 +                td->nodes[cur].score >= new_score) {
 +
 +                td->nodes[cur].bits      = bits;
 +                td->nodes[cur].score     = new_score;
 +                td->nodes[cur].prev_node = prev;
 +            }
 +        }
 +    }
 +
 +    error = td->nodes[trellis_node + min_quant].score;
 +    pq    = trellis_node + min_quant;
 +    for (q = min_quant + 1; q < max_quant + 2; q++) {
 +        if (td->nodes[trellis_node + q].score <= error) {
 +            error = td->nodes[trellis_node + q].score;
 +            pq    = trellis_node + q;
 +        }
 +    }
 +
 +    return pq;
 +}
 +
 +static int find_quant_thread(AVCodecContext *avctx, void *arg,
 +                             int jobnr, int threadnr)
 +{
 +    ProresContext *ctx = avctx->priv_data;
 +    ProresThreadData *td = ctx->tdata + threadnr;
 +    int mbs_per_slice = ctx->mbs_per_slice;
 +    int x, y = jobnr, mb, q = 0;
 +
 +    for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
 +        while (ctx->mb_width - x < mbs_per_slice)
 +            mbs_per_slice >>= 1;
 +        q = find_slice_quant(avctx,
 +                             (mb + 1) * TRELLIS_WIDTH, x, y,
 +                             mbs_per_slice, td);
 +    }
 +
 +    for (x = ctx->slices_width - 1; x >= 0; x--) {
 +        ctx->slice_q[x + y * ctx->slices_width] = td->nodes[q].quant;
 +        q = td->nodes[q].prev_node;
 +    }
 +
 +    return 0;
 +}
 +
 +static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                        const AVFrame *pic, int *got_packet)
 +{
 +    ProresContext *ctx = avctx->priv_data;
 +    uint8_t *orig_buf, *buf, *slice_hdr, *slice_sizes, *tmp;
 +    uint8_t *picture_size_pos;
 +    PutBitContext pb;
 +    int x, y, i, mb, q = 0;
 +    int sizes[4] = { 0 };
 +    int slice_hdr_size = 2 + 2 * (ctx->num_planes - 1);
 +    int frame_size, picture_size, slice_size;
 +    int pkt_size, ret;
 +    int max_slice_size = (ctx->frame_size_upper_bound - 200) / (ctx->pictures_per_frame * ctx->slices_per_picture + 1);
 +    uint8_t frame_flags;
 +
 +    ctx->pic = pic;
 +    pkt_size = ctx->frame_size_upper_bound;
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size + FF_MIN_BUFFER_SIZE)) < 0)
 +        return ret;
 +
 +    orig_buf = pkt->data;
 +
 +    // frame atom
 +    orig_buf += 4;                              // frame size
 +    bytestream_put_be32  (&orig_buf, FRAME_ID); // frame container ID
 +    buf = orig_buf;
 +
 +    // frame header
 +    tmp = buf;
 +    buf += 2;                                   // frame header size will be stored here
 +    bytestream_put_be16  (&buf, 0);             // version 1
 +    bytestream_put_buffer(&buf, ctx->vendor, 4);
 +    bytestream_put_be16  (&buf, avctx->width);
 +    bytestream_put_be16  (&buf, avctx->height);
 +
 +    frame_flags = ctx->chroma_factor << 6;
 +    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT)
 +        frame_flags |= pic->top_field_first ? 0x04 : 0x08;
 +    bytestream_put_byte  (&buf, frame_flags);
 +
 +    bytestream_put_byte  (&buf, 0);             // reserved
 +    bytestream_put_byte  (&buf, avctx->color_primaries);
 +    bytestream_put_byte  (&buf, avctx->color_trc);
 +    bytestream_put_byte  (&buf, avctx->colorspace);
 +    bytestream_put_byte  (&buf, 0x40 | (ctx->alpha_bits >> 3));
 +    bytestream_put_byte  (&buf, 0);             // reserved
 +    if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
 +        bytestream_put_byte  (&buf, 0x03);      // matrix flags - both matrices are present
 +        // luma quantisation matrix
 +        for (i = 0; i < 64; i++)
 +            bytestream_put_byte(&buf, ctx->quant_mat[i]);
 +        // chroma quantisation matrix
 +        for (i = 0; i < 64; i++)
 +            bytestream_put_byte(&buf, ctx->quant_mat[i]);
 +    } else {
 +        bytestream_put_byte  (&buf, 0x00);      // matrix flags - default matrices are used
 +    }
 +    bytestream_put_be16  (&tmp, buf - orig_buf); // write back frame header size
 +
 +    for (ctx->cur_picture_idx = 0;
 +         ctx->cur_picture_idx < ctx->pictures_per_frame;
 +         ctx->cur_picture_idx++) {
 +        // picture header
 +        picture_size_pos = buf + 1;
 +        bytestream_put_byte  (&buf, 0x40);          // picture header size (in bits)
 +        buf += 4;                                   // picture data size will be stored here
 +        bytestream_put_be16  (&buf, ctx->slices_per_picture);
 +        bytestream_put_byte  (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs
 +
 +        // seek table - will be filled during slice encoding
 +        slice_sizes = buf;
 +        buf += ctx->slices_per_picture * 2;
 +
 +        // slices
 +        if (!ctx->force_quant) {
 +            ret = avctx->execute2(avctx, find_quant_thread, (void*)pic, NULL,
 +                                  ctx->mb_height);
 +            if (ret)
 +                return ret;
 +        }
 +
 +        for (y = 0; y < ctx->mb_height; y++) {
 +            int mbs_per_slice = ctx->mbs_per_slice;
 +            for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
 +                q = ctx->force_quant ? ctx->force_quant
 +                                     : ctx->slice_q[mb + y * ctx->slices_width];
 +
 +                while (ctx->mb_width - x < mbs_per_slice)
 +                    mbs_per_slice >>= 1;
 +
 +                bytestream_put_byte(&buf, slice_hdr_size << 3);
 +                slice_hdr = buf;
 +                buf += slice_hdr_size - 1;
 +                if (pkt_size <= buf - orig_buf + 2 * max_slice_size) {
 +                    uint8_t *start = pkt->data;
 +                    // Recompute new size according to max_slice_size
 +                    // and deduce delta
 +                    int delta = 200 + (ctx->pictures_per_frame *
 +                                ctx->slices_per_picture + 1) *
 +                                max_slice_size - pkt_size;
 +
 +                    delta = FFMAX(delta, 2 * max_slice_size);
 +                    ctx->frame_size_upper_bound += delta;
 +
 +                    if (!ctx->warn) {
 +                        avpriv_request_sample(avctx,
 +                                              "Packet too small: is %i,"
 +                                              " needs %i (slice: %i). "
 +                                              "Correct allocation",
 +                                              pkt_size, delta, max_slice_size);
 +                        ctx->warn = 1;
 +                    }
 +
 +                    ret = av_grow_packet(pkt, delta);
 +                    if (ret < 0)
 +                        return ret;
 +
 +                    pkt_size += delta;
 +                    // restore pointers
 +                    orig_buf         = pkt->data + (orig_buf         - start);
 +                    buf              = pkt->data + (buf              - start);
 +                    picture_size_pos = pkt->data + (picture_size_pos - start);
 +                    slice_sizes      = pkt->data + (slice_sizes      - start);
 +                    slice_hdr        = pkt->data + (slice_hdr        - start);
 +                    tmp              = pkt->data + (tmp              - start);
 +                }
 +                init_put_bits(&pb, buf, (pkt_size - (buf - orig_buf)));
 +                ret = encode_slice(avctx, pic, &pb, sizes, x, y, q,
 +                                   mbs_per_slice);
 +                if (ret < 0)
 +                    return ret;
 +
 +                bytestream_put_byte(&slice_hdr, q);
 +                slice_size = slice_hdr_size + sizes[ctx->num_planes - 1];
 +                for (i = 0; i < ctx->num_planes - 1; i++) {
 +                    bytestream_put_be16(&slice_hdr, sizes[i]);
 +                    slice_size += sizes[i];
 +                }
 +                bytestream_put_be16(&slice_sizes, slice_size);
 +                buf += slice_size - slice_hdr_size;
 +                if (max_slice_size < slice_size)
 +                    max_slice_size = slice_size;
 +            }
 +        }
 +
 +        picture_size = buf - (picture_size_pos - 1);
 +        bytestream_put_be32(&picture_size_pos, picture_size);
 +    }
 +
 +    orig_buf -= 8;
 +    frame_size = buf - orig_buf;
 +    bytestream_put_be32(&orig_buf, frame_size);
 +
 +    pkt->size   = frame_size;
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +
 +    return 0;
 +}
 +
 +static av_cold int encode_close(AVCodecContext *avctx)
 +{
 +    ProresContext *ctx = avctx->priv_data;
 +    int i;
 +
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
 +    if (ctx->tdata) {
 +        for (i = 0; i < avctx->thread_count; i++)
 +            av_freep(&ctx->tdata[i].nodes);
 +    }
 +    av_freep(&ctx->tdata);
 +    av_freep(&ctx->slice_q);
 +
 +    return 0;
 +}
 +
 +static void prores_fdct(FDCTDSPContext *fdsp, const uint16_t *src,
 +                        int linesize, int16_t *block)
 +{
 +    int x, y;
 +    const uint16_t *tsrc = src;
 +
 +    for (y = 0; y < 8; y++) {
 +        for (x = 0; x < 8; x++)
 +            block[y * 8 + x] = tsrc[x];
 +        tsrc += linesize >> 1;
 +    }
 +    fdsp->fdct(block);
 +}
 +
 +static av_cold int encode_init(AVCodecContext *avctx)
 +{
 +    ProresContext *ctx = avctx->priv_data;
 +    int mps;
 +    int i, j;
 +    int min_quant, max_quant;
 +    int interlaced = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
 +
 +    avctx->bits_per_raw_sample = 10;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +    avctx->coded_frame->key_frame = 1;
 +
 +    ctx->fdct      = prores_fdct;
 +    ctx->scantable = interlaced ? ff_prores_interlaced_scan
 +                                : ff_prores_progressive_scan;
 +    ff_fdctdsp_init(&ctx->fdsp, avctx);
 +
 +    mps = ctx->mbs_per_slice;
 +    if (mps & (mps - 1)) {
 +        av_log(avctx, AV_LOG_ERROR,
 +               "there should be an integer power of two MBs per slice\n");
 +        return AVERROR(EINVAL);
 +    }
 +    if (ctx->profile == PRORES_PROFILE_AUTO) {
 +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
 +        ctx->profile = (desc->flags & AV_PIX_FMT_FLAG_ALPHA ||
 +                        !(desc->log2_chroma_w + desc->log2_chroma_h))
 +                     ? PRORES_PROFILE_4444 : PRORES_PROFILE_HQ;
 +        av_log(avctx, AV_LOG_INFO, "Autoselected %s. It can be overridden "
 +               "through -profile option.\n", ctx->profile == PRORES_PROFILE_4444
 +               ? "4:4:4:4 profile because of the used input colorspace"
 +               : "HQ profile to keep best quality");
 +    }
 +    if (av_pix_fmt_desc_get(avctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
 +        if (ctx->profile != PRORES_PROFILE_4444) {
 +            // force alpha and warn
 +            av_log(avctx, AV_LOG_WARNING, "Profile selected will not "
 +                   "encode alpha. Override with -profile if needed.\n");
 +            ctx->alpha_bits = 0;
 +        }
 +        if (ctx->alpha_bits & 7) {
 +            av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
 +            return AVERROR(EINVAL);
 +        }
 +        avctx->bits_per_coded_sample = 32;
 +    } else {
 +        ctx->alpha_bits = 0;
 +    }
 +
 +    ctx->chroma_factor = avctx->pix_fmt == AV_PIX_FMT_YUV422P10
 +                         ? CFACTOR_Y422
 +                         : CFACTOR_Y444;
 +    ctx->profile_info  = prores_profile_info + ctx->profile;
 +    ctx->num_planes    = 3 + !!ctx->alpha_bits;
 +
 +    ctx->mb_width      = FFALIGN(avctx->width,  16) >> 4;
 +
 +    if (interlaced)
 +        ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
 +    else
 +        ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
 +
 +    ctx->slices_width  = ctx->mb_width / mps;
 +    ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
 +    ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
 +    ctx->pictures_per_frame = 1 + interlaced;
 +
 +    if (ctx->quant_sel == -1)
 +        ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
 +    else
 +        ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
 +
 +    if (strlen(ctx->vendor) != 4) {
 +        av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
 +        return AVERROR_INVALIDDATA;
 +    }
 +
 +    ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
 +    if (!ctx->force_quant) {
 +        if (!ctx->bits_per_mb) {
 +            for (i = 0; i < NUM_MB_LIMITS - 1; i++)
 +                if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
 +                                           ctx->pictures_per_frame)
 +                    break;
 +            ctx->bits_per_mb   = ctx->profile_info->br_tab[i];
 +        } else if (ctx->bits_per_mb < 128) {
 +            av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +
 +        min_quant = ctx->profile_info->min_quant;
 +        max_quant = ctx->profile_info->max_quant;
 +        for (i = min_quant; i < MAX_STORED_Q; i++) {
 +            for (j = 0; j < 64; j++)
 +                ctx->quants[i][j] = ctx->quant_mat[j] * i;
 +        }
 +
 +        ctx->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q));
 +        if (!ctx->slice_q) {
 +            encode_close(avctx);
 +            return AVERROR(ENOMEM);
 +        }
 +
 +        ctx->tdata = av_mallocz(avctx->thread_count * sizeof(*ctx->tdata));
 +        if (!ctx->tdata) {
 +            encode_close(avctx);
 +            return AVERROR(ENOMEM);
 +        }
 +
 +        for (j = 0; j < avctx->thread_count; j++) {
 +            ctx->tdata[j].nodes = av_malloc((ctx->slices_width + 1)
 +                                            * TRELLIS_WIDTH
 +                                            * sizeof(*ctx->tdata->nodes));
 +            if (!ctx->tdata[j].nodes) {
 +                encode_close(avctx);
 +                return AVERROR(ENOMEM);
 +            }
 +            for (i = min_quant; i < max_quant + 2; i++) {
 +                ctx->tdata[j].nodes[i].prev_node = -1;
 +                ctx->tdata[j].nodes[i].bits      = 0;
 +                ctx->tdata[j].nodes[i].score     = 0;
 +            }
 +        }
 +    } else {
 +        int ls = 0;
 +
 +        if (ctx->force_quant > 64) {
 +            av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +
 +        for (j = 0; j < 64; j++) {
 +            ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
 +            ls += av_log2((1 << 11)  / ctx->quants[0][j]) * 2 + 1;
 +        }
 +
 +        ctx->bits_per_mb = ls * 8;
 +        if (ctx->chroma_factor == CFACTOR_Y444)
 +            ctx->bits_per_mb += ls * 4;
 +    }
 +
 +    ctx->frame_size_upper_bound = (ctx->pictures_per_frame *
 +                                   ctx->slices_per_picture + 1) *
 +                                  (2 + 2 * ctx->num_planes +
 +                                   (mps * ctx->bits_per_mb) / 8)
 +                                  + 200;
 +
 +    if (ctx->alpha_bits) {
 +         // The alpha plane is run-coded and might exceed the bit budget.
 +         ctx->frame_size_upper_bound += (ctx->pictures_per_frame *
 +                                         ctx->slices_per_picture + 1) *
 +         /* num pixels per slice */     (ctx->mbs_per_slice * 256 *
 +         /* bits per pixel */            (1 + ctx->alpha_bits + 1) + 7 >> 3);
 +    }
 +
 +    avctx->codec_tag   = ctx->profile_info->tag;
 +
 +    av_log(avctx, AV_LOG_DEBUG,
 +           "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
 +           ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
 +           interlaced ? "yes" : "no", ctx->bits_per_mb);
 +    av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
 +           ctx->frame_size_upper_bound);
 +
 +    return 0;
 +}
 +
 +#define OFFSET(x) offsetof(ProresContext, x)
 +#define VE     AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
 +
 +static const AVOption options[] = {
 +    { "mbs_per_slice", "macroblocks per slice", OFFSET(mbs_per_slice),
 +        AV_OPT_TYPE_INT, { .i64 = 8 }, 1, MAX_MBS_PER_SLICE, VE },
 +    { "profile",       NULL, OFFSET(profile), AV_OPT_TYPE_INT,
 +        { .i64 = PRORES_PROFILE_AUTO },
 +        PRORES_PROFILE_AUTO, PRORES_PROFILE_4444, VE, "profile" },
 +    { "auto",         NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_AUTO },
 +        0, 0, VE, "profile" },
 +    { "proxy",         NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_PROXY },
 +        0, 0, VE, "profile" },
 +    { "lt",            NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_LT },
 +        0, 0, VE, "profile" },
 +    { "standard",      NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_STANDARD },
 +        0, 0, VE, "profile" },
 +    { "hq",            NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_HQ },
 +        0, 0, VE, "profile" },
 +    { "4444",          NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444 },
 +        0, 0, VE, "profile" },
 +    { "vendor", "vendor ID", OFFSET(vendor),
 +        AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
 +    { "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
 +        AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE },
 +    { "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
 +        { .i64 = -1 }, -1, QUANT_MAT_DEFAULT, VE, "quant_mat" },
 +    { "auto",          NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 },
 +        0, 0, VE, "quant_mat" },
 +    { "proxy",         NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_PROXY },
 +        0, 0, VE, "quant_mat" },
 +    { "lt",            NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_LT },
 +        0, 0, VE, "quant_mat" },
 +    { "standard",      NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_STANDARD },
 +        0, 0, VE, "quant_mat" },
 +    { "hq",            NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_HQ },
 +        0, 0, VE, "quant_mat" },
 +    { "default",       NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_DEFAULT },
 +        0, 0, VE, "quant_mat" },
 +    { "alpha_bits", "bits for alpha plane", OFFSET(alpha_bits), AV_OPT_TYPE_INT,
 +        { .i64 = 16 }, 0, 16, VE },
 +    { NULL }
 +};
 +
 +static const AVClass proresenc_class = {
 +    .class_name = "ProRes encoder",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
 +AVCodec ff_prores_ks_encoder = {
 +    .name           = "prores_ks",
 +    .long_name      = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
 +    .type           = AVMEDIA_TYPE_VIDEO,
 +    .id             = AV_CODEC_ID_PRORES,
 +    .priv_data_size = sizeof(ProresContext),
 +    .init           = encode_init,
 +    .close          = encode_close,
 +    .encode2        = encode_frame,
 +    .capabilities   = CODEC_CAP_SLICE_THREADS,
 +    .pix_fmts       = (const enum AVPixelFormat[]) {
 +                          AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
 +                          AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
 +                      },
 +    .priv_class     = &proresenc_class,
 +};
Simple merge
@@@ -109,31 -96,25 +107,25 @@@ static av_cold int qtrle_encode_init(AV
          av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
          break;
      }
 -    avctx->bits_per_coded_sample = s->pixel_size*8;
 +    avctx->bits_per_coded_sample = avctx->pix_fmt == AV_PIX_FMT_GRAY8 ? 40 : s->pixel_size*8;
  
 -    s->rlecode_table = av_mallocz(s->avctx->width);
 -    s->skip_table    = av_mallocz(s->avctx->width);
 -    s->length_table  = av_mallocz((s->avctx->width + 1)*sizeof(int));
 +    s->rlecode_table = av_mallocz(s->logical_width);
 +    s->skip_table    = av_mallocz(s->logical_width);
 +    s->length_table  = av_mallocz_array(s->logical_width + 1, sizeof(int));
      if (!s->skip_table || !s->length_table || !s->rlecode_table) {
          av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n");
 -        return -1;
 +        return AVERROR(ENOMEM);
      }
 -    if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) {
 +    if ((ret = avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height)) < 0) {
          av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n");
 -        return -1;
 +        return ret;
      }
  
 -    s->max_buf_size = s->avctx->width*s->avctx->height*s->pixel_size*2 /* image base material */
 -                      + 15                                           /* header + footer */
 -                      + s->avctx->height*2                           /* skip code+rle end */
 -                      + s->avctx->width/MAX_RLE_BULK + 1             /* rle codes */;
 +    s->max_buf_size = s->logical_width*s->avctx->height*s->pixel_size*2 /* image base material */
 +                      + 15                                            /* header + footer */
 +                      + s->avctx->height*2                            /* skip code+rle end */
 +                      + s->logical_width/MAX_RLE_BULK + 1             /* rle codes */;
  
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         qtrle_encode_end(avctx);
-         return AVERROR(ENOMEM);
-     }
      return 0;
  }
  
index b7d5a07,0000000..0aae409
mode 100644,000000..100644
--- /dev/null
@@@ -1,123 -1,0 +1,101 @@@
- static av_cold int encode_init(AVCodecContext *avctx)
- {
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
-     return 0;
- }
 +/*
 + * R210 encoder
 + *
 + * Copyright (c) 2012 Paul B Mahol
 + *
 + * 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 "avcodec.h"
 +#include "internal.h"
 +#include "bytestream.h"
 +
- static av_cold int encode_close(AVCodecContext *avctx)
- {
-     av_frame_free(&avctx->coded_frame);
-     return 0;
- }
 +static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                        const AVFrame *pic, int *got_packet)
 +{
 +    int i, j, ret;
 +    int aligned_width = FFALIGN(avctx->width,
 +                                avctx->codec_id == AV_CODEC_ID_R10K ? 1 : 64);
 +    int pad = (aligned_width - avctx->width) * 4;
 +    uint8_t *src_line;
 +    uint8_t *dst;
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, 4 * aligned_width * avctx->height)) < 0)
 +        return ret;
 +
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +    src_line = pic->data[0];
 +    dst = pkt->data;
 +
 +    for (i = 0; i < avctx->height; i++) {
 +        uint16_t *src = (uint16_t *)src_line;
 +        for (j = 0; j < avctx->width; j++) {
 +            uint32_t pixel;
 +            uint16_t r = *src++ >> 6;
 +            uint16_t g = *src++ >> 6;
 +            uint16_t b = *src++ >> 6;
 +            if (avctx->codec_id == AV_CODEC_ID_R210)
 +                pixel = (r << 20) | (g << 10) | b;
 +            else
 +                pixel = (r << 22) | (g << 12) | (b << 2);
 +            if (avctx->codec_id == AV_CODEC_ID_AVRP)
 +                bytestream_put_le32(&dst, pixel);
 +            else
 +                bytestream_put_be32(&dst, pixel);
 +        }
 +        memset(dst, 0, pad);
 +        dst += pad;
 +        src_line += pic->linesize[0];
 +    }
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +    return 0;
 +}
 +
-     .init           = encode_init,
 +
 +#if CONFIG_R210_ENCODER
 +AVCodec ff_r210_encoder = {
 +    .name           = "r210",
 +    .long_name      = NULL_IF_CONFIG_SMALL("Uncompressed RGB 10-bit"),
 +    .type           = AVMEDIA_TYPE_VIDEO,
 +    .id             = AV_CODEC_ID_R210,
-     .close          = encode_close,
 +    .encode2        = encode_frame,
-     .init           = encode_init,
 +    .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE },
 +};
 +#endif
 +#if CONFIG_R10K_ENCODER
 +AVCodec ff_r10k_encoder = {
 +    .name           = "r10k",
 +    .long_name      = NULL_IF_CONFIG_SMALL("AJA Kona 10-bit RGB Codec"),
 +    .type           = AVMEDIA_TYPE_VIDEO,
 +    .id             = AV_CODEC_ID_R10K,
-     .close          = encode_close,
 +    .encode2        = encode_frame,
-     .init           = encode_init,
 +    .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE },
 +};
 +#endif
 +#if CONFIG_AVRP_ENCODER
 +AVCodec ff_avrp_encoder = {
 +    .name           = "avrp",
 +    .long_name      = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"),
 +    .type           = AVMEDIA_TYPE_VIDEO,
 +    .id             = AV_CODEC_ID_AVRP,
-     .close          = encode_close,
 +    .encode2        = encode_frame,
 +    .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE },
 +};
 +#endif
@@@ -35,11 -35,8 +35,7 @@@ static av_cold int raw_encode_init(AVCo
  {
      const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
  
-     avctx->coded_frame            = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
      avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 -    avctx->coded_frame->key_frame = 1;
      avctx->bits_per_coded_sample = av_get_bits_per_pixel(desc);
      if(!avctx->codec_tag)
          avctx->codec_tag = avcodec_pix_fmt_to_codec_tag(avctx->pix_fmt);
@@@ -979,13 -974,12 +979,12 @@@ static av_cold int roq_encode_end(AVCod
  
      av_frame_free(&enc->current_frame);
      av_frame_free(&enc->last_frame);
-     av_frame_free(&enc->avctx->coded_frame);
  
 -    av_free(enc->tmpData);
 -    av_free(enc->this_motion4);
 -    av_free(enc->last_motion4);
 -    av_free(enc->this_motion8);
 -    av_free(enc->last_motion8);
 +    av_freep(&enc->tmpData);
 +    av_freep(&enc->this_motion4);
 +    av_freep(&enc->last_motion4);
 +    av_freep(&enc->this_motion8);
 +    av_freep(&enc->last_motion8);
  
      return 0;
  }
Simple merge
index bd5c0fd,0000000..9c804ac
mode 100644,000000..100644
--- /dev/null
@@@ -1,2038 -1,0 +1,2036 @@@
-     avctx->coded_frame = av_frame_alloc();
-     if (!s->input_picture || !avctx->coded_frame)
 +/*
 + * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
 + *
 + * 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 "libavutil/intmath.h"
 +#include "libavutil/log.h"
 +#include "libavutil/opt.h"
 +#include "avcodec.h"
 +#include "internal.h"
 +#include "snow_dwt.h"
 +#include "snow.h"
 +
 +#include "rangecoder.h"
 +#include "mathops.h"
 +
 +#include "mpegvideo.h"
 +#include "h263.h"
 +
 +static av_cold int encode_init(AVCodecContext *avctx)
 +{
 +    SnowContext *s = avctx->priv_data;
 +    int plane_index, ret;
 +    int i;
 +
 +    if(avctx->prediction_method == DWT_97
 +       && (avctx->flags & CODEC_FLAG_QSCALE)
 +       && avctx->global_quality == 0){
 +        av_log(avctx, AV_LOG_ERROR, "The 9/7 wavelet is incompatible with lossless mode.\n");
 +        return -1;
 +    }
 +
 +    s->spatial_decomposition_type= avctx->prediction_method; //FIXME add decorrelator type r transform_type
 +
 +    s->mv_scale       = (avctx->flags & CODEC_FLAG_QPEL) ? 2 : 4;
 +    s->block_max_depth= (avctx->flags & CODEC_FLAG_4MV ) ? 1 : 0;
 +
 +    for(plane_index=0; plane_index<3; plane_index++){
 +        s->plane[plane_index].diag_mc= 1;
 +        s->plane[plane_index].htaps= 6;
 +        s->plane[plane_index].hcoeff[0]=  40;
 +        s->plane[plane_index].hcoeff[1]= -10;
 +        s->plane[plane_index].hcoeff[2]=   2;
 +        s->plane[plane_index].fast_mc= 1;
 +    }
 +
 +    if ((ret = ff_snow_common_init(avctx)) < 0) {
 +        return ret;
 +    }
 +    ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx);
 +
 +    ff_snow_alloc_blocks(s);
 +
 +    s->version=0;
 +
 +    s->m.avctx   = avctx;
 +    s->m.bit_rate= avctx->bit_rate;
 +
 +    s->m.me.temp      =
 +    s->m.me.scratchpad= av_mallocz_array((avctx->width+64), 2*16*2*sizeof(uint8_t));
 +    s->m.me.map       = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
 +    s->m.me.score_map = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
 +    s->m.sc.obmc_scratchpad= av_mallocz(MB_SIZE*MB_SIZE*12*sizeof(uint32_t));
 +    if (!s->m.me.scratchpad || !s->m.me.map || !s->m.me.score_map || !s->m.sc.obmc_scratchpad)
 +        return AVERROR(ENOMEM);
 +
 +    ff_h263_encode_init(&s->m); //mv_penalty
 +
 +    s->max_ref_frames = av_clip(avctx->refs, 1, MAX_REF_FRAMES);
 +
 +    if(avctx->flags&CODEC_FLAG_PASS1){
 +        if(!avctx->stats_out)
 +            avctx->stats_out = av_mallocz(256);
 +
 +        if (!avctx->stats_out)
 +            return AVERROR(ENOMEM);
 +    }
 +    if((avctx->flags&CODEC_FLAG_PASS2) || !(avctx->flags&CODEC_FLAG_QSCALE)){
 +        if(ff_rate_control_init(&s->m) < 0)
 +            return -1;
 +    }
 +    s->pass1_rc= !(avctx->flags & (CODEC_FLAG_QSCALE|CODEC_FLAG_PASS2));
 +
 +    switch(avctx->pix_fmt){
 +    case AV_PIX_FMT_YUV444P:
 +//    case AV_PIX_FMT_YUV422P:
 +    case AV_PIX_FMT_YUV420P:
 +//    case AV_PIX_FMT_YUV411P:
 +    case AV_PIX_FMT_YUV410P:
 +        s->nb_planes = 3;
 +        s->colorspace_type= 0;
 +        break;
 +    case AV_PIX_FMT_GRAY8:
 +        s->nb_planes = 1;
 +        s->colorspace_type = 1;
 +        break;
 +/*    case AV_PIX_FMT_RGB32:
 +        s->colorspace= 1;
 +        break;*/
 +    default:
 +        av_log(avctx, AV_LOG_ERROR, "pixel format not supported\n");
 +        return -1;
 +    }
 +    avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift);
 +
 +    ff_set_cmp(&s->mecc, s->mecc.me_cmp, s->avctx->me_cmp);
 +    ff_set_cmp(&s->mecc, s->mecc.me_sub_cmp, s->avctx->me_sub_cmp);
 +
 +    s->input_picture = av_frame_alloc();
-     if (avctx->coded_frame->key_frame)
++    if (!s->input_picture)
 +        return AVERROR(ENOMEM);
 +
 +    if ((ret = ff_snow_get_buffer(s, s->input_picture)) < 0)
 +        return ret;
 +
 +    if(s->avctx->me_method == ME_ITER){
 +        int size= s->b_width * s->b_height << 2*s->block_max_depth;
 +        for(i=0; i<s->max_ref_frames; i++){
 +            s->ref_mvs[i]= av_mallocz_array(size, sizeof(int16_t[2]));
 +            s->ref_scores[i]= av_mallocz_array(size, sizeof(uint32_t));
 +            if (!s->ref_mvs[i] || !s->ref_scores[i])
 +                return AVERROR(ENOMEM);
 +        }
 +    }
 +
 +    return 0;
 +}
 +
 +//near copy & paste from dsputil, FIXME
 +static int pix_sum(uint8_t * pix, int line_size, int w, int h)
 +{
 +    int s, i, j;
 +
 +    s = 0;
 +    for (i = 0; i < h; i++) {
 +        for (j = 0; j < w; j++) {
 +            s += pix[0];
 +            pix ++;
 +        }
 +        pix += line_size - w;
 +    }
 +    return s;
 +}
 +
 +//near copy & paste from dsputil, FIXME
 +static int pix_norm1(uint8_t * pix, int line_size, int w)
 +{
 +    int s, i, j;
 +    uint32_t *sq = ff_square_tab + 256;
 +
 +    s = 0;
 +    for (i = 0; i < w; i++) {
 +        for (j = 0; j < w; j ++) {
 +            s += sq[pix[0]];
 +            pix ++;
 +        }
 +        pix += line_size - w;
 +    }
 +    return s;
 +}
 +
 +static inline int get_penalty_factor(int lambda, int lambda2, int type){
 +    switch(type&0xFF){
 +    default:
 +    case FF_CMP_SAD:
 +        return lambda>>FF_LAMBDA_SHIFT;
 +    case FF_CMP_DCT:
 +        return (3*lambda)>>(FF_LAMBDA_SHIFT+1);
 +    case FF_CMP_W53:
 +        return (4*lambda)>>(FF_LAMBDA_SHIFT);
 +    case FF_CMP_W97:
 +        return (2*lambda)>>(FF_LAMBDA_SHIFT);
 +    case FF_CMP_SATD:
 +    case FF_CMP_DCT264:
 +        return (2*lambda)>>FF_LAMBDA_SHIFT;
 +    case FF_CMP_RD:
 +    case FF_CMP_PSNR:
 +    case FF_CMP_SSE:
 +    case FF_CMP_NSSE:
 +        return lambda2>>FF_LAMBDA_SHIFT;
 +    case FF_CMP_BIT:
 +        return 1;
 +    }
 +}
 +
 +//FIXME copy&paste
 +#define P_LEFT P[1]
 +#define P_TOP P[2]
 +#define P_TOPRIGHT P[3]
 +#define P_MEDIAN P[4]
 +#define P_MV1 P[9]
 +#define FLAG_QPEL   1 //must be 1
 +
 +static int encode_q_branch(SnowContext *s, int level, int x, int y){
 +    uint8_t p_buffer[1024];
 +    uint8_t i_buffer[1024];
 +    uint8_t p_state[sizeof(s->block_state)];
 +    uint8_t i_state[sizeof(s->block_state)];
 +    RangeCoder pc, ic;
 +    uint8_t *pbbak= s->c.bytestream;
 +    uint8_t *pbbak_start= s->c.bytestream_start;
 +    int score, score2, iscore, i_len, p_len, block_s, sum, base_bits;
 +    const int w= s->b_width  << s->block_max_depth;
 +    const int h= s->b_height << s->block_max_depth;
 +    const int rem_depth= s->block_max_depth - level;
 +    const int index= (x + y*w) << rem_depth;
 +    const int block_w= 1<<(LOG2_MB_SIZE - level);
 +    int trx= (x+1)<<rem_depth;
 +    int try= (y+1)<<rem_depth;
 +    const BlockNode *left  = x ? &s->block[index-1] : &null_block;
 +    const BlockNode *top   = y ? &s->block[index-w] : &null_block;
 +    const BlockNode *right = trx<w ? &s->block[index+1] : &null_block;
 +    const BlockNode *bottom= try<h ? &s->block[index+w] : &null_block;
 +    const BlockNode *tl    = y && x ? &s->block[index-w-1] : left;
 +    const BlockNode *tr    = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
 +    int pl = left->color[0];
 +    int pcb= left->color[1];
 +    int pcr= left->color[2];
 +    int pmx, pmy;
 +    int mx=0, my=0;
 +    int l,cr,cb;
 +    const int stride= s->current_picture->linesize[0];
 +    const int uvstride= s->current_picture->linesize[1];
 +    uint8_t *current_data[3]= { s->input_picture->data[0] + (x + y*  stride)*block_w,
 +                                s->input_picture->data[1] + ((x*block_w)>>s->chroma_h_shift) + ((y*uvstride*block_w)>>s->chroma_v_shift),
 +                                s->input_picture->data[2] + ((x*block_w)>>s->chroma_h_shift) + ((y*uvstride*block_w)>>s->chroma_v_shift)};
 +    int P[10][2];
 +    int16_t last_mv[3][2];
 +    int qpel= !!(s->avctx->flags & CODEC_FLAG_QPEL); //unused
 +    const int shift= 1+qpel;
 +    MotionEstContext *c= &s->m.me;
 +    int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
 +    int mx_context= av_log2(2*FFABS(left->mx - top->mx));
 +    int my_context= av_log2(2*FFABS(left->my - top->my));
 +    int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
 +    int ref, best_ref, ref_score, ref_mx, ref_my;
 +
 +    av_assert0(sizeof(s->block_state) >= 256);
 +    if(s->keyframe){
 +        set_blocks(s, level, x, y, pl, pcb, pcr, 0, 0, 0, BLOCK_INTRA);
 +        return 0;
 +    }
 +
 +//    clip predictors / edge ?
 +
 +    P_LEFT[0]= left->mx;
 +    P_LEFT[1]= left->my;
 +    P_TOP [0]= top->mx;
 +    P_TOP [1]= top->my;
 +    P_TOPRIGHT[0]= tr->mx;
 +    P_TOPRIGHT[1]= tr->my;
 +
 +    last_mv[0][0]= s->block[index].mx;
 +    last_mv[0][1]= s->block[index].my;
 +    last_mv[1][0]= right->mx;
 +    last_mv[1][1]= right->my;
 +    last_mv[2][0]= bottom->mx;
 +    last_mv[2][1]= bottom->my;
 +
 +    s->m.mb_stride=2;
 +    s->m.mb_x=
 +    s->m.mb_y= 0;
 +    c->skip= 0;
 +
 +    av_assert1(c->  stride ==   stride);
 +    av_assert1(c->uvstride == uvstride);
 +
 +    c->penalty_factor    = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp);
 +    c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp);
 +    c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp);
 +    c->current_mv_penalty= c->mv_penalty[s->m.f_code=1] + MAX_MV;
 +
 +    c->xmin = - x*block_w - 16+3;
 +    c->ymin = - y*block_w - 16+3;
 +    c->xmax = - (x+1)*block_w + (w<<(LOG2_MB_SIZE - s->block_max_depth)) + 16-3;
 +    c->ymax = - (y+1)*block_w + (h<<(LOG2_MB_SIZE - s->block_max_depth)) + 16-3;
 +
 +    if(P_LEFT[0]     > (c->xmax<<shift)) P_LEFT[0]    = (c->xmax<<shift);
 +    if(P_LEFT[1]     > (c->ymax<<shift)) P_LEFT[1]    = (c->ymax<<shift);
 +    if(P_TOP[0]      > (c->xmax<<shift)) P_TOP[0]     = (c->xmax<<shift);
 +    if(P_TOP[1]      > (c->ymax<<shift)) P_TOP[1]     = (c->ymax<<shift);
 +    if(P_TOPRIGHT[0] < (c->xmin<<shift)) P_TOPRIGHT[0]= (c->xmin<<shift);
 +    if(P_TOPRIGHT[0] > (c->xmax<<shift)) P_TOPRIGHT[0]= (c->xmax<<shift); //due to pmx no clip
 +    if(P_TOPRIGHT[1] > (c->ymax<<shift)) P_TOPRIGHT[1]= (c->ymax<<shift);
 +
 +    P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);
 +    P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
 +
 +    if (!y) {
 +        c->pred_x= P_LEFT[0];
 +        c->pred_y= P_LEFT[1];
 +    } else {
 +        c->pred_x = P_MEDIAN[0];
 +        c->pred_y = P_MEDIAN[1];
 +    }
 +
 +    score= INT_MAX;
 +    best_ref= 0;
 +    for(ref=0; ref<s->ref_frames; ref++){
 +        init_ref(c, current_data, s->last_picture[ref]->data, NULL, block_w*x, block_w*y, 0);
 +
 +        ref_score= ff_epzs_motion_search(&s->m, &ref_mx, &ref_my, P, 0, /*ref_index*/ 0, last_mv,
 +                                         (1<<16)>>shift, level-LOG2_MB_SIZE+4, block_w);
 +
 +        av_assert2(ref_mx >= c->xmin);
 +        av_assert2(ref_mx <= c->xmax);
 +        av_assert2(ref_my >= c->ymin);
 +        av_assert2(ref_my <= c->ymax);
 +
 +        ref_score= c->sub_motion_search(&s->m, &ref_mx, &ref_my, ref_score, 0, 0, level-LOG2_MB_SIZE+4, block_w);
 +        ref_score= ff_get_mb_score(&s->m, ref_mx, ref_my, 0, 0, level-LOG2_MB_SIZE+4, block_w, 0);
 +        ref_score+= 2*av_log2(2*ref)*c->penalty_factor;
 +        if(s->ref_mvs[ref]){
 +            s->ref_mvs[ref][index][0]= ref_mx;
 +            s->ref_mvs[ref][index][1]= ref_my;
 +            s->ref_scores[ref][index]= ref_score;
 +        }
 +        if(score > ref_score){
 +            score= ref_score;
 +            best_ref= ref;
 +            mx= ref_mx;
 +            my= ref_my;
 +        }
 +    }
 +    //FIXME if mb_cmp != SSE then intra cannot be compared currently and mb_penalty vs. lambda2
 +
 +  //  subpel search
 +    base_bits= get_rac_count(&s->c) - 8*(s->c.bytestream - s->c.bytestream_start);
 +    pc= s->c;
 +    pc.bytestream_start=
 +    pc.bytestream= p_buffer; //FIXME end/start? and at the other stoo
 +    memcpy(p_state, s->block_state, sizeof(s->block_state));
 +
 +    if(level!=s->block_max_depth)
 +        put_rac(&pc, &p_state[4 + s_context], 1);
 +    put_rac(&pc, &p_state[1 + left->type + top->type], 0);
 +    if(s->ref_frames > 1)
 +        put_symbol(&pc, &p_state[128 + 1024 + 32*ref_context], best_ref, 0);
 +    pred_mv(s, &pmx, &pmy, best_ref, left, top, tr);
 +    put_symbol(&pc, &p_state[128 + 32*(mx_context + 16*!!best_ref)], mx - pmx, 1);
 +    put_symbol(&pc, &p_state[128 + 32*(my_context + 16*!!best_ref)], my - pmy, 1);
 +    p_len= pc.bytestream - pc.bytestream_start;
 +    score += (s->lambda2*(get_rac_count(&pc)-base_bits))>>FF_LAMBDA_SHIFT;
 +
 +    block_s= block_w*block_w;
 +    sum = pix_sum(current_data[0], stride, block_w, block_w);
 +    l= (sum + block_s/2)/block_s;
 +    iscore = pix_norm1(current_data[0], stride, block_w) - 2*l*sum + l*l*block_s;
 +
 +    if (s->nb_planes > 2) {
 +        block_s= block_w*block_w>>(s->chroma_h_shift + s->chroma_v_shift);
 +        sum = pix_sum(current_data[1], uvstride, block_w>>s->chroma_h_shift, block_w>>s->chroma_v_shift);
 +        cb= (sum + block_s/2)/block_s;
 +    //    iscore += pix_norm1(&current_mb[1][0], uvstride, block_w>>1) - 2*cb*sum + cb*cb*block_s;
 +        sum = pix_sum(current_data[2], uvstride, block_w>>s->chroma_h_shift, block_w>>s->chroma_v_shift);
 +        cr= (sum + block_s/2)/block_s;
 +    //    iscore += pix_norm1(&current_mb[2][0], uvstride, block_w>>1) - 2*cr*sum + cr*cr*block_s;
 +    }else
 +        cb = cr = 0;
 +
 +    ic= s->c;
 +    ic.bytestream_start=
 +    ic.bytestream= i_buffer; //FIXME end/start? and at the other stoo
 +    memcpy(i_state, s->block_state, sizeof(s->block_state));
 +    if(level!=s->block_max_depth)
 +        put_rac(&ic, &i_state[4 + s_context], 1);
 +    put_rac(&ic, &i_state[1 + left->type + top->type], 1);
 +    put_symbol(&ic, &i_state[32],  l-pl , 1);
 +    if (s->nb_planes > 2) {
 +        put_symbol(&ic, &i_state[64], cb-pcb, 1);
 +        put_symbol(&ic, &i_state[96], cr-pcr, 1);
 +    }
 +    i_len= ic.bytestream - ic.bytestream_start;
 +    iscore += (s->lambda2*(get_rac_count(&ic)-base_bits))>>FF_LAMBDA_SHIFT;
 +
 +    av_assert1(iscore < 255*255*256 + s->lambda2*10);
 +    av_assert1(iscore >= 0);
 +    av_assert1(l>=0 && l<=255);
 +    av_assert1(pl>=0 && pl<=255);
 +
 +    if(level==0){
 +        int varc= iscore >> 8;
 +        int vard= score >> 8;
 +        if (vard <= 64 || vard < varc)
 +            c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
 +        else
 +            c->scene_change_score+= s->m.qscale;
 +    }
 +
 +    if(level!=s->block_max_depth){
 +        put_rac(&s->c, &s->block_state[4 + s_context], 0);
 +        score2 = encode_q_branch(s, level+1, 2*x+0, 2*y+0);
 +        score2+= encode_q_branch(s, level+1, 2*x+1, 2*y+0);
 +        score2+= encode_q_branch(s, level+1, 2*x+0, 2*y+1);
 +        score2+= encode_q_branch(s, level+1, 2*x+1, 2*y+1);
 +        score2+= s->lambda2>>FF_LAMBDA_SHIFT; //FIXME exact split overhead
 +
 +        if(score2 < score && score2 < iscore)
 +            return score2;
 +    }
 +
 +    if(iscore < score){
 +        pred_mv(s, &pmx, &pmy, 0, left, top, tr);
 +        memcpy(pbbak, i_buffer, i_len);
 +        s->c= ic;
 +        s->c.bytestream_start= pbbak_start;
 +        s->c.bytestream= pbbak + i_len;
 +        set_blocks(s, level, x, y, l, cb, cr, pmx, pmy, 0, BLOCK_INTRA);
 +        memcpy(s->block_state, i_state, sizeof(s->block_state));
 +        return iscore;
 +    }else{
 +        memcpy(pbbak, p_buffer, p_len);
 +        s->c= pc;
 +        s->c.bytestream_start= pbbak_start;
 +        s->c.bytestream= pbbak + p_len;
 +        set_blocks(s, level, x, y, pl, pcb, pcr, mx, my, best_ref, 0);
 +        memcpy(s->block_state, p_state, sizeof(s->block_state));
 +        return score;
 +    }
 +}
 +
 +static void encode_q_branch2(SnowContext *s, int level, int x, int y){
 +    const int w= s->b_width  << s->block_max_depth;
 +    const int rem_depth= s->block_max_depth - level;
 +    const int index= (x + y*w) << rem_depth;
 +    int trx= (x+1)<<rem_depth;
 +    BlockNode *b= &s->block[index];
 +    const BlockNode *left  = x ? &s->block[index-1] : &null_block;
 +    const BlockNode *top   = y ? &s->block[index-w] : &null_block;
 +    const BlockNode *tl    = y && x ? &s->block[index-w-1] : left;
 +    const BlockNode *tr    = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
 +    int pl = left->color[0];
 +    int pcb= left->color[1];
 +    int pcr= left->color[2];
 +    int pmx, pmy;
 +    int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
 +    int mx_context= av_log2(2*FFABS(left->mx - top->mx)) + 16*!!b->ref;
 +    int my_context= av_log2(2*FFABS(left->my - top->my)) + 16*!!b->ref;
 +    int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
 +
 +    if(s->keyframe){
 +        set_blocks(s, level, x, y, pl, pcb, pcr, 0, 0, 0, BLOCK_INTRA);
 +        return;
 +    }
 +
 +    if(level!=s->block_max_depth){
 +        if(same_block(b,b+1) && same_block(b,b+w) && same_block(b,b+w+1)){
 +            put_rac(&s->c, &s->block_state[4 + s_context], 1);
 +        }else{
 +            put_rac(&s->c, &s->block_state[4 + s_context], 0);
 +            encode_q_branch2(s, level+1, 2*x+0, 2*y+0);
 +            encode_q_branch2(s, level+1, 2*x+1, 2*y+0);
 +            encode_q_branch2(s, level+1, 2*x+0, 2*y+1);
 +            encode_q_branch2(s, level+1, 2*x+1, 2*y+1);
 +            return;
 +        }
 +    }
 +    if(b->type & BLOCK_INTRA){
 +        pred_mv(s, &pmx, &pmy, 0, left, top, tr);
 +        put_rac(&s->c, &s->block_state[1 + (left->type&1) + (top->type&1)], 1);
 +        put_symbol(&s->c, &s->block_state[32], b->color[0]-pl , 1);
 +        if (s->nb_planes > 2) {
 +            put_symbol(&s->c, &s->block_state[64], b->color[1]-pcb, 1);
 +            put_symbol(&s->c, &s->block_state[96], b->color[2]-pcr, 1);
 +        }
 +        set_blocks(s, level, x, y, b->color[0], b->color[1], b->color[2], pmx, pmy, 0, BLOCK_INTRA);
 +    }else{
 +        pred_mv(s, &pmx, &pmy, b->ref, left, top, tr);
 +        put_rac(&s->c, &s->block_state[1 + (left->type&1) + (top->type&1)], 0);
 +        if(s->ref_frames > 1)
 +            put_symbol(&s->c, &s->block_state[128 + 1024 + 32*ref_context], b->ref, 0);
 +        put_symbol(&s->c, &s->block_state[128 + 32*mx_context], b->mx - pmx, 1);
 +        put_symbol(&s->c, &s->block_state[128 + 32*my_context], b->my - pmy, 1);
 +        set_blocks(s, level, x, y, pl, pcb, pcr, b->mx, b->my, b->ref, 0);
 +    }
 +}
 +
 +static int get_dc(SnowContext *s, int mb_x, int mb_y, int plane_index){
 +    int i, x2, y2;
 +    Plane *p= &s->plane[plane_index];
 +    const int block_size = MB_SIZE >> s->block_max_depth;
 +    const int block_w    = plane_index ? block_size>>s->chroma_h_shift : block_size;
 +    const int block_h    = plane_index ? block_size>>s->chroma_v_shift : block_size;
 +    const uint8_t *obmc  = plane_index ? ff_obmc_tab[s->block_max_depth+s->chroma_h_shift] : ff_obmc_tab[s->block_max_depth];
 +    const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
 +    const int ref_stride= s->current_picture->linesize[plane_index];
 +    uint8_t *src= s-> input_picture->data[plane_index];
 +    IDWTELEM *dst= (IDWTELEM*)s->m.sc.obmc_scratchpad + plane_index*block_size*block_size*4; //FIXME change to unsigned
 +    const int b_stride = s->b_width << s->block_max_depth;
 +    const int w= p->width;
 +    const int h= p->height;
 +    int index= mb_x + mb_y*b_stride;
 +    BlockNode *b= &s->block[index];
 +    BlockNode backup= *b;
 +    int ab=0;
 +    int aa=0;
 +
 +    av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc stuff above
 +
 +    b->type|= BLOCK_INTRA;
 +    b->color[plane_index]= 0;
 +    memset(dst, 0, obmc_stride*obmc_stride*sizeof(IDWTELEM));
 +
 +    for(i=0; i<4; i++){
 +        int mb_x2= mb_x + (i &1) - 1;
 +        int mb_y2= mb_y + (i>>1) - 1;
 +        int x= block_w*mb_x2 + block_w/2;
 +        int y= block_h*mb_y2 + block_h/2;
 +
 +        add_yblock(s, 0, NULL, dst + (i&1)*block_w + (i>>1)*obmc_stride*block_h, NULL, obmc,
 +                    x, y, block_w, block_h, w, h, obmc_stride, ref_stride, obmc_stride, mb_x2, mb_y2, 0, 0, plane_index);
 +
 +        for(y2= FFMAX(y, 0); y2<FFMIN(h, y+block_h); y2++){
 +            for(x2= FFMAX(x, 0); x2<FFMIN(w, x+block_w); x2++){
 +                int index= x2-(block_w*mb_x - block_w/2) + (y2-(block_h*mb_y - block_h/2))*obmc_stride;
 +                int obmc_v= obmc[index];
 +                int d;
 +                if(y<0) obmc_v += obmc[index + block_h*obmc_stride];
 +                if(x<0) obmc_v += obmc[index + block_w];
 +                if(y+block_h>h) obmc_v += obmc[index - block_h*obmc_stride];
 +                if(x+block_w>w) obmc_v += obmc[index - block_w];
 +                //FIXME precalculate this or simplify it somehow else
 +
 +                d = -dst[index] + (1<<(FRAC_BITS-1));
 +                dst[index] = d;
 +                ab += (src[x2 + y2*ref_stride] - (d>>FRAC_BITS)) * obmc_v;
 +                aa += obmc_v * obmc_v; //FIXME precalculate this
 +            }
 +        }
 +    }
 +    *b= backup;
 +
 +    return av_clip_uint8( ROUNDED_DIV(ab<<LOG2_OBMC_MAX, aa) ); //FIXME we should not need clipping
 +}
 +
 +static inline int get_block_bits(SnowContext *s, int x, int y, int w){
 +    const int b_stride = s->b_width << s->block_max_depth;
 +    const int b_height = s->b_height<< s->block_max_depth;
 +    int index= x + y*b_stride;
 +    const BlockNode *b     = &s->block[index];
 +    const BlockNode *left  = x ? &s->block[index-1] : &null_block;
 +    const BlockNode *top   = y ? &s->block[index-b_stride] : &null_block;
 +    const BlockNode *tl    = y && x ? &s->block[index-b_stride-1] : left;
 +    const BlockNode *tr    = y && x+w<b_stride ? &s->block[index-b_stride+w] : tl;
 +    int dmx, dmy;
 +//  int mx_context= av_log2(2*FFABS(left->mx - top->mx));
 +//  int my_context= av_log2(2*FFABS(left->my - top->my));
 +
 +    if(x<0 || x>=b_stride || y>=b_height)
 +        return 0;
 +/*
 +1            0      0
 +01X          1-2    1
 +001XX        3-6    2-3
 +0001XXX      7-14   4-7
 +00001XXXX   15-30   8-15
 +*/
 +//FIXME try accurate rate
 +//FIXME intra and inter predictors if surrounding blocks are not the same type
 +    if(b->type & BLOCK_INTRA){
 +        return 3+2*( av_log2(2*FFABS(left->color[0] - b->color[0]))
 +                   + av_log2(2*FFABS(left->color[1] - b->color[1]))
 +                   + av_log2(2*FFABS(left->color[2] - b->color[2])));
 +    }else{
 +        pred_mv(s, &dmx, &dmy, b->ref, left, top, tr);
 +        dmx-= b->mx;
 +        dmy-= b->my;
 +        return 2*(1 + av_log2(2*FFABS(dmx)) //FIXME kill the 2* can be merged in lambda
 +                    + av_log2(2*FFABS(dmy))
 +                    + av_log2(2*b->ref));
 +    }
 +}
 +
 +static int get_block_rd(SnowContext *s, int mb_x, int mb_y, int plane_index, uint8_t (*obmc_edged)[MB_SIZE * 2]){
 +    Plane *p= &s->plane[plane_index];
 +    const int block_size = MB_SIZE >> s->block_max_depth;
 +    const int block_w    = plane_index ? block_size>>s->chroma_h_shift : block_size;
 +    const int block_h    = plane_index ? block_size>>s->chroma_v_shift : block_size;
 +    const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
 +    const int ref_stride= s->current_picture->linesize[plane_index];
 +    uint8_t *dst= s->current_picture->data[plane_index];
 +    uint8_t *src= s->  input_picture->data[plane_index];
 +    IDWTELEM *pred= (IDWTELEM*)s->m.sc.obmc_scratchpad + plane_index*block_size*block_size*4;
 +    uint8_t *cur = s->scratchbuf;
 +    uint8_t *tmp = s->emu_edge_buffer;
 +    const int b_stride = s->b_width << s->block_max_depth;
 +    const int b_height = s->b_height<< s->block_max_depth;
 +    const int w= p->width;
 +    const int h= p->height;
 +    int distortion;
 +    int rate= 0;
 +    const int penalty_factor= get_penalty_factor(s->lambda, s->lambda2, s->avctx->me_cmp);
 +    int sx= block_w*mb_x - block_w/2;
 +    int sy= block_h*mb_y - block_h/2;
 +    int x0= FFMAX(0,-sx);
 +    int y0= FFMAX(0,-sy);
 +    int x1= FFMIN(block_w*2, w-sx);
 +    int y1= FFMIN(block_h*2, h-sy);
 +    int i,x,y;
 +
 +    av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below chckinhg only block_w
 +
 +    ff_snow_pred_block(s, cur, tmp, ref_stride, sx, sy, block_w*2, block_h*2, &s->block[mb_x + mb_y*b_stride], plane_index, w, h);
 +
 +    for(y=y0; y<y1; y++){
 +        const uint8_t *obmc1= obmc_edged[y];
 +        const IDWTELEM *pred1 = pred + y*obmc_stride;
 +        uint8_t *cur1 = cur + y*ref_stride;
 +        uint8_t *dst1 = dst + sx + (sy+y)*ref_stride;
 +        for(x=x0; x<x1; x++){
 +#if FRAC_BITS >= LOG2_OBMC_MAX
 +            int v = (cur1[x] * obmc1[x]) << (FRAC_BITS - LOG2_OBMC_MAX);
 +#else
 +            int v = (cur1[x] * obmc1[x] + (1<<(LOG2_OBMC_MAX - FRAC_BITS-1))) >> (LOG2_OBMC_MAX - FRAC_BITS);
 +#endif
 +            v = (v + pred1[x]) >> FRAC_BITS;
 +            if(v&(~255)) v= ~(v>>31);
 +            dst1[x] = v;
 +        }
 +    }
 +
 +    /* copy the regions where obmc[] = (uint8_t)256 */
 +    if(LOG2_OBMC_MAX == 8
 +        && (mb_x == 0 || mb_x == b_stride-1)
 +        && (mb_y == 0 || mb_y == b_height-1)){
 +        if(mb_x == 0)
 +            x1 = block_w;
 +        else
 +            x0 = block_w;
 +        if(mb_y == 0)
 +            y1 = block_h;
 +        else
 +            y0 = block_h;
 +        for(y=y0; y<y1; y++)
 +            memcpy(dst + sx+x0 + (sy+y)*ref_stride, cur + x0 + y*ref_stride, x1-x0);
 +    }
 +
 +    if(block_w==16){
 +        /* FIXME rearrange dsputil to fit 32x32 cmp functions */
 +        /* FIXME check alignment of the cmp wavelet vs the encoding wavelet */
 +        /* FIXME cmps overlap but do not cover the wavelet's whole support.
 +         * So improving the score of one block is not strictly guaranteed
 +         * to improve the score of the whole frame, thus iterative motion
 +         * estimation does not always converge. */
 +        if(s->avctx->me_cmp == FF_CMP_W97)
 +            distortion = ff_w97_32_c(&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32);
 +        else if(s->avctx->me_cmp == FF_CMP_W53)
 +            distortion = ff_w53_32_c(&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32);
 +        else{
 +            distortion = 0;
 +            for(i=0; i<4; i++){
 +                int off = sx+16*(i&1) + (sy+16*(i>>1))*ref_stride;
 +                distortion += s->mecc.me_cmp[0](&s->m, src + off, dst + off, ref_stride, 16);
 +            }
 +        }
 +    }else{
 +        av_assert2(block_w==8);
 +        distortion = s->mecc.me_cmp[0](&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2);
 +    }
 +
 +    if(plane_index==0){
 +        for(i=0; i<4; i++){
 +/* ..RRr
 + * .RXx.
 + * rxx..
 + */
 +            rate += get_block_bits(s, mb_x + (i&1) - (i>>1), mb_y + (i>>1), 1);
 +        }
 +        if(mb_x == b_stride-2)
 +            rate += get_block_bits(s, mb_x + 1, mb_y + 1, 1);
 +    }
 +    return distortion + rate*penalty_factor;
 +}
 +
 +static int get_4block_rd(SnowContext *s, int mb_x, int mb_y, int plane_index){
 +    int i, y2;
 +    Plane *p= &s->plane[plane_index];
 +    const int block_size = MB_SIZE >> s->block_max_depth;
 +    const int block_w    = plane_index ? block_size>>s->chroma_h_shift : block_size;
 +    const int block_h    = plane_index ? block_size>>s->chroma_v_shift : block_size;
 +    const uint8_t *obmc  = plane_index ? ff_obmc_tab[s->block_max_depth+s->chroma_h_shift] : ff_obmc_tab[s->block_max_depth];
 +    const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
 +    const int ref_stride= s->current_picture->linesize[plane_index];
 +    uint8_t *dst= s->current_picture->data[plane_index];
 +    uint8_t *src= s-> input_picture->data[plane_index];
 +    //FIXME zero_dst is const but add_yblock changes dst if add is 0 (this is never the case for dst=zero_dst
 +    // const has only been removed from zero_dst to suppress a warning
 +    static IDWTELEM zero_dst[4096]; //FIXME
 +    const int b_stride = s->b_width << s->block_max_depth;
 +    const int w= p->width;
 +    const int h= p->height;
 +    int distortion= 0;
 +    int rate= 0;
 +    const int penalty_factor= get_penalty_factor(s->lambda, s->lambda2, s->avctx->me_cmp);
 +
 +    av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below
 +
 +    for(i=0; i<9; i++){
 +        int mb_x2= mb_x + (i%3) - 1;
 +        int mb_y2= mb_y + (i/3) - 1;
 +        int x= block_w*mb_x2 + block_w/2;
 +        int y= block_h*mb_y2 + block_h/2;
 +
 +        add_yblock(s, 0, NULL, zero_dst, dst, obmc,
 +                   x, y, block_w, block_h, w, h, /*dst_stride*/0, ref_stride, obmc_stride, mb_x2, mb_y2, 1, 1, plane_index);
 +
 +        //FIXME find a cleaner/simpler way to skip the outside stuff
 +        for(y2= y; y2<0; y2++)
 +            memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, block_w);
 +        for(y2= h; y2<y+block_h; y2++)
 +            memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, block_w);
 +        if(x<0){
 +            for(y2= y; y2<y+block_h; y2++)
 +                memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, -x);
 +        }
 +        if(x+block_w > w){
 +            for(y2= y; y2<y+block_h; y2++)
 +                memcpy(dst + w + y2*ref_stride, src + w + y2*ref_stride, x+block_w - w);
 +        }
 +
 +        av_assert1(block_w== 8 || block_w==16);
 +        distortion += s->mecc.me_cmp[block_w==8](&s->m, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_h);
 +    }
 +
 +    if(plane_index==0){
 +        BlockNode *b= &s->block[mb_x+mb_y*b_stride];
 +        int merged= same_block(b,b+1) && same_block(b,b+b_stride) && same_block(b,b+b_stride+1);
 +
 +/* ..RRRr
 + * .RXXx.
 + * .RXXx.
 + * rxxx.
 + */
 +        if(merged)
 +            rate = get_block_bits(s, mb_x, mb_y, 2);
 +        for(i=merged?4:0; i<9; i++){
 +            static const int dxy[9][2] = {{0,0},{1,0},{0,1},{1,1},{2,0},{2,1},{-1,2},{0,2},{1,2}};
 +            rate += get_block_bits(s, mb_x + dxy[i][0], mb_y + dxy[i][1], 1);
 +        }
 +    }
 +    return distortion + rate*penalty_factor;
 +}
 +
 +static int encode_subband_c0run(SnowContext *s, SubBand *b, const IDWTELEM *src, const IDWTELEM *parent, int stride, int orientation){
 +    const int w= b->width;
 +    const int h= b->height;
 +    int x, y;
 +
 +    if(1){
 +        int run=0;
 +        int *runs = s->run_buffer;
 +        int run_index=0;
 +        int max_index;
 +
 +        for(y=0; y<h; y++){
 +            for(x=0; x<w; x++){
 +                int v, p=0;
 +                int /*ll=0, */l=0, lt=0, t=0, rt=0;
 +                v= src[x + y*stride];
 +
 +                if(y){
 +                    t= src[x + (y-1)*stride];
 +                    if(x){
 +                        lt= src[x - 1 + (y-1)*stride];
 +                    }
 +                    if(x + 1 < w){
 +                        rt= src[x + 1 + (y-1)*stride];
 +                    }
 +                }
 +                if(x){
 +                    l= src[x - 1 + y*stride];
 +                    /*if(x > 1){
 +                        if(orientation==1) ll= src[y + (x-2)*stride];
 +                        else               ll= src[x - 2 + y*stride];
 +                    }*/
 +                }
 +                if(parent){
 +                    int px= x>>1;
 +                    int py= y>>1;
 +                    if(px<b->parent->width && py<b->parent->height)
 +                        p= parent[px + py*2*stride];
 +                }
 +                if(!(/*ll|*/l|lt|t|rt|p)){
 +                    if(v){
 +                        runs[run_index++]= run;
 +                        run=0;
 +                    }else{
 +                        run++;
 +                    }
 +                }
 +            }
 +        }
 +        max_index= run_index;
 +        runs[run_index++]= run;
 +        run_index=0;
 +        run= runs[run_index++];
 +
 +        put_symbol2(&s->c, b->state[30], max_index, 0);
 +        if(run_index <= max_index)
 +            put_symbol2(&s->c, b->state[1], run, 3);
 +
 +        for(y=0; y<h; y++){
 +            if(s->c.bytestream_end - s->c.bytestream < w*40){
 +                av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
 +                return -1;
 +            }
 +            for(x=0; x<w; x++){
 +                int v, p=0;
 +                int /*ll=0, */l=0, lt=0, t=0, rt=0;
 +                v= src[x + y*stride];
 +
 +                if(y){
 +                    t= src[x + (y-1)*stride];
 +                    if(x){
 +                        lt= src[x - 1 + (y-1)*stride];
 +                    }
 +                    if(x + 1 < w){
 +                        rt= src[x + 1 + (y-1)*stride];
 +                    }
 +                }
 +                if(x){
 +                    l= src[x - 1 + y*stride];
 +                    /*if(x > 1){
 +                        if(orientation==1) ll= src[y + (x-2)*stride];
 +                        else               ll= src[x - 2 + y*stride];
 +                    }*/
 +                }
 +                if(parent){
 +                    int px= x>>1;
 +                    int py= y>>1;
 +                    if(px<b->parent->width && py<b->parent->height)
 +                        p= parent[px + py*2*stride];
 +                }
 +                if(/*ll|*/l|lt|t|rt|p){
 +                    int context= av_log2(/*FFABS(ll) + */3*FFABS(l) + FFABS(lt) + 2*FFABS(t) + FFABS(rt) + FFABS(p));
 +
 +                    put_rac(&s->c, &b->state[0][context], !!v);
 +                }else{
 +                    if(!run){
 +                        run= runs[run_index++];
 +
 +                        if(run_index <= max_index)
 +                            put_symbol2(&s->c, b->state[1], run, 3);
 +                        av_assert2(v);
 +                    }else{
 +                        run--;
 +                        av_assert2(!v);
 +                    }
 +                }
 +                if(v){
 +                    int context= av_log2(/*FFABS(ll) + */3*FFABS(l) + FFABS(lt) + 2*FFABS(t) + FFABS(rt) + FFABS(p));
 +                    int l2= 2*FFABS(l) + (l<0);
 +                    int t2= 2*FFABS(t) + (t<0);
 +
 +                    put_symbol2(&s->c, b->state[context + 2], FFABS(v)-1, context-4);
 +                    put_rac(&s->c, &b->state[0][16 + 1 + 3 + ff_quant3bA[l2&0xFF] + 3*ff_quant3bA[t2&0xFF]], v<0);
 +                }
 +            }
 +        }
 +    }
 +    return 0;
 +}
 +
 +static int encode_subband(SnowContext *s, SubBand *b, const IDWTELEM *src, const IDWTELEM *parent, int stride, int orientation){
 +//    encode_subband_qtree(s, b, src, parent, stride, orientation);
 +//    encode_subband_z0run(s, b, src, parent, stride, orientation);
 +    return encode_subband_c0run(s, b, src, parent, stride, orientation);
 +//    encode_subband_dzr(s, b, src, parent, stride, orientation);
 +}
 +
 +static av_always_inline int check_block(SnowContext *s, int mb_x, int mb_y, int p[3], int intra, uint8_t (*obmc_edged)[MB_SIZE * 2], int *best_rd){
 +    const int b_stride= s->b_width << s->block_max_depth;
 +    BlockNode *block= &s->block[mb_x + mb_y * b_stride];
 +    BlockNode backup= *block;
 +    unsigned value;
 +    int rd, index;
 +
 +    av_assert2(mb_x>=0 && mb_y>=0);
 +    av_assert2(mb_x<b_stride);
 +
 +    if(intra){
 +        block->color[0] = p[0];
 +        block->color[1] = p[1];
 +        block->color[2] = p[2];
 +        block->type |= BLOCK_INTRA;
 +    }else{
 +        index= (p[0] + 31*p[1]) & (ME_CACHE_SIZE-1);
 +        value= s->me_cache_generation + (p[0]>>10) + (p[1]<<6) + (block->ref<<12);
 +        if(s->me_cache[index] == value)
 +            return 0;
 +        s->me_cache[index]= value;
 +
 +        block->mx= p[0];
 +        block->my= p[1];
 +        block->type &= ~BLOCK_INTRA;
 +    }
 +
 +    rd= get_block_rd(s, mb_x, mb_y, 0, obmc_edged) + s->intra_penalty * !!intra;
 +
 +//FIXME chroma
 +    if(rd < *best_rd){
 +        *best_rd= rd;
 +        return 1;
 +    }else{
 +        *block= backup;
 +        return 0;
 +    }
 +}
 +
 +/* special case for int[2] args we discard afterwards,
 + * fixes compilation problem with gcc 2.95 */
 +static av_always_inline int check_block_inter(SnowContext *s, int mb_x, int mb_y, int p0, int p1, uint8_t (*obmc_edged)[MB_SIZE * 2], int *best_rd){
 +    int p[2] = {p0, p1};
 +    return check_block(s, mb_x, mb_y, p, 0, obmc_edged, best_rd);
 +}
 +
 +static av_always_inline int check_4block_inter(SnowContext *s, int mb_x, int mb_y, int p0, int p1, int ref, int *best_rd){
 +    const int b_stride= s->b_width << s->block_max_depth;
 +    BlockNode *block= &s->block[mb_x + mb_y * b_stride];
 +    BlockNode backup[4];
 +    unsigned value;
 +    int rd, index;
 +
 +    /* We don't initialize backup[] during variable declaration, because
 +     * that fails to compile on MSVC: "cannot convert from 'BlockNode' to
 +     * 'int16_t'". */
 +    backup[0] = block[0];
 +    backup[1] = block[1];
 +    backup[2] = block[b_stride];
 +    backup[3] = block[b_stride + 1];
 +
 +    av_assert2(mb_x>=0 && mb_y>=0);
 +    av_assert2(mb_x<b_stride);
 +    av_assert2(((mb_x|mb_y)&1) == 0);
 +
 +    index= (p0 + 31*p1) & (ME_CACHE_SIZE-1);
 +    value= s->me_cache_generation + (p0>>10) + (p1<<6) + (block->ref<<12);
 +    if(s->me_cache[index] == value)
 +        return 0;
 +    s->me_cache[index]= value;
 +
 +    block->mx= p0;
 +    block->my= p1;
 +    block->ref= ref;
 +    block->type &= ~BLOCK_INTRA;
 +    block[1]= block[b_stride]= block[b_stride+1]= *block;
 +
 +    rd= get_4block_rd(s, mb_x, mb_y, 0);
 +
 +//FIXME chroma
 +    if(rd < *best_rd){
 +        *best_rd= rd;
 +        return 1;
 +    }else{
 +        block[0]= backup[0];
 +        block[1]= backup[1];
 +        block[b_stride]= backup[2];
 +        block[b_stride+1]= backup[3];
 +        return 0;
 +    }
 +}
 +
 +static void iterative_me(SnowContext *s){
 +    int pass, mb_x, mb_y;
 +    const int b_width = s->b_width  << s->block_max_depth;
 +    const int b_height= s->b_height << s->block_max_depth;
 +    const int b_stride= b_width;
 +    int color[3];
 +
 +    {
 +        RangeCoder r = s->c;
 +        uint8_t state[sizeof(s->block_state)];
 +        memcpy(state, s->block_state, sizeof(s->block_state));
 +        for(mb_y= 0; mb_y<s->b_height; mb_y++)
 +            for(mb_x= 0; mb_x<s->b_width; mb_x++)
 +                encode_q_branch(s, 0, mb_x, mb_y);
 +        s->c = r;
 +        memcpy(s->block_state, state, sizeof(s->block_state));
 +    }
 +
 +    for(pass=0; pass<25; pass++){
 +        int change= 0;
 +
 +        for(mb_y= 0; mb_y<b_height; mb_y++){
 +            for(mb_x= 0; mb_x<b_width; mb_x++){
 +                int dia_change, i, j, ref;
 +                int best_rd= INT_MAX, ref_rd;
 +                BlockNode backup, ref_b;
 +                const int index= mb_x + mb_y * b_stride;
 +                BlockNode *block= &s->block[index];
 +                BlockNode *tb =                   mb_y            ? &s->block[index-b_stride  ] : NULL;
 +                BlockNode *lb = mb_x                              ? &s->block[index         -1] : NULL;
 +                BlockNode *rb = mb_x+1<b_width                    ? &s->block[index         +1] : NULL;
 +                BlockNode *bb =                   mb_y+1<b_height ? &s->block[index+b_stride  ] : NULL;
 +                BlockNode *tlb= mb_x           && mb_y            ? &s->block[index-b_stride-1] : NULL;
 +                BlockNode *trb= mb_x+1<b_width && mb_y            ? &s->block[index-b_stride+1] : NULL;
 +                BlockNode *blb= mb_x           && mb_y+1<b_height ? &s->block[index+b_stride-1] : NULL;
 +                BlockNode *brb= mb_x+1<b_width && mb_y+1<b_height ? &s->block[index+b_stride+1] : NULL;
 +                const int b_w= (MB_SIZE >> s->block_max_depth);
 +                uint8_t obmc_edged[MB_SIZE * 2][MB_SIZE * 2];
 +
 +                if(pass && (block->type & BLOCK_OPT))
 +                    continue;
 +                block->type |= BLOCK_OPT;
 +
 +                backup= *block;
 +
 +                if(!s->me_cache_generation)
 +                    memset(s->me_cache, 0, sizeof(s->me_cache));
 +                s->me_cache_generation += 1<<22;
 +
 +                //FIXME precalculate
 +                {
 +                    int x, y;
 +                    for (y = 0; y < b_w * 2; y++)
 +                        memcpy(obmc_edged[y], ff_obmc_tab[s->block_max_depth] + y * b_w * 2, b_w * 2);
 +                    if(mb_x==0)
 +                        for(y=0; y<b_w*2; y++)
 +                            memset(obmc_edged[y], obmc_edged[y][0] + obmc_edged[y][b_w-1], b_w);
 +                    if(mb_x==b_stride-1)
 +                        for(y=0; y<b_w*2; y++)
 +                            memset(obmc_edged[y]+b_w, obmc_edged[y][b_w] + obmc_edged[y][b_w*2-1], b_w);
 +                    if(mb_y==0){
 +                        for(x=0; x<b_w*2; x++)
 +                            obmc_edged[0][x] += obmc_edged[b_w-1][x];
 +                        for(y=1; y<b_w; y++)
 +                            memcpy(obmc_edged[y], obmc_edged[0], b_w*2);
 +                    }
 +                    if(mb_y==b_height-1){
 +                        for(x=0; x<b_w*2; x++)
 +                            obmc_edged[b_w*2-1][x] += obmc_edged[b_w][x];
 +                        for(y=b_w; y<b_w*2-1; y++)
 +                            memcpy(obmc_edged[y], obmc_edged[b_w*2-1], b_w*2);
 +                    }
 +                }
 +
 +                //skip stuff outside the picture
 +                if(mb_x==0 || mb_y==0 || mb_x==b_width-1 || mb_y==b_height-1){
 +                    uint8_t *src= s->  input_picture->data[0];
 +                    uint8_t *dst= s->current_picture->data[0];
 +                    const int stride= s->current_picture->linesize[0];
 +                    const int block_w= MB_SIZE >> s->block_max_depth;
 +                    const int block_h= MB_SIZE >> s->block_max_depth;
 +                    const int sx= block_w*mb_x - block_w/2;
 +                    const int sy= block_h*mb_y - block_h/2;
 +                    const int w= s->plane[0].width;
 +                    const int h= s->plane[0].height;
 +                    int y;
 +
 +                    for(y=sy; y<0; y++)
 +                        memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
 +                    for(y=h; y<sy+block_h*2; y++)
 +                        memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
 +                    if(sx<0){
 +                        for(y=sy; y<sy+block_h*2; y++)
 +                            memcpy(dst + sx + y*stride, src + sx + y*stride, -sx);
 +                    }
 +                    if(sx+block_w*2 > w){
 +                        for(y=sy; y<sy+block_h*2; y++)
 +                            memcpy(dst + w + y*stride, src + w + y*stride, sx+block_w*2 - w);
 +                    }
 +                }
 +
 +                // intra(black) = neighbors' contribution to the current block
 +                for(i=0; i < s->nb_planes; i++)
 +                    color[i]= get_dc(s, mb_x, mb_y, i);
 +
 +                // get previous score (cannot be cached due to OBMC)
 +                if(pass > 0 && (block->type&BLOCK_INTRA)){
 +                    int color0[3]= {block->color[0], block->color[1], block->color[2]};
 +                    check_block(s, mb_x, mb_y, color0, 1, obmc_edged, &best_rd);
 +                }else
 +                    check_block_inter(s, mb_x, mb_y, block->mx, block->my, obmc_edged, &best_rd);
 +
 +                ref_b= *block;
 +                ref_rd= best_rd;
 +                for(ref=0; ref < s->ref_frames; ref++){
 +                    int16_t (*mvr)[2]= &s->ref_mvs[ref][index];
 +                    if(s->ref_scores[ref][index] > s->ref_scores[ref_b.ref][index]*3/2) //FIXME tune threshold
 +                        continue;
 +                    block->ref= ref;
 +                    best_rd= INT_MAX;
 +
 +                    check_block_inter(s, mb_x, mb_y, mvr[0][0], mvr[0][1], obmc_edged, &best_rd);
 +                    check_block_inter(s, mb_x, mb_y, 0, 0, obmc_edged, &best_rd);
 +                    if(tb)
 +                        check_block_inter(s, mb_x, mb_y, mvr[-b_stride][0], mvr[-b_stride][1], obmc_edged, &best_rd);
 +                    if(lb)
 +                        check_block_inter(s, mb_x, mb_y, mvr[-1][0], mvr[-1][1], obmc_edged, &best_rd);
 +                    if(rb)
 +                        check_block_inter(s, mb_x, mb_y, mvr[1][0], mvr[1][1], obmc_edged, &best_rd);
 +                    if(bb)
 +                        check_block_inter(s, mb_x, mb_y, mvr[b_stride][0], mvr[b_stride][1], obmc_edged, &best_rd);
 +
 +                    /* fullpel ME */
 +                    //FIXME avoid subpel interpolation / round to nearest integer
 +                    do{
 +                        int newx = block->mx;
 +                        int newy = block->my;
 +                        dia_change=0;
 +                        for(i=0; i<FFMAX(s->avctx->dia_size, 1); i++){
 +                            for(j=0; j<i; j++){
 +                                dia_change |= check_block_inter(s, mb_x, mb_y, newx+4*(i-j), newy+(4*j), obmc_edged, &best_rd);
 +                                dia_change |= check_block_inter(s, mb_x, mb_y, newx-4*(i-j), newy-(4*j), obmc_edged, &best_rd);
 +                                dia_change |= check_block_inter(s, mb_x, mb_y, newx-(4*j), newy+4*(i-j), obmc_edged, &best_rd);
 +                                dia_change |= check_block_inter(s, mb_x, mb_y, newx+(4*j), newy-4*(i-j), obmc_edged, &best_rd);
 +                            }
 +                        }
 +                    }while(dia_change);
 +                    /* subpel ME */
 +                    do{
 +                        static const int square[8][2]= {{+1, 0},{-1, 0},{ 0,+1},{ 0,-1},{+1,+1},{-1,-1},{+1,-1},{-1,+1},};
 +                        dia_change=0;
 +                        for(i=0; i<8; i++)
 +                            dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+square[i][0], block->my+square[i][1], obmc_edged, &best_rd);
 +                    }while(dia_change);
 +                    //FIXME or try the standard 2 pass qpel or similar
 +
 +                    mvr[0][0]= block->mx;
 +                    mvr[0][1]= block->my;
 +                    if(ref_rd > best_rd){
 +                        ref_rd= best_rd;
 +                        ref_b= *block;
 +                    }
 +                }
 +                best_rd= ref_rd;
 +                *block= ref_b;
 +                check_block(s, mb_x, mb_y, color, 1, obmc_edged, &best_rd);
 +                //FIXME RD style color selection
 +                if(!same_block(block, &backup)){
 +                    if(tb ) tb ->type &= ~BLOCK_OPT;
 +                    if(lb ) lb ->type &= ~BLOCK_OPT;
 +                    if(rb ) rb ->type &= ~BLOCK_OPT;
 +                    if(bb ) bb ->type &= ~BLOCK_OPT;
 +                    if(tlb) tlb->type &= ~BLOCK_OPT;
 +                    if(trb) trb->type &= ~BLOCK_OPT;
 +                    if(blb) blb->type &= ~BLOCK_OPT;
 +                    if(brb) brb->type &= ~BLOCK_OPT;
 +                    change ++;
 +                }
 +            }
 +        }
 +        av_log(s->avctx, AV_LOG_DEBUG, "pass:%d changed:%d\n", pass, change);
 +        if(!change)
 +            break;
 +    }
 +
 +    if(s->block_max_depth == 1){
 +        int change= 0;
 +        for(mb_y= 0; mb_y<b_height; mb_y+=2){
 +            for(mb_x= 0; mb_x<b_width; mb_x+=2){
 +                int i;
 +                int best_rd, init_rd;
 +                const int index= mb_x + mb_y * b_stride;
 +                BlockNode *b[4];
 +
 +                b[0]= &s->block[index];
 +                b[1]= b[0]+1;
 +                b[2]= b[0]+b_stride;
 +                b[3]= b[2]+1;
 +                if(same_block(b[0], b[1]) &&
 +                   same_block(b[0], b[2]) &&
 +                   same_block(b[0], b[3]))
 +                    continue;
 +
 +                if(!s->me_cache_generation)
 +                    memset(s->me_cache, 0, sizeof(s->me_cache));
 +                s->me_cache_generation += 1<<22;
 +
 +                init_rd= best_rd= get_4block_rd(s, mb_x, mb_y, 0);
 +
 +                //FIXME more multiref search?
 +                check_4block_inter(s, mb_x, mb_y,
 +                                   (b[0]->mx + b[1]->mx + b[2]->mx + b[3]->mx + 2) >> 2,
 +                                   (b[0]->my + b[1]->my + b[2]->my + b[3]->my + 2) >> 2, 0, &best_rd);
 +
 +                for(i=0; i<4; i++)
 +                    if(!(b[i]->type&BLOCK_INTRA))
 +                        check_4block_inter(s, mb_x, mb_y, b[i]->mx, b[i]->my, b[i]->ref, &best_rd);
 +
 +                if(init_rd != best_rd)
 +                    change++;
 +            }
 +        }
 +        av_log(s->avctx, AV_LOG_ERROR, "pass:4mv changed:%d\n", change*4);
 +    }
 +}
 +
 +static void encode_blocks(SnowContext *s, int search){
 +    int x, y;
 +    int w= s->b_width;
 +    int h= s->b_height;
 +
 +    if(s->avctx->me_method == ME_ITER && !s->keyframe && search)
 +        iterative_me(s);
 +
 +    for(y=0; y<h; y++){
 +        if(s->c.bytestream_end - s->c.bytestream < w*MB_SIZE*MB_SIZE*3){ //FIXME nicer limit
 +            av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
 +            return;
 +        }
 +        for(x=0; x<w; x++){
 +            if(s->avctx->me_method == ME_ITER || !search)
 +                encode_q_branch2(s, 0, x, y);
 +            else
 +                encode_q_branch (s, 0, x, y);
 +        }
 +    }
 +}
 +
 +static void quantize(SnowContext *s, SubBand *b, IDWTELEM *dst, DWTELEM *src, int stride, int bias){
 +    const int w= b->width;
 +    const int h= b->height;
 +    const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
 +    const int qmul= ff_qexp[qlog&(QROOT-1)]<<((qlog>>QSHIFT) + ENCODER_EXTRA_BITS);
 +    int x,y, thres1, thres2;
 +
 +    if(s->qlog == LOSSLESS_QLOG){
 +        for(y=0; y<h; y++)
 +            for(x=0; x<w; x++)
 +                dst[x + y*stride]= src[x + y*stride];
 +        return;
 +    }
 +
 +    bias= bias ? 0 : (3*qmul)>>3;
 +    thres1= ((qmul - bias)>>QEXPSHIFT) - 1;
 +    thres2= 2*thres1;
 +
 +    if(!bias){
 +        for(y=0; y<h; y++){
 +            for(x=0; x<w; x++){
 +                int i= src[x + y*stride];
 +
 +                if((unsigned)(i+thres1) > thres2){
 +                    if(i>=0){
 +                        i<<= QEXPSHIFT;
 +                        i/= qmul; //FIXME optimize
 +                        dst[x + y*stride]=  i;
 +                    }else{
 +                        i= -i;
 +                        i<<= QEXPSHIFT;
 +                        i/= qmul; //FIXME optimize
 +                        dst[x + y*stride]= -i;
 +                    }
 +                }else
 +                    dst[x + y*stride]= 0;
 +            }
 +        }
 +    }else{
 +        for(y=0; y<h; y++){
 +            for(x=0; x<w; x++){
 +                int i= src[x + y*stride];
 +
 +                if((unsigned)(i+thres1) > thres2){
 +                    if(i>=0){
 +                        i<<= QEXPSHIFT;
 +                        i= (i + bias) / qmul; //FIXME optimize
 +                        dst[x + y*stride]=  i;
 +                    }else{
 +                        i= -i;
 +                        i<<= QEXPSHIFT;
 +                        i= (i + bias) / qmul; //FIXME optimize
 +                        dst[x + y*stride]= -i;
 +                    }
 +                }else
 +                    dst[x + y*stride]= 0;
 +            }
 +        }
 +    }
 +}
 +
 +static void dequantize(SnowContext *s, SubBand *b, IDWTELEM *src, int stride){
 +    const int w= b->width;
 +    const int h= b->height;
 +    const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
 +    const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
 +    const int qadd= (s->qbias*qmul)>>QBIAS_SHIFT;
 +    int x,y;
 +
 +    if(s->qlog == LOSSLESS_QLOG) return;
 +
 +    for(y=0; y<h; y++){
 +        for(x=0; x<w; x++){
 +            int i= src[x + y*stride];
 +            if(i<0){
 +                src[x + y*stride]= -((-i*qmul + qadd)>>(QEXPSHIFT)); //FIXME try different bias
 +            }else if(i>0){
 +                src[x + y*stride]=  (( i*qmul + qadd)>>(QEXPSHIFT));
 +            }
 +        }
 +    }
 +}
 +
 +static void decorrelate(SnowContext *s, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median){
 +    const int w= b->width;
 +    const int h= b->height;
 +    int x,y;
 +
 +    for(y=h-1; y>=0; y--){
 +        for(x=w-1; x>=0; x--){
 +            int i= x + y*stride;
 +
 +            if(x){
 +                if(use_median){
 +                    if(y && x+1<w) src[i] -= mid_pred(src[i - 1], src[i - stride], src[i - stride + 1]);
 +                    else  src[i] -= src[i - 1];
 +                }else{
 +                    if(y) src[i] -= mid_pred(src[i - 1], src[i - stride], src[i - 1] + src[i - stride] - src[i - 1 - stride]);
 +                    else  src[i] -= src[i - 1];
 +                }
 +            }else{
 +                if(y) src[i] -= src[i - stride];
 +            }
 +        }
 +    }
 +}
 +
 +static void correlate(SnowContext *s, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median){
 +    const int w= b->width;
 +    const int h= b->height;
 +    int x,y;
 +
 +    for(y=0; y<h; y++){
 +        for(x=0; x<w; x++){
 +            int i= x + y*stride;
 +
 +            if(x){
 +                if(use_median){
 +                    if(y && x+1<w) src[i] += mid_pred(src[i - 1], src[i - stride], src[i - stride + 1]);
 +                    else  src[i] += src[i - 1];
 +                }else{
 +                    if(y) src[i] += mid_pred(src[i - 1], src[i - stride], src[i - 1] + src[i - stride] - src[i - 1 - stride]);
 +                    else  src[i] += src[i - 1];
 +                }
 +            }else{
 +                if(y) src[i] += src[i - stride];
 +            }
 +        }
 +    }
 +}
 +
 +static void encode_qlogs(SnowContext *s){
 +    int plane_index, level, orientation;
 +
 +    for(plane_index=0; plane_index<FFMIN(s->nb_planes, 2); plane_index++){
 +        for(level=0; level<s->spatial_decomposition_count; level++){
 +            for(orientation=level ? 1:0; orientation<4; orientation++){
 +                if(orientation==2) continue;
 +                put_symbol(&s->c, s->header_state, s->plane[plane_index].band[level][orientation].qlog, 1);
 +            }
 +        }
 +    }
 +}
 +
 +static void encode_header(SnowContext *s){
 +    int plane_index, i;
 +    uint8_t kstate[32];
 +
 +    memset(kstate, MID_STATE, sizeof(kstate));
 +
 +    put_rac(&s->c, kstate, s->keyframe);
 +    if(s->keyframe || s->always_reset){
 +        ff_snow_reset_contexts(s);
 +        s->last_spatial_decomposition_type=
 +        s->last_qlog=
 +        s->last_qbias=
 +        s->last_mv_scale=
 +        s->last_block_max_depth= 0;
 +        for(plane_index=0; plane_index<2; plane_index++){
 +            Plane *p= &s->plane[plane_index];
 +            p->last_htaps=0;
 +            p->last_diag_mc=0;
 +            memset(p->last_hcoeff, 0, sizeof(p->last_hcoeff));
 +        }
 +    }
 +    if(s->keyframe){
 +        put_symbol(&s->c, s->header_state, s->version, 0);
 +        put_rac(&s->c, s->header_state, s->always_reset);
 +        put_symbol(&s->c, s->header_state, s->temporal_decomposition_type, 0);
 +        put_symbol(&s->c, s->header_state, s->temporal_decomposition_count, 0);
 +        put_symbol(&s->c, s->header_state, s->spatial_decomposition_count, 0);
 +        put_symbol(&s->c, s->header_state, s->colorspace_type, 0);
 +        if (s->nb_planes > 2) {
 +            put_symbol(&s->c, s->header_state, s->chroma_h_shift, 0);
 +            put_symbol(&s->c, s->header_state, s->chroma_v_shift, 0);
 +        }
 +        put_rac(&s->c, s->header_state, s->spatial_scalability);
 +//        put_rac(&s->c, s->header_state, s->rate_scalability);
 +        put_symbol(&s->c, s->header_state, s->max_ref_frames-1, 0);
 +
 +        encode_qlogs(s);
 +    }
 +
 +    if(!s->keyframe){
 +        int update_mc=0;
 +        for(plane_index=0; plane_index<FFMIN(s->nb_planes, 2); plane_index++){
 +            Plane *p= &s->plane[plane_index];
 +            update_mc |= p->last_htaps   != p->htaps;
 +            update_mc |= p->last_diag_mc != p->diag_mc;
 +            update_mc |= !!memcmp(p->last_hcoeff, p->hcoeff, sizeof(p->hcoeff));
 +        }
 +        put_rac(&s->c, s->header_state, update_mc);
 +        if(update_mc){
 +            for(plane_index=0; plane_index<FFMIN(s->nb_planes, 2); plane_index++){
 +                Plane *p= &s->plane[plane_index];
 +                put_rac(&s->c, s->header_state, p->diag_mc);
 +                put_symbol(&s->c, s->header_state, p->htaps/2-1, 0);
 +                for(i= p->htaps/2; i; i--)
 +                    put_symbol(&s->c, s->header_state, FFABS(p->hcoeff[i]), 0);
 +            }
 +        }
 +        if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){
 +            put_rac(&s->c, s->header_state, 1);
 +            put_symbol(&s->c, s->header_state, s->spatial_decomposition_count, 0);
 +            encode_qlogs(s);
 +        }else
 +            put_rac(&s->c, s->header_state, 0);
 +    }
 +
 +    put_symbol(&s->c, s->header_state, s->spatial_decomposition_type - s->last_spatial_decomposition_type, 1);
 +    put_symbol(&s->c, s->header_state, s->qlog            - s->last_qlog    , 1);
 +    put_symbol(&s->c, s->header_state, s->mv_scale        - s->last_mv_scale, 1);
 +    put_symbol(&s->c, s->header_state, s->qbias           - s->last_qbias   , 1);
 +    put_symbol(&s->c, s->header_state, s->block_max_depth - s->last_block_max_depth, 1);
 +
 +}
 +
 +static void update_last_header_values(SnowContext *s){
 +    int plane_index;
 +
 +    if(!s->keyframe){
 +        for(plane_index=0; plane_index<2; plane_index++){
 +            Plane *p= &s->plane[plane_index];
 +            p->last_diag_mc= p->diag_mc;
 +            p->last_htaps  = p->htaps;
 +            memcpy(p->last_hcoeff, p->hcoeff, sizeof(p->hcoeff));
 +        }
 +    }
 +
 +    s->last_spatial_decomposition_type  = s->spatial_decomposition_type;
 +    s->last_qlog                        = s->qlog;
 +    s->last_qbias                       = s->qbias;
 +    s->last_mv_scale                    = s->mv_scale;
 +    s->last_block_max_depth             = s->block_max_depth;
 +    s->last_spatial_decomposition_count = s->spatial_decomposition_count;
 +}
 +
 +static int qscale2qlog(int qscale){
 +    return rint(QROOT*log2(qscale / (float)FF_QP2LAMBDA))
 +           + 61*QROOT/8; ///< 64 > 60
 +}
 +
 +static int ratecontrol_1pass(SnowContext *s, AVFrame *pict)
 +{
 +    /* Estimate the frame's complexity as a sum of weighted dwt coefficients.
 +     * FIXME we know exact mv bits at this point,
 +     * but ratecontrol isn't set up to include them. */
 +    uint32_t coef_sum= 0;
 +    int level, orientation, delta_qlog;
 +
 +    for(level=0; level<s->spatial_decomposition_count; level++){
 +        for(orientation=level ? 1 : 0; orientation<4; orientation++){
 +            SubBand *b= &s->plane[0].band[level][orientation];
 +            IDWTELEM *buf= b->ibuf;
 +            const int w= b->width;
 +            const int h= b->height;
 +            const int stride= b->stride;
 +            const int qlog= av_clip(2*QROOT + b->qlog, 0, QROOT*16);
 +            const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
 +            const int qdiv= (1<<16)/qmul;
 +            int x, y;
 +            //FIXME this is ugly
 +            for(y=0; y<h; y++)
 +                for(x=0; x<w; x++)
 +                    buf[x+y*stride]= b->buf[x+y*stride];
 +            if(orientation==0)
 +                decorrelate(s, b, buf, stride, 1, 0);
 +            for(y=0; y<h; y++)
 +                for(x=0; x<w; x++)
 +                    coef_sum+= abs(buf[x+y*stride]) * qdiv >> 16;
 +        }
 +    }
 +
 +    /* ugly, ratecontrol just takes a sqrt again */
 +    av_assert0(coef_sum < INT_MAX);
 +    coef_sum = (uint64_t)coef_sum * coef_sum >> 16;
 +
 +    if(pict->pict_type == AV_PICTURE_TYPE_I){
 +        s->m.current_picture.mb_var_sum= coef_sum;
 +        s->m.current_picture.mc_mb_var_sum= 0;
 +    }else{
 +        s->m.current_picture.mc_mb_var_sum= coef_sum;
 +        s->m.current_picture.mb_var_sum= 0;
 +    }
 +
 +    pict->quality= ff_rate_estimate_qscale(&s->m, 1);
 +    if (pict->quality < 0)
 +        return INT_MIN;
 +    s->lambda= pict->quality * 3/2;
 +    delta_qlog= qscale2qlog(pict->quality) - s->qlog;
 +    s->qlog+= delta_qlog;
 +    return delta_qlog;
 +}
 +
 +static void calculate_visual_weight(SnowContext *s, Plane *p){
 +    int width = p->width;
 +    int height= p->height;
 +    int level, orientation, x, y;
 +
 +    for(level=0; level<s->spatial_decomposition_count; level++){
 +        for(orientation=level ? 1 : 0; orientation<4; orientation++){
 +            SubBand *b= &p->band[level][orientation];
 +            IDWTELEM *ibuf= b->ibuf;
 +            int64_t error=0;
 +
 +            memset(s->spatial_idwt_buffer, 0, sizeof(*s->spatial_idwt_buffer)*width*height);
 +            ibuf[b->width/2 + b->height/2*b->stride]= 256*16;
 +            ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, width, height, width, s->spatial_decomposition_type, s->spatial_decomposition_count);
 +            for(y=0; y<height; y++){
 +                for(x=0; x<width; x++){
 +                    int64_t d= s->spatial_idwt_buffer[x + y*width]*16;
 +                    error += d*d;
 +                }
 +            }
 +
 +            b->qlog= (int)(log(352256.0/sqrt(error)) / log(pow(2.0, 1.0/QROOT))+0.5);
 +        }
 +    }
 +}
 +
 +static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                        const AVFrame *pict, int *got_packet)
 +{
 +    SnowContext *s = avctx->priv_data;
 +    RangeCoder * const c= &s->c;
 +    AVFrame *pic = pict;
 +    const int width= s->avctx->width;
 +    const int height= s->avctx->height;
 +    int level, orientation, plane_index, i, y, ret;
 +    uint8_t rc_header_bak[sizeof(s->header_state)];
 +    uint8_t rc_block_bak[sizeof(s->block_state)];
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, s->b_width*s->b_height*MB_SIZE*MB_SIZE*3 + FF_MIN_BUFFER_SIZE)) < 0)
 +        return ret;
 +
 +    ff_init_range_encoder(c, pkt->data, pkt->size);
 +    ff_build_rac_states(c, (1LL<<32)/20, 256-8);
 +
 +    for(i=0; i < s->nb_planes; i++){
 +        int hshift= i ? s->chroma_h_shift : 0;
 +        int vshift= i ? s->chroma_v_shift : 0;
 +        for(y=0; y<FF_CEIL_RSHIFT(height, vshift); y++)
 +            memcpy(&s->input_picture->data[i][y * s->input_picture->linesize[i]],
 +                   &pict->data[i][y * pict->linesize[i]],
 +                   FF_CEIL_RSHIFT(width, hshift));
 +        s->mpvencdsp.draw_edges(s->input_picture->data[i], s->input_picture->linesize[i],
 +                                FF_CEIL_RSHIFT(width, hshift), FF_CEIL_RSHIFT(height, vshift),
 +                                EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift,
 +                                EDGE_TOP | EDGE_BOTTOM);
 +
 +    }
 +    emms_c();
 +    s->new_picture = pict;
 +
 +    s->m.picture_number= avctx->frame_number;
 +    if(avctx->flags&CODEC_FLAG_PASS2){
 +        s->m.pict_type = pic->pict_type = s->m.rc_context.entry[avctx->frame_number].new_pict_type;
 +        s->keyframe = pic->pict_type == AV_PICTURE_TYPE_I;
 +        if(!(avctx->flags&CODEC_FLAG_QSCALE)) {
 +            pic->quality = ff_rate_estimate_qscale(&s->m, 0);
 +            if (pic->quality < 0)
 +                return -1;
 +        }
 +    }else{
 +        s->keyframe= avctx->gop_size==0 || avctx->frame_number % avctx->gop_size == 0;
 +        s->m.pict_type = pic->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
 +    }
 +
 +    if(s->pass1_rc && avctx->frame_number == 0)
 +        pic->quality = 2*FF_QP2LAMBDA;
 +    if (pic->quality) {
 +        s->qlog   = qscale2qlog(pic->quality);
 +        s->lambda = pic->quality * 3/2;
 +    }
 +    if (s->qlog < 0 || (!pic->quality && (avctx->flags & CODEC_FLAG_QSCALE))) {
 +        s->qlog= LOSSLESS_QLOG;
 +        s->lambda = 0;
 +    }//else keep previous frame's qlog until after motion estimation
 +
 +    if (s->current_picture->data[0] && !(s->avctx->flags&CODEC_FLAG_EMU_EDGE)) {
 +        int w = s->avctx->width;
 +        int h = s->avctx->height;
 +
 +        s->mpvencdsp.draw_edges(s->current_picture->data[0],
 +                                s->current_picture->linesize[0], w   , h   ,
 +                                EDGE_WIDTH  , EDGE_WIDTH  , EDGE_TOP | EDGE_BOTTOM);
 +        if (s->current_picture->data[2]) {
 +            s->mpvencdsp.draw_edges(s->current_picture->data[1],
 +                                    s->current_picture->linesize[1], w>>s->chroma_h_shift, h>>s->chroma_v_shift,
 +                                    EDGE_WIDTH>>s->chroma_h_shift, EDGE_WIDTH>>s->chroma_v_shift, EDGE_TOP | EDGE_BOTTOM);
 +            s->mpvencdsp.draw_edges(s->current_picture->data[2],
 +                                    s->current_picture->linesize[2], w>>s->chroma_h_shift, h>>s->chroma_v_shift,
 +                                    EDGE_WIDTH>>s->chroma_h_shift, EDGE_WIDTH>>s->chroma_v_shift, EDGE_TOP | EDGE_BOTTOM);
 +        }
 +    }
 +
 +    ff_snow_frame_start(s);
 +    av_frame_unref(avctx->coded_frame);
 +    ret = av_frame_ref(avctx->coded_frame, s->current_picture);
 +    if (ret < 0)
 +        return ret;
 +
 +    s->m.current_picture_ptr= &s->m.current_picture;
 +    s->m.current_picture.f = s->current_picture;
 +    s->m.current_picture.f->pts = pict->pts;
 +    if(pic->pict_type == AV_PICTURE_TYPE_P){
 +        int block_width = (width +15)>>4;
 +        int block_height= (height+15)>>4;
 +        int stride= s->current_picture->linesize[0];
 +
 +        av_assert0(s->current_picture->data[0]);
 +        av_assert0(s->last_picture[0]->data[0]);
 +
 +        s->m.avctx= s->avctx;
 +        s->m.   last_picture.f = s->last_picture[0];
 +        s->m.    new_picture.f = s->input_picture;
 +        s->m.   last_picture_ptr= &s->m.   last_picture;
 +        s->m.linesize = stride;
 +        s->m.uvlinesize= s->current_picture->linesize[1];
 +        s->m.width = width;
 +        s->m.height= height;
 +        s->m.mb_width = block_width;
 +        s->m.mb_height= block_height;
 +        s->m.mb_stride=   s->m.mb_width+1;
 +        s->m.b8_stride= 2*s->m.mb_width+1;
 +        s->m.f_code=1;
 +        s->m.pict_type = pic->pict_type;
 +        s->m.me_method= s->avctx->me_method;
 +        s->m.me.scene_change_score=0;
 +        s->m.me.dia_size = avctx->dia_size;
 +        s->m.quarter_sample= (s->avctx->flags & CODEC_FLAG_QPEL)!=0;
 +        s->m.out_format= FMT_H263;
 +        s->m.unrestricted_mv= 1;
 +
 +        s->m.lambda = s->lambda;
 +        s->m.qscale= (s->m.lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7);
 +        s->lambda2= s->m.lambda2= (s->m.lambda*s->m.lambda + FF_LAMBDA_SCALE/2) >> FF_LAMBDA_SHIFT;
 +
 +        s->m.mecc= s->mecc; //move
 +        s->m.qdsp= s->qdsp; //move
 +        s->m.hdsp = s->hdsp;
 +        ff_init_me(&s->m);
 +        s->hdsp = s->m.hdsp;
 +        s->mecc= s->m.mecc;
 +    }
 +
 +    if(s->pass1_rc){
 +        memcpy(rc_header_bak, s->header_state, sizeof(s->header_state));
 +        memcpy(rc_block_bak, s->block_state, sizeof(s->block_state));
 +    }
 +
 +redo_frame:
 +
 +    s->spatial_decomposition_count= 5;
 +
 +    while(   !(width >>(s->chroma_h_shift + s->spatial_decomposition_count))
 +          || !(height>>(s->chroma_v_shift + s->spatial_decomposition_count)))
 +        s->spatial_decomposition_count--;
 +
 +    if (s->spatial_decomposition_count <= 0) {
 +        av_log(avctx, AV_LOG_ERROR, "Resolution too low\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    s->m.pict_type = pic->pict_type;
 +    s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0;
 +
 +    ff_snow_common_init_after_header(avctx);
 +
 +    if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){
 +        for(plane_index=0; plane_index < s->nb_planes; plane_index++){
 +            calculate_visual_weight(s, &s->plane[plane_index]);
 +        }
 +    }
 +
 +    encode_header(s);
 +    s->m.misc_bits = 8*(s->c.bytestream - s->c.bytestream_start);
 +    encode_blocks(s, 1);
 +    s->m.mv_bits = 8*(s->c.bytestream - s->c.bytestream_start) - s->m.misc_bits;
 +
 +    for(plane_index=0; plane_index < s->nb_planes; plane_index++){
 +        Plane *p= &s->plane[plane_index];
 +        int w= p->width;
 +        int h= p->height;
 +        int x, y;
 +//        int bits= put_bits_count(&s->c.pb);
 +
 +        if (!s->memc_only) {
 +            //FIXME optimize
 +            if(pict->data[plane_index]) //FIXME gray hack
 +                for(y=0; y<h; y++){
 +                    for(x=0; x<w; x++){
 +                        s->spatial_idwt_buffer[y*w + x]= pict->data[plane_index][y*pict->linesize[plane_index] + x]<<FRAC_BITS;
 +                    }
 +                }
 +            predict_plane(s, s->spatial_idwt_buffer, plane_index, 0);
 +
 +            if(   plane_index==0
 +               && pic->pict_type == AV_PICTURE_TYPE_P
 +               && !(avctx->flags&CODEC_FLAG_PASS2)
 +               && s->m.me.scene_change_score > s->avctx->scenechange_threshold){
 +                ff_init_range_encoder(c, pkt->data, pkt->size);
 +                ff_build_rac_states(c, (1LL<<32)/20, 256-8);
 +                pic->pict_type= AV_PICTURE_TYPE_I;
 +                s->keyframe=1;
 +                s->current_picture->key_frame=1;
 +                goto redo_frame;
 +            }
 +
 +            if(s->qlog == LOSSLESS_QLOG){
 +                for(y=0; y<h; y++){
 +                    for(x=0; x<w; x++){
 +                        s->spatial_dwt_buffer[y*w + x]= (s->spatial_idwt_buffer[y*w + x] + (1<<(FRAC_BITS-1))-1)>>FRAC_BITS;
 +                    }
 +                }
 +            }else{
 +                for(y=0; y<h; y++){
 +                    for(x=0; x<w; x++){
 +                        s->spatial_dwt_buffer[y*w + x]=s->spatial_idwt_buffer[y*w + x]<<ENCODER_EXTRA_BITS;
 +                    }
 +                }
 +            }
 +
 +            ff_spatial_dwt(s->spatial_dwt_buffer, s->temp_dwt_buffer, w, h, w, s->spatial_decomposition_type, s->spatial_decomposition_count);
 +
 +            if(s->pass1_rc && plane_index==0){
 +                int delta_qlog = ratecontrol_1pass(s, pic);
 +                if (delta_qlog <= INT_MIN)
 +                    return -1;
 +                if(delta_qlog){
 +                    //reordering qlog in the bitstream would eliminate this reset
 +                    ff_init_range_encoder(c, pkt->data, pkt->size);
 +                    memcpy(s->header_state, rc_header_bak, sizeof(s->header_state));
 +                    memcpy(s->block_state, rc_block_bak, sizeof(s->block_state));
 +                    encode_header(s);
 +                    encode_blocks(s, 0);
 +                }
 +            }
 +
 +            for(level=0; level<s->spatial_decomposition_count; level++){
 +                for(orientation=level ? 1 : 0; orientation<4; orientation++){
 +                    SubBand *b= &p->band[level][orientation];
 +
 +                    quantize(s, b, b->ibuf, b->buf, b->stride, s->qbias);
 +                    if(orientation==0)
 +                        decorrelate(s, b, b->ibuf, b->stride, pic->pict_type == AV_PICTURE_TYPE_P, 0);
 +                    if (!s->no_bitstream)
 +                    encode_subband(s, b, b->ibuf, b->parent ? b->parent->ibuf : NULL, b->stride, orientation);
 +                    av_assert0(b->parent==NULL || b->parent->stride == b->stride*2);
 +                    if(orientation==0)
 +                        correlate(s, b, b->ibuf, b->stride, 1, 0);
 +                }
 +            }
 +
 +            for(level=0; level<s->spatial_decomposition_count; level++){
 +                for(orientation=level ? 1 : 0; orientation<4; orientation++){
 +                    SubBand *b= &p->band[level][orientation];
 +
 +                    dequantize(s, b, b->ibuf, b->stride);
 +                }
 +            }
 +
 +            ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, w, h, w, s->spatial_decomposition_type, s->spatial_decomposition_count);
 +            if(s->qlog == LOSSLESS_QLOG){
 +                for(y=0; y<h; y++){
 +                    for(x=0; x<w; x++){
 +                        s->spatial_idwt_buffer[y*w + x]<<=FRAC_BITS;
 +                    }
 +                }
 +            }
 +            predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
 +        }else{
 +            //ME/MC only
 +            if(pic->pict_type == AV_PICTURE_TYPE_I){
 +                for(y=0; y<h; y++){
 +                    for(x=0; x<w; x++){
 +                        s->current_picture->data[plane_index][y*s->current_picture->linesize[plane_index] + x]=
 +                            pict->data[plane_index][y*pict->linesize[plane_index] + x];
 +                    }
 +                }
 +            }else{
 +                memset(s->spatial_idwt_buffer, 0, sizeof(IDWTELEM)*w*h);
 +                predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
 +            }
 +        }
 +        if(s->avctx->flags&CODEC_FLAG_PSNR){
 +            int64_t error= 0;
 +
 +            if(pict->data[plane_index]) //FIXME gray hack
 +                for(y=0; y<h; y++){
 +                    for(x=0; x<w; x++){
 +                        int d= s->current_picture->data[plane_index][y*s->current_picture->linesize[plane_index] + x] - pict->data[plane_index][y*pict->linesize[plane_index] + x];
 +                        error += d*d;
 +                    }
 +                }
 +            s->avctx->error[plane_index] += error;
 +            s->current_picture->error[plane_index] = error;
 +        }
 +
 +    }
 +
 +    update_last_header_values(s);
 +
 +    ff_snow_release_buffer(avctx);
 +
 +    s->current_picture->coded_picture_number = avctx->frame_number;
 +    s->current_picture->pict_type = pict->pict_type;
 +    s->current_picture->quality = pict->quality;
 +    s->m.frame_bits = 8*(s->c.bytestream - s->c.bytestream_start);
 +    s->m.p_tex_bits = s->m.frame_bits - s->m.misc_bits - s->m.mv_bits;
 +    s->m.current_picture.f->display_picture_number =
 +    s->m.current_picture.f->coded_picture_number   = avctx->frame_number;
 +    s->m.current_picture.f->quality                = pic->quality;
 +    s->m.total_bits += 8*(s->c.bytestream - s->c.bytestream_start);
 +    if(s->pass1_rc)
 +        if (ff_rate_estimate_qscale(&s->m, 0) < 0)
 +            return -1;
 +    if(avctx->flags&CODEC_FLAG_PASS1)
 +        ff_write_pass1_stats(&s->m);
 +    s->m.last_pict_type = s->m.pict_type;
 +    avctx->frame_bits = s->m.frame_bits;
 +    avctx->mv_bits = s->m.mv_bits;
 +    avctx->misc_bits = s->m.misc_bits;
 +    avctx->p_tex_bits = s->m.p_tex_bits;
 +
 +    emms_c();
 +
 +    pkt->size = ff_rac_terminate(c);
-     av_frame_free(&avctx->coded_frame);
++    if (s->current_picture->key_frame)
 +        pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +
 +    return 0;
 +}
 +
 +static av_cold int encode_end(AVCodecContext *avctx)
 +{
 +    SnowContext *s = avctx->priv_data;
 +
 +    ff_snow_common_end(s);
 +    ff_rate_control_uninit(&s->m);
 +    av_frame_free(&s->input_picture);
 +    av_freep(&avctx->stats_out);
 +
 +    return 0;
 +}
 +
 +#define OFFSET(x) offsetof(SnowContext, x)
 +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
 +static const AVOption options[] = {
 +    FF_MPV_COMMON_OPTS
 +    { "memc_only",      "Only do ME/MC (I frames -> ref, P frame -> ME+MC).",   OFFSET(memc_only), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
 +    { "no_bitstream",   "Skip final bitstream writeout.",                    OFFSET(no_bitstream), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
 +    { "intra_penalty",  "Penalty for intra blocks in block decission",      OFFSET(intra_penalty), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
 +    { NULL },
 +};
 +
 +static const AVClass snowenc_class = {
 +    .class_name = "snow encoder",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
 +AVCodec ff_snow_encoder = {
 +    .name           = "snow",
 +    .long_name      = NULL_IF_CONFIG_SMALL("Snow"),
 +    .type           = AVMEDIA_TYPE_VIDEO,
 +    .id             = AV_CODEC_ID_SNOW,
 +    .priv_data_size = sizeof(SnowContext),
 +    .init           = encode_init,
 +    .encode2        = encode_frame,
 +    .close          = encode_end,
 +    .pix_fmts       = (const enum AVPixelFormat[]){
 +        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV444P,
 +        AV_PIX_FMT_GRAY8,
 +        AV_PIX_FMT_NONE
 +    },
 +    .priv_class     = &snowenc_class,
 +    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
 +                      FF_CODEC_CAP_INIT_CLEANUP,
 +};
 +
 +
 +#ifdef TEST
 +#undef malloc
 +#undef free
 +#undef printf
 +
 +#include "libavutil/lfg.h"
 +#include "libavutil/mathematics.h"
 +
 +int main(void){
 +#define width  256
 +#define height 256
 +    int buffer[2][width*height];
 +    SnowContext s;
 +    int i;
 +    AVLFG prng;
 +    s.spatial_decomposition_count=6;
 +    s.spatial_decomposition_type=1;
 +
 +    s.temp_dwt_buffer  = av_mallocz_array(width, sizeof(DWTELEM));
 +    s.temp_idwt_buffer = av_mallocz_array(width, sizeof(IDWTELEM));
 +
 +    if (!s.temp_dwt_buffer || !s.temp_idwt_buffer) {
 +        fprintf(stderr, "Failed to allocate memory\n");
 +        return 1;
 +    }
 +
 +    av_lfg_init(&prng, 1);
 +
 +    printf("testing 5/3 DWT\n");
 +    for(i=0; i<width*height; i++)
 +        buffer[0][i] = buffer[1][i] = av_lfg_get(&prng) % 54321 - 12345;
 +
 +    ff_spatial_dwt(buffer[0], s.temp_dwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
 +    ff_spatial_idwt((IDWTELEM*)buffer[0], s.temp_idwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
 +
 +    for(i=0; i<width*height; i++)
 +        if(buffer[0][i]!= buffer[1][i]) printf("fsck: %6d %12d %7d\n",i, buffer[0][i], buffer[1][i]);
 +
 +    printf("testing 9/7 DWT\n");
 +    s.spatial_decomposition_type=0;
 +    for(i=0; i<width*height; i++)
 +        buffer[0][i] = buffer[1][i] = av_lfg_get(&prng) % 54321 - 12345;
 +
 +    ff_spatial_dwt(buffer[0], s.temp_dwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
 +    ff_spatial_idwt((IDWTELEM*)buffer[0], s.temp_idwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
 +
 +    for(i=0; i<width*height; i++)
 +        if(FFABS(buffer[0][i] - buffer[1][i])>20) printf("fsck: %6d %12d %7d\n",i, buffer[0][i], buffer[1][i]);
 +
 +    {
 +    int level, orientation, x, y;
 +    int64_t errors[8][4];
 +    int64_t g=0;
 +
 +        memset(errors, 0, sizeof(errors));
 +        s.spatial_decomposition_count=3;
 +        s.spatial_decomposition_type=0;
 +        for(level=0; level<s.spatial_decomposition_count; level++){
 +            for(orientation=level ? 1 : 0; orientation<4; orientation++){
 +                int w= width  >> (s.spatial_decomposition_count-level);
 +                int h= height >> (s.spatial_decomposition_count-level);
 +                int stride= width  << (s.spatial_decomposition_count-level);
 +                DWTELEM *buf= buffer[0];
 +                int64_t error=0;
 +
 +                if(orientation&1) buf+=w;
 +                if(orientation>1) buf+=stride>>1;
 +
 +                memset(buffer[0], 0, sizeof(int)*width*height);
 +                buf[w/2 + h/2*stride]= 256*256;
 +                ff_spatial_idwt((IDWTELEM*)buffer[0], s.temp_idwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
 +                for(y=0; y<height; y++){
 +                    for(x=0; x<width; x++){
 +                        int64_t d= buffer[0][x + y*width];
 +                        error += d*d;
 +                        if(FFABS(width/2-x)<9 && FFABS(height/2-y)<9 && level==2) printf("%8"PRId64" ", d);
 +                    }
 +                    if(FFABS(height/2-y)<9 && level==2) printf("\n");
 +                }
 +                error= (int)(sqrt(error)+0.5);
 +                errors[level][orientation]= error;
 +                if(g) g=av_gcd(g, error);
 +                else g= error;
 +            }
 +        }
 +        printf("static int const visual_weight[][4]={\n");
 +        for(level=0; level<s.spatial_decomposition_count; level++){
 +            printf("  {");
 +            for(orientation=0; orientation<4; orientation++){
 +                printf("%8"PRId64",", errors[level][orientation]/g);
 +            }
 +            printf("},\n");
 +        }
 +        printf("};\n");
 +        {
 +            int level=2;
 +            int w= width  >> (s.spatial_decomposition_count-level);
 +            //int h= height >> (s.spatial_decomposition_count-level);
 +            int stride= width  << (s.spatial_decomposition_count-level);
 +            DWTELEM *buf= buffer[0];
 +            int64_t error=0;
 +
 +            buf+=w;
 +            buf+=stride>>1;
 +
 +            memset(buffer[0], 0, sizeof(int)*width*height);
 +            for(y=0; y<height; y++){
 +                for(x=0; x<width; x++){
 +                    int tab[4]={0,2,3,1};
 +                    buffer[0][x+width*y]= 256*256*tab[(x&1) + 2*(y&1)];
 +                }
 +            }
 +            ff_spatial_dwt(buffer[0], s.temp_dwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
 +            for(y=0; y<height; y++){
 +                for(x=0; x<width; x++){
 +                    int64_t d= buffer[0][x + y*width];
 +                    error += d*d;
 +                    if(FFABS(width/2-x)<9 && FFABS(height/2-y)<9) printf("%8"PRId64" ", d);
 +                }
 +                if(FFABS(height/2-y)<9) printf("\n");
 +            }
 +        }
 +
 +    }
 +    return 0;
 +}
 +#endif /* TEST */
Simple merge
Simple merge
@@@ -194,10 -162,9 +184,9 @@@ AVCodec ff_targa_encoder = 
      .type           = AVMEDIA_TYPE_VIDEO,
      .id             = AV_CODEC_ID_TARGA,
      .init           = targa_encode_init,
-     .close          = targa_encode_close,
      .encode2        = targa_encode_frame,
      .pix_fmts       = (const enum AVPixelFormat[]){
 -        AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8,
 +        AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8,
          AV_PIX_FMT_NONE
      },
  };
@@@ -520,27 -490,8 +520,21 @@@ fail
  
  static av_cold int encode_init(AVCodecContext *avctx)
  {
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
 +    TiffEncoderContext *s = avctx->priv_data;
      avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
      avctx->coded_frame->key_frame = 1;
-     av_frame_free(&avctx->coded_frame);
 +    s->avctx = avctx;
 +
 +    return 0;
 +}
 +
 +static av_cold int encode_close(AVCodecContext *avctx)
 +{
 +    TiffEncoderContext *s = avctx->priv_data;
 +
 +    av_freep(&s->strip_sizes);
 +    av_freep(&s->strip_offsets);
 +    av_freep(&s->yuv_line);
  
      return 0;
  }
@@@ -1514,21 -1167,13 +1514,26 @@@ int attribute_align_arg avcodec_open2(A
      if (!HAVE_THREADS && !(codec->capabilities & CODEC_CAP_AUTO_THREADS))
          avctx->thread_count = 1;
  
 +    if (avctx->codec->max_lowres < avctx->lowres || avctx->lowres < 0) {
 +        av_log(avctx, AV_LOG_ERROR, "The maximum value for lowres supported by the decoder is %d\n",
 +               avctx->codec->max_lowres);
 +        ret = AVERROR(EINVAL);
 +        goto free_and_end;
 +    }
 +
 +#if FF_API_VISMV
 +    if (avctx->debug_mv)
 +        av_log(avctx, AV_LOG_WARNING, "The 'vismv' option is deprecated, "
 +               "see the codecview filter instead.\n");
 +#endif
 +
      if (av_codec_is_encoder(avctx->codec)) {
          int i;
+         avctx->coded_frame = av_frame_alloc();
+         if (!avctx->coded_frame) {
+             ret = AVERROR(ENOMEM);
+             goto free_and_end;
+         }
          if (avctx->codec->sample_fmts) {
              for (i = 0; avctx->codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) {
                  if (avctx->sample_fmt == avctx->codec->sample_fmts[i])
@@@ -2882,9 -1804,6 +2889,8 @@@ av_cold int avcodec_close(AVCodecContex
              ff_thread_free(avctx);
          if (avctx->codec && avctx->codec->close)
              avctx->codec->close(avctx);
-         avctx->coded_frame = NULL;
 +        avctx->internal->byte_buffer_size = 0;
 +        av_freep(&avctx->internal->byte_buffer);
          av_frame_free(&avctx->internal->to_free);
          for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
              av_buffer_pool_uninit(&pool->pools[i]);
Simple merge
Simple merge
index 408784b,0000000..0e5ab82
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,85 @@@
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
-         return AVERROR(ENOMEM);
-     }
 +/*
 + * v308 encoder
 + *
 + * Copyright (c) 2011 Carl Eugen Hoyos
 + *
 + * 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 "libavutil/intreadwrite.h"
 +#include "avcodec.h"
 +#include "internal.h"
 +
 +static av_cold int v308_encode_init(AVCodecContext *avctx)
 +{
 +    if (avctx->width & 1) {
 +        av_log(avctx, AV_LOG_ERROR, "v308 requires width to be even.\n");
 +        return AVERROR_INVALIDDATA;
 +    }
 +
-     av_frame_free(&avctx->coded_frame);
 +    return 0;
 +}
 +
 +static int v308_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                             const AVFrame *pic, int *got_packet)
 +{
 +    uint8_t *dst;
 +    uint8_t *y, *u, *v;
 +    int i, j, ret;
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * 3)) < 0)
 +        return ret;
 +    dst = pkt->data;
 +
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +
 +    y = pic->data[0];
 +    u = pic->data[1];
 +    v = pic->data[2];
 +
 +    for (i = 0; i < avctx->height; i++) {
 +        for (j = 0; j < avctx->width; j++) {
 +            *dst++ = v[j];
 +            *dst++ = y[j];
 +            *dst++ = u[j];
 +        }
 +        y += pic->linesize[0];
 +        u += pic->linesize[1];
 +        v += pic->linesize[2];
 +    }
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +    return 0;
 +}
 +
 +static av_cold int v308_encode_close(AVCodecContext *avctx)
 +{
 +    return 0;
 +}
 +
 +AVCodec ff_v308_encoder = {
 +    .name         = "v308",
 +    .long_name    = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"),
 +    .type         = AVMEDIA_TYPE_VIDEO,
 +    .id           = AV_CODEC_ID_V308,
 +    .init         = v308_encode_init,
 +    .encode2      = v308_encode_frame,
 +    .close        = v308_encode_close,
 +    .pix_fmts     = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE },
 +};
index cdb2efa,0000000..b09da89
mode 100644,000000..100644
--- /dev/null
@@@ -1,113 -1,0 +1,105 @@@
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
-         return AVERROR(ENOMEM);
-     }
 +/*
 + * v408 encoder
 + *
 + * Copyright (c) 2012 Carl Eugen Hoyos
 + *
 + * 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 "libavutil/intreadwrite.h"
 +#include "avcodec.h"
 +#include "internal.h"
 +
 +static av_cold int v408_encode_init(AVCodecContext *avctx)
 +{
-     av_frame_free(&avctx->coded_frame);
 +
 +    return 0;
 +}
 +
 +static int v408_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                             const AVFrame *pic, int *got_packet)
 +{
 +    uint8_t *dst;
 +    uint8_t *y, *u, *v, *a;
 +    int i, j, ret;
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * 4)) < 0)
 +        return ret;
 +    dst = pkt->data;
 +
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +
 +    y = pic->data[0];
 +    u = pic->data[1];
 +    v = pic->data[2];
 +    a = pic->data[3];
 +
 +    for (i = 0; i < avctx->height; i++) {
 +        for (j = 0; j < avctx->width; j++) {
 +           if (avctx->codec_id==AV_CODEC_ID_AYUV) {
 +                *dst++ = v[j];
 +                *dst++ = u[j];
 +                *dst++ = y[j];
 +                *dst++ = a[j];
 +            } else {
 +                *dst++ = u[j];
 +                *dst++ = y[j];
 +                *dst++ = v[j];
 +                *dst++ = a[j];
 +            }
 +        }
 +        y += pic->linesize[0];
 +        u += pic->linesize[1];
 +        v += pic->linesize[2];
 +        a += pic->linesize[3];
 +    }
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +    return 0;
 +}
 +
 +static av_cold int v408_encode_close(AVCodecContext *avctx)
 +{
 +    return 0;
 +}
 +
 +#if CONFIG_AYUV_ENCODER
 +AVCodec ff_ayuv_encoder = {
 +    .name         = "ayuv",
 +    .long_name    = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"),
 +    .type         = AVMEDIA_TYPE_VIDEO,
 +    .id           = AV_CODEC_ID_AYUV,
 +    .init         = v408_encode_init,
 +    .encode2      = v408_encode_frame,
 +    .close        = v408_encode_close,
 +    .pix_fmts     = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE },
 +};
 +#endif
 +#if CONFIG_V408_ENCODER
 +AVCodec ff_v408_encoder = {
 +    .name         = "v408",
 +    .long_name    = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"),
 +    .type         = AVMEDIA_TYPE_VIDEO,
 +    .id           = AV_CODEC_ID_V408,
 +    .init         = v408_encode_init,
 +    .encode2      = v408_encode_frame,
 +    .close        = v408_encode_close,
 +    .pix_fmts     = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE },
 +};
 +#endif
Simple merge
index fa6f227,0000000..ca0f72b
mode 100644,000000..100644
--- /dev/null
@@@ -1,241 -1,0 +1,236 @@@
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame)
-         return AVERROR(ENOMEM);
 +/*
 + * Copyright (c) 1990 James Ashton - Sydney University
 + * Copyright (c) 2012 Stefano Sabatini
 + *
 + * 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
 + */
 +
 +/**
 + * @file
 + * X-Face encoder, based on libcompface, by James Ashton.
 + */
 +
 +#include "xface.h"
 +#include "avcodec.h"
 +#include "internal.h"
 +#include "libavutil/avassert.h"
 +
 +typedef struct XFaceContext {
 +    AVClass *class;
 +    uint8_t bitmap[XFACE_PIXELS]; ///< image used internally for decoding
 +    int max_line_len;             ///< max line length for compressed data
 +    int set_header;               ///< set X-Face header in the output
 +} XFaceContext;
 +
 +static int all_same(char *bitmap, int w, int h)
 +{
 +    char val, *row;
 +    int x;
 +
 +    val = *bitmap;
 +    while (h--) {
 +        row = bitmap;
 +        x = w;
 +        while (x--)
 +            if (*(row++) != val)
 +                return 0;
 +        bitmap += XFACE_WIDTH;
 +    }
 +    return 1;
 +}
 +
 +static int all_black(char *bitmap, int w, int h)
 +{
 +    if (w > 3) {
 +        w /= 2;
 +        h /= 2;
 +        return (all_black(bitmap, w, h) && all_black(bitmap + w, w, h) &&
 +                all_black(bitmap + XFACE_WIDTH * h, w, h) &&
 +                all_black(bitmap + XFACE_WIDTH * h + w, w, h));
 +    } else {
 +        /* at least one pixel in the 2x2 grid is non-zero */
 +        return *bitmap || *(bitmap + 1) ||
 +               *(bitmap + XFACE_WIDTH) || *(bitmap + XFACE_WIDTH + 1);
 +    }
 +}
 +
 +static int all_white(char *bitmap, int w, int h)
 +{
 +    return *bitmap == 0 && all_same(bitmap, w, h);
 +}
 +
 +typedef struct {
 +    ProbRange prob_ranges[XFACE_PIXELS*2];
 +    int prob_ranges_idx;
 +} ProbRangesQueue;
 +
 +static inline int pq_push(ProbRangesQueue *pq, const ProbRange *p)
 +{
 +    if (pq->prob_ranges_idx >= XFACE_PIXELS * 2 - 1)
 +        return -1;
 +    pq->prob_ranges[pq->prob_ranges_idx++] = *p;
 +    return 0;
 +}
 +
 +static void push_greys(ProbRangesQueue *pq, char *bitmap, int w, int h)
 +{
 +    if (w > 3) {
 +        w /= 2;
 +        h /= 2;
 +        push_greys(pq, bitmap,                       w, h);
 +        push_greys(pq, bitmap + w,                   w, h);
 +        push_greys(pq, bitmap + XFACE_WIDTH * h,     w, h);
 +        push_greys(pq, bitmap + XFACE_WIDTH * h + w, w, h);
 +    } else {
 +        const ProbRange *p = ff_xface_probranges_2x2 +
 +                 *bitmap +
 +            2 * *(bitmap + 1) +
 +            4 * *(bitmap + XFACE_WIDTH) +
 +            8 * *(bitmap + XFACE_WIDTH + 1);
 +        pq_push(pq, p);
 +    }
 +}
 +
 +static void encode_block(char *bitmap, int w, int h, int level, ProbRangesQueue *pq)
 +{
 +    if (all_white(bitmap, w, h)) {
 +        pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_WHITE]);
 +    } else if (all_black(bitmap, w, h)) {
 +        pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_BLACK]);
 +        push_greys(pq, bitmap, w, h);
 +    } else {
 +        pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_GREY]);
 +        w /= 2;
 +        h /= 2;
 +        level++;
 +        encode_block(bitmap,                       w, h, level, pq);
 +        encode_block(bitmap + w,                   w, h, level, pq);
 +        encode_block(bitmap + h * XFACE_WIDTH,     w, h, level, pq);
 +        encode_block(bitmap + w + h * XFACE_WIDTH, w, h, level, pq);
 +    }
 +}
 +
 +static av_cold int xface_encode_init(AVCodecContext *avctx)
 +{
-     av_frame_free(&avctx->coded_frame);
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +
 +    return 0;
 +}
 +
 +static void push_integer(BigInt *b, const ProbRange *prange)
 +{
 +    uint8_t r;
 +
 +    ff_big_div(b, prange->range, &r);
 +    ff_big_mul(b, 0);
 +    ff_big_add(b, r + prange->offset);
 +}
 +
 +static int xface_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                              const AVFrame *frame, int *got_packet)
 +{
 +    XFaceContext *xface = avctx->priv_data;
 +    ProbRangesQueue pq = {{{ 0 }}, 0};
 +    uint8_t bitmap_copy[XFACE_PIXELS];
 +    BigInt b = {0};
 +    int i, j, k, ret = 0;
 +    const uint8_t *buf;
 +    uint8_t *p;
 +    char intbuf[XFACE_MAX_DIGITS];
 +
 +    if (avctx->width || avctx->height) {
 +        if (avctx->width != XFACE_WIDTH || avctx->height != XFACE_HEIGHT) {
 +            av_log(avctx, AV_LOG_ERROR,
 +                   "Size value %dx%d not supported, only accepts a size of %dx%d\n",
 +                   avctx->width, avctx->height, XFACE_WIDTH, XFACE_HEIGHT);
 +            return AVERROR(EINVAL);
 +        }
 +    }
 +    avctx->width  = XFACE_WIDTH;
 +    avctx->height = XFACE_HEIGHT;
 +
 +    /* convert image from MONOWHITE to 1=black 0=white bitmap */
 +    buf = frame->data[0];
 +    i = j = 0;
 +    do {
 +        for (k = 0; k < 8; k++)
 +            xface->bitmap[i++] = (buf[j]>>(7-k))&1;
 +        if (++j == XFACE_WIDTH/8) {
 +            buf += frame->linesize[0];
 +            j = 0;
 +        }
 +    } while (i < XFACE_PIXELS);
 +
 +    /* create a copy of bitmap */
 +    memcpy(bitmap_copy, xface->bitmap, XFACE_PIXELS);
 +    ff_xface_generate_face(xface->bitmap, bitmap_copy);
 +
 +    encode_block(xface->bitmap,                         16, 16, 0, &pq);
 +    encode_block(xface->bitmap + 16,                    16, 16, 0, &pq);
 +    encode_block(xface->bitmap + 32,                    16, 16, 0, &pq);
 +    encode_block(xface->bitmap + XFACE_WIDTH * 16,      16, 16, 0, &pq);
 +    encode_block(xface->bitmap + XFACE_WIDTH * 16 + 16, 16, 16, 0, &pq);
 +    encode_block(xface->bitmap + XFACE_WIDTH * 16 + 32, 16, 16, 0, &pq);
 +    encode_block(xface->bitmap + XFACE_WIDTH * 32,      16, 16, 0, &pq);
 +    encode_block(xface->bitmap + XFACE_WIDTH * 32 + 16, 16, 16, 0, &pq);
 +    encode_block(xface->bitmap + XFACE_WIDTH * 32 + 32, 16, 16, 0, &pq);
 +
 +    while (pq.prob_ranges_idx > 0)
 +        push_integer(&b, &pq.prob_ranges[--pq.prob_ranges_idx]);
 +
 +    /* write the inverted big integer in b to intbuf */
 +    i = 0;
 +    av_assert0(b.nb_words < XFACE_MAX_WORDS);
 +    while (b.nb_words) {
 +        uint8_t r;
 +        ff_big_div(&b, XFACE_PRINTS, &r);
 +        av_assert0(i < sizeof(intbuf));
 +        intbuf[i++] = r + XFACE_FIRST_PRINT;
 +    }
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, i+2)) < 0)
 +        return ret;
 +
 +    /* revert the number, and close the buffer */
 +    p = pkt->data;
 +    while (--i >= 0)
 +        *(p++) = intbuf[i];
 +    *(p++) = '\n';
 +    *(p++) = 0;
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +
 +    return 0;
 +}
 +
 +static av_cold int xface_encode_close(AVCodecContext *avctx)
 +{
 +    return 0;
 +}
 +
 +AVCodec ff_xface_encoder = {
 +    .name           = "xface",
 +    .long_name      = NULL_IF_CONFIG_SMALL("X-face image"),
 +    .type           = AVMEDIA_TYPE_VIDEO,
 +    .id             = AV_CODEC_ID_XFACE,
 +    .priv_data_size = sizeof(XFaceContext),
 +    .init           = xface_encode_init,
 +    .close          = xface_encode_close,
 +    .encode2        = xface_encode_frame,
 +    .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE },
 +};
index 4778618,0000000..b30cbfa
mode 100644,000000..100644
--- /dev/null
@@@ -1,102 -1,0 +1,94 @@@
-     avctx->coded_frame = av_frame_alloc();
 +/*
 + * y41p encoder
 + *
 + * Copyright (c) 2012 Paul B Mahol
 + *
 + * 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 "avcodec.h"
 +#include "internal.h"
 +
 +static av_cold int y41p_encode_init(AVCodecContext *avctx)
 +{
 +    if (avctx->width & 7) {
 +        av_log(avctx, AV_LOG_ERROR, "y41p requires width to be divisible by 8.\n");
 +        return AVERROR_INVALIDDATA;
 +    }
 +
-     if (!avctx->coded_frame) {
-         av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
-         return AVERROR(ENOMEM);
-     }
 +    avctx->bits_per_coded_sample = 12;
 +
-     av_frame_free(&avctx->coded_frame);
 +    return 0;
 +}
 +
 +static int y41p_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                             const AVFrame *pic, int *got_packet)
 +{
 +    uint8_t *dst;
 +    uint8_t *y, *u, *v;
 +    int i, j, ret;
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * 1.5)) < 0)
 +        return ret;
 +
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +    dst = pkt->data;
 +
 +    for (i = avctx->height - 1; i >= 0; i--) {
 +        y = &pic->data[0][i * pic->linesize[0]];
 +        u = &pic->data[1][i * pic->linesize[1]];
 +        v = &pic->data[2][i * pic->linesize[2]];
 +        for (j = 0; j < avctx->width; j += 8) {
 +            *(dst++) = *(u++);
 +            *(dst++) = *(y++);
 +            *(dst++) = *(v++);
 +            *(dst++) = *(y++);
 +
 +            *(dst++) = *(u++);
 +            *(dst++) = *(y++);
 +            *(dst++) = *(v++);
 +            *(dst++) = *(y++);
 +
 +            *(dst++) = *(y++);
 +            *(dst++) = *(y++);
 +            *(dst++) = *(y++);
 +            *(dst++) = *(y++);
 +        }
 +    }
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +    return 0;
 +}
 +
 +static av_cold int y41p_encode_close(AVCodecContext *avctx)
 +{
 +    return 0;
 +}
 +
 +AVCodec ff_y41p_encoder = {
 +    .name         = "y41p",
 +    .long_name    = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
 +    .type         = AVMEDIA_TYPE_VIDEO,
 +    .id           = AV_CODEC_ID_Y41P,
 +    .init         = y41p_encode_init,
 +    .encode2      = y41p_encode_frame,
 +    .close        = y41p_encode_close,
 +    .pix_fmts     = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P,
 +                                                 AV_PIX_FMT_NONE },
 +};
index 5ce4846,0000000..cc9ecbb
mode 100644,000000..100644
--- /dev/null
@@@ -1,91 -1,0 +1,82 @@@
-     avctx->coded_frame = av_frame_alloc();
-     if (!avctx->coded_frame) {
-         av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
-         return AVERROR(ENOMEM);
-     }
 +/*
 + * libquicktime yuv4 encoder
 + *
 + * Copyright (c) 2011 Carl Eugen Hoyos
 + *
 + * 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 "avcodec.h"
 +#include "internal.h"
 +
 +static av_cold int yuv4_encode_init(AVCodecContext *avctx)
 +{
-     av_frame_free(&avctx->coded_frame);
 +    return 0;
 +}
 +
 +static int yuv4_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 +                             const AVFrame *pic, int *got_packet)
 +{
 +    uint8_t *dst;
 +    uint8_t *y, *u, *v;
 +    int i, j, ret;
 +
 +    if ((ret = ff_alloc_packet2(avctx, pkt, 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1))) < 0)
 +        return ret;
 +    dst = pkt->data;
 +
 +    avctx->coded_frame->key_frame = 1;
 +    avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
 +
 +    y = pic->data[0];
 +    u = pic->data[1];
 +    v = pic->data[2];
 +
 +    for (i = 0; i < avctx->height + 1 >> 1; i++) {
 +        for (j = 0; j < avctx->width + 1 >> 1; j++) {
 +            *dst++ = u[j] ^ 0x80;
 +            *dst++ = v[j] ^ 0x80;
 +            *dst++ = y[                   2 * j    ];
 +            *dst++ = y[                   2 * j + 1];
 +            *dst++ = y[pic->linesize[0] + 2 * j    ];
 +            *dst++ = y[pic->linesize[0] + 2 * j + 1];
 +        }
 +        y += 2 * pic->linesize[0];
 +        u +=     pic->linesize[1];
 +        v +=     pic->linesize[2];
 +    }
 +
 +    pkt->flags |= AV_PKT_FLAG_KEY;
 +    *got_packet = 1;
 +    return 0;
 +}
 +
 +static av_cold int yuv4_encode_close(AVCodecContext *avctx)
 +{
 +    return 0;
 +}
 +
 +AVCodec ff_yuv4_encoder = {
 +    .name         = "yuv4",
 +    .long_name    = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"),
 +    .type         = AVMEDIA_TYPE_VIDEO,
 +    .id           = AV_CODEC_ID_YUV4,
 +    .init         = yuv4_encode_init,
 +    .encode2      = yuv4_encode_frame,
 +    .close        = yuv4_encode_close,
 +    .pix_fmts     = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
 +};
Simple merge