std::string OMXPlayerVideo::GetText()
{
  OMXPacket *pkt = NULL;
  std::string strSubtitle = "";

  LockSubtitles();
  if (!m_subtitle_packets.empty())
  {
    pkt = m_subtitle_packets.front(); 
    if(!m_overlays.empty())
    {
      COMXOverlay *overlay = m_overlays.front();
      double now = m_av_clock->GetClock();
      double iPTSStartTime = pkt->pts;
      double iPTSStopTime = (overlay->iPTSStartTime > 0) ? iPTSStartTime + (overlay->iPTSStopTime - overlay->iPTSStartTime) : 0LL;

      if((iPTSStartTime <= now)
        && (iPTSStopTime >= now || iPTSStopTime == 0LL))
      {
        COMXOverlayText::CElement* e = ((COMXOverlayText*)overlay)->m_pHead;
        while (e)
        {
          if (e->IsElementType(COMXOverlayText::ELEMENT_TYPE_TEXT))
          {
            COMXOverlayText::CElementText* t = (COMXOverlayText::CElementText*)e;
            strSubtitle += t->m_text;
              strSubtitle += "\n";
          }
          e = e->pNext;
        }
      }
      else if(iPTSStopTime < now)
      {
        m_subtitle_packets.pop_front();
        m_overlays.pop_front();
        delete overlay;
        OMXReader::FreePacket(pkt);
      }
    }
  }
  UnLockSubtitles();

  return strSubtitle;
}
bool OMXPlayerVideo::Decode(OMXPacket *pkt)
{
  if(!pkt)
    return false;

  bool ret = false;

  if(!((unsigned long)m_decoder->GetFreeSpace() > pkt->size))
    OMXClock::OMXSleep(10);

  if (pkt->dts == DVD_NOPTS_VALUE && pkt->pts == DVD_NOPTS_VALUE)
    pkt->pts = m_pts;
  else if (pkt->pts == DVD_NOPTS_VALUE)
    pkt->pts = pkt->dts;

  if(pkt->pts != DVD_NOPTS_VALUE)
  {
    m_pts = pkt->pts;
    m_pts += m_iVideoDelay;
  }

  if(pkt->hints.codec == CODEC_ID_TEXT ||
     pkt->hints.codec == CODEC_ID_SSA )
  {
    if(!m_pSubtitleCodec)
    {
      m_pSubtitleCodec = new COMXOverlayCodecText();
      m_pSubtitleCodec->Open( pkt->hints );
    }
    int result = m_pSubtitleCodec->Decode(pkt->data, pkt->size, pkt->pts, pkt->duration);
    COMXOverlay* overlay;

    std::string strSubtitle = "";

    double pts = pkt->dts != DVD_NOPTS_VALUE ? pkt->dts : pkt->pts;
    double duration = pkt->duration;

    if(result == OC_OVERLAY)
    {

      while((overlay = m_pSubtitleCodec->GetOverlay()) != NULL)
      {
        if(overlay->iPTSStopTime > overlay->iPTSStartTime)
          duration = overlay->iPTSStopTime - overlay->iPTSStartTime;
        else if(pkt->duration != DVD_NOPTS_VALUE)
          duration = pkt->duration;
        else
          duration = 0.0;

        if     (pkt->pts != DVD_NOPTS_VALUE)
          pts = pkt->pts;
        else if(pkt->dts != DVD_NOPTS_VALUE)
          pts = pkt->dts;
        else
          pts = overlay->iPTSStartTime;

        pts -= m_iSubtitleDelay;

        overlay->iPTSStartTime = pts;
        if(duration)
          overlay->iPTSStopTime = pts + duration;
        else
        {
          overlay->iPTSStopTime = 0;
          overlay->replace = true;
        }

        COMXOverlayText::CElement* e = ((COMXOverlayText*)overlay)->m_pHead;
        while (e)
        {
          if (e->IsElementType(COMXOverlayText::ELEMENT_TYPE_TEXT))
          {
            COMXOverlayText::CElementText* t = (COMXOverlayText::CElementText*)e;
            strSubtitle += t->m_text;
              strSubtitle += "\n";
          }
          e = e->pNext;
        }

        m_overlays.push_back(overlay);

        if(strSubtitle.length())
          m_decoder->DecodeText((uint8_t *)strSubtitle.c_str(), strSubtitle.length(), overlay->iPTSStartTime, overlay->iPTSStartTime);
      }
    }

    ret = true;
  }
  else if((unsigned long)m_decoder->GetFreeSpace() > pkt->size)
  {
    if(m_bMpeg)
      m_decoder->Decode(pkt->data, pkt->size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
    else
      m_decoder->Decode(pkt->data, pkt->size, m_pts, m_pts);

    m_av_clock->SetVideoClock(m_pts);

    Output(m_pts);

    ret = true;
  }

  return ret;
}
bool OMXPlayerVideo::Decode(OMXPacket *pkt)
{
  if(!pkt)
    return false;

  if(pkt->hints.codec == AV_CODEC_ID_TEXT ||
     pkt->hints.codec == AV_CODEC_ID_SSA )
  {
    if(!m_pSubtitleCodec)
    {
      m_pSubtitleCodec = new COMXOverlayCodecText();
      m_pSubtitleCodec->Open( pkt->hints );
    }
    int result = m_pSubtitleCodec->Decode(pkt->data, pkt->size, pkt->pts, pkt->duration);
    COMXOverlay* overlay;

    std::string strSubtitle = "";

    double pts = pkt->dts != DVD_NOPTS_VALUE ? pkt->dts : pkt->pts;
    double duration = pkt->duration;

    if(result == OC_OVERLAY)
    {

      while((overlay = m_pSubtitleCodec->GetOverlay()) != NULL)
      {
        if(overlay->iPTSStopTime > overlay->iPTSStartTime)
          duration = overlay->iPTSStopTime - overlay->iPTSStartTime;
        else if(pkt->duration != DVD_NOPTS_VALUE)
          duration = pkt->duration;
        else
          duration = 0.0;

        if     (pkt->pts != DVD_NOPTS_VALUE)
          pts = pkt->pts;
        else if(pkt->dts != DVD_NOPTS_VALUE)
          pts = pkt->dts;
        else
          pts = overlay->iPTSStartTime;

        pts -= m_iSubtitleDelay;

        overlay->iPTSStartTime = pts;
        if(duration)
          overlay->iPTSStopTime = pts + duration;
        else
        {
          overlay->iPTSStopTime = 0;
          overlay->replace = true;
        }

        COMXOverlayText::CElement* e = ((COMXOverlayText*)overlay)->m_pHead;
        while (e)
        {
          if (e->IsElementType(COMXOverlayText::ELEMENT_TYPE_TEXT))
          {
            COMXOverlayText::CElementText* t = (COMXOverlayText::CElementText*)e;
            strSubtitle += t->m_text;
              strSubtitle += "\n";
          }
          e = e->pNext;
        }

        m_overlays.push_back(overlay);

        if(strSubtitle.length())
          m_decoder->DecodeText((uint8_t *)strSubtitle.c_str(), strSubtitle.length(), overlay->iPTSStartTime, overlay->iPTSStartTime);
      }
    }
  }
  else
  {
    // some packed bitstream AVI files set almost all pts values to DVD_NOPTS_VALUE, but have a scattering of real pts values.
    // the valid pts values match the dts values.
    // if a stream has had more than 4 valid pts values in the last 16, the use UNKNOWN, otherwise use dts
    m_history_valid_pts = (m_history_valid_pts << 1) | (pkt->pts != DVD_NOPTS_VALUE);
    double pts = pkt->pts;
    if(pkt->pts == DVD_NOPTS_VALUE && (m_iCurrentPts == DVD_NOPTS_VALUE || count_bits(m_history_valid_pts & 0xffff) < 4))
      pts = pkt->dts;

    if (pts != DVD_NOPTS_VALUE)
      pts += m_iVideoDelay;

    if(pts != DVD_NOPTS_VALUE)
      m_iCurrentPts = pts;

    while((int) m_decoder->GetFreeSpace() < pkt->size)
    {
      OMXClock::OMXSleep(10);
      if(m_flush_requested) return true;
    }

    CLog::Log(LOGINFO, "CDVDPlayerVideo::Decode dts:%.0f pts:%.0f cur:%.0f, size:%d", pkt->dts, pkt->pts, m_iCurrentPts, pkt->size);
    m_decoder->Decode(pkt->data, pkt->size, pts);
  }
  return true;
}