The URL Service for the website GiantBomb is a fairly basic example of offering more than one video quality in your list of media objects. In this case:
def MediaObjectsForURL(url):
return [
MediaObject(
parts = [PartObject(key=Callback(PlayVideo, url=url, fmt='hi'))],
container = 'mp4',
bitrate = 1500,
optimized_for_streaming = True,
video_resolution = 'sd',
#aspect_ratio = '1.78',
video_codec = VideoCodec.H264,
audio_codec = AudioCodec.AAC,
audio_channels = 2
),
MediaObject(
parts = [PartObject(key=Callback(PlayVideo, url=url, fmt='lo'))],
container = 'mp4',
bitrate = 700,
optimized_for_streaming = True,
video_resolution = 'sd',
#aspect_ratio = '1.78',
video_codec = VideoCodec.H264,
audio_codec = AudioCodec.AAC,
audio_channels = 2
)
]
you can see that there are 2 quality options. One with a higher bitrate labelled as the 'hd', and one with the lower bitrate labelled 'sd'. In the 'key' for each PartObject of each MediaObject, we use a Callback for PlayVideo and you can see that there is an extra argument passed to the PlayVideo function. In this case the argument is specified as 'fmt' but what it's called matters only in terms of (1) matching how it is declared in the PlayVideo() function definition, and (2) that it make some kind of sense to someone trying to interpret the code. The metadata included in the MediaObjects is what the clients use to make their intelligent decisions about which MediaObject to select. Eg. If the highest bitrate is higher than the available network connection, request the lower bitrate option, or if the option #1 uses a codec which the client cannot play natively try option #2 or request a transcode/remux from PMS, etc.
In the PlayVideo() function:
@indirect
def PlayVideo(url, fmt=''):
clip = GetClip(url)
if not clip:
return None
if fmt == 'hi':
video_url = clip['high_url']
elif fmt == 'lo':
video_url = clip['low_url']
return IndirectResponse(VideoClipObject, key=video_url)
we see that the function definition includes the 'fmt' argument with a default value of an empty string. Then the function logic takes the value of that argument into consideration when determining what video url to return to the client. In this case the PlayVideo() function uses the @indirect decorator to indicate that the response from the function will be another ObjectContainer with a pointer to the actual media rather returning a link directly to the Media. There's a good chance you won't need to worry about that at this point so, we'll deal with that if/when it becomes relevant.