我正在尝试使用Xuggler(我相信使用引擎盖下的ffmpeg
)来执行以下操作:
我已经看过/阅读过他们的一些优秀教程,到目前为止这里是我所拥有的:
// I'll worry about implementing this functionality later, but
// involves querying native device drivers.
byte[] nextMjpeg = getNextMjpegFromSerialPort();
// I'll also worry about implementing this functionality as well;
// I'm simply providing these for thoroughness.
BufferedImage mjpeg = MjpegFactory.newMjpeg(nextMjpeg);
// Specify a h.264 video stream (how?)
String h264Stream = "???";
IMediaWriter writer = ToolFactory.makeWriter(h264Stream);
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264);
writer.encodeVideo(0, mjpeg);
首先,我想我离这儿很近,但它仍然不正确;我只是通过阅读视频代码示例(而不是音频 - 我找不到任何好的音频示例)来实现这一目标。
从字面上看,我将获得对Xuggler实现中的原始视频和音频源的字节级访问。但对于我的生活,我无法弄清楚如何将它们变成h.264 / AAC / MPEG-TS格式。在此提前感谢您的任何帮助。
答案 0 :(得分:16)
查看Xuggler this sample code,以下内容应该可以将视频编码为H.264并将其复制到MPEG2TS容器中:
IMediaWriter writer = ToolFactory.makeWriter("output.ts");
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264, width, height);
for (...)
{
BufferedImage mjpeg = ...;
writer.encodeVideo(0, mjpeg);
}
从文件扩展名中猜出容器类型,显式指定编解码器。
要复用音频和视频,你可以这样做:
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);
}
在这种情况下,我相信您的代码负责交错音频和视频:您希望在每次通过循环时调用encodeAudio()或 encodeVideo(),具体取决于可用的数据(一大块音频样本或视频帧)具有早期时间戳。
根据IStreamCoder,您可能最终会使用另一个较低级别的API,从而可以更好地控制各种参数。我不认为你需要使用它。
回答您提出的具体问题:
(1)“将BufferedImage(M / JPEG)编码为h.264流” - 您已经知道了,writer.addVideoStream(..., ICodec.ID.CODEC_ID_H264)
确保您获得H.264 编解码器 。要获取传输流(MPEG2 TS)容器,只需使用扩展名为.ts的文件名调用makeWriter()
。
(2)“找出原始音频源的”BufferedImage等效“是什么” - 这是一个短[]或IAudioSamples对象(两者似乎都有效,但是IAudioSamples必须是从IBuffer构建,这不那么直截了当。)
(3)“将此音频类编码为AAC音频流” - 致电writer.addAudioStream(..., ICodec.ID.CODEC_ID_AAC, channelCount, sampleRate)
(4)“将两个流复用到同一个MPEG-TS容器中” - 使用.ts文件名调用makeWriter()
,该文件名设置容器类型。要获得正确的音频/视频同步,您可能需要以正确的顺序调用encodeVideo()/ encodeAudio()。
P.S。始终先传递最早的音频/视频。例如,如果您的音频块长度为440个样本(采样率为44000 Hz,440/44000 = 0.01秒),视频速度恰好为25fps(1/25 = 0.04秒),您可以将它们提供给作者这个顺序:
video0 @ 0.00 sec
audio0 @ 0.00 sec
audio1 @ 0.01 sec
audio2 @ 0.02 sec
audio3 @ 0.03 sec
video1 @ 0.04 sec
audio4 @ 0.04 sec
audio5 @ 0.05 sec
......等等
只要连续的音频/视频时间戳相对接近,大多数播放设备都可以使用流,但这就是您为完美的多路复用器所做的事情。
P.S。您可能需要参考几个文档:Xuggler class diagram,ToolFactory,IMediaWriter,ICodec。
答案 1 :(得分:0)
我认为你应该看看gstreamer:http://gstreamer.freedesktop.org/你必须寻找可以捕获摄像头输入然后将其传输到libx264和aac插件的插件,然后将它们传递给mpegts muxer。
gstreamer中的管道看起来像:
v4l2src queue-size=15 ! video/x-raw,framerate=25/1,width=384,height=576 ! \
avenc_mpeg4 name=venc \
alsasrc ! audio/x-raw,rate=48000,channels=1 ! audioconvert ! lamemp3enc name=aenc \
avimux name=mux ! filesink location=rec.avi venc. ! mux. aenc. ! mux.
在这个管道中正在使用mpeg4和mp3编码器,并且流被复用到avi。你应该能够找到libx264和aac的插件。如果您需要进一步的指示,请告诉我。