Add Text Codec To Codec String
This change has the hls master playlist add the text codec string to the list of codecs in a variant. Bug: 72942756 Change-Id: Ib25bb2064a291d10d7b1d261a4307991df62220c
This commit is contained in:
parent
c7929b1505
commit
30b5fdf19f
|
@ -5,5 +5,5 @@
|
|||
|
||||
#EXT-X-MEDIA:TYPE=SUBTITLES,URI="stream_0.m3u8",GROUP-ID="default-text-group",NAME="stream_0",AUTOSELECT=YES
|
||||
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=1105163,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group",SUBTITLES="default-text-group"
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=1105163,CODECS="avc1.64001e,mp4a.40.2,wvtt",RESOLUTION=640x360,AUDIO="default-audio-group",SUBTITLES="default-text-group"
|
||||
stream_2.m3u8
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "packager/base/files/file_path.h"
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/base/strings/string_util.h"
|
||||
#include "packager/base/strings/stringprintf.h"
|
||||
#include "packager/file/file.h"
|
||||
#include "packager/hls/base/media_playlist.h"
|
||||
|
@ -34,7 +35,8 @@ void AppendVersionString(std::string* content) {
|
|||
}
|
||||
|
||||
struct Variant {
|
||||
std::string audio_codec;
|
||||
std::set<std::string> audio_codecs;
|
||||
std::set<std::string> text_codecs;
|
||||
const std::string* audio_group_id = nullptr;
|
||||
const std::string* text_group_id = nullptr;
|
||||
uint64_t audio_bitrate = 0;
|
||||
|
@ -48,10 +50,15 @@ uint64_t MaxBitrate(const std::list<const MediaPlaylist*> playlists) {
|
|||
return max;
|
||||
}
|
||||
|
||||
std::string GetAudioGroupCodecString(
|
||||
std::set<std::string> GetGroupCodecString(
|
||||
const std::list<const MediaPlaylist*>& group) {
|
||||
// TODO(vaage): Should be a concatenation of all the codecs in the group.
|
||||
return group.front()->codec();
|
||||
std::set<std::string> codecs;
|
||||
|
||||
for (const MediaPlaylist* playlist : group) {
|
||||
codecs.insert(playlist->codec());
|
||||
}
|
||||
|
||||
return codecs;
|
||||
}
|
||||
|
||||
std::list<Variant> AudioGroupsToVariants(
|
||||
|
@ -60,9 +67,9 @@ std::list<Variant> AudioGroupsToVariants(
|
|||
|
||||
for (const auto& group : groups) {
|
||||
Variant variant;
|
||||
variant.audio_codec = GetAudioGroupCodecString(group.second);
|
||||
variant.audio_group_id = &group.first;
|
||||
variant.audio_bitrate = MaxBitrate(group.second);
|
||||
variant.audio_codecs = GetGroupCodecString(group.second);
|
||||
|
||||
variants.push_back(variant);
|
||||
}
|
||||
|
@ -102,6 +109,7 @@ std::list<Variant> SubtitleGroupsToVariants(
|
|||
for (const auto& group : groups) {
|
||||
Variant variant;
|
||||
variant.text_group_id = &group.first;
|
||||
variant.text_codecs = GetGroupCodecString(group.second);
|
||||
|
||||
variants.push_back(variant);
|
||||
}
|
||||
|
@ -131,7 +139,8 @@ std::list<Variant> BuildVariants(
|
|||
for (const auto& audio_variant : audio_variants) {
|
||||
for (const auto& subtitle_variant : subtitle_variants) {
|
||||
Variant variant;
|
||||
variant.audio_codec = audio_variant.audio_codec;
|
||||
variant.audio_codecs = audio_variant.audio_codecs;
|
||||
variant.text_codecs = subtitle_variant.text_codecs;
|
||||
variant.audio_group_id = audio_variant.audio_group_id;
|
||||
variant.text_group_id = subtitle_variant.text_group_id;
|
||||
variant.audio_bitrate = audio_variant.audio_bitrate;
|
||||
|
@ -151,17 +160,6 @@ void BuildStreamInfTag(const MediaPlaylist& playlist,
|
|||
std::string* out) {
|
||||
DCHECK(out);
|
||||
|
||||
const uint64_t bitrate = playlist.Bitrate() + variant.audio_bitrate;
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
CHECK(playlist.GetDisplayResolution(&width, &height));
|
||||
|
||||
std::string codecs = playlist.codec();
|
||||
if (!variant.audio_codec.empty()) {
|
||||
base::StringAppendF(&codecs, ",%s", variant.audio_codec.c_str());
|
||||
}
|
||||
|
||||
std::string tag_name;
|
||||
switch (playlist.stream_type()) {
|
||||
case MediaPlaylist::MediaPlaylistStreamType::kVideo:
|
||||
|
@ -177,8 +175,20 @@ void BuildStreamInfTag(const MediaPlaylist& playlist,
|
|||
}
|
||||
Tag tag(tag_name, out);
|
||||
|
||||
const uint64_t bitrate = playlist.Bitrate() + variant.audio_bitrate;
|
||||
tag.AddNumber("BANDWIDTH", bitrate);
|
||||
tag.AddQuotedString("CODECS", codecs);
|
||||
|
||||
std::vector<std::string> all_codecs;
|
||||
all_codecs.push_back(playlist.codec());
|
||||
all_codecs.insert(all_codecs.end(), variant.audio_codecs.begin(),
|
||||
variant.audio_codecs.end());
|
||||
all_codecs.insert(all_codecs.end(), variant.text_codecs.begin(),
|
||||
variant.text_codecs.end());
|
||||
tag.AddQuotedString("CODECS", base::JoinString(all_codecs, ","));
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
CHECK(playlist.GetDisplayResolution(&width, &height));
|
||||
tag.AddNumberPair("RESOLUTION", width, 'x', height);
|
||||
|
||||
if (variant.audio_group_id) {
|
||||
|
|
|
@ -97,6 +97,7 @@ std::unique_ptr<MockMediaPlaylist> CreateTextPlaylist(
|
|||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::string& group,
|
||||
const std::string& codec,
|
||||
const std::string& language) {
|
||||
std::unique_ptr<MockMediaPlaylist> playlist(
|
||||
new MockMediaPlaylist(kVodPlaylist, filename, name, group));
|
||||
|
@ -104,6 +105,7 @@ std::unique_ptr<MockMediaPlaylist> CreateTextPlaylist(
|
|||
EXPECT_CALL(*playlist, GetLanguage()).WillRepeatedly(Return(language));
|
||||
playlist->SetStreamTypeForTesting(
|
||||
MediaPlaylist::MediaPlaylistStreamType::kSubtitle);
|
||||
playlist->SetCodecForTesting(codec);
|
||||
|
||||
return playlist;
|
||||
}
|
||||
|
@ -336,11 +338,11 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideosAndTexts) {
|
|||
|
||||
// Text, eng.m3u8.
|
||||
std::unique_ptr<MockMediaPlaylist> text_eng =
|
||||
CreateTextPlaylist("eng.m3u8", "english", "textgroup", "en");
|
||||
CreateTextPlaylist("eng.m3u8", "english", "textgroup", "textcodec", "en");
|
||||
|
||||
// Text, fr.m3u8.
|
||||
std::unique_ptr<MockMediaPlaylist> text_fr =
|
||||
CreateTextPlaylist("fr.m3u8", "french", "textgroup", "fr");
|
||||
CreateTextPlaylist("fr.m3u8", "french", "textgroup", "textcodec", "fr");
|
||||
|
||||
const char kBaseUrl[] = "http://playlists.org/";
|
||||
EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(
|
||||
|
@ -361,10 +363,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideosAndTexts) {
|
|||
"#EXT-X-MEDIA:TYPE=SUBTITLES,URI=\"http://playlists.org/fr.m3u8\","
|
||||
"GROUP-ID=\"textgroup\",LANGUAGE=\"fr\",NAME=\"french\",AUTOSELECT=YES\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec,textcodec\","
|
||||
"RESOLUTION=800x600,SUBTITLES=\"textgroup\"\n"
|
||||
"http://playlists.org/sd.m3u8\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=600000,CODECS=\"sdvideocodec\","
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=600000,CODECS=\"sdvideocodec,textcodec\","
|
||||
"RESOLUTION=800x600,SUBTITLES=\"textgroup\"\n"
|
||||
"http://playlists.org/hd.m3u8\n";
|
||||
|
||||
|
@ -377,12 +379,12 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) {
|
|||
CreateVideoPlaylist("sd.m3u8", "sdvideocodec", 300000);
|
||||
|
||||
// Text, eng.m3u8.
|
||||
std::unique_ptr<MockMediaPlaylist> text_eng =
|
||||
CreateTextPlaylist("eng.m3u8", "english", "en-text-group", "en");
|
||||
std::unique_ptr<MockMediaPlaylist> text_eng = CreateTextPlaylist(
|
||||
"eng.m3u8", "english", "en-text-group", "textcodec", "en");
|
||||
|
||||
// Text, fr.m3u8.
|
||||
std::unique_ptr<MockMediaPlaylist> text_fr =
|
||||
CreateTextPlaylist("fr.m3u8", "french", "fr-text-group", "fr");
|
||||
std::unique_ptr<MockMediaPlaylist> text_fr = CreateTextPlaylist(
|
||||
"fr.m3u8", "french", "fr-text-group", "textcodec", "fr");
|
||||
|
||||
const char kBaseUrl[] = "http://playlists.org/";
|
||||
EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(
|
||||
|
@ -404,11 +406,11 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) {
|
|||
"GROUP-ID=\"fr-text-group\",LANGUAGE=\"fr\",NAME=\"french\","
|
||||
"AUTOSELECT=YES\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec,textcodec\","
|
||||
"RESOLUTION=800x600,SUBTITLES=\"en-text-group\"\n"
|
||||
"http://playlists.org/sd.m3u8\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec\","
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=300000,CODECS=\"sdvideocodec,textcodec\","
|
||||
"RESOLUTION=800x600,SUBTITLES=\"fr-text-group\"\n"
|
||||
"http://playlists.org/sd.m3u8\n";
|
||||
|
||||
|
@ -426,7 +428,7 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudioAndText) {
|
|||
|
||||
// Text, english.m3u8.
|
||||
std::unique_ptr<MockMediaPlaylist> text =
|
||||
CreateTextPlaylist("eng.m3u8", "english", "textgroup", "en");
|
||||
CreateTextPlaylist("eng.m3u8", "english", "textgroup", "textcodec", "en");
|
||||
|
||||
const char kBaseUrl[] = "http://playlists.org/";
|
||||
EXPECT_TRUE(master_playlist_.WriteMasterPlaylist(
|
||||
|
@ -448,8 +450,9 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudioAndText) {
|
|||
"GROUP-ID=\"textgroup\",LANGUAGE=\"en\",NAME=\"english\",DEFAULT=YES,"
|
||||
"AUTOSELECT=YES\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audiogroup\",SUBTITLES=\"textgroup\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audiogroup\",SUBTITLES="
|
||||
"\"textgroup\"\n"
|
||||
"http://playlists.org/sd.m3u8\n";
|
||||
|
||||
ASSERT_EQ(expected, actual);
|
||||
|
@ -469,8 +472,10 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMixedPlaylistsDifferentGroups) {
|
|||
"audiocodec", "en", kAudioChannels, kAudioBitRate),
|
||||
|
||||
// SUBTITLES
|
||||
CreateTextPlaylist("text-1.m3u8", "text 1", "text-group-1", "en"),
|
||||
CreateTextPlaylist("text-2.m3u8", "text 2", "text-group-2", "en"),
|
||||
CreateTextPlaylist("text-1.m3u8", "text 1", "text-group-1", "textcodec",
|
||||
"en"),
|
||||
CreateTextPlaylist("text-2.m3u8", "text 2", "text-group-2", "textcodec",
|
||||
"en"),
|
||||
|
||||
// VIDEO
|
||||
CreateVideoPlaylist("video-1.m3u8", "sdvideocodec", kVideoBitRate),
|
||||
|
@ -513,32 +518,40 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMixedPlaylistsDifferentGroups) {
|
|||
"GROUP-ID=\"text-group-2\",LANGUAGE=\"en\",NAME=\"text 2\","
|
||||
"DEFAULT=YES,AUTOSELECT=YES\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-"
|
||||
"group-1\"\n"
|
||||
"http://playlists.org/video-1.m3u8\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-1\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-"
|
||||
"group-1\"\n"
|
||||
"http://playlists.org/video-2.m3u8\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-2\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-"
|
||||
"group-2\"\n"
|
||||
"http://playlists.org/video-1.m3u8\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-group-2\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-1\",SUBTITLES=\"text-"
|
||||
"group-2\"\n"
|
||||
"http://playlists.org/video-2.m3u8\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-1\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-"
|
||||
"group-1\"\n"
|
||||
"http://playlists.org/video-1.m3u8\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-1\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-"
|
||||
"group-1\"\n"
|
||||
"http://playlists.org/video-2.m3u8\n"
|
||||
"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-2\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-"
|
||||
"group-2\"\n"
|
||||
"http://playlists.org/video-1.m3u8\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec\","
|
||||
"RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-group-2\"\n"
|
||||
"#EXT-X-STREAM-INF:BANDWIDTH=350000,CODECS=\"sdvideocodec,audiocodec,"
|
||||
"textcodec\",RESOLUTION=800x600,AUDIO=\"audio-group-2\",SUBTITLES=\"text-"
|
||||
"group-2\"\n"
|
||||
"http://playlists.org/video-2.m3u8\n"
|
||||
"\n"
|
||||
"#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=100000,CODECS=\"sdvideocodec\","
|
||||
|
|
|
@ -342,7 +342,7 @@ bool MediaPlaylist::SetMediaInfo(const MediaInfo& media_info) {
|
|||
codec_ = media_info.audio_info().codec();
|
||||
} else {
|
||||
stream_type_ = MediaPlaylistStreamType::kSubtitle;
|
||||
codec_ = media_info.text_info().format();
|
||||
codec_ = media_info.text_info().codec();
|
||||
}
|
||||
|
||||
time_scale_ = time_scale;
|
||||
|
|
|
@ -103,7 +103,7 @@ TEST_F(MediaPlaylistMultiSegmentTest, SetMediaInfoText) {
|
|||
MediaInfo media_info;
|
||||
media_info.set_reference_time_scale(kTimeScale);
|
||||
MediaInfo::TextInfo* text_info = media_info.mutable_text_info();
|
||||
text_info->set_format("vtt");
|
||||
text_info->set_codec("wvtt");
|
||||
EXPECT_TRUE(media_playlist_.SetMediaInfo(media_info));
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,8 @@ TEST_F(MediaPlaylistSingleSegmentTest, InitRangeWithOffset) {
|
|||
}
|
||||
|
||||
// Closest to the normal use case where there is an init range and then
|
||||
// subsegment ranges. There is index range between the subsegment and init range.
|
||||
// subsegment ranges. There is index range between the subsegment and init
|
||||
// range.
|
||||
TEST_F(MediaPlaylistSingleSegmentTest, AddSegmentByteRange) {
|
||||
const std::string kExpectedOutput =
|
||||
"#EXTM3U\n"
|
||||
|
@ -203,8 +204,7 @@ TEST_F(MediaPlaylistSingleSegmentTest, AddSegmentByteRange) {
|
|||
valid_video_media_info_.mutable_init_range()->set_end(500);
|
||||
|
||||
ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_));
|
||||
media_playlist_.AddSegment("file.mp4", 0, 10 * kTimeScale, 1000,
|
||||
1 * kMBytes);
|
||||
media_playlist_.AddSegment("file.mp4", 0, 10 * kTimeScale, 1000, 1 * kMBytes);
|
||||
media_playlist_.AddSegment("file.mp4", 10 * kTimeScale, 10 * kTimeScale,
|
||||
1001000, 2 * kMBytes);
|
||||
|
||||
|
@ -381,8 +381,8 @@ TEST_F(MediaPlaylistMultiSegmentTest, WriteToFileWithEncryptionInfoEmptyIv) {
|
|||
ASSERT_TRUE(media_playlist_.SetMediaInfo(valid_video_media_info_));
|
||||
|
||||
media_playlist_.AddEncryptionInfo(MediaPlaylist::EncryptionMethod::kSampleAes,
|
||||
"http://example.com", "", "", "com.widevine",
|
||||
"");
|
||||
"http://example.com", "", "",
|
||||
"com.widevine", "");
|
||||
media_playlist_.AddSegment("file1.ts", 0, 10 * kTimeScale, kZeroByteOffset,
|
||||
kMBytes);
|
||||
media_playlist_.AddSegment("file2.ts", 10 * kTimeScale, 30 * kTimeScale,
|
||||
|
@ -489,7 +489,8 @@ TEST_F(MediaPlaylistMultiSegmentTest, InitSegment) {
|
|||
const char kExpectedOutput[] =
|
||||
"#EXTM3U\n"
|
||||
"#EXT-X-VERSION:6\n"
|
||||
"## Generated with https://github.com/google/shaka-packager version test\n"
|
||||
"## Generated with https://github.com/google/shaka-packager version "
|
||||
"test\n"
|
||||
"#EXT-X-TARGETDURATION:30\n"
|
||||
"#EXT-X-PLAYLIST-TYPE:VOD\n"
|
||||
"#EXT-X-MAP:URI=\"init_segment.mp4\"\n"
|
||||
|
|
|
@ -128,31 +128,22 @@ void AddAudioInfo(const AudioStreamInfo* audio_stream_info,
|
|||
|
||||
void AddTextInfo(const TextStreamInfo& text_stream_info,
|
||||
MediaInfo* media_info) {
|
||||
MediaInfo::TextInfo* text_info = media_info->mutable_text_info();
|
||||
// For now, set everything as subtitle.
|
||||
MediaInfo::TextInfo* text_info = media_info->mutable_text_info();
|
||||
text_info->set_type(MediaInfo::TextInfo::SUBTITLE);
|
||||
if (text_stream_info.codec_string() == "wvtt") {
|
||||
text_info->set_format("vtt");
|
||||
} else {
|
||||
LOG(WARNING) << "Unhandled codec " << text_stream_info.codec_string()
|
||||
<< " copying it as format.";
|
||||
text_info->set_format(text_stream_info.codec_string());
|
||||
}
|
||||
|
||||
text_info->set_codec(text_stream_info.codec_string());
|
||||
text_info->set_language(text_stream_info.language());
|
||||
}
|
||||
|
||||
void SetMediaInfoStreamInfo(const StreamInfo& stream_info,
|
||||
MediaInfo* media_info) {
|
||||
if (stream_info.stream_type() == kStreamAudio) {
|
||||
AddAudioInfo(static_cast<const AudioStreamInfo*>(&stream_info),
|
||||
media_info);
|
||||
AddAudioInfo(static_cast<const AudioStreamInfo*>(&stream_info), media_info);
|
||||
} else if (stream_info.stream_type() == kStreamText) {
|
||||
AddTextInfo(static_cast<const TextStreamInfo&>(stream_info), media_info);
|
||||
} else {
|
||||
DCHECK_EQ(stream_info.stream_type(), kStreamVideo);
|
||||
AddVideoInfo(static_cast<const VideoStreamInfo*>(&stream_info),
|
||||
media_info);
|
||||
AddVideoInfo(static_cast<const VideoStreamInfo*>(&stream_info), media_info);
|
||||
}
|
||||
if (stream_info.duration() > 0) {
|
||||
// |stream_info.duration()| contains the media duration from the original
|
||||
|
@ -204,7 +195,6 @@ bool SetVodInformation(const MuxerListener::MediaRanges& media_ranges,
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (media_ranges.init_range) {
|
||||
SetRange(media_ranges.init_range->start, media_ranges.init_range->end,
|
||||
media_info->mutable_init_range());
|
||||
|
|
|
@ -109,7 +109,7 @@ TEST_F(AdaptationSetTest, CheckAdaptationSetAudioContentType) {
|
|||
TEST_F(AdaptationSetTest, CheckAdaptationSetTextContentType) {
|
||||
const char kTextMediaInfo[] =
|
||||
"text_info {\n"
|
||||
" format: 'ttml'\n"
|
||||
" codec: 'ttml'\n"
|
||||
" language: 'en'\n"
|
||||
"}\n"
|
||||
"container_type: CONTAINER_TEXT\n";
|
||||
|
@ -1072,7 +1072,7 @@ TEST_F(OnDemandAdaptationSetTest,
|
|||
TEST_F(OnDemandAdaptationSetTest, Text) {
|
||||
const char kTextMediaInfo[] =
|
||||
"text_info {\n"
|
||||
" format: 'ttml'\n"
|
||||
" codec: 'ttml'\n"
|
||||
" language: 'en'\n"
|
||||
" type: SUBTITLE\n"
|
||||
"}\n"
|
||||
|
|
|
@ -68,7 +68,7 @@ message MediaInfo {
|
|||
CAPTION = 1;
|
||||
SUBTITLE = 2;
|
||||
}
|
||||
optional string format = 1;
|
||||
optional string codec = 1;
|
||||
optional string language = 2;
|
||||
optional TextType type = 3;
|
||||
}
|
||||
|
|
|
@ -30,20 +30,22 @@ bool IsKeyRotationDefaultKeyId(const std::string& key_id) {
|
|||
|
||||
std::string TextCodecString(const MediaInfo& media_info) {
|
||||
CHECK(media_info.has_text_info());
|
||||
const std::string& format = media_info.text_info().format();
|
||||
// DASH IOP mentions that the codec for ttml in mp4 is stpp.
|
||||
if (format == "ttml" &&
|
||||
(media_info.container_type() == MediaInfo::CONTAINER_MP4)) {
|
||||
return "stpp";
|
||||
}
|
||||
if (format == "vtt" &&
|
||||
(media_info.container_type() == MediaInfo::CONTAINER_MP4)) {
|
||||
return "wvtt";
|
||||
const auto container_type = media_info.container_type();
|
||||
|
||||
// Codecs are not needed when mimeType is "text/*". Having a codec would be
|
||||
// redundant.
|
||||
if (container_type == MediaInfo::CONTAINER_TEXT) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Otherwise codec doesn't need to be specified, e.g. vtt and ttml+xml are
|
||||
// obvious from the mime type.
|
||||
return "";
|
||||
// DASH IOP mentions that the codec for ttml in mp4 is stpp, so override
|
||||
// the default codec value.
|
||||
const std::string& codec = media_info.text_info().codec();
|
||||
if (codec == "ttml" && container_type == MediaInfo::CONTAINER_MP4) {
|
||||
return "stpp";
|
||||
}
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -118,7 +120,7 @@ std::string GetBaseCodec(const MediaInfo& media_info) {
|
|||
} else if (media_info.has_audio_info()) {
|
||||
codec = media_info.audio_info().codec();
|
||||
} else if (media_info.has_text_info()) {
|
||||
codec = media_info.text_info().format();
|
||||
codec = media_info.text_info().codec();
|
||||
}
|
||||
// Convert, for example, "mp4a.40.2" to simply "mp4a".
|
||||
// "mp4a.40.2" and "mp4a.40.5" can exist in the same AdaptationSet.
|
||||
|
@ -186,10 +188,12 @@ bool MoreThanOneTrue(bool b1, bool b2, bool b3) {
|
|||
return (b1 && b2) || (b2 && b3) || (b3 && b1);
|
||||
}
|
||||
|
||||
bool AtLeastOneTrue(bool b1, bool b2, bool b3) { return b1 || b2 || b3; }
|
||||
bool AtLeastOneTrue(bool b1, bool b2, bool b3) {
|
||||
return b1 || b2 || b3;
|
||||
}
|
||||
|
||||
bool OnlyOneTrue(bool b1, bool b2, bool b3) {
|
||||
return !MoreThanOneTrue(b1, b2, b3) && AtLeastOneTrue(b1, b2, b3);
|
||||
return !MoreThanOneTrue(b1, b2, b3) && AtLeastOneTrue(b1, b2, b3);
|
||||
}
|
||||
|
||||
// Implement our own DoubleToString as base::DoubleToString uses third_party
|
||||
|
@ -375,5 +379,4 @@ void AddContentProtectionElements(const MediaInfo& media_info,
|
|||
AddContentProtectionElementsHelperTemplated(media_info, parent);
|
||||
}
|
||||
|
||||
|
||||
} // namespace shaka
|
||||
|
|
|
@ -213,7 +213,7 @@ TEST_P(PeriodTest, SetDurationAndGetXml) {
|
|||
TEST_P(PeriodTest, Text) {
|
||||
const char kTextMediaInfo[] =
|
||||
"text_info {\n"
|
||||
" format: 'ttml'\n"
|
||||
" codec: 'ttml'\n"
|
||||
" language: 'en'\n"
|
||||
"}\n"
|
||||
"container_type: CONTAINER_TEXT\n";
|
||||
|
|
|
@ -452,7 +452,7 @@ std::string Representation::GetAudioMimeType() const {
|
|||
|
||||
std::string Representation::GetTextMimeType() const {
|
||||
CHECK(media_info_.has_text_info());
|
||||
if (media_info_.text_info().format() == "ttml") {
|
||||
if (media_info_.text_info().codec() == "ttml") {
|
||||
switch (media_info_.container_type()) {
|
||||
case MediaInfo::CONTAINER_TEXT:
|
||||
return "application/ttml+xml";
|
||||
|
@ -464,7 +464,7 @@ std::string Representation::GetTextMimeType() const {
|
|||
return "";
|
||||
}
|
||||
}
|
||||
if (media_info_.text_info().format() == "vtt") {
|
||||
if (media_info_.text_info().codec() == "wvtt") {
|
||||
if (media_info_.container_type() == MediaInfo::CONTAINER_TEXT) {
|
||||
return "text/vtt";
|
||||
} else if (media_info_.container_type() == MediaInfo::CONTAINER_MP4) {
|
||||
|
@ -476,7 +476,7 @@ std::string Representation::GetTextMimeType() const {
|
|||
}
|
||||
|
||||
LOG(ERROR) << "Cannot determine MIME type for format: "
|
||||
<< media_info_.text_info().format()
|
||||
<< media_info_.text_info().codec()
|
||||
<< " container: " << media_info_.container_type();
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -291,7 +291,7 @@ TEST_F(RepresentationTest,
|
|||
TEST_F(RepresentationTest, TtmlXmlMimeType) {
|
||||
const char kTtmlXmlMediaInfo[] =
|
||||
"text_info {\n"
|
||||
" format: 'ttml'\n"
|
||||
" codec: 'ttml'\n"
|
||||
"}\n"
|
||||
"container_type: CONTAINER_TEXT\n";
|
||||
|
||||
|
@ -306,7 +306,7 @@ TEST_F(RepresentationTest, TtmlXmlMimeType) {
|
|||
TEST_F(RepresentationTest, TtmlMp4MimeType) {
|
||||
const char kTtmlMp4MediaInfo[] =
|
||||
"text_info {\n"
|
||||
" format: 'ttml'\n"
|
||||
" codec: 'ttml'\n"
|
||||
"}\n"
|
||||
"container_type: CONTAINER_MP4\n";
|
||||
|
||||
|
@ -321,7 +321,7 @@ TEST_F(RepresentationTest, TtmlMp4MimeType) {
|
|||
TEST_F(RepresentationTest, WebVttMimeType) {
|
||||
const char kWebVttMediaInfo[] =
|
||||
"text_info {\n"
|
||||
" format: 'vtt'\n"
|
||||
" codec: 'wvtt'\n"
|
||||
"}\n"
|
||||
"container_type: CONTAINER_TEXT\n";
|
||||
|
||||
|
|
|
@ -88,22 +88,32 @@ MuxerListenerFactory::StreamData ToMuxerListenerData(
|
|||
// TODO(rkuroiwa): Write TTML and WebVTT parser (demuxing) for a better check
|
||||
// and for supporting live/segmenting (muxing). With a demuxer and a muxer,
|
||||
// CreateAllJobs() shouldn't treat text as a special case.
|
||||
std::string DetermineTextFileFormat(const std::string& file) {
|
||||
bool DetermineTextFileCodec(const std::string& file, std::string* out) {
|
||||
CHECK(out);
|
||||
|
||||
std::string content;
|
||||
if (!File::ReadFileToString(file.c_str(), &content)) {
|
||||
LOG(ERROR) << "Failed to open file " << file
|
||||
<< " to determine file format.";
|
||||
return "";
|
||||
}
|
||||
MediaContainerName container_name = DetermineContainer(
|
||||
reinterpret_cast<const uint8_t*>(content.data()), content.size());
|
||||
if (container_name == CONTAINER_WEBVTT) {
|
||||
return "vtt";
|
||||
} else if (container_name == CONTAINER_TTML) {
|
||||
return "ttml";
|
||||
return false;
|
||||
}
|
||||
|
||||
return "";
|
||||
const uint8_t* content_data =
|
||||
reinterpret_cast<const uint8_t*>(content.data());
|
||||
MediaContainerName container_name =
|
||||
DetermineContainer(content_data, content.size());
|
||||
|
||||
if (container_name == CONTAINER_WEBVTT) {
|
||||
*out = "wvtt";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (container_name == CONTAINER_TTML) {
|
||||
*out = "ttml";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MediaContainerName GetOutputFormat(const StreamDescriptor& descriptor) {
|
||||
|
@ -278,14 +288,21 @@ class FakeClock : public base::Clock {
|
|||
|
||||
bool StreamInfoToTextMediaInfo(const StreamDescriptor& stream_descriptor,
|
||||
MediaInfo* text_media_info) {
|
||||
const std::string& language = stream_descriptor.language;
|
||||
const std::string format = DetermineTextFileFormat(stream_descriptor.input);
|
||||
if (format.empty()) {
|
||||
std::string codec;
|
||||
if (!DetermineTextFileCodec(stream_descriptor.input, &codec)) {
|
||||
LOG(ERROR) << "Failed to determine the text file format for "
|
||||
<< stream_descriptor.input;
|
||||
return false;
|
||||
}
|
||||
|
||||
MediaInfo::TextInfo* text_info = text_media_info->mutable_text_info();
|
||||
text_info->set_codec(codec);
|
||||
|
||||
const std::string& language = stream_descriptor.language;
|
||||
if (!language.empty()) {
|
||||
text_info->set_language(language);
|
||||
}
|
||||
|
||||
text_media_info->set_media_file_name(stream_descriptor.output);
|
||||
text_media_info->set_container_type(MediaInfo::CONTAINER_TEXT);
|
||||
|
||||
|
@ -299,11 +316,6 @@ bool StreamInfoToTextMediaInfo(const StreamDescriptor& stream_descriptor,
|
|||
text_media_info->set_bandwidth(kDefaultTextBandwidth);
|
||||
}
|
||||
|
||||
MediaInfo::TextInfo* text_info = text_media_info->mutable_text_info();
|
||||
text_info->set_format(format);
|
||||
if (!language.empty())
|
||||
text_info->set_language(language);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue