Compare commits

...

10 Commits

Author SHA1 Message Date
John Koleszar
b76c4c6ba7 WIP: reuse splitmv segmentation (partial)
still not reusing split mvs, but reusing partition size (8x8, 8x16, etc)

Change-Id: I4655b06fcdcbc71a97bff07def78297ae8e5104c
2012-03-22 15:06:53 -07:00
John Koleszar
7f6a695771 WIP: force keyframe based on frame refresh flags
Change-Id: I78d3001ebc02cb5a06d256b5d9ec6aa96f1f8bc0
2012-03-22 15:05:35 -07:00
John Koleszar
a764f61f70 WIP: read modemv from a different file
Change-Id: I0531a3ed133cea42cbad63daeb37815a92b00d83
2012-03-21 17:23:25 -07:00
John Koleszar
50c5e81c7c WIP: reuse splitmv directly (disabled for now)
Change-Id: Ia3a6c09ea5eee886b515ff74c6813a1d50e18b08
2012-03-21 17:11:19 -07:00
John Koleszar
6463c7cf72 WIP: add support for using the modemv from the original stream directly
Change-Id: I4e849a67eaeb654cd1f5c2ac907145cac040a532
2012-03-21 16:08:12 -07:00
John Koleszar
7070dab445 wip: reuse mode/mv in multistream file
Add --read-mvinfo and --write-mvinfo to pass modes and motion vectors
between encodes

Change-Id: I8d73fbd43d27f765bb2ff3026f4a2191b81c46a9
2012-03-09 18:00:12 -08:00
John Koleszar
0a9b65ba1c vpxenc: accept webm input
Change-Id: Id71cccb267fc29acbbe51d6e7378825cb692b2d3
2012-03-08 12:19:09 -08:00
John Koleszar
0a50a29121 vpxenc: generate multistream file
Add the ability to append mode/mv records onto the bitstream.

Change-Id: I83d3125ffe8e6c25dd9e2fa900c963f4f571e6f9
2012-03-08 12:19:09 -08:00
John Koleszar
118b445bab vpxenc: support scaling prior to encoding
Scales the input of the encoder using libyuv's "box filter". Each stream
may have a different width and height specified. If the width (or
height) parameter is missing (or is explicitly set to 0) then the value
will be calculated based on the specified height (or width) and the
input file's dimensions, preserving its aspect ratio. Leaving the height
unspecified behaves similarly.

Note: This functionality still does not take advantage of the
accelerated multi-resolution encoder support with
CONFIG_MULTI_RES_ENCODING.

Change-Id: Ic7026810b13be030826be80dc6f7fc4aaf0c35d0
2012-03-01 14:44:24 -08:00
John Koleszar
3e78b5f2b8 libyuv: fix compilation on ARM
ScaleRowDown2_NEON, ScaleRowDown4_NEON, ScaleRowDown34_NEON,
ScaleRowDown38_NEON had anonymous parameters, which are not valid
in C.

Change-Id: If55f765e0c410f35b01a23c2bb9aea8966c0109d
2012-03-01 14:44:23 -08:00
14 changed files with 1504 additions and 46 deletions

View File

@@ -8,6 +8,20 @@
## be found in the AUTHORS file in the root of the source tree.
##
LIBYUV_SRCS += third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/include/libyuv/cpu_id.h \
third_party/libyuv/include/libyuv/scale.h \
third_party/libyuv/source/row.h \
third_party/libyuv/source/scale.c \
third_party/libyuv/source/cpu_id.c
NESTEGG_SRCS += nestegg/halloc/halloc.h \
nestegg/halloc/src/align.h \
nestegg/halloc/src/halloc.c \
nestegg/halloc/src/hlist.h \
nestegg/halloc/src/macros.h \
nestegg/include/nestegg/nestegg.h \
nestegg/src/nestegg.c
# List of examples to build. UTILS are files that are taken from the source
# tree directly, and GEN_EXAMPLES are files that are created from the
@@ -18,13 +32,7 @@ vpxdec.SRCS += vpx_ports/vpx_timer.h
vpxdec.SRCS += vpx/vpx_integer.h
vpxdec.SRCS += args.c args.h
vpxdec.SRCS += tools_common.c tools_common.h
vpxdec.SRCS += nestegg/halloc/halloc.h
vpxdec.SRCS += nestegg/halloc/src/align.h
vpxdec.SRCS += nestegg/halloc/src/halloc.c
vpxdec.SRCS += nestegg/halloc/src/hlist.h
vpxdec.SRCS += nestegg/halloc/src/macros.h
vpxdec.SRCS += nestegg/include/nestegg/nestegg.h
vpxdec.SRCS += nestegg/src/nestegg.c
vpxdec.SRCS += $(NESTEGG_SRCS)
vpxdec.GUID = BA5FE66F-38DD-E034-F542-B1578C5FB950
vpxdec.DESCRIPTION = Full featured decoder
UTILS-$(CONFIG_ENCODERS) += vpxenc.c
@@ -35,6 +43,8 @@ vpxenc.SRCS += vpx_ports/mem_ops_aligned.h
vpxenc.SRCS += libmkv/EbmlIDs.h
vpxenc.SRCS += libmkv/EbmlWriter.c
vpxenc.SRCS += libmkv/EbmlWriter.h
vpxenc.SRCS += $(LIBYUV_SRCS)
vpxenc.SRCS += $(NESTEGG_SRCS)
vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
vpxenc.DESCRIPTION = Full featured encoder
UTILS-$(CONFIG_ENCODERS) += vp8_scalable_patterns.c
@@ -98,13 +108,7 @@ vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
# C file is provided, not generated automatically.
GEN_EXAMPLES-$(CONFIG_MULTI_RES_ENCODING) += vp8_multi_resolution_encoder.c
vp8_multi_resolution_encoder.SRCS \
+= third_party/libyuv/include/libyuv/basic_types.h \
third_party/libyuv/include/libyuv/cpu_id.h \
third_party/libyuv/include/libyuv/scale.h \
third_party/libyuv/source/row.h \
third_party/libyuv/source/scale.c \
third_party/libyuv/source/cpu_id.c
vp8_multi_resolution_encoder.SRCS += $(LIBYUV_SRCS)
vp8_multi_resolution_encoder.GUID = 04f8738e-63c8-423b-90fa-7c2703a374de
vp8_multi_resolution_encoder.DESCRIPTION = VP8 Multiple-resolution Encoding

View File

