-
Notifications
You must be signed in to change notification settings - Fork 54
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
Parse <SegmentList> and <SegmentBase> #18
Conversation
Merge in segment template changes
Support for inheriting BaseURL and alternate BaseURLs (#17)
src/toPlaylists.js
Outdated
@@ -18,16 +13,13 @@ export const generateSegments = (segmentInfo, attributes) => { | |||
|
|||
// TODO |
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.
probably not a TODO anymore
src/errors.js
Outdated
@@ -2,5 +2,8 @@ export default { | |||
INVALID_NUMBER_OF_PERIOD: 'INVALID_NUMBER_OF_PERIOD', | |||
DASH_EMPTY_MANIFEST: 'DASH_EMPTY_MANIFEST', | |||
DASH_INVALID_XML: 'DASH_INVALID_XML', | |||
UNSUPPORTED_SEGMENTATION_TYPE: 'UNSUPPORTED_SEGMENTATION_TYPE' | |||
UNSUPPORTED_SEGMENTATION_TYPE: 'UNSUPPORTED_SEGMENTATION_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.
No need for this error
src/inheritAttributes.js
Outdated
shallowMerge(getAttributes(segmentList), | ||
{ | ||
segmentUrls: segmentUrls && | ||
segmentUrls.map(s => |
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.
you could move this map
to findChildren(segmentList, 'SegmentURL').map(...
, then this just becomes { segmentUrls }
// Since we're mapping we should get rid of any blank segments (in case | ||
// the given SegmentTimeline is handling for more elements than we have | ||
// SegmentURLs for). | ||
}).filter(segment => segment); |
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 common/supposed/allowed to happen? What cases cause this?
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.
So... this shouldn't happen if the mpd is well constructed. But, let's say you have a segment timeline that defines r=10, but you only have 5 segments listed. We will have too many duration objects for the number of segments we have. I guess we could throw an error, but I felt like handling it and truncating made more sense in this case.
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.
Makes sense. I suppose its either we crash up front, or play what we can parse and just have an incomplete video, which is better than no video
|
||
// return segmentsFromList(attributes); | ||
return segmentsFromList( | ||
shallowMerge(segmentInfo.list, attributes), segmentInfo.timeline |
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 anything in attributes
overlap with segmentInfo.list
(and segmentInfo.base
for above)? If so we probably want to swap the order of the arguments so any overlapping values take from segmentInfo
. If not then no need
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.
Which makes me realize, I should double check for segment template
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.
In either case it seems safer to swap the order.
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.
It doesn't look like there will be any overlap. Depending on how Initialization
tag is handled, will have to keep that in mind for SegmentTemplate
since it can have both the tag and attribute. I don't think we will encounter a manifest with SegmentTemplate that has both the attribute and tag, but if we do, we will want to make a choice on which takes precedence.
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 shouldn't encounter that scenario, but it's a possibility. I didn't see anything in the spec with guidance where @initialization
and <Initialization>
relate to the same <SegmentTemplate>
. So it seems it's up to our discretion. I made an assumption that if both are provided that the <Initialization>
will take precedence (and added a comment noting as much). Given the tree structure I think that makes sense.
The other options are to just error if this is the case (less permissive, and it is probably easier to move from less permissive -> more permissive) or @initialization
taking precedence.
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.
Makes sense to me 👍
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 will need <Initialization>
support. SegmentBase
and SegmentList
do not have an initialization
attribute and require the tag. SegmentTemplate
can have the tag or as an attribute. Right now template doesn't support the tag, you can add it to this pr if you want, or we can add it into another, but I think for List and Base support, we should have it. See Table 13 (5.3.9.2.2) for semantics, and 5.3.9.5.2 to see where it mentions List and Template can have the tag since the spec does not mention it in their respective definitions.
Edit: They also all seem to be able to have a <RepresentationIndex>
, but I'm not quite sure what that is for or if we need it just yet.
Ah, good catch, I missed that bit of nuance. I'll handle that in this PR. Edit: I'm going to leave |
src/segment/segmentTemplate.js
Outdated
}; | ||
} | ||
|
||
if (attributes.initialization && typeof attributes.initialization === 'object') { |
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.
Based on what I picked up off the spec, <Initialization>
doesn't get templated, but @initialization
does, which is why there is a difference here.
src/inheritAttributes.js
Outdated
const template = segmentTemplate && getAttributes(segmentTemplate); | ||
|
||
if (template && segmentInitialization) { | ||
template.initialization = getAttributes(segmentInitialization); |
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 it would be good if we can account for the string
vs object
here and have template.initialization
always be an object.
if (template) {
template.initialization = (segmentInitialization && getAttributes(segmentIntitialization) || { sourceURL: template.initialization || '' };
}
This way in segmentsFromTemplate
you do not need the extra code path for the string
src/segment/segmentTemplate.js
Outdated
if (attributes.initialization && typeof attributes.initialization === 'object') { | ||
mapSegment = urlTypeToSegment({ | ||
baseUrl: attributes.baseUrl, | ||
source: attributes.initialization.sourceURL, |
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.
With the changes proposed in my other comment to handle the string to object conversion in getSegmentInformation
, I think you can safely do
source: constructTemplateUrl(attributes.initialization.sourceURL, templateValues)
In the case that the <Initialization>
node took precedence, there shouldn't be any template identifiers, so constructTemplateUrl
here should just return the sourceURL
unchanged
src/segment/urlType.js
Outdated
resolvedUri: resolveUrl(baseUrl || '', source) | ||
}; | ||
|
||
if (source && range) { |
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 range
should be parsed even if source
is not available. According to the spec for @sourceURL
,
If not present, then any BaseURL element is mapped to the @sourceURL attribute and the range attribute shall be present.
The BaseURL
mapping is already handled by the resolvedUri
above, but this check would prevent parsing of the range that "shall be present"
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.
Good catch. I made an assumption that both were required but the existence of baseUrl makes that a poor assumption.
src/inheritAttributes.js
Outdated
const segmentTimelineNode = segmentList || segmentTemplate; | ||
const segmentTimeline = | ||
segmentTimelineNode && findChildren(segmentTimelineNode, 'SegmentTimeline')[0]; | ||
const segmentInitializationNode = segmentList || segmentBase || segmentTemplate; |
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.
These variable names are a bit misleading. segmentTimelineNode
and segmentInitializationNode
are actually the parent nodes of those nodes
src/inheritAttributes.js
Outdated
findChildren(segmentTimeline, 'S').map(s => getAttributes(s)), | ||
list: segmentList && getAttributes(segmentList), | ||
base: segmentBase && getAttributes(segmentBase) | ||
findChildren(segmentTimeline, 'S').map(s => getAttributes(s)), |
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 know that this line was added by me, including the indentation, but do you mind fixing the indentation here?
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.
Wonder why the linter didn't catch this one, I think it gave me a warning or error for the indentation under list:
and base:
.
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.
Ya I'm surprised I added it myself, and didn't catch it myself or with the linter. Its not even lined up with anything ha
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.
Note for future PR:
In 5.3.9.5.2 of the spec, this is specified
If neither Initialization element nor SegmentTemplate@initialization attribute are present for a Representation then each Media Segment within the Representation shall be self-initializing.
Right now when this scenario is encountered, this PR will still create a segment.map = { uri: '', resolvedUri: baseUrl }
with baseUrl
not being the location of an initialization segment.
In VHS, the existence of segment.map
is used to determine if the segments are fmp4 or ts, and VHS will automatically request the initialization segment specified in segment.map
without any checks, and appends the response to the source buffer.
We will have to think about how to handle this case, which can potentially require changes in both this project and VHS.
This adds the ability for us to parse SegmentList and SegmentBase.
There were some minor reshuffling as well (I don't think it's a huge deal to keep it in here, although I can do it as a seperate PR if that's desirable).
As a note the reshuffling includes:
segmentTemplate.js
into its own file since SegmentBase shares that logic with SegmentTemplate.resolveUrl.js
into theutils
folder.