www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Linking with FFmpeg

reply "MrOrdinaire" <mrordinaire gmail.com> writes:
Hi,

I am working on D bindings for FFmpeg. I am trying to port the 
official examples of FFmpeg to D so that the bindings can be 
tested.

My question is how this function declaration is written in D.
int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                    int w, int h, enum AVPixelFormat pix_fmt, int 
align);

My best guess is the following.
extern(C) int av_image_alloc(ref uint8_t[4] *pointers, ref int[4] 
linesizes,
                              int w, int h, AVPixelFormat pix_fmt, 
int align_);

However, calling this would give nonsense value for the array 
passed as linesizes. I don't know how to look at the variable 
passed as pointers yet.

The whole source of the port is at 
https://gist.github.com/4466289, there you can also find the link 
to the original source.

Thanks,
Minh
Jan 06 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
MrOrdinaire:

 My question is how this function declaration is written in D.
 int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                    int w, int h, enum AVPixelFormat pix_fmt, 
 int align);

 My best guess is the following.
 extern(C) int av_image_alloc(ref uint8_t[4] *pointers, ref 
 int[4] linesizes,
                              int w, int h, AVPixelFormat 
 pix_fmt, int align_);
D ints are 32 bit long, while the length of C ints varies across different architectures. So you can't use int in your D signature. sizediff_t is better, but I remember there is a more specific type for this purpose, something like cint_t, I don't remember. In D the pointer symbol "*" is better (more meaningful) written justified on the right. If you use a D ref, you can't put a null there. Others will give you a better answer. Bye, bearophile
Jan 06 2013
parent reply "MrOrdinaire" <mrordinaire gmail.com> writes:
On Sunday, 6 January 2013 at 10:21:56 UTC, bearophile wrote:
 MrOrdinaire:

 My question is how this function declaration is written in D.
 int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                   int w, int h, enum AVPixelFormat pix_fmt, 
 int align);

 My best guess is the following.
 extern(C) int av_image_alloc(ref uint8_t[4] *pointers, ref 
 int[4] linesizes,
                             int w, int h, AVPixelFormat 
 pix_fmt, int align_);
D ints are 32 bit long, while the length of C ints varies across different architectures. So you can't use int in your D signature. sizediff_t is better, but I remember there is a more specific type for this purpose, something like cint_t, I don't remember. In D the pointer symbol "*" is better (more meaningful) written justified on the right. If you use a D ref, you can't put a null there. Others will give you a better answer. Bye, bearophile
Thank you for your reply. I cannot find "cint_t" nor "cint" in the d standard modules (mine are at /usr/include/d/). For the symbol "*", do you mean I should write something like this? uint8_t[4]* ptrs - Minh
Jan 06 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
MrOrdinaire:

 I cannot find "cint_t" nor "cint" in the d standard modules 
 (mine are at /usr/include/d/).
I don't remember the correct name.
 For the symbol "*", do you mean I should write something like 
 this?
 uint8_t[4]* ptrs
Right. It's a D coding style convention that has a practical base. In C this means a is a pointer and b is an integer, while in D it means both are pointers: int *a, b; In C this means a is an int and b is a pointer, while in D it's thankfully an error (Error: multiple declarations must have the same type, not int and int*): int a, *b; Bye, bearophile
Jan 06 2013
parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 06 Jan 2013 12:51:33 +0100
schrieb "bearophile" <bearophileHUGS lycos.com>:

 MrOrdinaire:
 
 I cannot find "cint_t" nor "cint" in the d standard modules 
 (mine are at /usr/include/d/).
I don't remember the correct name.
Are you sure about c_int? I never heard of that before, I only know c_long and c_ulong (in core.stdc.config). http://dlang.org/interfaceToC.html also says C int is the same as D int.
Jan 06 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
Johannes Pfau:

 also says C int is the same as D int.
How is this possible? Bye, bearophile
Jan 06 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
MrOrdinaire:

 For the symbol "*", do you mean I should write something like 
 this?
 uint8_t[4]* ptrs
In D "ubyte" is probably enough, instead of "uint8_t". Bye, bearophile
Jan 06 2013
parent "MrOrdinaire" <mrordinaire gmail.com> writes:
On Sunday, 6 January 2013 at 11:54:34 UTC, bearophile wrote:
 MrOrdinaire:

 For the symbol "*", do you mean I should write something like 
 this?
 uint8_t[4]* ptrs
In D "ubyte" is probably enough, instead of "uint8_t". Bye, bearophile
Thanks for noting that. I know that in std.stdint, uint8_t is an alias for ubyte. However, I want to keep to the original source so that people can do a diff more easily. - Minh
Jan 06 2013
prev sibling next sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 06 Jan 2013 10:48:25 +0100
schrieb "MrOrdinaire" <mrordinaire gmail.com>:

 Hi,
 
 I am working on D bindings for FFmpeg. I am trying to port the 
 official examples of FFmpeg to D so that the bindings can be 
 tested.
 
 My question is how this function declaration is written in D.
 int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                     int w, int h, enum AVPixelFormat pix_fmt, int 
 align);
 