@@ -60,7 +60,7 @@ void SetUseReferenceImpl(int use) {
#if defined(__ARM_NEON__) && !defined(YUV_DISABLE_ASM)
#define HAS_SCALEROWDOWN2_NEON
void ScaleRowDown2_NEON(const uint8* src_ptr, int /* src_stride */,
void ScaleRowDown2_NEON(const uint8* src_ptr, int src_stride,
uint8* dst, int dst_width) {
asm volatile (
"1: \n"
@@ -102,7 +102,7 @@ void ScaleRowDown2Int_NEON(const uint8* src_ptr, int src_stride,
}
#define HAS_SCALEROWDOWN4_NEON
static void ScaleRowDown4_NEON(const uint8* src_ptr, int /* src_stride */,
static void ScaleRowDown4_NEON(const uint8* src_ptr, int src_stride,
uint8* dst_ptr, int dst_width) {
asm volatile (
"1: \n"
@@ -160,7 +160,7 @@ static void ScaleRowDown4Int_NEON(const uint8* src_ptr, int src_stride,
// Down scale from 4 to 3 pixels. Use the neon multilane read/write
// to load up the every 4th pixel into a 4 different registers.
// Point samples 32 pixels to 24 pixels.
static void ScaleRowDown34_NEON(const uint8* src_ptr, int /* src_stride */,
static void ScaleRowDown34_NEON(const uint8* src_ptr, int src_stride,
uint8* dst_ptr, int dst_width) {
asm volatile (
"1: \n"
@@ -284,7 +284,7 @@ const unsigned short mult38_div9[8] __attribute__ ((aligned(16))) =
65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18 };
// 32 -> 12
static void ScaleRowDown38_NEON(const uint8* src_ptr, int,
static void ScaleRowDown38_NEON(const uint8* src_ptr, int src_stride,
uint8* dst_ptr, int dst_width) {
asm volatile (
"vld1.u8 {q3}, [%3] \n"

View File

@@ -205,6 +205,11 @@ typedef struct macroblockd
DECLARE_ALIGNED(16, short, dequant_y2[16]);
DECLARE_ALIGNED(16, short, dequant_uv[16]);
/* position of this macroblock */
int mbr;
int mbc;
int mbrc;
/* 16 Y blocks, 4 U, 4 V, 1 DC 2nd order block, each with 16 entries. */
BLOCKD block[25];
int fullpixel_mask;

View File

@@ -411,6 +411,10 @@ void encode_mb_row(VP8_COMP *cpi,
// for each macroblock col in image
for (mb_col = 0; mb_col < cm->mb_cols; mb_col++)
{
xd->mbr = mb_row;
xd->mbc = mb_col;
xd->mbrc = mb_row * cm->mb_cols + mb_col;
// Distance of Mb to the left & right edges, specified in
// 1/8th pel units as they are always compared to values
// that are in 1/8th pel units
@@ -1111,6 +1115,8 @@ extern int cnt_pm;
extern void vp8_fix_contexts(MACROBLOCKD *x);
#include "valgrind/memcheck.h"
int vp8cx_encode_inter_macroblock
(
VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t,
@@ -1130,6 +1136,15 @@ int vp8cx_encode_inter_macroblock
else
x->encode_breakout = cpi->oxcf.encode_breakout;
if (cpi->external_modeinfo)
{
vp8_rd_use_external_mode(cpi, x, recon_yoffset, recon_uvoffset, &rate,
&distortion, &intra_error);
VALGRIND_CHECK_VALUE_IS_DEFINED(rate);
VALGRIND_CHECK_VALUE_IS_DEFINED(distortion);
VALGRIND_CHECK_VALUE_IS_DEFINED(intra_error);
}
else
if (cpi->sf.RD)
{
int zbin_mode_boost_enabled = cpi->zbin_mode_boost_enabled;

View File

@@ -859,7 +859,7 @@ void vp8_set_speed_features(VP8_COMP *cpi)
{
sf->auto_filter = 0; // Faster selection of loop filter
sf->search_method = HEX;
sf->iterative_sub_pixel = 0;
//sf->iterative_sub_pixel = 0;
}
if (Speed > 6)
@@ -2449,7 +2449,7 @@ int vp8_use_as_reference(VP8_COMP *cpi, int ref_frame_flags)
}
int vp8_update_reference(VP8_COMP *cpi, int ref_frame_flags)
{
if (ref_frame_flags > 7)
if (ref_frame_flags > 127)
return -1 ;
cpi->common.refresh_golden_frame = 0;
@@ -2465,6 +2465,8 @@ int vp8_update_reference(VP8_COMP *cpi, int ref_frame_flags)
if (ref_frame_flags & VP8_ALT_FLAG)
cpi->common.refresh_alt_ref_frame = 1;
cpi->common.copy_buffer_to_gf = (ref_frame_flags >> 3) & 3;
cpi->common.copy_buffer_to_arf = (ref_frame_flags >> 5) & 3;
return 0;
}
@@ -3187,8 +3189,11 @@ static void encode_frame_to_data_rate
cpi->per_frame_bandwidth = (int)(cpi->target_bandwidth / cpi->output_frame_rate);
// Default turn off buffer to buffer copying
if(!cpi->external_modeinfo)
{
cm->copy_buffer_to_gf = 0;
cm->copy_buffer_to_arf = 0;
}
// Clear zbin over-quant value and mode boost values.
cpi->zbin_over_quant = 0;
@@ -4063,10 +4068,14 @@ static void encode_frame_to_data_rate
// For inter frames the current default behavior is that when
// cm->refresh_golden_frame is set we copy the old GF over to the ARF buffer
// This is purely an encoder decision at present.
if (!cpi->oxcf.error_resilient_mode && cm->refresh_golden_frame)
if(!cpi->external_modeinfo)
{
if (!cpi->oxcf.error_resilient_mode && cm->refresh_golden_frame
&& !cm->refresh_alt_ref_frame)
cm->copy_buffer_to_arf = 2;
else
cm->copy_buffer_to_arf = 0;
}
cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx];
@@ -4620,7 +4629,12 @@ int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags, unsigned l
return -1;
cm = &cpi->common;
if(cm->refresh_last_frame && cm->refresh_golden_frame && cm->refresh_alt_ref_frame)
{
cm->refresh_golden_frame = 0;
cm->refresh_alt_ref_frame = 0;
*frame_flags |= 1;
}
if (setjmp(cpi->common.error.jmp))
{
cpi->common.error.setjmp = 0;

View File

@@ -678,7 +678,7 @@ typedef struct VP8_COMP
/* Number of MBs per row at lower-resolution level */
int mr_low_res_mb_cols;
#endif
MODE_INFO *external_modeinfo;
} VP8_COMP;
void control_data_rate(VP8_COMP *cpi);

View File

@@ -33,6 +33,7 @@
#include "rdopt.h"
#include "vpx_mem/vpx_mem.h"
#include "vp8/common/systemdependent.h"
#include "valgrind/memcheck.h"
extern void vp8_update_zbin_extra(VP8_COMP *cpi, MACROBLOCK *x);
@@ -735,11 +736,12 @@ static int rd_pick_intra4x4mby_modes(VP8_COMP *cpi, MACROBLOCK *mb, int *Rate,
break;
}
VALGRIND_CHECK_VALUE_IS_DEFINED(tot_rate_y);
VALGRIND_CHECK_VALUE_IS_DEFINED(total_rd);
if(total_rd >= (int64_t)best_rd)
return INT_MAX;
*Rate = cost;
*rate_y += tot_rate_y;
*rate_y = tot_rate_y;
*Distortion = distortion;
return RDCOST(mb->rdmult, mb->rddiv, cost, distortion);
@@ -1477,6 +1479,246 @@ static int vp8_rd_pick_best_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x,
return bsi.segment_rd;
}
static void rd_reuse_segment(VP8_COMP *cpi, MACROBLOCK *x,
BEST_SEG_INFO *bsi, unsigned int segmentation)
{
int i;
int const *labels;
int br = 0;
int bd = 0;
B_PREDICTION_MODE this_mode;
int_mv reused_mv[16];
int label_count;
int this_segment_rd = 0;
int label_mv_thresh;
int rate = 0;
int sbr = 0;
int sbd = 0;
int segmentyrate = 0;
vp8_variance_fn_ptr_t *v_fn_ptr;
ENTROPY_CONTEXT_PLANES t_above, t_left;
ENTROPY_CONTEXT *ta;
ENTROPY_CONTEXT *tl;
ENTROPY_CONTEXT_PLANES t_above_b, t_left_b;
ENTROPY_CONTEXT *ta_b;
ENTROPY_CONTEXT *tl_b;
vpx_memcpy(&t_above, x->e_mbd.above_context, sizeof(ENTROPY_CONTEXT_PLANES));
vpx_memcpy(&t_left, x->e_mbd.left_context, sizeof(ENTROPY_CONTEXT_PLANES));
ta = (ENTROPY_CONTEXT *)&t_above;
tl = (ENTROPY_CONTEXT *)&t_left;
ta_b = (ENTROPY_CONTEXT *)&t_above_b;
tl_b = (ENTROPY_CONTEXT *)&t_left_b;
br = 0;
bd = 0;
v_fn_ptr = &cpi->fn_ptr[segmentation];
labels = vp8_mbsplits[segmentation];
label_count = vp8_mbsplit_count[segmentation];
// 64 makes this threshold really big effectively
// making it so that we very rarely check mvs on
// segments. setting this to 1 would make mv thresh
// roughly equal to what it is for macroblocks
label_mv_thresh = 1 * bsi->mvthresh / label_count ;
// Segmentation method overheads
rate = vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + segmentation);
rate += vp8_cost_mv_ref(SPLITMV, bsi->mdcounts);
this_segment_rd += RDCOST(x->rdmult, x->rddiv, rate, 0);
br += rate;
for (i = 0; i < 16; i++)
reused_mv[i].as_int = x->e_mbd.block[i].bmi.mv.as_int;
for (i = 0; i < label_count; i++)
{
int_mv mode_mv[B_MODE_COUNT];
int best_label_rd = INT_MAX;
B_PREDICTION_MODE mode_selected = ZERO4X4;
int bestlabelyrate = 0;
// search for the best motion vector on this segment
for (this_mode = LEFT4X4; this_mode <= NEW4X4 ; this_mode ++)
{
int this_rd;
int distortion;
int labelyrate;
ENTROPY_CONTEXT_PLANES t_above_s, t_left_s;
ENTROPY_CONTEXT *ta_s;
ENTROPY_CONTEXT *tl_s;
vpx_memcpy(&t_above_s, &t_above, sizeof(ENTROPY_CONTEXT_PLANES));
vpx_memcpy(&t_left_s, &t_left, sizeof(ENTROPY_CONTEXT_PLANES));
ta_s = (ENTROPY_CONTEXT *)&t_above_s;
tl_s = (ENTROPY_CONTEXT *)&t_left_s;
/* find the first block for this label */
if (this_mode == NEW4X4)
{
int b;
for(b=0; b<16; b++)
if(labels[b] == i) break;
mode_mv[NEW4X4].as_int = reused_mv[b].as_int;
}
rate = labels2mode(x, labels, i, this_mode, &mode_mv[this_mode],
bsi->ref_mv, x->mvcost);
// Trap vectors that reach beyond the UMV borders
if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) ||
((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max))
{
continue;
}
distortion = vp8_encode_inter_mb_segment(x, labels, i) / 4;
labelyrate = rdcost_mbsegment_y(x, labels, i, ta_s, tl_s);
rate += labelyrate;
this_rd = RDCOST(x->rdmult, x->rddiv, rate, distortion);
if (this_rd < best_label_rd)
{
sbr = rate;
sbd = distortion;
bestlabelyrate = labelyrate;
mode_selected = this_mode;
best_label_rd = this_rd;
vpx_memcpy(ta_b, ta_s, sizeof(ENTROPY_CONTEXT_PLANES));
vpx_memcpy(tl_b, tl_s, sizeof(ENTROPY_CONTEXT_PLANES));
}
} /*for each 4x4 mode*/
vpx_memcpy(ta, ta_b, sizeof(ENTROPY_CONTEXT_PLANES));
vpx_memcpy(tl, tl_b, sizeof(ENTROPY_CONTEXT_PLANES));
labels2mode(x, labels, i, mode_selected, &mode_mv[mode_selected],
bsi->ref_mv, x->mvcost);
br += sbr;
bd += sbd;
segmentyrate += bestlabelyrate;
this_segment_rd += best_label_rd;
if (this_segment_rd >= bsi->segment_rd)
break;
} /* for each label */
if (this_segment_rd < bsi->segment_rd)
{
bsi->r = br;
bsi->d = bd;
bsi->segment_yrate = segmentyrate;
bsi->segment_rd = this_segment_rd;
bsi->segment_num = segmentation;
// store everything needed to come back to this!!
for (i = 0; i < 16; i++)
{
bsi->mvs[i].as_mv = x->partition_info->bmi[i].mv.as_mv;
bsi->modes[i] = x->partition_info->bmi[i].mode;
bsi->eobs[i] = x->e_mbd.eobs[i];
}
}
}
static int vp8_rd_reuse_mbsegmentation(VP8_COMP *cpi, MACROBLOCK *x,
int_mv *best_ref_mv, int best_rd,
int *mdcounts, int *returntotrate,
int *returnyrate, int *returndistortion,
int mvthresh)
{
int i;
BEST_SEG_INFO bsi;
vpx_memset(&bsi, 0, sizeof(bsi));
bsi.segment_rd = best_rd;
bsi.ref_mv = best_ref_mv;
bsi.mvp.as_int = best_ref_mv->as_int;
bsi.mvthresh = mvthresh;
bsi.mdcounts = mdcounts;
for(i = 0; i < 16; i++)
{
bsi.modes[i] = ZERO4X4;
}
{
int s;
for(s = 0; s < BLOCK_4X4; s++)
{
char set[16] = {0};
int smv[16];
for (i=0; i<16; i++)
{
int p = vp8_mbsplits[s][i];
if(!set[p])
{
set[p] = 1;
smv[p] = x->e_mbd.block[i].bmi.mv.as_int;
}
if(smv[p] != x->e_mbd.block[i].bmi.mv.as_int)
break;
}
if(i==16)
break;
}
rd_check_segment(cpi, x, &bsi, s);
}
/* set it to the best */
for (i = 0; i < 16; i++)
{
BLOCKD *bd = &x->e_mbd.block[i];
bd->bmi.mv.as_int = bsi.mvs[i].as_int;
*bd->eob = bsi.eobs[i];
}
*returntotrate = bsi.r;
*returndistortion = bsi.d;
*returnyrate = bsi.segment_yrate;
/* save partitions */
x->e_mbd.mode_info_context->mbmi.partitioning = bsi.segment_num;
x->partition_info->count = vp8_mbsplit_count[bsi.segment_num];
for (i = 0; i < x->partition_info->count; i++)
{
int j;
j = vp8_mbsplit_offset[bsi.segment_num][i];
x->partition_info->bmi[i].mode = bsi.modes[j];
x->partition_info->bmi[i].mv.as_mv = bsi.mvs[j].as_mv;
}
/*
* used to set x->e_mbd.mode_info_context->mbmi.mv.as_int
*/
x->partition_info->bmi[15].mv.as_int = bsi.mvs[15].as_int;
return bsi.segment_rd;
}
//The improved MV prediction
void vp8_mv_pred
(
@@ -1709,6 +1951,591 @@ static void rd_update_mvcount(VP8_COMP *cpi, MACROBLOCK *x, int_mv *best_ref_mv)
}
}
#if 0
void vp8_rd_use_external_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int recon_uvoffset, int *returnrate,
int *returndistortion, int *returnintra)
{
unsigned char *plane[4][3];
MODE_INFO *mi;
int rate, rate_y, rate_uv;
int distortion, distortion_y, distortion_uv;
mi = cpi->external_modeinfo + x->e_mbd.mbrc;
*x->e_mbd.mode_info_context = *mi;
/* Map partitioning info */
if(mi->mbmi.mode == SPLITMV)
{
int i;
x->partition_info->count = vp8_mbsplit_count[mi->mbmi.partitioning];
for (i = 0; i < x->partition_info->count; i++)
{
int j;
j = vp8_mbsplit_offset[mi->mbmi.partitioning][i];
/* TODO: this is mapping a union onto a struct, assume the
* data will never be looked at from the wrong context.
*/
x->partition_info->bmi[i].mode = NEW4X4; //mi->bmi[j].as_mode;
x->partition_info->bmi[i].mv.as_int = mi->bmi[j].mv.as_int;
}
/*
* used to set x->e_mbd.mode_info_context->mbmi.mv.as_int
*/
x->partition_info->bmi[15].mv.as_int = mi->bmi[15].mv.as_int;
}
rate = x->mbmode_cost[x->e_mbd.frame_type][mi->mbmi.mode];
rate += x->ref_frame_cost[mi->mbmi.ref_frame];
if(mi->mbmi.ref_frame == INTRA_FRAME)
{
vp8_build_intra_predictors_mby(&x->e_mbd);
macro_block_yrd(x, &rate_y, &distortion);
//hack
rate_uv = rate_y/4;
distortion_uv = distortion_y/4;
}
else
{
int sign_bias;
int_mv best_ref_mv_sb[2];
int_mv mode_mv_sb[2][MB_MODE_COUNT];
int_mv best_ref_mv;
int mdcounts[4];
get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset);
x->e_mbd.pre.y_buffer = plane[mi->mbmi.ref_frame][0];
x->e_mbd.pre.u_buffer = plane[mi->mbmi.ref_frame][1];
x->e_mbd.pre.v_buffer = plane[mi->mbmi.ref_frame][2];
/* Get nearby MV info */
sign_bias = vp8_find_near_mvs_bias(&x->e_mbd,
x->e_mbd.mode_info_context,
mode_mv_sb,
best_ref_mv_sb,
mdcounts,
mi->mbmi.ref_frame,
cpi->common.ref_frame_sign_bias);
best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int;
if(mi->mbmi.mode != ZEROMV)
rate += vp8_mv_bit_cost(&mi->mbmi.mv, &best_ref_mv, x->mvcost, 96);
rate += vp8_cost_mv_ref(mi->mbmi.mode, mdcounts);
vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16);
//rate += vp8_cost_mv_ref(mi->mbmi.mode, mdcounts);
// Y cost and distortion
macro_block_yrd(x, &rate_y, &distortion_y);
// UV cost and distortion
rd_inter16x16_uv(cpi, x, &rate_uv, &distortion_uv,
cpi->common.full_pixel);
}
/* Test for skip blocks */
if (cpi->common.mb_no_coeff_skip)
{
int i, bit=1;
for(i=0; i<24; i++)
if(x->e_mbd.eobs[i])
{
bit = 0;
break;
}
if(bit)
{
rate_y = 0;
rate_uv = 0;
}
rate += vp8_cost_bit(cpi->prob_skip_false, bit);
}
*returnrate = rate + rate_y + rate_uv;
*returndistortion = distortion + distortion_y + distortion_uv;
*returnintra = (mi->mbmi.ref_frame == INTRA_FRAME)
? *returndistortion : INT_MAX;
}
#else
void vp8_rd_use_external_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int recon_uvoffset, int *returnrate,
int *returndistortion, int *returnintra)
{
MODE_INFO *mi = cpi->external_modeinfo + x->e_mbd.mbrc;
BLOCK *b = &x->block[0];
BLOCKD *d = &x->e_mbd.block[0];
MACROBLOCKD *xd = &x->e_mbd;
union b_mode_info best_bmodes[16];
MB_MODE_INFO best_mbmode;
PARTITION_INFO best_partition;
int_mv best_ref_mv_sb[2];
int_mv mode_mv_sb[2][MB_MODE_COUNT];
int_mv best_ref_mv;
int_mv *mode_mv;
MB_PREDICTION_MODE this_mode;
int num00;
int i;
int mdcounts[4];
int rate=0;
int distortion=0;
int best_rd = INT_MAX;
int rate2, distortion2;
int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly;
int rate_y, UNINITIALIZED_IS_SAFE(rate_uv);
int distortion_uv;
int best_yrd = INT_MAX;
MB_PREDICTION_MODE uv_intra_mode;
int_mv mvp;
int near_sadidx[8] = {0, 1, 2, 3, 4, 5, 6, 7};
int saddone=0;
int sr=0; //search range got from mv_pred(). It uses step_param levels. (0-7)
unsigned char *plane[4][3];
int sign_bias = 0;
mode_mv = mode_mv_sb[sign_bias];
best_ref_mv.as_int = 0;
vpx_memset(mode_mv_sb, 0, sizeof(mode_mv_sb));
vpx_memset(&best_mbmode, 0, sizeof(best_mbmode));
vpx_memset(&best_bmodes, 0, sizeof(best_bmodes));
{
sign_bias = vp8_find_near_mvs_bias(&x->e_mbd,
x->e_mbd.mode_info_context,
mode_mv_sb,
best_ref_mv_sb,
mdcounts,
LAST_FRAME,
cpi->common.ref_frame_sign_bias);
mode_mv = mode_mv_sb[sign_bias];
best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int;
}
cpi->ref_frame_flags|=0x7;
get_predictor_pointers(cpi, plane, recon_yoffset, recon_uvoffset);
*returnintra = INT_MAX;
cpi->mbs_tested_so_far++; // Count of the number of MBs tested so far this frame
x->skip = 0;
x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME;
rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, &uv_intra_rate_tokenonly, &uv_intra_distortion);
uv_intra_mode = x->e_mbd.mode_info_context->mbmi.uv_mode;
{
int this_rd = INT_MAX;
int disable_skip = 0;
int other_cost = 0;
int this_ref_frame;
// These variables hold are rolling total cost and distortion for this mode
rate2 = 0;
distortion2 = 0;
this_mode = mi->mbmi.mode; //JRK
this_ref_frame = mi->mbmi.ref_frame;
#if 1
memcpy(x->e_mbd.mode_info_context, mi, sizeof(*mi));
#else
x->e_mbd.mode_info_context->mbmi.mode = this_mode;
x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame;
#endif
//if(this_mode == SPLITMV) this_mode=NEWMV;
/* everything but intra */
if (x->e_mbd.mode_info_context->mbmi.ref_frame)
{
x->e_mbd.pre.y_buffer = plane[this_ref_frame][0];
x->e_mbd.pre.u_buffer = plane[this_ref_frame][1];
x->e_mbd.pre.v_buffer = plane[this_ref_frame][2];
if (sign_bias != cpi->common.ref_frame_sign_bias[this_ref_frame])
{
sign_bias = cpi->common.ref_frame_sign_bias[this_ref_frame];
mode_mv = mode_mv_sb[sign_bias];
best_ref_mv.as_int = best_ref_mv_sb[sign_bias].as_int;
}
}
// Experimental code. Special case for gf and arf zeromv modes. Increase zbin size to supress noise
if (cpi->zbin_mode_boost_enabled)
{
if ( this_ref_frame == INTRA_FRAME )
cpi->zbin_mode_boost = 0;
else
{
if (this_mode == ZEROMV)
{
if (this_ref_frame != LAST_FRAME)
cpi->zbin_mode_boost = GF_ZEROMV_ZBIN_BOOST;
else
cpi->zbin_mode_boost = LF_ZEROMV_ZBIN_BOOST;
}
else if (this_mode == SPLITMV)
cpi->zbin_mode_boost = 0;
else
cpi->zbin_mode_boost = MV_ZBIN_BOOST;
}
vp8_update_zbin_extra(cpi, x);
}
VALGRIND_CHECK_VALUE_IS_DEFINED(rate2);
switch (this_mode)
{
case B_PRED:
{
int tmp_rd;
// Note the rate value returned here includes the cost of coding the BPRED mode : x->mbmode_cost[x->e_mbd.frame_type][BPRED];
tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rate_y, &distortion, INT_MAX);
VALGRIND_CHECK_VALUE_IS_DEFINED(rate);
VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y);
VALGRIND_CHECK_VALUE_IS_DEFINED(distortion);
rate2 += rate;
distortion2 += distortion;
if(tmp_rd < best_yrd)
{
rate2 += uv_intra_rate;
rate_uv = uv_intra_rate_tokenonly;
distortion2 += uv_intra_distortion;
distortion_uv = uv_intra_distortion;
}
else
{
this_rd = INT_MAX;
disable_skip = 1;
}
}
break;
case SPLITMV:
{
#if 1
int tmp_rd;
int this_rd_thresh;
//this_rd_thresh = (this_ref_frame == 1) ? cpi->rd_threshes[THR_NEW1] : cpi->rd_threshes[THR_NEW3];
//this_rd_thresh = (this_ref_frame == 2) ? cpi->rd_threshes[THR_NEW2] : this_rd_thresh;
this_rd_thresh = 0;
#if 0
tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv,
best_yrd, mdcounts,
&rate, &rate_y, &distortion, this_rd_thresh) ;
#else
tmp_rd = vp8_rd_reuse_mbsegmentation(cpi, x, &best_ref_mv,
best_yrd, mdcounts,
&rate, &rate_y, &distortion, this_rd_thresh) ;
#endif
VALGRIND_CHECK_VALUE_IS_DEFINED(rate);
VALGRIND_CHECK_VALUE_IS_DEFINED(distortion);
rate2 += rate;
distortion2 += distortion;
// If even the 'Y' rd value of split is higher than best so far then dont bother looking at UV
if (tmp_rd < best_yrd)
{
// Now work out UV cost and add it in
rd_inter4x4_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel);
rate2 += rate_uv;
distortion2 += distortion_uv;
}
else
{
this_rd = INT_MAX;
disable_skip = 1;
}
#else
int i;
for (i = 0; i < 16; i++)
{
x->e_mbd.block[i].bmi = mi->bmi[i];
x->e_mbd.block[i].eob = 15;
}
x->e_mbd.mode_info_context->mbmi.partitioning = mi->mbmi.partitioning;
x->partition_info->count = vp8_mbsplit_count[mi->mbmi.partitioning];
for (i = 0; i < x->partition_info->count; i++)
{
int j;
j = vp8_mbsplit_offset[mi->mbmi.partitioning][i];
x->partition_info->bmi[i].mode =
mi->bmi[j].mv.as_int ? NEW4X4 : ZERO4X4;
x->partition_info->bmi[i].mv.as_mv = mi->bmi[j].mv.as_mv;
distortion2 = vp8_encode_inter_mb_segment(x, vp8_mbsplits[segmentation], i);
rate2 = 0;
}
// rate = labels2mode(x, labels, i, this_mode, &mode_mv[this_mode], bsi->ref_mv, x->mvcost);
#endif
}
VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y);
break;
case DC_PRED:
case V_PRED:
case H_PRED:
case TM_PRED:
x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME;
vp8_build_intra_predictors_mby
(&x->e_mbd);
macro_block_yrd(x, &rate_y, &distortion) ;
rate2 += rate_y;
distortion2 += distortion;
rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode];
rate2 += uv_intra_rate;
rate_uv = uv_intra_rate_tokenonly;
distortion2 += uv_intra_distortion;
distortion_uv = uv_intra_distortion;
VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y);
break;
case NEWMV:
mode_mv[NEWMV].as_int = mi->mbmi.mv.as_int;
case NEARESTMV:
case NEARMV:
// Clip "next_nearest" so that it does not extend to far out of image
vp8_clamp_mv2(&mode_mv[this_mode], xd);
// Do not bother proceeding if the vector (from newmv,nearest or near) is 0,0 as this should then be coded using the zeromv mode.
if (((this_mode == NEARMV) || (this_mode == NEARESTMV)) && (mode_mv[this_mode].as_int == 0))
this_mode = ZEROMV;
case ZEROMV:
// Trap vectors that reach beyond the UMV borders
// Note that ALL New MV, Nearest MV Near MV and Zero MV code drops through to this point
// because of the lack of break statements in the previous two cases.
if (((mode_mv[this_mode].as_mv.row >> 3) < x->mv_row_min) || ((mode_mv[this_mode].as_mv.row >> 3) > x->mv_row_max) ||
((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max))
assert(0);
vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]);
vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16);
if (cpi->active_map_enabled && x->active_ptr[0] == 0) {
x->skip = 1;
}
else if (x->encode_breakout)
{
unsigned int sse;
unsigned int var;
int threshold = (xd->block[0].dequant[1]
* xd->block[0].dequant[1] >>4);
if(threshold < x->encode_breakout)
threshold = x->encode_breakout;
var = vp8_variance16x16
(*(b->base_src), b->src_stride,
x->e_mbd.predictor, 16, &sse);
if (sse < threshold)
{
unsigned int q2dc = xd->block[24].dequant[0];
/* If theres is no codeable 2nd order dc
or a very small uniform pixel change change */
if ((sse - var < q2dc * q2dc >>4) ||
(sse /2 > var && sse-var < 64))
{
// Check u and v to make sure skip is ok
int sse2= VP8_UVSSE(x);
if (sse2 * 2 < threshold)
{
x->skip = 1;
distortion2 = sse + sse2;
rate2 = 500;
/* for best_yrd calculation */
rate_uv = 0;
distortion_uv = sse2;
disable_skip = 1;
this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2);
break;
}
}
}
}
//intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code
// Add in the Mv/mode cost
rate2 += vp8_cost_mv_ref(this_mode, mdcounts);
// Y cost and distortion
macro_block_yrd(x, &rate_y, &distortion);
rate2 += rate_y;
distortion2 += distortion;
// UV cost and distortion
rd_inter16x16_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel);
rate2 += rate_uv;
distortion2 += distortion_uv;
break;
default:
assert(0);
}
VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y);
VALGRIND_CHECK_VALUE_IS_DEFINED(rate2);
// Where skip is allowable add in the default per mb cost for the no skip case.
// where we then decide to skip we have to delete this and replace it with the
// cost of signallying a skip
if (cpi->common.mb_no_coeff_skip)
{
other_cost += vp8_cost_bit(cpi->prob_skip_false, 0);
rate2 += other_cost;
}
/* Estimate the reference frame signaling cost and add it
* to the rolling cost variable.
*/
rate2 +=
x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
VALGRIND_CHECK_VALUE_IS_DEFINED(rate2);
VALGRIND_CHECK_VALUE_IS_DEFINED(rate_y);
VALGRIND_CHECK_VALUE_IS_DEFINED(rate_uv);
if (!disable_skip)
{
// Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate
if (cpi->common.mb_no_coeff_skip)
{
int tteob;
tteob = 0;
for (i = 0; i <= 24; i++)
{
tteob += x->e_mbd.eobs[i];
}
if (tteob == 0)
{
rate2 -= (rate_y + rate_uv);
//for best_yrd calculation
rate_uv = 0;
// Back out no skip flag costing and add in skip flag costing
if (cpi->prob_skip_false)
{
int prob_skip_cost;
prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 1);
prob_skip_cost -= vp8_cost_bit(cpi->prob_skip_false, 0);
rate2 += prob_skip_cost;
other_cost += prob_skip_cost;
}
}
}
// Calculate the final RD estimate for this mode
this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2);
}
VALGRIND_CHECK_VALUE_IS_DEFINED(rate2);
// Keep record of best intra distortion
if (x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME)
{
*returnintra = distortion2 ;
}
// Did this mode help.. i.i is it the new best mode
{
if (this_mode <= B_PRED)
{
x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode;
/* required for left and above block mv */
x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
}
other_cost +=
x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame];
/* Calculate the final y RD estimate for this mode */
best_yrd = RDCOST(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost),
(distortion2-distortion_uv));
VALGRIND_CHECK_VALUE_IS_DEFINED(rate2);
*returnrate = rate2;
*returndistortion = distortion2;
best_rd = this_rd;
vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO));
vpx_memcpy(&best_partition, x->partition_info, sizeof(PARTITION_INFO));
if ((this_mode == B_PRED) || (this_mode == SPLITMV))
for (i = 0; i < 16; i++)
{
best_bmodes[i] = x->e_mbd.block[i].bmi;
}
}
}
VALGRIND_CHECK_VALUE_IS_DEFINED(*returnrate);
VALGRIND_CHECK_VALUE_IS_DEFINED(*returndistortion);
VALGRIND_CHECK_VALUE_IS_DEFINED(*returnintra);
if (cpi->is_src_frame_alt_ref &&
(best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME))
{
x->e_mbd.mode_info_context->mbmi.mode = ZEROMV;
x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME;
x->e_mbd.mode_info_context->mbmi.mv.as_int = 0;
x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
x->e_mbd.mode_info_context->mbmi.mb_skip_coeff =
(cpi->common.mb_no_coeff_skip);
x->e_mbd.mode_info_context->mbmi.partitioning = 0;
return;
}
// macroblock modes
vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, sizeof(MB_MODE_INFO));
if (best_mbmode.mode == B_PRED)
{
for (i = 0; i < 16; i++)
xd->mode_info_context->bmi[i].as_mode = best_bmodes[i].as_mode;
}
if (best_mbmode.mode == SPLITMV)
{
for (i = 0; i < 16; i++)
xd->mode_info_context->bmi[i].mv.as_int = best_bmodes[i].mv.as_int;
vpx_memcpy(x->partition_info, &best_partition, sizeof(PARTITION_INFO));
x->e_mbd.mode_info_context->mbmi.mv.as_int =
x->partition_info->bmi[15].mv.as_int;
}
if (sign_bias
!= cpi->common.ref_frame_sign_bias[xd->mode_info_context->mbmi.ref_frame])
best_ref_mv.as_int = best_ref_mv_sb[!sign_bias].as_int;
rd_update_mvcount(cpi, x, &best_ref_mv);
}
#endif
void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset,
int recon_uvoffset, int *returnrate,

