Jump to content
Daniel

struggling while importing c-function with multiple dereferenced pointers

Recommended Posts

*sigh* I am fighting with a function from a DLL requiring a pointer that is dereferenced twice. In theory it should be "a pointer to a pointer to a pointer" but somehow I did not find the right language-contruct in Delphi. I actually have to deal with two functions: one to acquire a data-structure, one to release it. while I found a way to get my hands on the correct data (so the first step of acquiring the data seems to be working), my program crashes when I try to free that memory.

 

Basically it is the following:

typedef struct libvlc_media_track_t
{
    /* some fields */
} libvlc_media_track_t;

/* the two functions I need to import */
unsigned libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t ***tracks )  // the second param is the problematic one
libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count )

 

The import-declaration of the functions look like this:

  function libvlc_media_tracks_get(p_md : libvlc_media_t_ptr; var tracks : Pointer) : LongWord; cdecl;
  procedure libvlc_media_tracks_release(tracks : Pointer; i_count : LongWord ); cdecl;

These declarations are not from me, but - so far - all other declarations from that unit have been working correctly, so I assume that these are also correct.

 

 

My approach was to offer just a pointer to the first function and do some nasty type-conversions afterwards:

var
  LTracksPtr : Pointer;
  LTracks : libvlc_media_track_t;  // a record
  LCount : int32;
begin
  LCount := libvlc_media_tracks_get( FVLCMIntf, LTracksPtr );  // FVLCMIntf is just (an initialised) pointer
  LTracks := libvlc_media_track_t( Pointer(LTracksPtr^)^ );  // works (i have the correct data in the record), but looks ugly to me
  libvlc_media_tracks_release( Pointer(LTracksPtr^), LCount );  // does clearly not work

Now the effects are more or less funny - after trying to release that memory in one out of two cases a listview in my program vanishes. Looks like it has a very unfortunate memory-address that is referenced here by mistake.

 

Could anyone with more c-experience point me into the right direction how to deal with that functions?

 

 

Share this post


Link to post

Logically, I would write

 

libvlc_media_tracks_release( LTracksPtr, LCount );

You pass the LTracksPtr in ..._get function, so only logical thing to do would be to pass same pointer to ..._release function.

 

But this is more logic than C... Strictly following the declarations, I would do the same you did in your non-working code.

Share this post


Link to post

This example should be working - and if I just (very naive) count the asterisks it should match the declarations. 

libvlc_media_track_t **tracks;
uint track_count;
if ((track_count = libvlc_media_tracks_get(media, &tracks)) > 0) {
    ...
    libvlc_media_tracks_release(tracks, track_count);
}

But I still fail to bring this to Delphi-language.

Share this post


Link to post
libvlc_media_tracks_release( LTracksPtr, LCount );

should be correct

In get function tracks is var parameter.  Which is pointer. So that LTracksPtr itself is required parameter for release.

You can also always add types
 

Plibvlc_media_track_t = ^libvlc_media_track_t;

PPlibvlc_media_track_t = ^Plibvlc_media_track_t;

and then functions would be
 

function libvlc_media_tracks_get(p_md : libvlc_media_t_ptr; var tracks : PPlibvlc_media_track_t ) : LongWord; cdecl;
procedure libvlc_media_tracks_release(tracks : PPlibvlc_media_track_t ; i_count : LongWord ); cdecl;

 

Edited by Virgo
correction

Share this post


Link to post

 I would declaree it all as types so  
t

type  
Pmedia_track_t = libvlc_media_track_t^;   
PPmedia_track_t = ^Pmedia_track_t; 

and then  
 

function libvlc_media_tracks_get(p_md : libvlc_media_t_ptr; var tracks : PPmedia_track_t) : LongWord; cdecl;   
procedure libvlc_media_tracks_release(tracks : PPmedia_track_t; i_count : LongWord ); cdecl;    

 

use as:    
 

var   
  LTracksPtr : PPmedia_track_t;   
  LTrackUse :  Pmedia_track_t;   
  LTracks : libvlc_media_track_t;  // a record   
  LCount : int32; 
begin  
LCount := libvlc_media_tracks_get( FVLCMIntf, LTracksPtr );  // FVLCMIntf is just (an initialised) pointer   
LTrackUse := LTracksPtr^;   
LTracks := LTrackUse^ ;  
// The above will point to the first record you can increment for the following or use a Array[0..0] of Pmedia_track_t
libvlc_media_tracks_release( LTracksPtr, LCount );  // should work
end;

 

Share this post


Link to post

Yes, sorry - I will post my solution tomorrow morning. I have just turned off the development-computer. 😉

Share this post


Link to post

I have used these functions for years (at least 7) for a remote visualization project in the security field (and not only) and I never had any problems in using them. The pointer of a pointer is simply .... a pointer. There is no need to change the "signature" of the originally imported functions. You may use the pointer argument like in this excerpt of a function (from Robert Jêdrzejczyk's PasLibVlc project):

 

function TPasLibVlcPlayer.GetVideoSampleAspectRatio(var sar_num, sar_den : Longword): Boolean;
var
  md           : libvlc_media_t_ptr;
  tracks_ptr   : Pointer;
  tracks_list  : libvlc_media_track_list_t_ptr;
  tracks_count : Integer;
  tracks_idx   : Integer;
  track_record : libvlc_media_track_t_ptr;
begin
  Result := FALSE;
  if (p_mi = NIL) then exit;
  md := libvlc_media_player_get_media(p_mi);
  tracks_count := libvlc_media_tracks_get(md, tracks_ptr);
  if (tracks_count > 0) then
  begin
    tracks_list := libvlc_media_track_list_t_ptr(@tracks_ptr);
    for tracks_idx := 0 to tracks_count-1 do
    begin
      track_record := tracks_list^[tracks_idx];
      if (track_record^.i_type = libvlc_track_video) then
      begin
        sar_num := track_record^.u.video^.i_sar_num;
        sar_den := track_record^.u.video^.i_sar_den;
        Result := TRUE;
        break;
      end;
    end;
    libvlc_media_tracks_release(tracks_ptr, tracks_count);
  end;
end;

 

Share this post


Link to post
On 2/22/2021 at 11:46 AM, Stefan Glienke said:

Should be an (*1)array of (*2)pointer to libvlc_media_track_t passed by (*3)reference, no?

 

I think this is a:

  • passed by reference (1*)
    • pointer variable, which will point (2*) to
      • array of pointers (3*) to libvlc_media_track_t structs.

 

type
  PTracks = ^TTracks;
  TTracks = array[0..1024] of ^libvlc_media_track_t;

function  libvlc_media_tracks_get(p_md: libvlc_media_t_ptr; var tracks: PTracks): LongWord; cdecl;
procedure libvlc_media_tracks_release(tracks: PTracks; i_count: LongWord); cdecl;

procedure GetTracks;
var
  tracks: PTracks;
  cnt:    Integer;
  track:  libvlc_media_track_t;
begin
  cnt := libvlc_media_tracks_get(FVLCMIntf, tracks);
  try
    for i := 0 to cnt - 1 do
    begin
      track := tracks[i]^;
      DoSomething(track);
    end;
  finally
    libvlc_media_tracks_release(tracks, cnt);
  end;
end;

 

Edited by balabuev

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×