2 FILM file parser for the MPlayer program
5 This demuxer handles FILM (a.k.a. CPK) files commonly found on
6 Sega Saturn CD-ROM games. FILM files have also been found on 3DO
9 Details of the FILM file format can be found at:
10 http://www.pcisys.net/~melanson/codecs/
21 #include "stream/stream.h"
25 // chunk types found in a FILM file
26 #define CHUNK_FILM mmioFOURCC('F', 'I', 'L', 'M')
27 #define CHUNK_FDSC mmioFOURCC('F', 'D', 'S', 'C')
28 #define CHUNK_STAB mmioFOURCC('S', 'T', 'A', 'B')
30 typedef struct film_chunk_t
34 unsigned int syncinfo1
;
35 unsigned int syncinfo2
;
40 typedef struct film_data_t
42 unsigned int total_chunks
;
43 unsigned int current_chunk
;
45 unsigned int chunks_per_second
;
46 unsigned int film_version
;
49 static void demux_seek_film(demuxer_t
*demuxer
, float rel_seek_secs
, float audio_delay
, int flags
)
51 film_data_t
*film_data
= (film_data_t
*)demuxer
->priv
;
52 int new_current_chunk
=(flags
&SEEK_ABSOLUTE
)?0:film_data
->current_chunk
;
55 new_current_chunk
+= rel_seek_secs
* film_data
->total_chunks
; // 0..1
57 new_current_chunk
+= rel_seek_secs
* film_data
->chunks_per_second
; // secs
60 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
,"current, total chunks = %d, %d; seek %5.3f sec, new chunk guess = %d\n",
61 film_data
->current_chunk
, film_data
->total_chunks
,
62 rel_seek_secs
, new_current_chunk
);
64 // check if the new chunk number is valid
65 if (new_current_chunk
< 0)
66 new_current_chunk
= 0;
67 if ((unsigned int)new_current_chunk
> film_data
->total_chunks
)
68 new_current_chunk
= film_data
->total_chunks
- 1;
70 while (((film_data
->chunks
[new_current_chunk
].syncinfo1
== 0xFFFFFFFF) ||
71 (film_data
->chunks
[new_current_chunk
].syncinfo1
& 0x80000000)) &&
72 (new_current_chunk
> 0))
75 film_data
->current_chunk
= new_current_chunk
;
77 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
," (flags = %X) actual new chunk = %d (syncinfo1 = %08X)\n",
78 flags
, film_data
->current_chunk
, film_data
->chunks
[film_data
->current_chunk
].syncinfo1
);
79 demuxer
->video
->pts
=film_data
->chunks
[film_data
->current_chunk
].pts
;
84 // 0 = EOF or no stream found
85 // 1 = successfully read a packet
86 static int demux_film_fill_buffer(demuxer_t
*demuxer
, demux_stream_t
*ds
)
89 unsigned char byte_swap
;
91 sh_video_t
*sh_video
= demuxer
->video
->sh
;
92 sh_audio_t
*sh_audio
= demuxer
->audio
->sh
;
93 film_data_t
*film_data
= (film_data_t
*)demuxer
->priv
;
94 film_chunk_t film_chunk
;
98 // see if the end has been reached
99 if (film_data
->current_chunk
>= film_data
->total_chunks
)
102 film_chunk
= film_data
->chunks
[film_data
->current_chunk
];
104 // position stream and fetch chunk
105 stream_seek(demuxer
->stream
, film_chunk
.chunk_offset
);
107 // load the chunks manually (instead of using ds_read_packet()), since
108 // they require some adjustment
109 // (all ones in syncinfo1 indicates an audio chunk)
110 if (film_chunk
.syncinfo1
== 0xFFFFFFFF)
112 if(demuxer
->audio
->id
>=-1){ // audio not disabled
113 dp
= new_demux_packet(film_chunk
.chunk_size
);
114 if (stream_read(demuxer
->stream
, dp
->buffer
, film_chunk
.chunk_size
) !=
115 film_chunk
.chunk_size
)
117 dp
->pts
= film_chunk
.pts
;
118 dp
->pos
= film_chunk
.chunk_offset
;
121 // adjust the data before queuing it:
122 // 8-bit: signed -> unsigned
123 // 16-bit: big-endian -> little-endian
124 if (sh_audio
->wf
->wBitsPerSample
== 8)
125 for (i
= 0; i
< film_chunk
.chunk_size
; i
++)
126 dp
->buffer
[i
] += 128;
128 for (i
= 0; i
< film_chunk
.chunk_size
; i
+= 2)
130 byte_swap
= dp
->buffer
[i
];
131 dp
->buffer
[i
] = dp
->buffer
[i
+ 1];
132 dp
->buffer
[i
+ 1] = byte_swap
;
135 /* for SegaSaturn .cpk file, translate audio data if stereo */
136 if (sh_audio
->wf
->nChannels
== 2) {
137 if (sh_audio
->wf
->wBitsPerSample
== 8) {
138 unsigned char* tmp
= dp
->buffer
;
139 unsigned char buf
[film_chunk
.chunk_size
];
140 for(i
= 0; i
< film_chunk
.chunk_size
/2; i
++) {
142 buf
[i
*2+1] = tmp
[film_chunk
.chunk_size
/2+i
];
144 memcpy( tmp
, buf
, film_chunk
.chunk_size
);
146 else {/* for 16bit */
147 unsigned short* tmp
= dp
->buffer
;
148 unsigned short buf
[film_chunk
.chunk_size
/2];
149 for(i
= 0; i
< film_chunk
.chunk_size
/4; i
++) {
151 buf
[i
*2+1] = tmp
[film_chunk
.chunk_size
/4+i
];
153 memcpy( tmp
, buf
, film_chunk
.chunk_size
);
157 // append packet to DS stream
158 ds_add_packet(demuxer
->audio
, dp
);
163 // if the demuxer is dealing with CVID data, deal with it a special way
164 if (sh_video
->format
== mmioFOURCC('c', 'v', 'i', 'd'))
166 if (film_data
->film_version
)
167 length_fix_bytes
= 2;
169 length_fix_bytes
= 6;
171 // account for the fix bytes when allocating the buffer
172 dp
= new_demux_packet(film_chunk
.chunk_size
- length_fix_bytes
);
174 // these CVID data chunks have a few extra bytes; skip them
175 if (stream_read(demuxer
->stream
, dp
->buffer
, 10) != 10)
177 stream_skip(demuxer
->stream
, length_fix_bytes
);
179 if (stream_read(demuxer
->stream
, dp
->buffer
+ 10,
180 film_chunk
.chunk_size
- (10 + length_fix_bytes
)) !=
181 (film_chunk
.chunk_size
- (10 + length_fix_bytes
)))
184 dp
->pts
= film_chunk
.pts
;
185 dp
->pos
= film_chunk
.chunk_offset
;
186 dp
->flags
= (film_chunk
.syncinfo1
& 0x80000000) ? 1 : 0;
188 // fix the CVID chunk size
189 cvid_size
= film_chunk
.chunk_size
- length_fix_bytes
;
190 dp
->buffer
[1] = (cvid_size
>> 16) & 0xFF;
191 dp
->buffer
[2] = (cvid_size
>> 8) & 0xFF;
192 dp
->buffer
[3] = (cvid_size
>> 0) & 0xFF;
194 // append packet to DS stream
195 ds_add_packet(demuxer
->video
, dp
);
199 ds_read_packet(demuxer
->video
, demuxer
->stream
, film_chunk
.chunk_size
,
201 film_chunk
.chunk_offset
, (film_chunk
.syncinfo1
& 0x80000000) ? 1 : 0);
204 film_data
->current_chunk
++;
209 static demuxer_t
* demux_open_film(demuxer_t
* demuxer
)
211 sh_video_t
*sh_video
= NULL
;
212 sh_audio_t
*sh_audio
= NULL
;
213 film_data_t
*film_data
;
214 film_chunk_t film_chunk
;
216 unsigned int chunk_type
;
217 unsigned int chunk_size
;
219 unsigned int video_format
;
222 unsigned int total_audio_bytes
= 0;
224 film_data
= malloc(sizeof(film_data_t
));
225 film_data
->total_chunks
= 0;
226 film_data
->current_chunk
= 0;
227 film_data
->chunks
= NULL
;
228 film_data
->chunks_per_second
= 0;
230 // go back to the beginning
231 stream_reset(demuxer
->stream
);
232 stream_seek(demuxer
->stream
, 0);
234 // read the master chunk type
235 chunk_type
= stream_read_fourcc(demuxer
->stream
);
236 // validate the chunk type
237 if (chunk_type
!= CHUNK_FILM
)
239 mp_msg(MSGT_DEMUX
, MSGL_ERR
, "Not a FILM file\n");
244 // get the header size, which implicitly points past the header and
245 // to the start of the data
246 header_size
= stream_read_dword(demuxer
->stream
);
247 film_data
->film_version
= stream_read_fourcc(demuxer
->stream
);
248 demuxer
->movi_start
= header_size
;
249 demuxer
->movi_end
= demuxer
->stream
->end_pos
;
252 mp_msg(MSGT_DEMUX
, MSGL_HINT
, "FILM version %.4s\n",
253 (char *)&film_data
->film_version
);
255 // skip to where the next chunk should be
256 stream_skip(demuxer
->stream
, 4);
258 // traverse through the header
259 while (header_size
> 0)
261 // fetch the chunk type and size
262 chunk_type
= stream_read_fourcc(demuxer
->stream
);
263 chunk_size
= stream_read_dword(demuxer
->stream
);
264 header_size
-= chunk_size
;
269 mp_msg(MSGT_DECVIDEO
, MSGL_V
, "parsing FDSC chunk\n");
271 // fetch the video codec fourcc to see if there's any video
272 video_format
= stream_read_fourcc(demuxer
->stream
);
275 // create and initialize the video stream header
276 sh_video
= new_sh_video(demuxer
, 0);
277 demuxer
->video
->sh
= sh_video
;
278 sh_video
->ds
= demuxer
->video
;
280 sh_video
->format
= video_format
;
281 sh_video
->disp_h
= stream_read_dword(demuxer
->stream
);
282 sh_video
->disp_w
= stream_read_dword(demuxer
->stream
);
283 mp_msg(MSGT_DECVIDEO
, MSGL_V
,
284 " FILM video: %d x %d\n", sh_video
->disp_w
,
288 // skip height and width if no video
289 stream_skip(demuxer
->stream
, 8);
291 if(demuxer
->audio
->id
<-1){
292 mp_msg(MSGT_DECVIDEO
, MSGL_INFO
,"chunk size = 0x%X \n",chunk_size
);
293 stream_skip(demuxer
->stream
, chunk_size
-12-8);
294 break; // audio disabled (or no soundcard)
297 // skip over unknown byte, but only if file had non-NULL version
298 if (film_data
->film_version
)
299 stream_skip(demuxer
->stream
, 1);
301 // fetch the audio channels to see if there's any audio
302 // don't do this if the file is a quirky file with NULL version
303 if (film_data
->film_version
)
305 audio_channels
= stream_read_char(demuxer
->stream
);
306 if (audio_channels
> 0)
308 // create and initialize the audio stream header
309 sh_audio
= new_sh_audio(demuxer
, 0);
310 demuxer
->audio
->id
= 0;
311 demuxer
->audio
->sh
= sh_audio
;
312 sh_audio
->ds
= demuxer
->audio
;
314 sh_audio
->wf
= malloc(sizeof(WAVEFORMATEX
));
316 // uncompressed PCM format
317 sh_audio
->wf
->wFormatTag
= 1;
318 sh_audio
->format
= 1;
319 sh_audio
->wf
->nChannels
= audio_channels
;
320 sh_audio
->wf
->wBitsPerSample
= stream_read_char(demuxer
->stream
);
321 stream_skip(demuxer
->stream
, 1); // skip unknown byte
322 sh_audio
->wf
->nSamplesPerSec
= stream_read_word(demuxer
->stream
);
323 sh_audio
->wf
->nAvgBytesPerSec
=
324 sh_audio
->wf
->nSamplesPerSec
* sh_audio
->wf
->wBitsPerSample
325 * sh_audio
->wf
->nChannels
/ 8;
326 stream_skip(demuxer
->stream
, 6); // skip the rest of the unknown
328 mp_msg(MSGT_DECVIDEO
, MSGL_V
,
329 " FILM audio: %d channels, %d bits, %d Hz\n",
330 sh_audio
->wf
->nChannels
, 8 * sh_audio
->wf
->wBitsPerSample
,
331 sh_audio
->wf
->nSamplesPerSec
);
334 stream_skip(demuxer
->stream
, 10);
338 // otherwise, make some assumptions about the audio
340 // create and initialize the audio stream header
341 sh_audio
= new_sh_audio(demuxer
, 0);
342 demuxer
->audio
->sh
= sh_audio
;
343 sh_audio
->ds
= demuxer
->audio
;
345 sh_audio
->wf
= malloc(sizeof(WAVEFORMATEX
));
347 // uncompressed PCM format
348 sh_audio
->wf
->wFormatTag
= 1;
349 sh_audio
->format
= 1;
350 sh_audio
->wf
->nChannels
= 1;
351 sh_audio
->wf
->wBitsPerSample
= 8;
352 sh_audio
->wf
->nSamplesPerSec
= 22050;
353 sh_audio
->wf
->nAvgBytesPerSec
=
354 sh_audio
->wf
->nSamplesPerSec
* sh_audio
->wf
->wBitsPerSample
355 * sh_audio
->wf
->nChannels
/ 8;
357 mp_msg(MSGT_DECVIDEO
, MSGL_V
,
358 " FILM audio: %d channels, %d bits, %d Hz\n",
359 sh_audio
->wf
->nChannels
, sh_audio
->wf
->wBitsPerSample
,
360 sh_audio
->wf
->nSamplesPerSec
);
365 mp_msg(MSGT_DECVIDEO
, MSGL_V
, "parsing STAB chunk\n");
369 sh_video
->fps
= stream_read_dword(demuxer
->stream
);
370 sh_video
->frametime
= 1.0 / sh_video
->fps
;
373 // fetch the number of chunks
374 film_data
->total_chunks
= stream_read_dword(demuxer
->stream
);
375 film_data
->current_chunk
= 0;
376 mp_msg(MSGT_DECVIDEO
, MSGL_V
,
377 " STAB chunk contains %d chunks\n", film_data
->total_chunks
);
379 // allocate enough entries for the chunk
381 calloc(film_data
->total_chunks
, sizeof(film_chunk_t
));
383 // build the chunk index
385 for (i
= 0; i
< film_data
->total_chunks
; i
++)
387 film_chunk
= film_data
->chunks
[i
];
388 film_chunk
.chunk_offset
=
389 demuxer
->movi_start
+ stream_read_dword(demuxer
->stream
);
390 film_chunk
.chunk_size
= stream_read_dword(demuxer
->stream
);
391 film_chunk
.syncinfo1
= stream_read_dword(demuxer
->stream
);
392 film_chunk
.syncinfo2
= stream_read_dword(demuxer
->stream
);
394 // count chunks for the purposes of seeking
397 // if we're counting chunks, always count an audio chunk
398 if (film_chunk
.syncinfo1
== 0xFFFFFFFF)
399 film_data
->chunks_per_second
++;
400 // if it's a video chunk, check if it's time to stop counting
401 else if ((film_chunk
.syncinfo1
& 0x7FFFFFFF) >= sh_video
->fps
)
404 film_data
->chunks_per_second
++;
408 if (film_chunk
.syncinfo1
== 0xFFFFFFFF)
410 if(demuxer
->audio
->id
>=-1)
412 (float)total_audio_bytes
/ (float)sh_audio
->wf
->nAvgBytesPerSec
;
413 total_audio_bytes
+= film_chunk
.chunk_size
;
417 (film_chunk
.syncinfo1
& 0x7FFFFFFF) / sh_video
->fps
;
419 film_data
->chunks
[i
] = film_chunk
;
422 // in some FILM files (notably '1.09'), the length of the FDSC chunk
423 // follows different rules
424 if (chunk_size
== (film_data
->total_chunks
* 16))
429 mp_msg(MSGT_DEMUX
, MSGL_ERR
, "Unrecognized FILM header chunk: %08X\n",
436 demuxer
->priv
= film_data
;
441 static void demux_close_film(demuxer_t
* demuxer
) {
442 film_data_t
*film_data
= demuxer
->priv
;
446 if(film_data
->chunks
)
447 free(film_data
->chunks
);
452 static int film_check_file(demuxer_t
* demuxer
)
454 int signature
=stream_read_fourcc(demuxer
->stream
);
456 // check for the FILM file magic number
457 if(signature
==mmioFOURCC('F', 'I', 'L', 'M'))
458 return DEMUXER_TYPE_FILM
;
464 const demuxer_desc_t demuxer_desc_film
= {
465 "FILM/CPK demuxer for Sega Saturn CD-ROM games",
471 0, // unsafe autodetect (short signature)
473 demux_film_fill_buffer
,