1
votes

Back in days I was able to use web cam within my delphi apps using DirectX header translations for Delphi.

Now Firemonkey offers an access to all video/audio capture devices via FMX.Media. I have VCL app and I wanted to use Firemonkey to access camera. I included FMX.Media in my camera unit and used TVideoCaptureDevice class. When getting bitmap from camera it's in Firemonkey bitmap format so I had to convert it to VCL bitmap format with a small trick. Then I draw it to Image on my form.

Everything works perfect but when I shut down an application I get a memory leak report. EurekaLog call stack points to FMX.Context.DX9 in CreateSharedDevice. I checked everything in my code and it looks fine so I am not directly making any memory leaks.

Is that memory leak because I am using FMX.Media in my VCL and it's intention is not to used it in VCL apps due to some conceptual differences? Has anyone else experienced it? By the way I am using Delphi XE6.

Thanks for your help and answers.

memory leak report image

OnCreateForm:

  CamImage := TImage.Create(Self);
  CamImage.Parent := pnlContainer;
  CamImage.Align := alClient;
  CamImage.Stretch := true;
  CamImage.AutoSize := false;

  FMX_BMP := FMX.Graphics.TBitmap.Create;
  VCL_BMP := VCL.Graphics.TBitmap.Create;
  Surface := TBitmapSurface.Create;
  Stream := TMemoryStream.Create;

OnDestroyForm:

  if VideoCamera <> nil then
  begin
    VideoCamera.OnSampleBufferReady := nil;
    VideoCamera.StopCapture;
  end;

  Stream.Free;
  Surface.Free;
  FMX_BMP.Free;
  VCL_BMP.Free;

Populating TPopUpMenu with camera names:

  DeviceList := TCaptureDeviceManager.Current.GetDevicesByMediaType (TMediaType.Video);
  for Idx := 0 to DeviceList.Count - 1 do
  begin
    MenuItem := CreateMenuItem(pmCameras, DeviceList[Idx].Name, false, false, false, 0, 0, pmCameras, evtSelectCamera);
    MenuItem.AutoHotkeys := maManual;
    pmCameras.Items.Add(MenuItem);
  end;

Event handler for selecting camera from TPopup:

procedure TCameraGraph.evtSelectCamera(Sender: TObject);
var Item: TMenuItem;
begin

if Sender is TMenuItem then
begin
  Item := Sender as TMenuItem;
  PrevCam := Item.Caption;
  VideoCamera := TVideoCaptureDevice(TCaptureDeviceManager.Current.GetDevicesByName(StripHotkey(Item.Caption)));
  Item.Checked := true;
  btnCamera.Caption := Item.Caption;
  RefreshMenuFonts;

  if (VideoCamera.State = TCaptureDeviceState.Stopped) then
  begin
    VideoCamera.OnSampleBufferReady := SampleBufferReady;
    VideoCamera.StartCapture;
  end else
  begin
    VideoCamera.OnSampleBufferReady := nil;
    VideoCamera.StopCapture;
  end;

end;


end;

Event handler for TVideoCaptureDevice.OnSampleBufferReady:

    procedure TCameraGraph.SampleBufferReady(Sender: TObject; const ATime: TMediaTime);
    begin
      TThread.Synchronize(TThread.CurrentThread, SampleBufferSync);
    end;

And finally getting firemonkey bitmap and converting it into VCL bitmap and displaying it:

procedure TCameraGraph.SampleBufferSync;
begin
 VideoCamera.SampleBufferToBitmap(FMX_BMP, true);
 Surface.Assign(FMX_BMP);

 TBitmapCodecManager.SaveToStream(Stream, Surface, 'bmp');
 Stream.Seek(0, TSeekOrigin.soBeginning);
 VCL_BMP.LoadFromStream(Stream);

 CamImage.Picture.Graphic := VCL_BMP;
end;
1
I would imagine yes, it is a result of mixing VCL and FMX in the same compilation. I didn't even think that was possible, it shouldn't work.Jerry Dodge
@JerryDodge: Tbh, I don't really pay much attention to FMX stuff, and yours was my first thought too, but I'm sure I've seen posts about mixed VCL/FMX projects somewhere ...MartynA
@MartynA Indeed, I haven't gotten into FMX. But I would imagine, this is like installing a rocket engine on a motorcycle. Even the fuel type is different.Jerry Dodge
It's not too bad. MonkeyMixer lets you have two forms side by side; TFireMonkeyContainer lets you embed a FMX form in a VCL one (like a panel or other component; it's my project, btw, for disclosure); there are others too. They are very different, but... you can always find a solution :)David
FastMM will tell you where the leak originated.David Heffernan

1 Answers

1
votes

FMX cleans up resources (e.g. bitmaps) in its main thread, which is missing in your case. There are (unofficial) ways to mix FMX and VCL (like MonkeyMixer) and they'll probably take care of this issue, but don't expect anything near the quality you had when using VCL with DirectShow: FMX is not thread safe and you'll have to synchronise all grabbed bitmaps with the FMX main thread before passing them on to your VCL app.