Ejemplo n.º 1
0
double OMXPlayerVideo::NextOverlay(double pts)
{
  double delta_start, delta_stop, min_delta = DVD_NOPTS_VALUE;

  CSingleLock lock(*m_pOverlayContainer);
  VecOverlays* pVecOverlays = m_pOverlayContainer->GetOverlays();
  VecOverlaysIter it = pVecOverlays->begin();

  //Find the minimum time before a subtitle is added or removed
  while (it != pVecOverlays->end())
  {
    CDVDOverlay* pOverlay = *it++;
    if(!pOverlay->bForced && !m_bRenderSubs)
      continue;

    double pts2 = pOverlay->bForced ? pts : pts - m_iSubtitleDelay;

    delta_start = pOverlay->iPTSStartTime - pts2;
    delta_stop = pOverlay->iPTSStopTime - pts2;

    // when currently on screen, we periodically update to allow (limited rate) ASS animation
    if (delta_start <= 0.0 && delta_stop > 0.0 && (min_delta == DVD_NOPTS_VALUE || DVD_MSEC_TO_TIME(100) < min_delta))
      min_delta = DVD_MSEC_TO_TIME(100);

    else if (delta_start > 0.0 && (min_delta == DVD_NOPTS_VALUE || delta_start < min_delta))
      min_delta = delta_start;

    else if (delta_stop > 0.0 && (min_delta == DVD_NOPTS_VALUE || delta_stop < min_delta))
      min_delta = delta_stop;
  }
  return min_delta == DVD_NOPTS_VALUE ? pts+DVD_MSEC_TO_TIME(500) : pts+min_delta;
}
Ejemplo n.º 2
0
int CDVDOverlayCodecFFmpeg::Decode(DemuxPacket *pPacket)
{
  if (!m_pCodecContext || !pPacket)
    return 1;

  int gotsub = 0, len = 0;

  FreeSubtitle(m_Subtitle);

  AVPacket avpkt;
  av_init_packet(&avpkt);
  avpkt.data = pPacket->pData;
  avpkt.size = pPacket->iSize;
  avpkt.pts = pPacket->pts == DVD_NOPTS_VALUE ? AV_NOPTS_VALUE : (int64_t)pPacket->pts;
  avpkt.dts = pPacket->dts == DVD_NOPTS_VALUE ? AV_NOPTS_VALUE : (int64_t)pPacket->dts;

  len = avcodec_decode_subtitle2(m_pCodecContext, &m_Subtitle, &gotsub, &avpkt);

  if (len < 0)
  {
    CLog::Log(LOGERROR, "%s - avcodec_decode_subtitle returned failure", __FUNCTION__);
    Flush();
    return OC_ERROR;
  }

  if (len != avpkt.size)
    CLog::Log(LOGWARNING, "%s - avcodec_decode_subtitle didn't consume the full packet", __FUNCTION__);

  if (!gotsub)
    return OC_BUFFER;

  double pts_offset = 0.0;
 
  if (m_pCodecContext->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && m_Subtitle.format == 0)
  {
    // for pgs subtitles the packet pts of the end_segments are wrong
    // instead use the subtitle pts to calc the offset here
    // see http://git.videolan.org/?p=ffmpeg.git;a=commit;h=2939e258f9d1fff89b3b68536beb931b54611585

    if (m_Subtitle.pts != AV_NOPTS_VALUE && pPacket->pts != DVD_NOPTS_VALUE)
    {
      pts_offset = m_Subtitle.pts - pPacket->pts ;
    }
  }

  m_StartTime   = DVD_MSEC_TO_TIME(m_Subtitle.start_display_time);
  m_StopTime    = DVD_MSEC_TO_TIME(m_Subtitle.end_display_time);

  //adapt start and stop time to our packet pts
  bool dummy = false;
  CDVDOverlayCodec::GetAbsoluteTimes(m_StartTime, m_StopTime, pPacket, dummy, pts_offset);
  m_SubtitleIndex = 0;

  return OC_OVERLAY;
}
Ejemplo n.º 3
0
bool CDVDClock::Update(double clock, double absolute, double limit, const char* log)
{
  CExclusiveLock lock(m_critSection);
  double was_absolute = SystemToAbsolute(m_startClock);
  double was_clock    = m_iDisc + absolute - was_absolute;
  lock.Leave();

  double error = std::abs(clock - was_clock);

  // skip minor updates while speed adjust is active
  // -> adjusting buffer levels
  if (m_speedAdjust != 0 && error < DVD_MSEC_TO_TIME(100))
  {
    return false;
  }
  else if (error > limit)
  {
    Discontinuity(clock, absolute);

    CLog::Log(LOGDEBUG, "CDVDClock::Discontinuity - %s - was:%f, should be:%f, error:%f"
                      , log
                      , was_clock
                      , clock
                      , clock - was_clock);
    return true;
  }
  else
    return false;
}
Ejemplo n.º 4
0
double OMXReader::NormalizeFrameduration(double frameduration)
{
	//if the duration is within 20 microseconds of a common duration, use that
	const double durations[] = {DVD_TIME_BASE * 1.001 / 24.0, DVD_TIME_BASE / 24.0, DVD_TIME_BASE / 25.0,
	                            DVD_TIME_BASE * 1.001 / 30.0, DVD_TIME_BASE / 30.0, DVD_TIME_BASE / 50.0,
	                            DVD_TIME_BASE * 1.001 / 60.0, DVD_TIME_BASE / 60.0
	                           };

	double lowestdiff = DVD_TIME_BASE;
	int    selected   = -1;
	for (size_t i = 0; i < sizeof(durations) / sizeof(durations[0]); i++)
	{
		double diff = fabs(frameduration - durations[i]);
		if (diff < DVD_MSEC_TO_TIME(0.02) && diff < lowestdiff)
		{
			selected = i;
			lowestdiff = diff;
		}
	}

	if (selected != -1)
	{
		return durations[selected];
	}
	else
	{
		return frameduration;
	}
}
Ejemplo n.º 5
0
void OMXPlayerVideo::Output(double pts, bool bDropPacket)
{
  if (!g_renderManager.IsStarted()) {
    CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__);
    return;
  }

  if (CThread::m_bStop)
    return;

  // we aim to submit subtitles 100ms early
  const double preroll = DVD_MSEC_TO_TIME(100);
  double media_pts = m_av_clock->OMXMediaTime();

  if (m_nextOverlay != DVD_NOPTS_VALUE && media_pts + preroll <= m_nextOverlay)
    return;

  int buffer = g_renderManager.WaitForBuffer(CThread::m_bStop);
  if (buffer < 0)
    return;

  double subtitle_pts = m_nextOverlay;
  double time = subtitle_pts != DVD_NOPTS_VALUE ? subtitle_pts - media_pts : 0.0;

  if (m_nextOverlay != DVD_NOPTS_VALUE)
    media_pts = m_nextOverlay;

  m_nextOverlay = NextOverlay(media_pts);

  ProcessOverlays(media_pts);

  time += m_av_clock->GetAbsoluteClock();
  g_renderManager.FlipPage(CThread::m_bStop, time/DVD_TIME_BASE);
}
Ejemplo n.º 6
0
double CDVDCodecUtils::NormalizeFrameduration(double frameduration, bool *match)
{
  //if the duration is within 20 microseconds of a common duration, use that
  const double durations[] = {DVD_TIME_BASE * 1.001 / 24.0, DVD_TIME_BASE / 24.0, DVD_TIME_BASE / 25.0,
                              DVD_TIME_BASE * 1.001 / 30.0, DVD_TIME_BASE / 30.0, DVD_TIME_BASE / 50.0,
                              DVD_TIME_BASE * 1.001 / 60.0, DVD_TIME_BASE / 60.0};

  double lowestdiff = DVD_TIME_BASE;
  int    selected   = -1;
  for (size_t i = 0; i < ARRAY_SIZE(durations); i++)
  {
    double diff = fabs(frameduration - durations[i]);
    if (diff < DVD_MSEC_TO_TIME(0.02) && diff < lowestdiff)
    {
      selected = i;
      lowestdiff = diff;
    }
  }

  if (selected != -1)
  {
    if (match)
      *match = true;
    return durations[selected];
  }
  else
  {
    if (match)
      *match = false;
    return frameduration;
  }
}
Ejemplo n.º 7
0
double CDVDClock::ErrorAdjust(double error, const char* log)
{
  CSingleLock lock(m_critSection);

  double clock, absolute, adjustment;
  clock = GetClock(absolute);

  // skip minor updates while speed adjust is active
  // -> adjusting buffer levels
  if (m_speedAdjust != 0 && error < DVD_MSEC_TO_TIME(100))
  {
    return 0;
  }

  adjustment = error;

  if (m_vSyncAdjust != 0)
  {
    if (error > 0.5 * m_frameTime)
      adjustment = m_frameTime;
    else if (error < -0.5 * m_frameTime)
      adjustment = -m_frameTime;
    else
      adjustment = 0;
  }

  if (adjustment == 0)
    return 0;

  Discontinuity(clock+adjustment, absolute);

  CLog::Log(LOGDEBUG, "CDVDClock::ErrorAdjust - %s - error:%f, adjusted:%f",
                      log, error, adjustment);
  return adjustment;
}
Ejemplo n.º 8
0
bool OMXReader::SeekTime(int time, bool backwords, double *startpts, bool doLoopOnFail)
{
    if(time < 0)
        time = 0;
    
    if(!avFormatContext)
        return false;
    
    if(fileObject && !fileObject->IoControl(IOCTRL_SEEK_POSSIBLE, NULL))
    {
        ofLog(OF_LOG_VERBOSE, "%s - input stream reports it is not seekable", __FUNCTION__);
        return false;
    }
    
    lock();
    
    //FlushRead();
    
    if(avioContext)
    {
        avioContext->buf_ptr = avioContext->buf_end;
    }
    
    int64_t seek_pts = (int64_t)time * (AV_TIME_BASE / 1000);
    if (avFormatContext->start_time != (int64_t)AV_NOPTS_VALUE)
    {
        seek_pts += avFormatContext->start_time;
    };
    
    
    int ret = av_seek_frame(avFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0);
    
    if(ret >= 0)
    {
        updateCurrentPTS();
    }else {
        //ofLogVerbose(__func__) << "av_seek_frame returned >= 0, no updateCurrentPTS" << ret;
        fileObject->rewindFile();
    }
    
    
    // in this case the start time is requested time
    if(startpts)
    {
        *startpts = DVD_MSEC_TO_TIME(time);
    }
    
    isEOF = false;
    if (fileObject && fileObject->getIsEOF() && ret <= 0)
    {
        isEOF = true;
        ret = 0;
    }
    
    
    unlock();
    
    return (ret >= 0);
}
Ejemplo n.º 9
0
bool OMXReader::SeekTime(int time, bool backwords, double *startpts)
{
  if(time < 0)
    time = 0;

  if(!m_pFormatContext)
    return false;

  if(m_pFile && !m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL))
  {
    CLog::Log(LOGDEBUG, "%s - input stream reports it is not seekable", __FUNCTION__);
    return false;
  }

  Lock();

  //FlushRead();

  if(m_ioContext)
    m_ioContext->buf_ptr = m_ioContext->buf_end;

  int64_t seek_pts = (int64_t)time * (AV_TIME_BASE / 1000);
  if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE)
    seek_pts += m_pFormatContext->start_time;


  int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0);

  if(ret >= 0)
  {
    UpdateCurrentPTS();
  }
  else {
    //m_pFile->rewindFile();
    m_pFile->Seek(0);
    UpdateCurrentPTS();
    wasFileRewound = true;
  }

  // in this case the start time is requested time
  if(startpts)
    *startpts = DVD_MSEC_TO_TIME(time);

  // demuxer will return failure, if you seek to eof
  m_eof = false;
  if (m_pFile && m_pFile->IsEOF() && ret <= 0)
  {
    m_eof = true;
    ret = 0;
  }

  CLog::Log(LOGDEBUG, "OMXReader::SeekTime(%d) - seek ended up on time %d",time,(int)(m_iCurrentPts / DVD_TIME_BASE * 1000));

  UnLock();

  return (ret >= 0);
}
Ejemplo n.º 10
0
bool OMXReader::SeekTime(int64_t seek_ms, int seek_flags, double *startpts)
{
  if(seek_ms < 0)
    seek_ms = 0;

  if(!m_pFile || !m_pFormatContext)
    return false;

  if(!m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL))
    return false;

  Lock();

  //FlushRead();

  if(m_ioContext)
    m_ioContext->buf_ptr = m_ioContext->buf_end;

  int64_t seek_pts = (int64_t)seek_ms * (AV_TIME_BASE / 1000);
  if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE)
    seek_pts += m_pFormatContext->start_time;

  /* seek behind eof */
  if((seek_pts / AV_TIME_BASE) > (GetStreamLength()  / 1000))
  {
    m_eof = true;
    UnLock();
    return true;
  }

  int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, seek_flags ? AVSEEK_FLAG_BACKWARD : 0);

  if(ret >= 0)
  {
    UpdateCurrentPTS();
    m_eof = false;
  }

  if(m_iCurrentPts == DVD_NOPTS_VALUE)
  {
    CLog::Log(LOGDEBUG, "OMXReader::SeekTime - unknown position after seek");
  }
  else
  {
    CLog::Log(LOGDEBUG, "OMXReader::SeekTime - seek ended up on time %d",(int)(m_iCurrentPts / DVD_TIME_BASE * 1000));
  }

  if(startpts)
    *startpts = DVD_MSEC_TO_TIME(seek_ms);

  UnLock();

  return (ret >= 0);
}
Ejemplo n.º 11
0
bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
{
  if(time < 0)
    time = 0;

  if (m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
  {
    CLog::Log(LOGDEBUG, "%s - seeking using navigator", __FUNCTION__);
    if (((CDVDInputStreamNavigator*)m_pInput)->SeekTime(time))
    {
      // since seek happens behind demuxers back, we have to reset it
      // this won't be a problem if we setup ffmpeg properly later
      Reset();

      // todo, calculate starting pts in this case
      return true;
    }
    return false;
  }

  if(!m_pInput->Seek(0, SEEK_POSSIBLE) 
  && !m_pInput->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
  {
    CLog::Log(LOGDEBUG, "%s - input stream reports it is not seekable", __FUNCTION__);
    return false;
  }

  __int64 seek_pts = (__int64)time * (AV_TIME_BASE / 1000);
  if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE)
    seek_pts += m_pFormatContext->start_time;

  Lock();
  int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0);

  if(ret >= 0)
    UpdateCurrentPTS();
  Unlock();

  if(m_iCurrentPts == DVD_NOPTS_VALUE)
    CLog::Log(LOGDEBUG, "%s - unknown position after seek", __FUNCTION__);
  else
    CLog::Log(LOGDEBUG, "%s - seek ended up on time %d", __FUNCTION__, (int)(m_iCurrentPts / DVD_TIME_BASE * 1000));

  // in this case the start time is requested time
  if(startpts)
    *startpts = DVD_MSEC_TO_TIME(time);

  // demuxer will return failure, if you seek to eof
  if (m_pInput->IsEOF() && ret <= 0)
    return true;

  return (ret >= 0);
}
Ejemplo n.º 12
0
bool CDVDDemuxVobsub::SeekTime(int time, bool backwords, double* startpts)
{
  double pts = DVD_MSEC_TO_TIME(time);
  m_Timestamp = m_Timestamps.begin();
  for (;m_Timestamp != m_Timestamps.end();++m_Timestamp)
  {
    if(m_Timestamp->pts > pts)
      break;
  }
  for (unsigned i=0;i<m_Streams.size() && m_Timestamps.begin() != m_Timestamp;i++)
  {
    --m_Timestamp;
  }
  return true;
}
Ejemplo n.º 13
0
bool CDVDPlayerAudio::OutputPacket(DVDAudioFrame &audioframe)
{
  double syncerror = m_dvdAudio.GetSyncError();

  if (m_synctype == SYNC_DISCON && fabs(syncerror) > DVD_MSEC_TO_TIME(10))
  {
    double correction = m_pClock->ErrorAdjust(syncerror, "CDVDPlayerAudio::OutputPacket");
    if (correction != 0)
    {
      m_dvdAudio.SetSyncErrorCorrection(-correction);
    }
  }
  m_dvdAudio.AddPackets(audioframe);

  return true;
}
Ejemplo n.º 14
0
double OMXClock::OMXMediaTime(bool lock /* = true */)
{
  double pts = 0.0;
  if(m_omx_clock.GetComponent() == NULL)
    return 0;

  double now = GetAbsoluteClock();
  if (now - m_last_media_time_read > DVD_MSEC_TO_TIME(100) || m_last_media_time == 0.0)
  {
    if(lock)
      Lock();

    OMX_ERRORTYPE omx_err = OMX_ErrorNone;

    OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
    OMX_INIT_STRUCTURE(timeStamp);
    timeStamp.nPortIndex = m_omx_clock.GetInputPort();

    omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentMediaTime, &timeStamp);
    if(omx_err != OMX_ErrorNone)
    {
      LOG_ERROR << "OMXClock::MediaTime error getting OMX_IndexConfigTimeCurrentMediaTime";
      if(lock)
        UnLock();
      return 0;
    }

    pts = FromOMXTime(timeStamp.nTimestamp);
    //CLog::Log(LOGINFO, "OMXClock::MediaTime %.2f (%.2f, %.2f)", pts, m_last_media_time, now - m_last_media_time_read);
    m_last_media_time = pts;
    m_last_media_time_read = now;

    if(lock)
      UnLock();
  }
  else
  {
    double speed = m_pause ? 0.0 : (double)m_omx_speed / DVD_PLAYSPEED_NORMAL;
    pts = m_last_media_time + (now - m_last_media_time_read) * speed;
    //CLog::Log(LOGINFO, "OMXClock::MediaTime cached %.2f (%.2f, %.2f)", pts, m_last_media_time, now - m_last_media_time_read);
  }
  return pts;
}
Ejemplo n.º 15
0
bool CVideoPlayerAudio::OutputPacket(DVDAudioFrame &audioframe)
{
  double syncerror = m_dvdAudio.GetSyncError();

  if (m_synctype == SYNC_DISCON)
  {
    double limit, error;
    limit = DVD_MSEC_TO_TIME(10);
    error = syncerror;

    double absolute;
    double clock = m_pClock->GetClock(absolute);
    if (m_pClock->Update(clock + error, absolute, limit - 0.001, "CVideoPlayerAudio::OutputPacket"))
    {
      m_dvdAudio.SetSyncErrorCorrection(-error);
    }
  }
  m_dvdAudio.AddPackets(audioframe);

  return true;
}
Ejemplo n.º 16
0
double CDVDClock::ErrorAdjust(double error, const char* log)
{
  CSingleLock lock(m_critSection);

  double clock, absolute, adjustment;
  clock = GetClock(absolute);

  // skip minor updates while speed adjust is active
  // -> adjusting buffer levels
  if (m_speedAdjust != 0 && error < DVD_MSEC_TO_TIME(100))
  {
    return 0;
  }

  adjustment = error;

  if (m_vSyncAdjust != 0)
  {
    // Audio ahead is more noticeable then audio behind video.
    // Correct if aufio is more than 20ms ahead or more then
    // 27ms behind. In a worst case scenario we switch from
    // 20ms ahead to 21ms behind (for fps of 23.976)
    if (error > 0.02 * DVD_TIME_BASE)
      adjustment = m_frameTime;
    else if (error < -0.027 * DVD_TIME_BASE)
      adjustment = -m_frameTime;
    else
      adjustment = 0;
  }

  if (adjustment == 0)
    return 0;

  Discontinuity(clock+adjustment, absolute);

  CLog::Log(LOGDEBUG, "CDVDClock::ErrorAdjust - %s - error:%f, adjusted:%f",
                      log, error, adjustment);
  return adjustment;
}
Ejemplo n.º 17
0
void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket)
{
  if (!g_renderManager.IsStarted()) {
    CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__);
    return;
  }

  // calculate the time we need to delay this picture before displaying
  double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;

  iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock
  iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison
  iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
  iFrameDuration = (double)DVD_TIME_BASE / m_fFrameRate; //pPacket->duration;

  // correct sleep times based on speed
  if(m_speed)
  {
    iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
    iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed);
    iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed);
  }
  else
  {
    iClockSleep = 0;
    iFrameSleep = 0;
  }

  // dropping to a very low framerate is not correct (it should not happen at all)
  iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500));
  iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500));

  if( m_stalled )
    iSleepTime = iFrameSleep;
  else
    iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;

  // present the current pts of this frame to user, and include the actual
  // presentation delay, to allow him to adjust for it
  if( m_stalled )
    m_iCurrentPts = DVD_NOPTS_VALUE;
  else
    m_iCurrentPts = pts - max(0.0, iSleepTime);

  // timestamp when we think next picture should be displayed based on current duration
  m_FlipTimeStamp  = iCurrentClock;
  m_FlipTimeStamp += max(0.0, iSleepTime);
  m_FlipTimeStamp += iFrameDuration;

  if( m_speed < 0 )
  {
    if( iClockSleep < -DVD_MSEC_TO_TIME(200))
      return;
  }

  if(bDropPacket)
    return;

