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

Как декодировать видеокадр H.264 в среде Java

Кто-нибудь знает, как декодировать видеокадр H.264 в среде Java?

Мои продукты для сетевых камер поддерживают потоки RTP/RTSP.

Сервисный стандарт RTP/RTSP от моей сетевой камеры обслуживается, а также поддерживает "RTP/RTSP через HTTP".

RTSP: TCP 554 Начальный порт RTP: UDP 5000

4b9b3361

Ответ 1

Или используйте Xuggler. Работает с RTP, RTMP, HTTP или другими протоколами и может декодировать и кодировать H264 и большинство других кодеков. И активно поддерживается, бесплатно и с открытым исходным кодом (LGPL).

Ответ 2

Я думаю, лучшее решение использует "JNI + ffmpeg". В моем текущем проекте мне нужно одновременно воспроизводить несколько полноэкранных видеороликов в java openGL-игре на основе libgdx. Я пробовал почти все бесплатные libs, но ни один из них не имеет приемлемой производительности. Поэтому, наконец, я решил написать свои собственные jni-коды для работы с ffmpeg. Вот окончательное исполнение на моем ноутбуке:

  • Окружающая среда: CPU: Core i7 Q740 @1.73G, видео: nVidia GeForce GT 435M, ОС: Windows 7 64bit, Java: Java7u60 64bit
  • Видео: h264rgb/h264 закодировано, нет звука, разрешение: 1366 * 768
  • Решение: Декодирование: JNI + ffmpeg v2.2.2, Загрузка в GPU: обновить текстуру openGL с помощью lwjgl
  • Производительность: Расшифровка: 700-800FPS, Текстура Загрузка: около 1 мс на фрейм.

Я провел всего несколько дней, чтобы завершить первую версию. Но скорость декодирования первой версии была всего около 120FPS, а время загрузки составляло около 5 мс на фрейм. После нескольких месяцев оптимизации я получил эту окончательную производительность и некоторые дополнительные функции. Теперь я могу воспроизводить несколько HD-видео одновременно без какой-либо медлительности.

Большинство видеороликов в моей игре имеют прозрачный фон. Этот вид прозрачного видео является файлом mp4 с двумя видеопотоками, один поток хранит h264rgb кодированные данные rgb, другой поток хранит кодированные альфа-данные h264. Поэтому для воспроизведения альфа-видео мне нужно декодировать 2 видеопотока и объединить их вместе, а затем загрузить на GPU. В результате я могу воспроизводить несколько прозрачных HD-видео выше непрозрачного HD-видео одновременно в моей игре.

Ответ 3

Вы можете использовать чистую библиотеку 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();
    }
}

Ответ 4

Я просто попробовал JCodec (http://jcodec.org). Это недопустимо медленно.

  • Условия тестирования: CPU: Core i7 Q740 @1.73G, ОС: Windows 7 64bit, Java 1.7.0_25 32bit
  • Тестовое видео: 1080p MPEG-4 видео, снятое Galaxy S3 mobile
  • Результат теста: среднее время извлечения кадра: 760ms за кадр.
  • Тестовый код:

    FrameGrab grab = new FrameGrab (новый FileChannelWrapper (новый RandomAccessFile ( "test.mp4", "r" ). getChannel()));

    long time = System.currentTimeMillis();

    для (int я = 0; я < 50; я ++) {   grab.getFrame(); }

    System.out.println( "Используемое время:" + (System.currentTimeMillis() - время));