int JitterBuffer::Write(const RTPDataFrame &frame, int path) {
  std::cout << "==========================================" << std::endl;
  if (path == 0) {
    std::cout << "direct frame: ";
  } else {
    std::cout << "Indirect frame: ";
  }
  std::cout << frame.GetSequenceNumber()
    << " " << frame.GetTimestamp() << "("
    << ConvertTimestamp(frame.GetTimestamp()) << ")" << std::endl;
  std::cout << "buffer: \n\tpackets_in = " << buffer_.size()
    << "\n\tsequence_deadline_ = " << sequence_deadline_ << std::endl;
  std::cout << "==========================================" << std::endl;

  if (path != 0) { // from indirect path
    uint16_t seq = frame.GetSequenceNumber();
    if (seq < sequence_deadline_)
      return 0;
    bench_.insert(std::pair<uint16_t, RTPDataFrame>(seq, frame));
    return 1;
  }

  // the following handles packets from direct path
  if (recv_packets_ == 0) {
    buffer_.push_back(frame);
    sequence_deadline_ = frame.GetSequenceNumber();
    recv_packets_++;
    return 1;
  }
  
  // a too-late-to-enqueue frame 
  if (frame < sequence_deadline_ ||
      ConvertTimestamp(frame.GetTimestamp()) < timestamp_deadline_)
    return 0;

  std::list<RTPDataFrame>::iterator it = --buffer_.end();
  for (; it != --buffer_.begin(); --it) {
    if (*it <= frame)
      break;
  }
  if (it == --buffer_.begin() || *it < frame) {
    buffer_.insert(++it, frame);
    recv_packets_++;
    return 1;
  } else {
    // a repeated frame
    return 0;
  }
}
Exemple #2
0
bool OMXReader::SeekChapter(int chapter, double* startpts)
{
	if(chapter < 1)
	{
		chapter = 1;
	}

	if(m_pFormatContext == NULL)
	{
		return false;
	}

	#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,14,0)
	if(chapter < 1 || chapter > (int)m_pFormatContext->nb_chapters)
	{
		return false;
	}

	AVChapter *ch = m_pFormatContext->chapters[chapter-1];
	double dts = ConvertTimestamp(ch->start, ch->time_base.den, ch->time_base.num);
	return SeekTime(DVD_TIME_TO_MSEC(dts), 0, startpts);
	#else
	return false;
	#endif
}
Exemple #3
0
int OMXReader::getChapter()
{
    if(avFormatContext == NULL
       || currentPTS == DVD_NOPTS_VALUE)
        return 0;
    
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,14,0)
    for(unsigned i = 0; i < avFormatContext->nb_chapters; i++)
    {
        AVChapter *chapter = avFormatContext->chapters[i];
        if(currentPTS >= ConvertTimestamp(chapter->start, chapter->time_base.den, chapter->time_base.num)
           && currentPTS <  ConvertTimestamp(chapter->end,   chapter->time_base.den, chapter->time_base.num))
            return i + 1;
    }
