简体   繁体   English

如何使用FFMPEG转码文件并在Java servlet的响应中流式传输输出文件?

[英]How can I transcode a file with FFMPEG and stream the output file in the response of a Java servlet?

Basically, this is what I'm trying to do: 1. User passes a URL as a GET parameter to my servlet. 基本上,这就是我要做的事情:1。用户将URL作为GET参数传递给我的servlet。 2. Servlet uses a ProcessBuilder to convert the media contained in that URL to a valid media format (ie: MP3). 2. Servlet使用ProcessBuilder将该URL中包含的媒体转换为有效的媒体格式(即:MP3)。 3. The servlet streams the output file being transcoded by FFMPEG back to the browser. 3. servlet将由FFMPEG转码的输出文件流回到浏览器。

1 and 2 work fine, but it is 3 I am having a problem with. 1和2工作正常,但它是3我有问题。 The best I can do is create a FileInputStream to the output file being transcoded and send that as the response but it is not working. 我能做的最好的事情是为正在转码的输出文件创建一个FileInputStream,并将其作为响应发送,但它不起作用。 My guess is that it is because the file is being written as I'm trying to stream it. 我的猜测是,因为我正在尝试流式传输文件。

Is there anyway to intercept the output file argument in FFMPEG and read it into an InputStream? 无论如何拦截FFMPEG中的输出文件参数并将其读入InputStream? In my mind it does not seem that it should be difficult to take input file A, transcode it to output file B, and then stream output file B back to the client, on the fly. 在我看来,似乎不应该难以获取输入文件A,将其转码为输出文件B,然后将输出文件B流式传输回客户端。

ProcessBuilder pb = new ProcessBuilder("ffmpeg.exe", "-i", url, "file.mp3");
    Process p = pb.start();

    final InputStream inStream = p.getErrorStream();

    new Thread(new Runnable() {

    public void run() {
            InputStreamReader reader = new InputStreamReader(inStream);
            Scanner scan = new Scanner(reader);
            while (scan.hasNextLine()) {
                System.out.println(scan.nextLine());
            }
        }
    }).start();

    ServletOutputStream stream = null;
    BufferedInputStream buf = null;
    try {

        stream = response.getOutputStream();
        File mp3 = new File(file.mp3");

        //set response headers
        response.setContentType("audio/mpeg");

        response.addHeader("Content-Disposition", "attachment; filename=file.mp3");

        response.setContentLength(-1);

        //response.setContentLength((int) mp3.length());

        FileInputStream input = new FileInputStream(mp3);
        buf = new BufferedInputStream(input);
        int readBytes = 0;
        //read from the file; write to the ServletOutputStream
        while ((readBytes = buf.read()) != -1) {
            stream.write(readBytes);
        }
    } catch (IOException ioe) {
        throw new ServletException(ioe.getMessage());
    } finally {
        if (stream != null) {
            stream.close();
        }
        if (buf != null) {
            buf.close();
        }
    }

FFmpeg doesn't have to write to a file. FFmpeg不必写入文件。 It can write to stdout: 它可以写入stdout:

ffmpeg -i $input -f mp3 -

- means standard output. -表示标准输出。 Since there is no file name, you need to specify the format with -f . 由于没有文件名,因此需要使用-f指定格式。

If you invoke it like this, you can read mp3 stream directly from Process 's InputStream . 如果你这样调用它,你可以直接从ProcessInputStream读取mp3流。

I figured it out. 我想到了。

The trick is not to create a file on the file system and try to stream that back to the client but to pipe the ffmpeg output to an InputStream in Java and f-in voila! 诀窍不是在文件系统上创建一个文件并尝试将其传回客户端,而是将ffmpeg输出传递给Java和f-in中的InputStream!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM