# Shaka Player Manifest Upgrade Guide (v3.0)

v3.0 introduced many changes to the `shaka.extern.Manifest` structure.
This is a detailed guide for upgrading `ManifestParser` plugins or applications
using `Player.getManifest()` to extract information about content.  Any
application with a custom `ManifestParser` or which uses `Player.getManifest()`
MUST be upgraded for compatibility with v3.0.


#### Registration

In addition to registering new parsers or overriding existing ones with
{@link shaka.media.ManifestParser.registerParserByMime}, you can now also
unregister them with {@link shaka.media.ManifestParser.unregisterParserByMime}.


#### Manifest and Period-flattening

The {@link shaka.extern.Manifest} structure has changed.  The concept of
"Periods", based closely on DASH, has been removed.  Many individual parts of
the manifest structure have changed to make this possible.  In this section, we
will give a high-level view of the changes.  In the sections below, you will
find details on the changes to the various parts of the `Manifest` structure and
the `ManifestParser` plugin interfaces.

If you have a custom `ManifestParser` plugin that parses multi-Period DASH
content, you will need to consider how `<Representation>`s connect across
`<Period>`s.  Each {@link shaka.extern.Stream} now comprises the entire
presentation, and {@link shaka.media.SegmentReference} timestamps are no longer
Period-relative.

If you have a custom `ManifestParser` plugin that parses other formats, or if
your application reads the `Manifest` structure, you will just need to move a
few fields and make some relatively minor API updates as detailed below.

In v2.5, `Manifest` objects contained `Period`s, and each `Period` contained
fields named `variants` and `textStreams`.  These fields are now part of the
top-level `Manifest` structure, and the `Stream` objects that make them up now
span all DASH Periods.  `ManifestParser` plugins MUST be updated to move these
fields, and applications which read the `Manifest` object MUST be updated to
look for them in the new location.


#### Filtering

