Public feed #601165

Someone

public text v1 · immutable
Raw Edit
·published 2007-07-03 10:30 UTC
rendered paste body
Index: phonon-xine/videowidget.cpp
===================================================================
--- phonon-xine/videowidget.cpp	(révision 682687)
+++ phonon-xine/videowidget.cpp	(copie de travail)
@@ -67,7 +67,6 @@
 void VideoWidget::xineCallback( int &x, int &y, int &width, int &height, double &ratio,
 		int videoWidth, int videoHeight, double videoRatio, bool mayResize )
 {
-	Q_UNUSED( videoRatio );
 	Q_UNUSED( videoWidth );
 	Q_UNUSED( videoHeight );
 	Q_UNUSED( mayResize );
@@ -76,6 +75,7 @@
 	y = this->y();
 	width = this->width();
 	height = this->height();
+	m_videoRatio = videoRatio;
 
 	// square pixels
 	ratio = 1.0;
@@ -87,7 +87,8 @@
     m_videoPort(0),
     m_path(0),
     m_fullScreen(false),
-    m_empty(true)
+    m_empty(true),
+    m_videoRatio(1.0)
 {
 	// for some reason it can hang if the widget is 0x0
 	setMinimumSize( 1, 1 );
@@ -175,6 +176,14 @@
 	m_path = 0;
 }
 
+void VideoWidget::requestScreenShot()
+{
+    if (m_path && m_path->mediaObject()) {
+        XineStream &xs = m_path->mediaObject()->stream();
+        xs.requestScreenShot( m_videoRatio );
+    }
+}
+
 Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
 {
 	return m_aspectRatio;
Index: phonon-xine/xinestream.h
===================================================================
--- phonon-xine/xinestream.h	(révision 682687)
+++ phonon-xine/xinestream.h	(copie de travail)
@@ -26,6 +26,7 @@
 #include <phonon/phononnamespace.h>
 #include <xine.h>
 #include <QWaitCondition>
+#include <QImage>
 
 #include <sys/time.h>
 #include <time.h>
@@ -65,6 +66,7 @@
         bool hasVideo() const;
         bool isSeekable() const;
         void setVolume(int vol);
+        void requestScreenShot(double videoRatio);
 
         void addAudioPostList(const AudioPostList &);
         void removeAudioPostList(const AudioPostList &);
@@ -140,6 +142,8 @@
         void angleChanged(int);
         void availableTitlesChanged(int);
         void titleChanged(int);
+        
+        void screenShotReady(const QImage&);
 
     protected:
         bool event(QEvent *ev);
@@ -165,6 +169,9 @@
         void error(Phonon::ErrorType, const QString &);
         void internalPause();
         void internalPlay();
+        void takeScreenShot();
+        uchar* yv12ToRgb(uint8_t *src_y, uint8_t *src_u, uint8_t *src_v, int width, int height);
+        void yuy2Toyv12(uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *input, int width, int height);
 
         xine_stream_t *m_stream;
         xine_event_queue_t *m_event_queue;
@@ -179,6 +186,7 @@
         QMutex m_portMutex;
         mutable QMutex m_mutex;
         mutable QMutex m_streamInfoMutex;
+        mutable QMutex m_screenshotMutex;
         mutable QMutex m_updateTimeMutex;
         mutable QWaitCondition m_waitingForStreamInfo;
         QWaitCondition m_waitingForEventLoop;
@@ -215,6 +223,8 @@
         bool m_ticking : 1;
         bool m_closing : 1;
         bool m_eventLoopReady : 1;
+        QImage m_screenshotImage;
+        double m_screenshotRatio;
 };
 
 } // namespace Xine
Index: phonon-xine/mediaobject.cpp
===================================================================
--- phonon-xine/mediaobject.cpp	(révision 682687)
+++ phonon-xine/mediaobject.cpp	(copie de travail)
@@ -80,6 +80,7 @@
     connect(&m_stream, SIGNAL(prefinishMarkReached(qint32)), SIGNAL(prefinishMarkReached(qint32)), Qt::QueuedConnection);
     connect(&m_stream, SIGNAL(availableTitlesChanged(int)), SLOT(handleAvailableTitlesChanged(int)));
     connect(&m_stream, SIGNAL(needNextUrl()), SLOT(needNextUrl()));
+    connect(&m_stream, SIGNAL(screenShotReady(const QImage&)), SIGNAL(screenShotReady(const QImage&)));
 }
 
 MediaObject::~MediaObject()
