Skip to content

Commit

Permalink
Fix filtering, sorting and selection of DVD audio streams when the ma…
Browse files Browse the repository at this point in the history
…pping in a PGC is not 1:1, which was broken due to different functions/methods providing or requiring a physical stream ID, logical track number or logical index, with little consistency between them, and 'disabled' streams not being filtered out.

DVDRingBuffer now returns and expects an index into the PGC_AST_CTL table for all audio stream methods, with GetAudioTrackNum now providing a mapping from physical stream ID to logical index.

The MythTV-specific change to vm_get_audio_stream in vm.c has been reverted as it didn't work as intended and the intended functionality is now in DVDRingBuffer::GetAudioTrackNum.

Fixes #11376
  • Loading branch information
Richard committed Jun 22, 2013
1 parent e5e9cc8 commit 8bcef59
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 61 deletions.
25 changes: 6 additions & 19 deletions mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c
Expand Up @@ -729,35 +729,22 @@ int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) {
*/
int vm_get_audio_stream(vm_t *vm, int audioN) {
int streamN = -1;
const uint AC3_OFFSET = 0x80;
const uint DTS_OFFSET = 0x88;
const uint LPCM_OFFSET = 0xA0;
const uint MP2_OFFSET = 0xC0;

int stream_id = audioN;
if (stream_id >= MP2_OFFSET) {
stream_id -= MP2_OFFSET;
} else if (stream_id >= LPCM_OFFSET) {
stream_id -= LPCM_OFFSET;
} else if (stream_id >= DTS_OFFSET) {
stream_id -= DTS_OFFSET;
} else if (stream_id >= AC3_OFFSET) {
stream_id -= AC3_OFFSET;
}

if((vm->state).domain != VTS_DOMAIN)
stream_id = 0;
audioN = 0;

if(stream_id < 8) {
if(audioN < 8) {
/* Is there any control info for this logical stream */
if((vm->state).pgc->audio_control[stream_id] & (1<<15)) {
streamN = ((vm->state).pgc->audio_control[stream_id] >> 8) & 0x07;
if((vm->state).pgc->audio_control[audioN] & (1<<15)) {
streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07;
}
}

if((vm->state).domain != VTS_DOMAIN && streamN == -1)
streamN = 0;

/* FIXME: Should also check in vtsi/vmgi status what kind of stream
* it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */
return streamN;
}

Expand Down
42 changes: 31 additions & 11 deletions mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
Expand Up @@ -85,18 +85,35 @@ void AvFormatDecoderDVD::PostProcessTracks(void)
{
stable_sort(tracks[kTrackTypeAudio].begin(),
tracks[kTrackTypeAudio].end());
sinfo_vec_t::iterator it = tracks[kTrackTypeAudio].begin();
for (; it != tracks[kTrackTypeAudio].end(); ++it)

int trackNo = -1;
int dvdTrack = ringBuffer->DVD()->GetTrack(kTrackTypeAudio);

for (uint i = 0; i < GetTrackCount(kTrackTypeAudio); i++)
{
LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("DVD Audio Track Map Stream id #%1, MPEG stream %2")
.arg(it->stream_id)
.arg(ic->streams[it->av_stream_index]->id));
QString("DVD Audio Track Map Stream id #%1, av_stream_idx %2, MPEG stream 0x%3, lang %4")
.arg(tracks[kTrackTypeAudio][i].stream_id)
.arg(tracks[kTrackTypeAudio][i].av_stream_index)
.arg(ic->streams[tracks[kTrackTypeAudio][i].av_stream_index]->id,0,16)
.arg(iso639_key_toName(tracks[kTrackTypeAudio][i].language)));

// Find the audio track in our list that maps to the
// selected track in the ringbuffer (the ringbuffer's
// list should be in the same order but can have gaps,
// so we look for the track with the same index)
if (tracks[kTrackTypeAudio][i].stream_id == dvdTrack)
trackNo = i;
}

if (trackNo < 0 && GetTrackCount(kTrackTypeAudio) > 0)
{
// Take the first track
trackNo = 0;
}
int trackNo = ringBuffer->DVD()->GetTrack(kTrackTypeAudio);
if (trackNo >= (int)GetTrackCount(kTrackTypeAudio))
trackNo = GetTrackCount(kTrackTypeAudio) - 1;
SetTrack(kTrackTypeAudio, trackNo);

if (trackNo >= 0)
SetTrack(kTrackTypeAudio, trackNo);
}

if (tracks[kTrackTypeSubtitle].size() > 0)
Expand Down Expand Up @@ -290,8 +307,11 @@ AudioTrackType AvFormatDecoderDVD::GetAudioTrackType(uint stream_index)
int type = 0;

if (ringBuffer && ringBuffer->DVD())
type = ringBuffer->DVD()->GetAudioTrackType(stream_index);

{
int logical_idx = ringBuffer->DVD()->GetAudioTrackNum(ic->streams[stream_index]->id);
type = ringBuffer->DVD()->GetAudioTrackType(logical_idx);
}

if (type > 0 && type < 5) // These are the only types defined in unofficial documentation
{
AudioTrackType ret = kAudioTypeNormal;
Expand Down
69 changes: 54 additions & 15 deletions mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
Expand Up @@ -709,13 +709,18 @@ int DVDRingBuffer::safe_read(void *data, uint sz)
// the audio stream changed
case DVDNAV_AUDIO_STREAM_CHANGE:
{
// get event details
dvdnav_audio_stream_change_event_t* audio =
(dvdnav_audio_stream_change_event_t*)(blockBuf);

// retrieve the new track
int new_track = dvdnav_get_active_audio_stream(m_dvdnav);
int new_track = GetAudioTrackNum(audio->physical);

// debug
LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
QString("DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2")
.arg(new_track).arg(m_curAudioTrack));
QString("DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2, physical %3, logical %4")
.arg(m_curAudioTrack).arg(new_track)
.arg(audio->physical).arg(audio->logical));

// tell the decoder to reset the audio streams if necessary
if (new_track != m_curAudioTrack)
Expand Down Expand Up @@ -1585,36 +1590,69 @@ int DVDRingBuffer::NumMenuButtons(void) const

/** \brief get the audio language from the dvd
*/
uint DVDRingBuffer::GetAudioLanguage(int id)
uint DVDRingBuffer::GetAudioLanguage(int idx)
{
uint16_t lang = dvdnav_audio_stream_to_lang(m_dvdnav, id);
int physicalStreamId = dvdnav_get_audio_logical_stream(m_dvdnav, idx);
uint16_t lang = dvdnav_audio_stream_to_lang(m_dvdnav, physicalStreamId);
LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("StreamID: %1; lang: %2").arg(id).arg(lang));
QString("StreamID: %1; lang: %2").arg(idx).arg(lang));
return ConvertLangCode(lang);
}

