[theora-dev] Is TH_ENCCTL_SET_DUP_COUNT compatible with TH_ENCCTL_SET_VP3_COMPATIBLE?

Id Kong spam_receptacle_ at hotmail.com
Thu Feb 18 01:18:34 PST 2010



> Date: Wed, 17 Feb 2010 19:15:55 -0500
> From: tterribe at email.unc.edu
> 
> Id Kong wrote:
> > Is the encoding control command TH_ENCCTL_SET_DUP_COUNT compatible with
> > the TH_ENCCTL_SET_VP3_COMPATIBLE setting?
> 
> It should be. Can you upload some input that exhibits the problem and
> (hopefully) the source code you're using to set the dup counts, or at
> least the actual counts used with that input?

	I've created a small sample program that exhibits the behavior.  I've created video with this program with and without the TH_ENCCTL_SET_DUP_COUNT used for each frame and I've played back the results with ffdshow tryout revision 1980 (Jun 2, 2008.  I found the about box!) and with VLC player 1.0.2 (Goldeneye), so I have two different players and two different ogg/theora streams...
	ffdshow has trouble playing this particular TH_ENCCTL_SET_VP3_COMPATIBLE file, without any TH_ENCCTL_SET_DUP_COUNT, for some odd reason since it plays other ogg/theora files with these properties just fine.  It plays the first little bit but quickly thinks it's reached the end of the file when it's really nowhere close...	VLC has no trouble playing this particular TH_ENCCTL_SET_VP3_COMPATIBLE file lacking any TH_ENCCTL_SET_DUP_COUNT.	ffdshow exhibits the strange green behavior I mentioned in my original post with both the TH_ENCCTL_SET_VP3_COMPATIBLE setting and with TH_ENCCTL_SET_DUP_COUNT applied to every frame, as you can see in the code.  All the timing works but the green is definitely a bug!	VLC can play the file with no green but it's obviously wrong about the timing.  It starts off with just black, then it sometimes plays smoothly, as if there are no duplicate frames, but occasionally pauses, way too long to simply be an additional frame, as was coded in the program.  It's as if it ignores the use of TH_ENCCTL_SET_DUP_COUNT until they pile up and it's forced to use them up all at once.
	Here's my sample program.  Like my previous sample program, it uses CxImage, so if you want to actually compile the program, I can create an include file with this image statically created in C++ syntax...	Thank you for your help!



#include <stdio.h>//#include <conio.h>#include <assert.h>
#include "CxImage\ximage.h"#include "theora\theoraenc.h"#include "theora\codec.h"

int const frame_rate = 30;//int const num_frames = frame_rate * 10;int const width = 320;int const height = 240;

int RoundTo16(int in) {	return (in + 15) / 16 * 16;}
unsigned 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);}
void WriteOggPage(FILE *file, ogg_stream_state *state, bool flush = false) {	while(true) {		ogg_page page;		int rc;		if( flush ) rc = ogg_stream_flush(  state, &page);		else        rc = ogg_stream_pageout(state, &page);
		if( rc == 0 ) {			break;
		} else {			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(width);			theora_input.frame_height = RoundTo16(height);			theora_input.pic_width = width;			theora_input.pic_height = height;			theora_input.pic_x = 0;			theora_input.pic_y = 0;			theora_input.colorspace = TH_CS_UNSPECIFIED;			theora_input.pixel_fmt = TH_PF_420;			theora_input.quality = 42;			theora_input.target_bitrate = 0;			theora_input.fps_numerator = frame_rate;			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 th_ctl = 5;			th_encode_ctl(theora_state, TH_ENCCTL_GET_SPLEVEL_MAX, &th_ctl, sizeof(th_ctl));			th_encode_ctl(theora_state, TH_ENCCTL_SET_SPLEVEL    , &th_ctl, sizeof(th_ctl));			th_ctl = 1;			// Strangely enough, pixel format TH_PF_420 doesn't seem to work without the TH_ENCCTL_SET_VP3_COMPATIBLE setting...			th_encode_ctl(theora_state, TH_ENCCTL_SET_VP3_COMPATIBLE, &th_ctl, sizeof(th_ctl));
			ogg_stream_state ogg_state;			ogg_stream_init(&ogg_state, 3001);  // Yeah, I know...
			FILE* output_file = fopen(output_filename, "wb");			ogg_packet packet;			bool go = true;
			th_comment comment;			th_comment_init(&comment); 			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}};				printf("Encoding video...\n");
				int num_frames = image.GetWidth() - width;				for(int i = 0; i < num_frames; i++) {
					// Fill the buffer with a pan of a small subset of the image so					// that we are encoding animation and not just a static image...					for(int j = 0; j < 3; j++) {						th_img_plane *plane = buffer + j;						if( j == 0 ) {							plane->width = theora_input.pic_width;							plane->height = theora_input.pic_height;						} else {							plane->width = theora_input.pic_width / 2;							plane->height = theora_input.pic_height / 2;						}						plane->stride = plane->width;						plane->data = new unsigned char[plane->width * plane->height];
						for(DWORD y = 0; y < height; y++) {							for(DWORD x = 0; x < width; x++) {								// the sum x + i creates our animation...								if( j == 0 )									plane->data[y * plane->stride     + x    ] = TransformPixel(tables[j], image.GetPixelColor(x + i, height - y, false));								else if( x % 2 == 0 && y % 2 == 0 )									plane->data[y * plane->stride / 2 + x / 2] = TransformPixel(tables[j], image.GetPixelColor(x + i, height - y, false));							}						}					}
					int dupes = 1;					th_encode_ctl(theora_state, TH_ENCCTL_SET_DUP_COUNT, &dupes, sizeof(dupes));					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;}
 		 	   		  
_________________________________________________________________
Introducing Windows® phone.
http://go.microsoft.com/?linkid=9708122
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.xiph.org/pipermail/theora-dev/attachments/20100218/0ddcec02/attachment-0001.htm 


More information about the theora-dev mailing list