comparison libmpdemux/demux_film.c @ 4564:5e1221d4655e

completely reworked FILM demuxer to support both audio and video...neither of which work yet (CVID video and uncompressed audio)...but the demuxer is working well now
author melanson
date Thu, 07 Feb 2002 05:55:29 +0000
parents 63baf6de03e1
children 1504901deed8
comparison
equal deleted inserted replaced
4563:835d4fce67d5 4564:5e1221d4655e
18 // chunk types found in a FILM file 18 // chunk types found in a FILM file
19 #define CHUNK_FILM mmioFOURCC('F', 'I', 'L', 'M') 19 #define CHUNK_FILM mmioFOURCC('F', 'I', 'L', 'M')
20 #define CHUNK_FDSC mmioFOURCC('F', 'D', 'S', 'C') 20 #define CHUNK_FDSC mmioFOURCC('F', 'D', 'S', 'C')
21 #define CHUNK_STAB mmioFOURCC('S', 'T', 'A', 'B') 21 #define CHUNK_STAB mmioFOURCC('S', 'T', 'A', 'B')
22 22
23 typedef struct _film_frames_t { 23 typedef struct _film_chunk_t
24 int num_frames; 24 {
25 int current_frame; 25 off_t chunk_offset;
26 off_t *filepos; 26 int chunk_size;
27 unsigned int *frame_size; 27
28 unsigned int *flags1; 28 unsigned int flags1;
29 unsigned int *flags2; 29 unsigned int flags2;
30 } film_frames_t; 30
31 31 unsigned int video_chunk_number; // in the case of a video chunk
32 void demux_seek_film(demuxer_t *demuxer,float rel_seek_secs,int flags){ 32 unsigned int running_audio_sample_count; // for an audio chunk
33 } film_chunk_t;
34
35 typedef struct _film_data_t
36 {
37 int total_chunks;
38 int current_chunk;
39 int total_video_chunks;
40 int total_audio_sample_count;
41 film_chunk_t *chunks;
42 } film_data_t;
43
44 #if 0
45 void demux_seek_film(demuxer_t *demuxer,float rel_seek_secs,int flags)
46 {
33 film_frames_t *frames = (film_frames_t *)demuxer->priv; 47 film_frames_t *frames = (film_frames_t *)demuxer->priv;
34 sh_video_t *sh_video = demuxer->video->sh; 48 sh_video_t *sh_video = demuxer->video->sh;
35 int newpos=(flags&1)?0:frames->current_frame; 49 int newpos=(flags&1)?0:frames->current_frame;
36 if(flags&2){ 50 if(flags&2){
37 // float 0..1 51 // float 0..1
42 } 56 }
43 if(newpos<0) newpos=0; else 57 if(newpos<0) newpos=0; else
44 if(newpos>frames->num_frames) newpos=frames->num_frames; 58 if(newpos>frames->num_frames) newpos=frames->num_frames;
45 frames->current_frame=newpos; 59 frames->current_frame=newpos;
46 } 60 }
61 #endif
47 62
48 // return value: 63 // return value:
49 // 0 = EOF or no stream found 64 // 0 = EOF or no stream found
50 // 1 = successfully read a packet 65 // 1 = successfully read a packet
51 int demux_film_fill_buffer(demuxer_t *demuxer){ 66 int demux_film_fill_buffer(demuxer_t *demuxer)
52 film_frames_t *frames = (film_frames_t *)demuxer->priv; 67 {
53 sh_video_t *sh_video = demuxer->video->sh; 68 sh_video_t *sh_video = demuxer->video->sh;
69 film_data_t *film_data = (film_data_t *)demuxer->priv;
70 film_chunk_t film_chunk;
54 71
55 // see if the end has been reached 72 // see if the end has been reached
56 if (frames->current_frame >= frames->num_frames) 73 if (film_data->current_chunk >= film_data->total_chunks)
57 return 0; 74 return 0;
58 75
59 // fetch the frame from the file 76 film_chunk = film_data->chunks[film_data->current_chunk];
60 // first, position the file properly since ds_read_packet() doesn't 77
61 // seem to do it, even though it takes a file offset as a parameter 78 // position stream and fetch chunk
62 stream_seek(demuxer->stream, frames->filepos[frames->current_frame]); 79 stream_seek(demuxer->stream, film_chunk.chunk_offset);
63 ds_read_packet(demuxer->video, 80 if (film_chunk.flags1 == 0xFFFFFFFF)
64 demuxer->stream, 81 ds_read_packet(demuxer->audio, demuxer->stream, film_chunk.chunk_size,
65 frames->frame_size[frames->current_frame], 82 0, /* pts */
66 frames->current_frame/sh_video->fps, 83 film_chunk.chunk_offset, 0);
67 frames->filepos[frames->current_frame], 84 else
68 0 /* what flags? -> demuxer.h (alex) */ 85 ds_read_packet(demuxer->video, demuxer->stream, film_chunk.chunk_size,
69 ); 86 film_chunk.video_chunk_number / sh_video->fps,
70 87 film_chunk.chunk_offset, 0);
71 // get the next frame ready 88
72 frames->current_frame++; 89 film_data->current_chunk++;
73
74 return 1; 90 return 1;
75 } 91 }
76 92
77 demuxer_t* demux_open_film(demuxer_t* demuxer){ 93 demuxer_t* demux_open_film(demuxer_t* demuxer)
94 {
78 sh_video_t *sh_video = NULL; 95 sh_video_t *sh_video = NULL;
79 film_frames_t *frames = (film_frames_t *)malloc(sizeof(film_frames_t)); 96 sh_audio_t *sh_audio = NULL;
97 film_data_t *film_data;
98 film_chunk_t film_chunk;
80 int header_size; 99 int header_size;
81 unsigned int chunk_type; 100 unsigned int chunk_type;
82 unsigned int chunk_size; 101 unsigned int chunk_size;
83 int i; 102 int i;
84 int frame_number; 103 unsigned int video_format;
85 104
105 int largest_audio_chunk = 0;
86 int audio_channels; 106 int audio_channels;
87 int audio_bits; 107
88 int audio_frequency; 108 film_data = (film_data_t *)malloc(sizeof(film_data_t));
109 film_data->total_chunks = 0;
110 film_data->current_chunk = 0;
111 film_data->total_video_chunks = 0;
112 film_data->chunks = NULL;
89 113
90 // go back to the beginning 114 // go back to the beginning
91 stream_reset(demuxer->stream); 115 stream_reset(demuxer->stream);
92 stream_seek(demuxer->stream, 0); 116 stream_seek(demuxer->stream, 0);
93 117
108 header_size -= 16; 132 header_size -= 16;
109 133
110 // skip to where the next chunk should be 134 // skip to where the next chunk should be
111 stream_skip(demuxer->stream, 8); 135 stream_skip(demuxer->stream, 8);
112 136
113 // create a new video stream header
114 sh_video = new_sh_video(demuxer, 0);
115
116 // make sure the demuxer knows about the new video stream header
117 demuxer->video->sh = sh_video;
118
119 // make sure that the video demuxer stream header knows about its
120 // parent video demuxer stream, or else
121 // video_read_properties() will choke
122 sh_video->ds = demuxer->video;
123
124 // traverse through the header 137 // traverse through the header
125 while (header_size > 0) 138 while (header_size > 0)
126 { 139 {
127 // fetch the chunk type and size 140 // fetch the chunk type and size
128 chunk_type = stream_read_fourcc(demuxer->stream); 141 chunk_type = stream_read_fourcc(demuxer->stream);
130 header_size -= chunk_size; 143 header_size -= chunk_size;
131 144
132 switch (chunk_type) 145 switch (chunk_type)
133 { 146 {
134 case CHUNK_FDSC: 147 case CHUNK_FDSC:
135 printf ("parsing FDSC chunk\n"); 148 mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing FDSC chunk\n");
136 // fetch the video codec fourcc, height, then width 149 // fetch the video codec fourcc to see if there's any video
137 sh_video->format = stream_read_fourcc(demuxer->stream); 150 video_format = stream_read_fourcc(demuxer->stream);
138 sh_video->disp_h = stream_read_dword(demuxer->stream); 151 if (video_format)
139 sh_video->disp_w = stream_read_dword(demuxer->stream); 152 {
140 sh_video->fps = stream_read_char(demuxer->stream); 153 // create and initialize the video stream header
141 sh_video->frametime = 1/sh_video->fps; 154 sh_video = new_sh_video(demuxer, 0);
142 printf (" FILM video: %d x %d, %f fps\n", sh_video->disp_w, 155 demuxer->video->sh = sh_video;
143 sh_video->disp_h, sh_video->fps); 156 sh_video->ds = demuxer->video;
144 157
145 // temporary: These will eventually go directly into an audio structure 158 sh_video->format = video_format;
146 // of some sort 159 sh_video->disp_h = stream_read_dword(demuxer->stream);
160 sh_video->disp_w = stream_read_dword(demuxer->stream);
161 sh_video->fps = stream_read_char(demuxer->stream);
162 sh_video->frametime = 1/sh_video->fps;
163 mp_msg(MSGT_DECVIDEO, MSGL_V,
164 " FILM video: %d x %d, %f fps\n", sh_video->disp_w,
165 sh_video->disp_h, sh_video->fps);
166 }
167 else
168 stream_skip(demuxer->stream, 9);
169
170 // fetch the audio channels to see if there's any audio
147 audio_channels = stream_read_char(demuxer->stream); 171 audio_channels = stream_read_char(demuxer->stream);
148 audio_bits = stream_read_char(demuxer->stream); 172 if (audio_channels > 0)
149 stream_skip(demuxer->stream, 1); // skip unknown byte 173 {
150 audio_frequency = stream_read_word(demuxer->stream); 174 // create and initialize the audio stream header
151 printf (" FILM audio: %d channels, %d bits, %d Hz\n", 175 sh_audio = new_sh_audio(demuxer, 0);
152 audio_channels, audio_bits, audio_frequency); 176 demuxer->audio->sh = sh_audio;
153 177 sh_audio->ds = demuxer->audio;
154 stream_skip(demuxer->stream, 6); 178
179 // go through the bother of making a WAVEFORMATEX structure
180 sh_audio->wf = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX));
181
182 // uncompressed PCM format
183 sh_audio->wf->wFormatTag = 1;
184 sh_audio->format = 1;
185 sh_audio->wf->nChannels = audio_channels;
186 sh_audio->wf->wBitsPerSample = stream_read_char(demuxer->stream);
187 stream_skip(demuxer->stream, 1); // skip unknown byte
188 sh_audio->wf->nSamplesPerSec = stream_read_word(demuxer->stream);
189 sh_audio->wf->nAvgBytesPerSec =
190 sh_audio->wf->nSamplesPerSec * sh_audio->wf->wBitsPerSample / 8;
191 stream_skip(demuxer->stream, 6); // skip the rest of the unknown
192
193 mp_msg(MSGT_DECVIDEO, MSGL_V,
194 " FILM audio: %d channels, %d bits, %d Hz\n",
195 sh_audio->wf->nChannels, 8 * sh_audio->wf->wBitsPerSample,
196 sh_audio->wf->nSamplesPerSec);
197 }
198 else
199 stream_skip(demuxer->stream, 10);
155 break; 200 break;
156 201
157 case CHUNK_STAB: 202 case CHUNK_STAB:
158 printf ("parsing STAB chunk\n"); 203 mp_msg(MSGT_DECVIDEO, MSGL_V, "parsing STAB chunk\n");
159 // skip unknown dword 204 // skip unknown dword
160 stream_skip(demuxer->stream, 4); 205 stream_skip(demuxer->stream, 4);
161 206
162 // fetch the number of frames 207 // fetch the number of chunks
163 frames->num_frames = stream_read_dword(demuxer->stream); 208 film_data->total_chunks = stream_read_dword(demuxer->stream);
164 frames->current_frame = 0; 209 film_data->current_chunk = 0;
165 210 mp_msg(MSGT_DECVIDEO, MSGL_V,
166 // allocate enough entries for the indices 211 " STAB chunk contains %d chunks\n", film_data->total_chunks);
167 frames->filepos = (off_t *)malloc(frames->num_frames * sizeof(off_t)); 212
168 frames->frame_size = (int *)malloc(frames->num_frames * sizeof(int)); 213 // allocate enough entries for the chunk
169 frames->flags1 = (int *)malloc(frames->num_frames * sizeof(int)); 214 film_data->chunks =
170 frames->flags2 = (int *)malloc(frames->num_frames * sizeof(int)); 215 (film_chunk_t *)malloc(film_data->total_chunks * sizeof(film_chunk_t));
171 216
172 // build the frame index 217 // build the chunk index
173 frame_number = 0; 218 for (i = 0; i < film_data->total_chunks; i++)
174 for (i = 0; i < frames->num_frames; i++)
175 { 219 {
176 if (frames->flags1[i] == 0) 220 film_chunk = film_data->chunks[i];
177 { 221 film_chunk.chunk_offset =
178 frames->filepos[frame_number] = demuxer->movi_start + stream_read_dword(demuxer->stream); 222 demuxer->movi_start + stream_read_dword(demuxer->stream);
179 frames->frame_size[frame_number] = stream_read_dword(demuxer->stream) - 8; 223 film_chunk.chunk_size = stream_read_dword(demuxer->stream) - 8;
180 frames->flags1[frame_number] = stream_read_dword(demuxer->stream); 224 film_chunk.flags1 = stream_read_dword(demuxer->stream);
181 frames->flags2[frame_number] = stream_read_dword(demuxer->stream); 225 film_chunk.flags2 = stream_read_dword(demuxer->stream);
182 frame_number++; 226 film_data->chunks[i] = film_chunk;
183 } 227
228 // audio housekeeping
229 if ((film_chunk.flags1 == 0xFFFFFFFF) &&
230 (film_chunk.chunk_size > largest_audio_chunk))
231 largest_audio_chunk = film_chunk.chunk_size;
232 film_data->total_audio_sample_count +=
233 (chunk_size / sh_audio->wf->nChannels);
234
235 // video housekeeping
236 if (film_chunk.flags1 != 0xFFFFFFFF)
237 film_chunk.video_chunk_number =
238 film_data->total_video_chunks++;
184 } 239 }
185 frames->num_frames = frame_number;
186 break; 240 break;
187 241
188 default: 242 default:
189 mp_msg(MSGT_DEMUX, MSGL_ERR, "Unrecognized FILM header chunk: %08X\n", 243 mp_msg(MSGT_DEMUX, MSGL_ERR, "Unrecognized FILM header chunk: %08X\n",
190 chunk_type); 244 chunk_type);
191 return(NULL); 245 return(NULL);
192 break; 246 break;
193 } 247 }
194 } 248 }
195 249
196 // hard code the speed for now 250 demuxer->priv = film_data;
197 sh_video->fps = 1;
198 sh_video->frametime = 1;
199
200 demuxer->priv = frames;
201 251
202 return demuxer; 252 return demuxer;
203 } 253 }