2012-12-12 7 views
12

Ich versuche Xuggler zu verwenden (was ich glauben verwendet ffmpeg unter der Haube) folgendes zu tun:Xuggler Codierung und Muxing

  • Accept ein rohes MPJPEG Video-Bitstrom (von einer kleinen seriellen TTL-Kamera) und kodiere/transcodiere es zu h.264; und
  • Akzeptieren Sie einen rohen Audio-Bitstrom (von einem Mikrofon) und kodieren Sie ihn zu AAC; dann
  • Mux die zwei (Audio und Video) bitsreams zusammen in einen MPEG-TS Container

Ich habe einige ihrer ausgezeichneten Tutorials angeschaut/lesen, und so weit ist hier, was ich habe:

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

Zum einen glaube ich, ich bin hier in der Nähe, aber es ist immer noch nicht korrekt; und ich bin nur so weit gekommen, indem ich die Videocode-Beispiele gelesen habe (nicht das Audio - ich kann keine guten Audio-Beispiele finden).

Wörtlich werde ich Byte-Level-Zugriff auf die rohen Video-und Audio-Feeds bekommen, die in meine Xuggler-Implementierung kommen. Aber für das Leben von mir kann ich nicht herausfinden, wie man sie in ein h.264/AAC/MPEG-TS Format bringt. Vielen Dank im Voraus für jede Hilfe hier.

+0

Ich hätte auch im Bounty-Text erwähnen sollen, dass ich nicht mit Xuggler "verheiratet" bin. Wenn jemand herausfinden kann, wie ich alles, was ich brauche (in der Bounty angegeben) mit sagen wir "ffmpeg" oder einem anderen Tool, das unter Linux laufen kann, machen kann, würde mich auch diese Lösung interessieren! – IAmYourFaja

+0

können Sie die Kamera über USB anschließen? Weißt du, ob xuggle die Eingabe von deiner Kamera über SPI – rajneesh

+0

Ja auf USB & SPI lesen kann, aber ich diese Option aus Gründen, die außerhalb des Bereichs dieser Frage liegen, nicht verwenden werde. Das einzige, was wirklich wichtig ist, ist, dass ich rohe Audio- und Video-Bitstreams in Form von byte [] 's bekommen werde. – IAmYourFaja

Antwort

16

bei Xuggler this sample code Sehen, sollte folgendes Video H.264 zu kodieren arbeiten und Mux es in einen Behälter 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); 
} 

Der Behälter ist aus der Dateierweiterung erraten, wird der Codec explizit angegeben.

Audio und Video Mux, Sie so etwas tun würde:

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); 
} 

In diesem Fall glaube ich Ihren Code zur Verschachtelung der Audio- und Video verantwortlich ist: Sie können entweder encodeAudio() anrufen möchten oder encodeVideo() bei jedem Durchgang durch die Schleife, basierend auf den verfügbaren Daten (ein Stück Audio-Samples oder ein Video-Frame) hat einen früheren Zeitstempel.

Es gibt eine andere, untergeordnete API, die Sie möglicherweise verwenden, basierend auf IStreamCoder, die mehr Kontrolle über verschiedene Parameter gibt. Ich denke nicht, dass du das benutzen musst.

die spezifischen Fragen zu beantworten, die Sie gestellt:

(1) "ein BufferedImage Encode (M/JPEG) in einen h.264-Stream" - Sie, dass bereits herausgefunden, writer.addVideoStream(..., ICodec.ID.CODEC_ID_H264) stellt sicher, dass Sie die H. bekommen 264 Codec.Um einen Transportstream (MPEG2 TS) Container zu erhalten, rufen Sie einfach makeWriter() mit einem Dateinamen mit der Erweiterung .ts.

(2) "herauszufinden, was das" BufferedImage-Äquivalent "für eine rohe Audio-Feed ist" - das ist entweder ein kurzes [] oder IAudioSamples Objekt (beide scheinen zu funktionieren, aber IAudioSamples muss aus einem gebaut werden IBuffer, der viel weniger einfach ist).

(3) "Encode diese Audioklasse in einen AAC-Audio-Stream" - Aufruf writer.addAudioStream(..., ICodec.ID.CODEC_ID_AAC, channelCount, sampleRate)

(4) "multiplex sowohl Strom in die gleichen MPEG-TS Container" - Aufruf makeWriter() mit einem .ts Dateinamen, die legt den Containertyp fest. Für eine korrekte Audio-/Videosynchronisation müssen Sie wahrscheinlich encodeVideo()/encodeAudio() in der richtigen Reihenfolge aufrufen.

P.S. Übergeben Sie immer zuerst das früheste verfügbare Audio/Video. Wenn Sie beispielsweise Audio - Chunks haben, die 440 Samples lang sind (bei 44000 Hz Sample - Rate, 440/44000 = 0,01 Sekunden) und Video bei genau 25 fps (1/25 = 0,04 Sekunden), würden Sie sie dem Writer in geben diese Reihenfolge:

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 

... und so weiter

die meisten Abspielgeräte sind wahrscheinlich mit dem Strom ok, solange die aufeinanderfolgenden Audio/Video-Zeitstempel relativ nahe sind, aber das ist, was Sie tun würden, für einen perfekten Mux.

P.S. Es gibt einige Dokumente, auf die Sie sich beziehen können: Xuggler class diagram, ToolFactory, IMediaWriter, ICodec.

+0

Wie genau erhalten Sie das 'short []' samples-Array? – wrahool

+0

@Wrahool: Verwenden Sie eine TargetDataLine oder AudioInputStream mit einem AudioFormat, das sampleSizeInBits = 16, encoding = PCM_SIGNED, bigEndian = false hat. Dann wandeln Sie die Bytes in Kurzschlüsse um, wie folgt: 'shortBuf [i] = (byteBuf [2 * i + 1] << 8) | byteBuf [2 * i]; 'Ich glaube nicht, dass es eine direktere Methode gibt, obwohl es davon abhängt, woher du das Audio bekommst. –

+0

Ich bekomme das Audio von einem Laptop-Mikrofon, obwohl ich es später auch von USB-Mikrofonen bekommen muss. – wrahool

0

Ich denke, Sie sollten sich gstreamer ansehen: http://gstreamer.freedesktop.org/ Sie müssten nach Plugin suchen, die Kamera Eingang erfassen und dann es zu libx264 und AAC-Plugins und sie leiten sie durch einen mpegts Muxer.

Eine Pipeline in gstreamer würde wie folgt aussehen:

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. 

In dieser Pipeline mpeg4 und MP3-Encoder verwendet werden und der Strom ist muxed avi. Sie sollten Plugins für libx264 und aac finden können. Lassen Sie es mich wissen, wenn Sie weitere Hinweise benötigen.