added check for HAVE_SIGNAL_H and HAVE_PTHREAD_H, fixed --help output.
[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 Matthias Kramm <kramm@quiss.org>
7
8    This file is distributed under the GPL, see file COPYING for details */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <fcntl.h>
14
15 #include "../config.h"
16
17 #ifdef HAVE_SIGNAL_H
18 #ifdef HAVE_PTHREAD_H
19 #include <pthread.h>
20 #include <signal.h>
21 #define DO_SIGNALS
22 #endif
23 #endif
24
25 extern "C" {
26 #include "../lib/args.h"
27 }
28 #include "v2swf.h"
29
30 #undef HAVE_CONFIG_H
31 #include <avifile/version.h>
32 #if (AVIFILE_MAJOR_VERSION == 0) && (AVIFILE_MINOR_VERSION>=6) 
33    #include <avifile.h>
34    #include <aviplay.h>
35    #include <fourcc.h>
36    #include <creators.h>
37    #include <StreamInfo.h>
38    #define VERSION6
39 #else
40    #include <avifile.h>
41    #include <aviplay.h>
42    #include <aviutil.h>
43    #define Width width
44    #define Height height
45    #define Data data
46    #define Bpp bpp
47 #endif
48
49 static char * filename = 0;
50 static char * outputfilename = "output.swf";
51 int verbose = 0;
52
53 static int quality = 80;
54 static double scale = 1.0;
55 static int flip = 0;
56 static int expensive = 0;
57
58 struct options_t options[] =
59 {
60  {"v","verbose"},
61  {"o","output"},
62  {"p","flip"},
63  {"q","quality"},
64  {"d","scale"},
65  {"x","extragood"},
66  {"V","version"},
67  {0,0}
68 };
69
70 int args_callback_option(char*name,char*val)
71 {
72     if(!strcmp(name, "V")) {
73         printf("avi2swf - part of %s %s\n", PACKAGE, VERSION);
74         exit(0);
75     } 
76     else if(!strcmp(name, "o")) {
77         outputfilename = val;
78         return 1;
79     }
80     else if(!strcmp(name, "q")) {
81         quality = atoi(val);
82         if(quality<0)
83             quality = 0;
84         if(quality>100)
85             quality = 100;
86         return 1;
87     }
88     else if(!strcmp(name, "p")) {
89         flip = 1;
90         return 0;
91     }
92     else if(!strcmp(name, "v")) {
93         verbose = 1;
94         return 0;
95     }
96     else if(!strcmp(name, "x")) {
97         expensive = 1;
98         return 0;
99     }
100     else if(!strcmp(name, "d")) {
101         scale = atoi(val)/100.0;
102         if(scale>1.0 || scale<=0) {
103             fprintf(stderr, "Scale must be in the range 1-100!\n");
104             exit(1);
105         }
106         return 1;
107     }
108     fprintf(stderr, "Unknown option: -%s\n", name);
109     exit(1);
110 }
111 int args_callback_longoption(char*name,char*val)
112 {
113     return args_long2shortoption(options, name, val);
114 }
115 void args_callback_usage(char*name)
116 {    
117     printf("\nUsage: %s file.avi\n", name);
118     printf("\t-h , --help\t\t Print help and exit\n");
119     printf("\t-o , --output filename\t Specify output filename\n"); 
120     printf("\t-n , --num frames\t Number of frames to encode\n");
121     printf("\t-d , --scale <val>\t Scale down to factor <val>. (in %, e.g. 100 = original size)\n");
122     printf("\t-p , --flip\t\t Turn movie upside down\n");
123     printf("\t-q , --quality <val>\t Set the quality to <val>. (0-100, 0=worst, 100=best, default:80)\n");
124     printf("\t-x , --extragood\t Enable some *very* expensive compression strategies. You may\n");
125     printf("\t                \t want to let this run overnight.\n");
126     printf("\t-V , --version\t\t Print program version and exit\n");
127     exit(0);
128 }
129 int args_callback_command(char*name,char*val)
130 {
131     if(filename) {
132         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
133                  filename, name);
134     }
135     filename = name;
136     return 0;
137 }
138
139 static char toabuf[128];
140 static char*ftoa(double a)
141 {
142     sprintf(toabuf, "%f", a);
143     return toabuf;
144 }
145 static char*itoa(int a)
146 {
147     sprintf(toabuf, "%d", a);
148     return toabuf;
149 }
150
151 typedef struct _videoreader_avifile_internal
152 {
153     IAviReadFile* player;
154     IAviReadStream* astream;
155     IAviReadStream* vstream;
156     int do_audio;
157     int do_video;
158     int eof;
159     int frame;
160     int soundbits;
161 } videoreader_avifile_internal;
162
163 static int shutdown_avi2swf = 0;
164 static int frameno = 0;
165
166 #ifdef DO_SIGNALS
167 pthread_t main_thread;
168 static void sigterm(int sig)
169 {
170     if(pthread_equal (pthread_self(), main_thread))
171     {
172         if(frameno>0 && !shutdown_avi2swf) {
173             if(verbose)
174                 printf("Thread [%08x] got sigterm %d\n", pthread_self(), sig);
175             shutdown_avi2swf++;
176         } else {
177             exit(1);
178         }
179     }
180 }
181 #endif
182
183 int videoreader_avifile_getsamples(videoreader_t* v, void*buffer, int num)
184 {
185     int ret;
186     unsigned int samples_read, bytes_read;
187     if(verbose) {
188         printf("videoreader_getsamples(%d)\n", num);fflush(stdout);
189     }
190     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
191     if(i->soundbits == 8) {
192         ret = i->astream->ReadFrames(buffer, num/2, num/(v->channels*2), samples_read, bytes_read);
193         unsigned char*b = (unsigned char*)buffer;
194         int t;
195         for(t=num-2;t>=0;t-=2) {
196             unsigned char x = b[t/2];
197             b[t] = 0;
198             b[t+1] = x-128;
199         }
200         return num;
201     }
202     if(i->soundbits == 16) {
203         ret = i->astream->ReadFrames(buffer, num, num/(v->channels*2), samples_read, bytes_read);
204         return num;
205     }
206     return 0;
207 }
208 int videoreader_avifile_getimage(videoreader_t* v, void*buffer)
209 {
210     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
211     if(verbose) {
212         printf("videoreader_getimage()\n");fflush(stdout);
213     }
214
215     if(shutdown_avi2swf)
216         i->eof = 1;
217     
218     if(i->eof)
219         return 0;
220
221     if(i->vstream->ReadFrame() < 0) {
222         i->eof = 1;
223         return 0;
224     }
225     CImage*img = i->vstream->GetFrame(true);
226     if(!img) {
227         i->eof = 1;
228         return 0;
229     }
230     img->ToRGB();
231     frameno++;
232     i->frame++;
233     unsigned char*data = img->Data();
234     int bpp = img->Bpp();
235     if(bpp == 3) {
236         int x,y;
237         for(y=0;y<v->height;y++) {
238             unsigned char*from,*to;
239             to = &((unsigned char*)buffer)[y*v->width*4];
240             if(flip)
241                 from = img->At(v->height-y-1);
242             else
243                 from = img->At(y);
244             for(x=0;x<v->width;x++) {
245                 to[x*4+0] = 0;
246                 to[x*4+1] = from[x*3+2];
247                 to[x*4+2] = from[x*3+1];
248                 to[x*4+3] = from[x*3+0];
249             }
250         }
251         return v->width*v->height*4;
252     } else {
253         return 0;
254     }
255 }
256 bool videoreader_avifile_eof(videoreader_t* v)
257 {
258     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
259     if(verbose) {
260         printf("videoreader_eof()\n");fflush(stdout);
261     }
262     return i->eof;
263 }
264 void videoreader_avifile_close(videoreader_t* v)
265 {
266     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
267     if(verbose) {
268         printf("videoreader_close()\n");fflush(stdout);
269     }
270 }
271 void* videoreader_avifile_getinfo(videoreader_t* v, char* name)
272 {
273     return 0;
274 }
275 void videoreader_avifile_setparameter(videoreader_t*v, char*name, char*value)
276 {
277     if(verbose) {
278         printf("videoreader_setparameter(%s, %s)\n", name, value);fflush(stdout);
279     }
280 }
281
282 int videoreader_avifile_open(videoreader_t* v, char* filename)
283 {
284     videoreader_avifile_internal* i;
285     i = (videoreader_avifile_internal*)malloc(sizeof(videoreader_avifile_internal));
286     memset(i, 0, sizeof(videoreader_avifile_internal));
287     memset(v, 0, sizeof(videoreader_t));
288     v->getsamples = videoreader_avifile_getsamples;
289     v->getinfo = videoreader_avifile_getinfo;
290     v->close = videoreader_avifile_close;
291     v->eof = videoreader_avifile_eof;
292     v->getimage = videoreader_avifile_getimage;
293     v->getsamples = videoreader_avifile_getsamples;
294     v->setparameter = videoreader_avifile_setparameter;
295     v->internal = i;
296
297     i->do_video = 1;
298     i->do_audio = 1;
299
300     i->player = CreateIAviReadFile(filename);    
301     if(verbose) {
302         printf("%d streams (%d video, %d audio)\n", 
303                 i->player->StreamCount(),
304                 i->player->VideoStreamCount(),
305                 i->player->AudioStreamCount());
306     }
307     i->astream = i->player->GetStream(0, AviStream::Audio);
308     i->vstream = i->player->GetStream(0, AviStream::Video);
309     if(!i->vstream) {
310         printf("Couldn't open video stream\n");
311         i->do_video = 0;
312     }
313     if(!i->astream) {
314         printf("Couldn't open video stream\n");
315         i->do_audio = 0;
316     }
317
318     if(!i->do_video && !i->do_audio) {
319         printf("File has neither audio nor video streams.(?)\n");
320         return 0;
321     }
322
323 #ifndef VERSION6
324     MainAVIHeader head;
325     int dwMicroSecPerFrame = 0;
326     player->GetFileHeader(&head);
327     printf("fps: %d\n", 1000000/head.dwMicroSecPerFrame);
328     printf("frames: %d\n", head.dwTotalFrames);
329     printf("streams: %d\n", head.dwStreams);
330     printf("width: %d\n", head.dwWidth);
331     printf("height: %d\n", head.dwHeight);
332     printf("sound: %u samples (%f seconds)\n", i->astream->GetEndPos(), i->astream->GetEndTime());
333     v->width = head.dwWidth;
334     v->height = head.dwHeight;
335     dwMicroSecPerFrame = head.dwMicroSecPerFrame;
336     samplesperframe = astream->GetEndPos()/astream->GetEndTime()*head.dwMicroSecPerFrame/1000000;
337     v->rate = (int)(astream->GetEndPos()/astream->GetEndTime());
338     v->fps = 1000000.0/dwMicroSecPerFrame;
339     i->soundbits = 16;
340 #else
341     StreamInfo*audioinfo;
342     StreamInfo*videoinfo;
343     if(i->do_video)
344     {
345         videoinfo = i->vstream->GetStreamInfo();
346         v->width = videoinfo->GetVideoWidth();
347         v->height = videoinfo->GetVideoHeight();
348         v->fps = (double)(videoinfo->GetFps());
349     }
350     if(i->do_audio)
351     {
352         WAVEFORMATEX wave;
353         i->astream->GetAudioFormatInfo(&wave,0);
354         v->channels = wave.nChannels;
355         i->soundbits = wave.wBitsPerSample;
356         if(wave.wBitsPerSample != 8 && wave.wBitsPerSample != 16) {
357             printf("Can't handle %d bit audio, disabling sound\n", wave.wBitsPerSample);
358             i->do_audio = 0;
359             v->channels = 0;
360             v->rate = 0;
361         }
362     }
363     if(i->do_audio)
364     {
365         audioinfo = i->astream->GetStreamInfo();
366         v->rate = audioinfo->GetAudioSamplesPerSec();
367     }
368 #endif
369     i->vstream -> StartStreaming();
370     if(i->do_audio)
371         i->astream -> StartStreaming();
372
373     return 1;
374 }
375
376 int main (int argc,char ** argv)
377
378     videoreader_t video;
379     v2swf_t v2swf;
380     int ret;
381     FILE*fi;
382
383 #ifdef DO_SIGNALS
384     signal(SIGTERM, sigterm);
385     signal(SIGINT , sigterm);
386     signal(SIGQUIT, sigterm);
387     main_thread = pthread_self();
388 #endif
389
390     processargs(argc, argv);
391     if(!filename)
392         exit(0);
393     
394     fi = fopen(outputfilename, "wb");
395     if(!fi) {
396         fflush(stdout); fflush(stderr);
397         fprintf(stderr, "Couldn't open %s\n", outputfilename);
398         exit(1);
399     }
400
401     ret = videoreader_avifile_open(&video, filename);
402
403     if(!ret) {
404         printf("Error opening %s\n", filename);
405         exit(1);
406     }
407
408     if(verbose) {
409         printf("| video framerate: %f\n", video.fps);
410         printf("| video size: %dx%d\n", video.width, video.height);
411         printf("| audio rate: %d\n", video.rate);
412         printf("| audio channels: %d\n", video.channels);
413     }
414
415     ret = v2swf_init(&v2swf, &video);
416     if(verbose)
417         v2swf_setparameter(&v2swf, "verbose", "1");
418     v2swf_setparameter(&v2swf, "quality", itoa(quality));
419     v2swf_setparameter(&v2swf, "blockdiff", "0");
420     v2swf_setparameter(&v2swf, "blockdiff_mode", "exact");
421     v2swf_setparameter(&v2swf, "mp3_bitrate", "128");
422     //v2swf_setparameter(&v2swf, "fixheader", "1");
423     //v2swf_setparameter(&v2swf, "framerate", "15");
424     v2swf_setparameter(&v2swf, "scale", ftoa(scale));
425     v2swf_setparameter(&v2swf, "prescale", "1");
426     v2swf_setparameter(&v2swf, "keyframe_interval", "200");
427     v2swf_setparameter(&v2swf, "flash_version", "6");
428     if(expensive)
429         v2swf_setparameter(&v2swf, "motioncompensation", "1");
430
431
432     char buffer[4096];
433     if(!verbose)
434         printf("\n");
435     while(1) {
436         int l=v2swf_read(&v2swf, buffer, 4096);
437         fwrite(buffer, l, 1, fi);
438         if(!l)
439             break;
440         if(!verbose) {
441             printf("\rConverting frame %d", frameno);fflush(stdout);
442         }
443     }
444     if(!verbose)
445         printf("\n");
446     fclose(fi);
447     v2swf_backpatch(&v2swf, outputfilename);
448     v2swf_close(&v2swf);
449 }
450