View File

@@ -77,6 +77,18 @@ static const struct extraconfig_map extracfg_map[] =
}
};
struct cx_data_iter
{
struct vpx_codec_cx_pkt pkt;
int frame_out;
int pkt_list_done;
vpx_codec_iter_t pkt_list_iter;
int mode_info_done;
int mode_info_row;
};
struct vpx_codec_alg_priv
{
vpx_codec_priv_t base;
@@ -92,6 +104,7 @@ struct vpx_codec_alg_priv
vpx_codec_pkt_list_decl(64) pkt_list; // changed to accomendate the maximum number of lagged frames allowed
int deprecated_mode;
unsigned int fixed_kf_cntr;
struct cx_data_iter cx_data_iter;
};
@@ -952,7 +965,45 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t *ctx,
static const vpx_codec_cx_pkt_t *vp8e_get_cxdata(vpx_codec_alg_priv_t *ctx,
vpx_codec_iter_t *iter)
{
return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter);
if(!*iter)
{
memset(&ctx->cx_data_iter, 0, sizeof(ctx->cx_data_iter));
*iter = &ctx->cx_data_iter;
}
if(!ctx->cx_data_iter.pkt_list_done)
{
const vpx_codec_cx_pkt_t *pkt;
pkt = vpx_codec_pkt_list_get(&ctx->pkt_list.head,
&ctx->cx_data_iter.pkt_list_iter);
if(pkt)
{
ctx->cx_data_iter.frame_out = 1;
return pkt;
}
ctx->cx_data_iter.pkt_list_done = 1;
}
if(!ctx->cx_data_iter.frame_out)
return NULL;
if(!ctx->cx_data_iter.mode_info_done)
{
vpx_codec_cx_pkt_t *pkt = &ctx->cx_data_iter.pkt;
if(ctx->cx_data_iter.mode_info_row < ctx->cpi->common.mb_rows)
{
pkt->kind = VPX_CODEC_CUSTOM_PKT;
pkt->data.raw.buf = ctx->cpi->common.mi
+ ctx->cpi->common.mode_info_stride
* ctx->cx_data_iter.mode_info_row;
pkt->data.raw.sz = sizeof(MODE_INFO) * ctx->cpi->common.mb_cols;
ctx->cx_data_iter.mode_info_row++;
return pkt;
}
else
ctx->cx_data_iter.mode_info_done = 1;
}
return NULL;
}
static vpx_codec_err_t vp8e_set_reference(vpx_codec_alg_priv_t *ctx,
@@ -1168,6 +1219,38 @@ static vpx_codec_err_t vp8e_set_scalemode(vpx_codec_alg_priv_t *ctx,
}
static vpx_codec_err_t set_modeinfo(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args)
{
vpx_fixed_buf_t *data = va_arg(args, vpx_fixed_buf_t *);
ctx->cpi->external_modeinfo = data ? data->buf : NULL;
return VPX_CODEC_OK;
}
static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
int ctrl_id,
va_list args)
{
int *update_info = va_arg(args, int *);
VP8_COMP *pbi = ctx->cpi;
if (update_info)
{
*update_info = pbi->common.refresh_alt_ref_frame * (int) VP8_ALTR_FRAME
+ pbi->common.refresh_golden_frame * (int) VP8_GOLD_FRAME
+ pbi->common.refresh_last_frame * (int) VP8_LAST_FRAME
+ (pbi->common.copy_buffer_to_gf << 3)
+ (pbi->common.copy_buffer_to_arf << 5);
return VPX_CODEC_OK;
}
else
return VPX_CODEC_INVALID_PARAM;
}
static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] =
{
{VP8_SET_REFERENCE, vp8e_set_reference},
@@ -1194,6 +1277,8 @@ static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] =
{VP8E_SET_TUNING, set_param},
{VP8E_SET_CQ_LEVEL, set_param},
{VP8E_SET_MAX_INTRA_BITRATE_PCT, set_param},
{VP8E_SET_MODEINFO, set_modeinfo},
{VP8E_GET_LAST_REF_UPDATES, vp8_get_last_ref_updates},
{ -1, NULL},
};

