[mythtv] Simple player

Michael Kedl mythtv-dev@snowman.net
07 Dec 2002 01:08:47 -0500


ok I replied a little to soon; it appears the video in the converted
file is slightly ahead of the audio as compared to the original myth
file.

but still watchable, video maybe .1 or .2 seconds ahead?

Mike

On Sat, 2002-12-07 at 00:53, Michael Kedl wrote:
> Cool, now xine can play it.
> 
> For the first 980s or so of a 30 minute show I still got duplicate 1
> frames every second or so.  Then it dropped to just a few for the rest
> of the video.
> 
> But it works great!
> Mike
> 
> On Fri, 2002-12-06 at 23:51, Matt Zimmerman wrote:
> > On Fri, Dec 06, 2002 at 07:17:29PM -0500, Matt Zimmerman wrote:
> > 
> > > The patch is attached.  If anyone can track down why mencoder complains:
> > > 
> > > duplicate 1 frame(s)!!!    
> > > 
> > > and fix it or tell me what the problem is, that would be fantastic.  I have
> > > only tested it with mpeg4 video and mp3 audio.
> > 
> > With some input from Isaac on IRC, I have this pretty much fixed.  It now
> > only duplicates about 1 frame out of 10,000, which should be insignificant
> > for just about any purpose.
> > 
> > -- 
> >  - mdz
> > ----
> > 
> 
> > 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;
> 
> 
> _______________________________________________
> mythtv-dev mailing list
> mythtv-dev@snowman.net
> http://www.snowman.net/mailman/listinfo/mythtv-dev
>