#if 0
  if( m_speed != DVD_PLAYSPEED_NORMAL)
  {
    // calculate frame dropping pattern to render at this speed
    // we do that by deciding if this or next frame is closest
    // to the flip timestamp
    double current   = fabs(m_dropbase -  m_droptime);
    double next      = fabs(m_dropbase - (m_droptime + iFrameDuration));
    double frametime = (double)DVD_TIME_BASE / m_fFrameRate;

    m_droptime += iFrameDuration;
#ifndef PROFILE
    if( next < current /*&& !(pPicture->iFlags & DVP_FLAG_NOSKIP) */)
      return /*result | EOS_DROPPED*/;
#endif

    while(!m_bStop && m_dropbase < m_droptime)             m_dropbase += frametime;
    while(!m_bStop && m_dropbase - frametime > m_droptime) m_dropbase -= frametime;
  }
  else
  {
    m_droptime = 0.0f;
    m_dropbase = 0.0f;
  }
#else
  m_droptime = 0.0f;
  m_dropbase = 0.0f;
#endif

  // DVDPlayer sleeps until m_iSleepEndTime here before calling FlipPage.
  // Video playback in asynchronous in OMXPlayer, so we don't want to do that here, as it prevents the video fifo from being kept full.
  // So, we keep track of when FlipPage would have been called on DVDPlayer and return early if it is not time.
  // m_iSleepEndTime == DVD_NOPTS_VALUE means we are not waiting to call FlipPage, otherwise it is the time we want to call FlipPage
  if (m_iSleepEndTime == DVD_NOPTS_VALUE) {
    m_iSleepEndTime = iCurrentClock + iSleepTime;
  }

  if (!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < m_iSleepEndTime + DVD_MSEC_TO_TIME(500))
    return;

  double pts_media = m_av_clock->OMXMediaTime(false, false);
  ProcessOverlays(iGroupId, pts_media);

  g_renderManager.FlipPage(CThread::m_bStop, m_iSleepEndTime / DVD_TIME_BASE, -1, FS_NONE);

  m_iSleepEndTime = DVD_NOPTS_VALUE;

  //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime));
}
Ejemplo n.º 18
0
CDVDOverlay* CDVDOverlayCodecFFmpeg::GetOverlay()
{
  if(m_SubtitleIndex<0)
    return NULL;

  if(m_Subtitle.num_rects == 0 && m_SubtitleIndex == 0)
  {
    // we must add an empty overlay to replace the previous one
    CDVDOverlay* o = new CDVDOverlay(DVDOVERLAY_TYPE_NONE);
    o->iPTSStartTime = 0;
    o->iPTSStopTime  = 0;
    o->replace  = true;
    m_SubtitleIndex++;
    return o;
  }

  if(m_Subtitle.format == 0)
  {
    if(m_SubtitleIndex >= (int)m_Subtitle.num_rects)
      return NULL;

#if LIBAVCODEC_VERSION_INT >= (52<<10)
    if(m_Subtitle.rects[m_SubtitleIndex] == NULL)
      return NULL;
    AVSubtitleRect& rect = *m_Subtitle.rects[m_SubtitleIndex];
#else
    AVSubtitleRect& rect = m_Subtitle.rects[m_SubtitleIndex];
#endif

    CDVDOverlayImage* overlay = new CDVDOverlayImage();

    overlay->iPTSStartTime = DVD_MSEC_TO_TIME(m_Subtitle.start_display_time);
    overlay->iPTSStopTime  = DVD_MSEC_TO_TIME(m_Subtitle.end_display_time);
    overlay->replace  = true;
    overlay->linesize = rect.w;
    overlay->data     = (BYTE*)malloc(rect.w * rect.h);
    overlay->palette  = (uint32_t*)malloc(rect.nb_colors*4);
    overlay->palette_colors = rect.nb_colors;
    overlay->x        = rect.x;
    overlay->y        = rect.y;
    overlay->width    = rect.w;
    overlay->height   = rect.h;

    int right  = overlay->x + overlay->width;
    int bottom = overlay->y + overlay->height;

    if(m_height == 0 && m_pCodecContext->height)
      m_height = m_pCodecContext->height;
    if(m_width  == 0 && m_pCodecContext->width)
      m_width  = m_pCodecContext->width;

    if(bottom > m_height)
    {
      if     (bottom <= 480)
        m_height      = 480;
      else if(bottom <= 576)
        m_height      = 576;
      else if(bottom <= 720)
        m_height      = 720;
      else if(bottom <= 1080)
        m_height      = 1080;
      else
        m_height      = bottom;
    }
    if(right > m_width)
    {
      if     (right <= 720)
        m_width      = 720;
      else if(right <= 1024)
        m_width      = 1024;
      else if(right <= 1280)
        m_width      = 1280;
      else if(right <= 1920)
        m_width      = 1920;
      else
        m_width      = right;
    }

    overlay->source_width  = m_width;
    overlay->source_height = m_height;

#if LIBAVCODEC_VERSION_INT >= (52<<10)
    BYTE* s = rect.pict.data[0];
    BYTE* t = overlay->data;
    for(int i=0;i<rect.h;i++)
    {
      memcpy(t, s, rect.w);
      s += rect.pict.linesize[0];
      t += overlay->linesize;
    }

    for(int i=0;i<rect.nb_colors;i++)
      overlay->palette[i] = Endian_SwapLE32(((uint32_t *)rect.pict.data[1])[i]);

    m_dllAvUtil.av_free(rect.pict.data[0]);
    m_dllAvUtil.av_free(rect.pict.data[1]);
    m_dllAvUtil.av_freep(&m_Subtitle.rects[m_SubtitleIndex]);
#else
    BYTE* s = rect.bitmap;
    BYTE* t = overlay->data;
    for(int i=0;i<rect.h;i++)
    {
      memcpy(t, s, rect.w);
      s += rect.linesize;
      t += overlay->linesize;
    }

    memcpy(overlay->palette, rect.rgba_palette, rect.nb_colors*4);

    m_dllAvUtil.av_freep(&rect.bitmap);
    m_dllAvUtil.av_freep(&rect.rgba_palette);
#endif
    m_SubtitleIndex++;

    return overlay;
  }

  return NULL;
}
Ejemplo n.º 19
0
bool OMXDoProcessing(struct SOmxPlayerState &m_OmxPlayerState, int m_playSpeed, IDVDStreamPlayerVideo *m_dvdPlayerVideo, IDVDStreamPlayerAudio *m_dvdPlayerAudio,
                     CCurrentStream m_CurrentAudio, CCurrentStream m_CurrentVideo, bool m_HasVideo, bool m_HasAudio)
{
  bool reopen_stream = false;
  double now = CDVDClock::GetAbsoluteClock();
  if (m_OmxPlayerState.last_check_time == 0.0 || m_OmxPlayerState.last_check_time + DVD_MSEC_TO_TIME(20) <= now)
  {
    m_OmxPlayerState.last_check_time = now;
    m_OmxPlayerState.stamp = m_OmxPlayerState.av_clock.OMXMediaTime();
    const bool m_Pause = m_playSpeed == DVD_PLAYSPEED_PAUSE;
    const bool not_accepts_data = (!m_dvdPlayerAudio->AcceptsData() && m_HasAudio) ||
        (!m_dvdPlayerVideo->AcceptsData() && m_HasVideo >= 0);
    /* when the video/audio fifos are low, we pause clock, when high we resume */
    double audio_pts = floor(m_dvdPlayerAudio->GetCurrentPts());
    double video_pts = floor(m_dvdPlayerVideo->GetCurrentPts());

    float audio_fifo = audio_pts / DVD_TIME_BASE - m_OmxPlayerState.stamp * 1e-6;
    float video_fifo = video_pts / DVD_TIME_BASE - m_OmxPlayerState.stamp * 1e-6;
    float threshold = 0.1f;
    bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false;

    if (m_OmxPlayerState.interlace_method == VS_INTERLACEMETHOD_MAX)
      m_OmxPlayerState.interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);

    // if deinterlace setting has changed, we should close and open video
    if (m_OmxPlayerState.current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode ||
       (m_OmxPlayerState.current_deinterlace != VS_DEINTERLACEMODE_OFF &&
        m_OmxPlayerState.interlace_method != g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod)))
    {
      CLog::Log(LOGNOTICE, "%s - Reopen stream due to interlace change (%d,%d,%d,%d)", __FUNCTION__,
        m_OmxPlayerState.current_deinterlace, CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode,
        m_OmxPlayerState.interlace_method, g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod));

      m_OmxPlayerState.current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
      m_OmxPlayerState.interlace_method    = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
      reopen_stream = true;
    }

    m_OmxPlayerState.video_fifo = (int)(100.0*(m_dvdPlayerVideo->GetDecoderBufferSize()-m_dvdPlayerVideo->GetDecoderFreeSpace())/m_dvdPlayerVideo->GetDecoderBufferSize());
    m_OmxPlayerState.audio_fifo = (int)(100.0*audio_fifo/m_dvdPlayerAudio->GetCacheTotal());

    #ifdef _DEBUG
    static unsigned count;
    if ((count++ & 7) == 0)
    {
      char response[80];
      if (m_dvdPlayerVideo->GetDecoderBufferSize() && m_dvdPlayerAudio->GetCacheTotal())
        vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d",
            m_OmxPlayerState.video_fifo,
            (int)(100.0*video_fifo/m_dvdPlayerAudio->GetCacheTotal()),
            0, 100);
      if (m_dvdPlayerAudio->GetCacheTotal())
        vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d",
            m_OmxPlayerState.audio_fifo,
            (int)(100.0*m_dvdPlayerAudio->GetDelay()/m_dvdPlayerAudio->GetCacheTotal()),
            0, 100);
      vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d",
            m_dvdPlayerVideo->GetLevel(), 0, 0, 100);
      vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d",
            m_dvdPlayerAudio->GetLevel(), 0, 0, 100);
    }
    #endif
    if (audio_pts != DVD_NOPTS_VALUE)
    {
      audio_fifo_low = m_HasAudio && audio_fifo < threshold;
      audio_fifo_high = audio_pts != DVD_NOPTS_VALUE && audio_fifo >= m_OmxPlayerState.threshold;
    }
    if (video_pts != DVD_NOPTS_VALUE)
    {
      video_fifo_low = m_HasVideo && video_fifo < threshold;
      video_fifo_high = video_pts != DVD_NOPTS_VALUE && video_fifo >= m_OmxPlayerState.threshold;
    }
    if (!m_HasAudio && m_HasVideo)
      audio_fifo_high = true;
    if (!m_HasVideo && m_HasAudio)
      video_fifo_high = true;

    #ifdef _DEBUG
    CLog::Log(LOGDEBUG, "%s::%s M:%.6f-%.6f (A:%.6f V:%.6f) PEF:%d%d%d S:%.2f A:%.2f V:%.2f/T:%.2f (A:%d%d V:%d%d) A:%d%% V:%d%% (%.2f,%.2f)", "CDVDPlayer", __FUNCTION__,
      m_OmxPlayerState.stamp*1e-6, m_OmxPlayerState.av_clock.OMXClockAdjustment()*1e-6, audio_pts*1e-6, video_pts*1e-6,
      m_OmxPlayerState.av_clock.OMXIsPaused(), m_OmxPlayerState.bOmxSentEOFs, not_accepts_data, m_playSpeed * (1.0f/DVD_PLAYSPEED_NORMAL),
      audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_OmxPlayerState.threshold,
      audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high,
      m_dvdPlayerAudio->GetLevel(), m_dvdPlayerVideo->GetLevel(), m_dvdPlayerAudio->GetDelay(), (float)m_dvdPlayerAudio->GetCacheTotal());
    #endif

    if(!m_Pause && (m_OmxPlayerState.bOmxSentEOFs || not_accepts_data || (audio_fifo_high && video_fifo_high) || m_playSpeed != DVD_PLAYSPEED_NORMAL))
    {
      if (m_OmxPlayerState.av_clock.OMXIsPaused())
      {
        CLog::Log(LOGDEBUG, "%s::%s Resume %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f", "CDVDPlayer", __FUNCTION__, audio_fifo, video_fifo,
          audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, m_OmxPlayerState.bOmxSentEOFs, not_accepts_data, m_OmxPlayerState.threshold);
        m_OmxPlayerState.av_clock.OMXResume();
      }
    }
    else if ((m_Pause || audio_fifo_low || video_fifo_low) && m_playSpeed == DVD_PLAYSPEED_NORMAL)
    {
      if (!m_OmxPlayerState.av_clock.OMXIsPaused())
      {
        if (!m_Pause)
          m_OmxPlayerState.threshold = std::min(2.0f*m_OmxPlayerState.threshold, 16.0f);
        CLog::Log(LOGDEBUG, "%s::%s Pause %.2f,%.2f (A:%d%d V:%d%d) EOF:%d FULL:%d T:%.2f", "CDVDPlayer", __FUNCTION__, audio_fifo, video_fifo,
          audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, m_OmxPlayerState.bOmxSentEOFs, not_accepts_data, m_OmxPlayerState.threshold);
        m_OmxPlayerState.av_clock.OMXPause();
      }
    }
  }
  return reopen_stream;
}
Ejemplo n.º 20
0
void CDVDPlayerAudio::HandleSyncError(double duration)
{
    double absolute;
    double clock = m_pClock->GetClock(absolute);
    double error = m_dvdAudio.GetPlayingPts() - clock;
    double threshold1 = DVD_MSEC_TO_TIME(100);
    double threshold2 = DVD_MSEC_TO_TIME(50);

    // adjust thresholds
    // some codecs like flac have a very large frame length
    if (threshold1 < 1.5 * duration)
        threshold1 = 1.5 *  duration;
    if (threshold2 < duration)
        threshold2 = duration;

    // as long as we are in sync mode, don't calculate the average
    // error because drop/dupe changes the value
    if (m_syncclock && fabs(error) > threshold1)
    {
        m_errors.Flush();
        m_integral = 0.0;
        m_resampleratio = 0.0;
        return;
    }

    // inertia of resampling
    if (m_synctype == SYNC_RESAMPLE)
        threshold1 *= 2;

    m_errors.Add(error);

    // check if measured error for 2 seconds
    // when moving from big erros and we are still above threshold2, calculate errors every
    // 500ms in order to get first resample ratio early. If we don't adjust rr early, error
    // may get above threshold1 again. Too small values for interval result in worse average errors

    if (!m_errors.Get(m_error, m_syncclock ? 100 : 2000))
        return;

    if (fabs(m_error) > threshold1)
    {
        m_syncclock = true;
        m_errors.Flush(100);
        m_integral = 0.0;
        m_resampleratio = 0.0;
        CLog::Log(LOGDEBUG,"CDVDPlayerAudio::HandleSyncError - average error %f above threshold of %f",
                  m_error, threshold1);
        return;
    }
    else if (m_syncclock && fabs(m_error) < threshold2)
    {
        m_syncclock = false;
        // we are about to get stable, increase interval
        m_errors.Flush(1000);
        m_integral = 0.0;
        CLog::Log(LOGDEBUG,"CDVDPlayerAudio::HandleSyncError - average error %f below threshold of %f",
                  m_error, threshold2);
    }

    if (m_synctype == SYNC_DISCON)
    {
        double limit, error;
        if (g_VideoReferenceClock.GetRefreshRate(&limit) > 0)
        {
            //when the videoreferenceclock is running, the discontinuity limit is one vblank period
            limit *= DVD_TIME_BASE;

            //make error a multiple of limit, rounded towards zero,
            //so it won't interfere with the sync methods in CXBMCRenderManager::WaitPresentTime
            if (m_error > 0.0)
                error = limit * floor(m_error / limit);
            else
                error = limit * ceil(m_error / limit);
        }
        else
        {
            limit = DVD_MSEC_TO_TIME(10);
            error = m_error;
        }

        m_pClock->Update(clock+error, absolute, limit - 0.001, "CDVDPlayerAudio::HandleSyncError2");
    }
    else if (m_synctype == SYNC_RESAMPLE)
    {
        //reset the integral on big errors, failsafe
        if (fabs(m_error) > DVD_TIME_BASE)
            m_integral = 0;
        else if (fabs(m_error) > DVD_MSEC_TO_TIME(5))
            m_integral += m_error / DVD_TIME_BASE / INTEGRAL;

        double proportional = 0.0;

        //on big errors use more proportional
        if (fabs(m_error / DVD_TIME_BASE) > 0.0)
        {
            double proportionaldiv = PROPORTIONAL * (PROPREF / fabs(m_error / DVD_TIME_BASE));
            if (proportionaldiv < PROPDIVMIN)
                proportionaldiv = PROPDIVMIN;
            else if (proportionaldiv > PROPDIVMAX)
                proportionaldiv = PROPDIVMAX;

            proportional = m_error / DVD_TIME_BASE / proportionaldiv;
        }
        m_resampleratio = 1.0 / m_pClock->GetClockSpeed() + proportional + m_integral;
    }
}
Ejemplo n.º 21
0
void OMXPlayerVideo::Output(double pts)
{
  if(m_syncclock)
  {
    double delay = m_FlipTimeStamp - m_av_clock->GetAbsoluteClock();
    if( delay > m_frametime ) delay = m_frametime;
    else if( delay < 0 )    delay = 0;

    //printf("OMXPlayerVideo - GENERAL_RESYNC(%f, 1) delay %f\n", pts, m_FlipTimeStamp);
    m_av_clock->Discontinuity(pts - delay);
    m_syncclock = false;
  }

  double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;
  iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock
  iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison
  iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
  iFrameDuration = m_frametime;

  // correct sleep times based on speed
  if(m_speed)
  {
    iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
    iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed);
    iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed);
  }
  else
  {
    iClockSleep = 0;
    iFrameSleep = 0;
  }
  // dropping to a very low framerate is not correct (it should not happen at all)
  iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500));
  iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500));

  bool m_stalled = false;
  int m_autosync = 1;
  if( m_stalled )
    iSleepTime = iFrameSleep;
  else
    iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;

  // present the current pts of this frame to user, and include the actual
  // presentation delay, to allow him to adjust for it
  if( m_stalled )
    m_iCurrentPts = DVD_NOPTS_VALUE;
  else
    m_iCurrentPts = pts - max(0.0, iSleepTime);

  m_av_clock->SetPTS(m_iCurrentPts);

  // timestamp when we think next picture should be displayed based on current duration
  m_FlipTimeStamp  = iCurrentClock;
  m_FlipTimeStamp += max(0.0, iSleepTime);
  m_FlipTimeStamp += iFrameDuration;

  while(m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) )
  {
    OMXClock::OMXSleep(10);
  }

  /*
  printf("iPlayingClock %f iCurrentClock %f iClockSleep %f iFrameSleep %f iFrameDuration %f WaitAbsolut %f m_FlipTimeStamp %f pts %f\n", 
      iPlayingClock / DVD_TIME_BASE, iCurrentClock  / DVD_TIME_BASE,
      iClockSleep / DVD_TIME_BASE, iFrameSleep / DVD_TIME_BASE,
      iFrameDuration / DVD_TIME_BASE, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, m_FlipTimeStamp / DVD_TIME_BASE, 
      pts / DVD_TIME_BASE);
  */

  //g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField);

  m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime));

  // guess next frame pts. iDuration is always valid
  if (m_speed != 0)
    m_pts += m_frametime * m_speed / abs(m_speed);
}
Ejemplo n.º 22
0
bool CDVDPlayerAudio::OutputPacket(DVDAudioFrame &audioframe)
{
    if (m_syncclock)
    {
        double absolute;
        double clock = m_pClock->GetClock(absolute);
        double error = m_dvdAudio.GetPlayingPts() - clock;
        m_dvdAudio.SetResampleRatio(1.0);

        // sync audio by skipping or dropping frames if we are above or
        // below a given threshold. the constants are aligned with known
        // durations: DTS = 11ms, AC3 = 32ms
        // during this stage audio is muted
        if (error > DVD_MSEC_TO_TIME(10))
        {
            if (AE_IS_RAW_RAW(audioframe.data_format))
            {
                double correction = int(std::min(DVD_MSEC_TO_TIME(100), error) / audioframe.duration) * audioframe.duration;

                if (correction > 0)
                {
                    // Force clock sync to audio
                    CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket forcing clock sync for passthrough - dup error(%f), clock(%f), correction(%f)", error, clock, correction);
                    m_pClock->Update(clock+correction, absolute, 0.0, "CDVDPlayerAudio::OutputPacket");
                }
                m_dvdAudio.AddPackets(audioframe);
            }
            else
            {
                unsigned int nb_frames = audioframe.nb_frames;
                double duration = audioframe.duration;

                // reduce large packets for better sync, i.e. FLAC can have 96ms packets
                // 32ms because I know this works good for AC3
                if (audioframe.duration > DVD_MSEC_TO_TIME(32) && audioframe.sample_rate)
                {
                    audioframe.nb_frames = 0.032 * audioframe.sample_rate;
                    audioframe.duration = ((double)audioframe.nb_frames * DVD_TIME_BASE) / audioframe.sample_rate;
                }

                int dups = std::min(DVD_MSEC_TO_TIME(100), error) / audioframe.duration;
                if (dups > 0)
                    CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket duplicate %d packets of duration %d",
                              dups, DVD_TIME_TO_MSEC(audioframe.duration));
                for (int i = 0; i < dups; i++)
                {
                    m_dvdAudio.AddPackets(audioframe);
                }

                audioframe.nb_frames = nb_frames;
                audioframe.duration = duration;

                m_dvdAudio.AddPackets(audioframe);
            }
        }
        else if (error < -DVD_MSEC_TO_TIME(32))
        {
            if (AE_IS_RAW_RAW(audioframe.data_format))
            {
                double correction = audioframe.duration;
                // Force clock sync to audio
                CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket forcing clock sync for passthrough - skip error(%f), clock(%f), correction(%f)", error, clock, correction);
                m_pClock->Update(clock-correction, absolute, 0.0, "CDVDPlayerAudio::OutputPacket");
                m_dvdAudio.AddPackets(audioframe);
            }
            else
            {
                m_dvdAudio.SetPlayingPts(audioframe.pts);
                CLog::Log(LOGNOTICE,"CDVDPlayerAudio::OutputPacket skipping a packets of duration %d",
                          DVD_TIME_TO_MSEC(audioframe.duration));
            }
        }
        else
        {
            m_dvdAudio.AddPackets(audioframe);
        }
    }
    else if (m_synctype == SYNC_DISCON)
    {
        m_dvdAudio.AddPackets(audioframe);
    }
    else if (m_synctype == SYNC_SKIPDUP)
    {
        double limit = std::max(DVD_MSEC_TO_TIME(10), audioframe.duration * 2.0 / 3.0);
        if (m_error < -limit)
        {
            m_prevskipped = !m_prevskipped;
            if (m_prevskipped)
                m_dvdAudio.AddPackets(audioframe);
            else
            {
                CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: Dropping packet of %d ms", DVD_TIME_TO_MSEC(audioframe.duration));
                m_error += audioframe.duration;
            }
        }
        else if(m_error > limit)
        {
            CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: Duplicating packet of %d ms", DVD_TIME_TO_MSEC(audioframe.duration));
            m_dvdAudio.AddPackets(audioframe);
            m_dvdAudio.AddPackets(audioframe);
            m_error -= audioframe.duration;
        }
        else
            m_dvdAudio.AddPackets(audioframe);
    }
    else if (m_synctype == SYNC_RESAMPLE)
    {
        m_dvdAudio.SetResampleRatio(m_resampleratio);
        m_dvdAudio.AddPackets(audioframe);
    }

    return true;
}
Ejemplo n.º 23
0
bool OMXReader::SeekTime(int time, bool backwords, double *startpts, bool doLoopOnFail)//doLoopOnFail = true
{
	if(time < 0)
	{
		time = 0;
	}

	if(!m_pFormatContext)
	{
		return false;
	}

	if(m_pFile && !m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL))
	{
		ofLog(OF_LOG_VERBOSE, "%s - input stream reports it is not seekable", __FUNCTION__);
		return false;
	}

	Lock();

	//FlushRead();

	if(m_ioContext)
	{
		m_ioContext->buf_ptr = m_ioContext->buf_end;
	}

	int64_t seek_pts = (int64_t)time * (AV_TIME_BASE / 1000);
	if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE)
	{
		seek_pts += m_pFormatContext->start_time;
	}

	//  virtual int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { return ::av_seek_frame(s, stream_index, timestamp, flags); }

	int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0);
	//int ret =avformat_seek_file(m_pFormatContext, -1, 0, seek_pts, m_pFormatContext->duration*1000, AVSEEK_FLAG_ANY);
	if(ret >= 0)
	{
		ofLogVerbose(__func__) << "av_seek_frame PASS: - returned: " << ret;
		UpdateCurrentPTS();
	}
	else
	{
		ofLogVerbose(__func__) << "av_seek_frame returned >= 0, - rewinding file" << ret;
		if (doLoopOnFail)
		{
			m_pFile->rewindFile();
			wasFileRewound = true;
		}

		UpdateCurrentPTS();

	}


	// in this case the start time is requested time
	if(startpts)
	{
		*startpts = DVD_MSEC_TO_TIME(time);
	}

	// demuxer will return failure, if you seek to eof
	m_eof = false;
	if (m_pFile && m_pFile->IsEOF() && ret <= 0)
	{
		m_eof = true;
		ret = 0;
	}
	//int landedTime = (int)(m_iCurrentPts / DVD_TIME_BASE * 1000);
	//ofLogVerbose(__func__) << "Seek ended up on time: " << landedTime;

	UnLock();

	return (ret >= 0);
}
Ejemplo n.º 24
0
/*------------------------------------------------------------------------------
|    OMX_MediaProcessor::mediaDecoding
+-----------------------------------------------------------------------------*/
void OMX_MediaProcessor::mediaDecoding()
{
   // See description in the qmakefile.
//#define ENABLE_PROFILE_MAIN_LOOP
//#define ENABLE_PAUSE_FOR_BUFFERING

   LOG_VERBOSE(LOG_TAG, "Decoding thread started.");
   emit playbackStarted();

   // Prealloc.
#ifdef ENABLE_PAUSE_FOR_BUFFERING
   float stamp     = 0;
   float audio_pts = 0;
   float video_pts = 0;

   float audio_fifo = 0;
   float video_fifo = 0;
   float threshold = 0;
   bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false;
   float m_threshold = 1.0f; //std::min(0.1f, audio_fifo_size * 0.1f);
#endif // ENABLE_PAUSE_FOR_BUFFERING
   bool sentStarted = false;
   double last_seek_pos = 0;

   bool sendEos = false;
   double m_last_check_time = 0.0;

   m_av_clock->OMXReset(m_has_video, m_has_audio);
   m_av_clock->OMXStateExecute();
   sentStarted = true;

   while (!m_pendingStop) {
#ifdef ENABLE_PROFILE_MAIN_LOOP
      static qint64 tot    = 0;
      static qint64 totNum = 0;
      static QElapsedTimer timer;
      static int count = 0;
      if (tot == 0) {
         timer.start();
         tot++;
      }
      else
         tot += timer.restart();
      totNum++;
      if ((count++)%30 == 0) {
         //LOG_VERBOSE(LOG_TAG, "Elapsed: %lld", timer.restart());
         LOG_VERBOSE(LOG_TAG, "Average: %f.", (double)tot/totNum);
      }
#endif

      double now = m_av_clock->GetAbsoluteClock();
      bool update = false;
      if (m_last_check_time == 0.0 || m_last_check_time + DVD_MSEC_TO_TIME(20) <= now) {
         update = true;
         m_last_check_time = now;
      }

      // If a request is pending then consider done here.
      m_mutexPending.lock();
      if (m_pendingPause) {
         m_waitPendingCommand.wakeAll();
         m_pendingPause = false;
      }
      m_mutexPending.unlock();

      // TODO: Use a semaphore instead.
      if (m_state == STATE_PAUSED) {
         OMXClock::OMXSleep(2);
         continue;
      }

      if (m_seekFlush || m_incr != 0) {
         double seek_pos = 0;
         double pts      = m_av_clock->OMXMediaTime();

         //seek_pos        = (pts / DVD_TIME_BASE) + m_incr;
         seek_pos = (pts ? pts / DVD_TIME_BASE : last_seek_pos) + m_incr;
         last_seek_pos = seek_pos;

         seek_pos        *= 1000.0;

         if(m_omx_reader->SeekTime((int)seek_pos, m_incr < 0.0f, &startpts))
         {
            unsigned t = (unsigned)(startpts*1e-6);
            auto dur = m_omx_reader->GetStreamLength() / 1000;

            log_info("Seek to: %02d:%02d:%02d\n", (t/3600), (t/60)%60, t%60);
            flushStreams(startpts);
         }

         m_player_video->Close();
         sentStarted = false;

         if (m_omx_reader->IsEof())
            break;

         if (m_has_video && !m_player_video->Open(
                *m_hints_video,
                m_av_clock,
                m_textureData,
                VS_DEINTERLACEMODE_OFF, /* deinterlace */
                OMX_ImageFilterAnaglyphNone,
                ENABLE_HDMI_CLOCK_SYNC,
                true,                   /* threaded */
                1.0,                    /* display aspect, unused */
                0,                      /* display */
                0,                      /* layer */
                m_video_queue_size, m_video_fifo_size
                )) {
            m_incr = 0;
            break;
         }

         m_incr = 0;

#ifdef ENABLE_PAUSE_FOR_BUFFERING
         m_av_clock->OMXPause();
#endif

#ifdef ENABLE_SUBTITLES
         if (m_has_subtitle)
            m_player_subtitles.Resume();
#endif

         unsigned t = (unsigned)(startpts*1e-6);
         LOG_VERBOSE(LOG_TAG, "Seeked to: %02d:%02d:%02d\n", (t/3600), (t/60)%60, t%60);
         m_packetAfterSeek = false;
         m_seekFlush       = false;
      }
      else if (m_packetAfterSeek && TRICKPLAY(m_av_clock->OMXPlaySpeed())) {
         double seek_pos     = 0;
         double pts          = 0;

         pts      = m_av_clock->OMXMediaTime();
         seek_pos = (pts/DVD_TIME_BASE);

         seek_pos *= 1000.0;

#if 1
         if (m_omx_reader->SeekTime((int)seek_pos, m_av_clock->OMXPlaySpeed() < 0, &startpts))
         {
            ; //FlushStreams(DVD_NOPTS_VALUE);
         }
#endif // 0

         CLog::Log(LOGDEBUG, "Seeked %.0f %.0f %.0f\n", DVD_MSEC_TO_TIME(seek_pos), startpts, m_av_clock->OMXMediaTime());

         //unsigned t = (unsigned)(startpts*1e-6);
         unsigned t = (unsigned)(pts*1e-6);
         printf("Seek to: %02d:%02d:%02d\n", (t/3600), (t/60)%60, t%60);
         m_packetAfterSeek = false;
      }

      // TODO: Better error handling.
      if (m_player_audio->Error()) {
         LOG_ERROR(LOG_TAG, "Audio player error. emergency exit!");
         break;
      }

      if (update) {
#ifdef ENABLE_PAUSE_FOR_BUFFERING
         /* when the video/audio fifos are low, we pause clock, when high we resume */
         stamp     = m_av_clock->OMXMediaTime();
         audio_pts = m_player_audio->GetCurrentPTS();
         video_pts = m_player_video->GetCurrentPTS();

         if (0 && m_av_clock->OMXIsPaused()) {
            double old_stamp = stamp;
            if (audio_pts != DVD_NOPTS_VALUE && (stamp == 0 || audio_pts < stamp))
               stamp = audio_pts;
            if (video_pts != DVD_NOPTS_VALUE && (stamp == 0 || video_pts < stamp))
               stamp = video_pts;
            if (old_stamp != stamp)
            {
               m_av_clock->OMXMediaTime(stamp);
               stamp = m_av_clock->OMXMediaTime();
            }
         }

         audio_fifo = audio_pts == DVD_NOPTS_VALUE ? 0.0f : audio_pts / DVD_TIME_BASE - stamp * 1e-6;
         video_fifo = video_pts == DVD_NOPTS_VALUE ? 0.0f : video_pts / DVD_TIME_BASE - stamp * 1e-6;
         threshold  = min(0.1f, (float)m_player_audio->GetCacheTotal()*0.1f);
#endif // ENABLE_PAUSE_FOR_BUFFERING

#if 0
         static int count;
         if ((count++ & 15) == 0) {
            LOG_VERBOSE(LOG_TAG, "M: %8.02f V : %8.02f %8d %8d A : %8.02f %8.02f/%8.02f Cv : %8d Ca : %8d \r", stamp,
                        audio_fifo, m_player_video->GetDecoderBufferSize(), m_player_video->GetDecoderFreeSpace(),
                        video_fifo, m_player_audio->GetDelay(), m_player_audio->GetCacheTotal(),
                        m_player_video->GetCached(), m_player_audio->GetCached());
         }
#endif

#if 0
         if(m_tv_show_info) {
            static unsigned count;
            if ((count++ & 15) == 0) {
               char response[80];
               if (m_player_video.GetDecoderBufferSize() && m_player_audio.GetCacheTotal())
                  vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d",
                            (int)(100.0*m_player_video.GetDecoderBufferSize()-m_player_video.GetDecoderFreeSpace())/m_player_video.GetDecoderBufferSize(),
                            (int)(100.0*video_fifo/m_player_audio.GetCacheTotal()),
                            0, 100);
               if (m_player_audio.GetCacheTotal())
                  vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d",
                            (int)(100.0*audio_fifo/m_player_audio.GetCacheTotal()),
                            (int)(100.0*m_player_audio.GetDelay()/m_player_audio.GetCacheTotal()),
                            0, 100);
               vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d",
                         m_player_video.GetLevel(), 0, 0, 100);
               vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d",
                         m_player_audio.GetLevel(), 0, 0, 100);
            }
         }
