2010-01-29 19 views
19

¿Alguien sabe cómo decodificar el video frame H.264 en el entorno Java?Cómo decodificar el video frame H.264 en el entorno Java

Los productos de mi cámara de red son compatibles con RTP/RTSP Streaming.

Se sirve el servicio estándar RTP/RTSP de mi cámara de red y también es compatible con "RTP/RTSP sobre HTTP".

RTSP: TCP 554 RTP puerto de inicio: UDP 5000

Respuesta

0

Tome un vistazo a Java Media Framework (JMF) - http://java.sun.com/javase/technologies/desktop/media/jmf/2.1.1/formats.html

lo usé hace un tiempo y que era un poco inmaduro, pero pueden haberlo reforzado desde entonces.

+7

JMF está abandonado, muerto durante años. Por lo tanto, no sería una buena idea confiar en un proyecto a largo plazo. Pero si esto es una cosa de una sola vez, estoy de acuerdo con que JMF es una buena solución. Aunque creo que JMF solo admite H263. –

+1

Eche un vistazo a FMJ que ha intentado recoger JMF. http://fmj-sf.net/ –

+2

Si JMF está muerto, ¿qué se puede usar como reemplazo? – kevindaub

6

O use Xuggler. Funciona con RTP, RTMP, HTTP u otros protocolos, y puede decodificar y codificar H264 y la mayoría de los demás códecs. Y se mantiene activamente, libre y de código abierto (LGPL).

+7

Parece que Xuggler ya no se mantiene activamente. http://blog.xuggle.com/ –

+0

Generalmente no es una buena idea usar un proyecto inactivo como Xuggler. Recomiendo encontrar algo que se desarrolle activamente. –

2

Puede usar una biblioteca pura de Java llamada JCodec (http://jcodec.org).
decodificación H.264 marco de uno es tan fácil como:

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 

Si desea leer una de de un recipiente (como MP4) se puede utilizar una mano FrameGrab clase de ayuda:

int frameNumber = 150; 
BufferedImage frame = FrameGrab.getFrame(new File("filename.mp4"), frameNumber); 
ImageIO.write(frame, "png", new File("frame_150.png")); 

Por último, he aquí una muestra sofisticada completo:

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(); 
    } 
} 
+0

Funciona muy lento, un segundo por cada getFrame(), que hace la misma decodificación que – Nativ

2

Sólo traté JCodec (http://jcodec.org). Es inaceptable lento.

  • entorno de prueba: CPU: Core i7 Q740 @ 1,73 g, SO: Windows 7 64 bits, 32 bits de Java 1.7.0_25
  • prueba de vídeo: 1080p MPEG-4 de vídeo capturado por Galaxy S3 móvil
  • prueba Resultado: tiempo promedio de extracción de cuadros: 760ms por cuadro.
  • Código de ensayo:

    FrameGrab grab = new FrameGrab (. Nuevo FileChannelWrapper (nuevo RandomAccessFile ("test.mp4", "r") getChannel()));

    long time = System.currentTimeMillis();

    para (int i = 0; i < 50; i ++) { grab.getFrame(); }

    System.out.println ("Tiempo utilizado:" + (System.currentTimeMillis() - time));

+2

¡JavaCV que usa FFMpeg para tomar fotogramas es mucho más rápido! Toma casi 1ms/frame en mi computadora portátil. Más detalles aquí: http://stackoverflow.com/a/22107132/398316 – M2X

3

Creo que la mejor solución es usar "JNI + ffmpeg". En mi proyecto actual, necesito reproducir varios videos de pantalla completa al mismo tiempo en un juego Java OpenGL basado en libgdx. He probado casi todas las librerías, pero ninguna de ellas tiene un rendimiento aceptable. Así que finalmente decidí escribir mis propios códigos Jni C para trabajar con ffmpeg.Esta es la última actuación en mi portátil:

  • Medio Ambiente: CPU: Core i7 Q740 @ 1,73 g, vídeo: Nvidia GeForce GT 435M, SO: Windows 7 64 bits, Java: Java7u60 64 bits
  • vídeo: h264rgb/h264 codificado, no hay sonido, resolución: 1366 * 768
  • Solución: Decode: JNI + ffmpeg v2.2.2, Sube a la GPU: actualización de textura de openGL usando lwjgl
  • Rendimiento: decodificación velocidad: 700-800FPS, textura cargando: aproximadamente 1ms por cuadro.

Solo me tomó varios días completar la primera versión. Pero la velocidad de decodificación de la primera versión era de solo 120 FPS, y el tiempo de carga era de aproximadamente 5 ms por cuadro. Después de varios meses de optimización, obtuve este rendimiento final y algunas características adicionales. Ahora puedo reproducir varios videos HD al mismo tiempo sin ninguna lentitud.

La mayoría de los videos en mi juego tienen fondo transparente. Este tipo de video transparente es un archivo mp4 con 2 transmisiones de video, una secuencia almacena datos rgb codificados h264rgb, la otra secuencia almacena datos alfa codificados h264. Entonces, para reproducir un video alfa, necesito decodificar 2 secuencias de video y unirlas y luego subirlas a la GPU. Como resultado, puedo jugar varios videos HD transparentes sobre un video HD opaco al mismo tiempo en mi juego.

+0

Creé una aplicación para Android que graba videos de la cámara y los envía usando RTP/RTSP. Usé la clase 'MediaRecorder' para capturar y codificar el video de la cámara. Probé mi implementación usando VLC y funciona. Traté de crear un cliente usando Java que recibe la carga útil '96'. Probé muchas cosas, por ejemplo, la clase 'Toolkit', pero su método' createImage (payload, 0, payloadLength) 'solo extrajo un JPG o PNG de la carga que es' byte [] 'También estoy probado con Xuggler pero Solo encontré ejemplos usando archivos mp4 que necesito decodificar desde un 'byte []'. (No sé C) – Teocci

Cuestiones relacionadas