Mercurial > mplayer.hg
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 } |