2 * $Logfile: /Freespace2/src/movie/mvelib.cpp $
7 * Lib functions for MVE player
10 * Revision 1.2 2005/03/29 07:50:34 taylor
11 * Update to newest movie code with much better video support and audio support from
12 * Pierre Willenbrock. Movies are enabled always now (no longer a build option)
13 * and but can be skipped with the "--nomovies" or "-n" cmdline options.
26 static const char MVE_HEADER[] = "Interplay MVE File\x1A";
27 static const short MVE_HDRCONST1 = 0x001A;
28 static const short MVE_HDRCONST2 = 0x0100;
29 static const short MVE_HDRCONST3 = 0x1133;
32 // -----------------------------------------------------------
33 // public MVEFILE functions
34 // -----------------------------------------------------------
36 // utility functions for mvefile and mveplayer
37 short mve_get_short(ubyte *data)
40 value = data[0] | (data[1] << 8);
44 ushort mve_get_ushort(ubyte *data)
47 value = data[0] | (data[1] << 8);
51 int mve_get_int(ubyte *data)
54 value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
59 MVEFILE *mvefile_open(const char *filename)
66 file = (MVEFILE *)malloc(sizeof(MVEFILE));
70 file->cur_chunk = NULL;
73 file->next_segment = 0;
75 // NOTE: CF_TYPE *must* be ANY to get movies off of the CDs
77 // lower case filename check - off of HD/CD-ROM
78 file->stream = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_MOVIES);
80 // upper case filename check - off of CD-ROM (or HD if case not changed)
81 if ( !file->stream ) {
82 char upper_name[MAX_FILENAME_LEN];
84 // upper case filename for checking
85 SDL_strlcpy(upper_name, filename, SDL_arraysize(upper_name));
86 SDL_strupr(upper_name);
88 file->stream = cfopen(upper_name, "rb", CFILE_NORMAL, CF_TYPE_ANY);
91 if ( !file->stream ) {
96 // initialize the buffer
97 file->cur_chunk = (ubyte *)malloc(100 + 1024);
98 file->buf_size = 100 + 1024;
100 // verify the file's header
101 cfread_string(buffer, 20, file->stream);
103 if (strcmp(buffer, MVE_HEADER))
106 if (cfread_short(file->stream) != MVE_HDRCONST1)
109 if (cfread_short(file->stream) != MVE_HDRCONST2)
112 if (cfread_short(file->stream) != MVE_HDRCONST3)
120 // now, prefetch the next chunk
121 mvefile_fetch_next_chunk(file);
127 void mvefile_close(MVEFILE *file)
131 cfclose(file->stream);
137 free(file->cur_chunk);
139 file->cur_chunk = NULL;
141 // not strictly necessary
144 file->next_segment = 0;
150 // get the size of the next segment
151 int mvefile_get_next_segment_size(MVEFILE *file)
153 // if nothing is cached, fail
154 if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
157 // if we don't have enough data to get a segment, fail
158 if (file->cur_fill - file->next_segment < 4)
161 // otherwise, get the data length
162 return mve_get_short(file->cur_chunk + file->next_segment);
165 // get type of next segment in chunk (0xff if no more segments in chunk)
166 ubyte mvefile_get_next_segment_major(MVEFILE *file)
168 // if nothing is cached, fail
169 if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
172 // if we don't have enough data to get a segment, fail
173 if (file->cur_fill - file->next_segment < 4)
176 // otherwise, get the data length
177 return file->cur_chunk[file->next_segment + 2];
180 // get subtype (version) of next segment in chunk (0xff if no more segments in chunk)
181 ubyte mvefile_get_next_segment_minor(MVEFILE *file)
183 // if nothing is cached, fail
184 if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
187 // if we don't have enough data to get a segment, fail
188 if (file->cur_fill - file->next_segment < 4)
191 // otherwise, get the data length
192 return file->cur_chunk[file->next_segment + 3];
195 // see next segment (return NULL if no next segment)
196 ubyte *mvefile_get_next_segment(MVEFILE *file)
198 // if nothing is cached, fail
199 if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
202 // if we don't have enough data to get a segment, fail
203 if (file->cur_fill - file->next_segment < 4)
206 // otherwise, get the data length
207 return file->cur_chunk + file->next_segment + 4;
210 // advance to next segment
211 void mvefile_advance_segment(MVEFILE *file)
213 // if nothing is cached, fail
214 if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
217 // if we don't have enough data to get a segment, fail
218 if (file->cur_fill - file->next_segment < 4)
221 // else, advance to next segment
222 file->next_segment += (4 + mve_get_ushort(file->cur_chunk + file->next_segment));
225 // fetch the next chunk (return 0 if at end of stream)
226 int mvefile_fetch_next_chunk(MVEFILE *file)
233 if (file->stream == NULL)
236 // fail if we can't read the next segment descriptor
237 if (cfread(buffer, 1, 4, file->stream) != 4)
240 // pull out the next length
241 length = mve_get_ushort(buffer);
243 // setup a new buffer if needed --
244 // only allocate new buffer is old one is too small
245 if (length > file->buf_size) {
246 // allocate new buffer
247 new_buffer = (ubyte *)malloc(100 + length);
250 if (file->cur_chunk && file->cur_fill)
251 memcpy(new_buffer, file->cur_chunk, file->cur_fill);
254 if (file->cur_chunk) {
255 free(file->cur_chunk);
256 file->cur_chunk = NULL;
259 // install new buffer
260 file->cur_chunk = new_buffer;
261 file->buf_size = 100 + length;
266 if (cfread(file->cur_chunk, 1, length, file->stream) != length)
270 file->cur_fill = length;
271 file->next_segment = 0;
276 // -----------------------------------------------------------
277 // public MVESTREAM functions
278 // -----------------------------------------------------------
280 // open an MVE stream
281 MVESTREAM *mve_open(const char *filename)
286 stream = (MVESTREAM *)malloc(sizeof(MVESTREAM));
289 stream->movie = NULL;
292 stream->movie = mvefile_open(filename);
294 if (stream->movie == NULL) {
302 // close an MVE stream
303 void mve_close(MVESTREAM *stream)
307 mvefile_close(stream->movie);
309 stream->movie = NULL;
315 int mve_play_next_chunk(MVESTREAM *stream)
321 // loop over segments
322 major = mvefile_get_next_segment_major(stream->movie);
324 while (major != 0xff) {
325 // check whether to handle the segment
327 minor = mvefile_get_next_segment_minor(stream->movie);
328 len = mvefile_get_next_segment_size(stream->movie);
329 data = mvefile_get_next_segment(stream->movie);
339 mve_timer_create(data);
342 mve_audio_createbuf(minor, data);
348 if (!mve_video_createbuf(minor, data))
355 mve_audio_data(major, data);
358 mve_audio_data(major, data);
361 mve_video_codemap(data, len);
364 mve_video_data(data, len);
371 // advance to next segment
372 mvefile_advance_segment(stream->movie);
373 major = mvefile_get_next_segment_major(stream->movie);
376 if (!mvefile_fetch_next_chunk(stream->movie))