Home | History | Annotate | Download | only in libstagefright
      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