FS2_Open
Open source remastering of the Freespace 2 engine
mvelib.cpp
Go to the documentation of this file.
1 
2 
3 #include "cfile/cfile.h"
4 #include "cutscene/mvelib.h"
5 #include "globalincs/pstypes.h"
6 
7 
8 static const char MVE_HEADER[] = "Interplay MVE File\x1A";
9 static const short MVE_HDRCONST1 = 0x001A;
10 static const short MVE_HDRCONST2 = 0x0100;
11 static const short MVE_HDRCONST3 = 0x1133;
12 
13 
14 // -----------------------------------------------------------
15 // public MVEFILE functions
16 // -----------------------------------------------------------
17 
18 // utility functions for mvefile and mveplayer
20 {
21  short value;
22  value = data[0] | (data[1] << 8);
23  return value;
24 }
25 
27 {
28  ushort value;
29  value = data[0] | (data[1] << 8);
30  return value;
31 }
32 
34 {
35  int value;
36  value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
37  return value;
38 }
39 
40 // open an MVE file
42 {
43  int cf_opened = 0;
44  int mve_valid = 1;
45  char lower_name[MAX_FILENAME_LEN];
46  char buffer[20];
47  MVEFILE *file;
48 
49  // create the file
50  file = (MVEFILE *)vm_malloc(sizeof(MVEFILE));
51 
52  // set defaults
53  file->stream = NULL;
54  file->cur_chunk = NULL;
55  file->buf_size = 0;
56  file->cur_fill = 0;
57  file->next_segment = 0;
58 
59  // lower case filename for checking
60  strncpy(lower_name, filename, strlen(filename)+1);
61  strlwr(lower_name);
62 
63  char *p = strchr( lower_name, '.' );
64  if ( p ) *p = 0;
65 
66  strcat_s( lower_name, ".mve" );
67 
68  // NOTE: CF_TYPE *must* be ANY to get movies off of the CDs
69  // assume lower case filename for *nix
70  file->stream = cfopen(lower_name, "rb", CFILE_NORMAL, CF_TYPE_ANY);
71  if ( file->stream ) {
72  cf_opened = 1;
73  }
74 
75  if (!cf_opened) {
76  mvefile_close(file);
77  return NULL;
78  }
79 
80  // initialize the buffer
81  file->cur_chunk = (ubyte *)vm_malloc(100 + 1024);
82  file->buf_size = 100 + 1024;
83 
84  // verify the file's header
85  cfread_string(buffer, 20, file->stream);
86 
87  if (strcmp(buffer, MVE_HEADER))
88  mve_valid = 0;
89 
90  if (cfread_short(file->stream) != MVE_HDRCONST1)
91  mve_valid = 0;
92 
93  if (cfread_short(file->stream) != MVE_HDRCONST2)
94  mve_valid = 0;
95 
96  if (cfread_short(file->stream) != MVE_HDRCONST3)
97  mve_valid = 0;
98 
99  if (!mve_valid) {
100  mvefile_close(file);
101  return NULL;
102  }
103 
104  // now, prefetch the next chunk
106 
107  return file;
108 }
109 
110 // close a MVE file
112 {
113  // free the stream
114  if (file->stream)
115  cfclose(file->stream);
116 
117  file->stream = NULL;
118 
119  // free the buffer
120  if (file->cur_chunk)
121  vm_free(file->cur_chunk);
122 
123  file->cur_chunk = NULL;
124 
125  // not strictly necessary
126  file->buf_size = 0;
127  file->cur_fill = 0;
128  file->next_segment = 0;
129 
130  // free the struct
131  vm_free(file);
132 }
133 
134 // get the size of the next segment
136 {
137  // if nothing is cached, fail
138  if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
139  return -1;
140 
141  // if we don't have enough data to get a segment, fail
142  if (file->cur_fill - file->next_segment < 4)
143  return -1;
144 
145  // otherwise, get the data length
146  return mve_get_short(file->cur_chunk + file->next_segment);
147 }
148 
149 // get type of next segment in chunk (0xff if no more segments in chunk)
151 {
152  // if nothing is cached, fail
153  if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
154  return 0xff;
155 
156  // if we don't have enough data to get a segment, fail
157  if (file->cur_fill - file->next_segment < 4)
158  return 0xff;
159 
160  // otherwise, get the data length
161  return file->cur_chunk[file->next_segment + 2];
162 }
163 
164 // get subtype (version) of next segment in chunk (0xff if no more segments in chunk)
166 {
167  // if nothing is cached, fail
168  if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
169  return 0xff;
170 
171  // if we don't have enough data to get a segment, fail
172  if (file->cur_fill - file->next_segment < 4)
173  return 0xff;
174 
175  // otherwise, get the data length
176  return file->cur_chunk[file->next_segment + 3];
177 }
178 
179 // see next segment (return NULL if no next segment)
181 {
182  // if nothing is cached, fail
183  if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
184  return NULL;
185 
186  // if we don't have enough data to get a segment, fail
187  if (file->cur_fill - file->next_segment < 4)
188  return NULL;
189 
190  // otherwise, get the data length
191  return file->cur_chunk + file->next_segment + 4;
192 }
193 
194 // advance to next segment
196 {
197  // if nothing is cached, fail
198  if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
199  return;
200 
201  // if we don't have enough data to get a segment, fail
202  if (file->cur_fill - file->next_segment < 4)
203  return;
204 
205  // else, advance to next segment
206  file->next_segment += (4 + mve_get_ushort(file->cur_chunk + file->next_segment));
207 }
208 
209 // fetch the next chunk (return 0 if at end of stream)
211 {
212  ubyte buffer[4];
213  ubyte *new_buffer;
214  ushort length;
215 
216  // fail if not open
217  if (file->stream == NULL)
218  return 0;
219 
220  // fail if we can't read the next segment descriptor
221  if (cfread(buffer, 1, 4, file->stream) < 4)
222  return 0;
223 
224  // pull out the next length
225  length = mve_get_short(buffer);
226 
227  // setup a new buffer if needed --
228  // only allocate new buffer is old one is too small
229  if (length > file->buf_size) {
230  // allocate new buffer
231  new_buffer = (ubyte *)vm_malloc(100 + length);
232 
233  // copy old data
234  if (file->cur_chunk && file->cur_fill)
235  memcpy(new_buffer, file->cur_chunk, file->cur_fill);
236 
237  // free old buffer
238  if (file->cur_chunk) {
239  vm_free(file->cur_chunk);
240  file->cur_chunk = NULL;
241  }
242 
243  // install new buffer
244  file->cur_chunk = new_buffer;
245  file->buf_size = 100 + length;
246  }
247 
248  // read the chunk
249  if (length > 0) {
250  if (cfread(file->cur_chunk, 1, length, file->stream) < length)
251  return 0;
252  }
253 
254  file->cur_fill = length;
255  file->next_segment = 0;
256 
257  return 1;
258 }
259 
260 // -----------------------------------------------------------
261 // public MVESTREAM functions
262 // -----------------------------------------------------------
263 
264 // open an MVE stream
266 {
267  MVESTREAM *stream;
268 
269  // allocate
270  stream = (MVESTREAM *)vm_malloc(sizeof(MVESTREAM));
271 
272  // defaults
273  stream->movie = NULL;
274 
275  // open
276  stream->movie = mvefile_open(filename);
277 
278  if (stream->movie == NULL) {
279  mve_close(stream);
280  return NULL;
281  }
282 
283  return stream;
284 }
285 
286 // close an MVE stream
288 {
289  // close MVEFILE
290  if (stream->movie)
291  mvefile_close(stream->movie);
292 
293  stream->movie = NULL;
294 
295  vm_free(stream);
296 }
297 
298 // play next chunk
300 {
301  ubyte major, minor;
302  ubyte *data;
303  int len;
304 
305  // loop over segments
306  major = mvefile_get_next_segment_major(stream->movie);
307  while (major != 0xff) {
308  // check whether to handle the segment
309  if (major < 32) {
310  minor = mvefile_get_next_segment_minor(stream->movie);
311  len = mvefile_get_next_segment_size(stream->movie);
312  data = mvefile_get_next_segment(stream->movie);
313 
314  switch (major) {
315  case 0x00:
316  mve_end_movie();
317  break;
318  case 0x01:
319  mve_end_chunk();
320  break;
321  case 0x02:
322  mve_timer_create(data);
323  break;
324  case 0x03:
325  mve_audio_createbuf(minor, data);
326  break;
327  case 0x04:
328  mve_audio_play();
329  break;
330  case 0x05:
331  if (!mve_video_createbuf(minor, data))
332  return 0;
333  break;
334  case 0x07:
336  break;
337  case 0x08:
338  mve_audio_data(major, data);
339  break;
340  case 0x09:
341  mve_audio_data(major, data);
342  break;
343  case 0x0a:
344  if (!mve_video_init(data))
345  return 0;
346  break;
347  case 0x0c:
348  mve_video_palette(data);
349  break;
350  case 0x0f:
351  mve_video_codemap(data, len);
352  break;
353  case 0x11:
354  mve_video_data(data, len);
355  break;
356  default:
357  break;
358  }
359  }
360 
361  // advance to next segment
363  major = mvefile_get_next_segment_major(stream->movie);
364  }
365 
366  if (!mvefile_fetch_next_chunk(stream->movie))
367  return 0;
368 
369  // return status
370  return 1;
371 }
void mve_audio_createbuf(ubyte minor, ubyte *data)
Definition: mveplayer.cpp:219
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
void mve_audio_play()
Definition: mveplayer.cpp:287
#define CFILE_NORMAL
Definition: cfile.h:89
#define vm_free(ptr)
Definition: pstypes.h:548
ushort mve_get_ushort(ubyte *data)
Definition: mvelib.cpp:26
int mvefile_fetch_next_chunk(MVEFILE *file)
Definition: mvelib.cpp:210
GLuint GLuint stream
Definition: Glext.h:7079
int mve_get_int(ubyte *data)
Definition: mvelib.cpp:33
ubyte * cur_chunk
Definition: mvelib.h:15
Definition: mvelib.h:12
int cfread(void *buf, int elsize, int nelem, CFILE *fp)
void mve_end_movie()
Definition: mveplayer.cpp:97
GLsizei const GLfloat * value
Definition: Glext.h:5646
int buf_size
Definition: mvelib.h:16
void cfread_string(char *buf, int n, CFILE *file)
Definition: cfile.cpp:1278
int mve_video_init(ubyte *data)
Definition: mveplayer.cpp:637
void mve_video_codemap(ubyte *data, int len)
Definition: mveplayer.cpp:713
int cur_fill
Definition: mvelib.h:17
ubyte * mvefile_get_next_segment(MVEFILE *file)
Definition: mvelib.cpp:180
short mve_get_short(ubyte *data)
Definition: mvelib.cpp:19
int mve_timer_create(ubyte *data)
Definition: mveplayer.cpp:106
#define cfopen(...)
Definition: cfile.h:134
char * filename
void mve_close(MVESTREAM *stream)
Definition: mvelib.cpp:287
void mve_video_data(ubyte *data, int len)
Definition: mveplayer.cpp:719
MVEFILE * movie
Definition: mvelib.h:48
GLuint buffer
Definition: Glext.h:5492
short cfread_short(CFILE *file, int ver, short deflt)
Definition: cfile.cpp:1192
int mve_audio_data(ubyte major, ubyte *data)
Definition: mveplayer.cpp:333
void mve_video_display()
Definition: mveplayer.cpp:585
void mvefile_advance_segment(MVEFILE *file)
Definition: mvelib.cpp:195
unsigned char ubyte
Definition: pstypes.h:62
CFILE * stream
Definition: mvelib.h:14
int mve_video_createbuf(ubyte minor, ubyte *data)
Definition: mveplayer.cpp:414
MVEFILE * mvefile_open(char *filename)
Definition: mvelib.cpp:41
int mve_play_next_chunk(MVESTREAM *stream)
Definition: mvelib.cpp:299
#define vm_malloc(size)
Definition: pstypes.h:547
int mvefile_get_next_segment_size(MVEFILE *file)
Definition: mvelib.cpp:135
int next_segment
Definition: mvelib.h:18
#define strcat_s(...)
Definition: safe_strings.h:68
ubyte mvefile_get_next_segment_major(MVEFILE *file)
Definition: mvelib.cpp:150
MVESTREAM * mve_open(char *filename)
Definition: mvelib.cpp:265
unsigned short ushort
Definition: pstypes.h:63
GLfloat GLfloat p
Definition: Glext.h:8373
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
GLenum GLuint GLenum GLsizei length
Definition: Glext.h:5156
GLenum GLsizei len
Definition: Glext.h:6283
void mve_end_chunk()
Definition: mveplayer.cpp:739
void mve_video_palette(ubyte *data)
Definition: mveplayer.cpp:705
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
ubyte mvefile_get_next_segment_minor(MVEFILE *file)
Definition: mvelib.cpp:165
#define CF_TYPE_ANY
Definition: cfile.h:42
void strlwr(char *s)
void mvefile_close(MVEFILE *file)
Definition: mvelib.cpp:111