applied variable samplerate patch from Marcus Doemling.
[swftools.git] / avi2swf / avi2swf.cc
1 /* avi2swf.cc
2    Convert avi movie files into swf.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001,2002,2003 Matthias Kramm <kramm@quiss.org>
7  
8    This program 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 of the License, or
11    (at your option) any later version.
12
13    This program 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 this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <fcntl.h>
26
27 #include "../config.h"
28
29 #ifdef HAVE_SIGNAL_H
30 #ifdef HAVE_PTHREAD_H
31 #include <pthread.h>
32 #include <signal.h>
33 #define DO_SIGNALS
34 #endif
35 #endif
36
37 extern "C" {
38 #include "../lib/args.h"
39 }
40 #include "v2swf.h"
41 #include "../lib/q.h"
42
43 #undef HAVE_CONFIG_H
44 #include <avifile/version.h>
45 #if (AVIFILE_MAJOR_VERSION == 0) && (AVIFILE_MINOR_VERSION>=6) 
46    #include <avifile.h>
47    #include <aviplay.h>
48    #include <fourcc.h>
49    #include <creators.h>
50    #include <StreamInfo.h>
51    #define VERSION6
52 #else
53    #include <avifile.h>
54    #include <aviplay.h>
55    #include <aviutil.h>
56    #define Width width
57    #define Height height
58    #define Data data
59    #define Bpp bpp
60 #endif
61
62 static char * filename = 0;
63 static char * outputfilename = "output.swf";
64 int verbose = 0;
65
66 static int quality = 80;
67 static double scale = 1.0;
68 static int flip = 0;
69 static int expensive = 0;
70 static int flashversion = 6;
71 static int keyframe_interval = -1;
72 static int skip = 0;
73 static float audio_adjust = 0;
74 static int mp3_bitrate = 32;
75
76 struct options_t options[] =
77 {
78  {"v","verbose"},
79  {"A","adjust"},
80  {"o","output"},
81  {"p","flip"},
82  {"m","mp3-bitrate"},
83  {"q","quality"},
84  {"s","scale"},
85  {"S","skip"},
86  {"x","extragood"},
87  {"T","flashversion"},
88  {"V","version"},
89  {0,0}
90 };
91
92 int args_callback_option(char*name,char*val)
93 {
94     if(!strcmp(name, "V")) {
95         printf("avi2swf-ng - part of %s %s\n", PACKAGE, VERSION);
96         exit(0);
97     } 
98     else if(!strcmp(name, "o")) {
99         outputfilename = val;
100         return 1;
101     }
102     else if(!strcmp(name, "q")) {
103         quality = atoi(val);
104         if(quality<0)
105             quality = 0;
106         if(quality>100)
107             quality = 100;
108         return 1;
109     }
110     else if(!strcmp(name, "p")) {
111         flip = 1;
112         return 0;
113     }
114     else if(!strcmp(name, "A")) {
115         audio_adjust = atof(val);
116         return 1;
117     }
118     else if(!strcmp(name, "v")) {
119         verbose = 1;
120         return 0;
121     }
122     else if(!strcmp(name, "T")) {
123         flashversion = atoi(val);
124         return 1;
125     }
126     else if(!strcmp(name, "x")) {
127         expensive = 1;
128         return 0;
129     }
130     else if(!strcmp(name, "m")) {
131         mp3_bitrate = atoi(val);
132         return 0;
133     }
134     else if(!strcmp(name, "S")) {
135         skip = atoi(val);
136         return 1;
137     }
138     else if(!strcmp(name, "s")) {
139         scale = atoi(val)/100.0;
140         if(scale>1.0 || scale<=0) {
141             fprintf(stderr, "Scale must be in the range 1-100!\n");
142             exit(1);
143         }
144         return 1;
145     }
146     fprintf(stderr, "Unknown option: -%s\n", name);
147     exit(1);
148 }
149 int args_callback_longoption(char*name,char*val)
150 {
151     return args_long2shortoption(options, name, val);
152 }
153 void args_callback_usage(char*name)
154 {    
155     printf("\nUsage: %s file.avi\n", name);
156     printf("\t-h , --help\t\t Print help and exit\n");
157     printf("\t-o , --output filename\t Specify output filename\n"); 
158     printf("\t-A , --adjust seconds\t Audio adjust: Shift sound -seconds to the future or +seconds into the past.\n"); 
159     printf("\t-n , --num frames\t Number of frames to encode\n");
160     printf("\t-m , --mp3-bitrate <rate>\t Set the mp3 bitrate to encode audio with\n");
161     printf("\t-d , --scale <val>\t Scale down to factor <val>. (in %, e.g. 100 = original size)\n");
162     printf("\t-p , --flip\t\t Turn movie upside down\n");
163     printf("\t-q , --quality <val>\t Set the quality to <val>. (0-100, 0=worst, 100=best, default:80)\n");
164     printf("\t-x , --extragood\t Enable some *very* expensive compression strategies. You may\n");
165     printf("\t                \t want to let this run overnight.\n");
166     printf("\t-T , --flashversion <n>\t Set output flash version to <n>. Notice: H.263 compression will only be\n");
167     printf("\t                       \t used for n >= 6.\n");
168     printf("\t-V , --version\t\t Print program version and exit\n");
169     exit(0);
170 }
171 int args_callback_command(char*name,char*val)
172 {
173     if(filename) {
174         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
175                  filename, name);
176     }
177     filename = name;
178     return 0;
179 }
180
181 static char toabuf[128];
182 static char*ftoa(double a)
183 {
184     sprintf(toabuf, "%f", a);
185     return toabuf;
186 }
187 static char*itoa(int a)
188 {
189     sprintf(toabuf, "%d", a);
190     return toabuf;
191 }
192
193 typedef struct _videoreader_avifile_internal
194 {
195     IAviReadFile* player;
196     IAviReadStream* astream;
197     IAviReadStream* vstream;
198     int do_audio;
199     int do_video;
200     int eof;
201     int frame;
202     int soundbits;
203     ringbuffer_t audio_buffer;
204 } videoreader_avifile_internal;
205
206 static int shutdown_avi2swf = 0;
207 static int frameno = 0;
208
209 #ifdef DO_SIGNALS
210 pthread_t main_thread;
211 static void sigterm(int sig)
212 {
213     if(pthread_equal (pthread_self(), main_thread))
214     {
215         if(frameno>0 && !shutdown_avi2swf) {
216             if(verbose)
217                 printf("Thread [%08x] got sigterm %d\n", pthread_self(), sig);
218             shutdown_avi2swf++;
219         } else {
220             exit(1);
221         }
222     }
223 }
224 #endif
225
226 static void readSamples(videoreader_avifile_internal*i, void*buffer, int buffer_size, int numsamples)
227 {
228     int ret;
229     while(i->audio_buffer.available < buffer_size) {
230         unsigned int samples_read = 0, bytes_read = 0;
231         ret = i->astream->ReadFrames(buffer, buffer_size, numsamples, samples_read, bytes_read);
232         if(samples_read<=0)
233             return;
234         ringbuffer_put(&i->audio_buffer, buffer, bytes_read);
235     }
236     ringbuffer_read(&i->audio_buffer, buffer, buffer_size);
237 }
238 int videoreader_avifile_getsamples(videoreader_t* v, void*buffer, int num)
239 {
240     if(verbose) {
241         printf("videoreader_getsamples(%d)\n", num);fflush(stdout);
242     }
243     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
244     if(i->soundbits == 8) {
245         readSamples(i, buffer, num/2, num/(v->channels*2));
246         unsigned char*b = (unsigned char*)buffer;
247         int t;
248         for(t=num-2;t>=0;t-=2) {
249             unsigned char x = b[t/2];
250             b[t] = 0;
251             b[t+1] = x-128;
252         }
253         return num;
254     }
255     if(i->soundbits == 16) {
256         readSamples(i, buffer, num, num/(v->channels*2));
257         return num;
258     }
259     return 0;
260 }
261 int videoreader_avifile_getimage(videoreader_t* v, void*buffer)
262 {
263     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
264     if(verbose) {
265         printf("videoreader_getimage()\n");fflush(stdout);
266     }
267
268     if(shutdown_avi2swf)
269         i->eof = 1;
270     
271     if(i->eof)
272         return 0;
273
274     if(i->vstream->ReadFrame() < 0) {
275         if(verbose) printf("vstream->ReadFrame() returned value < 0, shutting down...\n");
276         i->eof = 1;
277         return 0;
278     }
279     CImage*img2 = 0;
280     CImage*img = i->vstream->GetFrame();
281     if(!img) {
282         if(verbose) printf("vstream->GetFrame() returned NULL, shutting down...\n");
283         i->eof = 1;
284         return 0;
285     }
286     /* we convert the image to YUV first, because we can convert to RGB from YUV only */
287     img->ToYUV();
288     img->ToRGB();
289     if(img->Bpp() != 3) {
290         /* TODO: this doesn't work yet */
291         if(verbose) printf("Can't handle Bpp %d, shutting down...\n", img->Bpp());
292         return 0;
293         BitmapInfo tmp(v->width, v->height, 24);
294         img2 = new CImage(img, &tmp);
295         img = img2;
296     }
297
298
299     frameno++;
300     i->frame++;
301     unsigned char*data = img->Data();
302     int bpp = img->Bpp();
303     if(bpp == 3) {
304         int x,y;
305         for(y=0;y<v->height;y++) {
306             unsigned char*from,*to;
307             to = &((unsigned char*)buffer)[y*v->width*4];
308             if(flip)
309                 from = img->At(v->height-y-1);
310             else
311                 from = img->At(y);
312             for(x=0;x<v->width;x++) {
313                 to[x*4+0] = 0;
314                 to[x*4+1] = from[x*3+2];
315                 to[x*4+2] = from[x*3+1];
316                 to[x*4+3] = from[x*3+0];
317             }
318         }
319         if(img2) delete img2;
320         return v->width*v->height*4;
321     } else {
322         if(img2) delete img2;
323         if(verbose) printf("Can't handle bpp %d, shutting down...\n", bpp);
324         return 0;
325     }
326 }
327 bool videoreader_avifile_eof(videoreader_t* v)
328 {
329     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
330     if(verbose) {
331         printf("videoreader_eof()\n");fflush(stdout);
332     }
333     return i->eof;
334 }
335 void videoreader_avifile_close(videoreader_t* v)
336 {
337     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
338     if(verbose) {
339         printf("videoreader_close()\n");fflush(stdout);
340     }
341     if(i->do_audio) {
342         ringbuffer_clear(&i->audio_buffer);
343     }
344 }
345 void* videoreader_avifile_getinfo(videoreader_t* v, char* name)
346 {
347     return 0;
348 }
349 void videoreader_avifile_setparameter(videoreader_t*v, char*name, char*value)
350 {
351     if(verbose) {
352         printf("videoreader_setparameter(%s, %s)\n", name, value);fflush(stdout);
353     }
354 }
355
356 int videoreader_avifile_open(videoreader_t* v, char* filename)
357 {
358     videoreader_avifile_internal* i;
359     i = (videoreader_avifile_internal*)malloc(sizeof(videoreader_avifile_internal));
360     memset(i, 0, sizeof(videoreader_avifile_internal));
361     memset(v, 0, sizeof(videoreader_t));
362     v->getsamples = videoreader_avifile_getsamples;
363     v->getinfo = videoreader_avifile_getinfo;
364     v->close = videoreader_avifile_close;
365     v->eof = videoreader_avifile_eof;
366     v->getimage = videoreader_avifile_getimage;
367     v->getsamples = videoreader_avifile_getsamples;
368     v->setparameter = videoreader_avifile_setparameter;
369     v->internal = i;
370     
371     i->do_video = 1;
372     i->do_audio = 1;
373
374     i->player = CreateIAviReadFile(filename);    
375     if(verbose) {
376         printf("%d streams (%d video, %d audio)\n", 
377                 i->player->StreamCount(),
378                 i->player->VideoStreamCount(),
379                 i->player->AudioStreamCount());
380     }
381     i->astream = i->player->GetStream(0, AviStream::Audio);
382     i->vstream = i->player->GetStream(0, AviStream::Video);
383     if(!i->vstream) {
384         printf("Couldn't open video stream\n");
385         i->do_video = 0;
386     }
387     if(!i->astream) {
388         printf("Couldn't open video stream\n");
389         i->do_audio = 0;
390     }
391
392     if(!i->do_video && !i->do_audio) {
393         printf("File has neither audio nor video streams.(?)\n");
394         return 0;
395     }
396
397 #ifndef VERSION6
398     MainAVIHeader head;
399     int dwMicroSecPerFrame = 0;
400     player->GetFileHeader(&head);
401     printf("fps: %d\n", 1000000/head.dwMicroSecPerFrame);
402     printf("frames: %d\n", head.dwTotalFrames);
403     printf("streams: %d\n", head.dwStreams);
404     printf("width: %d\n", head.dwWidth);
405     printf("height: %d\n", head.dwHeight);
406     printf("sound: %u samples (%f seconds)\n", i->astream->GetEndPos(), i->astream->GetEndTime());
407     v->width = head.dwWidth;
408     v->height = head.dwHeight;
409     dwMicroSecPerFrame = head.dwMicroSecPerFrame;
410     samplesperframe = astream->GetEndPos()/astream->GetEndTime()*head.dwMicroSecPerFrame/1000000;
411     v->rate = (int)(astream->GetEndPos()/astream->GetEndTime());
412     v->fps = 1000000.0/dwMicroSecPerFrame;
413     i->soundbits = 16;
414 #else
415     if(i->do_video)
416     {
417         StreamInfo*videoinfo;
418         videoinfo = i->vstream->GetStreamInfo();
419         v->width = videoinfo->GetVideoWidth();
420         v->height = videoinfo->GetVideoHeight();
421         v->fps = (double)(videoinfo->GetFps());
422     }
423     if(i->do_audio)
424     {
425         WAVEFORMATEX wave;
426         StreamInfo*audioinfo;
427
428         i->astream->GetAudioFormatInfo(&wave,0);
429         audioinfo = i->astream->GetStreamInfo();
430
431         v->channels = wave.nChannels;
432         v->rate = wave.nSamplesPerSec;
433         i->soundbits = wave.wBitsPerSample;
434
435         if(v->channels==0 || v->rate==0 || i->soundbits==0 || wave.wFormatTag!=1) {
436             v->rate = audioinfo->GetAudioSamplesPerSec();
437             v->channels = audioinfo->GetAudioChannels();
438             i->soundbits = audioinfo->GetAudioBitsPerSample();
439         }
440
441         if(verbose) {
442             printf("formatinfo: format %d, %d channels, %d bits/sample, rate %d, blockalign %d\n", wave.wFormatTag, wave.nChannels, wave.wBitsPerSample, wave.nSamplesPerSec, wave.nBlockAlign);
443             printf("audioinfo: %d channels, %d bits/sample, rate %d\n", audioinfo->GetAudioChannels(), audioinfo->GetAudioBitsPerSample(), audioinfo->GetAudioSamplesPerSec());
444         }
445         if(i->soundbits != 8 && i->soundbits != 16) {
446             printf("Can't handle %d bit audio, disabling sound\n", wave.wBitsPerSample);
447             i->do_audio = 0;
448             i->soundbits = 0;
449             v->channels = 0;
450             v->rate = 0;
451         }
452     }
453 #endif
454     i->vstream -> StartStreaming();
455     if(i->do_audio) {
456         i->astream -> StartStreaming();
457         ringbuffer_init(&i->audio_buffer);
458 #ifdef VERSION6
459         WAVEFORMATEX wave;
460         i->astream -> GetOutputFormat(&wave, sizeof(wave));
461         printf("formatinfo: format %d, %d channels, %d bits/sample, rate %d, blockalign %d\n", wave.wFormatTag, wave.nChannels, wave.wBitsPerSample, wave.nSamplesPerSec, wave.nBlockAlign);
462 #endif
463     }
464
465     return 1;
466 }
467
468 int main (int argc,char ** argv)
469
470     videoreader_t video;
471     v2swf_t v2swf;
472     int ret;
473     FILE*fi;
474
475 #ifdef DO_SIGNALS
476     signal(SIGTERM, sigterm);
477     signal(SIGINT , sigterm);
478     signal(SIGQUIT, sigterm);
479     main_thread = pthread_self();
480 #endif
481
482     processargs(argc, argv);
483     if(!filename)
484         exit(0);
485     if(keyframe_interval<0) {
486         if(flashversion>=6)
487             keyframe_interval=200;
488         else
489             keyframe_interval=5;
490     }
491     
492     fi = fopen(outputfilename, "wb");
493     if(!fi) {
494         fflush(stdout); fflush(stderr);
495         fprintf(stderr, "Couldn't open %s\n", outputfilename);
496         exit(1);
497     }
498
499     ret = videoreader_avifile_open(&video, filename);
500
501     if(!ret) {
502         printf("Error opening %s\n", filename);
503         exit(1);
504     }
505
506     if(verbose) {
507         printf("| video framerate: %f\n", video.fps);
508         printf("| video size: %dx%d\n", video.width, video.height);
509         printf("| audio rate: %d\n", video.rate);
510         printf("| audio channels: %d\n", video.channels);
511     }
512
513     ret = v2swf_init(&v2swf, &video);
514     if(verbose)
515         v2swf_setparameter(&v2swf, "verbose", "1");
516     v2swf_setparameter(&v2swf, "quality", itoa(quality));
517     v2swf_setparameter(&v2swf, "blockdiff", "0");
518     v2swf_setparameter(&v2swf, "blockdiff_mode", "exact");
519     v2swf_setparameter(&v2swf, "mp3_bitrate", itoa(mp3_bitrate));
520     //v2swf_setparameter(&v2swf, "fixheader", "1");
521     //v2swf_setparameter(&v2swf, "framerate", "15");
522     v2swf_setparameter(&v2swf, "scale", ftoa(scale));
523     v2swf_setparameter(&v2swf, "prescale", "1");
524     v2swf_setparameter(&v2swf, "flash_version", itoa(flashversion));
525     v2swf_setparameter(&v2swf, "keyframe_interval", itoa(keyframe_interval));
526     if(expensive)
527         v2swf_setparameter(&v2swf, "motioncompensation", "1");
528
529     if(!verbose)
530         printf("\n");
531
532     if(audio_adjust>0) {
533         int num = ((int)(audio_adjust*video.rate))*video.channels*2;
534         void*buf = malloc(num);
535         video.getsamples(&video, buf, num);
536         free(buf);
537     } else if(audio_adjust<0) {
538         int num = (int)(-audio_adjust*video.fps);
539         void*buf = malloc(video.width*video.height*4);
540         int t;
541         for(t=0;t<num;t++) {
542             video.getimage(&video, buf);
543         }
544         free(buf);
545     }
546
547     if(skip) {
548         int t;
549         void*buf = malloc(video.width*video.height*4);
550         for(t=0;t<skip;t++) {
551             video.getimage(&video, buf);
552             video.getsamples(&video, buf, (int)((video.rate/video.fps)*video.channels*2));
553             if(!verbose) {
554                 printf("\rSkipping frame %d", frameno);fflush(stdout);
555             }
556         }
557         free(buf);
558     }
559
560     char buffer[4096];
561     while(1) {
562         int l=v2swf_read(&v2swf, buffer, 4096);
563         fwrite(buffer, l, 1, fi);
564         if(!l)
565             break;
566         if(!verbose) {
567             printf("\rConverting frame %d", frameno);fflush(stdout);
568         }
569     }
570     if(!verbose)
571         printf("\n");
572     fclose(fi);
573     v2swf_backpatch(&v2swf, outputfilename);
574     v2swf_close(&v2swf);
575 }
576