Skip to content

Commit

Permalink
Improve code for DVB VBI data
Browse files Browse the repository at this point in the history
libavcodec/codec_desc.c: move to correct location and correct description
libavcodec/codec_id.h: move to correct location in data codecs
libavformat/mpegts-mythtv.c: reuse teletext_descriptor code for VBI_teletext_descriptor

libmythbase/iso639.h: add used include
libmythbase/stringutil.h: add new funtion split_sv()
libmythtv/decoders/avformatdecoder.cpp:
AvFormatDecoder::ScanTeletextCaptions() was specific to AV_CODEC_ID_DVB_TELETEXT,
looking only at the teletext_descriptor in the PMT.

ScanTeletextCaptions() no longer uses the MythTV exported PMT, using what FFmpeg
already exported when it parsed PMTs.  Both AV_CODEC_ID_DVB_TELETEXT and
AV_CODEC_ID_DVB_VBI (if there is EBU teletext data in the VBI data) now add to
the tracks list and multiple streams are now supported.
  • Loading branch information
ulmus-scott committed Nov 15, 2024
1 parent ea21a58 commit 07c5b72
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 61 deletions.
12 changes: 6 additions & 6 deletions mythtv/external/FFmpeg/libavcodec/codec_desc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3622,12 +3622,6 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "mpeg2vbi",
.long_name = NULL_IF_CONFIG_SMALL("ivtv proprietary embedded VBI captions"),
},
{
.id = AV_CODEC_ID_DVB_VBI,
.type = AVMEDIA_TYPE_DATA,
.name = "dvb_vbi",
.long_name = NULL_IF_CONFIG_SMALL("dvb teletext"),
},
{
.id = AV_CODEC_ID_DSMCC_B,
.type = AVMEDIA_TYPE_DATA,
Expand Down Expand Up @@ -3720,6 +3714,12 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "lcevc",
.long_name = NULL_IF_CONFIG_SMALL("LCEVC (Low Complexity Enhancement Video Coding) / MPEG-5 LCEVC / MPEG-5 part 2"),
},
{
.id = AV_CODEC_ID_DVB_VBI,
.type = AVMEDIA_TYPE_DATA,
.name = "dvb_vbi",
.long_name = NULL_IF_CONFIG_SMALL("DVB VBI data"),
},
{
.id = AV_CODEC_ID_MPEG2TS,
.type = AVMEDIA_TYPE_DATA,
Expand Down
2 changes: 1 addition & 1 deletion mythtv/external/FFmpeg/libavcodec/codec_id.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,6 @@ enum AVCodecID {
/* MythTV */
/* teletext codecs */
AV_CODEC_ID_MPEG2VBI,
AV_CODEC_ID_DVB_VBI,

/* DSMCC codec */
AV_CODEC_ID_DSMCC_B,
Expand All @@ -598,6 +597,7 @@ enum AVCodecID {
AV_CODEC_ID_BIN_DATA,
AV_CODEC_ID_SMPTE_2038,
AV_CODEC_ID_LCEVC,
AV_CODEC_ID_DVB_VBI,


AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
Expand Down
10 changes: 1 addition & 9 deletions mythtv/external/FFmpeg/libavformat/mpegts-mythtv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1917,6 +1917,7 @@ int ff_mythtv_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stre
}
}
break;
case VBI_TELETEXT_DESCRIPTOR:
case 0x56: /* DVB teletext descriptor */
{
uint8_t *extradata = NULL;
Expand Down Expand Up @@ -2070,15 +2071,6 @@ int ff_mythtv_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stre
sti->stream_identifier = 1 + get8(pp, desc_end);
st->component_tag = sti->stream_identifier - 1;
break;
case VBI_TELETEXT_DESCRIPTOR:
language[0] = get8(pp, desc_end);
language[1] = get8(pp, desc_end);
language[2] = get8(pp, desc_end);
language[3] = 0;

if (language[0])
av_dict_set(&st->metadata, "language", language, 0);
break;
case METADATA_DESCRIPTOR:
if (get16(pp, desc_end) == 0xFFFF)
*pp += 4;
Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythbase/iso639.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#ifndef ISO_639_2_H
#define ISO_639_2_H

#include <cctype>
#include <vector>

#include <QMap>
Expand Down
29 changes: 29 additions & 0 deletions mythtv/libs/libmythbase/stringutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include <format>
#endif

#include <string_view>
#include <vector>

#include <QByteArray>
#include <QString>

Expand Down Expand Up @@ -60,6 +63,32 @@ inline bool naturalSortCompare(const QString &a, const QString &b,
MBASE_PUBLIC QString formatKBytes(int64_t sizeKB, int prec=1);
MBASE_PUBLIC QString formatBytes(int64_t sizeB, int prec=1);

/**
Split a `std::string_view` into a `std::vector` of `std::string_view`s.
@param s String to split, may be empty.
@param delimiter String to determine where to split.
@return Will always have a size >= 1. Only valid as long as the data
referenced by s remains valid.
*/
inline std::vector<std::string_view> split_sv(const std::string_view s, const std::string_view delimiter)
{
// There are infinitely many empty strings at each position, avoid infinite loop
if (delimiter.empty())
return {s};
std::vector<std::string_view> tokens;
size_t last_pos = 0;
size_t pos = 0;
do
{
pos = s.find(delimiter, last_pos);
tokens.emplace_back(s.substr(last_pos, pos - last_pos));
last_pos = pos + delimiter.size();
}
while (pos != std::string_view::npos);
return tokens;
}

} // namespace StringUtil

#endif // STRINGUTIL_H_
87 changes: 42 additions & 45 deletions mythtv/libs/libmythtv/decoders/avformatdecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ enum V4L2_MPEG_LINE_TYPES : std::uint8_t {
#include "mythvideoprofile.h"
#include "remoteencoder.h"

using namespace std::string_view_literals;

#define LOC QString("AFD: ")

// Maximum number of sequential invalid data packet errors before we try
Expand Down Expand Up @@ -1738,57 +1740,51 @@ void AvFormatDecoder::ScanTeletextCaptions(int av_index)
if (!m_tracks[kTrackTypeTeletextCaptions].empty())
return;

MythAVBufferRef pmt_buffer {get_pmt_section_for_AVStream_index(m_ic, av_index)};
if (!pmt_buffer.has_buffer())
AVStream* st = m_ic->streams[av_index];
const AVDictionaryEntry* language_dictionary_entry =
av_dict_get(st->metadata, "language", nullptr, 0);

if (language_dictionary_entry == nullptr ||
language_dictionary_entry->value == nullptr ||
st->codecpar->extradata == nullptr
)
{
return;
}
const ProgramMapTable pmt(PSIPTable(pmt_buffer.data()));

for (uint i = 0; i < pmt.StreamCount(); i++)
{
if (pmt.StreamType(i) != StreamID::PrivData)
continue;

const desc_list_t desc_list = MPEGDescriptor::ParseOnlyInclude(
pmt.StreamInfo(i), pmt.StreamInfoLength(i),
DescriptorID::teletext);
std::vector<std::string_view> languages {StringUtil::split_sv(language_dictionary_entry->value, ","sv)};

for (const auto *desc : desc_list)
if (st->codecpar->extradata_size != static_cast<int>(languages.size() * 2))
{
return;
}
for (size_t i = 0; i < languages.size(); i++)
{
if (languages[i].size() != 3)
{
const TeletextDescriptor td(desc);
if (!td.IsValid())
continue;
for (uint k = 0; k < td.StreamCount(); k++)
{
int type = td.TeletextType(k);
int language = td.CanonicalLanguageKey(k);
uint magazine = td.TeletextMagazineNum(k);
if (magazine == 0)
magazine = 8;
uint pagenum = td.TeletextPageNum(k);
uint lang_idx = (magazine << 8) | pagenum;
StreamInfo si {av_index, 0, language, lang_idx};
if (type == 2 || type == 1)
{
TrackType track = (type == 2) ? kTrackTypeTeletextCaptions :
kTrackTypeTeletextMenu;
m_tracks[track].push_back(si);
LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("Teletext stream #%1 (%2) is in the %3 language"
" on page %4 %5.")
.arg(QString::number(k),
(type == 2) ? "Caption" : "Menu",
iso639_key_toName(language),
QString::number(magazine),
QString::number(pagenum)));
}
}
continue;
}
int language = iso639_str3_to_key(languages[i].data());
uint8_t teletext_type = st->codecpar->extradata[i * 2] >> 3;
uint8_t teletext_magazine_number = st->codecpar->extradata[i * 2] & 0x7;
if (teletext_magazine_number == 0)
teletext_magazine_number = 8;
uint8_t teletext_page_number = st->codecpar->extradata[i * 2 + 1];
if (teletext_type == 2 || teletext_type == 1)
{
TrackType track = (teletext_type == 2) ?
kTrackTypeTeletextCaptions :
kTrackTypeTeletextMenu;
m_tracks[track].emplace_back(av_index, 0, language,
(static_cast<unsigned>(teletext_magazine_number) << 8) | teletext_page_number);
LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("Teletext stream #%1 (%2) is in the %3 language on page %4 %5.")
.arg(QString::number(i),
(teletext_type == 2) ? "Caption" : "Menu",
iso639_key_toName(language),
QString::number(teletext_magazine_number),
QString::number(teletext_page_number)));
}

// Assume there is only one multiplexed teletext stream in PMT..
if (!m_tracks[kTrackTypeTeletextCaptions].empty())
break;
}
}

Expand Down Expand Up @@ -2241,7 +2237,8 @@ int AvFormatDecoder::ScanStreams(bool novideo)
}
case AVMEDIA_TYPE_DATA:
{
ScanTeletextCaptions(static_cast<int>(strm));
if (par->codec_id == AV_CODEC_ID_DVB_VBI)
ScanTeletextCaptions(static_cast<int>(strm));
m_bitrate += par->bit_rate;
LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("data codec (%1)")
.arg(AVMediaTypeToString(par->codec_type)));
Expand Down

0 comments on commit 07c5b72

Please sign in to comment.