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"
29 typedef struct _videoreader_vfw_internal
{
37 BITMAPINFOHEADER bitmap
;
38 WAVEFORMATEX waveformat
;
56 } videoreader_vfw_internal_t
;
58 static int avifile_initialized
= 0;
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
);
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
);
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;
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) {
101 for(y
=starty
;y
!=endy
;y
+=yinc
) {
102 UCHAR
*line
= &img
[linex
*y
];
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];
112 for(y
=starty
;y
!=endy
;y
+=yinc
) {
113 UCHAR
*line
= &img
[linex
*y
];
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;
121 } else if(bi
->biBitCount
==8) {
122 UCHAR
*img
= &data
[bi
->biClrUsed
*4];
125 for(y
=starty
;y
!=endy
;y
+=yinc
) {
126 UCHAR
*line
= &img
[linex
*y
];
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;
133 } else if(bi
->biBitCount
==16) {
136 for(y
=starty
;y
!=endy
;y
+=yinc
) {
137 UCHAR
*line
= &img
[linex
*y
];
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);
145 } else if(bi
->biBitCount
==24) {
148 for(y
=starty
;y
!=endy
;y
+=yinc
) {
149 UCHAR
*line
= &img
[linex
*y
];
151 for(x
=0;x
<dest_width
;x
++) {
152 *dest
++ = 255|line
[2]<<8|line
[1]<<16|line
[0]<<24;
156 } else if(bi
->biBitCount
==32) {
159 for(y
=starty
;y
!=endy
;y
+=yinc
) {
160 UCHAR
*line
= &img
[linex
*y
];
162 for(x
=0;x
<dest_width
;x
++) {
163 *dest
++ = 255|line
[0]<<8|line
[1]<<16|line
[2]<<24;
168 fprintf(stderr
, "Unsupported format: bitcount=%d\n", bi
->biBitCount
);
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
)
184 LPBITMAPINFOHEADER bi
;
185 bi
= (LPBITMAPINFOHEADER
)AVIStreamGetFrame(i
->getframe
, i
->video_pos
);
191 fprintf(stderr
, "AVIStreamGetFrame failed\n");
195 if(!bitmap_to_rgba(bi
, buffer
, i
->width
, i
->height
, i
->flip
)) {
196 fprintf(stderr
, "couldn't convert bitmap to RGBA.\n");
199 return i
->width
*i
->height
*4;
202 static int readAudioBlock(videoreader_vfw_internal_t
* i
, void*buf
, int len
)
206 AVIStreamRead(i
->as
, i
->audio_pos
, len
/(2*i
->waveformat
.nChannels
), buf
, len
, &bytes
, &samples
);
207 i
->audio_pos
+= samples
;
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
;
218 switch(i
->waveformat
.wBitsPerSample
) {
220 int len
= readAudioBlock(i
, buf
, num
);
223 ((SHORT
*)buf
)[t
] = ((((BYTE
*)buf
)[t
>>3])>>(t
&7))<<15;
225 if(!len
) i
->audio_eof
= 1;
229 int len
= readAudioBlock(i
, buf
, num
);
232 ((SHORT
*)buf
)[t
] = (((BYTE
*)buf
)[t
]<<8)^0x8000;
234 if(!len
) i
->audio_eof
= 1;
238 int len
= readAudioBlock(i
, buf
, num
);
239 if(!len
) i
->audio_eof
= 1;
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
);
254 AVIStreamRelease(i
->vs
); i
->vs
= 0;
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
));
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
));
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
) {
296 if(AVIFileOpen(&i
->avifile
, filename
, OF_SHARE_DENY_WRITE
, 0)) {
297 fprintf(stderr
, "Couldn't open %s\n", filename
);
301 AVIFileInfo(i
->avifile
, &info
, sizeof(info
));
303 /* calculate framerate */
304 i
->fps
= (double)info
.dwRate
/(double)info
.dwScale
;
307 printf("vfw: file %s has %f fps, and %d streams\n", i
->fps
, info
.dwStreams
);
311 while(t
<info
.dwStreams
) {
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
) {
322 BITMAPINFOHEADER bitmap
;
323 LONG size
= sizeof(bitmap
);
324 AVIStreamReadFormat(stream
, 0, &bitmap
, &size
);
329 i
->width
= abs(bitmap
.biWidth
);
330 i
->height
= abs(bitmap
.biHeight
);
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
) {
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
;
350 i
->channels
= waveformat
.nChannels
;
351 i
->samplerate
= waveformat
.nSamplesPerSec
;
353 fprintf(stderr
, "Ignoring audio stream: bitspersample=%d\n", waveformat
.wBitsPerSample
);
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
;
367 fprintf(stderr
, "AVIReader: Warning: No video stream\n");
371 printf("vfw: audio stream: %d channels, %d samples/sec", i
->channels
, i
->samplerate
);
373 vr
->channels
= i
->channels
;
374 vr
->samplerate
= i
->samplerate
;
376 fprintf(stderr
, "AVIReader: Warning: No audio stream\n");
379 i
->getframe
= AVIStreamGetFrameOpen(i
->vs
, 0);
381 fprintf(stderr
, "Couldn't initialize AVIStream for %s- codec missing?\n", filename
);
385 i
->video_pos
= AVIStreamStart(i
->vs
);
386 i
->video_end
= AVIStreamEnd(i
->vs
);
388 i
->audio_end
= 0x7fffffff;
395 int videoreader_vfw_open(videoreader_t
* vr
, char* filename
)