2011-08-15 18 views
5

Estoy tratando de analizar cuadros H.264 desde un archivo .mov. Creo que he llegado a la conclusión de que mov.c de AVFormat, parte de FFMPEG, es el camino a seguir. Pero mov.c es ~ 2600 líneas de código siguiente sin comentario. Estoy buscando ejemplos de uso de FFMPEG, especialmente analizando la estructura de cualquier tipo de archivo. no importa si es MPEG4 o Quicktime Movie ya que son bastante similares en estructura.Analizando cuadro por cuadro desde .mov usando ffmpeg

si no hay ejemplos existentes (no puedo encontrar ninguno) tal vez alguien lo haya usado y pueda darme un par de líneas de código, o explicar cómo empezar?

Lo que estoy tratando de hacer: yo uso AVCaptureSession para capturar muestras de la cámara de vídeo, estas muestras se codifican en H264 y por escrito para presentar con la ayuda de AVAssetsWriter, AVAssetsWriterInput y AVAssetsWriterInputPixelBufferAdaptor. El motivo es que no puedo acceder directamente a la codificación de hardware H264, ya que Apple no lo permite. Lo que ahora necesito hacer (yo creo que no seguro) es omita:

Los "mdat" -atom (datos de película, puede haber más de un pienso) desde el archivo .mov. luego el "vide" -entorno y luego dentro del átomo de vide (muestra de datos de video, podría haber más de uno). Creo que habrá varios átomos que creo que son los marcos. estos serán del tipo "avc1" (ese es el tipo de H264). Corrígeme en esto porque estoy bastante seguro de que todavía no he recibido todo esto correctamente.

mi pregunta es, ¿cómo voy a proceder a analizar los cuadros individuales. He estado leyendo the documentation y miré iFrameExtractor (que no es muy útil ya que decodifica los marcos). Creo que lo he entendido correctamente cuando se supone que debo usar mov.c desde FFMPEG-AVFormat, pero no estoy seguro.

Editar: Ahora estoy tratando de esta manera:

  1. funciono con la función init ligeramente reducida i iFrameExtractor que encuentra el videostream en el Mov-archivo.

  2. puedo obtener los datos para la trama de la siguiente manera:

    AVPacket packet; 
    av_read_frame(pFormatCtx, &packet); 
    NSData *frame; 
    if(packet.stream_index == videoStream){ 
        frame = [NSData dataWithBytes:packet.data length:packet.size]; 
    } 
    videoStream++; 
    av_free_packet(&packet); 
    return frame; 
    

i luego pasarlo a una subclase de NSOperation donde es retenido a la espera de carga. pero recibo un EXC_BAD_ACC, ¿estoy haciendo algo mal al copiar los datos del marco? algunas ideas. obtengo el EXC _... cuando intento establecer la variable de clase NSData* frame usando su propiedad (no atómica, retener). (dice EXC_BAD_ACC en la fila sintetizar)

+0

