Best way to save lots of streaming data from iPhone - ios

Currently, I am streaming image and depth data from my iphone X and doing a series of computations on it using a compute metal kernel. The output every cycle (frame) is approximately 900,000 floats. Assuming there are 30 cycles (frames) a second, this represents 27million floats a second.
I would like to save a few seconds (3-5) of this data to a file, which I can then access later.
My current approach of writing the output every cycle is too slow (I/O is expensive) and I am not sure how to buffer the results of a few cycles correctly (I tried creating an array of arrays but then run into memory issues).
Copy data from mtl buffers:
//number of elements per frame approx 300,000
size_t len = elementCount
finalArrayX = new float [len];
finalArrayY = new float [len];
finalArrayZ = new float [len];
//MTLBuffers
finalArrayX = (float*) resultsBufferX.contents;
finalArrayY = (float*) resultsBufferY.contents;
finalArrayZ = (float*) resultsBufferZ.contents;
writeToFile(finalArrayX, finalArrayY, finalArrayZ)
writeToFile:
/*
* Get file handle to append to
*/
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *documentTXTPath = [documentsDirectory stringByAppendingPathComponent:#"test.txt"];
if(![[NSFileManager defaultManager] fileExistsAtPath: documentTXTPath]) {
[[NSFileManager defaultManager] createFileAtPath: documentTXTPath contents:nil attributes:nil];
}
NSFileHandle *myHandle = [NSFileHandle fileHandleForWritingAtPath:documentTXTPath];
[myHandle seekToEndOfFile];
/*
* Create strings and write line by line
*/
for(int k = 0; k < elementCount; k ++){
NSString *x_i = [NSString stringWithFormat:#"%.2f", finalArrayX[k]];
NSString *y_i = [NSString stringWithFormat:#"%.2f", finalArrayY[k]];
NSString *z_i = [NSString stringWithFormat:#"%.2f", finalArrayZ[k]];
NSString *temp = [line stringByAppendingString: x_i];
temp = [temp stringByAppendingString: #" "];
NSString *tempTwo = [temp stringByAppendingString: y_i];
tempTwo = [tempTwo stringByAppendingString: #" "];
NSString *tempThree = [tempTwo stringByAppendingString: z_i];
NSString *totalLine = [tempThree stringByAppendingString: #"\n"];
[myHandle writeData:[totalLine dataUsingEncoding:NSUTF8StringEncoding]];
}
Whats the best way to go about this?

Related

What is NSdocumentdirectory's limitation size?

What is the maximum size of NSDocumentdirectory that can be stored?.
Mostly I am saving images in NSDocumentdirectory, as it is backed up by iCloud.
Now i would like to know what is the maximum size that can be stored in it. Please help.
This code is giving the exact number of bytes.
- (unsigned long long int)folderSize:(NSString *)folderPath {
NSArray *folderArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
NSEnumerator *folderEnumerator = [folderArray objectEnumerator];
NSString *folderName;
unsigned long long int fileSize = 0;
while (folderName = [folderEnumerator nextObject]) {
NSDictionary *folderDictionary = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:fileName] traverseLink:YES];
folderSize += [folderDictionary folderSize];
}
return folderSize;
}
Hope it helps...

linphone_call_take_video_snapshot saved empty file

I am working on a project based on Linphone-iPhone, the project requires taking a snapshot of current video stream (both in and out).
I've found this 'linphone_call_take_video_snapshot' in liblinphone and gave it a try.
The code was simple and running without any error, but the size of the saved file is always 0 kb!
Here's the code:
- (void)capture {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *file_path = [documentsDirectory stringByAppendingPathComponent:#"snapshot.jpeg"];
LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]);
const char *c_file_path = [file_path cStringUsingEncoding:NSUTF8StringEncoding];
int ret = linphone_call_take_video_snapshot(call, c_file_path);
if (ret >= 0 && [[NSFileManager defaultManager] fileExistsAtPath:file_path]) {
UIImageWriteToSavedPhotosAlbum([UIImage imageWithContentsOfFile:file_path], nil,nil,nil);
}
}
Does linphone_call_take_video_snapshot really work? If so, what have I been doing wrong?

Fetch Image From Sqllite Database in iphone

I Want to save the image in Database and fetch the image in database.i am convert the image in NSData and the image is store successfully in database but when i fetch that image from database then it crash.it give this warning
Warning :- -[__NSCFString bytes]: unrecognized selector sent to instance 0x7916000
Below code For save the image in Database
NSData *dataImage1 = UIImagePNGRepresentation(image3.image);
NSString *str = [NSString stringWithFormat:#"Insert into Gallery(ImageName) VALUES ('%#')",dataImage1];
[Database executeQuery:str];
//Database.m
+(NSString* )getDatabasePath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"Database"];
return writableDBPath;
}
+(NSMutableArray *)executeQuery:(NSString*)str{
sqlite3_stmt *statement= nil;
sqlite3 *database;
NSString *strPath = [self getDatabasePath];
NSMutableArray *allDataArray = [[NSMutableArray alloc] init];
if (sqlite3_open([strPath UTF8String],&database) == SQLITE_OK) {
if (sqlite3_prepare_v2(database, [str UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSInteger i = 0;
NSInteger iColumnCount = sqlite3_column_count(statement);
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
while (i< iColumnCount) {
NSString *str = [self encodedString:(const unsigned char*)sqlite3_column_text(statement, i)];
NSString *strFieldName = [self encodedString:(const unsigned char*)sqlite3_column_name(statement, i)];
[dict setObject:str forKey:strFieldName];
i++;
}
[allDataArray addObject:dict];
[dict release];
}
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
return allDataArray;
}
//Fetch image
NSString *str =[NSString stringWithFormat:#"Select * from Gallery where id = 1"];
NSMutableArray *arra =[Database executeQuery:str];
NSData *d =[[arra objectAtIndex:0] valueForKey:#"ImageName"];
UIImage *img = [[UIImage alloc] initWithData:d];
NSLog(#"%#",img);
Thanks in Advance
Your problem is that you cannot insert binary data by building a SQL statement with a stringWithFormat. You're inserting the NSData (binary data) into a field called ImageName, and you cannot use stringWithFormat to build that SQL statement.
Did you really mean to insert the image itself? In that case you'd use SQL like below, with a ? placeholder, and then use sqlite3_bind_blob for column number 1 with your NSData before you call sqlite3_step. Thus, the SQL would look like:
Insert into Gallery(ImageName) VALUES (?)
(As an aside, I'm not a fan of the choice of ImageName for the actual data of the image. I'd either use Image for the actual image data, or ImageName for the name of the image.)
And then, after preparing your SQL, you'd then call:
sqlite3_bind_blob(statement, 1, [dataImage1 bytes], [dataImage1 length], SQLITE_TRANSIENT);
You can then invoke sqlite3_step, like normal, to execute the SQL to insert the data.
When retrieving the data, after you successfully sqlite3_step, you'd use the appropriate sqlite3_column_blob functions:
const void *bytes = sqlite3_column_blob(statement, 0);
int len = sqlite3_column_bytes(statement, 0);
NSData *data = [NSData dataWithBytes:bytes length:len];
UIImage *image = [UIImage imageWithData:data];
Having said that, SQLite is notoriously inefficient in storing large blob data. You might want to store the image in the Documents folder and then just store the filename in your ImageName field.
i think you are getting bytes in string type in
[[arra objectAtIndex:0] valueForKey:#"ImageName"];
so first get string and then convert it to data.
try like this:
NSData* data = [[[arra objectAtIndex:0] valueForKey:#"ImageName"] dataUsingEncoding:NSUTF8StringEncoding];

iOS SoundTouch framework BPM Detection example

I have searched all over the web and cannot find a tutorial on how to use the SoundTouch library for beat detection.
(Note: I have no C++ experience prior to this. I do know C, Objective-C, and Java. So I could have messed some of this up, but it compiles.)
I added the framework to my project and managed to get the following to compile:
NSString *path = [[NSBundle mainBundle] pathForResource:#"song" ofType:#"wav"];
NSData *data = [NSData dataWithContentsOfFile:path];
player =[[AVAudioPlayer alloc] initWithData:data error:NULL];
player.volume = 1.0;
player.delegate = self;
[player prepareToPlay];
[player play];
NSUInteger len = [player.data length]; // Get the length of the data
soundtouch::SAMPLETYPE sampleBuffer[len]; // Create buffer array
[player.data getBytes:sampleBuffer length:len]; // Copy the bytes into the buffer
soundtouch::BPMDetect *BPM = new soundtouch::BPMDetect(player.numberOfChannels, [[player.settings valueForKey:#"AVSampleRateKey"] longValue]); // This is working (tested)
BPM->inputSamples(sampleBuffer, len); // Send the samples to the BPM class
NSLog(#"Beats Per Minute = %f", BPM->getBpm()); // Print out the BPM - currently returns 0.00 for errors per documentation
The inputSamples(*samples, numSamples) song byte information confuses me.
How do I get these pieces of information from a song file?
I tried using memcpy() but it doesn't seem to be working.
Anyone have any thoughts?
After hours and hours of debugging and reading the limited documentation on the web, I modified a few things before stumbling upon this: You need to divide numSamples by numberOfChannels in the inputSamples() function.
My final code is like so:
NSString *path = [[NSBundle mainBundle] pathForResource:#"song" ofType:#"wav"];
NSData *data = [NSData dataWithContentsOfFile:path];
player =[[AVAudioPlayer alloc] initWithData:data error:NULL];
player.volume = 1.0; // optional to play music
player.delegate = self;
[player prepareToPlay]; // optional to play music
[player play]; // optional to play music
NSUInteger len = [player.data length];
soundtouch::SAMPLETYPE sampleBuffer[len];
[player.data getBytes:sampleBuffer length:len];
soundtouch::BPMDetect BPM(player.numberOfChannels, [[player.settings valueForKey:#"AVSampleRateKey"] longValue]);
BPM.inputSamples(sampleBuffer, len/player.numberOfChannels);
NSLog(#"Beats Per Minute = %f", BPM.getBpm());
I've tried this solution to read the BPM from mp3 files (using the TSLibraryImport class to convert to wav) inside the iOS Music Library:
MPMediaItem *item = [collection representativeItem];
NSURL *urlStr = [item valueForProperty:MPMediaItemPropertyAssetURL];
TSLibraryImport* import = [[TSLibraryImport alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSURL* destinationURL = [NSURL fileURLWithPath:[documentsDirectory stringByAppendingPathComponent:#"temp_data"]];
[[NSFileManager defaultManager] removeItemAtURL:destinationURL error:nil];
[import importAsset:urlStr toURL:destinationURL completionBlock:^(TSLibraryImport* import) {
NSString *outPath = [documentsDirectory stringByAppendingPathComponent:#"temp_data"];
NSData *data = [NSData dataWithContentsOfFile:outPath];
AVAudioPlayer *player =[[AVAudioPlayer alloc] initWithData:data error:NULL];
NSUInteger len = [player.data length];
int numChannels = player.numberOfChannels;
soundtouch::SAMPLETYPE sampleBuffer[1024];
soundtouch::BPMDetect *BPM = new soundtouch::BPMDetect(player.numberOfChannels, [[player.settings valueForKey:#"AVSampleRateKey"] longValue]);
for (NSUInteger i = 0; i <= len - 1024; i = i + 1024) {
NSRange r = NSMakeRange(i, 1024);
//NSData *temp = [player.data subdataWithRange:r];
[player.data getBytes:sampleBuffer range:r];
int samples = sizeof(sampleBuffer) / numChannels;
BPM->inputSamples(sampleBuffer, samples); // Send the samples to the BPM class
}
NSLog(#"Beats Per Minute = %f", BPM->getBpm());
}];
The strangeness is that the calculated BMP is always the same value:
2013-10-02 03:05:36.725 AppTestAudio[1464:1803] Beats Per Minute = 117.453835
No matter which track was i.e. number of frames or the buffer size (here I used 2K buffer size as for the SoundTouch example in the source code of the library).
For Swift 3:
https://github.com/Luccifer/BPM-Analyser
And use it like:
guard let filePath = Bundle.main.path(forResource: "TestMusic", ofType: "m4a"),
let url = URL(string: filePath) else {return "error occured, check fileURL"}
BPMAnalyzer.core.getBpmFrom(url, completion: nil)
Feel free to comment!

Unzipping NSData with ZipArchive

I am using ZipArchive and am reading data in from a device. What I want to do is take the data from the device and unzip it. The only examples I can find are taking the data, writing it to a file on the iOS device, and reading (unzipping) it back again...
This is the code (not working) that I have writing it to disk...
// Read the data in...
if ((recvStringLen = recvfrom(connectSock, recvString, 1025, 0, (struct sockaddr *)&broadcastAddr, &recvStringLen)) < 0) {
NSLog(#"ERROR: Unable to receive user perms message.");
[self showTimeoutError];
return -1;
}
// get the file size...
unsigned int fileSize = (( recvString[16] << 24 ) & 0xff000000) |
(( recvString[17] << 16 ) & 0xff0000) |
(( recvString[18] << 8 ) & 0xff00 ) |
( recvString[19] & 0xff );
NSLog(#"fileSize: %i", fileSize);
recvString[20+fileSize] = '\0'; // terminate the string...
// convert the char data to a string
NSString *stringData = [[[NSString alloc] initWithFormat:#"%s", &recvString[20]] autorelease];
NSData *data = [[[NSData alloc] initWithBytes:stringData length:fileSize] autorelease];
// write the data...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"userinfo.zip"];
[data writeToFile:appFile atomically:YES];
// exist?
BOOL zipExists = [[NSFileManager defaultManager] fileExistsAtPath:appFile];
NSString *zipFilePath = [documentsDirectory stringByAppendingPathComponent:#"userinfo.zip"];
NSString *output = [documentsDirectory stringByAppendingPathComponent:#"userinfo.dat"];
ZipArchive* za = [[ZipArchive alloc] init];
// unzip it...
BOOL success = [za UnzipOpenFile:zipFilePath];
if( success ) {
BOOL outSuccess = [za UnzipFileTo:output overWrite:YES];
if( outSuccess != NO ) {
NSLog(#"success");
}
[za UnzipCloseFile];
}
[za release];
BOOL datExists = [[NSFileManager defaultManager] fileExistsAtPath:output];
When it gets to 'success', it is always NO... even though 'zipExists' is YES.
The two issues I have:
1. The I haven't successfully written the data to disk, read it back, and unzipped it.
2. I would rather just unzip the data (NSData) instead of going thru writing it to disk and reading it back again...
I searched before posting, but was unable to find a solution...
Skip creating a NSString - that is your problem (or one of them). Create the data object from recvString directly. Think about what happens using %s if the data has a null byte.

Resources