/** \brief get real dvd track audio number
/** \brief get the logical track index (into PGC_AST_CTL) of
* the element that maps the given physical stream id.
* \param key stream_id
*/
int DVDRingBuffer::GetAudioTrackNum(uint stream_id)
{
return dvdnav_get_audio_logical_stream(m_dvdnav, stream_id);
const uint AC3_OFFSET = 0x0080;
const uint DTS_OFFSET = 0x0088;
const uint LPCM_OFFSET = 0x00A0;
const uint MP2_OFFSET = 0x01C0;

int logical = -1;

if (stream_id >= MP2_OFFSET) {
stream_id -= MP2_OFFSET;
} else if (stream_id >= LPCM_OFFSET) {
stream_id -= LPCM_OFFSET;
} else if (stream_id >= DTS_OFFSET) {
stream_id -= DTS_OFFSET;
} else if (stream_id >= AC3_OFFSET) {
stream_id -= AC3_OFFSET;
}

for (int i = 0; i < 8; i++)
{
// Get the physical stream number at the given index
// of the logical mapping table (function name is wrong!)
int phys = dvdnav_get_audio_logical_stream(m_dvdnav, i);

if ((uint)phys == stream_id)
{
logical = i;
break;
}
}

return logical;
}

int DVDRingBuffer::GetAudioTrackType(uint stream_id)
int DVDRingBuffer::GetAudioTrackType(uint idx)
{
int ret = -1;
audio_attr_t attributes;
int logicalStreamId = dvdnav_get_audio_logical_stream(m_dvdnav, stream_id);

int physicalStreamId = dvdnav_get_audio_logical_stream(m_dvdnav, idx);

if (logicalStreamId < 0)
if (physicalStreamId < 0)
return -1;

if (dvdnav_get_audio_attr(m_dvdnav, logicalStreamId, &attributes) >= 1)
if (dvdnav_get_audio_attr(m_dvdnav, physicalStreamId, &attributes) >= 1)
{
LOG(VB_AUDIO, LOG_INFO, QString("DVD Audio Track #%1 Language "
"Extension Code - %2")
.arg(stream_id)
.arg(idx)
.arg(attributes.code_extension));
ret = attributes.code_extension;
}
Expand Down Expand Up @@ -1715,9 +1753,10 @@ int DVDRingBuffer::GetTrack(uint type)
return 0;
}