View File

@@ -70,6 +70,7 @@ struct vpx_codec_alg_priv
vpx_image_t img;
int img_setup;
int img_avail;
vpx_fixed_buf_t mode_info;
};
static unsigned long vp8_priv_sz(const vpx_codec_dec_cfg_t *si, vpx_codec_flags_t flags)
@@ -692,7 +693,9 @@ static vpx_codec_err_t vp8_get_last_ref_updates(vpx_codec_alg_priv_t *ctx,
{
*update_info = pbi->common.refresh_alt_ref_frame * (int) VP8_ALTR_FRAME
+ pbi->common.refresh_golden_frame * (int) VP8_GOLD_FRAME
+ pbi->common.refresh_last_frame * (int) VP8_LAST_FRAME;
+ pbi->common.refresh_last_frame * (int) VP8_LAST_FRAME
+ (pbi->common.copy_buffer_to_gf << 3)
+ (pbi->common.copy_buffer_to_arf << 5);
return VPX_CODEC_OK;
}
@@ -741,6 +744,43 @@ static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
}
static vpx_codec_err_t get_mode_info(vpx_codec_alg_priv_t *ctx,
int ctrl_id,
va_list args)
{
vpx_fixed_buf_t **data = va_arg(args, vpx_fixed_buf_t **);
VP8D_COMP *pbi = (VP8D_COMP *)ctx->pbi;
size_t mi_sz = sizeof(MODE_INFO)*pbi->common.mb_rows * pbi->common.mb_cols;
char *buf;
size_t buf_stride;
int i;
MODE_INFO *mi;
if(data)
{
if(ctx->mode_info.sz != mi_sz)
{
free(ctx->mode_info.buf);
ctx->mode_info.buf = malloc(mi_sz);
ctx->mode_info.sz = mi_sz;
}
mi = pbi->common.mi;
buf = ctx->mode_info.buf;
buf_stride = pbi->common.mb_cols * sizeof(MODE_INFO);
for(i=0; i<pbi->common.mb_rows; i++)
{
memcpy(buf, mi, buf_stride);
buf += buf_stride;
mi += pbi->common.mode_info_stride;
}
*data = &ctx->mode_info;
return VPX_CODEC_OK;
}
else
return VPX_CODEC_INVALID_PARAM;
}
vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] =
{
{VP8_SET_REFERENCE, vp8_set_reference},
@@ -753,6 +793,7 @@ vpx_codec_ctrl_fn_map_t vp8_ctf_maps[] =
{VP8D_GET_LAST_REF_UPDATES, vp8_get_last_ref_updates},
{VP8D_GET_FRAME_CORRUPTED, vp8_get_frame_corrupted},
{VP8D_GET_LAST_REF_USED, vp8_get_last_ref_frame},
{VP8D_GET_MODE_INFO, get_mode_info},
{ -1, NULL},
};

