00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <stdlib.h>
00039 #include <fcntl.h>
00040 #include <unistd.h>
00041 #include <stdarg.h>
00042 #include <string.h>
00043 #include <time.h>
00044 #include <stdio.h>
00045 #include <dirent.h>
00046
00047 #include "framehook.h"
00048 #include "dsputil.h"
00049 #include "avformat.h"
00050 #include "swscale.h"
00051
00052 static int sws_flags = SWS_BICUBIC;
00053
00054 #define SCALEBITS 10
00055 #define ONE_HALF (1 << (SCALEBITS - 1))
00056 #define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
00057
00058 #define YUV_TO_RGB1_CCIR(cb1, cr1)\
00059 {\
00060 cb = (cb1) - 128;\
00061 cr = (cr1) - 128;\
00062 r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;\
00063 g_add = - FIX(0.34414*255.0/224.0) * cb - FIX(0.71414*255.0/224.0) * cr + \
00064 ONE_HALF;\
00065 b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;\
00066 }
00067
00068 #define YUV_TO_RGB2_CCIR(r, g, b, y1)\
00069 {\
00070 yt = ((y1) - 16) * FIX(255.0/219.0);\
00071 r = cm[(yt + r_add) >> SCALEBITS];\
00072 g = cm[(yt + g_add) >> SCALEBITS];\
00073 b = cm[(yt + b_add) >> SCALEBITS];\
00074 }
00075
00076
00077
00078
00079 typedef struct {
00080 int h;
00081 int s;
00082 int v;
00083 } HSV;
00084
00085 typedef struct {
00086 int zapping;
00087 int threshold;
00088 HSV dark, bright;
00089 char *dir;
00090 int file_limit;
00091 int debug;
00092 int min_interval;
00093 int64_t next_pts;
00094 int inset;
00095 int min_width;
00096 struct SwsContext *toRGB_convert_ctx;
00097 } ContextInfo;
00098
00099 static void dorange(const char *s, int *first, int *second, int maxval)
00100 {
00101 sscanf(s, "%d-%d", first, second);
00102 if (*first > maxval)
00103 *first = maxval;
00104 if (*second > maxval)
00105 *second = maxval;
00106 }
00107
00108 void Release(void *ctx)
00109 {
00110 ContextInfo *ci;
00111 ci = (ContextInfo *) ctx;
00112
00113 if (ctx) {
00114 sws_freeContext(ci->toRGB_convert_ctx);
00115 av_free(ctx);
00116 }
00117 }
00118
00119 int Configure(void **ctxp, int argc, char *argv[])
00120 {
00121 ContextInfo *ci;
00122 int c;
00123
00124 *ctxp = av_mallocz(sizeof(ContextInfo));
00125 ci = (ContextInfo *) *ctxp;
00126
00127 optind = 1;
00128
00129 ci->dir = "/tmp";
00130 ci->threshold = 100;
00131 ci->file_limit = 100;
00132 ci->min_interval = 1000000;
00133 ci->inset = 10;
00134
00135 while ((c = getopt(argc, argv, "w:i:dh:s:v:zl:t:D:")) > 0) {
00136 switch (c) {
00137 case 'h':
00138 dorange(optarg, &ci->dark.h, &ci->bright.h, 360);
00139 break;
00140 case 's':
00141 dorange(optarg, &ci->dark.s, &ci->bright.s, 255);
00142 break;
00143 case 'v':
00144 dorange(optarg, &ci->dark.v, &ci->bright.v, 255);
00145 break;
00146 case 'z':
00147 ci->zapping = 1;
00148 break;
00149 case 'l':
00150 ci->file_limit = atoi(optarg);
00151 break;
00152 case 'i':
00153 ci->min_interval = 1000000 * atof(optarg);
00154 break;
00155 case 't':
00156 ci->threshold = atof(optarg) * 1000;
00157 if (ci->threshold > 1000 || ci->threshold < 0) {
00158 fprintf(stderr, "Invalid threshold value '%s' (range is 0-1)\n", optarg);
00159 return -1;
00160 }
00161 break;
00162 case 'w':
00163 ci->min_width = atoi(optarg);
00164 break;
00165 case 'd':
00166 ci->debug++;
00167 break;
00168 case 'D':
00169 ci->dir = av_strdup(optarg);
00170 break;
00171 default:
00172 fprintf(stderr, "Unrecognized argument '%s'\n", argv[optind]);
00173 return -1;
00174 }
00175 }
00176
00177 fprintf(stderr, "Fish detector configured:\n");
00178 fprintf(stderr, " HSV range: %d,%d,%d - %d,%d,%d\n",
00179 ci->dark.h,
00180 ci->dark.s,
00181 ci->dark.v,
00182 ci->bright.h,
00183 ci->bright.s,
00184 ci->bright.v);
00185 fprintf(stderr, " Threshold is %d%% pixels\n", ci->threshold / 10);
00186
00187
00188 return 0;
00189 }
00190
00191 static void get_hsv(HSV *hsv, int r, int g, int b)
00192 {
00193 int i, v, x, f;
00194
00195 x = (r < g) ? r : g;
00196 if (b < x)
00197 x = b;
00198 v = (r > g) ? r : g;
00199 if (b > v)
00200 v = b;
00201
00202 if (v == x) {
00203 hsv->h = 0;
00204 hsv->s = 0;
00205 hsv->v = v;
00206 return;
00207 }
00208
00209 if (r == v) {
00210 f = g - b;
00211 i = 0;
00212 } else if (g == v) {
00213 f = b - r;
00214 i = 2 * 60;
00215 } else {
00216 f = r - g;
00217 i = 4 * 60;
00218 }
00219
00220 hsv->h = i + (60 * f) / (v - x);
00221 if (hsv->h < 0)
00222 hsv->h += 360;
00223
00224 hsv->s = (255 * (v - x)) / v;
00225 hsv->v = v;
00226
00227 return;
00228 }
00229
00230 void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
00231 {
00232 ContextInfo *ci = (ContextInfo *) ctx;
00233 uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
00234 int rowsize = picture->linesize[0];
00235
00236 #if 0
00237 printf("pix_fmt = %d, width = %d, pts = %lld, ci->next_pts = %lld\n",
00238 pix_fmt, width, pts, ci->next_pts);
00239 #endif
00240
00241 if (pts < ci->next_pts)
00242 return;
00243
00244 if (width < ci->min_width)
00245 return;
00246
00247 ci->next_pts = pts + 1000000;
00248
00249 if (pix_fmt == PIX_FMT_YUV420P) {
00250 uint8_t *y, *u, *v;
00251 int width2 = width >> 1;
00252 int inrange = 0;
00253 int pixcnt;
00254 int h;
00255 int h_start, h_end;
00256 int w_start, w_end;
00257
00258 h_end = 2 * ((ci->inset * height) / 200);
00259 h_start = height - h_end;
00260
00261 w_end = (ci->inset * width2) / 100;
00262 w_start = width2 - w_end;
00263
00264 pixcnt = ((h_start - h_end) >> 1) * (w_start - w_end);
00265
00266 y = picture->data[0] + h_end * picture->linesize[0] + w_end * 2;
00267 u = picture->data[1] + h_end * picture->linesize[1] / 2 + w_end;
00268 v = picture->data[2] + h_end * picture->linesize[2] / 2 + w_end;
00269
00270 for (h = h_start; h > h_end; h -= 2) {
00271 int w;
00272
00273 for (w = w_start; w > w_end; w--) {
00274 unsigned int r,g,b;
00275 HSV hsv;
00276 int cb, cr, yt, r_add, g_add, b_add;
00277
00278 YUV_TO_RGB1_CCIR(u[0], v[0]);
00279 YUV_TO_RGB2_CCIR(r, g, b, y[0]);
00280
00281 get_hsv(&hsv, r, g, b);
00282
00283 if (ci->debug > 1)
00284 fprintf(stderr, "(%d,%d,%d) -> (%d,%d,%d)\n",
00285 r,g,b,hsv.h,hsv.s,hsv.v);
00286
00287
00288 if (hsv.h >= ci->dark.h && hsv.h <= ci->bright.h &&
00289 hsv.s >= ci->dark.s && hsv.s <= ci->bright.s &&
00290 hsv.v >= ci->dark.v && hsv.v <= ci->bright.v) {
00291 inrange++;
00292 } else if (ci->zapping) {
00293 y[0] = y[1] = y[rowsize] = y[rowsize + 1] = 16;
00294 u[0] = 128;
00295 v[0] = 128;
00296 }
00297
00298 y+= 2;
00299 u++;
00300 v++;
00301 }
00302
00303 y += picture->linesize[0] * 2 - (w_start - w_end) * 2;
00304 u += picture->linesize[1] - (w_start - w_end);
00305 v += picture->linesize[2] - (w_start - w_end);
00306 }
00307
00308 if (ci->debug)
00309 fprintf(stderr, "Fish: Inrange=%d of %d = %d threshold\n", inrange, pixcnt, 1000 * inrange / pixcnt);
00310
00311 if (inrange * 1000 / pixcnt >= ci->threshold) {
00312
00313 int size;
00314 char *buf;
00315 AVPicture picture1;
00316 static int frame_counter;
00317 static int foundfile;
00318
00319 if ((frame_counter++ % 20) == 0) {
00320
00321 DIR *d;
00322
00323 foundfile = 0;
00324
00325 d = opendir(ci->dir);
00326 if (d) {
00327 struct dirent *dent;
00328
00329 while ((dent = readdir(d))) {
00330 if (strncmp("fishimg", dent->d_name, 7) == 0) {
00331 if (strcmp(".ppm", dent->d_name + strlen(dent->d_name) - 4) == 0) {
00332 foundfile++;
00333 }
00334 }
00335 }
00336 closedir(d);
00337 }
00338 }
00339
00340 if (foundfile < ci->file_limit) {
00341 FILE *f;
00342 char fname[256];
00343
00344 size = avpicture_get_size(PIX_FMT_RGB24, width, height);
00345 buf = av_malloc(size);
00346
00347 avpicture_fill(&picture1, buf, PIX_FMT_RGB24, width, height);
00348
00349
00350 ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
00351 width, height, pix_fmt,
00352 width, height, PIX_FMT_RGB24,
00353 sws_flags, NULL, NULL, NULL);
00354 if (ci->toRGB_convert_ctx == NULL) {
00355 av_log(NULL, AV_LOG_ERROR,
00356 "Cannot initialize the toRGB conversion context\n");
00357 return;
00358 }
00359
00360
00361 sws_scale(ci->toRGB_convert_ctx,
00362 picture->data, picture->linesize, 0, height,
00363 picture1.data, picture1.linesize);
00364
00365
00366 snprintf(fname, sizeof(fname), "%s/fishimg%ld_%"PRId64".ppm", ci->dir, (long)(av_gettime() / 1000000), pts);
00367 f = fopen(fname, "w");
00368 if (f) {
00369 fprintf(f, "P6 %d %d 255\n", width, height);
00370 fwrite(buf, width * height * 3, 1, f);
00371 fclose(f);
00372 }
00373
00374 av_free(buf);
00375 ci->next_pts = pts + ci->min_interval;
00376 }
00377 }
00378 }
00379 }
00380