1 /*
2 * yuvcorrect.c
3 * Copyright (C) 2002 Xavier Biquard <xbiquard@free.fr>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 // September/October 2002: First version
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <math.h>
30 #include <signal.h>
31 #include "yuv4mpeg.h"
32 #include "yuvcorrect.h"
33
34 extern const uint16_t OFFSET;
35 extern const uint16_t ALIGNENEMENT;
36 extern const char *legal_opt_flags;
37
38
39 const char PIPE[] = "PIPE";
40 const char STAT[] = "STAT";
41 const char FULL[] = "FULL";
42 const char HALF[] = "HALF";
43 const char TOP_FIRST[] = "INTERLACED_TOP_FIRST";
44 const char BOT_FIRST[] = "INTERLACED_BOTTOM_FIRST";
45 const char NOT_INTER[] = "NOT_INTERLACED";
46 const char PROGRESSIVE[] = "PROGRESSIVE";
47 const char LINESWITCH[] = "LINE_SWITCH";
48 const char NO_HEADER[] = "NO_HEADER";
49 const char TOP_FORWARD[] = "TOP_FORWARD";
50 const char BOTT_FORWARD[] = "BOTT_FORWARD";
51 const char RGBFIRST[] = "RGBFIRST";
52
53 // Prototypes specific to yuvcorrect
54 void yuvcorrect_print_usage (void);
55 void yuvcorrect_print_information (general_correction_t * gen_correct,
56 yuv_correction_t * yuv_correct,
57 rgb_correction_t * rgb_correct);
58 void yuvcorrect_handle_args (int argc, char *argv[], overall_t * overall,
59 general_correction_t * gen_correct);
60
61 void
yuvcorrect_print_usage(void)62 yuvcorrect_print_usage (void)
63 {
64 fprintf (stderr,
65 "usage: yuvcorrect -M [mode_keyword] -T [general_keyword] -Y [yuv_keyword] -R [RGB_keyword] [-v 0-2] [-h]\n"
66 "yuvcorrect applies different corrections related to interlacing and color\n"
67 "to yuv frames coming from stdin (in yuv4MPEG 4:2:0 format) to stdout.\n"
68 "In contrast to yuvscaler, frame size is kept constant.\n"
69 "\n"
70 "yuvcorrect is keyword driven :\n"
71 "\t -M for keyword concerning the correction MODE of yuvcorrect\n"
72 "\t -T for keyword concerning spatial, temporal or header corrections to be applied\n"
73 "\t -Y for keyword concerning color corrections in the yuv space\n"
74 "\t -R for keyword concerning color corrections in the RGB space\n"
75 "By default, yuvcorrect will not modify frames and simply act as a pass-through. Also, it will apply\n"
76 "YUV corrections first and then RGB corrections\n"
77 "\n" "Possible mode keyword are:\n"
78 "\t STAT to have yuvcorrect print statistical information on your frames _before_ corrections\n"
79 "\t RGBFIRST to have yuvcorrect apply RGB corrections first, then YUV corrections\n"
80 "\n"
81 "Possible general keyword are:\n"
82 "\t If you suspect that your video capture was given a wrong interlacing type,\n"
83 "\t and/or was spatially or temporarly missed up, please use and combine:\n"
84 "\t INTERLACED_TOP_FIRST to correct file header by specifying top_field_first as interlacing type\n"
85 "\t INTERLACED_BOTTOM_FIRST to correct file header by specifying bottom_field_first as interlacing\n"
86 "\t NOT_INTERLACED to correct file header by specifying not-interlaced/progressive as interlacing type\n"
87 "\t PROGRESSIVE to correct file header by specifying not-interlaced/progressive as interlacing type\n"
88 "\t NO_HEADER to suppress stream header generation (apply different corrections to different part of an input file)\n"
89 "\t LINE_SWITCH to switch lines two by two\n"
90 "\t BOTT_FORWARD to move the bottom field one frame forward\n"
91 "\t TOP_FORWARD to move the top field one frame forward\n"
92 "\n"
93 "Possible yuv keywords are:\n"
94 "\t LUMINANCE_Gamma_InputYmin_InputYmax_OutputYmin_OutputYmax or\n"
95 "\t Y_Gamma_InputYmin_InputYmax_OutputYmin_OutputYmax\n"
96 "\t to correct the input frame luminance by clipping it inside range [InputYmin;InputYmax],\n"
97 "\t scale with power (1/Gamma), and expand/shrink/shift it to [OutputYmin;OutputYmax]\n"
98 "\t CHROMINANCE_UVrotation_Ufactor_Urotcenter_Vfactor_Vrotcenter_UVmin_UVmax or\n"
99 "\t UV_UVrotation_Ufactor_Urotcenter_Vfactor_Vrotcenter_UVmin_UVmax\n"
100 "\t to rotate rescaled UV chroma components Ufactor*(U-Urotcenter) and Vfactor*(V-Vrotcenter)\n"
101 "\t by (float) UVrotation degrees, recenter to the normalize (128,128) center,\n"
102 "\t and _clip_ the result to range [UVmin;UVmax]\n"
103 "\t CONFORM to have yuvcorrect generate frames conform to the Rec.601 specification for Y'CbCr frames\n"
104 "\t that is LUMINANCE_1.0_16_235_16_235 and CHROMINANCE_0.0_1.0_128_1.0_128_16_240\n"
105 "\n"
106 "\t Possible RGB keywords are:\n"
107 "\t R_Gamma_InputRmin_InputRmax_OutputRmin_OutputRmax\n"
108 "\t G_Gamma_InputGmin_InputGmax_OutputGmin_OutputGmax\n"
109 "\t B_Gamma_InputBmin_InputBmax_OutputBmin_OutputBmax\n"
110 "\t to correct the input frame RGB color by clipping it inside range [InputRGBmin;InputRGBmax],\n"
111 "\t scale with power (1/Gamma), and expand/shrink/shift it to [OutputRGBmin;OutputRGBmax]\n"
112 "\n"
113 "-v Specifies the degree of verbosity: 0=quiet, 1=normal, 2=verbose/debug\n"
114 "-h : print this lot!\n");
115 exit (1);
116 }
117
118 void
handle_args_overall(int argc,char * argv[],overall_t * overall)119 handle_args_overall (int argc, char *argv[], overall_t * overall)
120 {
121 int c, verb;
122
123 while ((c = getopt (argc, argv, legal_opt_flags)) != -1)
124 {
125 switch (c)
126 {
127 case 'v':
128 verb = atoi (optarg);
129 if (verb < 0 || verb > 2)
130 {
131 mjpeg_info
132 ("Verbose level must be 0, 1 or 2 ! => resuming to default 1");
133 }
134 else
135 {
136 overall->verbose = verb;
137 }
138 break;
139
140 case 'h':
141 yuvcorrect_print_usage ();
142 break;
143
144 default:
145 break;
146 }
147 }
148 if (optind != argc)
149 yuvcorrect_print_usage ();
150 }
151
152 void
yuvcorrect_handle_args(int argc,char * argv[],overall_t * overall,general_correction_t * gen_correct)153 yuvcorrect_handle_args (int argc, char *argv[], overall_t * overall,
154 general_correction_t * gen_correct)
155 {
156 // This function handles argument passing on the command line
157 int c;
158 int k_mode, k_general;
159
160 // Ne pas oublier de mettre la putain de ligne qui suit, sinon, plus d'argument � la lign de commande, ils auront �t� bouff�s par l'appel pr�c�dnt � getopt!!
161 optind = 1;
162 while ((c = getopt (argc, argv, legal_opt_flags)) != -1)
163 {
164 switch (c)
165 {
166 // **************
167 // MODE KEYOWRD
168 // *************
169 case 'M':
170 k_mode = 0;
171 if (strcmp (optarg, STAT) == 0)
172 {
173 k_mode = 1;
174 overall->stat = 1;
175 }
176 if (strcmp (optarg, RGBFIRST) == 0)
177 {
178 k_mode = 1;
179 overall->rgbfirst = 1;
180 }
181 if (k_mode == 0)
182 mjpeg_error_exit1 ("Unrecognized MODE keyword: %s", optarg);
183 break;
184 // *************
185
186
187 // **************
188 // GENERAL KEYOWRD
189 // *************
190 case 'T':
191 k_general = 0;
192 if (strcmp (optarg, TOP_FIRST) == 0)
193 {
194 k_general = 1;
195 y4m_si_set_interlace (&gen_correct->streaminfo,
196 Y4M_ILACE_TOP_FIRST);
197 }
198 if (strcmp (optarg, BOT_FIRST) == 0)
199 {
200 k_general = 1;
201 y4m_si_set_interlace (&gen_correct->streaminfo,
202 Y4M_ILACE_BOTTOM_FIRST);
203 }
204 if ((strcmp (optarg, NOT_INTER) == 0)
205 || (strcmp (optarg, PROGRESSIVE) == 0))
206 {
207 k_general = 1;
208 y4m_si_set_interlace (&gen_correct->streaminfo, Y4M_ILACE_NONE);
209 }
210 if (strcmp (optarg, NO_HEADER) == 0)
211 {
212 k_general = 1;
213 gen_correct->no_header = 1;
214 }
215 if (strcmp (optarg, LINESWITCH) == 0)
216 {
217 k_general = 1;
218 gen_correct->line_switch = 1;
219 }
220 if (strcmp (optarg, BOTT_FORWARD) == 0)
221 {
222 k_general = 1;
223 gen_correct->field_move = 1;
224 }
225 if (strcmp (optarg, TOP_FORWARD) == 0)
226 {
227 k_general = 1;
228 gen_correct->field_move = -1;
229 }
230 if (k_general == 0)
231 mjpeg_error_exit1 ("Unrecognized GENERAL keyword: %s", optarg);
232 break;
233 // *************
234
235 default:
236 break;
237 }
238 }
239
240
241 }
242
243 void
yuvcorrect_print_information(general_correction_t * gen_correct,yuv_correction_t * yuv_correct,rgb_correction_t * rgb_correct)244 yuvcorrect_print_information (general_correction_t * gen_correct,
245 yuv_correction_t * yuv_correct,
246 rgb_correction_t * rgb_correct)
247 {
248 // This function print USER'S INFORMATION
249
250 y4m_log_stream_info (mjpeg_loglev_t("info"), "input: ", &gen_correct->streaminfo);
251
252 switch (gen_correct->line_switch)
253 {
254 case 0:
255 mjpeg_info ("no line switching");
256 break;
257 case 1:
258 mjpeg_info ("with line switching");
259 break;
260 default:
261 mjpeg_error_exit1 ("Unknown line switching status: %d",
262 gen_correct->line_switch);
263 }
264
265 switch (gen_correct->field_move)
266 {
267 case 0:
268 mjpeg_info ("no time forwarding");
269 break;
270 case 1:
271 mjpeg_info ("with bottom field one frame forward");
272 break;
273 case -1:
274 mjpeg_info ("with top field one frame forward");
275 break;
276 default:
277 mjpeg_error_exit1 ("Unknown time reordering status: %d",
278 gen_correct->field_move);
279 }
280
281 switch (yuv_correct->luma)
282 {
283 case 0:
284 mjpeg_info ("Without luminance correction");
285 break;
286 case 1:
287 mjpeg_info ("With luminance correction");
288 break;
289 default:
290 mjpeg_error_exit1 ("Unknown luminance correction status %u",
291 yuv_correct->luma);
292 }
293
294 switch (yuv_correct->chroma)
295 {
296 case 0:
297 mjpeg_info ("Without chrominance correction");
298 break;
299 case 1:
300 mjpeg_info ("With chrominance correction");
301 break;
302 default:
303 mjpeg_error_exit1 ("Unknown chrominance correction status %u",
304 yuv_correct->chroma);
305 }
306
307 switch (rgb_correct->rgb)
308 {
309 case 0:
310 mjpeg_info ("Without rgb correction");
311 break;
312 case 1:
313 mjpeg_info ("With rgb correction");
314 break;
315 default:
316 mjpeg_error_exit1 ("Unknown rgb correction status %u",
317 rgb_correct->rgb);
318 }
319
320 }
321
322 int
main(int argc,char * argv[])323 main (int argc, char *argv[])
324 {
325
326 // Defining yuvcorrect dedicated structures (see yuvcorrect.h)
327 overall_t *overall=NULL;
328 frame_t *frame=NULL;
329 general_correction_t *gen_correct=NULL;
330 yuv_correction_t *yuv_correct=NULL;
331 rgb_correction_t *rgb_correct=NULL;
332
333 int err = Y4M_OK;
334 uint8_t oddeven;
335
336 unsigned long int frame_num = 0;
337
338 y4m_accept_extensions(1);
339
340 // START OF INITIALISATION
341 // yuvcorrect overall structure initialisation
342 if (!(overall = (overall_t *) malloc (sizeof (overall_t))))
343 mjpeg_error_exit1
344 ("Could not allocate memory for overall structure pointer");
345 overall->verbose = 1;
346 overall->mode = overall->stat = overall->rgbfirst = 0;
347 handle_args_overall (argc, argv, overall);
348 mjpeg_default_handler_verbosity (overall->verbose);
349
350 mjpeg_debug ("Start of initialisation");
351
352 // yuvcorrect general_correction_t structure initialisations
353 if (!(gen_correct = (general_correction_t *) malloc (sizeof (general_correction_t))))
354 mjpeg_error_exit1
355 ("Could not allocate memory for gen_correct structure pointer");
356 // yuvcorrect frame_t structure initialisations
357 if (!(frame = (frame_t *) malloc (sizeof (frame_t))))
358 mjpeg_error_exit1
359 ("Could not allocate memory for frame structure pointer");
360 // yuvcorrect yuv_correction_t structure initialisation
361 if (!(yuv_correct = (yuv_correction_t *) malloc (sizeof (yuv_correction_t))))
362 mjpeg_error_exit1
363 ("Could not allocate memory for yuv_correct structure pointer");
364 // rgbcorrect rgb_correction_t structure initialisation
365 if (!(rgb_correct = (rgb_correction_t *) malloc (sizeof (rgb_correction_t))))
366 mjpeg_error_exit1
367 ("Could not allocate memory for rgb_correct structure pointer");
368
369 initialisation1(0,frame,gen_correct,yuv_correct,rgb_correct);
370 // Deal with args
371 handle_args_yuv_rgb (argc, argv, yuv_correct, rgb_correct);
372 yuvcorrect_handle_args (argc, argv, overall, gen_correct);
373 // Further initialisations depending on the stream itself
374 // General correction initialisations
375 if (gen_correct->field_move != 0)
376 {
377 if (!(frame->field1 = (uint8_t *) malloc ((frame->length >> 1)*sizeof(uint8_t))) ||
378 !(frame->field2 = (uint8_t *) malloc ((frame->length >> 1)*sizeof(uint8_t))))
379 mjpeg_error_exit1
380 ("Could not allocate memory for field1 or field2 tables. STOP!");
381 }
382 initialisation2(yuv_correct,rgb_correct);
383
384 // USER'S INFORMATION OUTPUT
385 yuvcorrect_print_information (gen_correct, yuv_correct, rgb_correct);
386
387 mjpeg_debug ("End of Initialisation");
388 // END OF INITIALISATION
389
390 // Eventually output file header
391 if (gen_correct->no_header == 0)
392 y4m_write_stream_header (1, &gen_correct->streaminfo);
393
394 mjpeg_debug ("overall: verbose=%u, mode=%d, stat=%u", overall->verbose,
395 overall->mode, overall->stat);
396 mjpeg_debug ("frame: Y:%ux%u=>%lu UV:%ux%u=>%lu Size=%lu", frame->y_width,
397 frame->y_height, frame->nb_y, frame->uv_width,
398 frame->uv_height, frame->nb_uv, frame->length);
399 mjpeg_debug
400 ("yuv: Gamma=%f, InputYmin=%u, InputYmax=%u, OutputYmin=%u, OutputYmax=%u",
401 yuv_correct->Gamma, yuv_correct->InputYmin, yuv_correct->InputYmax,
402 yuv_correct->OutputYmin, yuv_correct->OutputYmax);
403 // Master loop : continue until there is no next frame in stdin
404 while ((err = yuvcorrect_y4m_read_frame (0, &gen_correct->streaminfo, frame, gen_correct->line_switch)) == Y4M_OK)
405 {
406 if (overall->stat == 1)
407 yuvstat (frame);
408
409 mjpeg_info ("Frame number %ld", frame_num);
410
411 // Time reordering
412 if (gen_correct->field_move != 0)
413 {
414 oddeven = frame_num & (unsigned long int) 1; // oddeven = frame_num % 2, fast implementation
415 if (gen_correct->field_move == 1)
416 {
417 // Bottom field one frame forward
418 if (frame_num == 0)
419 {
420 bottom_field_storage (frame, oddeven, frame->field1, frame->field2);
421 if (yuvcorrect_y4m_read_frame (0, &gen_correct->streaminfo, frame, gen_correct->line_switch) !=
422 Y4M_OK)
423 mjpeg_error_exit1 ("Can't read frame %ld", frame_num);
424 frame_num++;
425 oddeven = frame_num & (unsigned long int) 1;
426 mjpeg_info ("Frame number %ld", frame_num);
427 }
428 bottom_field_storage (frame, oddeven, frame->field1, frame->field2);
429 bottom_field_replace (frame, oddeven, frame->field1, frame->field2);
430 }
431 else
432 {
433 // Top field one frame forward
434 if (frame_num == 0)
435 {
436 top_field_storage (frame, oddeven, frame->field1, frame->field2);
437 if (yuvcorrect_y4m_read_frame (0, &gen_correct->streaminfo, frame, gen_correct->line_switch) !=
438 Y4M_OK)
439 mjpeg_error_exit1 ("Can't read frame %ld", frame_num);
440 frame_num++;
441 oddeven = frame_num & (unsigned long int) 1;
442 mjpeg_info ("Frame number %ld", frame_num);
443 }
444 top_field_storage (frame, oddeven, frame->field1, frame->field2);
445 top_field_replace (frame, oddeven, frame->field1, frame->field2);
446 }
447 }
448
449
450 if (overall->rgbfirst == 1)
451 {
452 // RGB correction
453 if (rgb_correct->rgb == 1)
454 yuvcorrect_RGB_treatment (frame, rgb_correct);
455 }
456 // luminance correction
457 if (yuv_correct->luma == 1)
458 yuvcorrect_luminance_treatment (frame, yuv_correct);
459 // chrominance correction
460 if (yuv_correct->chroma == 1)
461 yuvcorrect_chrominance_treatment (frame, yuv_correct);
462 if (overall->rgbfirst != 1)
463 {
464 // RGB correction
465 if (rgb_correct->rgb == 1)
466 yuvcorrect_RGB_treatment (frame, rgb_correct);
467 }
468
469 // Output Frame Header
470 if (y4m_write_frame_header (1, &gen_correct->streaminfo, &frame->info) != Y4M_OK)
471 goto out_error;
472
473 // Output Frame content
474 if (y4m_write (1, frame->y, frame->length) != Y4M_OK)
475 goto out_error;
476
477 frame_num++;
478
479 }
480 // End of master loop => no more frame in stdin
481
482 if (err != Y4M_ERR_EOF)
483 mjpeg_error_exit1 ("Couldn't read frame number %ld!", frame_num);
484 else
485 mjpeg_info ("Normal exit: end of stream with frame number %ld!",
486 frame_num);
487 y4m_fini_stream_info (&gen_correct->streaminfo);
488 y4m_fini_frame_info (&frame->info);
489 return 0;
490
491
492 out_error:
493 mjpeg_error_exit1 ("Unable to write to output - aborting!");
494 return 1;
495 }
496
497 /*
498 * Local variables:
499 * tab-width: 8
500 * indent-tabs-mode: nil
501 * End:
502 */
503