ao_pulse: support native mute control
[mplayer.git] / libmpdemux / demux_film.c
blob8575d5f1e872748e882944e9ac04ec6622222b3f
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"
35 #include "stream/stream.h"
36 #include "demuxer.h"
37 #include "stheader.h"
39 // chunk types found in a FILM file
40 #define CHUNK_FILM mmioFOURCC('F', 'I', 'L', 'M')
41 #define CHUNK_FDSC mmioFOURCC('F', 'D', 'S', 'C')
42 #define CHUNK_STAB mmioFOURCC('S', 'T', 'A', 'B')
44 typedef struct film_chunk_t
46 off_t chunk_offset;
47 int chunk_size;
48 unsigned int syncinfo1;
49 unsigned int syncinfo2;
51 float pts;
52 } film_chunk_t;
54 typedef struct film_data_t
56 unsigned int total_chunks;
57 unsigned int current_chunk;
58 film_chunk_t *chunks;
59 unsigned int chunks_per_second;
60 unsigned int film_version;
61 } film_data_t;
63 static void demux_seek_film(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
65 film_data_t *film_data = (film_data_t *)demuxer->priv;
66 int new_current_chunk=(flags&SEEK_ABSOLUTE)?0:film_data->current_chunk;
68 if(flags&SEEK_FACTOR)
69 new_current_chunk += rel_seek_secs * film_data->total_chunks; // 0..1
70 else
71 new_current_chunk += rel_seek_secs * film_data->chunks_per_second; // secs
74 mp_msg(MSGT_DECVIDEO, MSGL_INFO,"current, total chunks = %d, %d; seek %5.3f sec, new chunk guess = %d\n",
75 film_data->current_chunk, film_data->total_chunks,
76 rel_seek_secs, new_current_chunk);
78 // check if the new chunk number is valid
79 if (new_current_chunk < 0)
80 new_current_chunk = 0;
81 if ((unsigned int)new_current_chunk > film_data->total_chunks)
82 new_current_chunk = film_data->total_chunks - 1;
84 while (((film_data->chunks[new_current_chunk].syncinfo1 == 0xFFFFFFFF) ||
85 (film_data->chunks[new_current_chunk].syncinfo1 & 0x80000000)) &&
86 (new_current_chunk > 0))
87 new_current_chunk--;
89 film_data->current_chunk = new_current_chunk;
91 mp_msg(MSGT_DECVIDEO, MSGL_INFO," (flags = %X) actual new chunk = %d (syncinfo1 = %08X)\n",
92 flags, film_data->current_chunk, film_data->chunks[film_data->current_chunk].syncinfo1);
93 demuxer->video->pts=film_data->chunks[film_data->current_chunk].pts;
97 // return value:
98 // 0 = EOF or no stream found
99 // 1 = successfully read a packet
100 static int demux_film_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
102 int i;
103 unsigned char byte_swap;
104 int cvid_size;
105 sh_video_t *sh_video = demuxer->video->sh;
106 sh_audio_t *sh_audio = demuxer->audio->sh;
107 film_data_t *film_data = (film_data_t *)demuxer->priv;
108 film_chunk_t film_chunk;
109 int length_fix_bytes;
110 demux_packet_t* dp;
112 // see if the end has been reached
113 if (film_data->current_chunk >= film_data->total_chunks)
114 return 0;
116 film_chunk = film_data->chunks[film_data->current_chunk];
118 // position stream and fetch chunk
119 stream_seek(demuxer->stream, film_chunk.chunk_offset);
121 // load the chunks manually (instead of using ds_read_packet()), since
122 // they require some adjustment
123 // (all ones in syncinfo1 indicates an audio chunk)
124 if (film_chunk.syncinfo1 == 0xFFFFFFFF)
126 if(demuxer->audio->id>=-1){ // audio not disabled
127 dp = new_demux_packet(film_chunk.chunk_size);
128 if (stream_read(demuxer->stream, dp->buffer, film_chunk.chunk_size) !=
129 film_chunk.chunk_size)
130 return 0;
131 dp->pts = film_chunk.pts;
132 dp->pos = film_chunk.chunk_offset;
133 dp->flags = 0;
135 // adjust the data before queuing it:
136 // 8-bit: signed -> unsigned
137 // 16-bit: big-endian -> little-endian
138 if (sh_audio->wf->wBitsPerSample == 8)
139 for (i = 0; i < film_chunk.chunk_size; i++)
140 dp->buffer[i] += 128;
141 else
142 for (i = 0; i < film_chunk.chunk_size; i += 2)
144 byte_swap = dp->buffer[i];
145 dp->buffer[i] = dp->buffer[i + 1];
146 dp->buffer[i + 1] = byte_swap;
149 /* for SegaSaturn .cpk file, translate audio data if stereo */
150 if (sh_audio->wf->nChannels == 2) {
151 if (sh_audio->wf->wBitsPerSample == 8) {
152 unsigned char* tmp = dp->buffer;
153 unsigned char buf[film_chunk.chunk_size];
154 for(i = 0; i < film_chunk.chunk_size/2; i++) {
155 buf[i*2] = tmp[i];
156 buf[i*2+1] = tmp[film_chunk.chunk_size/2+i];
158 memcpy( tmp, buf, film_chunk.chunk_size );
160 else {/* for 16bit */
161 unsigned short *tmp = (unsigned short *)dp->buffer;
162 unsigned short buf[film_chunk.chunk_size/2];
163 for(i = 0; i < film_chunk.chunk_size/4; i++) {
164 buf[i*2] = tmp[i];
165 buf[i*2+1] = tmp[film_chunk.chunk_size/4+i];
167 memcpy( tmp, buf, film_chunk.chunk_size );
171 // append packet to DS stream
172 ds_add_packet(demuxer->audio, dp);
175 else
177 // if the demuxer is dealing with CVID data, deal with it a special way
178 if (sh_video->format == mmioFOURCC('c', 'v', 'i', 'd'))
180 if (film_data->film_version)
181 length_fix_bytes = 2;
182 else
183 length_fix_bytes = 6;
185 // account for the fix bytes when allocating the buffer
186 dp = new_demux_packet(film_chunk.chunk_size - length_fix_bytes);
188 // these CVID data chunks have a few extra bytes; skip them
189 if (stream_read(demuxer->stream, dp->buffer, 10) != 10)
190 return 0;
191 stream_skip(demuxer->stream, length_fix_bytes);
193 if (stream_read(demuxer->stream, dp->buffer + 10,
194 film_chunk.chunk_size - (10 + length_fix_bytes)) !=
195 (film_chunk.chunk_size - (10 + length_fix_bytes)))
196 return 0;
198 dp->pts = film_chunk.pts;
199 dp->pos = film_chunk.chunk_offset;
200 dp->flags = (film_chunk.syncinfo1 & 0x80000000) ? 1 : 0;
202 // fix the CVID chunk size
203 cvid_size = film_chunk.chunk_size - length_fix_bytes;
204 dp->buffer[1] = (cvid_size >> 16) & 0xFF;
205 dp->buffer[2] = (cvid_size >> 8) & 0xFF;
206 dp->buffer[3] = (cvid_size >> 0) & 0xFF;
208 // append packet to DS stream
209 ds_add_packet(demuxer->video, dp);
211 else
213 ds_read_packet(demuxer->video, demuxer->stream, film_chunk.chunk_size,
214 film_chunk.pts,
215 film_chunk.chunk_offset, (film_chunk.syncinfo1 & 0x80000000) ? 1 : 0);
218 film_data->current_chunk++;
220 return 1;
223 static demuxer_t* demux_open_film(demuxer_t* demuxer)
225 sh_video_t *sh_video = NULL;
226 sh_audio_t *sh_audio = NULL;
227 film_data_t *film_data;
228 film_chunk_t film_chunk;
229 int header_size;
230 unsigned int chunk_type;
231 unsigned int chunk_size;
232 unsigned int i;
233 unsigned int video_format;
234 int audio_channels;
235 int counting_chunks;
236 unsigned int total_audio_bytes = 0;
238 film_data = malloc(sizeof(film_data_t));
239 film_data->total_chunks = 0;
240 film_data->current_chunk = 0;
241 film_data->chunks = NULL;
242 film_data->chunks_per_second = 0;
244 // go back to the beginning
245 stream_reset(demuxer->stream);
246 stream_seek(demuxer->stream, 0);
248 // read the master chunk type
249 chunk_type = stream_read_fourcc(demuxer->stream);
250 // validate the chunk type
251 if (chunk_type != CHUNK_FILM)
253 mp_msg(MSGT_DEMUX, MSGL_ERR, "Not a FILM file\n");
254 free(film_data);
255 return NULL;
258 // get the header size, which implicitly points past the header and
259 // to the start of the data
260 header_size = stream_read_dword(demuxer->stream);
261 film_data->film_version = stream_read_fourcc(demuxer->stream);
262 demuxer->movi_start = header_size;
263 demuxer->movi_end = demuxer->stream->end_pos;
264 header_size -= 16;
266 mp_msg(MSGT_DEMUX, MSGL_HINT, "FILM version %.4s\n",
267 (char *)&film_data->film_version);
269 // skip to where the next chunk should be
270 stream_skip(demuxer->stream, 4);
272 // traverse through the header
273 while (header_size > 0)
275 // fetch the chunk type and size
276 chunk_type = stream_read_fourcc(demuxer->stream);
277 chunk_size = stream_read_dword(demuxer->stream);
278 header_size -= chunk_size;
280 switch (chunk_type)
282 case CHUNK_FDSC:
283 mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing FDSC chunk\n");
285 // fetch the video codec fourcc to see if there's any video
286 video_format = stream_read_fourcc(demuxer->stream);
287 if (video_format)
289 // create and initialize the video stream header
290 sh_video = new_sh_video(demuxer, 0);
291 demuxer->video->sh = sh_video;
292 sh_video->ds = demuxer->video;
294 sh_video->format = video_format;
295 sh_video->disp_h = stream_read_dword(demuxer->stream);
296 sh_video->disp_w = stream_read_dword(demuxer->stream);
297 mp_msg(MSGT_DECVIDEO, MSGL_V,
298 " FILM video: %d x %d\n", sh_video->disp_w,
299 sh_video->disp_h);
301 else
302 // skip height and width if no video
303 stream_skip(demuxer->stream, 8);
305 if(demuxer->audio->id<-1){
306 mp_msg(MSGT_DECVIDEO, MSGL_INFO,"chunk size = 0x%X \n",chunk_size);
307 stream_skip(demuxer->stream, chunk_size-12-8);
308 break; // audio disabled (or no soundcard)
311 // skip over unknown byte, but only if file had non-NULL version
312 if (film_data->film_version)
313 stream_skip(demuxer->stream, 1);
315 // fetch the audio channels to see if there's any audio
316 // don't do this if the file is a quirky file with NULL version
317 if (film_data->film_version)
319 audio_channels = stream_read_char(demuxer->stream);
320 if (audio_channels > 0)
322 // create and initialize the audio stream header
323 sh_audio = new_sh_audio(demuxer, 0);
324 demuxer->audio->id = 0;
325 demuxer->audio->sh = sh_audio;
326 sh_audio->ds = demuxer->audio;
328 sh_audio->wf = malloc(sizeof(*sh_audio->wf));
330 // uncompressed PCM format
331 sh_audio->wf->wFormatTag = 1;
332 sh_audio->format = 1;
333 sh_audio->wf->nChannels = audio_channels;
334 sh_audio->wf->wBitsPerSample = stream_read_char(demuxer->stream);
335 stream_skip(demuxer->stream, 1); // skip unknown byte
336 sh_audio->wf->nSamplesPerSec = stream_read_word(demuxer->stream);
337 sh_audio->wf->nAvgBytesPerSec =
338 sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample
339 * sh_audio->wf->nChannels / 8;
340 stream_skip(demuxer->stream, 6); // skip the rest of the unknown
342 mp_msg(MSGT_DECVIDEO, MSGL_V,
343 " FILM audio: %d channels, %d bits, %d Hz\n",
344 sh_audio->wf->nChannels, 8 * sh_audio->wf->wBitsPerSample,
345 sh_audio->wf->nSamplesPerSec);
347 else
348 stream_skip(demuxer->stream, 10);
350 else
352 // otherwise, make some assumptions about the audio
354 // create and initialize the audio stream header
355 sh_audio = new_sh_audio(demuxer, 0);
356 demuxer->audio->sh = sh_audio;
357 sh_audio->ds = demuxer->audio;
359 sh_audio->wf = malloc(sizeof(*sh_audio->wf));
361 // uncompressed PCM format
362 sh_audio->wf->wFormatTag = 1;
363 sh_audio->format = 1;
364 sh_audio->wf->nChannels = 1;
365 sh_audio->wf->wBitsPerSample = 8;
366 sh_audio->wf->nSamplesPerSec = 22050;
367 sh_audio->wf->nAvgBytesPerSec =
368 sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample
369 * sh_audio->wf->nChannels / 8;
371 mp_msg(MSGT_DECVIDEO, MSGL_V,
372 " FILM audio: %d channels, %d bits, %d Hz\n",
373 sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
374 sh_audio->wf->nSamplesPerSec);
376 break;
378 case CHUNK_STAB:
379 mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing STAB chunk\n");
381 if (sh_video)
383 sh_video->fps = stream_read_dword(demuxer->stream);
384 sh_video->frametime = 1.0 / sh_video->fps;
387 // fetch the number of chunks
388 film_data->total_chunks = stream_read_dword(demuxer->stream);
389 film_data->current_chunk = 0;
390 mp_msg(MSGT_DECVIDEO, MSGL_V,
391 " STAB chunk contains %d chunks\n", film_data->total_chunks);
393 // allocate enough entries for the chunk
394 film_data->chunks =
395 calloc(film_data->total_chunks, sizeof(film_chunk_t));
397 // build the chunk index
398 counting_chunks = 1;
399 for (i = 0; i < film_data->total_chunks; i++)
401 film_chunk = film_data->chunks[i];
402 film_chunk.chunk_offset =
403 demuxer->movi_start + stream_read_dword(demuxer->stream);
404 film_chunk.chunk_size = stream_read_dword(demuxer->stream);
405 film_chunk.syncinfo1 = stream_read_dword(demuxer->stream);
406 film_chunk.syncinfo2 = stream_read_dword(demuxer->stream);
408 // count chunks for the purposes of seeking
409 if (counting_chunks)
411 // if we're counting chunks, always count an audio chunk
412 if (film_chunk.syncinfo1 == 0xFFFFFFFF)
413 film_data->chunks_per_second++;
414 // if it's a video chunk, check if it's time to stop counting
415 else if ((film_chunk.syncinfo1 & 0x7FFFFFFF) >= sh_video->fps)
416 counting_chunks = 0;
417 else
418 film_data->chunks_per_second++;
421 // precalculate PTS
422 if (film_chunk.syncinfo1 == 0xFFFFFFFF)
424 if(demuxer->audio->id>=-1)
425 film_chunk.pts =
426 (float)total_audio_bytes / (float)sh_audio->wf->nAvgBytesPerSec;
427 total_audio_bytes += film_chunk.chunk_size;
429 else
430 film_chunk.pts =
431 (film_chunk.syncinfo1 & 0x7FFFFFFF) / sh_video->fps;
433 film_data->chunks[i] = film_chunk;
436 // in some FILM files (notably '1.09'), the length of the FDSC chunk
437 // follows different rules
438 if (chunk_size == (film_data->total_chunks * 16))
439 header_size -= 16;
440 break;
442 default:
443 mp_msg(MSGT_DEMUX, MSGL_ERR, "Unrecognized FILM header chunk: %08X\n",
444 chunk_type);
445 return NULL;
446 break;
450 demuxer->priv = film_data;
452 return demuxer;
455 static void demux_close_film(demuxer_t* demuxer) {
456 film_data_t *film_data = demuxer->priv;
458 if(!film_data)
459 return;
460 free(film_data->chunks);
461 free(film_data);
465 static int film_check_file(demuxer_t* demuxer)
467 int signature=stream_read_fourcc(demuxer->stream);
469 // check for the FILM file magic number
470 if(signature==mmioFOURCC('F', 'I', 'L', 'M'))
471 return DEMUXER_TYPE_FILM;
473 return 0;
477 const demuxer_desc_t demuxer_desc_film = {
478 "FILM/CPK demuxer for Sega Saturn CD-ROM games",
479 "film",
480 "FILM",
481 "Mike Melanson",
483 DEMUXER_TYPE_FILM,
484 0, // unsafe autodetect (short signature)
485 film_check_file,
486 demux_film_fill_buffer,
487 demux_open_film,
488 demux_close_film,
489 demux_seek_film,
490 NULL