/******************************************************************* resize module *******************************************************************/ #define RESIZE_C #include "resize.h" #include #include #include #ifndef PI #define PI (atan(1)*4) #endif /* grobal */ FRAME *resize(FRAME *in, RESIZE_PARAMETER *prm); RESIZE_PARAMETER *create_resize_parameter(SEQUENCE_HEADER *seq, M2V_CONFIG *cfg); void release_resize_parameter(RESIZE_PARAMETER *prm); /* local */ static void setup_interpolation_parameter(int source_length, int result_length, RESIZE_PARAMETER *out); static void setup_decimation_parameter(int source_length, int result_length, RESIZE_PARAMETER *out); static double lanczos3_weight(double phase); static void setup_crop_parameter(int source_length, RESIZE_PARAMETER *r); static void component_resize(unsigned char *in, unsigned char *out, RESIZE_PARAMETER *prm); /*-----------------------------------------------------------------*/ FRAME *resize(FRAME *in, RESIZE_PARAMETER *prm) { FRAME *r; if(prm == NULL){ return in; } r = new_frame(prm->out_step, prm->height); if(r == NULL){ return NULL; } component_resize(in->y, r->y, prm); component_resize(in->u, r->u, prm); component_resize(in->v, r->v, prm); delete_frame(in); return r; } /*-----------------------------------------------------------------*/ RESIZE_PARAMETER *create_resize_parameter(SEQUENCE_HEADER *seq, M2V_CONFIG *cfg) { RESIZE_PARAMETER *r; int n; int src_width; if(cfg->aspect_ratio == M2V_CONFIG_IGNORE_ASPECT_RATIO){ return NULL; } r = (RESIZE_PARAMETER *)malloc(sizeof(RESIZE_PARAMETER)); if(r == NULL){ return NULL; } if(seq->has_sequence_display_extension){ if( (seq->sd.display_h_size == 0) || (seq->sd.display_v_size == 0) || (seq->sd.display_h_size > seq->h_size) || (seq->sd.display_v_size > seq->v_size) ) { seq->sd.display_h_size = seq->h_size; seq->sd.display_v_size = seq->v_size; } } if(seq->has_sequence_display_extension){ r->height = seq->sd.display_v_size; }else{ r->height = seq->orig_v_size; } if(seq->has_sequence_display_extension){ src_width = seq->sd.display_h_size; }else{ src_width = seq->orig_h_size; } switch(seq->aspect_ratio){ case 2: /* 4:3 */ r->width = r->height * 4 / 3; break; case 3: /* 16:9 */ r->width = r->height * 16 / 9; break; case 4: r->width = r->height * 221 / 100; break; default: r->width = src_width; } if(r->width == seq->orig_h_size){ free(r); return NULL; } r->in_step = seq->h_size; if(seq->has_sequence_display_extension){ n = (seq->orig_v_size - seq->sd.display_v_size) / 2; r->in_offset = r->in_step * n; n = (seq->orig_h_size - seq->sd.display_h_size) / 2; r->in_offset += n; }else{ r->in_offset = 0; } r->out_step = (r->width + 15) >> 4; r->out_step <<= 4; if(r->width < src_width){ setup_decimation_parameter(src_width, r->width, r); }else if(r->width == src_width){ setup_crop_parameter(src_width, r); }else{ setup_interpolation_parameter(src_width, r->width, r); } return r; } /*-----------------------------------------------------------------*/ void release_resize_parameter(RESIZE_PARAMETER *prm) { int i; if(prm == NULL){ return; } for(i=0;ilength;i++){ free(prm->weight[i]); free(prm->index[i]); } free(prm->index); free(prm->weight); free(prm); } /*-----------------------------------------------------------------*/ static void setup_interpolation_parameter(int source_length, int result_length, RESIZE_PARAMETER *out) { int i,j,n; double *work; double sum; double pos; out->length = result_length; out->index = (int **)malloc(sizeof(int *)*out->length); out->weight = (int **)malloc(sizeof(int *)*out->length); out->tap = 6; for(i=0;iweight[i] = (int *)malloc(sizeof(int)*out->tap); out->index[i] = (int *)malloc(sizeof(int)*out->tap); } work = (double *)malloc(sizeof(double)*out->tap); __asm {emms}; for(i=0;itap / 2); pos -= (out->tap / 2); sum = 0; for(j=0;jtap;j++){ if(n < 0){ out->index[i][j] = 0; }else if(n >= source_length){ out->index[i][j] = source_length-1; }else{ out->index[i][j] = n; } work[j] = lanczos3_weight(pos); sum += work[j]; pos += 1; n += 1; } for(j=0;jtap;j++){ out->weight[i][j] = (int)((work[j] / sum) * (1<<16)); } } free(work); } /*-----------------------------------------------------------------*/ static void setup_decimation_parameter(int source_length, int result_length, RESIZE_PARAMETER *out) { int i,j,n; double *work; double sum; double pos, phase; out->length = result_length; out->weight = (int **)malloc(sizeof(int *)*out->length); out->index = (int **)malloc(sizeof(int *)*out->length); out->tap = 6 * source_length / result_length; if((source_length % result_length) == 0){ out->tap -= 1; } for(i=0;iweight[i] = (int *)malloc(sizeof(int)*out->tap); out->index[i] = (int *)malloc(sizeof(int)*out->tap); } work = (double *)malloc(sizeof(double)*out->tap); for(i=0;itap / 2); sum = 0; for(j=0;jtap;j++){ phase = (n+0.5)*result_length; phase /= source_length; phase -= i; if(n < 0){ out->index[i][j] = 0; }else if(n >= source_length){ out->index[i][j] = source_length-1; }else{ out->index[i][j] = n; } work[j] = lanczos3_weight(phase); sum += work[j]; n += 1; } for(j=0;jtap;j++){ out->weight[i][j] = (int)((work[j] / sum) * (1<<16)); } } free(work); } /*-----------------------------------------------------------------*/ static double lanczos3_weight(double phase) { double ret; if(fabs(phase) < DBL_EPSILON){ return 1.0; } if(fabs(phase) >= 3.0){ return 0.0; } ret = sin(PI*phase)*sin(PI*phase/3)/(PI*PI*phase*phase/3); return ret; } /*-----------------------------------------------------------------*/ static void setup_crop_parameter(int result_length, RESIZE_PARAMETER *out) { int i; out->length = result_length; out->index = (int **)malloc(sizeof(int)*out->length); out->weight = (int **)malloc(sizeof(int *)*out->length); out->tap = 1; for(i=0;iweight[i] = (int *)malloc(sizeof(int)); out->index[i] = (int *)malloc(sizeof(int)); } for(i=0;iindex[i][0] = i; out->weight[i][0] = 1<<16; } return; } /*-----------------------------------------------------------------*/ static void component_resize(unsigned char *in, unsigned char *out, RESIZE_PARAMETER *prm) { int x,y; int i; int w; in += prm->in_offset; for(y=0;yheight;y++){ for(x=0;xwidth;x++){ w = 0; for(i=0;itap;i++){ w += in[prm->index[x][i]] * prm->weight[x][i]; } w += 32768; out[x] = uchar_clip_table[UCHAR_CLIP_TABLE_OFFSET+(w>>16)]; } out += prm->out_step; in += prm->in_step; } }