Play NUV files as sourced from MythTV
#1
it'd be great if the next version of xbmc included a patch to mplayer such that mplayer could play .nuv files as sourced from mythtv.

the patch to mplayer is at: <http://www.cse.sc.edu/~oldendic/mythtv/m...htv.patch>

this would mean that xbmcmythtv python scripts could actually play back the content i already have ...



diff -ru orig/mplayer-0.90pre10/libmpdemux/demux_nuv.c mplayer-0.90pre10/libmpdemux/demux_nuv.c
--- orig/mplayer-0.90pre10/libmpdemux/demux_nuv.c 2002-09-30 17:10:41.000000000 -0400
+++ mplayer-0.90pre10/libmpdemux/demux_nuv.c 2002-12-06 23:42:47.000000000 -0500
@@ -43,6 +43,60 @@
nuv_position_t *current_position;
} nuv_priv_t;

+/* stolen from libmp3lame -mdz */
+
+/* used to find nearest matching bitrate
+ * we need bitrate-based values
+ * determined using tables
+ *
+ * bitrate in kbps
+ *
+ * gabriel bouvigne 2002-11-03
+ */
+int nearestbitrate(const int bitrate)
+{
+ /* borrowed from dm abr presets*/
+
+ int index; // resolved range
+
+ const int bitrate_table[] = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320};
+
+
+ int lower_range = 0, lower_range_kbps = 0,
+ upper_range = 0, upper_range_kbps = 0;
+
+
+ int b;
+
+
+ // we assume specified bitrate will be 320kbps
+ upper_range_kbps = bitrate_table[16];
+ upper_range = 16;
+ lower_range_kbps = bitrate_table[16];
+ lower_range = 16;
+
+ // determine which significant bitrates the value specified falls between,
+ // if loop ends without breaking then we were correct above that the value was 320
+ for (b = 0; b < 16; b++) {
+ if (bitrate < bitrate_table[b+1]) {
+ upper_range_kbps = bitrate_table[b+1];
+ upper_range = b+1;
+ lower_range_kbps = bitrate_table[b];
+ lower_range = (b);
+ break; // we found upper range
+ }
+ }
+
+ // determine which range the value specified is closer to
+ if ((upper_range_kbps - bitrate) > (bitrate - lower_range_kbps))
+ index = lower_range;
+ else
+ index = upper_range;
+
+ return bitrate_table[index];
+}
+
+#define mktag(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))

/**
* seek to a position relative to the current position, indicated in time.
@@ -147,17 +201,19 @@
return 0; /* eof */

#if 0
- printf("nuv frame: frametype: %c, comptype: %c, packetlength: %d\n",
+ printf("nuv frame: frametype: %c, comptype: %c, packetlength: %d, timecode: %d\n",
rtjpeg_frameheader.frametype, rtjpeg_frameheader.comptype,
- rtjpeg_frameheader.packetlength);
+ rtjpeg_frameheader.packetlength, rtjpeg_frameheader.timecode);
#endif

/* skip seekpoint, text and sync for now */
if ((rtjpeg_frameheader.frametype == 'r') ||
(rtjpeg_frameheader.frametype == 't') ||
- (rtjpeg_frameheader.frametype == 's'))
+ (rtjpeg_frameheader.frametype == 'x') ||
+ (rtjpeg_frameheader.frametype == 'q') ||
+ (rtjpeg_frameheader.frametype == 's'))
return 1;
-
+
if (((rtjpeg_frameheader.frametype == 'd') &&
(rtjpeg_frameheader.comptype == 'r')) ||
(rtjpeg_frameheader.frametype == 'v'))
@@ -175,13 +231,13 @@
/* put rtjpeg tables, video info to video buffer */
stream_seek ( demuxer->stream, orig_pos );
ds_read_packet ( demuxer->video, demuxer->stream, rtjpeg_frameheader.packetlength + 12,
- rtjpeg_frameheader.timecode*0.001, orig_pos, 0 );
+ rtjpeg_frameheader.timecode*0.001, orig_pos, 0 );


} else
/* copy pcm only */
if (demuxer->audio && (rtjpeg_frameheader.frametype == 'a') &&
- (rtjpeg_frameheader.comptype == '0'))
+ 1 /*(rtjpeg_frameheader.comptype == '0')*/)
{
priv->current_audio_frame++;
if (want_audio) {
@@ -192,15 +248,101 @@
orig_pos + 12, 0 );
} else {
/* skip audio block */
- stream_seek ( demuxer->stream,
- stream_tell ( demuxer->stream )
- + rtjpeg_frameheader.packetlength );
+ stream_skip ( demuxer->stream,
+ rtjpeg_frameheader.packetlength );
}
}

return 1;
}

