Pass a class as argument to a NSThread - c++

How can I pass a class as argument to a thread using NSThread. In windows I was doing something like:
DWORD WINAPI threadFunc(LPVOID mpThis) {
MYCLSS *pThis = reinterpret_cast<MYCLSS*>(mpThis);
....
void MYCLSS::func() {
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadFunc, (void*)this, 0, NULL);
....
For Mac I have not found any examples of this kind. Please help me

I found the solution, it can be like windows
class CLS_CPP {
public:
void Func();
void Check();
int var_check;
};
#interface CLS_OSX : NSObject {
#public
void *obj;
}
-(void)osx_thread;
#end
#implementation CLS_OSX
-(void)osx_thread {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CLS_CPP *pThis = reinterpret_cast<CLS_CPP*>(obj);
pThis->Check();
NSLog(#"Check var %d", pThis->var_check);
[NSThread exit];
[pool drain];
}
#end
void CLS_CPP::Func() {
var_check=77;
CLS_OSX *trgt=[[CLS_OSX alloc] init];
trgt->obj=(void*)this;
[NSThread detachNewThreadSelector:#selector(osx_thread) toTarget:trgt withObject:trgt];
}
void CLS_CPP::Check() {
NSLog(#"CLS_CPP::Check success");
}
int main(int argc, char ** argv) {
CLS_CPP oAPP;
oAPP.Func();
}

Related

Cocos2d-x Scene MenuItemLabel CC_CALLBACK_1 error

OS : Win10
Language : c++
Cocos2d-x Ver : 3.8.1
Tool : Visual Studio 2013
//MainMenuScene.h
#ifndef ProjectV_MainMenuScene_h
#define ProjectV_MainMenuScene_h
#include "cocos2d.h"
class MainMenuScene :public cocos2d::CCLayerColor
{
public:
virtual bool init();
static cocos2d::CCScene *createScene();
CREATE_FUNC(MainMenuScene);
cocos2d::Label *PlayLabel;
void goPlayScene(cocos2d::Ref *pSender);
};
#endif
//MainMenuScene.cpp
#include "MainMenuScene.h"
#include "PlayScene.h"
USING_NS_CC;
CCScene *MainMenuScene::createScene()
{
CCScene *scene = CCScene::create();
MainMenuScene *layer = MainMenuScene::create();
scene->addChild(layer);
return scene;
}
bool MainMenuScene::init()
{
if (!CCLayerColor::initWithColor(Color4B(255, 255, 255, 255)))
{
return false;
}
PlayLabel = Label::createWithTTF("Play", "fonts/consola.ttf", 18);
PlayLabel->setColor(Color3B::BLACK);
auto PlayBtn = MenuItemLabel::create(
PlayLabel,
CC_CALLBACK_1(MainMenuScene::goPlayScene, this));
// i thought CC_CALLBACK_1(MainMenuScene::goPlayScene,this) mean call goPlayScene(Ref* pSender) when click or touch the label
PlayBtn->setPosition(Vec2(240, 100));
auto pMenu = Menu::create(PlayBtn, NULL);
pMenu->setPosition(Vec2::ZERO);
this->addChild(pMenu);
return true;
}
void MainMenuScene::goPlayScene(Ref* pSender)
{
CCScene *pScene = PlayScene::createScene();
TransitionScene *pTransScene = TransitionFade::create(1.0f, pScene, Color3B::WHITE);
Director::getInstance()->replaceScene(pTransScene);
}
i don't know why function don't call when i clicked the label
You is not passed an argument in the calling function
CC_CALLBACK_1(MainMenuScene::goPlayScene, this)
You need either remove the Ref* pSender from void MainMenuScene::goPlayScene() or add an your sender in CC_CALLBACK_1(MainMenuScene::goPlayScene, this) after this.

CopyFileEx with progress callback in Qt

Can anybody give me a working example of use CopyFileEx with progress callback in Qt?
I found some scratch and tried to merge it but with no success. I even couldn't pass CopyProgressRoutine function as an argument of CopyFileEx because I couldn't declare pointer to this function.
I'm not so good to port code from other IDEs, so I need help of yours.
The code below is a complete, self-contained example. It works under both Qt 5 and Qt 4, and uses C++11 (e.g. Visual Studio 2015 & newer).
main.cpp
// https://github.com/KubaO/stackoverflown/tree/master/questions/copyfileex-19136936
#include <QtGui>
#include <QtConcurrent>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
#include <windows.h>
#include <comdef.h>
//#define _WIN32_WINNT _WIN32_WINNT_WIN7
static QString toString(HRESULT hr) {
_com_error err{hr};
return QStringLiteral("Error 0x%1: %2").arg((quint32)hr, 8, 16, QLatin1Char('0'))
.arg(err.ErrorMessage());
}
static QString getLastErrorMsg() {
return toString(HRESULT_FROM_WIN32(GetLastError()));
}
static QString progressMessage(ULONGLONG part, ULONGLONG whole) {
return QStringLiteral("Transferred %1 of %2 bytes.")
.arg(part).arg(whole);
}
class Copier : public QObject {
Q_OBJECT
BOOL m_stop;
QMutex m_pauseMutex;
QAtomicInt m_pause;
QWaitCondition m_pauseWait;
QString m_src, m_dst;
ULONGLONG m_lastPart, m_lastWhole;
void newStatus(ULONGLONG part, ULONGLONG whole) {
if (part != m_lastPart || whole != m_lastWhole) {
m_lastPart = part;
m_lastWhole = whole;
emit newStatus(progressMessage(part, whole));
}
}
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
static COPYFILE2_MESSAGE_ACTION CALLBACK copyProgress2(
const COPYFILE2_MESSAGE *message, PVOID context);
#else
static DWORD CALLBACK copyProgress(
LARGE_INTEGER totalSize, LARGE_INTEGER totalTransferred,
LARGE_INTEGER streamSize, LARGE_INTEGER streamTransferred,
DWORD streamNo, DWORD callbackReason, HANDLE src, HANDLE dst,
LPVOID data);
#endif
public:
Copier(const QString & src, const QString & dst, QObject * parent = nullptr) :
QObject{parent}, m_src{src}, m_dst{dst} {}
Q_SIGNAL void newStatus(const QString &);
Q_SIGNAL void finished();
/// This method is thread-safe
Q_SLOT void copy();
/// This method is thread-safe
Q_SLOT void stop() {
resume();
m_stop = TRUE;
}
/// This method is thread-safe
Q_SLOT void pause() {
m_pause = true;
}
/// This method is thread-safe
Q_SLOT void resume() {
if (m_pause)
m_pauseWait.notify_one();
m_pause = false;
}
~Copier() override { stop(); }
};
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
void Copier::copy() {
m_lastPart = m_lastWhole = {};
m_stop = FALSE;
m_pause = false;
QtConcurrent::run([this]{
COPYFILE2_EXTENDED_PARAMETERS params{
sizeof(COPYFILE2_EXTENDED_PARAMETERS), 0, &m_stop,
Copier::copyProgress2, this
};
auto rc = CopyFile2((PCWSTR)m_src.utf16(), (PCWSTR)m_dst.utf16(), &params);
if (!SUCCEEDED(rc))
emit newStatus(toString(rc));
emit finished();
});
}
COPYFILE2_MESSAGE_ACTION CALLBACK Copier::copyProgress2(
const COPYFILE2_MESSAGE *message, PVOID context)
{
COPYFILE2_MESSAGE_ACTION action = COPYFILE2_PROGRESS_CONTINUE;
auto self = static_cast<Copier*>(context);
if (message->Type == COPYFILE2_CALLBACK_CHUNK_FINISHED) {
auto &info = message->Info.ChunkFinished;
self->newStatus(info.uliTotalBytesTransferred.QuadPart, info.uliTotalFileSize.QuadPart);
}
else if (message->Type == COPYFILE2_CALLBACK_ERROR) {
auto &info = message->Info.Error;
self->newStatus(info.uliTotalBytesTransferred.QuadPart, info.uliTotalFileSize.QuadPart);
emit self->newStatus(toString(info.hrFailure));
action = COPYFILE2_PROGRESS_CANCEL;
}
if (self->m_pause) {
QMutexLocker lock{&self->m_pauseMutex};
self->m_pauseWait.wait(&self->m_pauseMutex);
}
return action;
}
#else
void Copier::copy() {
m_lastPart = m_lastWhole = {};
m_stop = FALSE;
m_pause = false;
QtConcurrent::run([this]{
auto rc = CopyFileExW((LPCWSTR)m_src.utf16(), (LPCWSTR)m_dst.utf16(),
&copyProgress, this, &m_stop, 0);
if (!rc)
emit newStatus(getLastErrorMsg());
emit finished();
});
}
DWORD CALLBACK Copier::copyProgress(
const LARGE_INTEGER totalSize, const LARGE_INTEGER totalTransferred,
LARGE_INTEGER, LARGE_INTEGER, DWORD,
DWORD, HANDLE, HANDLE,
LPVOID data)
{
auto self = static_cast<Copier*>(data);
self->newStatus(totalTransferred.QuadPart, totalSize.QuadPart);
if (self->m_pause) {
QMutexLocker lock{&self->m_pauseMutex};
self->m_pauseWait.wait(&self->m_pauseMutex);
}
return PROGRESS_CONTINUE;
}
#endif
struct PathWidget : public QWidget {
QHBoxLayout layout{this};
QLineEdit edit;
QPushButton select{"..."};
QFileDialog dialog;
explicit PathWidget(const QString & caption) : dialog{this, caption} {
layout.setMargin(0);
layout.addWidget(&edit);
layout.addWidget(&select);
connect(&select, SIGNAL(clicked()), &dialog, SLOT(show()));
connect(&dialog, SIGNAL(fileSelected(QString)), &edit, SLOT(setText(QString)));
}
};
class Ui : public QWidget {
Q_OBJECT
QFormLayout m_layout{this};
QPlainTextEdit m_status;
PathWidget m_src{"Source File"}, m_dst{"Destination File"};
QPushButton m_copy{"Copy"};
QPushButton m_cancel{"Cancel"};
QStateMachine m_machine{this};
QState s_stopped{&m_machine};
QState s_copying{&m_machine};
Q_SIGNAL void stopCopy();
Q_SLOT void startCopy() {
auto copier = new Copier(m_src.edit.text(), m_dst.edit.text(), this);
connect(copier, SIGNAL(newStatus(QString)), &m_status, SLOT(appendPlainText(QString)));
connect(copier, SIGNAL(finished()), SIGNAL(copyFinished()));
connect(copier, SIGNAL(finished()), copier, SLOT(deleteLater()));
connect(this, SIGNAL(stopCopy()), copier, SLOT(stop()));
copier->copy();
}
Q_SIGNAL void copyFinished();
public:
Ui() {
m_layout.addRow("From:", &m_src);
m_layout.addRow("To:", &m_dst);
m_layout.addRow(&m_status);
m_layout.addRow(&m_copy);
m_layout.addRow(&m_cancel);
m_src.dialog.setFileMode(QFileDialog::ExistingFile);
m_dst.dialog.setAcceptMode(QFileDialog::AcceptSave);
m_status.setReadOnly(true);
m_status.setMaximumBlockCount(5);
m_machine.setInitialState(&s_stopped);
s_stopped.addTransition(&m_copy, SIGNAL(clicked()), &s_copying);
s_stopped.assignProperty(&m_copy, "enabled", true);
s_stopped.assignProperty(&m_cancel, "enabled", false);
s_copying.addTransition(&m_cancel, SIGNAL(clicked()), &s_stopped);
s_copying.addTransition(this, SIGNAL(copyFinished()), &s_stopped);
connect(&s_copying, SIGNAL(entered()), SLOT(startCopy()));
connect(&s_copying, SIGNAL(exited()), SIGNAL(stopCopy()));
s_copying.assignProperty(&m_copy, "enabled", false);
s_copying.assignProperty(&m_cancel, "enabled", true);
m_machine.start();
}
};
int main(int argc, char *argv[])
{
QApplication a{argc, argv};
Ui ui;
ui.show();
return a.exec();
}
#include "main.moc"

Schedule selector error

I'm trying to port my iPhone app to windows 8, I have a problem with this line (it's objective-c) :
[self schedule:#selector(fire:)];
The equivalent on c++ should be :
this->schedule(schedule_selector(AirScene::fire));
Where AirScene is the name of my class, but I have this error returning by Visual Studio 2012 :
error C2064: term does not evaluate to a function taking 1 arguments
So, in other words the function schedule(selector) is not found. It's strange because I have no problem with unschedule method, do you have any idea please ?
EDIT : AirScene.h
#include "cocos2d.h"
#include "Box2D\Box2D.h"
#include "AirSceneDelegate.h"
class AirScene : public cocos2d::CCLayer {
public:
AirScene::~AirScene(void);
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
static cocos2d::CCScene* scene();
LAYER_NODE_FUNC(AirScene);
//Methods
void selectSpriteForTouch(cocos2d::CCPoint touchLocation);
cocos2d::CCPoint checkPuckPosition(cocos2d::CCPoint newPosition);
void panForTranslation(cocos2d::CCPoint translation);
void updateQuestion(string question);
void restoreScene();
void enableScreensaver();
void disableScreensaver(cocos2d::CCPoint touchPosition);
//Setters
void setDelegate(AirSceneDelegate *delegate);
private:
// Init
void initBackground(cocos2d::CCSize winSize);
void initPuck(cocos2d::CCSize winSize, cocos2d::CCPoint position);
void initHoles(cocos2d::CCSize winSize);
void initQuestion(cocos2d::CCSize winSize);
// Methods
void fire(cocos2d::ccTime dt = 0);
void updateHoles(cocos2d::ccTime dt);
void validateVote(bool isPositiveVote);
float getVelocity();
// Attributes
...
//Delegate
AirSceneDelegate* _delegate;
};
AirScene.cpp
#include <iostream>
#include "AirScene.h"
USING_NS_CC;
#pragma region Delete
AirScene::~AirScene(void)
{
///TODO : DELETE ALL
delete(_delegate);
_delegate = 0;
}
#pragma endregion Delete
#pragma region Init
CCScene* AirScene::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::node();
// 'layer' is an autorelease object
AirScene *layer = AirScene::node();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool AirScene::init()
{
// Super Init
if (!CCLayer::init())
return false;
//Init Attributes
screenSaverMode = false;
hasVoted = false;
schedule = false;
_delegate = 0;
_selSprite = NULL;
//Create World
b2Vec2 gravity = b2Vec2(0, 0);
_world = new b2World(gravity);
CCSize size = CCDirector::sharedDirector()->getWinSize();
//Inits
AirScene::initBackground(size);
AirScene::initPuck(size, ccp(512, 200));
AirScene::initHoles(size);
AirScene::initQuestion(size);
return true;
}
// Init Background and set walls
void AirScene::initBackground(CCSize winSize)
{
...
}
/** Init Puck : create puck body and shape */
void AirScene::initPuck(CCSize winSize, CCPoint position)
{
...
}
void AirScene::initHoles(CCSize winSize)
{
...
}
// Set Question Label
void AirScene::initQuestion(CCSize winSize)
{
...
}
#pragma endregion Init
#pragma region Private
void AirScene::fire(ccTime dt)
{
_world->Step(dt, 8, 8);
//CCSprite *ballData = ((CCSprite *)_body->GetUserData())
((CCSprite *)_body->GetUserData())->setPosition(ccp(_body->GetPosition().x * PTM_RATIO, _body->GetPosition().y * PTM_RATIO));
_puckShadow->setPosition(ccp(((CCSprite *)_body->GetUserData())->getPosition().x + 2, ((CCSprite *)_body->GetUserData())->getPosition().y - 2));
if (screenSaverMode)
AirScene::updateHoles(0);
}
//Ajust Glow Effect and Validate Vote
void AirScene::updateHoles(cocos2d::ccTime dt)
{
...
}
float AirScene::getVelocity()
{
...
}
void AirScene::validateVote(bool isPositiveVote)
{
...
}
#pragma endregion Private
#pragma region Public
void AirScene::selectSpriteForTouch(CCPoint touchLocation)
{
...
}
// Check if the puck is not outside the view
CCPoint AirScene::checkPuckPosition(CCPoint newPosition)
{
...
}
// Move Puck
void AirScene::panForTranslation(CCPoint translation)
{
...
}
// Update Question
void AirScene::updateQuestion(string question)
{
...
}
void AirScene::restoreScene()
{
...
}
void AirScene::enableScreensaver()
{
screenSaverMode = true;
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
//Unschedule actions
this->unscheduleAllSelectors();
//Delete Puck
CCPoint puckPosition = _puck->getPosition();
_puck->removeAllChildrenWithCleanup(true);
_puck->removeFromParentAndCleanup(true);
_puckShadow->removeAllChildrenWithCleanup(true);
_puckShadow->removeFromParentAndCleanup(true);
_world->DestroyBody(_body);
delete(_puck);
delete(_puckShadow);
//RecreatePuck
this->initPuck(winSize, ccp(512, 200));
//Impulse
_body->SetLinearVelocity(b2Vec2(0, 0));
/** ERROR IS CAUSED BY THIS LINE */
this->schedule(schedule_selector(AirScene::fire));
}
void AirScene::disableScreensaver(cocos2d::CCPoint touchPosition)
{
}
#pragma endregion Public
#pragma region Getters & Setters
void AirScene::setDelegate(AirSceneDelegate *delegate)
{
_delegate = delegate;
}
#pragma endregion Getters & Setters
Fixed.
The version of cocos 2d which is used for windows 8 template is an old version, so the good way to schedule a selector is this one :
CCScheduler::sharedScheduler()->scheduleSelector(schedule_selector(AirScene::fire), this, 0, false);

can a function receive two arguements one each from two different functions?

i have 2 void functions(trying to implement radio button), i want them to send value to a third function by swapping values. and that function returning value to main function?
CODE OF MY MyScene.h FILE
#ifndef __MY_SCENE_H__
#define __MY_SCENE_H__
#include "cocos2d.h"
USING_NS_CC;
class MyScene : public cocos2d::CCLayerColor
{
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// there's no 'id' in cpp, so we recommand to return the exactly class pointer
static cocos2d::CCScene* scene();
CCMenuItemToggle *R;
CCMenuItemToggle *L;
// a selector callback
void swapL(CCObject *sender);
void swapR(CCObject *sender);
// implement the "static node()" method manually
LAYER_NODE_FUNC(MyScene);
};
#endif // __HELLOWORLD_SCENE_H__
CODE OF MY MyScene.cpp FILE
#include "MyScene.h"
USING_NS_CC;
CCScene* MyScene::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::node();
// 'layer' is an autorelease object
MyScene *layer = MyScene::node();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool MyScene::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayerColor::initWithColor(ccc4(255,255,255,255) ))
{
return false;
}
//////////////////////////////
// 2. add your codes below...
CCSize WinSize= CCDirector::sharedDirector()->getWinSizeInPixels();
CCSprite * fish=CCSprite::spriteWithFile("fish_bg.png");
fish->setPosition(CCPointZero);
fish->setAnchorPoint(CCPointZero);
fish->setScaleX(WinSize.width/480);
fish->setScaleY(WinSize.height/395);
this->addChild(fish,0,0);
CCSprite * on1=CCSprite::spriteWithFile("on.png");
CCSprite * on2=CCSprite::spriteWithFile("on.png");
CCSprite * on3=CCSprite::spriteWithFile("on.png");
CCSprite * on4=CCSprite::spriteWithFile("on.png");
CCSprite * off1=CCSprite::spriteWithFile("off.png");
CCSprite * off2=CCSprite::spriteWithFile("off.png");
CCSprite * off3=CCSprite::spriteWithFile("off.png");
CCSprite * off4=CCSprite::spriteWithFile("off.png");
CCMenuItem *LeftOn=CCMenuItemSprite::itemFromNormalSprite(on1,on2);
CCMenuItem *RightOn=CCMenuItemSprite::itemFromNormalSprite(on3,on4);
CCMenuItem *LeftOff=CCMenuItemSprite::itemFromNormalSprite(off1,off2);
CCMenuItem *RightOff=CCMenuItemSprite::itemFromNormalSprite(off3,off4);
CCMenuItemToggle *Left = CCMenuItemToggle::itemWithTarget(this, menu_selector(MyScene::swapL),LeftOn,LeftOff,NULL);
CCMenuItemToggle *Right = CCMenuItemToggle::itemWithTarget(this, menu_selector(MyScene::swapR),RightOn,RightOff,NULL);
CCMenu *Radio= CCMenu::menuWithItems(Left,Right,NULL);
Radio->alignItemsHorizontallyWithPadding(20);
Radio->setPosition(ccp(WinSize.width/2,WinSize.height/2));
this->addChild(Radio);
//////////////////////////////
return true;
}
void MyScene::swapL(CCObject *sender)
{
L= (CCMenuItemToggle*)sender;
CCLOG("L= %d",L->getSelectedIndex());
int i=(L->getSelectedIndex());
}
void MyScene::swapR(CCObject *sender)
{
R= (CCMenuItemToggle*)sender;
CCLOG("R= %d",R->getSelectedIndex());
int j=(R->getSelectedIndex());
}
Is it possible to have 2 void functions to send arguements to a third function one each from those 2 functions ?
Yes, It's possible, Why do you think it is not possible?
Online Sample:
#include<iostream>
void doSomething(int &i)
{
i = 10;
}
void doSomethingMore(int &j)
{
j = 20;
}
void FinalDoSomething(const int i, const int j, int &k)
{
k = i + j;
}
int main()
{
int i = 0;
doSomething(i);
int j = 0;
doSomethingMore(j);
int k = 0;
FinalDoSomething(i,j,k);
std::cout<<k;
return 0;
}
You could have a method between that calls. This function stores the first call value into a member and on the second call it calls the function you want to pass the two parameters (using the previously passed one + the member

Autorelease used but still leaking

I am writing a C++ program that has one class that has an Objective-C++ implementation. Each function has an autorelease pool when there is any opportunity for object creation.
When a specific object function gets called more than once I get 3 log messages of the type *** __NSAutoreleaseNoPool(): Object 0x10b730 of class NSCFArray autoreleased with no pool in place - just leaking
There is an autorelease pool in this specific function and also in either of the 2 functions that can call it. Is it possible that one of the frameworks I am using is creating some global objects that get leaked ?
I tried setting a breakpoint on __NSAutoreleaseNoPool but it won't break. I also set NSAutoreleaseHaltOnNoPool and couldn't break either.
EDIT: Here is the code,
qtdata.h :
#ifndef qtdata_h
#define qtdata_h
#include "../videodata.h"
class QTData : public VideoData
{
public:
QTData();
~QTData() { };
bool Open(const char *seqname, QImage *img = NULL);
bool ReadFirstFrame(const char *seqname, QImage &img);
private:
bool getFrame(void *handle, QImage *img);
};
#endif
qtdata.mm :
#include <CoreAudio/CoreAudio.h>
#include <QuickTime/Movies.h>
#import <QTKit/QTKit.h>
#include "qtdata.h"
QTData::QTData() : VideoData(){ };
// Open and read first frame into img
bool QTData::Open(const char *seqname, QImage *img)
{
NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
NSError *error;
QTMovie *movieHandle;
movieHandle = [[QTMovie movieWithFile:[NSString stringWithCString:seqname
encoding:NSUTF8StringEncoding] error:&error] retain];
if(movieHandle == nil)
{
[localpool release];
return(false);
}
[movieHandle gotoBeginning];
NSSize size = [[movieHandle attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
width = size.width;
height = size.height;
bool success = false;
if(img)
{
[movieHandle gotoBeginning];
success = getFrame(movieHandle, img);
}
[localpool drain];
return(success);
}
bool QTData::getFrame(void *handle, QImage *img)
{
bool success = false;
NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:QTMovieFrameImageTypeCVPixelBufferRef
forKey:QTMovieFrameImageType];
CVPixelBufferRef frame = (CVPixelBufferRef)[(QTMovie *)handle frameImageAtTime:[(QTMovie *)handle currentTime]
withAttributes:attributes error:nil];
CVPixelBufferLockBaseAddress(frame, 0);
QImage *buf;
int r, g, b;
char *pdata = (char *)CVPixelBufferGetBaseAddress(frame);
int stride = CVPixelBufferGetBytesPerRow(frame);
buf = new QImage(width, height, QImage::Format_RGB32);
for(int j = 0; j < height; j++)
{
for(int i = 0; i < width; i++)
{
r = *(pdata+(i*4)+1);
g = *(pdata+(i*4)+2);
b = *(pdata+(i*4)+3);
buf->setPixel(i, j, qRgb(r, g, b));
}
pdata += stride;
}
success = true;
*img = *buf;
delete buf;
CVPixelBufferUnlockBaseAddress(frame, 0);
CVBufferRelease(frame);
[localpool drain];
return(success);
}
bool QTData::ReadFirstFrame(const char *seqname, QImage &img)
{
NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
QTMovie *movieHandle;
movieHandle = [[QTMovie movieWithFile:[NSString stringWithCString:seqname
encoding:NSUTF8StringEncoding] error:&error] retain];
if(movieHandle == nil)
{
[localpool drain];
return(false);
}
[movieHandle gotoBeginning];
bool success = getFrame(movieHandle, &img);
[localpool drain];
return(success);
}
You have to create autorelease pool for each new thread. check main.m, it create it for the main thread.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// your code
[pool drain];
read NSAutoreleasePool doc
Note: If you are creating secondary threads using the POSIX thread APIs
instead of NSThread objects, you cannot use Cocoa, including
NSAutoreleasePool, unless Cocoa is in multithreading mode. Cocoa
enters multithreading mode only after detaching its first NSThread
object. To use Cocoa on secondary POSIX threads, your application must
first detach at least one NSThread object, which can immediately exit.
You can test whether Cocoa is in multithreading mode with the NSThread
class method isMultiThreaded.
update:
So you have to create a NSThread object to enable Cocoa multithreading mode.
NSThread *thread = [[NSThread alloc] init];
[thread start];
[thread release];
Than wrap all of the obj-c code in a autorelease pool like code above.