2009-11-15 14 views

Respuesta

3

Aquí está la libtheora API y example code.

Aquí hay un micro howto que muestra cómo usar los binarios theora. Como el codificador lee datos raw, descomprimidos 'yuv4mpeg' para el video, puede usarlo desde su aplicación, conectando los marcos de video al codificador.

9

La solución completa es un poco larga para publicar aquí como un ejemplo de código, pero si descarga libtheora de Xiph.org, hay un ejemplo png2theora. Todas las funciones de la biblioteca que voy a mencionar se pueden encontrar en la documentación en Xiph.org para theora y ogg.

  1. Llame a th_info_init() para inicializar una estructura th_info, luego configure los parámetros de salida asignando los miembros apropiados en eso.
  2. utilizar esa estructura en una llamada a th_encode_alloc() para obtener un contexto codificador
  3. Inicializar una corriente OGG, con ogg_stream_init()
  4. Inicializar una estructura th_comment blanco usando th_comment_init

Iterar a través del siguiente :

  1. Llame a th_encode_flushheader con el contexto del codificador, la estructura de comentario en blanco y un ogg_packet.
  2. enviar el paquete resultante de la corriente OGG con ogg_stream_packetin()

Hasta th_encode_flushheader devuelve 0 (o un código de error)

Ahora, en repetidas ocasiones llamar ogg_stream_pageout(), cada vez que escribir el page.header y luego page.body a un archivo de salida, hasta que devuelva 0. Ahora llame a ogg_stream_flush y escriba la página resultante en el archivo.

Ahora puede escribir cuadros en el codificador. Aquí es cómo lo hice:

int theora_write_frame(int outputFd, unsigned long w, unsigned long h, unsigned char *yuv_y, unsigned char *yuv_u, unsigned char *yuv_v, int last) 
{ 
    th_ycbcr_buffer ycbcr; 
    ogg_packet op; 
    ogg_page og; 

    unsigned long yuv_w; 
    unsigned long yuv_h; 

    /* Must hold: yuv_w >= w */ 
    yuv_w = (w + 15) & ~15; 
    /* Must hold: yuv_h >= h */ 
    yuv_h = (h + 15) & ~15; 

    //Fill out the ycbcr buffer 
    ycbcr[0].width = yuv_w; 
    ycbcr[0].height = yuv_h; 
    ycbcr[0].stride = yuv_w; 
    ycbcr[1].width = yuv_w; 
    ycbcr[1].stride = ycbcr[1].width; 
    ycbcr[1].height = yuv_h; 
    ycbcr[2].width = ycbcr[1].width; 
    ycbcr[2].stride = ycbcr[1].stride; 
    ycbcr[2].height = ycbcr[1].height; 

    if(encoderInfo->pixel_fmt == TH_PF_420) 
    { 
    //Chroma is decimated by 2 in both directions 
    ycbcr[1].width = yuv_w >> 1; 
    ycbcr[2].width = yuv_w >> 1; 
    ycbcr[1].height = yuv_h >> 1; 
    ycbcr[2].height = yuv_h >> 1; 
    }else if(encoderInfo->pixel_fmt == TH_PF_422) 
    { 
    ycbcr[1].width = yuv_w >> 1; 
    ycbcr[2].width = yuv_w >> 1; 
    }else if(encoderInfo->pixel_fmt != TH_PF_422) 
    { 
    //Then we have an unknown pixel format 
    //We don't know how long the arrays are! 
    fprintf(stderr, "[theora_write_frame] Unknown pixel format in writeFrame!\n"); 
    return -1; 
    } 

    ycbcr[0].data = yuv_y; 
    ycbcr[1].data = yuv_u; 
    ycbcr[2].data = yuv_v; 

    /* Theora is a one-frame-in,one-frame-out system; submit a frame 
    for compression and pull out the packet */ 
    if(th_encode_ycbcr_in(encoderContext, ycbcr)) { 
    fprintf(stderr, "[theora_write_frame] Error: could not encode frame\n"); 
    return -1; 
    } 

    if(!th_encode_packetout(encoderContext, last, &op)) { 
    fprintf(stderr, "[theora_write_frame] Error: could not read packets\n"); 
    return -1; 
    } 

    ogg_stream_packetin(&theoraStreamState, &op); 
    ssize_t bytesWritten = 0; 
    int pagesOut = 0; 
    while(ogg_stream_pageout(&theoraStreamState, &og)) { 
    pagesOut ++; 
    bytesWritten = write(outputFd, og.header, og.header_len); 
    if(bytesWritten != og.header_len) 
    { 
     fprintf(stderr, "[theora_write_frame] Error: Could not write to file\n"); 
     return -1; 
    } 
    bytesWritten = write(outputFd, og.body, og.body_len); 
    if(bytesWritten != og.body_len) 
    { 
     bytesWritten = fprintf(stderr, "[theora_write_frame] Error: Could not write to file\n"); 
     return -1; 
    } 
    } 
    return pagesOut; 
} 

Dónde encoderInfo es la estructura th_info utilizado para inicializar el codificador (estática en la sección de datos para mí).

En su último cuadro, establecer el último cuadro en th_encode_packetout() se asegurará de que la secuencia finalice correctamente.

Una vez hecho esto, solo asegúrese de limpiar (cerrar fds principalmente). th_info_clear() borrará la estructura th_info, y th_encode_free() liberará el contexto del codificador.

Obviamente, necesitará convertir su mapa de bits en planos YUV antes de poder pasarlos a theora_write_frame().

Espero que esto sea de alguna ayuda. ¡Buena suerte!