I am having some problems dynamically declaring a GLfloat array in Objective-C. Here is the c
ode i'm using:
GLfloat *m_bindPositions;
#implementation
int nVerts = [self m_countVertices];
m_bindPositions = (GLfloat*)malloc((nVerts * 3) * sizeof(GLfloat));
nVerts in this example equals 6704.
if I was to run sizeof(m_bindPositions) it should return 80448.
It currently returns 4.This makes me believe there is an error with the allocation of the
memory and I am not entirely sure why. Any help would be much appreciated.
Thanks
sizeof in this case is returning the size of the pointer, not the data pointed at by it.
However, the compiler is what handles sizeof, and it will not dynamically return values based on malloc, so you cannot double-check an allocation like that using sizeof (or anything else, other than malloc_size(), which will return a number equal to or greater than the allocation, representing the allocation block size.
Related
Do I need to null-terminate a basic float array in objective C?
I have a basic float array:
float data[] = {0.5, 0.1, 1};
and when I do a sizeof(data) I get "12".
You don't need to null terminate it to create one, no. And in general a method taking a float[] would also take a size parameter to indicate how many elements there are.
You get sizeof(data) = 12 because a float is 4-bytes on your architecture and there's 3 of them.
sizeof return the amount of memory (in bytes) occupied by the parameter. In your case, every float occupies 4 bytes, thus 4*3=12.
As Hot Licks said in the comment of mattjgalloway's answer, there is not a standard way to retrieve the number of elements in a C array.
Using size = sizeof(data) / sizeof(float) works, but you must be careful in using this approach, since if you pass the array as a parameter it won't work.
A common approach is to store the size in a variable and use it as upper bound in your for loop (often functions that expect an array have an additional parameter to get the size of the array).
Using a null-terminated array is useful because you can iterate through your array and stop when the i-esim element is null (that's the approach of methods like strcmp).
Values of type float can never be null, so it's not possible to terminate an array of type float with null. For one thing, variables of any primitive type always have a numeric value, and the various null constants (in Objective-C nil, Nil, NULL, and '\0') have the literal value 0, which is obviously a valid value in range of a float.
So even if you can compile the following line without a warning,
float x = NULL;
...it would have the same consequence as this:
float x = 0;
Inserting a null constant in an array of type float would be indistinguishable from inserting 0.0 or any other constant zero value.
I've searched the forum and seen some possible partial solutions to this question, but I'd like help putting it all together.
I'm getting the frames from the camera and doing image processing on the difference between the current frame and previous frame. In addition to the RGB values from the camera, I'm also calculating Hue and Saturation for each pixel, each of which is also an int. So my 2 questions are:
What is the best way to store all of these values from each call to didOutputSampleBuffer? From what I've been reading, it seems like with this many values, the overhead from NSNumber will be noticable so least memory would be spent using a classic c-style array of ints w/ length 144 x 192 x 5(R,G,B,H,S) = 138,240. Does that make sense?
How do I put this array in the scope of my didOutputSampleBuffer method, because I'm initializing the array upon app launch, not in the didOutputSampleBuffer method. Someone on the forum mentioned perhaps I could wrap the array in NSMutableData and then i could just store it as a property?
Thank you for your advice,
Don
Given that the size of an image won't change, you should be able to create a buffer to store these components as interleaved bytes or a few buffers for each color component plane. You could do this by manually using malloc() and free() to create this buffer and destroy it when done.
If you'd prefer to use reference counting, you could wrap these bytes in an NSData instance, which won't add much overhead to your processing. Either a pointer to your processed buffer bytes or an NSData instance could be used as properties.
Note that you'll probably want to use unsigned char types for each component, because you're only getting back individual bytes for each of the color components. Why waste memory with unnecessary precision?
Yes, that is a good way to store the data. Alternatively, you could use a c array of structures (see my example).
You could use a global variable or a property, containing either a NSMutableData object or the pointer to the array. Since you want access to the data as integers and not raw data, storing the pointer to the data would probably be easier than a NSData object.
Example:
// header file
struct PixelData {
int r, g, b, h, s;
};
#interface TheClass : TheSuperclass {
struct PixelData *dataPointer;
}
#property struct PixelData *dataPointer;
#end
// implementation file
#implementation TheClass
#synthesize dataPointer;
- (void)didOutputSampleBuffer { // Yes, I know this isn't the full name.
// parse data
// store data for pixel at index i:
struct PixelData *dp = self.dataPointer;
dp[i].r = r;
dp[i].g = g;
dp[i].b = b;
dp[i].h = h;
dp[i].s = s;
}
#end
When I was dealing with a similar problem I simply made the c style array an ivar on an object.
This way I could attach additional properties to it like metadata, etc.
#interface MyObject : NSObject {
int *arrayOfInts;
}
#property (readwrite) int *arrayOfInts;
#end
You still have to explicitly manage the memory in this case.
How do I convert this to Objective-C?? Mainly this: float *newH= new float[newD];
What do I substitute new for in obj-c??
int newD = 100;
float *newH = new float[newD];
for(int i=0; i<newD; i++){
newH[i] = 0.0f;
}
Objective-C is a true superset of C. In C, one uses malloc to allocate memory.
So,
float *newH = malloc( newD * sizeof( float) );
Of course, depending on what you are really doing, you may also want to investigate NSArray and NSNumber.
Note, that Objective-C++ is available as well and you can continue to use 'new' to allocate your memory.
If you have a lot of C++ code to port, you might be better off writing your app in Objective-C++. Then you can use your C++ code as is.
I agree that Objective C++ is the way to go. However, if you absolutely want to stay within the spirit of Objective C (not straight C), here are the options:
use an NSArray of NSNumber objects. This is slow - float boxing penalty applies.
use a NSData as a allocation mechanism, cast [bytes] to float *. This is ugly, the way pointer typecasts are.
My question is a little tricky, and I'm not exactly experienced (I might get some terms wrong), so here goes.
I'm declaring an instance of an object called "Singer". The instance is called "singer1". "singer1" produces an audio signal. Now, the following is the code where the specifics of the audio signal are determined:
OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
//Singer *me = (Singer *)inRefCon;
static int phase = 0;
for(UInt32 i = 0; i < ioData->mNumberBuffers; i++) {
int samples = ioData->mBuffers[i].mDataByteSize / sizeof(SInt16);
SInt16 values[samples];
float waves;
float volume=.5;
for(int j = 0; j < samples; j++) {
waves = 0;
waves += sin(kWaveform * 600 * phase)*volume;
waves += sin(kWaveform * 400 * phase)*volume;
waves += sin(kWaveform * 200 * phase)*volume;
waves += sin(kWaveform * 100 * phase)*volume;
waves *= 32500 / 4; // <--------- make sure to divide by how many waves you're stacking
values[j] = (SInt16)waves;
values[j] += values[j]<<16;
phase++;
}
memcpy(ioData->mBuffers[i].mData, values, samples * sizeof(SInt16));
}
return noErr;
}
99% of this is borrowed code, so I only have a basic understanding of how it works (I don't know about the OSStatus class or method or whatever this is. However, you see those 4 lines with 600, 400, 200 and 100 in them? Those determine the frequency. Now, what I want to do (for now) is insert my own variable in there in place of a constant, which I can change on a whim. This variable is called "fr1". "fr1" is declared in the header file, but if I try to compile I get an error about "fr1" being undeclared. Currently, my technique to fix this is the following: right beneath where I #import stuff, I add the line
fr1=0.0;//any number will work properly
This sort of works, as the code will compile and singer1.fr1 will actually change values if I tell it to. The problems are now this:A)even though this compiles and the tone specified will play (0.0 is no tone), I get the warnings "Data definition has no type or storage class" and "Type defaults to 'int' in declaration of 'fr1'". I bet this is because for some reason it's not seeing my previous declaration in the header file (as a float). However, again, if I leave this line out the code won't compile because "fr1 is undeclared". B)Just because I change the value of fr1 doesn't mean that singer1 will update the value stored inside the "playbackcallback" variable or whatever is in charge of updating the output buffers. Perhaps this can be fixed by coding differently? C)even if this did work, there is still a noticeable "gap" when pausing/playing the audio, which I need to eliminate. This might mean a complete overhaul of the code so that I can "dynamically" insert new values without disrupting anything. However, the reason I'm going through all this effort to post is because this method does exactly what I want (I can compute a value mathematically and it goes straight to the DAC, which means I can use it in the future to make triangle, square, etc waves easily). I have uploaded Singer.h and .m to pastebin for your veiwing pleasure, perhaps they will help. Sorry, I can't post 2 HTML tags so here are the full links.
(http://pastebin.com/ewhKW2Tk)
(http://pastebin.com/CNAT4gFv)
So, TL;DR, all I really want to do is be able to define the current equation/value of the 4 waves and re-define them very often without a gap in the sound.
Thanks. (And sorry if the post was confusing or got off track, which I'm pretty sure it did.)
My understanding is that your callback function is called every time the buffer needs to be re-filled. So changing fr1..fr4 will alter the waveform, but only when the buffer updates. You shouldn't need to stop and re-start the sound to get a change, but you will notice an abrupt shift in the timbre if you change your fr values. In order to get a smooth transition in timbre, you'd have to implement something that smoothly changes the fr values over time. Tweaking the buffer size will give you some control over how responsive the sound is to your changing fr values.
Your issue with fr being undefined is due to your callback being a straight c function. Your fr variables are declared as objective-c instance variables as part of your Singer object. They are not accessible by default.
take a look at this project, and see how he implements access to his instance variables from within his callback. Basically he passes a reference to his instance to the callback function, and then accesses instance variables through that.
https://github.com/youpy/dowoscillator
notice:
Sinewave *sineObject = inRefCon;
float freq = sineObject.frequency * 2 * M_PI / samplingRate;
and:
AURenderCallbackStruct input;
input.inputProc = RenderCallback;
input.inputProcRefCon = self;
Also, you'll want to move your callback function outside of your #implementation block, because it's not actually part of your Singer object.
You can see this all in action here: https://github.com/coryalder/SineWaver
I have an Objective-C class (although I don't believe this is anything Obj-C specific) that I am using to write a video out to disk from a series of CGImages. (The code I am using at the top to get the pixel data comes right from Apple: http://developer.apple.com/mac/library/qa/qa2007/qa1509.html). I successfully create the codec and context - everything is going fine until it gets to avcodec_encode_video, when I get EXC_BAD_ACCESS. I think this should be a simple fix, but I just can't figure out where I am going wrong.
I took out some error checking for succinctness. 'c' is an AVCodecContext*, which is created successfully.
-(void)addFrame:(CGImageRef)img
{
CFDataRef bitmapData = CGDataProviderCopyData(CGImageGetDataProvider(img));
long dataLength = CFDataGetLength(bitmapData);
uint8_t* picture_buff = (uint8_t*)malloc(dataLength);
CFDataGetBytes(bitmapData, CFRangeMake(0, dataLength), picture_buff);
AVFrame *picture = avcodec_alloc_frame();
avpicture_fill((AVPicture*)picture, picture_buff, c->pix_fmt, c->width, c->height);
int outbuf_size = avpicture_get_size(c->pix_fmt, c->width, c->height);
uint8_t *outbuf = (uint8_t*)av_malloc(outbuf_size);
out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture); // ERROR occurs here
printf("encoding frame %3d (size=%5d)\n", i, out_size);
fwrite(outbuf, 1, out_size, f);
CFRelease(bitmapData);
free(picture_buff);
free(outbuf);
av_free(picture);
i++;
}
I have stepped through it dozens of times. Here are some numbers...
dataLength = 408960
picture_buff = 0x5c85000
picture->data[0] = 0x5c85000 -- which I take to mean that avpicture_fill worked...
outbuf_size = 408960
and then I get EXC_BAD_ACCESS at avcodec_encode_video. Not sure if it's relevant, but most of this code comes from api-example.c. I am using XCode, compiling for armv6/armv7 on Snow Leopard.
Thanks so much in advance for help!
I have not enough information here to point to the exact error, but I think that the problem is that the input picture contains less data than avcodec_encode_video() expects:
avpicture_fill() only sets some pointers and numeric values in the AVFrame structure. It does not copy anything, and does not check whether the buffer is large enough (and it cannot, since the buffer size is not passed to it). It does something like this (copied from ffmpeg source):
size = picture->linesize[0] * height;
picture->data[0] = ptr;
picture->data[1] = picture->data[0] + size;
picture->data[2] = picture->data[1] + size2;
picture->data[3] = picture->data[1] + size2 + size2;
Note that the width and height is passed from the variable "c" (the AVCodecContext, I assume), so it may be larger than the actual size of the input frame.
It is also possible that the width/height is good, but the pixel format of the input frame is different from what is passed to avpicture_fill(). (note that the pixel format also comes from the AVCodecContext, which may differ from the input). For example, if c->pix_fmt is RGBA and the input buffer is in YUV420 format (or, more likely for iPhone, a biplanar YCbCr), then the size of the input buffer is width*height*1.5, but avpicture_fill() expects the size of width*height*4.
So checking the input/output geometry and pixel formats should lead you to the cause of the error. If it does not help, I suggest that you should try to compile for i386 first. It is tricky to compile FFMPEG for the iPhone properly.
Does the codec you are encoding support the RGB color space? You may need to use libswscale to convert to I420 before encoding. What codec are you using? Can you post the code where you initialize your codec context?
The function RGBtoYUV420P may help you.
http://www.mail-archive.com/libav-user#mplayerhq.hu/msg03956.html