📄 mediaplayerprivategstreamer.cpp
字号:
/* * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Collabora Ltd. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * aint with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#include "config.h"#if ENABLE(VIDEO)#include "MediaPlayerPrivateGStreamer.h"#include "VideoSinkGStreamer.h"#include "CString.h"#include "GraphicsContext.h"#include "IntRect.h"#include "KURL.h"#include "MIMETypeRegistry.h"#include "MediaPlayer.h"#include "NotImplemented.h"#include "ScrollView.h"#include "Widget.h"#include <wtf/GOwnPtr.h>#include <gdk/gdkx.h>#include <gst/base/gstbasesrc.h>#include <gst/gst.h>#include <gst/interfaces/mixer.h>#include <gst/interfaces/xoverlay.h>#include <gst/video/video.h>#include <limits>#include <math.h>using namespace std;namespace WebCore {gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data){ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) { GOwnPtr<GError> err; GOwnPtr<gchar> debug; gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); if (err->code == 3) { LOG_VERBOSE(Media, "File not found"); MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); if (mp) mp->loadingFailed(); } else LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); } return true;}gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data){ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) { LOG_VERBOSE(Media, "End of Stream"); MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); mp->didEnd(); } return true;}gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data){ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) { MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); mp->updateStates(); } return true;}gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data){ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING) { gint percent = 0; gst_message_parse_buffering(message, &percent); LOG_VERBOSE(Media, "Buffering %d", percent); } return true;}MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) { return new MediaPlayerPrivate(player);}void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar){ if (isAvailable()) registrar(create, getSupportedTypes, supportsType);}MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_playBin(0) , m_videoSink(0) , m_source(0) , m_rate(1.0f) , m_endTime(numeric_limits<float>::infinity()) , m_isEndReached(false) , m_volume(0.5f) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::DataUnavailable) , m_startedPlaying(false) , m_isStreaming(false) , m_size(IntSize()) , m_visible(true){ static bool gstInitialized = false; // FIXME: We should pass the arguments from the command line if (!gstInitialized) { gst_init(0, NULL); gstInitialized = true; } // FIXME: The size shouldn't be fixed here, this is just a quick hack. m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480);}MediaPlayerPrivate::~MediaPlayerPrivate(){ if (m_surface) cairo_surface_destroy(m_surface); if (m_playBin) { gst_element_set_state(m_playBin, GST_STATE_NULL); gst_object_unref(GST_OBJECT(m_playBin)); }}void MediaPlayerPrivate::load(const String& url){ LOG_VERBOSE(Media, "Load %s", url.utf8().data()); if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; m_player->networkStateChanged(); } if (m_readyState != MediaPlayer::DataUnavailable) { m_readyState = MediaPlayer::DataUnavailable; m_player->readyStateChanged(); } createGSTPlayBin(url); pause();}void MediaPlayerPrivate::play(){ LOG_VERBOSE(Media, "Play"); // When end reached, rewind for Test video-seek-past-end-playing if (m_isEndReached) seek(0); m_isEndReached = false; gst_element_set_state(m_playBin, GST_STATE_PLAYING); m_startedPlaying = true;}void MediaPlayerPrivate::pause(){ LOG_VERBOSE(Media, "Pause"); gst_element_set_state(m_playBin, GST_STATE_PAUSED); m_startedPlaying = false;}float MediaPlayerPrivate::duration() const{ if (!m_playBin) return 0.0; GstFormat fmt = GST_FORMAT_TIME; gint64 len = 0; if (gst_element_query_duration(m_playBin, &fmt, &len)) LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len)); else LOG_VERBOSE(Media, "Duration query failed "); if ((GstClockTime)len == GST_CLOCK_TIME_NONE) { m_isStreaming = true; return numeric_limits<float>::infinity(); } return (float) (len / 1000000000.0); // FIXME: handle 3.14.9.5 properly}float MediaPlayerPrivate::currentTime() const{ if (!m_playBin) return 0; // Necessary as sometimes, gstreamer return 0:00 at the EOS if (m_isEndReached) return m_endTime; float ret; GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); if (gst_element_query(m_playBin, query)) { gint64 position; gst_query_parse_position(query, NULL, &position); ret = (float) (position / 1000000000.0); LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); } else { LOG_VERBOSE(Media, "Position query failed..."); ret = 0.0; } gst_query_unref(query); return ret;}void MediaPlayerPrivate::seek(float time){ GstClockTime sec = (GstClockTime)(time * GST_SECOND); if (!m_playBin) return; if (m_isStreaming) return; LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec)); // FIXME: What happens when the seeked position is not available? if (!gst_element_seek( m_playBin, m_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, sec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) LOG_VERBOSE(Media, "Seek to %f failed", time);}void MediaPlayerPrivate::setEndTime(float time){ if (!m_playBin) return; if (m_isStreaming) return; if (m_endTime != time) { m_endTime = time; GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND); GstClockTime end = (GstClockTime)(time * GST_SECOND); LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end)); // FIXME: What happens when the seeked position is not available? if (!gst_element_seek(m_playBin, m_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, end )) LOG_VERBOSE(Media, "Seek to %f failed", time); }}void MediaPlayerPrivate::startEndPointTimerIfNeeded(){ notImplemented();}void MediaPlayerPrivate::cancelSeek(){ notImplemented();}void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*){ notImplemented();}bool MediaPlayerPrivate::paused() const{ return !m_startedPlaying;}bool MediaPlayerPrivate::seeking() const{ return false;}// Returns the size of the videoIntSize MediaPlayerPrivate::naturalSize() const{ if (!hasVideo()) return IntSize(); int x = 0, y = 0; if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) { gst_video_get_size(GST_PAD(pad), &x, &y); gst_object_unref(GST_OBJECT(pad)); } return IntSize(x, y);}bool MediaPlayerPrivate::hasVideo() const{ gint currentVideo = -1; if (m_playBin) g_object_get(G_OBJECT(m_playBin), "current-video", ¤tVideo, NULL); return currentVideo > -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -