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;