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); }
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); }
bool CDVDDemuxFFmpeg::SeekByte(__int64 pos) { Lock(); int ret = m_dllAvFormat.av_seek_frame(m_pFormatContext, -1, pos, AVSEEK_FLAG_BYTE); if(ret >= 0) UpdateCurrentPTS(); Unlock(); return (ret >= 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); }
bool OMXReader::Open(std::string filename, bool dump_format) { if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load()) return false; m_iCurrentPts = DVD_NOPTS_VALUE; m_filename = filename; m_speed = DVD_PLAYSPEED_NORMAL; m_program = UINT_MAX; const AVIOInterruptCB int_cb = { interrupt_cb, NULL }; ClearStreams(); m_dllAvFormat.av_register_all(); m_dllAvFormat.avformat_network_init(); m_dllAvUtil.av_log_set_level(AV_LOG_QUIET); int result = -1; AVInputFormat *iformat = NULL; unsigned char *buffer = NULL; unsigned int flags = READ_TRUNCATED | READ_BITRATE | READ_CHUNKED; #ifndef STANDALONE if( CFileItem(m_filename, false).IsInternetStream() ) flags |= READ_CACHED; #endif if(m_filename.substr(0, 8) == "shout://" ) m_filename.replace(0, 8, "http://"); if(m_filename.substr(0,6) == "mms://" || m_filename.substr(0,7) == "http://" || m_filename.substr(0,7) == "rtmp://" || m_filename.substr(0,6) == "udp://") { // ffmpeg dislikes the useragent from AirPlay urls //int idx = m_filename.Find("|User-Agent=AppleCoreMedia"); size_t idx = m_filename.find("|"); if(idx != string::npos) m_filename = m_filename.substr(0, idx); result = m_dllAvFormat.avformat_open_input(&m_pFormatContext, m_filename.c_str(), iformat, NULL); if(result < 0) { CLog::Log(LOGERROR, "COMXPlayer::OpenFile - avformat_open_input %s ", m_filename.c_str()); Close(); return false; } } else { m_pFile = new CFile(); if (!m_pFile->Open(m_filename, flags)) { CLog::Log(LOGERROR, "COMXPlayer::OpenFile - %s ", m_filename.c_str()); Close(); return false; } buffer = (unsigned char*)m_dllAvUtil.av_malloc(FFMPEG_FILE_BUFFER_SIZE); m_ioContext = m_dllAvFormat.avio_alloc_context(buffer, FFMPEG_FILE_BUFFER_SIZE, 0, m_pFile, dvd_file_read, NULL, dvd_file_seek); m_ioContext->max_packet_size = 6144; if(m_ioContext->max_packet_size) m_ioContext->max_packet_size *= FFMPEG_FILE_BUFFER_SIZE / m_ioContext->max_packet_size; if(m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL) == 0) m_ioContext->seekable = 0; m_dllAvFormat.av_probe_input_buffer(m_ioContext, &iformat, m_filename.c_str(), NULL, 0, 0); if(!iformat) { CLog::Log(LOGERROR, "COMXPlayer::OpenFile - av_probe_input_buffer %s ", m_filename.c_str()); Close(); return false; } m_pFormatContext = m_dllAvFormat.avformat_alloc_context(); m_pFormatContext->pb = m_ioContext; result = m_dllAvFormat.avformat_open_input(&m_pFormatContext, m_filename.c_str(), iformat, NULL); if(result < 0) { Close(); return false; } } // set the interrupt callback, appeared in libavformat 53.15.0 m_pFormatContext->interrupt_callback = int_cb; m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0; m_bMpeg = strcmp(m_pFormatContext->iformat->name, "mpeg") == 0; // if format can be nonblocking, let's use that m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; // analyse very short to speed up mjpeg playback start if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0) m_pFormatContext->max_analyze_duration = 500000; #ifdef STANDALONE if(/*m_bAVI || */m_bMatroska) m_pFormatContext->max_analyze_duration = 0; #endif result = m_dllAvFormat.avformat_find_stream_info(m_pFormatContext, NULL); if(result < 0) { Close(); return false; } if(!GetStreams()) { Close(); return false; } if(m_pFile) { int64_t len = m_pFile->GetLength(); int64_t tim = GetStreamLength(); if(len > 0 && tim > 0) { unsigned rate = len * 1000 / tim; unsigned maxrate = rate + 1024 * 1024 / 8; if(m_pFile->IoControl(IOCTRL_CACHE_SETRATE, &maxrate) >= 0) CLog::Log(LOGDEBUG, "COMXPlayer::OpenFile - set cache throttle rate to %u bytes per second", maxrate); } } printf("file : %s reult %d format %s audio streams %d video streams %d chapters %d subtitles %d\n", m_filename.c_str(), result, m_pFormatContext->iformat->name, m_audio_count, m_video_count, m_chapter_count, m_subtitle_count); m_speed = DVD_PLAYSPEED_NORMAL; if(dump_format) m_dllAvFormat.av_dump_format(m_pFormatContext, 0, m_filename.c_str(), 0); UpdateCurrentPTS(); m_open = true; return true; }
bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput) { AVInputFormat* iformat = NULL; std::string strFile; m_iCurrentPts = DVD_NOPTS_VALUE; m_speed = DVD_PLAYSPEED_NORMAL; if (!pInput) return false; if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load()) { CLog::Log(LOGERROR,"CDVDDemuxFFmpeg::Open - failed to load ffmpeg libraries"); return false; } // register codecs m_dllAvFormat.av_register_all(); m_dllAvFormat.url_set_interrupt_cb(interrupt_cb); // could be used for interupting ffmpeg while opening a file (eg internet streams) // url_set_interrupt_cb(NULL); m_pInput = pInput; strFile = m_pInput->GetFileName(); bool streaminfo = true; /* set to true if we want to look for streams before playback*/ if( m_pInput->GetContent().length() > 0 ) { std::string content = m_pInput->GetContent(); /* check if we can get a hint from content */ if( content.compare("audio/aacp") == 0 ) iformat = m_dllAvFormat.av_find_input_format("aac"); else if( content.compare("audio/aac") == 0 ) iformat = m_dllAvFormat.av_find_input_format("aac"); else if( content.compare("audio/mpeg") == 0 ) iformat = m_dllAvFormat.av_find_input_format("mp3"); else if( content.compare("video/mpeg") == 0 ) iformat = m_dllAvFormat.av_find_input_format("mpeg"); else if( content.compare("video/flv") == 0 ) iformat = m_dllAvFormat.av_find_input_format("flv"); else if( content.compare("video/x-flv") == 0 ) iformat = m_dllAvFormat.av_find_input_format("flv"); /* these are likely pure streams, and as such we don't */ /* want to try to look for streaminfo before playback */ if( iformat ) streaminfo = false; } if( m_pInput->IsStreamType(DVDSTREAM_TYPE_FFMPEG) ) { g_urltimeout = GetTickCount() + 10000; // special stream type that makes avformat handle file opening // allows internal ffmpeg protocols to be used if( m_dllAvFormat.av_open_input_file(&m_pFormatContext, strFile.c_str(), iformat, FFMPEG_FILE_BUFFER_SIZE, NULL) < 0 ) { CLog::Log(LOGDEBUG, "Error, could not open file %s", strFile.c_str()); Dispose(); return false; } } else { g_urltimeout = 0; // initialize url context to be used as filedevice URLContext* context = (URLContext*)m_dllAvUtil.av_mallocz(sizeof(struct URLContext) + strFile.length() + 1); context->prot = &dvd_file_protocol; context->priv_data = (void*)m_pInput; context->max_packet_size = FFMPEG_FILE_BUFFER_SIZE; if (m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)) { context->max_packet_size = FFMPEG_DVDNAV_BUFFER_SIZE; context->is_streamed = 1; } if (m_pInput->IsStreamType(DVDSTREAM_TYPE_TV)) { if(m_pInput->Seek(0, SEEK_POSSIBLE) == 0) context->is_streamed = 1; // this actually speeds up channel changes by almost a second // however, it alsa makes player not buffer anything, this // leads to buffer underruns in audio renderer //if(context->is_streamed) // streaminfo = false; } else { if(m_pInput->Seek(0, SEEK_POSSIBLE) == 0) context->is_streamed = 1; } #if LIBAVFORMAT_VERSION_INT >= (52<<16) context->filename = (char *) &context[1]; #endif strcpy(context->filename, strFile.c_str()); // open our virtual file device if(m_dllAvFormat.url_fdopen(&m_ioContext, context) < 0) { CLog::Log(LOGERROR, "%s - Unable to init io context", __FUNCTION__); m_dllAvUtil.av_free(context); Dispose(); return false; } if( iformat == NULL ) { // let ffmpeg decide which demuxer we have to open AVProbeData pd; BYTE probe_buffer[2048]; // init probe data pd.buf = probe_buffer; pd.filename = strFile.c_str(); // read data using avformat's buffers pd.buf_size = m_dllAvFormat.get_buffer(m_ioContext, pd.buf, sizeof(probe_buffer)); if (pd.buf_size == 0) { CLog::Log(LOGERROR, "%s - error reading from input stream, %s", __FUNCTION__, strFile.c_str()); return false; } // restore position again m_dllAvFormat.url_fseek(m_ioContext , 0, SEEK_SET); iformat = m_dllAvFormat.av_probe_input_format(&pd, 1); if (!iformat) { CLog::Log(LOGERROR, "%s - error probing input format, %s", __FUNCTION__, strFile.c_str()); return false; } } // open the demuxer if (m_dllAvFormat.av_open_input_stream(&m_pFormatContext, m_ioContext, strFile.c_str(), iformat, NULL) < 0) { CLog::Log(LOGERROR, "Error, could not open file %s", strFile.c_str()); Dispose(); return false; } } // we need to know if this is matroska later m_bMatroska = strcmp(m_pFormatContext->iformat->name, "matroska") == 0; // in combination with libdvdnav seek, av_find_stream_info wont work // so we do this for files only if (streaminfo) { if (m_pInput->IsStreamType(DVDSTREAM_TYPE_TV)) { /* too speed up livetv channel changes, only analyse very short */ if(m_pInput->Seek(0, SEEK_POSSIBLE) == 0) m_pFormatContext->max_analyze_duration = 500000; } CLog::Log(LOGDEBUG, "%s - av_find_stream_info starting", __FUNCTION__); int iErr = m_dllAvFormat.av_find_stream_info(m_pFormatContext); if (iErr < 0) { CLog::Log(LOGWARNING,"could not find codec parameters for %s", strFile.c_str()); if (m_pFormatContext->nb_streams == 1 && m_pFormatContext->streams[0]->codec->codec_id == CODEC_ID_AC3) { // special case, our codecs can still handle it. } else { Dispose(); return false; } } CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__); } // reset any timeout g_urltimeout = 0; // if format can be nonblocking, let's use that m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; // print some extra information m_dllAvFormat.dump_format(m_pFormatContext, 0, strFile.c_str(), 0); UpdateCurrentPTS(); // add the ffmpeg streams to our own stream array m_program = 0; if (m_pFormatContext->nb_programs) { // discard nonselected programs for (unsigned int i = 0; i < m_pFormatContext->nb_programs; i++) { if(i != m_program) m_pFormatContext->programs[m_program]->discard = AVDISCARD_ALL; } // 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]); } else { for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++) AddStream(i); } return true; }
bool OMXReader::Open(std::string filename, bool dump_format, bool live /* =false */, float timeout /* = 0.0f */, std::string cookie /* = "" */, std::string user_agent /* = "" */) { if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load()) return false; timeout_default_duration = (int64_t) (timeout * 1e9); m_iCurrentPts = DVD_NOPTS_VALUE; m_filename = filename; m_speed = DVD_PLAYSPEED_NORMAL; m_program = UINT_MAX; const AVIOInterruptCB int_cb = { interrupt_cb, NULL }; RESET_TIMEOUT(3); ClearStreams(); m_dllAvFormat.av_register_all(); m_dllAvFormat.avformat_network_init(); m_dllAvUtil.av_log_set_level(dump_format ? AV_LOG_INFO:AV_LOG_QUIET); int result = -1; AVInputFormat *iformat = NULL; unsigned char *buffer = NULL; unsigned int flags = READ_TRUNCATED | READ_BITRATE | READ_CHUNKED; m_pFormatContext = m_dllAvFormat.avformat_alloc_context(); if (!m_pFormatContext) { log_err("Failed to create format context."); return false; } // set the interrupt callback, appeared in libavformat 53.15.0 m_pFormatContext->interrupt_callback = int_cb; // if format can be nonblocking, let's use that m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; if(m_filename.substr(0, 8) == "shout://" ) m_filename.replace(0, 8, "http://"); if(m_filename.substr(0,6) == "mms://" || m_filename.substr(0,7) == "mmsh://" || m_filename.substr(0,7) == "mmst://" || m_filename.substr(0,7) == "mmsu://" || m_filename.substr(0,7) == "http://" || m_filename.substr(0,8) == "https://" || m_filename.substr(0,7) == "rtmp://" || m_filename.substr(0,6) == "udp://" || m_filename.substr(0,7) == "rtsp://" || m_filename.substr(0,6) == "rtp://" || m_filename.substr(0,6) == "ftp://" || m_filename.substr(0,7) == "sftp://" || m_filename.substr(0,6) == "smb://") { // ffmpeg dislikes the useragent from AirPlay urls //int idx = m_filename.Find("|User-Agent=AppleCoreMedia"); size_t idx = m_filename.find("|"); if(idx != string::npos) m_filename = m_filename.substr(0, idx); AVDictionary *d = NULL; // Enable seeking if http, ftp if(!live && (m_filename.substr(0,7) == "http://" || m_filename.substr(0,6) == "ftp://" || m_filename.substr(0,7) == "sftp://" || m_filename.substr(0,6) == "smb://")) { av_dict_set(&d, "seekable", "1", 0); if(!cookie.empty()) { av_dict_set(&d, "cookies", cookie.c_str(), 0); } if(!user_agent.empty()) { av_dict_set(&d, "user_agent", user_agent.c_str(), 0); } } CLog::Log(LOGDEBUG, "COMXPlayer::OpenFile - avformat_open_input %s ", m_filename.c_str()); result = m_dllAvFormat.avformat_open_input(&m_pFormatContext, m_filename.c_str(), iformat, &d); if(av_dict_count(d) == 0) { CLog::Log(LOGDEBUG, "COMXPlayer::OpenFile - avformat_open_input enabled SEEKING "); if(m_filename.substr(0,7) == "http://") m_pFormatContext->pb->seekable = AVIO_SEEKABLE_NORMAL; } av_dict_free(&d); if(result < 0) { CLog::Log(LOGERROR, "COMXPlayer::OpenFile - avformat_open_input %s ", m_filename.c_str()); Close(); return false; } } else { m_pFile = new CFile(); if (!m_pFile->Open(m_filename, flags)) { CLog::Log(LOGERROR, "COMXPlayer::OpenFile - %s ", m_filename.c_str()); Close(); return false; } buffer = (unsigned char*)m_dllAvUtil.av_malloc(FFMPEG_FILE_BUFFER_SIZE); m_ioContext = m_dllAvFormat.avio_alloc_context(buffer, FFMPEG_FILE_BUFFER_SIZE, 0, m_pFile, dvd_file_read, NULL, dvd_file_seek); if (!m_ioContext) { log_err("Failed to create avio context."); return false; } m_ioContext->max_packet_size = 6144; if(m_ioContext->max_packet_size) m_ioContext->max_packet_size *= FFMPEG_FILE_BUFFER_SIZE / m_ioContext->max_packet_size; if(m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL) == 0) m_ioContext->seekable = 0; m_dllAvFormat.av_probe_input_buffer(m_ioContext, &iformat, m_filename.c_str(), NULL, 0, 0); if(!iformat) { CLog::Log(LOGERROR, "COMXPlayer::OpenFile - av_probe_input_buffer %s ", m_filename.c_str()); Close(); return false; } m_pFormatContext->pb = m_ioContext; if (!m_pFormatContext->internal) { log_err("AVFormat internal null."); abort(); } result = m_dllAvFormat.avformat_open_input(&m_pFormatContext, m_filename.c_str(), iformat, NULL); if(result < 0) { Close(); return false; } } m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0; // analyse very short to speed up mjpeg playback start if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0) m_pFormatContext->max_analyze_duration = 500000; if(/*m_bAVI || */m_bMatroska) m_pFormatContext->max_analyze_duration = 0; if (live) m_pFormatContext->flags |= AVFMT_FLAG_NOBUFFER; result = m_dllAvFormat.avformat_find_stream_info(m_pFormatContext, NULL); if(result < 0) { Close(); return false; } if(!GetStreams()) { Close(); return false; } if(m_pFile) { int64_t len = m_pFile->GetLength(); int64_t tim = GetStreamLength(); if(len > 0 && tim > 0) { unsigned rate = len * 1000 / tim; unsigned maxrate = rate + 1024 * 1024 / 8; if(m_pFile->IoControl(IOCTRL_CACHE_SETRATE, &maxrate) >= 0) CLog::Log(LOGDEBUG, "COMXPlayer::OpenFile - set cache throttle rate to %u bytes per second", maxrate); } } m_speed = DVD_PLAYSPEED_NORMAL; if(dump_format) m_dllAvFormat.av_dump_format(m_pFormatContext, 0, m_filename.c_str(), 0); UpdateCurrentPTS(); m_open = true; return true; }
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); }