#endif

#ifdef ENABLE_PAUSE_FOR_BUFFERING
         if (audio_pts != DVD_NOPTS_VALUE) {
            audio_fifo_low  = m_has_audio && audio_fifo < threshold;
            audio_fifo_high = !m_has_audio || (audio_pts != DVD_NOPTS_VALUE && audio_fifo > m_threshold);
         }

         if (video_pts != DVD_NOPTS_VALUE) {
            video_fifo_low  = m_has_video && video_fifo < threshold;
            video_fifo_high = !m_has_video || (video_pts != DVD_NOPTS_VALUE && video_fifo > m_threshold);
         }

         // Enable this to enable pause for buffering.
         if (m_state != STATE_PAUSED && (m_omx_reader->IsEof() || m_omx_pkt || TRICKPLAY(m_av_clock->OMXPlaySpeed()) || (audio_fifo_high && video_fifo_high)))
         {
            if (m_av_clock->OMXIsPaused())
            {
               CLog::Log(LOGDEBUG, "Resume %.2f,%.2f (%d,%d,%d,%d) EOF:%d PKT:%p\n", audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_omx_reader->IsEof(), m_omx_pkt);
               log_verbose("Pausing for buffering...");
               //m_av_clock->OMXStateExecute();
               m_av_clock->OMXResume();
            }
         }
         else if (m_state == STATE_PAUSED || audio_fifo_low || video_fifo_low)
         {
            if (!m_av_clock->OMXIsPaused())
            {
               if (m_state != STATE_PAUSED)
                 m_threshold = std::min(2.0f*m_threshold, 16.0f);
               CLog::Log(LOGDEBUG, "Pause %.2f,%.2f (%d,%d,%d,%d) %.2f\n", audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_threshold);
               log_verbose("Buffering completed. Resuming...");
               m_av_clock->OMXPause();
            }
         }
