2009-11-15 1 views

ответ

3

Вот libtheora API и example code.

Вот micro howto, в котором показано, как использовать теоретические двоичные файлы. Поскольку кодировщик считывает необработанные, несжатые данные «yuv4mpeg» для видео, вы также можете использовать это из своего приложения, связав видеокадры с кодировщиком.

9

Все решение немного длиннее для публикации здесь в качестве образца кода, но если вы загружаете libtheora с Xiph.org, то есть пример png2theora. Все библиотечные функции, о которых я расскажу, можно найти в документации по Xiph.org для теорем и ogg.

  1. Позвоните th_info_init(), чтобы инициализировать структуру th_info, а затем настройте выходные параметры, назначив в ней соответствующие элементы.
  2. Используйте эту структуру в вызове th_encode_alloc(), чтобы получить контекст кодера
  3. Инициализировать поток Ogg, с ogg_stream_init()
  4. Инициализировать пустую структуру th_comment использования th_comment_init

перебирать следующее :

  1. Вызов th_encode_flushheader с контекстом кодировщика, пустой структурой комментариев и ogg_packet.
  2. Отправить получившийся пакет в Ogg поток с ogg_stream_packetin()

Пока th_encode_flushheader не возвращает 0 (или код ошибки)

Теперь, неоднократно называют ogg_stream_pageout(), каждый раз писать page.header а затем page.body в выходной файл, пока он не вернет 0. Теперь вызовите ogg_stream_flush и напишите результирующую страницу в файл.

Теперь вы можете записать кадры в кодировщик. Вот как я это сделал:

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

Где encoderInfo структура th_info используется для инициализации датчика (статический в разделе данных для меня).

На вашем последнем кадре установка последнего кадра на th_encode_packetout() будет гарантировать, что поток завершится правильно.

Как только вы закончите, просто убедитесь, что вы очистили (главным образом, закрыв fds). th_info_clear() очистит структуру th_info, а th_encode_free() освободит контекст кодировщика.

Очевидно, что вам нужно будет преобразовать растровое изображение в плоскости YUV, прежде чем вы сможете передать их в theora_write_frame().

Надеюсь, это поможет. Удачи!