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/hardware/VideoAPI.h>
     22 #include <media/stagefright/SurfaceUtils.h>
     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 = 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 
    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 
    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 
    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 
    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