1/*
2 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11
12#include <limits.h>
13#include "vpx_config.h"
14#include "onyx_int.h"
15#include "mr_dissim.h"
16#include "vpx_mem/vpx_mem.h"
17#include "rdopt.h"
18
19void vp8_cal_low_res_mb_cols(VP8_COMP *cpi)
20{
21    int low_res_w;
22
23    /* Support arbitrary down-sampling factor */
24    unsigned int iw = cpi->oxcf.Width*cpi->oxcf.mr_down_sampling_factor.den
25                      + cpi->oxcf.mr_down_sampling_factor.num - 1;
26
27    low_res_w = iw/cpi->oxcf.mr_down_sampling_factor.num;
28    cpi->mr_low_res_mb_cols = ((low_res_w + 15) >> 4);
29}
30
31#define GET_MV(x)    \
32if(x->mbmi.ref_frame !=INTRA_FRAME)   \
33{   \
34    mvx[cnt] = x->mbmi.mv.as_mv.row;  \
35    mvy[cnt] = x->mbmi.mv.as_mv.col;  \
36    cnt++;    \
37}
38
39#define GET_MV_SIGN(x)    \
40if(x->mbmi.ref_frame !=INTRA_FRAME)   \
41{   \
42    mvx[cnt] = x->mbmi.mv.as_mv.row;  \
43    mvy[cnt] = x->mbmi.mv.as_mv.col;  \
44    if (cm->ref_frame_sign_bias[x->mbmi.ref_frame]  \
45        != cm->ref_frame_sign_bias[tmp->mbmi.ref_frame])  \
46    {  \
47        mvx[cnt] *= -1;   \
48        mvy[cnt] *= -1;   \
49    }  \
50    cnt++;  \
51}
52
53void vp8_cal_dissimilarity(VP8_COMP *cpi)
54{
55    VP8_COMMON *cm = &cpi->common;
56    int i;
57
58    /* Note: The first row & first column in mip are outside the frame, which
59     * were initialized to all 0.(ref_frame, mode, mv...)
60     * Their ref_frame = 0 means they won't be counted in the following
61     * calculation.
62     */
63    if (cpi->oxcf.mr_total_resolutions >1
64        && cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1))
65    {
66        /* Store info for show/no-show frames for supporting alt_ref.
67         * If parent frame is alt_ref, child has one too.
68         */
69        LOWER_RES_FRAME_INFO* store_info
70                      = (LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info;
71
72        store_info->frame_type = cm->frame_type;
73
74        if(cm->frame_type != KEY_FRAME)
75        {
76            store_info->is_frame_dropped = 0;
77            for (i = 1; i < MAX_REF_FRAMES; i++)
78                store_info->low_res_ref_frames[i] = cpi->current_ref_frames[i];
79        }
80
81        if(cm->frame_type != KEY_FRAME)
82        {
83            int mb_row;
84            int mb_col;
85            /* Point to beginning of allocated MODE_INFO arrays. */
86            MODE_INFO *tmp = cm->mip + cm->mode_info_stride;
87            LOWER_RES_MB_INFO* store_mode_info = store_info->mb_info;
88
89            for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++)
90            {
91                tmp++;
92                for (mb_col = 0; mb_col < cm->mb_cols; mb_col ++)
93                {
94                    int dissim = INT_MAX;
95
96                    if(tmp->mbmi.ref_frame !=INTRA_FRAME)
97                    {
98                        int              mvx[8];
99                        int              mvy[8];
100                        int              mmvx;
101                        int              mmvy;
102                        int              cnt=0;
103                        const MODE_INFO *here = tmp;
104                        const MODE_INFO *above = here - cm->mode_info_stride;
105                        const MODE_INFO *left = here - 1;
106                        const MODE_INFO *aboveleft = above - 1;
107                        const MODE_INFO *aboveright = NULL;
108                        const MODE_INFO *right = NULL;
109                        const MODE_INFO *belowleft = NULL;
110                        const MODE_INFO *below = NULL;
111                        const MODE_INFO *belowright = NULL;
112
113                        /* If alternate reference frame is used, we have to
114                         * check sign of MV. */
115                        if(cpi->oxcf.play_alternate)
116                        {
117                            /* Gather mv of neighboring MBs */
118                            GET_MV_SIGN(above)
119                            GET_MV_SIGN(left)
120                            GET_MV_SIGN(aboveleft)
121
122                            if(mb_col < (cm->mb_cols-1))
123                            {
124                                right = here + 1;
125                                aboveright = above + 1;
126                                GET_MV_SIGN(right)
127                                GET_MV_SIGN(aboveright)
128                            }
129
130                            if(mb_row < (cm->mb_rows-1))
131                            {
132                                below = here + cm->mode_info_stride;
133                                belowleft = below - 1;
134                                GET_MV_SIGN(below)
135                                GET_MV_SIGN(belowleft)
136                            }
137
138                            if(mb_col < (cm->mb_cols-1)
139                                && mb_row < (cm->mb_rows-1))
140                            {
141                                belowright = below + 1;
142                                GET_MV_SIGN(belowright)
143                            }
144                        }else
145                        {
146                            /* No alt_ref and gather mv of neighboring MBs */
147                            GET_MV(above)
148                            GET_MV(left)
149                            GET_MV(aboveleft)
150
151                            if(mb_col < (cm->mb_cols-1))
152                            {
153                                right = here + 1;
154                                aboveright = above + 1;
155                                GET_MV(right)
156                                GET_MV(aboveright)
157                            }
158
159                            if(mb_row < (cm->mb_rows-1))
160                            {
161                                below = here + cm->mode_info_stride;
162                                belowleft = below - 1;
163                                GET_MV(below)
164                                GET_MV(belowleft)
165                            }
166
167                            if(mb_col < (cm->mb_cols-1)
168                                && mb_row < (cm->mb_rows-1))
169                            {
170                                belowright = below + 1;
171                                GET_MV(belowright)
172                            }
173                        }
174
175                        if (cnt > 0)
176                        {
177                            int max_mvx = mvx[0];
178                            int min_mvx = mvx[0];
179                            int max_mvy = mvy[0];
180                            int min_mvy = mvy[0];
181                            int i;
182
183                            if (cnt > 1)
184                            {
185                                for (i=1; i< cnt; i++)
186                                {
187                                    if (mvx[i] > max_mvx) max_mvx = mvx[i];
188                                    else if (mvx[i] < min_mvx) min_mvx = mvx[i];
189                                    if (mvy[i] > max_mvy) max_mvy = mvy[i];
190                                    else if (mvy[i] < min_mvy) min_mvy = mvy[i];
191                                }
192                            }
193
194                            mmvx = MAX(abs(min_mvx - here->mbmi.mv.as_mv.row),
195                                       abs(max_mvx - here->mbmi.mv.as_mv.row));
196                            mmvy = MAX(abs(min_mvy - here->mbmi.mv.as_mv.col),
197                                       abs(max_mvy - here->mbmi.mv.as_mv.col));
198                            dissim = MAX(mmvx, mmvy);
199                        }
200                    }
201
202                    /* Store mode info for next resolution encoding */
203                    store_mode_info->mode = tmp->mbmi.mode;
204                    store_mode_info->ref_frame = tmp->mbmi.ref_frame;
205                    store_mode_info->mv.as_int = tmp->mbmi.mv.as_int;
206                    store_mode_info->dissim = dissim;
207                    tmp++;
208                    store_mode_info++;
209                }
210            }
211        }
212    }
213}
214
215/* This function is called only when this frame is dropped at current
216   resolution level. */
217void vp8_store_drop_frame_info(VP8_COMP *cpi)
218{
219    /* If the frame is dropped in lower-resolution encoding, this information
220       is passed to higher resolution level so that the encoder knows there
221       is no mode & motion info available.
222     */
223    if (cpi->oxcf.mr_total_resolutions >1
224        && cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1))
225    {
226        /* Store info for show/no-show frames for supporting alt_ref.
227         * If parent frame is alt_ref, child has one too.
228         */
229        LOWER_RES_FRAME_INFO* store_info
230                      = (LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info;
231
232        /* Set frame_type to be INTER_FRAME since we won't drop key frame. */
233        store_info->frame_type = INTER_FRAME;
234        store_info->is_frame_dropped = 1;
235    }
236}
237