2009-11-15 12 views

risposta

3

Ecco il libtheora API e example code.

Ecco uno micro howto che mostra come utilizzare i file binari di theora. Poiché l'encoder legge dati non compressi "yuv4mpeg" per il video, è possibile utilizzarlo anche dall'app, collegando i frame video all'encoder.

9

L'intera soluzione è un po 'lunga da postare qui come esempio di codice, ma se scarichi libtheora da Xiph.org, c'è un esempio di png2theora. Tutte le funzioni della libreria che sto per menzionare possono essere trovate nella documentazione su Xiph.org per theora e ogg.

  1. Chiama th_info_init() per inizializzare una struttura th_info, quindi imposta i parametri di output assegnando i membri appropriati in quello.
  2. Utilizzare tale struttura in una chiamata a th_encode_alloc() per ottenere un contesto encoder
  3. Inizializzare un flusso ogg, con ogg_stream_init()
  4. Inizializzare una struttura th_comment vuoto utilizzando th_comment_init

Scorrere il seguente :

  1. Chiama th_encode_flushheader con il contesto dell'encoder, la struttura dei commenti vuota e un ogg_packet.
  2. inviare il pacchetto risultante al flusso ogg con ogg_stream_packetin()

Fino th_encode_flushheader restituisce 0 (o un codice di errore)

Ora, chiamare ripetutamente ogg_stream_pageout(), ogni volta che scrivendo il page.header e quindi page.body in un file di output, finché non restituisce 0. Ora chiama ogg_stream_flush e scrivi la pagina risultante nel file.

Ora è possibile scrivere i frame nell'encoder. Ecco come ho fatto:

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; 
} 

Dove encoderInfo è la struttura th_info utilizzato per inizializzare l'encoder (statico nella sezione dati per me).

Sull'ultimo fotogramma, l'impostazione dell'ultimo fotogramma su th_encode_packetout() garantisce che lo streaming termina correttamente.

Una volta terminato, è sufficiente assicurarsi di eseguire la pulizia (chiusura di fds principalmente). th_info_clear() cancellerà la struttura th_info e th_encode_free() libererà il contesto del tuo codificatore.

Ovviamente, è necessario convertire la bitmap in piani YUV prima di poterli passare a theora_write_frame().

Spero che questo sia di qualche aiuto. In bocca al lupo!