From 6320659aa46adf4226794468b20a80adb4ad511a Mon Sep 17 00:00:00 2001 From: carlonluca Date: Sat, 27 Feb 2016 02:31:31 +0100 Subject: [PATCH] Fixes for #51 and several improvements. --- .gitignore | 2 +- changelog.txt | 17 +++ piomxtextures_lib/piomxtextures_lib.pro | 2 +- .../qml/POC_TextPosition.qml | 14 +-- .../mediaplayer/openmaxilplayercontrol.cpp | 6 +- .../mediaplayer/openmaxilplayercontrol.h | 2 +- .../openmaxilvideorenderercontrol.cpp | 41 ++++++- piomxtextures_src/omx_mediaprocessor.cpp | 74 +++++++++--- piomxtextures_src/omx_mediaprocessor.h | 27 ++++- piomxtextures_src/omx_textureprovider.cpp | 26 ++++- piomxtextures_src/omx_textureprovider.h | 110 +++++++++++++----- piomxtextures_src/omxplayer_lib/OMXReader.cpp | 16 +++ piomxtextures_src/omxplayer_lib/OMXVideo.cpp | 18 +-- piomxtextures_tools/compile_ffmpeg.sh | 2 +- 14 files changed, 279 insertions(+), 78 deletions(-) diff --git a/.gitignore b/.gitignore index 3bf9465..abdb106 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ tools/build* *.pro.user* -3rdparty* +3rdparty*/* 3rdparty/* openmaxil_backend/3rdparty/* piomxtextures_qt_driver/mediaplayer/.qmake.conf diff --git a/changelog.txt b/changelog.txt index 23fc209..3157775 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,22 @@ Changelog +Version 5.2.0 +============= +1. Bump ffmpeg to 2.8.5. +2. Fixed leaks when video processor is destroyed. + +Version 5.1.0 +============= + +Version 5.0.0 +============= + +Version 4.5.0 +============= + +Version 4.4.0 +============= + Version 4.3.0 ============= 1. Updated for Qt 5.4.0. diff --git a/piomxtextures_lib/piomxtextures_lib.pro b/piomxtextures_lib/piomxtextures_lib.pro index 4b0a7c1..576fe4d 100644 --- a/piomxtextures_lib/piomxtextures_lib.pro +++ b/piomxtextures_lib/piomxtextures_lib.pro @@ -23,7 +23,7 @@ TEMPLATE = lib -VERSION = 5.1.0 +VERSION = 5.2.0 QT += core core-private gui gui-private opengl quick quick-private CONFIG += no_private_qt_headers_warning diff --git a/piomxtextures_pocplayer/qml/POC_TextPosition.qml b/piomxtextures_pocplayer/qml/POC_TextPosition.qml index 786fd4c..5973067 100644 --- a/piomxtextures_pocplayer/qml/POC_TextPosition.qml +++ b/piomxtextures_pocplayer/qml/POC_TextPosition.qml @@ -26,12 +26,12 @@ import "POC_StringUtils.js" as POC_StringUtils // The duration text. Text { - id: textPosition - text: formatText(); + id: textPosition + text: formatText(); - function formatText() { - var position = POC_StringUtils.secondsToHHMMSS(parent.source.position/1000); - var duration = POC_StringUtils.secondsToHHMMSS(parent.source.duration/1000); - return position + "/" + duration; - } + function formatText() { + var position = POC_StringUtils.secondsToHHMMSS(parent.source.position/1000); + var duration = POC_StringUtils.secondsToHHMMSS(parent.source.duration/1000); + return position + "/" + duration; + } } diff --git a/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp b/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp index e6da574..7ee7bcc 100644 --- a/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp +++ b/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.cpp @@ -76,19 +76,19 @@ OpenMAXILPlayerControl::OpenMAXILPlayerControl(QObject *parent) : QMediaPlayerControl(parent) , m_ownStream(false) , m_seekToStartPending(false) - , m_pendingSeekPosition(-1) + , m_pendingSeekPosition(-1) , m_texProvider(make_shared()) , m_mediaProcessor(new OMX_MediaProcessor(m_texProvider)) , m_renderer(NULL) { - logi_debug_func; + logi_debug_func; connect(m_mediaProcessor, SIGNAL(stateChanged(OMX_MediaProcessor::OMX_MediaProcessorState)), this, SLOT(onStateChanged(OMX_MediaProcessor::OMX_MediaProcessorState))); connect(m_mediaProcessor, SIGNAL(mediaStatusChanged(OMX_MediaProcessor::OMX_MediaStatus)), this, SLOT(onMediaStatusChanged(OMX_MediaProcessor::OMX_MediaStatus))); connect(m_mediaProcessor, SIGNAL(metadataChanged(QVariantMap)), - this, SIGNAL(metaDataChanged(QVariantMap))); + this, SIGNAL(metaDataChanged(QVariantMap))); } /*------------------------------------------------------------------------------ diff --git a/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.h b/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.h index 4384790..a53a61c 100644 --- a/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.h +++ b/piomxtextures_qt_driver/mediaplayer/openmaxilplayercontrol.h @@ -127,7 +127,7 @@ private slots: bool m_ownStream; bool m_seekToStartPending; - qint64 m_pendingSeekPosition; + qint64 m_pendingSeekPosition; QMediaContent m_currentResource; diff --git a/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp b/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp index d643b07..5bc3e82 100644 --- a/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp +++ b/piomxtextures_qt_driver/mediaplayer/openmaxilvideorenderercontrol.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef OGL_CONTEXT_FROM_SURFACE #include #endif // OGL_CONTEXT_FROM_SURFACE @@ -37,6 +38,37 @@ #include "omx_logging.h" +/*------------------------------------------------------------------------------ +| definitions ++-----------------------------------------------------------------------------*/ +//#define OMX_RENDER_WATCHDOG +#define OMX_RENDER_WATCHDOG_FILE "/tmp/omx_render_signal" + +#ifdef OMX_RENDER_WATCHDOG +/*------------------------------------------------------------------------------ +| handleWatchdogFile ++-----------------------------------------------------------------------------*/ +inline void handleWatchdogFile() +{ + static QFile f(OMX_RENDER_WATCHDOG_FILE); + static QDateTime lastTouch = QDateTime::currentDateTime(); + + const QDateTime current = QDateTime::currentDateTime(); + if (current.toMSecsSinceEpoch() - lastTouch.toMSecsSinceEpoch() < 1000) + return; + + if (!f.open(QIODevice::WriteOnly)) { + log_warn("Failed to touch " OMX_RENDER_WATCHDOG_FILE "."); + return; + } + + lastTouch = current; + + f.close(); +} + +#endif // OMX_RENDER_WATCHDOG + /*------------------------------------------------------------------------------ | OpenMAXILVideoBuffer class +-----------------------------------------------------------------------------*/ @@ -191,7 +223,7 @@ void OpenMAXILVideoRendererControl::onTexturesReady() // Just take one random texture to determine the size. Do not place // any texture yet in the scene as I can't guarantee it is filled // already with valid data. - m_buffer = new OpenMAXILVideoBuffer( + m_buffer = new OpenMAXILVideoBuffer( QAbstractVideoBuffer::GLTextureHandle, 0 ); @@ -244,11 +276,10 @@ void OpenMAXILVideoRendererControl::onUpdateTriggered() return; if (UNLIKELY(!m_surface || !m_frame || !m_surfaceFormat)) return; - if (UNLIKELY(!m_surface->isActive() && !m_surface->start(*m_surfaceFormat))) log_warn("Failed to start surface."); - GLuint t = m_mediaProcessor->m_provider->getNextTexture(); + const GLuint t = m_mediaProcessor->m_provider->getNextTexture(); // It seems that in some cases the fillBufferDone arrives even after // completely flushing the pipeline. This presents frames to be shown @@ -257,6 +288,10 @@ void OpenMAXILVideoRendererControl::onUpdateTriggered() return; m_buffer->setHandle(t); m_surface->present(*m_frame); + +#ifdef OMX_RENDER_WATCHDOG + handleWatchdogFile(); +#endif // OMX_RENDER_WATCHDOG } /*------------------------------------------------------------------------------ diff --git a/piomxtextures_src/omx_mediaprocessor.cpp b/piomxtextures_src/omx_mediaprocessor.cpp index 567fb3e..f5d2727 100644 --- a/piomxtextures_src/omx_mediaprocessor.cpp +++ b/piomxtextures_src/omx_mediaprocessor.cpp @@ -97,6 +97,8 @@ const char* OMX_MediaProcessor::M_STATUS[] = { #define INVOKE(...) \ QMetaObject::invokeMethod(this, __VA_ARGS__) +#define INVOKE_CONN \ + Qt::QueuedConnection /*------------------------------------------------------------------------------ | get_mem_gpu @@ -136,13 +138,27 @@ static void start_watchdog_once() } #endif // OMX_LOCK_WATCHDOG +/*------------------------------------------------------------------------------ +| OMX_MediaProcessorHelper::onFreeRequest ++-----------------------------------------------------------------------------*/ +void OMX_MediaProcessorHelper::onFreeRequest() +{ + m_provider->free(); + m_provider->deinit(); +} + /*------------------------------------------------------------------------------ | OMX_MediaProcessor::OMX_MediaProcessor +-----------------------------------------------------------------------------*/ OMX_MediaProcessor::OMX_MediaProcessor(OMX_EGLBufferProviderSh provider) : QObject(), m_provider(provider), - m_thread(new OMX_QThread), +#define THREADED_GL +#ifdef THREADED_GL + m_thread(new QThread), +#else + m_thread(QOpenGLContext::globalShareContext()->thread()), +#endif m_state(STATE_INACTIVE), m_mediaStatus(MEDIA_STATUS_NO_MEDIA), m_sendCmd(QMutex::Recursive), @@ -204,7 +220,7 @@ OMX_MediaProcessor::OMX_MediaProcessor(OMX_EGLBufferProviderSh provider) : moveToThread(m_thread); m_thread->start(); - INVOKE("init"); + INVOKE("init", INVOKE_CONN); } /*------------------------------------------------------------------------------ @@ -213,16 +229,21 @@ OMX_MediaProcessor::OMX_MediaProcessor(OMX_EGLBufferProviderSh provider) : void OMX_MediaProcessor::init() { log_info("Initializing GPU context in media processor..."); - m_provider->init(); + + const OMX_MediaProcessorHelper* helper = new OMX_MediaProcessorHelper(m_provider, m_thread); connect(this, SIGNAL(destroyed(QObject*)), - m_provider.get(), SLOT(free())); - connect(this, SIGNAL(destroyed(QObject*)), - m_provider.get(), SLOT(deinit())); + helper, SLOT(onFreeRequest())); connect(this, SIGNAL(destroyed(QObject*)), - m_thread, SLOT(quit())); - connect(m_thread, SIGNAL(finished()), - m_thread, SLOT(deleteLater())); + helper, SLOT(deleteLater())); + if (m_thread != QOpenGLContext::globalShareContext()->thread()) { + connect(this, SIGNAL(destroyed(QObject*)), + m_thread, SLOT(quit())); + connect(m_thread, SIGNAL(finished()), + m_thread, SLOT(deleteLater())); + } + + m_provider->init(); } /*------------------------------------------------------------------------------ @@ -257,7 +278,7 @@ QStringList OMX_MediaProcessor::streams() +-----------------------------------------------------------------------------*/ bool OMX_MediaProcessor::setFilename(const QString& filename) { - return INVOKE("setFilenameWrapper", Q_ARG(QString, filename)); + return INVOKE("setFilenameWrapper", INVOKE_CONN, Q_ARG(QString, filename)); } /*------------------------------------------------------------------------------ @@ -492,7 +513,7 @@ bool OMX_MediaProcessor::playInt() +-----------------------------------------------------------------------------*/ bool OMX_MediaProcessor::play() { - return INVOKE("playInt"); + return INVOKE("playInt", INVOKE_CONN); } /*------------------------------------------------------------------------------ @@ -500,7 +521,7 @@ bool OMX_MediaProcessor::play() +-----------------------------------------------------------------------------*/ bool OMX_MediaProcessor::stop() { - return INVOKE("stopInt"); + return INVOKE("stopInt", INVOKE_CONN); } /*------------------------------------------------------------------------------ @@ -544,7 +565,7 @@ bool OMX_MediaProcessor::stopInt() +-----------------------------------------------------------------------------*/ bool OMX_MediaProcessor::pause() { - return INVOKE("pauseInt"); + return INVOKE("pauseInt", INVOKE_CONN); } /*------------------------------------------------------------------------------ @@ -680,8 +701,8 @@ bool OMX_MediaProcessor::muted() void OMX_MediaProcessor::mediaDecoding() { // See description in the qmakefile. - //#define ENABLE_PROFILE_MAIN_LOOP - //#define ENABLE_PAUSE_FOR_BUFFERING +//#define ENABLE_PROFILE_MAIN_LOOP +//#define ENABLE_PAUSE_FOR_BUFFERING LOG_VERBOSE(LOG_TAG, "Decoding thread started."); emit playbackStarted(); @@ -928,9 +949,30 @@ void OMX_MediaProcessor::mediaDecoding() if (!m_omx_pkt) m_omx_pkt = m_omx_reader->Read(); - if (m_omx_pkt) + if (m_omx_pkt) { sendEos = false; +//#define DUMP_FFMPEG_PACKETS +#ifdef DUMP_FFMPEG_PACKETS + OMXPacket* p = m_omx_pkt; + QFile f("demuxed.txt"); + if (!f.open(QIODevice::WriteOnly | QIODevice::Append)) + log_warn("Failed to open file for writing frames."); + else { + QTextStream s(&f); + s << p->pts << ", " + << p->dts << ", " + << p->now << ", " + << p->duration << ", " + << p->size << ", " + << QByteArray::fromRawData((const char*)p->data, p->size) << ", " + << p->stream_index << ", " + << p->codec_type << "."; + } + f.close(); +#endif + } + if (UNLIKELY(m_omx_reader->IsEof() && !m_omx_pkt)) { // demuxer EOF, but may have not played out data yet if ((m_has_video && m_player_video->GetCached()) || diff --git a/piomxtextures_src/omx_mediaprocessor.h b/piomxtextures_src/omx_mediaprocessor.h index d14e721..7e51398 100644 --- a/piomxtextures_src/omx_mediaprocessor.h +++ b/piomxtextures_src/omx_mediaprocessor.h @@ -67,6 +67,27 @@ class COMXStreamInfo; class OMXVideoConfig; class OMXAudioConfig; +/*------------------------------------------------------------------------------ +| OMX_MediaProcessorHelper class ++-----------------------------------------------------------------------------*/ +class OMX_MediaProcessorHelper : public QObject +{ + Q_OBJECT +public: + OMX_MediaProcessorHelper(OMX_EGLBufferProviderSh provider, QThread* t) { + moveToThread(t); + m_provider = provider; + } + + virtual ~OMX_MediaProcessorHelper() {} + +public slots: + void onFreeRequest(); + +private: + OMX_EGLBufferProviderSh m_provider; +}; + /*------------------------------------------------------------------------------ | OMX_MediaProcessor class +-----------------------------------------------------------------------------*/ @@ -171,7 +192,7 @@ private slots: void flushStreams(double pts); void convertMetaData(); - OMX_QThread* m_thread; + QThread* m_thread; QString m_filename; AVFormatContext* fmt_ctx; @@ -263,9 +284,10 @@ inline OMX_MediaProcessor::OMX_MediaStatus OMX_MediaProcessor::mediaStatus() { | OMX_MediaProcessor::setState +-----------------------------------------------------------------------------*/ inline void OMX_MediaProcessor::setState(OMX_MediaProcessorState state) { - log_verbose("State changing from %s to %s...", STATE_STR[m_state], STATE_STR[state]); if (m_state == state) return; + + log_verbose("State changing from %s to %s...", STATE_STR[m_state], STATE_STR[state]); m_state = state; emit stateChanged(state); } @@ -276,6 +298,7 @@ inline void OMX_MediaProcessor::setState(OMX_MediaProcessorState state) { inline void OMX_MediaProcessor::setMediaStatus(OMX_MediaStatus status) { if (m_mediaStatus == status) return; + log_verbose("Media status changing from %s to %s...", M_STATUS[m_mediaStatus], M_STATUS[status]); m_mediaStatus = status; emit mediaStatusChanged(status); diff --git a/piomxtextures_src/omx_textureprovider.cpp b/piomxtextures_src/omx_textureprovider.cpp index 9867bed..9cf5b59 100644 --- a/piomxtextures_src/omx_textureprovider.cpp +++ b/piomxtextures_src/omx_textureprovider.cpp @@ -39,6 +39,13 @@ #include "omx_globals.h" #include "omx_logging.h" +/*------------------------------------------------------------------------------ +| definitions ++-----------------------------------------------------------------------------*/ +#ifdef DEBUG_TDATA_LEAKS +int OMX_TextureData::count = 0; +#endif // DEBUG_TDATA_LEAKS + /*------------------------------------------------------------------------------ | check_gl_error +-----------------------------------------------------------------------------*/ @@ -87,7 +94,10 @@ OMX_TextureData::OMX_TextureData() : m_eglImage(NULL), m_textureSize(QSize(0, 0)) { - // Do nothing. +#ifdef DEBUG_TDATA_LEAKS + count++; + log_debug("Currently %d texture data around.", count); +#endif // DEBUG_TDATA_LEAKS } /*------------------------------------------------------------------------------ @@ -100,7 +110,10 @@ OMX_TextureData::OMX_TextureData(const OMX_TextureData& textureData) : m_textureSize(textureData.m_textureSize), m_omxBuffer(textureData.m_omxBuffer) { - // Do nothing. +#ifdef DEBUG_TDATA_LEAKS + count++; + log_debug("Currently %d texture data around.", count); +#endif // DEBUG_TDATA_LEAKS } /*------------------------------------------------------------------------------ @@ -108,6 +121,11 @@ OMX_TextureData::OMX_TextureData(const OMX_TextureData& textureData) : +-----------------------------------------------------------------------------*/ OMX_TextureData::~OMX_TextureData() { +#ifdef DEBUG_TDATA_LEAKS + count--; + log_debug("Currently %d texture data around.", count); +#endif // DEBUG_TDATA_LEAKS + if (m_textureData || m_textureId || m_eglImage) log_warn("Loosing pointers to GPU data."); } @@ -122,7 +140,7 @@ void OMX_TextureData::freeData() // Destroy texture, EGL image and free the buffer. if (m_eglImage) { - log_verbose("Freeing KHR image..."); + log_verbose("Freeing KHR image %p...", m_eglImage); if (eglDestroyImageKHR(eglDisplay, m_eglImage) != EGL_TRUE) { LOG_ERROR(LOG_TAG, "Failed to destroy EGLImageKHR: %s.", get_egl_errstr()); } @@ -131,7 +149,7 @@ void OMX_TextureData::freeData() } if (m_textureId) { - log_verbose("Freeing texture..."); + log_verbose("Freeing texture %d...", m_textureId); glDeleteTextures(1, &m_textureId); check_gl_error(); diff --git a/piomxtextures_src/omx_textureprovider.h b/piomxtextures_src/omx_textureprovider.h index af72d29..cdfd768 100644 --- a/piomxtextures_src/omx_textureprovider.h +++ b/piomxtextures_src/omx_textureprovider.h @@ -55,6 +55,7 @@ class QQuickItem; #define TEXTURE_COUNT (OMX_StaticConf::getTextureCount()) //#define DEBUG_TEXTURE_PROVIDER +#define DEBUG_TDATA_LEAKS /*------------------------------------------------------------------------------ | OMX_TextureData class @@ -74,6 +75,10 @@ class OMX_TextureData EGLImageKHR m_eglImage; QSize m_textureSize; OMX_BUFFERHEADERTYPE* m_omxBuffer; + +#ifdef DEBUG_TDATA_LEAKS + static int count; +#endif // DEBUG_TDATA_LEAKS }; /*------------------------------------------------------------------------------ @@ -90,6 +95,7 @@ class OMX_EGLBufferProvider : public QObject , m_currentRenderer(NULL) , m_mutex(QMutex::Recursive) , m_initialized(false) + , m_threadId(0) , m_oglContext(NULL) , m_eglContext(NULL) , m_eglSurface(NULL) @@ -162,6 +168,7 @@ public slots: OMX_TextureData* m_currentRenderer; QMutex m_mutex; bool m_initialized; + Qt::HANDLE m_threadId; // The context to be used to create buffers and textures. QOpenGLContext* m_oglContext; @@ -210,6 +217,14 @@ bool OMX_EGLBufferProvider::init() QMutexLocker locker(&m_mutex); if (m_initialized) return true; + + m_threadId = QThread::currentThreadId(); + + // Get global strictures. + m_eglDisplay = get_egl_display(); + if (!m_eglDisplay) + return false; + if (QOpenGLContext::currentContext()) { log_info("Using old sync OGL architecture."); m_oglContext = QOpenGLContext::currentContext(); @@ -219,20 +234,11 @@ bool OMX_EGLBufferProvider::init() } log_info("Initializing buffer provider..."); - QOpenGLContext* sharedOglContext = QOpenGLContext::globalShareContext(); - if (!sharedOglContext) - return log_err("Failed to get shared OGL context. Please enable it with the proper attr."); - - log_verbose("Creating a new OpenGL context in thread %p.", QThread::currentThreadId()); - m_oglContext = new QOpenGLContext(); - m_oglContext->setShareContext(sharedOglContext); - m_oglContext->makeCurrent(sharedOglContext->surface()); - - // Get global strictures. - m_eglDisplay = get_egl_display(); - if (!m_eglDisplay) - return false; + if (!sharedOglContext) { + log_err("Failed to get shared OGL context. Please enable it with the proper attr."); + abort(); + } EGLContext eglGlobalContext = get_global_egl_context(); if (!eglGlobalContext) @@ -262,12 +268,20 @@ bool OMX_EGLBufferProvider::init() // Create new EGL context. m_eglContext = eglCreateContext(m_eglDisplay, eglConfig, eglGlobalContext, NULL); if (!m_eglContext) - return log_err("Failed to create new EGL context."); + return log_err("Failed to create new EGL context: %d.", eglGetError()); m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, eglConfig, NULL); - if (eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext) != EGL_TRUE) + if (m_eglSurface == EGL_NO_SURFACE) + return log_err("Failed to create pbuffer surface: %d.", eglGetError()); + + if (eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext) == EGL_FALSE) return log_err("Failed to make current EGL ctx."); + log_verbose("Creating a new OpenGL context in thread %p.", QThread::currentThreadId()); + m_oglContext = new QOpenGLContext(); + m_oglContext->setShareContext(sharedOglContext); + m_oglContext->makeCurrent(sharedOglContext->surface()); + return (m_initialized = true); } @@ -321,21 +335,24 @@ inline OMX_TextureData* OMX_EGLBufferProvider::instantiateTexture(const QSize& s EGLint attr[] = {EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE}; GLuint textureId; + + log_verbose("Creating OGL texture..."); glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); + log_verbose("OGL texture %d created...", textureId); // It seems that only 4byte pixels is supported here. //GLubyte* pixel = new GLubyte[size.width()*size.height()*2]; //memset(pixel, 0, size.width()*size.height()*2); - GLubyte* pixel = NULL; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, pixel); + //GLubyte* pixel = NULL; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - log_info("Creating EGLImageKHR..."); + log_verbose("Creating EGLImageKHR..."); EGLImageKHR eglImage = eglCreateImageKHR( m_eglDisplay, m_eglContext, @@ -354,7 +371,7 @@ inline OMX_TextureData* OMX_EGLBufferProvider::instantiateTexture(const QSize& s log_verbose("Creating OMX_TextureData..."); OMX_TextureData* textureData = new OMX_TextureData; textureData->m_textureId = textureId; - textureData->m_textureData = pixel; + textureData->m_textureData = NULL; textureData->m_eglImage = eglImage; textureData->m_textureSize = size; @@ -448,18 +465,29 @@ OMX_TextureData* OMX_EGLBufferProvider::getNextEmptyBuffer() inline void OMX_EGLBufferProvider::free() { QMutexLocker locker(&m_mutex); + + if (eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext) == EGL_FALSE) { + log_err("Failed to make current EGL ctx."); + return; + } + + log_debug("Freeing textures in thread: %p.", QThread::currentThreadId()); foreach (OMX_TextureData* data, m_available) data->freeData(); m_currentDecoder = NULL; m_currentRenderer = NULL; + m_semEmpty.release(TEXTURE_COUNT - m_semEmpty.available()); + + // qDeleteAll only calls delete, does not remove the object from + // the container. + qDeleteAll(m_available); + m_filledQueue.clear(); m_emptyQueue.clear(); m_available.clear(); - m_semEmpty.release(TEXTURE_COUNT - m_semEmpty.available()); - emit texturesFreed(); } @@ -471,24 +499,42 @@ inline void OMX_EGLBufferProvider::deinit() QMutexLocker locker(&m_mutex); if (!m_initialized) return; + if (m_threadId != QThread::currentThreadId()) { + log_err("Internal error. Deinit of texture provide in thrad %p instead of %p.", + QThread::currentThreadId(), m_threadId); + return; + } + + log_debug("Deinit context in thread: %p.", QThread::currentThreadId()); + EGLBoolean ret = EGL_TRUE; // Free EGL surface. - log_verbose("Destroying EGL surface..."); - EGLBoolean ret = eglDestroySurface(m_eglDisplay, m_eglSurface); - if (ret != EGL_TRUE) - log_warn("Failed to destroy EGL surface: %u.", ret); - m_eglSurface = NULL; + if (m_eglSurface) { + log_verbose("Destroying EGL surface..."); + ret = eglDestroySurface(m_eglDisplay, m_eglSurface); + if (ret != EGL_TRUE) + log_warn("Failed to destroy EGL surface: %u.", ret); + m_eglSurface = NULL; + } + + if (eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) + log_err("Failed to make current EGL ctx."); // Free EGL context. - log_verbose("Destroying EGL aux context..."); - ret = eglDestroyContext(m_eglDisplay, m_eglContext); - if (ret != EGL_TRUE) - log_warn("Failed to destroy EGL aux context: %u.", ret); + if (m_eglContext) { + log_verbose("Destroying EGL aux context..."); + ret = eglDestroyContext(m_eglDisplay, m_eglContext); + if (ret != EGL_TRUE) + log_warn("Failed to destroy EGL aux context: %u.", ret); + } // Destroy OGL context. - log_verbose("Destroying OGL aux context..."); - delete m_oglContext; + if (m_oglContext && m_oglContext != QOpenGLContext::globalShareContext()) { + log_verbose("Destroying OGL aux context..."); + delete m_oglContext; + } + m_threadId = 0; m_initialized = false; } diff --git a/piomxtextures_src/omxplayer_lib/OMXReader.cpp b/piomxtextures_src/omxplayer_lib/OMXReader.cpp index 4f61f6d..56209f5 100644 --- a/piomxtextures_src/omxplayer_lib/OMXReader.cpp +++ b/piomxtextures_src/omxplayer_lib/OMXReader.cpp @@ -28,6 +28,8 @@ #include "OMXReader.h" #include "OMXClock.h" +#include "omx_logging.h" + #include #include @@ -159,6 +161,10 @@ bool OMXReader::Open(std::string filename, bool dump_format, bool live /* =false 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; @@ -226,6 +232,11 @@ bool OMXReader::Open(std::string filename, bool dump_format, bool live /* =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; @@ -243,6 +254,11 @@ bool OMXReader::Open(std::string filename, bool dump_format, bool live /* =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) { diff --git a/piomxtextures_src/omxplayer_lib/OMXVideo.cpp b/piomxtextures_src/omxplayer_lib/OMXVideo.cpp index d1dc0d2..82e8dad 100644 --- a/piomxtextures_src/omxplayer_lib/OMXVideo.cpp +++ b/piomxtextures_src/omxplayer_lib/OMXVideo.cpp @@ -71,14 +71,18 @@ // lcarlon: needed callback for OMX componenent. OMX_ERRORTYPE fill_buffer_done_callback(OMX_HANDLETYPE handle, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer) { - (void)pAppData; + (void)pAppData; - if (UNLIKELY(pBuffer->nFlags & OMX_BUFFERFLAG_EOS)) - log_verbose("EOS in FillBufferDone cb."); + if (UNLIKELY(pBuffer->nFlags & OMX_BUFFERFLAG_EOS)) + log_verbose("EOS in FillBufferDone cb."); - COMXVideo* videoDecoder = static_cast(pBuffer->pAppPrivate); - OMX_EGLBufferProvider* provider = videoDecoder->m_provider.get(); - assert(provider->registerFilledBuffer(pBuffer)); +#if 0 + log_debug("Registering filled buffer..."); +#endif + + COMXVideo* videoDecoder = static_cast(pBuffer->pAppPrivate); + OMX_EGLBufferProvider* provider = videoDecoder->m_provider.get(); + provider->registerFilledBuffer(pBuffer); // Get next empty buffer. It is possible none is returned when the provider // was cleaned up. @@ -88,7 +92,7 @@ OMX_ERRORTYPE fill_buffer_done_callback(OMX_HANDLETYPE handle, OMX_PTR pAppData, return OMX_ErrorNone; } - return OMX_FillThisBuffer(handle, empty->m_omxBuffer); + return OMX_FillThisBuffer(handle, empty->m_omxBuffer); } COMXVideo::COMXVideo(OMX_EGLBufferProviderSh provider) : m_video_codec_name("") diff --git a/piomxtextures_tools/compile_ffmpeg.sh b/piomxtextures_tools/compile_ffmpeg.sh index 7a59ad3..25eea33 100755 --- a/piomxtextures_tools/compile_ffmpeg.sh +++ b/piomxtextures_tools/compile_ffmpeg.sh @@ -61,7 +61,7 @@ fi cd 3rdparty/ffmpeg rm -rf ffmpeg_src -git clone git://source.ffmpeg.org/ffmpeg ffmpeg_src -bn2.7.2 --depth=1 +git clone git://source.ffmpeg.org/ffmpeg ffmpeg_src -bn2.8.5 --depth=1 cd ffmpeg_src; export PATH="$COMPILER_PATH":$PATH