#endif
      }

      if (!sentStarted)
      {
         CLog::Log(LOGDEBUG, "COMXPlayer::HandleMessages - player started RESET");
         m_av_clock->OMXReset(m_has_video, m_has_audio);
         m_av_clock->OMXStateExecute();
         sentStarted = true;
      }

      if (!m_omx_pkt)
         m_omx_pkt = m_omx_reader->Read();

      if (m_omx_pkt)
         sendEos = false;

      if (m_omx_reader->IsEof() && !m_omx_pkt) {
         // demuxer EOF, but may have not played out data yet
         if ((m_has_video && m_player_video->GetCached()) ||
             (m_has_audio && m_player_audio->GetCached())) {
            OMXClock::OMXSleep(10);
            continue;
         }
         if (m_loop) {
            m_incr = m_loop_from - (m_av_clock->OMXMediaTime() ? m_av_clock->OMXMediaTime() / DVD_TIME_BASE : last_seek_pos);
            continue;
         }

         if (!sendEos && m_has_video)
            m_player_video->SubmitEOS();
         if (!sendEos && m_has_audio)
            m_player_audio->SubmitEOS();
         sendEos = true;
         if ((m_has_video && !m_player_video->IsEOS()) ||
             (m_has_audio && !m_player_audio->IsEOS()) ) {
            OMXClock::OMXSleep(10);
            continue;
         }

         break;
      }

      if (!m_omx_pkt)
         m_omx_pkt = m_omx_reader->Read();

      if(m_omx_pkt)
        sendEos = false;

      if(m_omx_reader->IsEof() && !m_omx_pkt) {
        // demuxer EOF, but may have not played out data yet
        if ( (m_has_video && m_player_video->GetCached()) ||
             (m_has_audio && m_player_audio->GetCached()) )
        {
          OMXClock::OMXSleep(10);
          continue;
        }
        if (!sendEos && m_has_video)
          m_player_video->SubmitEOS();
        if (!sendEos && m_has_audio)
          m_player_audio->SubmitEOS();
        sendEos = true;
        if ( (m_has_video && !m_player_video->IsEOS()) ||
             (m_has_audio && !m_player_audio->IsEOS()) )
        {
          OMXClock::OMXSleep(10);
          continue;
        }
        break;
      }

      if(m_has_video && m_omx_pkt && m_omx_reader->IsActive(OMXSTREAM_VIDEO, m_omx_pkt->stream_index))
      {
        if (TRICKPLAY(m_av_clock->OMXPlaySpeed()))
        {
           m_packetAfterSeek = true;
        }
        if(m_player_video->AddPacket(m_omx_pkt))
          m_omx_pkt = NULL;
        else
          OMXClock::OMXSleep(10);
      }
      else if(m_has_audio && m_omx_pkt && !TRICKPLAY(m_av_clock->OMXPlaySpeed()) && m_omx_pkt->codec_type == AVMEDIA_TYPE_AUDIO)
      {
        if(m_player_audio->AddPacket(m_omx_pkt))
          m_omx_pkt = NULL;
        else
          OMXClock::OMXSleep(10);
      }
