2012-12-12 18 views
12

我试图使用Xuggler(我相信使用ffmpeg引擎盖下)执行以下操作:Xuggler编码和多路复用

  • 接受原始MPJPEG视频比特流(从一个小TTL串口摄像头)并将其编码/转码为h.264;和
  • 接受原始音频位流(来自麦克风)并将其编码为AAC;然后
  • 复用两个(音频和视频)bitsreams汇集成MPEG-TS容器

我看过/阅读他们的一些优秀的教程,到目前为止,这里是我得到了什么:

// 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

我也有,我不是“嫁”给Xuggler赏金文中提到。如果有人能想出如何做,说,'ffmpeg'或其他工具的一切,我需要(赏金规定),可以运行在Linux上,我会很感兴趣的是解决方案,以及! – IAmYourFaja

+0

你可以通过USB连接相机吗?你知道xuggle是否可以通过SPI从你的摄像头读取输入 – rajneesh

+0

在USB和SPI上是的,但是我不会因为这个问题范围之外的原因而使用这个选项。唯一真正重要的是我将以'byte []'的形式获取原始音频和视频比特流。 – IAmYourFaja

回答

16

来看,以下应该工作对视频编码,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); 
} 

容器类型从文件扩展名猜测,该编解码器明确指定。

于MUX音频和视频,你会做这样的事情:

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“是什么” - 这是一个short []或者一个IAudioSamples对象(两者似乎都可以工作,但是IAudioSamples必须从IBuffer不那么简单)。

(3) “编码该音频类成AAC音频流” - 呼叫writer.addAudioStream(..., ICodec.ID.CODEC_ID_AAC, channelCount, sampleRate)

(4) “复用两个流到相同的MPEG-TS的容器” - 呼叫makeWriter()用的.ts文件名,其设置容器类型。要获得正确的音频/视频同步,您可能需要按正确的顺序调用encodeVideo()/ encodeAudio()。

P.S.总是先传递最早的音频/视频。例如,如果有音频块,其是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 diagramToolFactoryIMediaWriterICodec

+0

你究竟如何得到'short []'样本数组? – wrahool

+0

@wrahool:使用带有sampleSizeInBits = 16,encoding = PCM_SIGNED,bigEndian = false的AudioFormat的TargetDataLine或AudioInputStream。然后字节转换为短裤,像这样:'shortBuf [I] =(byteBuf [2 * I + 1] << 8)| byteBuf [2 * i];'我不认为有更直接的方法,尽管它取决于你从哪里获取音频。 –

+0

我从笔记本电脑麦克风获取音频,但我可能需要稍后从USB麦克风中获取音频。 – wrahool

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的插件。让我知道你是否需要更多指针。在Xuggler this sample code