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/hardware/VideoAPI.h> 22 #include <media/stagefright/SurfaceUtils.h> 23 #include <gui/Surface.h> 24 25 namespace android { 26 27 status_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 131 void setNativeWindowHdrMetadata(ANativeWindow *nativeWindow, HDRStaticInfo *info) { 132 struct android_smpte2086_metadata smpte2086_meta = { 133 .displayPrimaryRed = { 134 info->sType1.mR.x * 0.00002f, 135 info->sType1.mR.y * 0.00002f 136 }, 137 .displayPrimaryGreen = { 138 info->sType1.mG.x * 0.00002f, 139 info->sType1.mG.y * 0.00002f 140 }, 141 .displayPrimaryBlue = { 142 info->sType1.mB.x * 0.00002f, 143 info->sType1.mB.y * 0.00002f 144 }, 145 .whitePoint = { 146 info->sType1.mW.x * 0.00002f, 147 info->sType1.mW.y * 0.00002f 148 }, 149 .maxLuminance = (float) info->sType1.mMaxDisplayLuminance, 150 .minLuminance = info->sType1.mMinDisplayLuminance * 0.0001f 151 }; 152 153 int err = native_window_set_buffers_smpte2086_metadata(nativeWindow, &smpte2086_meta); 154 ALOGW_IF(err != 0, "failed to set smpte2086 metadata on surface (%d)", err); 155 156 struct android_cta861_3_metadata cta861_meta = { 157 .maxContentLightLevel = (float) info->sType1.mMaxContentLightLevel, 158 .maxFrameAverageLightLevel = (float) info->sType1.mMaxFrameAverageLightLevel 159 }; 160 161 err = native_window_set_buffers_cta861_3_metadata(nativeWindow, &cta861_meta); 162 ALOGW_IF(err != 0, "failed to set cta861_3 metadata on surface (%d)", err); 163 } 164 165 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) { 166 status_t err = NO_ERROR; 167 ANativeWindowBuffer* anb = NULL; 168 int numBufs = 0; 169 int minUndequeuedBufs = 0; 170 171 // We need to reconnect to the ANativeWindow as a CPU client to ensure that 172 // no frames get dropped by SurfaceFlinger assuming that these are video 173 // frames. 174 err = nativeWindowDisconnect(nativeWindow, "pushBlankBuffersToNativeWindow"); 175 if (err != NO_ERROR) { 176 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err); 177 return err; 178 } 179 180 err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU); 181 if (err != NO_ERROR) { 182 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 183 (void)nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err)"); 184 return err; 185 } 186 187 err = setNativeWindowSizeFormatAndUsage( 188 nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, 189 false /* reconnect */); 190 if (err != NO_ERROR) { 191 goto error; 192 } 193 194 static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true); 195 196 err = nativeWindow->query(nativeWindow, 197 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); 198 if (err != NO_ERROR) { 199 ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query " 200 "failed: %s (%d)", strerror(-err), -err); 201 goto error; 202 } 203 204 numBufs = minUndequeuedBufs + 1; 205 err = native_window_set_buffer_count(nativeWindow, numBufs); 206 if (err != NO_ERROR) { 207 ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err); 208 goto error; 209 } 210 211 // We push numBufs + 1 buffers to ensure that we've drawn into the same 212 // buffer twice. This should guarantee that the buffer has been displayed 213 // on the screen and then been replaced, so an previous video frames are 214 // guaranteed NOT to be currently displayed. 215 for (int i = 0; i < numBufs + 1; i++) { 216 err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb); 217 if (err != NO_ERROR) { 218 ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", 219 strerror(-err), -err); 220 break; 221 } 222 223 sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); 224 225 // Fill the buffer with the a 1x1 checkerboard pattern ;) 226 uint32_t *img = NULL; 227 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 228 if (err != NO_ERROR) { 229 ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err); 230 break; 231 } 232 233 *img = 0; 234 235 err = buf->unlock(); 236 if (err != NO_ERROR) { 237 ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err); 238 break; 239 } 240 241 err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1); 242 if (err != NO_ERROR) { 243 ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err); 244 break; 245 } 246 247 anb = NULL; 248 } 249 250 error: 251 252 if (anb != NULL) { 253 nativeWindow->cancelBuffer(nativeWindow, anb, -1); 254 anb = NULL; 255 } 256 257 // Clean up after success or error. 258 status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU); 259 if (err2 != NO_ERROR) { 260 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2); 261 if (err == NO_ERROR) { 262 err = err2; 263 } 264 } 265 266 err2 = nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err2)"); 267 if (err2 != NO_ERROR) { 268 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 269 if (err == NO_ERROR) { 270 err = err2; 271 } 272 } 273 274 return err; 275 } 276 277 status_t nativeWindowConnect(ANativeWindow *surface, const char *reason) { 278 ALOGD("connecting to surface %p, reason %s", surface, reason); 279 280 status_t err = native_window_api_connect(surface, NATIVE_WINDOW_API_MEDIA); 281 ALOGE_IF(err != OK, "Failed to connect to surface %p, err %d", surface, err); 282 283 return err; 284 } 285 286 status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason) { 287 ALOGD("disconnecting from surface %p, reason %s", surface, reason); 288 289 status_t err = native_window_api_disconnect(surface, NATIVE_WINDOW_API_MEDIA); 290 ALOGE_IF(err != OK, "Failed to disconnect from surface %p, err %d", surface, err); 291 292 return err; 293 } 294 } // namespace android 295 296