Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm working on a piece of code which is able to read a frame from an AVI file and extract its pixel data. So far, I can succesfully open the AVI file and read any frame, but something goes wrong when decompressing.
This is the code I use (with error checking left out):

AVIFileInit();
PAVIFILE pf;
AVIFileOpen(&pf, filename, OF_READ, 0);
PAVISTREAM ps;
AVIFileGetStream(pf, &ps, streamtypeVIDEO, 0);
AVISTREAMINFO strhdr = {0};
AVIStreamInfo(ps, &strhdr, sizeof(strhdr));

BITMAPINFO *bi_in, bi_out;
long biSize = sizeof(bi_out);
AVIStreamReadFormat(ps, 0, 0, &biSize);
bi_in = (BITMAPINFO*)malloc(biSize+sizeof(bi_out.bmiColors));
bi_in->bmiHeader.biSize = biSize;
AVIStreamReadFormat(ps, 0, bi_in, &biSize);
bi_out = *bi_in;

HIC hic = 0;
// Check if the data is already in a recognised format (i.e. Uncompressed RGB or YUY2)
if(bi_in->bmiHeader.biCompression != 0 && bi_in->bmiHeader.biCompression != mmioFOURCC('Y','U','Y','2')){
	hic = ICDecompressOpen('CDIV', 0, &bi_in->bmiHeader, 0);

	biSize = ICDecompressGetFormat(hic, bi_in, &bi_out);
	
	// Check if the codec decompresses to YUY2 by default
	switch(bi_out.bmiHeader.biCompression){
		case mmioFOURCC('Y','U','Y','2'):
			bi_out.bmiHeader.biBitCount = 16;
			bi_out.bmiHeader.biSizeImage = 
				bi_out.bmiHeader.biWidth*bi_out.bmiHeader.biHeight*bi_out.bmiHeader.biBitCount/8;
			break;
		case 0:
			bi_out.bmiHeader.biBitCount = 24;
			bi_out.bmiHeader.biSizeImage =
				bi_out.bmiHeader.biWidth*bi_out.bmiHeader.biHeight*bi_out.bmiHeader.biBitCount/8;
			break;
		default:
			// Check if the codec is able to decompress to this format
			bi_out.bmiHeader.biCompression = mmioFOURCC('Y','U','Y','2');
			bi_out.bmiHeader.biBitCount = 16;
			bi_out.bmiHeader.biSizeImage =
				bi_out.bmiHeader.biWidth*bi_out.bmiHeader.biHeight*bi_out.bmiHeader.biBitCount/8;
			if(ICDecompressQuery(hic, &bi_in, &bi_out) != ICERR_OK)
				return 0;
	}
	ICDecompressBegin(hic,bi_in, &bi_out);
}

int in_buf_siz  = strhdr.dwSuggestedBufferSize;
int out_buf_siz = bi_out.bmiHeader.biSizeImage;
void *inbuf, *outbuf;
if(hic)
	inbuf = malloc(max(out_buf_siz,in_buf_siz));

// This is the buffer the pixels are going to be in
unsigned char *AVIbuffer = (unsigned char *)malloc(out_buf_siz);
if(hic)
	outbuf = AVIbuffer;
else
	inbuf  = AVIbuffer;

long size = 0;
AVIStreamRead(ps, frame-1, 1, inbuf, in_buf_siz, &size, 0);

// Decompress the data
if(hic){
	bi_in->bmiHeader.biSizeImage = size;
	ICDecompress(hic, 0, &bi_in->bmiHeader, inbuf, &bi_out.bmiHeader, outbuf);
}

// At this point, I access AVIbuffer to find the pixel values of the current frame (be it in RGB or YUY2).


The code succesfully reaches the end and doesn't give errors anywhere, but the pixel data isn't right. Occasionaly there is a good frame (like once every 300) and inbetween the frames are mostly empty (grey, with very low contrast, occasionaly with fragments of the pixel data).
The AVI files I have tried to decompress have 4CC's of DIV3, DX50 and XVID. I do have the correct codecs installed on my PC; Windows Media Player can read the AVI correctly.

Any tips on what to change would be highly appreciated.
Thanks in advance!
Posted
Comments
Henry Minute 14-Dec-10 13:36pm    
If you don't get a response after a reasonable time, it might be worth your while posting this in one of the more specific forums as a lot of the folks that follow there don't visit here. The Graphics forum, maybe (http://www.codeproject.com/Forums/387159/Graphics.aspx).

If you do that, mention that you have asked in Q&A but got no response, give it a few hours first though.
AspDotNetDev 14-Dec-10 13:39pm    
Don't worry, Henry, we look at the Q&A forums too :-)

1 solution

I didn't look at your code, but from what you describe I think I know the problem. You are probably decoding the keyframes correctly. The other frames are likely offset images that, when combined with the preceding frame, produce the result frame. Different formats have different strategies for the offset images... some do an alternating offset with each frame is offset from the frame 2 before it (for example). The file format you are working with probably stores this strategy, or the strategy used is described in the document describing the format.
 
Share this answer
 
Comments
[no name] 14-Dec-10 14:20pm    
Thanks for your fast reply, I think you're right about what the problem is.
I tried passing ICDECOMPRESS_NOTKEYFRAME as dwFlags argument of ICDecompress though, and it doesn't seem to have an effect. Should I do this differently?
AspDotNetDev 14-Dec-10 14:35pm    
Not really sure. I haven't worked with code like this before... I am only familiar with formats in general. Maybe you are supposed to combine the keyframes manually?
[no name] 14-Dec-10 15:11pm    
After some more testing, I think I've found the solution. ICDecompress can decompress these frames, I don't have to do it manually. It only works however, if it's done in order; so at least the previous key frame and all frames between that and the requested frame have to be processed.
Henry Minute 14-Dec-10 16:58pm    
Not all the 'experts' do. For example Luc rarely posts here.:))

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900