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 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 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA); 35 if (err != NO_ERROR) { 36 ALOGE("native_window_api_disconnect failed: %s (%d)", strerror(-err), -err); 37 return err; 38 } 39 40 err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA); 41 if (err != NO_ERROR) { 42 ALOGE("native_window_api_connect 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 ANativeWindow uses hardware protected buffers. 95 if (queuesToNativeWindow != 1 && !(consumerUsage & GRALLOC_USAGE_PROTECTED)) { 96 ALOGE("native window could not be authenticated"); 97 return PERMISSION_DENIED; 98 } 99 } 100 101 int finalUsage = usage | consumerUsage; 102 ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage); 103 err = native_window_set_usage(nativeWindow, finalUsage); 104 if (err != NO_ERROR) { 105 ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); 106 return err; 107 } 108 109 err = native_window_set_scaling_mode( 110 nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); 111 if (err != NO_ERROR) { 112 ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err); 113 return err; 114 } 115 116 ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x", 117 nativeWindow, width, height, format, rotation, finalUsage); 118 return NO_ERROR; 119 } 120 121 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) { 122 status_t err = NO_ERROR; 123 ANativeWindowBuffer* anb = NULL; 124 int numBufs = 0; 125 int minUndequeuedBufs = 0; 126 127 // We need to reconnect to the ANativeWindow as a CPU client to ensure that 128 // no frames get dropped by SurfaceFlinger assuming that these are video 129 // frames. 130 err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA); 131 if (err != NO_ERROR) { 132 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err); 133 return err; 134 } 135 136 err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU); 137 if (err != NO_ERROR) { 138 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 139 (void)native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA); 140 return err; 141 } 142 143 err = setNativeWindowSizeFormatAndUsage( 144 nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, 145 false /* reconnect */); 146 if (err != NO_ERROR) { 147 goto error; 148 } 149 150 static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true); 151 152 err = nativeWindow->query(nativeWindow, 153 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); 154 if (err != NO_ERROR) { 155 ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query " 156 "failed: %s (%d)", strerror(-err), -err); 157 goto error; 158 } 159 160 numBufs = minUndequeuedBufs + 1; 161 err = native_window_set_buffer_count(nativeWindow, numBufs); 162 if (err != NO_ERROR) { 163 ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err); 164 goto error; 165 } 166 167 // We push numBufs + 1 buffers to ensure that we've drawn into the same 168 // buffer twice. This should guarantee that the buffer has been displayed 169 // on the screen and then been replaced, so an previous video frames are 170 // guaranteed NOT to be currently displayed. 171 for (int i = 0; i < numBufs + 1; i++) { 172 err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb); 173 if (err != NO_ERROR) { 174 ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", 175 strerror(-err), -err); 176 break; 177 } 178 179 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); 180 181 // Fill the buffer with the a 1x1 checkerboard pattern ;) 182 uint32_t *img = NULL; 183 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 184 if (err != NO_ERROR) { 185 ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err); 186 break; 187 } 188 189 *img = 0; 190 191 err = buf->unlock(); 192 if (err != NO_ERROR) { 193 ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err); 194 break; 195 } 196 197 err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1); 198 if (err != NO_ERROR) { 199 ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err); 200 break; 201 } 202 203 anb = NULL; 204 } 205 206 error: 207 208 if (anb != NULL) { 209 nativeWindow->cancelBuffer(nativeWindow, anb, -1); 210 anb = NULL; 211 } 212 213 // Clean up after success or error. 214 status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU); 215 if (err2 != NO_ERROR) { 216 ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2); 217 if (err == NO_ERROR) { 218 err = err2; 219 } 220 } 221 222 err2 = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA); 223 if (err2 != NO_ERROR) { 224 ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); 225 if (err == NO_ERROR) { 226 err = err2; 227 } 228 } 229 230 return err; 231 } 232 233 } // namespace android 234 235