[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: KDE/kdebase/runtime/phonon/xine
From: Matthias Kretz <kretz () kde ! org>
Date: 2008-08-09 12:13:01
Message-ID: 1218283981.741690.1925.nullmailer () svn ! kde ! org
[Download RAW message or body]
SVN commit 844334 by mkretz:
I messed up the branches - here comes the Experimental::SnapshotInterface \
implementation for trunk
M +5 -1 events.h
M +4 -0 mediaobject.cpp
M +31 -10 videowidget.cpp
M +13 -2 videowidget.h
M +106 -0 xinestream.cpp
--- trunk/KDE/kdebase/runtime/phonon/xine/events.h #844333:844334
@@ -28,6 +28,7 @@
#include <QtCore/QSize>
#include <QtCore/QPair>
#include <QtCore/QList>
+#include <QtGui/QImage>
#define QEVENT(type) Event(Event::type)
@@ -98,7 +99,9 @@
IsThereAXineEngineForMe,
NoThereIsNoXineEngineForYou,
HeresYourXineStream,
- Cleanup
+ Cleanup,
+ RequestSnapshot,
+ SnapshotReady
};
int ref;
@@ -115,6 +118,7 @@
return 0;
}
+EVENT_CLASS1(SnapshotReady, QImage i, image(i), const QImage, image)
EVENT_CLASS1(HeresYourXineStream, QExplicitlySharedDataPointer<XineStream> s, \
stream(s), QExplicitlySharedDataPointer<XineStream>, stream) EVENT_CLASS1(HasVideo, \
bool v, hasVideo(v), const bool, hasVideo) EVENT_CLASS1(UpdateVolume, int v, \
volume(v), const int, volume)
--- trunk/KDE/kdebase/runtime/phonon/xine/mediaobject.cpp #844333:844334
@@ -667,6 +667,10 @@
// postEvent takes ownership of the event and will delete it when done
QCoreApplication::postEvent(m_stream, \
copyEvent(static_cast<UpdateVolumeEvent *>(e))); break;
+ case Event::RequestSnapshot:
+ // postEvent takes ownership of the event and will delete it when done
+ QCoreApplication::postEvent(m_stream, new Event(e->type()));
+ break;
case Event::SetParam:
// postEvent takes ownership of the event and will delete it when done
QCoreApplication::postEvent(m_stream, copyEvent(static_cast<SetParamEvent \
*>(e)));
--- trunk/KDE/kdebase/runtime/phonon/xine/videowidget.cpp #844333:844334
@@ -1,19 +1,20 @@
/* This file is part of the KDE project
Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2
- as published by the Free Software Foundation.
+ This program 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 program is distributed in the hope that it will be useful,
+ 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 General Public License for more details.
+ 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 General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
+ You should have received a copy of the GNU Library General Public License
+ along 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.
*/
@@ -21,6 +22,7 @@
#include "events.h"
#include <QPalette>
#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QMutexLocker>
#include <QtCore/QSharedData>
#include <QImage>
#include <QPainter>
@@ -339,6 +341,18 @@
}
}
+QImage VideoWidget::snapshot() const
+{
+ QImage img;
+ QMutexLocker lock(&m_snapshotLock);
+ const_cast<VideoWidget *>(this)->upstreamEvent(new \
Event(Event::RequestSnapshot)); + if (m_snapshotWait.wait(&m_snapshotLock, 1000)) \
{ + img = m_snapshotImage;
+ m_snapshotImage = QImage();
+ }
+ return img;
+}
+
/*
int VideoWidget::overlayCapabilities() const
{
@@ -557,6 +571,7 @@
p.fillRect(rect(), Qt::black);
//#ifndef PHONON_XINE_NO_VIDEOWIDGET
} else if (xt->m_videoPort) {
+ //kDebug();
const QRect &rect = event->rect();
xcb_expose_event_t xcb_event;
@@ -629,6 +644,12 @@
}
}
break;
+ case Event::SnapshotReady:
+ m_snapshotLock.lock();
+ m_snapshotImage = static_cast<const SnapshotReadyEvent *>(e)->image;
+ m_snapshotWait.wakeAll();
+ m_snapshotLock.unlock();
+ break;
default:
QCoreApplication::sendEvent(this, e);
break;
--- trunk/KDE/kdebase/runtime/phonon/xine/videowidget.h #844333:844334
@@ -21,6 +21,9 @@
#define PHONON_XINE_VIDEOWIDGET_H
#include <QWidget>
+#include <QtCore/QMutex>
+#include <QtGui/QImage>
+#include <QtCore/QWaitCondition>
#include "sinknode.h"
#include <QPixmap>
#include <xine.h>
@@ -31,6 +34,8 @@
#include <Phonon/VideoWidget>
#include <Phonon/VideoWidgetInterface>
+//#include <Phonon/Experimental/SnapshotInterface>
+#include <phonon/experimental/snapshotinterface.h>
#include "connectnotificationinterface.h"
class QMouseEvent;
@@ -87,10 +92,10 @@
bool m_isValid;
};
-class VideoWidget : public QWidget, public Phonon::VideoWidgetInterface, public \
Phonon::Xine::SinkNode +class VideoWidget : public QWidget, public \
Phonon::VideoWidgetInterface, public Phonon::Xine::SinkNode, public \
Phonon::Experimental::SnapshotInterface {
Q_OBJECT
- Q_INTERFACES(Phonon::VideoWidgetInterface Phonon::Xine::SinkNode)
+ Q_INTERFACES(Phonon::VideoWidgetInterface Phonon::Xine::SinkNode \
Phonon::Experimental::SnapshotInterface) public:
VideoWidget(QWidget *parent = 0);
~VideoWidget();
@@ -114,6 +119,8 @@
qreal saturation() const;
void setSaturation(qreal);
+ QImage snapshot() const;
+
void xineCallback(int &x, int &y, int &width, int &height,
double &ratio, int videoWidth, int videoHeight, double videoRatio, \
bool mayResize);
@@ -144,6 +151,10 @@
Phonon::VideoWidget::AspectRatio m_aspectRatio;
Phonon::VideoWidget::ScaleMode m_scaleMode;
+ mutable QMutex m_snapshotLock;
+ mutable QWaitCondition m_snapshotWait;
+ mutable QImage m_snapshotImage;
+
QSize m_sizeHint;
/**
--- trunk/KDE/kdebase/runtime/phonon/xine/xinestream.cpp #844333:844334
@@ -1027,6 +1027,112 @@
}
}
return true;
+ case Event::RequestSnapshot:
+ ev->accept();
+ if (m_stream) {
+ const int32_t w = xine_get_stream_info(m_stream, \
XINE_STREAM_INFO_VIDEO_WIDTH); + const int32_t h = \
xine_get_stream_info(m_stream, XINE_STREAM_INFO_VIDEO_HEIGHT); + \
kDebug(610) << "taking snapshot of" << w << h; + if (w > 0 && h > 0) {
+ int width, height, ratio_code, format;
+ uint8_t img[w * h * 4];
+ int success = xine_get_current_frame (m_stream, &width, &height, \
&ratio_code, + &format, &img[0]);
+ if (!success) {
+ return true;
+ }
+ Q_ASSERT(w * h * 2 >= width * height);
+ QImage qimg(width, height, QImage::Format_RGB32);
+ /*
+ * Do YCbCr - sRGB conversion according to ITU-R BT.709 with Kb = \
0.0722 and Kr = 0.2126 + *
+ * / \ / \ / \
\ + * | R | | 76309.0411, 0.0, 117489.0789 | | \
Y - 16 | + * | | | \
| | | + * => | G | = | 76309.0411, -13975.46119, \
-34924.74576 | * | Cb - 128 | * 2^-16 + * | | | \
| | | + * | B | | 76309.0411, 138438.3634, \
0 | | Cr - 128 | + * \ / \ \
/ \ / + */
+ switch (format) {
+ case XINE_IMGFMT_YUY2: // every four consecutive pixels Y0 Cb Y1 Cr
+ kDebug(610) << "got a YUY2 snapshot";
+ Q_ASSERT(width % 2 == 0);
+ for (int row = 0; row < height; ++row) {
+ QRgb *line = reinterpret_cast<QRgb *>(qimg.scanLine(row));
+ const uint8_t *yuyv = &img[2 * width];
+ for (int col = 0; col < 2 * width; col += 4) {
+ const int y0 = (yuyv[col] - 16) * 76309;
+ const int u = yuyv[col + 1] - 128;
+ const int y1 = (yuyv[col + 2] - 16) * 76309;
+ const int v = yuyv[col + 3] - 128;
+ const int r = 117489 * v + 16384;
+ const int g = -13975 * u -34925 * v + 16384;
+ const int b = 138438 * u + 16384;
+ line[col >> 1] = qRgb(
+ qBound(0, (y0 + r) >> 16, 255),
+ qBound(0, (y0 + g) >> 16, 255),
+ qBound(0, (y0 + b) >> 16, 255));
+ line[(col >> 1) + 1] = qRgb(
+ qBound(0, (y1 + r) >> 16, 255),
+ qBound(0, (y1 + g) >> 16, 255),
+ qBound(0, (y1 + b) >> 16, 255));
+ }
+ }
+ break;
+ case XINE_IMGFMT_YV12:
+ kDebug(610) << "got a YV12 snapshot";
+ Q_ASSERT(width % 2 == 0);
+ Q_ASSERT(height % 2 == 0);
+ {
+ const int w2 = width >> 1;
+ const uint8_t *yplane = &img[0];
+ const uint8_t *uplane = &img[width * height];
+ const uint8_t *vplane = &img[width * height + ((width * \
height) >> 2)]; + for (int row = 0; row < height; row += 2) {
+ QRgb *line0 = reinterpret_cast<QRgb \
*>(qimg.scanLine(row)); + QRgb *line1 = \
reinterpret_cast<QRgb *>(qimg.scanLine(row + 1)); + const \
uint8_t *yline0 = &yplane[row * width]; + const uint8_t \
*yline1 = &yplane[(row + 1) * width]; + const uint8_t \
*uline = &uplane[(row >> 1) * w2]; + const uint8_t *vline \
= &vplane[(row >> 1) * w2]; + for (int col = 0; col < \
width; col += 2) { + const int y0 = (yline0[col ] - \
16) * 76309; + const int y1 = (yline0[col + 1] - 16) * \
76309; + const int y2 = (yline1[col ] - 16) * \
76309; + const int y3 = (yline1[col + 1] - 16) * \
76309; + const int u = (uline[col >> 1] - 128);
+ const int v = (vline[col >> 1] - 128);
+ const int r = 117489 * v + 16384;
+ const int g = -13975 * u -34925 * v + 16384;
+ const int b = 138438 * u + 16384;
+ line0[col] = qRgb(
+ qBound(0, (y0 + r) >> 16, 255),
+ qBound(0, (y0 + g) >> 16, 255),
+ qBound(0, (y0 + b) >> 16, 255));
+ line0[col + 1] = qRgb(
+ qBound(0, (y1 + r) >> 16, 255),
+ qBound(0, (y1 + g) >> 16, 255),
+ qBound(0, (y1 + b) >> 16, 255));
+ line1[col] = qRgb(
+ qBound(0, (y2 + r) >> 16, 255),
+ qBound(0, (y2 + g) >> 16, 255),
+ qBound(0, (y2 + b) >> 16, 255));
+ line1[col + 1] = qRgb(
+ qBound(0, (y3 + r) >> 16, 255),
+ qBound(0, (y3 + g) >> 16, 255),
+ qBound(0, (y3 + b) >> 16, 255));
+ }
+ }
+ }
+ break;
+ default:
+ return true;
+ }
+ handleDownstreamEvent(new SnapshotReadyEvent(qimg));
+ }
+ }
+ return true;
case Event::MrlChanged:
ev->accept();
{
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic