mirror of
https://github.com/mpv-player/mpv.git
synced 2024-09-20 12:02:23 +02:00
Support more MythTV nuv files, based on Gentoo portage patch
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@16165 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
3138932d9a
commit
2d14fdcb3a
@ -43,6 +43,22 @@ typedef struct _nuv_info_t
|
||||
nuv_position_t *current_position;
|
||||
} nuv_priv_t;
|
||||
|
||||
/**
|
||||
* \brief find best matching bitrate (in kbps) out of a table
|
||||
* \param bitrate bitrate to find best match for
|
||||
* \return best match from table
|
||||
*/
|
||||
static int nearestBitrate(int bitrate) {
|
||||
const int rates[17] = {8000, 16000, 24000, 32000, 40000, 48000, 56000,
|
||||
64000, 80000, 96000, 112000, 128000, 160000,
|
||||
192000, 224000, 256000, 320000};
|
||||
int i;
|
||||
for (i = 0; i < 16; i++) {
|
||||
if ((rates[i] + rates[i + 1]) / 2 > bitrate)
|
||||
break;
|
||||
}
|
||||
return rates[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek to a position relative to the current position, indicated in time.
|
||||
@ -154,12 +170,19 @@ int demux_nuv_fill_buffer ( demuxer_t *demuxer )
|
||||
rtjpeg_frameheader.packetlength);
|
||||
#endif
|
||||
|
||||
/* Skip Seekpoint, Text and Sync for now */
|
||||
/* Skip Seekpoint, Extended header and Sync for now */
|
||||
if ((rtjpeg_frameheader.frametype == 'R') ||
|
||||
(rtjpeg_frameheader.frametype == 'T') ||
|
||||
(rtjpeg_frameheader.frametype == 'X') ||
|
||||
(rtjpeg_frameheader.frametype == 'S'))
|
||||
return 1;
|
||||
|
||||
/* Skip seektable and text (these have a payload) */
|
||||
if ((rtjpeg_frameheader.frametype == 'Q') ||
|
||||
(rtjpeg_frameheader.frametype == 'T')) {
|
||||
stream_skip(demuxer->stream, rtjpeg_frameheader.packetlength);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (((rtjpeg_frameheader.frametype == 'D') &&
|
||||
(rtjpeg_frameheader.comptype == 'R')) ||
|
||||
(rtjpeg_frameheader.frametype == 'V'))
|
||||
@ -181,9 +204,7 @@ int demux_nuv_fill_buffer ( demuxer_t *demuxer )
|
||||
|
||||
|
||||
} else
|
||||
/* copy PCM only */
|
||||
if (demuxer->audio && (rtjpeg_frameheader.frametype == 'A') &&
|
||||
(rtjpeg_frameheader.comptype == '0'))
|
||||
if (demuxer->audio && (rtjpeg_frameheader.frametype == 'A'))
|
||||
{
|
||||
priv->current_audio_frame++;
|
||||
if (want_audio) {
|
||||
@ -194,15 +215,99 @@ int demux_nuv_fill_buffer ( demuxer_t *demuxer )
|
||||
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 */
|
||||
static int demux_xscan_nuv(demuxer_t* demuxer, int width, int height) {
|
||||
int i;
|
||||
int res = 0;
|
||||
off_t orig_pos = stream_tell(demuxer->stream);
|
||||
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))
|
||||
goto out;
|
||||
|
||||
if (rtjpeg_frameheader.frametype != 'X')
|
||||
stream_skip(demuxer->stream, rtjpeg_frameheader.packetlength);
|
||||
}
|
||||
|
||||
if ( rtjpeg_frameheader.frametype != 'X' )
|
||||
goto out;
|
||||
|
||||
if (rtjpeg_frameheader.packetlength != sizeof(ext)) {
|
||||
mp_msg(MSGT_DEMUXER, MSGL_WARN,
|
||||
"NUV extended frame does not have expected length, ignoring\n");
|
||||
goto out;
|
||||
}
|
||||
le2me_extendeddata(&ext);
|
||||
|
||||
if (stream_read(demuxer->stream, (char*)&ext, sizeof(ext)) < sizeof(ext))
|
||||
goto out;
|
||||
|
||||
if (ext.version != 1) {
|
||||
mp_msg(MSGT_DEMUXER, MSGL_WARN,
|
||||
"NUV extended frame has unknown version number (%d), ignoring\n",
|
||||
ext.version);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mp_msg(MSGT_DEMUXER, MSGL_V, "Detected MythTV stream\n");
|
||||
|
||||
/* Video parameters */
|
||||
mp_msg(MSGT_DEMUXER, MSGL_V, "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);
|
||||
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 {
|
||||
mp_msg(MSGT_DEMUXER, MSGL_WARN,
|
||||
"Unknown audio format 0x%x\n", ext.audio_fourcc);
|
||||
}
|
||||
|
||||
sh_audio->channels = ext.audio_channels;
|
||||
sh_audio->samplerate = ext.audio_sample_rate;
|
||||
sh_audio->i_bps = sh_audio->channels * sh_audio->samplerate *
|
||||
ext.audio_bits_per_sample;
|
||||
if (sh_audio->format != 0x1)
|
||||
sh_audio->i_bps = nearestBitrate(sh_audio->i_bps /
|
||||
ext.audio_compression_ratio);
|
||||
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->i_bps / 8;
|
||||
sh_audio->wf->nBlockAlign = sh_audio->channels * 2;
|
||||
sh_audio->wf->wBitsPerSample = ext.audio_bits_per_sample;
|
||||
sh_audio->wf->cbSize = 0;
|
||||
|
||||
mp_msg(MSGT_DEMUXER, MSGL_V,
|
||||
"channels=%d bitspersample=%d samplerate=%d compression_ratio=%d\n",
|
||||
ext.audio_channels, ext.audio_bits_per_sample,
|
||||
ext.audio_sample_rate, ext.audio_compression_ratio);
|
||||
return 1;
|
||||
out:
|
||||
stream_reset(demuxer->stream);
|
||||
stream_seek(demuxer->stream, orig_pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
demuxer_t* demux_open_nuv ( demuxer_t* demuxer )
|
||||
{
|
||||
@ -282,6 +387,13 @@ demuxer_t* demux_open_nuv ( demuxer_t* demuxer )
|
||||
sh_audio->wf->cbSize = 0;
|
||||
}
|
||||
|
||||
/* Check for extended data (X frame) and read settings from it */
|
||||
if (!demux_xscan_nuv(demuxer, rtjpeg_fileheader.width,
|
||||
rtjpeg_fileheader.height))
|
||||
/* Otherwise assume defaults */
|
||||
mp_msg(MSGT_DEMUXER, MSGL_V, "No NUV extended frame, using defaults\n");
|
||||
|
||||
|
||||
priv->index_list = (nuv_position_t*) malloc(sizeof(nuv_position_t));
|
||||
priv->index_list->frame = 0;
|
||||
priv->index_list->time = 0;
|
||||
@ -304,9 +416,12 @@ int nuv_check_file ( demuxer_t* demuxer )
|
||||
if(stream_read(demuxer->stream,(char*)&ns,sizeof(ns)) != sizeof(ns))
|
||||
return 0;
|
||||
|
||||
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 */
|
||||
|
@ -71,6 +71,34 @@ typedef struct __attribute__((packed)) rtframeheader
|
||||
// R: do not use here! (fixed 'RTjjjjjjjjjjjjjj')
|
||||
} rtframeheader;
|
||||
|
||||
/* for MythTV */
|
||||
typedef struct __attribute__((packed)) 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;
|
||||
|
||||
#define FRAMEHEADERSIZE sizeof(rtframeheader)
|
||||
#define FILEHEADERSIZE sizeof(rtfileheader)
|
||||
|
||||
@ -108,4 +136,21 @@ typedef struct audbuffertype
|
||||
(h)->timecode = le2me_32((h)->timecode); \
|
||||
(h)->packetlength = le2me_32((h)->packetlength); \
|
||||
}
|
||||
#define le2me_extendeddata(h) { \
|
||||
(h)->version = le2me_32((h)->version); \
|
||||
(h)->video_fourcc = le2me_32((h)->video_fourcc); \
|
||||
(h)->audio_fourcc = le2me_32((h)->audio_fourcc); \
|
||||
(h)->audio_sample_rate = le2me_32((h)->audio_sample_rate); \
|
||||
(h)->audio_bits_per_sample = le2me_32((h)->audio_bits_per_sample);\
|
||||
(h)->audio_channels = le2me_32((h)->audio_channels); \
|
||||
(h)->audio_compression_ratio = le2me_32((h)->audio_compression_ratio);\
|
||||
(h)->audio_quality = le2me_32((h)->audio_quality); \
|
||||
(h)->rtjpeg_quality = le2me_32((h)->rtjpeg_quality); \
|
||||
(h)->rtjpeg_luma_filter = le2me_32((h)->rtjpeg_luma_filter); \
|
||||
(h)->rtjpeg_chroma_filter = le2me_32((h)->rtjpeg_chroma_filter);\
|
||||
(h)->lavc_bitrate = le2me_32((h)->lavc_bitrate); \
|
||||
(h)->lavc_qmin = le2me_32((h)->lavc_qmin); \
|
||||
(h)->lavc_qmax = le2me_32((h)->lavc_qmax); \
|
||||
(h)->lavc_maxqdiff = le2me_32((h)->lavc_maxqdiff); \
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user