1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * H.263/MPEG-4 backend for encoder and decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2000,2001 Fabrice Bellard
4cabdff1aSopenharmony_ci * H.263+ support.
5cabdff1aSopenharmony_ci * Copyright (c) 2001 Juan J. Sierralta P
6cabdff1aSopenharmony_ci * Copyright (c) 2002-2004 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 * H.263/MPEG-4 codec.
28cabdff1aSopenharmony_ci */
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "libavutil/thread.h"
31cabdff1aSopenharmony_ci#include "mpegvideo.h"
32cabdff1aSopenharmony_ci#include "h263.h"
33cabdff1aSopenharmony_ci#include "h263data.h"
34cabdff1aSopenharmony_ci#include "h263dsp.h"
35cabdff1aSopenharmony_ci#include "idctdsp.h"
36cabdff1aSopenharmony_ci#include "mathops.h"
37cabdff1aSopenharmony_ci#include "mpegpicture.h"
38cabdff1aSopenharmony_ci#include "mpegutils.h"
39cabdff1aSopenharmony_ci#include "rl.h"
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_cistatic av_cold void h263_init_rl_inter(void)
42cabdff1aSopenharmony_ci{
43cabdff1aSopenharmony_ci    static uint8_t h263_rl_inter_table[2][2 * MAX_RUN + MAX_LEVEL + 3];
44cabdff1aSopenharmony_ci    ff_rl_init(&ff_h263_rl_inter, h263_rl_inter_table);
45cabdff1aSopenharmony_ci}
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ciav_cold void ff_h263_init_rl_inter(void)
48cabdff1aSopenharmony_ci{
49cabdff1aSopenharmony_ci    static AVOnce init_static_once = AV_ONCE_INIT;
50cabdff1aSopenharmony_ci    ff_thread_once(&init_static_once, h263_init_rl_inter);
51cabdff1aSopenharmony_ci}
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_civoid ff_h263_update_motion_val(MpegEncContext * s){
54cabdff1aSopenharmony_ci    const int mb_xy = s->mb_y * s->mb_stride + s->mb_x;
55cabdff1aSopenharmony_ci               //FIXME a lot of that is only needed for !low_delay
56cabdff1aSopenharmony_ci    const int wrap = s->b8_stride;
57cabdff1aSopenharmony_ci    const int xy = s->block_index[0];
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ci    s->current_picture.mbskip_table[mb_xy] = s->mb_skipped;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    if(s->mv_type != MV_TYPE_8X8){
62cabdff1aSopenharmony_ci        int motion_x, motion_y;
63cabdff1aSopenharmony_ci        if (s->mb_intra) {
64cabdff1aSopenharmony_ci            motion_x = 0;
65cabdff1aSopenharmony_ci            motion_y = 0;
66cabdff1aSopenharmony_ci        } else if (s->mv_type == MV_TYPE_16X16) {
67cabdff1aSopenharmony_ci            motion_x = s->mv[0][0][0];
68cabdff1aSopenharmony_ci            motion_y = s->mv[0][0][1];
69cabdff1aSopenharmony_ci        } else /*if (s->mv_type == MV_TYPE_FIELD)*/ {
70cabdff1aSopenharmony_ci            int i;
71cabdff1aSopenharmony_ci            motion_x = s->mv[0][0][0] + s->mv[0][1][0];
72cabdff1aSopenharmony_ci            motion_y = s->mv[0][0][1] + s->mv[0][1][1];
73cabdff1aSopenharmony_ci            motion_x = (motion_x>>1) | (motion_x&1);
74cabdff1aSopenharmony_ci            for(i=0; i<2; i++){
75cabdff1aSopenharmony_ci                s->p_field_mv_table[i][0][mb_xy][0]= s->mv[0][i][0];
76cabdff1aSopenharmony_ci                s->p_field_mv_table[i][0][mb_xy][1]= s->mv[0][i][1];
77cabdff1aSopenharmony_ci            }
78cabdff1aSopenharmony_ci            s->current_picture.ref_index[0][4*mb_xy    ] =
79cabdff1aSopenharmony_ci            s->current_picture.ref_index[0][4*mb_xy + 1] = s->field_select[0][0];
80cabdff1aSopenharmony_ci            s->current_picture.ref_index[0][4*mb_xy + 2] =
81cabdff1aSopenharmony_ci            s->current_picture.ref_index[0][4*mb_xy + 3] = s->field_select[0][1];
82cabdff1aSopenharmony_ci        }
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci        /* no update if 8X8 because it has been done during parsing */
85cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy][0]            = motion_x;
86cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy][1]            = motion_y;
87cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy + 1][0]        = motion_x;
88cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy + 1][1]        = motion_y;
89cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy + wrap][0]     = motion_x;
90cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy + wrap][1]     = motion_y;
91cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy + 1 + wrap][0] = motion_x;
92cabdff1aSopenharmony_ci        s->current_picture.motion_val[0][xy + 1 + wrap][1] = motion_y;
93cabdff1aSopenharmony_ci    }
94cabdff1aSopenharmony_ci
95cabdff1aSopenharmony_ci    if(s->encoding){ //FIXME encoding MUST be cleaned up
96cabdff1aSopenharmony_ci        if (s->mv_type == MV_TYPE_8X8)
97cabdff1aSopenharmony_ci            s->current_picture.mb_type[mb_xy] = MB_TYPE_L0 | MB_TYPE_8x8;
98cabdff1aSopenharmony_ci        else if(s->mb_intra)
99cabdff1aSopenharmony_ci            s->current_picture.mb_type[mb_xy] = MB_TYPE_INTRA;
100cabdff1aSopenharmony_ci        else
101cabdff1aSopenharmony_ci            s->current_picture.mb_type[mb_xy] = MB_TYPE_L0 | MB_TYPE_16x16;
102cabdff1aSopenharmony_ci    }
103cabdff1aSopenharmony_ci}
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_civoid ff_h263_loop_filter(MpegEncContext * s){
106cabdff1aSopenharmony_ci    int qp_c;
107cabdff1aSopenharmony_ci    const int linesize  = s->linesize;
108cabdff1aSopenharmony_ci    const int uvlinesize= s->uvlinesize;
109cabdff1aSopenharmony_ci    const int xy = s->mb_y * s->mb_stride + s->mb_x;
110cabdff1aSopenharmony_ci    uint8_t *dest_y = s->dest[0];
111cabdff1aSopenharmony_ci    uint8_t *dest_cb= s->dest[1];
112cabdff1aSopenharmony_ci    uint8_t *dest_cr= s->dest[2];
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_ci    /*
115cabdff1aSopenharmony_ci       Diag Top
116cabdff1aSopenharmony_ci       Left Center
117cabdff1aSopenharmony_ci    */
118cabdff1aSopenharmony_ci    if (!IS_SKIP(s->current_picture.mb_type[xy])) {
119cabdff1aSopenharmony_ci        qp_c= s->qscale;
120cabdff1aSopenharmony_ci        s->h263dsp.h263_v_loop_filter(dest_y + 8 * linesize,     linesize, qp_c);
121cabdff1aSopenharmony_ci        s->h263dsp.h263_v_loop_filter(dest_y + 8 * linesize + 8, linesize, qp_c);
122cabdff1aSopenharmony_ci    }else
123cabdff1aSopenharmony_ci        qp_c= 0;
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    if(s->mb_y){
126cabdff1aSopenharmony_ci        int qp_dt, qp_tt, qp_tc;
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci        if (IS_SKIP(s->current_picture.mb_type[xy - s->mb_stride]))
129cabdff1aSopenharmony_ci            qp_tt=0;
130cabdff1aSopenharmony_ci        else
131cabdff1aSopenharmony_ci            qp_tt = s->current_picture.qscale_table[xy - s->mb_stride];
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_ci        if(qp_c)
134cabdff1aSopenharmony_ci            qp_tc= qp_c;
135cabdff1aSopenharmony_ci        else
136cabdff1aSopenharmony_ci            qp_tc= qp_tt;
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci        if(qp_tc){
139cabdff1aSopenharmony_ci            const int chroma_qp= s->chroma_qscale_table[qp_tc];
140cabdff1aSopenharmony_ci            s->h263dsp.h263_v_loop_filter(dest_y,     linesize, qp_tc);
141cabdff1aSopenharmony_ci            s->h263dsp.h263_v_loop_filter(dest_y + 8, linesize, qp_tc);
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_ci            s->h263dsp.h263_v_loop_filter(dest_cb, uvlinesize, chroma_qp);
144cabdff1aSopenharmony_ci            s->h263dsp.h263_v_loop_filter(dest_cr, uvlinesize, chroma_qp);
145cabdff1aSopenharmony_ci        }
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ci        if(qp_tt)
148cabdff1aSopenharmony_ci            s->h263dsp.h263_h_loop_filter(dest_y - 8 * linesize + 8, linesize, qp_tt);
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci        if(s->mb_x){
151cabdff1aSopenharmony_ci            if (qp_tt || IS_SKIP(s->current_picture.mb_type[xy - 1 - s->mb_stride]))
152cabdff1aSopenharmony_ci                qp_dt= qp_tt;
153cabdff1aSopenharmony_ci            else
154cabdff1aSopenharmony_ci                qp_dt = s->current_picture.qscale_table[xy - 1 - s->mb_stride];
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_ci            if(qp_dt){
157cabdff1aSopenharmony_ci                const int chroma_qp= s->chroma_qscale_table[qp_dt];
158cabdff1aSopenharmony_ci                s->h263dsp.h263_h_loop_filter(dest_y  - 8 * linesize,   linesize,   qp_dt);
159cabdff1aSopenharmony_ci                s->h263dsp.h263_h_loop_filter(dest_cb - 8 * uvlinesize, uvlinesize, chroma_qp);
160cabdff1aSopenharmony_ci                s->h263dsp.h263_h_loop_filter(dest_cr - 8 * uvlinesize, uvlinesize, chroma_qp);
161cabdff1aSopenharmony_ci            }
162cabdff1aSopenharmony_ci        }
163cabdff1aSopenharmony_ci    }
164cabdff1aSopenharmony_ci
165cabdff1aSopenharmony_ci    if(qp_c){
166cabdff1aSopenharmony_ci        s->h263dsp.h263_h_loop_filter(dest_y + 8, linesize, qp_c);
167cabdff1aSopenharmony_ci        if(s->mb_y + 1 == s->mb_height)
168cabdff1aSopenharmony_ci            s->h263dsp.h263_h_loop_filter(dest_y + 8 * linesize + 8, linesize, qp_c);
169cabdff1aSopenharmony_ci    }
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci    if(s->mb_x){
172cabdff1aSopenharmony_ci        int qp_lc;
173cabdff1aSopenharmony_ci        if (qp_c || IS_SKIP(s->current_picture.mb_type[xy - 1]))
174cabdff1aSopenharmony_ci            qp_lc= qp_c;
175cabdff1aSopenharmony_ci        else
176cabdff1aSopenharmony_ci            qp_lc = s->current_picture.qscale_table[xy - 1];
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci        if(qp_lc){
179cabdff1aSopenharmony_ci            s->h263dsp.h263_h_loop_filter(dest_y, linesize, qp_lc);
180cabdff1aSopenharmony_ci            if(s->mb_y + 1 == s->mb_height){
181cabdff1aSopenharmony_ci                const int chroma_qp= s->chroma_qscale_table[qp_lc];
182cabdff1aSopenharmony_ci                s->h263dsp.h263_h_loop_filter(dest_y + 8 * linesize, linesize, qp_lc);
183cabdff1aSopenharmony_ci                s->h263dsp.h263_h_loop_filter(dest_cb, uvlinesize, chroma_qp);
184cabdff1aSopenharmony_ci                s->h263dsp.h263_h_loop_filter(dest_cr, uvlinesize, chroma_qp);
185cabdff1aSopenharmony_ci            }
186cabdff1aSopenharmony_ci        }
187cabdff1aSopenharmony_ci    }
188cabdff1aSopenharmony_ci}
189cabdff1aSopenharmony_ci
190cabdff1aSopenharmony_ciint16_t *ff_h263_pred_motion(MpegEncContext * s, int block, int dir,
191cabdff1aSopenharmony_ci                             int *px, int *py)
192cabdff1aSopenharmony_ci{
193cabdff1aSopenharmony_ci    int wrap;
194cabdff1aSopenharmony_ci    int16_t *A, *B, *C, (*mot_val)[2];
195cabdff1aSopenharmony_ci    static const int off[4]= {2, 1, 1, -1};
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    wrap = s->b8_stride;
198cabdff1aSopenharmony_ci    mot_val = s->current_picture.motion_val[dir] + s->block_index[block];
199cabdff1aSopenharmony_ci
200cabdff1aSopenharmony_ci    A = mot_val[ - 1];
201cabdff1aSopenharmony_ci    /* special case for first (slice) line */
202cabdff1aSopenharmony_ci    if (s->first_slice_line && block<3) {
203cabdff1aSopenharmony_ci        // we can't just change some MVs to simulate that as we need them for the B-frames (and ME)
204cabdff1aSopenharmony_ci        // and if we ever support non rectangular objects than we need to do a few ifs here anyway :(
205cabdff1aSopenharmony_ci        if(block==0){ //most common case
206cabdff1aSopenharmony_ci            if(s->mb_x  == s->resync_mb_x){ //rare
207cabdff1aSopenharmony_ci                *px= *py = 0;
208cabdff1aSopenharmony_ci            }else if(s->mb_x + 1 == s->resync_mb_x && s->h263_pred){ //rare
209cabdff1aSopenharmony_ci                C = mot_val[off[block] - wrap];
210cabdff1aSopenharmony_ci                if(s->mb_x==0){
211cabdff1aSopenharmony_ci                    *px = C[0];
212cabdff1aSopenharmony_ci                    *py = C[1];
213cabdff1aSopenharmony_ci                }else{
214cabdff1aSopenharmony_ci                    *px = mid_pred(A[0], 0, C[0]);
215cabdff1aSopenharmony_ci                    *py = mid_pred(A[1], 0, C[1]);
216cabdff1aSopenharmony_ci                }
217cabdff1aSopenharmony_ci            }else{
218cabdff1aSopenharmony_ci                *px = A[0];
219cabdff1aSopenharmony_ci                *py = A[1];
220cabdff1aSopenharmony_ci            }
221cabdff1aSopenharmony_ci        }else if(block==1){
222cabdff1aSopenharmony_ci            if(s->mb_x + 1 == s->resync_mb_x && s->h263_pred){ //rare
223cabdff1aSopenharmony_ci                C = mot_val[off[block] - wrap];
224cabdff1aSopenharmony_ci                *px = mid_pred(A[0], 0, C[0]);
225cabdff1aSopenharmony_ci                *py = mid_pred(A[1], 0, C[1]);
226cabdff1aSopenharmony_ci            }else{
227cabdff1aSopenharmony_ci                *px = A[0];
228cabdff1aSopenharmony_ci                *py = A[1];
229cabdff1aSopenharmony_ci            }
230cabdff1aSopenharmony_ci        }else{ /* block==2*/
231cabdff1aSopenharmony_ci            B = mot_val[ - wrap];
232cabdff1aSopenharmony_ci            C = mot_val[off[block] - wrap];
233cabdff1aSopenharmony_ci            if(s->mb_x == s->resync_mb_x) //rare
234cabdff1aSopenharmony_ci                A[0]=A[1]=0;
235cabdff1aSopenharmony_ci
236cabdff1aSopenharmony_ci            *px = mid_pred(A[0], B[0], C[0]);
237cabdff1aSopenharmony_ci            *py = mid_pred(A[1], B[1], C[1]);
238cabdff1aSopenharmony_ci        }
239cabdff1aSopenharmony_ci    } else {
240cabdff1aSopenharmony_ci        B = mot_val[ - wrap];
241cabdff1aSopenharmony_ci        C = mot_val[off[block] - wrap];
242cabdff1aSopenharmony_ci        *px = mid_pred(A[0], B[0], C[0]);
243cabdff1aSopenharmony_ci        *py = mid_pred(A[1], B[1], C[1]);
244cabdff1aSopenharmony_ci    }
245cabdff1aSopenharmony_ci    return *mot_val;
246cabdff1aSopenharmony_ci}
247