|
MythTV
0.26-pre
|
00001 /* range / gamma adjustment filter 00002 */ 00003 00004 #include <stdlib.h> 00005 #include <stdio.h> 00006 00007 #include "config.h" 00008 #if HAVE_STDINT_H 00009 #include <stdint.h> 00010 #endif 00011 00012 #include <string.h> 00013 #include <math.h> 00014 00015 #include "filter.h" 00016 #include "frame.h" 00017 00018 #if HAVE_MMX 00019 00020 #include "libavutil/mem.h" 00021 #include "libavcodec/dsputil.h" 00022 #include "ffmpeg-mmx.h" 00023 00024 static const mmx_t mm_cpool[] = { 00025 { w: {1, 1, 1, 1} }, 00026 { ub: {36, 36, 36, 36, 36, 36, 36, 36} }, 00027 { ub: {20, 20, 20, 20, 20, 20, 20, 20} }, 00028 { ub: {31, 31, 31, 31, 31, 31, 31, 31} }, 00029 { ub: {15, 15, 15, 15, 15, 15, 15, 15} } 00030 }; 00031 00032 #endif /* HAVE_MMX */ 00033 00034 typedef struct ThisFilter 00035 { 00036 VideoFilter vf; 00037 00038 #if HAVE_MMX 00039 int yfilt; 00040 int cfilt; 00041 00042 mmx_t yscale; 00043 mmx_t yshift; 00044 mmx_t ymin; 00045 00046 mmx_t cscale; 00047 mmx_t cshift; 00048 mmx_t cmin; 00049 #endif /* HAVE_MMX */ 00050 00051 uint8_t ytable[256]; 00052 uint8_t ctable[256]; 00053 00054 TF_STRUCT; 00055 } ThisFilter; 00056 00057 static void adjustRegion(uint8_t *buf, uint8_t *end, const uint8_t *table) 00058 { 00059 while (buf < end) 00060 { 00061 *buf = table[*buf]; 00062 buf++; 00063 } 00064 } 00065 00066 #if HAVE_MMX 00067 static void adjustRegionMMX(uint8_t *buf, uint8_t *end, const uint8_t *table, 00068 const mmx_t *shift, const mmx_t *scale, const mmx_t *min, 00069 const mmx_t *clamp1, const mmx_t *clamp2) 00070 { 00071 movq_m2r (*scale, mm6); 00072 movq_m2r (*min, mm7); 00073 while (buf < end - 15) 00074 { 00075 movq_m2r (buf[0], mm0); 00076 movq_m2r (buf[8], mm2); 00077 movq_m2r (*shift, mm4); 00078 pxor_r2r (mm5, mm5); 00079 00080 psubusb_r2r (mm7, mm0); 00081 psubusb_r2r (mm7, mm2); 00082 00083 movq_r2r (mm0, mm1); 00084 movq_r2r (mm2, mm3); 00085 00086 punpcklbw_r2r (mm5, mm0); 00087 punpckhbw_r2r (mm5, mm1); 00088 punpcklbw_r2r (mm5, mm2); 00089 punpckhbw_r2r (mm5, mm3); 00090 00091 movq_m2r (mm_cpool[0], mm5); 00092 00093 psllw_r2r (mm4, mm0); 00094 psllw_r2r (mm4, mm1); 00095 psllw_r2r (mm4, mm2); 00096 psllw_r2r (mm4, mm3); 00097 00098 movq_m2r (*clamp1, mm4); 00099 00100 pmulhw_r2r (mm6, mm0); 00101 pmulhw_r2r (mm6, mm1); 00102 pmulhw_r2r (mm6, mm2); 00103 pmulhw_r2r (mm6, mm3); 00104 00105 paddw_r2r (mm5, mm0); 00106 paddw_r2r (mm5, mm1); 00107 paddw_r2r (mm5, mm2); 00108 paddw_r2r (mm5, mm3); 00109 00110 movq_m2r (*clamp2, mm5); 00111 00112 psrlw_i2r (1, mm0); 00113 psrlw_i2r (1, mm1); 00114 psrlw_i2r (1, mm2); 00115 psrlw_i2r (1, mm3); 00116 00117 packuswb_r2r (mm1, mm0); 00118 packuswb_r2r (mm3, mm2); 00119 00120 paddusb_r2r (mm4, mm0); 00121 paddusb_r2r (mm4, mm2); 00122 00123 psubusb_r2r (mm5, mm0); 00124 psubusb_r2r (mm5, mm2); 00125 00126 movq_r2m (mm0, buf[0]); 00127 movq_r2m (mm2, buf[8]); 00128 00129 buf += 16; 00130 } 00131 while (buf < end) 00132 { 00133 *buf = table[*buf]; 00134 buf++; 00135 } 00136 } 00137 #endif /* HAVE_MMX */ 00138 00139 static int adjustFilter (VideoFilter *vf, VideoFrame *frame, int field) 00140 { 00141 (void)field; 00142 ThisFilter *filter = (ThisFilter *) vf; 00143 TF_VARS; 00144 00145 TF_START; 00146 { 00147 unsigned char *ybeg = frame->buf + frame->offsets[0]; 00148 unsigned char *yend = ybeg + (frame->pitches[0] * frame->height); 00149 int cheight = (frame->codec == FMT_YV12) ? 00150 (frame->height >> 1) : frame->height; 00151 unsigned char *ubeg = frame->buf + frame->offsets[1]; 00152 unsigned char *uend = ubeg + (frame->pitches[1] * cheight); 00153 unsigned char *vbeg = frame->buf + frame->offsets[2]; 00154 unsigned char *vend = ubeg + (frame->pitches[2] * cheight); 00155 00156 #if HAVE_MMX 00157 if (filter->yfilt) 00158 adjustRegionMMX(ybeg, yend, filter->ytable, 00159 &(filter->yshift), &(filter->yscale), 00160 &(filter->ymin), mm_cpool + 1, mm_cpool + 2); 00161 else 00162 adjustRegion(ybeg, yend, filter->ytable); 00163 00164 if (filter->cfilt) 00165 { 00166 adjustRegionMMX(ubeg, uend, filter->ctable, 00167 &(filter->cshift), &(filter->cscale), 00168 &(filter->cmin), mm_cpool + 3, mm_cpool + 4); 00169 adjustRegionMMX(vbeg, vend, filter->ctable, 00170 &(filter->cshift), &(filter->cscale), 00171 &(filter->cmin), mm_cpool + 3, mm_cpool + 4); 00172 } 00173 else 00174 { 00175 adjustRegion(ubeg, uend, filter->ctable); 00176 adjustRegion(vbeg, vend, filter->ctable); 00177 } 00178 00179 if (filter->yfilt || filter->cfilt) 00180 emms(); 00181 00182 #else /* HAVE_MMX */ 00183 adjustRegion(ybeg, yend, filter->ytable); 00184 adjustRegion(ubeg, uend, filter->ctable); 00185 adjustRegion(vbeg, vend, filter->ctable); 00186 #endif /* HAVE_MMX */ 00187 } 00188 TF_END(filter, "Adjust: "); 00189 return 0; 00190 } 00191 00192 static void fillTable(uint8_t *table, int in_min, int in_max, int out_min, 00193 int out_max, float gamma) 00194 { 00195 int i; 00196 float f; 00197 00198 for (i = 0; i < 256; i++) 00199 { 00200 f = ((float)i - in_min) / (in_max - in_min); 00201 f = f < 0.0 ? 0.0 : f; 00202 f = f > 1.0 ? 1.0 : f; 00203 table[i] = (pow (f, gamma) * (out_max - out_min) + out_min + 0.5); 00204 } 00205 } 00206 00207 #if HAVE_MMX 00208 static int fillTableMMX(uint8_t *table, mmx_t *shift, mmx_t *scale, mmx_t *min, 00209 int in_min, int in_max, int out_min, int out_max, 00210 float gamma) 00211 { 00212 int shiftc, scalec, i; 00213 00214 fillTable(table, in_min, in_max, out_min, out_max, gamma); 00215 scalec = ((out_max - out_min) << 15)/(in_max - in_min); 00216 if ((av_get_cpu_flags() & AV_CPU_FLAG_MMX) == 0 || gamma < 0.9999 || 00217 gamma > 1.00001 || scalec > 32767 << 7) 00218 return 0; 00219 shiftc = 2; 00220 while (scalec > 32767) 00221 { 00222 shiftc++; 00223 scalec >>= 1; 00224 } 00225 if (shiftc > 7) 00226 return 0; 00227 for (i = 0; i < 4; i++) 00228 { 00229 scale->w[i] = scalec; 00230 } 00231 for (i = 0; i < 8; i++) 00232 min->b[i] = in_min; 00233 shift->q = shiftc; 00234 return 1; 00235 } 00236 #endif /* HAVE_MMX */ 00237 00238 static VideoFilter * 00239 newAdjustFilter (VideoFrameType inpixfmt, VideoFrameType outpixfmt, 00240 int *width, int *height, char *options, int threads) 00241 { 00242 ThisFilter *filter; 00243 int numopts = 0, ymin = 16, ymax = 253, cmin = 16, cmax = 240; 00244 float ygamma = 1.0f, cgamma = 1.0f; 00245 (void) width; 00246 (void) height; 00247 (void) threads; 00248 00249 if (inpixfmt != outpixfmt || 00250 (inpixfmt != FMT_YV12 && inpixfmt != FMT_YUV422P)) 00251 { 00252 fprintf(stderr, "adjust: only YV12->YV12 and YUV422P->YUV422P" 00253 " conversions are supported\n"); 00254 return NULL; 00255 } 00256 00257 if (options) 00258 { 00259 numopts = sscanf(options, "%20d:%20d:%20f:%20d:%20d:%20f", 00260 &ymin, &ymax, &ygamma, 00261 &cmin, &cmax, &cgamma); 00262 } 00263 00264 if (numopts != 6 && (numopts !=1 && ymin != -1)) 00265 { 00266 ymin = 16; 00267 ymax = 253; 00268 ygamma = 1.0f; 00269 cmin = 16; 00270 cmax = 240; 00271 cgamma = 1.0f; 00272 } 00273 00274 filter = malloc (sizeof (ThisFilter)); 00275 00276 if (filter == NULL) 00277 { 00278 fprintf (stderr, "adjust: failed to allocate memory for filter\n"); 00279 return NULL; 00280 } 00281 00282 if (ymin == -1) 00283 { 00284 filter->vf.filter = NULL; 00285 filter->vf.cleanup = NULL; 00286 return (VideoFilter *) filter; 00287 } 00288 00289 #if HAVE_MMX 00290 filter->yfilt = fillTableMMX (filter->ytable, &(filter->yshift), 00291 &(filter->yscale), &(filter->ymin), 00292 ymin, ymax, 16, 235, ygamma); 00293 filter->cfilt = fillTableMMX (filter->ctable, &(filter->cshift), 00294 &(filter->cscale), &(filter->cmin), 00295 cmin, cmax, 16, 240, cgamma); 00296 #else 00297 fillTable (filter->ytable, ymin, ymax, 16, 235, ygamma); 00298 fillTable (filter->ctable, cmin, cmax, 16, 240, cgamma); 00299 #endif 00300 00301 filter->vf.filter = &adjustFilter; 00302 filter->vf.cleanup = NULL; 00303 00304 TF_INIT(filter); 00305 return (VideoFilter *) filter; 00306 } 00307 00308 static FmtConv FmtList[] = 00309 { 00310 { FMT_YV12, FMT_YV12 }, 00311 { FMT_YUV422P, FMT_YUV422P }, 00312 FMT_NULL 00313 }; 00314 00315 ConstFilterInfo filter_table[] = 00316 { 00317 { 00318 filter_init: &newAdjustFilter, 00319 name: "adjust", 00320 descript: "adjust range and gamma of video", 00321 formats: FmtList, 00322 libname: NULL 00323 }, 00324 FILT_NULL 00325 };
1.7.6.1