1 /*
2 *
3 * lav2wav.c
4 *
5 * Copyright (C) 2000 MSSG, Rainer Johanni, Aaron Holtzman, Andrew Stevens
6 *
7 * This file is part of lav2wav,a component of the "MJPEG tools"
8 * suite of open source tools for MJPEG and MPEG processing.
9 *
10 * lav2wav is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * lav2wav is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with GNU Make; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include "lav_io.h"
31 #include "editlist.h"
32 #include "mjpeg_logging.h"
33
34 struct wave_header wave;
35 static uint8_t audio_buff[2*256*1024]; /* Enough for 1fps, 48kHz ... */
36 int verbose = 1;
37 int big_endian; /* The endian detection */
38 int silence_sr, silence_bs, silence_ch ;
39 EditList el;
40
41 void set_silence (char *);
42 int wav_header(unsigned int bits, unsigned int rate, unsigned int channels, int fd);
43 void Usage(char *str);
44
45 /* Raw write does *not* guarantee to write the entire buffer load if it
46 becomes possible to do so. This does... */
do_write(int fd,void * buf,size_t count)47 static size_t do_write( int fd, void *buf, size_t count )
48 {
49 char *cbuf = buf;
50 size_t count_left = count;
51 size_t written;
52 while( count_left > 0 )
53 {
54 written = write( fd, cbuf, count_left );
55 if( written < 0 )
56 return count-count_left;
57 count_left -= written;
58 cbuf += written;
59 }
60 return count;
61 }
62
wav_header(unsigned int bits,unsigned int rate,unsigned int channels,int fd)63 int wav_header( unsigned int bits, unsigned int rate, unsigned int channels, int fd )
64 {
65 uint16_t temp_16; /* temp variables for swapping the bytes */
66 uint32_t temp_32; /* temp variables for swapping the bytes */
67 uint32_t dummy_size = 0x7fffff00+sizeof(wave);
68
69 /* Write out a ZEROD wave header first */
70 memset(&wave, 0, sizeof(wave));
71
72 strncpy((char*)wave.riff.id, "RIFF", 4);
73 strncpy((char*)wave.riff.wave_id, "WAVE",4);
74 dummy_size -=8;
75 wave.riff.len = reorder_32(dummy_size, big_endian);
76
77 strncpy((char*)wave.format.id, "fmt ",4);
78 wave.format.len = reorder_32((uint32_t)sizeof(struct common_struct), big_endian);
79
80 /* Store information */
81 if (big_endian == 0)
82 {
83 wave.common.wFormatTag = WAVE_FORMAT_PCM;
84 wave.common.wChannels = channels;
85 wave.common.dwSamplesPerSec = rate;
86 wave.common.dwAvgBytesPerSec = channels*rate*bits/8;
87 wave.common.wBlockAlign = channels*bits/8;
88 wave.common.wBitsPerSample = bits;
89 }
90 else /* We have a big endian machine and have to swap the bytes */
91 {
92 temp_16 = WAVE_FORMAT_PCM;
93 swab(&temp_16, &wave.common.wFormatTag,2);
94 temp_16 = channels;
95 swab(&temp_16, &wave.common.wChannels, 2);
96 temp_32 = rate;
97 wave.common.dwSamplesPerSec = reorder_32 (temp_32, big_endian);
98 temp_32 = channels*rate*bits/8;
99 wave.common.dwAvgBytesPerSec = reorder_32 (temp_32, big_endian);
100 temp_16 = channels*bits/8;
101 swab(&temp_16, &wave.common.wBlockAlign, 2);
102 temp_16 = bits;
103 swab(&temp_16, &wave.common.wBitsPerSample, 2);
104 }
105
106 strncpy((char*)wave.data.id, "data",4);
107 dummy_size -= 20+sizeof(struct common_struct);
108
109 wave.data.len = reorder_32 (dummy_size, big_endian);
110 if (do_write(fd, &wave, sizeof(wave)) != sizeof(wave))
111 return 1;
112 return 0;
113 }
114
wav_close(int fd)115 static void wav_close(int fd)
116 {
117 unsigned int size;
118
119 /* Find how long our file is in total, including header */
120 size = lseek(fd, 0, SEEK_CUR);
121
122 if (size < 0 )
123 {
124 if( fd > 2 )
125 mjpeg_error("lseek failed - wav-header is corrupt");
126 goto EXIT;
127 }
128
129 /* Rewind file */
130 if (lseek(fd, 0, SEEK_SET) < 0)
131 {
132 mjpeg_error("rewind failed - wav-header is corrupt");
133 goto EXIT;
134 }
135 mjpeg_debug("Writing WAV header");
136
137 /* Fill out our wav-header with some information. */
138 size -= 8;
139 wave.riff.len = reorder_32 ((uint32_t)size, big_endian);
140
141 size -= 20+sizeof(struct common_struct);
142 wave.data.len = reorder_32 ((uint32_t)size, big_endian);
143
144 if (do_write(fd, &wave, sizeof(wave)) < sizeof(wave))
145 {
146 mjpeg_error("wav-header write failed -- file is corrupt");
147 goto EXIT;
148 }
149 mjpeg_info("WAV done");
150 EXIT:
151 close(fd);
152 }
153
154 /* The typical help output */
Usage(char * str)155 void Usage(char *str)
156 {
157 fprintf(stderr, "Usage: %s [options] inputfiles\n",str);
158 fprintf(stderr, "where options are:\n");
159 fprintf(stderr, "-o num Start extracting at video frame (num)\n");
160 fprintf(stderr, "-f num Extract (num) frames of audio\n");
161 fprintf(stderr, "-s/-c Backwards compatibility options for -o/-f\n");
162 fprintf(stderr, "-v num verbose level [0..2]\n");
163 fprintf(stderr, "-I Ignore unsupported bitrates/bits per sample\n");
164 fprintf(stderr, "-r sr,bs,ch If the file does not contain any sound generate silence\n");
165 fprintf(stderr, " sr samplerate 32000,44100,48000 bs bytesize 8,16, ch channes 1/2\n");
166 fprintf(stderr, "-R The same as -r but now a silence with 44100, 16, 2 is created\n");
167
168 exit(0);
169 }
170
171 /* Setting the type of silence, samplerate, bitesize, chanels */
set_silence(char * optarg)172 void set_silence (char *optarg)
173 {
174 unsigned int u1, u2, u3;
175 int i;
176
177 i = (sscanf (optarg, "%i,%i,%i", &u1, &u2, &u3));
178
179 if (i != 3)
180 mjpeg_error_exit1("Wrong number of arguments given to the -r option");
181 else /*Setting user chosen values */
182 {
183 if ( (u1 == 32000) || (u1 == 44100) || (u1 == 48000) )
184 silence_sr = u1;
185 else
186 mjpeg_error_exit1("Wrong sampelrate use: 32000,44100,48000, exiting");
187
188 if ( (u2 == 8) || (u2 == 16) )
189 silence_bs = u2;
190 else
191 mjpeg_error_exit1("Wrong audio bitsize use 8 or 16, exiting");
192
193 if ( (u3 == 1) || (u3 == 2) )
194 silence_ch = u3;
195 else
196 mjpeg_error_exit1("Wrong number of chanels use 1 or 2, exiting");
197 }
198
199 mjpeg_info("Setting silence to %i sampelrate, %i bitsize, %i chanels",
200 silence_sr, silence_bs, silence_ch);
201 }
202
203 int
main(argc,argv)204 main(argc, argv)
205 int argc;
206 char **argv;
207 {
208 int n,f,i;
209 int res;
210 int warned = 0;
211 int start_frame = 0;
212 int num_frames = -1;
213 int ignore_bitrate = 0;
214 int fragments;
215
216 silence_sr=0; /* silence_sr is use for detecting if the -r option is used */
217 silence_bs=0; silence_ch=0;
218
219 while( (n=getopt(argc,argv,"v:s:r:Rc:o:f:I")) != EOF)
220 {
221 switch(n) {
222
223 case 'v':
224 verbose = atoi(optarg);
225 if( verbose < 0 || verbose > 2 )
226 Usage(argv[0]);
227 break;
228 case 'o':
229 case 's':
230 start_frame = atoi(optarg);
231 break;
232 case 'r':
233 set_silence(optarg);
234 break;
235 case 'R':
236 silence_sr=44100;
237 silence_bs=16;
238 silence_ch=2;
239 break;
240 case 'f':
241 case 'c':
242 num_frames = atoi(optarg);
243 break;
244 case 'I':
245 ignore_bitrate = 1;
246 break;
247 case '?':
248 Usage(argv[0]);
249 }
250 }
251
252 big_endian = lav_detect_endian();
253 if (big_endian < 0)
254 exit(1);
255
256 /* Open editlist */
257 if( argc-optind < 1)
258 Usage(argv[0]);
259
260 (void)mjpeg_default_handler_verbosity(verbose);
261
262 read_video_files(argv + optind, argc - optind, &el,0);
263
264 if(!el.has_audio)
265 {
266 if (silence_sr == 0)
267 mjpeg_error_exit1("Input file(s) have no audio, use -r to generate silence");
268 else
269 {
270
271 mjpeg_info("mjpeg_framerate %f ", el.video_fps);
272
273 /* Create wav header (skeleton) on stdout ... */
274 /* audio_bits, audio_rate, audio_chans */
275 wav_header( silence_bs, silence_sr, silence_ch, 1);
276 /* skip to the start frame if specified */
277 f = 0;
278 if (start_frame != 0)
279 f = start_frame;
280 /* num_frames = -1, read em all, else read specified # */
281 if ( num_frames == -1)
282 num_frames = el.video_frames;
283
284 fragments = silence_sr / el.video_fps;
285
286 /* Here is a dirty hack for the number of fragments we put out
287 I dont know a other way how to put out a certain number of \x00
288 So we put always 4bytes of 00h out and reduce the number of
289 fragments. Works perfect for PAL framerate. But in NTSC there is
290 a round problem. At 44k1Hz, 16bs 2ch 0,47 samples/frame
291 That means that we have on second offset per hour of film */
292 if (silence_bs == 8)
293 fragments = fragments / 2;
294 if (silence_ch == 1)
295 fragments = fragments / 2;
296
297 /* Stream out audio wav-style... in per-frame chunks */
298 for( ; f < num_frames; ++f )
299 {
300 for ( i = 0; i < fragments ; i++)
301 do_write (1, "\x0000000", 4);
302 }
303
304 wav_close(1);
305 exit(0);
306 }
307 }
308
309 if (!ignore_bitrate)
310 {
311 if (el.audio_bits!=16)
312 mjpeg_error_exit1("Input file(s) must have 16 bit audio!");
313
314 switch (el.audio_rate) {
315 case 48000 :
316 case 44100 :
317 case 32000 :
318 break;
319 default:
320 mjpeg_error_exit1("Audio rate is %ld Hz - must be 32000, 44100 or 48000!", el.audio_rate);
321 }
322 }
323
324 switch (el.audio_chans) {
325 case 1:
326 case 2:
327 break;
328 default:
329 mjpeg_error_exit1("Audio channels %d not allowed",el.audio_chans);
330 }
331
332 /* Create wav header (skeleton) on stdout ... */
333 wav_header( el.audio_bits, el.audio_rate, el.audio_chans, 1);
334 /* skip to the start frame if specified */
335 f = 0;
336 if (start_frame != 0)
337 f = start_frame;
338 /* num_frames = -1, read em all, else read specified # */
339 if ( num_frames == -1)
340 num_frames = el.video_frames;
341
342 /* Stream out audio wav-style... in per-frame chunks */
343 for( ; f < num_frames; ++f )
344 {
345 n = el_get_audio_data(audio_buff, f, &el, 0);
346 if (n < 0)
347 mjpeg_error_exit1( "Couldn't get audio for frame %d!", f);
348 if( n != 0 )
349 {
350 res = do_write( 1, audio_buff, n );
351 if (res != n)
352 mjpeg_error_exit1("Couldn't write audio for frame %d!",f);
353 }
354
355 else if( f < num_frames && ! warned )
356 {
357 mjpeg_warn("audio ends early at frame %d", f);
358 warned = 1;
359 }
360 }
361
362 wav_close(1);
363 exit(0);
364 }
365