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 */
27 #include "videoreader.h"
29 typedef struct _videoreader_vfw_internal {
37 BITMAPINFOHEADER bitmap;
38 WAVEFORMATEX waveformat;
52 } videoreader_vfw_internal_t;
54 bool videoreader_vfw_eof(videoreader_t* vr)
56 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
57 return (i->video_pos >= i->video_end);
60 static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width, const int dest_height)
62 UCHAR*data = (UCHAR*)(bi+1); // actual bitmap data starts after the header
64 if(bi->biPlanes!=1 || bi->biCompression!=0 || bi->biBitCount%4!=0) {
65 /* unsupported format */
66 fprintf(stderr, "bitmap_to_rgba: unsupported format: biPlanes=%d, biCompression=%d biBitCount=%d\n",
67 bi->biPlanes, bi->biCompression, bi->biBitCount);
71 ULONG*dest = (ULONG*)buffer;
73 int width = bi->biWidth;
74 int height = bi->biHeight;
75 if(dest_width != width || dest_height != height) {
76 /* TODO: size conversion */
77 fprintf(stderr, "size mismatch: %dx%d != %dx%d\n", width, height, dest_width, dest_height);
81 /* convert the various image types to RGBA-
82 TODO: is there some way to let the Windows API do this? */
83 int bytesperpixel = ((bi->biWidth*bi->biBitCount)+7)&~7;
84 int linex = ((bytesperpixel/8)+3)&~3;
85 memset(dest, 255, dest_width*dest_height*4);//pre-fill alpha channel
86 if(bi->biBitCount==1) {
89 for(y=0;y<dest_height;y++) {
90 UCHAR*line = &img[linex*y];
92 for(x=0;x<dest_width;x++) {
93 *dest++ = 255*((line[x/8]>>(x&7))&1);
96 } else if(bi->biBitCount==4) {
98 UCHAR*img = &data[bi->biClrUsed*4];
100 for(y=0;y<dest_height;y++) {
101 UCHAR*line = &img[linex*y];
103 for(x=0;x<dest_width/2;x++) {
104 *dest++ = 255|pal[(line[0]>>4)<<2|0]<<8|pal[(line[0]>>4)<<2|1]<<16|pal[(line[0]>>4)<<2|2]<<24;
105 *dest++ = 255|pal[(line[0]&0x0f)<<2|0]<<8|pal[(line[0]&0x0f)<<2|1]<<16|pal[(line[0]&0x0f)<<2|2]<<24;
109 } else if(bi->biBitCount==8) {
111 UCHAR*img = &data[bi->biClrUsed*4];
113 for(y=0;y<dest_height;y++) {
114 UCHAR*line = &img[linex*y];
116 for(x=0;x<dest_width;x++) {
117 *dest++ = 255|pal[line[0]*4+2]<<8|pal[line[0]*4+1]<<16|pal[line[0]*4+0]<<24;
121 } else if(bi->biBitCount==24) {
124 for(y=0;y<dest_height;y++) {
125 UCHAR*line = &img[linex*y];
127 for(x=0;x<dest_width;x++) {
128 *dest++ = 255|line[2]<<8|line[1]<<16|line[0]<<24;
132 } else if(bi->biBitCount==32) {
135 for(y=0;y<dest_height;y++) {
136 UCHAR*line = &img[linex*y];
138 for(x=0;x<dest_width;x++) {
139 *dest++ = 255|line[0]<<8|line[1]<<16|line[2]<<24;
144 fprintf(stderr, "Unsupported format: bitcount=%d\n", bi->biBitCount);
150 int videoreader_vfw_getimage(videoreader_t* vr, void*buffer)
152 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
154 if(videoreader_vfw_eof(vr))
157 LPBITMAPINFOHEADER bi;
158 bi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(i->getframe, i->video_pos);
163 fprintf(stderr, "AVIStreamGetFrame failed\n");
166 printf("%dx%d:%d\n", bi->biWidth, bi->biHeight, bi->biBitCount);
168 if(!bitmap_to_rgba(bi, buffer, i->width, i->height)) {
169 fprintf(stderr, "couldn't convert bitmap to RGBA.\n");
172 return i->width*i->height*4;
175 static int readAudioBlock(videoreader_vfw_internal_t* i, void*buf, int len)
179 AVIStreamRead(i->as, i->audio_pos, len/(2*i->waveformat.nChannels), buf, len, &bytes, &samples);
180 i->audio_pos += samples;
184 int videoreader_vfw_getsamples(videoreader_t* vr, void*buf, int num)
186 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
188 switch(i->waveformat.wBitsPerSample) {
190 int len = readAudioBlock(i, buf, num);
193 ((SHORT*)buf)[t] = ((((BYTE*)buf)[t>>3])>>(t&7))<<15;
198 int len = readAudioBlock(i, buf, num);
201 ((SHORT*)buf)[t] = (((BYTE*)buf)[t]<<8)^0x8000;
206 return readAudioBlock(i, buf, num);
214 void videoreader_vfw_close(videoreader_t* vr)
216 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
218 AVIStreamGetFrameClose(i->getframe);
220 AVIStreamRelease(i->vs); i->vs = 0;
223 AVIStreamRelease(i->as); i->vs = 0;
225 AVIFileRelease(i->avifile); i->avifile = 0;
228 free(vr->internal); vr->internal = 0;
231 void videoreader_vfw_setparameter(videoreader_t* vr, char*name, char*value) {}
233 int videoreader_vfw_open(videoreader_t* vr, char* filename)
235 memset(vr, 0, sizeof(videoreader_t));
241 videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)malloc(sizeof(videoreader_vfw_internal_t));
242 memset(i, 0, sizeof(videoreader_vfw_internal_t));
245 vr->eof = videoreader_vfw_eof;
246 vr->getimage = videoreader_vfw_getimage;
247 vr->getsamples = videoreader_vfw_getsamples;
248 vr->close = videoreader_vfw_close;
249 vr->setparameter = videoreader_vfw_setparameter;
252 if(AVIFileOpen(&i->avifile, filename, OF_SHARE_DENY_WRITE, 0)) {
253 fprintf(stderr, "Couldn't open %s\n", filename);
257 AVIFileInfo(i->avifile, &info, sizeof(info));
259 /* calculate framerate */
260 i->fps = (double)info.dwRate/(double)info.dwScale;
263 while(t<info.dwStreams) {
265 if(AVIFileGetStream(i->avifile, &stream, streamtypeANY, t) != AVIERR_OK || !stream)
266 break; //video_end of (working) streams
268 AVISTREAMINFO streaminfo;
269 AVIStreamInfo(stream, &streaminfo, sizeof(streaminfo));
271 if (streaminfo.fccType == streamtypeVIDEO) {
274 BITMAPINFOHEADER bitmap;
275 LONG size = sizeof(i->bitmap);
276 AVIStreamReadFormat(i->vs, 0, &bitmap, &size);
278 if(i->bitmap.biCompression == 0/*RGB*/) {
281 i->width = bitmap.biWidth;
282 i->height = bitmap.biHeight;
285 else if (streaminfo.fccType == streamtypeAUDIO) {
288 WAVEFORMATEX waveformat;
289 LONG size = sizeof(i->waveformat);
290 AVIStreamReadFormat(i->as, 0, &waveformat, &size);
292 if(i->waveformat.wBitsPerSample == 16 || i->waveformat.wBitsPerSample == 8) {
293 i->waveformat = waveformat;
295 i->channels = i->waveformat.nChannels;
296 i->samplerate = i->waveformat.nSamplesPerSec;
302 vr->width = i->width;
303 vr->height = i->height;
306 fprintf(stderr, "AVIReader: Warning: No video stream\n");
309 vr->channels = i->channels;
310 vr->samplerate = i->samplerate;
312 fprintf(stderr, "AVIReader: Warning: No audio stream\n");
315 i->getframe = AVIStreamGetFrameOpen(i->vs, 0);
320 i->video_pos = AVIStreamStart(i->vs);
321 i->video_end = AVIStreamEnd(i->vs);
323 i->audio_end = 0x7fffffff;
330 int videoreader_vfw_open(videoreader_t* vr, char* filename)