Permalink
Browse files

Fix a crash caused by background animated image loading.

The background animated image loader was calling SetImages() which
triggers non thread-safe routines in MythUI.  Instead of calling
SetImages() in the background thread, return the image QVector
in the ImageLoadEvent and set the images and delays in the UI
thread similar to how we set non-animated images.

Fixes #9388.

NOTE: This changes the binary API, so make clean, etc., whatever
you normally do.
  • Loading branch information...
1 parent 607206b commit 02f8352b91d8f43f39e37e4704edc481ffc1abdd @cpinkham cpinkham committed Oct 18, 2011
@@ -12,7 +12,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
-#define MYTH_BINARY_VERSION "0.25.20111018-2"
+#define MYTH_BINARY_VERSION "0.25.20111018-3"
/** \brief Increment this whenever the MythTV network protocol changes.
*
@@ -432,6 +432,12 @@ MythImageReader::MythImageReader(const QString &fileName)
}
else if (!m_fileName.isEmpty())
{
+ if (!m_fileName.startsWith("/") && !QFile::exists(m_fileName))
+ {
+ QString tmpFile = GetMythUI()->GetThemeDir() + '/' + m_fileName;
+ if (QFile::exists(tmpFile))
+ m_fileName = tmpFile;
+ }
setFileName(m_fileName);
}
}
@@ -42,7 +42,16 @@ class ImageLoadEvent : public QEvent
int number)
: QEvent(kEventType),
m_parent(parent), m_image(image), m_basefile(basefile),
- m_filename(filename), m_number(number) { }
+ m_filename(filename), m_number(number),
+ m_images(NULL), m_delays(NULL) { }
+
+ ImageLoadEvent(MythUIImage *parent, QVector<MythImage *> *images,
+ QVector<int> *delays, const QString &basefile,
+ const QString &filename)
+ : QEvent(kEventType),
+ m_parent(parent), m_image(NULL), m_basefile(basefile),
+ m_filename(filename), m_number(0),
+ m_images(images), m_delays(delays) { }
MythUIImage *GetParent() const
{
@@ -64,6 +73,14 @@ class ImageLoadEvent : public QEvent
{
return m_number;
}
+ QVector<MythImage *> *GetImages() const
+ {
+ return m_images;
+ }
+ QVector<int> *GetDelays() const
+ {
+ return m_delays;
+ }
static Type kEventType;
@@ -73,6 +90,10 @@ class ImageLoadEvent : public QEvent
QString m_basefile;
QString m_filename;
int m_number;
+
+ // Animated Images
+ QVector<MythImage *> *m_images;
+ QVector<int> *m_delays;
};
QEvent::Type ImageLoadEvent::kEventType =
@@ -107,8 +128,16 @@ class ImageLoadThread : public QRunnable
if (imageReader.supportsAnimation())
{
+ QVector<MythImage *> *images = new QVector<MythImage *>;
+ QVector<int> *delays = new QVector<int>;
+
m_parent->LoadAnimatedImage(
- imageReader, m_filename, m_ForceSize, m_cacheMode);
+ imageReader, m_filename, m_ForceSize, m_cacheMode,
+ images, delays);
+
+ ImageLoadEvent *le = new ImageLoadEvent(m_parent, images, delays,
+ m_basefile, m_filename);
+ QCoreApplication::postEvent(m_parent, le);
}
else
{
@@ -412,7 +441,7 @@ void MythUIImage::SetImage(MythImage *img)
* Use is strongly discouraged, use SetFilepattern() instead.
*
*/
-void MythUIImage::SetImages(QVector<MythImage *> &images)
+void MythUIImage::SetImages(QVector<MythImage *> *images)
{
Clear();
@@ -421,7 +450,7 @@ void MythUIImage::SetImages(QVector<MythImage *> &images)
QVector<MythImage *>::iterator it;
- for (it = images.begin(); it != images.end(); ++it)
+ for (it = images->begin(); it != images->end(); ++it)
{
MythImage *im = (*it);
@@ -462,6 +491,7 @@ void MythUIImage::SetImages(QVector<MythImage *> &images)
SetSize(aSize);
m_CurPos = 0;
+ m_animatedImage = true;
SetRedraw();
}
@@ -873,7 +903,8 @@ MythImage *MythUIImage::LoadImage(
*/
bool MythUIImage::LoadAnimatedImage(
MythImageReader &imageReader, const QString &imFile,
- QSize bForceSize, int cacheMode)
+ QSize bForceSize, int cacheMode, QVector<MythImage *> *images,
+ QVector<int> *delays)
{
bool result = false;
m_loadingImagesLock.lock();
@@ -899,14 +930,25 @@ bool MythUIImage::LoadAnimatedImage(
QString filename = QString("frame-%1-") + imFile;
QString frameFilename;
- QVector<MythImage *> images;
- QVector<int> delays;
+ QVector<MythImage *> *myImages = NULL;
+ QVector<int> *myDelays = NULL;
int imageCount = 1;
QString imageLabel;
int w = -1;
int h = -1;
+ if (images)
+ {
+ myImages = images;
+ myDelays = delays;
+ }
+ else
+ {
+ myImages = new QVector<MythImage *>;
+ myDelays = new QVector<int>;
+ }
+
if (!bForceSize.isNull())
{
if (bForceSize.width() != -1)
@@ -927,21 +969,27 @@ bool MythUIImage::LoadAnimatedImage(
if (!im)
break;
- images.append(im);
- delays.append(imageReader.nextImageDelay());
+ myImages->append(im);
+ myDelays->append(imageReader.nextImageDelay());
imageCount++;
}
- if (images.size())
+ if (myImages->size())
{
- m_animatedImage = true;
- SetImages(images);
-
- if ((m_Delay == -1) &&
- (imageReader.supportsAnimation()) &&
- (delays.size()))
+ // Only SetImages() if not returning them via the passed-in QVector
+ if (!images)
{
- SetDelays(delays);
+ SetImages(myImages);
+
+ if ((m_Delay == -1) &&
+ (imageReader.supportsAnimation()) &&
+ (myDelays->size()))
+ {
+ SetDelays(*myDelays);
+ }
+
+ delete myImages;
+ delete myDelays;
}
result = true;
@@ -1316,7 +1364,7 @@ void MythUIImage::CopyFrom(MythUIType *base)
m_animationCycle = im->m_animationCycle;
m_animatedImage = im->m_animatedImage;
- //SetImages(im->m_Images);
+ //SetImages(&im->m_Images);
MythUIType::CopyFrom(base);
@@ -1389,37 +1437,72 @@ void MythUIImage::LoadNow(void)
*/
void MythUIImage::customEvent(QEvent *event)
{
+ MythImage *image = NULL;
+ QVector<MythImage *> *images = NULL;
+ QVector<int> *delays = NULL;
+ int number = 0;
+
if (event->type() == ImageLoadEvent::kEventType)
{
ImageLoadEvent *le = dynamic_cast<ImageLoadEvent *>(event);
if (le->GetParent() != this)
return;
- MythImage *image = le->GetImage();
-
- if (!image)
- return;
+ image = le->GetImage();
+ number = le->GetNumber();
+ images = le->GetImages();
+ delays = le->GetDelays();
d->m_UpdateLock.lockForRead();
if (le->GetBasefile() != m_Filename)
{
d->m_UpdateLock.unlock();
-#if 0
- LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
- QString("customEvent(): Expecting '%2', got '%3'")
- .arg(m_Filename).arg(le->GetBasefile()));
-#endif
- image->DownRef();
+
+ if (image)
+ image->DownRef();
+
+ if (images)
+ {
+ QVector<MythImage *>::iterator it;
+
+ for (it = images->begin(); it != images->end(); ++it)
+ {
+ MythImage *im = (*it);
+ im->DownRef();
+ }
+
+ delete images;
+ delete delays;
+ }
+
return;
}
d->m_UpdateLock.unlock();
+ }
+
+ if (images)
+ {
+ if (images->size())
+ {
+ SetImages(images);
+
+ if (delays && delays->size())
+ SetDelays(*delays);
+ }
- QString filename = le->GetFilename();
- int number = le->GetNumber();
+ delete images;
+ if (delays)
+ delete delays;
+
+ return;
+ }
+
+ if (image)
+ {
d->m_UpdateLock.lockForWrite();
if (m_ForceSize.isNull())
@@ -47,7 +47,7 @@ class MUI_PUBLIC MythUIImage : public MythUIType
/** Should not be used unless absolutely necessary since it bypasses the
* image caching and threaded loaded mechanisms.
*/
- void SetImages(QVector<MythImage *> &images);
+ void SetImages(QVector<MythImage *> *images);
void SetDelay(int delayms);
void SetDelays(QVector<int> delays);
@@ -68,7 +68,9 @@ class MUI_PUBLIC MythUIImage : public MythUIType
MythImage* LoadImage(MythImageReader &imageReader, const QString &imFile,
QSize bForceSize, int cacheMode);
bool LoadAnimatedImage(MythImageReader &imageReader, const QString &imFile,
- QSize bForceSize, int mode);
+ QSize bForceSize, int mode,
+ QVector<MythImage *> *images = NULL,
+ QVector<int> *delays = NULL);
void customEvent(QEvent *event);
virtual bool ParseElement(

0 comments on commit 02f8352

Please sign in to comment.