moved out of avi2swf.cc
[swftools.git] / avi2swf / videoreader_avifile.cc
1 /* videoreader_avifile.cc
2    Read avi files using the avifile library.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001,2002,2003 Matthias Kramm <kramm@quiss.org>
7  
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.
12
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.
17
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 */
21
22 #include "../config.h"
23
24 extern "C" {
25 #include "../lib/args.h"
26 }
27 #include "v2swf.h"
28 #include "../lib/q.h"
29
30 #undef HAVE_CONFIG_H
31
32 #ifdef HAVE_VERSION_H
33   #include <version.h>
34 #endif
35 #ifdef HAVE_AVIFILE_VERSION_H
36   #include <avifile/version.h>
37 #endif
38
39 #if (AVIFILE_MAJOR_VERSION == 0) && (AVIFILE_MINOR_VERSION>=6) 
40    #include <avifile.h>
41    #include <aviplay.h>
42    #include <fourcc.h>
43    #include <creators.h>
44    #include <StreamInfo.h>
45    #define VERSION6
46 #else
47    #include <avifile.h>
48    #include <aviplay.h>
49    #include <aviutil.h>
50    #define Width width
51    #define Height height
52    #define Data data
53    #define Bpp bpp
54 #endif
55
56 #include "videoreader.h"
57
58 typedef struct _videoreader_avifile_internal
59 {
60     IAviReadFile* player;
61     IAviReadStream* astream;
62     IAviReadStream* vstream;
63     int do_audio;
64     int do_video;
65     int eof;
66     int frame;
67     int soundbits;
68     ringbuffer_t audio_buffer;
69 } videoreader_avifile_internal;
70
71 static void readSamples(videoreader_avifile_internal*i, void*buffer, int buffer_size, int numsamples)
72 {
73     int ret;
74     while(i->audio_buffer.available < buffer_size) {
75         unsigned int samples_read = 0, bytes_read = 0;
76         ret = i->astream->ReadFrames(buffer, buffer_size, numsamples, samples_read, bytes_read);
77         if(samples_read<=0)
78             return;
79         ringbuffer_put(&i->audio_buffer, buffer, bytes_read);
80     }
81     ringbuffer_read(&i->audio_buffer, buffer, buffer_size);
82 }
83 static int videoreader_avifile_getsamples(videoreader_t* v, void*buffer, int num)
84 {
85     if(verbose) {
86         printf("videoreader_getsamples(%d)\n", num);fflush(stdout);
87     }
88     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
89     if(i->soundbits == 8) {
90         readSamples(i, buffer, num/2, num/(v->channels*2));
91         unsigned char*b = (unsigned char*)buffer;
92         int t;
93         for(t=num-2;t>=0;t-=2) {
94             unsigned char x = b[t/2];
95             b[t] = 0;
96             b[t+1] = x-128;
97         }
98         return num;
99     }
100     if(i->soundbits == 16) {
101         readSamples(i, buffer, num, num/(v->channels*2));
102         return num;
103     }
104     return 0;
105 }
106 static int videoreader_avifile_getimage(videoreader_t* v, void*buffer)
107 {
108     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
109     if(verbose) {
110         printf("videoreader_getimage()\n");fflush(stdout);
111     }
112
113     if(shutdown_avi2swf)
114         i->eof = 1;
115     
116     if(i->eof)
117         return 0;
118
119     if(i->vstream->ReadFrame() < 0) {
120         if(verbose) printf("vstream->ReadFrame() returned value < 0, shutting down...\n");
121         i->eof = 1;
122         return 0;
123     }
124     CImage*img2 = 0;
125     CImage*img = i->vstream->GetFrame();
126     if(!img) {
127         if(verbose) printf("vstream->GetFrame() returned NULL, shutting down...\n");
128         i->eof = 1;
129         return 0;
130     }
131     /* we convert the image to YUV first, because we can convert to RGB from YUV only */
132     img->ToYUV();
133     img->ToRGB();
134     if(img->Bpp() != 3) {
135         if(verbose) printf("Warning: converthing from bpp %d to bpp 3, this fails on older avifile versions...\n", img->Bpp());
136         BitmapInfo tmp(v->width, v->height, 24);
137         img2 = new CImage(img, &tmp);
138         img = img2;
139     }
140
141
142     frameno++;
143     i->frame++;
144     unsigned char*data = img->Data();
145     int bpp = img->Bpp();
146     if(bpp == 3) {
147         int x,y;
148         for(y=0;y<v->height;y++) {
149             unsigned char*from,*to;
150             to = &((unsigned char*)buffer)[y*v->width*4];
151             if(flip)
152                 from = img->At(v->height-y-1);
153             else
154                 from = img->At(y);
155             for(x=0;x<v->width;x++) {
156                 to[x*4+0] = 0;
157                 to[x*4+1] = from[x*3+2];
158                 to[x*4+2] = from[x*3+1];
159                 to[x*4+3] = from[x*3+0];
160             }
161         }
162         if(img2) delete img2;
163         return v->width*v->height*4;
164     } else {
165         if(img2) delete img2;
166         if(verbose) printf("Can't handle bpp %d, shutting down...\n", bpp);
167         return 0;
168     }
169 }
170 static bool videoreader_avifile_eof(videoreader_t* v)
171 {
172     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
173     if(verbose) {
174         printf("videoreader_eof()\n");fflush(stdout);
175     }
176     return i->eof;
177 }
178 static void videoreader_avifile_close(videoreader_t* v)
179 {
180     videoreader_avifile_internal*i = (videoreader_avifile_internal*)v->internal;
181     if(verbose) {
182         printf("videoreader_close()\n");fflush(stdout);
183     }
184     if(i->do_audio) {
185         ringbuffer_clear(&i->audio_buffer);
186     }
187 }
188 static void videoreader_avifile_setparameter(videoreader_t*v, char*name, char*value)
189 {
190     if(verbose) {
191         printf("videoreader_setparameter(%s, %s)\n", name, value);fflush(stdout);
192     }
193 }
194
195 int videoreader_avifile_open(videoreader_t* v, char* filename)
196 {
197     videoreader_avifile_internal* i;
198     i = (videoreader_avifile_internal*)malloc(sizeof(videoreader_avifile_internal));
199     memset(i, 0, sizeof(videoreader_avifile_internal));
200     memset(v, 0, sizeof(videoreader_t));
201     v->getsamples = videoreader_avifile_getsamples;
202     v->getinfo = videoreader_avifile_getinfo;
203     v->close = videoreader_avifile_close;
204     v->eof = videoreader_avifile_eof;
205     v->getimage = videoreader_avifile_getimage;
206     v->getsamples = videoreader_avifile_getsamples;
207     v->setparameter = videoreader_avifile_setparameter;
208     v->internal = i;
209     
210     i->do_video = 1;
211     i->do_audio = 1;
212
213     i->player = CreateIAviReadFile(filename);    
214     if(verbose) {
215         printf("%d streams (%d video, %d audio)\n", 
216                 i->player->StreamCount(),
217                 i->player->VideoStreamCount(),
218                 i->player->AudioStreamCount());
219     }
220     i->astream = i->player->GetStream(0, AviStream::Audio);
221     i->vstream = i->player->GetStream(0, AviStream::Video);
222     if(!i->vstream) {
223         printf("Couldn't open video stream\n");
224         i->do_video = 0;
225     }
226     if(!i->astream) {
227         printf("Couldn't open video stream\n");
228         i->do_audio = 0;
229     }
230 #ifdef NO_MP3
231     if(i->do_audio) {
232         printf(stderr, "MP3 support has been disabled at compile time, not converting soundtrack");
233         i->do_audio = 0;
234     }
235 #endif
236
237     if(!i->do_video && !i->do_audio) {
238         printf("File has neither audio nor video streams.(?)\n");
239         return 0;
240     }
241
242 #ifndef VERSION6
243     MainAVIHeader head;
244     int dwMicroSecPerFrame = 0;
245     player->GetFileHeader(&head);
246     printf("fps: %d\n", 1000000/head.dwMicroSecPerFrame);
247     printf("frames: %d\n", head.dwTotalFrames);
248     printf("streams: %d\n", head.dwStreams);
249     printf("width: %d\n", head.dwWidth);
250     printf("height: %d\n", head.dwHeight);
251     printf("sound: %u samples (%f seconds)\n", i->astream->GetEndPos(), i->astream->GetEndTime());
252     v->width = head.dwWidth;
253     v->height = head.dwHeight;
254     dwMicroSecPerFrame = head.dwMicroSecPerFrame;
255     samplesperframe = astream->GetEndPos()/astream->GetEndTime()*head.dwMicroSecPerFrame/1000000;
256     v->rate = (int)(astream->GetEndPos()/astream->GetEndTime());
257     v->fps = 1000000.0/dwMicroSecPerFrame;
258     i->soundbits = 16;
259 #else
260     if(i->do_video)
261     {
262         StreamInfo*videoinfo;
263         videoinfo = i->vstream->GetStreamInfo();
264         v->width = videoinfo->GetVideoWidth();
265         v->height = videoinfo->GetVideoHeight();
266         v->fps = (double)(videoinfo->GetFps());
267     }
268     if(i->do_audio)
269     {
270         WAVEFORMATEX wave;
271         StreamInfo*audioinfo;
272
273         i->astream->GetAudioFormatInfo(&wave,0);
274         audioinfo = i->astream->GetStreamInfo();
275
276         v->channels = wave.nChannels;
277         v->rate = wave.nSamplesPerSec;
278         i->soundbits = wave.wBitsPerSample;
279
280         if(v->channels==0 || v->rate==0 || i->soundbits==0 || wave.wFormatTag!=1) {
281             v->rate = audioinfo->GetAudioSamplesPerSec();
282             v->channels = audioinfo->GetAudioChannels();
283             i->soundbits = audioinfo->GetAudioBitsPerSample();
284         }
285
286         if(verbose) {
287             printf("formatinfo: format %d, %d channels, %d bits/sample, rate %d, blockalign %d\n", wave.wFormatTag, wave.nChannels, wave.wBitsPerSample, wave.nSamplesPerSec, wave.nBlockAlign);
288             printf("audioinfo: %d channels, %d bits/sample, rate %d\n", audioinfo->GetAudioChannels(), audioinfo->GetAudioBitsPerSample(), audioinfo->GetAudioSamplesPerSec());
289         }
290         if(i->soundbits != 8 && i->soundbits != 16) {
291             printf("Can't handle %d bit audio, disabling sound\n", wave.wBitsPerSample);
292             i->do_audio = 0;
293             i->soundbits = 0;
294             v->channels = 0;
295             v->rate = 0;
296         }
297     }
298 #endif
299     i->vstream -> StartStreaming();
300     if(i->do_audio) {
301         i->astream -> StartStreaming();
302         ringbuffer_init(&i->audio_buffer);
303 #ifdef VERSION6
304         WAVEFORMATEX wave;
305         i->astream -> GetOutputFormat(&wave, sizeof(wave));
306         printf("formatinfo: format %d, %d channels, %d bits/sample, rate %d, blockalign %d\n", wave.wFormatTag, wave.nChannels, wave.wBitsPerSample, wave.nSamplesPerSec, wave.nBlockAlign);
307 #endif
308     }
309
310     return 1;
311 }
312