Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2011 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  *************************************************************************
     18  * @file   M4MCS_VideoPreProcessing.c
     19  * @brief  MCS implementation
     20  * @note   This file implements the encoder callback of the MCS.
     21  *************************************************************************
     22  **/
     23 
     24 /**
     25  ********************************************************************
     26  * Includes
     27  ********************************************************************
     28  */
     29 /* OSAL headers */
     30 #include "M4OSA_Memory.h"       /* OSAL memory management */
     31 #include "M4OSA_Debug.h"        /* OSAL debug management */
     32 
     33 
     34 /* Core headers */
     35 #include "M4MCS_InternalTypes.h"
     36 #include "M4MCS_ErrorCodes.h"
     37 
     38 /**
     39  * Video preprocessing interface definition */
     40 #include "M4VPP_API.h"
     41 
     42 /**
     43  * Video filters */
     44 #include "M4VIFI_FiltersAPI.h" /**< for M4VIFI_ResizeBilinearYUV420toYUV420() */
     45 
     46 #ifndef M4MCS_AUDIOONLY
     47 #include "M4AIR_API.h"
     48 #endif /*M4MCS_AUDIOONLY*/
     49 /**/
     50 
     51 
     52 
     53 
     54 /*
     55  ******************************************************************************
     56  * M4OSA_ERR M4MCS_intApplyVPP(M4VPP_Context pContext, M4VIFI_ImagePlane* pPlaneIn,
     57  *                               M4VIFI_ImagePlane* pPlaneOut)
     58  * @brief    Do the video rendering and the resize (if needed)
     59  * @note    It is called by the video encoder
     60  * @param    pContext    (IN) VPP context, which actually is the MCS internal context in our case
     61  * @param    pPlaneIn    (IN) Contains the image
     62  * @param    pPlaneOut    (IN/OUT) Pointer to an array of 3 planes that will contain the output
     63  *                                  YUV420 image
     64  * @return    M4NO_ERROR:    No error
     65  * @return    M4MCS_ERR_VIDEO_DECODE_ERROR: the video decoding failed
     66  * @return    M4MCS_ERR_RESIZE_ERROR: the resizing failed
     67  * @return    Any error returned by an underlaying module
     68  ******************************************************************************
     69  */
     70 M4OSA_ERR M4MCS_intApplyVPP(M4VPP_Context pContext, M4VIFI_ImagePlane* pPlaneIn,
     71                              M4VIFI_ImagePlane* pPlaneOut)
     72 {
     73     M4OSA_ERR        err = M4NO_ERROR;
     74 
     75 /* This part is used only if video codecs are compiled*/
     76 #ifndef M4MCS_AUDIOONLY
     77     /**
     78      * The VPP context is actually the MCS context! */
     79     M4MCS_InternalContext *pC = (M4MCS_InternalContext*)(pContext);
     80 
     81     M4_MediaTime mtCts = pC->dViDecCurrentCts;
     82 
     83     /**
     84      * When Closing after an error occured, it may happen that pReaderVideoAU->m_dataAddress has
     85      * not been allocated yet. When closing in pause mode, the decoder can be null.
     86      * We don't want an error to be returned because it would interrupt the close process and
     87      * thus some resources would be locked. So we return M4NO_ERROR.
     88      */
     89     /* Initialize to black plane the output plane if the media rendering
     90      is black borders */
     91     if(pC->MediaRendering == M4MCS_kBlackBorders)
     92     {
     93         memset((void *)pPlaneOut[0].pac_data,Y_PLANE_BORDER_VALUE,
     94             (pPlaneOut[0].u_height*pPlaneOut[0].u_stride));
     95         memset((void *)pPlaneOut[1].pac_data,U_PLANE_BORDER_VALUE,
     96             (pPlaneOut[1].u_height*pPlaneOut[1].u_stride));
     97         memset((void *)pPlaneOut[2].pac_data,V_PLANE_BORDER_VALUE,
     98             (pPlaneOut[2].u_height*pPlaneOut[2].u_stride));
     99     }
    100     else if ((M4OSA_NULL == pC->ReaderVideoAU.m_dataAddress) ||
    101              (M4OSA_NULL == pC->pViDecCtxt))
    102     {
    103         /**
    104          * We must fill the input of the encoder with a dummy image, because
    105          * encoding noise leads to a huge video AU, and thus a writer buffer overflow. */
    106         memset((void *)pPlaneOut[0].pac_data,0,
    107              pPlaneOut[0].u_stride * pPlaneOut[0].u_height);
    108         memset((void *)pPlaneOut[1].pac_data,0,
    109              pPlaneOut[1].u_stride * pPlaneOut[1].u_height);
    110         memset((void *)pPlaneOut[2].pac_data,0,
    111              pPlaneOut[2].u_stride * pPlaneOut[2].u_height);
    112 
    113         M4OSA_TRACE1_0("M4MCS_intApplyVPP: pReaderVideoAU->m_dataAddress is M4OSA_NULL,\
    114                        returning M4NO_ERROR");
    115         return M4NO_ERROR;
    116     }
    117 
    118     if(pC->isRenderDup == M4OSA_FALSE)
    119     {
    120         /**
    121          *    m_pPreResizeFrame different than M4OSA_NULL means that resizing is needed */
    122         if (M4OSA_NULL != pC->pPreResizeFrame)
    123         {
    124             /** FB 2008/10/20:
    125             Used for cropping and black borders*/
    126             M4AIR_Params Params;
    127 
    128             M4OSA_TRACE3_0("M4MCS_intApplyVPP: Need to resize");
    129             err = pC->m_pVideoDecoder->m_pFctRender(pC->pViDecCtxt, &mtCts,
    130                 pC->pPreResizeFrame, M4OSA_TRUE);
    131             if (M4NO_ERROR != err)
    132             {
    133                 M4OSA_TRACE1_1("M4MCS_intApplyVPP: m_pFctRender returns 0x%x!", err);
    134                 return err;
    135             }
    136 
    137             if(pC->MediaRendering == M4MCS_kResizing)
    138             {
    139                 /*
    140                  * Call the resize filter. From the intermediate frame to the encoder
    141                  * image plane
    142                  */
    143                 err = M4VIFI_ResizeBilinearYUV420toYUV420(M4OSA_NULL,
    144                     pC->pPreResizeFrame, pPlaneOut);
    145                 if (M4NO_ERROR != err)
    146                 {
    147                     M4OSA_TRACE1_1("M4MCS_intApplyVPP: M4ViFilResizeBilinearYUV420toYUV420\
    148                                    returns 0x%x!", err);
    149                     return err;
    150                 }
    151             }
    152             else
    153             {
    154                 M4VIFI_ImagePlane pImagePlanesTemp[3];
    155                 M4VIFI_ImagePlane* pPlaneTemp;
    156                 M4OSA_UInt8* pOutPlaneY = pPlaneOut[0].pac_data +
    157                                           pPlaneOut[0].u_topleft;
    158                 M4OSA_UInt8* pOutPlaneU = pPlaneOut[1].pac_data +
    159                                           pPlaneOut[1].u_topleft;
    160                 M4OSA_UInt8* pOutPlaneV = pPlaneOut[2].pac_data +
    161                                           pPlaneOut[2].u_topleft;
    162                 M4OSA_UInt8* pInPlaneY = M4OSA_NULL;
    163                 M4OSA_UInt8* pInPlaneU = M4OSA_NULL;
    164                 M4OSA_UInt8* pInPlaneV = M4OSA_NULL;
    165                 M4OSA_UInt32 i = 0;
    166 
    167                 /*FB 2008/10/20: to keep media aspect ratio*/
    168                 /*Initialize AIR Params*/
    169                 Params.m_inputCoord.m_x = 0;
    170                 Params.m_inputCoord.m_y = 0;
    171                 Params.m_inputSize.m_height = pC->pPreResizeFrame->u_height;
    172                 Params.m_inputSize.m_width = pC->pPreResizeFrame->u_width;
    173                 Params.m_outputSize.m_width = pPlaneOut->u_width;
    174                 Params.m_outputSize.m_height = pPlaneOut->u_height;
    175                 Params.m_bOutputStripe = M4OSA_FALSE;
    176                 Params.m_outputOrientation = M4COMMON_kOrientationTopLeft;
    177 
    178                 /**
    179                 Media rendering: Black borders*/
    180                 if(pC->MediaRendering == M4MCS_kBlackBorders)
    181                 {
    182                     pImagePlanesTemp[0].u_width = pPlaneOut[0].u_width;
    183                     pImagePlanesTemp[0].u_height = pPlaneOut[0].u_height;
    184                     pImagePlanesTemp[0].u_stride = pPlaneOut[0].u_width;
    185                     pImagePlanesTemp[0].u_topleft = 0;
    186 
    187                     pImagePlanesTemp[1].u_width = pPlaneOut[1].u_width;
    188                     pImagePlanesTemp[1].u_height = pPlaneOut[1].u_height;
    189                     pImagePlanesTemp[1].u_stride = pPlaneOut[1].u_width;
    190                     pImagePlanesTemp[1].u_topleft = 0;
    191 
    192                     pImagePlanesTemp[2].u_width = pPlaneOut[2].u_width;
    193                     pImagePlanesTemp[2].u_height = pPlaneOut[2].u_height;
    194                     pImagePlanesTemp[2].u_stride = pPlaneOut[2].u_width;
    195                     pImagePlanesTemp[2].u_topleft = 0;
    196 
    197                     /* Allocates plan in local image plane structure */
    198                     pImagePlanesTemp[0].pac_data =
    199                         (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(pImagePlanesTemp[0]\
    200                         .u_width * pImagePlanesTemp[0].u_height, M4VS,
    201                         (M4OSA_Char *)"M4xVSS_PictureCallbackFct: temporary plane bufferY") ;
    202                     if(pImagePlanesTemp[0].pac_data == M4OSA_NULL)
    203                     {
    204                         M4OSA_TRACE1_0("Error alloc in M4MCS_intApplyVPP");
    205                         return M4ERR_ALLOC;
    206                     }
    207                     pImagePlanesTemp[1].pac_data =
    208                         (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(pImagePlanesTemp[1]\
    209                         .u_width * pImagePlanesTemp[1].u_height, M4VS,
    210                         (M4OSA_Char *)"M4xVSS_PictureCallbackFct: temporary plane bufferU") ;
    211                     if(pImagePlanesTemp[1].pac_data == M4OSA_NULL)
    212                     {
    213                         M4OSA_TRACE1_0("Error alloc in M4MCS_intApplyVPP");
    214                         return M4ERR_ALLOC;
    215                     }
    216                     pImagePlanesTemp[2].pac_data =
    217                         (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(pImagePlanesTemp[2]\
    218                         .u_width * pImagePlanesTemp[2].u_height,
    219                         M4VS,(M4OSA_Char *)"M4xVSS_PictureCallbackFct: temporary plane bufferV") ;
    220                     if(pImagePlanesTemp[2].pac_data == M4OSA_NULL)
    221                     {
    222                         M4OSA_TRACE1_0("Error alloc in M4MCS_intApplyVPP");
    223                         return M4ERR_ALLOC;
    224                     }
    225 
    226                     pInPlaneY = pImagePlanesTemp[0].pac_data ;
    227                     pInPlaneU = pImagePlanesTemp[1].pac_data ;
    228                     pInPlaneV = pImagePlanesTemp[2].pac_data ;
    229 
    230                     memset((void *)pImagePlanesTemp[0].pac_data,Y_PLANE_BORDER_VALUE,
    231                         (pImagePlanesTemp[0].u_height*pImagePlanesTemp[0].u_stride));
    232                     memset((void *)pImagePlanesTemp[1].pac_data,U_PLANE_BORDER_VALUE,
    233                         (pImagePlanesTemp[1].u_height*pImagePlanesTemp[1].u_stride));
    234                     memset((void *)pImagePlanesTemp[2].pac_data,V_PLANE_BORDER_VALUE,
    235                         (pImagePlanesTemp[2].u_height*pImagePlanesTemp[2].u_stride));
    236 
    237                     if((M4OSA_UInt32)((pC->pPreResizeFrame->u_height * pPlaneOut->u_width)\
    238                          /pC->pPreResizeFrame->u_width) <= pPlaneOut->u_height)
    239                          //Params.m_inputSize.m_height < Params.m_inputSize.m_width)
    240                     {
    241                         /*it is height so black borders will be on the top and on the bottom side*/
    242                         Params.m_outputSize.m_width = pPlaneOut->u_width;
    243                         Params.m_outputSize.m_height =
    244                              (M4OSA_UInt32)
    245                              ((pC->pPreResizeFrame->u_height * pPlaneOut->u_width)\
    246                              /pC->pPreResizeFrame->u_width);
    247                         /*number of lines at the top*/
    248                         pImagePlanesTemp[0].u_topleft =
    249                              (M4MCS_ABS((M4OSA_Int32)
    250                              (pImagePlanesTemp[0].u_height\
    251                              -Params.m_outputSize.m_height)>>1)) *
    252                              pImagePlanesTemp[0].u_stride;
    253                         pImagePlanesTemp[0].u_height = Params.m_outputSize.m_height;
    254                         pImagePlanesTemp[1].u_topleft =
    255                              (M4MCS_ABS((M4OSA_Int32)(pImagePlanesTemp[1].u_height\
    256                              -(Params.m_outputSize.m_height>>1)))>>1)\
    257                              * pImagePlanesTemp[1].u_stride;
    258                         pImagePlanesTemp[1].u_height = Params.m_outputSize.m_height>>1;
    259                         pImagePlanesTemp[2].u_topleft =
    260                              (M4MCS_ABS((M4OSA_Int32)(pImagePlanesTemp[2].u_height\
    261                              -(Params.m_outputSize.m_height>>1)))>>1)\
    262                              * pImagePlanesTemp[2].u_stride;
    263                         pImagePlanesTemp[2].u_height = Params.m_outputSize.m_height>>1;
    264                     }
    265                     else
    266                     {
    267                         /*it is width so black borders will be on the left and right side*/
    268                         Params.m_outputSize.m_height = pPlaneOut->u_height;
    269                         Params.m_outputSize.m_width =
    270                              (M4OSA_UInt32)((pC->pPreResizeFrame->u_width
    271                              * pPlaneOut->u_height)\
    272                              /pC->pPreResizeFrame->u_height);
    273 
    274                         pImagePlanesTemp[0].u_topleft =
    275                              (M4MCS_ABS((M4OSA_Int32)(pImagePlanesTemp[0].u_width-\
    276                                 Params.m_outputSize.m_width)>>1));
    277                         pImagePlanesTemp[0].u_width = Params.m_outputSize.m_width;
    278                         pImagePlanesTemp[1].u_topleft =
    279                              (M4MCS_ABS((M4OSA_Int32)(pImagePlanesTemp[1].u_width-\
    280                                 (Params.m_outputSize.m_width>>1)))>>1);
    281                         pImagePlanesTemp[1].u_width = Params.m_outputSize.m_width>>1;
    282                         pImagePlanesTemp[2].u_topleft =
    283                             (M4MCS_ABS((M4OSA_Int32)(pImagePlanesTemp[2].u_width-\
    284                                 (Params.m_outputSize.m_width>>1)))>>1);
    285                         pImagePlanesTemp[2].u_width = Params.m_outputSize.m_width>>1;
    286                     }
    287 
    288                     /*Width and height have to be even*/
    289                     Params.m_outputSize.m_width = (Params.m_outputSize.m_width>>1)<<1;
    290                     Params.m_outputSize.m_height = (Params.m_outputSize.m_height>>1)<<1;
    291                     Params.m_inputSize.m_width = (Params.m_inputSize.m_width>>1)<<1;
    292                     Params.m_inputSize.m_height = (Params.m_inputSize.m_height>>1)<<1;
    293                     pImagePlanesTemp[0].u_width = (pImagePlanesTemp[0].u_width>>1)<<1;
    294                     pImagePlanesTemp[1].u_width = (pImagePlanesTemp[1].u_width>>1)<<1;
    295                     pImagePlanesTemp[2].u_width = (pImagePlanesTemp[2].u_width>>1)<<1;
    296                     pImagePlanesTemp[0].u_height = (pImagePlanesTemp[0].u_height>>1)<<1;
    297                     pImagePlanesTemp[1].u_height = (pImagePlanesTemp[1].u_height>>1)<<1;
    298                     pImagePlanesTemp[2].u_height = (pImagePlanesTemp[2].u_height>>1)<<1;
    299 
    300                     /*Check that values are coherent*/
    301                     if(Params.m_inputSize.m_height == Params.m_outputSize.m_height)
    302                     {
    303                         Params.m_inputSize.m_width = Params.m_outputSize.m_width;
    304                     }
    305                     else if(Params.m_inputSize.m_width == Params.m_outputSize.m_width)
    306                     {
    307                         Params.m_inputSize.m_height = Params.m_outputSize.m_height;
    308                     }
    309                     pPlaneTemp = pImagePlanesTemp;
    310                 }
    311 
    312                 /**
    313                 Media rendering: Cropping*/
    314                 if(pC->MediaRendering == M4MCS_kCropping)
    315                 {
    316                     Params.m_outputSize.m_height = pPlaneOut->u_height;
    317                     Params.m_outputSize.m_width = pPlaneOut->u_width;
    318                     if((Params.m_outputSize.m_height * Params.m_inputSize.m_width)\
    319                          /Params.m_outputSize.m_width<Params.m_inputSize.m_height)
    320                     {
    321                         /*height will be cropped*/
    322                         Params.m_inputSize.m_height =
    323                              (M4OSA_UInt32)((Params.m_outputSize.m_height \
    324                              * Params.m_inputSize.m_width) /
    325                              Params.m_outputSize.m_width);
    326                         Params.m_inputSize.m_height =
    327                             (Params.m_inputSize.m_height>>1)<<1;
    328                         Params.m_inputCoord.m_y =
    329                             (M4OSA_Int32)((M4OSA_Int32)
    330                             ((pC->pPreResizeFrame->u_height\
    331                             - Params.m_inputSize.m_height))>>1);
    332                     }
    333                     else
    334                     {
    335                         /*width will be cropped*/
    336                         Params.m_inputSize.m_width =
    337                              (M4OSA_UInt32)((Params.m_outputSize.m_width\
    338                                  * Params.m_inputSize.m_height) /
    339                                  Params.m_outputSize.m_height);
    340                         Params.m_inputSize.m_width =
    341                              (Params.m_inputSize.m_width>>1)<<1;
    342                         Params.m_inputCoord.m_x =
    343                             (M4OSA_Int32)((M4OSA_Int32)
    344                             ((pC->pPreResizeFrame->u_width\
    345                             - Params.m_inputSize.m_width))>>1);
    346                     }
    347                     pPlaneTemp = pPlaneOut;
    348                 }
    349                 /**
    350                  * Call AIR functions */
    351                 if(M4OSA_NULL == pC->m_air_context)
    352                 {
    353                     err = M4AIR_create(&pC->m_air_context, M4AIR_kYUV420P);
    354                     if(err != M4NO_ERROR)
    355                     {
    356                         M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct:\
    357                          Error when initializing AIR: 0x%x", err);
    358                         return err;
    359                     }
    360                 }
    361 
    362                 err = M4AIR_configure(pC->m_air_context, &Params);
    363                 if(err != M4NO_ERROR)
    364                 {
    365                     M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct:\
    366                      Error when configuring AIR: 0x%x", err);
    367                     M4AIR_cleanUp(pC->m_air_context);
    368                     return err;
    369                 }
    370 
    371                 err = M4AIR_get(pC->m_air_context, pC->pPreResizeFrame,
    372                                 pPlaneTemp);
    373                 if(err != M4NO_ERROR)
    374                 {
    375                     M4OSA_TRACE1_1("M4xVSS_PictureCallbackFct:\
    376                      Error when getting AIR plane: 0x%x", err);
    377                     M4AIR_cleanUp(pC->m_air_context);
    378                     return err;
    379                 }
    380 
    381                 if(pC->MediaRendering == M4MCS_kBlackBorders)
    382                 {
    383                     for(i=0; i<pPlaneOut[0].u_height; i++)
    384                     {
    385                         memcpy(   (void *)pOutPlaneY,
    386                                         (void *)pInPlaneY,
    387                                         pPlaneOut[0].u_width);
    388                         pInPlaneY += pPlaneOut[0].u_width;
    389                         pOutPlaneY += pPlaneOut[0].u_stride;
    390                     }
    391                     for(i=0; i<pPlaneOut[1].u_height; i++)
    392                     {
    393                         memcpy(   (void *)pOutPlaneU,
    394                                         (void *)pInPlaneU,
    395                                         pPlaneOut[1].u_width);
    396                         pInPlaneU += pPlaneOut[1].u_width;
    397                         pOutPlaneU += pPlaneOut[1].u_stride;
    398                     }
    399                     for(i=0; i<pPlaneOut[2].u_height; i++)
    400                     {
    401                         memcpy(   (void *)pOutPlaneV,
    402                                         (void *)pInPlaneV,
    403                                         pPlaneOut[2].u_width);
    404                         pInPlaneV += pPlaneOut[2].u_width;
    405                         pOutPlaneV += pPlaneOut[2].u_stride;
    406                     }
    407 
    408                     for(i=0; i<3; i++)
    409                     {
    410                         if(pImagePlanesTemp[i].pac_data != M4OSA_NULL)
    411                         {
    412                             free(
    413                                         pImagePlanesTemp[i].pac_data);
    414                             pImagePlanesTemp[i].pac_data = M4OSA_NULL;
    415                         }
    416                     }
    417                 }
    418             }
    419         }
    420         else
    421         {
    422             M4OSA_TRACE3_0("M4MCS_intApplyVPP: Don't need resizing");
    423             err = pC->m_pVideoDecoder->m_pFctRender(pC->pViDecCtxt,
    424                                                     &mtCts, pPlaneOut,
    425                                                     M4OSA_TRUE);
    426             if (M4NO_ERROR != err)
    427             {
    428                 M4OSA_TRACE1_1("M4MCS_intApplyVPP: m_pFctRender returns 0x%x!", err);
    429                 return err;
    430             }
    431         }
    432         pC->lastDecodedPlane = pPlaneOut;
    433     }
    434     else
    435     {
    436         /* Copy last decoded plane to output plane */
    437         memcpy((void *)pPlaneOut[0].pac_data,
    438                         (void *)pC->lastDecodedPlane[0].pac_data,
    439                          (pPlaneOut[0].u_height * pPlaneOut[0].u_width));
    440         memcpy((void *)pPlaneOut[1].pac_data,
    441                         (void *)pC->lastDecodedPlane[1].pac_data,
    442                           (pPlaneOut[1].u_height * pPlaneOut[1].u_width));
    443         memcpy((void *)pPlaneOut[2].pac_data,
    444                         (void *)pC->lastDecodedPlane[2].pac_data,
    445                           (pPlaneOut[2].u_height * pPlaneOut[2].u_width));
    446         pC->lastDecodedPlane = pPlaneOut;
    447     }
    448 
    449 
    450 #endif /*M4MCS_AUDIOONLY*/
    451     M4OSA_TRACE3_0("M4MCS_intApplyVPP: returning M4NO_ERROR");
    452     return M4NO_ERROR;
    453 }
    454 
    455 
    456