i am an ios developer who uses swift. I am using an sdk in order to communicate with an ip camera retrieve data from it, and show it to the user. I ve a project shipped with the sdk, which is written in obj c, and is working without problems. The problem is i am not able to pass the parameter to the expected parameter type from the function. The SDK is very old, i integrated it using static libraries and a bridging header and i was able to connect successfully to the camera. I think the sdk is written in c or c++, and i am basically having problems with the parameter conversion.
Fos.h
typedef struct
{
int channel;
long long time;
unsigned int index;
FOSMEDIATYPE type; //Is video or audio
FOSDECFMT fmt; //The format of video or audio.
short isKey;
short multiAudioPage;
int frameTag;
union{
FOSVIDEO_INFO video; //Media type is video.
FOSAUDIO_INFO audio; //Media type is audio.
} media;
unsigned long long pts; //Pts.
unsigned int len; //Size of data.
char data[0]; //Just data.
}ATTRIBUTE_PACKED FOSDEC_DATA; //Save the video or audio data,include video or audio information.
.
Objective C function, currently working
- (IBAction)login:(id)sender {
//[self._imageView add]
NSString* str = [self._textField text];
const char* url = [str UTF8String];
char ip[128];
int port;
char usr[64];
char pwd[64];
int count = sscanf(url, "%[^:]:%d/%[^:]:%s", ip, &port, usr, pwd);
if (count != 4) {
return;
}
mHandle = FosSdk_Create(ip, "", usr, pwd, port, port, FOSIPC_H264, FOSCNTYPE_IP);
//mHandle = FosSdk_Create(ip, "FASDFDSAFDASFASD", usr, pwd, port, port, FOSIPC_H264, FOSCNTYPE_P2P);
if (mHandle == FOSHANDLE_INVALID) {
return;
}
[self._Login setEnabled:NO];
[self._Logout setEnabled:YES];
[NSThread detachNewThreadSelector:@selector(RunInThread:) toTarget:self withObject:^(void *param){
int usrPrivilege = 0;
FOSCMD_RESULT ret = FosSdk_Login(mHandle, &usrPrivilege, 500);
if (FOSCMDRET_OK != ret) {
return;
}
ret = FosSdk_OpenVideo(mHandle, FOSSTREAM_SUB, 500);
if (FOSCMDRET_OK != ret) {
return;
}
//char* framebuf = (char*)malloc(512*1024);
FOSDEC_DATA* data = NULL;
int outlen = 0;
while (mHandle) {
// FosSdk_RetainHandle(mHandle, &usrPrivilege);
if ( FOSCMDRET_OK == FosSdk_GetVideoData(mHandle, (char**)&data, &outlen, FOSDECTYPE_RGB24) && outlen>0)
{
if (data->type == FOSMEDIATYPE_VIDEO) {
//int a=0;
//a++;
[self imageFromAVPicture:data->data width:data->media.video.picWidth height:data->media.video.picHeight];
}
else{
}
}
usleep(20*1000);
}
}];
}
.
The method signature in fos.h
FOSSDK FOSCMD_RESULT FOSAPI FosSdk_GetVideoData(FOSHANDLE handle, char **data, int *outLen, FOSDECFMT videoFmt);
.
When calling it from objective-c
FosSdk_GetVideoData(<#unsigned int handle#>, <#char **data#>, <#int *outLen#>, <#FOSDECFMT videoFmt#>)
}];
.
When calling it from swift
FosSdk_GetVideoData(handle: UInt32,
data: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!,
outLen: UnsafeMutablePointer<Int32>!,
videoFmt: FOSDECFMT)
.
The error is data parameter, exactly:
Cannot convert value of type 'UnsafeMutablePointer<FOSDEC_DATA>' to expected argument type 'UnsafeMutablePointer<Int8>?'
.
I ve tried changing the declaration of data to this, but it gives me this error
let data = UnsafeMutablePointer<Int8>(&fosdecData)
Ambiguous use of 'init'
.
This pointer stuff is a bit complicated but i was able to pair my device with the camera, using methods which used unsafeMutablePointers too. However, i cannot figure out how to pass this empy data object to the function.
The SDK is outdated and bad documented, which does not help. Anyway, i need to make it working. Hope to get some help, thanks coders! .
EDIT, THANKS TO OOPer . Here is the updated version in swift, which actually produces an unexpected error. The result returned from the function is now 0, so it s correct. However, trying to access original FosdedData struct, i have a Command failed due to signal: Segmentation fault: 11. How could i solve this? Sorry for long question, i wanted to be accurate.
var mhandle : UInt32 = FOS_HANDLE_INIT.rawValue
override func viewDidLoad() {
super.viewDidLoad()
//These functions basically do camera pairing, and write result on mhandle, which is equal to 0 , if functions work, otherwise 1
initializeFOS()
startEzLinkFOS()
sdkCreateFOS()
loginFOS()
openVideoFOS()
var data: UnsafeMutablePointer<FOSDEC_DATA>? = nil
var outlen : Int32 = 0
while self.mhandle > 0 {
let resultOOPer = withUnsafeMutablePointer(to: &data) { pointerToFosdecData in
pointerToFosdecData.withMemoryRebound(to: UnsafeMutablePointer<Int8>?.self, capacity: 1, { (pointerToInt8Pointer) in
FosSdk_GetVideoData(self.mhandle, pointerToInt8Pointer, &outlen, FOSDECTYPE_RGB24)
})
}
if resultOOPer == FOSCMDRET_OK && outlen > 0{
if let unwrData = data {
//if unwrData.pointee.type == FOSMEDIATYPE_VIDEO{
//Produced Output when i try access pointee, which is actually the fosdecData struct i need:
//Command failed due to signal: Segmentation fault: 11
//}
}
}
usleep(20*1000)
}
}
First of all, using the initializer of
UnsafeMutablePointer
in this way may generate an unexpected result and you should never do:Swift compiler may prepare a temporary region for the inout parameter and pass the address of the region, which is released immediately after the call. Unfortunately, this code may work in some cases, but you know codes work-in-some-cases can be a hard-to-fix bug.
Second, in your Objective-C code, you declare
data
asFOSDEC_DATA*
-- pointer toFOSDEC_DATA
-- and initializing it toNULL
.Why are you trying to initialize your Swift version of
data
with&fosdecData
? There's nofosdecData
in your Objective-C code.The equivalent Swift code for the declaration of
data
should be like this:You should declare
data
asUnsafeMutablePointer<FOSDEC_DATA>?
-- pointer toFOSDEC_DATA
-- and initialize it tonil
.In addition, it needs to be
var
, yourFosSdk_GetVideoData
would rewrite it to a valid pointer toFOSDEC_DATA
.Third, you need to pass
UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!
to the second parameter ofFosSdk_GetVideoData
, but&data
would generate a pointer of typeUnsafeMutablePointer<UnsafeMutablePointer<FOSDEC_DATA>?>
.To make this sort of pointer type conversion, you need to use
withMemoryRebound<T, Result>(to:capacity:_:)
. And you need to callwithUnsafeMutablePointer<T, Result>(to:_:)
to get a pointer todata
.So, your Swift code equivalent to your Objective-C code would be something like this:
EDIT
Code updated to reflect whole behavior of the currently working Objective-C code. (Renamed
mhandle
tomHandle
as in Objective-C code.)