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