Skip to content
This repository has been archived by the owner on Oct 14, 2021. It is now read-only.

Getting standard output #71

Closed
nbros opened this issue Oct 12, 2019 · 16 comments
Closed

Getting standard output #71

nbros opened this issue Oct 12, 2019 · 16 comments
Assignees
Labels
enhancement New feature or request fixed question Further information is requested

Comments

@nbros
Copy link

nbros commented Oct 12, 2019

Currently, getLastCommandOutput() returns ffmpeg's error output, but AFAIK there is no way to get the standard (raw) output. This would be useful in order to convert a file to a memory buffer instead of having to write it to a temporary file just to read the file again.

@tanersener tanersener self-assigned this Oct 15, 2019
@tanersener tanersener added the question Further information is requested label Oct 15, 2019
@tanersener
Copy link
Owner

Currently, getLastCommandOutput() returns ffmpeg's error output, but AFAIK there is no way to get the standard (raw) output.

flutter_ffmpeg does not work like that. Output returned from getLastCommandOutput() is collected using a callback function registered in av_log_set_callback. It is not stderr. Technically, it is possible to get stdout/stderr but using av_log_set_callback is faster and safer.

This would be useful in order to convert a file to a memory buffer instead of having to write it to a temporary file just to read the file again.

Is this an ffmpeg use case, can you give me an example?

@nbros
Copy link
Author

nbros commented Oct 16, 2019

Hello,
Here is the ffmpeg documentation for pipes :
http://ffmpeg.org/ffmpeg-protocols.html#pipe

@nbros nbros closed this as completed Oct 16, 2019
@nbros nbros reopened this Oct 16, 2019
@tanersener
Copy link
Owner

flutter_ffmpeg supports pipe protocol. If you are asking about getting stdout as input, unfortunately that is not possible in both Android and iOS.

@nbros
Copy link
Author

nbros commented Oct 20, 2019

Yes, I would like to get the output of flutter_ffmpeg as an in-memory buffer (list of 8-bit unsigned integers) representing the data from the file, without having to write the output to a temporary file then read it again. Is there a way to achieve this with flutter_ffmpeg?

@tanersener
Copy link
Owner

Is there a way to achieve this with flutter_ffmpeg?

No. I can try to implement this feature but the second part of this functionality would be a method/plugin which allows you to read memory and use it. Do you know a method/plugin which does that in flutter?

@nbros
Copy link
Author

nbros commented Oct 20, 2019

I assumed flutter_ffmpeg would return (or provide a getter for) the buffer as a Dart list of 8-bit unsigned integers, which I could then process further from Dart code. Is that doable?

@tanersener
Copy link
Owner

Technically, flutter_ffmpeg can not write the output to memory. I can design a new method which uses File(path).readAsBytes() to read the output file into the memory but it will be over-engineering. You can already do it yourself, implementing this method won't add anything to flutter_ffmpeg.

@nbros
Copy link
Author

nbros commented Oct 20, 2019

Yes I agree, I already do File(path).readAsBytes() so doing that inside flutter_ffmpeg wouldn't save much. This issue is about optimizing out the disk write by writing the ffmpeg output to memory (with pipe:1 or -) and reading it back from memory.
Would Process#getInputStream on the ffmpeg process work here?
https://developer.android.com/reference/java/lang/Process.html#getInputStream()

@nbros
Copy link
Author

nbros commented Oct 20, 2019

Nevermind, I digged a bit deeper and I saw that flutter_ffmpeg uses the mobile-ffmpeg library which calls into native code in https://github.com/tanersener/mobile-ffmpeg/blob/master/android/app/src/main/cpp/mobileffmpeg.c so my comment about Java method getInputStream does not apply.

You said flutter_ffmpeg supports the pipe protocol. Would you have an example of writing ffmpeg output to a pipe and reading from the pipe in dart code? Is that possible?

@tanersener
Copy link
Owner

Well, the first part of your question is answered in your link about pipes. The following command writes its output into a pipe.

