Xuggler 编码和复用
Posted
技术标签:
【中文标题】Xuggler 编码和复用【英文标题】:Xuggler encoding and muxing 【发布时间】:2012-11-30 03:54:03 【问题描述】:我正在尝试使用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 格式。在此先感谢您的帮助。
【问题讨论】:
我也应该在赏金文本中提到我没有与 Xuggler“结婚”。如果有人能弄清楚如何使用ffmpeg
或其他可以在 Linux 上运行的工具来完成我需要的一切(在赏金中指定),我也会对该解决方案感兴趣!
你可以通过USB连接相机吗?你知道 xuggle 是否可以通过 SPI 读取相机的输入
在 USB 和 SPI 上是的,但出于此问题范围之外的原因,我不会使用该选项。唯一真正重要的是,我将以byte[]
s 的形式获取原始音频和视频比特流。
【参考方案1】:
我认为您应该查看 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 的插件。如果您需要进一步的指示,请告诉我。
【讨论】:
【参考方案2】:查看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)容器,只需调用 makeWriter()
并使用带有 .ts 扩展名的文件名。
(2) “弄清楚原始音频馈送的“BufferedImage-equivalent”是什么”-它是一个短 [] 或 IAudioSamples 对象(两者似乎都有效,但 IAudioSamples 必须从一个不那么简单的 IBuffer)。
(3) “将此音频类编码为 AAC 音频流” - 致电writer.addAudioStream(..., ICodec.ID.CODEC_ID_AAC, channelCount, sampleRate)
(4) “将两个流多路复用到同一个 MPEG-TS 容器中” - 使用 .ts 文件名调用 makeWriter()
,它设置容器类型。为了正确的音频/视频同步,您可能需要以正确的顺序调用 encodeVideo()/encodeAudio()。
附:始终先通过最早可用的音频/视频。例如,如果您有 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
...等等
只要连续的音频/视频时间戳相对接近,大多数播放设备可能都可以使用流,但这是完美的多路复用器。
附:您可能需要参考一些文档:Xuggler class diagram、ToolFactory、IMediaWriter、ICodec。
【讨论】:
您究竟是如何获得short[]
样本数组的?
@wrahool:使用具有 sampleSizeInBits=16、encoding=PCM_SIGNED、bigEndian=false 的 AudioFormat 的 TargetDataLine 或 AudioInputStream。然后将字节转换为短裤,如下所示:shortBuf[i] = (byteBuf[2*i + 1] << 8) | byteBuf[2*i];
我认为没有更直接的方法,尽管这取决于您从哪里获取音频。
我正在从笔记本电脑的麦克风中获取音频,不过我以后可能还需要从 USB 麦克风中获取它。
@wrahool:如果需要,您可以将其作为一个单独的问题发布,这听起来有点太复杂,无法在 cmets 中充分探索。
现在已经做到了。 ***.com/questions/21569703/…以上是关于Xuggler 编码和复用的主要内容,如果未能解决你的问题,请参考以下文章
编码音频时的 xuggle-xuggler 5.4 NullPointerException
如何使用 libogg 复用 Vorbis 和 Theora 流