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 <android/api-level.h> 22 #include <media/hardware/VideoAPI.h> 23 #include <media/stagefright/SurfaceUtils.h> 24 #include <gui/Surface.h> 25 26 extern "C" int android_get_application_target_sdk_version(); 27 28 namespace android { 29 30 status_t setNativeWindowSizeFormatAndUsage( 31 ANativeWindow *nativeWindow /* nonnull */, 32 int width, int height, int format, int rotation, int usage, bool reconnect) { 33 status_t err = NO_ERROR; 34 35 // In some cases we need to reconnect so that we can dequeue all buffers 36 if (reconnect) { 37 err = nativeWindowDisconnect(nativeWindow, "setNativeWindowSizeFormatAndUsage"); 38 if (err != NO_ERROR) { 39 ALOGE("nativeWindowDisconnect failed: %s (%d)", strerror(-err), -err); 40 return err; 41 } 42 43 err = nativeWindowConnect(nativeWindow, "setNativeWindowSizeFormatAndUsage"); 44 if (err != NO_ERROR) { 45 ALOGE("nativeWindowConnect failed: %s (%d)", strerror(-err), -err); 46 return err; 47 } 48 } 49 50 err = native_window_set_buffers_dimensions(nativeWindow, width, height); 51 if (err != NO_ERROR) { 52 ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err); 53 return err; 54 } 55 56 err = native_window_set_buffers_format(nativeWindow, format); 57 if (err != NO_ERROR) { 58 ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err); 59 return err; 60 } 61 62 int transform = 0; 63 if ((rotation % 90) == 0) { 64 switch ((rotation / 90) & 3) { 65 case 1: transform = HAL_TRANSFORM_ROT_90; break; 66 case 2: transform = HAL_TRANSFORM_ROT_180; break; 67 case 3: transform = HAL_TRANSFORM_ROT_270; break; 68 default: transform = 0; break; 69 } 70 } 71 72 err = native_window_set_buffers_transform(nativeWindow, transform); 73 if (err != NO_ERROR) { 74 ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err); 75 return err; 76 } 77 78 int consumerUsage = 0; 79 err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage); 80 if (err != NO_ERROR) { 81 ALOGW("failed to get consumer usage bits. ignoring"); 82 err = NO_ERROR; 83 } 84 85 // Make sure to check whether either Stagefright or the video decoder 86 // requested protected buffers. 87 if (usage & GRALLOC_USAGE_PROTECTED) { 88 // Check if the ANativeWindow sends images directly to SurfaceFlinger. 89 int queuesToNativeWindow = 0; 90 err = nativeWindow->query( 91 nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow); 92 if (err != NO_ERROR) { 93 ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err); 94 return err; 95 } 96 97 // Check if the consumer end of the ANativeWindow can handle protected content. 98 int isConsumerProtected = 0; 99 err = nativeWindow->query( 100 nativeWindow, NATIVE_WINDOW_CONSUMER_IS_PROTECTED, &isConsumerProtected); 101 if (err != NO_ERROR) { 102 ALOGE("error query native window: %s (%d)", strerror(-err), -err); 103 return err; 104 } 105 106 // Deny queuing into native window if neither condition is satisfied. 107 if (queuesToNativeWindow != 1 && isConsumerProtected != 1) { 108 ALOGE("native window cannot handle protected buffers: the consumer should either be " 109 "a hardware composer or support hardware protection"); 110 return PERMISSION_DENIED; 111 } 112 } 113 114 int finalUsage = usage | consumerUsage; 115 ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage); 116 err = native_window_set_usage(nativeWindow, finalUsage); 117 if (err != NO_ERROR) { 118 ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); 119 return err; 120 } 121 122 err = native_window_set_scaling_mode( 123 nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); 124 if (err != NO_ERROR) { 125 ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err); 126 return err; 127 } 128 129 ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x", 130 nativeWindow, width, height, format, rotation, finalUsage); 131 return NO_ERROR; 132 } 133 134 void setNativeWindowHdrMetadata(ANativeWindow *nativeWindow, HDRStaticInfo *info) { 135 struct android_smpte2086_metadata smpte2086_meta = { 136 .displayPrimaryRed = { 137 info->sType1.mR.x * 0.00002f, 138 info->sType1.mR.y * 0.00002f 139 }, 140 .displayPrimaryGreen = { 141 info->sType1.mG.x * 0.00002f, 142 info->sType1.mG.y * 0.00002f 143 }, 144 .displayPrimaryBlue = { 145 info->sType1.mB.x * 0.00002f, 146 info->sType1.mB.y * 0.00002f 147 }, 148 .whitePoint = { 149 info->sType1.mW.x * 0.00002f, 150 info->sType1.mW.y * 0.00002f 151 }, 152 .maxLuminance = (float) info->sType1.mMaxDisplayLuminance, 153 .minLuminance = info->sType1.mMinDisplayLuminance * 0.0001f 154 }; 155 156 int err = native_window_set_buffers_smpte2086_metadata(nativeWindow, &smpte2086_meta); 157 ALOGW_IF(err != 0, "failed to set smpte2086 metadata on surface (%d)", err); 158 159 struct android_cta861_3_metadata cta861_meta = { 160 .maxContentLightLevel = (float) info->sType1.mMaxContentLightLevel, 161 .maxFrameAverageLightLevel = (float) info->sType1.mMaxFrameAverageLightLevel 162 }; 163 164 err = native_window_set_buffers_cta861_3_metadata(nativeWindow, &cta861_meta); 165 ALOGW_IF(err != 0, "failed to set cta861_3 metadata on surface (%d)", err); 166 } 167 168 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) { 169 status_t err = NO_ERROR; 170 ANativeWindowBuffer* anb = NULL; 171 int numBufs = 0; 172 int minUndequeuedBufs = 0; 173 174 // We need to reconnect to the ANativeWindow as a CPU client to ensure that 175 // no frames get dropped by SurfaceFlinger assuming that these are video 176 // frames. 177 err = nativeWindowDisconnect(nativeWindow, "pushBlankBuffersToNativeWindow"); 178 if (err != NO_ERROR) { 179 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err); 180 return err; 181 } 182 183 err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU); 184 if (err != NO_ERROR) { 185 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 186 (void)nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err)"); 187 return err; 188 } 189 190 err = setNativeWindowSizeFormatAndUsage( 191 nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, 192 false /* reconnect */); 193 if (err != NO_ERROR) { 194 goto error; 195 } 196 197 static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true); 198 199 err = nativeWindow->query(nativeWindow, 200 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); 201 if (err != NO_ERROR) { 202 ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query " 203 "failed: %s (%d)", strerror(-err), -err); 204 goto error; 205 } 206 207 numBufs = minUndequeuedBufs + 1; 208 err = native_window_set_buffer_count(nativeWindow, numBufs); 209 if (err != NO_ERROR) { 210 ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err); 211 goto error; 212 } 213 214 // We push numBufs + 1 buffers to ensure that we've drawn into the same 215 // buffer twice. This should guarantee that the buffer has been displayed 216 // on the screen and then been replaced, so an previous video frames are 217 // guaranteed NOT to be currently displayed. 218 for (int i = 0; i < numBufs + 1; i++) { 219 err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb); 220 if (err != NO_ERROR) { 221 ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", 222 strerror(-err), -err); 223 break; 224 } 225 226 sp<GraphicBuffer> buf(GraphicBuffer::from(anb)); 227 228 // Fill the buffer with the a 1x1 checkerboard pattern ;) 229 uint32_t *img = NULL; 230 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 231 if (err != NO_ERROR) { 232 ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err); 233 break; 234 } 235 236 *img = 0; 237 238 err = buf->unlock(); 239 if (err != NO_ERROR) { 240 ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err); 241 break; 242 } 243 244 err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1); 245 if (err != NO_ERROR) { 246 ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err); 247 break; 248 } 249 250 anb = NULL; 251 } 252 253 error: 254 255 if (anb != NULL) { 256 nativeWindow->cancelBuffer(nativeWindow, anb, -1); 257 anb = NULL; 258 } 259 260 // Clean up after success or error. 261 status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU); 262 if (err2 != NO_ERROR) { 263 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2); 264 if (err == NO_ERROR) { 265 err = err2; 266 } 267 } 268 269 err2 = nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err2)"); 270 if (err2 != NO_ERROR) { 271 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 272 if (err == NO_ERROR) { 273 err = err2; 274 } 275 } 276 277 return err; 278 } 279 280 status_t nativeWindowConnect(ANativeWindow *surface, const char *reason) { 281 ALOGD("connecting to surface %p, reason %s", surface, reason); 282 283 status_t err = native_window_api_connect(surface, NATIVE_WINDOW_API_MEDIA); 284 ALOGE_IF(err != OK, "Failed to connect to surface %p, err %d", surface, err); 285 286 return err; 287 } 288 289 status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason) { 290 ALOGD("disconnecting from surface %p, reason %s", surface, reason); 291 292 status_t err = native_window_api_disconnect(surface, NATIVE_WINDOW_API_MEDIA); 293 ALOGE_IF(err != OK, "Failed to disconnect from surface %p, err %d", surface, err); 294 295 return err; 296 } 297 298 status_t disableLegacyBufferDropPostQ(const sp<Surface> &surface) { 299 sp<IGraphicBufferProducer> igbp = 300 surface ? surface->getIGraphicBufferProducer() : nullptr; 301 if (igbp) { 302 int targetSdk = android_get_application_target_sdk_version(); 303 // When the caller is not an app (e.g. MediaPlayer in mediaserver) 304 // targetSdk is __ANDROID_API_FUTURE__. 305 bool drop = 306 targetSdk < __ANDROID_API_Q__ || 307 targetSdk == __ANDROID_API_FUTURE__; 308 if (!drop) { 309 status_t err = igbp->setLegacyBufferDrop(false); 310 if (err == NO_ERROR) { 311 ALOGD("legacy buffer drop disabled: target sdk (%d)", 312 targetSdk); 313 } else { 314 ALOGD("disabling legacy buffer drop failed: %d", err); 315 } 316 } 317 } 318 return NO_ERROR; 319 } 320 } // namespace android 321 322