[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