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