视频中的声音充满了静电

时间:2015-02-17 12:46:08

标签: java audio ffmpeg javacv

我尝试通过获取FFMpegFrameGrabber并将音频样本发送到Frame来尝试播放来自SourceDataLine的声音。这就是我到目前为止所拥有的:

创建SourceDataLine

int channels = _grabber.getAudioChannels();
int format = _grabber.getSampleFormat();
AudioFormat fmt = new AudioFormat(_grabber.getSampleRate(), format, channels, true, true);
_sourceDataLine=(SourceDataLine)AudioSystem.getLine(new DataLine.Info(SourceDataLine.class, fmt));
_sourceDataLine.open(fmt);
_sourceDataLine.start();

尝试播放声音(图像在else块中处理):

org.bytedeco.javacv.Frame f = _grabber.grabFrame();

if (f.samples != null && f.samples.length > 0)
{
    byte[] bytes = new byte[4096];
    for (Buffer buffer : f.samples)
    {
        FloatBuffer floatBuffer = (FloatBuffer) buffer;
        ByteBuffer byteBuffer = ByteBuffer.allocate(floatBuffer.capacity() * 4);
        byteBuffer.asFloatBuffer().put(floatBuffer);
        byteBuffer.rewind();
        byteBuffer.get(bytes);
        _sourceDataLine.write(bytes, 0, bytes.length);
    }
}

(注意:我尝试了几个不同的版本,它们都有静态。我尝试的版本包括将缓冲区合并到一个大缓冲区中,只尝试播放一个样本而不是每个通道,并更改音频格式到许多不同的排列。)

问题是声音充满了静电,几乎完全无法理解。这是我第一次做任何音频编程,所以我确定我做的事情完全荒谬。

我感谢任何帮助。谢谢。

修改

为了回应Radiodef,我尝试了许多AudioFormats,但我找不到适用于PCM_FLOAT的音频格式。我发现了一个使用它的例子:

fmt = new AudioFormat(AudioFormat.Encoding.PCM_FLOAT, _grabber.getSampleRate(), format, channels, channels, _grabber.getSampleRate(), true);

注意:我为示例中的帧大小尝试了几个不同的值:channels * format / 8channels * 8,硬编码采样率为64,channels * 4,硬编码采样率为32,以及

的任何组合

但它给了我这个例外:

java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_FLOAT 44100.0 Hz, 8 bit, stereo, 2 bytes/frame,  is supported.
    at javax.sound.sampled.AudioSystem.getLine(Unknown Source)
    at com.enplug.player.video.Video.<init>(Video.java:52) <- where I get the SourceDataLine
    ...

编辑2

抱歉延误。我非常感谢Radiodef的所有帮助。

以下是自动输出的FFMpegGrabber的一些输出。

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\Users\Shawn\AppData\Roaming\Enplug Display\Download\Resource\c7cb496d-96ea-4be8-a238-5ffd50955a3e.mp4':
  Metadata:
    major_brand     : qt
    minor_version   : 0
    compatible_brands: qt
    creation_time   : 2014-10-02 07:14:38
  Duration: 00:00:31.13, start: 0.000000, bitrate: 2412 kb/s
    Stream #0:0(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 246 kb/s (default)
    Metadata:
      creation_time   : 2014-10-02 07:14:38
      handler_name    : Core Media Data Handler
    Stream #0:1(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1280x720, 2157 kb/s, 30 fps, 30 tbr, 600 tbn, 1200 tbc (default)
    Metadata:
      creation_time   : 2014-10-02 07:14:38
      handler_name    : Core Media Data Handler
      encoder         : H.264

我有两个我正在测试的视频,第一个(上面例子中的那个)有以下内容:

Bit rate: 247 kbps
Channels: 2 (stereo)
Audio sample rate: 44 kHz

第二个是:

Bit rate: 161 kbps
Channels: 2 (stereo)
Audio sample rate: 48 kHz

他们都是mp4,如果需要,我可以提供有关视频本身的任何细节。

至于图书馆,是的,我非常喜欢JavaCV。我们已经播放了没有声音的视频,但我们现在正试图为我们的节目添加声音。

当我从JSR link运行示例程序时,我得到了:

PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian

2 个答案:

答案 0 :(得分:1)

除了FFMpeg,我不太了解,看起来你构建AudioFormat的方式存在问题。您使用的构造函数假定整数LPCM,但您正在为它编写浮点数。您应该使用带AudioFormat.Encoding的构造函数。如果您知道它将是浮动的,那么您应该使用AudioFormat.Encoding.PCM_FLOAT

再次,如果您知道该文件是32位浮点数,您可以将格式硬编码为验证它是否正常,如下所示:

new AudioFormat(
    AudioFormat.Encoding.PCM_FLOAT,
    _grabber.getSampleRate(),
    32,
    channels,
    channels * 4,
    _grabber.getSampleRate(),
    true // you should also verify whether this is true
)

这应该让你有效。如果这不能让你找到一条线,那么它就不是平台可以播放的格式。

答案 1 :(得分:0)

我在我的程序中添加了声音。最近我想使用javaCV播放带声音的视频。当您使用aac格式音频播放视频时,您可以抓取哪个样本类型为FloatBuffer的帧。浮点值范围是-1到1那么你可以简单地将它们转换为短值ref

    private ShortBuffer convert(FloatBuffer arr){
    int len = arr.capacity();
    float f;
    ShortBuffer res = ShortBuffer.allocate(len);
    for(int i=0;i<len;i++){
        f = arr.get(i)*32768;
        if(f>32767.0f) f = 32767.0f;
        if(f<-32768.0f) f = 32768.0f;
        res.put(i,(short)f);
    }
    return res;
}

然后你可以创建一个AudioFormat,如果你的aac是立体声,如下:

AudioFormat af = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,audioSampleRate,16,2,4,audioSampleRate,true);

注意:endian为true或false取决于你如何将float转换为byte,如果设置相反,则会产生噪音。

但是Buffer []的长度是2,每个Buffer都是一个通道,因此当你将shortBuffer转换为byte作为flowwing时,你应该将它们混合到一个流中:

byte[] buf0,buf1;
byte[] stream = new byte[4];
for(int i=0;i<buf0.length;i=i+2){//mix the two channel
    for(int j=0;j<2;j++){
        stream[j] = buf0[i+j];
        stream[j+2] = buf1[i+j];
         }
    sourceDataLine.write(stream,0,4);
}