source: trunk/src/3rdparty/phonon/qt7/videoframe.mm

Last change on this file was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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