Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Source/WTF/wtf/MediaTime.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -374,7 +374,7 @@ MediaTime::operator bool() const
return compare(zeroTime()) != EqualTo;
}

MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs, bool fuzzy) const
{
if ((isPositiveInfinite() && rhs.isPositiveInfinite())
|| (isNegativeInfinite() && rhs.isNegativeInfinite())
Expand DownExpand Up@@ -403,6 +403,8 @@ MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
if (hasDoubleValue() && rhs.hasDoubleValue()) {
if (m_timeValueAsDouble == rhs.m_timeValueAsDouble)
return EqualTo;
if (fuzzy && fabs(m_timeValueAsDouble - rhs.m_timeValueAsDouble) <= fuzzinessThreshold().toDouble())
return EqualTo;

return m_timeValueAsDouble < rhs.m_timeValueAsDouble ? LessThan : GreaterThan;
}
Expand DownExpand Up@@ -463,6 +465,12 @@ const MediaTime& MediaTime::indefiniteTime()
return *time;
}

const MediaTime& MediaTime::fuzzinessThreshold()
{
static const MediaTime* time = new MediaTime(createWithDouble(0.00002));
return *time;
}

void MediaTime::setTimeScale(int32_t timeScale)
{
if (hasDoubleValue()) {
Expand Down
3 changes: 2 additions & 1 deletion Source/WTF/wtf/MediaTime.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -87,7 +87,7 @@ class WTF_EXPORT_PRIVATE MediaTime {
GreaterThan = 1,
} ComparisonFlags;

ComparisonFlags compare(const MediaTime& rhs) const;
ComparisonFlags compare(const MediaTime& rhs, bool fuzzy = false) const;

bool isValid() const { return m_timeFlags & Valid; }
bool isInvalid() const { return !isValid(); }
Expand All@@ -102,6 +102,7 @@ class WTF_EXPORT_PRIVATE MediaTime {
static const MediaTime& positiveInfiniteTime();
static const MediaTime& negativeInfiniteTime();
static const MediaTime& indefiniteTime();
static const MediaTime& fuzzinessThreshold();

const int64_t& timeValue() const { return m_timeValue; }
const int32_t& timeScale() const { return m_timeScale; }
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/platform/graphics/PlatformTimeRanges.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -98,7 +98,7 @@ class PlatformTimeRanges {

inline bool isContiguousWithRange(const Range& range) const
{
return range.m_start== m_end || range.m_end== m_start;
return range.m_start.compare(m_end, true) == MediaTime::EqualTo || range.m_end.compare(m_start, true) == MediaTime::EqualTo;
}

inline Range unionWithOverlappingOrContiguousRange(const Range& range) const
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/platform/graphics/SourceBufferPrivateClient.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -89,6 +89,8 @@ class SourceBufferPrivateClient {
};
virtual void sourceBufferPrivateAppendComplete(SourceBufferPrivate*, AppendResult) = 0;
virtual void sourceBufferPrivateDidReceiveRenderingError(SourceBufferPrivate*, int errocCode) = 0;

virtual double timestampOffset() const = 0;
};

}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,6 +37,8 @@ AudioTrackPrivateGStreamer::AudioTrackPrivateGStreamer(GRefPtr<GstElement> playb
: TrackPrivateBaseGStreamer(this, index, pad)
, m_playbin(playbin)
{
// FIXME: Get a real ID here
m_id = "A" + String::number(index);
notifyTrackOfActiveChanged();
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,12 +48,14 @@ class AudioTrackPrivateGStreamer final : public AudioTrackPrivate, public TrackP

virtual int trackIndex() const override { return m_index; }

virtual AtomicString id() const override { return m_id; }
virtual AtomicString label() const override { return m_label; }
virtual AtomicString language() const override { return m_language; }

private:
AudioTrackPrivateGStreamer(GRefPtr<GstElement> playbin, gint index, GRefPtr<GstPad>);

AtomicString m_id;
GRefPtr<GstElement> m_playbin;
};

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -333,6 +333,7 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()

#if ENABLE(MEDIA_SOURCE)
if (m_source && WEBKIT_IS_MEDIA_SRC(m_source.get())) {
webkit_media_src_set_mediaplayerprivate(WEBKIT_MEDIA_SRC(m_source.get()), 0);
g_signal_handlers_disconnect_by_func(m_source.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoChangedCallback), this);
g_signal_handlers_disconnect_by_func(m_source.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateAudioChangedCallback), this);
g_signal_handlers_disconnect_by_func(m_source.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateTextChangedCallback), this);
Expand DownExpand Up@@ -658,7 +659,11 @@ void MediaPlayerPrivateGStreamer::seek(float time)
LOG_MEDIA_MESSAGE("[Seek] cannot seek, current state change is %s", gst_element_state_change_return_get_name(getStateResult));
return;
}
if (getStateResult == GST_STATE_CHANGE_ASYNC || state < GST_STATE_PAUSED || m_isEndReached) {
if (getStateResult == GST_STATE_CHANGE_ASYNC || state < GST_STATE_PAUSED
#if ENABLE(MEDIA_SOURCE)
|| (isMediaSource() && webkit_media_src_is_appending(WEBKIT_MEDIA_SRC(m_source.get())))
#endif
|| m_isEndReached) {
m_seekIsPending = true;
if (m_isEndReached) {
LOG_MEDIA_MESSAGE("[Seek] reset pipeline");
Expand All@@ -683,11 +688,6 @@ bool MediaPlayerPrivateGStreamer::doSeek(gint64 position, float rate, GstSeekFla
{
gint64 startTime, endTime;

// TODO: Should do more than that, need to notify the media source
// and probably flush the pipeline at least.
if (isMediaSource())
return true;

if (rate > 0) {
startTime = position;
endTime = GST_CLOCK_TIME_NONE;
Expand All@@ -704,8 +704,23 @@ bool MediaPlayerPrivateGStreamer::doSeek(gint64 position, float rate, GstSeekFla
if (!rate)
rate = 1.0;

return gst_element_seek(m_pipeline.get(), rate, GST_FORMAT_TIME, seekType,
GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET, endTime);
MediaTime time(MediaTime::createWithDouble(double(static_cast<double>(position) / GST_SECOND)));

#if ENABLE(MEDIA_SOURCE)
if (isMediaSource())
webkit_media_src_set_seek_time(WEBKIT_MEDIA_SRC(m_source.get()), time);
#endif

if (!gst_element_seek(m_pipeline.get(), rate, GST_FORMAT_TIME, seekType,
GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET, endTime))
return false;

#if ENABLE(MEDIA_SOURCE)
if (isMediaSource())
m_mediaSource->seekToTime(time);
#endif

return true;
}

void MediaPlayerPrivateGStreamer::updatePlaybackRate()
Expand DownExpand Up@@ -784,7 +799,9 @@ void MediaPlayerPrivateGStreamer::videoCapsChanged()
void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
{
gint numTracks = 0;
#if ENABLE(MEDIA_SOURCE)
bool useMediaSource = false;
#endif
if (m_pipeline) {
#if ENABLE(MEDIA_SOURCE)
if (m_mediaSource && WEBKIT_IS_MEDIA_SRC(m_source.get())) {
Expand DownExpand Up@@ -862,7 +879,9 @@ void MediaPlayerPrivateGStreamer::audioChanged()
void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
{
gint numTracks = 0;
#if ENABLE(MEDIA_SOURCE)
bool useMediaSource = false;
#endif
if (m_pipeline) {
#if ENABLE(MEDIA_SOURCE)
if (m_mediaSource && WEBKIT_IS_MEDIA_SRC(m_source.get())) {
Expand DownExpand Up@@ -935,7 +954,9 @@ void MediaPlayerPrivateGStreamer::textChanged()
void MediaPlayerPrivateGStreamer::notifyPlayerOfText()
{
gint numTracks = 0;
#if ENABLE(MEDIA_SOURCE)
bool useMediaSource = false;
#endif
if (m_pipeline) {
#if ENABLE(MEDIA_SOURCE)
if (m_mediaSource && WEBKIT_IS_MEDIA_SRC(m_source.get())) {
Expand DownExpand Up@@ -1112,6 +1133,56 @@ std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateGStreamer::buffered() cons
return timeRanges;
}

#if ENABLE(MEDIA_SOURCE)
static StreamType getStreamType(GstElement* element)
{
g_return_val_if_fail(GST_IS_ELEMENT(element), STREAM_TYPE_UNKNOWN);

GstIterator* it;
GValue item = G_VALUE_INIT;
StreamType result = STREAM_TYPE_UNKNOWN;

it = gst_element_iterate_sink_pads(element);

if (it && (gst_iterator_next(it, &item)) == GST_ITERATOR_OK) {
GstPad* pad = GST_PAD(g_value_get_object(&item));
if (pad) {
GstCaps* caps = gst_pad_get_current_caps(pad);
if (caps && GST_IS_CAPS(caps)) {
const GstStructure* structure = gst_caps_get_structure(caps, 0);
if (structure) {
const gchar* mediatype = gst_structure_get_name(structure);
if (mediatype) {
// Look for "audio", "video", "text"
switch (mediatype[0]) {
case 'a':
result = STREAM_TYPE_AUDIO;
break;
case 'v':
result = STREAM_TYPE_VIDEO;
break;
case 't':
result = STREAM_TYPE_TEXT;
break;
default:
break;
}
}
}
gst_caps_unref(caps);
}
}
}

g_value_unset(&item);

if (it)
gst_iterator_free(it);

return result;
}
#endif

void MediaPlayerPrivateGStreamer::handleSyncMessage(GstMessage* message)
{
// FIXME: Use proper formatting across USE(GSTREAMER_GL) and ENABLE(ENCRYPTED_MEDIA_V2).
Expand DownExpand Up@@ -1357,6 +1428,15 @@ gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
case GST_MESSAGE_TOC:
processTableOfContents(message);
break;
#endif
#if ENABLE(MEDIA_SOURCE)
case GST_MESSAGE_RESET_TIME:
if (m_source && WEBKIT_IS_MEDIA_SRC(m_source.get())) {
StreamType streamType = getStreamType(GST_ELEMENT(GST_MESSAGE_SRC(message)));
if (streamType == STREAM_TYPE_AUDIO || streamType == STREAM_TYPE_VIDEO)
webkit_media_src_segment_needed(WEBKIT_MEDIA_SRC(m_source.get()), streamType);
}
break;
#endif
default:
LOG_MEDIA_MESSAGE("Unhandled GStreamer message type: %s",
Expand DownExpand Up@@ -1560,7 +1640,13 @@ float MediaPlayerPrivateGStreamer::maxTimeLoaded() const

bool MediaPlayerPrivateGStreamer::didLoadingProgress() const
{
if (!m_pipeline || !m_mediaDuration || (!isMediaSource() && !totalBytes()))
if (!m_pipeline ||
#if ENABLE(MEDIA_SOURCE)
(!isMediaSource() && !totalBytes())
#else
!totalBytes()
#endif
|| !m_mediaDuration)
return false;
float currentMaxTimeLoaded = maxTimeLoaded();
bool didLoadingProgress = currentMaxTimeLoaded != m_maxTimeLoadedAtLastDidLoadingProgress;
Expand DownExpand Up@@ -1637,6 +1723,7 @@ void MediaPlayerPrivateGStreamer::sourceChanged()
g_signal_connect(m_source.get(), "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
g_signal_connect(m_source.get(), "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
g_signal_connect(m_source.get(), "text-changed", G_CALLBACK(mediaPlayerPrivateTextChangedCallback), this);
webkit_media_src_set_mediaplayerprivate(WEBKIT_MEDIA_SRC(m_source.get()), this);
}
#endif
}
Expand DownExpand Up@@ -1985,6 +2072,20 @@ void MediaPlayerPrivateGStreamer::didEnd()
}
}

#if ENABLE(MEDIA_SOURCE)
void MediaPlayerPrivateGStreamer::notifyAppendComplete()
{
if (m_seekIsPending) {
updatePlaybackRate();
LOG_MEDIA_MESSAGE("[Seek] committing pending seek to %f after append completed", m_seekTime);
m_seekIsPending = false;
m_seeking = doSeek(toGstClockTime(m_seekTime), m_player->rate(), static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE));
if (!m_seeking)
LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", m_seekTime);
}
}
#endif

void MediaPlayerPrivateGStreamer::cacheDuration()
{
if (m_mediaDuration || !m_mediaDurationKnown)
Expand DownExpand Up@@ -2334,6 +2435,23 @@ GstElement* MediaPlayerPrivateGStreamer::audioSink() const
GstElement* sink;
g_object_get(m_pipeline.get(), "audio-sink", &sink, nullptr);
return sink;

GRefPtr<GstElement> playsink = adoptGRef(gst_bin_get_by_name(GST_BIN(m_pipeline.get()), "playsink"));
if (playsink) {
// The default value (0) means "send events to all the sinks", instead
// of "only to the first that returns true". This is needed for MSE seek.
g_object_set(G_OBJECT(playsink.get()), "send-event-mode", 0, NULL);
}
}

void MediaPlayerPrivateGStreamer::configurePlaySink()
{
GRefPtr<GstElement> playsink = adoptGRef(gst_bin_get_by_name(GST_BIN(m_pipeline.get()), "playsink"));
if (playsink) {
// The default value (0) means "send events to all the sinks", instead
// of "only to the first that returns true". This is needed for MSE seek.
g_object_set(G_OBJECT(playsink.get()), "send-event-mode", 0, NULL);
}
}

void MediaPlayerPrivateGStreamer::createGSTPlayBin()
Expand DownExpand Up@@ -2389,6 +2507,7 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin()
#endif

g_object_set(m_pipeline.get(), "video-sink", createVideoSink(), "audio-sink", createAudioSink(), nullptr);
configurePlaySink();

// On 1.4.2 and newer we use the audio-filter property instead.
// See https://bugzilla.gnome.org/show_bug.cgi?id=735748 for
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -137,6 +137,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateGStreamerBase {

void sourceChanged();
GstElement* audioSink() const;
void configurePlaySink();

void setAudioStreamProperties(GObject*);

Expand All@@ -157,6 +158,11 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateGStreamerBase {
void signalDRM();
#endif

virtual bool isLiveStream() const { return m_isStreaming; }
#if ENABLE(MEDIA_SOURCE)
void notifyAppendComplete();
#endif

private:
static void getSupportedTypes(HashSet<String>&);
static MediaPlayer::SupportsType supportsType(const MediaEngineSupportParameters&);
Expand DownExpand Up@@ -191,7 +197,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateGStreamerBase {


virtual String engineDescription() const { return "GStreamer"; }
virtual bool isLiveStream() const { return m_isStreaming; }
virtual bool didPassCORSAccessCheck() const;
virtual bool canSaveMediaData() const override;

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,22 +100,21 @@ void SourceBufferPrivateGStreamer::setReadyState(MediaPlayer::ReadyState state)
m_mediaSource->setReadyState(state);
}

// TODO: Implement these
void SourceBufferPrivateGStreamer::flushAndEnqueueNonDisplayingSamples(Vector<RefPtr<MediaSample> >, AtomicString)
void SourceBufferPrivateGStreamer::flushAndEnqueueNonDisplayingSamples(Vector<RefPtr<MediaSample> > samples, AtomicString trackIDString)
{
notImplemented();
if (m_client)
m_client->flushAndEnqueueNonDisplayingSamples(samples, trackIDString);
}

void SourceBufferPrivateGStreamer::enqueueSample(PassRefPtr<MediaSample>, AtomicString)
void SourceBufferPrivateGStreamer::enqueueSample(PassRefPtr<MediaSample> sample, AtomicString trackIDString)
{
notImplemented();
if (m_client)
m_client->enqueueSample(sample, trackIDString);
}

bool SourceBufferPrivateGStreamer::isReadyForMoreSamples(AtomicString)
{
notImplemented();

return false;
return true;
}

void SourceBufferPrivateGStreamer::setActive(bool isActive)
Expand DownExpand Up@@ -155,5 +154,13 @@ void SourceBufferPrivateGStreamer::didReceiveAllPendingSamples()
}
#endif

double SourceBufferPrivateGStreamer::timestampOffset() const
{
if (m_sourceBufferPrivateClient)
return m_sourceBufferPrivateClient->timestampOffset();
else
return 0.0;
}

}
#endif
Loading