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 
setNativeWindowSizeFormatAndUsage(ANativeWindow * nativeWindow,int width,int height,int format,int rotation,int usage,bool reconnect)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 
setNativeWindowHdrMetadata(ANativeWindow * nativeWindow,HDRStaticInfo * info)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 
pushBlankBuffersToNativeWindow(ANativeWindow * nativeWindow)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 
nativeWindowConnect(ANativeWindow * surface,const char * reason)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 
nativeWindowDisconnect(ANativeWindow * surface,const char * reason)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