Record video from camera on Android to mp4

2019-01-19 07:39发布

问题:

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...

回答1:

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.



回答2:

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.