My C is pretty bad, is uint8_t *pointers[4] a static array with 4 elements of uint8_t* or is it a pointer to a static array with 4 uint8_t elements? I guess it's the former, so in D it's (uint8_t*)[4] or better (ubyte*)[4]. In D static arrays are passed by value, in C by reference, so you have to do this: extern(C) int av_image_alloc(ref (ubyte*)[4] pointers, ref int[4] linesizes, int w, int h, AVPixelFormat pix_fmt, int align_); Some more information is here: http://dlang.org/interfaceToC.html
Jan 06 2013
parent "MrOrdinaire" <mrordinaire gmail.com> writes:
On Sunday, 6 January 2013 at 12:46:05 UTC, Johannes Pfau wrote:
 Am Sun, 06 Jan 2013 10:48:25 +0100
 schrieb "MrOrdinaire" <mrordinaire gmail.com>:

 Hi,
 
 I am working on D bindings for FFmpeg. I am trying to port the 
 official examples of FFmpeg to D so that the bindings can be 
 tested.
 
 My question is how this function declaration is written in D.
 int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                     int w, int h, enum AVPixelFormat pix_fmt, 
 int align);
 
My C is pretty bad, is uint8_t *pointers[4] a static array with 4 elements of uint8_t* or is it a pointer to a static array with 4 uint8_t elements? I guess it's the former, so in D it's (uint8_t*)[4] or better (ubyte*)[4]. In D static arrays are passed by value, in C by reference, so you have to do this: extern(C) int av_image_alloc(ref (ubyte*)[4] pointers, ref int[4] linesizes, int w, int h, AVPixelFormat pix_fmt, int align_); Some more information is here: http://dlang.org/interfaceToC.html
According to this (http://c-faq.com/decl/spiral.anderson.html), I think pointers is an array of 4 pointers to uint8_t. So in D, you read declarations from right to left? - Minh
Jan 06 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sun, Jan 06, 2013 at 10:48:25AM +0100, MrOrdinaire wrote:
 Hi,
 
 I am working on D bindings for FFmpeg. I am trying to port the
 official examples of FFmpeg to D so that the bindings can be tested.
 
 My question is how this function declaration is written in D.
 int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
                    int w, int h, enum AVPixelFormat pix_fmt, int
 align);
 
 My best guess is the following.
 extern(C) int av_image_alloc(ref uint8_t[4] *pointers, ref int[4]
 linesizes,
                              int w, int h, AVPixelFormat pix_fmt,
 int align_);
The first parameter should be: uint8_t* pointers, and you need to call it like this: uint8_t[4] pointers; int[4] linesizes; auto ret = av_image_alloc(pointers.ptr, linesizes.ptr, ...); To make it D-friendly, you might want to consider using a wrapper function that takes ref uint8_t[4] and ref int[4] instead.
 However, calling this would give nonsense value for the array passed
 as linesizes. I don't know how to look at the variable passed as
 pointers yet.
[...] Just write *ptr to dereference a pointer. You can also take advantage of D's auto-dereferencing: struct S { int val = 123; } S s; S* ptr = &s; writeln(s.val); // prints 123 writeln(ptr.val); // also prints 123 (ptr is automatically // dereferenced) Finally, please note that in D, the * in pointer types associate with the _type_ rather than the variable name (as in C/C++), so you should always write "int* x,y" instead of "int *x, *y". Similarly, an array of pointers is written as "int*[] arr", whereas writing "int[]* arr" is actually declaring a pointer to an array. (In D, pointers and arrays are not the same thing.) T -- I don't trust computers, I've spent too long programming to think that they can get anything right. -- James Miller
Jan 06 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/06/2013 01:48 AM, MrOrdinaire wrote:

 My question is how this function declaration is written in D.
 int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
 int w, int h, enum AVPixelFormat pix_fmt, int align);
1) No array is passed to a function as-is in C. Even though there seem to be arrays of 4 elements above, they are both passed as pointers to their first elements. (That 4 has no bearing at all.) 2) uint8_t *pointers[4] means an array of elements of type 'uint8_t*'. 3) int linesizes[4] means an array of ints. 4) uint8_t and friends are defined in the std.stdint module in Phobos. 5) enum should not be used in that signature in D. 6) align is a keyword and cannot be used. This is the declaration of that function in D: extern(C) int av_image_alloc(uint8_t** pointers, int* linesizes, int w, int h, AVPixelFormat pix_fmt, int alignment); Here is a program that I used to test it: import std.stdint; extern(C) { enum AVPixelFormat { one, two } int av_image_alloc(uint8_t** pointers, int* linesizes, int w, int h, AVPixelFormat pix_fmt, int alignment); } void main() { uint8_t ui0 = 7; uint8_t ui1 = 8; uint8_t*[] pointers = [ &ui0, &ui1 ]; // Ditto int[] linesizes = [ 20, 30, 40 ]; int result = av_image_alloc(pointers.ptr, linesizes.ptr, 44, 55, AVPixelFormat.two, 100); assert(result == 42); } I tested it with the following C file: #include <stdint.h> #include <assert.h> enum AVPixelFormat { AVPixelFormat_one, AVPixelFormat_two }; int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align) { assert(*pointers[0] == 7); assert(*pointers[1] == 8); assert(linesizes[0] == 20); assert(linesizes[1] == 30); assert(linesizes[2] == 40); assert(w == 44); assert(h == 55); assert(pix_fmt == AVPixelFormat_two); assert(align == 100); return 42; } I compiled the C file like this: $ gcc -c deneme.c Then compiled the D program like this (note that the C .o was in a different directory): $ dmd ../c/deneme.o deneme.d And ran it like this: $ ./deneme All assertions passed. Yay! :) Ali P.S. To prove the point that that 4 in the signature has no meaning, I tested the C function also with the following C program: int main() { uint8_t ui0 = 7; uint8_t ui1 = 8; // Deliberately 10 (not 4) to prove a point uint8_t* pointers[10] = { &ui0, &ui1 }; // Ditto int linesizes[10] = { 20, 30, 40 }; av_image_alloc(pointers, linesizes, 44, 55, AVPixelFormat_two, 100); }
Jan 06 2013
parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 06 Jan 2013 09:43:11 -0800
schrieb Ali =C3=87ehreli <acehreli yahoo.com>:

=20
 Ali
=20
 P.S. To prove the point that that 4 in the signature has no meaning,
 I tested the C function also with the following C program:
With C's arrays are pointers thing, that might be true. But the signature (and ffmpeg) documentation suggest that the av_image_alloc function will always write 4 ubyte* pointers to the pointers parameter. So you can't use an array smaller than 4 pointers. You can use more, as it doesn't matter for the ABI, but av_image_alloc will only use 4 pointers. So I'd argue that ((ubyte*)[4])* is better as a type than ubyte** as it allows the D compiler to do more checks. And the Interfacing to C page recommends using ref for static arrays instead of a pointer, as that allows using the code as in C: void av_image_alloc(ref (ubyte*)[4]); (ubyte*)[4] ptr; av_image_alloc(ptr); void av_image_alloc((ubyte*)[4]*); (ubyte*)[4] ptr; av_image_alloc(&ptr); //need & void av_image_alloc(ubyte**); (ubyte*)[3] ptr; ubyte* test; //overwritten, BUG! av_image_alloc(&ptr); //need &, and accepts to small arrays, bug prone
Jan 06 2013
parent reply "MrOrdinaire" <mrordinaire gmail.com> writes:
On Sunday, 6 January 2013 at 18:39:32 UTC, Johannes Pfau wrote:
 Am Sun, 06 Jan 2013 09:43:11 -0800
 schrieb Ali Çehreli <acehreli yahoo.com>:

 
 Ali
 
 P.S. To prove the point that that 4 in the signature has no 
 meaning,
 I tested the C function also with the following C program:
With C's arrays are pointers thing, that might be true. But the signature (and ffmpeg) documentation suggest that the av_image_alloc function will always write 4 ubyte* pointers to the pointers parameter. So you can't use an array smaller than 4 pointers. You can use more, as it doesn't matter for the ABI, but av_image_alloc will only use 4 pointers. So I'd argue that ((ubyte*)[4])* is better as a type than ubyte** as it allows the D compiler to do more checks. And the Interfacing to C page recommends using ref for static arrays instead of a pointer, as that allows using the code as in C: void av_image_alloc(ref (ubyte*)[4]); (ubyte*)[4] ptr; av_image_alloc(ptr); void av_image_alloc((ubyte*)[4]*); (ubyte*)[4] ptr; av_image_alloc(&ptr); //need & void av_image_alloc(ubyte**); (ubyte*)[3] ptr; ubyte* test; //overwritten, BUG! av_image_alloc(&ptr); //need &, and accepts to small arrays, bug prone
I agree with you. One quick question, why do you need a pair of parentheses in these declarations, ref (ubyte*)[4] and (ubyte*)[4]? The compiler doesn't complain if I remove it.
Jan 06 2013
parent Johannes Pfau <nospam example.com> writes:
Am Mon, 07 Jan 2013 03:31:51 +0100
schrieb "MrOrdinaire" <mrordinaire gmail.com>:

 
 I agree with you.
 
 One quick question, why do you need a pair of parentheses in 
 these declarations, ref (ubyte*)[4] and (ubyte*)[4]? The compiler 
 doesn't complain if I remove it.
I wasn't sure if it's necessary. Imho it makes the code easier to read but that's probably just a personal preference.
Jan 07 2013