Mercurial > mplayer.hg
annotate libmpdemux/demux_roq.c @ 15205:19243f85e164
nico partially fixed the bug i reported; here's the rest of the fix.
basically demux_audio was mixing data in its header buffer in a bogus
manner, whereby it could sometimes "make up" valid mpeg headers where
no such header actually occurred in the file. it should be correct now.
btw these changes also fix the bug where mplayer reports huge initial
cpu usage for sound when playing mp3 files.
author | rfelker |
---|---|
date | Sun, 17 Apr 2005 17:17:52 +0000 |
parents | 1a26db279e50 |
children | 6b86089c2edd |
rev | line source |
---|---|
4451 | 1 /* |
2 RoQ file demuxer for the MPlayer program | |
3 by Mike Melanson | |
4 based on Dr. Tim Ferguson's RoQ document found at: | |
5 http://www.csse.monash.edu.au/~timf/videocodec.html | |
6 */ | |
7 | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 #include <unistd.h> | |
11 | |
12 #include "config.h" | |
13 #include "mp_msg.h" | |
14 #include "help_mp.h" | |
15 | |
16 #include "stream.h" | |
17 #include "demuxer.h" | |
18 #include "stheader.h" | |
19 | |
20 #define RoQ_INFO 0x1001 | |
21 #define RoQ_QUAD_CODEBOOK 0x1002 | |
22 #define RoQ_QUAD_VQ 0x1011 | |
23 #define RoQ_SOUND_MONO 0x1020 | |
24 #define RoQ_SOUND_STEREO 0x1021 | |
25 | |
26 #define CHUNK_TYPE_AUDIO 0 | |
27 #define CHUNK_TYPE_VIDEO 1 | |
28 | |
29 typedef struct roq_chunk_t | |
30 { | |
31 int chunk_type; | |
32 off_t chunk_offset; | |
33 int chunk_size; | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
34 |
5424
e6d180ceb1ef
changed int -> float for proper PTS calculation (works just as well as the
melanson
parents:
5421
diff
changeset
|
35 float video_chunk_number; // in the case of a video chunk |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
36 int running_audio_sample_count; // for an audio chunk |
4451 | 37 } roq_chunk_t; |
38 | |
39 typedef struct roq_data_t | |
40 { | |
41 int total_chunks; | |
42 int current_chunk; | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
43 int total_video_chunks; |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
44 int total_audio_sample_count; |
4451 | 45 roq_chunk_t *chunks; |
46 } roq_data_t; | |
47 | |
48 // Check if a stream qualifies as a RoQ file based on the magic numbers | |
49 // at the start of the file: | |
4753
f3562b5411f9
fixed RoQ file detection and FPS determination (maybe)
melanson
parents:
4532
diff
changeset
|
50 // 84 10 FF FF FF FF xx xx |
4451 | 51 int roq_check_file(demuxer_t *demuxer) |
52 { | |
53 if ((stream_read_dword(demuxer->stream) == 0x8410FFFF) && | |
4753
f3562b5411f9
fixed RoQ file detection and FPS determination (maybe)
melanson
parents:
4532
diff
changeset
|
54 ((stream_read_dword(demuxer->stream) & 0xFFFF0000) == 0xFFFF0000)) |
4451 | 55 return 1; |
56 else | |
57 return 0; | |
58 } | |
59 | |
60 // return value: | |
61 // 0 = EOF or no stream found | |
62 // 1 = successfully read a packet | |
63 int demux_roq_fill_buffer(demuxer_t *demuxer) | |
64 { | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
65 sh_video_t *sh_video = demuxer->video->sh; |
4451 | 66 roq_data_t *roq_data = (roq_data_t *)demuxer->priv; |
67 roq_chunk_t roq_chunk; | |
68 | |
69 if (roq_data->current_chunk >= roq_data->total_chunks) | |
70 return 0; | |
71 | |
72 roq_chunk = roq_data->chunks[roq_data->current_chunk]; | |
73 | |
74 // make sure we're at the right place in the stream and fetch the chunk | |
75 stream_seek(demuxer->stream, roq_chunk.chunk_offset); | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
76 |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
77 if (roq_chunk.chunk_type == CHUNK_TYPE_AUDIO) |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
78 ds_read_packet(demuxer->audio, demuxer->stream, roq_chunk.chunk_size, |
5421
d1ff2c2f74f0
fixed RoQ framerate by multiplying PTS calculation by some absurd constant
melanson
parents:
4753
diff
changeset
|
79 0, |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
80 roq_chunk.chunk_offset, 0); |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
81 else |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
82 ds_read_packet(demuxer->video, demuxer->stream, roq_chunk.chunk_size, |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
83 roq_chunk.video_chunk_number / sh_video->fps, |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
84 roq_chunk.chunk_offset, 0); |
4451 | 85 |
86 roq_data->current_chunk++; | |
87 return 1; | |
88 } | |
89 | |
90 demuxer_t* demux_open_roq(demuxer_t* demuxer) | |
91 { | |
92 sh_video_t *sh_video = NULL; | |
93 sh_audio_t *sh_audio = NULL; | |
94 | |
95 roq_data_t *roq_data = (roq_data_t *)malloc(sizeof(roq_data_t)); | |
96 int chunk_id; | |
97 int chunk_size; | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
98 int chunk_arg; |
4451 | 99 int last_chunk_id = 0; |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
100 int largest_audio_chunk = 0; |
4753
f3562b5411f9
fixed RoQ file detection and FPS determination (maybe)
melanson
parents:
4532
diff
changeset
|
101 int fps; |
4451 | 102 |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
103 roq_data->total_chunks = 0; |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
104 roq_data->current_chunk = 0; |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
105 roq_data->total_video_chunks = 0; |
4451 | 106 roq_data->chunks = NULL; |
107 | |
108 // position the stream and start traversing | |
4753
f3562b5411f9
fixed RoQ file detection and FPS determination (maybe)
melanson
parents:
4532
diff
changeset
|
109 stream_seek(demuxer->stream, 6); |
f3562b5411f9
fixed RoQ file detection and FPS determination (maybe)
melanson
parents:
4532
diff
changeset
|
110 fps = stream_read_word_le(demuxer->stream); |
4451 | 111 while (!stream_eof(demuxer->stream)) |
112 { | |
113 chunk_id = stream_read_word_le(demuxer->stream); | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
114 chunk_size = stream_read_dword_le(demuxer->stream); |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
115 chunk_arg = stream_read_word_le(demuxer->stream); |
4451 | 116 |
117 // this is the only useful header info in the file | |
118 if (chunk_id == RoQ_INFO) | |
119 { | |
120 // there should only be one RoQ_INFO chunk per file | |
121 if (sh_video) | |
122 { | |
123 mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Found more than one RoQ_INFO chunk\n"); | |
124 stream_skip(demuxer->stream, 8); | |
125 } | |
126 else | |
127 { | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
128 // this is a good opportunity to create a video stream header |
4451 | 129 sh_video = new_sh_video(demuxer, 0); |
130 // make sure the demuxer knows about the new stream header | |
131 demuxer->video->sh = sh_video; | |
132 // make sure that the video demuxer stream header knows about its | |
133 // parent video demuxer stream | |
134 sh_video->ds = demuxer->video; | |
135 | |
136 sh_video->disp_w = stream_read_word_le(demuxer->stream); | |
137 sh_video->disp_h = stream_read_word_le(demuxer->stream); | |
138 stream_skip(demuxer->stream, 4); | |
139 | |
140 // custom fourcc for internal MPlayer use | |
141 sh_video->format = mmioFOURCC('R', 'o', 'Q', 'V'); | |
142 | |
143 // constant frame rate | |
5424
e6d180ceb1ef
changed int -> float for proper PTS calculation (works just as well as the
melanson
parents:
5421
diff
changeset
|
144 sh_video->fps = fps; |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
145 sh_video->frametime = 1 / sh_video->fps; |
4451 | 146 } |
147 } | |
148 else if ((chunk_id == RoQ_SOUND_MONO) || | |
149 (chunk_id == RoQ_SOUND_STEREO)) | |
150 { | |
151 // create the audio stream header if it hasn't been created it | |
152 if (sh_audio == NULL) | |
153 { | |
154 // make the header first | |
155 sh_audio = new_sh_audio(demuxer, 0); | |
156 // make sure the demuxer knows about the new stream header | |
157 demuxer->audio->sh = sh_audio; | |
158 // make sure that the audio demuxer stream header knows about its | |
159 // parent audio demuxer stream | |
160 sh_audio->ds = demuxer->audio; | |
161 | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
162 // go through the bother of making a WAVEFORMATEX structure |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
163 sh_audio->wf = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX)); |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
164 |
4451 | 165 // custom fourcc for internal MPlayer use |
166 sh_audio->format = mmioFOURCC('R', 'o', 'Q', 'A'); | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
167 if (chunk_id == RoQ_SOUND_STEREO) |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
168 sh_audio->wf->nChannels = 2; |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
169 else |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
170 sh_audio->wf->nChannels = 1; |
4451 | 171 // always 22KHz, 16-bit |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
172 sh_audio->wf->nSamplesPerSec = 22050; |
5421
d1ff2c2f74f0
fixed RoQ framerate by multiplying PTS calculation by some absurd constant
melanson
parents:
4753
diff
changeset
|
173 sh_audio->wf->wBitsPerSample = 16; |
4451 | 174 } |
175 | |
176 // index the chunk | |
177 roq_data->chunks = (roq_chunk_t *)realloc(roq_data->chunks, | |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
178 (roq_data->total_chunks + 1) * sizeof (roq_chunk_t)); |
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
179 roq_data->chunks[roq_data->total_chunks].chunk_type = CHUNK_TYPE_AUDIO; |
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
180 roq_data->chunks[roq_data->total_chunks].chunk_offset = |
4451 | 181 stream_tell(demuxer->stream) - 8; |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
182 roq_data->chunks[roq_data->total_chunks].chunk_size = chunk_size + 8; |
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
183 roq_data->chunks[roq_data->total_chunks].running_audio_sample_count = |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
184 roq_data->total_audio_sample_count; |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
185 |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
186 // audio housekeeping |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
187 if (chunk_size > largest_audio_chunk) |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
188 largest_audio_chunk = chunk_size; |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
189 roq_data->total_audio_sample_count += |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
190 (chunk_size / sh_audio->wf->nChannels); |
4451 | 191 |
192 stream_skip(demuxer->stream, chunk_size); | |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
193 roq_data->total_chunks++; |
4451 | 194 } |
195 else if ((chunk_id == RoQ_QUAD_CODEBOOK) || | |
196 ((chunk_id == RoQ_QUAD_VQ) && (last_chunk_id != RoQ_QUAD_CODEBOOK))) | |
197 { | |
198 // index a new chunk if it's a codebook or quad VQ not following a | |
199 // codebook | |
200 roq_data->chunks = (roq_chunk_t *)realloc(roq_data->chunks, | |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
201 (roq_data->total_chunks + 1) * sizeof (roq_chunk_t)); |
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
202 roq_data->chunks[roq_data->total_chunks].chunk_type = CHUNK_TYPE_VIDEO; |
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
203 roq_data->chunks[roq_data->total_chunks].chunk_offset = |
4451 | 204 stream_tell(demuxer->stream) - 8; |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
205 roq_data->chunks[roq_data->total_chunks].chunk_size = chunk_size + 8; |
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
206 roq_data->chunks[roq_data->total_chunks].video_chunk_number = |
5424
e6d180ceb1ef
changed int -> float for proper PTS calculation (works just as well as the
melanson
parents:
5421
diff
changeset
|
207 roq_data->total_video_chunks++; |
4451 | 208 |
209 stream_skip(demuxer->stream, chunk_size); | |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
210 roq_data->total_chunks++; |
4451 | 211 } |
212 else if ((chunk_id == RoQ_QUAD_VQ) && (last_chunk_id == RoQ_QUAD_CODEBOOK)) | |
213 { | |
214 // if it's a quad VQ chunk following a codebook chunk, extend the last | |
215 // chunk | |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
216 roq_data->chunks[roq_data->total_chunks - 1].chunk_size += (chunk_size + 8); |
4451 | 217 stream_skip(demuxer->stream, chunk_size); |
218 } | |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
219 else if (!stream_eof(demuxer->stream)) |
4451 | 220 { |
221 mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Unknown RoQ chunk ID: %04X\n", chunk_id); | |
222 } | |
223 | |
224 last_chunk_id = chunk_id; | |
225 } | |
226 | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
227 // minimum output buffer size = largest audio chunk * 2, since each byte |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
228 // in the DPCM encoding effectively represents 1 16-bit sample |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
229 // (store it in wf->nBlockAlign for the time being since init_audio() will |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
230 // step on it anyway) |
4532
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
231 if (sh_audio) |
f86c1915ca79
fixed FPS as well as crash bug when no audio chunks are present
melanson
parents:
4485
diff
changeset
|
232 sh_audio->wf->nBlockAlign = largest_audio_chunk * 2; |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
233 |
4451 | 234 roq_data->current_chunk = 0; |
235 | |
236 demuxer->priv = roq_data; | |
237 | |
4485
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
238 stream_reset(demuxer->stream); |
eaa4a2242552
demuxer is now more complete, though still not perfect
melanson
parents:
4451
diff
changeset
|
239 |
4451 | 240 return demuxer; |
241 } | |
5810 | 242 |
243 void demux_close_roq(demuxer_t* demuxer) { | |
244 roq_data_t *roq_data = demuxer->priv; | |
245 | |
246 if(!roq_data) | |
247 return; | |
248 free(roq_data); | |
249 } | |
250 |