+/* scan for the extended data in mythtv nuv streams */
+int demux_xscan_nuv ( demuxer_t* demuxer )
+{
+ int i;
+ struct rtframeheader rtjpeg_frameheader;
+ struct extendeddata ext;
+ sh_video_t* sh_video = demuxer->video->sh;
+ sh_audio_t* sh_audio = demuxer->audio->sh;
+
+ for( i = 0 ; i < 2 ; ++i ) {
+ if (stream_read ( demuxer->stream, (char*)& rtjpeg_frameheader, sizeof ( rtjpeg_frameheader ) ) < sizeof(rtjpeg_frameheader))
+ return 0; /* eof */
+
+ if (rtjpeg_frameheader.frametype != 'x')
+ stream_skip( demuxer->stream, rtjpeg_frameheader.packetlength );
+ }
+
+ if ( rtjpeg_frameheader.frametype != 'x' ) {
+ stream_reset( demuxer->stream );
+ return 0; /* no x frame in the expected place */
+ }
+
+ if ( rtjpeg_frameheader.packetlength != sizeof(ext) ) {
+ printf("nuv extended frame does not have expected length, ignoring\n");
+ stream_reset( demuxer->stream );
+ return 0;
+ }
+
+ if (stream_read( demuxer->stream, (char*)& ext, sizeof(ext)) < sizeof(ext)) {
+ stream_reset( demuxer->stream );
+ return 0; /* eof */
+ }
+
+ if ( ext.version != 1 ) {
+ printf("nuv extended frame has unknown version number (%d), ignoring\n",
+ ext.version);
+ stream_reset( demuxer->stream );
+ return 0;
+ }
+
+ printf("detected mythtv stream, reading extended format information\n");
+
+ /* video parameters */
+ printf("fourcc: %c%c%c%c\n",
+ (ext.video_fourcc >> 24) & 0xff,
+ (ext.video_fourcc >> 16) & 0xff,
+ (ext.video_fourcc >> 8) & 0xff,
+ (ext.video_fourcc) & 0xff);
+ if ( ext.video_fourcc == mmiofourcc('r', 'j', 'p', 'g') ) {
+ sh_video->format = mmiofourcc('n', 'u', 'v', '1');
+ } else {
+ sh_video->format = ext.video_fourcc;
+ sh_video->i_bps = ext.lavc_bitrate;
+ }
+
+ /* audio parameters */
+ if ( ext.audio_fourcc == mmiofourcc('l', 'a', 'm', 'e') ) {
+ sh_audio->format = 0x55;
+ } else if ( ext.audio_fourcc == mmiofourcc('r', 'a', 'w', 'a') ) {
+ sh_audio->format = 0x1;
+ } else {
+ printf("warning! unknown audio format %d\n", ext.audio_fourcc);
+ }
+
+ sh_audio->samplerate = ext.audio_sample_rate;
+ sh_audio->channels = ext.audio_channels;
+
+ /* this is a little silly so that we can use libmp3lame's
+ nearestbitrate verbatim */
+ sh_audio->i_bps = nearestbitrate(ext.audio_channels
+ * ext.audio_bits_per_sample * ext.audio_sample_rate /
+ ext.audio_compression_ratio / 1000) * 1000;
+
+ sh_audio->wf->wbitspersample = ext.audio_bits_per_sample;
+ sh_audio->wf->navgbytespersec = sh_audio->i_bps / 8;
+ sh_audio->wf->nblockalign = sh_audio->channels * 2;
+ sh_audio->wf->cbsize = 0;
+ sh_audio->wf->nsamplespersec = ext.audio_sample_rate;
+ sh_audio->wf->wformattag = sh_audio->format;
+ sh_audio->wf->nchannels = ext.audio_channels;
+
+ printf("channels=%d bitspersample=%d samplerate=%d audio_compression_ratio=%d\n", ext.audio_channels, ext.audio_bits_per_sample, ext.audio_sample_rate, ext.audio_compression_ratio);
+
+ stream_reset( demuxer->stream );
+
+ return 1;
+}

