Public feed #600309

Mine

public text v1 · immutable
Raw Edit
·published 2007-07-02 19:17 UTC
rendered paste body
Index: videowidget.cpp
===================================================================
--- videowidget.cpp	(révision 682403)
+++ 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;
 }
 
+QImage& VideoWidget::getScreenShot()
+{
+    if (m_path && m_path->mediaObject()) {
+        XineStream &xs = m_path->mediaObject()->stream();
+        return xs.getScreenShot( m_videoRatio );
+    }
+}
+
 Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
 {
 	return m_aspectRatio;
Index: xinestream.h
===================================================================
--- xinestream.h	(révision 682403)
+++ 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);
+        QImage& getScreenShot(double videoRatio);
 
         void addAudioPostList(const AudioPostList &);
         void removeAudioPostList(const AudioPostList &);
@@ -165,6 +167,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,8 +184,10 @@
         QMutex m_portMutex;
         mutable QMutex m_mutex;
         mutable QMutex m_streamInfoMutex;
+        mutable QMutex m_screenshotMutex;
         mutable QMutex m_updateTimeMutex;
         mutable QWaitCondition m_waitingForStreamInfo;
+        mutable QWaitCondition m_waitingForScreenshot;
         QWaitCondition m_waitingForEventLoop;
         QWaitCondition m_waitingForClose;
         QWaitCondition m_waitingForRewire;
@@ -215,6 +222,8 @@
         bool m_ticking : 1;
         bool m_closing : 1;
         bool m_eventLoopReady : 1;
+        QImage m_screenshotImage;
+        double m_screenshotRatio;
 };
 
 } // namespace Xine
Index: xinestream.cpp
===================================================================
--- xinestream.cpp	(révision 682403)
+++ 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,21 @@
 }
 
 // called from main thread
+QImage& XineStream::getScreenShot(double videoRatio)
+{
+    QMutexLocker locker(&m_screenshotMutex);
+    m_screenshotImage = QImage();
+    m_screenshotRatio = videoRatio,
+    QCoreApplication::postEvent(const_cast<XineStream*>(this), new QEvent(static_cast<QEvent::Type>(GetScreenShot)));
+    if (!m_waitingForScreenshot.wait(&m_screenshotMutex, 500)) {
+            kDebug(610) << k_funcinfo << "waitcondition timed out" << endl;
+    }
+
+    return m_screenshotImage;
+}
+
+
+// called from main thread
 bool XineStream::isSeekable() const
 {
     if (!m_streamInfoReady) {
@@ -335,6 +351,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, 32, 0, 0, QImage::IgnoreEndian);
+            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.smoothScale(width, height);
+            delete [] rgb32BitData;
+        }
+        delete [] yuv;
+    }
+out:
+    m_waitingForScreenshot.wakeAll();
+}
+
+// xine thread
 void XineStream::getStreamInfo()
 {
     Q_ASSERT(QThread::currentThread() == this);
@@ -1618,6 +1692,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: videowidget.h
===================================================================
--- videowidget.h	(révision 682403)
+++ videowidget.h	(copie de travail)
@@ -65,6 +65,8 @@
 
             bool isValid() const { return videoPort() != 0; }
             void setVideoEmpty(bool);
+            
+            QImage& getScreenShot();
 
 		signals:
 			void videoPortChanged();
@@ -96,6 +98,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