[theora-dev] Video encoded using libtheora-1.1.1 and libogg-1.1.4 plays too fast...
Id Kong
spam_receptacle_ at hotmail.com
Wed Feb 10 22:52:12 PST 2010
I'm new to mailing lists so please forgive me if I break any protocols...
I've been trying to encode video using libtheora-1.1.1 and libogg-1.1.4 on a Win32 system. While I did have to change the code in order to get them to compile, I'm assuming they're correct. With that assumption, the video I make with them plays way too fast. Either the framerate is interpreted by players to be way too high or not all the frames are getting encoded in the stream. Media reporting software (like MediaInfo) report the correct framerate from the ogg file. I will post the test code that I'm using so people can take a cursory look and see if there are any obvious mistakes that I'm making. If anyone actually wants to compile the code, I can post a version of it that doesn't use an external image library, in this case CxImage. Any help is greatly appreciated. Thank you!
#include <stdio.h>//#include <conio.h>#include <assert.h>
#include "CxImage\ximage.h"#include "theora\theoraenc.h"#include "theora\codec.h"
// Rounds to the next multiple of 16int RoundTo16(int in) { return (in + 15) / 16 * 16;}
// This is a cheap transform but it will do for a simple testunsigned char TransformPixel(int *tables, RGBQUAD colour) { return static_cast<unsigned char>(tables[0] + (tables[1] * colour.rgbRed + tables[2] * colour.rgbGreen + tables[3] * colour.rgbBlue) / 256);}
// This is done so often that we might as well factor it outvoid WriteOggPage(FILE *file, ogg_stream_state *state, bool flush = false) { ogg_page page; int rc; if( flush ) rc = ogg_stream_flush( state, &page); else rc = ogg_stream_pageout(state, &page);
if( rc != 0 ) { fwrite(page.header, 1, page.header_len, file); fwrite(page.body, 1, page.body_len, file); }}
int main(int argc, char *argv[]) { if( argc < 3 ) { printf("Too few parameters...\n");
} else { char *input_filename = argv[1]; char *output_filename = argv[2];
CxImage image; image.Load(input_filename);
if( image.IsValid() ) { printf("Loaded image!\n");
th_info theora_input; th_info_init(&theora_input); theora_input.frame_width = RoundTo16(image.GetWidth()); theora_input.frame_height = RoundTo16(image.GetHeight()); theora_input.pic_width = image.GetWidth(); theora_input.pic_height = image.GetHeight(); theora_input.pic_x = 0; theora_input.pic_y = 0; theora_input.colorspace = TH_CS_UNSPECIFIED; theora_input.pixel_fmt = TH_PF_444; theora_input.quality = 42; theora_input.target_bitrate = 0; theora_input.fps_numerator = 30; theora_input.fps_denominator = 1; theora_input.aspect_numerator = 0; theora_input.aspect_denominator = 0;
th_enc_ctx *theora_state = th_encode_alloc(&theora_input);
int temp = 5; //th_encode_ctl(theora_state, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE, &temp, sizeof(temp)); th_encode_ctl(theora_state, TH_ENCCTL_GET_SPLEVEL_MAX, &temp, sizeof(temp)); th_encode_ctl(theora_state, TH_ENCCTL_SET_SPLEVEL , &temp, sizeof(temp));
ogg_stream_state ogg_state; ogg_stream_init(&ogg_state, 3001); // Does it really matter what this is?
FILE* output_file = fopen(output_filename, "wb"); ogg_packet packet; bool go = true;
th_comment comment = {0}; int rc = th_encode_flushheader(theora_state, &comment, &packet); ogg_stream_packetin(&ogg_state, &packet); // Can this really fail? WriteOggPage(output_file, &ogg_state, true);
while(true) { int rc = th_encode_flushheader(theora_state, &comment, &packet); //printf("%i\n", packet.packetno); if( rc == 0) { printf("Done headers!\n"); break; } else { printf("Another packet...\n"); } ogg_stream_packetin(&ogg_state, &packet); // Can this really fail? } WriteOggPage(output_file, &ogg_state, true);
if( go ) { printf("Preparing frame...\n");
th_ycbcr_buffer buffer; int tables[][4] = {{16, 66, 129, 25}, {128, -38, -74, 112}, {128, 112, -94, -18}}; for(int i = 0; i < 3; i++) { buffer[i].width = theora_input.frame_width; buffer[i].height = theora_input.frame_height; buffer[i].stride = theora_input.frame_width; buffer[i].data = new unsigned char[theora_input.frame_width * theora_input.frame_height];
for(DWORD y = 0; y < image.GetHeight(); y++) { for(DWORD x = 0; x < image.GetWidth(); x++) { buffer[i].data[y * buffer[i].stride + x] = TransformPixel(tables[i], image.GetPixelColor(x, image.GetHeight() - y, false)); } } }
printf("Encoding video...\n");
int num_frames = 30 * 10; // This should be 10 seconds of video but it ends up being about 3... for(int i = 0; i < num_frames; i++) { int rc = th_encode_ycbcr_in(theora_state, buffer); if( rc == 0 ) { while(true) { int rc = th_encode_packetout(theora_state, (i == num_frames - 1) ? 1 : 0, &packet); if( rc == 0 ) break; ogg_stream_packetin(&ogg_state, &packet); } WriteOggPage(output_file, &ogg_state);
} else { printf("Encoding error was encountered!\n"); break; } } WriteOggPage(output_file, &ogg_state, true);
for(int i = 0; i < 3; i++) { delete [] buffer[i].data; }
fclose(output_file);
printf("Done encoding!\n"); }
ogg_stream_clear(&ogg_state); th_encode_free(theora_state);
} else { printf("Bad image input...\n"); } }
//_getch();
return 0;}
_________________________________________________________________
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.xiph.org/pipermail/theora-dev/attachments/20100211/ec1e499d/attachment.htm
More information about the theora-dev
mailing list