#endif
    return 0;
}
Exemple #4
0
int OMXReader::GetChapter()
{
  if(m_pFormatContext == NULL
  || m_iCurrentPts == DVD_NOPTS_VALUE)
    return 0;

#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,14,0)
  for(unsigned i = 0; i < m_pFormatContext->nb_chapters; i++)
  {
    AVChapter *chapter = m_pFormatContext->chapters[i];
    //if(m_iCurrentPts >= ConvertTimestamp(chapter->start, chapter->time_base.den, chapter->time_base.num)
    //  && m_iCurrentPts <  ConvertTimestamp(chapter->end,   chapter->time_base.den, chapter->time_base.num))
    if(m_iCurrentPts >= ConvertTimestamp(chapter->start, &chapter->time_base)
      && m_iCurrentPts <  ConvertTimestamp(chapter->end, &chapter->time_base))
      return i + 1;
  }
#endif
  return 0;
}
void CDVDDemuxFFmpeg::UpdateCurrentPTS()
{
  m_iCurrentPts = DVD_NOPTS_VALUE;
  for(int i=0;i<MAX_STREAMS;i++)
  {
    AVStream *stream = m_pFormatContext->streams[i];
    if(stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE)
    {
      double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num);
      if(m_iCurrentPts == DVD_NOPTS_VALUE || m_iCurrentPts > ts )
        m_iCurrentPts = ts;
    }
  }
}
Exemple #6
0
void OMXReader::UpdateCurrentPTS()
{
  m_iCurrentPts = DVD_NOPTS_VALUE;
  for(unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
  {
    AVStream *stream = m_pFormatContext->streams[i];
    if(stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE)
    {
      double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num);
      if(m_iCurrentPts == DVD_NOPTS_VALUE || m_iCurrentPts > ts )
        m_iCurrentPts = ts;
    }
  }
}
Exemple #7
0
void OMXReader::updateCurrentPTS()
{
    currentPTS = DVD_NOPTS_VALUE;
    for(unsigned int i = 0; i < avFormatContext->nb_streams; i++)
    {
        AVStream *stream = avFormatContext->streams[i];
        if(stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE)
        {
            double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num);
            if(currentPTS == DVD_NOPTS_VALUE || currentPTS > ts )
            {
                currentPTS = ts;
            }
        }
        //ofLogVerbose(__func__) << "currentPTS: " << currentPTS;
    }
}
Exemple #8
0
bool OMXReader::GetStreams()
{
  if(!m_pFormatContext)
    return false;

  unsigned int    m_program         = UINT_MAX;

  ClearStreams();

  if (m_pFormatContext->nb_programs)
  {
    // look for first non empty stream and discard nonselected programs
    for (unsigned int i = 0; i < m_pFormatContext->nb_programs; i++)
    {
      if(m_program == UINT_MAX && m_pFormatContext->programs[i]->nb_stream_indexes > 0)
        m_program = i;

      if(i != m_program)
        m_pFormatContext->programs[i]->discard = AVDISCARD_ALL;
    }
      if(m_program != UINT_MAX)
      {
        // add streams from selected program
        for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
          AddStream(m_pFormatContext->programs[m_program]->stream_index[i]);
      }
    }

  // if there were no programs or they were all empty, add all streams
  if (m_program == UINT_MAX)
  {
    for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
      AddStream(i);
  }

  if(m_video_count)
    SetActiveStreamInternal(OMXSTREAM_VIDEO, 0);

  if(m_audio_count)
    SetActiveStreamInternal(OMXSTREAM_AUDIO, 0);

  if(m_subtitle_count)
    SetActiveStreamInternal(OMXSTREAM_SUBTITLE, 0);

  int i = 0;
  for(i = 0; i < MAX_OMX_CHAPTERS; i++)
  {
    m_chapters[i].name      = "";
    m_chapters[i].seekto_ms = 0;
    m_chapters[i].ts        = 0;
  }

  m_chapter_count = 0;

  if(m_video_index != -1)
  {
    //m_current_chapter = 0;
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,14,0)
    m_chapter_count = (m_pFormatContext->nb_chapters > MAX_OMX_CHAPTERS) ? MAX_OMX_CHAPTERS : m_pFormatContext->nb_chapters;
    for(i = 0; i < m_chapter_count; i++)
    {
      if(i > MAX_OMX_CHAPTERS)
        break;

      AVChapter *chapter = m_pFormatContext->chapters[i];
      if(!chapter)
        continue;

      //m_chapters[i].seekto_ms = ConvertTimestamp(chapter->start, chapter->time_base.den, chapter->time_base.num) / 1000;
      m_chapters[i].seekto_ms = ConvertTimestamp(chapter->start, &chapter->time_base) / 1000;
      m_chapters[i].ts        = m_chapters[i].seekto_ms / 1000;

#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,83,0)
      AVDictionaryEntry *titleTag = m_dllAvUtil.av_dict_get(m_pFormatContext->chapters[i]->metadata,"title", NULL, 0);
      if (titleTag)
        m_chapters[i].name = titleTag->value;
#else
      if(m_pFormatContext->chapters[i]->title)
        m_chapters[i].name = m_pFormatContext->chapters[i]->title;
#endif
      printf("Chapter : \t%d \t%s \t%8.2f\n", i, m_chapters[i].name.c_str(), m_chapters[i].ts);
    }
  }
