From 27e0a4e6031b26816093deb2afb3da97ebfbbd3e Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Tue, 7 Feb 2017 21:35:58 +0100 Subject: [PATCH] [DEV] Continue integration for a better player video --- tools/player-video/appl/ClientProperty.cpp | 89 +++++++- tools/player-video/appl/ClientProperty.hpp | 8 + tools/player-video/appl/MediaDecoder.cpp | 201 +++++++++++++++++- tools/player-video/appl/MediaDecoder.hpp | 24 +++ tools/player-video/appl/Windows.cpp | 97 ++++++++- tools/player-video/appl/Windows.hpp | 6 + tools/player-video/appl/widget/Connection.cpp | 177 ++++----------- tools/player-video/appl/widget/Connection.hpp | 46 ++-- tools/player-video/appl/widget/ListViewer.cpp | 16 +- tools/player-video/appl/widget/ListViewer.hpp | 2 +- .../player-video/appl/widget/VideoPlayer.cpp | 2 +- tools/player-video/data/gui-connection.xml | 9 +- tools/player-video/data/gui.xml | 8 + tools/player-video/lutin_zeus-player-video.py | 2 + .../service-video/appl/main-service-video.cpp | 38 ++-- 15 files changed, 512 insertions(+), 213 deletions(-) diff --git a/tools/player-video/appl/ClientProperty.cpp b/tools/player-video/appl/ClientProperty.cpp index 24a86b1..4077b75 100644 --- a/tools/player-video/appl/ClientProperty.cpp +++ b/tools/player-video/appl/ClientProperty.cpp @@ -26,10 +26,40 @@ #include #include +appl::ClientProperty::ClientProperty() { + address = "127.0.0.1"; + port = 1983; +} + +ejson::Object appl::ClientProperty::toJson() { + ejson::Object out; + out.add("user", ejson::String(fromUser)); + out.add("pass", ejson::String(pass)); + out.add("address", ejson::String(address)); + out.add("port", ejson::Number(port)); + return out; +} + +void appl::ClientProperty::fromJson(ejson::Object _obj) { + fromUser = _obj["user"].toString().get(); + toUser = fromUser; + pass = _obj["pass"].toString().get(); + address = _obj["address"].toString().get(); + port = _obj["port"].toNumber().getU64(); +} + void appl::ClientProperty::connect() { // Generate IP and Port in the client interface - connection.propertyIp.set(address); - connection.propertyPort.set(port); + if (address == "") { + connection.propertyIp.set("127.0.0.1"); + } else { + connection.propertyIp.set(address); + } + if (port == 0) { + connection.propertyPort.set(1983); + } else { + connection.propertyPort.set(port); + } // Connection depending on the mode requested if (fromUser == toUser) { bool ret = connection.connect(fromUser, pass); @@ -45,7 +75,7 @@ void appl::ClientProperty::connect() { APPL_ERROR(" ==> NOT Connected to '" << toUser << "' with '" << fromUser << "'"); return; } else { - APPL_INFO(" ==> Connected with '" << toUser << "'"); + APPL_INFO(" ==> Connected with '" << toUser << "' with '" << fromUser << "'"); } } else { bool ret = connection.connect(toUser); @@ -58,6 +88,59 @@ void appl::ClientProperty::connect() { } } +void appl::ClientProperty::setLogin(std::string _login) { + fromUser = ""; + toUser = ""; + // separate loggin and IP adress ... + std::string login; + std::vector listElem = etk::split(_login, '~'); + if (listElem.size() == 0) { + APPL_ERROR("Not enouth element in the login ..."); + return; + } + fromUser = listElem[0]; + toUser = listElem[0]; + if (listElem.size() == 1) { + // connnect on local host ... nothing to do + } else { + std::vector listElem2 = etk::split(listElem[1], ':'); + if (listElem2.size() >= 1) { + address = listElem2[0]; + } + if (listElem2.size() >= 2) { + port = etk::string_to_uint32_t(listElem2[1]); + } + } +} + +std::string appl::ClientProperty::getLogin() { + std::string out = fromUser; + bool hasTild = false; + if (address != "") { + if (hasTild == false) { + out += "~" ; + hasTild = true; + } + out += address; + } + if ( port != 1983 + && port != 0) { + if (hasTild == false) { + out += "~" ; + hasTild = true; + } + out += ":" + etk::to_string(port); + } + return out; +} + +void appl::ClientProperty::setPassword(std::string _password) { + pass = _password; +} + +std::string appl::ClientProperty::getPassword() { + return pass; +} #include ESIGNAL_DECLARE_SIGNAL(ememory::SharedPtr); diff --git a/tools/player-video/appl/ClientProperty.hpp b/tools/player-video/appl/ClientProperty.hpp index 1d68555..15eff13 100644 --- a/tools/player-video/appl/ClientProperty.hpp +++ b/tools/player-video/appl/ClientProperty.hpp @@ -14,6 +14,7 @@ #include #include +#include namespace appl { class ClientProperty { @@ -24,8 +25,15 @@ namespace appl { std::string address; uint16_t port; zeus::Client connection; + ClientProperty(); void connect(); void disconnect(); + ejson::Object toJson(); + void fromJson(ejson::Object _obj); + void setLogin(std::string _login); + std::string getLogin(); + void setPassword(std::string _password); + std::string getPassword(); }; } diff --git a/tools/player-video/appl/MediaDecoder.cpp b/tools/player-video/appl/MediaDecoder.cpp index 6319b59..767b951 100644 --- a/tools/player-video/appl/MediaDecoder.cpp +++ b/tools/player-video/appl/MediaDecoder.cpp @@ -17,6 +17,34 @@ #include #include #include +#include + +#define BUFFER_SIZE_GET_SLOT (1024*512) + + + +static int g_readFunc(void* _opaque, uint8_t* _buf, int _bufSize) { + if (_opaque == nullptr) { + return 0; + } + return static_cast(_opaque)->readFunc(_buf, _bufSize); +} + +static int g_writeFunc(void* _opaque, uint8_t* _buf, int _bufSize) { + if (_opaque == nullptr) { + return 0; + } + return static_cast(_opaque)->writeFunc(_buf, _bufSize); +} + +static int64_t g_seekFunc(void* _opaque, int64_t _offset, int _whence) { + if (_opaque == nullptr) { + return 0; + } + return static_cast(_opaque)->seekFunc(_offset, _whence); +} + + static void init_ffmpeg() { static bool isInit = false; @@ -132,6 +160,7 @@ void appl::MessageElementAudio::configure(audio::format _format, uint32_t _sampl appl::MediaDecoder::MediaDecoder() { init_ffmpeg(); + m_IOContext = nullptr; m_formatContext = nullptr; m_videoDecoderContext = nullptr; m_audioDecoderContext = nullptr; @@ -315,7 +344,7 @@ double appl::MediaDecoder::getFps(AVCodecContext *_avctx) { void appl::MediaDecoder::init(ememory::SharedPtr _property, uint32_t _mediaId) { // TODO : Correct this later ... We first download the media and after we play it - // TODO : We need to down load only a small part ... + // TODO : We need to download only a small part ... // get the requested node: if (_property == nullptr) { APPL_ERROR("Request play of not handle property ==> nullptr"); @@ -328,37 +357,187 @@ void appl::MediaDecoder::init(ememory::SharedPtr _property, uint zeus::service::ProxyVideo remoteServiceVideo = _property->connection.getService("video"); // remove all media (for test) if (remoteServiceVideo.exist() == false) { - APPL_ERROR("Vide servie is ==> 'not alive'"); + APPL_ERROR("Video service is ==> 'not alive'"); return; } - // TODO : Do it better ... - zeus::ProxyFile dataFile = remoteServiceVideo.mediaGet(_mediaId).wait().get(); + m_remoteFileHandle = remoteServiceVideo.mediaGet(_mediaId).wait().get(); + + std::string mimeType = m_remoteFileHandle.getMineType().wait().get(); + uint64_t fileSize = m_remoteFileHandle.getSize().wait().get(); + // pre-allcocate data file size: + m_remoteBuffer.resize(fileSize, 0); + // start with loading of 1 Mo + auto futData = m_remoteFileHandle.getPart(0, BUFFER_SIZE_GET_SLOT); + futData.wait(); + if (futData.hasError() == true) { + APPL_ERROR("Error when loading data (First 1 MB)"); + } + zeus::Raw buffer = futData.get(); + memcpy(&m_remoteBuffer[0], buffer.data(), buffer.size()); + m_remoteBufferFillSection.push_back(std::pair(0,buffer.size())); + m_remoteBufferReadPosition = 0; + m_remoteProperty = _property; + m_remoteMediaId = _mediaId; - std::string mimeType = dataFile.getMineType().wait().get(); // create temporary file: + /* etk::FSNode tmpFile("CACHE:videoPlayer." + zeus::getExtention(mimeType)); APPL_WARNING("Store in tmpFile : " << tmpFile << " ==> " << tmpFile.getName()); std::string sha512String = zeus::storeInFile(dataFile, tmpFile.getName()); APPL_WARNING("Store in tmpFile : " << tmpFile << " ==> " << tmpFile.getFileSystemName() << " DONE"); - init(tmpFile.getFileSystemName()); + */ + init(""); // TODO : init(tmpFile); } +int appl::MediaDecoder::readFunc(uint8_t* _buf, int _bufSize) { + APPL_ERROR("call read ... " << m_remoteBufferReadPosition << " size=" << _bufSize); + // check if enought data: + bool find = false; + for (auto &it : m_remoteBufferFillSection) { + if ( m_remoteBufferReadPosition >= it.first + && m_remoteBufferReadPosition < it.second) { + find = true; + // part already download... + if (it.second - m_remoteBufferReadPosition < _bufSize) { + // missing data ==> reduce copy size + _bufSize = it.second - m_remoteBufferReadPosition; + } + break; + } + } + if (find == false) { + // No data in the buffer + return 0; + } + memcpy(_buf, &m_remoteBuffer[m_remoteBufferReadPosition], _bufSize); + m_remoteBufferReadPosition += _bufSize; + return _bufSize; +} + +int appl::MediaDecoder::writeFunc(uint8_t* _buf, int _bufSize) { + APPL_ERROR("call write ..."); + return _bufSize; +} + +int64_t appl::MediaDecoder::seekFunc(int64_t _offset, int _whence) { + int64_t lastPosition = m_remoteBufferReadPosition; + switch (_whence) { + case AVSEEK_SIZE: + APPL_ERROR("call seek 'SIZE' ... " << m_remoteBuffer.size()); + return m_remoteBuffer.size(); + case AVSEEK_FORCE: + APPL_ERROR("call seek 'FORCE' ... pos=" << _offset << " size=" << m_remoteBuffer.size()); + m_remoteBufferReadPosition = _offset; + break; + case SEEK_SET: + APPL_ERROR("call seek 'SET' ... pos=" << _offset << " size=" << m_remoteBuffer.size()); + m_remoteBufferReadPosition = _offset; + break; + case SEEK_CUR: + APPL_ERROR("call seek 'CUR' ... _offset=" << _offset << " size=" << m_remoteBuffer.size()); + m_remoteBufferReadPosition += _offset; + break; + case SEEK_END: + APPL_ERROR("call seek 'END' ... _end=" << _offset << " size=" << m_remoteBuffer.size()); + m_remoteBufferReadPosition = m_remoteBuffer.size()-_offset; + break; + default: + APPL_ERROR("Unknow the _whence=" << _whence); + return AVERROR(EINVAL); + } + if (m_remoteBufferReadPosition < 0 ) { + APPL_WARNING("Request seek before start of the File"); + m_remoteBufferReadPosition = 0; + } + if (m_remoteBufferReadPosition > m_remoteBuffer.size()) { + APPL_WARNING("Request seek after end of the File"); + m_remoteBufferReadPosition = m_remoteBuffer.size()-1; + } + if (lastPosition != m_remoteBufferReadPosition) { + checkIfWeNeedMoreDataFromNetwork(); + } + return m_remoteBufferReadPosition; +} + +void appl::MediaDecoder::checkIfWeNeedMoreDataFromNetwork() { + // check if enought data: + bool find = false; + auto it = m_remoteBufferFillSection.begin(); + if (it == m_remoteBufferFillSection.end()) { + // no data in the buffer... + //Get some + // start with loading of 1 Mo + auto futData = m_remoteFileHandle.getPart(0, BUFFER_SIZE_GET_SLOT); + futData.andThen([=](zeus::Future _fut) mutable { + return true; + }); + /* + futData.wait(); + if (futData.hasError() == true) { + APPL_ERROR("Error when loading data (First 1 MB)"); + } + zeus::Raw buffer = futData.get(); + memcpy(&m_remoteBuffer[0], buffer.data(), buffer.size()); + m_remoteBufferFillSection.push_back(std::pair(0,buffer.size())); + return; + */ + } + /* + for (auto &it : m_remoteBufferFillSection) { + if ( m_remoteBufferReadPosition >= it.first + && m_remoteBufferReadPosition < it.second) { + find = true; + // part already download... + if (it.second - m_remoteBufferReadPosition < _bufSize) { + // missing data ==> reduce copy size + _bufSize = it.second - m_remoteBufferReadPosition; + } + break; + } + } + if (find == false) { + // No data in the buffer + return; + } + */ +} + void appl::MediaDecoder::init(const std::string& _filename) { m_updateVideoTimeStampAfterSeek = false; m_sourceFilename = _filename; ethread::setName("ffmpegThread"); // open input file, and allocate format context - if (avformat_open_input(&m_formatContext, m_sourceFilename.c_str(), nullptr, nullptr) < 0) { - APPL_ERROR("Could not open source file " << m_sourceFilename); - exit(1); - } + #ifdef APPL_USE_GENERIC_FFMPEG + if (avformat_open_input(&m_formatContext, m_sourceFilename.c_str(), nullptr, nullptr) < 0) { + APPL_ERROR("Could not open source file " << m_sourceFilename); + return; + } + #else + + if (!(m_formatContext = avformat_alloc_context())) { + APPL_ERROR("Could not create Format context"); + return; + } + m_bufferFFMPEG.resize(1024*1024); // 1Mo buffer is good enought + m_IOContext = avio_alloc_context(&m_bufferFFMPEG[0], m_bufferFFMPEG.size(), 0 /* can not write */, this, g_readFunc, g_writeFunc, g_seekFunc); + if (m_IOContext == nullptr) { + APPL_ERROR("Could not create IO stream"); + return; + } + // set IO read and write interface + m_formatContext->pb = m_IOContext; + if (avformat_open_input(&m_formatContext, nullptr, nullptr, nullptr) < 0) { + APPL_ERROR("Could not open source file " << m_sourceFilename); + return; + } + #endif // retrieve stream information if (avformat_find_stream_info(m_formatContext, nullptr) < 0) { APPL_ERROR("Could not find stream information"); // TODO : check this, this will create a memeory leak - return;; + return; } m_duration = echrono::Duration(double(m_formatContext->duration)/double(AV_TIME_BASE)); APPL_INFO("Stream duration : " << m_duration); diff --git a/tools/player-video/appl/MediaDecoder.hpp b/tools/player-video/appl/MediaDecoder.hpp index 5b19569..40b100b 100644 --- a/tools/player-video/appl/MediaDecoder.hpp +++ b/tools/player-video/appl/MediaDecoder.hpp @@ -10,12 +10,14 @@ #include