如何在 C\C++ 中将位图作为帧写入 Ogg Theora?
一些带有源代码的例子会很有趣!)
将整个解决方案作为代码示例发布在此处有点冗长,但如果您从 Xiph.org 下载 libtheora,则有一个示例 png2theora。我将要提到的所有库函数都可以在 Xiph.org 上的 theora 和 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()。
希望这个对你有帮助。祝你好运!
这是一个微操作指南,展示了如何使用 theora 二进制文件。当编码器读取视频的原始、未压缩的“yuv4mpeg”数据时,您也可以通过将视频帧传送到编码器来从您的应用程序中使用它。