1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * MSMPEG4 backend for encoder and decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2001 Fabrice Bellard
4cabdff1aSopenharmony_ci * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * msmpeg4v1 & v2 stuff by Michael Niedermayer <michaelni@gmx.at>
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * This file is part of FFmpeg.
9cabdff1aSopenharmony_ci *
10cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
11cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
12cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
13cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
14cabdff1aSopenharmony_ci *
15cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
16cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
17cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18cabdff1aSopenharmony_ci * Lesser General Public License for more details.
19cabdff1aSopenharmony_ci *
20cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
21cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
22cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23cabdff1aSopenharmony_ci */
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci/**
26cabdff1aSopenharmony_ci * @file
27cabdff1aSopenharmony_ci * MSMPEG4 backend for encoder and decoder
28cabdff1aSopenharmony_ci */
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "config_components.h"
31cabdff1aSopenharmony_ci
32cabdff1aSopenharmony_ci#include "libavutil/thread.h"
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_ci#include "avcodec.h"
35cabdff1aSopenharmony_ci#include "idctdsp.h"
36cabdff1aSopenharmony_ci#include "mpegvideo.h"
37cabdff1aSopenharmony_ci#include "msmpeg4.h"
38cabdff1aSopenharmony_ci#include "libavutil/x86/asm.h"
39cabdff1aSopenharmony_ci#include "mpeg4videodata.h"
40cabdff1aSopenharmony_ci#include "msmpeg4data.h"
41cabdff1aSopenharmony_ci#include "mpegvideodata.h"
42cabdff1aSopenharmony_ci#include "vc1data.h"
43cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_ci/*
46cabdff1aSopenharmony_ci * You can also call this codec: MPEG-4 with a twist!
47cabdff1aSopenharmony_ci *
48cabdff1aSopenharmony_ci * TODO:
49cabdff1aSopenharmony_ci *        - (encoding) select best mv table (two choices)
50cabdff1aSopenharmony_ci *        - (encoding) select best vlc/dc table
51cabdff1aSopenharmony_ci */
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci/* This table is practically identical to the one from H.263
54cabdff1aSopenharmony_ci * except that it is inverted. */
55cabdff1aSopenharmony_cistatic av_cold void init_h263_dc_for_msmpeg4(void)
56cabdff1aSopenharmony_ci{
57cabdff1aSopenharmony_ci    for (int level = -256; level < 256; level++) {
58cabdff1aSopenharmony_ci        int uni_code, uni_len;
59cabdff1aSopenharmony_ci        int size, v, l;
60cabdff1aSopenharmony_ci        /* find number of bits */
61cabdff1aSopenharmony_ci        size = 0;
62cabdff1aSopenharmony_ci        v = abs(level);
63cabdff1aSopenharmony_ci        while (v) {
64cabdff1aSopenharmony_ci            v >>= 1;
65cabdff1aSopenharmony_ci            size++;
66cabdff1aSopenharmony_ci        }
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci        if (level < 0)
69cabdff1aSopenharmony_ci            l = (-level) ^ ((1 << size) - 1);
70cabdff1aSopenharmony_ci        else
71cabdff1aSopenharmony_ci            l = level;
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci        /* luminance H.263 */
74cabdff1aSopenharmony_ci        uni_code  = ff_mpeg4_DCtab_lum[size][0];
75cabdff1aSopenharmony_ci        uni_len   = ff_mpeg4_DCtab_lum[size][1];
76cabdff1aSopenharmony_ci        uni_code ^= (1 << uni_len) - 1; //M$ does not like compatibility
77cabdff1aSopenharmony_ci
78cabdff1aSopenharmony_ci        if (size > 0) {
79cabdff1aSopenharmony_ci            uni_code <<= size; uni_code |= l;
80cabdff1aSopenharmony_ci            uni_len   += size;
81cabdff1aSopenharmony_ci            if (size > 8) {
82cabdff1aSopenharmony_ci                uni_code <<= 1; uni_code |= 1;
83cabdff1aSopenharmony_ci                uni_len++;
84cabdff1aSopenharmony_ci            }
85cabdff1aSopenharmony_ci        }
86cabdff1aSopenharmony_ci        ff_v2_dc_lum_table[level + 256][0] = uni_code;
87cabdff1aSopenharmony_ci        ff_v2_dc_lum_table[level + 256][1] = uni_len;
88cabdff1aSopenharmony_ci
89cabdff1aSopenharmony_ci        /* chrominance H.263 */
90cabdff1aSopenharmony_ci        uni_code  = ff_mpeg4_DCtab_chrom[size][0];
91cabdff1aSopenharmony_ci        uni_len   = ff_mpeg4_DCtab_chrom[size][1];
92cabdff1aSopenharmony_ci        uni_code ^= (1 << uni_len) - 1; //M$ does not like compatibility
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_ci        if (size > 0) {
95cabdff1aSopenharmony_ci            uni_code <<= size; uni_code |= l;
96cabdff1aSopenharmony_ci            uni_len   +=size;
97cabdff1aSopenharmony_ci            if (size > 8) {
98cabdff1aSopenharmony_ci                uni_code <<= 1; uni_code |= 1;
99cabdff1aSopenharmony_ci                uni_len++;
100cabdff1aSopenharmony_ci            }
101cabdff1aSopenharmony_ci        }
102cabdff1aSopenharmony_ci        ff_v2_dc_chroma_table[level + 256][0] = uni_code;
103cabdff1aSopenharmony_ci        ff_v2_dc_chroma_table[level + 256][1] = uni_len;
104cabdff1aSopenharmony_ci    }
105cabdff1aSopenharmony_ci}
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_cistatic av_cold void msmpeg4_common_init_static(void)
108cabdff1aSopenharmony_ci{
109cabdff1aSopenharmony_ci    static uint8_t rl_table_store[NB_RL_TABLES][2][2 * MAX_RUN + MAX_LEVEL + 3];
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    for (int i = 0; i < NB_RL_TABLES; i++)
112cabdff1aSopenharmony_ci        ff_rl_init(&ff_rl_table[i], rl_table_store[i]);
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_ci    init_h263_dc_for_msmpeg4();
115cabdff1aSopenharmony_ci}
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ciav_cold void ff_msmpeg4_common_init(MpegEncContext *s)
118cabdff1aSopenharmony_ci{
119cabdff1aSopenharmony_ci    static AVOnce init_static_once = AV_ONCE_INIT;
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ci    switch(s->msmpeg4_version){
122cabdff1aSopenharmony_ci    case 1:
123cabdff1aSopenharmony_ci    case 2:
124cabdff1aSopenharmony_ci        s->y_dc_scale_table=
125cabdff1aSopenharmony_ci        s->c_dc_scale_table= ff_mpeg1_dc_scale_table;
126cabdff1aSopenharmony_ci        break;
127cabdff1aSopenharmony_ci    case 3:
128cabdff1aSopenharmony_ci        if(s->workaround_bugs){
129cabdff1aSopenharmony_ci            s->y_dc_scale_table= ff_old_ff_y_dc_scale_table;
130cabdff1aSopenharmony_ci            s->c_dc_scale_table= ff_wmv1_c_dc_scale_table;
131cabdff1aSopenharmony_ci        } else{
132cabdff1aSopenharmony_ci            s->y_dc_scale_table= ff_mpeg4_y_dc_scale_table;
133cabdff1aSopenharmony_ci            s->c_dc_scale_table= ff_mpeg4_c_dc_scale_table;
134cabdff1aSopenharmony_ci        }
135cabdff1aSopenharmony_ci        break;
136cabdff1aSopenharmony_ci    case 4:
137cabdff1aSopenharmony_ci    case 5:
138cabdff1aSopenharmony_ci        s->y_dc_scale_table= ff_wmv1_y_dc_scale_table;
139cabdff1aSopenharmony_ci        s->c_dc_scale_table= ff_wmv1_c_dc_scale_table;
140cabdff1aSopenharmony_ci        break;
141cabdff1aSopenharmony_ci#if CONFIG_VC1_DECODER
142cabdff1aSopenharmony_ci    case 6:
143cabdff1aSopenharmony_ci        s->y_dc_scale_table= ff_wmv3_dc_scale_table;
144cabdff1aSopenharmony_ci        s->c_dc_scale_table= ff_wmv3_dc_scale_table;
145cabdff1aSopenharmony_ci        break;
146cabdff1aSopenharmony_ci#endif
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    }
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci    if(s->msmpeg4_version>=4){
152cabdff1aSopenharmony_ci        ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable,   ff_wmv1_scantable[1]);
153cabdff1aSopenharmony_ci        ff_init_scantable(s->idsp.idct_permutation, &s->intra_h_scantable, ff_wmv1_scantable[2]);
154cabdff1aSopenharmony_ci        ff_init_scantable(s->idsp.idct_permutation, &s->intra_v_scantable, ff_wmv1_scantable[3]);
155cabdff1aSopenharmony_ci        ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable,   ff_wmv1_scantable[0]);
156cabdff1aSopenharmony_ci    }
157cabdff1aSopenharmony_ci    //Note the default tables are set in common_init in mpegvideo.c
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    ff_thread_once(&init_static_once, msmpeg4_common_init_static);
160cabdff1aSopenharmony_ci}
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ci/* predict coded block */
163cabdff1aSopenharmony_ciint ff_msmpeg4_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr)
164cabdff1aSopenharmony_ci{
165cabdff1aSopenharmony_ci    int xy, wrap, pred, a, b, c;
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci    xy = s->block_index[n];
168cabdff1aSopenharmony_ci    wrap = s->b8_stride;
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_ci    /* B C
171cabdff1aSopenharmony_ci     * A X
172cabdff1aSopenharmony_ci     */
173cabdff1aSopenharmony_ci    a = s->coded_block[xy - 1       ];
174cabdff1aSopenharmony_ci    b = s->coded_block[xy - 1 - wrap];
175cabdff1aSopenharmony_ci    c = s->coded_block[xy     - wrap];
176cabdff1aSopenharmony_ci
177cabdff1aSopenharmony_ci    if (b == c) {
178cabdff1aSopenharmony_ci        pred = a;
179cabdff1aSopenharmony_ci    } else {
180cabdff1aSopenharmony_ci        pred = c;
181cabdff1aSopenharmony_ci    }
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci    /* store value */
184cabdff1aSopenharmony_ci    *coded_block_ptr = &s->coded_block[xy];
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci    return pred;
187cabdff1aSopenharmony_ci}
188cabdff1aSopenharmony_ci
189cabdff1aSopenharmony_cistatic int get_dc(uint8_t *src, int stride, int scale, int block_size)
190cabdff1aSopenharmony_ci{
191cabdff1aSopenharmony_ci    int y;
192cabdff1aSopenharmony_ci    int sum=0;
193cabdff1aSopenharmony_ci    for(y=0; y<block_size; y++){
194cabdff1aSopenharmony_ci        int x;
195cabdff1aSopenharmony_ci        for(x=0; x<block_size; x++){
196cabdff1aSopenharmony_ci            sum+=src[x + y*stride];
197cabdff1aSopenharmony_ci        }
198cabdff1aSopenharmony_ci    }
199cabdff1aSopenharmony_ci    return FASTDIV((sum + (scale>>1)), scale);
200cabdff1aSopenharmony_ci}
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci/* dir = 0: left, dir = 1: top prediction */
203cabdff1aSopenharmony_ciint ff_msmpeg4_pred_dc(MpegEncContext *s, int n,
204cabdff1aSopenharmony_ci                       int16_t **dc_val_ptr, int *dir_ptr)
205cabdff1aSopenharmony_ci{
206cabdff1aSopenharmony_ci    int a, b, c, wrap, pred, scale;
207cabdff1aSopenharmony_ci    int16_t *dc_val;
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    /* find prediction */
210cabdff1aSopenharmony_ci    if (n < 4) {
211cabdff1aSopenharmony_ci        scale = s->y_dc_scale;
212cabdff1aSopenharmony_ci    } else {
213cabdff1aSopenharmony_ci        scale = s->c_dc_scale;
214cabdff1aSopenharmony_ci    }
215cabdff1aSopenharmony_ci
216cabdff1aSopenharmony_ci    wrap = s->block_wrap[n];
217cabdff1aSopenharmony_ci    dc_val= s->dc_val[0] + s->block_index[n];
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci    /* B C
220cabdff1aSopenharmony_ci     * A X
221cabdff1aSopenharmony_ci     */
222cabdff1aSopenharmony_ci    a = dc_val[ - 1];
223cabdff1aSopenharmony_ci    b = dc_val[ - 1 - wrap];
224cabdff1aSopenharmony_ci    c = dc_val[ - wrap];
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_ci    if(s->first_slice_line && (n&2)==0 && s->msmpeg4_version<4){
227cabdff1aSopenharmony_ci        b=c=1024;
228cabdff1aSopenharmony_ci    }
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    /* XXX: the following solution consumes divisions, but it does not
231cabdff1aSopenharmony_ci       necessitate to modify mpegvideo.c. The problem comes from the
232cabdff1aSopenharmony_ci       fact they decided to store the quantized DC (which would lead
233cabdff1aSopenharmony_ci       to problems if Q could vary !) */
234cabdff1aSopenharmony_ci#if ARCH_X86 && HAVE_7REGS && HAVE_EBX_AVAILABLE
235cabdff1aSopenharmony_ci    __asm__ volatile(
236cabdff1aSopenharmony_ci        "movl %3, %%eax         \n\t"
237cabdff1aSopenharmony_ci        "shrl $1, %%eax         \n\t"
238cabdff1aSopenharmony_ci        "addl %%eax, %2         \n\t"
239cabdff1aSopenharmony_ci        "addl %%eax, %1         \n\t"
240cabdff1aSopenharmony_ci        "addl %0, %%eax         \n\t"
241cabdff1aSopenharmony_ci        "imull %4               \n\t"
242cabdff1aSopenharmony_ci        "movl %%edx, %0         \n\t"
243cabdff1aSopenharmony_ci        "movl %1, %%eax         \n\t"
244cabdff1aSopenharmony_ci        "imull %4               \n\t"
245cabdff1aSopenharmony_ci        "movl %%edx, %1         \n\t"
246cabdff1aSopenharmony_ci        "movl %2, %%eax         \n\t"
247cabdff1aSopenharmony_ci        "imull %4               \n\t"
248cabdff1aSopenharmony_ci        "movl %%edx, %2         \n\t"
249cabdff1aSopenharmony_ci        : "+b" (a), "+c" (b), "+D" (c)
250cabdff1aSopenharmony_ci        : "g" (scale), "S" (ff_inverse[scale])
251cabdff1aSopenharmony_ci        : "%eax", "%edx"
252cabdff1aSopenharmony_ci    );
253cabdff1aSopenharmony_ci#else
254cabdff1aSopenharmony_ci    /* Divisions are costly everywhere; optimize the most common case. */
255cabdff1aSopenharmony_ci    if (scale == 8) {
256cabdff1aSopenharmony_ci        a = (a + (8 >> 1)) / 8;
257cabdff1aSopenharmony_ci        b = (b + (8 >> 1)) / 8;
258cabdff1aSopenharmony_ci        c = (c + (8 >> 1)) / 8;
259cabdff1aSopenharmony_ci    } else {
260cabdff1aSopenharmony_ci        a = FASTDIV((a + (scale >> 1)), scale);
261cabdff1aSopenharmony_ci        b = FASTDIV((b + (scale >> 1)), scale);
262cabdff1aSopenharmony_ci        c = FASTDIV((c + (scale >> 1)), scale);
263cabdff1aSopenharmony_ci    }
264cabdff1aSopenharmony_ci#endif
265cabdff1aSopenharmony_ci    /* XXX: WARNING: they did not choose the same test as MPEG-4. This
266cabdff1aSopenharmony_ci       is very important ! */
267cabdff1aSopenharmony_ci    if(s->msmpeg4_version>3){
268cabdff1aSopenharmony_ci        if(s->inter_intra_pred){
269cabdff1aSopenharmony_ci            uint8_t *dest;
270cabdff1aSopenharmony_ci            int wrap;
271cabdff1aSopenharmony_ci
272cabdff1aSopenharmony_ci            if(n==1){
273cabdff1aSopenharmony_ci                pred=a;
274cabdff1aSopenharmony_ci                *dir_ptr = 0;
275cabdff1aSopenharmony_ci            }else if(n==2){
276cabdff1aSopenharmony_ci                pred=c;
277cabdff1aSopenharmony_ci                *dir_ptr = 1;
278cabdff1aSopenharmony_ci            }else if(n==3){
279cabdff1aSopenharmony_ci                if (abs(a - b) < abs(b - c)) {
280cabdff1aSopenharmony_ci                    pred = c;
281cabdff1aSopenharmony_ci                    *dir_ptr = 1;
282cabdff1aSopenharmony_ci                } else {
283cabdff1aSopenharmony_ci                    pred = a;
284cabdff1aSopenharmony_ci                    *dir_ptr = 0;
285cabdff1aSopenharmony_ci                }
286cabdff1aSopenharmony_ci            }else{
287cabdff1aSopenharmony_ci                int bs = 8 >> s->avctx->lowres;
288cabdff1aSopenharmony_ci                if(n<4){
289cabdff1aSopenharmony_ci                    wrap= s->linesize;
290cabdff1aSopenharmony_ci                    dest= s->current_picture.f->data[0] + (((n >> 1) + 2*s->mb_y) * bs*  wrap ) + ((n & 1) + 2*s->mb_x) * bs;
291cabdff1aSopenharmony_ci                }else{
292cabdff1aSopenharmony_ci                    wrap= s->uvlinesize;
293cabdff1aSopenharmony_ci                    dest= s->current_picture.f->data[n - 3] + (s->mb_y * bs * wrap) + s->mb_x * bs;
294cabdff1aSopenharmony_ci                }
295cabdff1aSopenharmony_ci                if(s->mb_x==0) a= (1024 + (scale>>1))/scale;
296cabdff1aSopenharmony_ci                else           a= get_dc(dest-bs, wrap, scale*8>>(2*s->avctx->lowres), bs);
297cabdff1aSopenharmony_ci                if(s->mb_y==0) c= (1024 + (scale>>1))/scale;
298cabdff1aSopenharmony_ci                else           c= get_dc(dest-bs*wrap, wrap, scale*8>>(2*s->avctx->lowres), bs);
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci                if (s->h263_aic_dir==0) {
301cabdff1aSopenharmony_ci                    pred= a;
302cabdff1aSopenharmony_ci                    *dir_ptr = 0;
303cabdff1aSopenharmony_ci                }else if (s->h263_aic_dir==1) {
304cabdff1aSopenharmony_ci                    if(n==0){
305cabdff1aSopenharmony_ci                        pred= c;
306cabdff1aSopenharmony_ci                        *dir_ptr = 1;
307cabdff1aSopenharmony_ci                    }else{
308cabdff1aSopenharmony_ci                        pred= a;
309cabdff1aSopenharmony_ci                        *dir_ptr = 0;
310cabdff1aSopenharmony_ci                    }
311cabdff1aSopenharmony_ci                }else if (s->h263_aic_dir==2) {
312cabdff1aSopenharmony_ci                    if(n==0){
313cabdff1aSopenharmony_ci                        pred= a;
314cabdff1aSopenharmony_ci                        *dir_ptr = 0;
315cabdff1aSopenharmony_ci                    }else{
316cabdff1aSopenharmony_ci                        pred= c;
317cabdff1aSopenharmony_ci                        *dir_ptr = 1;
318cabdff1aSopenharmony_ci                    }
319cabdff1aSopenharmony_ci                } else {
320cabdff1aSopenharmony_ci                    pred= c;
321cabdff1aSopenharmony_ci                    *dir_ptr = 1;
322cabdff1aSopenharmony_ci                }
323cabdff1aSopenharmony_ci            }
324cabdff1aSopenharmony_ci        }else{
325cabdff1aSopenharmony_ci            if (abs(a - b) < abs(b - c)) {
326cabdff1aSopenharmony_ci                pred = c;
327cabdff1aSopenharmony_ci                *dir_ptr = 1;
328cabdff1aSopenharmony_ci            } else {
329cabdff1aSopenharmony_ci                pred = a;
330cabdff1aSopenharmony_ci                *dir_ptr = 0;
331cabdff1aSopenharmony_ci            }
332cabdff1aSopenharmony_ci        }
333cabdff1aSopenharmony_ci    }else{
334cabdff1aSopenharmony_ci        if (abs(a - b) <= abs(b - c)) {
335cabdff1aSopenharmony_ci            pred = c;
336cabdff1aSopenharmony_ci            *dir_ptr = 1;
337cabdff1aSopenharmony_ci        } else {
338cabdff1aSopenharmony_ci            pred = a;
339cabdff1aSopenharmony_ci            *dir_ptr = 0;
340cabdff1aSopenharmony_ci        }
341cabdff1aSopenharmony_ci    }
342cabdff1aSopenharmony_ci
343cabdff1aSopenharmony_ci    /* update predictor */
344cabdff1aSopenharmony_ci    *dc_val_ptr = &dc_val[0];
345cabdff1aSopenharmony_ci    return pred;
346cabdff1aSopenharmony_ci}
347cabdff1aSopenharmony_ci
348