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