ffmpeg -i test.wav -f avi pipe:<pipe number>

But the second part, reading from the pipe in dart code, is very difficult. So I think pipe protocol support is not practically usable on flutter_ffmpeg.

Parent library, mobile-ffmpeg, supports named pipes using registerNewFFmpegPipe API method. You can use this method to create a named pipe and use the path of that pipe as a file input in ffmpeg commands. Pipe Support wiki page explains how that works.

I can implement registerNewFFmpegPipe method in flutter_ffmpeg. You'll be able to use the path of the pipe as a regular file in your commands. But it won't reside on the file system and it will have some rules about reading/writing. Will that work for you? You'll need to write some extra lines of code but it will work as reading from stdin/stdout/stderr.

@nbros
Copy link
Author

nbros commented Oct 24, 2019

Hello,
Creating the pipe would of course be the first step, but I don't know yet how to read from that pipe in Dart code though. I might try with dart:ffi which seems suited for this purpose.
Also, does registerNewFFmpegPipe do anything actually specific to ffmpeg? Otherwise you might put it in a new Dart library that helps working with native pipes in Dart: it could be helpful for other people and other purposes too. Just a suggestion :-)

@tanersener
Copy link
Owner

Hello,
Creating the pipe would of course be the first step, but I don't know yet how to read from that pipe in Dart code though. I might try with dart:ffi which seems suited for this purpose.

Reading a named pipe is the same as reading a file. In fact, named pipes look like files on the file system but they do not reside on the file system, their size is always 0 and can only be read once.

Also, does registerNewFFmpegPipe do anything actually specific to ffmpeg? Otherwise you might put it in a new Dart library that helps working with native pipes in Dart: it could be helpful for other people and other purposes too. Just a suggestion :-)

Well, I don't want to maintain another dart package. That's the main reason. Also, forcing a user to install another package don't look like a good design.

@nbros
Copy link
Author

nbros commented Oct 26, 2019

Hello,
That's reasonable ; feel free to implement it as you see fit.
Thanks

@tanersener tanersener added enhancement New feature or request fixed labels Oct 26, 2019
@tanersener
Copy link
Owner

There is a new API method called registerNewFFmpegPipe in new v0.2.8 release. You can use it to create a pipe and use it as a file in your ffmpeg commands.

_flutterFFmpeg.registerNewFFmpegPipe();

@nbros
Copy link
Author

nbros commented Nov 1, 2019

Thanks! I tried using it and it seems to be working insofar as ffmpeg is writing to the created pipe when I read from it using cat in the terminal (from adb shell, run-as myapp, then cat mf_pipe_1).
But I couldn't figure out how to read from that pipe in dart code though.
I tried creating an isolate and listening to the pipe before starting ffmpeg like this:

void readPipe(pipeName) async {
  var file = File(pipeName);
  var stream = file.openRead();
  stream.listen((e) {
    print(e.length.toString() + "\n");
  }, onError: (e){
    print(e);
  });
}
String pipeName = await ffmpeg.registerNewFFmpegPipe();
var arguments = ["-y", "-i", audioFilePath, "-f", "s16le", "-ac", "1", "-c:a", "pcm_s16le", pipeName];
compute(readPipe, pipeName);
// wait for the isolate to spawn
await Future.delayed(Duration(seconds: 1));
await ffmpeg.executeWithArguments(arguments);

But that last call blocks and nothing is received in the listening isolate.

@nbros
Copy link
Author

nbros commented Nov 1, 2019

Actually this seems to be caused by this bug: dart-lang/sdk#32191
I managed to work around this issue by using pipe.readAsBytes() instead of pipe.openRead().listen(...).
This is sub-optimal because we have to wait for the whole thing to be processed and read from the pipe before processing the result, instead of piping the result as it is being produced by ffmpeg and processing it in parallel (in a separate isolate).
But I guess this is the best that can be done for now given the aforementioned dart bug.
Thank you for implementing registerNewFFmpegPipe.
This issue can now be closed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request fixed question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants