4

There seems to be TVideoCaptureDevice in FireMonkey (Delphi XE6), but on official documentation, capturing process ends up on lines:

if(VideoCamera){
  //do something
}

What do I do to record video to mp4 on flight? Tried looking on google, but didn't find any answer...

Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
Flash Thunder
  • 11,672
  • 8
  • 47
  • 91
  • Maybe this [documentation link](http://developer.android.com/reference/android/media/MediaRecorder.OutputFormat.html#MPEG_4) is helpful – Sir Rufo May 23 '14 at 20:56
  • There seems to be no MediaRecorder class on Delphi... oh and seems to be no TVideoCaptureDevice neither... :/ – Flash Thunder May 23 '14 at 20:58
  • 1
    [`FMX.Media.TVideoCaptureDevice`](http://docwiki.embarcadero.com/Libraries/en/FMX.Media.TVideoCaptureDevice) and the wrapped classes (hidden in implementation section) are located in `FMX.Media.Android`. Some of the (mostly platform specific) possibilities are not fully implemented by emba and you have to put some effort to use them – Sir Rufo May 23 '14 at 21:15
  • 1
    Ok, so there is no easy way, right? Then writting it in Delphi has no sense... – Flash Thunder May 23 '14 at 21:22
  • Yeah, sometimes easy sounding jobs getting rather difficult with delphi. Maybe you will find it implemented in XE9 or later ... :o) – Sir Rufo May 23 '14 at 21:24

2 Answers2

6

See the following docwiki for an answer (sort-of).

Delphi Video Capturing in XE7

Of course the word "capturing" here means, getting the video input and putting it on the display. "Recording" means joining the frames together to make a movie file.

The following code was kindly provided to me by the people at

flashavconverter and is posted here with their approval:

uses
  Androidapi.JNI.GraphicsContentViewText;

const
  RECORD_VIDEO = 9;

implementation

uses 
  System.IOUtils,
  Androidapi.JNI.Provider,
  Androidapi.JNI.App,
  Androidapi.JNI.Net,
  Androidapi.JNIBridge,
  Androidapi.Helpers,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.Os;

{$R *.fmx}

procedure TFormMain.btnRecordClick(Sender: TObject);
var
  VideoIntent: JIntent;
  videoUri: Jnet_Uri;
  AFile: JFile;
  FileName: TFileName;
begin
  FMessageSubscriptionID := 
    TMessageManager.DefaultManager.SubscribeToMessage(
      TMessageResultNotification, HandleActivityMessage);
  VideoIntent := 
    TJIntent.JavaClass.init(
      TJMediaStore.JavaClass.ACTION_VIDEO_CAPTURE
    );
  if (
    VideoIntent.resolveActivity(
      SharedActivityContext.getPackageManager()
    ) <> nil) then
  begin
    FileName := TPath.Combined(
      TPath.GetSharedDocumentsPath, 'recording.mp4')
    AFile:=TJFile.JavaClass.init(
      StringToJString(FileName));
    videoUri:=TJnet_Uri.JavaClass.fromFile(AFile);
    VideoIntent.putExtra(
      TJMediaStore.JavaClass.EXTRA_OUTPUT, 
      TJParcelable.Wrap((videoUri as ILocalObject).GetObjectID));
    SharedActivity.startActivityForResult(VideoIntent, RECORD_VIDEO);
  end;
end;

procedure TFormMain.HandleActivityMessage(const Sender: TObject;
  const M: TMessage);
begin
  if M is TMessageResultNotification then
    OnActivityResult(
      TMessageResultNotification(M).RequestCode,
      TMessageResultNotification(M).ResultCode,
      TMessageResultNotification(M).Value);
end;

function TFormMain.OnActivityResult(RequestCode, ResultCode: Integer;
  Data: JIntent): Boolean;
begin
  Result := False;

  TMessageManager.DefaultManager.Unsubscribe(
    TMessageResultNotification, FMessageSubscriptionID);
  FMessageSubscriptionID := 0;

  if RequestCode = RECORD_VIDEO then
  begin
    if ResultCode = TJActivity.JavaClass.RESULT_OK then
    begin
      TThread.Queue(nil, procedure
      begin
        lable1.Text:='recording completed';
        Invalidate;
      end);
    end;
  end;

end;

This code is a (near) complete answer to the question. The device-specific video recorder UI is launched for the user to interact with. There is no programmatic control other than the name of the file that the recording is saved to. As a Delphi developer who is overwhelmed by the Android API, I am grateful for this solution.

Freddie Bell
  • 2,186
  • 24
  • 43
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Ian Kemp Apr 24 '15 at 07:17
  • I have updated the response to include a substantial answer to the question. – Freddie Bell May 23 '15 at 18:06
  • @Ian Kemp Please remove the downvote from this answer. – Freddie Bell May 24 '15 at 13:25
  • Hi any idea how to save a frame or thumbnail image from the video just captured, similar to what VideoCamera.SampleBufferToBitmap does? I would have used TVideoCaptureDevice but these delphi media components are buggy. – sandman Feb 27 '17 at 11:00
  • I don't think you understand the solution here. Notice how I said "There is no programmatic control other than the name of the file". This is a pure "intent" solution. To go deeper, buy the library from the flashavconverter people and dig into the source code. This solution is level 1. Their solution is level 10. Be warned. – Freddie Bell Mar 02 '17 at 12:08
  • Don't think I want to buy the entire library just for this one feature. I do get the concept of intents. Other apps use intents and manage to save the previews/thumbnails just fine. It's a nice to have, so if anyone knows a way it would be appreciated. – sandman Mar 03 '17 at 09:17
1

Here is how it is done on Android using native API:

var
    texture : JSurfaceTexture;
    surface: JSurface;
    recorder: JMediaRecorder;
begin
  texture := TJSurfaceTexture.JavaClass.init(1);
  surface := TJSurface.JavaClass.init(texture); 
  recorder := TJMediaRecorder.Create();

  recorder.setPreviewDisplay(surface);
  recorder.setAudioSource(AUDIO_MIC);
  recorder.setVideoSource(VIDEO_CAMERA);
  recorder.setOutputFormat(FORMAT_THREE_GPP);
  recorder.setAudioEncoder(AFORMAT_AMR_NB);
  recorder.setVideoEncoder(VFORMAT_MPEG_4_SP);
  recorder.setMaxDuration(1800000); // 30 minutes

  recorder.setVideoSize(320, 240);
  recorder.setVideoFrameRate(15);
  recorder.setOutputFile(StringToJString(TPath.GetSharedCameraPath + OUTPUT_FILE));

  recorder.prepare();
  recorder.start();
end;

File will be recorded, just don't forget to send recorder.stop() when you wish to stop recording.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571