• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = 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 
pushBlankBuffersToNativeWindow(ANativeWindow * nativeWindow)131 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) {
132     status_t err = NO_ERROR;
133     ANativeWindowBuffer* anb = NULL;
134     int numBufs = 0;
135     int minUndequeuedBufs = 0;
136 
137     // We need to reconnect to the ANativeWindow as a CPU client to ensure that
138     // no frames get dropped by SurfaceFlinger assuming that these are video
139     // frames.
140     err = nativeWindowDisconnect(nativeWindow, "pushBlankBuffersToNativeWindow");
141     if (err != NO_ERROR) {
142         ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err);
143         return err;
144     }
145 
146     err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU);
147     if (err != NO_ERROR) {
148         ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
149         (void)nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err)");
150         return err;
151     }
152 
153     err = setNativeWindowSizeFormatAndUsage(
154             nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
155             false /* reconnect */);
156     if (err != NO_ERROR) {
157         goto error;
158     }
159 
160     static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true);
161 
162     err = nativeWindow->query(nativeWindow,
163             NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
164     if (err != NO_ERROR) {
165         ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
166                 "failed: %s (%d)", strerror(-err), -err);
167         goto error;
168     }
169 
170     numBufs = minUndequeuedBufs + 1;
171     err = native_window_set_buffer_count(nativeWindow, numBufs);
172     if (err != NO_ERROR) {
173         ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err);
174         goto error;
175     }
176 
177     // We push numBufs + 1 buffers to ensure that we've drawn into the same
178     // buffer twice.  This should guarantee that the buffer has been displayed
179     // on the screen and then been replaced, so an previous video frames are
180     // guaranteed NOT to be currently displayed.
181     for (int i = 0; i < numBufs + 1; i++) {
182         err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb);
183         if (err != NO_ERROR) {
184             ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
185                     strerror(-err), -err);
186             break;
187         }
188 
189         sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
190 
191         // Fill the buffer with the a 1x1 checkerboard pattern ;)
192         uint32_t *img = NULL;
193         err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
194         if (err != NO_ERROR) {
195             ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
196             break;
197         }
198 
199         *img = 0;
200 
201         err = buf->unlock();
202         if (err != NO_ERROR) {
203             ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err);
204             break;
205         }
206 
207         err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1);
208         if (err != NO_ERROR) {
209             ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err);
210             break;
211         }
212 
213         anb = NULL;
214     }
215 
216 error:
217 
218     if (anb != NULL) {
219         nativeWindow->cancelBuffer(nativeWindow, anb, -1);
220         anb = NULL;
221     }
222 
223     // Clean up after success or error.
224     status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU);
225     if (err2 != NO_ERROR) {
226         ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2);
227         if (err == NO_ERROR) {
228             err = err2;
229         }
230     }
231 
232     err2 = nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err2)");
233     if (err2 != NO_ERROR) {
234         ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
235         if (err == NO_ERROR) {
236             err = err2;
237         }
238     }
239 
240     return err;
241 }
242 
nativeWindowConnect(ANativeWindow * surface,const char * reason)243 status_t nativeWindowConnect(ANativeWindow *surface, const char *reason) {
244     ALOGD("connecting to surface %p, reason %s", surface, reason);
245 
246     status_t err = native_window_api_connect(surface, NATIVE_WINDOW_API_MEDIA);
247     ALOGE_IF(err != OK, "Failed to connect to surface %p, err %d", surface, err);
248 
249     return err;
250 }
251 
nativeWindowDisconnect(ANativeWindow * surface,const char * reason)252 status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason) {
253     ALOGD("disconnecting from surface %p, reason %s", surface, reason);
254 
255     status_t err = native_window_api_disconnect(surface, NATIVE_WINDOW_API_MEDIA);
256     ALOGE_IF(err != OK, "Failed to disconnect from surface %p, err %d", surface, err);
257 
258     return err;
259 }
260 }  // namespace android
261 
262