1 /* 2 * OMAP3430 support 3 * 4 * Author: Srini Gosangi <srini.gosangi (at) windriver.com> 5 * Author: Michael Barabanov <michael.barabanov (at) windriver.com> 6 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 16 * express or implied. 17 * See the License for the specific language governing permissions 18 */ 19 20 /* ------------------------------------------------------------------ 21 * Copyright (C) 2008 PacketVideo 22 * 23 * Licensed under the Apache License, Version 2.0 (the "License"); 24 * you may not use this file except in compliance with the License. 25 * You may obtain a copy of the License at 26 * 27 * http://www.apache.org/licenses/LICENSE-2.0 28 * 29 * Unless required by applicable law or agreed to in writing, software 30 * distributed under the License is distributed on an "AS IS" BASIS, 31 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 32 * express or implied. 33 * See the License for the specific language governing permissions 34 * and limitations under the License. 35 * ------------------------------------------------------------------- 36 */ 37 38 39 //#define LOG_NDEBUG 0 40 #ifdef LOG_NDEBUG 41 #warning LOG_NDEBUG ##LOG_NDEBUG## 42 #endif 43 44 #define LOG_TAG "VideoMio34xx" 45 #include <utils/Log.h> 46 47 #include <cutils/properties.h> 48 #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) 49 static int mDebugFps = 0; 50 51 #include "android_surface_output_omap34xx.h" 52 #include "pv_mime_string_utils.h" 53 #include "pvmf_video.h" 54 #include <media/PVPlayer.h> 55 56 extern "C" { 57 #include "v4l2_utils.h" 58 } 59 60 #define CACHEABLE_BUFFERS 0x1 61 62 using namespace android; 63 64 static void convertYuv420ToYuv422(int width, int height, void* src, void* dst); 65 66 OSCL_EXPORT_REF AndroidSurfaceOutputOmap34xx::AndroidSurfaceOutputOmap34xx() : 67 AndroidSurfaceOutput() 68 { 69 mUseOverlay = true; 70 mOverlay = NULL; 71 mIsFirstFrame = true; 72 mbufferAlloc.buffer_address = NULL; 73 mConvert = false; 74 } 75 76 OSCL_EXPORT_REF AndroidSurfaceOutputOmap34xx::~AndroidSurfaceOutputOmap34xx() 77 { 78 mUseOverlay = false; 79 } 80 81 OSCL_EXPORT_REF bool AndroidSurfaceOutputOmap34xx::initCheck() 82 { 83 LOGV("Calling Vendor(34xx) Specific initCheck"); 84 85 // reset flags in case display format changes in the middle of a stream 86 resetVideoParameterFlags(); 87 bufEnc = 0; 88 89 // copy parameters in case we need to adjust them 90 int displayWidth = iVideoDisplayWidth; 91 int displayHeight = iVideoDisplayHeight; 92 int frameWidth = iVideoWidth; 93 int frameHeight = iVideoHeight; 94 int frameSize; 95 int videoFormat = OVERLAY_FORMAT_CbYCrY_422_I; 96 mapping_data_t *data; 97 LOGV("Use Overlays"); 98 99 if (mUseOverlay) { 100 if(mOverlay == NULL){ 101 LOGV("using Vendor Specific(34xx) codec"); 102 sp<OverlayRef> ref = NULL; 103 // FIXME: 104 // Surfaceflinger may hold onto the previous overlay reference for some 105 // time after we try to destroy it. retry a few times. In the future, we 106 // should make the destroy call block, or possibly specify that we can 107 // wait in the createOverlay call if the previous overlay is in the 108 // process of being destroyed. 109 for (int retry = 0; retry < 50; ++retry) { 110 ref = mSurface->createOverlay(displayWidth, displayHeight, videoFormat, 0); 111 if (ref != NULL) break; 112 LOGD("Overlay create failed - retrying"); 113 usleep(100000); 114 } 115 if ( ref.get() == NULL ) 116 { 117 LOGE("Overlay Creation Failed!"); 118 return mInitialized; 119 } 120 mOverlay = new Overlay(ref); 121 mOverlay->setParameter(CACHEABLE_BUFFERS, 0); 122 } 123 else 124 { 125 mOverlay->resizeInput(displayWidth, displayHeight); 126 } 127 128 mbufferAlloc.maxBuffers = 6; // Hardcoded to work with OMX decoder component 129 mbufferAlloc.bufferSize = iBufferSize; 130 if (mbufferAlloc.buffer_address) { 131 delete [] mbufferAlloc.buffer_address; 132 } 133 mbufferAlloc.buffer_address = new uint8*[mbufferAlloc.maxBuffers]; 134 if (mbufferAlloc.buffer_address == NULL) { 135 LOGE("unable to allocate mem for overlay addresses"); 136 return mInitialized; 137 } 138 LOGV("number of buffers = %d\n", mbufferAlloc.maxBuffers); 139 for (int i = 0; i < mbufferAlloc.maxBuffers; i++) { 140 data = (mapping_data_t *)mOverlay->getBufferAddress((void*)i); 141 mbufferAlloc.buffer_address[i] = (uint8*)data->ptr; 142 strcpy((char *)mbufferAlloc.buffer_address[i], "hello"); 143 if (strcmp((char *)mbufferAlloc.buffer_address[i], "hello")) { 144 LOGI("problem with buffer\n"); 145 return mInitialized; 146 }else{ 147 LOGV("buffer = %d allocated addr=%#lx\n", i, (unsigned long) mbufferAlloc.buffer_address[i]); 148 } 149 } 150 } 151 mInitialized = true; 152 LOGV("sendEvent(MEDIA_SET_VIDEO_SIZE, %d, %d)", iVideoDisplayWidth, iVideoDisplayHeight); 153 mPvPlayer->sendEvent(MEDIA_SET_VIDEO_SIZE, iVideoDisplayWidth, iVideoDisplayHeight); 154 155 // is conversion necessary? 156 if (iVideoSubFormat == PVMF_MIME_YUV420_PLANAR) { 157 LOGV("Use YUV420_PLANAR -> YUV422_INTERLEAVED_UYVY converter"); 158 mConvert = true; 159 } 160 161 char value[PROPERTY_VALUE_MAX]; 162 property_get("debug.video.showfps", value, "0"); 163 mDebugFps = atoi(value); 164 LOGV_IF(mDebugFps, "showfps enabled"); 165 166 return mInitialized; 167 } 168 169 static void debugShowFPS() 170 { 171 static int mFrameCount = 0; 172 static int mLastFrameCount = 0; 173 static nsecs_t mLastFpsTime = 0; 174 static float mFps = 0; 175 mFrameCount++; 176 if (!(mFrameCount & 0x1F)) { 177 nsecs_t now = systemTime(); 178 nsecs_t diff = now - mLastFpsTime; 179 mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; 180 mLastFpsTime = now; 181 mLastFrameCount = mFrameCount; 182 LOGV("%d Frames, %f FPS", mFrameCount, mFps); 183 } 184 // XXX: mFPS has the value we want 185 } 186 187 PVMFStatus AndroidSurfaceOutputOmap34xx::writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info) 188 { 189 LOGV(" calling Vendor Specific(34xx) writeFrameBuf call"); 190 if (mSurface == 0) return PVMFFailure; 191 192 if (UNLIKELY(mDebugFps)) { 193 debugShowFPS(); 194 } 195 196 if (mUseOverlay) { 197 int ret; 198 199 // Convert from YUV420 to YUV422 for software codec 200 if (mConvert) { 201 convertYuv420ToYuv422(iVideoWidth, iVideoHeight, aData, mbufferAlloc.buffer_address[bufEnc]); 202 } else { 203 int i; 204 for (i = 0; i < mbufferAlloc.maxBuffers; i++) { 205 if (mbufferAlloc.buffer_address[i] == aData) { 206 break; 207 } 208 209 } 210 if (i == mbufferAlloc.maxBuffers) { 211 LOGE("aData does not match any v4l buffer address\n"); 212 return PVMFSuccess; 213 } 214 LOGV("queueBuffer %d\n", i); 215 bufEnc = i; 216 } 217 218 /* This is to reset the buffer queue when stream_off is called as 219 * all the buffers are flushed when stream_off is called. 220 */ 221 ret = mOverlay->queueBuffer((void*)bufEnc); 222 if (ret == ALL_BUFFERS_FLUSHED) { 223 mIsFirstFrame = true; 224 mOverlay->queueBuffer((void*)bufEnc); 225 } 226 227 overlay_buffer_t overlay_buffer; 228 229 /* This is to prevent dequeueBuffer to be called before the first 230 * queueBuffer call is done. If that happens, there will be a delay 231 * as the dequeueBuffer call will be blocked. 232 */ 233 if (!mIsFirstFrame) 234 { 235 ret = mOverlay->dequeueBuffer(&overlay_buffer); 236 if (ret != NO_ERROR) { 237 if (ret == ALL_BUFFERS_FLUSHED) 238 mIsFirstFrame = true; 239 return false; 240 } 241 } 242 else 243 { 244 mIsFirstFrame = false; 245 } 246 247 // advance the overlay index if using color conversion 248 if (mConvert) { 249 if (++bufEnc == mbufferAlloc.maxBuffers) { 250 bufEnc = 0; 251 } 252 } 253 } 254 return PVMFSuccess; 255 } 256 257 258 #define USE_BUFFER_ALLOC 1 259 260 /* based on test code in pvmi/media_io/pvmiofileoutput/src/pvmi_media_io_fileoutput.cpp */ 261 void AndroidSurfaceOutputOmap34xx::setParametersSync(PvmiMIOSession aSession, 262 PvmiKvp* aParameters, 263 int num_elements, 264 PvmiKvp * & aRet_kvp) 265 { 266 OSCL_UNUSED_ARG(aSession); 267 aRet_kvp = NULL; 268 269 #ifndef USE_BUFFER_ALLOC 270 AndroidSurfaceOutput::setParametersSync(aSession, aParameters, num_elements, aRet_kvp); 271 return; 272 #endif 273 274 for (int32 i = 0;i < num_elements;i++) 275 { 276 if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_FORMAT_KEY) == 0) 277 { 278 iVideoFormatString=aParameters[i].value.pChar_value; 279 iVideoFormat=iVideoFormatString.get_str(); 280 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Video Format Key, Value %s",iVideoFormatString.get_str()); 281 } 282 else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0) 283 { 284 uint8* data = (uint8*)aParameters->value.key_specific_value; 285 PVMFYuvFormatSpecificInfo0* yuvInfo = (PVMFYuvFormatSpecificInfo0*)data; 286 287 iVideoWidth = (int32)yuvInfo->width; 288 iVideoParameterFlags |= VIDEO_WIDTH_VALID; 289 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Video Width, Value %d", iVideoWidth); 290 291 iVideoHeight = (int32)yuvInfo->height; 292 iVideoParameterFlags |= VIDEO_HEIGHT_VALID; 293 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Video Height, Value %d", iVideoHeight); 294 295 iVideoDisplayHeight = (int32)yuvInfo->display_height; 296 iVideoParameterFlags |= DISPLAY_HEIGHT_VALID; 297 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Video Display Height, Value %d", iVideoDisplayHeight); 298 299 300 iVideoDisplayWidth = (int32)yuvInfo->display_width; 301 iVideoParameterFlags |= DISPLAY_WIDTH_VALID; 302 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Video Display Width, Value %d", iVideoDisplayWidth); 303 304 iNumberOfBuffers = (int32)yuvInfo->num_buffers; 305 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Number of Buffer, Value %d", iNumberOfBuffers); 306 307 iBufferSize = (int32)yuvInfo->buffer_size; 308 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Buffer Size, Value %d", iBufferSize); 309 310 LOGV("Ln %d video_format %s", __LINE__, yuvInfo->video_format.getMIMEStrPtr() ); 311 iVideoSubFormat = yuvInfo->video_format.getMIMEStrPtr(); 312 iVideoParameterFlags |= VIDEO_SUBFORMAT_VALID; 313 } 314 else 315 { 316 //if we get here the key is unrecognized. 317 LOGV("AndroidSurfaceOutputOmap34xx::setParametersSync() Error, unrecognized key %s ", aParameters[i].key); 318 319 //set the return value to indicate the unrecognized key 320 //and return. 321 aRet_kvp = &aParameters[i]; 322 return; 323 } 324 } 325 /* Copy Code from base class. Ideally we'd just call base class's setParametersSync, but we can't as it will not get to initCheck if it encounters an unrecognized parameter such as the one we're handling here */ 326 uint32 mycache = iVideoParameterFlags ; 327 if( checkVideoParameterFlags() ) { 328 initCheck(); 329 } 330 iVideoParameterFlags = mycache; 331 if(!iIsMIOConfigured && checkVideoParameterFlags() ) 332 { 333 iIsMIOConfigured = true; 334 if(iObserver) 335 { 336 iObserver->ReportInfoEvent(PVMFMIOConfigurationComplete); 337 } 338 } 339 } 340 341 /* based on test code in pvmi/media_io/pvmiofileoutput/src/pvmi_media_io_fileoutput.cpp */ 342 PVMFStatus AndroidSurfaceOutputOmap34xx::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, 343 PvmiKvp*& aParameters, int& num_parameter_elements, 344 PvmiCapabilityContext aContext) 345 { 346 #ifdef USE_BUFFER_ALLOC 347 OSCL_UNUSED_ARG(aSession); 348 OSCL_UNUSED_ARG(aContext); 349 aParameters=NULL; 350 351 if (strcmp(aIdentifier, PVMF_BUFFER_ALLOCATOR_KEY) == 0) 352 { 353 if( iVideoSubFormat != PVMF_MIME_YUV422_INTERLEAVED_UYVY ) { 354 LOGV("Ln %d iVideoSubFormat %s. do NOT allocate decoder buffer from overlay", __LINE__, iVideoSubFormat.getMIMEStrPtr() ); 355 OSCL_LEAVE(OsclErrNotSupported); 356 return PVMFErrNotSupported; 357 } 358 359 int32 err; 360 aParameters = (PvmiKvp*)oscl_malloc(sizeof(PvmiKvp)); 361 if (!aParameters) 362 { 363 return PVMFErrNoMemory; 364 } 365 aParameters[0].value.key_specific_value = (PVInterface*)&mbufferAlloc; 366 return PVMFSuccess; 367 } 368 369 #endif 370 return AndroidSurfaceOutput::getParametersSync(aSession, aIdentifier, aParameters, num_parameter_elements, aContext); 371 } 372 373 // post the last video frame to refresh screen after pause 374 void AndroidSurfaceOutputOmap34xx::postLastFrame() 375 { 376 //do nothing here, this is only for override the Android_Surface_output::PostLastFrame() 377 LOGV("AndroidSurfaceOutputOmap34xx::postLastFrame()"); 378 //mSurface->postBuffer(mOffset); 379 } 380 381 void AndroidSurfaceOutputOmap34xx::closeFrameBuf() 382 { 383 LOGV("Vendor(34xx) Speicif CloseFrameBuf"); 384 if (UNLIKELY(mDebugFps)) { 385 debugShowFPS(); 386 } 387 if (mOverlay != NULL){ 388 mOverlay->destroy(); 389 mOverlay = NULL; 390 } 391 if (mbufferAlloc.buffer_address) { 392 delete [] mbufferAlloc.buffer_address; 393 mbufferAlloc.buffer_address = NULL; 394 } 395 if (!mInitialized) return; 396 mInitialized = false; 397 } 398 399 // return a byte offset from any pointer 400 static inline void* byteOffset(void* p, size_t offset) { return (void*)((uint8_t*)p + offset); } 401 402 static void convertYuv420ToYuv422(int width, int height, void* src, void* dst) 403 { 404 405 // calculate total number of pixels, and offsets to U and V planes 406 int pixelCount = height * width; 407 int srcLineLength = width / 4; 408 int destLineLength = width / 2; 409 uint32_t* ySrc = (uint32_t*) src; 410 uint16_t* uSrc = (uint16_t*) byteOffset(src, pixelCount); 411 uint16_t* vSrc = (uint16_t*) byteOffset(uSrc, pixelCount >> 2); 412 uint32_t *p = (uint32_t*) dst; 413 414 // convert lines 415 for (int i = 0; i < height; i += 2) { 416 417 // upsample by repeating the UV values on adjacent lines 418 // to save memory accesses, we handle 2 adjacent lines at a time 419 // convert 4 pixels in 2 adjacent lines at a time 420 for (int j = 0; j < srcLineLength; j++) { 421 422 // fetch 4 Y values for each line 423 uint32_t y0 = ySrc[0]; 424 uint32_t y1 = ySrc[srcLineLength]; 425 ySrc++; 426 427 // fetch 2 U/V values 428 uint32_t u = *uSrc++; 429 uint32_t v = *vSrc++; 430 431 // assemble first U/V pair, leave holes for Y's 432 uint32_t uv = (u | (v << 16)) & 0x00ff00ff; 433 434 // OR y values and write to memory 435 p[0] = ((y0 & 0xff) << 8) | ((y0 & 0xff00) << 16) | uv; 436 p[destLineLength] = ((y1 & 0xff) << 8) | ((y1 & 0xff00) << 16) | uv; 437 p++; 438 439 // assemble second U/V pair, leave holes for Y's 440 uv = ((u >> 8) | (v << 8)) & 0x00ff00ff; 441 442 // OR y values and write to memory 443 p[0] = ((y0 >> 8) & 0xff00) | (y0 & 0xff000000) | uv; 444 p[destLineLength] = ((y1 >> 8) & 0xff00) | (y1 & 0xff000000) | uv; 445 p++; 446 } 447 448 // skip the next y line, we already converted it 449 ySrc += srcLineLength; 450 p += destLineLength; 451 } 452 } 453 454 455 // factory function for playerdriver linkage 456 extern "C" AndroidSurfaceOutputOmap34xx* createVideoMio() 457 { 458 LOGV("Creating Vendor(34xx) Specific MIO component"); 459 return new AndroidSurfaceOutputOmap34xx(); 460 } 461