enable fontconfig support by default. This change takes only in effect,
[mplayer/glamo.git] / libmpdemux / demux_film.c
blob0737e8748f58520389402582bedaf2ad42916ac5
1 /*
2 * FILM file parser
3 * Copyright (C) 2002 Mike Melanson
5 * This demuxer handles FILM (a.k.a. CPK) files commonly found on Sega
6 * Saturn CD-ROM games. FILM files have also been found on 3DO games.
8 * details of the FILM file format can be found at:
9 * http://www.pcisys.net/~melanson/codecs/
11 * This file is part of MPlayer.
13 * MPlayer is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * MPlayer is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
32 #include "config.h"
33 #include "mp_msg.h"
34 #include "help_mp.h"
36 #include "stream/stream.h"
37 #include "demuxer.h"
38 #include "stheader.h"
40 // chunk types found in a FILM file
41 #define CHUNK_FILM mmioFOURCC('F', 'I', 'L', 'M')
42 #define CHUNK_FDSC mmioFOURCC('F', 'D', 'S', 'C')
43 #define CHUNK_STAB mmioFOURCC('S', 'T', 'A', 'B')
45 typedef struct film_chunk_t
47 off_t chunk_offset;
48 int chunk_size;
49 unsigned int syncinfo1;
50 unsigned int syncinfo2;
52 float pts;
53 } film_chunk_t;
55 typedef struct film_data_t
57 unsigned int total_chunks;
58 unsigned int current_chunk;
59 film_chunk_t *chunks;
60 unsigned int chunks_per_second;
61 unsigned int film_version;
62 } film_data_t;
64 static void demux_seek_film(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
66 film_data_t *film_data = (film_data_t *)demuxer->priv;
67 int new_current_chunk=(flags&SEEK_ABSOLUTE)?0:film_data->current_chunk;
69 if(flags&SEEK_FACTOR)
70 new_current_chunk += rel_seek_secs * film_data->total_chunks; // 0..1
71 else
72 new_current_chunk += rel_seek_secs * film_data->chunks_per_second; // secs
75 mp_msg(MSGT_DECVIDEO, MSGL_INFO,"current, total chunks = %d, %d; seek %5.3f sec, new chunk guess = %d\n",
76 film_data->current_chunk, film_data->total_chunks,
77 rel_seek_secs, new_current_chunk);
79 // check if the new chunk number is valid
80 if (new_current_chunk < 0)
81 new_current_chunk = 0;
82 if ((unsigned int)new_current_chunk > film_data->total_chunks)
83 new_current_chunk = film_data->total_chunks - 1;
85 while (((film_data->chunks[new_current_chunk].syncinfo1 == 0xFFFFFFFF) ||
86 (film_data->chunks[new_current_chunk].syncinfo1 & 0x80000000)) &&
87 (new_current_chunk > 0))
88 new_current_chunk--;
90 film_data->current_chunk = new_current_chunk;
92 mp_msg(MSGT_DECVIDEO, MSGL_INFO," (flags = %X) actual new chunk = %d (syncinfo1 = %08X)\n",
93 flags, film_data->current_chunk, film_data->chunks[film_data->current_chunk].syncinfo1);
94 demuxer->video->pts=film_data->chunks[film_data->current_chunk].pts;
98 // return value:
99 // 0 = EOF or no stream found
100 // 1 = successfully read a packet
101 static int demux_film_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
103 int i;
104 unsigned char byte_swap;
105 int cvid_size;
106 sh_video_t *sh_video = demuxer->video->sh;
107 sh_audio_t *sh_audio = demuxer->audio->sh;
108 film_data_t *film_data = (film_data_t *)demuxer->priv;
109 film_chunk_t film_chunk;
110 int length_fix_bytes;
111 demux_packet_t* dp;
113 // see if the end has been reached
114 if (film_data->current_chunk >= film_data->total_chunks)
115 return 0;
117 film_chunk = film_data->chunks[film_data->current_chunk];
119 // position stream and fetch chunk
120 stream_seek(demuxer->stream, film_chunk.chunk_offset);
122 // load the chunks manually (instead of using ds_read_packet()), since
123 // they require some adjustment
124 // (all ones in syncinfo1 indicates an audio chunk)
125 if (film_chunk.syncinfo1 == 0xFFFFFFFF)
127 if(demuxer->audio->id>=-1){ // audio not disabled
128 dp = new_demux_packet(film_chunk.chunk_size);
129 if (stream_read(demuxer->stream, dp->buffer, film_chunk.chunk_size) !=
130 film_chunk.chunk_size)
131 return 0;
132 dp->pts = film_chunk.pts;
133 dp->pos = film_chunk.chunk_offset;
134 dp->flags = 0;
136 // adjust the data before queuing it:
137 // 8-bit: signed -> unsigned
138 // 16-bit: big-endian -> little-endian
139 if (sh_audio->wf->wBitsPerSample == 8)
140 for (i = 0; i < film_chunk.chunk_size; i++)
141 dp->buffer[i] += 128;
142 else
143 for (i = 0; i < film_chunk.chunk_size; i += 2)
145 byte_swap = dp->buffer[i];
146 dp->buffer[i] = dp->buffer[i + 1];
147 dp->buffer[i + 1] = byte_swap;
150 /* for SegaSaturn .cpk file, translate audio data if stereo */
151 if (sh_audio->wf->nChannels == 2) {
152 if (sh_audio->wf->wBitsPerSample == 8) {
153 unsigned char* tmp = dp->buffer;
154 unsigned char buf[film_chunk.chunk_size];
155 for(i = 0; i < film_chunk.chunk_size/2; i++) {
156 buf[i*2] = tmp[i];
157 buf[i*2+1] = tmp[film_chunk.chunk_size/2+i];
159 memcpy( tmp, buf, film_chunk.chunk_size );
161 else {/* for 16bit */
162 unsigned short* tmp = dp->buffer;
163 unsigned short buf[film_chunk.chunk_size/2];
164 for(i = 0; i < film_chunk.chunk_size/4; i++) {
165 buf[i*2] = tmp[i];
166 buf[i*2+1] = tmp[film_chunk.chunk_size/4+i];
168 memcpy( tmp, buf, film_chunk.chunk_size );
172 // append packet to DS stream
173 ds_add_packet(demuxer->audio, dp);
176 else
178 // if the demuxer is dealing with CVID data, deal with it a special way
179 if (sh_video->format == mmioFOURCC('c', 'v', 'i', 'd'))
181 if (film_data->film_version)
182 length_fix_bytes = 2;
183 else
184 length_fix_bytes = 6;
186 // account for the fix bytes when allocating the buffer
187 dp = new_demux_packet(film_chunk.chunk_size - length_fix_bytes);
189 // these CVID data chunks have a few extra bytes; skip them
190 if (stream_read(demuxer->stream, dp->buffer, 10) != 10)
191 return 0;
192 stream_skip(demuxer->stream, length_fix_bytes);
194 if (stream_read(demuxer->stream, dp->buffer + 10,
195 film_chunk.chunk_size - (10 + length_fix_bytes)) !=
196 (film_chunk.chunk_size - (10 + length_fix_bytes)))
197 return 0;
199 dp->pts = film_chunk.pts;
200 dp->pos = film_chunk.chunk_offset;
201 dp->flags = (film_chunk.syncinfo1 & 0x80000000) ? 1 : 0;
203 // fix the CVID chunk size
204 cvid_size = film_chunk.chunk_size - length_fix_bytes;
205 dp->buffer[1] = (cvid_size >> 16) & 0xFF;
206 dp->buffer[2] = (cvid_size >> 8) & 0xFF;
207 dp->buffer[3] = (cvid_size >> 0) & 0xFF;
209 // append packet to DS stream
210 ds_add_packet(demuxer->video, dp);
212 else
214 ds_read_packet(demuxer->video, demuxer->stream, film_chunk.chunk_size,
215 film_chunk.pts,
216 film_chunk.chunk_offset, (film_chunk.syncinfo1 & 0x80000000) ? 1 : 0);
219 film_data->current_chunk++;
221 return 1;
224 static demuxer_t* demux_open_film(demuxer_t* demuxer)
226 sh_video_t *sh_video = NULL;
227 sh_audio_t *sh_audio = NULL;
228 film_data_t *film_data;
229 film_chunk_t film_chunk;
230 int header_size;
231 unsigned int chunk_type;
232 unsigned int chunk_size;
233 unsigned int i;
234 unsigned int video_format;
235 int audio_channels;
236 int counting_chunks;
237 unsigned int total_audio_bytes = 0;
239 film_data = malloc(sizeof(film_data_t));
240 film_data->total_chunks = 0;
241 film_data->current_chunk = 0;
242 film_data->chunks = NULL;
243 film_data->chunks_per_second = 0;
245 // go back to the beginning
246 stream_reset(demuxer->stream);
247 stream_seek(demuxer->stream, 0);
249 // read the master chunk type
250 chunk_type = stream_read_fourcc(demuxer->stream);
251 // validate the chunk type
252 if (chunk_type != CHUNK_FILM)
254 mp_msg(MSGT_DEMUX, MSGL_ERR, "Not a FILM file\n");
255 free(film_data);
256 return NULL;
259 // get the header size, which implicitly points past the header and
260 // to the start of the data
261 header_size = stream_read_dword(demuxer->stream);
262 film_data->film_version = stream_read_fourcc(demuxer->stream);
263 demuxer->movi_start = header_size;
264 demuxer->movi_end = demuxer->stream->end_pos;
265 header_size -= 16;
267 mp_msg(MSGT_DEMUX, MSGL_HINT, "FILM version %.4s\n",
268 (char *)&film_data->film_version);
270 // skip to where the next chunk should be
271 stream_skip(demuxer->stream, 4);
273 // traverse through the header
274 while (header_size > 0)
276 // fetch the chunk type and size
277 chunk_type = stream_read_fourcc(demuxer->stream);
278 chunk_size = stream_read_dword(demuxer->stream);
279 header_size -= chunk_size;
281 switch (chunk_type)
283 case CHUNK_FDSC:
284 mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing FDSC chunk\n");
286 // fetch the video codec fourcc to see if there's any video
287 video_format = stream_read_fourcc(demuxer->stream);
288 if (video_format)
290 // create and initialize the video stream header
291 sh_video = new_sh_video(demuxer, 0);
292 demuxer->video->sh = sh_video;
293 sh_video->ds = demuxer->video;
295 sh_video->format = video_format;
296 sh_video->disp_h = stream_read_dword(demuxer->stream);
297 sh_video->disp_w = stream_read_dword(demuxer->stream);
298 mp_msg(MSGT_DECVIDEO, MSGL_V,
299 " FILM video: %d x %d\n", sh_video->disp_w,
300 sh_video->disp_h);
302 else
303 // skip height and width if no video
304 stream_skip(demuxer->stream, 8);
306 if(demuxer->audio->id<-1){
307 mp_msg(MSGT_DECVIDEO, MSGL_INFO,"chunk size = 0x%X \n",chunk_size);
308 stream_skip(demuxer->stream, chunk_size-12-8);
309 break; // audio disabled (or no soundcard)
312 // skip over unknown byte, but only if file had non-NULL version
313 if (film_data->film_version)
314 stream_skip(demuxer->stream, 1);
316 // fetch the audio channels to see if there's any audio
317 // don't do this if the file is a quirky file with NULL version
318 if (film_data->film_version)
320 audio_channels = stream_read_char(demuxer->stream);
321 if (audio_channels > 0)
323 // create and initialize the audio stream header
324 sh_audio = new_sh_audio(demuxer, 0);
325 demuxer->audio->id = 0;
326 demuxer->audio->sh = sh_audio;
327 sh_audio->ds = demuxer->audio;
329 sh_audio->wf = malloc(sizeof(WAVEFORMATEX));
331 // uncompressed PCM format
332 sh_audio->wf->wFormatTag = 1;
333 sh_audio->format = 1;
334 sh_audio->wf->nChannels = audio_channels;
335 sh_audio->wf->wBitsPerSample = stream_read_char(demuxer->stream);
336 stream_skip(demuxer->stream, 1); // skip unknown byte
337 sh_audio->wf->nSamplesPerSec = stream_read_word(demuxer->stream);
338 sh_audio->wf->nAvgBytesPerSec =
339 sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample
340 * sh_audio->wf->nChannels / 8;
341 stream_skip(demuxer->stream, 6); // skip the rest of the unknown
343 mp_msg(MSGT_DECVIDEO, MSGL_V,
344 " FILM audio: %d channels, %d bits, %d Hz\n",
345 sh_audio->wf->nChannels, 8 * sh_audio->wf->wBitsPerSample,
346 sh_audio->wf->nSamplesPerSec);
348 else
349 stream_skip(demuxer->stream, 10);
351 else
353 // otherwise, make some assumptions about the audio
355 // create and initialize the audio stream header
356 sh_audio = new_sh_audio(demuxer, 0);
357 demuxer->audio->sh = sh_audio;
358 sh_audio->ds = demuxer->audio;
360 sh_audio->wf = malloc(sizeof(WAVEFORMATEX));
362 // uncompressed PCM format
363 sh_audio->wf->wFormatTag = 1;
364 sh_audio->format = 1;
365 sh_audio->wf->nChannels = 1;
366 sh_audio->wf->wBitsPerSample = 8;
367 sh_audio->wf->nSamplesPerSec = 22050;
368 sh_audio->wf->nAvgBytesPerSec =
369 sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample
370 * sh_audio->wf->nChannels / 8;
372 mp_msg(MSGT_DECVIDEO, MSGL_V,
373 " FILM audio: %d channels, %d bits, %d Hz\n",
374 sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
375 sh_audio->wf->nSamplesPerSec);
377 break;
379 case CHUNK_STAB:
380 mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing STAB chunk\n");
382 if (sh_video)
384 sh_video->fps = stream_read_dword(demuxer->stream);
385 sh_video->frametime = 1.0 / sh_video->fps;
388 // fetch the number of chunks
389 film_data->total_chunks = stream_read_dword(demuxer->stream);
390 film_data->current_chunk = 0;
391 mp_msg(MSGT_DECVIDEO, MSGL_V,
392 " STAB chunk contains %d chunks\n", film_data->total_chunks);
394 // allocate enough entries for the chunk
395 film_data->chunks =
396 calloc(film_data->total_chunks, sizeof(film_chunk_t));
398 // build the chunk index
399 counting_chunks = 1;
400 for (i = 0; i < film_data->total_chunks; i++)
402 film_chunk = film_data->chunks[i];
403 film_chunk.chunk_offset =
404 demuxer->movi_start + stream_read_dword(demuxer->stream);
405 film_chunk.chunk_size = stream_read_dword(demuxer->stream);
406 film_chunk.syncinfo1 = stream_read_dword(demuxer->stream);
407 film_chunk.syncinfo2 = stream_read_dword(demuxer->stream);
409 // count chunks for the purposes of seeking
410 if (counting_chunks)
412 // if we're counting chunks, always count an audio chunk
413 if (film_chunk.syncinfo1 == 0xFFFFFFFF)
414 film_data->chunks_per_second++;
415 // if it's a video chunk, check if it's time to stop counting
416 else if ((film_chunk.syncinfo1 & 0x7FFFFFFF) >= sh_video->fps)
417 counting_chunks = 0;
418 else
419 film_data->chunks_per_second++;
422 // precalculate PTS
423 if (film_chunk.syncinfo1 == 0xFFFFFFFF)
425 if(demuxer->audio->id>=-1)
426 film_chunk.pts =
427 (float)total_audio_bytes / (float)sh_audio->wf->nAvgBytesPerSec;
428 total_audio_bytes += film_chunk.chunk_size;
430 else
431 film_chunk.pts =
432 (film_chunk.syncinfo1 & 0x7FFFFFFF) / sh_video->fps;
434 film_data->chunks[i] = film_chunk;
437 // in some FILM files (notably '1.09'), the length of the FDSC chunk
438 // follows different rules
439 if (chunk_size == (film_data->total_chunks * 16))
440 header_size -= 16;
441 break;
443 default:
444 mp_msg(MSGT_DEMUX, MSGL_ERR, "Unrecognized FILM header chunk: %08X\n",
445 chunk_type);
446 return NULL;
447 break;
451 demuxer->priv = film_data;
453 return demuxer;
456 static void demux_close_film(demuxer_t* demuxer) {
457 film_data_t *film_data = demuxer->priv;
459 if(!film_data)
460 return;
461 if(film_data->chunks)
462 free(film_data->chunks);
463 free(film_data);
467 static int film_check_file(demuxer_t* demuxer)
469 int signature=stream_read_fourcc(demuxer->stream);
471 // check for the FILM file magic number
472 if(signature==mmioFOURCC('F', 'I', 'L', 'M'))
473 return DEMUXER_TYPE_FILM;
475 return 0;
479 const demuxer_desc_t demuxer_desc_film = {
480 "FILM/CPK demuxer for Sega Saturn CD-ROM games",
481 "film",
482 "FILM",
483 "Mike Melanson",
485 DEMUXER_TYPE_FILM,
486 0, // unsafe autodetect (short signature)
487 film_check_file,
488 demux_film_fill_buffer,
489 demux_open_film,
490 demux_close_film,
491 demux_seek_film,
492 NULL