Skip to content
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

Channel count as an input feature #84

Merged

Conversation

mariocynicys
Copy link
Collaborator

@mariocynicys mariocynicys commented Jul 21, 2021

This PR removes the channels field from the pipeline configuration and replaces it with channel_layouts, a list of channel layouts to encode.
It also adds channel_layout field for Input class.

@mariocynicys
Copy link
Collaborator Author

We can also follow the VideoResolutionName approach and make an AudioChannelLayoutName and have a channel_layout field instead where the user can type in stereo, mono, etc..

@@ -146,6 +146,9 @@ class Input(configuration.Base):
Otherwise, it will default to 'und' (undetermined).
"""

channels = configuration.Field(int).cast()
"""The number of audio channels to encode."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more like "The number of channels in an audio input", right? It's less about encoding, and more about the structure of the input. Do I understand that right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, i feel a bit confused because of this too.
This is actually an output feature, the number of channels to encode in the final output file. sticking it with the each input(instead of the pipeline config) will allow us to give different channel counts for each input in a multi-period list.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another less confusing approach could be, to deal with it like resolutions, we may specify the channel counts we want as an output to be encoded with, and it's a list of channel counts rather than a single channel count and each input will be encoded with different channel counts up till its own channel count just like video resolutions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make sense to me. I like having it in the input, though, with auto-detection, just like resolution and frame rate for video inputs. If auto-detect fails, or if the input is coming from a pipe, rather than a file, we would need to be able to specify it in the input config.

So let's keep what you have (but fix the comment here on the field meaning), and then let's add a list of output channel counts in the pipeline config, just like we do for resolutions.

@@ -561,5 +561,5 @@ def validate(cls, key):

if key not in cls.map_class.keys():
raise ValueError(
'{} is not a valid {}'.format(key, cls.map_class.__name__))
'{} is not a valid {}, {}'.format(key, cls.map_class.__name__, cls.name()))
Copy link
Member

@joeyparrish joeyparrish Jul 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can tell re-reading the source, this now repeats cls.map_class.__name__, which is also printed by name() above:

"foo is not a valid VideoResolution, VideoResolution name (one of 720p, 1080p, ...)"

Should we drop cls.map_class.__name__ in favor of cls.name()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You read that write.
Yes i think we should drop it in favor of cls.name().

"""The number of audio channels to encode."""
channel_layouts = configuration.Field(
List[bitrate_configuration.AudioChannelLayoutName],
required=True).cast()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't agree with making this a required field. I think we should have a default value instead. Perhaps ['surround', 'stereo']. Not sure. What are your thoughts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fear that someone might provide a generic bitrate config that doesn't have stereo in it.

My thoughts is that we can default to a list that contains only the lowest channel_layout. So we read the channel_layouts using the BitrateConfig class and then provide this list as a default [AudioChannelLayout.sorted_values()[0].get_key()], now it will pick stereo by default, or, when a generic user provided bitrate config is there, it will pick the lowest of what ever the user has.

We can do the same for resolutions field as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too bad this is not gonna work :(,
Because channel_layouts and resolutions are class variables and are initialized at indexing time, so even before the bitrate config is provided.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you agree to the proposed idea above, we can monkey-patch the default of these fields in the __init__ of the PipelineConfig.
like this.

self.__class__.resolutions.default=[ # type: ignore
        bitrate_configuration.VideoResolution.sorted_values()[0].get_key()]
self.__class__.channel_layouts.default=[ # type: ignore
        bitrate_configuration.AudioChannelLayout.sorted_values()[0].get_key()]

we need the # type: ignore now because since we did the cast() for these class attributes, mypy will think they are actual [RuntimeMap] while they are actually Field instances.

tests/tests.js Outdated
'audio_codecs': ['aac', 'opus'],
};
await startStreamer(inputConfigDict, pipelineConfigDict);
await player.load(manifestUrl);

const trackList = player.getVariantTracks();
const audioCodecList = trackList.map(track => track.audioCodec);
let codecList = await getAudioAndVideoCodecs(manifestUrl)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: Add a semicolon at the end of this statement.

tests/tests.js Outdated
@@ -726,17 +740,17 @@ function codecTests(manifestUrl, format) {
const pipelineConfigDict = {
'streaming_mode': 'vod',
'resolutions': [],
'channel_layouts': ['stereo'],
'audio_codecs': ['aac', 'opus'],
};
await startStreamer(inputConfigDict, pipelineConfigDict);
await player.load(manifestUrl);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to call player.load() if you're using getAudioAndVideoCodecs(), which will do that internally.

@@ -307,6 +305,10 @@ class PipelineConfig(configuration.Base):


def __init__(self, *args) -> None:
self.__class__.resolutions.default=[ # type: ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since resolution and channel layout have a behavior of "use every option that doesn't upscale/upmix", perhaps the best default would be the entire list. Can you please try that and let me know how it goes? Also, please update the docstrings for those fields to say that they default to all defined values from the bitrate config.

@joeyparrish
Copy link
Member

Looks like there are a couple of conflicts with the Windows PR. Can you rebase/merge and fix those up please?


# The features that will be used to generate the output filename.
self._features = {
'language': input.language,
'channels': str(self.channels),
'channels': str(self.layout.max_channels),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like having this to be 'channel_layout': self.layout.get_key() instead.
@joeyparrish

@joeyparrish joeyparrish merged commit 5a5b53d into shaka-project:master Aug 10, 2021
@mariocynicys mariocynicys deleted the channel-as-input-feature branch August 10, 2021 04:05
@github-actions github-actions bot added the status: archived Archived and locked; will not be updated label Jul 25, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: archived Archived and locked; will not be updated
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants