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

时间:2009-11-15 01:49:13

标签: c++ c ogg-theora

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

源代码的一些例子将是格栅!)

2 个答案:

答案 0 :(得分:9)

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

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

    重复以下内容:

    1. 使用编码器上下文,空白注释结构和ogg_packet调用th_encode_flushheader。
    2. 使用ogg_stream_packetin()
    3. 将结果数据包发送到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()。

      希望这有一些帮助。祝你好运!

答案 1 :(得分:3)

以下是libtheora APIexample code

这是一个micro howto,展示了如何使用theora二进制文件。当编码器读取原始的,未压缩的'yuv4mpeg'视频数据时,您也可以通过将视频帧传输到编码器来使用应用程序中的数据。