-
Notifications
You must be signed in to change notification settings - Fork 57
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
MediaSource in Worker #175
Comments
#14 also seems relevant here -- based on my reading of that bug it would help with part of this problem (once you fetch a segment you'd pass a stream to that audio to MediaSource and would bypass the main thread, or even a worker thread in terms of getting that data to where it needs to go). But that still leaves the issue of fetching a manifest and initiating a request for a segment |
That it's a bottleneck would be mostly a user agent implementation issue. I wish issue #100 progressed further, it would certainly facilitate handling those operations. |
The issue here isn't the cost of video on the main thread. The issue is that if the main thread is busy with other work (say the javascript needed to render a page) that it can not be responsive to input from the network. This means that the video will be slower to buffer even though the client has been able to get the video over the network. The goal is for the video loading code to be isolated on a worker thread where it can operate in real time without the risk of latency induced by work on the main thread. |
We are seeing the same issue on YouTube and I'd like to add our voice to support a solution here as well. Moving append buffer off the main thread would greatly simplify the juggling we need to do to prioritize video playback. |
It's great to see that youtube has the same take on this issue. Would it be worth taking the next step here and drafting out what a spec change would look like? I think we can model this on the offscreen canvas api (https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/)
Essentially MediaSource would offer an API which would pass control of the media source APIs to a worker thread. Any APIs that MediaSource offers (eg to add source buffers) would only be callable from the worker. MediaSource is a fairly complex API with a number of events / methods. It'd be great to get some feedback from @zhaoz, @DanielBaulig as well as folks who work on browsers and this spec to comment on what kind of threading issues might come up with this API. |
The main limitation with transferring MediaSource object that I can currently see is that in general most video player implementations heavily depend on certain video node attribute for determining which video segments to fetch and play. These are as far as I can tell primarily However, the API itself could have support for this: the worker could get copies of these values on every event loop exposed. This exposure could happen as part of the transferred MediaSource object, e.g. on a bag of exposed values or directly on the object:
Another problem may be that the main thread indirectly retains a reference to the MediaSource as an object URL on the videos |
That makes total sense. It does seem like the MediaSource API should be responsible for relaying that information -- accessing it directly from the video element seems like it violates layering and would make the threading far more difficult here. One other thing we should think about -- maybe this is a totally separate issue -- I worry about the latency of starting the worker, downloading the necessary JS, etc. On Facebook we've found that the amount of JS necessary to have the logic for streaming the video can be pretty high. I wonder if there's a way to allow the server to list the URLs necessary to start streaming so that they can be fetched and inserted into the buffer while the more advanced control starts up. |
I don't think there's anything preventing video player implementations from doing something like this currently. That said, in the context of a transferable MediaSource, this becomes a little harder. This could potentially mean creating a MediaSource object and several sourceBuffers on the main thread, appending data to the sourceBuffers and only later transferring ownership to the Worker. This transfer won't be simple anymore though since there's a complex mix of objects and possibly tasks that has to be dealt with. |
One of the issue in dealing with a sourcebuffer in a worker thread, is how, currently, the source buffer notifies that the current operation has completed: through events fired on the attached media element and which is only ever accessed on the main thread. So if your main thread is busy, no update/updateend event and you're back to the issue of not being able to keep up with your source buffer. This problem could be easily worked around if rather than relying on events such as update/updateend to know when you can feed new data to the source buffer we used Promises. The beauty with SourceBuffer::appendBuffer and SourceBuffer::remove with returning Promises is that it would be fully backward compatible. Once the appendBuffer operation has completed, resolve the Promise and queue update/updateend Making a SourceBuffer usable on a worker thread wouldn't be a too complicated task (famous last words) in gecko, the architecture is already asynchronous and thread-safe. But if we limit the interaction to the source buffer to appendBuffer and remove operations, and checking of the buffered range to be performed on the source buffers alone, and we use Promises then it should be straight forward. |
@#175 (comment), 'updateend' is fired on the SourceBuffer , not HTMLMediaElement. However, readyState transitions (and consequent events like 'loadedmetadata') would occur on the media element on the main thread. I'm less clear that Promises are required for MSE-on-SW, though I'm not opposed (I just don't want to tangle the two features). |
Here's a summary of this issue so far, from my understanding. I have a set of questions, below, for which web author input would be greatly appreciated. Proposals in [2] and [3] help to limit the scope of this to be specific to just MSE, and not require exposing all of HTMLMediaElement API also to Service Worker (SW): [2] Proposes that the MediaSource API be made “transferrable” to a SW [1] #175 Questions:
-- edit: substitute "Worker" for "Service Worker" in this post, please. I had conflated them. |
Am I assuming correctly that you are using the term Service Worker and the general Worker API interchangeably? I'll try to answer most of the questions for which I believe I have enough context:
This is probably not necessary. The
I am not sure I can answer this question.
We've spent some time internally thinking about this and we came to the conclusion that the entirety of the SourceBuffer API is probably the minimally viable subset of the API for the application. Having the MediaSource object itself available is preferred but not necessarily required. We believe though due to the amount of dependencies between the MediaSource object and it's SourceBuffer objects, that transferring the MediaSource object is likely the easier approach from a spec and implementation perspective. We'd love to hear some thoughts from implementors on this though.
The Worker would generally require access to information that is helpful in making decisions on how much, how fast and what kind of data to buffer. Generally this could be the current playhead (currentTime), the current state of the video buffer (buffered attribute) and current payback rate (playbackRate), if audio is audible (muted and volume) and probably more. For those reasons and to make the specification and implementation process easier we would probably suggest to leave this synchronization completely up to the application. The application can use postMessage to update any necessary state in the Worker as required.
I think that is the current understanding.
This seems to be more of an implementation / specification related question that I am not entirely sure I am able to give feedback on. My understanding here however is that the buffered attribute both for sourceBuffer as well as the video node already need information from the (already) asynchronous and in a different thread running process of media decoding. |
Thanks for your answers - those do help describe the possible feature scope more precisely. w.r.t.:
You're indeed correct - I had mistakenly constrained the scope too far :). Unless the general Worker API is too broad, let's target it, not just Service Workers. |
Decoding itself doesn't impact buffered ranges (unless there's a decode error and transition of MediaSource readyState to closed.) Rather, operations on the MSE API itself can change the buffered ranges. What I was trying to get at is: what are the potentially required synchronization points between the HTMLMediaElement attached by a transferred MSE worker context? For example:
|
These are great questions. I think my intuition is that generally the worker thread which holds the MSE will be communicating with the main thread, eg via postMessage. I think it would make sense to enforce logical causality. For example, if you call appendBuffer, then send a message to the main thread the result of that appendBuffer should be observable when processing the send message. I agree that MediaSource.buffered probably makes sense -- there's no need to query the main thread for this information. |
To be clear, I assume you mean more like "if you call appendBuffer, and upon later receiving updateend you send a message to the main thread, the result of the appendBuffer should be visible on the main thread when processing the receipt of that message." Please correct me if I misunderstand :) |
Also, does it make sense to use such a transferred MSE API from a Service Worker context (I don't think so, because such a context is independent of a web page, and therefore from a DOM containing a media element). ISTM, this makes sense from a web worker context, not from SW context. |
yep, exactly.
By worker I meant web worker here |
I agree with what @bmaurer said: maintaining logical causality with postMessage probably makes sense. If we are considering replicating the |
Thanks for your responses to my questions. Here's my newbie-to-workers question: can a Worker do a fetch that is intercepted by a Service Worker, thereby enabling a combination of offline MSE-in-Worker being fed by data provided by the Service Worker? Where are known gaps in spec or implementation to accomplish such a scenario (other than, of course, this issue's MSE-in-Worker discussion :) )? |
I'm with @jyavenard thinking that adding #100 while workerising SourceBuffer would be worthwhile. It may be timely because the worker codepath may end up being a fork of the non-worker path. I'd like to hear from @bmaurer and @zhaoz about whether this will make the player implementation simpler or better. |
I would like to share my point of view about the transferring of MediaSource and SourceBuffer objects to workers. If I have understood the spec correctly, a normal use of a MediaSource is via Would be probably cleaner to expose MediaSource and SourceBuffer constructors to workers. The change I propose is mark MediaSource interface in this way:
same for SourceBuffer. Note that SourceBuffer supports the appending of ArrayBuffer and ArrayBufferView. Both are already transferable to workers. |
Agree with comment, it would be easy if we restrict the media source and source buffer could only be used in one thread all the time and disallow them being transferrable. If they’re transferable, how should the behavior of event handlers be defined? It seems a difficult problem, and the spec doesn't mention anything about it. eg. — If what I understand it correctly, the usage scenario would like the following. First, we create both media source and source buffer on the WT, and send the URL back to MT after wrapping media source as URL. After the media source is attached successfully to media element, “sourceopen” would be triggered on WT. Next, MT should send the video URL to WT, then all things could be done independently inside the WT from fetching data to appending data into buffer (and with some new API for getting the status of media element). Please correct me if I was wrong and welcome to propose other possible scenarios. |
I see the intentions here and agree that this would make several aspects easier. The only concern I have is that this would add a significant amount of additional startup time. On top of the time it takes to complete In a scenario with a transferable MediaSource, waiting for The biggest risks associated with moving MSE into Workers from a product perspective is probably the startup latency. The solution as suggested in #175 (comment) increases this risk significantly. |
This might be a stupid question, why couldn't we bootstrap worker in advance, before starting playing video? Can we bootstrap worker in the beginning? and then use
If we can start worker in advance, the following might be the possible use case. In this case, MT only need one time slice to handle the message sent from WT. worker.postMessage(url /* used for fetching on WT */);
worker.onMessage = e => { mediaElement.src = e.data; }; |
The main problem to make media source transferable is "how to handle the event handler of transferable object", because it's undefined behavior. I think this topic is out of the media scope, and I would like to know how strong intention we want to go with this direction? If do so, we need to discuss and modify with worker's working group and make sure the behavior can be well defined. However, it might be take a long time, and @bakulf, who is our worker expert, also suggest don't try to transfer an object with event handler. |
@alastor0325 We can only bootstrap the Worker ahead of time, if we have an opportunity to do so. If the first thing we are doing on a blank page load is to create and assign a MediaSource, there's no way for us to bootstrap a Worker ahead of time. In addition to that, creating the object URL on the Worker thread will require us to touch the main thread twice. Consider the following example: /* main thread code */
// first main thread execution
const video = document.querySelector('video');
const worker = new Worker('mse_worker.js');
worker.addEventListener('message', (event) => {
// second main thread execution
video.src = event.data;
}); But if we can create the MediaSource on the main thread, we only need one time slice on the main thread: /* main thread code */
// first main thread execution
const video = document.querySelector('video');
const worker = new Worker('mse_worker.js');
const ms = new MediaSource();
const url = window.URL.createObjectURL(ms);
video.src = url;
worker.postMessage(ms, [ ms ]); We don't need a second time slice on the main thread before we can start loading video. Talking to some folks at Mozilla, they wanted to look into why the Another option could be to require transferring of the MediaSource to the Worker before the URL assignment happens. In that case any events firing on the MediaSource could be deterministically scheduled to execute on the Worker instead of the main thread. Lastly, I could imagine something TransferableMediaSource, that internally does all the steps MediaSource would do upon creation, but doesn't expose any external API interface except for a getMediaSource() method. After the method was called, the TransferableMediaSource looses it's ability to be transferred. |
Why not only having the source buffers in a worker? |
@DanielBaulig I think it's a good idea to have "TransferableMediaSource", it could fix the problem about the event handler and also it would only need one time slice on the main thread. In addition, you've mention we would need something like "mediaSource.mediaElementState" which can be reflected the status of media element. Maybe we could start to define the specific attributes which we need. |
For the most part I think it's sufficient to provide these media element states via postMessage to the worker at a regular rate. Unless the platform can significantly improve update performance or maybe even provide thread-safe, but otherwise real-time variations of these, I don't think they are of highest priority. The most important states/properties are probably
Generally this is correct. I remember that this was brought up before as an option, but I'm not entirely sure what the arguments against it were. There's definitely the limitation of having to touch the main thread twice though (you have to wait for |
LGTM from our app's perspective, as long as |
@#175 (comment) thanks for your input. We're currently considering two options: Change from exception to null value for the 'handle' attribute when accessed on a main thread MediaSource, or change visibility of that handle getter to only be visible on the dedicated worker context (for now at least). I presume we'll disallow exception even in the latter case. Either way, it looks like, on main thread (or on worker thread), |
From discussion during Media Working Group meeting at TPAC 2022 today, both @jernoble and @dontcallmedom also supported the visibility restriction option for the handle getter. I presented both options (null with custom spec replacement for [SameObject], or just exposed=dedicatedworker -- neither can throw exception). I'll update (or just abandon/replace) the PR #316 to instead do visibility restriction of that getter, without exception throwing. |
Removes the MediaSource handle attribute visibility from the main Window context, leaving it visible only in dedicated worker contexts. Also removes the conditional throwing of NotSupportedError exceptions on getting this attribute's value if the implementation doesn't support that. Overall, this change is to undo the backwards incompatibility issue found when older versions of MSE web app libraries enumerated main thread MediaSource attribute values, hitting exception in the Chromium feature implementation through milestone 107. This change replaces that with simpler and safer visibility restriction of this getter to just the context where it must be supported if the implementation supports MSE-in-Workers. Note, this change replaces the alternative fix discussed in w3c/media-source PR #316. Reference feature tracking spec issue for MSE-in-Workers w3c/media-source issue #175.
In Chrome, the feature has been fixed to behave per #317 and builds of Chrome >= 108.0.5334.0 should include it enabled by default. See also the Chromium feature tracking issue 878133. |
Adds a readonly, boolean-valued, static attribute named `canConstructInDedicatedWorker` to the MediaSource interface. Currently, this attribute is only visible to web apps if the RunTimeEnabledFeature "MediaSourceInWorkers" is enabled. When visible, this attribute always returns true. The primary goal of having this attribute is to enable web app's main thread to proactively determine whether or not MSE is supported from a dedicated worker context *before* deciding whether or not to create or try using MSE from such a context. As an initial example of this use case, the existing MSE-in-Workers web_tests are updated to use this new attribute's existence and value to fail-fast rather than potentially flakily fail (e.g. previously, the ...worker-terminate test might flakily pass/fail some of its test cases on implementations lacking MSE-in-Workers support if the test completed before handling receipt of error message from worker.) A further test is added to ensure that, if the attribute is missing or exists but is not `true`, a dedicated worker does not have ability to construct a MediaSource instance. See also w3c/media-source#175 for further discussion which led to this new attribute. BUG=878133 Change-Id: I697ca6adc5b5dc65d5c5084ff67a541430a9237b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2487834 Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Reviewed-by: Will Cassella <cassew@google.com> Cr-Commit-Position: refs/heads/master@{#819564} GitOrigin-RevId: 27d63ac81be017698d0b799365cd2ef4cbdd8813
Adds core MediaSourceHandle interface and modules implementation. Later changes will enable apps to get a handle from a dedicated worker MediaSource, post it to the main thread and attach it to an HTMLMediaElement via the srcObject attribute; they will also include test updates. References: Full prototype CL: https://chromium-review.googlesource.com/c/chromium/src/+/3515334 MSE spec issue: w3c/media-source#175 MSE spec feature updates switching from worker MSE attachment via object URL to attachment via srcObject MediaSourceHandle: * w3c/media-source#305 * further clarifications in discussion at w3c/media-source#306 (comment) BUG=878133 Change-Id: I9a3b47ea02d2755a9860999e245eafc26f864977 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3687146 Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Reviewed-by: Kentaro Hara <haraken@chromium.org> Reviewed-by: Dale Curtis <dalecurtis@chromium.org> Cr-Commit-Position: refs/heads/main@{#1012115} NOKEYCHECK=True GitOrigin-RevId: 2813392442e5ff5cc8702a743bdd52a1bab82be4
Adds ability for apps to get a MediaSourceHandle from a dedicated worker MediaSource instance, gated by RuntimeEnabledFeature "MediaSourceInWorkersUsingHandle". Updates the PassKey required for creation of a concrete MediaSourceAttachmentSupplement to allow that only from either URLMediaSource::createObjectURL or the new MediaSource::getHandle method. This specificity is enabled by a new AttachmentCreationPassKeyProvider type. Later changes will enable apps to post the handle to the main thread and attach it to an HTMLMediaElement via the srcObject attribute; they will also include test updates. References: Full prototype CL: https://chromium-review.googlesource.com/c/chromium/src/+/3515334 MSE spec issue: w3c/media-source#175 MSE spec feature updates switching from worker MSE attachment via object URL to attachment via srcObject MediaSourceHandle: * w3c/media-source#305 * further clarifications in discussion at w3c/media-source#306 (comment) crbug.com/506273 is somewhat related, but not fixed by this change (it refers to directly setting MediaSource on Window context to the media element's srcObject attribute.) This change sequence is specific to enabling MSE-in-Worker attachment via srcObject using a handle object. BUG=878133,506273 Change-Id: Ic61f4cc4193080bdbc39234b98897d9a789778d6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688613 Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Reviewed-by: Will Cassella <cassew@chromium.org> Cr-Commit-Position: refs/heads/main@{#1012129} NOKEYCHECK=True GitOrigin-RevId: 09e5fb1a68416f65ef2255c846b81a46f6aa8e52
Adds ability to serialize a MediaSourceHandleImpl, conditionally failing with DataCloneError if the handle is_serialized() already or if the handle is_used() (both of those are initialized to be false in the new instance created during deserialization.) Later changes will enable apps to attach the handle to a main thread HTMLMediaElement via the srcObject attribute; they will also include test updates. References: Full prototype CL: https://chromium-review.googlesource.com/c/chromium/src/+/3515334 MSE spec issue: w3c/media-source#175 MSE spec feature updates switching from worker MSE attachment via object URL to attachment via srcObject MediaSourceHandle: * w3c/media-source#305 * further clarifications in discussion at w3c/media-source#306 (comment) BUG=878133 Change-Id: I19cc8a450423964aef78e8e468776e8cd912503a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688599 Reviewed-by: Will Cassella <cassew@chromium.org> Reviewed-by: Kentaro Hara <haraken@chromium.org> Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Cr-Commit-Position: refs/heads/main@{#1012132} NOKEYCHECK=True GitOrigin-RevId: d5d391975da969d6242e5785c68609d6cd15fda3
Adds ability to attach a dedicated-worker-owned MediaSource to an HTMLMediaElement using a MediaSourceHandle for that MediaSource instance that the app has posted over to the main thread and assigned to the srcObject attribute on the media element. Previously, only a MediaStream could be set as a srcObject in Chrome. This change adds the relevant MediaProvider IDL union type and makes it the type of that srcObject attribute. For historical reasons, the srcObject attribute of an HTMLMediaElement is implemented in modules as a partial interface; this change updates that partial interface as well as the media element implementation to enable the scenario without regressing existing ability to use MediaStream as media element's srcObject. The attachment of the worker MediaSource using the handle does not involve lookup into a URL registry; rather, an internal blob URL is built into the handle when it was retrieved from the MediaSource and that URL is used to satisfy existing media element load safety checks as well as provide the underlying WebMediaPlayer a URL that it can use when logging to devtools. Later changes will add further test updates and remove the previous ability to attach a worker MediaSource using a registered object URL. References: Full prototype CL: https://chromium-review.googlesource.com/c/chromium/src/+/3515334 MSE spec issue: w3c/media-source#175 MSE spec feature updates switching from worker MSE attachment via object URL to attachment via srcObject MediaSourceHandle: * w3c/media-source#305 * further clarifications in discussion at w3c/media-source#306 (comment) crbug.com/506273 is somewhat related, but not fixed by this change (it refers to directly setting MediaSource on Window context to the media element's srcObject attribute.) This change sequence is specific to enabling MSE-in-Worker attachment via srcObject using a handle object. BUG=878133,506273 Change-Id: I86cddd87bafae1c7cbae9e94ea4614418067012f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688740 Reviewed-by: Kentaro Hara <haraken@chromium.org> Reviewed-by: Elad Alon <eladalon@chromium.org> Reviewed-by: Dale Curtis <dalecurtis@chromium.org> Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Cr-Commit-Position: refs/heads/main@{#1012202} NOKEYCHECK=True GitOrigin-RevId: 756af69b67c9e40e0a0c92cb6c0a911c96ea6835
If the MediaSourceInWorkersUsingHandle feature is enabled, this change prevents successful ability of obtaining an objectURL that would succeed in loading a worker-owned MediaSource. It changes the wpt tests to use handle for attachment and verifies expected new behavior of getHandle and that worker objectURL attachment fails (these tests run on experimental builds of Chromium with currently-experimental MediaSourceInWorkersUsingHandle feature enabled, just like the currently-experimental MediaSourceInWorkers feature.) References: Full prototype CL for the parts 1-4 that have already landed: https://chromium-review.googlesource.com/c/chromium/src/+/3515334 MSE spec issue: w3c/media-source#175 MSE spec feature updates switching from worker MSE attachment via object URL to attachment via srcObject MediaSourceHandle: * w3c/media-source#305 * further clarifications in discussion at w3c/media-source#306 (comment) BUG=878133 Change-Id: I60ddca79ee0f95c87b6d84e4f44ad9c283f359a3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3698231 Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Auto-Submit: Matthew Wolenetz <wolenetz@chromium.org> Reviewed-by: Will Cassella <cassew@chromium.org> Cr-Commit-Position: refs/heads/main@{#1012712} NOKEYCHECK=True GitOrigin-RevId: 6315549b8c2ece3dbbf3062c1a87347589a5e115
…bjectURL" This reverts commit 6315549b8c2ece3dbbf3062c1a87347589a5e115. Reason for revert: This is causing failures on the WebKit Linux Leak builder i.e. https://ci.chromium.org/ui/p/chromium/builders/ci/WebKit%20Linux%20Leak/39394/overview Original change's description: > MSE-in-Workers: srcObject part 5: Conditionally fail worker objectURL > > If the MediaSourceInWorkersUsingHandle feature is enabled, this change > prevents successful ability of obtaining an objectURL that would succeed > in loading a worker-owned MediaSource. > > It changes the wpt tests to use handle for attachment and verifies > expected new behavior of getHandle and that worker objectURL attachment > fails (these tests run on experimental builds of Chromium with > currently-experimental MediaSourceInWorkersUsingHandle feature enabled, > just like the currently-experimental MediaSourceInWorkers feature.) > > References: > Full prototype CL for the parts 1-4 that have already landed: > https://chromium-review.googlesource.com/c/chromium/src/+/3515334 > MSE spec issue: > w3c/media-source#175 > MSE spec feature updates switching from worker MSE attachment via > object URL to attachment via srcObject MediaSourceHandle: > * w3c/media-source#305 > * further clarifications in discussion at > w3c/media-source#306 (comment) > > BUG=878133 > > Change-Id: I60ddca79ee0f95c87b6d84e4f44ad9c283f359a3 > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3698231 > Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> > Auto-Submit: Matthew Wolenetz <wolenetz@chromium.org> > Reviewed-by: Will Cassella <cassew@chromium.org> > Cr-Commit-Position: refs/heads/main@{#1012712} Bug: 878133 Change-Id: I1e405ae1de146d1f3183592b00a43bd3c38d849d No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3695890 Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org> Owners-Override: Nidhi Jaju <nidhijaju@chromium.org> Cr-Commit-Position: refs/heads/main@{#1012823} NOKEYCHECK=True GitOrigin-RevId: f438823c5527e6499b8dedb4eef7bb8ed43f4371
…bjectURL With the underlying leak fixed by https://chromium-review.googlesource.com/c/chromium/src/+/3704191, this change can be relanded now. Previous revert: > Revert "MSE-in-Workers: srcObject part 5: Conditionally fail worker objectURL" > > This reverts commit 6315549b8c2ece3dbbf3062c1a87347589a5e115. > > Reason for revert: This is causing failures on the WebKit Linux Leak builder > i.e. https://ci.chromium.org/ui/p/chromium/builders/ci/WebKit%20Linux%20Leak/39394/overview > > Original change's description: > > MSE-in-Workers: srcObject part 5: Conditionally fail worker objectURL > > > > If the MediaSourceInWorkersUsingHandle feature is enabled, this change > > prevents successful ability of obtaining an objectURL that would succeed > > in loading a worker-owned MediaSource. > > > > It changes the wpt tests to use handle for attachment and verifies > > expected new behavior of getHandle and that worker objectURL attachment > > fails (these tests run on experimental builds of Chromium with > > currently-experimental MediaSourceInWorkersUsingHandle feature enabled, > > just like the currently-experimental MediaSourceInWorkers feature.) > > > > References: > > Full prototype CL for the parts 1-4 that have already landed: > > https://chromium-review.googlesource.com/c/chromium/src/+/3515334 > > MSE spec issue: > > w3c/media-source#175 > > MSE spec feature updates switching from worker MSE attachment via > > object URL to attachment via srcObject MediaSourceHandle: > > * w3c/media-source#305 > > * further clarifications in discussion at > > w3c/media-source#306 (comment) > > > > BUG=878133 > > > > Change-Id: I60ddca79ee0f95c87b6d84e4f44ad9c283f359a3 > > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3698231 > > Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> > > Auto-Submit: Matthew Wolenetz <wolenetz@chromium.org> > > Reviewed-by: Will Cassella <cassew@chromium.org> > > Cr-Commit-Position: refs/heads/main@{#1012712} > > Bug: 878133 > Change-Id: I1e405ae1de146d1f3183592b00a43bd3c38d849d > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3695890 > Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> > Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org> > Owners-Override: Nidhi Jaju <nidhijaju@chromium.org> > Cr-Commit-Position: refs/heads/main@{#1012823} Bug: 878133 Change-Id: I56e4ecd4d8b58d9d58ed3c575b0fb52f596b6fae Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3708465 Reviewed-by: Will Cassella <cassew@chromium.org> Commit-Queue: Matthew Wolenetz <wolenetz@chromium.org> Cr-Commit-Position: refs/heads/main@{#1014755} NOKEYCHECK=True GitOrigin-RevId: 39878163d3ff90baabd342ad784671a4b54262ed
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
This commit adds the `declareInitSegment` and `freeInitSegment` methods to the RxPlayer's SegmentBuffer abstractions (which is the part of the code handling the operations on SourceBuffers, such as pushing media and init segments). The short term idea is to improve the handling of initialization segments in the SegmentBuffer. Until now, each pushed media segment lead to a check that the initialization segment it relies on is the same than the last one pushed. To be able to perform that check, a caller need to communicate again the initialization segment's data each time a chunk is pushed to the buffer. This check can be performed efficiently in most cases because we first check init segment's data equality by reference, which, by pure luck, should be equal in most cases in the current code. In cases where it isn't the same reference however, it can lead to a byte-per-byte check, which should not be an issue in terms of performance in most cases, but is still an ugly specificity which could be handled in a more optimal and understandable way. This commit now allows the definition of a `initSegmentUniqueId`, an identifier for initialization segments, on SegmentBuffers. Any pushed segments can then refer to its associated init segment by indicating which `initSegmentUniqueId` it is linked to. The SegmentBuffer will ensure behind the hood that the right initialization segment is pushed before pushing media segments, like before, excepted that this can now be done just by comparing this `initSegmentUniqueId` - it also means that the caller is no more required to keep in memory the data of the loaded initialization segment, the `SegmentBuffer` is already doing that. Previously, the initialization segment's data was kept by the `RepresentationStream`, the abstraction choosing which segments to load (which is part of the reasons why the reference mostly never changed). The declaration and "freeing" of init segment is done through a `declareInitSegment`/`freeInitSegment` pair of methods on a `SegmentBuffer`. This sadly means that memory freeing for the initialization segment is now manual, whereas we just relied on garbage collection when the initialization segment was directly used. --- Though mostly, the long term benefit is to implement the hybrid-worker mode that we plan to have in the future, where buffering is performed in a WebWorker (thus improving concurrence with an application, with the goal of preventing both UI stuttering due to heavy player tasks and rebuffering due to heavy UI tasks). In the currently-planned long term worker features we would have thus the following modes: - full worker: where both the rebuffering logic and MSE API are called in a WebWorker, allowing to avoid UI and media playback blocking each other to some extent This however requires the [MSE-in-Worker](w3c/media-source#175) feature to be available in the browser AND it also implies a more complex API, notably some callbacks (`manifestLoader`, `segmentLoader` and `representationFilter`) which will have to be updated. - hybrid mode: The buffering logic is mainly performed in a WebWorker but MSE API are still in the main thread. This allows e.g. to not fight for CPU with the UI to know which segments to download and to avoid blocking the UI when the Manifest is being parsed. Though the UI blocking could still mean that a loaded segment is waiting to be pushed in that mode. Because here MSE APIs may have to be called through `postMessage`-style message passing, the previous logic of communicating each time the same initialization segment each time a segment was pushed, with no mean to just move that data (in JavaScript linguo, to "transfer" it) was considerably worst than before. Relying on a short identifier instead seems a better solution here. - normal mode: The current mode where everything stays in main thread. However it should be noted that all of this long term objective is still in an higly experimental phase, and the gains are only theoretical for now.
The Videos team at Facebook has a growing need to move calls to Media Source Extensions off of the main thread and into a Worker. While most parts of your off-the-shelve streaming video player can be implemented in a Worker (fetching and parsing of the manifest as well as selecting and fetching of segments) the calls to and interactions with the Media Source Extensions API (e.g.
SourceBuffer.prototype.appendBuffer
,SourceBuffer.prototype.remove
, etc) remain a bottleneck and have to happen on the main browser rendering thread.On a sizable and complex web site large blocks of JS execution can regularly block the main thread making videos slow to start playing and causing lots of rebuffering, especially in live videos where you can only buffer ahead very little data. To ensure great web video performance in the long run, even as web apps continue to grow in size and complexity, we believe we need to allow video players to move into Workers and off of the main thread.
We would like to propose this change to the working group and involve other API users as well as implementors in the discussion.
The text was updated successfully, but these errors were encountered: