1/* 2 * Copyright 2015 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "SurfaceUtils" 19#include <utils/Log.h> 20 21#include <media/stagefright/SurfaceUtils.h> 22 23#include <gui/Surface.h> 24 25namespace android { 26 27status_t setNativeWindowSizeFormatAndUsage( 28 ANativeWindow *nativeWindow /* nonnull */, 29 int width, int height, int format, int rotation, int usage, bool reconnect) { 30 status_t err = NO_ERROR; 31 32 // In some cases we need to reconnect so that we can dequeue all buffers 33 if (reconnect) { 34 err = nativeWindowDisconnect(nativeWindow, "setNativeWindowSizeFormatAndUsage"); 35 if (err != NO_ERROR) { 36 ALOGE("nativeWindowDisconnect failed: %s (%d)", strerror(-err), -err); 37 return err; 38 } 39 40 err = nativeWindowConnect(nativeWindow, "setNativeWindowSizeFormatAndUsage"); 41 if (err != NO_ERROR) { 42 ALOGE("nativeWindowConnect failed: %s (%d)", strerror(-err), -err); 43 return err; 44 } 45 } 46 47 err = native_window_set_buffers_dimensions(nativeWindow, width, height); 48 if (err != NO_ERROR) { 49 ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err); 50 return err; 51 } 52 53 err = native_window_set_buffers_format(nativeWindow, format); 54 if (err != NO_ERROR) { 55 ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err); 56 return err; 57 } 58 59 int transform = 0; 60 if ((rotation % 90) == 0) { 61 switch ((rotation / 90) & 3) { 62 case 1: transform = HAL_TRANSFORM_ROT_90; break; 63 case 2: transform = HAL_TRANSFORM_ROT_180; break; 64 case 3: transform = HAL_TRANSFORM_ROT_270; break; 65 default: transform = 0; break; 66 } 67 } 68 69 err = native_window_set_buffers_transform(nativeWindow, transform); 70 if (err != NO_ERROR) { 71 ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err); 72 return err; 73 } 74 75 int consumerUsage = 0; 76 err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage); 77 if (err != NO_ERROR) { 78 ALOGW("failed to get consumer usage bits. ignoring"); 79 err = NO_ERROR; 80 } 81 82 // Make sure to check whether either Stagefright or the video decoder 83 // requested protected buffers. 84 if (usage & GRALLOC_USAGE_PROTECTED) { 85 // Check if the ANativeWindow sends images directly to SurfaceFlinger. 86 int queuesToNativeWindow = 0; 87 err = nativeWindow->query( 88 nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow); 89 if (err != NO_ERROR) { 90 ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err); 91 return err; 92 } 93 94 // Check if the consumer end of the ANativeWindow can handle protected content. 95 int isConsumerProtected = 0; 96 err = nativeWindow->query( 97 nativeWindow, NATIVE_WINDOW_CONSUMER_IS_PROTECTED, &isConsumerProtected); 98 if (err != NO_ERROR) { 99 ALOGE("error query native window: %s (%d)", strerror(-err), -err); 100 return err; 101 } 102 103 // Deny queuing into native window if neither condition is satisfied. 104 if (queuesToNativeWindow != 1 && isConsumerProtected != 1) { 105 ALOGE("native window cannot handle protected buffers: the consumer should either be " 106 "a hardware composer or support hardware protection"); 107 return PERMISSION_DENIED; 108 } 109 } 110 111 int finalUsage = usage | consumerUsage; 112 ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage); 113 err = native_window_set_usage(nativeWindow, finalUsage); 114 if (err != NO_ERROR) { 115 ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); 116 return err; 117 } 118 119 err = native_window_set_scaling_mode( 120 nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); 121 if (err != NO_ERROR) { 122 ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err); 123 return err; 124 } 125 126 ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x", 127 nativeWindow, width, height, format, rotation, finalUsage); 128 return NO_ERROR; 129} 130 131status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) { 132 status_t err = NO_ERROR; 133 ANativeWindowBuffer* anb = NULL; 134 int numBufs = 0; 135 int minUndequeuedBufs = 0; 136 137 // We need to reconnect to the ANativeWindow as a CPU client to ensure that 138 // no frames get dropped by SurfaceFlinger assuming that these are video 139 // frames. 140 err = nativeWindowDisconnect(nativeWindow, "pushBlankBuffersToNativeWindow"); 141 if (err != NO_ERROR) { 142 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err); 143 return err; 144 } 145 146 err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU); 147 if (err != NO_ERROR) { 148 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 149 (void)nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err)"); 150 return err; 151 } 152 153 err = setNativeWindowSizeFormatAndUsage( 154 nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, 155 false /* reconnect */); 156 if (err != NO_ERROR) { 157 goto error; 158 } 159 160 static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true); 161 162 err = nativeWindow->query(nativeWindow, 163 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); 164 if (err != NO_ERROR) { 165 ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query " 166 "failed: %s (%d)", strerror(-err), -err); 167 goto error; 168 } 169 170 numBufs = minUndequeuedBufs + 1; 171 err = native_window_set_buffer_count(nativeWindow, numBufs); 172 if (err != NO_ERROR) { 173 ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err); 174 goto error; 175 } 176 177 // We push numBufs + 1 buffers to ensure that we've drawn into the same 178 // buffer twice. This should guarantee that the buffer has been displayed 179 // on the screen and then been replaced, so an previous video frames are 180 // guaranteed NOT to be currently displayed. 181 for (int i = 0; i < numBufs + 1; i++) { 182 err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb); 183 if (err != NO_ERROR) { 184 ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", 185 strerror(-err), -err); 186 break; 187 } 188 189 sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); 190 191 // Fill the buffer with the a 1x1 checkerboard pattern ;) 192 uint32_t *img = NULL; 193 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 194 if (err != NO_ERROR) { 195 ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err); 196 break; 197 } 198 199 *img = 0; 200 201 err = buf->unlock(); 202 if (err != NO_ERROR) { 203 ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err); 204 break; 205 } 206 207 err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1); 208 if (err != NO_ERROR) { 209 ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err); 210 break; 211 } 212 213 anb = NULL; 214 } 215 216error: 217 218 if (anb != NULL) { 219 nativeWindow->cancelBuffer(nativeWindow, anb, -1); 220 anb = NULL; 221 } 222 223 // Clean up after success or error. 224 status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU); 225 if (err2 != NO_ERROR) { 226 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2); 227 if (err == NO_ERROR) { 228 err = err2; 229 } 230 } 231 232 err2 = nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err2)"); 233 if (err2 != NO_ERROR) { 234 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 235 if (err == NO_ERROR) { 236 err = err2; 237 } 238 } 239 240 return err; 241} 242 243status_t nativeWindowConnect(ANativeWindow *surface, const char *reason) { 244 ALOGD("connecting to surface %p, reason %s", surface, reason); 245 246 status_t err = native_window_api_connect(surface, NATIVE_WINDOW_API_MEDIA); 247 ALOGE_IF(err != OK, "Failed to connect to surface %p, err %d", surface, err); 248 249 return err; 250} 251 252status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason) { 253 ALOGD("disconnecting from surface %p, reason %s", surface, reason); 254 255 status_t err = native_window_api_disconnect(surface, NATIVE_WINDOW_API_MEDIA); 256 ALOGE_IF(err != OK, "Failed to disconnect from surface %p, err %d", surface, err); 257 258 return err; 259} 260} // namespace android 261 262