Part of https://github.com/shaka-project/shaka-packager/issues/369 This adds read support for some MPEG-TS PMT elementary stream descriptors: - ISO639 Language Descriptor providing language code and audio type - Maximum Bitrate Descriptor providing peak stream bandwidth Those metadata are propagated to StreamInfo structures: - StreamInfo.language field - AudioStreamMetadata.max_bitrate field for audio streams - audio type is currently not propagated - corresponding field has to be added to AudioStreamMetadata Test vector file containing those descriptors is provided.
This commit is contained in:
parent
2ba67bc24c
commit
c09eb831b8
|
@ -60,6 +60,10 @@ class AudioStreamInfo : public StreamInfo {
|
||||||
sampling_frequency_ = sampling_frequency;
|
sampling_frequency_ = sampling_frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_max_bitrate(const uint32_t max_bitrate) {
|
||||||
|
max_bitrate_ = max_bitrate;
|
||||||
|
}
|
||||||
|
|
||||||
/// @param audio_object_type is only used by AAC Codec, ignored otherwise.
|
/// @param audio_object_type is only used by AAC Codec, ignored otherwise.
|
||||||
/// @return The codec string.
|
/// @return The codec string.
|
||||||
static std::string GetCodecString(Codec codec, uint8_t audio_object_type);
|
static std::string GetCodecString(Codec codec, uint8_t audio_object_type);
|
||||||
|
|
|
@ -33,6 +33,7 @@ add_library(mp2t STATIC
|
||||||
pes_packet_generator.h
|
pes_packet_generator.h
|
||||||
program_map_table_writer.cc
|
program_map_table_writer.cc
|
||||||
program_map_table_writer.h
|
program_map_table_writer.h
|
||||||
|
ts_audio_type.h
|
||||||
ts_muxer.cc
|
ts_muxer.cc
|
||||||
ts_muxer.h
|
ts_muxer.h
|
||||||
ts_packet.cc
|
ts_packet.cc
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <packager/media/formats/mp2t/es_parser_h264.h>
|
#include <packager/media/formats/mp2t/es_parser_h264.h>
|
||||||
#include <packager/media/formats/mp2t/es_parser_h265.h>
|
#include <packager/media/formats/mp2t/es_parser_h265.h>
|
||||||
#include <packager/media/formats/mp2t/mp2t_common.h>
|
#include <packager/media/formats/mp2t/mp2t_common.h>
|
||||||
|
#include <packager/media/formats/mp2t/ts_audio_type.h>
|
||||||
#include <packager/media/formats/mp2t/ts_packet.h>
|
#include <packager/media/formats/mp2t/ts_packet.h>
|
||||||
#include <packager/media/formats/mp2t/ts_section.h>
|
#include <packager/media/formats/mp2t/ts_section.h>
|
||||||
#include <packager/media/formats/mp2t/ts_section_pat.h>
|
#include <packager/media/formats/mp2t/ts_section_pat.h>
|
||||||
|
@ -274,7 +275,8 @@ void Mp2tMediaParser::RegisterPmt(int program_number, int pmt_pid) {
|
||||||
DVLOG(1) << "Create a new PMT parser";
|
DVLOG(1) << "Create a new PMT parser";
|
||||||
std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(std::bind(
|
std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(std::bind(
|
||||||
&Mp2tMediaParser::RegisterPes, this, pmt_pid, std::placeholders::_1,
|
&Mp2tMediaParser::RegisterPes, this, pmt_pid, std::placeholders::_1,
|
||||||
std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)));
|
std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
|
||||||
|
std::placeholders::_5, std::placeholders::_6, std::placeholders::_7)));
|
||||||
std::unique_ptr<PidState> pmt_pid_state(
|
std::unique_ptr<PidState> pmt_pid_state(
|
||||||
new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
|
new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
|
||||||
pmt_pid_state->Enable();
|
pmt_pid_state->Enable();
|
||||||
|
@ -284,13 +286,19 @@ void Mp2tMediaParser::RegisterPmt(int program_number, int pmt_pid) {
|
||||||
void Mp2tMediaParser::RegisterPes(int pmt_pid,
|
void Mp2tMediaParser::RegisterPes(int pmt_pid,
|
||||||
int pes_pid,
|
int pes_pid,
|
||||||
TsStreamType stream_type,
|
TsStreamType stream_type,
|
||||||
|
uint32_t max_bitrate,
|
||||||
|
const std::string& lang,
|
||||||
|
TsAudioType audio_type,
|
||||||
const uint8_t* descriptor,
|
const uint8_t* descriptor,
|
||||||
size_t descriptor_length) {
|
size_t descriptor_length) {
|
||||||
if (pids_.count(pes_pid) != 0)
|
if (pids_.count(pes_pid) != 0)
|
||||||
return;
|
return;
|
||||||
DVLOG(1) << "RegisterPes:"
|
DVLOG(1) << "RegisterPes:"
|
||||||
<< " pes_pid=" << pes_pid << " stream_type=" << std::hex
|
<< " pes_pid=" << pes_pid << " stream_type=" << std::hex
|
||||||
<< static_cast<int>(stream_type) << std::dec;
|
<< static_cast<int>(stream_type) << std::dec
|
||||||
|
<< "max_bitrate=" << max_bitrate << " lang=" << lang
|
||||||
|
<< "audio_type=" << std::hex << static_cast<int>(audio_type)
|
||||||
|
<< std::dec;
|
||||||
|
|
||||||
// Create a stream parser corresponding to the stream type.
|
// Create a stream parser corresponding to the stream type.
|
||||||
PidState::PidType pid_type = PidState::kPidVideoPes;
|
PidState::PidType pid_type = PidState::kPidVideoPes;
|
||||||
|
@ -340,6 +348,10 @@ void Mp2tMediaParser::RegisterPes(int pmt_pid,
|
||||||
new PidState(pes_pid, pid_type, std::move(pes_section_parser)));
|
new PidState(pes_pid, pid_type, std::move(pes_section_parser)));
|
||||||
pes_pid_state->Enable();
|
pes_pid_state->Enable();
|
||||||
pids_.emplace(pes_pid, std::move(pes_pid_state));
|
pids_.emplace(pes_pid, std::move(pes_pid_state));
|
||||||
|
|
||||||
|
// Store PES metadata.
|
||||||
|
pes_metadata_.insert(
|
||||||
|
std::make_pair(pes_pid, PesMetadata{max_bitrate, lang, audio_type}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp2tMediaParser::OnNewStreamInfo(
|
void Mp2tMediaParser::OnNewStreamInfo(
|
||||||
|
@ -358,6 +370,17 @@ void Mp2tMediaParser::OnNewStreamInfo(
|
||||||
|
|
||||||
if (new_stream_info) {
|
if (new_stream_info) {
|
||||||
// Set the stream configuration information for the PID.
|
// Set the stream configuration information for the PID.
|
||||||
|
auto pes_metadata = pes_metadata_.find(pes_pid);
|
||||||
|
DCHECK(pes_metadata != pes_metadata_.end());
|
||||||
|
if (!pes_metadata->second.language.empty())
|
||||||
|
new_stream_info->set_language(pes_metadata->second.language);
|
||||||
|
if (new_stream_info->stream_type() == kStreamAudio) {
|
||||||
|
auto* audio_info = static_cast<AudioStreamInfo*>(new_stream_info.get());
|
||||||
|
audio_info->set_max_bitrate(pes_metadata->second.max_bitrate);
|
||||||
|
// TODO(modernletter) Add some field for audio type to AudioStreamInfo
|
||||||
|
// and set here from audio_type
|
||||||
|
}
|
||||||
|
|
||||||
pid_state->second->set_config(new_stream_info);
|
pid_state->second->set_config(new_stream_info);
|
||||||
} else {
|
} else {
|
||||||
LOG(WARNING) << "Ignoring unsupported stream with pid=" << pes_pid;
|
LOG(WARNING) << "Ignoring unsupported stream with pid=" << pes_pid;
|
||||||
|
|
|
@ -9,11 +9,13 @@
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <packager/macros/classes.h>
|
#include <packager/macros/classes.h>
|
||||||
#include <packager/media/base/byte_queue.h>
|
#include <packager/media/base/byte_queue.h>
|
||||||
#include <packager/media/base/media_parser.h>
|
#include <packager/media/base/media_parser.h>
|
||||||
#include <packager/media/base/stream_info.h>
|
#include <packager/media/base/stream_info.h>
|
||||||
|
#include <packager/media/formats/mp2t/ts_audio_type.h>
|
||||||
#include <packager/media/formats/mp2t/ts_stream_type.h>
|
#include <packager/media/formats/mp2t/ts_stream_type.h>
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
@ -27,6 +29,12 @@ class PidState;
|
||||||
class TsPacket;
|
class TsPacket;
|
||||||
class TsSection;
|
class TsSection;
|
||||||
|
|
||||||
|
struct PesMetadata {
|
||||||
|
uint32_t max_bitrate;
|
||||||
|
std::string language;
|
||||||
|
TsAudioType audio_type;
|
||||||
|
};
|
||||||
|
|
||||||
class Mp2tMediaParser : public MediaParser {
|
class Mp2tMediaParser : public MediaParser {
|
||||||
public:
|
public:
|
||||||
Mp2tMediaParser();
|
Mp2tMediaParser();
|
||||||
|
@ -50,10 +58,15 @@ class Mp2tMediaParser : public MediaParser {
|
||||||
// Callback invoked to register a PES pid.
|
// Callback invoked to register a PES pid.
|
||||||
// Possible values for |media_type| are defined in:
|
// Possible values for |media_type| are defined in:
|
||||||
// ISO-13818.1 / ITU H.222 Table 2.34 "Media type assignments".
|
// ISO-13818.1 / ITU H.222 Table 2.34 "Media type assignments".
|
||||||
|
// Possible values for |audio_type| are defined in:
|
||||||
|
// ISO-13818.1 / ITU H.222 Table 2-60 "Audio type values".
|
||||||
// |pes_pid| is part of the Program Map Table refered by |pmt_pid|.
|
// |pes_pid| is part of the Program Map Table refered by |pmt_pid|.
|
||||||
void RegisterPes(int pmt_pid,
|
void RegisterPes(int pmt_pid,
|
||||||
int pes_pid,
|
int pes_pid,
|
||||||
TsStreamType media_type,
|
TsStreamType media_type,
|
||||||
|
uint32_t max_bitrate,
|
||||||
|
const std::string& lang,
|
||||||
|
TsAudioType audio_type,
|
||||||
const uint8_t* descriptor,
|
const uint8_t* descriptor,
|
||||||
size_t descriptor_length);
|
size_t descriptor_length);
|
||||||
|
|
||||||
|
@ -94,6 +107,9 @@ class Mp2tMediaParser : public MediaParser {
|
||||||
// has a deterministic order.
|
// has a deterministic order.
|
||||||
std::map<int, std::unique_ptr<PidState>> pids_;
|
std::map<int, std::unique_ptr<PidState>> pids_;
|
||||||
|
|
||||||
|
// Map of PIDs and their metadata.
|
||||||
|
std::map<int, PesMetadata> pes_metadata_;
|
||||||
|
|
||||||
// Whether |init_cb_| has been invoked.
|
// Whether |init_cb_| has been invoked.
|
||||||
bool is_initialized_;
|
bool is_initialized_;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <packager/macros/logging.h>
|
#include <packager/macros/logging.h>
|
||||||
|
#include <packager/media/base/audio_stream_info.h>
|
||||||
#include <packager/media/base/media_sample.h>
|
#include <packager/media/base/media_sample.h>
|
||||||
#include <packager/media/base/stream_info.h>
|
#include <packager/media/base/stream_info.h>
|
||||||
#include <packager/media/base/timestamp.h>
|
#include <packager/media/base/timestamp.h>
|
||||||
|
@ -190,6 +191,19 @@ TEST_F(Mp2tMediaParserTest, PtsZeroDtsWrapAround) {
|
||||||
EXPECT_GT(video_max_pts_, static_cast<int64_t>(1) << 33);
|
EXPECT_GT(video_max_pts_, static_cast<int64_t>(1) << 33);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(Mp2tMediaParserTest, PmtEsDescriptors) {
|
||||||
|
//"bear-eng-visualy-impaired-audio.ts" consist of audio stream marked as
|
||||||
|
// english audio with commentary for visualy impaired viewer and max
|
||||||
|
// bitrate set to ~128kbps
|
||||||
|
|
||||||
|
ParseMpeg2TsFile("bear-visualy-impaired-eng-audio.ts", 188);
|
||||||
|
EXPECT_TRUE(parser_->Flush());
|
||||||
|
EXPECT_STREQ("eng", stream_map_[257]->language().c_str());
|
||||||
|
|
||||||
|
auto* audio_info = static_cast<AudioStreamInfo*>(stream_map_[257].get());
|
||||||
|
EXPECT_EQ(131600, audio_info->max_bitrate());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mp2t
|
} // namespace mp2t
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2023 Google LLC. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#ifndef PACKAGER_MEDIA_FORMATS_MP2T_TS_AUDIO_TYPE_H
|
||||||
|
#define PACKAGER_MEDIA_FORMATS_MP2T_TS_AUDIO_TYPE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace shaka {
|
||||||
|
namespace media {
|
||||||
|
namespace mp2t {
|
||||||
|
|
||||||
|
enum class TsAudioType : uint8_t {
|
||||||
|
// ISO-13818.1 / ITU H.222 Table 2-60 "Audio type values"
|
||||||
|
kUndefined = 0x00,
|
||||||
|
kCleanEffects = 0x01,
|
||||||
|
kHearingImpaired = 0x02,
|
||||||
|
kVisualyImpairedCommentary = 0x03,
|
||||||
|
// 0x04-0x7F - user private
|
||||||
|
// 0x80-0xFF - reserved
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mp2t
|
||||||
|
} // namespace media
|
||||||
|
} // namespace shaka
|
||||||
|
|
||||||
|
#endif // PACKAGER_MEDIA_FORMATS_MP2T_TS_AUDIO_TYPE_H
|
|
@ -10,12 +10,21 @@
|
||||||
|
|
||||||
#include <packager/media/base/bit_reader.h>
|
#include <packager/media/base/bit_reader.h>
|
||||||
#include <packager/media/formats/mp2t/mp2t_common.h>
|
#include <packager/media/formats/mp2t/mp2t_common.h>
|
||||||
|
#include <packager/media/formats/mp2t/ts_audio_type.h>
|
||||||
#include <packager/media/formats/mp2t/ts_stream_type.h>
|
#include <packager/media/formats/mp2t/ts_stream_type.h>
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp2t {
|
namespace mp2t {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const int kISO639LanguageDescriptor = 0x0A;
|
||||||
|
const int kMaximumBitrateDescriptor = 0x0E;
|
||||||
|
const int kSubtitlingDescriptor = 0x59;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
TsSectionPmt::TsSectionPmt(const RegisterPesCb& register_pes_cb)
|
TsSectionPmt::TsSectionPmt(const RegisterPesCb& register_pes_cb)
|
||||||
: register_pes_cb_(register_pes_cb) {
|
: register_pes_cb_(register_pes_cb) {
|
||||||
}
|
}
|
||||||
|
@ -82,6 +91,9 @@ bool TsSectionPmt::ParsePsiSection(BitReader* bit_reader) {
|
||||||
TsStreamType stream_type;
|
TsStreamType stream_type;
|
||||||
const uint8_t* descriptor;
|
const uint8_t* descriptor;
|
||||||
size_t descriptor_length;
|
size_t descriptor_length;
|
||||||
|
std::string lang;
|
||||||
|
uint32_t max_bitrate;
|
||||||
|
TsAudioType audio_type;
|
||||||
};
|
};
|
||||||
std::vector<Info> pid_info;
|
std::vector<Info> pid_info;
|
||||||
while (static_cast<int>(bit_reader->bits_available()) >
|
while (static_cast<int>(bit_reader->bits_available()) >
|
||||||
|
@ -99,22 +111,59 @@ bool TsSectionPmt::ParsePsiSection(BitReader* bit_reader) {
|
||||||
// Do not register the PID right away.
|
// Do not register the PID right away.
|
||||||
// Wait for the end of the section to be fully parsed
|
// Wait for the end of the section to be fully parsed
|
||||||
// to make sure there is no error.
|
// to make sure there is no error.
|
||||||
pid_info.push_back({pid_es, stream_type, descriptor, es_info_length});
|
pid_info.push_back({pid_es, stream_type, descriptor, es_info_length, "", 0,
|
||||||
|
TsAudioType::kUndefined});
|
||||||
|
|
||||||
// Read the ES info descriptors.
|
// Read the ES info descriptors.
|
||||||
// Defined in section 2.6 of ISO-13818.
|
// Defined in section 2.6 of ISO-13818.
|
||||||
if (es_info_length > 0) {
|
uint8_t descriptor_tag;
|
||||||
uint8_t descriptor_tag;
|
uint8_t descriptor_length;
|
||||||
|
|
||||||
|
while (es_info_length) {
|
||||||
RCHECK(bit_reader->ReadBits(8, &descriptor_tag));
|
RCHECK(bit_reader->ReadBits(8, &descriptor_tag));
|
||||||
es_info_length--;
|
RCHECK(bit_reader->ReadBits(8, &descriptor_length));
|
||||||
|
es_info_length -= 2;
|
||||||
|
|
||||||
// See ETSI EN 300 468 Section 6.1
|
// See ETSI EN 300 468 Section 6.1
|
||||||
if (stream_type == TsStreamType::kPesPrivateData &&
|
if (stream_type == TsStreamType::kPesPrivateData &&
|
||||||
descriptor_tag == 0x59) { // subtitling_descriptor
|
descriptor_tag == kSubtitlingDescriptor) {
|
||||||
pid_info.back().stream_type = TsStreamType::kDvbSubtitles;
|
pid_info.back().stream_type = TsStreamType::kDvbSubtitles;
|
||||||
|
} else if (descriptor_tag == kISO639LanguageDescriptor &&
|
||||||
|
descriptor_length >= 4) {
|
||||||
|
// See section 2.6.19 of ISO-13818
|
||||||
|
// Descriptor can contain 0..N language defintions,
|
||||||
|
// we process only the first one
|
||||||
|
RCHECK(es_info_length >= 4);
|
||||||
|
|
||||||
|
char lang[3];
|
||||||
|
RCHECK(bit_reader->ReadBits(8, &lang[0])); // ISO_639_language_code
|
||||||
|
RCHECK(bit_reader->ReadBits(8, &lang[1]));
|
||||||
|
RCHECK(bit_reader->ReadBits(8, &lang[2]));
|
||||||
|
RCHECK(bit_reader->ReadBits(8, &pid_info.back().audio_type));
|
||||||
|
pid_info.back().lang = std::string(lang, 3);
|
||||||
|
|
||||||
|
es_info_length -= 4;
|
||||||
|
descriptor_length -= 4;
|
||||||
|
} else if (descriptor_tag == kMaximumBitrateDescriptor &&
|
||||||
|
descriptor_length >= 3) {
|
||||||
|
// See section 2.6.25 of ISO-13818
|
||||||
|
RCHECK(es_info_length >= 3);
|
||||||
|
|
||||||
|
uint32_t max_bitrate;
|
||||||
|
RCHECK(bit_reader->SkipBits(2)); // reserved
|
||||||
|
RCHECK(bit_reader->ReadBits(22, &max_bitrate));
|
||||||
|
// maximum bitrate is stored in units of 50 bytes per second
|
||||||
|
pid_info.back().max_bitrate = 50 * 8 * max_bitrate;
|
||||||
|
|
||||||
|
es_info_length -= 3;
|
||||||
|
descriptor_length -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCHECK(bit_reader->SkipBits(8 * descriptor_length));
|
||||||
|
es_info_length -= descriptor_length;
|
||||||
}
|
}
|
||||||
RCHECK(bit_reader->SkipBits(8 * es_info_length));
|
|
||||||
|
RCHECK(bit_reader->SkipBytes(es_info_length));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the CRC.
|
// Read the CRC.
|
||||||
|
@ -123,8 +172,8 @@ bool TsSectionPmt::ParsePsiSection(BitReader* bit_reader) {
|
||||||
|
|
||||||
// Once the PMT has been proved to be correct, register the PIDs.
|
// Once the PMT has been proved to be correct, register the PIDs.
|
||||||
for (auto& info : pid_info) {
|
for (auto& info : pid_info) {
|
||||||
register_pes_cb_(info.pid_es, info.stream_type, info.descriptor,
|
register_pes_cb_(info.pid_es, info.stream_type, info.max_bitrate, info.lang,
|
||||||
info.descriptor_length);
|
info.audio_type, info.descriptor, info.descriptor_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
#define PACKAGER_MEDIA_FORMATS_MP2T_TS_SECTION_PMT_H_
|
#define PACKAGER_MEDIA_FORMATS_MP2T_TS_SECTION_PMT_H_
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <packager/macros/classes.h>
|
#include <packager/macros/classes.h>
|
||||||
|
#include <packager/media/formats/mp2t/ts_audio_type.h>
|
||||||
#include <packager/media/formats/mp2t/ts_section_psi.h>
|
#include <packager/media/formats/mp2t/ts_section_psi.h>
|
||||||
#include <packager/media/formats/mp2t/ts_stream_type.h>
|
#include <packager/media/formats/mp2t/ts_stream_type.h>
|
||||||
|
|
||||||
|
@ -17,10 +19,20 @@ namespace mp2t {
|
||||||
|
|
||||||
class TsSectionPmt : public TsSectionPsi {
|
class TsSectionPmt : public TsSectionPsi {
|
||||||
public:
|
public:
|
||||||
// RegisterPesCb::Run(int pes_pid, int stream_type);
|
// RegisterPesCb::Run(int pes_pid, int stream_type, uint32_t max_bitrate,
|
||||||
|
// const string& lang, TsAudioType audio_type, uint8_t* descriptor,
|
||||||
|
// size_t desriptor_size);
|
||||||
// Stream type is defined in
|
// Stream type is defined in
|
||||||
// "Table 2-34 – Stream type assignments" in H.222
|
// "Table 2-34 – Stream type assignments" in H.222
|
||||||
typedef std::function<void(int, TsStreamType, const uint8_t*, size_t)>
|
// Audio type is defined in
|
||||||
|
// "Table 2-60 - Audio type values" in H.222
|
||||||
|
typedef std::function<void(int,
|
||||||
|
TsStreamType,
|
||||||
|
uint32_t,
|
||||||
|
const std::string&,
|
||||||
|
TsAudioType,
|
||||||
|
const uint8_t*,
|
||||||
|
size_t)>
|
||||||
RegisterPesCb;
|
RegisterPesCb;
|
||||||
|
|
||||||
explicit TsSectionPmt(const RegisterPesCb& register_pes_cb);
|
explicit TsSectionPmt(const RegisterPesCb& register_pes_cb);
|
||||||
|
|
|
@ -29,6 +29,12 @@ bear-640x360.ts - AVC + AAC encode, multiplexed into an MPEG2-TS container.
|
||||||
bear-640x360_ptswraparound.ts - Same as bear-640x360.ts, with a timestamp wrap-around in the middle, created with the below command:
|
bear-640x360_ptswraparound.ts - Same as bear-640x360.ts, with a timestamp wrap-around in the middle, created with the below command:
|
||||||
ffmpeg -itsoffset 95442 -i bear-640x360.ts -c:v copy -c:a copy -muxdelay 0 bear-640x360_ptswraparound.ts
|
ffmpeg -itsoffset 95442 -i bear-640x360.ts -c:v copy -c:a copy -muxdelay 0 bear-640x360_ptswraparound.ts
|
||||||
bear-640x360-hevc.ts - HEVC + AAC encode, multiplexed into an MPEG2-TS container.
|
bear-640x360-hevc.ts - HEVC + AAC encode, multiplexed into an MPEG2-TS container.
|
||||||
|
bear-eng-visualy-impaired-audio.ts - Audio stream from bear-640x360.ts marked as english with commentary for visually impaired viewer using the below commands:
|
||||||
|
tsp -I file bear-640x360.ts \
|
||||||
|
-P filter --video --negate
|
||||||
|
-P inject --replace --pid 4096 --xml bear-visualy-impaired-eng-audio-pmt.xml \
|
||||||
|
-O file bear-visualy-impaired-eng-audio.ts
|
||||||
|
(xml template can be obtained by command "tsp -I file bear-640x360.ts -P tables --pid 4096 --tid 2 --max 1 --xml pmt.xml -O drop")
|
||||||
|
|
||||||
// ISO-BMFF streams.
|
// ISO-BMFF streams.
|
||||||
bear-1280x720.mp4 - AVC + AAC encode, mulitplexed into an ISOBMFF container.
|
bear-1280x720.mp4 - AVC + AAC encode, mulitplexed into an ISOBMFF container.
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<tsduck>
|
||||||
|
<PMT version="0" current="true" service_id="0x0001" PCR_PID="0x0100">
|
||||||
|
<metadata PID="4,096"/>
|
||||||
|
<component elementary_PID="0x0101" stream_type="0x0F">
|
||||||
|
<ISO_639_language_descriptor>
|
||||||
|
<language code="eng" audio_type="0x03"/>
|
||||||
|
</ISO_639_language_descriptor>
|
||||||
|
<maximum_bitrate_descriptor maximum_bitrate="131,600"/>
|
||||||
|
</component>
|
||||||
|
</PMT>
|
||||||
|
</tsduck>
|
Binary file not shown.
Loading…
Reference in New Issue