简体   繁体   English

如何将位图作为帧写入C \\ C ++中的Ogg Theora?

[英]How to write bitmaps as frames to Ogg Theora in C\C++?

How to write bitmaps as frames to Ogg Theora in C\\C++? 如何将位图作为帧写入C \\ C ++中的Ogg Theora?

Some Examples with source would be grate!) 一些来源的例子将是格栅!)

The entire solution is a little lengthy to post on here as a code sample, but if you download libtheora from Xiph.org, there is an example png2theora. 整个解决方案有点冗长,可以在这里作为代码示例发布,但如果你从Xiph.org下载libtheora,就会有一个例子png2theora。 All of the library functions I am about to mention can be found in the documentation on Xiph.org for theora and ogg. 我将要提到的所有库函数都可以在Xiph.org上关于theora和ogg的文档中找到。

  1. Call th_info_init() to initialise a th_info structure, then set up you output parameters by assigning the appropriate members in that. 调用th_info_init()来初始化th_info结构,然后通过在其中分配适当的成员来设置输出参数。
  2. Use that structure in a call to th_encode_alloc() to get an encoder context 在调用th_encode_alloc()时使用该结构来获取编码器上下文
  3. Initialise an ogg stream, with ogg_stream_init() 使用ogg_stream_init()初始化ogg流
  4. Initialise a blank th_comment structure using th_comment_init 使用th_comment_init初始化空白的th_comment结构

Iterate through the following: 通过以下方式迭代:

  1. Call th_encode_flushheader with the the encoder context, the blank comment structure and an ogg_packet. 使用编码器上下文,空白注释结构和ogg_packet调用th_encode_flushheader。
  2. Send the resulting packet to the ogg stream with ogg_stream_packetin() 使用ogg_stream_packetin()将生成的数据包发送到ogg流

Until th_encode_flushheader returns 0 (or an error code) 直到th_encode_flushheader返回0(或错误代码)

Now, repeatedly call ogg_stream_pageout(), every time writing the page.header and then page.body to an output file, until it returns 0. Now call ogg_stream_flush and write the resulting page to the file. 现在,每次重复调用ogg_stream_pageout(),每次将page.header和page.body写入输出文件,直到它返回0.现在调用ogg_stream_flush并将结果页面写入文件。

You can now write frames to the encoder. 您现在可以将帧写入编码器。 Here is how I did it: 我是这样做的:

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

Where encoderInfo is the th_info structure used to initialise the encoder (static in the data section for me). 其中encoderInfo是用于初始化编码器的th_info结构(对于我来说,数据部分是静态的)。

On your last frame, setting the last frame on th_encode_packetout() will make sure the stream terminates properly. 在最后一帧上,在th_encode_packetout()上设置最后一帧将确保流正确终止。

Once your done, just make sure to clean up (closing fds mainly). 一旦完成,只需确保清理(主要关闭fds)。 th_info_clear() will clear the th_info structure, and th_encode_free() will free your encoder context. th_info_clear()将清除th_info结构,th_encode_free()将释放您的编码器上下文。

Obviously, you'll need to convert your bitmap into YUV planes before you can pass them to theora_write_frame(). 显然,您需要先将位图转换为YUV平面,然后才能将它们传递给theora_write_frame()。

Hope this is of some help. 希望这个对你有帮助。 Good luck! 祝好运!

Here's the libtheora API and example code . 这是libtheora API示例代码

Here's a micro howto that shows how to use the theora binaries. 这是一个显示如何使用theora二进制文件的指南。 As the encoder reads raw, uncompressed 'yuv4mpeg' data for video you could use that from your app, too by piping the video frames to the encoder. 当编码器读取视频的原始未压缩“yuv4mpeg”数据时,您也可以通过将视频帧传输到编码器来使用应用程序中的数据

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM