src/3rdparty/phonon/qt7/videoframe.mm
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*  This file is part of the KDE project.
       
     2 
       
     3     Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 
       
     5     This library is free software: you can redistribute it and/or modify
       
     6     it under the terms of the GNU Lesser General Public License as published by
       
     7     the Free Software Foundation, either version 2.1 or 3 of the License.
       
     8 
       
     9     This library is distributed in the hope that it will be useful,
       
    10     but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12     GNU Lesser General Public License for more details.
       
    13 
       
    14     You should have received a copy of the GNU Lesser General Public License
       
    15     along with this library.  If not, see <http://www.gnu.org/licenses/>.
       
    16 */
       
    17 
       
    18 #include "videoframe.h"
       
    19 #include "quicktimevideoplayer.h"
       
    20 #import <QuartzCore/CIFilter.h>
       
    21 #import <QuartzCore/CIContext.h>
       
    22 
       
    23 //#define CACHE_CV_TEXTURE
       
    24 
       
    25 QT_BEGIN_NAMESPACE
       
    26 
       
    27 namespace Phonon
       
    28 {
       
    29 namespace QT7
       
    30 {
       
    31 
       
    32     VideoFrame::VideoFrame()
       
    33     {
       
    34         initMembers();
       
    35     }
       
    36 
       
    37     VideoFrame::VideoFrame(QuickTimeVideoPlayer *videoPlayer)
       
    38     {
       
    39         initMembers();
       
    40         m_videoPlayer = videoPlayer;
       
    41     }
       
    42 
       
    43     VideoFrame::VideoFrame(const VideoFrame& frame)
       
    44     {
       
    45         copyMembers(frame);
       
    46         retain();
       
    47     }
       
    48 
       
    49     void VideoFrame::operator=(const VideoFrame& frame)
       
    50     {
       
    51         if (this == &frame)
       
    52             return;
       
    53 
       
    54         release();
       
    55         copyMembers(frame);
       
    56         retain();
       
    57     }
       
    58 
       
    59     void VideoFrame::initMembers()
       
    60     {
       
    61         m_cachedCVTextureRef = 0;
       
    62 		m_cachedCIImage = 0;
       
    63         m_cachedNSBitmap = 0;
       
    64         m_videoPlayer = 0;
       
    65         m_brightness = 0;
       
    66         m_contrast = 0;
       
    67         m_hue = 0;
       
    68         m_saturation = 0;
       
    69         m_opacity = 1;
       
    70         m_backgroundFrame = 0;
       
    71     }
       
    72 
       
    73     void VideoFrame::copyMembers(const VideoFrame& frame)
       
    74     {
       
    75 #ifdef CACHE_CV_TEXTURE
       
    76         m_cachedCVTextureRef = frame.m_cachedCVTextureRef;
       
    77 #endif
       
    78 		m_cachedCIImage = frame.m_cachedCIImage;
       
    79 		m_cachedQImage = frame.m_cachedQImage;
       
    80         m_cachedNSBitmap = frame.m_cachedNSBitmap;
       
    81         m_videoPlayer = frame.m_videoPlayer;
       
    82         m_brightness = frame.m_brightness;
       
    83         m_contrast = frame.m_contrast;
       
    84         m_hue = frame.m_hue;
       
    85         m_saturation = frame.m_saturation;
       
    86         m_opacity = frame.m_opacity;
       
    87         m_backgroundFrame = frame.m_backgroundFrame;
       
    88     }
       
    89 
       
    90     VideoFrame::~VideoFrame()
       
    91     {
       
    92         release();
       
    93     }
       
    94 
       
    95     QuickTimeVideoPlayer *VideoFrame::videoPlayer()
       
    96     {
       
    97         return m_videoPlayer;
       
    98     }
       
    99 
       
   100     void VideoFrame::setBackgroundFrame(const VideoFrame &frame)
       
   101     {
       
   102         m_backgroundFrame = new VideoFrame(frame);
       
   103     }
       
   104 
       
   105     QRect VideoFrame::frameRect() const
       
   106     {
       
   107         return m_videoPlayer->videoRect();
       
   108     }
       
   109 
       
   110     CVOpenGLTextureRef VideoFrame::cachedCVTexture() const
       
   111     {
       
   112 #ifdef CACHE_CV_TEXTURE
       
   113         if (!m_cachedCVTextureRef && m_videoPlayer){
       
   114             m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation);
       
   115             (const_cast<VideoFrame *>(this))->m_cachedCVTextureRef = m_videoPlayer->currentFrameAsCVTexture();
       
   116             CVOpenGLTextureRetain((const_cast<VideoFrame *>(this))->m_cachedCVTextureRef);
       
   117         }
       
   118         return m_cachedCVTextureRef;
       
   119 #else
       
   120         if (m_videoPlayer){
       
   121             m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation);
       
   122             return m_videoPlayer->currentFrameAsCVTexture();
       
   123         }
       
   124         return 0;
       
   125 #endif
       
   126     }
       
   127 
       
   128     void *VideoFrame::cachedCIImage() const
       
   129     {
       
   130         if (!m_cachedCIImage && m_videoPlayer){
       
   131             m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation);
       
   132             (const_cast<VideoFrame *>(this))->m_cachedCIImage = m_videoPlayer->currentFrameAsCIImage();
       
   133         }
       
   134         return m_cachedCIImage;
       
   135     }
       
   136 
       
   137     GLuint VideoFrame::glTextureRef() const
       
   138     {
       
   139         return CVOpenGLTextureGetName(cachedCVTexture());
       
   140     }
       
   141 
       
   142     void VideoFrame::setColors(qreal brightness, qreal contrast, qreal hue, qreal saturation)
       
   143     {
       
   144         if (m_backgroundFrame)
       
   145             m_backgroundFrame->setColors(brightness, contrast, hue, saturation);
       
   146         if (m_brightness == brightness
       
   147             && m_contrast == contrast
       
   148             && m_hue == hue
       
   149             && m_saturation == saturation)
       
   150             return;
       
   151 
       
   152         m_brightness = brightness;
       
   153         m_contrast = contrast;
       
   154         m_hue = hue;
       
   155         m_saturation = saturation;
       
   156 
       
   157         invalidateImage();
       
   158     }
       
   159 
       
   160 	CGRect VideoFrame::QRectToCGRect(const QRect & qrect)
       
   161 	{
       
   162         CGRect cgrect;
       
   163         cgrect.origin.x = qrect.x();
       
   164         cgrect.origin.y = qrect.y() + qrect.height();
       
   165         cgrect.size.width = qrect.width();
       
   166         cgrect.size.height = -qrect.height();
       
   167 		return cgrect;
       
   168 	}
       
   169 
       
   170 	bool VideoFrame::hasColorAdjustments()
       
   171 	{
       
   172 		return (m_brightness || m_contrast || m_saturation || m_hue);
       
   173 	}
       
   174 
       
   175     void VideoFrame::setBaseOpacity(qreal opacity)
       
   176     {
       
   177         m_opacity = opacity;
       
   178     }
       
   179 
       
   180     void VideoFrame::drawQImage(QPainter *p, const QRect &rect) const
       
   181 	{
       
   182         if (!m_videoPlayer)
       
   183             return;
       
   184 #ifdef QUICKTIME_C_API_AVAILABLE
       
   185         if (m_cachedQImage.isNull()){
       
   186             m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation);
       
   187             (const_cast<VideoFrame *>(this))->m_cachedQImage = m_videoPlayer->currentFrameAsQImage();
       
   188         }
       
   189 #else
       
   190         // Since cocoa-64 doesn't give us OpenGL textures directly, the process of converting
       
   191         // CIImges into QImages takes time. We could still call m_videoPlayer->currentFrameAsQImage(),
       
   192         // but because of bitmap memory management issues, and the fact that we need to swap red and
       
   193         // blue, we can optimize the process a bit here since we are going to draw immidiatly:
       
   194         CIImage *img = (CIImage*)cachedCIImage();
       
   195         if (!img)
       
   196             return;
       
   197 
       
   198         if (!m_cachedNSBitmap){
       
   199             (const_cast<VideoFrame *>(this))->m_cachedNSBitmap =
       
   200                 [[NSBitmapImageRep alloc] initWithCIImage:img];
       
   201             CGRect bounds = [img extent];
       
   202             int w = bounds.size.width;
       
   203             int h = bounds.size.height;
       
   204             (const_cast<VideoFrame *>(this))->m_cachedQImage =
       
   205                 QImage([m_cachedNSBitmap bitmapData], w, h, QImage::Format_ARGB32);
       
   206 			// Swap red and blue (same as QImage::rgbSwapped, but without copy)
       
   207             for (int i=0; i<h; ++i) {
       
   208                 uint *p = (uint*) m_cachedQImage.scanLine(i);
       
   209                 uint *end = p + w;
       
   210                 while (p < end) {
       
   211                     *p = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
       
   212                     p++;
       
   213                 }
       
   214             }
       
   215         }
       
   216 #endif
       
   217         p->drawImage(rect, m_cachedQImage);
       
   218 	}
       
   219 
       
   220     void VideoFrame::drawCIImage(const QRect &rect, float opacity) const
       
   221 	{
       
   222 		drawCIImage(QRectToCGRect(rect), opacity);
       
   223 	}
       
   224 
       
   225     void VideoFrame::drawCIImage(const CGRect &rect, float opacity) const
       
   226 	{
       
   227 		Q_UNUSED(opacity);
       
   228 		CIImage *img = (CIImage *) cachedCIImage();
       
   229 		if (!img)
       
   230 			return;
       
   231 
       
   232 	    CIContext* ciContext = [[NSGraphicsContext currentContext] CIContext];
       
   233 	    [ciContext drawImage:img inRect:rect fromRect:[img extent]];
       
   234 	}
       
   235 
       
   236     void VideoFrame::drawCVTexture(const QRect &rect, float opacity) const
       
   237     {
       
   238         if (!m_videoPlayer)
       
   239             return;
       
   240         if (m_backgroundFrame)
       
   241             m_backgroundFrame->drawCVTexture(rect, opacity);
       
   242 
       
   243         CVOpenGLTextureRef texRef = cachedCVTexture();
       
   244         if (!texRef)
       
   245             return;
       
   246 
       
   247         glPushMatrix();
       
   248             glDisable(GL_CULL_FACE);
       
   249             GLenum target = CVOpenGLTextureGetTarget(texRef);
       
   250             glEnable(target);
       
   251 
       
   252             opacity *= m_opacity;
       
   253             if (opacity < 1){
       
   254                 glEnable(GL_BLEND);
       
   255                 glColor4f(1, 1, 1, opacity);
       
   256                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
       
   257             } else {
       
   258                 glColor3f(1, 1, 1);
       
   259                 glDisable(GL_BLEND);
       
   260             }
       
   261 
       
   262             glBindTexture(target, CVOpenGLTextureGetName(texRef));
       
   263             glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
       
   264             glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       
   265             GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2];
       
   266             CVOpenGLTextureGetCleanTexCoords(texRef, lowerLeft, lowerRight, upperRight, upperLeft);
       
   267 
       
   268             glBegin(GL_QUADS);
       
   269                 glTexCoord2f(lowerLeft[0], lowerLeft[1]);
       
   270                 glVertex2i(rect.topLeft().x(), rect.topLeft().y());
       
   271                 glTexCoord2f(lowerRight[0], lowerRight[1]);
       
   272                 glVertex2i(rect.topRight().x() + 1, rect.topRight().y());
       
   273                 glTexCoord2f(upperRight[0], upperRight[1]);
       
   274                 glVertex2i(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1);
       
   275                 glTexCoord2f(upperLeft[0], upperLeft[1]);
       
   276                 glVertex2i(rect.bottomLeft().x(), rect.bottomLeft().y() + 1);
       
   277             glEnd();
       
   278         glPopMatrix();
       
   279     }
       
   280 
       
   281     void VideoFrame::drawGLTexture(const QRect &rect, float opacity) const
       
   282     {
       
   283         if (!m_videoPlayer)
       
   284             return;
       
   285         if (m_backgroundFrame)
       
   286             m_backgroundFrame->drawGLTexture(rect, opacity);
       
   287 
       
   288         GLuint texture = m_videoPlayer->currentFrameAsGLTexture();
       
   289         if (!texture)
       
   290             return;
       
   291 
       
   292         glPushMatrix();
       
   293             glDisable(GL_CULL_FACE);
       
   294             glEnable(GL_TEXTURE_RECTANGLE_EXT);
       
   295 
       
   296             opacity *= m_opacity;
       
   297             if (opacity < 1){
       
   298                 glEnable(GL_BLEND);
       
   299                 glColor4f(1, 1, 1, opacity);
       
   300                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
       
   301             } else {
       
   302                 glColor3f(1, 1, 1);
       
   303                 glDisable(GL_BLEND);
       
   304             }
       
   305 
       
   306             glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texture);
       
   307             glTexParameterf(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
       
   308             glTexParameterf(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       
   309 
       
   310             QRect videoRect = m_videoPlayer->videoRect();
       
   311             GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2];
       
   312             lowerLeft[0] = 0;
       
   313             lowerLeft[1] = videoRect.height();
       
   314             lowerRight[0] = videoRect.width();
       
   315             lowerRight[1] = videoRect.height();
       
   316             upperRight[0] = videoRect.width();
       
   317             upperRight[1] = 0;
       
   318             upperLeft[0] = 0;
       
   319             upperLeft[1] = 0;
       
   320 
       
   321             glBegin(GL_QUADS);
       
   322                 glTexCoord2f(lowerLeft[0], lowerLeft[1]);
       
   323                 glVertex2i(rect.topLeft().x(), rect.topLeft().y());
       
   324                 glTexCoord2f(lowerRight[0], lowerRight[1]);
       
   325                 glVertex2i(rect.topRight().x() + 1, rect.topRight().y());
       
   326                 glTexCoord2f(upperRight[0], upperRight[1]);
       
   327                 glVertex2i(rect.bottomRight().x() + 1, rect.bottomRight().y() + 1);
       
   328                 glTexCoord2f(upperLeft[0], upperLeft[1]);
       
   329                 glVertex2i(rect.bottomLeft().x(), rect.bottomLeft().y() + 1);
       
   330             glEnd();
       
   331         glPopMatrix();
       
   332 
       
   333 
       
   334         // FOR NOW. FREE THE TEXTURE:
       
   335         glDeleteTextures(1, &texture);
       
   336     }
       
   337 
       
   338     bool VideoFrame::isEmpty()
       
   339     {
       
   340         return (m_videoPlayer == 0);
       
   341     }
       
   342 
       
   343     void VideoFrame::invalidateImage() const
       
   344     {
       
   345 #ifdef CACHE_CV_TEXTURE
       
   346         if (m_cachedCVTextureRef){
       
   347             CVOpenGLTextureRelease(m_cachedCVTextureRef);
       
   348             (const_cast<VideoFrame *>(this))->m_cachedCVTextureRef = 0;
       
   349         }
       
   350 #endif
       
   351         if (m_cachedCIImage){
       
   352 			[(CIImage *) m_cachedCIImage release];
       
   353             (const_cast<VideoFrame *>(this))->m_cachedCIImage = 0;
       
   354         }
       
   355         if (m_cachedNSBitmap){
       
   356             [m_cachedNSBitmap release];
       
   357             (const_cast<VideoFrame *>(this))->m_cachedNSBitmap = 0;
       
   358         }
       
   359         (const_cast<VideoFrame *>(this))-> m_cachedQImage = QImage();
       
   360     }
       
   361 
       
   362     void VideoFrame::retain() const
       
   363     {
       
   364 #ifdef CACHE_CV_TEXTURE
       
   365         if (m_cachedCVTextureRef)
       
   366             CVOpenGLTextureRetain(m_cachedCVTextureRef);
       
   367 #endif
       
   368 		if (m_cachedCIImage)
       
   369 			[(CIImage *) m_cachedCIImage retain];
       
   370         if (m_backgroundFrame)
       
   371             m_backgroundFrame->retain();
       
   372         if (m_cachedNSBitmap)
       
   373             [m_cachedNSBitmap retain];
       
   374     }
       
   375 
       
   376     void VideoFrame::release() const
       
   377     {
       
   378 #ifdef CACHE_CV_TEXTURE
       
   379         if (m_cachedCVTextureRef){
       
   380             CVOpenGLTextureRelease(m_cachedCVTextureRef);
       
   381             (const_cast<VideoFrame *>(this))->m_cachedCVTextureRef = 0;
       
   382         }
       
   383 #endif
       
   384 		if (m_cachedCIImage)
       
   385 			[(CIImage *) m_cachedCIImage release];
       
   386         if (m_backgroundFrame)
       
   387             m_backgroundFrame->release();
       
   388         if (m_cachedNSBitmap)
       
   389             [m_cachedNSBitmap release];
       
   390 
       
   391         (const_cast<VideoFrame *>(this))->m_backgroundFrame = 0;
       
   392         (const_cast<VideoFrame *>(this))->m_cachedCIImage = 0;
       
   393         (const_cast<VideoFrame *>(this))->m_cachedNSBitmap = 0;
       
   394     }
       
   395 
       
   396 }} //namespace Phonon::QT7
       
   397 
       
   398 QT_END_NAMESPACE