ios: add helper class for enumerating all available assets

Add support for enumerating all available assets on the device.

Trailing patches will use the class to fetch a list of all available
assets for directory listing, and to search for assets that cannot be
loaded by [ALAssetsLibrary assetForURL:].

Change-Id: I319721b536b14424fc8f54f683513aa7ca64e7f0
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@theqtcompany.com>
bb10
Richard Moe Gustavsen 2015-04-20 12:29:35 +02:00
parent fb5530cd69
commit 1665e0d105
1 changed files with 116 additions and 0 deletions

View File

@ -38,6 +38,122 @@
#include <QtCore/QTimer>
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/qurl.h>
#include <QtCore/qset.h>
static const int kBufferSize = 10;
static ALAsset *kNoAsset = 0;
class QIOSAssetEnumerator
{
public:
QIOSAssetEnumerator(ALAssetsLibrary *assetsLibrary, ALAssetsGroupType type)
: m_semWriteAsset(dispatch_semaphore_create(kBufferSize))
, m_semReadAsset(dispatch_semaphore_create(0))
, m_stop(false)
, m_assetsLibrary([assetsLibrary retain])
, m_type(type)
, m_buffer(QVector<ALAsset *>(kBufferSize))
, m_readIndex(0)
, m_writeIndex(0)
, m_nextAssetReady(false)
{
startEnumerate();
}
~QIOSAssetEnumerator()
{
m_stop = true;
// Flush and autorelease remaining assets in the buffer
while (hasNext())
next();
// Documentation states that we need to balance out calls to 'wait'
// and 'signal'. Since the enumeration function always will be one 'wait'
// ahead, we need to signal m_semProceedToNextAsset one last time.
dispatch_semaphore_signal(m_semWriteAsset);
dispatch_release(m_semReadAsset);
dispatch_release(m_semWriteAsset);
[m_assetsLibrary autorelease];
}
bool hasNext()
{
if (!m_nextAssetReady) {
dispatch_semaphore_wait(m_semReadAsset, DISPATCH_TIME_FOREVER);
m_nextAssetReady = true;
}
return m_buffer[m_readIndex] != kNoAsset;
}
ALAsset *next()
{
Q_ASSERT(m_nextAssetReady);
Q_ASSERT(m_buffer[m_readIndex]);
ALAsset *asset = [m_buffer[m_readIndex] autorelease];
dispatch_semaphore_signal(m_semWriteAsset);
m_readIndex = (m_readIndex + 1) % kBufferSize;
m_nextAssetReady = false;
return asset;
}
private:
dispatch_semaphore_t m_semWriteAsset;
dispatch_semaphore_t m_semReadAsset;
std::atomic_bool m_stop;
ALAssetsLibrary *m_assetsLibrary;
ALAssetsGroupType m_type;
QVector<ALAsset *> m_buffer;
int m_readIndex;
int m_writeIndex;
bool m_nextAssetReady;
void writeAsset(ALAsset *asset)
{
dispatch_semaphore_wait(m_semWriteAsset, DISPATCH_TIME_FOREVER);
m_buffer[m_writeIndex] = [asset retain];
dispatch_semaphore_signal(m_semReadAsset);
m_writeIndex = (m_writeIndex + 1) % kBufferSize;
}
void startEnumerate()
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[m_assetsLibrary enumerateGroupsWithTypes:m_type usingBlock:^(ALAssetsGroup *group, BOOL *stopEnumerate) {
if (!group) {
writeAsset(kNoAsset);
return;
}
if (m_stop) {
*stopEnumerate = true;
return;
}
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stopEnumerate) {
Q_UNUSED(index);
if (!asset || ![[asset valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypePhoto])
return;
writeAsset(asset);
*stopEnumerate = m_stop;
}];
} failureBlock:^(NSError *error) {
NSLog(@"QIOSFileEngine: %@", error);
writeAsset(kNoAsset);
}];
});
}
};
// -------------------------------------------------------------------------
class QIOSAssetData : public QObject
{