mov.c no lo ayudará con el objetivo final. Si necesita ayuda con el análisis de MOV/MP4, puede ser útil. Otra biblioteca útil para cuando las cosas se ponen difíciles [mp4v2] (http://code.google.com/p/mp4v2/). Básicamente, tendrás que escribir esto tú mismo. Ninguna biblioteca hará el trabajo por una variedad de razones. –

+0

@Steve McFarlin, gracias, tienes algunos consejos sobre la lectura, excepto la qt-documentation para comprender toda la estructura del archivo mov porque realmente estoy teniendo problemas para abarcarlo todo, ¿es correcto que el átomo ni siquiera debe estar en un orden específico? ¿Cuál pensaste que era más fácil trabajar con mov o mp4? –

+0

@ Steve McFarlin, supongo que has visto el proyecto iFrameExtractor. también es esencialmente el mismo código que en el tutorial de Martin Böhme (por ejemplo en dranger.com). en la función de siguiente cuadro solo usan av_read_frame y luego decodifican esto. ¿el AVPacket modificado por av_read_frame no será el marco codificado H264? –

Respuesta

1

utilizo el siguiente para analizar cada fotograma del archivo de los movimientos.

-(NSData *)nextFrame { 
    AVPacket packet; 
    NSData *frame = nil; 

    while(!frame && av_read_frame(pFormatCtx, &packet)>=0) { 

     if(packet.stream_index == streamNo) { 
      frame = [[[NSData alloc] initWithBytes:packet.data length:packet.size] autorelease]; 
     } 
     av_free_packet(&packet); 
    } 
    return frame; 
} 

aunque cuidado, ya av_read_frame no verifica los marcos, que se realiza en la etapa de decodificación. esto significa que los "marcos" devueltos pueden contener información adicional que no forma parte del cuadro real.

a inicializar el AVFormatContext * pFormatCtx y AVCodecContext * pCodecCtx utilizo este código (que creo que se deriva del código de ejemplo de Martin Böhme):

AVCodec *pCodec; 

    // Register all formats and codecs 
    av_register_all(); 

    // Open video file 
    if(avformat_open_input(&pFormatCtx, [moviePath cStringUsingEncoding:NSASCIIStringEncoding], NULL, NULL)!=0) 
     goto initError; // Couldn't open file 

    // Retrieve stream information 
    if(avformat_find_stream_info(pFormatCtx,NULL)<0) 
     goto initError; // Couldn't find stream information 

    // Find the video stream 
    streamNo = -1; 
    for(int i=0; i<pFormatCtx->nb_streams; i++){ 
     if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 
     { 
      streamNo = i; 
      break; 
     } 
    } 
    if(streamNo == -1) 
     goto initError; // Didn't find a video stream 

    // Get a pointer to the codec context for the video stream 
    pCodecCtx=pFormatCtx->streams[streamNo]->codec; 

    // Find the decoder for the video stream 
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id); 
    if(pCodec==NULL) 
     goto initError; // Codec not found 

    // Open codec 
    if(avcodec_open2(pCodecCtx, pCodec, NULL)<0) 
     goto initError; // Could not open codec 

    return self; 

initError: 
    NSLog(@"initError in VideoFrameExtractor"); 
    [self release]; 
    return nil; 

esperanza esto ayuda a alguien en el futuro.

0

Hay un buen tutorial sobre el uso de libavcodec/libavformat here. Lo poco que parece que le interesa es la función DoSomethingWithTheImage() que no se ha implementado.

+0

quiero datos RAW H.264, por lo que puedo volver a montar los marcos en un mov en el lado del servidor más adelante. He visto este ejemplo antes y no pude entender si se suponía que debía omitir el paso de decodificación. y simplemente mantener el 'rawData = packet.data'? ¿Qué pasa cuando decodifico? ¿Voy desde el estándar H.264 entonces? –

+1

¿ambos leen y escriben .mov? ¿que estas haciendo entonces? –

+0

@yi_H estoy desmontando el archivo .mov mientras se está grabando para enviar las tramas H264 a un servidor donde vuelvo a montarlas. es la única forma de transmitir H264 en tiempo real con iOS, tal como lo entiendo. –

0

Si transmite H264 a iOS, necesita transmisión segmentada (también conocida como transmisión en vivo de Apple).

Aquí es un proyecto de código abierto: http://code.google.com/p/httpsegmenter/

+1

Voy a transmitir desde iOS. usando AVCaptureSession y AVAssetsWriter para escribir de cámara en archivo. entonces quiero analizar el archivo para obtener los cuadros H264 y subirlos al archivo. Tengo todo funcionando, incluidos los paquetes http para cargar. lo que necesito es una forma de acceder a los marcos en el archivo .mov, acceder a los datos del marco sin procesar. tal vez funcionará con el ejemplo publicado en la otra respuesta. Lo estoy intentando ahora, si tienes otra sugerencia sobre cómo puedo hacerlo funcionar, por favor compártelo :) –

+0

¿quieres soltar el canal de audio? quieres usar un contenedor diferente? Todavía no lo entiendo –

+0

me di cuenta de que la otra respuesta no funcionará, ya que decodifica el cuadro, por lo que ya no estará codificado en H264. Necesito extraer los cuadros inmediatamente de la secuencia de video sin decodificar –

Cuestiones relacionadas