Fix default_language not effective with 2-char code
Two-character ISO-639 code in --default_language was ignored due to a bug in language code matching as the language code in stream is always converted to 3-character code. Fixes #371. Change-Id: I8618938af583a417446636ff9efe1c72ce822c33
This commit is contained in:
parent
4549b1d569
commit
0ef078a23b
|
@ -276,6 +276,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
utc_timings=None,
|
utc_timings=None,
|
||||||
generate_static_mpd=False,
|
generate_static_mpd=False,
|
||||||
ad_cues=None,
|
ad_cues=None,
|
||||||
|
default_language=None,
|
||||||
use_fake_clock=True):
|
use_fake_clock=True):
|
||||||
flags = []
|
flags = []
|
||||||
|
|
||||||
|
@ -351,6 +352,9 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
if ad_cues:
|
if ad_cues:
|
||||||
flags += ['--ad_cues', ad_cues]
|
flags += ['--ad_cues', ad_cues]
|
||||||
|
|
||||||
|
if default_language:
|
||||||
|
flags += ['--default_language', default_language]
|
||||||
|
|
||||||
flags.append('--segment_duration=1')
|
flags.append('--segment_duration=1')
|
||||||
# Use fake clock, so output can be compared.
|
# Use fake clock, so output can be compared.
|
||||||
if use_fake_clock:
|
if use_fake_clock:
|
||||||
|
@ -585,8 +589,26 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
|
|
||||||
def testPackageAudioVideoWithLanguageOverride(self):
|
def testPackageAudioVideoWithLanguageOverride(self):
|
||||||
self.assertPackageSuccess(
|
self.assertPackageSuccess(
|
||||||
self._GetStreams(['audio', 'video'], language='por-BR'),
|
self._GetStreams(['audio', 'video'], language='por'),
|
||||||
self._GetFlags())
|
self._GetFlags(default_language='por'))
|
||||||
|
self._CheckTestResults('audio-video-with-language-override')
|
||||||
|
|
||||||
|
def testPackageAudioVideoWithLanguageOverrideUsingMixingCode(self):
|
||||||
|
self.assertPackageSuccess(
|
||||||
|
self._GetStreams(['audio', 'video'], language='por'),
|
||||||
|
self._GetFlags(default_language='pt'))
|
||||||
|
self._CheckTestResults('audio-video-with-language-override')
|
||||||
|
|
||||||
|
def testPackageAudioVideoWithLanguageOverrideUsingMixingCode2(self):
|
||||||
|
self.assertPackageSuccess(
|
||||||
|
self._GetStreams(['audio', 'video'], language='pt'),
|
||||||
|
self._GetFlags(default_language='por'))
|
||||||
|
self._CheckTestResults('audio-video-with-language-override')
|
||||||
|
|
||||||
|
def testPackageAudioVideoWithLanguageOverrideUsingTwoCharacterCode(self):
|
||||||
|
self.assertPackageSuccess(
|
||||||
|
self._GetStreams(['audio', 'video'], language='pt'),
|
||||||
|
self._GetFlags(default_language='pt'))
|
||||||
self._CheckTestResults('audio-video-with-language-override')
|
self._CheckTestResults('audio-video-with-language-override')
|
||||||
|
|
||||||
def testPackageAudioVideoWithLanguageOverrideWithSubtag(self):
|
def testPackageAudioVideoWithLanguageOverrideWithSubtag(self):
|
||||||
|
@ -623,6 +645,32 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
self._GetFlags(output_hls=True))
|
self._GetFlags(output_hls=True))
|
||||||
self._CheckTestResults('avc-aac-ts')
|
self._CheckTestResults('avc-aac-ts')
|
||||||
|
|
||||||
|
def testPackageAvcAacTsLanguage(self):
|
||||||
|
# Currently we only support live packaging for ts.
|
||||||
|
self.assertPackageSuccess(
|
||||||
|
self._GetStreams(
|
||||||
|
['audio', 'video'],
|
||||||
|
output_format='ts',
|
||||||
|
segmented=True,
|
||||||
|
hls=True,
|
||||||
|
language='por',
|
||||||
|
test_files=['bear-640x360.ts']),
|
||||||
|
self._GetFlags(output_hls=True, default_language='por'))
|
||||||
|
self._CheckTestResults('avc-aac-ts-language')
|
||||||
|
|
||||||
|
def testPackageAvcAacTsLanguageUsingTwoCharacterCode(self):
|
||||||
|
# Currently we only support live packaging for ts.
|
||||||
|
self.assertPackageSuccess(
|
||||||
|
self._GetStreams(
|
||||||
|
['audio', 'video'],
|
||||||
|
output_format='ts',
|
||||||
|
segmented=True,
|
||||||
|
hls=True,
|
||||||
|
language='pt',
|
||||||
|
test_files=['bear-640x360.ts']),
|
||||||
|
self._GetFlags(output_hls=True, default_language='pt'))
|
||||||
|
self._CheckTestResults('avc-aac-ts-language')
|
||||||
|
|
||||||
def testPackageAvcAc3Ts(self):
|
def testPackageAvcAc3Ts(self):
|
||||||
# Currently we only support live packaging for ts.
|
# Currently we only support live packaging for ts.
|
||||||
self.assertPackageSuccess(
|
self.assertPackageSuccess(
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="audio" lang="pt-BR" subsegmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" lang="pt" subsegmentAlignment="true">
|
||||||
|
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
|
||||||
<Representation id="1" bandwidth="126510" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="126510" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<BaseURL>bear-640x360-audio.mp4</BaseURL>
|
<BaseURL>bear-640x360-audio.mp4</BaseURL>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,12 @@
|
||||||
|
#EXTM3U
|
||||||
|
#EXT-X-VERSION:6
|
||||||
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
|
#EXT-X-TARGETDURATION:2
|
||||||
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
#EXTINF:0.975,
|
||||||
|
bear-640x360-audio-1.ts
|
||||||
|
#EXTINF:0.998,
|
||||||
|
bear-640x360-audio-2.ts
|
||||||
|
#EXTINF:0.789,
|
||||||
|
bear-640x360-audio-3.ts
|
||||||
|
#EXT-X-ENDLIST
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
16
packager/app/test/testdata/avc-aac-ts-language/bear-640x360-video-iframe.m3u8
vendored
Normal file
16
packager/app/test/testdata/avc-aac-ts-language/bear-640x360-video-iframe.m3u8
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#EXTM3U
|
||||||
|
#EXT-X-VERSION:6
|
||||||
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
|
#EXT-X-TARGETDURATION:2
|
||||||
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
#EXT-X-I-FRAMES-ONLY
|
||||||
|
#EXTINF:1.001,
|
||||||
|
#EXT-X-BYTERANGE:15604@376
|
||||||
|
bear-640x360-video-1.ts
|
||||||
|
#EXTINF:1.001,
|
||||||
|
#EXT-X-BYTERANGE:18236@376
|
||||||
|
bear-640x360-video-2.ts
|
||||||
|
#EXTINF:0.667,
|
||||||
|
#EXT-X-BYTERANGE:19928@376
|
||||||
|
bear-640x360-video-3.ts
|
||||||
|
#EXT-X-ENDLIST
|
|
@ -0,0 +1,12 @@
|
||||||
|
#EXTM3U
|
||||||
|
#EXT-X-VERSION:6
|
||||||
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
|
#EXT-X-TARGETDURATION:2
|
||||||
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
|
#EXTINF:1.001,
|
||||||
|
bear-640x360-video-1.ts
|
||||||
|
#EXTINF:1.001,
|
||||||
|
bear-640x360-video-2.ts
|
||||||
|
#EXTINF:0.734,
|
||||||
|
bear-640x360-video-3.ts
|
||||||
|
#EXT-X-ENDLIST
|
|
@ -0,0 +1,9 @@
|
||||||
|
#EXTM3U
|
||||||
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
|
|
||||||
|
#EXT-X-MEDIA:TYPE=AUDIO,URI="bear-640x360-audio.m3u8",GROUP-ID="default-audio-group",LANGUAGE="pt",NAME="stream_0",DEFAULT=YES,AUTOSELECT=YES,CHANNELS="2"
|
||||||
|
|
||||||
|
#EXT-X-STREAM-INF:BANDWIDTH=1217518,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=640x360,AUDIO="default-audio-group"
|
||||||
|
bear-640x360-video.m3u8
|
||||||
|
|
||||||
|
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=238897,CODECS="avc1.64001e",RESOLUTION=640x360,URI="bear-640x360-video-iframe.m3u8"
|
|
@ -241,7 +241,7 @@ void BuildMediaTag(const MediaPlaylist& playlist,
|
||||||
tag.AddQuotedString("URI", base_url + playlist.file_name());
|
tag.AddQuotedString("URI", base_url + playlist.file_name());
|
||||||
tag.AddQuotedString("GROUP-ID", group_id);
|
tag.AddQuotedString("GROUP-ID", group_id);
|
||||||
|
|
||||||
const std::string& language = playlist.GetLanguage();
|
const std::string& language = playlist.language();
|
||||||
if (!language.empty()) {
|
if (!language.empty()) {
|
||||||
tag.AddQuotedString("LANGUAGE", language);
|
tag.AddQuotedString("LANGUAGE", language);
|
||||||
}
|
}
|
||||||
|
@ -292,7 +292,7 @@ void BuildMediaTags(
|
||||||
bool is_default = false;
|
bool is_default = false;
|
||||||
bool is_autoselect = false;
|
bool is_autoselect = false;
|
||||||
|
|
||||||
const std::string language = playlist->GetLanguage();
|
const std::string language = playlist->language();
|
||||||
if (languages.find(language) == languages.end()) {
|
if (languages.find(language) == languages.end()) {
|
||||||
is_default = !language.empty() && language == default_language;
|
is_default = !language.empty() && language == default_language;
|
||||||
is_autoselect = true;
|
is_autoselect = true;
|
||||||
|
|
|
@ -78,12 +78,12 @@ std::unique_ptr<MockMediaPlaylist> CreateAudioPlaylist(
|
||||||
std::unique_ptr<MockMediaPlaylist> playlist(
|
std::unique_ptr<MockMediaPlaylist> playlist(
|
||||||
new MockMediaPlaylist(kVodPlaylist, filename, name, group));
|
new MockMediaPlaylist(kVodPlaylist, filename, name, group));
|
||||||
|
|
||||||
EXPECT_CALL(*playlist, GetLanguage()).WillRepeatedly(Return(language));
|
|
||||||
EXPECT_CALL(*playlist, GetNumChannels()).WillRepeatedly(Return(channels));
|
EXPECT_CALL(*playlist, GetNumChannels()).WillRepeatedly(Return(channels));
|
||||||
|
|
||||||
playlist->SetStreamTypeForTesting(
|
playlist->SetStreamTypeForTesting(
|
||||||
MediaPlaylist::MediaPlaylistStreamType::kAudio);
|
MediaPlaylist::MediaPlaylistStreamType::kAudio);
|
||||||
playlist->SetCodecForTesting(codec);
|
playlist->SetCodecForTesting(codec);
|
||||||
|
playlist->SetLanguageForTesting(language);
|
||||||
|
|
||||||
EXPECT_CALL(*playlist, Bitrate())
|
EXPECT_CALL(*playlist, Bitrate())
|
||||||
.Times(AtLeast(1))
|
.Times(AtLeast(1))
|
||||||
|
@ -102,10 +102,10 @@ std::unique_ptr<MockMediaPlaylist> CreateTextPlaylist(
|
||||||
std::unique_ptr<MockMediaPlaylist> playlist(
|
std::unique_ptr<MockMediaPlaylist> playlist(
|
||||||
new MockMediaPlaylist(kVodPlaylist, filename, name, group));
|
new MockMediaPlaylist(kVodPlaylist, filename, name, group));
|
||||||
|
|
||||||
EXPECT_CALL(*playlist, GetLanguage()).WillRepeatedly(Return(language));
|
|
||||||
playlist->SetStreamTypeForTesting(
|
playlist->SetStreamTypeForTesting(
|
||||||
MediaPlaylist::MediaPlaylistStreamType::kSubtitle);
|
MediaPlaylist::MediaPlaylistStreamType::kSubtitle);
|
||||||
playlist->SetCodecForTesting(codec);
|
playlist->SetCodecForTesting(codec);
|
||||||
|
playlist->SetLanguageForTesting(language);
|
||||||
|
|
||||||
return playlist;
|
return playlist;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,22 @@ uint32_t GetTimeScale(const MediaInfo& media_info) {
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Duplicated from MpdUtils because:
|
||||||
|
// 1. MpdUtils header depends on libxml header, which is not in the deps here
|
||||||
|
// 2. GetLanguage depends on MediaInfo from packager/mpd/
|
||||||
|
// 3. Moving GetLanguage to LanguageUtils would create a a media => mpd dep.
|
||||||
|
// TODO(https://github.com/google/shaka-packager/issues/373): Fix this
|
||||||
|
// dependency situation and factor this out to a common location.
|
||||||
|
std::string GetLanguage(const MediaInfo& media_info) {
|
||||||
|
std::string lang;
|
||||||
|
if (media_info.has_audio_info()) {
|
||||||
|
lang = media_info.audio_info().language();
|
||||||
|
} else if (media_info.has_text_info()) {
|
||||||
|
lang = media_info.text_info().language();
|
||||||
|
}
|
||||||
|
return LanguageToShortestForm(lang);
|
||||||
|
}
|
||||||
|
|
||||||
void AppendExtXMap(const MediaInfo& media_info, std::string* out) {
|
void AppendExtXMap(const MediaInfo& media_info, std::string* out) {
|
||||||
if (media_info.has_init_segment_name()) {
|
if (media_info.has_init_segment_name()) {
|
||||||
Tag tag("#EXT-X-MAP", out);
|
Tag tag("#EXT-X-MAP", out);
|
||||||
|
@ -327,6 +343,10 @@ void MediaPlaylist::SetCodecForTesting(const std::string& codec) {
|
||||||
codec_ = codec;
|
codec_ = codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaPlaylist::SetLanguageForTesting(const std::string& language) {
|
||||||
|
language_ = language;
|
||||||
|
}
|
||||||
|
|
||||||
bool MediaPlaylist::SetMediaInfo(const MediaInfo& media_info) {
|
bool MediaPlaylist::SetMediaInfo(const MediaInfo& media_info) {
|
||||||
const uint32_t time_scale = GetTimeScale(media_info);
|
const uint32_t time_scale = GetTimeScale(media_info);
|
||||||
if (time_scale == 0) {
|
if (time_scale == 0) {
|
||||||
|
@ -347,6 +367,7 @@ bool MediaPlaylist::SetMediaInfo(const MediaInfo& media_info) {
|
||||||
|
|
||||||
time_scale_ = time_scale;
|
time_scale_ = time_scale;
|
||||||
media_info_ = media_info;
|
media_info_ = media_info;
|
||||||
|
language_ = GetLanguage(media_info);
|
||||||
use_byte_range_ = !media_info_.has_segment_template();
|
use_byte_range_ = !media_info_.has_segment_template();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -473,21 +494,6 @@ void MediaPlaylist::SetTargetDuration(uint32_t target_duration) {
|
||||||
target_duration_set_ = true;
|
target_duration_set_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicated from MpdUtils because:
|
|
||||||
// 1. MpdUtils header depends on libxml header, which is not in the deps here
|
|
||||||
// 2. GetLanguage depends on MediaInfo from packager/mpd/
|
|
||||||
// 3. Moving GetLanguage to LanguageUtils would create a a media => mpd dep.
|
|
||||||
// TODO: fix this dependency situation and factor this out to a common location
|
|
||||||
std::string MediaPlaylist::GetLanguage() const {
|
|
||||||
std::string lang;
|
|
||||||
if (media_info_.has_audio_info()) {
|
|
||||||
lang = media_info_.audio_info().language();
|
|
||||||
} else if (media_info_.has_text_info()) {
|
|
||||||
lang = media_info_.text_info().language();
|
|
||||||
}
|
|
||||||
return LanguageToShortestForm(lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MediaPlaylist::GetNumChannels() const {
|
int MediaPlaylist::GetNumChannels() const {
|
||||||
return media_info_.audio_info().num_channels();
|
return media_info_.audio_info().num_channels();
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,9 @@ class MediaPlaylist {
|
||||||
/// For testing only.
|
/// For testing only.
|
||||||
void SetCodecForTesting(const std::string& codec);
|
void SetCodecForTesting(const std::string& codec);
|
||||||
|
|
||||||
|
/// For testing only.
|
||||||
|
void SetLanguageForTesting(const std::string& language);
|
||||||
|
|
||||||
/// This must succeed before calling any other public methods.
|
/// This must succeed before calling any other public methods.
|
||||||
/// @param media_info is the info of the segments that are going to be added
|
/// @param media_info is the info of the segments that are going to be added
|
||||||
/// to this playlist.
|
/// to this playlist.
|
||||||
|
@ -167,10 +170,6 @@ class MediaPlaylist {
|
||||||
/// @param target_duration is the target duration for this playlist.
|
/// @param target_duration is the target duration for this playlist.
|
||||||
virtual void SetTargetDuration(uint32_t target_duration);
|
virtual void SetTargetDuration(uint32_t target_duration);
|
||||||
|
|
||||||
/// @return the language of the media, as an ISO language tag in its shortest
|
|
||||||
/// form. May be an empty string for video.
|
|
||||||
virtual std::string GetLanguage() const;
|
|
||||||
|
|
||||||
/// @return number of channels for audio. 0 is returned for video.
|
/// @return number of channels for audio. 0 is returned for video.
|
||||||
virtual int GetNumChannels() const;
|
virtual int GetNumChannels() const;
|
||||||
|
|
||||||
|
@ -178,6 +177,10 @@ class MediaPlaylist {
|
||||||
/// resolution values.
|
/// resolution values.
|
||||||
virtual bool GetDisplayResolution(uint32_t* width, uint32_t* height) const;
|
virtual bool GetDisplayResolution(uint32_t* width, uint32_t* height) const;
|
||||||
|
|
||||||
|
/// @return the language of the media, as an ISO language tag in its shortest
|
||||||
|
/// form. May be an empty string for video.
|
||||||
|
std::string language() const { return language_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Add a SegmentInfoEntry (#EXTINF).
|
// Add a SegmentInfoEntry (#EXTINF).
|
||||||
void AddSegmentInfoEntry(const std::string& segment_file_name,
|
void AddSegmentInfoEntry(const std::string& segment_file_name,
|
||||||
|
@ -200,6 +203,7 @@ class MediaPlaylist {
|
||||||
// Whether to use byte range for SegmentInfoEntry.
|
// Whether to use byte range for SegmentInfoEntry.
|
||||||
bool use_byte_range_ = false;
|
bool use_byte_range_ = false;
|
||||||
std::string codec_;
|
std::string codec_;
|
||||||
|
std::string language_;
|
||||||
int media_sequence_number_ = 0;
|
int media_sequence_number_ = 0;
|
||||||
bool inserted_discontinuity_tag_ = false;
|
bool inserted_discontinuity_tag_ = false;
|
||||||
int discontinuity_sequence_number_ = 0;
|
int discontinuity_sequence_number_ = 0;
|
||||||
|
|
|
@ -449,15 +449,15 @@ TEST_F(MediaPlaylistMultiSegmentTest, GetLanguage) {
|
||||||
// Check conversions from long to short form.
|
// Check conversions from long to short form.
|
||||||
media_info.mutable_audio_info()->set_language("eng");
|
media_info.mutable_audio_info()->set_language("eng");
|
||||||
ASSERT_TRUE(media_playlist_.SetMediaInfo(media_info));
|
ASSERT_TRUE(media_playlist_.SetMediaInfo(media_info));
|
||||||
EXPECT_EQ("en", media_playlist_.GetLanguage()); // short form
|
EXPECT_EQ("en", media_playlist_.language()); // short form
|
||||||
|
|
||||||
media_info.mutable_audio_info()->set_language("eng-US");
|
media_info.mutable_audio_info()->set_language("eng-US");
|
||||||
ASSERT_TRUE(media_playlist_.SetMediaInfo(media_info));
|
ASSERT_TRUE(media_playlist_.SetMediaInfo(media_info));
|
||||||
EXPECT_EQ("en-US", media_playlist_.GetLanguage()); // region preserved
|
EXPECT_EQ("en-US", media_playlist_.language()); // region preserved
|
||||||
|
|
||||||
media_info.mutable_audio_info()->set_language("apa");
|
media_info.mutable_audio_info()->set_language("apa");
|
||||||
ASSERT_TRUE(media_playlist_.SetMediaInfo(media_info));
|
ASSERT_TRUE(media_playlist_.SetMediaInfo(media_info));
|
||||||
EXPECT_EQ("apa", media_playlist_.GetLanguage()); // no short form exists
|
EXPECT_EQ("apa", media_playlist_.language()); // no short form exists
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MediaPlaylistMultiSegmentTest, GetNumChannels) {
|
TEST_F(MediaPlaylistMultiSegmentTest, GetNumChannels) {
|
||||||
|
|
|
@ -47,7 +47,6 @@ class MockMediaPlaylist : public MediaPlaylist {
|
||||||
MOCK_CONST_METHOD0(Bitrate, uint64_t());
|
MOCK_CONST_METHOD0(Bitrate, uint64_t());
|
||||||
MOCK_CONST_METHOD0(GetLongestSegmentDuration, double());
|
MOCK_CONST_METHOD0(GetLongestSegmentDuration, double());
|
||||||
MOCK_METHOD1(SetTargetDuration, void(uint32_t target_duration));
|
MOCK_METHOD1(SetTargetDuration, void(uint32_t target_duration));
|
||||||
MOCK_CONST_METHOD0(GetLanguage, std::string());
|
|
||||||
MOCK_CONST_METHOD0(GetNumChannels, int());
|
MOCK_CONST_METHOD0(GetNumChannels, int());
|
||||||
MOCK_CONST_METHOD2(GetDisplayResolution,
|
MOCK_CONST_METHOD2(GetDisplayResolution,
|
||||||
bool(uint32_t* width, uint32_t* height));
|
bool(uint32_t* width, uint32_t* height));
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
#include "packager/base/strings/string_number_conversions.h"
|
#include "packager/base/strings/string_number_conversions.h"
|
||||||
#include "packager/media/base/language_utils.h"
|
|
||||||
#include "packager/mpd/base/media_info.pb.h"
|
#include "packager/mpd/base/media_info.pb.h"
|
||||||
#include "packager/mpd/base/mpd_options.h"
|
#include "packager/mpd/base/mpd_options.h"
|
||||||
#include "packager/mpd/base/mpd_utils.h"
|
#include "packager/mpd/base/mpd_utils.h"
|
||||||
|
@ -167,11 +166,11 @@ class RepresentationStateChangeListenerImpl
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AdaptationSet::AdaptationSet(const std::string& lang,
|
AdaptationSet::AdaptationSet(const std::string& language,
|
||||||
const MpdOptions& mpd_options,
|
const MpdOptions& mpd_options,
|
||||||
base::AtomicSequenceNumber* counter)
|
base::AtomicSequenceNumber* counter)
|
||||||
: representation_counter_(counter),
|
: representation_counter_(counter),
|
||||||
lang_(lang),
|
language_(language),
|
||||||
mpd_options_(mpd_options),
|
mpd_options_(mpd_options),
|
||||||
segments_aligned_(kSegmentAlignmentUnknown),
|
segments_aligned_(kSegmentAlignmentUnknown),
|
||||||
force_set_segment_alignment_(false) {
|
force_set_segment_alignment_(false) {
|
||||||
|
@ -246,8 +245,8 @@ xml::scoped_xml_ptr<xmlNode> AdaptationSet::GetXml() {
|
||||||
if (id_)
|
if (id_)
|
||||||
adaptation_set.SetId(id_.value());
|
adaptation_set.SetId(id_.value());
|
||||||
adaptation_set.SetStringAttribute("contentType", content_type_);
|
adaptation_set.SetStringAttribute("contentType", content_type_);
|
||||||
if (!lang_.empty() && lang_ != "und") {
|
if (!language_.empty() && language_ != "und") {
|
||||||
adaptation_set.SetStringAttribute("lang", LanguageToShortestForm(lang_));
|
adaptation_set.SetStringAttribute("lang", language_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that std::{set,map} are ordered, so the last element is the max value.
|
// Note that std::{set,map} are ordered, so the last element is the max value.
|
||||||
|
|
|
@ -170,13 +170,13 @@ class AdaptationSet {
|
||||||
bool IsVideo() const;
|
bool IsVideo() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// @param lang is the language of this AdaptationSet. Mainly relevant for
|
/// @param language is the language of this AdaptationSet. Mainly relevant for
|
||||||
/// audio.
|
/// audio.
|
||||||
/// @param mpd_options is the options for this MPD.
|
/// @param mpd_options is the options for this MPD.
|
||||||
/// @param mpd_type is the type of this MPD.
|
/// @param mpd_type is the type of this MPD.
|
||||||
/// @param representation_counter is a Counter for assigning ID numbers to
|
/// @param representation_counter is a Counter for assigning ID numbers to
|
||||||
/// Representation. It can not be NULL.
|
/// Representation. It can not be NULL.
|
||||||
AdaptationSet(const std::string& lang,
|
AdaptationSet(const std::string& language,
|
||||||
const MpdOptions& mpd_options,
|
const MpdOptions& mpd_options,
|
||||||
base::AtomicSequenceNumber* representation_counter);
|
base::AtomicSequenceNumber* representation_counter);
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ class AdaptationSet {
|
||||||
base::AtomicSequenceNumber* const representation_counter_;
|
base::AtomicSequenceNumber* const representation_counter_;
|
||||||
|
|
||||||
base::Optional<uint32_t> id_;
|
base::Optional<uint32_t> id_;
|
||||||
const std::string lang_;
|
const std::string language_;
|
||||||
const MpdOptions& mpd_options_;
|
const MpdOptions& mpd_options_;
|
||||||
|
|
||||||
// An array of adaptation sets this adaptation set can switch to.
|
// An array of adaptation sets this adaptation set can switch to.
|
||||||
|
|
|
@ -155,14 +155,6 @@ TEST_F(AdaptationSetTest, CheckLanguageAttributeSet) {
|
||||||
EXPECT_THAT(adaptation_set->GetXml().get(), AttributeEqual("lang", "en"));
|
EXPECT_THAT(adaptation_set->GetXml().get(), AttributeEqual("lang", "en"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that language tags with subtags can still be converted.
|
|
||||||
TEST_F(AdaptationSetTest, CheckConvertLanguageWithSubtag) {
|
|
||||||
// "por-BR" is the long tag for Brazillian Portuguese. The short tag
|
|
||||||
// is "pt-BR", which is what should appear in the manifest.
|
|
||||||
auto adaptation_set = CreateAdaptationSet("por-BR");
|
|
||||||
EXPECT_THAT(adaptation_set->GetXml().get(), AttributeEqual("lang", "pt-BR"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AdaptationSetTest, CheckAdaptationSetId) {
|
TEST_F(AdaptationSetTest, CheckAdaptationSetId) {
|
||||||
auto adaptation_set = CreateAdaptationSet(kNoLanguage);
|
auto adaptation_set = CreateAdaptationSet(kNoLanguage);
|
||||||
const uint32_t kAdaptationSetId = 42;
|
const uint32_t kAdaptationSetId = 42;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
#include "packager/base/strings/string_number_conversions.h"
|
#include "packager/base/strings/string_number_conversions.h"
|
||||||
#include "packager/base/strings/string_util.h"
|
#include "packager/base/strings/string_util.h"
|
||||||
|
#include "packager/media/base/language_utils.h"
|
||||||
#include "packager/mpd/base/adaptation_set.h"
|
#include "packager/mpd/base/adaptation_set.h"
|
||||||
#include "packager/mpd/base/content_protection_element.h"
|
#include "packager/mpd/base/content_protection_element.h"
|
||||||
#include "packager/mpd/base/representation.h"
|
#include "packager/mpd/base/representation.h"
|
||||||
|
@ -81,7 +82,7 @@ std::string GetLanguage(const MediaInfo& media_info) {
|
||||||
} else if (media_info.has_text_info()) {
|
} else if (media_info.has_text_info()) {
|
||||||
lang = media_info.text_info().language();
|
lang = media_info.text_info().language();
|
||||||
}
|
}
|
||||||
return lang;
|
return LanguageToShortestForm(lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetCodecs(const MediaInfo& media_info) {
|
std::string GetCodecs(const MediaInfo& media_info) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ bool HasLiveOnlyFields(const MediaInfo& media_info);
|
||||||
void RemoveDuplicateAttributes(
|
void RemoveDuplicateAttributes(
|
||||||
ContentProtectionElement* content_protection_element);
|
ContentProtectionElement* content_protection_element);
|
||||||
|
|
||||||
// Returns a language tag. May be blank for video.
|
// Returns a language in ISO-639 shortest form. May be blank for video.
|
||||||
std::string GetLanguage(const MediaInfo& media_info);
|
std::string GetLanguage(const MediaInfo& media_info);
|
||||||
|
|
||||||
// Returns a 'codecs' string that has all the video and audio codecs joined with
|
// Returns a 'codecs' string that has all the video and audio codecs joined with
|
||||||
|
|
|
@ -847,6 +847,13 @@ Status Packager::Initialize(
|
||||||
hls_params.master_playlist_output = File::MakeCallbackFileName(
|
hls_params.master_playlist_output = File::MakeCallbackFileName(
|
||||||
internal->buffer_callback_params, hls_params.master_playlist_output);
|
internal->buffer_callback_params, hls_params.master_playlist_output);
|
||||||
}
|
}
|
||||||
|
// Both DASH and HLS require language to follow RFC5646
|
||||||
|
// (https://tools.ietf.org/html/rfc5646), which requires the language to be
|
||||||
|
// in the shortest form.
|
||||||
|
mpd_params.default_language =
|
||||||
|
LanguageToShortestForm(mpd_params.default_language);
|
||||||
|
hls_params.default_language =
|
||||||
|
LanguageToShortestForm(hls_params.default_language);
|
||||||
|
|
||||||
if (!mpd_params.mpd_output.empty()) {
|
if (!mpd_params.mpd_output.empty()) {
|
||||||
const bool on_demand_dash_profile =
|
const bool on_demand_dash_profile =
|
||||||
|
|
Loading…
Reference in New Issue