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

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

一些带有源的示例将是格栅!)

这是libtheora API和示例代码 。

这是一个显示如何使用theora二进制文件的微指南。 当编码器读取video的原始未压缩“yuv4mpeg”数据时,您也可以通过将video帧传输到编码器来使用应用程序中的数据

整个解决方案有点冗长,可以在这里作为代码示例发布,但如果您从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()。

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