uint8_t DVDRingBuffer::GetNumAudioChannels(int id)
uint8_t DVDRingBuffer::GetNumAudioChannels(int idx)
{
unsigned char channels = dvdnav_audio_stream_channels(m_dvdnav, id);
int physical = dvdnav_get_audio_logical_stream(m_dvdnav, idx);
unsigned char channels = dvdnav_audio_stream_channels(m_dvdnav, physical);
if (channels == 0xff)
return 0;
return (uint8_t)channels;
Expand Down
8 changes: 4 additions & 4 deletions mythtv/libs/libmythtv/DVD/dvdringbuffer.h
Expand Up @@ -94,9 +94,9 @@ class MTV_PUBLIC DVDRingBuffer : public RingBuffer
bool DecodeSubtitles(AVSubtitle * sub, int * gotSubtitles,
const uint8_t * buf, int buf_size, uint32_t startTime);

uint GetAudioLanguage(int id);
int GetAudioTrackNum(uint key);
int GetAudioTrackType(uint stream_id);
uint GetAudioLanguage(int idx);
int GetAudioTrackNum(uint stream_id);
int GetAudioTrackType(uint idx);

bool GetNameAndSerialNum(QString& _name, QString& _serialnum);
double GetFrameRate(void);
Expand Down Expand Up @@ -133,7 +133,7 @@ class MTV_PUBLIC DVDRingBuffer : public RingBuffer
uint TitleTimeLeft(void);
void SetTrack(uint type, int trackNo);
int GetTrack(uint type);
uint8_t GetNumAudioChannels(int id);
uint8_t GetNumAudioChannels(int idx);
void SetDVDSpeed(void);
void SetDVDSpeed(int speed);
bool SwitchAngle(uint angle);
Expand Down
6 changes: 5 additions & 1 deletion mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp
Expand Up @@ -454,7 +454,11 @@ void MythDVDPlayer::SeekForScreenGrab(uint64_t &number, uint64_t frameNum,
int MythDVDPlayer::SetTrack(uint type, int trackNo)
{
if (kTrackTypeAudio == type)
player_ctx->buffer->DVD()->SetTrack(type, trackNo);
{
StreamInfo stream = decoder->GetTrackInfo(type, trackNo);
player_ctx->buffer->DVD()->SetTrack(type, stream.stream_id);
}

return MythPlayer::SetTrack(type, trackNo);
}

Expand Down
23 changes: 12 additions & 11 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Expand Up @@ -2034,22 +2034,28 @@ int AvFormatDecoder::ScanStreams(bool novideo)
int logical_stream_id;
if (ringBuffer && ringBuffer->IsDVD())
{
logical_stream_id =
ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id);
logical_stream_id = ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id);
channels = ringBuffer->DVD()->GetNumAudioChannels(logical_stream_id);
}
else
logical_stream_id = ic->streams[i]->id;

if (logical_stream_id == -1)
{
// This stream isn't mapped, so skip it
continue;
}

tracks[kTrackTypeAudio].push_back(
StreamInfo(i, lang, lang_indx, logical_stream_id, channels,
false, false, false, type));
}

LOG(VB_AUDIO, LOG_INFO, LOC +
QString("Audio Track #%1, of type (%2) is A/V stream #%3 "
"and has %4 channels in the %5 language(%6).")
QString("Audio Track #%1, of type (%2) is A/V stream #%3 (id=0x%4) "
"and has %5 channels in the %6 language(%7).")
.arg(tracks[kTrackTypeAudio].size()).arg(toString(type))
.arg(i).arg(enc->channels)
.arg(i).arg(ic->streams[i]->id,0,16).arg(enc->channels)
.arg(iso639_key_toName(lang)).arg(lang));
}
}
Expand Down Expand Up @@ -3817,9 +3823,6 @@ QString AvFormatDecoder::GetTrackDesc(uint type, uint trackNo) const
QString forcedString = forced ? QObject::tr(" (forced)") : "";
if (kTrackTypeAudio == type)
{
if (ringBuffer->IsDVD())
lang_key = ringBuffer->DVD()->GetAudioLanguage(trackNo);

QString msg = iso639_key_toName(lang_key);

switch (tracks[type][trackNo].audio_type)
Expand All @@ -3837,9 +3840,7 @@ QString AvFormatDecoder::GetTrackDesc(uint type, uint trackNo) const
msg += QString(" %1").arg(s->codec->codec->name).toUpper();

int channels = 0;
if (ringBuffer->IsDVD())
channels = ringBuffer->DVD()->GetNumAudioChannels(trackNo);
else if (s->codec->channels)
if (ringBuffer->IsDVD() || s->codec->channels)
channels = tracks[kTrackTypeAudio][trackNo].orig_num_channels;

if (channels == 0)
Expand Down

0 comments on commit 8bcef59

Please sign in to comment.