1 /*
2  *  avimerge.c
3  *
4  *  Copyright (C) Thomas Oestreich - June 2001
5  *
6  *  This file is part of transcode, a video stream processing tool
7  *
8  *  transcode is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2, or (at your option)
11  *  any later version.
12  *
13  *  transcode is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with GNU Make; see the file COPYING.  If not, write to
20  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 // TODO: Simplify this code. Immediatly
24 
25 #include "transcode.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 
32 #include "aud_scan.h"
33 #include "aud_scan_avi.h"
34 
35 #define EXE "avimerge"
36 
37 /* AVI_info is no longer in avilib */
38 void AVI_info(avi_t *avifile);
39 
version(void)40 void version(void)
41 {
42   printf("%s (%s v%s) (C) 2001-2004 Thomas Oestreich, T. Bitterberg"
43                         " 2004-2010 Transcode Team\n",
44                       EXE, PACKAGE, VERSION);
45 }
46 
usage(int status)47 static void usage(int status)
48 {
49     version();
50     printf("\nUsage: %s [options]\n", EXE);
51     printf("    -o file                   output file name\n");
52     printf("    -i file1 [file2 [...]]    input file(s)\n");
53     printf("    -p file                   multiplex additional audio track from file\n");
54     printf("    -a num                    select audio track number from input file [0]\n");
55     printf("    -A num                    select audio track number in output file [next]\n");
56     printf("    -b n                      handle vbr audio [autodetect]\n");
57     printf("    -c                        drop video frames in case audio is missing [off]\n");
58     printf("    -f FILE                   read AVI comments from FILE [off]\n");
59     printf("    -x FILE                   read AVI index from FILE [off] (see aviindex(1))\n");
60     exit(status);
61 }
62 
63 static char data[SIZE_RGB_FRAME];
64 static char *comfile = NULL;
65 static char *indexfile = NULL;
66 long sum_frames = 0;
67 int is_vbr=1;
68 int drop_video=0;
69 
70 
merger(avi_t * out,char * file)71 static int merger(avi_t *out, char *file)
72 {
73     avi_t *in;
74     long frames, n, bytes;
75     int key, j, aud_tracks;
76     static int init = 0;
77     static int vid_chunks = 0;
78 
79     double fps;
80     static double vid_ms;
81     static double aud_ms[AVI_MAX_TRACKS];
82     int have_printed=0;
83     int do_drop_video=0;
84 
85     if (!init) {
86 	for (j=0; j<AVI_MAX_TRACKS; j++)
87 	    aud_ms[j] = 0.0;
88 	vid_ms = 0;
89 	vid_chunks = 0;
90 	init = 1;
91     }
92 
93     if(indexfile)  {
94 	if (NULL == (in = AVI_open_input_indexfile(file, 0, indexfile))) {
95 	    AVI_print_error("AVI open with indexfile");
96 	    return(-1);
97 	}
98     }
99     else if(NULL == (in = AVI_open_input_file(file,1))) {
100 	AVI_print_error("AVI open");
101 	return(-1);
102     }
103 
104     AVI_seek_start(in);
105     fps    =  AVI_frame_rate(in);
106     frames =  AVI_video_frames(in);
107     aud_tracks = AVI_audio_tracks(in);
108 
109     for (n=0; n<frames; ++n) {
110 
111       ++vid_chunks;
112       vid_ms = vid_chunks*1000.0/fps;
113 
114       // audio
115       for(j=0; j<aud_tracks; ++j) {
116 
117 	  int ret;
118 	  double old_ms = aud_ms[j];
119 
120 	  AVI_set_audio_track(in, j);
121 	  AVI_set_audio_track(out, j);
122 
123 	  ret = sync_audio_video_avi2avi (vid_ms, &aud_ms[j], in, out);
124 	  if (ret<0) {
125 	      if (ret==-2) {
126 		  if (aud_ms[j] == old_ms) {
127 		      do_drop_video = 1;
128 		      if (!have_printed) {
129 			  fprintf(stderr, "\nNo audiodata left for track %d->%d (%.2f=%.2f) %s ..\n",
130 			      AVI_get_audio_track(in), AVI_get_audio_track(out),
131 			      old_ms, aud_ms[j], (do_drop_video && drop_video)?"breaking (-c)":"continuing");
132 			  have_printed++;
133 		      }
134 		  }
135 	      } else {
136 		  fprintf(stderr, "\nAn error happend at frame %ld track %d\n", n, j);
137 	      }
138 	  }
139 
140       }
141 
142       if (do_drop_video && drop_video) {
143 	  fprintf(stderr, "\n[avimerge] Dropping %ld frames\n", frames-n-1);
144 	  goto out;
145       }
146 
147       // video
148       bytes = AVI_read_frame(in, data, &key);
149 
150       if(bytes < 0) {
151 	AVI_print_error("AVI read video frame");
152 	return(-1);
153       }
154 
155       if(AVI_write_frame(out, data, bytes, key)<0) {
156 	AVI_print_error("AVI write video frame");
157 	return(-1);
158       }
159 
160       // progress
161       fprintf(stderr, "[%s] (%06ld-%06ld) (%.2f <-> %.2f)\r", file, sum_frames, sum_frames + n, vid_ms, aud_ms[0]);
162     }
163 out:
164     fprintf(stderr, "\n");
165 
166     AVI_close(in);
167 
168     sum_frames += n;
169 
170     return(0);
171 }
172 
173 
main(int argc,char * argv[])174 int main(int argc, char *argv[])
175 {
176   avi_t *avifile, *avifile1, *avifile2;
177 
178   char *outfile=NULL, *infile=NULL, *audfile=NULL;
179 
180   long rate, mp3rate;
181 
182   int j, ch, cc=0, track_num=0, out_track_num=-1;
183   int width, height, format=0, format_add, chan, bits, aud_error=0;
184 
185   double fps;
186 
187   char *codec;
188 
189   long offset, frames, n, bytes, aud_offset=0;
190 
191   int key;
192 
193   int aud_tracks;
194 
195   // for mp3 audio
196   FILE *f=NULL;
197   int len, headlen, chan_i, rate_i, mp3rate_i;
198   unsigned long vid_chunks=0;
199   char head[8];
200   off_t pos;
201   double aud_ms = 0.0, vid_ms = 0.0;
202   double aud_ms_w[AVI_MAX_TRACKS];
203 
204   ac_init(AC_ALL);
205 
206   if(argc==1) usage(EXIT_FAILURE);
207 
208   while ((ch = getopt(argc, argv, "A:a:b:ci:o:p:f:x:?hv")) != -1) {
209 
210     switch (ch) {
211 
212     case 'i':
213 
214       if(optarg[0]=='-') usage(EXIT_FAILURE);
215       infile = optarg;
216 
217       break;
218 
219     case 'A':
220 
221       if(optarg[0]=='-') usage(EXIT_FAILURE);
222       out_track_num = atoi(optarg);
223 
224       if(out_track_num<-1) usage(EXIT_FAILURE);
225 
226       break;
227 
228     case 'a':
229 
230       if(optarg[0]=='-') usage(EXIT_FAILURE);
231       track_num = atoi(optarg);
232 
233       if(track_num<0) usage(EXIT_FAILURE);
234 
235       break;
236 
237     case 'b':
238 
239       if(optarg[0]=='-') usage(EXIT_FAILURE);
240       is_vbr = atoi(optarg);
241 
242       if(is_vbr<0) usage(EXIT_FAILURE);
243 
244       break;
245 
246     case 'c':
247 
248       drop_video = 1;
249 
250       break;
251 
252     case 'o':
253 
254       if(optarg[0]=='-') usage(EXIT_FAILURE);
255       outfile = optarg;
256 
257       break;
258 
259     case 'p':
260 
261       if(optarg[0]=='-') usage(EXIT_FAILURE);
262       audfile = optarg;
263 
264       break;
265 
266     case 'f':
267 
268       if(optarg[0]=='-') usage(EXIT_FAILURE);
269       comfile = optarg;
270 
271       break;
272 
273 
274     case 'x':
275 
276       if(optarg[0]=='-') usage(EXIT_FAILURE);
277       indexfile = optarg;
278 
279       break;
280 
281     case 'v':
282       version();
283       exit(EXIT_SUCCESS);
284     case 'h':
285       usage(EXIT_SUCCESS);
286     default:
287       usage(EXIT_FAILURE);
288     }
289   }
290 
291   if(outfile == NULL || infile == NULL) usage(EXIT_FAILURE);
292 
293   printf("scanning file %s for video/audio parameter\n", infile);
294 
295   // open first file for video/audio info read only
296   if(indexfile) {
297       if (NULL == (avifile1 = AVI_open_input_indexfile(infile,0,indexfile))) {
298 	  AVI_print_error("AVI open with index file");
299       }
300   }
301   else if(NULL == (avifile1 = AVI_open_input_file(infile,1))) {
302       AVI_print_error("AVI open");
303       exit(1);
304   }
305 
306   AVI_info(avifile1);
307 
308   // safety checks
309 
310   if(strcmp(infile, outfile)==0) {
311     printf("error: output filename conflicts with input filename\n");
312     exit(1);
313   }
314 
315   ch = optind;
316 
317   while (ch < argc) {
318 
319     if(tc_file_check(argv[ch]) != 0) {
320       printf("error: file not found\n");
321       exit(1);
322     }
323 
324     if(strcmp(argv[ch++], outfile)==0) {
325       printf("error: output filename conflicts with input filename\n");
326       exit(1);
327     }
328   }
329 
330   // open output file
331   if(NULL == (avifile = AVI_open_output_file(outfile))) {
332     AVI_print_error("AVI open");
333     exit(1);
334   }
335 
336 
337   // read video info;
338 
339   width  =  AVI_video_width(avifile1);
340   height =  AVI_video_height(avifile1);
341 
342   fps    =  AVI_frame_rate(avifile1);
343   codec  =  AVI_video_compressor(avifile1);
344 
345   //set video in outputfile
346   AVI_set_video(avifile, width, height, fps, codec);
347 
348   if (comfile!=NULL)
349     AVI_set_comment_fd(avifile, open(comfile, O_RDONLY));
350 
351   //multi audio tracks?
352   aud_tracks = AVI_audio_tracks(avifile1);
353   if (out_track_num < 0) out_track_num = aud_tracks;
354 
355   for(j=0; j<aud_tracks; ++j) {
356 
357       if (out_track_num == j) continue;
358       AVI_set_audio_track(avifile1, j);
359 
360       rate   =  AVI_audio_rate(avifile1);
361       chan   =  AVI_audio_channels(avifile1);
362       bits   =  AVI_audio_bits(avifile1);
363 
364       format =  AVI_audio_format(avifile1);
365       mp3rate=  AVI_audio_mp3rate(avifile1);
366       //printf("TRACK %d MP3RATE %ld VBR %ld\n", j, mp3rate, AVI_get_audio_vbr(avifile1));
367 
368       //set next track of output file
369       AVI_set_audio_track(avifile, j);
370       AVI_set_audio(avifile, chan, rate, bits, format, mp3rate);
371       AVI_set_audio_vbr(avifile, AVI_get_audio_vbr(avifile1));
372   }
373 
374   if(audfile!=NULL) goto audio_merge;
375 
376   // close reopen in merger function
377   AVI_close(avifile1);
378 
379   //-------------------------------------------------------------
380 
381   printf("merging multiple AVI-files (concatenating) ...\n");
382 
383   // extract and write to new files
384 
385   printf ("file %02d %s\n", ++cc, infile);
386   merger(avifile, infile);
387 
388   while (optind < argc) {
389 
390     printf ("file %02d %s\n", ++cc, argv[optind]);
391     merger(avifile, argv[optind++]);
392   }
393 
394   // close new AVI file
395 
396   AVI_close(avifile);
397 
398   printf("... done merging %d file(s) in %s\n", cc, outfile);
399 
400   // reopen file for video/audio info
401   if(NULL == (avifile = AVI_open_input_file(outfile,1))) {
402     AVI_print_error("AVI open");
403     exit(1);
404   }
405   AVI_info(avifile);
406 
407   return(0);
408 
409   //-------------------------------------------------------------
410 
411 
412 // *************************************************
413 // Merge the audio track of an additional AVI file
414 // *************************************************
415 
416  audio_merge:
417 
418   printf("merging audio %s track %d (multiplexing) into %d ...\n", audfile, track_num, out_track_num);
419 
420   // open audio file read only
421   if(NULL == (avifile2 = AVI_open_input_file(audfile,1))) {
422     int f=open(audfile, O_RDONLY), ret=0;
423     char head[1024], *c;
424     c = head;
425     if (f>0 && (1024 == read(f, head, 1024)) ) {
426       while ((c-head<1024-8) && (ret = tc_probe_audio_header(c, 8))<=0 ) {
427 	c++;
428       }
429       close(f);
430 
431       if (ret > 0) {
432 	aud_offset = c-head;
433 	//printf("found atrack 0x%x off=%ld\n", ret, aud_offset);
434 	goto merge_mp3;
435       }
436     }
437 
438     AVI_print_error("AVI open");
439     exit(1);
440   }
441 
442   AVI_info(avifile2);
443 
444   //switch to requested track
445 
446   if(AVI_set_audio_track(avifile2, track_num)<0) {
447     fprintf(stderr, "invalid audio track\n");
448   }
449 
450   rate   =  AVI_audio_rate(avifile2);
451   chan   =  AVI_audio_channels(avifile2);
452   bits   =  AVI_audio_bits(avifile2);
453 
454   format =  AVI_audio_format(avifile2);
455   mp3rate=  AVI_audio_mp3rate(avifile2);
456 
457   //set next track
458   AVI_set_audio_track(avifile, out_track_num);
459   AVI_set_audio(avifile, chan, rate, bits, format, mp3rate);
460   AVI_set_audio_vbr(avifile, AVI_get_audio_vbr(avifile2));
461 
462   AVI_seek_start(avifile1);
463   frames =  AVI_video_frames(avifile1);
464   offset = 0;
465 
466   printf ("file %02d %s\n", ++cc, infile);
467 
468   for (n=0; n<AVI_MAX_TRACKS; n++)
469     aud_ms_w[n] = 0.0;
470   vid_chunks=0;
471 
472   for (n=0; n<frames; ++n) {
473 
474     // video
475     bytes = AVI_read_frame(avifile1, data, &key);
476 
477     if(bytes < 0) {
478       AVI_print_error("AVI read video frame");
479       return(-1);
480     }
481 
482     if(AVI_write_frame(avifile, data, bytes, key)<0) {
483       AVI_print_error("AVI write video frame");
484       return(-1);
485     }
486     ++vid_chunks;
487     vid_ms = vid_chunks*1000.0/fps;
488 
489     for(j=0; j<aud_tracks; ++j) {
490 
491       if (j == out_track_num) continue;
492       AVI_set_audio_track(avifile1, j);
493       AVI_set_audio_track(avifile, j);
494       chan   = AVI_audio_channels(avifile1);
495 
496       // audio
497       chan = AVI_audio_channels(avifile1);
498       if(chan) {
499 	  sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile);
500       }
501     }
502 
503 
504     // merge additional track
505 
506     // audio
507     chan = AVI_audio_channels(avifile2);
508     AVI_set_audio_track(avifile, out_track_num);
509 
510     if(chan) {
511 	sync_audio_video_avi2avi(vid_ms, &aud_ms, avifile2, avifile);
512     }
513 
514     // progress
515     fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n);
516 
517   }
518 
519   fprintf(stderr,"\n");
520 
521   offset = frames;
522 
523   //more files to merge?
524 
525   AVI_close(avifile1);
526 
527   while (optind < argc) {
528 
529     printf ("file %02d %s\n", ++cc, argv[optind]);
530 
531     if(NULL == ( avifile1 = AVI_open_input_file(argv[optind++],1))) {
532       AVI_print_error("AVI open");
533       goto finish;
534     }
535 
536     AVI_seek_start(avifile1);
537     frames =  AVI_video_frames(avifile1);
538 
539     for (n=0; n<frames; ++n) {
540 
541       // video
542       bytes = AVI_read_frame(avifile1, data, &key);
543 
544       if(bytes < 0) {
545 	AVI_print_error("AVI read video frame");
546 	return(-1);
547       }
548 
549       if(AVI_write_frame(avifile, data, bytes, key)<0) {
550 	AVI_print_error("AVI write video frame");
551 	return(-1);
552       }
553 
554       ++vid_chunks;
555       vid_ms = vid_chunks*1000.0/fps;
556 
557       // audio
558       for(j=0; j<aud_tracks; ++j) {
559 
560 	if (j == out_track_num) continue;
561 	AVI_set_audio_track(avifile1, j);
562 	AVI_set_audio_track(avifile, j);
563 
564 	chan   = AVI_audio_channels(avifile1);
565 
566 	if(chan) {
567 	  sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile);
568 	}
569       }
570 
571       // merge additional track
572 
573       chan   = AVI_audio_channels(avifile2);
574       AVI_set_audio_track(avifile, out_track_num);
575 
576       if(chan) {
577 	  sync_audio_video_avi2avi(vid_ms, &aud_ms, avifile2, avifile);
578       } // chan
579 
580       // progress
581       fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n);
582     }
583 
584     fprintf(stderr, "\n");
585 
586     offset += frames;
587     AVI_close(avifile1);
588   }
589 
590  finish:
591 
592   // close new AVI file
593 
594   printf("... done multiplexing in %s\n", outfile);
595 
596   AVI_info(avifile);
597   AVI_close(avifile);
598 
599   return(0);
600 
601 
602 // *************************************************
603 // Merge a raw audio file which is either MP3 or AC3
604 // *************************************************
605 
606 merge_mp3:
607 
608   f = fopen(audfile,"rb");
609   if (!f) { perror ("fopen"); exit(1); }
610 
611   fseek(f, aud_offset, SEEK_SET);
612   len = fread(head, 1, 8, f);
613   format_add  = tc_probe_audio_header(head, len);
614   headlen = tc_get_audio_header(head, len, format_add, &chan_i, &rate_i, &mp3rate_i);
615   fprintf(stderr, "... this looks like a %s track ...\n", (format_add==0x55)?"MP3":"AC3");
616 
617   fseek(f, aud_offset, SEEK_SET);
618 
619   //set next track
620   AVI_set_audio_track(avifile, out_track_num);
621   AVI_set_audio(avifile, chan_i, rate_i, 16, format_add, mp3rate_i);
622   AVI_set_audio_vbr(avifile, is_vbr);
623 
624   AVI_seek_start(avifile1);
625   frames =  AVI_video_frames(avifile1);
626   offset = 0;
627 
628   for (n=0; n<AVI_MAX_TRACKS; ++n)
629       aud_ms_w[n] = 0.0;
630 
631   for (n=0; n<frames; ++n) {
632 
633     // video
634     bytes = AVI_read_frame(avifile1, data, &key);
635 
636     if(bytes < 0) {
637       AVI_print_error("AVI read video frame");
638       return(-1);
639     }
640 
641     if(AVI_write_frame(avifile, data, bytes, key)<0) {
642       AVI_print_error("AVI write video frame");
643       return(-1);
644     }
645 
646     vid_chunks++;
647     vid_ms = vid_chunks*1000.0/fps;
648 
649     for(j=0; j<aud_tracks; ++j) {
650 
651       if (j == out_track_num) continue;
652       AVI_set_audio_track(avifile1, j);
653       AVI_set_audio_track(avifile, j);
654       chan   = AVI_audio_channels(avifile1);
655 
656       if(chan) {
657 	sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile);
658       }
659     }
660 
661 
662     // merge additional track
663 
664     if(headlen>4 && !aud_error) {
665       while (aud_ms < vid_ms) {
666 	//printf("reading Audio Chunk ch(%ld) vms(%lf) ams(%lf)\n", vid_chunks, vid_ms, aud_ms);
667 	pos = ftell(f);
668 
669 	len = fread (head, 1, 8, f);
670 	if (len<=0) { //eof
671 	  fprintf(stderr, "EOF in %s; continuing ..\n", audfile);
672 	  aud_error=1;
673 	  break;
674 	}
675 
676 	if ( (headlen = tc_get_audio_header(head, len, format_add, NULL, NULL, &mp3rate_i))<0) {
677 	  fprintf(stderr, "Broken %s track #(%d)? skipping\n", (format_add==0x55?"MP3":"AC3"), aud_tracks);
678 	  aud_ms = vid_ms;
679 	  aud_error=1;
680 	} else { // look in import/tcscan.c for explanation
681 	  aud_ms += (headlen*8.0)/(mp3rate_i);
682 	}
683 
684 	fseek (f, pos, SEEK_SET);
685 
686 	len = fread (data, headlen, 1, f);
687 	if (len<=0) { //eof
688 	  fprintf(stderr, "EOF in %s; continuing ..\n", audfile);
689 	  aud_error=1;
690 	  break;
691 	}
692 
693 	AVI_set_audio_track(avifile, out_track_num);
694 
695 	if(AVI_write_audio(avifile, data, headlen)<0) {
696 	  AVI_print_error("AVI write audio frame");
697 	  return(-1);
698 	}
699 
700       }
701     }
702 
703     // progress
704     fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n);
705 
706   }
707 
708   fprintf(stderr,"\n");
709   offset = frames;
710 
711   // more files?
712   while (optind < argc) {
713 
714     printf ("file %02d %s\n", ++cc, argv[optind]);
715 
716     if(NULL == ( avifile1 = AVI_open_input_file(argv[optind++],1))) {
717       AVI_print_error("AVI open");
718       goto finish;
719     }
720 
721     AVI_seek_start(avifile1);
722     frames =  AVI_video_frames(avifile1);
723 
724     for (n=0; n<frames; ++n) {
725 
726       // video
727       bytes = AVI_read_frame(avifile1, data, &key);
728 
729       if(bytes < 0) {
730 	AVI_print_error("AVI read video frame");
731 	return(-1);
732       }
733 
734       if(AVI_write_frame(avifile, data, bytes, key)<0) {
735 	AVI_print_error("AVI write video frame");
736 	return(-1);
737       }
738 
739       vid_chunks++;
740       vid_ms = vid_chunks*1000.0/fps;
741 
742       for(j=0; j<aud_tracks; ++j) {
743 
744 	if (j == out_track_num) continue;
745 	AVI_set_audio_track(avifile1, j);
746 	AVI_set_audio_track(avifile, j);
747 	chan   = AVI_audio_channels(avifile1);
748 
749 	if(chan) {
750 	  sync_audio_video_avi2avi(vid_ms, &aud_ms_w[j], avifile1, avifile);
751 	}
752       }
753 
754       // merge additional track
755       // audio
756 
757       if(headlen>4 && !aud_error) {
758 	while (aud_ms < vid_ms) {
759 	  //printf("reading Audio Chunk ch(%ld) vms(%lf) ams(%lf)\n", vid_chunks, vid_ms, aud_ms);
760 	  pos = ftell(f);
761 
762 	  len = fread (head, 8, 1, f);
763 	  if (len<=0) { //eof
764 	    fprintf(stderr, "EOF in %s; continuing ..\n", audfile);
765 	    aud_error=1; break;
766 	  }
767 
768 	  if ( (headlen = tc_get_audio_header(head, len, format_add, NULL, NULL, &mp3rate_i))<0) {
769 	    fprintf(stderr, "Broken %s track #(%d)?\n", (format_add==0x55?"MP3":"AC3"), aud_tracks);
770 	    aud_ms = vid_ms;
771 	    aud_error=1;
772 	  } else { // look in import/tcscan.c for explanation
773 	    aud_ms += (headlen*8.0)/(mp3rate_i);
774 	  }
775 
776 	  fseek (f, pos, SEEK_SET);
777 
778 	  len = fread (data, headlen, 1, f);
779 	  if (len<=0) { //eof
780 	    fprintf(stderr, "EOF in %s; continuing ..\n", audfile);
781 	    aud_error=1; break;
782 	  }
783 
784 	  AVI_set_audio_track(avifile, out_track_num);
785 
786 	  if(AVI_write_audio(avifile, data, headlen)<0) {
787 	    AVI_print_error("AVI write audio frame");
788 	    return(-1);
789 	  }
790 
791 	}
792       }
793 
794       // progress
795       fprintf(stderr, "[%s] (%06ld-%06ld)\r", outfile, offset, offset + n);
796     }
797 
798     fprintf(stderr, "\n");
799 
800     offset += frames;
801     AVI_close(avifile1);
802   }
803 
804 
805   if (f) fclose(f);
806 
807   printf("... done multiplexing in %s\n", outfile);
808 
809   AVI_close(avifile);
810 
811   return(0);
812 }
813 
814 /*************************************************************************/
815 
816 /*
817  * Local variables:
818  *   c-file-style: "stroustrup"
819  *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
820  *   indent-tabs-mode: nil
821  * End:
822  *
823  * vim: expandtab shiftwidth=4:
824  */
825