Как написать растровые изображения как фреймы для Ogg Theora в C \ C ++? - PullRequest
5 голосов
/ 15 ноября 2009

Как записать растровые изображения как фреймы в Ogg Theora на C \ C ++?

Некоторые примеры с источником были бы полезны!)

Ответы [ 2 ]

9 голосов
/ 30 августа 2010

Полное решение немного длинно, чтобы публиковать здесь в качестве примера кода, но если вы скачаете libtheora с Xiph.org, есть пример png2theora. Все библиотечные функции, о которых я собираюсь упомянуть, можно найти в документации по Xiph.org для theora и 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 ().

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

3 голосов
/ 21 декабря 2009

Вот пример libtheora API и пример кода .

Вот микрошино , в котором показано, как использовать двоичные файлы теории. Поскольку кодировщик читает необработанные, несжатые данные 'yuv4mpeg' для видео , вы можете использовать их и из своего приложения, передавая видеокадры в кодировщик.

...