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; } }
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 }
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; }
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; } } }
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; } } }
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; } }
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; }
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; }
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; }
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; }