View File

@@ -178,6 +178,10 @@ enum vp8e_enc_control_id
*
*/
VP8E_SET_MAX_INTRA_BITRATE_PCT,
/*!\brief Mode/mv data */
VP8E_SET_MODEINFO,
VP8E_GET_LAST_REF_UPDATES
};
/*!\brief vpx 1-D scaling mode
@@ -311,6 +315,8 @@ VPX_CTRL_USE_TYPE(VP8E_GET_LAST_QUANTIZER_64, int *)
VPX_CTRL_USE_TYPE(VP8E_SET_MAX_INTRA_BITRATE_PCT, unsigned int)
VPX_CTRL_USE_TYPE(VP8E_SET_MODEINFO, vpx_fixed_buf_t *)
VPX_CTRL_USE_TYPE(VP8E_GET_LAST_REF_UPDATES, int *)
/*! @} - end defgroup vp8_encoder */
#include "vpx_codec_impl_bottom.h"

View File

@@ -60,6 +60,8 @@ enum vp8_dec_control_id
*/
VP8D_GET_LAST_REF_USED,
VP8D_GET_MODE_INFO,
VP8_DECODER_CTRL_ID_MAX
} ;
@@ -75,6 +77,7 @@ enum vp8_dec_control_id
VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_UPDATES, int *)
VPX_CTRL_USE_TYPE(VP8D_GET_FRAME_CORRUPTED, int *)
VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED, int *)
VPX_CTRL_USE_TYPE(VP8D_GET_MODE_INFO, vpx_fixed_buf_t **)
/*! @} - end defgroup vp8_decoder */

