bool OMXReader::Close() { if (m_pFormatContext) { if (m_ioContext && m_pFormatContext->pb && m_pFormatContext->pb != m_ioContext) { CLog::Log(LOGWARNING, "CDVDDemuxFFmpeg::Dispose - demuxer changed our byte context behind our back, possible memleak"); m_ioContext = m_pFormatContext->pb; } m_dllAvFormat.avformat_close_input(&m_pFormatContext); } if(m_ioContext) { m_dllAvUtil.av_free(m_ioContext->buffer); m_dllAvUtil.av_free(m_ioContext); } m_ioContext = NULL; m_pFormatContext = NULL; if(m_pFile) { m_pFile->Close(); delete m_pFile; m_pFile = NULL; } m_dllAvFormat.avformat_network_deinit(); m_dllAvUtil.Unload(); m_dllAvCodec.Unload(); m_dllAvFormat.Unload(); m_open = false; m_filename = ""; m_bMatroska = false; m_bAVI = false; m_bMpeg = false; m_video_count = 0; m_audio_count = 0; m_subtitle_count = 0; m_audio_index = -1; m_video_index = -1; m_subtitle_index = -1; m_eof = false; m_chapter_count = 0; m_iCurrentPts = DVD_NOPTS_VALUE; m_speed = DVD_PLAYSPEED_NORMAL; ClearStreams(); return true; }
bool OMXReader::close() { if (avFormatContext) { if (avioContext && avFormatContext->pb && avFormatContext->pb != avioContext) { ofLog(OF_LOG_WARNING, "CDVDDemuxFFmpeg::Dispose - demuxer changed our byte context behind our back, possible memleak"); avioContext = avFormatContext->pb; } avformat_close_input(&avFormatContext); } if(avioContext) { av_free(avioContext->buffer); av_free(avioContext); } avioContext = NULL; avFormatContext = NULL; if(fileObject) { fileObject->close(); delete fileObject; fileObject = NULL; } isOpen = false; fileName = ""; isMatroska = false; isAVI = false; videoCount = 0; audioCount = 0; subtitleCount = 0; audioIndex = -1; videoIndex = -1; subtitleIndex = -1; isEOF = false; chapterCount = 0; currentPTS = DVD_NOPTS_VALUE; speed = DVD_PLAYSPEED_NORMAL; ClearStreams(); return true; }
OMXReader::OMXReader() { m_open = false; m_filename = ""; m_bMatroska = false; m_bAVI = false; g_abort = false; m_pFile = NULL; m_ioContext = NULL; m_pFormatContext = NULL; m_eof = false; m_chapter_count = 0; m_iCurrentPts = DVD_NOPTS_VALUE; for(int i = 0; i < MAX_STREAMS; i++) m_streams[i].extradata = NULL; ClearStreams(); pthread_mutex_init(&m_lock, NULL); }
OMXReader::OMXReader() { isOpen = false; fileName = ""; isMatroska = false; isAVI = false; fileObject = NULL; avioContext = NULL; avFormatContext = NULL; isEOF = false; chapterCount = 0; currentPTS = DVD_NOPTS_VALUE; for(int i = 0; i < MAX_STREAMS; i++) { omxStreams[i].extradata = NULL; } ClearStreams(); pthread_mutex_init(&m_lock, NULL); }
Multiplexer::~Multiplexer() { ClearStreams(); delete m_pdatastreams; }
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; }
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 OMXReader::open(std::string filename, bool doSkipAvProbe) { currentPTS = DVD_NOPTS_VALUE; fileName = filename; speed = DVD_PLAYSPEED_NORMAL; programID = UINT_MAX; AVIOInterruptCB int_cb = { interrupt_cb, NULL }; ClearStreams(); int result = -1; AVInputFormat *iformat = NULL; unsigned char *buffer = NULL; unsigned int flags = READ_TRUNCATED | READ_BITRATE | READ_CHUNKED; if(fileName.substr(0, 8) == "shout://" ) fileName.replace(0, 8, "http://"); if(fileName.substr(0,6) == "mms://" || fileName.substr(0,7) == "mmsh://" || fileName.substr(0,7) == "mmst://" || fileName.substr(0,7) == "mmsu://" || fileName.substr(0,7) == "http://" || fileName.substr(0,7) == "rtmp://" || fileName.substr(0,6) == "udp://" || fileName.substr(0,7) == "rtsp://" ) { doSkipAvProbe = false; // ffmpeg dislikes the useragent from AirPlay urls //int idx = fileName.Find("|User-Agent=AppleCoreMedia"); size_t idx = fileName.find("|"); if(idx != string::npos) fileName = fileName.substr(0, idx); AVDictionary *d = NULL; // Enable seeking if http if(fileName.substr(0,7) == "http://") { av_dict_set(&d, "seekable", "1", 0); } ofLog(OF_LOG_VERBOSE, "OMXPlayer::OpenFile - avformat_open_input %s ", fileName.c_str()); result = avformat_open_input(&avFormatContext, fileName.c_str(), iformat, &d); if(av_dict_count(d) == 0) { ofLog(OF_LOG_VERBOSE, "OMXPlayer::OpenFile - avformat_open_input enabled SEEKING "); if(fileName.substr(0,7) == "http://") avFormatContext->pb->seekable = AVIO_SEEKABLE_NORMAL; } av_dict_free(&d); if(result < 0) { ofLog(OF_LOG_ERROR, "OMXPlayer::OpenFile - avformat_open_input %s ", fileName.c_str()); close(); return false; } } else { fileObject = new File(); if (!fileObject->open(fileName, flags)) { ofLog(OF_LOG_ERROR, "OMXPlayer::OpenFile - %s ", fileName.c_str()); close(); return false; } buffer = (unsigned char*)av_malloc(FFMPEG_FILE_BUFFER_SIZE); avioContext = avio_alloc_context(buffer, FFMPEG_FILE_BUFFER_SIZE, 0, fileObject, read_callback, NULL, seek_callback); avioContext->max_packet_size = 6144; if(avioContext->max_packet_size) avioContext->max_packet_size *= FFMPEG_FILE_BUFFER_SIZE / avioContext->max_packet_size; if(fileObject->IoControl(IOCTRL_SEEK_POSSIBLE, NULL) == 0) avioContext->seekable = 0; av_probe_input_buffer(avioContext, &iformat, fileName.c_str(), NULL, 0, 0); if(!iformat) { ofLog(OF_LOG_ERROR, "OMXPlayer::OpenFile - av_probe_input_buffer %s ", fileName.c_str()); close(); return false; } //#warning experimental //iformat->flags |= AVFMT_SEEK_TO_PTS; avFormatContext = avformat_alloc_context(); avFormatContext->pb = avioContext; result = avformat_open_input(&avFormatContext, fileName.c_str(), iformat, NULL); if(result < 0) { close(); return false; } } // set the interrupt callback, appeared in libavformat 53.15.0 avFormatContext->interrupt_callback = int_cb; isMatroska = strncmp(avFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" isAVI = strcmp(avFormatContext->iformat->name, "avi") == 0; // if format can be nonblocking, let's use that avFormatContext->flags |= AVFMT_FLAG_NONBLOCK; // analyse very short to speed up mjpeg playback start if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && avioContext->seekable == 0) avFormatContext->max_analyze_duration = 500000; if(/*isAVI || */isMatroska) avFormatContext->max_analyze_duration = 0; if(!doSkipAvProbe) { unsigned long long startTime = ofGetElapsedTimeMillis(); result = avformat_find_stream_info(avFormatContext, NULL); unsigned long long endTime = ofGetElapsedTimeMillis(); ofLogNotice(__func__) << "avformat_find_stream_info TOOK " << endTime-startTime << " MS"; if(result < 0) { close(); return false; } } if(!getStreams()) { close(); return false; } if(fileObject) { int64_t len = fileObject->GetLength(); int64_t tim = getStreamLength(); if(len > 0 && tim > 0) { unsigned rate = len * 1000 / tim; unsigned maxrate = rate + 1024 * 1024 / 8; if(fileObject->IoControl(IOCTRL_CACHE_SETRATE, &maxrate) >= 0) ofLog(OF_LOG_VERBOSE, "OMXPlayer::OpenFile - set cache throttle rate to %u bytes per second", maxrate); } } speed = DVD_PLAYSPEED_NORMAL; /* if(dump_format) av_dump_format(avFormatContext, 0, fileName.c_str(), 0);*/ updateCurrentPTS(); isOpen = true; return true; }
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; }
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; }