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 
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 = 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 
pushBlankBuffersToNativeWindow(ANativeWindow * nativeWindow)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