#ifdef ENABLE_SUBTITLES
      else if(m_has_subtitle && m_omx_pkt && !TRICKPLAY(m_av_clock->OMXPlaySpeed()) &&
              m_omx_pkt->codec_type == AVMEDIA_TYPE_SUBTITLE)
      {
        auto result = m_player_subtitles.AddPacket(m_omx_pkt,
                        m_omx_reader.GetRelativeIndex(m_omx_pkt->stream_index));
        if (result)
          m_omx_pkt = NULL;
        else
          OMXClock::OMXSleep(10);
      }
#endif
      else
      {
        if(m_omx_pkt)
        {
          m_omx_reader->FreePacket(m_omx_pkt);
          m_omx_pkt = NULL;
        }
        else
          OMXClock::OMXSleep(10);
      }
   }

   LOG_VERBOSE(LOG_TAG, "Stopping OMX clock...");
   //m_av_clock->OMXResume();
   m_av_clock->OMXStop();
   m_av_clock->OMXStateIdle();
   //m_av_clock->OMXStateExecute();
   //m_av_clock->OMXReset(m_has_video, m_has_audio);

   // Restart video player. It seems it is necessary to close
   // and open again. omxplayer does this also when seeking so
   // maybe there is no other way to restart it.
   m_player_video->Close();
   if (m_has_video)
      if (!m_player_video->Open(
             *m_hints_video,
             m_av_clock,
             m_textureData,
             VS_DEINTERLACEMODE_OFF, /* deinterlace */
             OMX_ImageFilterAnaglyphNone,
             ENABLE_HDMI_CLOCK_SYNC,
             true,                   /* threaded */
             1.0,                    /* display aspect, unused */
             0,                      /* display, unused */
             0,                      /* layer */
             m_video_queue_size, m_video_fifo_size
             )) {
         LOG_ERROR(LOG_TAG, "Failed to reopen media.");
      }
   // TODO: Handle failure.

   setState(STATE_STOPPED);
   emit playbackCompleted();

   // Actually change the state here and reset flags.
   m_mutexPending.lock();
   if (m_pendingStop) {
      m_pendingStop = false;
      m_waitPendingCommand.wakeAll();
   }
   m_mutexPending.unlock();
}
void OMXEGLImagePlayer::Output(double pts)
{
	
	if(m_syncclock)
	{
		double delay = m_FlipTimeStamp - m_av_clock->GetAbsoluteClock();
		if( delay > m_frametime )
		{
			delay = m_frametime;
		}else 
		{
			if( delay < 0 )
			{
				delay = 0;
			}
		}

		//printf("OMXEGLImagePlayer - GENERAL_RESYNC(%f, 1) delay %f\n", pts, m_FlipTimeStamp);
		m_av_clock->Discontinuity(pts - delay);
		m_syncclock = false;
	}

	double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;
	iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock
	iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison
	iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
	iFrameDuration = m_frametime;

	// correct sleep times based on speed
	if(m_speed)
	{
		iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
		iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed);
		iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed);
	}
	else
	{
		iClockSleep = 0;
		iFrameSleep = 0;
	}
	
	// dropping to a very low framerate is not correct (it should not happen at all)
	iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500));
	iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500));

	bool m_stalled = false;
	int m_autosync = 1;
	if( m_stalled )
	{
		iSleepTime = iFrameSleep;
	}
	else
	{
		iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;
	}

	// present the current pts of this frame to user, and include the actual
	// presentation delay, to allow him to adjust for it
	if( m_stalled )
	{
		m_iCurrentPts = DVD_NOPTS_VALUE;
	}
	else
	{
		m_iCurrentPts = pts - max(0.0, iSleepTime);
	}

	m_av_clock->SetPTS(m_iCurrentPts);

	// timestamp when we think next picture should be displayed based on current duration
	m_FlipTimeStamp  = iCurrentClock;
	m_FlipTimeStamp += max(0.0, iSleepTime);
	m_FlipTimeStamp += iFrameDuration;
	
	if(doDebugging)
	{
		sprintf(debugInfoBuffer, 
				"iPlayingClock		 %f	\n\
				iCurrentClock		 %f	\n\
				iClockSleep			 %f	\n\
				iFrameSleep			 %f	\n\
				iFrameDuration		 %f	\n\
				WaitAbsolut			 %f	\n\
				m_FlipTimeStamp		 %f	\n\
				pts					 %f	\n\
				currentFrame		 %d	\n\
				Cached Video		 %8d", 
				iPlayingClock / DVD_TIME_BASE, 
				iCurrentClock  / DVD_TIME_BASE,
				iClockSleep / DVD_TIME_BASE, 
				iFrameSleep / DVD_TIME_BASE,
				iFrameDuration / DVD_TIME_BASE, 
				(iCurrentClock + iSleepTime) / DVD_TIME_BASE, 
				m_FlipTimeStamp / DVD_TIME_BASE, 
				pts / DVD_TIME_BASE,
				(int)((m_FlipTimeStamp / DVD_TIME_BASE)*m_fps),
				m_cached_size);
		
		debugInfo = (string) debugInfoBuffer;
	}

	//ofLogVerbose() << debugInfo;
	
	if(m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) )
	{
		//ofLogVerbose() << "OMXEGLImagePlayer::Output returning early";
		return;
	}
	
  	

	m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime));

	// guess next frame pts. iDuration is always valid
	if (m_speed != 0)
    {
		m_pts += m_frametime * m_speed / abs(m_speed);
	}
}
Ejemplo n.º 26
0
void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket)
{
  if (!g_renderManager.IsStarted()) {
    CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__);
    return;
  }

  // calculate the time we need to delay this picture before displaying
  double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;

  iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock
  iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison
  iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
  iFrameDuration = (double)DVD_TIME_BASE / m_fFrameRate; //pPacket->duration;

  // correct sleep times based on speed
  if(m_speed)
  {
    iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
    iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed);
    iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed);
  }
  else
  {
    iClockSleep = 0;
    iFrameSleep = 0;
  }

  // dropping to a very low framerate is not correct (it should not happen at all)
  iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500));
  iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500));

  if( m_stalled )
    iSleepTime = iFrameSleep;
  else
    iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;

  // present the current pts of this frame to user, and include the actual
  // presentation delay, to allow him to adjust for it
  if( m_stalled )
    m_iCurrentPts = DVD_NOPTS_VALUE;
  else
    m_iCurrentPts = pts - max(0.0, iSleepTime);

  // timestamp when we think next picture should be displayed based on current duration
  m_FlipTimeStamp  = iCurrentClock;
  m_FlipTimeStamp += max(0.0, iSleepTime);
  m_FlipTimeStamp += iFrameDuration;

  if( m_speed < 0 )
  {
    if( iClockSleep < -DVD_MSEC_TO_TIME(200))
      return;
  }

  if(bDropPacket)
    return;

