diff -ru MPlayer-0.90rc4/libmpdemux/demux_nuv.c MPlayer-0.90rc4+mdz/libmpdemux/demux_nuv.c --- MPlayer-0.90rc4/libmpdemux/demux_nuv.c 2002-09-30 17:10:41.000000000 -0400 +++ MPlayer-0.90rc4+mdz/libmpdemux/demux_nuv.c 2003-02-27 14:22:20.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,25 @@ 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 == 'S')) return 1; - + + /* Skip seektable (actually has a payload) */ + if (rtjpeg_frameheader.frametype == 'Q') { + stream_skip(demuxer->stream, rtjpeg_frameheader.packetlength); + return 1; + } + + if (((rtjpeg_frameheader.frametype == 'D') && (rtjpeg_frameheader.comptype == 'R')) || (rtjpeg_frameheader.frametype == 'V')) @@ -175,13 +237,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 +254,103 @@ 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 */ + if (sh_audio->format != 0x1) + 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 +390,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 +406,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 +464,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 MPlayer-0.90rc4/libmpdemux/nuppelvideo.h MPlayer-0.90rc4+mdz/libmpdemux/nuppelvideo.h --- MPlayer-0.90rc4/libmpdemux/nuppelvideo.h 2001-12-27 17:20:15.000000000 -0500 +++ MPlayer-0.90rc4+mdz/libmpdemux/nuppelvideo.h 2003-02-27 13:59:44.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;