Bug 70452 - Implement storage and retrieval of TextTrackCues during video playback.
Summary: Implement storage and retrieval of TextTrackCues during video playback.
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Media (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Anna Cavender
URL:
Keywords:
Depends on: 72269
Blocks: 62883
  Show dependency treegraph
 
Reported: 2011-10-19 16:44 PDT by Anna Cavender
Modified: 2011-11-14 06:39 PST (History)
5 users (show)

See Also:


Attachments
Patch (11.88 KB, patch)
2011-10-21 17:19 PDT, Anna Cavender
no flags Details | Formatted Diff | Diff
uses PODIntervalTree as data structure (44.13 KB, patch)
2011-11-09 09:50 PST, Anna Cavender
no flags Details | Formatted Diff | Diff
addressing reviewer comments and updating to ToT (45.25 KB, patch)
2011-11-11 13:43 PST, Anna Cavender
no flags Details | Formatted Diff | Diff
using scheduleLoad(TextTrackResource) instead of configureTextTracks() (45.78 KB, patch)
2011-11-11 16:40 PST, Anna Cavender
no flags Details | Formatted Diff | Diff
addressing Eric's comments (44.00 KB, patch)
2011-11-11 16:59 PST, Anna Cavender
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Anna Cavender 2011-10-19 16:44:04 PDT
TextTrackCueIndex is used as a fast look-up for text track cues (from any text track) during video playback.  TextTrackCueSet is used as a structure for common operations on sets of text track cues.  Both can point to existing text track cues but neither owns or modifies them.
Comment 1 Anna Cavender 2011-10-21 17:19:15 PDT
Created attachment 112047 [details]
Patch
Comment 2 Sam Weinig 2011-10-23 12:10:55 PDT
Can you explain the algorithm you use for fast lookup.  On the base of it, I would assume an IntervalMap to be a good data structure for this.
Comment 3 Sam Weinig 2011-10-23 12:12:01 PDT
Also, if this is an optimization, can you please show the speedups through some sort of perf test (it doesn't have to be checked in, you just need to show that this is speeding something up).
Comment 4 Anna Cavender 2011-10-23 22:13:33 PDT
'fast' is a relative term, so I probably should not have used it here as there is no current functionality to compare to (there are no demonstrable speedups because this is new).

The intent of TextTrackCueIndex is a handy storage mechanism for TextTrackCues that may come from multiple text tracks to be used in HTMLMediaElement (or any other player).  As cues are parsed or otherwise discovered, they will be stored in a TextTrackCueIndex in order of startTime/endTime so that as playback progresses, the cues that should be currently visible can be easily looked up.  The alternative would be for HTMLMediaElement to iterate through it's list of tracks, finding cues with timestamps in the range of the current playback position, and then sort them in text track cue order before displaying them.  TextTrackCueIndex and TextTrackCueSet make this process easier and likely more efficient.
Comment 5 Sam Weinig 2011-10-30 12:15:34 PDT
Without any performance data, I don't think it makes sense to complicate the code with this.  I also think an IntervalMap-type data structure would probably be a better fix for this type of optimization, should it be shown to be needed.
Comment 6 Anna Cavender 2011-10-31 07:42:47 PDT
Sam, are you suggesting that TextTrackCueIndex and TextTrackCueSet not be included at all and HTMLMediaElement would be responsible for managing cues visible at runtime?

Can you tell me more (and/or add a link) about IntervalMap.  I don't see this as a WebKit data structure.

Thanks for the feedback.
Comment 7 Anna Cavender 2011-11-09 09:50:24 PST
Created attachment 114304 [details]
uses PODIntervalTree as data structure
Comment 8 Anna Cavender 2011-11-09 09:52:17 PST
This patch overlaps a bit with this one: https://bugs.webkit.org/show_bug.cgi?id=71123 so we'll need to take turns, but I thought I'd get the review process started.

Thanks!
Comment 9 Sam Weinig 2011-11-10 20:51:50 PST
Comment on attachment 114304 [details]
uses PODIntervalTree as data structure

View in context: https://bugs.webkit.org/attachment.cgi?id=114304&action=review

> Source/WebCore/html/HTMLMediaElement.h:523
> +    typedef PODInterval<float, TextTrackCue*> CueInterval;
> +    PODIntervalTree<float, TextTrackCue*> m_cueTree;
> +    Vector<CueInterval> m_currentlyVisibleCues;

This might read slightly cleaner if you wrote it as:

typedef PODIntervalTree <float, TextTrackCue*> CueIntervalTree;
CueIntervalTree m_cueTree;
Vectore<CueIntervalTree::IntervalType> m_currentlyVisibleCues;
Comment 10 Eric Carlson 2011-11-11 08:33:45 PST
Comment on attachment 114304 [details]
uses PODIntervalTree as data structure

View in context: https://bugs.webkit.org/attachment.cgi?id=114304&action=review

Every non-DOM object that is an EventTarget needs code (for JSC at lease, I don't know about V8) to make sure that the wrapper isn't collected during event dispatch or while the parent/owner object is reachable. For example, see JSTextTrackListOwner::isReachableFromOpaqueRoots and the tracklist-is-reachable.html test added in https://bugs.webkit.org/show_bug.cgi?id=71123. 

I think this is fine to do in a follow up patch, but please file a bug for the fix (and I am happy to make the changes for JSC).

> Source/WebCore/html/HTMLMediaElement.cpp:852
> +void HTMLMediaElement::updateActiveTextTrackCues()
> +{
> +    float movieTime = currentTime();
> +

Nit: it would be slightly more efficient if this function took the current time because one of the places it is called will have just fetched it.

> Source/WebCore/html/HTMLMediaElement.h:522
> +    typedef PODInterval<float, TextTrackCue*> CueInterval;
> +    PODIntervalTree<float, TextTrackCue*> m_cueTree;

TextTrackCue startTime and endTime times both doubles, why use float ?

> Source/WebCore/html/TextTrackCue.cpp:154
> +    if (active)
> +        dispatchEvent(Event::create(eventNames().enterEvent, false, false), ec);
> +    else
> +        dispatchEvent(Event::create(eventNames().exitEvent, false, false), ec);
> +

This is missing a number of the steps listed in the spec. All of the cue events for a time should be put into a queue, sorted and filtered, and then fired asynchronously.

Because the events have to fire in order across all of the tracks/cues, maybe it make sense for the media element to own and maintain a queue of cue events?

> Source/WebCore/html/TextTrackCue.cpp:156
> +    if (m_track)
> +        m_track->fireCueChangeEvent();

The 'cuechange' event must fire on both the TextTrack and <track> : 

    ... queue a task to fire a simple event named cuechange at the TextTrack object, and, if the text track has a corresponding track element, to then fire a simple event named cuechange at the track element as well ...

> LayoutTests/media/track/track-cues-cuechange.html:25
> +        function cueChanged()
> +        {
> +            var cues = testTrack.track.cues;
> +            
> +            var currentCue = cues[Math.floor(cueChangeCount/2)];
> +

Nit: I think it would be helpful to log "EVENT(cuechange)" here so the results make it obvious these checks happen in response to the event.

> LayoutTests/media/track/track-cues-cuechange.html:49
> +                testTrack = document.getElementById("testTrack");
> +                testExpected("testTrack.track.cues.length", 3);
> +                testTrack.track.addEventListener('cuechange', cueChanged);

This should also verify that 'cuechange' is fired on the <track>.

> LayoutTests/media/track/track-cues-enter-exit.html:10
> +        <p>Tests that TextTrack's cues are indexed and updated within 500ms during video playback. Test uses the enter and exits events on TextTrackCue.</p>

How did you decide on 500ms?

> LayoutTests/media/track/track-cues-enter-exit.html:22
> +        function cueEntered()
> +        {
> +            var currentCue = testTrack.track.cues[cueCount];

Nit: I think it would be helpful to log "EVENT(enter)" here so the results make it obvious these checks happen in response to the event.

> LayoutTests/media/track/track-cues-enter-exit.html:33
> +        function cueExited()
> +        {
> +            var currentCue = testTrack.track.cues[cueCount];

Logging the event name would be good here as well.
Comment 11 Anna Cavender 2011-11-11 13:43:13 PST
Comment on attachment 114304 [details]
uses PODIntervalTree as data structure

View in context: https://bugs.webkit.org/attachment.cgi?id=114304&action=review

Thanks Eric and Sam.  I'll look into the changes needed for non-DOM objects to extend EventTarget as a follow up.

>> Source/WebCore/html/HTMLMediaElement.cpp:852
>> +
> 
> Nit: it would be slightly more efficient if this function took the current time because one of the places it is called will have just fetched it.

Done.

>> Source/WebCore/html/HTMLMediaElement.h:522
>> +    PODIntervalTree<float, TextTrackCue*> m_cueTree;
> 
> TextTrackCue startTime and endTime times both doubles, why use float ?

Oops, thanks.  Fixed

>> Source/WebCore/html/HTMLMediaElement.h:523
>> +    Vector<CueInterval> m_currentlyVisibleCues;
> 
> This might read slightly cleaner if you wrote it as:
> 
> typedef PODIntervalTree <float, TextTrackCue*> CueIntervalTree;
> CueIntervalTree m_cueTree;
> Vectore<CueIntervalTree::IntervalType> m_currentlyVisibleCues;

Done.

>> Source/WebCore/html/TextTrackCue.cpp:154
>> +
> 
> This is missing a number of the steps listed in the spec. All of the cue events for a time should be put into a queue, sorted and filtered, and then fired asynchronously.
> 
> Because the events have to fire in order across all of the tracks/cues, maybe it make sense for the media element to own and maintain a queue of cue events?

Sounds like a great idea for a follow up patch.  I'll file a bug

>> Source/WebCore/html/TextTrackCue.cpp:156
>> +        m_track->fireCueChangeEvent();
> 
> The 'cuechange' event must fire on both the TextTrack and <track> : 
> 
>     ... queue a task to fire a simple event named cuechange at the TextTrack object, and, if the text track has a corresponding track element, to then fire a simple event named cuechange at the track element as well ...

Done.

>> LayoutTests/media/track/track-cues-cuechange.html:25
>> +
> 
> Nit: I think it would be helpful to log "EVENT(cuechange)" here so the results make it obvious these checks happen in response to the event.

Done.

>> LayoutTests/media/track/track-cues-enter-exit.html:10
>> +        <p>Tests that TextTrack's cues are indexed and updated within 500ms during video playback. Test uses the enter and exits events on TextTrackCue.</p>
> 
> How did you decide on 500ms?

We fire time updates every 250ms, so I figured every cue should be encountered and appropriate events should be fired within 500ms.  I'm open to suggestions on the best way to check for this.

>> LayoutTests/media/track/track-cues-enter-exit.html:22
>> +            var currentCue = testTrack.track.cues[cueCount];
> 
> Nit: I think it would be helpful to log "EVENT(enter)" here so the results make it obvious these checks happen in response to the event.

Done.

>> LayoutTests/media/track/track-cues-enter-exit.html:33
>> +            var currentCue = testTrack.track.cues[cueCount];
> 
> Logging the event name would be good here as well.

Done.
Comment 12 Anna Cavender 2011-11-11 13:43:35 PST
Created attachment 114764 [details]
addressing reviewer comments and updating to ToT
Comment 13 Anna Cavender 2011-11-11 13:45:49 PST
Comment on attachment 114764 [details]
addressing reviewer comments and updating to ToT

View in context: https://bugs.webkit.org/attachment.cgi?id=114764&action=review

> Source/WebCore/html/HTMLMediaElement.cpp:-507
> -

I believe this is no longer needed here because it is covered by trackWasAdded().  eric.carlson, please check my logic here as you recently added this.
Comment 14 Eric Carlson 2011-11-11 16:36:09 PST
Comment on attachment 114764 [details]
addressing reviewer comments and updating to ToT

View in context: https://bugs.webkit.org/attachment.cgi?id=114764&action=review

>> Source/WebCore/html/HTMLMediaElement.cpp:-507

> 
> I believe this is no longer needed here because it is covered by trackWasAdded().  eric.carlson, please check my logic here as you recently added this.

There is a problem, but I think it is that HTMLMediaElement::addTextTrack should call scheduleLoad(TextTrackResource) instead of configureTextTracks() because we need to start the load asynchronously.


> Source/WebCore/html/HTMLMediaElement.cpp:1965
> +    float movieTime = currentTime();
> +    updateActiveTextTrackCues(movieTime);

Nit: the local variable isn't necessary.


> Source/WebCore/html/HTMLTrackElement.cpp:157
> +        m_track = LoadableTextTrack::create(scriptExecutionContext(), this, kind(), label(), srclang(), isDefault());

You shouldn't need to pass a ScriptExecutionContext, the track can use the Document associated with the track element for the ScriptExecutionContext.
Comment 15 Anna Cavender 2011-11-11 16:40:15 PST
Created attachment 114799 [details]
using scheduleLoad(TextTrackResource) instead of configureTextTracks()
Comment 16 Anna Cavender 2011-11-11 16:59:28 PST
Created attachment 114801 [details]
addressing Eric's comments
Comment 17 WebKit Review Bot 2011-11-11 19:37:57 PST
Comment on attachment 114801 [details]
addressing Eric's comments

Clearing flags on attachment: 114801

Committed r100064: <http://trac.webkit.org/changeset/100064>
Comment 18 WebKit Review Bot 2011-11-11 19:38:03 PST
All reviewed patches have been landed.  Closing bug.