Index: phonon-xine/videowidget.h
===================================================================
--- phonon-xine/videowidget.h	(révision 682687)
+++ phonon-xine/videowidget.h	(copie de travail)
@@ -65,6 +65,9 @@
 
             bool isValid() const { return videoPort() != 0; }
             void setVideoEmpty(bool);
+            
+        public Q_SLOTS:
+            void requestScreenShot();            
 
 		signals:
 			void videoPortChanged();
@@ -96,6 +99,7 @@
             QSize m_sizeHint;
 			int m_videoWidth;
 			int m_videoHeight;
+			double m_videoRatio;
 			bool m_fullScreen;
             /**
              * No video should be shown, all paint events should draw black
Index: phonon-xine/xinestream.cpp
===================================================================
--- phonon-xine/xinestream.cpp	(révision 682687)
+++ phonon-xine/xinestream.cpp	(copie de travail)
@@ -66,7 +66,8 @@
     QuitEventLoop = 2018,
     PauseForBuffering = 2019,  // XXX numerically used in bytestream.cpp
     UnpauseForBuffering = 2020, // XXX numerically used in bytestream.cpp
-    Error = 2021
+    Error = 2021,
+    GetScreenShot = 2022
 };
 
 class ErrorEvent : public QEvent
@@ -317,6 +318,16 @@
 }
 
 // called from main thread
+void XineStream::requestScreenShot(double videoRatio)
+{
+    QMutexLocker locker(&m_screenshotMutex);
+    m_screenshotImage = QImage();
+    m_screenshotRatio = videoRatio,
+    QCoreApplication::postEvent(this, new QEvent(static_cast<QEvent::Type>(GetScreenShot)));
+}
+
+
+// called from main thread
 bool XineStream::isSeekable() const
 {
     if (!m_streamInfoReady) {
@@ -335,6 +346,64 @@
 }
 
 // xine thread
+void XineStream::takeScreenShot()
+{
+    Q_ASSERT(QThread::currentThread() == this);
+
+    if (m_stream) {
+        QMutexLocker locker(&m_screenshotMutex);
+        uint8_t *yuv=NULL, *y=NULL, *u=NULL, *v=NULL;
+        int width, height, ratio, format;
+        if (!xine_get_current_frame(m_stream, &width, &height, &ratio, &format, NULL))
+            goto out;
+        yuv = new uint8_t[((width+8) * (height+1) * 2)];
+        if (yuv == NULL)
+            //Not enough memory to make screenshot!
+            goto out;
+        
+        xine_get_current_frame(m_stream, &width, &height, &ratio, &format, yuv);
+        //convert to yv12 if necessary
+        switch (format) {
+            case XINE_IMGFMT_YUY2:{
+                uint8_t *yuy2 = yuv;
+                yuv = new uint8_t[(width * height * 2)];
+                if (yuv == NULL)
+                    //Not enough memory to make screenshot!
+                    goto out;
+                y = yuv;
+                u = yuv + width * height;
+                v = yuv + width * height * 5 / 4;
+                yuy2Toyv12 (y, u, v, yuy2, width, height);delete [] yuy2;
+                break;
+            }
+            case XINE_IMGFMT_YV12:
+                y = yuv;
+                u = yuv + width * height;
+                v = yuv + width * height * 5 / 4;
+                break;
+            default:
+                //unsupported format
+                delete [] yuv;
+                goto out;
+        }
+        //convert to rgb
+        uchar *rgb32BitData = yv12ToRgb (y, u, v, width, height);
+        if (rgb32BitData) {
+            m_screenshotImage = QImage(rgb32BitData, width, height, QImage::Format_RGB32);
+            if (m_screenshotRatio >= 1.0)
+                width = (int)((double) width * m_screenshotRatio + 0.5);
+            else
+                height = (int)((double) height / m_screenshotRatio + 0.5);
+            m_screenshotImage = m_screenshotImage.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+            delete [] rgb32BitData;
+        }
+        delete [] yuv;
+    }
+out:
+    emit screenShotReady( m_screenshotImage );
+}
+
+// xine thread
 void XineStream::getStreamInfo()
 {
     Q_ASSERT(QThread::currentThread() == this);
@@ -941,6 +1010,10 @@
             getStreamInfo();
             ev->accept();
             return true;
+        case GetScreenShot:
+            takeScreenShot();
+            ev->accept();
+            return true;
         case UpdateVolume:
             if (m_stream) {
                 xine_set_param(m_stream, XINE_PARAM_AUDIO_AMP_LEVEL, m_volume);
@@ -1618,6 +1691,111 @@
     }
 }
 
+/************************************************************
+ *   Helpers to convert yuy and yv12 frames to rgb          *
+ *   code from gxine modified for 32bit output              *
+ *   Copyright (C) 2000-2003 the xine project               *
+ ************************************************************/
+void XineStream::yuy2Toyv12(uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *input, int width, int height)
+{
+    int i, j, w2;
+    w2 = width / 2;
+    
+    for (i = 0; i < height; i += 2) {
+        for (j = 0; j < w2; j++) {
+            // packed YUV 422 is: Y[i] U[i] Y[i+1] V[i]
+            *(y++) = *(input++);
+            *(u++) = *(input++);
+            *(y++) = *(input++);
+            *(v++) = *(input++);
+        }
+        // down sampling
+        for (j = 0; j < w2; j++) {
+            // skip every second line for U and V
+            *(y++) = *(input++);
+            input++;
+            *(y++) = *(input++);
+            input++;
+        }
+    }
+}
+
+uchar* XineStream::yv12ToRgb(uint8_t *src_y, uint8_t *src_u, uint8_t *src_v, int width, int height)
+{
+    // Create rgb data from yv12
+#define clip_8_bit(val)              \
+{                                    \
+   if (val < 0)                      \
+      val = 0;                       \
+   else                              \
+      if (val > 255) val = 255;      \
+}
+    int i, j;
+    int y, u, v;
+    int r, g, b;
+    int sub_i_uv;
+    int sub_j_uv;
+    int uv_width, uv_height;
+    uchar *rgb;
+    
+    uv_width  = width / 2;
+    uv_height = height / 2;
+    
+    rgb = new uchar[(width * height * 4)]; //qt needs a 32bit align
+    if (!rgb)
+        return NULL;
+
+    for (i = 0; i < height; ++i) {
+        // calculate u & v rows
+        sub_i_uv = ((i * uv_height) / height);
+        for (j = 0; j < width; ++j) {
+            // calculate u & v columns
+            sub_j_uv = ((j * uv_width) / width);
+            /***************************************************
+            *
+            *  Colour conversion from
+            *    http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
+            *
+            *  Thanks to Billy Biggs <vektor@dumbterm.net>
+            *  for the pointer and the following conversion.
+            *
+            *   R' = [ 1.1644         0    1.5960 ]   ([ Y' ]   [  16 ])
+            *   G' = [ 1.1644   -0.3918   -0.8130 ] * ([ Cb ] - [ 128 ])
+            *   B' = [ 1.1644    2.0172         0 ]   ([ Cr ]   [ 128 ])
+            *
+            *  Where in xine the above values are represented as
+            *
+            *   Y' == image->y
+            *   Cb == image->u
+            *   Cr == image->v
+            *
+            ***************************************************/
+            y = src_y[(i * width) + j] - 16;
+            u = src_u[(sub_i_uv * uv_width) + sub_j_uv] - 128;
+            v = src_v[(sub_i_uv * uv_width) + sub_j_uv] - 128;
+            r = (int)((1.1644 * (double)y) + (1.5960 * (double)v));
+            g = (int)((1.1644 * (double)y) - (0.3918 * (double)u) - (0.8130 * (double)v));
+            b = (int)((1.1644 * (double)y) + (2.0172 * (double)u));
+            clip_8_bit (r);
+            clip_8_bit (g);
+            clip_8_bit (b);
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+            rgb[(i * width + j) * 4 + 0] = b;
+            rgb[(i * width + j) * 4 + 1] = g;
+            rgb[(i * width + j) * 4 + 2] = r;
+            rgb[(i * width + j) * 4 + 3] = 0;
+#else
+            rgb[(i * width + j) * 4 + 3] = b;
+            rgb[(i * width + j) * 4 + 2] = g;
+            rgb[(i * width + j) * 4 + 1] = r;
+            rgb[(i * width + j) * 4 + 0] = 0;
+#endif
+        }
+    }
+    return rgb;
+}
+
+
 } // namespace Xine
 } // namespace Phonon
 
Index: phonon-xine/mediaobject.h
===================================================================
--- phonon-xine/mediaobject.h	(révision 682687)
+++ phonon-xine/mediaobject.h	(copie de travail)
@@ -128,6 +128,8 @@
             void chapterChanged(int);
             void availableAnglesChanged(int);
             void angleChanged(int);
+            
+            void screenShotReady(const QImage&);
 
         protected:
             VideoPath* videoPath() const { return m_videoPath; }