2013-03-20 88 views
3

我在我的项目中使用paslibvlc获得一个视频摄像头在h.264流。我需要从此流中获取快照,并尝试使用vmem。我的项目编写于delphi 7。当我用字符串“rtsp:// ip/main”连接摄像机时,一切正常,但是当我设置回调和格式时,会出现访问存储器违规的错误。有人可以对我说,我做错了什么? 这是代码libvlc vmem访问冲突

PBytes = ^TBytes; 
TBytes = array of byte; 

var 
    MainForm: TMainForm; 
    ctx:TBytes; 

const 
    cameraURL = 'rtsp://192.168.123.100/main'; 

function lock(opaque : Pointer; var planes : Pointer) : Pointer; 
function unlock(opaque : Pointer; picture : Pointer; planes : Pointer) : Pointer; 
function display(opaque : Pointer; picture : Pointer) : Pointer; 

implementation 

{$R *.dfm} 


function lock(opaque : Pointer; var planes : Pointer) : Pointer; 
begin 
    planes := x; 
end; 

function unlock(opaque : Pointer; picture : Pointer; planes : Pointer) : Pointer; 
begin 
end; 

function display(opaque : Pointer; picture : Pointer) : Pointer; 
begin 
end; 

procedure TMainForm.PlayerInit(); 
var 
    args: packed array[0..6] of PAnsiChar; 
begin 
    libvlc_dynamic_dll_init(); 

    SetLength(ctx, 1280*720*4+32); 

    if (libvlc_dynamic_dll_error <> '') then 
    begin 
    MessageDlg(libvlc_dynamic_dll_error, mtError, [mbOK], 0); 
    exit; 
    end; 

    args[0] := PAnsiChar(libvlc_dynamic_dll_path); 
    args[1] := '--no-video-title-show'; 
    args[2] := '--no-xlib'; 
    args[3] := '--no-audio'; 

    p_li := libvlc_new(Length(args)-1, @args[0]); 
    p_mi := NIL; 
end; 

procedure TMainForm.PlayerPlay(fileName: WideString); 
var 
    p_md: libvlc_media_t_ptr; 
begin 
    btm:=Tbitmap.Create; 
    btm.Width:=1280; 
    btm.Height:=720; 
    PlayerStop(); 

    // create new media from fileName 
    p_md := libvlc_media_new_path(p_li, PAnsiChar(System.UTF8Encode(fileName))); 

    //libvlc_media_player_set_media(p_mi, p_md); 
    p_mi := libvlc_media_player_new_from_media(p_md); 

    if (p_mi <> NIL) then 
    begin 
    libvlc_video_set_callbacks(p_mi,@lock,@unlock,@display,@ctx); 
    libvlc_video_set_format(p_mi, 'RV32', 1280, 720, 1280*4); 
    //libvlc_media_player_set_hwnd(p_mi, btm.Handle); 
    end; 

    // play 
    libvlc_media_player_play(p_mi); 

    // release media 
    if (p_md <> NIL) then 
    begin 
    libvlc_media_release(p_md); 
    // p_md := NIL; 
    end; 
end; 



procedure TMainForm.FormActivate(Sender: TObject); 
begin 
    PlayerInit(); 
    PlayerPlay(cameraURL); 
end; 
+0

请在标签中指定Delphi版本。谢谢。顺便说一句,你为什么不让你的avatara透明?在蓝色背景中的白色边框只是看起来不圆滑;-) – 2013-03-20 16:03:25

回答

3

你的回调使用register调用约定。但这是一个Delphi特定的调用约定。您的图书馆使用cdecl。这可以从该库的帕斯卡尔源代码中可以看出:

type 
    libvlc_video_lock_cb = function(opaque : Pointer; 
     var planes : Pointer) : Pointer; cdecl; 
    libvlc_video_unlock_cb = function(opaque : Pointer; 
     picture : Pointer; planes : Pointer) : Pointer; cdecl; 
    libvlc_video_display_cb = function(opaque : Pointer; 
     picture : Pointer) : Pointer; cdecl; 

你需要改变你的回调库的调用约定相匹配。

编译器会告诉你所有这些,只要你没有使用@运算符来获得函数指针。这样做意味着编译器不会检查您的函数指针的签名是否与声明的签名匹配。这是人们犯的最常见的错误之一。无论出于何种原因,神话一直延续,获得函数指针的方式是使用@运算符。

总之你需要添加cdecl到您的回调函数:

function lock(opaque : Pointer; var planes : Pointer) : Pointer; cdecl; 
function unlock(opaque : Pointer; picture : Pointer; 
    planes : Pointer) : Pointer; cdecl; 
function display(opaque : Pointer; picture : Pointer) : Pointer; cdecl; 

然后停止使用@获取函数指针:

libvlc_video_set_callbacks(p_mi, lock, unlock, display, @ctx); 
+0

谢谢你的答案。是的,这是我的错误,我没有用cdecl声明回调函数。我做了这个,但我有类似的错误 - 访问冲突( – Divon 2013-03-20 09:39:16

+0

我不认为我可以帮助没有更多的信息 – 2013-03-20 09:42:05

+0

这里是一个小项目,我试图做到这一点[PasLibVlcDemo](http:// www .datafilehost.com/download-8c30c25d.html) – Divon 2013-03-20 10:21:42

0

所有问题是我如何分配内存。在第一个主题中,我在SetLength(ctx,1280 * 720 * 4 + 32)等程序的语言环境内存中分配内存,但为了做好工作,我必须使用AllocMem来使用非托管内存。

+0

不,问题中的代码问题与我所描述的完全相同,在问题中的代码中你从来没有提到'ctx',所以它是无关紧要的在这个问题中,一旦你解决了代码中的问题,你就会遇到其他问题,但是由于代码和问题不在问题中,所以不相关,我非常失望你不接受我的答案。 – 2013-03-29 10:42:24

+0

而且,为了它的价值,你可以很好地使用'SetLength'来分配你的缓冲区。但是要传递一个指向缓冲区第一个字节的指针,你可以使用'@ctx [0]'而不是'@ ctx'。你所要做的只是询问一个后续问题,我们也可以为你解决这个问题。 – 2013-03-29 10:46:07