From a09dc00fdecda4cfde45308a607e1b9fd9c996ce Mon Sep 17 00:00:00 2001
From: Richard <peper03@yahoo.com>
Date: Wed, 29 May 2013 23:28:46 +0200
Subject: [PATCH 1/2] Fix filtering, sorting and selection of DVD audio
streams when the mapping 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.
---
mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c | 25 ++------
mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp | 42 ++++++++++----
mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp | 66 +++++++++++++++++-----
mythtv/libs/libmythtv/DVD/dvdringbuffer.h | 8 +--
mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp | 6 +-
mythtv/libs/libmythtv/avformatdecoder.cpp | 23 ++++----
6 files changed, 110 insertions(+), 60 deletions(-)
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c b/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c
index f531ade..2f1d1c6 100644
a
|
b
|
int vm_get_current_title_part(vm_t *vm, int *title_result, int *part_result) { |
729 | 729 | */ |
730 | 730 | int vm_get_audio_stream(vm_t *vm, int audioN) { |
731 | 731 | int streamN = -1; |
732 | | const uint AC3_OFFSET = 0x80; |
733 | | const uint DTS_OFFSET = 0x88; |
734 | | const uint LPCM_OFFSET = 0xA0; |
735 | | const uint MP2_OFFSET = 0xC0; |
736 | | |
737 | | int stream_id = audioN; |
738 | | if (stream_id >= MP2_OFFSET) { |
739 | | stream_id -= MP2_OFFSET; |
740 | | } else if (stream_id >= LPCM_OFFSET) { |
741 | | stream_id -= LPCM_OFFSET; |
742 | | } else if (stream_id >= DTS_OFFSET) { |
743 | | stream_id -= DTS_OFFSET; |
744 | | } else if (stream_id >= AC3_OFFSET) { |
745 | | stream_id -= AC3_OFFSET; |
746 | | } |
747 | 732 | |
748 | 733 | if((vm->state).domain != VTS_DOMAIN) |
749 | | stream_id = 0; |
| 734 | audioN = 0; |
750 | 735 | |
751 | | if(stream_id < 8) { |
| 736 | if(audioN < 8) { |
752 | 737 | /* Is there any control info for this logical stream */ |
753 | | if((vm->state).pgc->audio_control[stream_id] & (1<<15)) { |
754 | | streamN = ((vm->state).pgc->audio_control[stream_id] >> 8) & 0x07; |
| 738 | if((vm->state).pgc->audio_control[audioN] & (1<<15)) { |
| 739 | streamN = ((vm->state).pgc->audio_control[audioN] >> 8) & 0x07; |
755 | 740 | } |
756 | 741 | } |
757 | 742 | |
758 | 743 | if((vm->state).domain != VTS_DOMAIN && streamN == -1) |
759 | 744 | streamN = 0; |
760 | 745 | |
| 746 | /* FIXME: Should also check in vtsi/vmgi status what kind of stream |
| 747 | * it is (ac3/lpcm/dts/sdds...) to find the right (sub)stream id */ |
761 | 748 | return streamN; |
762 | 749 | } |
763 | 750 | |
diff --git a/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp b/mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
index ce7731b..1abf566 100644
a
|
b
|
void AvFormatDecoderDVD::PostProcessTracks(void) |
85 | 85 | { |
86 | 86 | stable_sort(tracks[kTrackTypeAudio].begin(), |
87 | 87 | tracks[kTrackTypeAudio].end()); |
88 | | sinfo_vec_t::iterator it = tracks[kTrackTypeAudio].begin(); |
89 | | for (; it != tracks[kTrackTypeAudio].end(); ++it) |
| 88 | |
| 89 | int trackNo = -1; |
| 90 | int dvdTrack = ringBuffer->DVD()->GetTrack(kTrackTypeAudio); |
| 91 | |
| 92 | for (uint i = 0; i < GetTrackCount(kTrackTypeAudio); i++) |
90 | 93 | { |
91 | 94 | LOG(VB_PLAYBACK, LOG_INFO, LOC + |
92 | | QString("DVD Audio Track Map Stream id #%1, MPEG stream %2") |
93 | | .arg(it->stream_id) |
94 | | .arg(ic->streams[it->av_stream_index]->id)); |
| 95 | QString("DVD Audio Track Map Stream id #%1, av_stream_idx %2, MPEG stream 0x%3, lang %4") |
| 96 | .arg(tracks[kTrackTypeAudio][i].stream_id) |
| 97 | .arg(tracks[kTrackTypeAudio][i].av_stream_index) |
| 98 | .arg(ic->streams[tracks[kTrackTypeAudio][i].av_stream_index]->id,0,16) |
| 99 | .arg(iso639_key_toName(tracks[kTrackTypeAudio][i].language))); |
| 100 | |
| 101 | // Find the audio track in our list that maps to the |
| 102 | // selected track in the ringbuffer (the ringbuffer's |
| 103 | // list should be in the same order but can have gaps, |
| 104 | // so we look for the track with the same index) |
| 105 | if (tracks[kTrackTypeAudio][i].stream_id == dvdTrack) |
| 106 | trackNo = i; |
| 107 | } |
| 108 | |
| 109 | if (trackNo < 0 && GetTrackCount(kTrackTypeAudio) > 0) |
| 110 | { |
| 111 | // Take the first track |
| 112 | trackNo = 0; |
95 | 113 | } |
96 | | int trackNo = ringBuffer->DVD()->GetTrack(kTrackTypeAudio); |
97 | | if (trackNo >= (int)GetTrackCount(kTrackTypeAudio)) |
98 | | trackNo = GetTrackCount(kTrackTypeAudio) - 1; |
99 | | SetTrack(kTrackTypeAudio, trackNo); |
| 114 | |
| 115 | if (trackNo >= 0) |
| 116 | SetTrack(kTrackTypeAudio, trackNo); |
100 | 117 | } |
101 | 118 | |
102 | 119 | if (tracks[kTrackTypeSubtitle].size() > 0) |
… |
… |
AudioTrackType AvFormatDecoderDVD::GetAudioTrackType(uint stream_index) |
220 | 237 | int type = 0; |
221 | 238 | |
222 | 239 | if (ringBuffer && ringBuffer->DVD()) |
223 | | type = ringBuffer->DVD()->GetAudioTrackType(stream_index); |
224 | | |
| 240 | { |
| 241 | int logical_idx = ringBuffer->DVD()->GetAudioTrackNum(ic->streams[stream_index]->id); |
| 242 | type = ringBuffer->DVD()->GetAudioTrackType(logical_idx); |
| 243 | } |
| 244 | |
225 | 245 | if (type > 0 && type < 5) // These are the only types defined in unofficial documentation |
226 | 246 | { |
227 | 247 | AudioTrackType ret = kAudioTypeNormal; |
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp b/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
index 1b5cfa4..361e883 100644
a
|
b
|
int DVDRingBuffer::safe_read(void *data, uint sz) |
709 | 709 | // the audio stream changed |
710 | 710 | case DVDNAV_AUDIO_STREAM_CHANGE: |
711 | 711 | { |
| 712 | // get event details |
| 713 | dvdnav_audio_stream_change_event_t* audio = |
| 714 | (dvdnav_audio_stream_change_event_t*)(blockBuf); |
| 715 | |
712 | 716 | // retrieve the new track |
713 | | int new_track = dvdnav_get_active_audio_stream(m_dvdnav); |
| 717 | int new_track = GetAudioTrackNum(audio->physical); |
714 | 718 | |
715 | 719 | // debug |
716 | 720 | LOG(VB_PLAYBACK, LOG_DEBUG, LOC + |
717 | | QString("DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2") |
718 | | .arg(new_track).arg(m_curAudioTrack)); |
| 721 | QString("DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2, physical %3, logical %4") |
| 722 | .arg(m_curAudioTrack).arg(new_track) |
| 723 | .arg(audio->physical).arg(audio->logical)); |
719 | 724 | |
720 | 725 | // tell the decoder to reset the audio streams if necessary |
721 | 726 | if (new_track != m_curAudioTrack) |
… |
… |
int DVDRingBuffer::NumMenuButtons(void) const |
1584 | 1589 | |
1585 | 1590 | /** \brief get the audio language from the dvd |
1586 | 1591 | */ |
1587 | | uint DVDRingBuffer::GetAudioLanguage(int id) |
| 1592 | uint DVDRingBuffer::GetAudioLanguage(int idx) |
1588 | 1593 | { |
1589 | | uint16_t lang = dvdnav_audio_stream_to_lang(m_dvdnav, id); |
| 1594 | int physicalStreamId = dvdnav_get_audio_logical_stream(m_dvdnav, idx); |
| 1595 | uint16_t lang = dvdnav_audio_stream_to_lang(m_dvdnav, physicalStreamId); |
1590 | 1596 | LOG(VB_PLAYBACK, LOG_INFO, LOC + |
1591 | | QString("StreamID: %1; lang: %2").arg(id).arg(lang)); |
| 1597 | QString("StreamID: %1; lang: %2").arg(idx).arg(lang)); |
1592 | 1598 | return ConvertLangCode(lang); |
1593 | 1599 | } |
1594 | 1600 | |
1595 | | /** \brief get real dvd track audio number |
| 1601 | /** \brief get the logical track index (into PGC_AST_CTL) of |
| 1602 | * the element that maps the given physical stream id. |
1596 | 1603 | * \param key stream_id |
1597 | 1604 | */ |
1598 | 1605 | int DVDRingBuffer::GetAudioTrackNum(uint stream_id) |
1599 | 1606 | { |
1600 | | return dvdnav_get_audio_logical_stream(m_dvdnav, stream_id); |
| 1607 | const uint AC3_OFFSET = 0x0080; |
| 1608 | const uint DTS_OFFSET = 0x0088; |
| 1609 | const uint LPCM_OFFSET = 0x00A0; |
| 1610 | const uint MP2_OFFSET = 0x01C0; |
| 1611 | |
| 1612 | int logical = -1; |
| 1613 | |
| 1614 | if (stream_id >= MP2_OFFSET) { |
| 1615 | stream_id -= MP2_OFFSET; |
| 1616 | } else if (stream_id >= LPCM_OFFSET) { |
| 1617 | stream_id -= LPCM_OFFSET; |
| 1618 | } else if (stream_id >= DTS_OFFSET) { |
| 1619 | stream_id -= DTS_OFFSET; |
| 1620 | } else if (stream_id >= AC3_OFFSET) { |
| 1621 | stream_id -= AC3_OFFSET; |
| 1622 | } |
| 1623 | |
| 1624 | for (int i = 0; i < 8; i++) |
| 1625 | { |
| 1626 | // Get the physical stream number at the given index |
| 1627 | // of the logical mapping table (function name is wrong!) |
| 1628 | int phys = dvdnav_get_audio_logical_stream(m_dvdnav, i); |
| 1629 | |
| 1630 | if ((uint)phys == stream_id) |
| 1631 | { |
| 1632 | logical = i; |
| 1633 | break; |
| 1634 | } |
| 1635 | } |
| 1636 | |
| 1637 | return logical; |
1601 | 1638 | } |
1602 | 1639 | |
1603 | | int DVDRingBuffer::GetAudioTrackType(uint stream_id) |
| 1640 | int DVDRingBuffer::GetAudioTrackType(uint idx) |
1604 | 1641 | { |
1605 | 1642 | int ret = -1; |
1606 | 1643 | audio_attr_t attributes; |
1607 | | int logicalStreamId = dvdnav_get_audio_logical_stream(m_dvdnav, stream_id); |
1608 | | if (dvdnav_get_audio_attr(m_dvdnav, logicalStreamId, &attributes) >= 1) |
| 1644 | int physicalStreamId = dvdnav_get_audio_logical_stream(m_dvdnav, idx); |
| 1645 | if (dvdnav_get_audio_attr(m_dvdnav, physicalStreamId, &attributes) >= 1) |
1609 | 1646 | { |
1610 | 1647 | LOG(VB_AUDIO, LOG_INFO, QString("DVD Audio Track #%1 Language " |
1611 | 1648 | "Extension Code - %2") |
1612 | | .arg(stream_id) |
| 1649 | .arg(idx) |
1613 | 1650 | .arg(attributes.code_extension)); |
1614 | 1651 | ret = attributes.code_extension; |
1615 | 1652 | } |
… |
… |
int DVDRingBuffer::GetTrack(uint type) |
1702 | 1739 | return 0; |
1703 | 1740 | } |
1704 | 1741 | |
1705 | | uint8_t DVDRingBuffer::GetNumAudioChannels(int id) |
| 1742 | uint8_t DVDRingBuffer::GetNumAudioChannels(int idx) |
1706 | 1743 | { |
1707 | | unsigned char channels = dvdnav_audio_stream_channels(m_dvdnav, id); |
| 1744 | int physical = dvdnav_get_audio_logical_stream(m_dvdnav, idx); |
| 1745 | unsigned char channels = dvdnav_audio_stream_channels(m_dvdnav, physical); |
1708 | 1746 | if (channels == 0xff) |
1709 | 1747 | return 0; |
1710 | 1748 | return (uint8_t)channels; |
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.h b/mythtv/libs/libmythtv/DVD/dvdringbuffer.h
index 0e3247f..05809b7 100644
a
|
b
|
class MTV_PUBLIC DVDRingBuffer : public RingBuffer |
93 | 93 | bool DecodeSubtitles(AVSubtitle * sub, int * gotSubtitles, |
94 | 94 | const uint8_t * buf, int buf_size, uint32_t startTime); |
95 | 95 | |
96 | | uint GetAudioLanguage(int id); |
97 | | int GetAudioTrackNum(uint key); |
98 | | int GetAudioTrackType(uint stream_id); |
| 96 | uint GetAudioLanguage(int idx); |
| 97 | int GetAudioTrackNum(uint stream_id); |
| 98 | int GetAudioTrackType(uint idx); |
99 | 99 | |
100 | 100 | bool GetNameAndSerialNum(QString& _name, QString& _serialnum); |
101 | 101 | double GetFrameRate(void); |
… |
… |
class MTV_PUBLIC DVDRingBuffer : public RingBuffer |
132 | 132 | uint TitleTimeLeft(void); |
133 | 133 | void SetTrack(uint type, int trackNo); |
134 | 134 | int GetTrack(uint type); |
135 | | uint8_t GetNumAudioChannels(int id); |
| 135 | uint8_t GetNumAudioChannels(int idx); |
136 | 136 | void SetDVDSpeed(void); |
137 | 137 | void SetDVDSpeed(int speed); |
138 | 138 | bool SwitchAngle(uint angle); |
diff --git a/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp b/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp
index 11a0add..2bfbd11 100644
a
|
b
|
void MythDVDPlayer::SeekForScreenGrab(uint64_t &number, uint64_t frameNum, |
446 | 446 | int MythDVDPlayer::SetTrack(uint type, int trackNo) |
447 | 447 | { |
448 | 448 | if (kTrackTypeAudio == type) |
449 | | player_ctx->buffer->DVD()->SetTrack(type, trackNo); |
| 449 | { |
| 450 | StreamInfo stream = decoder->GetTrackInfo(type, trackNo); |
| 451 | player_ctx->buffer->DVD()->SetTrack(type, stream.stream_id); |
| 452 | } |
| 453 | |
450 | 454 | return MythPlayer::SetTrack(type, trackNo); |
451 | 455 | } |
452 | 456 | |
diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
index 6acdba7..2d71ec9 100644
a
|
b
|
int AvFormatDecoder::ScanStreams(bool novideo) |
2033 | 2033 | int logical_stream_id; |
2034 | 2034 | if (ringBuffer && ringBuffer->IsDVD()) |
2035 | 2035 | { |
2036 | | logical_stream_id = |
2037 | | ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id); |
| 2036 | logical_stream_id = ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id); |
| 2037 | channels = ringBuffer->DVD()->GetNumAudioChannels(logical_stream_id); |
2038 | 2038 | } |
2039 | 2039 | else |
2040 | 2040 | logical_stream_id = ic->streams[i]->id; |
2041 | 2041 | |
| 2042 | if (logical_stream_id == -1) |
| 2043 | { |
| 2044 | // This stream isn't mapped, so skip it |
| 2045 | continue; |
| 2046 | } |
| 2047 | |
2042 | 2048 | tracks[kTrackTypeAudio].push_back( |
2043 | 2049 | StreamInfo(i, lang, lang_indx, logical_stream_id, channels, |
2044 | 2050 | false, false, false, type)); |
2045 | 2051 | } |
2046 | 2052 | |
2047 | 2053 | LOG(VB_AUDIO, LOG_INFO, LOC + |
2048 | | QString("Audio Track #%1, of type (%2) is A/V stream #%3 " |
2049 | | "and has %4 channels in the %5 language(%6).") |
| 2054 | QString("Audio Track #%1, of type (%2) is A/V stream #%3 (id=0x%4) " |
| 2055 | "and has %5 channels in the %6 language(%7).") |
2050 | 2056 | .arg(tracks[kTrackTypeAudio].size()).arg(toString(type)) |
2051 | | .arg(i).arg(enc->channels) |
| 2057 | .arg(i).arg(ic->streams[i]->id,0,16).arg(enc->channels) |
2052 | 2058 | .arg(iso639_key_toName(lang)).arg(lang)); |
2053 | 2059 | } |
2054 | 2060 | } |
… |
… |
QString AvFormatDecoder::GetTrackDesc(uint type, uint trackNo) const |
3826 | 3832 | QString forcedString = forced ? QObject::tr(" (forced)") : ""; |
3827 | 3833 | if (kTrackTypeAudio == type) |
3828 | 3834 | { |
3829 | | if (ringBuffer->IsDVD()) |
3830 | | lang_key = ringBuffer->DVD()->GetAudioLanguage(trackNo); |
3831 | | |
3832 | 3835 | QString msg = iso639_key_toName(lang_key); |
3833 | 3836 | |
3834 | 3837 | switch (tracks[type][trackNo].audio_type) |
… |
… |
QString AvFormatDecoder::GetTrackDesc(uint type, uint trackNo) const |
3846 | 3849 | msg += QString(" %1").arg(s->codec->codec->name).toUpper(); |
3847 | 3850 | |
3848 | 3851 | int channels = 0; |
3849 | | if (ringBuffer->IsDVD()) |
3850 | | channels = ringBuffer->DVD()->GetNumAudioChannels(trackNo); |
3851 | | else if (s->codec->channels) |
| 3852 | if (ringBuffer->IsDVD() || s->codec->channels) |
3852 | 3853 | channels = tracks[kTrackTypeAudio][trackNo].orig_num_channels; |
3853 | 3854 | |
3854 | 3855 | if (channels == 0) |