The {@link shaka.extern.ManifestParser.PlayerInterface} structure has changed.
Instead of `filterNewPeriod` and `filterAllPeriods`, there is now a single
callback: {@link shaka.extern.ManifestParser.PlayerInterface#filter}.  This
should be invoked any time new text streams or variants are added to the
manifest.  `ManifestParser` plugins MUST be updated to use the new callback.
Keep in mind that the new `filter` method is asynchronous, and thus it should
probably be used in conjunction with `.then()` or `await`.

```js
// v2.5:
// Call this after the initial parsing
this.playerInterface_.filterAllPeriods(periods);

// Call this after any new periods are added
this.playerInterface_.filterNewPeriod(someNewPeriod);

// v3.0:
// Call this after the initial parsing or after any new streams are added
await this.playerInterface_.filter(manifest);
```


#### PresentationTimeline

The API for {@link shaka.media.PresentationTimeline} has changed.
`ManifestParser` plugins that use these methods MUST be updated:

  - {@link shaka.media.PresentationTimeline#notifySegments} now takes a
    reference array only, instead of a reference array and a Period start time
    or boolean flag.

```js
// v2.4:
timeline.notifySegments(segmentList, /* periodStart= */ 0);

// v2.5:
timeline.notifySegments(segmentList, /* isFirstPeriod= */ true);

// v3.0:
timeline.notifySegments(segmentList);
```


#### DrmInfo

The {@link shaka.extern.DrmInfo} structure has changed.  The `keyIds` field is
now a `Set` of `string`s instead of an `Array`.  `ManifestParser` plugins MUST
be updated to return the correct type, and applications which read this part of
the `Manifest` structure MUST be updated to interact with `Set` instead of an
`Array`.


#### Variant

The {@link shaka.extern.Variant} structure has changed.  The `drmInfos` field
has moved to {@link shaka.extern.Stream}.  `ManifestParser` plugins MUST be
updated to output this field on the correct object.


#### Stream

The {@link shaka.extern.Stream} structure has changed.

The `drmInfos` field that used to appear in {@link shaka.extern.Variant} has
been moved here.  `ManifestParser` plugins MUST be updated to output this field
on the correct object.

The `findSegmentPosition` and `getSegmentReference` callbacks have been replaced
with `segmentIndex`, an instance of {@link shaka.media.SegmentIndex}.
`ManifestParser` plugins MUST be updated to output a `segmentIndex` instead of
these callbacks.  (In many cases, you may have been basing these callbacks on a
`SegmentIndex` object's `find` and `get` methods already.)

The `initSegmentReference` and `presentationTimeOffset` fields are no longer
part of `Stream`.  This information has moved to
{@link shaka.media.SegmentReference}.  `ManifestParser` plugins MUST be updated
accordingly.  See the section on `SegmentReference` for details.

The `keyId` field, a string, has been replaced with the `keyIds` field, a `Set`
of `string`s.  `ManifestParser` plugins MUST be updated to output the new field.


#### InitSegmentReference

The {@link shaka.media.InitSegmentReference} API has changed.  The `createUris`
methods has been removed, as it was redundant.  Applications with custom
`ManifestParser` plugins and applications which read `InitSegmentReference`s
MUST be updated to use `getUris` instead.


#### SegmentReference

The {@link shaka.media.SegmentReference} API has changed.  Applications with
custom `ManifestParser` plugins and applications which read `SegmentReference`s
MUST be updated to account for all changes below.

The `createUris` methods has also been removed, as it was redundant.  Use
`getUris` instead.

`SegmentReference` objects no longer have any internal concept of "position".
The `getPosition` method has been removed, and the constructor no longer takes a
position parameter.

`SegmentReference` timestamps are no longer relative to the Period.  Instead,
they are presentation timestamps.  For example, if the Period starts at 100 and
the segment begins at time 5 within that Period, `startTime` will now be 105.

`SegmentReference` objects now contain their `InitSegmentReference`.  This
allows the segments within a `Stream` to change init segments mid-stream, which
is used both for multi-Period DASH and for HLS discontinuities.  If two segments
have the same initialization segment, their `SegmentReference`s MUST have the
same `InitSegmentReference` object at the same memory address.
`StreamingEngine` will compare `InitSegmentReference` objects to determine when
a new init segment must be fetched, and this will NOT be a deep comparison of
the contents of the object.

`SegmentReference` objects now contain an append window.  This is used to trim
content in `MediaSource`.  For multi-Period content, this is the start and end
of the Period from which the segment comes.  For other content, the start is
usually 0 and the end is usually `Infinity`.

`SegmentReference` objects now contain a timestamp offset.  `MediaSource` adds
this value to the timestamps in the media segment when it is parsed by the
browser.  This should be the value which aligns the media timestamps (in the
segment) to the presentation timestamps (in the `SegmentReference`).  This is
related to the `presentationTimeOffset` from v2.5 and earlier.
`timestampOffset` should be the period start time minus the
`presentationTimeOffset`.  (In v2.5, this is how `MediaSource`'s
`timestampOffset` field was calculated.  Now, we pass the `timestampOffset`
field from the `SegmentReference` directly to `MediaSource`.)

```js
// v2.5
const period = {
  startTime: 100,
  /* ... */
};
const initSegmentReference = /* ... */;
const stream = {
  /* ... */
  initSegmentReference,
  presentationTimeOffset: 20,
};
const ref = new shaka.media.SegmentReference(
    /* position= */ 0,
    /* startTime= */ 0,
    /* endTime= */ 10,
    /* uris= */ () => [uri],
    /* startByte= */ 0,
    /* endByte= */ null);

// v3.0
const ref = new shaka.media.SegmentReference(
    /* startTime= */ 100,  // <-- period start 100 + period-relative timestamp 0
    /* endTime= */ 110,
    /* uris= */ () => [uri],
    /* startByte= */ 0,
    /* endByte= */ null,
    initSegmentReference,
    /* timestampOffset= */ 80,  // <-- period start 100 - PTO 20
    /* appendWindowStart= */ 100,  // <-- period start
    /* appendWindowEnd= */ Infinity);  // <-- for the last period in live stream
```


#### SegmentIndex

The {@link shaka.media.SegmentIndex} API has changed.  Applications with custom
`ManifestParser` plugins and applications which read `SegmentIndex`es MUST be
updated to account for all changes below.

The asynchronous `destroy` method has been replaced with the synchronous
`release` method.  Applications which destroy `SegmentIndex` objects SHOULD be
updated to call `release` instead.  Backward compatibility will be removed in
v4.0.

The `find` method still returns a position which can be passed to `get`, but
this position is no longer part of the underlying `SegmentReference` object.
(See changes to `SegmentReference` in the section above.)  The value returned
from `find` is now abstract.  This should be completely compatible with v2.5,
but the value can no longer be tied to a `SegmentReference`.

The `merge` method has been simplified.  It was already documented to only
support extending the reference array without replacing anything or interleaving
new references into the old ones.  Now it is actually a true statement about the
implementation.  If your custom `ManifestParser` plugin was relying on the old
merge behavior rather than its documentation, you MUST update your plugin.

The `evict` method now takes a presentation timestamp.  See related changes in
the `SegmentReference` section above.

The `fit` method now takes a window start and end time instead of a period
duration.  See related changes in the `SegmentReference` section above.

The `updateEvery` method has been added.  This allows `ManifestParser` plugins
to schedule callbacks to calculate additional `SegmentReference`s to be appended
to the reference array.  This is useful, for example, in generating references
for `<SegmentTemplate>` content in DASH.

The static `forSingleSegment` method has been added.  It will generate a
`SegmentIndex` for a single segment based on a start time, duration, and URIs.
This is useful for `ManifestParser` plugins creating non-segmented text
`Stream`s.

Finally, `SegmentIndex` now implements the `Iterable` protocol.  This means
applications can now iterate through the index or convert it to an Array.  For
example:

```js
for (const reference of stream.segmentIndex) {
  // ...
}

// OR

const listOfReferences = Array.from(stream.segmentIndex);

// OR

const firstReference = Array.from(stream.segmentIndex)[0];
```

This could be useful to applications which read the contents of a `Manifest`.