demuxer_t* demux_open_nuv ( demuxer_t* demuxer )
{
@@ -240,8 +382,6 @@
*/
sh_video->ds = demuxer->video;

- /* custom fourcc for internal mplayer use */
- sh_video->format = mmiofourcc('n', 'u', 'v', '1');

sh_video->disp_w = rtjpeg_fileheader.width;
sh_video->disp_h = rtjpeg_fileheader.height;
@@ -258,26 +398,42 @@
sh_video->fps = rtjpeg_fileheader.fps;
sh_video->frametime = 1 / sh_video->fps;

- if (rtjpeg_fileheader.audioblocks != 0)
- {
- sh_audio = new_sh_audio(demuxer, 0);
- demuxer->audio->sh = sh_audio;
- sh_audio->ds = demuxer->audio;
- sh_audio->format = 0x1;
- sh_audio->channels = 2;
- sh_audio->samplerate = 44100;
-
- sh_audio->wf = malloc(sizeof(waveformatex));
- memset(sh_audio->wf, 0, sizeof(waveformatex));
- sh_audio->wf->wformattag = sh_audio->format;
- sh_audio->wf->nchannels = sh_audio->channels;
- sh_audio->wf->wbitspersample = 16;
- sh_audio->wf->nsamplespersec = sh_audio->samplerate;
- sh_audio->wf->navgbytespersec = sh_audio->wf->nchannels*
- sh_audio->wf->wbitspersample*sh_audio->wf->nsamplespersec/8;
- sh_audio->wf->nblockalign = sh_audio->channels * 2;
- sh_audio->wf->cbsize = 0;
- }
+ if (rtjpeg_fileheader.audioblocks != 0)
+ {
+ sh_audio = new_sh_audio(demuxer, 0);
+ demuxer->audio->sh = sh_audio;
+ sh_audio->ds = demuxer->audio;
+ sh_audio->wf = malloc(sizeof(waveformatex));
+ memset(sh_audio->wf, 0, sizeof(waveformatex));
+ }
+
+ /* check for extended data (x frame) and read settings from it */
+ if (! demux_xscan_nuv( demuxer ) ) {
+ /* otherwise assume defaults */
+ printf("no nuv extended frame, using defaults\n");
+
+ /* custom fourcc for internal mplayer use */
+ sh_video->format = mmiofourcc('n', 'u', 'v', '1');
+
+ if (rtjpeg_fileheader.audioblocks != 0)
+ {
+ sh_audio->format = 0x1;
+ sh_audio->channels = 2;
+ sh_audio->samplerate = 44100;
+ sh_audio->wf->wbitspersample = 16;
+ }
+
+ if (rtjpeg_fileheader.audioblocks != 0)
+ {
+ sh_audio->wf->wformattag = sh_audio->format;
+ sh_audio->wf->nchannels = sh_audio->channels;
+ sh_audio->wf->nsamplespersec = sh_audio->samplerate;
+ sh_audio->wf->navgbytespersec = sh_audio->wf->nchannels*
+ sh_audio->wf->wbitspersample*sh_audio->wf->nsamplespersec/8;
+ sh_audio->wf->nblockalign = sh_audio->channels * 2;
+ sh_audio->wf->cbsize = 0;
+ }
+ }

priv->index_list = (nuv_position_t*) malloc(sizeof(nuv_position_t));
priv->index_list->frame = 0;
@@ -300,9 +456,12 @@

stream_read(demuxer->stream,(char*)&ns,sizeof(ns));

- if ( strncmp ( ns.finfo, "nuppelvideo", 12 ) )
+ if ( strncmp ( ns.finfo, "nuppelvideo", 12 ) &&
+ strncmp ( ns.finfo, "mythtvvideo", 12 ) )
return 0; /* not a nuppelvideo file */
- if ( strncmp ( ns.version, "0.05", 5 ) )
+ if ( strncmp ( ns.version, "0.05", 5 ) &&
+ strncmp ( ns.version, "0.06", 5 ) &&
+ strncmp ( ns.version, "0.07", 5 ) )
return 0; /* wrong version nuppelvideo file */

/* return to original position */
diff -ru orig/mplayer-0.90pre10/libmpdemux/nuppelvideo.h mplayer-0.90pre10/libmpdemux/nuppelvideo.h
--- orig/mplayer-0.90pre10/libmpdemux/nuppelvideo.h 2001-12-27 17:20:15.000000000 -0500
+++ mplayer-0.90pre10/libmpdemux/nuppelvideo.h 2002-11-27 23:56:10.000000000 -0500
@@ -90,3 +90,30 @@
unsigned char *buffer_offset;
} audbuffertyp;

+/* for mythtv */
+typedef struct extendeddata
+{
+ int version; // yes, this is repeated from the file header
+ int video_fourcc; // video encoding method used
+ int audio_fourcc; // audio encoding method used
+ // generic data
+ int audio_sample_rate;
+ int audio_bits_per_sample;
+ int audio_channels;
+ // codec specific
+ // mp3lame
+ int audio_compression_ratio;
+ int audio_quality;
+ // rtjpeg
+ int rtjpeg_quality;
+ int rtjpeg_luma_filter;
+ int rtjpeg_chroma_filter;
+ // libavcodec
+ int lavc_bitrate;
+ int lavc_qmin;
+ int lavc_qmax;
+ int lavc_maxqdiff;
+ // unused for later -- total size of 128 integers.
+ // new fields must be added at the end, above this comment.
+ int expansion[113];
+} extendeddata;
Reply
#2
that's a huge patch.. best would be to have it commited into the normal mplayer.. thou it looks abit too messy for that right now. will look abit at it, but don't have too high hopes..

also it is abit old, ie patch against 0.90pre10, thou there hasn't been many updates to that file since then, but still..

ps. you could allways compile the dll yourself with the patch included.
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#3
if your using a hardware encoder (usually to mpeg2) mplayer will play the 'nuv' files fine. (such as haupagge tuners)

you need to be more specific in your description if these files. likely your encoding to one of the two software encoders in mythtv. if you do have a pvr-150/250/350/500 dont do software encoding.

if you only have a software encoder your sol at this time.
Reply
#4
http://www.xboxmediaplayer.de/cgi-bin....;t=1921
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.
Reply

Logout Mark Read Team Forum Stats Members Help
Play NUV files as sourced from MythTV0