#include "vp8/common/blockd.h"
#include "onyx_int.h"
#include "vp8/common/systemdependent.h"
+#include "vp8/common/skin_detection.h"
#include "vp8/encoder/quantize.h"
#include "vp8/common/alloccommon.h"
#include "mcomp.h"
#include "vp8/common/reconintra.h"
#include "vp8/common/swapyv12buffer.h"
#include "vp8/common/threading.h"
+#include "vpx_ports/system_state.h"
#include "vpx_ports/vpx_timer.h"
#if ARCH_ARM
#include "vpx_ports/arm.h"
#endif
#include "encodeframe.h"
+#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <limits.h>
#ifdef OUTPUT_YUV_DENOISED
FILE *yuv_denoised_file;
#endif
+#ifdef OUTPUT_YUV_SKINMAP
+FILE *yuv_skinmap_file = NULL;
+#endif
#if 0
FILE *framepsnr;
SPEED_FEATURES *sf = &cpi->sf;
int Mode = cpi->compressor_speed;
int Speed = cpi->Speed;
+ int Speed2;
int i;
VP8_COMMON *cm = &cpi->common;
int last_improved_quant = sf->improved_quant;
cpi->mode_check_freq[THR_V_PRED] = cpi->mode_check_freq[THR_H_PRED] =
cpi->mode_check_freq[THR_B_PRED] =
speed_map(Speed, mode_check_freq_map_vhbpred);
- cpi->mode_check_freq[THR_NEW1] = speed_map(Speed, mode_check_freq_map_new1);
+
+ // For real-time mode at speed 10 keep the mode_check_freq threshold
+ // for NEW1 similar to that of speed 9.
+ Speed2 = Speed;
+ if (cpi->Speed == 10 && Mode == 2) Speed2 = RT(9);
+ cpi->mode_check_freq[THR_NEW1] = speed_map(Speed2, mode_check_freq_map_new1);
+
cpi->mode_check_freq[THR_NEW2] = cpi->mode_check_freq[THR_NEW3] =
speed_map(Speed, mode_check_freq_map_new2);
+
cpi->mode_check_freq[THR_SPLIT1] =
speed_map(Speed, mode_check_freq_map_split1);
cpi->mode_check_freq[THR_SPLIT2] = cpi->mode_check_freq[THR_SPLIT3] =
cpi->baseline_gf_interval =
cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL;
+ // GF behavior for 1 pass CBR, used when error_resilience is off.
+ if (!cpi->oxcf.error_resilient_mode &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
+ cpi->oxcf.Mode == MODE_REALTIME)
+ cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
+
#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
cpi->oxcf.token_partitions = 3;
#endif
cm->sharpness_level = cpi->oxcf.Sharpness;
if (cm->horiz_scale != NORMAL || cm->vert_scale != NORMAL) {
- int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs);
- int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs);
+ int hr, hs, vr, vs;
Scale2Ratio(cm->horiz_scale, &hr, &hs);
Scale2Ratio(cm->vert_scale, &vr, &vs);
cpi->mse_source_denoised = 0;
/* Should we use the cyclic refresh method.
- * Currently this is tied to error resilliant mode
+ * Currently there is no external control for this.
+ * Enable it for error_resilient_mode, or for 1 pass CBR mode.
*/
- cpi->cyclic_refresh_mode_enabled = cpi->oxcf.error_resilient_mode;
+ cpi->cyclic_refresh_mode_enabled =
+ (cpi->oxcf.error_resilient_mode ||
+ (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
+ cpi->oxcf.Mode <= 2));
cpi->cyclic_refresh_mode_max_mbs_perframe =
(cpi->common.mb_rows * cpi->common.mb_cols) / 7;
if (cpi->oxcf.number_of_layers == 1) {
cpi->cyclic_refresh_mode_index = 0;
cpi->cyclic_refresh_q = 32;
+ // GF behavior for 1 pass CBR, used when error_resilience is off.
+ cpi->gf_update_onepass_cbr = 0;
+ cpi->gf_noboost_onepass_cbr = 0;
+ if (!cpi->oxcf.error_resilient_mode &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER && cpi->oxcf.Mode <= 2) {
+ cpi->gf_update_onepass_cbr = 1;
+ cpi->gf_noboost_onepass_cbr = 1;
+ cpi->gf_interval_onepass_cbr =
+ cpi->cyclic_refresh_mode_max_mbs_perframe > 0
+ ? (2 * (cpi->common.mb_rows * cpi->common.mb_cols) /
+ cpi->cyclic_refresh_mode_max_mbs_perframe)
+ : 10;
+ cpi->gf_interval_onepass_cbr =
+ VPXMIN(40, VPXMAX(6, cpi->gf_interval_onepass_cbr));
+ cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
+ }
+
if (cpi->cyclic_refresh_mode_enabled) {
CHECK_MEM_ERROR(cpi->cyclic_refresh_map,
vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1));
#ifdef OUTPUT_YUV_DENOISED
yuv_denoised_file = fopen("denoised.yuv", "ab");
#endif
+#ifdef OUTPUT_YUV_SKINMAP
+ yuv_skinmap_file = fopen("skinmap.yuv", "ab");
+#endif
#if 0
framepsnr = fopen("framepsnr.stt", "a");
cpi->fn_ptr[BLOCK_16X16].sdf = vpx_sad16x16;
cpi->fn_ptr[BLOCK_16X16].vf = vpx_variance16x16;
cpi->fn_ptr[BLOCK_16X16].svf = vpx_sub_pixel_variance16x16;
- cpi->fn_ptr[BLOCK_16X16].svf_halfpix_h = vpx_variance_halfpixvar16x16_h;
- cpi->fn_ptr[BLOCK_16X16].svf_halfpix_v = vpx_variance_halfpixvar16x16_v;
- cpi->fn_ptr[BLOCK_16X16].svf_halfpix_hv = vpx_variance_halfpixvar16x16_hv;
cpi->fn_ptr[BLOCK_16X16].sdx3f = vpx_sad16x16x3;
cpi->fn_ptr[BLOCK_16X16].sdx8f = vpx_sad16x16x8;
cpi->fn_ptr[BLOCK_16X16].sdx4df = vpx_sad16x16x4d;
cpi->fn_ptr[BLOCK_16X8].sdf = vpx_sad16x8;
cpi->fn_ptr[BLOCK_16X8].vf = vpx_variance16x8;
cpi->fn_ptr[BLOCK_16X8].svf = vpx_sub_pixel_variance16x8;
- cpi->fn_ptr[BLOCK_16X8].svf_halfpix_h = NULL;
- cpi->fn_ptr[BLOCK_16X8].svf_halfpix_v = NULL;
- cpi->fn_ptr[BLOCK_16X8].svf_halfpix_hv = NULL;
cpi->fn_ptr[BLOCK_16X8].sdx3f = vpx_sad16x8x3;
cpi->fn_ptr[BLOCK_16X8].sdx8f = vpx_sad16x8x8;
cpi->fn_ptr[BLOCK_16X8].sdx4df = vpx_sad16x8x4d;
cpi->fn_ptr[BLOCK_8X16].sdf = vpx_sad8x16;
cpi->fn_ptr[BLOCK_8X16].vf = vpx_variance8x16;
cpi->fn_ptr[BLOCK_8X16].svf = vpx_sub_pixel_variance8x16;
- cpi->fn_ptr[BLOCK_8X16].svf_halfpix_h = NULL;
- cpi->fn_ptr[BLOCK_8X16].svf_halfpix_v = NULL;
- cpi->fn_ptr[BLOCK_8X16].svf_halfpix_hv = NULL;
cpi->fn_ptr[BLOCK_8X16].sdx3f = vpx_sad8x16x3;
cpi->fn_ptr[BLOCK_8X16].sdx8f = vpx_sad8x16x8;
cpi->fn_ptr[BLOCK_8X16].sdx4df = vpx_sad8x16x4d;
cpi->fn_ptr[BLOCK_8X8].sdf = vpx_sad8x8;
cpi->fn_ptr[BLOCK_8X8].vf = vpx_variance8x8;
cpi->fn_ptr[BLOCK_8X8].svf = vpx_sub_pixel_variance8x8;
- cpi->fn_ptr[BLOCK_8X8].svf_halfpix_h = NULL;
- cpi->fn_ptr[BLOCK_8X8].svf_halfpix_v = NULL;
- cpi->fn_ptr[BLOCK_8X8].svf_halfpix_hv = NULL;
cpi->fn_ptr[BLOCK_8X8].sdx3f = vpx_sad8x8x3;
cpi->fn_ptr[BLOCK_8X8].sdx8f = vpx_sad8x8x8;
cpi->fn_ptr[BLOCK_8X8].sdx4df = vpx_sad8x8x4d;
cpi->fn_ptr[BLOCK_4X4].sdf = vpx_sad4x4;
cpi->fn_ptr[BLOCK_4X4].vf = vpx_variance4x4;
cpi->fn_ptr[BLOCK_4X4].svf = vpx_sub_pixel_variance4x4;
- cpi->fn_ptr[BLOCK_4X4].svf_halfpix_h = NULL;
- cpi->fn_ptr[BLOCK_4X4].svf_halfpix_v = NULL;
- cpi->fn_ptr[BLOCK_4X4].svf_halfpix_hv = NULL;
cpi->fn_ptr[BLOCK_4X4].sdx3f = vpx_sad4x4x3;
cpi->fn_ptr[BLOCK_4X4].sdx8f = vpx_sad4x4x8;
cpi->fn_ptr[BLOCK_4X4].sdx4df = vpx_sad4x4x4d;
double time_encoded =
(cpi->last_end_time_stamp_seen - cpi->first_time_stamp_ever) /
10000000.000;
- double total_encode_time =
- (cpi->time_receive_data + cpi->time_compress_data) / 1000.000;
double dr = (double)cpi->bytes * 8.0 / 1000.0 / time_encoded;
- const double target_rate = (double)cpi->oxcf.target_bandwidth / 1000;
- const double rate_err = ((100.0 * (dr - target_rate)) / target_rate);
if (cpi->b_calculate_psnr) {
if (cpi->oxcf.number_of_layers > 1) {
fprintf(f,
"Layer\tBitrate\tAVGPsnr\tGLBPsnr\tAVPsnrP\t"
- "GLPsnrP\tVPXSSIM\t\n");
+ "GLPsnrP\tVPXSSIM\n");
for (i = 0; i < (int)cpi->oxcf.number_of_layers; ++i) {
double dr =
(double)cpi->bytes_in_layer[i] * 8.0 / 1000.0 / time_encoded;
fprintf(f,
"Bitrate\tAVGPsnr\tGLBPsnr\tAVPsnrP\t"
- "GLPsnrP\tVPXSSIM\t Time(us) Rc-Err "
- "Abs Err\n");
+ "GLPsnrP\tVPXSSIM\n");
fprintf(f,
"%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t"
- "%7.3f\t%8.0f %7.2f %7.2f\n",
+ "%7.3f\n",
dr, cpi->total / cpi->count, total_psnr,
- cpi->totalp / cpi->count, total_psnr2, total_ssim,
- total_encode_time, rate_err, fabs(rate_err));
+ cpi->totalp / cpi->count, total_psnr2, total_ssim);
}
}
fclose(f);
#ifdef OUTPUT_YUV_DENOISED
fclose(yuv_denoised_file);
#endif
+#ifdef OUTPUT_YUV_SKINMAP
+ fclose(yuv_skinmap_file);
+#endif
#if 0
recon += recon_stride;
}
- vp8_clear_system_state();
+ vpx_clear_system_state();
return total_sse;
}
return 0;
}
-#if defined(OUTPUT_YUV_SRC) || defined(OUTPUT_YUV_DENOISED)
+#if defined(OUTPUT_YUV_SRC) || defined(OUTPUT_YUV_DENOISED) || \
+ defined(OUTPUT_YUV_SKINMAP)
void vp8_write_yuv_frame(FILE *yuv_file, YV12_BUFFER_CONFIG *s) {
unsigned char *src = s->y_buffer;
- int h = s->y_height;
+ int h = s->y_crop_height;
do {
fwrite(src, s->y_width, 1, yuv_file);
} while (--h);
src = s->u_buffer;
- h = s->uv_height;
+ h = s->uv_crop_height;
do {
fwrite(src, s->uv_width, 1, yuv_file);
} while (--h);
src = s->v_buffer;
- h = s->uv_height;
+ h = s->uv_crop_height;
do {
fwrite(src, s->uv_width, 1, yuv_file);
/* are we resizing the image */
if (cm->horiz_scale != 0 || cm->vert_scale != 0) {
#if CONFIG_SPATIAL_RESAMPLING
- int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs);
- int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs);
+ int hr, hs, vr, vs;
int tmp_height;
if (cm->vert_scale == 3) {
*/
if (cpi->oxcf.allow_spatial_resampling &&
(cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) {
- int UNINITIALIZED_IS_SAFE(hr), UNINITIALIZED_IS_SAFE(hs);
- int UNINITIALIZED_IS_SAFE(vr), UNINITIALIZED_IS_SAFE(vs);
+ int hr, hs, vr, vs;
int new_width, new_height;
/* If we are below the resample DOWN watermark then scale down a
if (cpi->Speed > 11) return 0;
/* Clear down mmx registers */
- vp8_clear_system_state();
+ vpx_clear_system_state();
if ((cpi->compressor_speed == 2) && (cpi->Speed >= 5) && (cpi->sf.RD == 0)) {
double change = 1.0 *
return code_key_frame;
}
-static void Pass1Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest,
+static void Pass1Encode(VP8_COMP *cpi, size_t *size, unsigned char *dest,
unsigned int *frame_flags) {
(void)size;
(void)dest;
}
// Only return non-zero if we have at least ~1/16 samples for estimate.
if (num_blocks > (tot_num_blocks >> 4)) {
+ assert(num_blocks != 0);
return (Total / num_blocks);
} else {
return 0;
} else {
struct vpx_usec_timer timer;
- vp8_clear_system_state();
+ vpx_clear_system_state();
vpx_usec_timer_start(&timer);
if (cpi->sf.auto_filter == 0) {
vp8_yv12_extend_frame_borders(cm->frame_to_show);
}
-static void encode_frame_to_data_rate(VP8_COMP *cpi, unsigned long *size,
+static void encode_frame_to_data_rate(VP8_COMP *cpi, size_t *size,
unsigned char *dest,
unsigned char *dest_end,
unsigned int *frame_flags) {
int drop_mark25 = drop_mark / 8;
/* Clear down mmx registers to allow floating point in what follows */
- vp8_clear_system_state();
+ vpx_clear_system_state();
if (cpi->force_next_frame_intra) {
cm->frame_type = KEY_FRAME; /* delayed intra frame */
cpi->force_next_frame_intra = 0;
}
-/* For an alt ref frame in 2 pass we skip the call to the second pass
- * function that sets the target bandwidth
- */
+ /* For an alt ref frame in 2 pass we skip the call to the second pass
+ * function that sets the target bandwidth
+ */
+ switch (cpi->pass) {
#if !CONFIG_REALTIME_ONLY
-
- if (cpi->pass == 2) {
- if (cpi->common.refresh_alt_ref_frame) {
- /* Per frame bit target for the alt ref frame */
- cpi->per_frame_bandwidth = cpi->twopass.gf_bits;
- /* per second target bitrate */
- cpi->target_bandwidth =
- (int)(cpi->twopass.gf_bits * cpi->output_framerate);
- }
- } else
-#endif
- cpi->per_frame_bandwidth =
- (int)(cpi->target_bandwidth / cpi->output_framerate);
+ case 2:
+ if (cpi->common.refresh_alt_ref_frame) {
+ /* Per frame bit target for the alt ref frame */
+ cpi->per_frame_bandwidth = cpi->twopass.gf_bits;
+ /* per second target bitrate */
+ cpi->target_bandwidth =
+ (int)(cpi->twopass.gf_bits * cpi->output_framerate);
+ }
+ break;
+#endif // !CONFIG_REALTIME_ONLY
+ default:
+ cpi->per_frame_bandwidth =
+ (int)(cpi->target_bandwidth / cpi->output_framerate);
+ break;
+ }
/* Default turn off buffer to buffer copying */
cm->copy_buffer_to_gf = 0;
* There is some odd behavior for one pass here that needs attention.
*/
if ((cpi->pass == 2) || (cpi->ni_frames > 150)) {
- vp8_clear_system_state();
+ vpx_clear_system_state();
Q = cpi->active_worst_quality;
#endif
do {
- vp8_clear_system_state();
+ vpx_clear_system_state();
vp8_set_quantizer(cpi, Q);
#else
/* transform / motion compensation build reconstruction frame */
vp8_encode_frame(cpi);
-
if (cpi->oxcf.screen_content_mode == 2) {
if (vp8_drop_encodedframe_overshoot(cpi, Q)) return;
}
cpi->projected_frame_size =
(cpi->projected_frame_size > 0) ? cpi->projected_frame_size : 0;
#endif
- vp8_clear_system_state();
+ vpx_clear_system_state();
/* Test to see if the stats generated for this frame indicate that
* we should have coded a key frame (assuming that we didn't)!
#endif
}
- vp8_clear_system_state();
+ vpx_clear_system_state();
if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1;
#if !CONFIG_REALTIME_ONLY
top_index = cpi->active_worst_quality;
#endif // !CONFIG_REALTIME_ONLY
- /* If we have updated the active max Q do not call
- * vp8_update_rate_correction_factors() this loop.
- */
+ /* If we have updated the active max Q do not call
+ * vp8_update_rate_correction_factors() this loop.
+ */
active_worst_qchanged = 1;
} else {
active_worst_qchanged = 0;
}
-#if !CONFIG_REALTIME_ONLY
+#if CONFIG_REALTIME_ONLY
+ Loop = 0;
+#else
/* Special case handling for forced key frames */
if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) {
int last_q = Q;
: cpi->mb.zbin_over_quant;
Loop = Q != last_q;
- } else
-#endif
+ } else {
Loop = 0;
+ }
+#endif // CONFIG_REALTIME_ONLY
if (cpi->is_src_frame_alt_ref) Loop = 0;
}
} while (Loop == 1);
+#if defined(DROP_UNCODED_FRAMES)
+ /* if there are no coded macroblocks at all drop this frame */
+ if (cpi->common.MBs == cpi->mb.skip_true_count &&
+ (cpi->drop_frame_count & 7) != 7 && cm->frame_type != KEY_FRAME) {
+ cpi->common.current_video_frame++;
+ cpi->frames_since_key++;
+ cpi->drop_frame_count++;
+ // We advance the temporal pattern for dropped frames.
+ cpi->temporal_pattern_counter++;
+ return;
+ }
+ cpi->drop_frame_count = 0;
+#endif
+
#if 0
/* Experimental code for lagged and one pass
* Update stats used for one pass GF selection
}
#endif
+#ifdef OUTPUT_YUV_SKINMAP
+ if (cpi->common.current_video_frame > 1) {
+ compute_skin_map(cpi, yuv_skinmap_file);
+ }
+#endif
+
#if CONFIG_MULTITHREAD
if (cpi->b_multi_threaded) {
/* start loopfilter in separate thread */
sem_post(&cpi->h_event_start_lpf);
+ cpi->b_lpf_running = 1;
} else
#endif
{
/* build the bitstream */
vp8_pack_bitstream(cpi, dest, dest_end, size);
-#if CONFIG_MULTITHREAD
- /* wait for the lpf thread done */
- if (cpi->b_multi_threaded) {
- sem_wait(&cpi->h_event_end_lpf);
- }
-#endif
-
/* Move storing frame_type out of the above loop since it is also
* needed in motion search besides loopfilter */
cm->last_frame_type = cm->frame_type;
/* Update rate control heuristics */
cpi->total_byte_count += (*size);
- cpi->projected_frame_size = (*size) << 3;
+ cpi->projected_frame_size = (int)(*size) << 3;
if (cpi->oxcf.number_of_layers > 1) {
unsigned int i;
{
FILE *f = fopen("tmp.stt", "a");
- vp8_clear_system_state();
+ vpx_clear_system_state();
if (cpi->twopass.total_left_stats.coded_error != 0.0)
fprintf(f, "%10d %10d %10d %10d %10d %10"PRId64" %10"PRId64
/* vp8_write_yuv_frame("encoder_recon.yuv", cm->frame_to_show); */
}
#if !CONFIG_REALTIME_ONLY
-static void Pass2Encode(VP8_COMP *cpi, unsigned long *size, unsigned char *dest,
+static void Pass2Encode(VP8_COMP *cpi, size_t *size, unsigned char *dest,
unsigned char *dest_end, unsigned int *frame_flags) {
if (!cpi->common.refresh_alt_ref_frame) vp8_second_pass(cpi);
}
int vp8_get_compressed_data(VP8_COMP *cpi, unsigned int *frame_flags,
- unsigned long *size, unsigned char *dest,
+ size_t *size, unsigned char *dest,
unsigned char *dest_end, int64_t *time_stamp,
int64_t *time_end, int flush) {
VP8_COMMON *cm;
if (setjmp(cpi->common.error.jmp)) {
cpi->common.error.setjmp = 0;
- vp8_clear_system_state();
+ vpx_clear_system_state();
return VPX_CODEC_CORRUPT_FRAME;
}
*size = 0;
/* Clear down mmx registers */
- vp8_clear_system_state();
+ vpx_clear_system_state();
cm->frame_type = INTER_FRAME;
cm->frame_flags = *frame_flags;
assert(i < NUM_YV12_BUFFERS);
}
+ switch (cpi->pass) {
#if !CONFIG_REALTIME_ONLY
-
- if (cpi->pass == 1) {
- Pass1Encode(cpi, size, dest, frame_flags);
- } else if (cpi->pass == 2) {
- Pass2Encode(cpi, size, dest, dest_end, frame_flags);
- } else
-#endif
- encode_frame_to_data_rate(cpi, size, dest, dest_end, frame_flags);
+ case 1: Pass1Encode(cpi, size, dest, frame_flags); break;
+ case 2: Pass2Encode(cpi, size, dest, dest_end, frame_flags); break;
+#endif // !CONFIG_REALTIME_ONLY
+ default:
+ encode_frame_to_data_rate(cpi, size, dest, dest_end, frame_flags);
+ break;
+ }
if (cpi->compressor_speed == 2) {
unsigned int duration, duration2;
vp8_deblock(cm, cm->frame_to_show, &cm->post_proc_buffer,
cm->filter_level * 10 / 6, 1, 0);
- vp8_clear_system_state();
+ vpx_clear_system_state();
ye = calc_plane_error(orig->y_buffer, orig->y_stride, pp->y_buffer,
pp->y_stride, y_width, y_height);
cpi->common.error.setjmp = 0;
+#if CONFIG_MULTITHREAD
+ /* wait for the lpf thread done */
+ if (cpi->b_multi_threaded && cpi->b_lpf_running) {
+ sem_wait(&cpi->h_event_end_lpf);
+ cpi->b_lpf_running = 0;
+ }
+#endif
+
return 0;
}
}
#endif
- vp8_clear_system_state();
+ vpx_clear_system_state();
return ret;
}
}