Java TargetDataLine和Xuggler通过屏幕视频录制音频
Java TargetDataLine和Xuggler通过屏幕视频录制音频,java,audio,video,sequence,xuggler,Java,Audio,Video,Sequence,Xuggler,TargetDataLine是迄今为止,用Java捕获麦克风输入的最简单方法。我想对我用屏幕视频(在屏幕录制软件中)捕获的音频进行编码,以便用户可以创建教程、幻灯片盒等。 我使用Xuggler对视频进行编码。 他们确实有一个关于用视频编码音频的教程,但他们从文件中获取音频。就我而言,音频是实时的。 为了对视频进行编码,我使用了com.xuggle.mediaTool.IMediaWriter。IMediaWriter对象允许我添加视频流,并具有 encodeAudio(int streamIn
TargetDataLine
是迄今为止,用Java捕获麦克风输入的最简单方法。我想对我用屏幕视频(在屏幕录制软件中)捕获的音频进行编码,以便用户可以创建教程、幻灯片盒等。我使用
Xuggler
对视频进行编码。他们确实有一个关于用视频编码音频的教程,但他们从文件中获取音频。就我而言,音频是实时的。
为了对视频进行编码,我使用了
com.xuggle.mediaTool.IMediaWriter
。IMediaWriter对象允许我添加视频流,并具有encodeAudio(int streamIndex,short[]示例,long timeStamp,TimeUnit TimeUnit)
如果我可以从目标数据行获取样本,作为
short[]
,我就可以使用它。它返回字节[]
因此,有两个问题是: 如何用视频对现场音频进行编码? 如何保持音频数据包的正确定时,以便在正确的时间对其进行编码? 参考文献:
1.TargetDataLine的DavaDoc:
2.Xuggler文档:
更新 我的视频捕获代码
我最近在这个问题下回答了大部分问题: 代码示例:
writer.addVideoStream(videoStreamIndex, 0, videoCodec, width, height);
writer.addAudioStream(audioStreamIndex, 0, audioCodec, channelCount, sampleRate);
while (... have more data ...)
{
BufferedImage videoFrame = ...;
long videoFrameTime = ...; // this is the time to display this frame
writer.encodeVideo(videoStreamIndex, videoFrame, videoFrameTime, DEFAULT_TIME_UNIT);
short[] audioSamples = ...; // the size of this array should be number of samples * channelCount
long audioSamplesTime = ...; // this is the time to play back this bit of audio
writer.encodeAudio(audioStreamIndex, audioSamples, audioSamplesTime, DEFAULT_TIME_UNIT);
}
对于TargetDataLine,将告诉您audioSamplesTime所需的时间。这似乎从打开TargetDataLine
时开始。您需要弄清楚如何获取引用到同一时钟的视频时间戳,这取决于视频设备和/或捕获视频的方式。绝对值并不重要,只要它们都使用相同的时钟。您可以从视频和音频时间中减去初始值(在流开始时),以便时间戳匹配,但这只是一个近似匹配(在实践中可能足够接近)
您需要按严格的时间顺序调用
encodeVideo
和encodeAudio
;你可能需要缓冲一些音频和视频,以确保你能做到这一点。更多详细信息。我已编辑了问题,以便您可以查看代码。在我的例子中,帧速率可以在10到25之间变化,那么如何动态地保持正确的定时呢?PS:我的代码做的东西正确吗?比如以10fps的速度编码等?@LittleChild:你可以将视频时间戳作为从createscreenscapture
获取帧的时间。“动态保持正确的计时”-只需从音频和视频时间戳中减去第一个值(在流的开始处),然后按时间戳的增加顺序将音频/视频馈送到媒体写入器。@LittleChild:我可以看到一些问题,您确实为可变帧速率流指定了帧速率,但没有指定编解码器。另一种方法更好:)尝试调用addVideoStream(int-inputIndex,int-streamId,ICodec.ID-codecId,int-width,int-height)代码>取而代之。嘿,我想了想TargetDataLine
,但这里有一个新问题。请像你写这封信一样写上这封信。这里:附言。你可以使用任何你想要的编解码器,但我建议视频使用ICodec.ID.CODEC\u ID\u H264
(或测试期间使用CODEC\u ID\u MPEG2VIDEO
),音频使用ICodec.ID.CODEC\u ID\u AAC
(或CODEC\u ID\u MP3
)。确保您的输出容器也可以多路复用以下内容:.mp4或.mkv或.ts应该可以。
writer.addVideoStream(videoStreamIndex, 0, videoCodec, width, height);
writer.addAudioStream(audioStreamIndex, 0, audioCodec, channelCount, sampleRate);
while (... have more data ...)
{
BufferedImage videoFrame = ...;
long videoFrameTime = ...; // this is the time to display this frame
writer.encodeVideo(videoStreamIndex, videoFrame, videoFrameTime, DEFAULT_TIME_UNIT);
short[] audioSamples = ...; // the size of this array should be number of samples * channelCount
long audioSamplesTime = ...; // this is the time to play back this bit of audio
writer.encodeAudio(audioStreamIndex, audioSamples, audioSamplesTime, DEFAULT_TIME_UNIT);
}