#endif

  return true;
}
Exemple #9
0
OMXPacket *OMXReader::Read()
{
  assert(!IsEof());
  
  AVPacket  pkt;
  OMXPacket *m_omx_pkt = NULL;
  int       result = -1;

  if(!m_pFormatContext)
    return NULL;

  Lock();

  // assume we are not eof
  if(m_pFormatContext->pb)
    m_pFormatContext->pb->eof_reached = 0;

  // keep track if ffmpeg doesn't always set these
  pkt.size = 0;
  pkt.data = NULL;
  pkt.stream_index = MAX_OMX_STREAMS;

  result = m_dllAvFormat.av_read_frame(m_pFormatContext, &pkt);
  if (result < 0)
  {
    m_eof = true;
    //FlushRead();
    //m_dllAvCodec.av_free_packet(&pkt);
    UnLock();
    return NULL;
  }
  else if (pkt.size < 0 || pkt.stream_index >= MAX_OMX_STREAMS)
  {
    // XXX, in some cases ffmpeg returns a negative packet size
    if(m_pFormatContext->pb && !m_pFormatContext->pb->eof_reached)
    {
      CLog::Log(LOGERROR, "OMXReader::Read no valid packet");
      //FlushRead();
    }

    m_dllAvCodec.av_free_packet(&pkt);

    m_eof = true;
    UnLock();
    return NULL;
  }

  AVStream *pStream = m_pFormatContext->streams[pkt.stream_index];

  /* only read packets for active streams */
  /*
  if(!IsActive(pkt.stream_index))
  {
    m_dllAvCodec.av_free_packet(&pkt);
    UnLock();
    return NULL;
  }
  */

  // lavf sometimes bugs out and gives 0 dts/pts instead of no dts/pts
  // since this could only happens on initial frame under normal
  // circomstances, let's assume it is wrong all the time
  if(pkt.dts == 0)
    pkt.dts = AV_NOPTS_VALUE;
  if(pkt.pts == 0)
    pkt.pts = AV_NOPTS_VALUE;

  if(m_bMatroska && pStream->codec && pStream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  { // matroska can store different timestamps
    // for different formats, for native stored
    // stuff it is pts, but for ms compatibility
    // tracks, it is really dts. sadly ffmpeg
    // sets these two timestamps equal all the
    // time, so we select it here instead
    if(pStream->codec->codec_tag == 0)
      pkt.dts = AV_NOPTS_VALUE;
    else
      pkt.pts = AV_NOPTS_VALUE;
  }
  // we need to get duration slightly different for matroska embedded text subtitels
  if(m_bMatroska && pStream->codec->codec_id == CODEC_ID_TEXT && pkt.convergence_duration != 0)
    pkt.duration = pkt.convergence_duration;

  if(m_bAVI && pStream->codec && pStream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  {
    // AVI's always have borked pts, specially if m_pFormatContext->flags includes
    // AVFMT_FLAG_GENPTS so always use dts
    pkt.pts = AV_NOPTS_VALUE;
  }

  m_omx_pkt = AllocPacket(pkt.size);
  /* oom error allocation av packet */
  if(!m_omx_pkt)
  {
    m_eof = true;
    m_dllAvCodec.av_free_packet(&pkt);
    UnLock();
    return NULL;
  }

  m_omx_pkt->codec_type = pStream->codec->codec_type;

  /* copy content into our own packet */
  m_omx_pkt->size = pkt.size;

  if (pkt.data)
    memcpy(m_omx_pkt->data, pkt.data, m_omx_pkt->size);

  m_omx_pkt->stream_index = pkt.stream_index;
  GetHints(pStream, &m_omx_pkt->hints);

  //m_omx_pkt->dts = ConvertTimestamp(pkt.dts, pStream->time_base.den, pStream->time_base.num);
  //m_omx_pkt->pts = ConvertTimestamp(pkt.pts, pStream->time_base.den, pStream->time_base.num);
  m_omx_pkt->dts = ConvertTimestamp(pkt.dts, &pStream->time_base);
  m_omx_pkt->pts = ConvertTimestamp(pkt.pts, &pStream->time_base);
  m_omx_pkt->duration = DVD_SEC_TO_TIME((double)pkt.duration * pStream->time_base.num / pStream->time_base.den);

  // used to guess streamlength
  if (m_omx_pkt->dts != DVD_NOPTS_VALUE && (m_omx_pkt->dts > m_iCurrentPts || m_iCurrentPts == DVD_NOPTS_VALUE))
    m_iCurrentPts = m_omx_pkt->dts;

  // check if stream has passed full duration, needed for live streams
  if(pkt.dts != (int64_t)AV_NOPTS_VALUE)
  {
    int64_t duration;
    duration = pkt.dts;
    if(pStream->start_time != (int64_t)AV_NOPTS_VALUE)
      duration -= pStream->start_time;

    if(duration > pStream->duration)
    {
      pStream->duration = duration;
      duration = m_dllAvUtil.av_rescale_rnd(pStream->duration, (int64_t)pStream->time_base.num * AV_TIME_BASE, 
                                            pStream->time_base.den, AV_ROUND_NEAR_INF);
      if ((m_pFormatContext->duration == (int64_t)AV_NOPTS_VALUE)
          ||  (m_pFormatContext->duration != (int64_t)AV_NOPTS_VALUE && duration > m_pFormatContext->duration))
        m_pFormatContext->duration = duration;
    }
  }

  m_dllAvCodec.av_free_packet(&pkt);

  UnLock();
  return m_omx_pkt;
}
Exemple #10
0
DemuxPacket* CDVDDemuxFFmpeg::Read()
{
  AVPacket pkt;
  DemuxPacket* pPacket = NULL;
  // on some cases where the received packet is invalid we will need to return an empty packet (0 length) otherwise the main loop (in CDVDPlayer) 
  // would consider this the end of stream and stop.
  bool bReturnEmpty = false;
  Lock();
  if (m_pFormatContext)
  {
    // assume we are not eof
    if(m_pFormatContext->pb)
      m_pFormatContext->pb->eof_reached = 0;

    // timeout reads after 100ms
    g_urltimeout = GetTickCount() + 100;
    //g_urltimeout = 0;
    int result = 0;
    try
    {
      result = m_dllAvFormat.av_read_frame(m_pFormatContext, &pkt);
    }
    catch(const win32_exception &e)
    {
      e.writelog(__FUNCTION__);
      result = AVERROR(EFAULT);
    }
    g_urltimeout = 0;

    if (result == AVERROR(EINTR) || result == AVERROR(EAGAIN))
    {
      // timeout, probably no real error, return empty packet
      bReturnEmpty = true;
    }
    else if (result < 0)
    {
      Flush();
    }
    else
    {
      // XXX, in some cases ffmpeg returns a negative packet size
      if (pkt.size < 0 || pkt.stream_index >= MAX_STREAMS)
      {
        CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::Read() no valid packet");
        bReturnEmpty = true;
      }
      else
      {
        AVStream *stream = m_pFormatContext->streams[pkt.stream_index];

        if (m_pFormatContext->nb_programs)
        {
          /* check so packet belongs to selected program */
          for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
          {
            if(pkt.stream_index == (int)m_pFormatContext->programs[m_program]->stream_index[i])
            {
              pPacket = CDVDDemuxUtils::AllocateDemuxPacket(pkt.size);
              break;
            }
          }

          if (!pPacket)
            bReturnEmpty = true;
        }
        else
          pPacket = CDVDDemuxUtils::AllocateDemuxPacket(pkt.size);

        if (pPacket)
        {
          // lavf sometimes bugs out and gives 0 dts/pts instead of no dts/pts
          // since this could only happens on initial frame under normal
          // circomstances, let's assume it is wrong all the time
          if(pkt.dts == 0)
            pkt.dts = AV_NOPTS_VALUE;
          if(pkt.pts == 0)
            pkt.pts = AV_NOPTS_VALUE;

          if(m_bMatroska && stream->codec && stream->codec->codec_type == CODEC_TYPE_VIDEO)
          { // matroska can store different timestamps
            // for different formats, for native stored
            // stuff it is pts, but for ms compatibility
            // tracks, it is really dts. sadly ffmpeg
            // sets these two timestamps equal all the
            // time, so we select it here instead
            if(stream->codec->codec_tag == 0)
              pkt.dts = AV_NOPTS_VALUE;
            else
              pkt.pts = AV_NOPTS_VALUE;
          }

          // copy contents into our own packet
          pPacket->iSize = pkt.size;

          // maybe we can avoid a memcpy here by detecting where pkt.destruct is pointing too?
          if (pkt.data)
            memcpy(pPacket->pData, pkt.data, pPacket->iSize);

          pPacket->pts = ConvertTimestamp(pkt.pts, stream->time_base.den, stream->time_base.num);
          pPacket->dts = ConvertTimestamp(pkt.dts, stream->time_base.den, stream->time_base.num);
          pPacket->duration =  DVD_SEC_TO_TIME((double)pkt.duration * stream->time_base.num / stream->time_base.den);

          // used to guess streamlength
          if (pPacket->dts != DVD_NOPTS_VALUE && (pPacket->dts > m_iCurrentPts || m_iCurrentPts == DVD_NOPTS_VALUE))
            m_iCurrentPts = pPacket->dts;


          // check if stream has passed full duration, needed for live streams
          if(pkt.dts != (int64_t)AV_NOPTS_VALUE)
          {
              int64_t duration;
              duration = pkt.dts;
              if(stream->start_time != (int64_t)AV_NOPTS_VALUE)
                duration -= stream->start_time;

              if(duration > stream->duration)
              {
                stream->duration = duration;
                duration = m_dllAvUtil.av_rescale_rnd(stream->duration, stream->time_base.num * AV_TIME_BASE, stream->time_base.den, AV_ROUND_NEAR_INF);
                if(m_pFormatContext->duration == (int64_t)AV_NOPTS_VALUE && m_pFormatContext->file_size > 0
                || m_pFormatContext->duration != (int64_t)AV_NOPTS_VALUE && duration > m_pFormatContext->duration)
                  m_pFormatContext->duration = duration;
              }
          }

          // check if stream seem to have grown since start
          if(m_pFormatContext->file_size > 0 && m_pFormatContext->pb)
          {
            if(m_pFormatContext->pb->pos > m_pFormatContext->file_size)
              m_pFormatContext->file_size = m_pFormatContext->pb->pos;
          }

          pPacket->iStreamId = pkt.stream_index; // XXX just for now
        }
      }
      av_free_packet(&pkt);
    }
  }
  Unlock();

  if (bReturnEmpty && !pPacket)
  {
      pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0);
      if(pPacket)
      {
        pPacket->dts = DVD_NOPTS_VALUE;
        pPacket->pts = DVD_NOPTS_VALUE;
        pPacket->iStreamId = -1;
      }
  }

  if (!pPacket) return NULL;

  // check streams, can we make this a bit more simple?
  if (pPacket && pPacket->iStreamId >= 0 && pPacket->iStreamId <= MAX_STREAMS)
  {
    if (!m_streams[pPacket->iStreamId] ||
        m_streams[pPacket->iStreamId]->pPrivate != m_pFormatContext->streams[pPacket->iStreamId] ||
        m_streams[pPacket->iStreamId]->codec != m_pFormatContext->streams[pPacket->iStreamId]->codec->codec_id)
    {
      // content has changed, or stream did not yet exist
      AddStream(pPacket->iStreamId);
    }
    // we already check for a valid m_streams[pPacket->iStreamId] above
    else if (m_streams[pPacket->iStreamId]->type == STREAM_AUDIO)
    {
      if (((CDemuxStreamAudio*)m_streams[pPacket->iStreamId])->iChannels != m_pFormatContext->streams[pPacket->iStreamId]->codec->channels ||
          ((CDemuxStreamAudio*)m_streams[pPacket->iStreamId])->iSampleRate != m_pFormatContext->streams[pPacket->iStreamId]->codec->sample_rate)
      {
        // content has changed
        AddStream(pPacket->iStreamId);
      }
    }
    else if (m_streams[pPacket->iStreamId]->type == STREAM_VIDEO)
    {
      if (((CDemuxStreamVideo*)m_streams[pPacket->iStreamId])->iWidth != m_pFormatContext->streams[pPacket->iStreamId]->codec->width ||
          ((CDemuxStreamVideo*)m_streams[pPacket->iStreamId])->iHeight != m_pFormatContext->streams[pPacket->iStreamId]->codec->height)
      {
        // content has changed
        AddStream(pPacket->iStreamId);
      }
    }
  }
  return pPacket;
}
RTPDataFrame *JitterBuffer::Read(uint32_t timestamp, int *finished) {
  // timestamp_deadline_ = timestamp + 1;
  
  // timestamp == 0xffffffff means clearing all packets in buffer & bench
  // despite what their timestamps are
  if (timestamp == 0xffffffff && !bench_.empty()) {
    while (!bench_.empty()) {
      RTPDataFrame frame(bench_.begin()->second);
      if (frame.GetSequenceNumber() >= sequence_deadline_) {
        std::list<RTPDataFrame>::iterator it = --buffer_.end();
        for (; it != --buffer_.begin(); --it) {
          if (*it <= frame)
            break;
        }
        if (it == --buffer_.begin() || *it < frame) {
          buffer_.insert(++it, frame);
          recv_packets_++;
        }
      }
      bench_.erase(bench_.begin());
    }
  }

  std::cout << "+++++++++++++++++++++++++++++++++++++++++" << std::endl;
  if (buffer_.empty()) {
    std::cout << "empty buffer()" << std::endl;
    *finished = 1;
    return NULL;
  }

  std::cout << "sequence_deadline: " << sequence_deadline_ << std::endl;
  std::cout << "buffer_head: " << buffer_.front().GetSequenceNumber() 
    << " " << buffer_.front().GetTimestamp() 
    << "(" << ConvertTimestamp(buffer_.front().GetTimestamp()) << ")"
    << std::endl;
  std::cout << "buffer_tail: " << buffer_.back().GetSequenceNumber()
    << " " << buffer_.back().GetTimestamp()
    << "(" << ConvertTimestamp(buffer_.back().GetTimestamp()) << ")"
    << std::endl;
  
  RTPDataFrame *pframe = NULL;
  uint32_t last_timestamp = ConvertTimestamp(buffer_.back().GetTimestamp());

  if (buffer_.front().GetSequenceNumber() == sequence_deadline_) {
    bench_.erase(buffer_.front().GetSequenceNumber());
    if (timestamp == 0xffffffff || ConvertTimestamp(buffer_.front().GetTimestamp()) + min_length_ <= last_timestamp) {
      pframe = new RTPDataFrame(buffer_.front());
      sequence_deadline_ = pframe->GetSequenceNumber() + 1;
      buffer_.pop_front();
    } else {
      *finished = 1;
      return NULL;
    }
  } else {
    std::map<uint16_t, RTPDataFrame>::iterator it = 
      bench_.find(sequence_deadline_);
    if (it != bench_.end()) {
      // expected packet in bench (received from indirect path)
      if (timestamp == 0xffffffff || ConvertTimestamp(it->second.GetTimestamp()) + min_length_ <= last_timestamp) {
        pframe = new RTPDataFrame(it->second);
        recv_packets_++;
        sequence_deadline_ = pframe->GetSequenceNumber() + 1;
        bench_.erase(it);
      } else {
        *finished = 1;
        return NULL;
      }
    } else {
      // expected packet is lost
      // look for the packet with smallest sequence in buffer & bench
      uint16_t i = sequence_deadline_ + 1;
      bool flag = false;
      for (; i < buffer_.front().GetSequenceNumber(); i++) {
        if ((it = bench_.find(i)) != bench_.end()) {
          flag = true;
          break;
        }
      }
      // i is the smallest sequence number
      if (!flag) {
        // i == buffer_.front().GetSequence()
        bench_.erase(i);
        if (timestamp == 0xffffffff || ConvertTimestamp(buffer_.front().GetTimestamp()) + min_length_ <= last_timestamp) {
          // it's time for playing this packet
          sequence_deadline_ = i + 1;
          pframe = new RTPDataFrame(buffer_.front());
          buffer_.pop_front();
        } else {
          *finished = 1;
          return NULL;
        }
      } else {
        if (timestamp == 0xffffffff || ConvertTimestamp(it->second.GetTimestamp()) + min_length_ <= last_timestamp) {
          sequence_deadline_ = i + 1;
          pframe = new RTPDataFrame(it->second);
          bench_.erase(it);
        } else {
          *finished = 1;
          return NULL;
        }
      }
    }
  }
  
  // check next frame's timestamp, determine whether finished
  if (buffer_.empty()) {
    // reading a group of frames with same timestamp finished
    *finished = 1;
  } else {
    // look for the packet with smallest sequence in buffer & bench
    std::map<uint16_t, RTPDataFrame>::iterator it;
    bool flag = false;
    uint16_t i = sequence_deadline_;
    for (; i < buffer_.front().GetSequenceNumber(); i++) {
      if ((it = bench_.find(i)) != bench_.end()) {
        flag = true;
        break;
      }
    }
    if (!flag) {
      bench_.erase(i);
      if (timestamp == 0xffffffff || ConvertTimestamp(buffer_.front().GetTimestamp()) + min_length_ <= last_timestamp) {
        // not finished yet
        *finished = 0;
      } else {
        *finished = 1;
      }
    } else {
      if (timestamp == 0xffffffff || ConvertTimestamp(it->second.GetTimestamp()) + min_length_ <= last_timestamp) {
        *finished = 0;
      } else {
        *finished = 1;
      }
      // move this packet from bench to buffer
      // make it faster in the next calling of Read()
      buffer_.push_front(it->second);
      recv_packets_++;
      bench_.erase(it);
    }
  }
  return pframe;
}
Exemple #12
0
bool OMXReader::getStreams()
{
    if(!avFormatContext)
        return false;
    
    unsigned int    programID         = UINT_MAX;
    
    ClearStreams();
    
    if (avFormatContext->nb_programs)
    {
        // look for first non empty stream and discard nonselected programs
        for (unsigned int i = 0; i < avFormatContext->nb_programs; i++)
        {
            if(programID == UINT_MAX && avFormatContext->programs[i]->nb_stream_indexes > 0)
                programID = i;
            
            if(i != programID)
                avFormatContext->programs[i]->discard = AVDISCARD_ALL;
        }
        if(programID != UINT_MAX)
        {
            // add streams from selected program
            for (unsigned int i = 0; i < avFormatContext->programs[programID]->nb_stream_indexes; i++)
                addStream(avFormatContext->programs[programID]->stream_index[i]);
        }
    }
    
    // if there were no programs or they were all empty, add all streams
    if (programID == UINT_MAX)
    {
        for (unsigned int i = 0; i < avFormatContext->nb_streams; i++)
            addStream(i);
    }
    
    if(videoCount)
        setActiveStreamInternal(OMXSTREAM_VIDEO, 0);
    
    if(audioCount)
        setActiveStreamInternal(OMXSTREAM_AUDIO, 0);
    
    if(subtitleCount)
        setActiveStreamInternal(OMXSTREAM_SUBTITLE, 0);
    
    int i = 0;
    for(i = 0; i < MAX_OMX_CHAPTERS; i++)
    {
        omxChapters[i].name      = "";
        omxChapters[i].seekto_ms = 0;
        omxChapters[i].ts        = 0;
    }
    
    chapterCount = 0;
    
    if(videoIndex != -1)
    {
        //m_current_chapter = 0;
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,14,0)
        chapterCount = (avFormatContext->nb_chapters > MAX_OMX_CHAPTERS) ? MAX_OMX_CHAPTERS : avFormatContext->nb_chapters;
        for(i = 0; i < chapterCount; i++)
        {
            if(i > MAX_OMX_CHAPTERS)
                break;
            
            AVChapter *chapter = avFormatContext->chapters[i];
            if(!chapter)
                continue;
            
            omxChapters[i].seekto_ms = ConvertTimestamp(chapter->start, chapter->time_base.den, chapter->time_base.num) / 1000;
            omxChapters[i].ts        = omxChapters[i].seekto_ms / 1000;
            
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,83,0)
            AVDictionaryEntry *titleTag = av_dict_get(avFormatContext->chapters[i]->metadata,"title", NULL, 0);
            if (titleTag)
                omxChapters[i].name = titleTag->value;
#else
            if(avFormatContext->chapters[i]->title)
                omxChapters[i].name = avFormatContext->chapters[i]->title;
#endif
            printf("Chapter : \t%d \t%s \t%8.2f\n", i, omxChapters[i].name.c_str(), omxChapters[i].ts);
        }
    }
