/* * Copyright (c) 2012 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 "vp8/common/onyxc_int.h" #define MAX_REGIONS 24000 #ifndef NULL #define NULL 0 #endif #define min_mbs_in_region 3 // this linked list structure holds equivalences for connected // component labeling struct list_el { int label; int seg_value; int count; struct list_el * next; }; typedef struct list_el item; // connected colorsegments typedef struct { int min_x; int min_y; int max_x; int max_y; long long sum_x; long long sum_y; int pixels; int seg_value; int label; } segment_info; typedef enum { SEGMENT_MODE, SEGMENT_MV, SEGMENT_REFFRAME, SEGMENT_SKIPPED } SEGMENT_TYPE; // this merges the two equivalence lists and // then makes sure that every label points to the same // equivalence list void merge ( item *labels, int u, int v ) { item *a = labels[u].next; item *b = labels[v].next; item c; item *it = &c; int count; // check if they are already merged if(u==v || a==b) return; count = a->count + b->count; // merge 2 sorted linked lists. while ( a != NULL && b != NULL ) { if ( a->label < b->label) { it->next = a; a = a->next; } else { it->next = b; b = b->next; } it = it->next; } if ( a == NULL ) it->next = b; else it->next = a; it = c.next; // make sure every equivalence in the linked list points to this new ll while( it != NULL) { labels[it->label].next = c.next; it=it->next; } c.next->count = count; } void segment_via_mode_info( VP8_COMMON *oci, int how) { MODE_INFO *mi = oci->mi; int i,j; int mb_index = 0; int label=1; int pitch = oci->mb_cols; // holds linked list equivalences // the max should probably be allocated at a higher level in oci item equivalences[MAX_REGIONS]; int eq_ptr = 0; item labels[MAX_REGIONS]; segment_info segments[MAX_REGIONS]; int label_count = 1; int labeling[400*300]; int *lp = labeling; label_count = 1; memset(labels,0,sizeof(labels)); memset(segments,0,sizeof(segments)); /* Go through each macroblock first pass labelling */ for (i = 0; i < oci->mb_rows; i++,lp+=pitch) { for (j = 0; j < oci->mb_cols; j++) { // int above seg_value, left seg_value, this seg_value... int a=-1,l=-1,n=-1; // above label, left label int al=-1,ll=-1; if(i) { al=lp[j-pitch]; a = labels[al].next->seg_value; } if(j) { ll=lp[j-1]; l = labels[ll].next->seg_value; } // what setting are we going to do the implicit segmentation on switch (how) { case SEGMENT_MODE: n= mi[mb_index].mbmi.mode; break; case SEGMENT_MV: n = mi[mb_index].mbmi.mv.as_int; if(mi[mb_index].mbmi.ref_frame == INTRA_FRAME) n=-9999999; break; case SEGMENT_REFFRAME: n = mi[mb_index].mbmi.ref_frame; break; case SEGMENT_SKIPPED: n = mi[mb_index].mbmi.mb_skip_coeff; break; } // above and left both have the same seg_value if(n==a&&n==l) { // pick the lowest label lp[j] = (alcount++; // merge the above and left equivalencies merge( labels, al, ll ); } // this matches above seg_value else if(n==a) { // give it the same label as above lp[j]=al; labels[al].next->count++; } // this matches left seg_value else if(n==l) { // give it the same label as above lp[j]=ll; labels[ll].next->count++; } else { // new label doesn't match either item *e = &labels[label]; item *nl = &equivalences[eq_ptr++]; lp[j]=label; nl->label = label; nl->next = 0; nl->seg_value = n; nl->count = 1; e->next = nl; label++; } mb_index++; } mb_index++; } lp = labeling; // give new labels to regions for(i=1;icount >min_mbs_in_region && labels[labels[i].next->label].label == 0 ) { segment_info *cs= &segments[label_count]; cs->label = label_count; labels[labels[i].next->label].label = label_count++; labels[labels[i].next->label].seg_value = labels[i].next->seg_value; cs->seg_value = labels[labels[i].next->label].seg_value; cs->min_x = oci->mb_cols; cs->min_y = oci->mb_rows; cs->max_x = 0; cs->max_y = 0; cs->sum_x = 0; cs->sum_y = 0; cs->pixels= 0; } lp = labeling; // this is just to gather stats... for(i=0;imb_rows;i++,lp+=pitch) { for(j=0;jmb_cols;j++) { segment_info *cs; int oldlab = labels[lp[j]].next->label; int lab = labels[oldlab].label; lp[j] = lab; cs= &segments[lab]; cs->min_x = (jmin_x?j:cs->min_x); cs->max_x = (j>cs->max_x?j:cs->max_x); cs->min_y = (imin_y?i:cs->min_y); cs->max_y = (i>cs->max_y?i:cs->max_y); cs->sum_x += j; cs->sum_y += i; cs->pixels ++; lp[j] = lab; mb_index++; } mb_index++; } { lp = labeling; printf("labelling \n"); mb_index = 0; for(i=0;imb_rows;i++,lp+=pitch) { for(j=0;jmb_cols;j++) { printf("%4d",lp[j]); } printf(" "); for(j=0;jmb_cols;j++,mb_index++) { //printf("%3d",mi[mb_index].mbmi.mode ); printf("%4d:%4d",mi[mb_index].mbmi.mv.as_mv.row,mi[mb_index].mbmi.mv.as_mv.col ); } printf("\n"); ++mb_index; } printf("\n"); } }