fixed graphics bug
[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         if(verbose) printf("Warning: converthing from bpp %d to bpp 3, this fails on older avifile versions...\n", img->Bpp());
309         BitmapInfo tmp(v->width, v->height, 24);
310         img2 = new CImage(img, &tmp);
311         img = img2;
312     }
313
314
315     frameno++;
316     i->frame++;
317     unsigned char*data = img->Data();
318     int bpp = img->Bpp();
319     if(bpp == 3) {
320         int x,y;
321         for(y=0;y<v->height;y++) {
322             unsigned char*from,*to;
323             to = &((unsigned char*)buffer)[y*v->width*4];
324             if(flip)
325                 from = img->At(v->height-y-1);
326             else
327                 from = img->At(y);
328             for(x=0;x<v->width;x++) {
329                 to[x*4+0] = 0;
330                 to[x*4+1] = from[x*3+2];
331                 to[x*4+2] = from[x*3+1];
332                 to[x*4+3] = from[x*3+0];
333             }
334         }
335         if(img2) delete img2;
336         return v->width*v->height*4;
337     } else {
338         if(img2) delete img2;
339         if(verbose) printf("Can't handle bpp %d, shutting down...\n", bpp);
340         return 0;
341     }
342 }
343 bool videoreader_avifile_eof(videoreader_t* v)
344 {
345     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
346     if(verbose) {
347         printf("videoreader_eof()\n");fflush(stdout);
348     }
349     return i->eof;
350 }
351 void videoreader_avifile_close(videoreader_t* v)
352 {
353     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
354     if(verbose) {
355         printf("videoreader_close()\n");fflush(stdout);
356     }
357     if(i->do_audio) {
358         ringbuffer_clear(&i->audio_buffer);
359     }
360 }
361 void* videoreader_avifile_getinfo(videoreader_t* v, char* name)
362 {
363     return 0;
364 }
365 void videoreader_avifile_setparameter(videoreader_t*v, char*name, char*value)
366 {
367     if(verbose) {
368         printf("videoreader_setparameter(%s, %s)\n", name, value);fflush(stdout);
369     }
370 }
371
372 int videoreader_avifile_open(videoreader_t* v, char* filename)
373 {
374     videoreader_avifile_internal* i;
375     i = (videoreader_avifile_internal*)malloc(sizeof(videoreader_avifile_internal));
376     memset(i, 0, sizeof(videoreader_avifile_internal));
377     memset(v, 0, sizeof(videoreader_t));
378     v->getsamples = videoreader_avifile_getsamples;
379     v->getinfo = videoreader_avifile_getinfo;
380     v->close = videoreader_avifile_close;
381     v->eof = videoreader_avifile_eof;
382     v->getimage = videoreader_avifile_getimage;
383     v->getsamples = videoreader_avifile_getsamples;
384     v->setparameter = videoreader_avifile_setparameter;
385     v->internal = i;
386     
387     i->do_video = 1;
388     i->do_audio = 1;
389
390     i->player = CreateIAviReadFile(filename);    
391     if(verbose) {
392         printf("%d streams (%d video, %d audio)\n", 
393                 i->player->StreamCount(),
394                 i->player->VideoStreamCount(),
395                 i->player->AudioStreamCount());
396     }
397     i->astream = i->player->GetStream(0, AviStream::Audio);
398     i->vstream = i->player->GetStream(0, AviStream::Video);
399     if(!i->vstream) {
400         printf("Couldn't open video stream\n");
401         i->do_video = 0;
402     }
403     if(!i->astream) {
404         printf("Couldn't open video stream\n");
405         i->do_audio = 0;
406     }
407 #ifdef NO_MP3
408     if(i->do_audio) {
409         printf(stderr, "MP3 support has been disabled at compile time, not converting soundtrack");
410         i->do_audio = 0;
411     }
412 #endif
413
414     if(!i->do_video && !i->do_audio) {
415         printf("File has neither audio nor video streams.(?)\n");
416         return 0;
417     }
418
419 #ifndef VERSION6
420     MainAVIHeader head;
421     int dwMicroSecPerFrame = 0;
422     player->GetFileHeader(&head);
423     printf("fps: %d\n", 1000000/head.dwMicroSecPerFrame);
424     printf("frames: %d\n", head.dwTotalFrames);
425     printf("streams: %d\n", head.dwStreams);
426     printf("width: %d\n", head.dwWidth);
427     printf("height: %d\n", head.dwHeight);
428     printf("sound: %u samples (%f seconds)\n", i->astream->GetEndPos(), i->astream->GetEndTime());
429     v->width = head.dwWidth;
430     v->height = head.dwHeight;
431     dwMicroSecPerFrame = head.dwMicroSecPerFrame;
432     samplesperframe = astream->GetEndPos()/astream->GetEndTime()*head.dwMicroSecPerFrame/1000000;
433     v->rate = (int)(astream->GetEndPos()/astream->GetEndTime());
434     v->fps = 1000000.0/dwMicroSecPerFrame;
435     i->soundbits = 16;
436 #else
437     if(i->do_video)
438     {
439         StreamInfo*videoinfo;
440         videoinfo = i->vstream->GetStreamInfo();
441         v->width = videoinfo->GetVideoWidth();
442         v->height = videoinfo->GetVideoHeight();
443         v->fps = (double)(videoinfo->GetFps());
444     }
445     if(i->do_audio)
446     {
447         WAVEFORMATEX wave;
448         StreamInfo*audioinfo;
449
450         i->astream->GetAudioFormatInfo(&wave,0);
451         audioinfo = i->astream->GetStreamInfo();
452
453         v->channels = wave.nChannels;
454         v->rate = wave.nSamplesPerSec;
455         i->soundbits = wave.wBitsPerSample;
456
457         if(v->channels==0 || v->rate==0 || i->soundbits==0 || wave.wFormatTag!=1) {
458             v->rate = audioinfo->GetAudioSamplesPerSec();
459             v->channels = audioinfo->GetAudioChannels();
460             i->soundbits = audioinfo->GetAudioBitsPerSample();
461         }
462
463         if(verbose) {
464             printf("formatinfo: format %d, %d channels, %d bits/sample, rate %d, blockalign %d\n", wave.wFormatTag, wave.nChannels, wave.wBitsPerSample, wave.nSamplesPerSec, wave.nBlockAlign);
465             printf("audioinfo: %d channels, %d bits/sample, rate %d\n", audioinfo->GetAudioChannels(), audioinfo->GetAudioBitsPerSample(), audioinfo->GetAudioSamplesPerSec());
466         }
467         if(i->soundbits != 8 && i->soundbits != 16) {
468             printf("Can't handle %d bit audio, disabling sound\n", wave.wBitsPerSample);
469             i->do_audio = 0;
470             i->soundbits = 0;
471             v->channels = 0;
472             v->rate = 0;
473         }
474     }
475 #endif
476     i->vstream -> StartStreaming();
477     if(i->do_audio) {
478         i->astream -> StartStreaming();
479         ringbuffer_init(&i->audio_buffer);
480 #ifdef VERSION6
481         WAVEFORMATEX wave;
482         i->astream -> GetOutputFormat(&wave, sizeof(wave));
483         printf("formatinfo: format %d, %d channels, %d bits/sample, rate %d, blockalign %d\n", wave.wFormatTag, wave.nChannels, wave.wBitsPerSample, wave.nSamplesPerSec, wave.nBlockAlign);
484 #endif
485     }
486
487     return 1;
488 }
489
490 int main (int argc,char ** argv)
491
492     videoreader_t video;
493     v2swf_t v2swf;
494     int ret;
495     FILE*fi;
496
497 #ifdef DO_SIGNALS
498     signal(SIGTERM, sigterm);
499     signal(SIGINT , sigterm);
500     signal(SIGQUIT, sigterm);
501     main_thread = pthread_self();
502 #endif
503
504     processargs(argc, argv);
505     if(!filename)
506         exit(0);
507     if(keyframe_interval<0) {
508         if(flashversion>=6)
509             keyframe_interval=200;
510         else
511             keyframe_interval=5;
512     }
513     
514     fi = fopen(outputfilename, "wb");
515     if(!fi) {
516         fflush(stdout); fflush(stderr);
517         fprintf(stderr, "Couldn't open %s\n", outputfilename);
518         exit(1);
519     }
520
521     ret = videoreader_avifile_open(&video, filename);
522
523     if(!ret) {
524         printf("Error opening %s\n", filename);
525         exit(1);
526     }
527
528     if(verbose) {
529         printf("| video framerate: %f\n", video.fps);
530         printf("| video size: %dx%d\n", video.width, video.height);
531         printf("| audio rate: %d\n", video.rate);
532         printf("| audio channels: %d\n", video.channels);
533     }
534
535     ret = v2swf_init(&v2swf, &video);
536     if(verbose)
537         v2swf_setparameter(&v2swf, "verbose", "1");
538     v2swf_setparameter(&v2swf, "quality", itoa(quality));
539     v2swf_setparameter(&v2swf, "blockdiff", "0");
540     v2swf_setparameter(&v2swf, "blockdiff_mode", "exact");
541     v2swf_setparameter(&v2swf, "mp3_bitrate", itoa(mp3_bitrate));
542     v2swf_setparameter(&v2swf, "samplerate", itoa(samplerate));
543     //v2swf_setparameter(&v2swf, "fixheader", "1");
544     //v2swf_setparameter(&v2swf, "framerate", "15");
545     v2swf_setparameter(&v2swf, "scale", ftoa(scale));
546     v2swf_setparameter(&v2swf, "prescale", "1");
547     v2swf_setparameter(&v2swf, "flash_version", itoa(flashversion));
548     v2swf_setparameter(&v2swf, "keyframe_interval", itoa(keyframe_interval));
549     if(expensive)
550         v2swf_setparameter(&v2swf, "motioncompensation", "1");
551
552     if(!verbose)
553         printf("\n");
554
555     if(audio_adjust>0) {
556         int num = ((int)(audio_adjust*video.rate))*video.channels*2;
557         void*buf = malloc(num);
558         video.getsamples(&video, buf, num);
559         free(buf);
560     } else if(audio_adjust<0) {
561         int num = (int)(-audio_adjust*video.fps);
562         void*buf = malloc(video.width*video.height*4);
563         int t;
564         for(t=0;t<num;t++) {
565             video.getimage(&video, buf);
566         }
567         free(buf);
568     }
569
570     if(skip) {
571         int t;
572         void*buf = malloc(video.width*video.height*4);
573         for(t=0;t<skip;t++) {
574             video.getimage(&video, buf);
575             video.getsamples(&video, buf, (int)((video.rate/video.fps)*video.channels*2));
576             if(!verbose) {
577                 printf("\rSkipping frame %d", frameno);fflush(stdout);
578             }
579         }
580         free(buf);
581     }
582
583     char buffer[4096];
584     while(1) {
585         int l=v2swf_read(&v2swf, buffer, 4096);
586         fwrite(buffer, l, 1, fi);
587         if(!l)
588             break;
589         if(!verbose) {
590             printf("\rConverting frame %d", frameno);fflush(stdout);
591         }
592     }
593     if(!verbose)
594         printf("\n");
595     fclose(fi);
596     v2swf_backpatch(&v2swf, outputfilename);
597     v2swf_close(&v2swf);
598 }
599