Commit cb9c513a authored by philipj@opera.com's avatar philipj@opera.com

Implement AudioTrack, AudioTrackList, VideoTrack, and VideoTrackList

This is based on Aaron Colwell's patch:
https://codereview.chromium.org/170233009/#ps270001

BUG=249427
TEST=LayoutTests/media/avtracklists.html

Review URL: https://codereview.chromium.org/284513003

git-svn-id: svn://svn.chromium.org/blink/trunk@176224 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 74c1b44b
<!doctype html>
<html>
<head>
<title>AudioTrackList &amp; VideoTrackList addtrack event</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../media-file.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function addtrack_test(tagName, src, label)
{
function onTrackListEvent(actualEventList, e)
{
actualEventList.push(e.type);
if (e.type == "addtrack") {
assert_equals(e.track, e.target[0], "Track property matches first track in list.");
}
}
function setupTrackListHandlers(t, trackList, actualEventList)
{
trackList.addEventListener("addtrack", t.step_func(onTrackListEvent.bind(this, actualEventList)));
trackList.addEventListener("change", t.step_func(onTrackListEvent.bind(this, actualEventList)));
trackList.addEventListener("removetrack", t.step_func(onTrackListEvent.bind(this, actualEventList)));
}
async_test(function(t)
{
var e = document.createElement(tagName);
e.src = src;
var expectedEvents = ["addtrack"];
var actualAudioEvents = [];
var actualVideoEvents = [];
setupTrackListHandlers(t, e.audioTracks, actualAudioEvents, "audioTracks events");
setupTrackListHandlers(t, e.videoTracks, actualVideoEvents, "videoTracks events");
e.load();
e.addEventListener("loadedmetadata", t.step_func(function()
{
assert_array_equals(actualAudioEvents, expectedEvents);
if (e.videoTracks.length > 0) {
assert_equals(label, "audio-video");
assert_array_equals(actualVideoEvents, expectedEvents);
} else {
assert_equals(label, "audio-only");
assert_equals(actualVideoEvents.length, 0);
}
t.done();
}));
}, tagName + " : " + label);
}
addtrack_test("audio", findMediaFile("audio", "../content/test"), "audio-only");
addtrack_test("audio", findMediaFile("video", "../content/test"), "audio-video");
addtrack_test("video", findMediaFile("audio", "../content/test"), "audio-only");
addtrack_test("video", findMediaFile("video", "../content/test"), "audio-video");
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>AudioTrack.enabled change</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../media-file.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(t)
{
var e = document.createElement("audio");
e.src = findMediaFile("audio", "../content/test");
e.onloadedmetadata = t.step_func(function()
{
assert_equals(e.audioTracks.length, 1, "audioTracks.length");
assert_true(e.audioTracks[0].enabled, "audioTrack.enabled (initial)");
e.audioTracks[0].enabled = false;
assert_false(e.audioTracks[0].enabled, "audioTrack.enabled (first setter)");
e.audioTracks.onchange = t.step_func(function()
{
assert_false(e.audioTracks[0].enabled, "audioTrack.enabled (first change event)");
e.audioTracks[0].enabled = true;
assert_true(e.audioTracks[0].enabled, "audioTrack.enabled (second setter)");
e.audioTracks.onchange = t.step_func(function()
{
assert_true(e.audioTracks[0].enabled, "audioTrack.enabled (second change event)");
t.done();
});
});
});
}, "AudioTrack.enabled = false");
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>AudioTrackList &amp; VideoTrackList after load()</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../media-file.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(t)
{
var e = document.createElement("video");
e.src = findMediaFile("video", "../content/test");
e.addEventListener("loadedmetadata", t.step_func(function()
{
assert_equals(e.audioTracks.length, 1, "audioTracks.length");
assert_equals(e.videoTracks.length, 1, "videoTracks.length");
assert_equals(e.videoTracks.selectedIndex, 0, "videoTracks.selectedIndex");
e.load();
assert_equals(e.audioTracks.length, 0, "audioTracks.length");
assert_equals(e.videoTracks.length, 0, "videoTracks.length");
assert_equals(e.videoTracks.selectedIndex, -1, "videoTracks.selectedIndex");
t.done();
}));
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>AudioTrack &amp; VideoTrack garbage collection</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../media-file.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(t)
{
var e = document.createElement('video');
e.src = findMediaFile('video', '../content/test');
e.addEventListener('loadedmetadata', t.step_func(function()
{
e.audioTracks.foo = 'foo';
e.audioTracks[0].bar = 'bar';
e.videoTracks.baz = 'baz';
e.videoTracks[0].qux = 'qux';
gc();
assert_equals(e.audioTracks.foo, 'foo');
assert_equals(e.audioTracks[0].bar, 'bar');
assert_equals(e.videoTracks.baz, 'baz');
assert_equals(e.videoTracks[0].qux, 'qux');
t.done();
}));
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>AudioTrackList &amp; VideoTrackList.getTrackById</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../media-file.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(t)
{
var e = document.createElement('video');
assert_equals(e.audioTracks.length, 0);
assert_equals(e.audioTracks.getTrackById(''), null);
assert_equals(e.videoTracks.length, 0);
assert_equals(e.videoTracks.getTrackById(''), null);
e.src = findMediaFile('video', '../content/test');
e.addEventListener('loadedmetadata', t.step_func(function()
{
assert_equals(e.audioTracks.length, 1);
assert_equals(e.audioTracks.getTrackById(e.audioTracks[0].id), e.audioTracks[0]);
assert_equals(e.audioTracks.getTrackById('fake-id'), null);
assert_equals(e.videoTracks.length, 1);
assert_equals(e.videoTracks.getTrackById(e.videoTracks[0].id), e.videoTracks[0]);
assert_equals(e.videoTracks.getTrackById('fake-id'), null);
t.done();
}));
});
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>VideoTrack.selected change</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../media-file.js"></script>
</head>
<body>
<div id="log"></div>
<script>
async_test(function(t)
{
var e = document.createElement("video");
e.src = findMediaFile("video", "../content/test");
e.onloadedmetadata = t.step_func(function()
{
assert_equals(e.videoTracks.length, 1, "videoTracks.length");
assert_equals(e.videoTracks.selectedIndex, 0, "videoTracks.selectedIndex (initial)");
assert_true(e.videoTracks[0].selected, "videoTrack.selected (initial)");
e.videoTracks[0].selected = false;
assert_equals(e.videoTracks.selectedIndex, -1, "videoTracks.selectedIndex (first setter)");
assert_false(e.videoTracks[0].selected, "videoTrack.selected (first setter)");
e.videoTracks.onchange = t.unreached_func("setting selected to false fired change event");
setTimeout(t.step_func(function()
{
e.videoTracks[0].selected = true;
assert_equals(e.videoTracks.selectedIndex, 0, "videoTracks.selectedIndex (second setter)");
assert_true(e.videoTracks[0].selected, "videoTrack.selected (second setter)");
e.videoTracks.onchange = t.step_func(function()
{
assert_equals(e.videoTracks.selectedIndex, 0, "videoTracks.selectedIndex (change event)");
assert_true(e.videoTracks[0].selected, "videoTrack.selected (change event)");
t.done();
});
}), 0);
});
}, "VideoTrackList track change");
</script>
</body>
</html>
......@@ -24,6 +24,8 @@ AudioListener
AudioNode
AudioParam
AudioProcessingEvent
AudioTrack
AudioTrackList
AutocompleteErrorEvent
BarProp
BatteryManager
......@@ -452,6 +454,8 @@ VTTRegion
VTTRegionList
ValidityState
VideoPlaybackQuality
VideoTrack
VideoTrackList
WaveShaperNode
WeakMap
WeakSet
......
......@@ -31,7 +31,9 @@
#include "config.h"
#include "bindings/core/v8/V8TrackEvent.h"
#include "bindings/core/v8/V8AudioTrack.h"
#include "bindings/core/v8/V8TextTrack.h"
#include "bindings/core/v8/V8VideoTrack.h"
#include "core/html/track/TrackBase.h"
#include "core/html/track/TrackEvent.h"
......@@ -53,10 +55,12 @@ void V8TrackEvent::trackAttributeGetterCustom(const v8::PropertyCallbackInfo<v8:
return;
case TrackBase::AudioTrack:
v8SetReturnValueFast(info, static_cast<AudioTrack*>(track), trackEvent);
return;
case TrackBase::VideoTrack:
// This should not happen until VideoTrack and AudioTrack are implemented.
ASSERT_NOT_REACHED();
break;
v8SetReturnValueFast(info, static_cast<VideoTrack*>(track), trackEvent);
return;
}
v8SetReturnValueNull(info);
......
......@@ -259,11 +259,15 @@
'html/canvas/WebGLUniformLocation.idl',
'html/canvas/WebGLVertexArrayObjectOES.idl',
'html/ime/InputMethodContext.idl',
'html/track/AudioTrack.idl',
'html/track/AudioTrackList.idl',
'html/track/TextTrack.idl',
'html/track/TextTrackCue.idl',
'html/track/TextTrackCueList.idl',
'html/track/TextTrackList.idl',
'html/track/TrackEvent.idl',
'html/track/VideoTrack.idl',
'html/track/VideoTrackList.idl',
'html/track/vtt/VTTCue.idl',
'html/track/vtt/VTTRegion.idl',
'html/track/vtt/VTTRegionList.idl',
......@@ -2804,6 +2808,10 @@
'html/shadow/SpinButtonElement.h',
'html/shadow/TextControlInnerElements.cpp',
'html/shadow/TextControlInnerElements.h',
'html/track/AudioTrack.cpp',
'html/track/AudioTrack.h',
'html/track/AudioTrackList.cpp',
'html/track/AudioTrackList.h',
'html/track/InbandTextTrack.cpp',
'html/track/InbandTextTrack.h',
'html/track/LoadableTextTrack.cpp',
......@@ -2818,6 +2826,11 @@
'html/track/TrackBase.cpp',
'html/track/TrackBase.h',
'html/track/TrackEvent.cpp',
'html/track/TrackListBase.h',
'html/track/VideoTrack.cpp',
'html/track/VideoTrack.h',
'html/track/VideoTrackList.cpp',
'html/track/VideoTrackList.h',
'html/track/vtt/BufferedLineReader.cpp',
'html/track/vtt/BufferedLineReader.h',
'html/track/vtt/VTTCue.cpp',
......
......@@ -7,9 +7,11 @@ core/dom/Node
core/fileapi/FileReader
core/html/MediaController
core/html/ime/InputMethodContext
core/html/track/AudioTrackList
core/html/track/TextTrack
core/html/track/TextTrackCue
core/html/track/TextTrackList
core/html/track/VideoTrackList
core/loader/appcache/ApplicationCache
core/page/EventSource
core/timing/Performance
......
......@@ -34,6 +34,7 @@
#include "core/html/track/vtt/VTTCue.h"
#include "platform/PODIntervalTree.h"
#include "platform/graphics/media/MediaPlayer.h"
#include "public/platform/WebMediaPlayerClient.h"
#include "public/platform/WebMimeRegistry.h"
namespace blink {
......@@ -48,6 +49,7 @@ namespace WebCore {
class AudioSourceProvider;
class AudioSourceProviderClient;
#endif
class AudioTrackList;
class ContentType;
class Event;
class ExceptionState;
......@@ -61,6 +63,7 @@ class HTMLMediaSource;
class TextTrackList;
class TimeRanges;
class URLRegistry;
class VideoTrackList;
typedef PODIntervalTree<double, TextTrackCue*> CueIntervalTree;
typedef CueIntervalTree::IntervalType CueInterval;
......@@ -167,6 +170,12 @@ public:
bool togglePlayStateWillPlay() const;
void togglePlayState();
AudioTrackList& audioTracks();
void audioTrackChanged();
VideoTrackList& videoTracks();
void selectedVideoTrackChanged(blink::WebMediaPlayer::TrackId*);
PassRefPtrWillBeRawPtr<TextTrack> addTextTrack(const AtomicString& kind, const AtomicString& label, const AtomicString& language, ExceptionState&);
PassRefPtrWillBeRawPtr<TextTrack> addTextTrack(const AtomicString& kind, const AtomicString& label, ExceptionState& exceptionState) { return addTextTrack(kind, label, emptyAtom, exceptionState); }
PassRefPtrWillBeRawPtr<TextTrack> addTextTrack(const AtomicString& kind, ExceptionState& exceptionState) { return addTextTrack(kind, emptyAtom, emptyAtom, exceptionState); }
......@@ -185,6 +194,11 @@ public:
void didAddTrackElement(HTMLTrackElement*);
void didRemoveTrackElement(HTMLTrackElement*);
blink::WebMediaPlayer::TrackId addAudioTrack(const String& id, blink::WebMediaPlayerClient::AudioTrackKind, const AtomicString& label, const AtomicString& language, bool enabled);
void removeAudioTrack(blink::WebMediaPlayer::TrackId);
blink::WebMediaPlayer::TrackId addVideoTrack(const String& id, blink::WebMediaPlayerClient::VideoTrackKind, const AtomicString& label, const AtomicString& language, bool selected);
void removeVideoTrack(blink::WebMediaPlayer::TrackId);
virtual void mediaPlayerDidAddTextTrack(blink::WebInbandTextTrack*) OVERRIDE FINAL;
virtual void mediaPlayerDidRemoveTextTrack(blink::WebInbandTextTrack*) OVERRIDE FINAL;
// FIXME: Remove this when WebMediaPlayerClientImpl::loadInternal does not depend on it.
......@@ -433,9 +447,22 @@ private:
blink::WebMediaPlayer::CORSMode corsMode() const;
// Creates placeholder AudioTrack and/or VideoTrack objects when WebMemediaPlayer objects
// advertise they have audio and/or video, but don't explicitly signal them via
// addAudioTrack() and addVideoTrack().
// FIXME: Remove this once all WebMediaPlayer implementations properly report their track info.
void createPlaceholderTracksIfNecessary();
// Sets the selected/enabled tracks if they aren't set before we initially
// transition to HAVE_METADATA.
void selectInitialTracksIfNecessary();
void audioTracksTimerFired(Timer<HTMLMediaElement>*);
Timer<HTMLMediaElement> m_loadTimer;
Timer<HTMLMediaElement> m_progressEventTimer;
Timer<HTMLMediaElement> m_playbackProgressTimer;
Timer<HTMLMediaElement> m_audioTracksTimer;
RefPtr<TimeRanges> m_playedTimeRanges;
OwnPtrWillBeMember<GenericEventQueue> m_asyncEventQueue;
......@@ -536,6 +563,8 @@ private:
#endif
double m_lastTextTrackUpdateTime;
RefPtrWillBeMember<AudioTrackList> m_audioTracks;
RefPtrWillBeMember<VideoTrackList> m_videoTracks;
RefPtrWillBeMember<TextTrackList> m_textTracks;
WillBeHeapVector<RefPtrWillBeMember<TextTrack> > m_textTracksWhenResourceSelectionBegan;
......
......@@ -82,6 +82,8 @@
[Reflect=muted] attribute boolean defaultMuted;
// tracks
[RuntimeEnabled=AudioVideoTracks] readonly attribute AudioTrackList audioTracks;
[RuntimeEnabled=AudioVideoTracks] readonly attribute VideoTrackList videoTracks;
readonly attribute TextTrackList textTracks;
[RaisesException] TextTrack addTextTrack(DOMString kind, optional DOMString label, optional DOMString language);
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/html/track/AudioTrack.h"
#include "core/html/HTMLMediaElement.h"
namespace WebCore {
AudioTrack::AudioTrack(const String& id, const AtomicString& kind, const AtomicString& label, const AtomicString& language, bool enabled)
: TrackBase(TrackBase::AudioTrack, label, language, id)
, m_enabled(enabled)
{
ScriptWrappable::init(this);
setKind(kind);
}
AudioTrack::~AudioTrack()
{
}
void AudioTrack::setEnabled(bool enabled)
{
if (enabled == m_enabled)
return;
m_enabled = enabled;
if (mediaElement())
mediaElement()->audioTrackChanged();
}
const AtomicString& AudioTrack::alternativeKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("alternative", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& AudioTrack::descriptionsKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("descriptions", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& AudioTrack::mainKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("main", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& AudioTrack::mainDescriptionsKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("main-desc", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& AudioTrack::translationKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("translation", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& AudioTrack::commentaryKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("commentary", AtomicString::ConstructFromLiteral));
return keyword;
}
bool AudioTrack::isValidKind(const AtomicString& kind) const
{
return (kind == alternativeKeyword())
|| (kind == descriptionsKeyword())
|| (kind == mainKeyword())
|| (kind == mainDescriptionsKeyword())
|| (kind == translationKeyword())
|| (kind == commentaryKeyword());
}
AtomicString AudioTrack::defaultKind() const
{
return emptyAtom;
}
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef AudioTrack_h
#define AudioTrack_h
#include "bindings/v8/ScriptWrappable.h"
#include "core/html/track/TrackBase.h"
namespace WebCore {
class AudioTrack FINAL : public TrackBase, public ScriptWrappable {
public:
static PassRefPtrWillBeRawPtr<AudioTrack> create(const String& id, const AtomicString& kind, const AtomicString& label, const AtomicString& language, bool enabled)
{
return adoptRefWillBeRefCountedGarbageCollected(new AudioTrack(id, kind, label, language, enabled));
}
virtual ~AudioTrack();
bool enabled() const { return m_enabled; }
void setEnabled(bool);
// Valid kind keywords.
static const AtomicString& alternativeKeyword();
static const AtomicString& descriptionsKeyword();
static const AtomicString& mainKeyword();
static const AtomicString& mainDescriptionsKeyword();
static const AtomicString& translationKeyword();
static const AtomicString& commentaryKeyword();
private:
AudioTrack(const String& id, const AtomicString& kind, const AtomicString& label, const AtomicString& language, bool enabled);
// TrackBase
virtual bool isValidKind(const AtomicString&) const OVERRIDE;
virtual AtomicString defaultKind() const OVERRIDE;
bool m_enabled;
};
}
#endif
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
RuntimeEnabled=AudioVideoTracks,
SetWrapperReferenceFrom=owner,
WillBeGarbageCollected,
] interface AudioTrack {
readonly attribute DOMString id;
readonly attribute DOMString kind;
readonly attribute DOMString label;
readonly attribute DOMString language;
attribute boolean enabled;
};
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/html/track/AudioTrackList.h"
namespace WebCore {
PassRefPtrWillBeRawPtr<AudioTrackList> AudioTrackList::create(HTMLMediaElement& mediaElement)
{
return adoptRefWillBeRefCountedGarbageCollected(new AudioTrackList(mediaElement));
}
AudioTrackList::~AudioTrackList()
{
}
AudioTrackList::AudioTrackList(HTMLMediaElement& mediaElement)
: TrackListBase<AudioTrack>(&mediaElement)
{
ScriptWrappable::init(this);
}
bool AudioTrackList::hasEnabledTrack() const
{
for (unsigned i = 0; i < length(); ++i) {
if (anonymousIndexedGetter(i)->enabled())
return true;
}
return false;
}
const AtomicString& AudioTrackList::interfaceName() const
{
return EventTargetNames::AudioTrackList;
}
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef AudioTrackList_h
#define AudioTrackList_h
#include "bindings/v8/ScriptWrappable.h"
#include "core/html/track/AudioTrack.h"
#include "core/html/track/TrackListBase.h"
namespace WebCore {
class AudioTrackList FINAL : public TrackListBase<AudioTrack>, public ScriptWrappable {
public:
static PassRefPtrWillBeRawPtr<AudioTrackList> create(HTMLMediaElement&);
virtual ~AudioTrackList();
bool hasEnabledTrack() const;
// EventTarget
virtual const AtomicString& interfaceName() const OVERRIDE;
private:
explicit AudioTrackList(HTMLMediaElement&);
};
}
#endif
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
RuntimeEnabled=AudioVideoTracks,
SetWrapperReferenceFrom=owner,
] interface AudioTrackList : EventTarget {
readonly attribute unsigned long length;
getter AudioTrack (unsigned long index);
AudioTrack? getTrackById(DOMString id);
attribute EventHandler onchange;
attribute EventHandler onaddtrack;
attribute EventHandler onremovetrack;
};
......@@ -31,18 +31,42 @@
#include "config.h"
#include "core/html/track/TrackBase.h"
#include "core/html/HTMLMediaElement.h"
namespace WebCore {
TrackBase::TrackBase(Type type, const AtomicString& label, const AtomicString& language, const AtomicString& id)
: m_type(type)
static blink::WebMediaPlayer::TrackId nextTrackId()
{
static blink::WebMediaPlayer::TrackId next = 0;
return ++next;
}
TrackBase::TrackBase(Type type, const AtomicString& label, const AtomicString& language, const String& id)
: m_trackId(nextTrackId())
, m_type(type)
, m_label(label)
, m_language(language)
, m_id(id)
, m_mediaElement(nullptr)
{
}
TrackBase::~TrackBase()
{
#if !ENABLE(OILPAN)
ASSERT(!m_mediaElement);
#endif
}
Node* TrackBase::owner() const
{
return m_mediaElement;
}
void TrackBase::trace(Visitor* visitor)
{
visitor->trace(m_mediaElement);
}
void TrackBase::setKind(const AtomicString& kind)
......@@ -54,4 +78,3 @@ void TrackBase::setKind(const AtomicString& kind)
}
} // namespace WebCore
......@@ -27,15 +27,20 @@
#define TrackBase_h
#include "platform/heap/Handle.h"
#include "public/platform/WebMediaPlayer.h"
#include "wtf/RefCounted.h"
#include "wtf/text/AtomicString.h"
namespace WebCore {
class HTMLMediaElement;
class TrackBase : public RefCountedWillBeRefCountedGarbageCollected<TrackBase> {
public:
virtual ~TrackBase();
blink::WebMediaPlayer::TrackId trackId() const { return m_trackId; }
enum Type { TextTrack, AudioTrack, VideoTrack };
Type type() const { return m_type; }
......@@ -48,23 +53,29 @@ public:
AtomicString language() const { return m_language; }
void setLanguage(const AtomicString& language) { m_language = language; }
AtomicString id() const { return m_id; }
void setId(const AtomicString& id) { m_id = id; }
String id() const { return m_id; }
void setId(const String& id) { m_id = id; }
void setMediaElement(HTMLMediaElement* mediaElement) { m_mediaElement = mediaElement; }
HTMLMediaElement* mediaElement() const { return m_mediaElement; }
Node* owner() const;
virtual void trace(Visitor*) { }
virtual void trace(Visitor*);
protected:
TrackBase(Type, const AtomicString& label, const AtomicString& language, const AtomicString& id);
TrackBase(Type, const AtomicString& label, const AtomicString& language, const String& id);
virtual bool isValidKind(const AtomicString&) const = 0;
virtual AtomicString defaultKind() const = 0;
private:
blink::WebMediaPlayer::TrackId m_trackId;
Type m_type;
AtomicString m_kind;
AtomicString m_label;
AtomicString m_language;
AtomicString m_id;
String m_id;
RawPtrWillBeMember<HTMLMediaElement> m_mediaElement;
};
} // namespace WebCore
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TrackListBase_h
#define TrackListBase_h
#include "core/events/EventTarget.h"
#include "core/html/HTMLMediaElement.h"
#include "core/html/track/TrackEvent.h"
namespace WebCore {
template<class T>
class TrackListBase : public RefCountedWillBeRefCountedGarbageCollected<TrackListBase<T> >, public EventTargetWithInlineData {
REFCOUNTED_EVENT_TARGET(TrackListBase);
WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(TrackListBase);
public:
explicit TrackListBase(HTMLMediaElement* mediaElement)
: m_mediaElement(mediaElement)
{
}
virtual ~TrackListBase()
{
#if !ENABLE(OILPAN)
ASSERT(m_tracks.isEmpty());
ASSERT(!m_mediaElement);
#endif
}
unsigned length() const { return m_tracks.size(); }
T* anonymousIndexedGetter(unsigned index) const
{
if (index >= m_tracks.size())
return 0;
return m_tracks[index].get();
}
T* getTrackById(const String& id) const
{
for (unsigned i = 0; i < m_tracks.size(); ++i) {
if (m_tracks[i]->id() == id)
return m_tracks[i].get();
}
return 0;
}
DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
DEFINE_ATTRIBUTE_EVENT_LISTENER(addtrack);
DEFINE_ATTRIBUTE_EVENT_LISTENER(removetrack);
// EventTarget interface
virtual ExecutionContext* executionContext() const OVERRIDE
{
if (m_mediaElement)
return m_mediaElement->executionContext();
return 0;
}
#if !ENABLE(OILPAN)
void shutdown()
{
removeAll();
m_mediaElement = nullptr;
}
#endif
void add(PassRefPtrWillBeRawPtr<T> prpTrack)
{
RefPtrWillBeRawPtr<T> track = prpTrack;
track->setMediaElement(m_mediaElement);
m_tracks.append(track);
scheduleTrackEvent(EventTypeNames::addtrack, track.release());
}
void remove(blink::WebMediaPlayer::TrackId trackId)
{
for (unsigned i = 0; i < m_tracks.size(); ++i) {
if (m_tracks[i]->trackId() != trackId)
continue;
m_tracks[i]->setMediaElement(0);
scheduleTrackEvent(EventTypeNames::removetrack, m_tracks[i]);
m_tracks.remove(i);
return;
}
ASSERT_NOT_REACHED();
}
void removeAll()
{
for (unsigned i = 0; i < m_tracks.size(); ++i)
m_tracks[i]->setMediaElement(0);
m_tracks.clear();
}
void scheduleChangeEvent()
{
EventInit initializer;
initializer.bubbles = false;
initializer.cancelable = false;
RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::change, initializer);
event->setTarget(this);
m_mediaElement->scheduleEvent(event);
}
Node* owner() const { return m_mediaElement; }
void trace(Visitor* visitor)
{
visitor->trace(m_tracks);
visitor->trace(m_mediaElement);
EventTargetWithInlineData::trace(visitor);
}
private:
void scheduleTrackEvent(const AtomicString& eventName, PassRefPtrWillBeRawPtr<T> track)
{
TrackEventInit initializer;
initializer.track = track;
initializer.bubbles = false;
initializer.cancelable = false;
RefPtrWillBeRawPtr<Event> event = TrackEvent::create(eventName, initializer);
event->setTarget(this);
m_mediaElement->scheduleEvent(event);
}
WillBeHeapVector<RefPtrWillBeMember<T> > m_tracks;
RawPtrWillBeMember<HTMLMediaElement> m_mediaElement;
};
}
#endif
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/html/track/VideoTrack.h"
#include "core/html/HTMLMediaElement.h"
namespace WebCore {
VideoTrack::VideoTrack(const String& id, const AtomicString& kind, const AtomicString& label, const AtomicString& language, bool selected)
: TrackBase(TrackBase::VideoTrack, label, language, id)
, m_selected(selected)
{
ScriptWrappable::init(this);
setKind(kind);
}
VideoTrack::~VideoTrack()
{
}
void VideoTrack::setSelected(bool selected)
{
if (selected == m_selected)
return;
m_selected = selected;
if (mediaElement()) {
blink::WebMediaPlayer::TrackId selectedTrackId = trackId();
mediaElement()->selectedVideoTrackChanged(selected ? &selectedTrackId : 0);
}
}
const AtomicString& VideoTrack::alternativeKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("alternative", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& VideoTrack::captionsKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("captions", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& VideoTrack::mainKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("main", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& VideoTrack::signKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("sign", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& VideoTrack::subtitlesKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("subtitles", AtomicString::ConstructFromLiteral));
return keyword;
}
const AtomicString& VideoTrack::commentaryKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, keyword, ("commentary", AtomicString::ConstructFromLiteral));
return keyword;
}
bool VideoTrack::isValidKind(const AtomicString& kind) const
{
return (kind == alternativeKeyword())
|| (kind == captionsKeyword())
|| (kind == mainKeyword())
|| (kind == signKeyword())
|| (kind == subtitlesKeyword())
|| (kind == commentaryKeyword());
}
AtomicString VideoTrack::defaultKind() const
{
return emptyAtom;
}
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef VideoTrack_h
#define VideoTrack_h
#include "bindings/v8/ScriptWrappable.h"
#include "core/html/track/TrackBase.h"
namespace WebCore {
class VideoTrack FINAL : public TrackBase, public ScriptWrappable {
public:
static PassRefPtrWillBeRawPtr<VideoTrack> create(const String& id, const AtomicString& kind, const AtomicString& label, const AtomicString& language, bool selected)
{
return adoptRefWillBeRefCountedGarbageCollected(new VideoTrack(id, kind, label, language, selected));
}
virtual ~VideoTrack();
bool selected() const { return m_selected; }
void setSelected(bool);
// Set selected to false without notifying the owner media element. Used when
// another video track is selected, implicitly deselecting this one.
void clearSelected() { m_selected = false; }
// Valid kind keywords.
static const AtomicString& alternativeKeyword();
static const AtomicString& captionsKeyword();
static const AtomicString& mainKeyword();
static const AtomicString& signKeyword();
static const AtomicString& subtitlesKeyword();
static const AtomicString& commentaryKeyword();
private:
VideoTrack(const String& id, const AtomicString& kind, const AtomicString& label, const AtomicString& language, bool selected);
// TrackBase
virtual bool isValidKind(const AtomicString&) const OVERRIDE;
virtual AtomicString defaultKind() const OVERRIDE;
bool m_selected;
};
}
#endif
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
RuntimeEnabled=AudioVideoTracks,
SetWrapperReferenceFrom=owner,
WillBeGarbageCollected,
] interface VideoTrack {
readonly attribute DOMString id;
readonly attribute DOMString kind;
readonly attribute DOMString label;
readonly attribute DOMString language;
attribute boolean selected;
};
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/html/track/VideoTrackList.h"
#include "core/html/HTMLMediaElement.h"
#include "core/html/track/VideoTrack.h"
namespace WebCore {
PassRefPtrWillBeRawPtr<VideoTrackList> VideoTrackList::create(HTMLMediaElement& mediaElement)
{
return adoptRefWillBeRefCountedGarbageCollected(new VideoTrackList(mediaElement));
}
VideoTrackList::~VideoTrackList()
{
}
VideoTrackList::VideoTrackList(HTMLMediaElement& mediaElement)
: TrackListBase<VideoTrack>(&mediaElement)
{
ScriptWrappable::init(this);
}
const AtomicString& VideoTrackList::interfaceName() const
{
return EventTargetNames::VideoTrackList;
}
int VideoTrackList::selectedIndex() const
{
for (unsigned i = 0; i < length(); ++i) {
VideoTrack* track = anonymousIndexedGetter(i);
if (track->selected())
return i;
}
return -1;
}
void VideoTrackList::trackSelected(blink::WebMediaPlayer::TrackId selectedTrackId)
{
// Clear the selected flag on the previously selected track, if any.
for (unsigned i = 0; i < length(); ++i) {
VideoTrack* track = anonymousIndexedGetter(i);
if (track->trackId() != selectedTrackId)
track->clearSelected();
else
ASSERT(track->selected());
}
scheduleChangeEvent();
}
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef VideoTrackList_h
#define VideoTrackList_h
#include "bindings/v8/ScriptWrappable.h"
#include "core/html/track/TrackListBase.h"
#include "core/html/track/VideoTrack.h"
namespace WebCore {
class VideoTrackList FINAL : public TrackListBase<VideoTrack>, public ScriptWrappable {
public:
static PassRefPtrWillBeRawPtr<VideoTrackList> create(HTMLMediaElement&);
virtual ~VideoTrackList();
int selectedIndex() const;
// EventTarget
virtual const AtomicString& interfaceName() const OVERRIDE;
void trackSelected(blink::WebMediaPlayer::TrackId selectedTrackId);
private:
explicit VideoTrackList(HTMLMediaElement&);
};
}
#endif
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
RuntimeEnabled=AudioVideoTracks,
SetWrapperReferenceFrom=owner,
] interface VideoTrackList : EventTarget {
readonly attribute unsigned long length;
getter VideoTrack (unsigned long index);
VideoTrack? getTrackById(DOMString id);
readonly attribute long selectedIndex;
attribute EventHandler onchange;
attribute EventHandler onaddtrack;
attribute EventHandler onremovetrack;
};
......@@ -16,6 +16,7 @@
// #if ENABLE(FEATURE) guards. These are deprecated and should all be removed.
ApplicationCache status=stable
AudioVideoTracks depends_on=Media, status=experimental
AuthorShadowDOMForAnyElement
BatteryStatus status=experimental
Beacon status=experimental
......
......@@ -146,6 +146,26 @@ void WebMediaPlayerClientImpl::setWebLayer(blink::WebLayer* layer)
m_client->mediaPlayerSetWebLayer(layer);
}
WebMediaPlayer::TrackId WebMediaPlayerClientImpl::addAudioTrack(const WebString& id, AudioTrackKind kind, const WebString& label, const WebString& language, bool enabled)
{
return mediaElement().addAudioTrack(id, kind, label, language, enabled);
}
void WebMediaPlayerClientImpl::removeAudioTrack(WebMediaPlayer::TrackId id)
{
mediaElement().removeAudioTrack(id);
}
WebMediaPlayer::TrackId WebMediaPlayerClientImpl::addVideoTrack(const WebString& id, VideoTrackKind kind, const WebString& label, const WebString& language, bool selected)
{
return mediaElement().addVideoTrack(id, kind, label, language, selected);
}
void WebMediaPlayerClientImpl::removeVideoTrack(WebMediaPlayer::TrackId id)
{
mediaElement().removeVideoTrack(id);
}
void WebMediaPlayerClientImpl::addTextTrack(WebInbandTextTrack* textTrack)
{
m_client->mediaPlayerDidAddTextTrack(textTrack);
......
......@@ -85,6 +85,10 @@ public:
virtual void keyNeeded(const WebString& contentType, const unsigned char* initData, unsigned initDataLength) OVERRIDE;
virtual void setWebLayer(WebLayer*) OVERRIDE;
virtual WebMediaPlayer::TrackId addAudioTrack(const WebString& id, AudioTrackKind, const WebString& label, const WebString& language, bool enabled) OVERRIDE;
virtual void removeAudioTrack(WebMediaPlayer::TrackId) OVERRIDE;
virtual WebMediaPlayer::TrackId addVideoTrack(const WebString& id, VideoTrackKind, const WebString& label, const WebString& language, bool selected) OVERRIDE;
virtual void removeVideoTrack(WebMediaPlayer::TrackId) OVERRIDE;
virtual void addTextTrack(WebInbandTextTrack*) OVERRIDE;
virtual void removeTextTrack(WebInbandTextTrack*) OVERRIDE;
virtual void mediaSourceOpened(WebMediaSource*) OVERRIDE;
......
......@@ -95,6 +95,8 @@ public:
LoadTypeMediaStream,
};
typedef unsigned TrackId;
virtual ~WebMediaPlayer() { }
virtual void load(LoadType, const WebURL&, CORSMode) = 0;
......@@ -162,6 +164,10 @@ public:
virtual void exitFullscreen() { }
// Returns true if the player can enter fullscreen.
virtual bool canEnterFullscreen() const { return false; }
virtual void enabledAudioTracksChanged(const WebVector<TrackId>& enabledTrackIds) { }
// |selectedTrackId| is null if no track is selected.
virtual void selectedVideoTrackChanged(TrackId* selectedTrackId) { }
};
} // namespace blink
......
......@@ -53,6 +53,26 @@ public:
MediaKeyErrorCodeDomain,
};
enum VideoTrackKind {
VideoTrackKindNone,
VideoTrackKindAlternative,
VideoTrackKindCaptions,
VideoTrackKindMain,
VideoTrackKindSign,
VideoTrackKindSubtitles,
VideoTrackKindCommentary
};
enum AudioTrackKind {
AudioTrackKindNone,
AudioTrackKindAlternative,
AudioTrackKindDescriptions,
AudioTrackKindMain,
AudioTrackKindMainDescriptions,
AudioTrackKindTranslation,
AudioTrackKindCommentary
};
virtual void networkStateChanged() = 0;
virtual void readyStateChanged() = 0;
virtual void timeChanged() = 0;
......@@ -68,6 +88,10 @@ public:
virtual void keyMessage(const WebString& keySystem, const WebString& sessionId, const unsigned char* message, unsigned messageLength, const WebURL& defaultURL) = 0;
virtual void keyNeeded(const WebString& contentType, const unsigned char* initData, unsigned initDataLength) = 0;
virtual void setWebLayer(WebLayer*) = 0;
virtual WebMediaPlayer::TrackId addAudioTrack(const WebString& id, AudioTrackKind, const WebString& label, const WebString& language, bool enabled) = 0;
virtual void removeAudioTrack(WebMediaPlayer::TrackId) = 0;
virtual WebMediaPlayer::TrackId addVideoTrack(const WebString& id, VideoTrackKind, const WebString& label, const WebString& language, bool selected) = 0;
virtual void removeVideoTrack(WebMediaPlayer::TrackId) = 0;
virtual void addTextTrack(WebInbandTextTrack*) = 0;
virtual void removeTextTrack(WebInbandTextTrack*) = 0;
virtual void mediaSourceOpened(WebMediaSource*) = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment