aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar melanson <melanson@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-02-10 01:23:36 +0000
committerGravatar melanson <melanson@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-02-10 01:23:36 +0000
commitb3cf29263b9fa75643621490d581d2db02860813 (patch)
treec8dfbbaf1a36942515622b8338d22d73786b940f
parent00d399805667f38c9508b63345fed34b7f8c2131 (diff)
Fixed FILM demuxer so that it now plays (my) FILM files
correctly; modified Cinepak decoder in order to deal with the deviant CVID data from FILM files git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@4629 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r--cinepak.c12
-rw-r--r--dec_video.c11
-rw-r--r--libmpdemux/demux_film.c143
3 files changed, 134 insertions, 32 deletions
diff --git a/cinepak.c b/cinepak.c
index b66b30b630..09af55b8fa 100644
--- a/cinepak.c
+++ b/cinepak.c
@@ -36,7 +36,7 @@ typedef struct
typedef struct {
cvid_codebook *v4_codebook[MAX_STRIPS];
cvid_codebook *v1_codebook[MAX_STRIPS];
- int strip_num;
+ unsigned long strip_num;
} cinepak_info;
@@ -392,6 +392,7 @@ unsigned long x, y, y_bottom, frame_flags, strips, cv_width, cv_height, cnum,
long len, top_size, chunk_size;
unsigned char *frm_ptr, *frm_end;
int i, cur_strip, d0, d1, d2, d3, frm_stride, bpp = 3;
+int modulo;
void (*read_codebook)(cvid_codebook *c, int mode) = read_codebook_24;
void (*cvid_v1)(unsigned char *frm, unsigned char *end, int stride, cvid_codebook *cb) = cvid_v1_24;
void (*cvid_v4)(unsigned char *frm, unsigned char *end, int stride, cvid_codebook *cb0,
@@ -498,7 +499,7 @@ void (*cvid_v4)(unsigned char *frm, unsigned char *end, int stride, cvid_codeboo
x = 0;
if(x1 != width)
printf("CVID: Warning x1 (%ld) != width (%d)\n", x1, width);
-
+x1 = width;
#if DBUG
printf(" %d) %04lx %04ld <%ld,%ld> <%ld,%ld> yt %ld %d\n",
cur_strip, strip_id, top_size, x0, y0, x1, y1, y_bottom);
@@ -520,9 +521,12 @@ void (*cvid_v4)(unsigned char *frm, unsigned char *end, int stride, cvid_codeboo
/* -------------------- Codebook Entries -------------------- */
case 0x2000:
case 0x2200:
+ modulo = chunk_size % 6;
codebook = (chunk_id == 0x2200 ? v1_codebook : v4_codebook);
- cnum = chunk_size/6;
+ cnum = (chunk_size - modulo) / 6;
for(i = 0; i < cnum; i++) read_codebook(codebook+i, 0);
+ while (modulo--)
+ get_byte();
break;
case 0x2400:
@@ -537,7 +541,7 @@ void (*cvid_v4)(unsigned char *frm, unsigned char *end, int stride, cvid_codeboo
codebook = (chunk_id == 0x2300 ? v1_codebook : v4_codebook);
ci = 0;
- while(chunk_size > 0)
+ while(chunk_size > 3)
{
flag = get_long();
chunk_size -= 4;
diff --git a/dec_video.c b/dec_video.c
index f0468cd8ff..c96674ffdc 100644
--- a/dec_video.c
+++ b/dec_video.c
@@ -824,9 +824,14 @@ if( !(mpi->flags&MP_IMGFLAG_ALLOCATED) && !(mpi->flags&MP_IMGFLAG_DIRECT) ){
//-------------------- Decode a frame: -----------------------
switch(sh_video->codec->driver){
case VFM_CINEPAK:
- decode_cinepak(sh_video->context, start, in_size, sh_video->our_out_buffer,
- sh_video->disp_w, sh_video->disp_h, (out_fmt==IMGFMT_YUY2)?16:(out_fmt&255));
- blit_frame = 3;
+ if (in_size == 0)
+ blit_frame = 0;
+ else
+ {
+ decode_cinepak(sh_video->context, start, in_size, sh_video->our_out_buffer,
+ sh_video->disp_w, sh_video->disp_h, (out_fmt==IMGFMT_YUY2)?16:(out_fmt&255));
+ blit_frame = 3;
+ }
break;
#ifdef USE_XANIM
case VFM_XANIM: {
diff --git a/libmpdemux/demux_film.c b/libmpdemux/demux_film.c
index 0c8650ca79..86992bad28 100644
--- a/libmpdemux/demux_film.c
+++ b/libmpdemux/demux_film.c
@@ -1,6 +1,9 @@
/*
FILM file parser for the MPlayer program
by Mike Melanson
+
+ Details of the FILM file format can be found at:
+ http://www.pcisys.net/~melanson/codecs/
*/
#include <stdio.h>
@@ -20,6 +23,10 @@
#define CHUNK_FDSC mmioFOURCC('F', 'D', 'S', 'C')
#define CHUNK_STAB mmioFOURCC('S', 'T', 'A', 'B')
+#define VERSION_1_01 mmioFOURCC('1', '.', '0', '1')
+
+#define MAGIC_FPS_CONSTANT 27
+
typedef struct _film_chunk_t
{
off_t chunk_offset;
@@ -39,6 +46,8 @@ typedef struct _film_data_t
int total_video_chunks;
int total_audio_sample_count;
film_chunk_t *chunks;
+ unsigned int ticks;
+ unsigned int film_version;
} film_data_t;
#if 0
@@ -65,7 +74,11 @@ void demux_seek_film(demuxer_t *demuxer,float rel_seek_secs,int flags)
// 1 = successfully read a packet
int demux_film_fill_buffer(demuxer_t *demuxer)
{
+ int i;
+ unsigned char byte_swap;
+ int cvid_size;
sh_video_t *sh_video = demuxer->video->sh;
+ sh_audio_t *sh_audio = demuxer->audio->sh;
film_data_t *film_data = (film_data_t *)demuxer->priv;
film_chunk_t film_chunk;
@@ -77,16 +90,82 @@ int demux_film_fill_buffer(demuxer_t *demuxer)
// position stream and fetch chunk
stream_seek(demuxer->stream, film_chunk.chunk_offset);
+
+ // load the chunks manually (instead of using ds_read_packet()), since
+ // they require some adjustment
+ // (all ones in flags1 indicates an audio chunk)
if (film_chunk.flags1 == 0xFFFFFFFF)
- ds_read_packet(demuxer->audio, demuxer->stream, film_chunk.chunk_size,
- 0, /* pts */
- film_chunk.chunk_offset, 0);
+ {
+ demux_packet_t* dp=new_demux_packet(film_chunk.chunk_size);
+ stream_read(demuxer->stream, dp->buffer, film_chunk.chunk_size);
+ dp->pts = 0;
+ dp->pos = film_chunk.chunk_offset;
+ dp->flags = 0;
+
+ // adjust the data before queuing it:
+ // 8-bit: signed -> unsigned
+ // 16-bit: big-endian -> little-endian
+ if (sh_audio->wf->wBitsPerSample == 8)
+ for (i = 0; i < film_chunk.chunk_size; i++)
+ dp->buffer[i] += 128;
+ else
+ for (i = 0; i < film_chunk.chunk_size; i += 2)
+ {
+ byte_swap = dp->buffer[i];
+ dp->buffer[i] = dp->buffer[i + 1];
+ dp->buffer[i + 1] = byte_swap;
+ }
+
+ // append packet to DS stream
+ ds_add_packet(demuxer->audio, dp);
+ film_data->current_chunk++;
+ }
else
- ds_read_packet(demuxer->video, demuxer->stream, film_chunk.chunk_size,
- film_chunk.video_chunk_number / sh_video->fps,
- film_chunk.chunk_offset, 0);
+ {
+ // check the tick to see if it's time to dispatch a new frame
+ if ((film_data->film_version == VERSION_1_01) &&
+ ((film_chunk.flags1 & 0x7FFFFFFF) != film_data->ticks++))
+ {
+ demux_packet_t* dp=new_demux_packet(0);
+ dp->pts = 0;
+ dp->pos = 0;
+ dp->flags = 0;
+ ds_add_packet(demuxer->video, dp);
+ }
+ // if the demuxer is dealing with CVID data, deal with it a special way
+ else if (sh_video->format == mmioFOURCC('c', 'v', 'i', 'd'))
+ {
+ // account for 2 extra bytes
+ demux_packet_t* dp=new_demux_packet(film_chunk.chunk_size - 2);
+
+ // these CVID data chunks appear to have 2 extra bytes; skip them
+ stream_read(demuxer->stream, dp->buffer, 10);
+ stream_skip(demuxer->stream, 2);
+ stream_read(demuxer->stream, dp->buffer + 10, film_chunk.chunk_size - 12);
+ dp->pts = film_chunk.video_chunk_number / sh_video->fps;
+ dp->pos = film_chunk.chunk_offset;
+ dp->flags = (film_chunk.flags1 & 0x80000000) ? 1 : 0;
+
+ // fix the CVID chunk size by adding 6
+ cvid_size = (dp->buffer[1] << 16) | (dp->buffer[2] << 8) | dp->buffer[3];
+ cvid_size += 6;
+ dp->buffer[1] = (cvid_size >> 16) & 0xFF;
+ dp->buffer[2] = (cvid_size >> 8) & 0xFF;
+ dp->buffer[3] = (cvid_size >> 0) & 0xFF;
+
+ // append packet to DS stream
+ ds_add_packet(demuxer->video, dp);
+ film_data->current_chunk++;
+ }
+ else
+ {
+ ds_read_packet(demuxer->video, demuxer->stream, film_chunk.chunk_size,
+ film_chunk.video_chunk_number / sh_video->fps, /* pts */
+ film_chunk.chunk_offset, (film_chunk.flags1 & 0x80000000) ? 1 : 0);
+ film_data->current_chunk++;
+ }
+ }
- film_data->current_chunk++;
return 1;
}
@@ -110,6 +189,7 @@ demuxer_t* demux_open_film(demuxer_t* demuxer)
film_data->current_chunk = 0;
film_data->total_video_chunks = 0;
film_data->chunks = NULL;
+ film_data->ticks = 0;
// go back to the beginning
stream_reset(demuxer->stream);
@@ -127,12 +207,13 @@ demuxer_t* demux_open_film(demuxer_t* demuxer)
// get the header size, which implicitly points past the header and
// to the start of the data
header_size = stream_read_dword(demuxer->stream);
+ film_data->film_version = stream_read_fourcc(demuxer->stream);
demuxer->movi_start = header_size;
demuxer->movi_end = demuxer->stream->end_pos;
header_size -= 16;
// skip to where the next chunk should be
- stream_skip(demuxer->stream, 8);
+ stream_skip(demuxer->stream, 4);
// traverse through the header
while (header_size > 0)
@@ -158,11 +239,10 @@ demuxer_t* demux_open_film(demuxer_t* demuxer)
sh_video->format = video_format;
sh_video->disp_h = stream_read_dword(demuxer->stream);
sh_video->disp_w = stream_read_dword(demuxer->stream);
- sh_video->fps = stream_read_char(demuxer->stream);
- sh_video->frametime = 1/sh_video->fps;
+ stream_skip(demuxer->stream, 1); // unknown byte
mp_msg(MSGT_DECVIDEO, MSGL_V,
- " FILM video: %d x %d, %f fps\n", sh_video->disp_w,
- sh_video->disp_h, sh_video->fps);
+ " FILM video: %d x %d\n", sh_video->disp_w,
+ sh_video->disp_h);
}
else
stream_skip(demuxer->stream, 9);
@@ -176,7 +256,6 @@ demuxer_t* demux_open_film(demuxer_t* demuxer)
demuxer->audio->sh = sh_audio;
sh_audio->ds = demuxer->audio;
- // go through the bother of making a WAVEFORMATEX structure
sh_audio->wf = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX));
// uncompressed PCM format
@@ -187,7 +266,8 @@ demuxer_t* demux_open_film(demuxer_t* demuxer)
stream_skip(demuxer->stream, 1); // skip unknown byte
sh_audio->wf->nSamplesPerSec = stream_read_word(demuxer->stream);
sh_audio->wf->nAvgBytesPerSec =
- sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample / 8;
+ sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample
+ * sh_audio->wf->nChannels / 8;
stream_skip(demuxer->stream, 6); // skip the rest of the unknown
mp_msg(MSGT_DECVIDEO, MSGL_V,
@@ -201,8 +281,15 @@ demuxer_t* demux_open_film(demuxer_t* demuxer)
case CHUNK_STAB:
mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing STAB chunk\n");
- // skip unknown dword
- stream_skip(demuxer->stream, 4);
+
+ // FPS hack based on empirical observation
+ if (sh_video)
+ {
+ sh_video->fps = stream_read_dword(demuxer->stream);
+ if (film_data->film_version != VERSION_1_01)
+ sh_video->fps = MAGIC_FPS_CONSTANT;
+ sh_video->frametime = 1 / sh_video->fps;
+ }
// fetch the number of chunks
film_data->total_chunks = stream_read_dword(demuxer->stream);
@@ -220,22 +307,28 @@ demuxer_t* demux_open_film(demuxer_t* demuxer)
film_chunk = film_data->chunks[i];
film_chunk.chunk_offset =
demuxer->movi_start + stream_read_dword(demuxer->stream);
- film_chunk.chunk_size = stream_read_dword(demuxer->stream) - 8;
+ film_chunk.chunk_size = stream_read_dword(demuxer->stream);
film_chunk.flags1 = stream_read_dword(demuxer->stream);
film_chunk.flags2 = stream_read_dword(demuxer->stream);
film_data->chunks[i] = film_chunk;
// audio housekeeping
- if ((film_chunk.flags1 == 0xFFFFFFFF) &&
- (film_chunk.chunk_size > largest_audio_chunk))
- largest_audio_chunk = film_chunk.chunk_size;
- film_data->total_audio_sample_count +=
- (chunk_size / sh_audio->wf->nChannels);
+ if (sh_audio)
+ {
+ if ((film_chunk.flags1 == 0xFFFFFFFF) &&
+ (film_chunk.chunk_size > largest_audio_chunk))
+ largest_audio_chunk = film_chunk.chunk_size;
+ film_data->total_audio_sample_count +=
+ (chunk_size / sh_audio->wf->nChannels);
+ }
// video housekeeping
- if (film_chunk.flags1 != 0xFFFFFFFF)
- film_chunk.video_chunk_number =
- film_data->total_video_chunks++;
+ if (sh_video)
+ {
+ if (film_chunk.flags1 != 0xFFFFFFFF)
+ film_chunk.video_chunk_number =
+ film_data->total_video_chunks++;
+ }
}
break;