使用控制台应用程序中的VFrame在网络摄像头中截取屏幕截图

时间:2016-07-07 18:58:31

标签: delphi

我正在做一个程序来使用Delphi XE2和VFrame来拍摄网络摄像头来实现这个目标,问题是我已经弄明白了,在图形应用程序中一切正常,但是当我使用时在控制台应用程序中的单位,它返回错误说

  

76B6B727的首次机会异常。模块' console.exe'中的地址004A271B处的消息'访问冲突的异常类EAccessViolation。读取地址00000260'。处理console.exe(3676)

我的单位:

unit Webcam;

interface

uses SysUtils, Windows, Vcl.Imaging.Jpeg, Vcl.Graphics, VSample,
  VFrames, Classes;

type
  TWebcam = class
  private
    procedure NewVideoFrameEvent(Sender: TObject; Width, Height: integer;
      DataPtr: pointer);
  public
    constructor Create;
    destructor Destroy; override;
    procedure capture_webcam(take_name: string);

  end;

var
  web_image: TVideoImage;
  name_screen: string;

implementation

constructor TWebcam.Create;
begin
  inherited Create;
end;

destructor TWebcam.Destroy;
begin
  inherited Destroy;
end;

Procedure TWebcam.NewVideoFrameEvent(Sender: TObject; Width, Height: integer;
  DataPtr: pointer);
var
  bitmap: TBitmap;
  name: string;
begin
  name := name_screen;
  if (FileExists(name)) then
  begin
    DeleteFile(Pchar(name));
  end;
  bitmap := TBitmap.Create;
  bitmap.PixelFormat := pf24bit;
  web_image.GetBitmap(bitmap);
  bitmap.SaveToFile(name);
  bitmap.Free;
  web_image.VideoStop;
  web_image.Free;
end;

procedure TWebcam.capture_webcam(take_name: string);
var
  list_cams: TStringList;
begin

  web_image := TVideoImage.Create();

  list_cams := TStringList.Create;

  web_image.GetListOfDevices(list_cams);
  if not(list_cams.count = 0) then
  begin
    name_screen := take_name;
    web_image.VideoStart(list_cams[0]);
  end;

  list_cams.Free;

  web_image.OnNewVideoFrame := NewVideoFrameEvent;

end;

end.

控制台:

program console;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  Webcam;

var
  webcamz: TWebcam;

begin
  try
    webcamz := TWebcam.Create();
    webcamz.capture_webcam('test.jpg');
    webcamz.Free();
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

end.

我该怎么办?

1 个答案:

答案 0 :(得分:1)

VFrames单元的相关源代码可在Github上找到:

https://github.com/heise/GRBLize/blob/edge/VFrames.pas

https://github.com/heise/GRBLize/blob/edge/VSample.pas

TVideoImage.VideoStart()方法依赖于Application.MainForm.Handle。默认情况下,控制台应用程序没有MainForm,因此除非您创建MainForm(这会破坏创建控制台应用程序的目的),否则它将导致控制台应用程序中的代码崩溃。

除此之外,TVideoImage还依赖于消息循环,因为它会创建一个隐藏窗口来接收用于触发OnNewVideoFrame事件的视频通知。您的控制台应用程序没有消息循环。即使它确实如此,你仍然会在事件发生之前释放TVideoImage对象,因为你的capture_webcam()代码在退出之前没有等待事件发生。

此外,TVideoSample类(TVideoImage内部使用)使用DirectShow API从网络摄像头的视频流中捕获图像。 DirectShow是一个基于COM的API。在使用TVideoImage之前,您的控制台应用程序未初始化COM。仅此一项将导致GetListOfDevices()失败并返回空白列表。如果您试图忽略它并提供设备名称,VideoStart()在尝试访问TVideoSample在构造期间无法创建的COM对象时仍会崩溃。