如何写位图作为框架来Ogg theora格式的C\C++?

一些示例的源将篦!)

有帮助吗?

解决方案

这里的 libtheora API例码.

这里有一个 微howto 这显示如何使用theora格式的二进制文件。编码器读取 原始的、无压缩'yuv4mpeg'数据的视频 你可以使用自己的应用程序,也通过管道的视频框架的编码。

其他提示

整个解决方案作为代码示例发布在此处有点冗长,但如果您从 Xiph.org 下载 libtheora,则会有一个示例 png2theora。我要提到的所有库函数都可以在 Xiph.org 上的 theora 和 ogg 文档中找到。

  1. 调用 th_info_init() 来初始化 th_info 结构,然后通过在其中分配适当的成员来设置输出参数。
  2. 在调用 th_encode_alloc() 时使用该结构来获取编码器上下文
  3. 使用 ogg_stream_init() 初始化 ogg 流
  4. 使用 th_comment_init 初始化一个空白的 th_comment 结构

迭代以下内容:

  1. 使用编码器上下文、空白注释结构和 ogg_packet 调用 th_encode_flushheader。
  2. 使用 ogg_stream_packetin() 将生成的数据包发送到 ogg 流

直到 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()。

希望这个对你有帮助。祝你好运!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top