Write output directly to disk
[swftools.git] / lib / example / avi2swf.cc
1 /* avi2swf.cc
2    Convert avi movie files into swf.
3    As soon as there's an algorithm implemented for writing the
4    data directly to disk, this file should maybe go to ../src.
5
6    Part of the swftools package.
7    
8    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
9
10    This file is distributed under the GPL, see file COPYING for details */
11
12 #include <stdio.h>
13 #include <fcntl.h>
14 extern "C" {
15 #include "../rfxswf.h"
16 #include "../args.h"
17 }
18 #include "avifile.h"
19 #include "aviplay.h"
20
21 char * filename = 0;
22 char * outputfilename = "output.swf";
23 unsigned int lastframe = 0xffffffff;
24
25 int jpeg_quality = 40;
26
27 struct options_t options[] =
28 {
29  {"v","verbose"},
30  {"o","output"},
31  {"e","end"},
32  {"V","version"},
33  {0,0}
34 };
35
36 int args_callback_option(char*name,char*val)
37 {
38     if(!strcmp(name, "V")) {
39         printf("avi2swf - part of %s %s\n", PACKAGE, VERSION);
40         exit(0);
41     } 
42     else if(!strcmp(name, "o")) {
43         outputfilename = val;
44         return 1;
45     }
46     else if(!strcmp(name, "e")) {
47         lastframe = atoi(val);
48         return 1;
49     }
50 }
51 int args_callback_longoption(char*name,char*val)
52 {
53     return args_long2shortoption(options, name, val);
54 }
55 void args_callback_usage(char*name)
56 {    
57     printf("\nUsage: %s file.swf\n", name);
58     printf("\t-h , --help\t\t Print help and exit\n");
59     printf("\t-o , --output=filename\t Specify output filename\n"); 
60     printf("\t-e , --end=frame\t\t Last frame to encode\n");
61     printf("\t-V , --version\t\t Print program version and exit\n");
62     exit(0);
63 }
64 int args_callback_command(char*name,char*val)
65 {
66     if(filename) {
67         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
68                  filename, name);
69     }
70     filename = name;
71     return 0;
72 }
73
74 SWF swf;
75 TAG*tag;
76
77 int main (int argc,char ** argv)
78 { int file;
79   IAviReadFile* player;
80   IAviReadStream* astream;
81   IAviReadStream* vstream;
82   MainAVIHeader head;
83   SRECT r;
84
85   processargs(argc, argv);
86   if(!filename)
87       exit(0);
88
89   player = CreateIAviReadFile(filename);    
90   player->GetFileHeader(&head);
91   printf("fps: %d\n", 1000000/head.dwMicroSecPerFrame);
92   printf("frames: %d\n", head.dwTotalFrames);
93   printf("streams: %d\n", head.dwStreams);
94   printf("streams: %d\n", player->StreamCount());
95   printf("width: %d\n", head.dwWidth);
96   printf("height: %d\n", head.dwHeight);
97   
98   astream = player->GetStream(0, AviStream::Audio);
99   vstream = player->GetStream(0, AviStream::Video);
100
101   vstream -> StartStreaming();
102   
103   file = open(outputfilename,O_WRONLY|O_CREAT|O_TRUNC, 0644);
104   
105   memset(&swf, 0, sizeof(swf));
106   swf.frameRate = (int)(1000000.0/head.dwMicroSecPerFrame*256);
107   swf.fileVersion = 4;
108   swf.fileSize = 0x0fffffff;
109   r.xmin = 0;
110   r.ymin = 0;
111   r.xmax = head.dwWidth*20;
112   r.ymax = head.dwHeight*20;
113   swf.movieSize = r;
114
115   swf_WriteHeader(file, &swf);
116
117   tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
118   swf_SetU8(tag,0); //black
119   swf_SetU8(tag,0);
120   swf_SetU8(tag,0);
121   swf_WriteTag(file, tag);
122   swf_DeleteTag(tag);
123
124   U8*newdata = (U8*)malloc((head.dwWidth+3) * head.dwHeight * 4);
125
126   int frame = 0;
127
128   int lastsize = (head.dwWidth+3) * head.dwHeight * 4;
129   U8* lastdata = (U8*)malloc(lastsize);
130   U8* data;
131   memset(lastdata,0, lastsize);
132
133   while(1) {
134     if(vstream->ReadFrame()<0) {
135         printf("\n");
136         break;
137     }
138     printf("\rconvert frame %d",frame);
139     fflush(stdout);
140     CImage*img = vstream->GetFrame();
141     img->ToRGB();
142     data = img->data();
143     int width = img->width();
144     int bpp = img->bpp();
145     int width4 = width*4;
146     int height = img->height();
147     int x,y;
148     int fs,ls;
149     SHAPE*s;
150     MATRIX m;
151     SRECT r;
152     RGBA rgb;
153
154     if(frame!=0) {
155         tag = swf_InsertTag(NULL, ST_REMOVEOBJECT2);
156         swf_SetU16(tag, 1); //depth
157         swf_WriteTag(file, tag);
158         swf_DeleteTag(tag);
159     }
160
161     /* todo: dynamically decide whether to generate jpeg/lossless
162        bitmaps, (using transparency to modify the previous 
163        picture), and which jpeg compression depth to use.
164        (btw: Are there video frame transitions which can
165         reasonably be approximated by shapes?)
166      */
167
168     int type = 1;
169     int rel = 0;
170     if(type == 0) {
171         tag = swf_InsertTag(NULL, ST_DEFINEBITSLOSSLESS);
172         swf_SetU16(tag, frame*2);
173         U8*mylastdata = lastdata;
174         for(y=0;y<height;y++) {
175             U8*nd = &newdata[width4*y];
176             U8*mydata = img->at(y);
177             if(!rel)
178             for(x=0;x<width;x++) {
179                 nd[3]=mydata[0];
180                 nd[2]=mydata[1];
181                 nd[1]=mydata[2];
182                 mylastdata[2] = mydata[2];
183                 mylastdata[1] = mydata[1];
184                 mylastdata[0] = mydata[0];
185                 nd+=4;
186                 mydata+=3;
187                 mylastdata+=3;
188             }
189             else
190             for(x=0;x<width;x++) {
191                 int a = mylastdata[3]-data[3];
192                 int b = mylastdata[2]-data[2];
193                 int c = mylastdata[1]-data[1];
194                 if((a*a+b*b+c*c)>64)
195                 {
196                     nd[3]=mydata[0];
197                     nd[2]=mydata[1];
198                     nd[1]=mydata[2];
199                     nd[0]=255;
200                 } else {
201                     nd[3]=0;
202                     nd[2]=0;
203                     nd[1]=0;
204                     nd[0]=0;
205                 }
206                 mylastdata[2] = mydata[2];
207                 mylastdata[1] = mydata[1];
208                 mylastdata[0] = mydata[0];
209                 nd+=4;
210                 mydata+=3;
211                 mylastdata+=3;
212             }
213         }
214         swf_SetLosslessBits(tag,width,height,newdata,BMF_32BIT);
215         swf_WriteTag(file, tag);
216         swf_DeleteTag(tag);
217     } else 
218     if(type == 1) {
219         tag = swf_InsertTag(NULL, ST_DEFINEBITSJPEG2);
220         swf_SetU16(tag, frame*2);
221         JPEGBITS * jb = swf_SetJPEGBitsStart(tag,width,height,jpeg_quality);
222         U8*mylastdata = lastdata;
223         for(y=0;y<height;y++) {
224             U8*nd = newdata;
225             U8*mydata = img->at(y);
226             for(x=0;x<width;x++) {
227                 nd[0] = mydata[2];
228                 nd[1] = mydata[1];
229                 nd[2] = mydata[0];
230                 if(rel) {
231                     nd[0] = (mydata[2]-mylastdata[2])/2+0x80;
232                     nd[1] = (mydata[1]-mylastdata[1])/2+0x80;
233                     nd[2] = (mydata[0]-mylastdata[0])/2+0x80;
234                 }
235                 mylastdata[2] = mydata[2];
236                 mylastdata[1] = mydata[1];
237                 mylastdata[0] = mydata[0];
238                 nd+=3;
239                 mydata+=3;
240                 mylastdata+=3;
241             }
242             swf_SetJPEGBitsLine(jb,newdata);
243         }
244         swf_SetJPEGBitsFinish(jb);
245         swf_WriteTag(file, tag);
246         swf_DeleteTag(tag);
247     }
248
249     tag = swf_InsertTag(NULL, ST_DEFINESHAPE);
250       swf_ShapeNew(&s);
251       rgb.b = rgb.g = rgb.r = 0xff;
252       ls = swf_ShapeAddLineStyle(s,20,&rgb);  
253       swf_GetMatrix(NULL,&m);
254       m.sx = 20*65536;
255       m.sy = 20*65536;
256
257       fs = swf_ShapeAddBitmapFillStyle(s,&m,frame*2,0);
258       swf_SetU16(tag ,frame*2+1);   // ID   
259       r.xmin = 0;
260       r.ymin = 0;
261       r.xmax = width*20;
262       r.ymax = height*20;
263       swf_SetRect(tag,&r);
264
265       swf_SetShapeStyles(tag,s);
266       swf_ShapeCountBits(s,NULL,NULL);
267       swf_SetShapeBits(tag,s);
268
269       swf_ShapeSetAll(tag,s,0,0,ls,fs,0);
270
271       swf_ShapeSetLine(tag,s,width*20,0);
272       swf_ShapeSetLine(tag,s,0,height*20);
273       swf_ShapeSetLine(tag,s,-width*20,0);
274       swf_ShapeSetLine(tag,s,0,-height*20);
275       swf_ShapeSetEnd(tag);
276     swf_WriteTag(file, tag);
277     swf_DeleteTag(tag);
278
279     tag = swf_InsertTag(NULL,ST_PLACEOBJECT2);
280       swf_ObjectPlace(tag,frame*2+1,1,0,0,0);
281     swf_WriteTag(file, tag);
282     swf_DeleteTag(tag);
283
284     tag = swf_InsertTag(NULL, ST_SHOWFRAME);
285     swf_WriteTag(file, tag);
286     swf_DeleteTag(tag);
287
288     frame++;
289     if(frame == lastframe)
290         break;
291   }
292   free(newdata);
293   printf("\n");
294   
295   tag = swf_InsertTag(NULL, ST_END);
296   swf_WriteTag(file, tag);
297   swf_DeleteTag(tag);
298
299   close(file);
300
301   return 0;
302 }
303