// If this block is labeled for refresh, check if we should reset the
// segment_id.
- if (mbmi->segment_id != CR_SEGMENT_ID_BASE)
+ if (cyclic_refresh_segment_id_boosted(mbmi->segment_id))
mbmi->segment_id = refresh_this_block;
// Update the cyclic refresh map, to be used for setting segmentation map
// for the next frame. If the block will be refreshed this frame, mark it
// as clean. The magnitude of the -ve influences how long before we consider
// it for refresh again.
- if (mbmi->segment_id != CR_SEGMENT_ID_BASE) {
+ if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) {
new_map_value = -cr->time_for_refresh;
} else if (refresh_this_block) {
// Else if it is accepted as candidate for refresh, and has not already
int mi_row, mi_col;
cr->actual_num_seg_blocks = 0;
for (mi_row = 0; mi_row < cm->mi_rows; mi_row++)
- for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
- if (seg_map[mi_row * cm->mi_cols + mi_col] != CR_SEGMENT_ID_BASE)
- cr->actual_num_seg_blocks++;
- }
+ for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
+ if (cyclic_refresh_segment_id_boosted(
+ seg_map[mi_row * cm->mi_cols + mi_col]))
+ cr->actual_num_seg_blocks++;
+ }
}
// Set golden frame update interval, for non-svc 1 pass CBR mode.
#include "vp9/encoder/vp9_svc_layercontext.h"
#include "vp9/encoder/vp9_skin_detection.h"
+#define AM_SEGMENT_ID_INACTIVE 7
+#define AM_SEGMENT_ID_ACTIVE 0
#define SHARP_FILTER_QTHRESH 0 /* Q threshold for 8-tap sharp filter */
}
}
+// Mark all inactive blocks as active. Other segmentation features may be set
+// so memset cannot be used, instead only inactive blocks should be reset.
+void vp9_suppress_active_map(VP9_COMP *cpi) {
+ unsigned char *const seg_map = cpi->segmentation_map;
+ int i;
+ if (cpi->active_map.enabled || cpi->active_map.update)
+ for (i = 0; i < cpi->common.mi_rows * cpi->common.mi_cols; ++i)
+ if (seg_map[i] == AM_SEGMENT_ID_INACTIVE)
+ seg_map[i] = AM_SEGMENT_ID_ACTIVE;
+}
+
+void vp9_apply_active_map(VP9_COMP *cpi) {
+ struct segmentation *const seg = &cpi->common.seg;
+ unsigned char *const seg_map = cpi->segmentation_map;
+ const unsigned char *const active_map = cpi->active_map.map;
+ int i;
+
+ assert(AM_SEGMENT_ID_ACTIVE == CR_SEGMENT_ID_BASE);
+
+ if (cpi->active_map.update) {
+ if (cpi->active_map.enabled) {
+ for (i = 0; i < cpi->common.mi_rows * cpi->common.mi_cols; ++i)
+ if (seg_map[i] == AM_SEGMENT_ID_ACTIVE) seg_map[i] = active_map[i];
+ vp9_enable_segmentation(seg);
+ vp9_enable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_SKIP);
+ } else {
+ vp9_disable_segfeature(seg, AM_SEGMENT_ID_INACTIVE, SEG_LVL_SKIP);
+ if (seg->enabled) {
+ seg->update_data = 1;
+ seg->update_map = 1;
+ }
+ }
+ cpi->active_map.update = 0;
+ }
+}
+
+int vp9_set_active_map(VP9_COMP* cpi,
+ unsigned char* new_map_16x16,
+ int rows,
+ int cols) {
+ if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) {
+ unsigned char *const active_map_8x8 = cpi->active_map.map;
+ const int mi_rows = cpi->common.mi_rows;
+ const int mi_cols = cpi->common.mi_cols;
+ cpi->active_map.update = 1;
+ if (new_map_16x16) {
+ int r, c;
+ for (r = 0; r < mi_rows; ++r) {
+ for (c = 0; c < mi_cols; ++c) {
+ active_map_8x8[r * mi_cols + c] =
+ new_map_16x16[(r >> 1) * cols + (c >> 1)]
+ ? AM_SEGMENT_ID_ACTIVE
+ : AM_SEGMENT_ID_INACTIVE;
+ }
+ }
+ cpi->active_map.enabled = 1;
+ } else {
+ cpi->active_map.enabled = 0;
+ }
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
void vp9_set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv) {
MACROBLOCK *const mb = &cpi->td.mb;
cpi->common.allow_high_precision_mv = allow_high_precision_mv;
vp9_cyclic_refresh_free(cpi->cyclic_refresh);
cpi->cyclic_refresh = NULL;
+ vpx_free(cpi->active_map.map);
+ cpi->active_map.map = NULL;
+
vp9_free_ref_frame_buffers(cm);
vp9_free_context_buffers(cm);
cpi->partition_search_skippable_frame = 0;
cpi->tile_data = NULL;
+ // TODO(aconverse): Realloc these tables on frame resize
// Create the encoder segmentation map and set all entries to 0
CHECK_MEM_ERROR(cm, cpi->segmentation_map,
vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
CHECK_MEM_ERROR(cm, cpi->cyclic_refresh,
vp9_cyclic_refresh_alloc(cm->mi_rows, cm->mi_cols));
+ CHECK_MEM_ERROR(cm, cpi->active_map.map,
+ vpx_calloc(cm->mi_rows * cm->mi_cols, 1));
+
// And a place holder structure is the coding context
// for use if we want to save and restore it
CHECK_MEM_ERROR(cm, cpi->coding_context.last_frame_seg_map_copy,
setup_frame(cpi);
+ vp9_suppress_active_map(cpi);
// Variance adaptive and in frame q adjustment experiments are mutually
// exclusive.
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
} else if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
vp9_cyclic_refresh_setup(cpi);
}
+ vp9_apply_active_map(cpi);
+
// transform / motion compensation build reconstruction frame
vp9_encode_frame(cpi);
}
}
-int vp9_set_active_map(VP9_COMP *cpi, unsigned char *map, int rows, int cols) {
- if (rows == cpi->common.mb_rows && cols == cpi->common.mb_cols) {
- const int mi_rows = cpi->common.mi_rows;
- const int mi_cols = cpi->common.mi_cols;
- if (map) {
- int r, c;
- for (r = 0; r < mi_rows; r++) {
- for (c = 0; c < mi_cols; c++) {
- cpi->segmentation_map[r * mi_cols + c] =
- !map[(r >> 1) * cols + (c >> 1)];
- }
- }
- vp9_enable_segfeature(&cpi->common.seg, 1, SEG_LVL_SKIP);
- vp9_enable_segmentation(&cpi->common.seg);
- } else {
- vp9_disable_segmentation(&cpi->common.seg);
- }
- return 0;
- } else {
- return -1;
- }
-}
-
int vp9_set_internal_size(VP9_COMP *cpi,
VPX_SCALING horiz_mode, VPX_SCALING vert_mode) {
VP9_COMMON *cm = &cpi->common;