我尝试通过获取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 / 8
,channels * 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
答案 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);
}