XBMC 使用 Android StageFright 硬件解码

转载自:http://blog.csdn.net/mirkerson/article/details/40184803
XBMC 在 Android 平台上,除了可以通过 Java MediaCodec API 使用硬件解码功能,还可以直接调用 Android 媒体框架 StageFright 提供的 C++ API 访问硬件解码器。

StageFright 是 Android 在 4.0 (level 14) 上的媒体框架(http://source.android.com/devices/media.html),支持 OpenMAX 标准。在该媒体框架下,硬件厂商采用 OMX plugin 方式封装 libstagefrighthw.so 私有库,为系统提供硬件编解码器。Android 的 MediaPlayer 通过调用 StageFright API 为 App 提供编解码功能。

虽然 StageFright API 属于非正式的 API,为了较好的视频播放效果,XBMC 也直接调用 Stagefright API,进行硬件解码。

## XBMC 调用 StageFright API

XBMC 使用 StageFright 分两步:首先封装一个通用类,供程序上层使用统一接口调用;再将与 Android 底层
相关的 StageFright 代码封装到一个单独的动态链接库,并提供自己的 API。随着 Android 平台的升级,如果 StageFright API 有改变,只需要更新底层的动态链接库。

### CDVDVideoCodecStageFrigh t 类

支持 StageFright 的 CDVDVideoCodec 为 CDVDVideoCodecStageFrigh t:

      xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright .h:
      
      class CDVDVideoCodecStageFrigh t : public CDVDVideoCodec

播放视频时,XBMC 根据系统和软件设置,决定是否使用 Codec Factory 创建 StageFright 解码器

      xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp:
      
      CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigned int surfaces, const std::vector& formats)
      {
         CDVDVideoCodec* pCodec = NULL;

      #if defined(HAS_LIBSTAGEFRIGHT)
         hwSupport += "libstagefright:yes ";
      #elif defined(_LINUX)
         hwSupport += "libstagefright:no ";
      #endif

      #if defined(HAS_LIBSTAGEFRIGHT)
         if (!hint.software && CSettings::Get().GetBool("videoplayer.usestagefright"))
            {
                  switch(hint.codec)
                  {
                     case CODEC_ID_H264:
                     case CODEC_ID_MPEG4:
                     case CODEC_ID_MPEG2VIDEO:
                     case CODEC_ID_VC1:
                     case CODEC_ID_WMV3:
                     case CODEC_ID_VP3:
                     case CODEC_ID_VP6:
                     case CODEC_ID_VP6F:
                     case CODEC_ID_VP8:
                        if ( (pCodec = OpenCodec(new CDVDVideoCodecStageFrigh t(), hint, options)) ) return pCodec;
                        break;
                     default:
                        break;
                  }
            }
      #endif
      }

      CDVDVideoCodec* CDVDFactoryCodec::OpenCodec(CDVDVideoCodec* pCodec, CDVDStreamInfo &hints, CDVDCodecOptions &options )
      {
            if( pCodec->Open( hints, options ) )
            {
               CLog::Log(LOGDEBUG, "FactoryCodec - Video: %s - Opened", pCodec->GetName());
               return pCodec;
            }
         return NULL;
      }

在 DVDVideoCodecStageFright  中,加载动态链接库 libXBMCvcodec_stagefrightICS-arm.so

      xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStagefright .cpp:

      CDVDVideoCodecStageFrigh t::CDVDVideoCodecStageFrigh t()
         : CDVDVideoCodec()
         , m_convert_bitstream(false),   m_converter(NULL)
         , m_stf_handle(NULL)
      {
         if (!m_stf_dll)
            m_stf_dll = new DllLibStageFrightCodec;
      }

然后调用它提供的接口函数:

      bool CDVDVideoCodecStageFrigh t::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
      {
            m_stf_handle = m_stf_dll->create_stf(&g_application, &CApplicationMessenger::Get(), &g_Windowing, &g_advancedSettings);

            if (!m_stf_dll->stf_Open(m_stf_handle, hints))
            {
               Dispose();
               return false;
            }
            return true;
      }

      int CDVDVideoCodecStageFrigh t::Decode(uint8_t *pData, int iSize, double dts, double pts)
      {
         rtn = m_stf_dll->stf_Decode(m_stf_handle, demuxer_content, demuxer_bytes, dts, pts);
         return rtn;
      }
      
### 封装 StageFright 的动态链接库 libXBMCvcodec_stagefrightICS-arm.so

在它的 Makefile 中,可以看到它依赖 libstagefright.so

      LIBS += -landroid -lEGL -lGLESv2 -L${prefix}/opt/android-libs -lstdc++ -lutils -lcutils -lstagefright -lbinder -lui -lgui

