1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Interface to xvidcore for MPEG-4 encoding
3cabdff1aSopenharmony_ci * Copyright (c) 2004 Adam Thayer <krevnik@comcast.net>
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * Interface to xvidcore for MPEG-4 compliant encoding.
25cabdff1aSopenharmony_ci * @author Adam Thayer (krevnik@comcast.net)
26cabdff1aSopenharmony_ci */
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include <stdio.h>
29cabdff1aSopenharmony_ci#include <string.h>
30cabdff1aSopenharmony_ci#include <xvid.h>
31cabdff1aSopenharmony_ci
32cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
33cabdff1aSopenharmony_ci#include "libavutil/file.h"
34cabdff1aSopenharmony_ci#include "libavutil/internal.h"
35cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
36cabdff1aSopenharmony_ci#include "libavutil/mathematics.h"
37cabdff1aSopenharmony_ci#include "libavutil/mem.h"
38cabdff1aSopenharmony_ci#include "libavutil/opt.h"
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci#include "avcodec.h"
41cabdff1aSopenharmony_ci#include "codec_internal.h"
42cabdff1aSopenharmony_ci#include "encode.h"
43cabdff1aSopenharmony_ci#include "mpegutils.h"
44cabdff1aSopenharmony_ci#include "packet_internal.h"
45cabdff1aSopenharmony_ci
46cabdff1aSopenharmony_ci#if HAVE_UNISTD_H
47cabdff1aSopenharmony_ci#include <unistd.h>
48cabdff1aSopenharmony_ci#endif
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci#if HAVE_IO_H
51cabdff1aSopenharmony_ci#include <io.h>
52cabdff1aSopenharmony_ci#endif
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_ci/**
55cabdff1aSopenharmony_ci * Buffer management macros.
56cabdff1aSopenharmony_ci */
57cabdff1aSopenharmony_ci#define BUFFER_SIZE         1024
58cabdff1aSopenharmony_ci#define BUFFER_REMAINING(x) (BUFFER_SIZE - strlen(x))
59cabdff1aSopenharmony_ci#define BUFFER_CAT(x)       (&((x)[strlen(x)]))
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci/**
62cabdff1aSopenharmony_ci * Structure for the private Xvid context.
63cabdff1aSopenharmony_ci * This stores all the private context for the codec.
64cabdff1aSopenharmony_ci */
65cabdff1aSopenharmony_cistruct xvid_context {
66cabdff1aSopenharmony_ci    AVClass *class;
67cabdff1aSopenharmony_ci    void *encoder_handle;          /**< Handle for Xvid encoder */
68cabdff1aSopenharmony_ci    int xsize;                     /**< Frame x size */
69cabdff1aSopenharmony_ci    int ysize;                     /**< Frame y size */
70cabdff1aSopenharmony_ci    int vop_flags;                 /**< VOP flags for Xvid encoder */
71cabdff1aSopenharmony_ci    int vol_flags;                 /**< VOL flags for Xvid encoder */
72cabdff1aSopenharmony_ci    int me_flags;                  /**< Motion Estimation flags */
73cabdff1aSopenharmony_ci    int qscale;                    /**< Do we use constant scale? */
74cabdff1aSopenharmony_ci    int quicktime_format;          /**< Are we in a QT-based format? */
75cabdff1aSopenharmony_ci    char *twopassbuffer;           /**< Character buffer for two-pass */
76cabdff1aSopenharmony_ci    char *old_twopassbuffer;       /**< Old character buffer (two-pass) */
77cabdff1aSopenharmony_ci    char *twopassfile;             /**< second pass temp file name */
78cabdff1aSopenharmony_ci    int twopassfd;
79cabdff1aSopenharmony_ci    unsigned char *intra_matrix;   /**< P-Frame Quant Matrix */
80cabdff1aSopenharmony_ci    unsigned char *inter_matrix;   /**< I-Frame Quant Matrix */
81cabdff1aSopenharmony_ci    int lumi_aq;                   /**< Lumi masking as an aq method */
82cabdff1aSopenharmony_ci    int variance_aq;               /**< Variance adaptive quantization */
83cabdff1aSopenharmony_ci    int ssim;                      /**< SSIM information display mode */
84cabdff1aSopenharmony_ci    int ssim_acc;                  /**< SSIM accuracy. 0: accurate. 4: fast. */
85cabdff1aSopenharmony_ci    int gmc;
86cabdff1aSopenharmony_ci    int me_quality;                /**< Motion estimation quality. 0: fast 6: best. */
87cabdff1aSopenharmony_ci    int mpeg_quant;                /**< Quantization type. 0: H.263, 1: MPEG */
88cabdff1aSopenharmony_ci};
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci/**
91cabdff1aSopenharmony_ci * Structure for the private first-pass plugin.
92cabdff1aSopenharmony_ci */
93cabdff1aSopenharmony_cistruct xvid_ff_pass1 {
94cabdff1aSopenharmony_ci    int version;                    /**< Xvid version */
95cabdff1aSopenharmony_ci    struct xvid_context *context;   /**< Pointer to private context */
96cabdff1aSopenharmony_ci};
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_cistatic int xvid_encode_close(AVCodecContext *avctx);
99cabdff1aSopenharmony_cistatic int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
100cabdff1aSopenharmony_ci                             const AVFrame *picture, int *got_packet);
101cabdff1aSopenharmony_ci
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci/*
104cabdff1aSopenharmony_ci * Xvid 2-Pass Kludge Section
105cabdff1aSopenharmony_ci *
106cabdff1aSopenharmony_ci * Xvid's default 2-pass doesn't allow us to create data as we need to, so
107cabdff1aSopenharmony_ci * this section spends time replacing the first pass plugin so we can write
108cabdff1aSopenharmony_ci * statistic information as libavcodec requests in. We have another kludge
109cabdff1aSopenharmony_ci * that allows us to pass data to the second pass in Xvid without a custom
110cabdff1aSopenharmony_ci * rate-control plugin.
111cabdff1aSopenharmony_ci */
112cabdff1aSopenharmony_ci
113cabdff1aSopenharmony_ci/**
114cabdff1aSopenharmony_ci * Initialize the two-pass plugin and context.
115cabdff1aSopenharmony_ci *
116cabdff1aSopenharmony_ci * @param param Input construction parameter structure
117cabdff1aSopenharmony_ci * @param handle Private context handle
118cabdff1aSopenharmony_ci * @return Returns XVID_ERR_xxxx on failure, or 0 on success.
119cabdff1aSopenharmony_ci */
120cabdff1aSopenharmony_cistatic int xvid_ff_2pass_create(xvid_plg_create_t *param, void **handle)
121cabdff1aSopenharmony_ci{
122cabdff1aSopenharmony_ci    struct xvid_ff_pass1 *x = (struct xvid_ff_pass1 *) param->param;
123cabdff1aSopenharmony_ci    char *log = x->context->twopassbuffer;
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    /* Do a quick bounds check */
126cabdff1aSopenharmony_ci    if (!log)
127cabdff1aSopenharmony_ci        return XVID_ERR_FAIL;
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_ci    /* We use snprintf() */
130cabdff1aSopenharmony_ci    /* This is because we can safely prevent a buffer overflow */
131cabdff1aSopenharmony_ci    log[0] = 0;
132cabdff1aSopenharmony_ci    snprintf(log, BUFFER_REMAINING(log),
133cabdff1aSopenharmony_ci             "# ffmpeg 2-pass log file, using xvid codec\n");
134cabdff1aSopenharmony_ci    snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log),
135cabdff1aSopenharmony_ci             "# Do not modify. libxvidcore version: %d.%d.%d\n\n",
136cabdff1aSopenharmony_ci             XVID_VERSION_MAJOR(XVID_VERSION),
137cabdff1aSopenharmony_ci             XVID_VERSION_MINOR(XVID_VERSION),
138cabdff1aSopenharmony_ci             XVID_VERSION_PATCH(XVID_VERSION));
139cabdff1aSopenharmony_ci
140cabdff1aSopenharmony_ci    *handle = x->context;
141cabdff1aSopenharmony_ci    return 0;
142cabdff1aSopenharmony_ci}
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_ci/**
145cabdff1aSopenharmony_ci * Destroy the two-pass plugin context.
146cabdff1aSopenharmony_ci *
147cabdff1aSopenharmony_ci * @param ref Context pointer for the plugin
148cabdff1aSopenharmony_ci * @param param Destroy context
149cabdff1aSopenharmony_ci * @return Returns 0, success guaranteed
150cabdff1aSopenharmony_ci */
151cabdff1aSopenharmony_cistatic int xvid_ff_2pass_destroy(struct xvid_context *ref,
152cabdff1aSopenharmony_ci                                 xvid_plg_destroy_t *param)
153cabdff1aSopenharmony_ci{
154cabdff1aSopenharmony_ci    /* Currently cannot think of anything to do on destruction */
155cabdff1aSopenharmony_ci    /* Still, the framework should be here for reference/use */
156cabdff1aSopenharmony_ci    if (ref->twopassbuffer)
157cabdff1aSopenharmony_ci        ref->twopassbuffer[0] = 0;
158cabdff1aSopenharmony_ci    return 0;
159cabdff1aSopenharmony_ci}
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci/**
162cabdff1aSopenharmony_ci * Enable fast encode mode during the first pass.
163cabdff1aSopenharmony_ci *
164cabdff1aSopenharmony_ci * @param ref Context pointer for the plugin
165cabdff1aSopenharmony_ci * @param param Frame data
166cabdff1aSopenharmony_ci * @return Returns 0, success guaranteed
167cabdff1aSopenharmony_ci */
168cabdff1aSopenharmony_cistatic int xvid_ff_2pass_before(struct xvid_context *ref,
169cabdff1aSopenharmony_ci                                xvid_plg_data_t *param)
170cabdff1aSopenharmony_ci{
171cabdff1aSopenharmony_ci    int motion_remove;
172cabdff1aSopenharmony_ci    int motion_replacements;
173cabdff1aSopenharmony_ci    int vop_remove;
174cabdff1aSopenharmony_ci
175cabdff1aSopenharmony_ci    /* Nothing to do here, result is changed too much */
176cabdff1aSopenharmony_ci    if (param->zone && param->zone->mode == XVID_ZONE_QUANT)
177cabdff1aSopenharmony_ci        return 0;
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_ci    /* We can implement a 'turbo' first pass mode here */
180cabdff1aSopenharmony_ci    param->quant = 2;
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci    /* Init values */
183cabdff1aSopenharmony_ci    motion_remove       = ~XVID_ME_CHROMA_PVOP &
184cabdff1aSopenharmony_ci                          ~XVID_ME_CHROMA_BVOP &
185cabdff1aSopenharmony_ci                          ~XVID_ME_EXTSEARCH16 &
186cabdff1aSopenharmony_ci                          ~XVID_ME_ADVANCEDDIAMOND16;
187cabdff1aSopenharmony_ci    motion_replacements = XVID_ME_FAST_MODEINTERPOLATE |
188cabdff1aSopenharmony_ci                          XVID_ME_SKIP_DELTASEARCH     |
189cabdff1aSopenharmony_ci                          XVID_ME_FASTREFINE16         |
190cabdff1aSopenharmony_ci                          XVID_ME_BFRAME_EARLYSTOP;
191cabdff1aSopenharmony_ci    vop_remove          = ~XVID_VOP_MODEDECISION_RD      &
192cabdff1aSopenharmony_ci                          ~XVID_VOP_FAST_MODEDECISION_RD &
193cabdff1aSopenharmony_ci                          ~XVID_VOP_TRELLISQUANT         &
194cabdff1aSopenharmony_ci                          ~XVID_VOP_INTER4V              &
195cabdff1aSopenharmony_ci                          ~XVID_VOP_HQACPRED;
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    param->vol_flags    &= ~XVID_VOL_GMC;
198cabdff1aSopenharmony_ci    param->vop_flags    &= vop_remove;
199cabdff1aSopenharmony_ci    param->motion_flags &= motion_remove;
200cabdff1aSopenharmony_ci    param->motion_flags |= motion_replacements;
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci    return 0;
203cabdff1aSopenharmony_ci}
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_ci/**
206cabdff1aSopenharmony_ci * Capture statistic data and write it during first pass.
207cabdff1aSopenharmony_ci *
208cabdff1aSopenharmony_ci * @param ref Context pointer for the plugin
209cabdff1aSopenharmony_ci * @param param Statistic data
210cabdff1aSopenharmony_ci * @return Returns XVID_ERR_xxxx on failure, or 0 on success
211cabdff1aSopenharmony_ci */
212cabdff1aSopenharmony_cistatic int xvid_ff_2pass_after(struct xvid_context *ref,
213cabdff1aSopenharmony_ci                               xvid_plg_data_t *param)
214cabdff1aSopenharmony_ci{
215cabdff1aSopenharmony_ci    char *log = ref->twopassbuffer;
216cabdff1aSopenharmony_ci    const char *frame_types = " ipbs";
217cabdff1aSopenharmony_ci    char frame_type;
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci    /* Quick bounds check */
220cabdff1aSopenharmony_ci    if (!log)
221cabdff1aSopenharmony_ci        return XVID_ERR_FAIL;
222cabdff1aSopenharmony_ci
223cabdff1aSopenharmony_ci    /* Convert the type given to us into a character */
224cabdff1aSopenharmony_ci    if (param->type < 5 && param->type > 0)
225cabdff1aSopenharmony_ci        frame_type = frame_types[param->type];
226cabdff1aSopenharmony_ci    else
227cabdff1aSopenharmony_ci        return XVID_ERR_FAIL;
228cabdff1aSopenharmony_ci
229cabdff1aSopenharmony_ci    snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log),
230cabdff1aSopenharmony_ci             "%c %d %d %d %d %d %d\n",
231cabdff1aSopenharmony_ci             frame_type, param->stats.quant, param->stats.kblks,
232cabdff1aSopenharmony_ci             param->stats.mblks, param->stats.ublks,
233cabdff1aSopenharmony_ci             param->stats.length, param->stats.hlength);
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    return 0;
236cabdff1aSopenharmony_ci}
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci/**
239cabdff1aSopenharmony_ci * Dispatch function for our custom plugin.
240cabdff1aSopenharmony_ci * This handles the dispatch for the Xvid plugin. It passes data
241cabdff1aSopenharmony_ci * on to other functions for actual processing.
242cabdff1aSopenharmony_ci *
243cabdff1aSopenharmony_ci * @param ref Context pointer for the plugin
244cabdff1aSopenharmony_ci * @param cmd The task given for us to complete
245cabdff1aSopenharmony_ci * @param p1 First parameter (varies)
246cabdff1aSopenharmony_ci * @param p2 Second parameter (varies)
247cabdff1aSopenharmony_ci * @return Returns XVID_ERR_xxxx on failure, or 0 on success
248cabdff1aSopenharmony_ci */
249cabdff1aSopenharmony_cistatic int xvid_ff_2pass(void *ref, int cmd, void *p1, void *p2)
250cabdff1aSopenharmony_ci{
251cabdff1aSopenharmony_ci    switch (cmd) {
252cabdff1aSopenharmony_ci    case XVID_PLG_INFO:
253cabdff1aSopenharmony_ci    case XVID_PLG_FRAME:
254cabdff1aSopenharmony_ci        return 0;
255cabdff1aSopenharmony_ci    case XVID_PLG_BEFORE:
256cabdff1aSopenharmony_ci        return xvid_ff_2pass_before(ref, p1);
257cabdff1aSopenharmony_ci    case XVID_PLG_CREATE:
258cabdff1aSopenharmony_ci        return xvid_ff_2pass_create(p1, p2);
259cabdff1aSopenharmony_ci    case XVID_PLG_AFTER:
260cabdff1aSopenharmony_ci        return xvid_ff_2pass_after(ref, p1);
261cabdff1aSopenharmony_ci    case XVID_PLG_DESTROY:
262cabdff1aSopenharmony_ci        return xvid_ff_2pass_destroy(ref, p1);
263cabdff1aSopenharmony_ci    default:
264cabdff1aSopenharmony_ci        return XVID_ERR_FAIL;
265cabdff1aSopenharmony_ci    }
266cabdff1aSopenharmony_ci}
267cabdff1aSopenharmony_ci
268cabdff1aSopenharmony_ci/**
269cabdff1aSopenharmony_ci * Routine to create a global VO/VOL header for MP4 container.
270cabdff1aSopenharmony_ci * What we do here is extract the header from the Xvid bitstream
271cabdff1aSopenharmony_ci * as it is encoded. We also strip the repeated headers from the
272cabdff1aSopenharmony_ci * bitstream when a global header is requested for MPEG-4 ISO
273cabdff1aSopenharmony_ci * compliance.
274cabdff1aSopenharmony_ci *
275cabdff1aSopenharmony_ci * @param avctx AVCodecContext pointer to context
276cabdff1aSopenharmony_ci * @param frame Pointer to encoded frame data
277cabdff1aSopenharmony_ci * @param header_len Length of header to search
278cabdff1aSopenharmony_ci * @param frame_len Length of encoded frame data
279cabdff1aSopenharmony_ci * @return Returns new length of frame data
280cabdff1aSopenharmony_ci */
281cabdff1aSopenharmony_cistatic int xvid_strip_vol_header(AVCodecContext *avctx, AVPacket *pkt,
282cabdff1aSopenharmony_ci                                 unsigned int header_len,
283cabdff1aSopenharmony_ci                                 unsigned int frame_len)
284cabdff1aSopenharmony_ci{
285cabdff1aSopenharmony_ci    int vo_len = 0, i;
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_ci    for (i = 0; i < header_len - 3; i++) {
288cabdff1aSopenharmony_ci        if (pkt->data[i]     == 0x00 &&
289cabdff1aSopenharmony_ci            pkt->data[i + 1] == 0x00 &&
290cabdff1aSopenharmony_ci            pkt->data[i + 2] == 0x01 &&
291cabdff1aSopenharmony_ci            pkt->data[i + 3] == 0xB6) {
292cabdff1aSopenharmony_ci            vo_len = i;
293cabdff1aSopenharmony_ci            break;
294cabdff1aSopenharmony_ci        }
295cabdff1aSopenharmony_ci    }
296cabdff1aSopenharmony_ci
297cabdff1aSopenharmony_ci    if (vo_len > 0) {
298cabdff1aSopenharmony_ci        /* We need to store the header, so extract it */
299cabdff1aSopenharmony_ci        if (!avctx->extradata) {
300cabdff1aSopenharmony_ci            avctx->extradata = av_malloc(vo_len);
301cabdff1aSopenharmony_ci            if (!avctx->extradata)
302cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
303cabdff1aSopenharmony_ci            memcpy(avctx->extradata, pkt->data, vo_len);
304cabdff1aSopenharmony_ci            avctx->extradata_size = vo_len;
305cabdff1aSopenharmony_ci        }
306cabdff1aSopenharmony_ci        /* Less dangerous now, memmove properly copies the two
307cabdff1aSopenharmony_ci         * chunks of overlapping data */
308cabdff1aSopenharmony_ci        memmove(pkt->data, &pkt->data[vo_len], frame_len - vo_len);
309cabdff1aSopenharmony_ci        pkt->size = frame_len - vo_len;
310cabdff1aSopenharmony_ci    }
311cabdff1aSopenharmony_ci    return 0;
312cabdff1aSopenharmony_ci}
313cabdff1aSopenharmony_ci
314cabdff1aSopenharmony_ci/**
315cabdff1aSopenharmony_ci * Routine to correct a possibly erroneous framerate being fed to us.
316cabdff1aSopenharmony_ci * Xvid currently chokes on framerates where the ticks per frame is
317cabdff1aSopenharmony_ci * extremely large. This function works to correct problems in this area
318cabdff1aSopenharmony_ci * by estimating a new framerate and taking the simpler fraction of
319cabdff1aSopenharmony_ci * the two presented.
320cabdff1aSopenharmony_ci *
321cabdff1aSopenharmony_ci * @param avctx Context that contains the framerate to correct.
322cabdff1aSopenharmony_ci */
323cabdff1aSopenharmony_cistatic void xvid_correct_framerate(AVCodecContext *avctx)
324cabdff1aSopenharmony_ci{
325cabdff1aSopenharmony_ci    int frate, fbase;
326cabdff1aSopenharmony_ci    int est_frate, est_fbase;
327cabdff1aSopenharmony_ci    int gcd;
328cabdff1aSopenharmony_ci    float est_fps, fps;
329cabdff1aSopenharmony_ci
330cabdff1aSopenharmony_ci    frate = avctx->time_base.den;
331cabdff1aSopenharmony_ci    fbase = avctx->time_base.num;
332cabdff1aSopenharmony_ci
333cabdff1aSopenharmony_ci    gcd = av_gcd(frate, fbase);
334cabdff1aSopenharmony_ci    if (gcd > 1) {
335cabdff1aSopenharmony_ci        frate /= gcd;
336cabdff1aSopenharmony_ci        fbase /= gcd;
337cabdff1aSopenharmony_ci    }
338cabdff1aSopenharmony_ci
339cabdff1aSopenharmony_ci    if (frate <= 65000 && fbase <= 65000) {
340cabdff1aSopenharmony_ci        avctx->time_base.den = frate;
341cabdff1aSopenharmony_ci        avctx->time_base.num = fbase;
342cabdff1aSopenharmony_ci        return;
343cabdff1aSopenharmony_ci    }
344cabdff1aSopenharmony_ci
345cabdff1aSopenharmony_ci    fps     = (float) frate / (float) fbase;
346cabdff1aSopenharmony_ci    est_fps = roundf(fps * 1000.0) / 1000.0;
347cabdff1aSopenharmony_ci
348cabdff1aSopenharmony_ci    est_frate = (int) est_fps;
349cabdff1aSopenharmony_ci    if (est_fps > (int) est_fps) {
350cabdff1aSopenharmony_ci        est_frate = (est_frate + 1) * 1000;
351cabdff1aSopenharmony_ci        est_fbase = (int) roundf((float) est_frate / est_fps);
352cabdff1aSopenharmony_ci    } else
353cabdff1aSopenharmony_ci        est_fbase = 1;
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_ci    gcd = av_gcd(est_frate, est_fbase);
356cabdff1aSopenharmony_ci    if (gcd > 1) {
357cabdff1aSopenharmony_ci        est_frate /= gcd;
358cabdff1aSopenharmony_ci        est_fbase /= gcd;
359cabdff1aSopenharmony_ci    }
360cabdff1aSopenharmony_ci
361cabdff1aSopenharmony_ci    if (fbase > est_fbase) {
362cabdff1aSopenharmony_ci        avctx->time_base.den = est_frate;
363cabdff1aSopenharmony_ci        avctx->time_base.num = est_fbase;
364cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG,
365cabdff1aSopenharmony_ci               "Xvid: framerate re-estimated: %.2f, %.3f%% correction\n",
366cabdff1aSopenharmony_ci               est_fps, (((est_fps - fps) / fps) * 100.0));
367cabdff1aSopenharmony_ci    } else {
368cabdff1aSopenharmony_ci        avctx->time_base.den = frate;
369cabdff1aSopenharmony_ci        avctx->time_base.num = fbase;
370cabdff1aSopenharmony_ci    }
371cabdff1aSopenharmony_ci}
372cabdff1aSopenharmony_ci
373cabdff1aSopenharmony_cistatic av_cold int xvid_encode_init(AVCodecContext *avctx)
374cabdff1aSopenharmony_ci{
375cabdff1aSopenharmony_ci    int xerr, i, ret = -1;
376cabdff1aSopenharmony_ci    int xvid_flags = avctx->flags;
377cabdff1aSopenharmony_ci    struct xvid_context *x = avctx->priv_data;
378cabdff1aSopenharmony_ci    uint16_t *intra, *inter;
379cabdff1aSopenharmony_ci    int fd;
380cabdff1aSopenharmony_ci
381cabdff1aSopenharmony_ci    xvid_plugin_single_t      single          = { 0 };
382cabdff1aSopenharmony_ci    struct xvid_ff_pass1      rc2pass1        = { 0 };
383cabdff1aSopenharmony_ci    xvid_plugin_2pass2_t      rc2pass2        = { 0 };
384cabdff1aSopenharmony_ci    xvid_plugin_lumimasking_t masking_l       = { 0 }; /* For lumi masking */
385cabdff1aSopenharmony_ci    xvid_plugin_lumimasking_t masking_v       = { 0 }; /* For variance AQ */
386cabdff1aSopenharmony_ci    xvid_plugin_ssim_t        ssim            = { 0 };
387cabdff1aSopenharmony_ci    xvid_gbl_init_t           xvid_gbl_init   = { 0 };
388cabdff1aSopenharmony_ci    xvid_enc_create_t         xvid_enc_create = { 0 };
389cabdff1aSopenharmony_ci    xvid_enc_plugin_t         plugins[4];
390cabdff1aSopenharmony_ci
391cabdff1aSopenharmony_ci    x->twopassfd = -1;
392cabdff1aSopenharmony_ci
393cabdff1aSopenharmony_ci    /* Bring in VOP flags from ffmpeg command-line */
394cabdff1aSopenharmony_ci    x->vop_flags = XVID_VOP_HALFPEL;              /* Bare minimum quality */
395cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_4MV)
396cabdff1aSopenharmony_ci        x->vop_flags    |= XVID_VOP_INTER4V;      /* Level 3 */
397cabdff1aSopenharmony_ci    if (avctx->trellis)
398cabdff1aSopenharmony_ci        x->vop_flags    |= XVID_VOP_TRELLISQUANT; /* Level 5 */
399cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_AC_PRED)
400cabdff1aSopenharmony_ci        x->vop_flags    |= XVID_VOP_HQACPRED;     /* Level 6 */
401cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_GRAY)
402cabdff1aSopenharmony_ci        x->vop_flags    |= XVID_VOP_GREYSCALE;
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_ci    /* Decide which ME quality setting to use */
405cabdff1aSopenharmony_ci    x->me_flags = 0;
406cabdff1aSopenharmony_ci    switch (x->me_quality) {
407cabdff1aSopenharmony_ci    case 6:
408cabdff1aSopenharmony_ci    case 5:
409cabdff1aSopenharmony_ci        x->me_flags |= XVID_ME_EXTSEARCH16 |
410cabdff1aSopenharmony_ci                       XVID_ME_EXTSEARCH8;
411cabdff1aSopenharmony_ci    case 4:
412cabdff1aSopenharmony_ci    case 3:
413cabdff1aSopenharmony_ci        x->me_flags |= XVID_ME_ADVANCEDDIAMOND8 |
414cabdff1aSopenharmony_ci                       XVID_ME_HALFPELREFINE8   |
415cabdff1aSopenharmony_ci                       XVID_ME_CHROMA_PVOP      |
416cabdff1aSopenharmony_ci                       XVID_ME_CHROMA_BVOP;
417cabdff1aSopenharmony_ci    case 2:
418cabdff1aSopenharmony_ci    case 1:
419cabdff1aSopenharmony_ci        x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 |
420cabdff1aSopenharmony_ci                       XVID_ME_HALFPELREFINE16;
421cabdff1aSopenharmony_ci    }
422cabdff1aSopenharmony_ci
423cabdff1aSopenharmony_ci    /* Decide how we should decide blocks */
424cabdff1aSopenharmony_ci    switch (avctx->mb_decision) {
425cabdff1aSopenharmony_ci    case 2:
426cabdff1aSopenharmony_ci        x->vop_flags |=  XVID_VOP_MODEDECISION_RD;
427cabdff1aSopenharmony_ci        x->me_flags  |=  XVID_ME_HALFPELREFINE8_RD    |
428cabdff1aSopenharmony_ci                         XVID_ME_QUARTERPELREFINE8_RD |
429cabdff1aSopenharmony_ci                         XVID_ME_EXTSEARCH_RD         |
430cabdff1aSopenharmony_ci                         XVID_ME_CHECKPREDICTION_RD;
431cabdff1aSopenharmony_ci    case 1:
432cabdff1aSopenharmony_ci        if (!(x->vop_flags & XVID_VOP_MODEDECISION_RD))
433cabdff1aSopenharmony_ci            x->vop_flags |= XVID_VOP_FAST_MODEDECISION_RD;
434cabdff1aSopenharmony_ci        x->me_flags |= XVID_ME_HALFPELREFINE16_RD |
435cabdff1aSopenharmony_ci                       XVID_ME_QUARTERPELREFINE16_RD;
436cabdff1aSopenharmony_ci    default:
437cabdff1aSopenharmony_ci        break;
438cabdff1aSopenharmony_ci    }
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci    /* Bring in VOL flags from ffmpeg command-line */
441cabdff1aSopenharmony_ci    x->vol_flags = 0;
442cabdff1aSopenharmony_ci    if (x->gmc) {
443cabdff1aSopenharmony_ci        x->vol_flags |= XVID_VOL_GMC;
444cabdff1aSopenharmony_ci        x->me_flags  |= XVID_ME_GME_REFINE;
445cabdff1aSopenharmony_ci    }
446cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_QPEL) {
447cabdff1aSopenharmony_ci        x->vol_flags |= XVID_VOL_QUARTERPEL;
448cabdff1aSopenharmony_ci        x->me_flags  |= XVID_ME_QUARTERPELREFINE16;
449cabdff1aSopenharmony_ci        if (x->vop_flags & XVID_VOP_INTER4V)
450cabdff1aSopenharmony_ci            x->me_flags |= XVID_ME_QUARTERPELREFINE8;
451cabdff1aSopenharmony_ci    }
452cabdff1aSopenharmony_ci
453cabdff1aSopenharmony_ci    xvid_gbl_init.version   = XVID_VERSION;
454cabdff1aSopenharmony_ci    xvid_gbl_init.debug     = 0;
455cabdff1aSopenharmony_ci    xvid_gbl_init.cpu_flags = 0;
456cabdff1aSopenharmony_ci
457cabdff1aSopenharmony_ci    /* Initialize */
458cabdff1aSopenharmony_ci    xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_ci    /* Create the encoder reference */
461cabdff1aSopenharmony_ci    xvid_enc_create.version = XVID_VERSION;
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ci    /* Store the desired frame size */
464cabdff1aSopenharmony_ci    xvid_enc_create.width  =
465cabdff1aSopenharmony_ci    x->xsize               = avctx->width;
466cabdff1aSopenharmony_ci    xvid_enc_create.height =
467cabdff1aSopenharmony_ci    x->ysize               = avctx->height;
468cabdff1aSopenharmony_ci
469cabdff1aSopenharmony_ci    /* Xvid can determine the proper profile to use */
470cabdff1aSopenharmony_ci    /* xvid_enc_create.profile = XVID_PROFILE_S_L3; */
471cabdff1aSopenharmony_ci
472cabdff1aSopenharmony_ci    /* We don't use zones */
473cabdff1aSopenharmony_ci    xvid_enc_create.zones     = NULL;
474cabdff1aSopenharmony_ci    xvid_enc_create.num_zones = 0;
475cabdff1aSopenharmony_ci
476cabdff1aSopenharmony_ci    xvid_enc_create.num_threads = avctx->thread_count;
477cabdff1aSopenharmony_ci#if (XVID_VERSION <= 0x010303) && (XVID_VERSION >= 0x010300)
478cabdff1aSopenharmony_ci    /* workaround for a bug in libxvidcore */
479cabdff1aSopenharmony_ci    if (avctx->height <= 16) {
480cabdff1aSopenharmony_ci        if (avctx->thread_count < 2) {
481cabdff1aSopenharmony_ci            xvid_enc_create.num_threads = 0;
482cabdff1aSopenharmony_ci        } else {
483cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
484cabdff1aSopenharmony_ci                   "Too small height for threads > 1.");
485cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
486cabdff1aSopenharmony_ci        }
487cabdff1aSopenharmony_ci    }
488cabdff1aSopenharmony_ci#endif
489cabdff1aSopenharmony_ci
490cabdff1aSopenharmony_ci    xvid_enc_create.plugins     = plugins;
491cabdff1aSopenharmony_ci    xvid_enc_create.num_plugins = 0;
492cabdff1aSopenharmony_ci
493cabdff1aSopenharmony_ci    /* Initialize Buffers */
494cabdff1aSopenharmony_ci    x->twopassbuffer     = NULL;
495cabdff1aSopenharmony_ci    x->old_twopassbuffer = NULL;
496cabdff1aSopenharmony_ci    x->twopassfile       = NULL;
497cabdff1aSopenharmony_ci
498cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_PASS1) {
499cabdff1aSopenharmony_ci        rc2pass1.version     = XVID_VERSION;
500cabdff1aSopenharmony_ci        rc2pass1.context     = x;
501cabdff1aSopenharmony_ci        x->twopassbuffer     = av_malloc(BUFFER_SIZE);
502cabdff1aSopenharmony_ci        x->old_twopassbuffer = av_malloc(BUFFER_SIZE);
503cabdff1aSopenharmony_ci        if (!x->twopassbuffer || !x->old_twopassbuffer) {
504cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
505cabdff1aSopenharmony_ci                   "Xvid: Cannot allocate 2-pass log buffers\n");
506cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
507cabdff1aSopenharmony_ci        }
508cabdff1aSopenharmony_ci        x->twopassbuffer[0]     =
509cabdff1aSopenharmony_ci        x->old_twopassbuffer[0] = 0;
510cabdff1aSopenharmony_ci
511cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].func  = xvid_ff_2pass;
512cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].param = &rc2pass1;
513cabdff1aSopenharmony_ci        xvid_enc_create.num_plugins++;
514cabdff1aSopenharmony_ci    } else if (xvid_flags & AV_CODEC_FLAG_PASS2) {
515cabdff1aSopenharmony_ci        rc2pass2.version = XVID_VERSION;
516cabdff1aSopenharmony_ci        rc2pass2.bitrate = avctx->bit_rate;
517cabdff1aSopenharmony_ci
518cabdff1aSopenharmony_ci        fd = avpriv_tempfile("xvidff.", &x->twopassfile, 0, avctx);
519cabdff1aSopenharmony_ci        if (fd < 0) {
520cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write 2-pass pipe\n");
521cabdff1aSopenharmony_ci            return fd;
522cabdff1aSopenharmony_ci        }
523cabdff1aSopenharmony_ci        x->twopassfd = fd;
524cabdff1aSopenharmony_ci
525cabdff1aSopenharmony_ci        if (!avctx->stats_in) {
526cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
527cabdff1aSopenharmony_ci                   "Xvid: No 2-pass information loaded for second pass\n");
528cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
529cabdff1aSopenharmony_ci        }
530cabdff1aSopenharmony_ci
531cabdff1aSopenharmony_ci        ret = write(fd, avctx->stats_in, strlen(avctx->stats_in));
532cabdff1aSopenharmony_ci        if (ret == -1)
533cabdff1aSopenharmony_ci            ret = AVERROR(errno);
534cabdff1aSopenharmony_ci        else if (strlen(avctx->stats_in) > ret) {
535cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write to 2-pass pipe\n");
536cabdff1aSopenharmony_ci            ret = AVERROR(EIO);
537cabdff1aSopenharmony_ci        }
538cabdff1aSopenharmony_ci        if (ret < 0)
539cabdff1aSopenharmony_ci            return ret;
540cabdff1aSopenharmony_ci
541cabdff1aSopenharmony_ci        rc2pass2.filename                          = x->twopassfile;
542cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].func  = xvid_plugin_2pass2;
543cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].param = &rc2pass2;
544cabdff1aSopenharmony_ci        xvid_enc_create.num_plugins++;
545cabdff1aSopenharmony_ci    } else if (!(xvid_flags & AV_CODEC_FLAG_QSCALE)) {
546cabdff1aSopenharmony_ci        /* Single Pass Bitrate Control! */
547cabdff1aSopenharmony_ci        single.version = XVID_VERSION;
548cabdff1aSopenharmony_ci        single.bitrate = avctx->bit_rate;
549cabdff1aSopenharmony_ci
550cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].func  = xvid_plugin_single;
551cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].param = &single;
552cabdff1aSopenharmony_ci        xvid_enc_create.num_plugins++;
553cabdff1aSopenharmony_ci    }
554cabdff1aSopenharmony_ci
555cabdff1aSopenharmony_ci    if (avctx->lumi_masking != 0.0)
556cabdff1aSopenharmony_ci        x->lumi_aq = 1;
557cabdff1aSopenharmony_ci
558cabdff1aSopenharmony_ci    /* Luminance Masking */
559cabdff1aSopenharmony_ci    if (x->lumi_aq) {
560cabdff1aSopenharmony_ci        masking_l.method                          = 0;
561cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking;
562cabdff1aSopenharmony_ci
563cabdff1aSopenharmony_ci        /* The old behavior is that when avctx->lumi_masking is specified,
564cabdff1aSopenharmony_ci         * plugins[...].param = NULL. Trying to keep the old behavior here. */
565cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].param =
566cabdff1aSopenharmony_ci            avctx->lumi_masking ? NULL : &masking_l;
567cabdff1aSopenharmony_ci        xvid_enc_create.num_plugins++;
568cabdff1aSopenharmony_ci    }
569cabdff1aSopenharmony_ci
570cabdff1aSopenharmony_ci    /* Variance AQ */
571cabdff1aSopenharmony_ci    if (x->variance_aq) {
572cabdff1aSopenharmony_ci        masking_v.method                           = 1;
573cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].func  = xvid_plugin_lumimasking;
574cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].param = &masking_v;
575cabdff1aSopenharmony_ci        xvid_enc_create.num_plugins++;
576cabdff1aSopenharmony_ci    }
577cabdff1aSopenharmony_ci
578cabdff1aSopenharmony_ci    if (x->lumi_aq && x->variance_aq )
579cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_INFO,
580cabdff1aSopenharmony_ci               "Both lumi_aq and variance_aq are enabled. The resulting quality"
581cabdff1aSopenharmony_ci               "will be the worse one of the two effects made by the AQ.\n");
582cabdff1aSopenharmony_ci
583cabdff1aSopenharmony_ci    /* SSIM */
584cabdff1aSopenharmony_ci    if (x->ssim) {
585cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].func  = xvid_plugin_ssim;
586cabdff1aSopenharmony_ci        ssim.b_printstat                           = x->ssim == 2;
587cabdff1aSopenharmony_ci        ssim.acc                                   = x->ssim_acc;
588cabdff1aSopenharmony_ci        ssim.cpu_flags                             = xvid_gbl_init.cpu_flags;
589cabdff1aSopenharmony_ci        ssim.b_visualize                           = 0;
590cabdff1aSopenharmony_ci        plugins[xvid_enc_create.num_plugins].param = &ssim;
591cabdff1aSopenharmony_ci        xvid_enc_create.num_plugins++;
592cabdff1aSopenharmony_ci    }
593cabdff1aSopenharmony_ci
594cabdff1aSopenharmony_ci    /* Frame Rate and Key Frames */
595cabdff1aSopenharmony_ci    xvid_correct_framerate(avctx);
596cabdff1aSopenharmony_ci    xvid_enc_create.fincr = avctx->time_base.num;
597cabdff1aSopenharmony_ci    xvid_enc_create.fbase = avctx->time_base.den;
598cabdff1aSopenharmony_ci    if (avctx->gop_size > 0)
599cabdff1aSopenharmony_ci        xvid_enc_create.max_key_interval = avctx->gop_size;
600cabdff1aSopenharmony_ci    else
601cabdff1aSopenharmony_ci        xvid_enc_create.max_key_interval = 240; /* Xvid's best default */
602cabdff1aSopenharmony_ci
603cabdff1aSopenharmony_ci    /* Quants */
604cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_QSCALE)
605cabdff1aSopenharmony_ci        x->qscale = 1;
606cabdff1aSopenharmony_ci    else
607cabdff1aSopenharmony_ci        x->qscale = 0;
608cabdff1aSopenharmony_ci
609cabdff1aSopenharmony_ci    xvid_enc_create.min_quant[0] = avctx->qmin;
610cabdff1aSopenharmony_ci    xvid_enc_create.min_quant[1] = avctx->qmin;
611cabdff1aSopenharmony_ci    xvid_enc_create.min_quant[2] = avctx->qmin;
612cabdff1aSopenharmony_ci    xvid_enc_create.max_quant[0] = avctx->qmax;
613cabdff1aSopenharmony_ci    xvid_enc_create.max_quant[1] = avctx->qmax;
614cabdff1aSopenharmony_ci    xvid_enc_create.max_quant[2] = avctx->qmax;
615cabdff1aSopenharmony_ci
616cabdff1aSopenharmony_ci    /* Quant Matrices */
617cabdff1aSopenharmony_ci    x->intra_matrix =
618cabdff1aSopenharmony_ci    x->inter_matrix = NULL;
619cabdff1aSopenharmony_ci
620cabdff1aSopenharmony_ci    if (x->mpeg_quant)
621cabdff1aSopenharmony_ci        x->vol_flags |= XVID_VOL_MPEGQUANT;
622cabdff1aSopenharmony_ci    if ((avctx->intra_matrix || avctx->inter_matrix)) {
623cabdff1aSopenharmony_ci        x->vol_flags |= XVID_VOL_MPEGQUANT;
624cabdff1aSopenharmony_ci
625cabdff1aSopenharmony_ci        if (avctx->intra_matrix) {
626cabdff1aSopenharmony_ci            intra           = avctx->intra_matrix;
627cabdff1aSopenharmony_ci            x->intra_matrix = av_malloc(sizeof(unsigned char) * 64);
628cabdff1aSopenharmony_ci            if (!x->intra_matrix)
629cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
630cabdff1aSopenharmony_ci        } else
631cabdff1aSopenharmony_ci            intra = NULL;
632cabdff1aSopenharmony_ci        if (avctx->inter_matrix) {
633cabdff1aSopenharmony_ci            inter           = avctx->inter_matrix;
634cabdff1aSopenharmony_ci            x->inter_matrix = av_malloc(sizeof(unsigned char) * 64);
635cabdff1aSopenharmony_ci            if (!x->inter_matrix)
636cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
637cabdff1aSopenharmony_ci        } else
638cabdff1aSopenharmony_ci            inter = NULL;
639cabdff1aSopenharmony_ci
640cabdff1aSopenharmony_ci        for (i = 0; i < 64; i++) {
641cabdff1aSopenharmony_ci            if (intra)
642cabdff1aSopenharmony_ci                x->intra_matrix[i] = (unsigned char) intra[i];
643cabdff1aSopenharmony_ci            if (inter)
644cabdff1aSopenharmony_ci                x->inter_matrix[i] = (unsigned char) inter[i];
645cabdff1aSopenharmony_ci        }
646cabdff1aSopenharmony_ci    }
647cabdff1aSopenharmony_ci
648cabdff1aSopenharmony_ci    /* Misc Settings */
649cabdff1aSopenharmony_ci    xvid_enc_create.frame_drop_ratio = 0;
650cabdff1aSopenharmony_ci    xvid_enc_create.global           = 0;
651cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_CLOSED_GOP)
652cabdff1aSopenharmony_ci        xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP;
653cabdff1aSopenharmony_ci
654cabdff1aSopenharmony_ci    /* Determines which codec mode we are operating in */
655cabdff1aSopenharmony_ci    avctx->extradata      = NULL;
656cabdff1aSopenharmony_ci    avctx->extradata_size = 0;
657cabdff1aSopenharmony_ci    if (xvid_flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
658cabdff1aSopenharmony_ci        /* In this case, we are claiming to be MPEG-4 */
659cabdff1aSopenharmony_ci        x->quicktime_format = 1;
660cabdff1aSopenharmony_ci    } else {
661cabdff1aSopenharmony_ci        /* We are claiming to be Xvid */
662cabdff1aSopenharmony_ci        x->quicktime_format = 0;
663cabdff1aSopenharmony_ci        if (!avctx->codec_tag)
664cabdff1aSopenharmony_ci            avctx->codec_tag = AV_RL32("xvid");
665cabdff1aSopenharmony_ci    }
666cabdff1aSopenharmony_ci
667cabdff1aSopenharmony_ci    /* Bframes */
668cabdff1aSopenharmony_ci    xvid_enc_create.max_bframes   = avctx->max_b_frames;
669cabdff1aSopenharmony_ci    xvid_enc_create.bquant_offset = 100 * avctx->b_quant_offset;
670cabdff1aSopenharmony_ci    xvid_enc_create.bquant_ratio  = 100 * avctx->b_quant_factor;
671cabdff1aSopenharmony_ci    if (avctx->max_b_frames > 0 && !x->quicktime_format)
672cabdff1aSopenharmony_ci        xvid_enc_create.global |= XVID_GLOBAL_PACKED;
673cabdff1aSopenharmony_ci
674cabdff1aSopenharmony_ci    av_assert0(xvid_enc_create.num_plugins + (!!x->ssim) + (!!x->variance_aq) + (!!x->lumi_aq) <= FF_ARRAY_ELEMS(plugins));
675cabdff1aSopenharmony_ci
676cabdff1aSopenharmony_ci    /* Encode a dummy frame to get the extradata immediately */
677cabdff1aSopenharmony_ci    if (x->quicktime_format) {
678cabdff1aSopenharmony_ci        AVFrame *picture;
679cabdff1aSopenharmony_ci        AVPacket *packet;
680cabdff1aSopenharmony_ci        int size, got_packet;
681cabdff1aSopenharmony_ci
682cabdff1aSopenharmony_ci        packet = av_packet_alloc();
683cabdff1aSopenharmony_ci        if (!packet)
684cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
685cabdff1aSopenharmony_ci
686cabdff1aSopenharmony_ci        picture = av_frame_alloc();
687cabdff1aSopenharmony_ci        if (!picture) {
688cabdff1aSopenharmony_ci            av_packet_free(&packet);
689cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
690cabdff1aSopenharmony_ci        }
691cabdff1aSopenharmony_ci
692cabdff1aSopenharmony_ci        xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);
693cabdff1aSopenharmony_ci        if( xerr ) {
694cabdff1aSopenharmony_ci            av_packet_free(&packet);
695cabdff1aSopenharmony_ci            av_frame_free(&picture);
696cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Xvid: Could not create encoder reference\n");
697cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
698cabdff1aSopenharmony_ci        }
699cabdff1aSopenharmony_ci        x->encoder_handle = xvid_enc_create.handle;
700cabdff1aSopenharmony_ci        size = ((avctx->width + 1) & ~1) * ((avctx->height + 1) & ~1);
701cabdff1aSopenharmony_ci        picture->data[0] = av_malloc(size + size / 2);
702cabdff1aSopenharmony_ci        if (!picture->data[0]) {
703cabdff1aSopenharmony_ci            av_packet_free(&packet);
704cabdff1aSopenharmony_ci            av_frame_free(&picture);
705cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
706cabdff1aSopenharmony_ci        }
707cabdff1aSopenharmony_ci        picture->data[1] = picture->data[0] + size;
708cabdff1aSopenharmony_ci        picture->data[2] = picture->data[1] + size / 4;
709cabdff1aSopenharmony_ci        memset(picture->data[0], 0, size);
710cabdff1aSopenharmony_ci        memset(picture->data[1], 128, size / 2);
711cabdff1aSopenharmony_ci        xvid_encode_frame(avctx, packet, picture, &got_packet);
712cabdff1aSopenharmony_ci        av_packet_free(&packet);
713cabdff1aSopenharmony_ci        av_free(picture->data[0]);
714cabdff1aSopenharmony_ci        av_frame_free(&picture);
715cabdff1aSopenharmony_ci        xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL);
716cabdff1aSopenharmony_ci    }
717cabdff1aSopenharmony_ci
718cabdff1aSopenharmony_ci    /* Create encoder context */
719cabdff1aSopenharmony_ci    xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);
720cabdff1aSopenharmony_ci    if (xerr) {
721cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Xvid: Could not create encoder reference\n");
722cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
723cabdff1aSopenharmony_ci    }
724cabdff1aSopenharmony_ci
725cabdff1aSopenharmony_ci    x->encoder_handle  = xvid_enc_create.handle;
726cabdff1aSopenharmony_ci
727cabdff1aSopenharmony_ci    return 0;
728cabdff1aSopenharmony_ci}
729cabdff1aSopenharmony_ci
730cabdff1aSopenharmony_cistatic int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
731cabdff1aSopenharmony_ci                             const AVFrame *picture, int *got_packet)
732cabdff1aSopenharmony_ci{
733cabdff1aSopenharmony_ci    int xerr, i, ret;
734cabdff1aSopenharmony_ci    struct xvid_context *x = avctx->priv_data;
735cabdff1aSopenharmony_ci    int mb_width  = (avctx->width  + 15) / 16;
736cabdff1aSopenharmony_ci    int mb_height = (avctx->height + 15) / 16;
737cabdff1aSopenharmony_ci    char *tmp;
738cabdff1aSopenharmony_ci
739cabdff1aSopenharmony_ci    xvid_enc_frame_t xvid_enc_frame = { 0 };
740cabdff1aSopenharmony_ci    xvid_enc_stats_t xvid_enc_stats = { 0 };
741cabdff1aSopenharmony_ci
742cabdff1aSopenharmony_ci    if ((ret = ff_alloc_packet(avctx, pkt, mb_width*(int64_t)mb_height*MAX_MB_BYTES + AV_INPUT_BUFFER_MIN_SIZE)) < 0)
743cabdff1aSopenharmony_ci        return ret;
744cabdff1aSopenharmony_ci
745cabdff1aSopenharmony_ci    /* Start setting up the frame */
746cabdff1aSopenharmony_ci    xvid_enc_frame.version = XVID_VERSION;
747cabdff1aSopenharmony_ci    xvid_enc_stats.version = XVID_VERSION;
748cabdff1aSopenharmony_ci
749cabdff1aSopenharmony_ci    /* Let Xvid know where to put the frame. */
750cabdff1aSopenharmony_ci    xvid_enc_frame.bitstream = pkt->data;
751cabdff1aSopenharmony_ci    xvid_enc_frame.length    = pkt->size;
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_ci    /* Initialize input image fields */
754cabdff1aSopenharmony_ci    if (avctx->pix_fmt != AV_PIX_FMT_YUV420P) {
755cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
756cabdff1aSopenharmony_ci               "Xvid: Color spaces other than 420P not supported\n");
757cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
758cabdff1aSopenharmony_ci    }
759cabdff1aSopenharmony_ci
760cabdff1aSopenharmony_ci    xvid_enc_frame.input.csp = XVID_CSP_PLANAR; /* YUV420P */
761cabdff1aSopenharmony_ci
762cabdff1aSopenharmony_ci    for (i = 0; i < 4; i++) {
763cabdff1aSopenharmony_ci        xvid_enc_frame.input.plane[i]  = picture->data[i];
764cabdff1aSopenharmony_ci        xvid_enc_frame.input.stride[i] = picture->linesize[i];
765cabdff1aSopenharmony_ci    }
766cabdff1aSopenharmony_ci
767cabdff1aSopenharmony_ci    /* Encoder Flags */
768cabdff1aSopenharmony_ci    xvid_enc_frame.vop_flags = x->vop_flags;
769cabdff1aSopenharmony_ci    xvid_enc_frame.vol_flags = x->vol_flags;
770cabdff1aSopenharmony_ci    xvid_enc_frame.motion    = x->me_flags;
771cabdff1aSopenharmony_ci    xvid_enc_frame.type      =
772cabdff1aSopenharmony_ci        picture->pict_type == AV_PICTURE_TYPE_I ? XVID_TYPE_IVOP :
773cabdff1aSopenharmony_ci        picture->pict_type == AV_PICTURE_TYPE_P ? XVID_TYPE_PVOP :
774cabdff1aSopenharmony_ci        picture->pict_type == AV_PICTURE_TYPE_B ? XVID_TYPE_BVOP :
775cabdff1aSopenharmony_ci                                                  XVID_TYPE_AUTO;
776cabdff1aSopenharmony_ci
777cabdff1aSopenharmony_ci    /* Pixel aspect ratio setting */
778cabdff1aSopenharmony_ci    if (avctx->sample_aspect_ratio.num < 0 || avctx->sample_aspect_ratio.num > 255 ||
779cabdff1aSopenharmony_ci        avctx->sample_aspect_ratio.den < 0 || avctx->sample_aspect_ratio.den > 255) {
780cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_WARNING,
781cabdff1aSopenharmony_ci               "Invalid pixel aspect ratio %i/%i, limit is 255/255 reducing\n",
782cabdff1aSopenharmony_ci               avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den);
783cabdff1aSopenharmony_ci        av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den,
784cabdff1aSopenharmony_ci                   avctx->sample_aspect_ratio.num,  avctx->sample_aspect_ratio.den, 255);
785cabdff1aSopenharmony_ci    }
786cabdff1aSopenharmony_ci    xvid_enc_frame.par        = XVID_PAR_EXT;
787cabdff1aSopenharmony_ci    xvid_enc_frame.par_width  = avctx->sample_aspect_ratio.num;
788cabdff1aSopenharmony_ci    xvid_enc_frame.par_height = avctx->sample_aspect_ratio.den;
789cabdff1aSopenharmony_ci
790cabdff1aSopenharmony_ci    /* Quant Setting */
791cabdff1aSopenharmony_ci    if (x->qscale)
792cabdff1aSopenharmony_ci        xvid_enc_frame.quant = picture->quality / FF_QP2LAMBDA;
793cabdff1aSopenharmony_ci    else
794cabdff1aSopenharmony_ci        xvid_enc_frame.quant = 0;
795cabdff1aSopenharmony_ci
796cabdff1aSopenharmony_ci    /* Matrices */
797cabdff1aSopenharmony_ci    xvid_enc_frame.quant_intra_matrix = x->intra_matrix;
798cabdff1aSopenharmony_ci    xvid_enc_frame.quant_inter_matrix = x->inter_matrix;
799cabdff1aSopenharmony_ci
800cabdff1aSopenharmony_ci    /* Encode */
801cabdff1aSopenharmony_ci    xerr = xvid_encore(x->encoder_handle, XVID_ENC_ENCODE,
802cabdff1aSopenharmony_ci                       &xvid_enc_frame, &xvid_enc_stats);
803cabdff1aSopenharmony_ci
804cabdff1aSopenharmony_ci    /* Two-pass log buffer swapping */
805cabdff1aSopenharmony_ci    avctx->stats_out = NULL;
806cabdff1aSopenharmony_ci    if (x->twopassbuffer) {
807cabdff1aSopenharmony_ci        tmp                  = x->old_twopassbuffer;
808cabdff1aSopenharmony_ci        x->old_twopassbuffer = x->twopassbuffer;
809cabdff1aSopenharmony_ci        x->twopassbuffer     = tmp;
810cabdff1aSopenharmony_ci        x->twopassbuffer[0]  = 0;
811cabdff1aSopenharmony_ci        if (x->old_twopassbuffer[0] != 0) {
812cabdff1aSopenharmony_ci            avctx->stats_out = x->old_twopassbuffer;
813cabdff1aSopenharmony_ci        }
814cabdff1aSopenharmony_ci    }
815cabdff1aSopenharmony_ci
816cabdff1aSopenharmony_ci    if (xerr > 0) {
817cabdff1aSopenharmony_ci        int pict_type;
818cabdff1aSopenharmony_ci
819cabdff1aSopenharmony_ci        *got_packet = 1;
820cabdff1aSopenharmony_ci
821cabdff1aSopenharmony_ci        if (xvid_enc_stats.type == XVID_TYPE_PVOP)
822cabdff1aSopenharmony_ci            pict_type = AV_PICTURE_TYPE_P;
823cabdff1aSopenharmony_ci        else if (xvid_enc_stats.type == XVID_TYPE_BVOP)
824cabdff1aSopenharmony_ci            pict_type = AV_PICTURE_TYPE_B;
825cabdff1aSopenharmony_ci        else if (xvid_enc_stats.type == XVID_TYPE_SVOP)
826cabdff1aSopenharmony_ci            pict_type = AV_PICTURE_TYPE_S;
827cabdff1aSopenharmony_ci        else
828cabdff1aSopenharmony_ci            pict_type = AV_PICTURE_TYPE_I;
829cabdff1aSopenharmony_ci
830cabdff1aSopenharmony_ci        ff_side_data_set_encoder_stats(pkt, xvid_enc_stats.quant * FF_QP2LAMBDA, NULL, 0, pict_type);
831cabdff1aSopenharmony_ci
832cabdff1aSopenharmony_ci        if (xvid_enc_frame.out_flags & XVID_KEYFRAME) {
833cabdff1aSopenharmony_ci            pkt->flags  |= AV_PKT_FLAG_KEY;
834cabdff1aSopenharmony_ci            if (x->quicktime_format)
835cabdff1aSopenharmony_ci                return xvid_strip_vol_header(avctx, pkt,
836cabdff1aSopenharmony_ci                                             xvid_enc_stats.hlength, xerr);
837cabdff1aSopenharmony_ci        }
838cabdff1aSopenharmony_ci
839cabdff1aSopenharmony_ci        pkt->size = xerr;
840cabdff1aSopenharmony_ci
841cabdff1aSopenharmony_ci        return 0;
842cabdff1aSopenharmony_ci    } else {
843cabdff1aSopenharmony_ci        if (!xerr)
844cabdff1aSopenharmony_ci            return 0;
845cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
846cabdff1aSopenharmony_ci               "Xvid: Encoding Error Occurred: %i\n", xerr);
847cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
848cabdff1aSopenharmony_ci    }
849cabdff1aSopenharmony_ci}
850cabdff1aSopenharmony_ci
851cabdff1aSopenharmony_cistatic av_cold int xvid_encode_close(AVCodecContext *avctx)
852cabdff1aSopenharmony_ci{
853cabdff1aSopenharmony_ci    struct xvid_context *x = avctx->priv_data;
854cabdff1aSopenharmony_ci
855cabdff1aSopenharmony_ci    if (x->encoder_handle) {
856cabdff1aSopenharmony_ci        xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL);
857cabdff1aSopenharmony_ci        x->encoder_handle = NULL;
858cabdff1aSopenharmony_ci    }
859cabdff1aSopenharmony_ci
860cabdff1aSopenharmony_ci    if (x->twopassbuffer) {
861cabdff1aSopenharmony_ci        av_freep(&x->twopassbuffer);
862cabdff1aSopenharmony_ci        av_freep(&x->old_twopassbuffer);
863cabdff1aSopenharmony_ci        avctx->stats_out = NULL;
864cabdff1aSopenharmony_ci    }
865cabdff1aSopenharmony_ci    if (x->twopassfd>=0) {
866cabdff1aSopenharmony_ci        unlink(x->twopassfile);
867cabdff1aSopenharmony_ci        close(x->twopassfd);
868cabdff1aSopenharmony_ci        x->twopassfd = -1;
869cabdff1aSopenharmony_ci    }
870cabdff1aSopenharmony_ci    av_freep(&x->twopassfile);
871cabdff1aSopenharmony_ci    av_freep(&x->intra_matrix);
872cabdff1aSopenharmony_ci    av_freep(&x->inter_matrix);
873cabdff1aSopenharmony_ci
874cabdff1aSopenharmony_ci    return 0;
875cabdff1aSopenharmony_ci}
876cabdff1aSopenharmony_ci
877cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(struct xvid_context, x)
878cabdff1aSopenharmony_ci#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
879cabdff1aSopenharmony_cistatic const AVOption options[] = {
880cabdff1aSopenharmony_ci    { "lumi_aq",     "Luminance masking AQ",            OFFSET(lumi_aq),     AV_OPT_TYPE_INT,   { .i64 = 0 },       0,       1, VE         },
881cabdff1aSopenharmony_ci    { "variance_aq", "Variance AQ",                     OFFSET(variance_aq), AV_OPT_TYPE_INT,   { .i64 = 0 },       0,       1, VE         },
882cabdff1aSopenharmony_ci    { "ssim",        "Show SSIM information to stdout", OFFSET(ssim),        AV_OPT_TYPE_INT,   { .i64 = 0 },       0,       2, VE, "ssim" },
883cabdff1aSopenharmony_ci    { "off",         NULL,                                                0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "ssim" },
884cabdff1aSopenharmony_ci    { "avg",         NULL,                                                0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "ssim" },
885cabdff1aSopenharmony_ci    { "frame",       NULL,                                                0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "ssim" },
886cabdff1aSopenharmony_ci    { "ssim_acc",    "SSIM accuracy",                   OFFSET(ssim_acc),    AV_OPT_TYPE_INT,   { .i64 = 2 },       0,       4, VE         },
887cabdff1aSopenharmony_ci    { "gmc",         "use GMC",                         OFFSET(gmc),         AV_OPT_TYPE_INT,   { .i64 = 0 },       0,       1, VE         },
888cabdff1aSopenharmony_ci    { "me_quality",  "Motion estimation quality",       OFFSET(me_quality),  AV_OPT_TYPE_INT,   { .i64 = 4 },       0,       6, VE         },
889cabdff1aSopenharmony_ci    { "mpeg_quant",  "Use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, { .i64 = 0 },     0,       1, VE         },
890cabdff1aSopenharmony_ci    { NULL },
891cabdff1aSopenharmony_ci};
892cabdff1aSopenharmony_ci
893cabdff1aSopenharmony_cistatic const AVClass xvid_class = {
894cabdff1aSopenharmony_ci    .class_name = "libxvid",
895cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
896cabdff1aSopenharmony_ci    .option     = options,
897cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
898cabdff1aSopenharmony_ci};
899cabdff1aSopenharmony_ci
900cabdff1aSopenharmony_ciconst FFCodec ff_libxvid_encoder = {
901cabdff1aSopenharmony_ci    .p.name         = "libxvid",
902cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("libxvidcore MPEG-4 part 2"),
903cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
904cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_MPEG4,
905cabdff1aSopenharmony_ci    .priv_data_size = sizeof(struct xvid_context),
906cabdff1aSopenharmony_ci    .init           = xvid_encode_init,
907cabdff1aSopenharmony_ci    FF_CODEC_ENCODE_CB(xvid_encode_frame),
908cabdff1aSopenharmony_ci    .close          = xvid_encode_close,
909cabdff1aSopenharmony_ci    .p.pix_fmts     = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
910cabdff1aSopenharmony_ci    .p.priv_class   = &xvid_class,
911cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
912cabdff1aSopenharmony_ci                      FF_CODEC_CAP_INIT_CLEANUP,
913cabdff1aSopenharmony_ci    .p.wrapper_name = "libxvid",
914cabdff1aSopenharmony_ci};
915