Home | History | Annotate | Download | only in libopencorehw
      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