View File

@@ -134,6 +134,17 @@ extern "C" {
vpx_codec_err_t;
/*!\brief Generic fixed size buffer structure
*
* This structure is able to hold a reference to any fixed size buffer.
*/
typedef struct vpx_fixed_buf
{
void *buf; /**< Pointer to the data */
size_t sz; /**< Length of the buffer, in chars */
} vpx_fixed_buf_t; /**< alias for struct vpx_fixed_buf */
/*! \brief Codec capabilities bitfield
*
* Each codec advertises the capabilities it supports as part of its

View File

@@ -77,17 +77,6 @@ extern "C" {
partition at a time. */
/*!\brief Generic fixed size buffer structure
*
* This structure is able to hold a reference to any fixed size buffer.
*/
typedef struct vpx_fixed_buf
{
void *buf; /**< Pointer to the data */
size_t sz; /**< Length of the buffer, in chars */
} vpx_fixed_buf_t; /**< alias for struct vpx_fixed_buf */
/*!\brief Time Stamp Type
*
* An integer, which when multiplied by the stream's time base, provides

474
vpxenc.c
View File

@@ -39,6 +39,10 @@
#include "y4minput.h"
#include "libmkv/EbmlWriter.h"
#include "libmkv/EbmlIDs.h"
#include "third_party/libyuv/include/libyuv/scale.h"
#include "nestegg/include/nestegg/nestegg.h"
#include "vpx/vpx_decoder.h"
#include "vpx/vp8dx.h"
/* Need special handling of these functions on Windows */
#if defined(_MSC_VER)
@@ -289,7 +293,8 @@ enum video_file_type
{
FILE_TYPE_RAW,
FILE_TYPE_IVF,
FILE_TYPE_Y4M
FILE_TYPE_Y4M,
FILE_TYPE_WEBM
};
struct detect_buffer {
@@ -299,6 +304,151 @@ struct detect_buffer {
};
struct webm_ctx
{
FILE *infile;
nestegg *nestegg_ctx;
nestegg_packet *pkt;
unsigned int chunk;
unsigned int chunks;
unsigned int video_track;
vpx_codec_ctx_t decoder;
unsigned char *buf;
size_t buf_sz;
};
static int
nestegg_read_cb(void *buffer, size_t length, void *userdata)
{
FILE *f = userdata;
if(fread(buffer, 1, length, f) < length)
{
if (ferror(f))
return -1;
if (feof(f))
return 0;
}
return 1;
}
static int
nestegg_seek_cb(int64_t offset, int whence, void * userdata)
{
switch(whence) {
case NESTEGG_SEEK_SET: whence = SEEK_SET; break;
case NESTEGG_SEEK_CUR: whence = SEEK_CUR; break;
case NESTEGG_SEEK_END: whence = SEEK_END; break;
};
return fseek(userdata, offset, whence)? -1 : 0;
}
static int64_t
nestegg_tell_cb(void * userdata)
{
return ftell(userdata);
}
static int
webm_guess_framerate(struct webm_ctx *input,
unsigned int *fps_den,
unsigned int *fps_num)
{
unsigned int i;
uint64_t tstamp=0;
/* Guess the framerate. Read up to 1 second, or 50 video packets,
* whichever comes first.
*/
for(i=0; tstamp < 1000000000 && i < 50;)
{
nestegg_packet * pkt;
unsigned int track;
if(nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0)
break;
nestegg_packet_track(pkt, &track);
if(track == input->video_track)
{
nestegg_packet_tstamp(pkt, &tstamp);
i++;
}
nestegg_free_packet(pkt);
}
if(nestegg_track_seek(input->nestegg_ctx, input->video_track, 0))
goto fail;
*fps_num = (i - 1) * 1000000;
*fps_den = tstamp / 1000;
return 0;
fail:
nestegg_destroy(input->nestegg_ctx);
input->nestegg_ctx = NULL;
rewind(input->infile);
return 1;
}
static int
file_is_webm(struct webm_ctx *input,
unsigned int *width,
unsigned int *height,
unsigned int *fps_den,
unsigned int *fps_num)
{
unsigned int i, n;
int track_type = -1;
nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb,
input->infile};
nestegg_video_params params;
if(nestegg_init(&input->nestegg_ctx, io, NULL))
goto fail;
if(nestegg_track_count(input->nestegg_ctx, &n))
goto fail;
for(i=0; i<n; i++)
{
track_type = nestegg_track_type(input->nestegg_ctx, i);
if(track_type == NESTEGG_TRACK_VIDEO)
break;
else if(track_type < 0)
goto fail;
}
if(nestegg_track_codec_id(input->nestegg_ctx, i) != NESTEGG_CODEC_VP8)
{
fprintf(stderr, "Not VP8 video, quitting.\n");
exit(1);
}
input->video_track = i;
if(nestegg_track_video_params(input->nestegg_ctx, i, &params))
goto fail;
if(webm_guess_framerate(input, fps_den, fps_num))
goto fail;
*width = params.width;
*height = params.height;
return 1;
fail:
input->nestegg_ctx = NULL;
rewind(input->infile);
return 0;
}
struct input_state
{
char *fn;
@@ -310,6 +460,7 @@ struct input_state
unsigned int h;
struct vpx_rational framerate;
int use_i420;
struct webm_ctx webm;
};
@@ -323,6 +474,53 @@ static int read_frame(struct input_state *input, vpx_image_t *img)
int plane = 0;
int shortread = 0;
if (file_type == FILE_TYPE_WEBM)
{
struct webm_ctx *webm = &input->webm;
unsigned int p,r;
vpx_image_t *src;
vpx_codec_iter_t iter = NULL;
if(webm->chunk >= webm->chunks)
{
unsigned int track;
do
{
/* End of this packet, get another. */
if(webm->pkt)
nestegg_free_packet(webm->pkt);
if(nestegg_read_packet(webm->nestegg_ctx, &webm->pkt) <= 0
|| nestegg_packet_track(webm->pkt, &track))
return 0;
} while(track != webm->video_track);
if(nestegg_packet_count(webm->pkt, &webm->chunks))
return 0;
webm->chunk = 0;
}
if(nestegg_packet_data(webm->pkt, webm->chunk,
&webm->buf, &webm->buf_sz))
return 0;
webm->chunk++;
if (vpx_codec_decode(&webm->decoder, webm->buf, webm->buf_sz, NULL, 0))
fatal("decode failed");
if ((src = vpx_codec_get_frame(&webm->decoder, &iter)))
for(p=0; p<3; p++)
for(r=0; r<img->d_h >> (p>0); r++)
memcpy(img->planes[p] + r * img->stride[p],
src->planes[p] + r * src->stride[p],
img->d_w >> (p>0));
return !!src;
}
else
if (file_type == FILE_TYPE_Y4M)
{
if (y4m_input_fetch_frame(y4m, f, img) < 1)
@@ -984,12 +1182,17 @@ static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1,
"Show quantizer histogram (n-buckets)");
static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1,
"Show rate histogram (n-buckets)");
static const arg_def_t read_modemv_arg = ARG_DEF(NULL, "read-modemv", 1,
"Read modes/mvs");
static const arg_def_t write_modemv_arg = ARG_DEF(NULL, "write-modemv", 0,
"Write modes/mvs");
static const arg_def_t *main_args[] =
{
&debugmode,
&outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &deadline,
&best_dl, &good_dl, &rt_dl,
&verbosearg, &psnrarg, &use_ivf, &q_hist_n, &rate_hist_n,
&read_modemv_arg, &write_modemv_arg,
NULL
};
@@ -1495,6 +1698,9 @@ struct global_config
int debug;
int show_q_hist_buckets;
int show_rate_hist_buckets;
int read_modemv;
int write_modemv;
const char *modemv_file;
};
@@ -1530,6 +1736,7 @@ struct stream_state
uint64_t cx_time;
size_t nbytes;
stats_io_t stats;
struct vpx_image *img;
};
@@ -1609,6 +1816,13 @@ static void parse_global_config(struct global_config *global, char **argv)
global->show_q_hist_buckets = arg_parse_uint(&arg);
else if (arg_match(&arg, &rate_hist_n, argi))
global->show_rate_hist_buckets = arg_parse_uint(&arg);
else if (arg_match(&arg, &read_modemv_arg, argi))
{
global->read_modemv = 1;
global->modemv_file = arg.val;
}
else if (arg_match(&arg, &write_modemv_arg, argi))
global->write_modemv = 1;
else
argj++;
}
@@ -1639,6 +1853,21 @@ void open_input_file(struct input_state *input)
if (!input->file)
fatal("Failed to open input file");
if(strstr(input->fn, ".webm"))
{
input->webm.infile = input->file;
input->file_type = FILE_TYPE_WEBM;
if(!file_is_webm(&input->webm,
&input->w, &input->h,
&input->framerate.den,
&input->framerate.num))
fatal("Couldn't open webm file");
if (vpx_codec_dec_init(&input->webm.decoder,
&vpx_codec_vp8_dx_algo, NULL, 0))
fatal("Couldn't init decoder");
return;
}
/* For RAW input sources, these bytes will applied on the first frame
* in read_frame().
*/
@@ -1943,11 +2172,17 @@ static void set_stream_dimensions(struct stream_state *stream,
unsigned int w,
unsigned int h)
{
if ((stream->config.cfg.g_w && stream->config.cfg.g_w != w)
||(stream->config.cfg.g_h && stream->config.cfg.g_h != h))
fatal("Stream %d: Resizing not yet supported", stream->index);
stream->config.cfg.g_w = w;
stream->config.cfg.g_h = h;
if(!stream->config.cfg.g_w)
{
if(!stream->config.cfg.g_h)
stream->config.cfg.g_w = w;
else
stream->config.cfg.g_w = w * stream->config.cfg.g_h / h;
}
if(!stream->config.cfg.g_h)
{
stream->config.cfg.g_h = h * stream->config.cfg.g_w / w;
}
}
@@ -2117,6 +2352,26 @@ static void encode_frame(struct stream_state *stream,
next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in)
* global->framerate.den)
/ cfg->g_timebase.num / global->framerate.num;
/* Scale if necessary */
if(img && (img->d_w != cfg->g_w || img->d_h != cfg->g_h))
{
if(!stream->img)
stream->img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420,
cfg->g_w, cfg->g_h, 16);
I420Scale(img->planes[PLANE_Y], img->stride[PLANE_Y],
img->planes[PLANE_U], img->stride[PLANE_U],
img->planes[PLANE_V], img->stride[PLANE_V],
img->d_w, img->d_h,
stream->img->planes[PLANE_Y], stream->img->stride[PLANE_Y],
stream->img->planes[PLANE_U], stream->img->stride[PLANE_U],
stream->img->planes[PLANE_V], stream->img->stride[PLANE_V],
stream->img->d_w, stream->img->d_h,
kFilterBox);
img = stream->img;
}
vpx_usec_timer_start(&timer);
vpx_codec_encode(&stream->encoder, img, frame_start,
next_frame_start - frame_start,
@@ -2211,6 +2466,128 @@ static void get_cx_data(struct stream_state *stream,
}
struct link_record
{
uint32_t sz;
uint16_t w;
uint16_t h;
int refs_updated;
};
static void
write_multistream_file(struct stream_state *streams,
struct global_config *global,
int *got_data)
{
const vpx_codec_cx_pkt_t *pkt;
vpx_codec_cx_pkt_t outpkt = {0};
int newsz;
FOREACH_STREAM({
vpx_codec_iter_t iter = NULL;
const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg;
struct link_record link = {0};
vpx_codec_control(&stream->encoder, VP8E_GET_LAST_REF_UPDATES, &link.refs_updated);
ctx_exit_on_error(&stream->encoder, "Failed to get refs");
while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter)))
{
*got_data = 1;
switch (pkt->kind)
{
case VPX_CODEC_CX_FRAME_PKT:
stream->frames_out++;
fprintf(stderr, " %6luF",
(unsigned long)pkt->data.frame.sz);
update_rate_histogram(&stream->rate_hist, cfg, pkt);
stream->nbytes += pkt->data.raw.sz;
if(stream == streams)
{
outpkt = *pkt;
outpkt.data.raw.buf = malloc(outpkt.data.raw.sz);
memcpy(outpkt.data.raw.buf, pkt->data.raw.buf, pkt->data.raw.sz);
}
break;
case VPX_CODEC_STATS_PKT:
stream->frames_out++;
fprintf(stderr, " %6luS",
(unsigned long)pkt->data.twopass_stats.sz);
stats_write(&stream->stats,
pkt->data.twopass_stats.buf,
pkt->data.twopass_stats.sz);
stream->nbytes += pkt->data.raw.sz;
break;
case VPX_CODEC_PSNR_PKT:
if (global->show_psnr)
{
int i;
stream->psnr_sse_total += pkt->data.psnr.sse[0];
stream->psnr_samples_total += pkt->data.psnr.samples[0];
for (i = 0; i < 4; i++)
{
fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]);
stream->psnr_totals[i] += pkt->data.psnr.psnr[i];
}
stream->psnr_count++;
}
break;
default:
/* Append other data packets to outpkt */
newsz = outpkt.data.raw.sz + pkt->data.raw.sz;
outpkt.data.raw.buf = realloc(outpkt.data.raw.buf, newsz);
memcpy((char*)outpkt.data.raw.buf + outpkt.data.raw.sz,
pkt->data.raw.buf, pkt->data.raw.sz);
outpkt.data.raw.sz = newsz;
link.sz += pkt->data.raw.sz;
break;
}
}
if(link.sz)
{
link.w = cfg->g_w;
link.h = cfg->g_h;
link.sz |= (stream == streams)?0:(1<<31);
newsz = outpkt.data.raw.sz + sizeof(link);
outpkt.data.raw.buf = realloc(outpkt.data.raw.buf, newsz);
memcpy((char*)outpkt.data.raw.buf + outpkt.data.raw.sz,
&link, sizeof(link));
outpkt.data.raw.sz = newsz;
}
});
if(outpkt.data.raw.sz)
{
const struct vpx_codec_enc_cfg *cfg = &streams->config.cfg;
struct stream_state *stream = streams;
const vpx_codec_cx_pkt_t *pkt = &outpkt;
if(stream->config.write_webm)
{
/* Update the hash */
if(!stream->ebml.debug)
stream->hash = murmur(pkt->data.frame.buf,
pkt->data.frame.sz, stream->hash);
write_webm_block(&streams->ebml, cfg, pkt);
}
else
{
write_ivf_frame_header(stream->file, pkt);
if(fwrite(pkt->data.frame.buf, 1,
pkt->data.frame.sz, stream->file));
}
free(outpkt.data.raw.buf);
}
}
static void show_psnr(struct stream_state *stream)
{
int i;
@@ -2238,13 +2615,71 @@ float usec_to_fps(uint64_t usec, unsigned int frames)
}
static void set_modeinfo(struct stream_state *stream,
struct input_state *input)
{
struct webm_ctx *webm = &input->webm;
unsigned char *ptr;
struct link_record link;
int again;
int refs=0;
int mi_set = 0;
vpx_codec_control(&stream->encoder, VP8E_SET_MODEINFO, NULL);
ptr = webm->buf + webm->buf_sz;
do
{
ptr -= sizeof(link);
memcpy(&link, ptr, sizeof(link));
again = link.sz >> 31;
link.sz &= ~(1<<31);
ptr -= link.sz;
if(link.w == stream->config.cfg.g_w
&& link.h == stream->config.cfg.g_h)
{
vpx_fixed_buf_t modeinfo;
modeinfo.buf = ptr;
modeinfo.sz = link.sz;
vpx_codec_control(&stream->encoder, VP8E_SET_MODEINFO, &modeinfo);
vpx_codec_control(&stream->encoder, VP8E_UPD_REFERENCE, link.refs_updated);
ctx_exit_on_error(&stream->encoder, "Failed to set refs");
mi_set = 1;
break;
}
if((link.w|link.sz)&0xF)
break;
if(link.w > 16383 || link.h > 16383)
break;
} while(again);
if(!mi_set
&& stream->config.cfg.g_w == input->w
&& stream->config.cfg.g_h == input->h)
{
vpx_fixed_buf_t *modeinfo;
int refs_updated;
vpx_codec_control(&webm->decoder, VP8D_GET_MODE_INFO, &modeinfo);
ctx_exit_on_error(&webm->decoder, "Failed to get mode info");
vpx_codec_control(&stream->encoder, VP8E_SET_MODEINFO, modeinfo);
ctx_exit_on_error(&webm->decoder, "Failed to set mode info");
vpx_codec_control(&webm->decoder, VP8D_GET_LAST_REF_UPDATES, &refs_updated);
ctx_exit_on_error(&webm->decoder, "Failed to get ref updates");
vpx_codec_control(&stream->encoder, VP8E_UPD_REFERENCE, refs_updated);
ctx_exit_on_error(&stream->encoder, "Failed to set ref updates");
}
}
int main(int argc, const char **argv_)
{
int pass;
vpx_image_t raw;
vpx_image_t raw, junk;
int frame_avail, got_data;
struct input_state input = {0};
struct input_state modemv_input = {0};
struct global_config global;
struct stream_state *streams = NULL;
char **argv, **argi;
@@ -2300,6 +2735,12 @@ int main(int argc, const char **argv_)
int frames_in = 0;
open_input_file(&input);
if(global.read_modemv)
{
modemv_input = input;
modemv_input.fn = global.modemv_file;
open_input_file(&modemv_input);
}
/* If the input file doesn't specify its w/h (raw files), try to get
* the data from the first stream's configuration.
@@ -2315,6 +2756,9 @@ int main(int argc, const char **argv_)
});
/* Update stream configurations from the input file's parameters */
if(!input.w || !input.h)
fatal("Specify stream dimensions with --width (-w) "
" and --height (-h)");
FOREACH_STREAM(set_stream_dimensions(stream, input.w, input.h));
FOREACH_STREAM(validate_stream_config(stream));
@@ -2356,6 +2800,11 @@ int main(int argc, const char **argv_)
&global.framerate));
}
if(global.read_modemv)
vpx_img_alloc(&junk,
input.use_i420 ? VPX_IMG_FMT_I420
: VPX_IMG_FMT_YV12,
input.w, input.h, 1);
FOREACH_STREAM(open_output_file(stream, &global));
FOREACH_STREAM(setup_pass(stream, &global, pass));
FOREACH_STREAM(initialize_encoder(stream, &global));
@@ -2370,6 +2819,8 @@ int main(int argc, const char **argv_)
if (!global.limit || frames_in < global.limit)
{
frame_avail = read_frame(&input, &raw);
if(global.read_modemv)
read_frame(&modemv_input, &junk);
if (frame_avail)
frames_in++;
@@ -2391,6 +2842,10 @@ int main(int argc, const char **argv_)
else
frame_avail = 0;
/* Update mode/mv info if available */
if(modemv_input.file_type == FILE_TYPE_WEBM && global.read_modemv)
FOREACH_STREAM(set_modeinfo(stream, &modemv_input));
vpx_usec_timer_start(&timer);
FOREACH_STREAM(encode_frame(stream, &global,
frame_avail ? &raw : NULL,
@@ -2401,7 +2856,10 @@ int main(int argc, const char **argv_)
FOREACH_STREAM(update_quantizer_histogram(stream));
got_data = 0;
FOREACH_STREAM(get_cx_data(stream, &global, &got_data));
if(global.write_modemv)
write_multistream_file(streams, &global, &got_data);
else
FOREACH_STREAM(get_cx_data(stream, &global, &got_data));
fflush(stdout);
}