#if 0
  if( m_speed != DVD_PLAYSPEED_NORMAL)
  {
    // calculate frame dropping pattern to render at this speed
    // we do that by deciding if this or next frame is closest
    // to the flip timestamp
    double current   = fabs(m_dropbase -  m_droptime);
    double next      = fabs(m_dropbase - (m_droptime + iFrameDuration));
    double frametime = (double)DVD_TIME_BASE / m_fFrameRate;

    m_droptime += iFrameDuration;
#ifndef PROFILE
    if( next < current /*&& !(pPicture->iFlags & DVP_FLAG_NOSKIP) */)
      return /*result | EOS_DROPPED*/;
#endif

    while(!m_bStop && m_dropbase < m_droptime)             m_dropbase += frametime;
    while(!m_bStop && m_dropbase - frametime > m_droptime) m_dropbase -= frametime;
  }
  else
  {
    m_droptime = 0.0f;
    m_dropbase = 0.0f;
  }
#else
  m_droptime = 0.0f;
  m_dropbase = 0.0f;
#endif

  int buffer = g_renderManager.WaitForBuffer(m_bStop, 0);
  if (buffer < 0)
    return;

  double pts_overlay = m_av_clock->OMXMediaTime(false, false)
                     + 2* (double)DVD_TIME_BASE / g_graphicsContext.GetFPS();
  ProcessOverlays(iGroupId, pts_overlay);

  double timestamp = CDVDClock::GetAbsoluteClock(false) + 2 / g_graphicsContext.GetFPS();
  g_renderManager.FlipPage(CThread::m_bStop, timestamp, -1, FS_NONE);
}
Ejemplo n.º 27
0
void OMXPlayerAudio::HandleSyncError(double duration)
{
  double clock = m_av_clock->GetClock();
  double error = m_audioClock - clock;
  int64_t now;

  if( fabs(error) > DVD_MSEC_TO_TIME(100) || m_syncclock )
  {
    m_av_clock->Discontinuity(clock+error);
    /*
    if(m_speed == DVD_PLAYSPEED_NORMAL)
    CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Discontinuity - was:%f, should be:%f, error:%f\n", clock, clock+error, error);
    */

    m_errorbuff = 0;
    m_errorcount = 0;
    m_skipdupcount = 0;
    m_error = 0;
    m_syncclock = false;
    m_errortime = m_av_clock->CurrentHostCounter();

    return;
  }

  if (m_speed != DVD_PLAYSPEED_NORMAL)
  {
    m_errorbuff = 0;
    m_errorcount = 0;
    m_integral = 0;
    m_skipdupcount = 0;
    m_error = 0;
    m_errortime = m_av_clock->CurrentHostCounter();
    return;
  }

  //check if measured error for 1 second
  now = m_av_clock->CurrentHostCounter();
  if ((now - m_errortime) >= m_freq)
  {
    m_errortime = now;
    m_error = m_errorbuff / m_errorcount;

    m_errorbuff = 0;
    m_errorcount = 0;

    if (m_synctype == SYNC_DISCON)
    {
      double limit, error;

      if (m_av_clock->GetRefreshRate(&limit) > 0)
      {
        //when the videoreferenceclock is running, the discontinuity limit is one vblank period
        limit *= DVD_TIME_BASE;

        //make error a multiple of limit, rounded towards zero,
        //so it won't interfere with the sync methods in CXBMCRenderManager::WaitPresentTime
        if (m_error > 0.0)
          error = limit * floor(m_error / limit);
        else
          error = limit * ceil(m_error / limit);
      }
      else
      {
        limit = DVD_MSEC_TO_TIME(10);
        error = m_error;
      }

      /*
      limit = DVD_MSEC_TO_TIME(10);
      error = m_error;
      */

      if (fabs(error) > limit - 0.001)
      {
        m_av_clock->Discontinuity(clock+error);
        /*
        if(m_speed == DVD_PLAYSPEED_NORMAL)
          CLog::Log(LOGDEBUG, "COMXPlayerAudio:: Discontinuity - was:%f, should be:%f, error:%f", clock, clock+error, error);
        */
      }
    }
    /*
    else if (m_synctype == SYNC_SKIPDUP && m_skipdupcount == 0 && fabs(m_error) > DVD_MSEC_TO_TIME(10))
    if (m_skipdupcount == 0 && fabs(m_error) > DVD_MSEC_TO_TIME(10))
    {
      //check how many packets to skip/duplicate
      m_skipdupcount = (int)(m_error / duration);
      //if less than one frame off, see if it's more than two thirds of a frame, so we can get better in sync
      if (m_skipdupcount == 0 && fabs(m_error) > duration / 3 * 2)
        m_skipdupcount = (int)(m_error / (duration / 3 * 2));

      if (m_skipdupcount > 0)
        CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Duplicating %i packet(s) of %.2f ms duration",
                  m_skipdupcount, duration / DVD_TIME_BASE * 1000.0);
      else if (m_skipdupcount < 0)
        CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Skipping %i packet(s) of %.2f ms duration ",
                  m_skipdupcount * -1,  duration / DVD_TIME_BASE * 1000.0);
    }
    */
  }
}
Ejemplo n.º 28
0
bool CVideoPlayerAudio::ProcessDecoderOutput(DVDAudioFrame &audioframe)
{
  if (audioframe.nb_frames <= audioframe.framesOut)
  {
    m_pAudioCodec->GetData(audioframe);

    if (audioframe.nb_frames == 0)
    {
      return false;
    }

    audioframe.hasTimestamp = true;
    if (audioframe.pts == DVD_NOPTS_VALUE)
    {
      audioframe.pts = m_audioClock;
      audioframe.hasTimestamp = false;
    }
    else
    {
      m_audioClock = audioframe.pts;
    }

    if (audioframe.format.m_sampleRate && m_streaminfo.samplerate != (int) audioframe.format.m_sampleRate)
    {
      // The sample rate has changed or we just got it for the first time
      // for this stream. See if we should enable/disable passthrough due
      // to it.
      m_streaminfo.samplerate = audioframe.format.m_sampleRate;
      if (SwitchCodecIfNeeded())
      {
        audioframe.nb_frames = 0;
        return false;
      }
    }

    // if stream switches to realtime, disable pass through
    // or switch to resample
    if (m_processInfo.IsRealtimeStream() && m_synctype != SYNC_RESAMPLE)
    {
      m_synctype = SYNC_RESAMPLE;
      if (SwitchCodecIfNeeded())
      {
        audioframe.nb_frames = 0;
        return false;
      }
    }

    // demuxer reads metatags that influence channel layout
    if (m_streaminfo.codec == AV_CODEC_ID_FLAC && m_streaminfo.channellayout)
      audioframe.format.m_channelLayout = CAEUtil::GetAEChannelLayout(m_streaminfo.channellayout);

    // we have successfully decoded an audio frame, setup renderer to match
    if (!m_audioSink.IsValidFormat(audioframe))
    {
      if (m_speed)
        m_audioSink.Drain();

      m_audioSink.Destroy(false);

      if (!m_audioSink.Create(audioframe, m_streaminfo.codec, m_synctype == SYNC_RESAMPLE))
        CLog::Log(LOGERROR, "%s - failed to create audio renderer", __FUNCTION__);

      m_audioSink.SetDynamicRangeCompression((long)(m_processInfo.GetVideoSettings().m_VolumeAmplification * 100));

      if (m_syncState == IDVDStreamPlayer::SYNC_INSYNC)
        m_audioSink.Resume();
    }

    SetSyncType(audioframe.passthrough);
  }


  {
    double syncerror = m_audioSink.GetSyncError();
    if (m_synctype == SYNC_DISCON && fabs(syncerror) > DVD_MSEC_TO_TIME(10))
    {
      double correction = m_pClock->ErrorAdjust(syncerror, "CVideoPlayerAudio::OutputPacket");
      if (correction != 0)
      {
        m_audioSink.SetSyncErrorCorrection(-correction);
      }
    }
  }

  int framesOutput = m_audioSink.AddPackets(audioframe);

  // guess next pts
  m_audioClock += audioframe.duration * ((double)framesOutput / audioframe.nb_frames);

  audioframe.framesOut += framesOutput;

  // signal to our parent that we have initialized
  if (m_syncState == IDVDStreamPlayer::SYNC_STARTING)
  {
    double cachetotal = m_audioSink.GetCacheTotal();
    double cachetime = m_audioSink.GetCacheTime();
    if (cachetime >= cachetotal * 0.75)
    {
      m_syncState = IDVDStreamPlayer::SYNC_WAITSYNC;
      m_stalled = false;
      SStartMsg msg;
      msg.player = VideoPlayer_AUDIO;
      msg.cachetotal = m_audioSink.GetMaxDelay() * DVD_TIME_BASE;
      msg.cachetime = m_audioSink.GetDelay();
      msg.timestamp = audioframe.hasTimestamp ? audioframe.pts : DVD_NOPTS_VALUE;
      m_messageParent.Put(new CDVDMsgType<SStartMsg>(CDVDMsg::PLAYER_STARTED, msg));

      m_streaminfo.channels = audioframe.format.m_channelLayout.Count();
      m_processInfo.SetAudioChannels(audioframe.format.m_channelLayout);
      m_processInfo.SetAudioSampleRate(audioframe.format.m_sampleRate);
      m_processInfo.SetAudioBitsPerSample(audioframe.bits_per_sample);
      m_processInfo.SetAudioDecoderName(m_pAudioCodec->GetName());
      m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE));
    }
  }

  return true;
}
Ejemplo n.º 29
0
void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket)
{

  if (!g_renderManager.IsConfigured()
    || m_video_width != m_width
    || m_video_height != m_height
    || m_fps != m_fFrameRate)
  {
    m_width   = m_video_width;
    m_height  = m_video_height;
    m_fps     = m_fFrameRate;

    unsigned flags = 0;
    ERenderFormat format = RENDER_FMT_BYPASS;

    if(m_bAllowFullscreen)
    {
      flags |= CONF_FLAGS_FULLSCREEN;
      m_bAllowFullscreen = false; // only allow on first configure
    }

    if(m_flags & CONF_FLAGS_FORMAT_SBS)
    {
      if(g_Windowing.Support3D(m_video_width, m_video_height, D3DPRESENTFLAG_MODE3DSBS))
      {
        CLog::Log(LOGNOTICE, "3DSBS movie found");
        flags |= CONF_FLAGS_FORMAT_SBS;
      }
    }

    CLog::Log(LOGDEBUG,"%s - change configuration. %dx%d. framerate: %4.2f. format: BYPASS",
        __FUNCTION__, m_width, m_height, m_fps);

    if(!g_renderManager.Configure(m_video_width, m_video_height, 
          m_video_width, m_video_height, m_fps, flags, format, 0,
          m_hints.orientation))
    {
      CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__);
      return;
    }
  }

  if (!g_renderManager.IsStarted()) {
    CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__);
    return;
  }

  // calculate the time we need to delay this picture before displaying
  double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;

  iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock
  iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison
  iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
  iFrameDuration = (double)DVD_TIME_BASE / m_fFrameRate; //pPacket->duration;

  // correct sleep times based on speed
  if(m_speed)
  {
    iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
    iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed);
    iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed);
  }
  else
  {
    iClockSleep = 0;
    iFrameSleep = 0;
  }

  // dropping to a very low framerate is not correct (it should not happen at all)
  iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500));
  iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500));

  if( m_stalled )
    iSleepTime = iFrameSleep;
  else
    iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;

  // present the current pts of this frame to user, and include the actual
  // presentation delay, to allow him to adjust for it
  if( m_stalled )
    m_iCurrentPts = DVD_NOPTS_VALUE;
  else
    m_iCurrentPts = pts - max(0.0, iSleepTime);

  // timestamp when we think next picture should be displayed based on current duration
  m_FlipTimeStamp  = iCurrentClock;
  m_FlipTimeStamp += max(0.0, iSleepTime);
  m_FlipTimeStamp += iFrameDuration;

  if( m_speed < 0 )
  {
    if( iClockSleep < -DVD_MSEC_TO_TIME(200))
      return;
  }

  if(bDropPacket)
    return;

