aa7335e610
The example encoder down-samples the input video frames a number of times with a down-sampling factor, and then encodes and outputs bitstreams with different resolutions. Support arbitrary down-sampling factor, and down-sampling factor can be different for each encoding level. For example, the encoder can be tested as follows. 1. Configure with multi-resolution encoding enabled: ../libvpx/configure --target=x86-linux-gcc --disable-codecs --enable-vp8 --enable-runtime_cpu_detect --enable-debug --disable-install-docs --enable-error-concealment --enable-multi-res-encoding 2. Run make 3. Encode: If input video is 1280x720, run: ./vp8_multi_resolution_encoder 1280 720 input.yuv 1.ivf 2.ivf 3.ivf 1 (output: 1.ivf(1280x720); 2.ivf(640x360); 3.ivf(320x180). The last parameter is set to 1/0 to show/not show PSNR.) 4. Decode: ./simple_decoder 1.ivf 1.yuv ./simple_decoder 2.ivf 2.yuv ./simple_decoder 3.ivf 3.yuv 5. View video: mplayer 1.yuv -demuxer rawvideo -rawvideo w=1280:h=720 -loop 0 -fps 30 mplayer 2.yuv -demuxer rawvideo -rawvideo w=640:h=360 -loop 0 -fps 30 mplayer 3.yuv -demuxer rawvideo -rawvideo w=320:h=180 -loop 0 -fps 30 The encoding parameters can be modified in vp8_multi_resolution_encoder.c, for example, target bitrate, frame rate... Modified API. John helped a lot with that. Thanks! Change-Id: I03be9a51167eddf94399f92d269599fb3f3d54f5
202 lines
7.6 KiB
C
202 lines
7.6 KiB
C
/*
|
|
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
|
|
#include <limits.h>
|
|
#include "vpx_config.h"
|
|
#include "onyx_int.h"
|
|
#include "mr_dissim.h"
|
|
#include "vpx_mem/vpx_mem.h"
|
|
#include "rdopt.h"
|
|
|
|
void vp8_cal_low_res_mb_cols(VP8_COMP *cpi)
|
|
{
|
|
int low_res_w;
|
|
|
|
/* Support arbitrary down-sampling factor */
|
|
unsigned int iw = cpi->oxcf.Width*cpi->oxcf.mr_down_sampling_factor.den
|
|
+ cpi->oxcf.mr_down_sampling_factor.num - 1;
|
|
|
|
low_res_w = iw/cpi->oxcf.mr_down_sampling_factor.num;
|
|
cpi->mr_low_res_mb_cols = ((low_res_w + 15) >> 4);
|
|
}
|
|
|
|
#define GET_MV(x) \
|
|
if(x->mbmi.ref_frame !=INTRA_FRAME) \
|
|
{ \
|
|
mvx[cnt] = x->mbmi.mv.as_mv.row; \
|
|
mvy[cnt] = x->mbmi.mv.as_mv.col; \
|
|
cnt++; \
|
|
}
|
|
|
|
#define GET_MV_SIGN(x) \
|
|
if(x->mbmi.ref_frame !=INTRA_FRAME) \
|
|
{ \
|
|
mvx[cnt] = x->mbmi.mv.as_mv.row; \
|
|
mvy[cnt] = x->mbmi.mv.as_mv.col; \
|
|
if (cm->ref_frame_sign_bias[x->mbmi.ref_frame] \
|
|
!= cm->ref_frame_sign_bias[tmp->mbmi.ref_frame]) \
|
|
{ \
|
|
mvx[cnt] *= -1; \
|
|
mvy[cnt] *= -1; \
|
|
} \
|
|
cnt++; \
|
|
}
|
|
|
|
void vp8_cal_dissimilarity(VP8_COMP *cpi)
|
|
{
|
|
VP8_COMMON *cm = &cpi->common;
|
|
|
|
/* Note: The first row & first column in mip are outside the frame, which
|
|
* were initialized to all 0.(ref_frame, mode, mv...)
|
|
* Their ref_frame = 0 means they won't be counted in the following
|
|
* calculation.
|
|
*/
|
|
if (cpi->oxcf.mr_total_resolutions >1
|
|
&& cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1))
|
|
{
|
|
/* Store info for show/no-show frames for supporting alt_ref.
|
|
* If parent frame is alt_ref, child has one too.
|
|
*/
|
|
if(cm->frame_type != KEY_FRAME)
|
|
{
|
|
int mb_row;
|
|
int mb_col;
|
|
/* Point to beginning of allocated MODE_INFO arrays. */
|
|
MODE_INFO *tmp = cm->mip + cm->mode_info_stride;
|
|
LOWER_RES_INFO* store_mode_info
|
|
= (LOWER_RES_INFO*)cpi->oxcf.mr_low_res_mode_info;
|
|
|
|
for (mb_row = 0; mb_row < cm->mb_rows; mb_row ++)
|
|
{
|
|
tmp++;
|
|
for (mb_col = 0; mb_col < cm->mb_cols; mb_col ++)
|
|
{
|
|
int dissim = INT_MAX;
|
|
|
|
if(tmp->mbmi.ref_frame !=INTRA_FRAME)
|
|
{
|
|
int mvx[8];
|
|
int mvy[8];
|
|
int mmvx;
|
|
int mmvy;
|
|
int cnt=0;
|
|
const MODE_INFO *here = tmp;
|
|
const MODE_INFO *above = here - cm->mode_info_stride;
|
|
const MODE_INFO *left = here - 1;
|
|
const MODE_INFO *aboveleft = above - 1;
|
|
const MODE_INFO *aboveright = NULL;
|
|
const MODE_INFO *right = NULL;
|
|
const MODE_INFO *belowleft = NULL;
|
|
const MODE_INFO *below = NULL;
|
|
const MODE_INFO *belowright = NULL;
|
|
|
|
/* If alternate reference frame is used, we have to
|
|
* check sign of MV. */
|
|
if(cpi->oxcf.play_alternate)
|
|
{
|
|
/* Gather mv of neighboring MBs */
|
|
GET_MV_SIGN(above)
|
|
GET_MV_SIGN(left)
|
|
GET_MV_SIGN(aboveleft)
|
|
|
|
if(mb_col < (cm->mb_cols-1))
|
|
{
|
|
right = here + 1;
|
|
aboveright = above + 1;
|
|
GET_MV_SIGN(right)
|
|
GET_MV_SIGN(aboveright)
|
|
}
|
|
|
|
if(mb_row < (cm->mb_rows-1))
|
|
{
|
|
below = here + cm->mode_info_stride;
|
|
belowleft = below - 1;
|
|
GET_MV_SIGN(below)
|
|
GET_MV_SIGN(belowleft)
|
|
}
|
|
|
|
if(mb_col < (cm->mb_cols-1)
|
|
&& mb_row < (cm->mb_rows-1))
|
|
{
|
|
belowright = below + 1;
|
|
GET_MV_SIGN(belowright)
|
|
}
|
|
}else
|
|
{
|
|
/* No alt_ref and gather mv of neighboring MBs */
|
|
GET_MV(above)
|
|
GET_MV(left)
|
|
GET_MV(aboveleft)
|
|
|
|
if(mb_col < (cm->mb_cols-1))
|
|
{
|
|
right = here + 1;
|
|
aboveright = above + 1;
|
|
GET_MV(right)
|
|
GET_MV(aboveright)
|
|
}
|
|
|
|
if(mb_row < (cm->mb_rows-1))
|
|
{
|
|
below = here + cm->mode_info_stride;
|
|
belowleft = below - 1;
|
|
GET_MV(below)
|
|
GET_MV(belowleft)
|
|
}
|
|
|
|
if(mb_col < (cm->mb_cols-1)
|
|
&& mb_row < (cm->mb_rows-1))
|
|
{
|
|
belowright = below + 1;
|
|
GET_MV(belowright)
|
|
}
|
|
}
|
|
|
|
if (cnt > 0)
|
|
{
|
|
int max_mvx = mvx[0];
|
|
int min_mvx = mvx[0];
|
|
int max_mvy = mvy[0];
|
|
int min_mvy = mvy[0];
|
|
int i;
|
|
|
|
if (cnt > 1)
|
|
{
|
|
for (i=1; i< cnt; i++)
|
|
{
|
|
if (mvx[i] > max_mvx) max_mvx = mvx[i];
|
|
else if (mvx[i] < min_mvx) min_mvx = mvx[i];
|
|
if (mvy[i] > max_mvy) max_mvy = mvy[i];
|
|
else if (mvy[i] < min_mvy) min_mvy = mvy[i];
|
|
}
|
|
}
|
|
|
|
mmvx = MAX(abs(min_mvx - here->mbmi.mv.as_mv.row),
|
|
abs(max_mvx - here->mbmi.mv.as_mv.row));
|
|
mmvy = MAX(abs(min_mvy - here->mbmi.mv.as_mv.col),
|
|
abs(max_mvy - here->mbmi.mv.as_mv.col));
|
|
dissim = MAX(mmvx, mmvy);
|
|
}
|
|
}
|
|
|
|
/* Store mode info for next resolution encoding */
|
|
store_mode_info->mode = tmp->mbmi.mode;
|
|
store_mode_info->ref_frame = tmp->mbmi.ref_frame;
|
|
store_mode_info->mv.as_int = tmp->mbmi.mv.as_int;
|
|
store_mode_info->dissim = dissim;
|
|
tmp++;
|
|
store_mode_info++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|