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

C++ 如何将位图作为帧写入C\C+中的Ogg Theora+;?,c++,c,ogg-theora,C++,C,Ogg Theora,如何在C\C++中将位图作为帧写入Ogg Theora 一些源代码示例如下!) 这是和 下面是一个演示如何使用theora二进制文件的示例。当编码器读取原始、未压缩的“yuv4mpeg”视频数据时,您也可以通过将视频帧传输到编码器来从应用程序中使用这些数据。整个解决方案在这里作为代码示例发布有点长,但如果您从Xiph.org下载liborea,则有一个示例png2theora。我将要提到的所有库函数都可以在Xiph.org上的theora和ogg文档中找到 调用th_info_init()初始化

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

一些源代码示例如下!)

这是和


下面是一个演示如何使用theora二进制文件的示例。当编码器读取原始、未压缩的“yuv4mpeg”视频数据时,您也可以通过将视频帧传输到编码器来从应用程序中使用这些数据。

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

  • 调用th_info_init()初始化th_info结构,然后通过在该结构中分配适当的成员来设置输出参数
  • 在调用th_encode_alloc()以获取编码器上下文时使用该结构
  • 使用ogg_stream_init()初始化ogg流
  • 使用THU comment init初始化空白THU comment结构
  • 反复进行以下操作:

    调用编码器上下文、空白注释结构和OGGX包。
  • 使用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是用于初始化编码器的THU info结构(对于我来说,在数据部分是静态的)

    在最后一帧上,在th_encode_packetout()上设置最后一帧将确保流正确终止

    完成后,只需确保清理(主要关闭fds)。th_info_clear()将清除th_info结构,th_encode_free()将释放编码器上下文

    显然,在将位图传递到theora_write_frame()之前,需要将其转换为YUV平面

    希望这能有所帮助。祝你好运