• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
M4MCS_intApplyVPP(M4VPP_Context pContext,M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut)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