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