#if 0
  if( m_speed != DVD_PLAYSPEED_NORMAL)
  {
    // calculate frame dropping pattern to render at this speed
    // we do that by deciding if this or next frame is closest
    // to the flip timestamp
    double current   = fabs(m_dropbase -  m_droptime);
    double next      = fabs(m_dropbase - (m_droptime + iFrameDuration));
    double frametime = (double)DVD_TIME_BASE / m_fFrameRate;

    m_droptime += iFrameDuration;
#ifndef PROFILE
    if( next < current /*&& !(pPicture->iFlags & DVP_FLAG_NOSKIP) */)
      return /*result | EOS_DROPPED*/;
#endif

    while(!m_bStop && m_dropbase < m_droptime)             m_dropbase += frametime;
    while(!m_bStop && m_dropbase - frametime > m_droptime) m_dropbase -= frametime;
  }
  else
  {
    m_droptime = 0.0f;
    m_dropbase = 0.0f;
  }
#else
  m_droptime = 0.0f;
  m_dropbase = 0.0f;
#endif

  double pts_media = m_av_clock->OMXMediaTime();
  ProcessOverlays(iGroupId, pts_media);

  while(!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) )
    Sleep(1);

  g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE);

  //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime));
}
Ejemplo n.º 30
0
bool CVideoPlayerVideo::ProcessDecoderOutput(double &frametime, double &pts)
{
  CDVDVideoCodec::VCReturn decoderState = m_pVideoCodec->GetPicture(&m_picture);

  if (decoderState == CDVDVideoCodec::VC_BUFFER)
  {
    return false;
  }

  // if decoder was flushed, we need to seek back again to resume rendering
  if (decoderState == CDVDVideoCodec::VC_FLUSHED)
  {
    CLog::Log(LOGDEBUG, "CVideoPlayerVideo - video decoder was flushed");
    while (!m_packets.empty())
    {
      CDVDMsgDemuxerPacket* msg = static_cast<CDVDMsgDemuxerPacket*>(m_packets.front().message->Acquire());
      m_packets.pop_front();

      SendMessage(msg, 10);
    }

    m_pVideoCodec->Reset();
    m_packets.clear();
    //picture.iFlags &= ~DVP_FLAG_ALLOCATED;
    m_renderManager.DiscardBuffer();
    return false;
  }

  if (decoderState == CDVDVideoCodec::VC_REOPEN)
  {
    while (!m_packets.empty())
    {
      CDVDMsgDemuxerPacket* msg = static_cast<CDVDMsgDemuxerPacket*>(m_packets.front().message->Acquire());
      m_packets.pop_front();
      SendMessage(msg, 10);
    }

    m_pVideoCodec->Reopen();
    m_packets.clear();
    m_renderManager.DiscardBuffer();
    return false;
  }

  // if decoder had an error, tell it to reset to avoid more problems
  if (decoderState == CDVDVideoCodec::VC_ERROR)
  {
    CLog::Log(LOGDEBUG, "CVideoPlayerVideo - video decoder returned error");
    return false;
  }

  if (decoderState == CDVDVideoCodec::VC_EOF)
  {
    if (m_syncState == IDVDStreamPlayer::SYNC_STARTING)
    {
      SStartMsg msg;
      msg.player = VideoPlayer_VIDEO;
      msg.cachetime = DVD_MSEC_TO_TIME(50);
      msg.cachetotal = DVD_MSEC_TO_TIME(100);
      msg.timestamp = DVD_NOPTS_VALUE;
      m_messageParent.Put(new CDVDMsgType<SStartMsg>(CDVDMsg::PLAYER_STARTED, msg));
    }
    return false;
  }

  // check for a new picture
  if (decoderState == CDVDVideoCodec::VC_PICTURE)
  {
    bool hasTimestamp = true;

    m_picture.iDuration = frametime;

    // validate picture timing,
    // if both dts/pts invalid, use pts calulated from picture.iDuration
    // if pts invalid use dts, else use picture.pts as passed
    if (m_picture.dts == DVD_NOPTS_VALUE && m_picture.pts == DVD_NOPTS_VALUE)
    {
      m_picture.pts = pts;
      hasTimestamp = false;
    }
    else if (m_picture.pts == DVD_NOPTS_VALUE)
      m_picture.pts = m_picture.dts;

    // use forced aspect if any
    if (m_fForcedAspectRatio != 0.0f)
    {
      m_picture.iDisplayWidth = (int) (m_picture.iDisplayHeight * m_fForcedAspectRatio);
      if (m_picture.iDisplayWidth > m_picture.iWidth)
      {
        m_picture.iDisplayWidth =  m_picture.iWidth;
        m_picture.iDisplayHeight = (int) (m_picture.iDisplayWidth / m_fForcedAspectRatio);
      }
    }

    // set stereo mode if not set by decoder
    if (m_picture.stereoMode.empty())
    {
      std::string stereoMode;
      switch(m_processInfo.GetVideoSettings().m_StereoMode)
      {
        case RENDER_STEREO_MODE_SPLIT_VERTICAL:
          stereoMode = "left_right";
          if (m_processInfo.GetVideoSettings().m_StereoInvert)
            stereoMode = "right_left";
          break;
        case RENDER_STEREO_MODE_SPLIT_HORIZONTAL:
          stereoMode = "top_bottom";
          if (m_processInfo.GetVideoSettings().m_StereoInvert)
            stereoMode = "bottom_top";
          break;
        default:
          stereoMode = m_hints.stereo_mode;
          break;
      }
      if (!stereoMode.empty() && stereoMode != "mono")
      {
        m_picture.stereoMode = stereoMode;
      }
    }

    // if frame has a pts (usually originiating from demux packet), use that
    if (m_picture.pts != DVD_NOPTS_VALUE)
    {
      pts = m_picture.pts;
    }

    double extraDelay = 0.0;
    if (m_picture.iRepeatPicture)
    {
      extraDelay = m_picture.iRepeatPicture * m_picture.iDuration;
      m_picture.iDuration += extraDelay;
    }

    m_picture.pts = pts + extraDelay;
    // guess next frame pts. iDuration is always valid
    if (m_speed != 0)
      pts += m_picture.iDuration * m_speed / abs(m_speed);

    m_outputSate = OutputPicture(&m_picture);

    if (m_outputSate == OUTPUT_AGAIN)
    {
      return true;
    }
    else if (m_outputSate == OUTPUT_ABORT)
    {
      return false;
    }
    else if ((m_outputSate == OUTPUT_DROPPED) && !(m_picture.iFlags & DVP_FLAG_DROPPED))
    {
      m_iDroppedFrames++;
      m_ptsTracker.Flush();
    }

    if (m_syncState == IDVDStreamPlayer::SYNC_STARTING &&
        m_outputSate != OUTPUT_DROPPED &&
        !(m_picture.iFlags & DVP_FLAG_DROPPED))
    {
      m_syncState = IDVDStreamPlayer::SYNC_WAITSYNC;
      SStartMsg msg;
      msg.player = VideoPlayer_VIDEO;
      msg.cachetime = DVD_MSEC_TO_TIME(50); //! @todo implement
      msg.cachetotal = DVD_MSEC_TO_TIME(100); //! @todo implement
      msg.timestamp = hasTimestamp ? (pts + m_renderManager.GetDelay() * 1000) : DVD_NOPTS_VALUE;
      m_messageParent.Put(new CDVDMsgType<SStartMsg>(CDVDMsg::PLAYER_STARTED, msg));
    }

    frametime = (double)DVD_TIME_BASE / m_fFrameRate;
  }

  return true;
}