2 * This file is part of CameraPlus.
4 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "videoplayer.h"
22 #include <QDeclarativeInfo>
23 #include "qtcamgraphicsviewfinder.h"
24 #include "cameraconfig.h"
27 VideoPlayer::VideoPlayer(QDeclarativeItem *parent) :
28 QDeclarativeItem(parent),
32 m_state(VideoPlayer::StateStopped),
33 m_timer(new QTimer(this)),
36 m_timer->setSingleShot(false);
37 m_timer->setInterval(500);
38 QObject::connect(m_timer, SIGNAL(timeout()), this, SIGNAL(positionChanged()));
41 VideoPlayer::~VideoPlayer() {
45 gst_object_unref(m_bin);
50 void VideoPlayer::componentComplete() {
54 void VideoPlayer::classBegin() {
55 m_bin = gst_element_factory_make ("playbin2", "VideoPlayerBin");
57 qmlInfo(this) << "Failed to create playbin2";
61 g_object_set (m_bin, "flags", 99, NULL);
63 GstElement *elem = gst_element_factory_make("pulsesink", "VideoPlayerPulseSink");
65 qmlInfo(this) << "Failed to create pulsesink";
68 // TODO: properties on sink
69 g_object_set (m_bin, "audio-sink", elem, NULL);
72 GstBus *bus = gst_element_get_bus(m_bin);
73 gst_bus_add_watch(bus, bus_call, this);
74 gst_object_unref(bus);
77 QUrl VideoPlayer::source() const {
81 void VideoPlayer::setSource(const QUrl& source) {
82 if (m_url != source) {
88 CameraConfig *VideoPlayer::cameraConfig() const {
92 void VideoPlayer::setCameraConfig(CameraConfig *config) {
93 if (m_config && m_config != config) {
94 qmlInfo(this) << "Cannot reset CameraConfig";
99 qmlInfo(this) << "CameraConfig cannot be empty";
103 if (m_config != config) {
105 // TODO: We need fence sync here.
106 m_vf = new QtCamGraphicsViewfinder(m_config->config(), this);
107 m_vf->resize(QSizeF(width(), height()));
108 emit cameraConfigChanged();
112 g_object_set(m_bin, "video-sink", m_vf->sinkElement(), NULL);
116 qint64 VideoPlayer::duration() const {
121 GstFormat format = GST_FORMAT_TIME;
123 if (!gst_element_query_duration(m_bin, &format, &dur)) {
124 qmlInfo(this) << "Failed to query pipeline duration";
128 if (format != GST_FORMAT_TIME) {
129 qmlInfo(this) << "Pipeline format is not time";
138 qint64 VideoPlayer::position() {
143 GstFormat format = GST_FORMAT_TIME;
145 if (!gst_element_query_position(m_bin, &format, &pos)) {
146 qmlInfo(this) << "Failed to query pipeline position";
150 if (format != GST_FORMAT_TIME) {
151 qmlInfo(this) << "Pipeline format is not time";
162 void VideoPlayer::setPosition(qint64 position) {
166 bool VideoPlayer::pause() {
167 return setState(VideoPlayer::StatePaused);
170 bool VideoPlayer::play() {
171 return setState(VideoPlayer::StatePlaying);
174 bool VideoPlayer::seek(qint64 offset) {
176 qmlInfo(this) << "no playbin2";
184 GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE);
185 gboolean ret = gst_element_seek_simple (m_bin, GST_FORMAT_TIME,
197 bool VideoPlayer::stop() {
198 return setState(VideoPlayer::StateStopped);
201 void VideoPlayer::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) {
202 QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
205 m_vf->resize(newGeometry.size());
209 VideoPlayer::State VideoPlayer::state() const {
213 bool VideoPlayer::setState(const VideoPlayer::State& state) {
214 if (state == m_state) {
219 qmlInfo(this) << "no playbin2";
223 if (state == VideoPlayer::StatePaused) {
226 // Set uri if needed:
227 if (m_state == VideoPlayer::StateStopped) {
228 const char *uri = m_url.toString().toUtf8().constData();
229 g_object_set(m_bin, "uri", uri, NULL);
232 if (gst_element_set_state(m_bin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
233 qmlInfo(this) << "error setting pipeline to PAUSED";
238 if (gst_element_get_state(m_bin, &st, NULL, GST_CLOCK_TIME_NONE)
239 == GST_STATE_CHANGE_FAILURE) {
240 qmlInfo(this) << "setting pipeline to PAUSED failed";
244 if (st != GST_STATE_PAUSED) {
245 qmlInfo(this) << "pipeline failed to transition to to PAUSED state";
254 else if (state == VideoPlayer::StatePlaying) {
255 // Set uri if needed:
256 if (m_state == VideoPlayer::StateStopped) {
257 const char *uri = m_url.toString().toUtf8().constData();
258 g_object_set(m_bin, "uri", uri, NULL);
261 if (gst_element_set_state(m_bin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
262 qmlInfo(this) << "error setting pipeline to PLAYING";
267 if (gst_element_get_state(m_bin, &st, NULL, GST_CLOCK_TIME_NONE)
268 == GST_STATE_CHANGE_FAILURE) {
269 qmlInfo(this) << "setting pipeline to PLAYING failed";
273 if (st != GST_STATE_PLAYING) {
274 qmlInfo(this) << "pipeline failed to transition to to PLAYING state";
281 emit durationChanged();
282 emit positionChanged();
291 if (gst_element_set_state(m_bin, GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE) {
292 qmlInfo(this) << "error setting pipeline to NULL";
297 if (gst_element_get_state(m_bin, &st, NULL, GST_CLOCK_TIME_NONE)
298 == GST_STATE_CHANGE_FAILURE) {
299 qmlInfo(this) << "setting pipeline to NULL failed";
303 if (st != GST_STATE_NULL) {
304 qmlInfo(this) << "pipeline failed to transition to to NULL state";
311 emit durationChanged();
312 emit positionChanged();
318 gboolean VideoPlayer::bus_call(GstBus *bus, GstMessage *msg, gpointer data) {
321 VideoPlayer *that = (VideoPlayer *) data;
326 switch (GST_MESSAGE_TYPE(msg)) {
327 case GST_MESSAGE_EOS:
331 case GST_MESSAGE_ERROR:
332 gst_message_parse_error (msg, &err, &debug);
334 emit that->error(err->message, err->code, debug);