【问题标题】:Using ffmpeg to convert audio from Red5使用 ffmpeg 从 Red5 转换音频
【发布时间】:2014-08-14 11:43:24
【问题描述】:

我的项目遇到了一些问题。

在我的项目中,我需要使用用于将音频流存储在服务器上的 Actionscript 实现与 RED5 服务器的麦克风集成,然后我在 java 代码中使用 ffmpeg 将 flv 文件转换为 mp3。

我在这里面临两个问题:

  1. 录制的音频创建 .flv 文件,该文件已被删除。

  2. 当我尝试使用 ffmpeg 将 .flv 转换为 .mp3 时,它会卡住,直到我停止 Red5 服务器。

这是我的两个地方的代码。请让我知道我哪里做错了。

在 red5 上录制麦克风音频和流式传输的 Actionscipt:

private function initConnection():Void {

        trace("Connecting...");

        nc = new NetConnection();
        nc.client = this;
        nc.addEventListener(NetStatusEvent.NET_STATUS, onNetConnectionStatus);
        nc.connect("rtmp://127.0.0.1/test");

        this.mic = Microphone.getMicrophone();

        if (this.mic != null) {
            this.mic.rate = 44;
            mic.setSilenceLevel(0);
            mic.gain = 100;
            mic.setUseEchoSuppression(true); 
            mic.setLoopBack(true);              
        }                   
    }

在 Red5 上发送:

public function startSending( nc: NetConnection, filename:String ) {
        ns = new NetStream(nc);
        ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStreamStatus);
        ns.publish(filename, 'record');
        ns.attachAudio(mic);        
}

停止录制/发送:

public function stopSending() {
        mic.setLoopBack(false);
        ns.attachAudio(null);
        ns.close();     
}

生成的 .flv 存储在已修改的服务器上。

不将 .flv 转换为 .mp3,我在我的 Java 代码中使用了 ffmpeg,如下所示:

String ffmpegArgs[] = {executableDir,"-i",flvFile.getAbsolutePath(), "-vn", mp3File.getAbsolutePath()};
Process process = new ProcessBuilder(Arrays.asList(ffmpegArgs)).start();

这会启动文件转换,但会卡住。一段时间后,当我停止服务器时,它会立即显示转换后的文件。 请告诉我,我在哪里做错了。

【问题讨论】:

  • FLV 播放是否正确?在尝试转换它之前,您可能需要确保它没问题。我还建议您将环回设置为 false。

标签: java actionscript-3 ffmpeg red5


【解决方案1】:

我从未使用过 Red5,所以对此无能为力。您是使用服务器存储数据还是可以将原始字节保存到本地存储(或仅保存在内存中),然后在记录结束后将它们发送到 Java 服务器?如果是这样,我在我的项目中解决了一个类似的问题,该问题用于从 ActionScript 声音文件(和其他资产)制作视频。如果在发送到服务器之前将字节编码为 WAVE,您将获得良好的结果。这里有一个用于进行转换的对象 - thibault 来源:https://code.google.com/p/micrecorder/downloads/detail?name=MicRecorder%201.2.zip&can=2&q=

该包中的相关代码是这样的:

    public class WavEncoder implements ISoundEncoder
{
    private static const RIFF:String = "RIFF";  
    private static const WAVE:String = "WAVE";  
    private static const FMT:String = "fmt ";   
    private static const DATA:String = "data";  

    private var _bytes:ByteArray = new ByteArray();
    private var _buffer:ByteArray = new ByteArray();
    private var _volume:Number;

    /**
     * 
     * @param volume
     * 
     */     
    public function WavEncoder( volume:Number=1 )
    {
        _volume = volume;
    }

    /**
     * 
     * @param samples
     * @param channels
     * @param bits
     * @param rate
     * @return 
     * 
     */     
    public function encode( samples:ByteArray, channels:int=2, bits:int=16, rate:int=22100 ):ByteArray
    {
        //var data:ByteArray = create( samples );
        create(samples);

        _bytes.length = 0;
        _bytes.endian = Endian.LITTLE_ENDIAN;

        //create(samples);

        _bytes.writeUTFBytes( WavEncoder.RIFF );
        //_bytes.writeInt( uint( data.length + 44 ) );
        _bytes.writeInt( uint( _buffer.length + 44 ) );
        _bytes.writeUTFBytes( WavEncoder.WAVE );
        _bytes.writeUTFBytes( WavEncoder.FMT );
        _bytes.writeInt( uint( 16 ) );
        _bytes.writeShort( uint( 1 ) );
        _bytes.writeShort( channels );
        _bytes.writeInt( rate );
        _bytes.writeInt( uint( rate * channels * ( bits >> 3 ) ) );
        _bytes.writeShort( uint( channels * ( bits >> 3 ) ) );
        _bytes.writeShort( bits );
        _bytes.writeUTFBytes( WavEncoder.DATA );
        //_bytes.writeInt( data.length );
        _bytes.writeInt(_buffer.length);
        //_bytes.writeBytes( data );
        _bytes.writeBytes( _buffer);
        _bytes.position = 0;

        //data.clear();
        _buffer.clear();
        return _bytes;
    }

    private function create( bytes:ByteArray ):ByteArray        {

        if(!_buffer)
            _buffer = new ByteArray();

        _buffer.endian = Endian.LITTLE_ENDIAN;
        _buffer.length = 0;
        bytes.position = 0;

        while( bytes.bytesAvailable ) 
            _buffer.writeShort( bytes.readFloat() * (0x7fff * _volume) );
        return _buffer;
    }
}

FFmpeg 可能无法理解您的编码,因此正在尝试但失败了。不确定我发布的内容是否对您有帮助,但我发布它以防万一。如果您对我如何完全实现这一点以使用 FFmpeg、Java 和 AS 执行与您尝试做的类似的事情来获得良好的声音播放有任何疑问,请告诉我。

【讨论】:

  • 不要吹毛求疵,但默认的“速率”应该是 22050 而不是 22100
  • 感谢 Mondain - 永远不要挑剔以使代码更好。我将更新我的项目,并在我制作的下一个视频中查看结果。我正在发送原始字节,就像 Chntan 在编码之前一样。当我尝试仅发送 AS mic 字节时,我也遇到了 FFmpeg 失败 - 会创建视频,但声音失真且无法播放。这为我解决了问题。
【解决方案2】:

我终于得到了答案。

场景是这样的:

由于我的源 .flv 文件已损坏,当我从命令行执行 ffmpeg 命令时,它会显示许多警告。

当我从我的 java 代码中执行相同的命令时,警告会缓冲在 jvm 中,因此它会变满并且进程挂起。我在另一个 stackoverflow 线程中找到了解决方案,我们需要通过读取流来刷新错误和其他。这是它的代码;

final BufferedReader stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = "";
for (l = 0; ((line = stderr.readLine()) != null);) {
           System.out.println(line)
           l++;
}

 stderr.close();

它对我有用!

【讨论】:

    猜你喜欢
    • 2021-07-20
    • 2011-03-07
    • 2016-04-26
    • 2020-08-25
    • 2014-09-12
    • 2018-01-03
    • 2011-03-16
    • 2018-07-22
    • 1970-01-01
    相关资源
    最近更新 更多