2 * Copyright (C) 2011 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "MediaTexture.h"
18 #include "TilesManager.h"
20 #include "MediaListener.h"
22 #if USE(ACCELERATED_COMPOSITING)
24 #include <android/native_window.h>
25 #include <gui/SurfaceTexture.h>
26 #include <gui/SurfaceTextureClient.h>
27 #include <wtf/CurrentTime.h>
28 #include <JNIUtility.h>
29 #include "WebCoreJni.h"
36 #include <cutils/log.h>
37 #include <wtf/text/CString.h>
40 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "MediaTexture", __VA_ARGS__)
51 MediaTexture::MediaTexture(jobject webViewRef) : android::LightRefBase<MediaTexture>()
54 JNIEnv* env = JSC::Bindings::getJNIEnv();
55 m_weakWebViewRef = env->NewWeakGlobalRef(webViewRef);
61 m_dimensions.setEmpty();
62 m_newWindowRequest = false;
63 m_newWindowReady = false;
64 m_mediaListener = new MediaListener(m_weakWebViewRef);
67 MediaTexture::~MediaTexture()
69 releaseNativeWindow();
71 glDeleteTextures(1, &m_textureId);
72 if (m_weakWebViewRef) {
73 JNIEnv* env = JSC::Bindings::getJNIEnv();
74 env->DeleteWeakGlobalRef(m_weakWebViewRef);
78 void MediaTexture::initNativeWindowIfNeeded()
81 android::Mutex::Autolock lock(m_mediaLock);
83 if(!m_newWindowRequest)
86 // reuse an existing texture if possible
88 glGenTextures(1, &m_textureId);
90 m_surfaceTexture = new android::SurfaceTexture(m_textureId);
91 m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture);
94 m_mediaListener->resetFrameAvailable();
95 m_surfaceTexture->setFrameAvailableListener(m_mediaListener);
97 m_newWindowRequest = false;
98 m_newWindowReady = true;
100 m_newMediaRequestCond.signal();
103 void MediaTexture::drawContent(const TransformationMatrix& matrix)
105 android::Mutex::Autolock lock(m_mediaLock);
107 if(!m_surfaceTexture.get() || m_dimensions.isEmpty()
108 || !m_mediaListener->isFrameAvailable())
111 m_surfaceTexture->updateTexImage();
113 sp<GraphicBuffer> buf = m_surfaceTexture->getCurrentBuffer();
115 PixelFormat f = buf->getPixelFormat();
116 // only attempt to use alpha blending if alpha channel exists
117 bool forceAlphaBlending = !(
118 PIXEL_FORMAT_RGBX_8888 == f ||
119 PIXEL_FORMAT_RGB_888 == f ||
120 PIXEL_FORMAT_RGB_565 == f ||
121 PIXEL_FORMAT_RGB_332 == f);
123 TilesManager::instance()->shader()->drawLayerQuad(matrix, m_dimensions,
126 GL_TEXTURE_EXTERNAL_OES);
129 void MediaTexture::drawVideo(const TransformationMatrix& matrix, const SkRect& parentBounds)
131 android::Mutex::Autolock lock(m_mediaLock);
133 if(!m_surfaceTexture.get() || m_dimensions.isEmpty()
134 || !m_mediaListener->isFrameAvailable())
137 m_surfaceTexture->updateTexImage();
139 float surfaceMatrix[16];
140 m_surfaceTexture->getTransformMatrix(surfaceMatrix);
142 SkRect dimensions = m_dimensions;
143 dimensions.offset(parentBounds.fLeft, parentBounds.fTop);
146 if (!parentBounds.contains(dimensions)) {
147 XLOG("The video exceeds is parent's bounds.");
151 TilesManager::instance()->shader()->drawVideoLayerQuad(matrix, surfaceMatrix,
152 dimensions, m_textureId);
155 ANativeWindow* MediaTexture::requestNewWindow()
157 android::Mutex::Autolock lock(m_mediaLock);
159 // the window was not ready before the timeout so return it this time
160 if (m_newWindowReady) {
161 m_newWindowReady = false;
162 return m_surfaceTextureClient.get();
164 // we only allow for one texture, so if one already exists return null
165 else if (m_surfaceTextureClient.get()) {
169 m_newWindowRequest = true;
171 // post an inval message to the UI thread to fulfill the request
172 if (m_weakWebViewRef) {
173 JNIEnv* env = JSC::Bindings::getJNIEnv();
174 jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
175 if (localWebViewRef) {
176 jclass wvClass = env->GetObjectClass(localWebViewRef);
177 jmethodID postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V");
178 env->CallVoidMethod(localWebViewRef, postInvalMethod);
179 env->DeleteLocalRef(wvClass);
180 env->DeleteLocalRef(localWebViewRef);
185 //block until the request can be fulfilled or we time out
186 bool timedOut = false;
187 while (m_newWindowRequest && !timedOut) {
188 int ret = m_newMediaRequestCond.waitRelative(m_mediaLock, 500000000); // .5 sec
189 timedOut = ret == TIMED_OUT;
192 if (m_surfaceTextureClient.get())
193 m_newWindowReady = false;
195 return m_surfaceTextureClient.get();
198 ANativeWindow* MediaTexture::getNativeWindow()
200 android::Mutex::Autolock lock(m_mediaLock);
201 return m_surfaceTextureClient.get();
204 void MediaTexture::releaseNativeWindow()
206 android::Mutex::Autolock lock(m_mediaLock);
207 m_dimensions.setEmpty();
209 if (m_surfaceTexture.get())
210 m_surfaceTexture->setFrameAvailableListener(0);
212 // clear the strong pointer references
213 m_surfaceTextureClient.clear();
214 m_surfaceTexture.clear();
217 void MediaTexture::setDimensions(const SkRect& dimensions)
219 android::Mutex::Autolock lock(m_mediaLock);
220 m_dimensions = dimensions;
223 } // namespace WebCore
225 #endif // USE(ACCELERATED_COMPOSITING)