• 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)27 status_t setNativeWindowSizeFormatAndUsage(
28         ANativeWindow *nativeWindow /* nonnull */,
29         int width, int height, int format, int rotation, int usage) {
30     status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height);
31     if (err != NO_ERROR) {
32         ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err);
33         return err;
34     }
35 
36     err = native_window_set_buffers_format(nativeWindow, format);
37     if (err != NO_ERROR) {
38         ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err);
39         return err;
40     }
41 
42     int transform = 0;
43     if ((rotation % 90) == 0) {
44         switch ((rotation / 90) & 3) {
45             case 1:  transform = HAL_TRANSFORM_ROT_90;  break;
46             case 2:  transform = HAL_TRANSFORM_ROT_180; break;
47             case 3:  transform = HAL_TRANSFORM_ROT_270; break;
48             default: transform = 0;                     break;
49         }
50     }
51 
52     err = native_window_set_buffers_transform(nativeWindow, transform);
53     if (err != NO_ERROR) {
54         ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err);
55         return err;
56     }
57 
58     // Make sure to check whether either Stagefright or the video decoder
59     // requested protected buffers.
60     if (usage & GRALLOC_USAGE_PROTECTED) {
61         // Verify that the ANativeWindow sends images directly to
62         // SurfaceFlinger.
63         int queuesToNativeWindow = 0;
64         err = nativeWindow->query(
65                 nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow);
66         if (err != NO_ERROR) {
67             ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err);
68             return err;
69         }
70         if (queuesToNativeWindow != 1) {
71             ALOGE("native window could not be authenticated");
72             return PERMISSION_DENIED;
73         }
74     }
75 
76     int consumerUsage = 0;
77     err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
78     if (err != NO_ERROR) {
79         ALOGW("failed to get consumer usage bits. ignoring");
80         err = NO_ERROR;
81     }
82 
83     int finalUsage = usage | consumerUsage;
84     ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage);
85     err = native_window_set_usage(nativeWindow, finalUsage);
86     if (err != NO_ERROR) {
87         ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
88         return err;
89     }
90 
91     err = native_window_set_scaling_mode(
92             nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
93     if (err != NO_ERROR) {
94         ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err);
95         return err;
96     }
97 
98     ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x",
99             nativeWindow, width, height, format, rotation, finalUsage);
100     return NO_ERROR;
101 }
102 
pushBlankBuffersToNativeWindow(ANativeWindow * nativeWindow)103 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) {
104     status_t err = NO_ERROR;
105     ANativeWindowBuffer* anb = NULL;
106     int numBufs = 0;
107     int minUndequeuedBufs = 0;
108 
109     // We need to reconnect to the ANativeWindow as a CPU client to ensure that
110     // no frames get dropped by SurfaceFlinger assuming that these are video
111     // frames.
112     err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
113     if (err != NO_ERROR) {
114         ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err);
115         return err;
116     }
117 
118     err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU);
119     if (err != NO_ERROR) {
120         ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
121         (void)native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
122         return err;
123     }
124 
125     err = setNativeWindowSizeFormatAndUsage(
126             nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN);
127     if (err != NO_ERROR) {
128         goto error;
129     }
130 
131     static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true);
132 
133     err = nativeWindow->query(nativeWindow,
134             NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
135     if (err != NO_ERROR) {
136         ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
137                 "failed: %s (%d)", strerror(-err), -err);
138         goto error;
139     }
140 
141     numBufs = minUndequeuedBufs + 1;
142     err = native_window_set_buffer_count(nativeWindow, numBufs);
143     if (err != NO_ERROR) {
144         ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err);
145         goto error;
146     }
147 
148     // We push numBufs + 1 buffers to ensure that we've drawn into the same
149     // buffer twice.  This should guarantee that the buffer has been displayed
150     // on the screen and then been replaced, so an previous video frames are
151     // guaranteed NOT to be currently displayed.
152     for (int i = 0; i < numBufs + 1; i++) {
153         err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb);
154         if (err != NO_ERROR) {
155             ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
156                     strerror(-err), -err);
157             break;
158         }
159 
160         sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
161 
162         // Fill the buffer with the a 1x1 checkerboard pattern ;)
163         uint32_t *img = NULL;
164         err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
165         if (err != NO_ERROR) {
166             ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
167             break;
168         }
169 
170         *img = 0;
171 
172         err = buf->unlock();
173         if (err != NO_ERROR) {
174             ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err);
175             break;
176         }
177 
178         err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1);
179         if (err != NO_ERROR) {
180             ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err);
181             break;
182         }
183 
184         anb = NULL;
185     }
186 
187 error:
188 
189     if (anb != NULL) {
190         nativeWindow->cancelBuffer(nativeWindow, anb, -1);
191         anb = NULL;
192     }
193 
194     // Clean up after success or error.
195     status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU);
196     if (err2 != NO_ERROR) {
197         ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2);
198         if (err == NO_ERROR) {
199             err = err2;
200         }
201     }
202 
203     err2 = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
204     if (err2 != NO_ERROR) {
205         ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
206         if (err == NO_ERROR) {
207             err = err2;
208         }
209     }
210 
211     return err;
212 }
213 
214 }  // namespace android
215 
216