Mercurial > mplayer.hg
comparison libmpdemux/demux_nuv.c @ 16164:ec76d55a25f1
Support more MythTV nuv files, based on Gentoo portage patch
author | reimar |
---|---|
date | Mon, 01 Aug 2005 18:52:20 +0000 |
parents | cce2717344f4 |
children | 6b86089c2edd |
comparison
equal
deleted
inserted
replaced
16163:ed52261ea934 | 16164:ec76d55a25f1 |
---|---|
41 int current_video_frame; | 41 int current_video_frame; |
42 nuv_position_t *index_list; | 42 nuv_position_t *index_list; |
43 nuv_position_t *current_position; | 43 nuv_position_t *current_position; |
44 } nuv_priv_t; | 44 } nuv_priv_t; |
45 | 45 |
46 /** | |
47 * \brief find best matching bitrate (in kbps) out of a table | |
48 * \param bitrate bitrate to find best match for | |
49 * \return best match from table | |
50 */ | |
51 static int nearestBitrate(int bitrate) { | |
52 const int rates[17] = {8000, 16000, 24000, 32000, 40000, 48000, 56000, | |
53 64000, 80000, 96000, 112000, 128000, 160000, | |
54 192000, 224000, 256000, 320000}; | |
55 int i; | |
56 for (i = 0; i < 16; i++) { | |
57 if ((rates[i] + rates[i + 1]) / 2 > bitrate) | |
58 break; | |
59 } | |
60 return rates[i]; | |
61 } | |
46 | 62 |
47 /** | 63 /** |
48 * Seek to a position relative to the current position, indicated in time. | 64 * Seek to a position relative to the current position, indicated in time. |
49 */ | 65 */ |
50 void demux_seek_nuv ( demuxer_t *demuxer, float rel_seek_secs, int flags ) | 66 void demux_seek_nuv ( demuxer_t *demuxer, float rel_seek_secs, int flags ) |
152 printf("NUV frame: frametype: %c, comptype: %c, packetlength: %d\n", | 168 printf("NUV frame: frametype: %c, comptype: %c, packetlength: %d\n", |
153 rtjpeg_frameheader.frametype, rtjpeg_frameheader.comptype, | 169 rtjpeg_frameheader.frametype, rtjpeg_frameheader.comptype, |
154 rtjpeg_frameheader.packetlength); | 170 rtjpeg_frameheader.packetlength); |
155 #endif | 171 #endif |
156 | 172 |
157 /* Skip Seekpoint, Text and Sync for now */ | 173 /* Skip Seekpoint, Extended header and Sync for now */ |
158 if ((rtjpeg_frameheader.frametype == 'R') || | 174 if ((rtjpeg_frameheader.frametype == 'R') || |
159 (rtjpeg_frameheader.frametype == 'T') || | 175 (rtjpeg_frameheader.frametype == 'X') || |
160 (rtjpeg_frameheader.frametype == 'S')) | 176 (rtjpeg_frameheader.frametype == 'S')) |
161 return 1; | 177 return 1; |
162 | 178 |
179 /* Skip seektable and text (these have a payload) */ | |
180 if ((rtjpeg_frameheader.frametype == 'Q') || | |
181 (rtjpeg_frameheader.frametype == 'T')) { | |
182 stream_skip(demuxer->stream, rtjpeg_frameheader.packetlength); | |
183 return 1; | |
184 } | |
185 | |
163 if (((rtjpeg_frameheader.frametype == 'D') && | 186 if (((rtjpeg_frameheader.frametype == 'D') && |
164 (rtjpeg_frameheader.comptype == 'R')) || | 187 (rtjpeg_frameheader.comptype == 'R')) || |
165 (rtjpeg_frameheader.frametype == 'V')) | 188 (rtjpeg_frameheader.frametype == 'V')) |
166 { | 189 { |
167 if ( rtjpeg_frameheader.frametype == 'V' ) | 190 if ( rtjpeg_frameheader.frametype == 'V' ) |
179 ds_read_packet ( demuxer->video, demuxer->stream, rtjpeg_frameheader.packetlength + 12, | 202 ds_read_packet ( demuxer->video, demuxer->stream, rtjpeg_frameheader.packetlength + 12, |
180 rtjpeg_frameheader.timecode*0.001, orig_pos, 0 ); | 203 rtjpeg_frameheader.timecode*0.001, orig_pos, 0 ); |
181 | 204 |
182 | 205 |
183 } else | 206 } else |
184 /* copy PCM only */ | 207 if (demuxer->audio && (rtjpeg_frameheader.frametype == 'A')) |
185 if (demuxer->audio && (rtjpeg_frameheader.frametype == 'A') && | |
186 (rtjpeg_frameheader.comptype == '0')) | |
187 { | 208 { |
188 priv->current_audio_frame++; | 209 priv->current_audio_frame++; |
189 if (want_audio) { | 210 if (want_audio) { |
190 /* put Audio to audio buffer */ | 211 /* put Audio to audio buffer */ |
191 ds_read_packet ( demuxer->audio, demuxer->stream, | 212 ds_read_packet ( demuxer->audio, demuxer->stream, |
192 rtjpeg_frameheader.packetlength, | 213 rtjpeg_frameheader.packetlength, |
193 rtjpeg_frameheader.timecode*0.001, | 214 rtjpeg_frameheader.timecode*0.001, |
194 orig_pos + 12, 0 ); | 215 orig_pos + 12, 0 ); |
195 } else { | 216 } else { |
196 /* skip audio block */ | 217 /* skip audio block */ |
197 stream_seek ( demuxer->stream, | 218 stream_skip ( demuxer->stream, |
198 stream_tell ( demuxer->stream ) | 219 rtjpeg_frameheader.packetlength ); |
199 + rtjpeg_frameheader.packetlength ); | |
200 } | 220 } |
201 } | 221 } |
202 | 222 |
203 return 1; | 223 return 1; |
204 } | 224 } |
205 | 225 |
226 /* Scan for the extended data in MythTV nuv streams */ | |
227 static int demux_xscan_nuv(demuxer_t* demuxer, int width, int height) { | |
228 int i; | |
229 int res = 0; | |
230 off_t orig_pos = stream_tell(demuxer->stream); | |
231 struct rtframeheader rtjpeg_frameheader; | |
232 struct extendeddata ext; | |
233 sh_video_t* sh_video = demuxer->video->sh; | |
234 sh_audio_t* sh_audio = demuxer->audio->sh; | |
235 | |
236 for (i = 0; i < 2; ++i) { | |
237 if (stream_read(demuxer->stream, (char*)&rtjpeg_frameheader, | |
238 sizeof(rtjpeg_frameheader)) < sizeof(rtjpeg_frameheader)) | |
239 goto out; | |
240 | |
241 if (rtjpeg_frameheader.frametype != 'X') | |
242 stream_skip(demuxer->stream, rtjpeg_frameheader.packetlength); | |
243 } | |
244 | |
245 if ( rtjpeg_frameheader.frametype != 'X' ) | |
246 goto out; | |
247 | |
248 if (rtjpeg_frameheader.packetlength != sizeof(ext)) { | |
249 mp_msg(MSGT_DEMUXER, MSGL_WARN, | |
250 "NUV extended frame does not have expected length, ignoring\n"); | |
251 goto out; | |
252 } | |
253 le2me_extendeddata(&ext); | |
254 | |
255 if (stream_read(demuxer->stream, (char*)&ext, sizeof(ext)) < sizeof(ext)) | |
256 goto out; | |
257 | |
258 if (ext.version != 1) { | |
259 mp_msg(MSGT_DEMUXER, MSGL_WARN, | |
260 "NUV extended frame has unknown version number (%d), ignoring\n", | |
261 ext.version); | |
262 goto out; | |
263 } | |
264 | |
265 mp_msg(MSGT_DEMUXER, MSGL_V, "Detected MythTV stream\n"); | |
266 | |
267 /* Video parameters */ | |
268 mp_msg(MSGT_DEMUXER, MSGL_V, "FOURCC: %c%c%c%c\n", | |
269 (ext.video_fourcc >> 24) & 0xff, | |
270 (ext.video_fourcc >> 16) & 0xff, | |
271 (ext.video_fourcc >> 8) & 0xff, | |
272 (ext.video_fourcc) & 0xff); | |
273 sh_video->format = ext.video_fourcc; | |
274 sh_video->i_bps = ext.lavc_bitrate; | |
275 | |
276 /* Audio parameters */ | |
277 if (ext.audio_fourcc == mmioFOURCC('L', 'A', 'M', 'E')) { | |
278 sh_audio->format = 0x55; | |
279 } else if (ext.audio_fourcc == mmioFOURCC('R', 'A', 'W', 'A')) { | |
280 sh_audio->format = 0x1; | |
281 } else { | |
282 mp_msg(MSGT_DEMUXER, MSGL_WARN, | |
283 "Unknown audio format 0x%x\n", ext.audio_fourcc); | |
284 } | |
285 | |
286 sh_audio->channels = ext.audio_channels; | |
287 sh_audio->samplerate = ext.audio_sample_rate; | |
288 sh_audio->i_bps = sh_audio->channels * sh_audio->samplerate * | |
289 ext.audio_bits_per_sample; | |
290 if (sh_audio->format != 0x1) | |
291 sh_audio->i_bps = nearestBitrate(sh_audio->i_bps / | |
292 ext.audio_compression_ratio); | |
293 sh_audio->wf->wFormatTag = sh_audio->format; | |
294 sh_audio->wf->nChannels = sh_audio->channels; | |
295 sh_audio->wf->nSamplesPerSec = sh_audio->samplerate; | |
296 sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps / 8; | |
297 sh_audio->wf->nBlockAlign = sh_audio->channels * 2; | |
298 sh_audio->wf->wBitsPerSample = ext.audio_bits_per_sample; | |
299 sh_audio->wf->cbSize = 0; | |
300 | |
301 mp_msg(MSGT_DEMUXER, MSGL_V, | |
302 "channels=%d bitspersample=%d samplerate=%d compression_ratio=%d\n", | |
303 ext.audio_channels, ext.audio_bits_per_sample, | |
304 ext.audio_sample_rate, ext.audio_compression_ratio); | |
305 return 1; | |
306 out: | |
307 stream_reset(demuxer->stream); | |
308 stream_seek(demuxer->stream, orig_pos); | |
309 return 0; | |
310 } | |
206 | 311 |
207 demuxer_t* demux_open_nuv ( demuxer_t* demuxer ) | 312 demuxer_t* demux_open_nuv ( demuxer_t* demuxer ) |
208 { | 313 { |
209 sh_video_t *sh_video = NULL; | 314 sh_video_t *sh_video = NULL; |
210 sh_audio_t *sh_audio = NULL; | 315 sh_audio_t *sh_audio = NULL; |
280 sh_audio->wf->wBitsPerSample*sh_audio->wf->nSamplesPerSec/8; | 385 sh_audio->wf->wBitsPerSample*sh_audio->wf->nSamplesPerSec/8; |
281 sh_audio->wf->nBlockAlign = sh_audio->channels * 2; | 386 sh_audio->wf->nBlockAlign = sh_audio->channels * 2; |
282 sh_audio->wf->cbSize = 0; | 387 sh_audio->wf->cbSize = 0; |
283 } | 388 } |
284 | 389 |
390 /* Check for extended data (X frame) and read settings from it */ | |
391 if (!demux_xscan_nuv(demuxer, rtjpeg_fileheader.width, | |
392 rtjpeg_fileheader.height)) | |
393 /* Otherwise assume defaults */ | |
394 mp_msg(MSGT_DEMUXER, MSGL_V, "No NUV extended frame, using defaults\n"); | |
395 | |
396 | |
285 priv->index_list = (nuv_position_t*) malloc(sizeof(nuv_position_t)); | 397 priv->index_list = (nuv_position_t*) malloc(sizeof(nuv_position_t)); |
286 priv->index_list->frame = 0; | 398 priv->index_list->frame = 0; |
287 priv->index_list->time = 0; | 399 priv->index_list->time = 0; |
288 priv->index_list->offset = stream_tell ( demuxer->stream ); | 400 priv->index_list->offset = stream_tell ( demuxer->stream ); |
289 priv->index_list->next = NULL; | 401 priv->index_list->next = NULL; |
302 mp_msg ( MSGT_DEMUX, MSGL_V, "Checking for NuppelVideo\n" ); | 414 mp_msg ( MSGT_DEMUX, MSGL_V, "Checking for NuppelVideo\n" ); |
303 | 415 |
304 if(stream_read(demuxer->stream,(char*)&ns,sizeof(ns)) != sizeof(ns)) | 416 if(stream_read(demuxer->stream,(char*)&ns,sizeof(ns)) != sizeof(ns)) |
305 return 0; | 417 return 0; |
306 | 418 |
307 if ( strncmp ( ns.finfo, "NuppelVideo", 12 ) ) | 419 if ( strncmp ( ns.finfo, "NuppelVideo", 12 ) && |
420 strncmp ( ns.finfo, "MythTVVideo", 12 ) ) | |
308 return 0; /* Not a NuppelVideo file */ | 421 return 0; /* Not a NuppelVideo file */ |
309 if ( strncmp ( ns.version, "0.05", 5 ) ) | 422 if ( strncmp ( ns.version, "0.05", 5 ) && |
423 strncmp ( ns.version, "0.06", 5 ) && | |
424 strncmp ( ns.version, "0.07", 5 ) ) | |
310 return 0; /* Wrong version NuppelVideo file */ | 425 return 0; /* Wrong version NuppelVideo file */ |
311 | 426 |
312 /* Return to original position */ | 427 /* Return to original position */ |
313 stream_seek ( demuxer->stream, orig_pos ); | 428 stream_seek ( demuxer->stream, orig_pos ); |
314 return 1; | 429 return 1; |