1 /* lav2yuv - stream any lav input file to stdout as YUV4MPEG data */
2
3 /* Copyright (C) 2000, Rainer Johanni, Andrew Stevens */
4 /* - added scene change detection code 2001, pHilipp Zabel */
5 /* - broke some common code out to lav_common.c and lav_common.h,
6 * July 2001, Shawn Sulma <lavtools@athos.cx>. In doing this, I
7 * repackaged the numerous globals into three structs that get passed into
8 * the relevant functions. See lav_common.h for a bit more information.
9 * Helpful feedback is welcome.
10 */
11 /* - removed a lot of subsumed functionality and unnecessary cruft
12 * March 2002, Matthew Marjanovic <maddog@mir.com>.
13 */
14
15 /*
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "lav_common.h"
36 #include <stdio.h>
37
38 void error(char *text);
39 void Usage(char *str);
40 void streamout(void);
41
42 int verbose = 1;
43
44 EditList el;
45
Usage(char * str)46 void Usage(char *str)
47 {
48 fprintf(stderr,
49 "Usage: %s [params] inputfiles\n"
50 " where possible params are:\n"
51 " -m Force mono-chrome\n"
52 " -S list.el Output a scene list with scene detection\n"
53 " -T num Set scene detection threshold to num (default: 4)\n"
54 " -D num Width decimation to use for scene detection (default: 2)\n"
55 " -A w:h Set output sample aspect ratio\n"
56 " (default: read from DV files, or guess for MJPEG)\n"
57 " -P w:h Declare the intended display aspect ratio (used to guess\n"
58 " the sample aspect ratio). Common values are 4:3 and 16:9.\n"
59 " (default: read from DV files, or assume 4:3 for MJPEG)\n"
60 " -C chroma Set output chroma (default: '420jpeg')\n"
61 " '420jpeg', '420mpeg2', '420paldv', '422', '411' are available\n"
62 " -o num Frame offset - skip num frames in the beginning\n"
63 " if num is negative, all but the last num frames are skipped\n"
64 " -f num Only num frames are written to stdout (0 means all frames)\n"
65 " -c Conceal corrupt jpeg frames by repeating previous frame\n"
66 " -x Exchange fields\n",
67 str);
68 exit(0);
69 }
70
71 static int lum_mean;
72 static int last_lum_mean;
73 static int delta_lum;
74 static int scene_num;
75 static int scene_start;
76
77 LavParam param;
78 uint8_t *frame_bufs[6];
79
80 static int conceal_errframes;
81 static int altbuf;
82
streamout(void)83 void streamout(void)
84 {
85
86 int framenum, movie_num=0, index[MAX_EDIT_LIST_FILES];
87 int concealnum = 0;
88 long int oldframe=N_EL_FRAME(el.frame_list[0])-1;
89 FILE *fd=NULL;
90
91 int fd_out = 1; /* stdout. */
92
93 char temp[32];
94
95 y4m_stream_info_t streaminfo;
96 y4m_frame_info_t frameinfo;
97
98 y4m_init_stream_info(&streaminfo);
99 y4m_init_frame_info(&frameinfo);
100
101
102 if (!param.scenefile)
103 writeoutYUV4MPEGheader(fd_out, ¶m, el, &streaminfo);
104 scene_num = scene_start = 0;
105 if (param.scenefile)
106 {
107 int num_files;
108 int i;
109
110 param.output_width =
111 param.output_width / param.scene_detection_decimation;
112
113 /* Output file */
114
115 unlink(param.scenefile);
116 fd = fopen(param.scenefile,"w");
117 if(fd==0)
118 {
119 mjpeg_error_exit1("Can not open %s - no edit list written!",param.scenefile);
120 }
121 fprintf(fd,"LAV Edit List\n");
122 fprintf(fd,"%s\n",el.video_norm=='n'?"NTSC":"PAL");
123 for(i=0;i<MAX_EDIT_LIST_FILES;i++) index[i] = -1;
124 for(i=0;i<el.video_frames;i++) index[N_EL_FILE(el.frame_list[i])] = 1;
125 num_files = 0;
126 for(i=0;i<MAX_EDIT_LIST_FILES;i++)
127 if(index[i]==1)
128 index[i] = num_files++;
129 fprintf(fd,"%d\n",num_files);
130 for(i=0;i<MAX_EDIT_LIST_FILES;i++)
131 if(index[i]>=0)
132 fprintf(fd,"%s\n",el.video_file_list[i]);
133 sprintf(temp,"%d %ld",
134 index[N_EL_FILE(el.frame_list[0])],
135 N_EL_FRAME(el.frame_list[0]));
136 }
137
138 for (framenum = param.offset; framenum < (param.offset + param.frames); ++framenum)
139 {
140 int rf;
141 uint8_t **read_buf;
142 uint8_t **frame_buf;
143 if(conceal_errframes)
144 read_buf = &frame_bufs[4 * (altbuf ^ 1)];
145 else
146 read_buf = &frame_bufs[0];
147
148 rf = readframe(framenum, read_buf, ¶m, el);
149 if(conceal_errframes) {
150 if(rf == 2) { // corrupt frame; repeat previous
151 mjpeg_debug("corrupt jpeg data in frame %d; repeating previous frame.", framenum);
152 frame_buf = &frame_bufs[4 * altbuf];
153 concealnum++;
154 } else { // use new frame
155 frame_buf = read_buf;
156 altbuf ^= 1;
157 }
158 } else {
159 if(rf == 2)
160 mjpeg_debug("corrupt jpeg data in frame %d", framenum);
161 frame_buf = &frame_bufs[0];
162 }
163
164 if (param.scenefile)
165 {
166 lum_mean =
167 luminance_mean(frame_buf,
168 param.output_width, param.output_height );
169 if (framenum == 0)
170 {
171 delta_lum = 0;
172 movie_num = N_EL_FILE(el.frame_list[0]);
173 }
174 else
175 delta_lum = abs(lum_mean - last_lum_mean);
176 last_lum_mean = lum_mean;
177
178 mjpeg_debug( "frame %d/%ld, lum_mean %d, delta_lum %d ", framenum,
179 el.video_frames, lum_mean, delta_lum);
180
181 if (delta_lum > param.delta_lum_threshold || index[N_EL_FILE(el.frame_list[framenum])] != movie_num ||
182 oldframe+1 != N_EL_FRAME(el.frame_list[framenum])) {
183 if (delta_lum <= param.delta_lum_threshold)
184 fprintf(fd,"%c",'+'); /* Same scene, new file */
185 fprintf(fd,"%s %ld\n", temp, N_EL_FRAME(el.frame_list[framenum-1]));
186 sprintf(temp,"%d %ld",index[N_EL_FILE(el.frame_list[framenum])], N_EL_FRAME(el.frame_list[framenum]));
187 scene_start = framenum;
188 scene_num++;
189 }
190
191 oldframe = N_EL_FRAME(el.frame_list[framenum]);
192 movie_num = N_EL_FILE(el.frame_list[framenum]);
193
194 }
195 else
196 {
197 int i;
198 i = y4m_write_frame(fd_out,
199 &streaminfo, &frameinfo, frame_buf);
200 if (i != Y4M_OK)
201 mjpeg_error("Failed to write frame: %s", y4m_strerr(i));
202 }
203 }
204 mjpeg_info( "Repeated frames (for error concealment): %d", concealnum);
205 if (param.scenefile)
206 {
207 fprintf(fd, "%s %ld\n", temp, N_EL_FRAME(el.video_frames-1));
208 fclose(fd);
209 mjpeg_info( "Editlist written to %s", param.scenefile);
210 }
211
212 y4m_fini_frame_info(&frameinfo);
213 }
214
main(argc,argv)215 int main(argc, argv)
216 int argc;
217 char *argv[];
218 {
219 int n, nerr = 0;
220 int exchange_fields = 0;
221
222 y4m_accept_extensions(1);
223
224 param.offset = 0;
225 param.frames = 0;
226 param.mono = 0;
227 param.scenefile = NULL;
228 param.delta_lum_threshold = 4;
229 param.scene_detection_decimation = 2;
230 param.output_width = 0;
231 param.output_height = 0;
232 param.interlace = -1;
233 param.sar = y4m_sar_UNKNOWN;
234 param.dar = y4m_dar_4_3;
235 param.chroma = Y4M_UNKNOWN;
236
237 while ((n = getopt(argc, argv, "xmYv:S:T:D:o:f:P:A:C:c")) != EOF) {
238 switch (n) {
239
240 case 'v':
241 verbose = atoi(optarg);
242 if (verbose < 0 ||verbose > 2) {
243 mjpeg_error( "-v option requires arg 0, 1, or 2");
244 nerr++;
245 }
246 break;
247 case 'm':
248 param.mono = 1;
249 break;
250 case 'x':
251 exchange_fields = 1;
252 break;
253 case 'c':
254 conceal_errframes = 1;
255 break;
256 case 'S':
257 param.scenefile = optarg;
258 break;
259 case 'T':
260 param.delta_lum_threshold = atoi(optarg);
261 break;
262 case 'D':
263 param.scene_detection_decimation = atoi(optarg);
264 break;
265 case 'o':
266 param.offset = atoi(optarg);
267 break;
268 case 'f':
269 param.frames = atoi(optarg);
270 break;
271
272 case 'A':
273 if (y4m_parse_ratio(&(param.sar), optarg)) {
274 mjpeg_error("Couldn't parse ratio '%s'", optarg);
275 nerr++;
276 }
277 break;
278 case 'P':
279 if (y4m_parse_ratio(&(param.dar), optarg)) {
280 mjpeg_error("Couldn't parse ratio '%s'", optarg);
281 nerr++;
282 }
283 break;
284 case 'C':
285 param.chroma = y4m_chroma_parse_keyword(optarg);
286 switch (param.chroma) {
287 case Y4M_CHROMA_420JPEG:
288 case Y4M_CHROMA_420MPEG2:
289 case Y4M_CHROMA_420PALDV:
290 case Y4M_CHROMA_422:
291 case Y4M_CHROMA_411:
292 break;
293 default:
294 mjpeg_error("Unsupported chroma '%s'", optarg);
295 nerr++;
296 break;
297 }
298 break;
299 default:
300 nerr++;
301 }
302 }
303
304 if (optind >= argc)
305 nerr++;
306
307 if (nerr)
308 Usage(argv[0]);
309
310 (void)mjpeg_default_handler_verbosity(verbose);
311
312 /* Open editlist */
313
314 read_video_files(argv + optind, argc - optind, &el,0);
315
316 param.output_width = el.video_width;
317 param.output_height = el.video_height;
318 if(exchange_fields) {
319 if(el.video_inter == Y4M_ILACE_BOTTOM_FIRST) {
320 mjpeg_info("Exchange from BOTTOM_FIRST to TOP_FIRST");
321 el.video_inter = Y4M_ILACE_TOP_FIRST;
322 }
323 else if(el.video_inter == Y4M_ILACE_TOP_FIRST) {
324 mjpeg_info("Exchange from TOP_FIRST to BOTTOM_FIRST");
325 el.video_inter = Y4M_ILACE_BOTTOM_FIRST;
326 }
327 else {
328 mjpeg_warn("Video NOT INTERLACED! Could not exchange fields");
329 }
330 }
331
332 if (param.offset < 0) {
333 param.offset = el.video_frames + param.offset;
334 }
335 if (param.offset >= el.video_frames) {
336 mjpeg_error_exit1("offset greater than # of frames in input");
337 }
338 if ((param.offset + param.frames) > el.video_frames) {
339 mjpeg_warn("input too short for -f %d", param.frames);
340 param.frames = el.video_frames - param.offset;
341 }
342 if (param.frames == 0) {
343 param.frames = el.video_frames - param.offset;
344 }
345
346 param.interlace = el.video_inter;
347
348 init(¶m, &frame_bufs[0] /*&buffer*/);
349 if(conceal_errframes)
350 init(¶m, &frame_bufs[4] /*&buffer*/);
351
352 #ifdef HAVE_LIBDV
353 lav_init_dv_decoder();
354 #endif
355 if (param.delta_lum_threshold != -1)
356 {
357 streamout();
358 }
359 else
360 {
361 write_edit_list(param.scenefile, 0, el.video_frames, &el);
362 }
363
364 return 0;
365 }
366