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