该动态链接库中定义了一套自己的接口函数来使用解码器:

      xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterfac.cpp

      extern "C"
      {
         void* create_stf(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings);
         void destroy_stf(void*);

         bool stf_Open(void*, CDVDStreamInfo &hints);
         void stf_Dispose(void*);
         int   stf_Decode(void*, uint8_t *pData, int iSize, double dts, double pts);
         void stf_Reset(void*);
         bool stf_GetPicture(void*, DVDVideoPicture *pDvdVideoPicture);
         bool stf_ClearPicture(void*, DVDVideoPicture* pDvdVideoPicture);
         void stf_SetDropState(void*, bool bDrop);
         void stf_SetSpeed(void*, int iSpeed);

         void stf_LockBuffer(void*, EGLImageKHR eglimg);
         void stf_ReleaseBuffer(void*, EGLImageKHR eglimg);
      }

在接口函数实现代码中,解码功能又通过 CStageFrightVideo 对象完成。

      xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterfac.cpp

      void* create_stf(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings)
      {
         return (void*)new CStageFrightVideo(application, applicationMessenger, windowing, advsettings);
      }

      bool stf_Open(void* stf, CDVDStreamInfo &hints)
      {
         return ((CStageFrightVideo*)stf)->Open(hints);
      }

      int   stf_Decode(void* stf, uint8_t *pData, int iSize, double dts, double pts)
      {
         return ((CStageFrightVideo*)stf)->Decode(pData, iSize, dts, pts);
      }

最后,所有直接调用 Stagefright API 的操作都被封装到 CStageFrightVideo 类中。

      xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.h

      class CStageFrightVideo
      {
      public:
         CStageFrightVideo(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings);
         virtual ~CStageFrightVideo();

         bool Open(CDVDStreamInfo &hints);
         void Dispose(void);
         int   Decode(uint8_t *pData, int iSize, double dts, double pts);
         void Reset(void);
         bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
         bool ClearPicture(DVDVideoPicture* pDvdVideoPicture);
         void SetDropState(bool bDrop);
         virtual void SetSpeed(int iSpeed);

         void LockBuffer(EGLImageKHR eglimg);
         void ReleaseBuffer(EGLImageKHR eglimg);

      private:
         CStageFrightVideoPrivate * p;
      };

通过 StageFright API 使用解码器也分为三个步骤:

1. 创建解码器

主要调用 StageFright 中 OMXClient 的 connect() 和 OMXCodec 的 Create() 函数,同时创建解码线程。

      xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.cpp

      CStageFrightVideo::CStageFrightVideo(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings)
      {
         p = new CStageFrightVideoPrivate ;
         ...
      }

      bool CStageFrightVideo::Open(CDVDStreamInfo &hints)
      {
         p->source      = new CStageFrightMediaSource(p, p->meta);
         p->client      = new OMXClient;

         if (p->client->connect() !=   OK)
         {
            return false;
         }

         p->decoder   = OMXCodec::Create(p->client->interface(), p->meta,
                                                                    false, p->source, NULL,
                                                                    OMXCodec::kHardwareCodecsOnly | (p->quirks & QuirkSWRender ? OMXCodec::kClientNeedsFramebuffer : 0),
                                                                    p->mVideoNativeWindow
                                                                    );

         if (!(p->decoder != NULL && p->decoder->start() ==   OK))
         {
            return false;
         }

         p->decode_thread = new CStageFrightDecodeThread (p);
         p->decode_thread->Create(true );
      }

2. 将编码的数据传给解码器

编码数据由 Decode() 函数复制到 in_queue 中的空闲缓存

      int   CStageFrightVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
      {
         Frame *frame;
         int demuxer_bytes = iSize;
         uint8_t *demuxer_content = pData;
         int ret = 0;

         if (demuxer_content)
         {
            frame = (Frame*)malloc(sizeof(Frame));
            frame->status   = OK;
            frame->medbuf = p->getBuffer(demuxer_bytes);
            fast_memcpy(frame->medbuf->data(), demuxer_content, demuxer_bytes);

            p->in_mutex.lock();
            p->in_queue.push_back(frame);
            p->in_condition.notify();
            p->in_mutex.unlock();
         }
      }

创建解码器时传入的 p->source 对象,其类 CStageFrightMediaSource 提供的 read() 函数,负责将 in_queue 队列中的缓存取出交给 OMXCodec 解码器处理。

      class CStageFrightMediaSource : public MediaSource
      {
         virtual status_t read(MediaBuffer **buffer,
                                          const MediaSource::ReadOptions *options)
         {
            Frame *frame;
            status_t ret;
            *buffer = NULL;

            std::list
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值