#include "Application.h"
#include "ApplicationMessenger.h"
#include "settings/AdvancedSettings.h"
+#include "android/jni/Build.h"
#include "xbmc/guilib/FrameBufferObject.h"
return VC_ERROR;
}
- std::map<int64_t,Frame*>::iterator it = p->in_queue.begin();
- frame = it->second;
+ std::list<Frame*>::iterator it = p->in_queue.begin();
+ frame = *it;
ret = frame->status;
*buffer = frame->medbuf;
void Process()
{
Frame* frame;
- int32_t w, h, dw, dh;
+ int32_t w, h;
int decode_done = 0;
- int32_t keyframe = 0;
- int32_t unreadable = 0;
MediaSource::ReadOptions readopt;
// GLuint texid;
sp<MetaData> outFormat = p->decoder->getFormat();
outFormat->findInt32(kKeyWidth , &w);
outFormat->findInt32(kKeyHeight, &h);
-
- // The OMX.SEC decoder doesn't signal the modified width/height
- if (p->decoder_component && (w & 15 || h & 15) && !strncmp(p->decoder_component, "OMX.SEC", 7))
- {
- if (((w + 15)&~15) * ((h + 15)&~15) * 3/2 == frame->medbuf->range_length())
- {
- w = (w + 15)&~15;
- h = (h + 15)&~15;
- frame->width = w;
- frame->height = h;
- }
- }
frame->medbuf->meta_data()->findInt64(kKeyTime, &(frame->pts));
}
else if (frame->status == INFO_FORMAT_CHANGED)
}
else if (p->texwidth != frame->width || p->texheight != frame->height)
{
- p->UninitializeEGL();
+ p->ReleaseEGL();
p->InitializeEGL(frame->width, frame->height);
}
- if (p->free_queue.empty())
- {
- CLog::Log(LOGERROR, "%s::%s - Error: No free output buffers\n", CLASSNAME, __func__);
- if (frame->medbuf)
- frame->medbuf->release();
- free(frame);
- continue;
- }
-
ANativeWindowBuffer* graphicBuffer = frame->medbuf->graphicBuffer()->getNativeBuffer();
native_window_set_buffers_timestamp(p->mVideoNativeWindow.get(), frame->pts * 1000);
int err = p->mVideoNativeWindow.get()->queueBuffer(p->mVideoNativeWindow.get(), graphicBuffer);
if (!p->drop_state)
{
p->free_mutex.lock();
- while (!p->free_queue.size())
- usleep(10000);
- std::list<std::pair<EGLImageKHR, int> >::iterator itfree = p->free_queue.begin();
- int cur_slot = itfree->second;
- p->fbo.BindToTexture(GL_TEXTURE_2D, p->slots[cur_slot].texid);
+
+ stSlot* cur_slot = p->getFreeSlot();
+ if (!cur_slot)
+ {
+ CLog::Log(LOGERROR, "STF: No free output buffers\n");
+ continue;
+ }
+
+ p->fbo.BindToTexture(GL_TEXTURE_2D, cur_slot->texid);
p->fbo.BeginRender();
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, p->mVideoTextureId);
GLfloat texMatrix[16];
- // const GLfloat texMatrix[] = {
- // 1, 0, 0, 0,
- // 0, -1, 0, 0,
- // 0, 0, 1, 0,
- // 0, 1, 0, 1
- // };
p->GetSurfaceTextureTransformMatrix(texMatrix);
glUniformMatrix4fv(p->mTexMatrixHandle, 1, GL_FALSE, texMatrix);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
- // glDeleteTextures(1, &texid);
- // eglDestroyImageKHR(p->eglDisplay, img);
p->fbo.EndRender();
glBindTexture(GL_TEXTURE_2D, 0);
- frame->eglimg = p->slots[cur_slot].eglimg;
- p->busy_queue.push_back(std::pair<EGLImageKHR, int>(*itfree));
- p->free_queue.erase(itfree);
+ frame->eglimg = cur_slot->eglimg;
p->free_mutex.unlock();
}
}
#if defined(DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s: >>> pushed OUT frame; w:%d, h:%d, dw:%d, dh:%d, kf:%d, ur:%d, img:%p, tm:%d\n", CLASSNAME, frame->width, frame->height, dw, dh, keyframe, unreadable, frame->eglimg, XbmcThreads::SystemClockMillis() - time);
+ CLog::Log(LOGDEBUG, "%s: >>> pushed OUT frame; w:%d, h:%d, img:%p, tm:%d\n", CLASSNAME, frame->width, frame->height, frame->eglimg, XbmcThreads::SystemClockMillis() - time);
#endif
p->out_mutex.lock();
while (!decode_done && !m_bStop);
if (p->eglInitialized)
- p->UninitializeEGL();
+ p->ReleaseEGL();
}
};
CLog::Log(LOGDEBUG, "%s::Open\n", CLASSNAME);
#endif
+ CLog::Log(LOGDEBUG,
+ "CStageFrightVideo - p:%s, d:%s, b:%s - m:%s, b:%s, m:%s, h:%s",
+ CJNIBuild::PRODUCT.c_str(), CJNIBuild::DEVICE.c_str(), CJNIBuild::BOARD.c_str(),
+ CJNIBuild::MANUFACTURER.c_str(), CJNIBuild::BRAND.c_str(), CJNIBuild::MODEL.c_str(), CJNIBuild::HARDWARE.c_str());
+
CSingleLock lock(g_graphicsContext);
// stagefright crashes with null size. Trap this...
if (p->m_g_advancedSettings->m_stagefrightConfig.useSwRenderer)
p->quirks |= QuirkSWRender;
- sp<MetaData> outFormat;
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- //Vector<String8> matchingCodecs;
-
p->meta = new MetaData;
if (p->meta == NULL)
{
if (p->source == NULL || p->client == NULL)
{
+ p->meta = NULL;
+ p->source = NULL;
+ p->decoder = NULL;
CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Cannot obtain source / client");
return false;
}
if (p->client->connect() != OK)
{
+ p->meta = NULL;
+ p->source = NULL;
delete p->client;
p->client = NULL;
CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Cannot connect OMX client");
if ((p->quirks & QuirkSWRender) == 0)
if (!p->InitSurfaceTexture())
{
+ p->meta = NULL;
+ p->source = NULL;
delete p->client;
p->client = NULL;
CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Cannot allocate texture");
if (!(p->decoder != NULL && p->decoder->start() == OK))
{
+ p->meta = NULL;
+ p->source = NULL;
p->decoder = NULL;
return false;
}
- outFormat = p->decoder->getFormat();
+ sp<MetaData> outFormat = p->decoder->getFormat();
if (!outFormat->findInt32(kKeyWidth, &p->width) || !outFormat->findInt32(kKeyHeight, &p->height)
|| !outFormat->findInt32(kKeyColorFormat, &p->videoColorFormat))
+ {
+ p->meta = NULL;
+ p->source = NULL;
+ p->decoder = NULL;
return false;
+ }
const char *component;
if (outFormat->findCString(kKeyDecoderComponent, &component))
}
}
+ int32_t cropLeft, cropTop, cropRight, cropBottom;
cropLeft = cropTop = cropRight = cropBottom = 0;
if (!outFormat->findRect(kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom))
{
frame->medbuf = p->getBuffer(demuxer_bytes);
if (!frame->medbuf)
{
+ CLog::Log(LOGWARNING, "STF: Cannot get input buffer\n");
free(frame);
return VC_ERROR;
}
frame->medbuf->meta_data()->setInt64(kKeyTime, frame->pts);
p->in_mutex.lock();
- p->framecount++;
- p->in_queue.insert(std::pair<int64_t, Frame*>(p->framecount, frame));
+ p->in_queue.push_back(frame);
p->in_condition.notify();
p->in_mutex.unlock();
}
if (pDvdVideoPicture->format == RENDER_FMT_EGLIMG)
{
pDvdVideoPicture->eglimg = frame->eglimg;
+ if (pDvdVideoPicture->eglimg == EGL_NO_IMAGE_KHR)
+ pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
+ else
+ LockBuffer(pDvdVideoPicture->eglimg);
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, ">>> pic dts:%f, pts:%llu, img:%p, tm:%d\n", pDvdVideoPicture->dts, frame->pts, pDvdVideoPicture->eglimg, XbmcThreads::SystemClockMillis() - time);
#endif
return true;
}
-void CStageFrightVideo::Close()
+void CStageFrightVideo::Dispose()
{
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, "%s::Close\n", CLASSNAME);
CLog::Log(LOGDEBUG, "Stopping omxcodec\n");
#endif
if (p->decoder != NULL)
+ {
p->decoder->stop();
+ p->decoder = NULL;
+ }
if (p->client)
+ {
p->client->disconnect();
+ delete p->client;
+ }
+ p->meta = NULL;
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, "Cleaning IN(%d)\n", p->in_queue.size());
#endif
- std::map<int64_t,Frame*>::iterator it;
+ std::list<Frame*>::iterator it;
while (!p->in_queue.empty())
{
it = p->in_queue.begin();
- frame = it->second;
+ frame = *it;
p->in_queue.erase(it);
if (frame->medbuf)
frame->medbuf->release();
free(frame);
}
-
+ for (int i=0; i<INBUFCOUNT; ++i)
+ {
+ if (p->inbuf[i])
+ {
+ p->inbuf[i]->setObserver(NULL);
+ p->inbuf[i]->release();
+ p->inbuf[i] = NULL;
+ }
+ }
+ p->source = NULL;
+
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, "Cleaning libstagefright\n", p->in_queue.size());
#endif
#endif
if (p->decoder_component)
free(&p->decoder_component);
-
- delete p->client;
-
- for (int i=0; i<INBUFCOUNT; ++i)
- {
- if (p->inbuf[i])
- {
- p->inbuf[i]->setObserver(NULL);
- p->inbuf[i]->release();
- p->inbuf[i] = NULL;
- }
- }
}
void CStageFrightVideo::Reset(void)
#endif
Frame* frame;
p->in_mutex.lock();
- std::map<int64_t,Frame*>::iterator it;
+ std::list<Frame*>::iterator it;
while (!p->in_queue.empty())
{
it = p->in_queue.begin();
- frame = it->second;
+ frame = *it;
p->in_queue.erase(it);
if (frame->medbuf)
frame->medbuf->release();
free(frame);
}
p->resetting = true;
- p->framecount = 0;
p->in_mutex.unlock();
}
void CStageFrightVideo::LockBuffer(EGLImageKHR eglimg)
{
- #if defined(DEBUG_VERBOSE)
+#if defined(DEBUG_VERBOSE)
unsigned int time = XbmcThreads::SystemClockMillis();
#endif
p->free_mutex.lock();
- std::list<std::pair<EGLImageKHR, int> >::iterator it = p->free_queue.begin();
- for(;it != p->free_queue.end(); ++it)
+ stSlot* slot = p->getSlot(eglimg);
+ if (!slot)
{
- if ((*it).first == eglimg)
- break;
- }
- if (it == p->free_queue.end())
- {
- p->busy_queue.push_back(std::pair<EGLImageKHR, int>(*it));
+ CLog::Log(LOGDEBUG, "STF: LockBuffer: Unknown img(%p)", eglimg);
p->free_mutex.unlock();
return;
}
+ slot->use_cnt++;
+
#if defined(DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "Locking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time);
+ CLog::Log(LOGDEBUG, "STF: LockBuffer: Locking %p: cnt:%d tm:%d\n", eglimg, slot->use_cnt, XbmcThreads::SystemClockMillis() - time);
#endif
-
- p->busy_queue.push_back(std::pair<EGLImageKHR, int>(*it));
- p->free_queue.erase(it);
p->free_mutex.unlock();
}
void CStageFrightVideo::ReleaseBuffer(EGLImageKHR eglimg)
{
- #if defined(DEBUG_VERBOSE)
+#if defined(DEBUG_VERBOSE)
unsigned int time = XbmcThreads::SystemClockMillis();
#endif
p->free_mutex.lock();
- int cnt = 0;
- std::list<std::pair<EGLImageKHR, int> >::iterator it = p->busy_queue.begin();
- std::list<std::pair<EGLImageKHR, int> >::iterator itfree;
- for(;it != p->busy_queue.end(); ++it)
+ stSlot* slot = p->getSlot(eglimg);
+ if (!slot)
{
- if ((*it).first == eglimg)
- {
- cnt++;
- if (cnt==1)
- itfree = it;
- else
- break;
- }
+ CLog::Log(LOGDEBUG, "STF: ReleaseBuffer: Unknown img(%p)", eglimg);
+ p->free_mutex.unlock();
+ return;
}
- if (it == p->busy_queue.end() && !cnt)
+ if (slot->use_cnt == 0)
{
+ CLog::Log(LOGDEBUG, "STF: ReleaseBuffer: already unlocked img(%p)", eglimg);
p->free_mutex.unlock();
return;
}
+ slot->use_cnt--;
+
#if defined(DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "Unlocking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time);
+ CLog::Log(LOGDEBUG, "STF: ReleaseBuffer: Unlocking %p: cnt:%d tm:%d\n", eglimg, slot->use_cnt, XbmcThreads::SystemClockMillis() - time);
#endif
-
- if (cnt==1)
- {
- p->free_queue.push_back(std::pair<EGLImageKHR, int>(*itfree));
- p->busy_queue.erase(itfree);
- }
p->free_mutex.unlock();
}
inbuf[i]->setObserver(this);
}
+ inbuf[i]->reset();
inbuf[i]->add_ref();
- inbuf[i]->set_range(0, size);
return inbuf[i];
}
return false;
}
+stSlot* CStageFrightVideoPrivate::getSlot(EGLImageKHR eglimg)
+{
+ for (int i=0; i<NUMFBOTEX; ++i)
+ if (texslots[i].eglimg == eglimg)
+ return &(texslots[i]);
+
+ return NULL;
+}
+
+stSlot* CStageFrightVideoPrivate::getFreeSlot()
+{
+ for (int i=0; i<NUMFBOTEX; ++i)
+ if (texslots[i].use_cnt == 0)
+ return &(texslots[i]);
+
+ return NULL;
+}
+
void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader)
{
#if defined(DEBUG_VERBOSE)
for (int i=0; i<NUMFBOTEX; ++i)
{
- glGenTextures(1, &(slots[i].texid));
- glBindTexture(GL_TEXTURE_2D, slots[i].texid);
+ glGenTextures(1, &(texslots[i].texid));
+ glBindTexture(GL_TEXTURE_2D, texslots[i].texid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- slots[i].eglimg = eglCreateImageKHR(eglDisplay, eglContext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(slots[i].texid),imageAttributes);
- free_queue.push_back(std::pair<EGLImageKHR, int>(slots[i].eglimg, i));
-
+ texslots[i].eglimg = eglCreateImageKHR(eglDisplay, eglContext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(texslots[i].texid),imageAttributes);
+ texslots[i].use_cnt = 0;
}
glBindTexture(GL_TEXTURE_2D, 0);
#endif
}
-void CStageFrightVideoPrivate::UninitializeEGL()
+void CStageFrightVideoPrivate::ReleaseEGL()
{
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, "%s: >>> UninitializeEGL\n", CLASSNAME);
fbo.Cleanup();
for (int i=0; i<NUMFBOTEX; ++i)
{
- glDeleteTextures(1, &(slots[i].texid));
- eglDestroyImageKHR(eglDisplay, slots[i].eglimg);
+ glDeleteTextures(1, &(texslots[i].texid));
+ eglDestroyImageKHR(eglDisplay, texslots[i].eglimg);
}
if (eglContext != EGL_NO_CONTEXT)
glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture( GL_TEXTURE_EXTERNAL_OES, 0);
mVideoTextureId = texture_id;
-
- mSurfTexture = new CJNISurfaceTexture(mVideoTextureId);
- mSurface = new CJNISurface(*mSurfTexture);
-
- JNIEnv* env = xbmc_jnienv();
- mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw());
- native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
-
- #if defined(DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s: <<< InitSurfaceTexture\n", CLASSNAME);
- #endif
}
else
{
// wait for it.
m_g_applicationMessenger->SendMessage(msg, true);
+
+ mSurfTexture = new CJNISurfaceTexture(mVideoTextureId);
+ mSurface = new CJNISurface(*mSurfTexture);
+
+ JNIEnv* env = xbmc_jnienv();
+ mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw());
+ native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
+
+ #if defined(DEBUG_VERBOSE)
+ CLog::Log(LOGDEBUG, "%s: <<< InitSurfaceTexture texid(%d) natwin(%p)\n", CLASSNAME, mVideoTextureId, mVideoNativeWindow.get());
+ #endif
}
return (mVideoTextureId != -1);
native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
ANativeWindow_release(mVideoNativeWindow.get());
- mVideoNativeWindow = NULL;
+ mVideoNativeWindow.clear();
mSurface->release();
mSurfTexture->release();
delete mSurface;
delete mSurfTexture;
- glDeleteTextures(1, &mVideoTextureId);
+ if (mVideoTextureId > 0)
+ glDeleteTextures(1, &mVideoTextureId);
#if defined(DEBUG_VERBOSE)
CLog::Log(LOGDEBUG, "%s: <<< ReleaseSurfaceTexture\n", CLASSNAME);
#endif