-
Notifications
You must be signed in to change notification settings - Fork 506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding allow_codec_switching parameter #726
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this feature request. I left a few comments.
Also, can you add an end to end test in packager_test.py like you have done before in #721?
@@ -62,3 +62,8 @@ DEFINE_bool( | |||
"completely." | |||
"Ignored if $Time$ is used in segment template, since $Time$ requires " | |||
"accurate Segment Timeline."); | |||
DEFINE_bool(allow_codec_switching, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block is not formatted correctly. Please follow either the blocks from line 49 - 52 or the blocks from line 53 - 64. Alternatively, you may need to use clang-format: https://github.com/google/shaka-packager/blob/master/packager/tools/git/check_formatting.py
packager/app/mpd_flags.cc
Outdated
false, | ||
"if enabled, allow switching between different codecs, if they " | ||
"have the same language, media type (audio, video etc) and " | ||
"container type"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a period, i.e. "." after type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/switching/adaptive switching/
packager/mpd/base/adaptation_set.cc
Outdated
@@ -165,12 +165,14 @@ class RepresentationStateChangeListenerImpl | |||
|
|||
AdaptationSet::AdaptationSet(const std::string& language, | |||
const MpdOptions& mpd_options, | |||
uint32_t* counter) | |||
uint32_t* counter, | |||
const MediaInfo& media_info) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move "const MediaInfo& media_info" before "uint32_t* counter".
We follow Google C++ style guide, where input parameters are always placed before output parameters: https://google.github.io/styleguide/cppguide.html#Output_Parameters.
I thought about it again. This change is probably not needed if we don't plan to refactor out ProtectedContentMap.
Instead, what you need is to change line 85 of period.cc to include the bool flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kqyang Just including the bool flag on line 85 will not create a new adaptation set along with switching supplemental property. I will take a look into refactoring out ProtectedContentMap. Please let me know if you have any pointers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just including the bool flag on line 85 will not create a new adaptation set along with switching supplemental property
There are a few additional changes associated with that. See below:
// AdaptationSets with the same key could differ in ContentProtection or codec (depends
// on whether codec switching is allowed).
const std::string key = GetAdaptationSetKey(media_info, mpd_options_.allow_codec_switching);
std::list<AdaptationSet*>& adaptation_sets = adaptation_set_list_map_[key];
for (AdaptationSet* adaptation_set : adaptation_sets) {
// TODO: Change Match to check if codecs is the same too.
if (protected_adaptation_set_map_.Match(*adaptation_set, media_info))
return adaptation_set;
}
// None of the adaptation sets match with the new content protection.
// Need a new one.
const std::string language = GetLanguage(media_info);
std::unique_ptr<AdaptationSet> new_adaptation_set =
NewAdaptationSet(language, mpd_options_, representation_counter_);
if (!SetNewAdaptationSetAttributes(language, media_info, adaptation_sets,
new_adaptation_set.get())) {
return nullptr;
}
if (content_protection_in_adaptation_set &&
media_info.has_protected_content()) {
protected_adaptation_set_map_.Register(*new_adaptation_set, media_info);
AddContentProtectionElements(media_info, new_adaptation_set.get());
}
for (AdaptationSet* adaptation_set : adaptation_sets) {
if (protected_adaptation_set_map_.Switchable(*adaptation_set,
*new_adaptation_set)) {
adaptation_set->AddAdaptationSetSwitching(new_adaptation_set.get());
new_adaptation_set->AddAdaptationSetSwitching(adaptation_set);
}
}
I will take a look into refactoring out ProtectedContentMap. Please let me know if you have any pointers.
That will be great. I think we can start with the change above and we can file a separate issue for the refactoring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For comparing the codec in Match(), do you think adding codec as AdaptationSet member and setting it via SetNewAdaptationSetAttributes make sense or is there any other way to access codec info?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized that you can store the codec in AdaptationSet::UpdateFromMediaInfo function.
packager/mpd/base/adaptation_set.h
Outdated
@@ -135,6 +135,9 @@ class AdaptationSet { | |||
/// @param id is the new ID to be set. | |||
void set_id(uint32_t id) { id_ = id; } | |||
|
|||
/// Get media info. | |||
const MediaInfo& getMediaInfo() const { return media_info_;} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/getMediaInfo/media_info/ to be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed mediainfo from adaptation set
packager/mpd/base/mpd_utils.cc
Outdated
@@ -142,7 +142,7 @@ std::string GetBaseCodec(const MediaInfo& media_info) { | |||
return codec; | |||
} | |||
|
|||
std::string GetAdaptationSetKey(const MediaInfo& media_info) { | |||
std::string GetAdaptationSetKey(const MediaInfo& media_info, bool no_codec) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/no_codec/ignore_codec/
packager/mpd/base/period.h
Outdated
@@ -130,7 +131,8 @@ class Period { | |||
const MediaInfo& media_info); | |||
// Check if the two adaptation sets are switchable. | |||
bool Switchable(const AdaptationSet& adaptation_set_a, | |||
const AdaptationSet& adaptation_set_b); | |||
const AdaptationSet& adaptation_set_b, | |||
const bool allow_codec_switching); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove const here. We don't prefix primitive types with const in this code base.
packager/mpd/base/period.h
Outdated
@@ -88,7 +88,8 @@ class Period { | |||
virtual std::unique_ptr<AdaptationSet> NewAdaptationSet( | |||
const std::string& lang, | |||
const MpdOptions& options, | |||
uint32_t* representation_counter); | |||
uint32_t* representation_counter, | |||
const MediaInfo& media_info); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment. Move media_info before representation_counter.
packager/mpd/base/period.cc
Outdated
@@ -112,12 +112,26 @@ AdaptationSet* Period::GetOrCreateAdaptationSet( | |||
|
|||
for (AdaptationSet* adaptation_set : adaptation_sets) { | |||
if (protected_adaptation_set_map_.Switchable(*adaptation_set, | |||
*new_adaptation_set)) { | |||
*new_adaptation_set, false)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code here shouldn't need to be updated if you don't plan to refactor ProtectedAdaptationSetMap out.
Instead, what you need is to change line 85 to include the bool flag.
packager/mpd/base/mpd_utils.h
Outdated
@@ -47,7 +47,8 @@ std::string GetCodecs(const MediaInfo& media_info); | |||
std::string GetBaseCodec(const MediaInfo& media_info); | |||
|
|||
// Returns a key made from the characteristics that separate AdaptationSets. | |||
std::string GetAdaptationSetKey(const MediaInfo& media_info); | |||
std::string GetAdaptationSetKey(const MediaInfo& media_info, | |||
bool no_codec = false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't normally allow default parameters, which could hide problems. Please do not use default parameter here.
@kqyang CI jobs are failing. Please review and let me know. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sr1990 Good job! A few more comments. Appreciated your work on this change.
packager/mpd/base/adaptation_set.h
Outdated
@@ -183,7 +183,7 @@ class AdaptationSet { | |||
/// @param mpd_type is the type of this MPD. | |||
/// @param representation_counter is a Counter for assigning ID numbers to | |||
/// Representation. It can not be NULL. | |||
AdaptationSet(const std::string& language, | |||
AdaptationSet(const std::string& language, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the extra whitespace in the beginning.
packager/mpd/base/adaptation_set.h
Outdated
@@ -269,6 +269,9 @@ class AdaptationSet { | |||
// Determined by examining the MediaInfo passed to AddRepresentation(). | |||
std::string content_type_; | |||
|
|||
// Codec of AdaptationSet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an ending period ".".
packager/mpd/base/mpd_utils.h
Outdated
@@ -47,7 +47,8 @@ std::string GetCodecs(const MediaInfo& media_info); | |||
std::string GetBaseCodec(const MediaInfo& media_info); | |||
|
|||
// Returns a key made from the characteristics that separate AdaptationSets. | |||
std::string GetAdaptationSetKey(const MediaInfo& media_info); | |||
std::string GetAdaptationSetKey(const MediaInfo& media_info, | |||
bool ignore_codec); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align "bool" with "const". If they fit in the same line (<=80), move to the same line.
packager/mpd/public/mpd_params.h
Outdated
@@ -80,6 +80,9 @@ struct MpdParams { | |||
/// SegmentTimeline if it is enabled. It will be populated from segment | |||
/// duration specified in ChunkingParams if not specified. | |||
double target_segment_duration = 0; | |||
///If enabled, allow switching between different codecs, if they have the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a space before "If". Same below.
packager/mpd/base/period.cc
Outdated
@@ -82,19 +83,17 @@ AdaptationSet* Period::GetOrCreateAdaptationSet( | |||
// AdaptationSets with the same key should only differ in ContentProtection, | |||
// which also means that if |content_protection_in_adaptation_set| is false, | |||
// there should be at most one entry in |adaptation_sets|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you update or remove this comment as it no longer applies?
packager/mpd/base/adaptation_set.cc
Outdated
@@ -412,10 +412,16 @@ void AdaptationSet::UpdateFromMediaInfo(const MediaInfo& media_info) { | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer just set
codec_ = GetCodecs(media_info);
packager/mpd/base/period.cc
Outdated
base::SPLIT_WANT_NONEMPTY)[0]) != 0) | ||
return false; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is SplitString needed?
with the change suggested above in line 412 of adaptation_set.cc, we can just do:
if (adaptation_set.codec() != GetCodecs(media_info))
return false;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetCodecs returns the entire codec string (avc1.4d400d,avc1.4d401f, etc) if container type is not webm. Should I change the GetCodecs to return media_info.video_info().codec().substr(0, 4); for all container types or keep the SplitString in Match?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good catch, we shouldn't be using the entire codec string as two different representations in the same adaptation set could have two different codec strings.
Please replace GetCodecs with GetBaseCodec instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TrickPlayWithMatchingAdaptationSet unit test is failing as the codec in default_adaptation_set_ is not set because of no call to UpdateFromMediaInfo.
So, instead of setting codec from AdaptationSet::UpdateFromMediaInfo do you think it would make sense to set it at Period::SetNewAdaptationSetAttributes. If not, how would you change the unit test in this case? I tried calling the UpdateFromMediaInfo directly but that did not work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. You may add a AdaptationSet::set_codec(const std::string& codec) function and call it in Period::SetNewAdaptationSetAttributes.
(This tells me that we should really refactor the code later to clean up the code and remove ProtectedContentMap)
@@ -269,6 +269,9 @@ class AdaptationSet { | |||
// Determined by examining the MediaInfo passed to AddRepresentation(). | |||
std::string content_type_; | |||
|
|||
// Codec of AdaptationSet | |||
std::string codec_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also define an accessor for codec_ after line 178:
/// @return codec.
std::string codec() const { return codec_; }
|
||
self.assertPackageSuccess(streams, self._GetFlags(output_dash=True,allow_codec_switching=True)) | ||
self._CheckTestResults('audio-video-with-codec-switching') | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add another variant with encryption and trick play?
def testAllowCodecSwitchingWithEncryptionAndTrickplay(self):
streams = [
self._GetStream('video', test_file='bear-640x360-hevc.mp4'),
self._GetStream('video', test_file='bear-640x360.mp4'),
self._GetStream('video', test_file='bear-1280x720.mp4'),
self._GetStream('video', test_file='bear-1280x720.mp4', trick_play_factor=1),
self._GetStream('audio', test_file='bear-640x360.mp4'),
]
self.assertPackageSuccess(streams,
self._GetFlags(output_dash=True,
allow_codec_switching=True,
encryption=True))
# Mpd cannot be validated right now since we don't generate determinstic
# mpd with multiple inputs due to thread racing.
# TODO(b/73349711): Generate determinstic mpd or at least validate mpd
# schema.
# See also https://github.com/google/shaka-packager/issues/177.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops, I forgot one additional line here in my previous comment:
self._CheckTestResults(
'audio-video-with-codec-switching-encryption-trick-play',
diff_files_policy=DiffFilesPolicy(
allowed_diff_files=['output.mpd'], exact=False))
Similar for the test above:
self._CheckTestResults(
'audio-video-with-codec-switching',
diff_files_policy=DiffFilesPolicy(
allowed_diff_files=['output.mpd'], exact=False))
packager/app/test/packager_test.py
Outdated
] | ||
|
||
self.assertPackageSuccess(streams, self._GetFlags(output_dash=True,allow_codec_switching=True)) | ||
self._CheckTestResults('audio-video-with-codec-switching') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this line has to be removed as we don't generate determinstic mpd with multiple inputs right now.
Replace it with:
# Mpd cannot be validated right now since we don't generate determinstic
# mpd with multiple inputs due to thread racing.
# TODO(b/73349711): Generate determinstic mpd or at least validate mpd
# schema.
# See also https://github.com/google/shaka-packager/issues/177.
…t#728) It happens if `git` is not installed as a standard alone application, but as a shell command. Fixes shaka-project#724.
All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the ℹ️ Googlers: Go here for more info. |
1 similar comment
All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the ℹ️ Googlers: Go here for more info. |
@googlebot I consent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks very good to me. I have only a few more style comments. Thanks.
packager/app/test/packager_test.py
Outdated
self._GetStream('video', test_file='bear-640x360.mp4'), | ||
self._GetStream('video', test_file='bear-1280x720.mp4'), | ||
self._GetStream('video', test_file='bear-1280x720.mp4', | ||
trick_play_factor=1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think trick_play_factor should align with 'video' above. You may use 'pyformat' to align it properly (there could be other formatting issues in this file, so it is fine to leave it as is for now and do it in a separate pull request or leave it to us to address).
packager/mpd/base/adaptation_set.h
Outdated
@@ -176,6 +176,13 @@ class AdaptationSet { | |||
/// @return true if it is a video AdaptationSet. | |||
bool IsVideo() const; | |||
|
|||
/// @return codec. | |||
std::string codec() const { return codec_; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use const reference to avoid unnecessary copying:
const std::string& codec() const { return codec_; }
packager/mpd/base/period.cc
Outdated
@@ -7,6 +7,7 @@ | |||
#include "packager/mpd/base/period.h" | |||
|
|||
#include "packager/base/stl_util.h" | |||
#include "packager/base/strings/string_split.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no. removed it.
packager/mpd/base/period.cc
Outdated
@@ -176,7 +173,8 @@ bool Period::SetNewAdaptationSetAttributes( | |||
const std::string& language, | |||
const MediaInfo& media_info, | |||
const std::list<AdaptationSet*>& adaptation_sets, | |||
AdaptationSet* new_adaptation_set) { | |||
AdaptationSet* new_adaptation_set, | |||
bool content_protection_in_adaptation_set) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swap the order of the last two parameters as Google C++ style guide requires the input argument to be placed before the output argument: https://google.github.io/styleguide/cppguide.html#Output_Parameters
@@ -80,6 +80,9 @@ struct MpdParams { | |||
/// SegmentTimeline if it is enabled. It will be populated from segment | |||
/// duration specified in ChunkingParams if not specified. | |||
double target_segment_duration = 0; | |||
/// If enabled, allow switching between different codecs, if they have the | |||
/// same language, media type (audio, video etc) and container type. | |||
bool allow_codec_switching = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally we don't pull changes from master, which may cause confusions to the bots as seen in this PR. I'll see if I can merge it with this later.
@kqyang Do you think it makes sense to check and add audio channel count to adaptation set key in mpd_utils.cc:GetAdaptationSetKey when allow_codec_switching parameter is set to true ? |
Audio streams with different number of channels can be put in the same AdaptationSet, regardless of the |
I think adaptive switch between audio with different channels won't be seamless. So for players that do not handle this case, we could add a flag (--allow_audio_mixed_channel_count set to true by default) on the packager side to disable audio representations with different channel counts in the same adaptation set or we could let the players handle it. What do you think? |
@sr1990 So ExoPlayer already handles the case of a single AdaptationSet with audio streams of different number of channels, the feature for packager is not helpful for ExoPlayer. It seems that it may create problems instead, as people would have to package two sets of contents if they want to enable adaptive switching between different audio streams in one platform but disable it in another platform. |
|
This PR is related to #542 .
Adding allow_codec_switching=true, will allow switching between different codecs, if they have the same language, media type (audio, video etc) and container type.