#endif
    
    return true;
}
DWORD WINAPI reading_thread(void *param) {
    static const int ABM_SAMPLELENGTH = 4;					// approximate duration of one sample in ms
    static const int ABM_TP_PACKAGESIZE = 12;				// number of bytes in one package of thirdparty data
    static const int ABM_TP_TIME_OFFSET = 3;				// offset (in bytes) of where the third party timestamp starts
    static const int ABM_TP_DATA_OFFSET = 10;				// offset (in bytes) of where the third party data starts
    static const int ABM_TIME_PACKAGESIZE = 4;				// number of bytes in one timestamp package
    static const int ABM_RAW_PACKAGESIZE = 16;				// number of bytes in one raw data package
    static const int ABM_RAW_CHANNEL1_OFFSET = 6;			// offset (in bytes) until channel 1 starts

    std::deque<float> raw_data;								// raw data as received
    std::deque<unsigned int> raw_data_ts;					// timestamps for the raw data (ms)
    std::deque<unsigned char> events;						// events as received
    std::deque<unsigned int> events_ts;						// timestamps for the events (ms)
    unsigned char latest_event = 0;							//

    while (running) {
        {
            concurrency::critical_section::scoped_lock lock(bci_mutex);
            int rawCount, thirdPartySize;
            unsigned char * thirdParty = GetThirdPartyData(thirdPartySize);

            float * raw = GetRawData(rawCount);
            unsigned char * timeStamps = GetTimeStampsStreamData(TIMESTAMP_RAW);

            if (raw) {
                for (int i = 0; i < rawCount; ++i) {
                    int offset = ABM_RAW_PACKAGESIZE * i + ABM_RAW_CHANNEL1_OFFSET;

                    raw_data.insert(raw_data.end(), raw + offset, raw + offset + num_channels);
                    offset = ABM_TIME_PACKAGESIZE * i;
                    int new_ts = ConvertTimestamp(timeStamps + offset);

                    if (i % 2 == 0) {
                        // sensor packets come in pairs; we artificially move the timestamp of
                        // the earlier part of each pair back one sample period for consistency
                        new_ts -= ABM_SAMPLELENGTH;
                    }
                    raw_data_ts.push_back(new_ts);
                }
            }

            if (thirdParty) {
                int numEvents = thirdPartySize / ABM_TP_PACKAGESIZE;
                for (int i = 0; i < numEvents; ++i) {
                    int offset = i * ABM_TP_PACKAGESIZE;
                    events_ts.push_back(ConvertTimestamp(thirdParty + offset + ABM_TP_TIME_OFFSET));
                    events.push_back(thirdParty[offset + ABM_TP_DATA_OFFSET]);
                }
            }
        }

        {
            concurrency::critical_section::scoped_lock lock(queue_mutex);

            while (!raw_data_ts.empty()) {
                while (events_ts.size() && events_ts.front() <= raw_data_ts.front()) {
                    latest_event = events.front();

                    events.pop_front();
                    events_ts.pop_front();
                }

                DataBlock db;
                db.timestamp = raw_data_ts.front();
                db.thirdparty = latest_event;

                for (int i = 0; i < num_channels; ++i) {
                    db.data.push_back(raw_data.front());
                    raw_data.pop_front();
                }

                data_queue.push_back(db);
                raw_data_ts.pop_front();
            }
        }
        assert(raw_data.empty());

        Sleep(10); // called 100 times per second
        if (!running) {
            return 0;
        }
    }
    return 0;
}