Подтвердить что ты не робот

Xuggler-кодирование и мультиплексирование

Я пытаюсь использовать Xuggler (который, я считаю, использует ffmpeg под капотом), чтобы сделать следующее:

  • Примите необработанный поток битов видео MPJPEG (с небольшой последовательной камеры TTL) и закодируйте/перекодируйте его на h.264; и
  • Принять исходный звуковой битрейт (от микрофона) и закодировать его до AAC; затем
  • Смешайте два (аудио и видео) бита в одном контейнере 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. Заранее спасибо за любую помощь здесь.

4b9b3361

Ответ 1

Рассматривая Xuggler этот пример кода, следующее должно работать для кодирования видео как 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() на каждом проходе через цикл, на основе которого доступны данные (фрагмент аудиозаписей или видеокадр) имеет более раннюю метку времени.

Существует еще один API более низкого уровня, который вы можете использовать на основе IStreamCoder, что дает больший контроль над различными параметрами. Я не думаю, что вам нужно будет это использовать.

Чтобы ответить на заданные вами вопросы:

(1) "Кодировать BufferedImage (M/JPEG) в поток h.264" - вы уже поняли, что вне, writer.addVideoStream(..., ICodec.ID.CODEC_ID_H264) гарантирует, что вы получите кодек H.264. Чтобы получить контейнер транспортного потока (MPEG2 TS), просто вызовите makeWriter() с именем файла с расширением .ts.

(2) "Выясните, что такое" BufferedImage-эквивалент "для сырой аудиоподачи" - это либо короткий [], либо 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 Гц, 440/44000 = 0,01 секунды) и видео с точностью до 25 кадров в секунду (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, ToolFactory, IMediaWriter, ICodec.

Ответ 2

Я думаю, вам стоит взглянуть на gstreamer: http://gstreamer.freedesktop.org/ Вам нужно будет искать плагин, который может захватывать вход камеры, а затем транслировать его к libx264 и aac-плагинам, и они передают их через mpegts-мультиплекс.

Конвейер в 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. Дайте мне знать, если вам нужны дальнейшие указатели.