bugfixes in remove_invisible_characters filter
[swftools.git] / avi2swf / videoreader_vfw.cc
blobca8a6b72f6af37cae017096f6e6e52a8a9180106
1 /* videoreader_vfw.cc
2 Read avi files using Video For Windows (vfw).
4 Part of the swftools package.
6 Copyright (c) 2004 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
22 #include "videoreader.h"
23 #ifdef WIN32
24 #include <windows.h>
25 #include <vfw.h>
26 #include <stdlib.h>
27 #include <stdio.h>
29 typedef struct _videoreader_vfw_internal {
30 //video:
31 PAVISTREAM vs;
32 //audio:
33 PAVISTREAM as;
35 PGETFRAME getframe;
36 IAVIFile* avifile;
37 BITMAPINFOHEADER bitmap;
38 WAVEFORMATEX waveformat;
40 int audio_eof;
41 int video_eof;
43 int video_pos;
44 int video_end;
46 int audio_pos;
47 int audio_end;
49 float fps;
50 int width,height;
52 int samplerate;
53 int channels;
55 int flip;
56 } videoreader_vfw_internal_t;
58 static int avifile_initialized = 0;
59 static int verbose;
61 #define _TRACE_ {printf("vfw: %s: %d (%s)\n",__FILE__,__LINE__,__func__);fflush(stdout);}
63 static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width, const int dest_height, int flip)
65 UCHAR*data = (UCHAR*)(bi+1); // actual bitmap data starts after the header
67 if(bi->biPlanes!=1 || bi->biCompression!=0 || bi->biBitCount%4!=0) {
68 /* unsupported format */
69 fprintf(stderr, "bitmap_to_rgba: unsupported format: biPlanes=%d, biCompression=%d biBitCount=%d\n",
70 bi->biPlanes, bi->biCompression, bi->biBitCount);
71 return 0;
74 ULONG*dest = (ULONG*)buffer;
76 int width = abs(bi->biWidth);
77 int height = abs(bi->biHeight);
78 if(dest_width != width || dest_height != height) {
79 /* TODO: size conversion */
80 fprintf(stderr, "size mismatch: %dx%d != %dx%d\n", width, height, dest_width, dest_height);
81 return 0;
84 /* convert the various image types to RGBA-
85 TODO: is there some way to let the Windows API do this? */
86 int bytesperpixel = ((bi->biWidth*bi->biBitCount)+7)&~7;
87 int linex = ((bytesperpixel/8)+3)&~3;
88 memset(dest, 255, dest_width*dest_height*4);//pre-fill alpha channel
90 const int starty = flip? 0 : dest_height-1;
91 const int endy = flip? dest_height : -1;
92 const int yinc = flip? 1 : -1;
94 if(verbose) {
95 printf("vfw: Convering scanlines %d to %d from bpp %d, %d stepping, flip=%d\n", starty, endy, bi->biBitCount, yinc, flip);
98 if(bi->biBitCount==1) {
99 UCHAR*img = data;
100 int y;
101 for(y=starty;y!=endy;y+=yinc) {
102 UCHAR*line = &img[linex*y];
103 int x;
104 for(x=0;x<dest_width;x++) {
105 *dest++ = 255*((line[x/8]>>(x&7))&1);
108 } else if(bi->biBitCount==4) {
109 UCHAR*img = &data[bi->biClrUsed*4];
110 UCHAR*pal = data;
111 int y;
112 for(y=starty;y!=endy;y+=yinc) {
113 UCHAR*line = &img[linex*y];
114 int x;
115 for(x=0;x<dest_width/2;x++) {
116 *dest++ = 255|pal[(line[0]>>4)<<2|0]<<8|pal[(line[0]>>4)<<2|1]<<16|pal[(line[0]>>4)<<2|2]<<24;
117 *dest++ = 255|pal[(line[0]&0x0f)<<2|0]<<8|pal[(line[0]&0x0f)<<2|1]<<16|pal[(line[0]&0x0f)<<2|2]<<24;
118 line++;
121 } else if(bi->biBitCount==8) {
122 UCHAR*img = &data[bi->biClrUsed*4];
123 UCHAR*pal = data;
124 int y;
125 for(y=starty;y!=endy;y+=yinc) {
126 UCHAR*line = &img[linex*y];
127 int x;
128 for(x=0;x<dest_width;x++) {
129 *dest++ = 255|pal[line[0]*4+2]<<8|pal[line[0]*4+1]<<16|pal[line[0]*4+0]<<24;
130 line++;
133 } else if(bi->biBitCount==16) {
134 UCHAR*img = data;
135 int y;
136 for(y=starty;y!=endy;y+=yinc) {
137 UCHAR*line = &img[linex*y];
138 int x;
139 for(x=0;x<dest_width;x++) {
140 USHORT c = line[0]|line[1]<<8;
141 *dest++ = 255|(c&0x1f)<<(24+3)|(c>>5&0x1f)<<(16+3)|(c>>10&0x1f)<<(8+3);
142 line+=2;
145 } else if(bi->biBitCount==24) {
146 UCHAR*img = data;
147 int y;
148 for(y=starty;y!=endy;y+=yinc) {
149 UCHAR*line = &img[linex*y];
150 int x;
151 for(x=0;x<dest_width;x++) {
152 *dest++ = 255|line[2]<<8|line[1]<<16|line[0]<<24;
153 line+=3;
156 } else if(bi->biBitCount==32) {
157 UCHAR*img = data;
158 int y;
159 for(y=starty;y!=endy;y+=yinc) {
160 UCHAR*line = &img[linex*y];
161 int x;
162 for(x=0;x<dest_width;x++) {
163 *dest++ = 255|line[0]<<8|line[1]<<16|line[2]<<24;
164 line+=4;
167 } else {
168 fprintf(stderr, "Unsupported format: bitcount=%d\n", bi->biBitCount);
169 return 0;
171 return 1;
174 static int videoreader_vfw_getimage(videoreader_t* vr, void*buffer)
176 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
178 if (i->video_pos >= i->video_end)
179 i->video_eof = 1;
181 if(i->video_eof)
182 return 0;
184 LPBITMAPINFOHEADER bi;
185 bi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(i->getframe, i->video_pos);
187 i->video_pos++;
188 vr->frame++;
190 if(!bi) {
191 fprintf(stderr, "AVIStreamGetFrame failed\n");
192 return 0;
195 if(!bitmap_to_rgba(bi, buffer, i->width, i->height, i->flip)) {
196 fprintf(stderr, "couldn't convert bitmap to RGBA.\n");
197 return 0;
199 return i->width*i->height*4;
202 static int readAudioBlock(videoreader_vfw_internal_t* i, void*buf, int len)
204 LONG bytes;
205 LONG samples;
206 AVIStreamRead(i->as, i->audio_pos, len/(2*i->waveformat.nChannels), buf, len, &bytes, &samples);
207 i->audio_pos += samples;
208 return bytes;
211 static int videoreader_vfw_getsamples(videoreader_t* vr, void*buf, int num)
213 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
215 if(i->audio_eof)
216 return 0;
218 switch(i->waveformat.wBitsPerSample) {
219 case 1: {
220 int len = readAudioBlock(i, buf, num);
221 int t = len-1;
222 do {
223 ((SHORT*)buf)[t] = ((((BYTE*)buf)[t>>3])>>(t&7))<<15;
224 } while(--t>=0);
225 if(!len) i->audio_eof = 1;
226 return len*8;
228 case 8: {
229 int len = readAudioBlock(i, buf, num);
230 int t = len-1;
231 do {
232 ((SHORT*)buf)[t] = (((BYTE*)buf)[t]<<8)^0x8000;
233 } while(--t>=0);
234 if(!len) i->audio_eof = 1;
235 return len*2;
237 case 16: {
238 int len = readAudioBlock(i, buf, num);
239 if(!len) i->audio_eof = 1;
240 return len;
242 default: {
243 return 0;
248 static void videoreader_vfw_close(videoreader_t* vr)
250 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
252 AVIStreamGetFrameClose(i->getframe);
253 if(i->vs) {
254 AVIStreamRelease(i->vs); i->vs = 0;
256 if(i->as) {
257 AVIStreamRelease(i->as); i->vs = 0;
259 AVIFileRelease(i->avifile); i->avifile = 0;
261 AVIFileExit(); avifile_initialized=0;
263 free(vr->internal); vr->internal = 0;
266 static void videoreader_vfw_setparameter(videoreader_t*vr, char*name, char*value)
268 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
269 if(!strcmp(name, "flip")) {
270 i->flip = atoi(value);
271 } else if(!strcmp(name, "verbose")) {
272 verbose = atoi(value);
276 int videoreader_vfw_open(videoreader_t* vr, char* filename)
278 memset(vr, 0, sizeof(videoreader_t));
279 if(!filename) {
280 /* codec query */
281 return 1;
284 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)malloc(sizeof(videoreader_vfw_internal_t));
285 memset(i, 0, sizeof(videoreader_vfw_internal_t));
287 vr->internal = i;
288 vr->getimage = videoreader_vfw_getimage;
289 vr->getsamples = videoreader_vfw_getsamples;
290 vr->close = videoreader_vfw_close;
291 vr->setparameter = videoreader_vfw_setparameter;
293 if(!avifile_initialized) {
294 AVIFileInit();
296 if(AVIFileOpen(&i->avifile, filename, OF_SHARE_DENY_WRITE, 0)) {
297 fprintf(stderr, "Couldn't open %s\n", filename);
298 return -1;
300 AVIFILEINFO info;
301 AVIFileInfo(i->avifile, &info, sizeof(info));
303 /* calculate framerate */
304 i->fps = (double)info.dwRate/(double)info.dwScale;
306 if(verbose) {
307 printf("vfw: file %s has %f fps, and %d streams\n", i->fps, info.dwStreams);
310 unsigned int t=0;
311 while(t<info.dwStreams) {
312 PAVISTREAM stream;
313 if(AVIFileGetStream(i->avifile, &stream, streamtypeANY, t) != AVIERR_OK || !stream)
314 break; //video_end of (working) streams
316 AVISTREAMINFO streaminfo;
317 AVIStreamInfo(stream, &streaminfo, sizeof(streaminfo));
319 if (streaminfo.fccType == streamtypeVIDEO) {
320 /* video stream */
322 BITMAPINFOHEADER bitmap;
323 LONG size = sizeof(bitmap);
324 AVIStreamReadFormat(stream, 0, &bitmap, &size);
326 if(1) {
327 i->bitmap = bitmap;
328 i->vs = stream;
329 i->width = abs(bitmap.biWidth);
330 i->height = abs(bitmap.biHeight);
331 } else {
332 fprintf(stderr, "Ignoring video stream: %dx%d compression=%d planes=%d\n",
333 abs(bitmap.biWidth), abs(bitmap.biHeight),
334 bitmap.biCompression,bitmap.biPlanes);
337 else if (streaminfo.fccType == streamtypeAUDIO) {
338 /* audio stream */
340 WAVEFORMATEX waveformat;
341 LONG size = sizeof(waveformat);
342 AVIStreamReadFormat(stream, 0, &waveformat, &size);
344 if(waveformat.wBitsPerSample == 16 ||
345 waveformat.wBitsPerSample == 8 ||
346 waveformat.wBitsPerSample == 1
348 i->waveformat = waveformat;
349 i->as = stream;
350 i->channels = waveformat.nChannels;
351 i->samplerate = waveformat.nSamplesPerSec;
352 } else {
353 fprintf(stderr, "Ignoring audio stream: bitspersample=%d\n", waveformat.wBitsPerSample);
356 t++;
359 if(i->vs) {
360 if(verbose) {
361 printf("vfw: video stream: %dx%d, %.2f\n", i->width, i->height, i->fps);
363 vr->width = i->width;
364 vr->height = i->height;
365 vr->fps = i->fps;
366 } else {
367 fprintf(stderr, "AVIReader: Warning: No video stream\n");
369 if(i->as) {
370 if(verbose) {
371 printf("vfw: audio stream: %d channels, %d samples/sec", i->channels, i->samplerate);
373 vr->channels = i->channels;
374 vr->samplerate = i->samplerate;
375 } else {
376 fprintf(stderr, "AVIReader: Warning: No audio stream\n");
379 i->getframe = AVIStreamGetFrameOpen(i->vs, 0);
380 if(!i->getframe) {
381 fprintf(stderr, "Couldn't initialize AVIStream for %s- codec missing?\n", filename);
382 return -1;
385 i->video_pos = AVIStreamStart(i->vs);
386 i->video_end = AVIStreamEnd(i->vs);
387 i->audio_pos = 0;
388 i->audio_end = 0x7fffffff;
390 return 0;
393 #else //WIN32
395 int videoreader_vfw_open(videoreader_t* vr, char* filename)
397 return -1;
400 #endif //WIN32