Ответ 1
Или используйте Xuggler. Работает с RTP, RTMP, HTTP или другими протоколами и может декодировать и кодировать H264 и большинство других кодеков. И активно поддерживается, бесплатно и с открытым исходным кодом (LGPL).
Кто-нибудь знает, как декодировать видеокадр H.264 в среде Java?
Мои продукты для сетевых камер поддерживают потоки RTP/RTSP.
Сервисный стандарт RTP/RTSP от моей сетевой камеры обслуживается, а также поддерживает "RTP/RTSP через HTTP".
RTSP: TCP 554 Начальный порт RTP: UDP 5000
Или используйте Xuggler. Работает с RTP, RTMP, HTTP или другими протоколами и может декодировать и кодировать H264 и большинство других кодеков. И активно поддерживается, бесплатно и с открытым исходным кодом (LGPL).
Я думаю, лучшее решение использует "JNI + ffmpeg". В моем текущем проекте мне нужно одновременно воспроизводить несколько полноэкранных видеороликов в java openGL-игре на основе libgdx. Я пробовал почти все бесплатные libs, но ни один из них не имеет приемлемой производительности. Поэтому, наконец, я решил написать свои собственные jni-коды для работы с ffmpeg. Вот окончательное исполнение на моем ноутбуке:
Я провел всего несколько дней, чтобы завершить первую версию. Но скорость декодирования первой версии была всего около 120FPS, а время загрузки составляло около 5 мс на фрейм. После нескольких месяцев оптимизации я получил эту окончательную производительность и некоторые дополнительные функции. Теперь я могу воспроизводить несколько HD-видео одновременно без какой-либо медлительности.
Большинство видеороликов в моей игре имеют прозрачный фон. Этот вид прозрачного видео является файлом mp4 с двумя видеопотоками, один поток хранит h264rgb кодированные данные rgb, другой поток хранит кодированные альфа-данные h264. Поэтому для воспроизведения альфа-видео мне нужно декодировать 2 видеопотока и объединить их вместе, а затем загрузить на GPU. В результате я могу воспроизводить несколько прозрачных HD-видео выше непрозрачного HD-видео одновременно в моей игре.
Вы можете использовать чистую библиотеку Java под названием JCodec (http://jcodec.org).
Декодирование одного кадра H.264 так же просто, как:
ByteBuffer bb = ... // Your frame data is stored in this buffer
H264Decoder decoder = new H264Decoder();
Picture out = Picture.create(1920, 1088, ColorSpace.YUV_420); // Allocate output frame of max size
Picture real = decoder.decodeFrame(bb, out.getData());
BufferedImage bi = JCodecUtil.toBufferedImage(real); // If you prefere AWT image
Если вы хотите прочитать a из контейнера (например, MP4), вы можете использовать удобный вспомогательный класс FrameGrab:
int frameNumber = 150;
BufferedImage frame = FrameGrab.getFrame(new File("filename.mp4"), frameNumber);
ImageIO.write(frame, "png", new File("frame_150.png"));
Наконец, здесь полный сложный пример:
private static void avc2png(String in, String out) throws IOException {
SeekableByteChannel sink = null;
SeekableByteChannel source = null;
try {
source = readableFileChannel(in);
sink = writableFileChannel(out);
MP4Demuxer demux = new MP4Demuxer(source);
H264Decoder decoder = new H264Decoder();
Transform transform = new Yuv420pToRgb(0, 0);
MP4DemuxerTrack inTrack = demux.getVideoTrack();
VideoSampleEntry ine = (VideoSampleEntry) inTrack.getSampleEntries()[0];
Picture target1 = Picture.create((ine.getWidth() + 15) & ~0xf, (ine.getHeight() + 15) & ~0xf,
ColorSpace.YUV420);
Picture rgb = Picture.create(ine.getWidth(), ine.getHeight(), ColorSpace.RGB);
ByteBuffer _out = ByteBuffer.allocate(ine.getWidth() * ine.getHeight() * 6);
BufferedImage bi = new BufferedImage(ine.getWidth(), ine.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
AvcCBox avcC = Box.as(AvcCBox.class, Box.findFirst(ine, LeafBox.class, "avcC"));
decoder.addSps(avcC.getSpsList());
decoder.addPps(avcC.getPpsList());
Packet inFrame;
int totalFrames = (int) inTrack.getFrameCount();
for (int i = 0; (inFrame = inTrack.getFrames(1)) != null; i++) {
ByteBuffer data = inFrame.getData();
Picture dec = decoder.decodeFrame(splitMOVPacket(data, avcC), target1.getData());
transform.transform(dec, rgb);
_out.clear();
AWTUtil.toBufferedImage(rgb, bi);
ImageIO.write(bi, "png", new File(format(out, i)));
if (i % 100 == 0)
System.out.println((i * 100 / totalFrames) + "%");
}
} finally {
if (sink != null)
sink.close();
if (source != null)
source.close();
}
}
Я просто попробовал JCodec (http://jcodec.org). Это недопустимо медленно.
Тестовый код:
FrameGrab grab = new FrameGrab (новый FileChannelWrapper (новый RandomAccessFile ( "test.mp4", "r" ). getChannel()));
long time = System.currentTimeMillis();
для (int я = 0; я < 50; я ++) { grab.getFrame(); }
System.out.println( "Используемое время:" + (System.currentTimeMillis() - время));
Взгляните на Java Media Framework (JMF) - http://java.sun.com/javase/technologies/desktop/media/jmf/2.1.1/formats.html
Я использовал его некоторое время назад, и это было немного незрелым, но с тех пор они, возможно, усилили его.