Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C++ C Multimedia
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 14-Dec-10 8:25am
Comments
Henry Minute at 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 at 14-Dec-10 13:39pm
   
Don't worry, Henry, we look at the Q&A forums too :-)

1 solution

Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

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.
  Permalink  
Comments
Henry Minute at 14-Dec-10 16:58pm
   
Not all the 'experts' do. For example Luc rarely posts here.:))
Thaddeus Jones at 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 at 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?
Thaddeus Jones at 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.

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

  Print Answers RSS
0 OriginalGriff 245
1 Jochen Arndt 155
2 PIEBALDconsult 150
3 Afzaal Ahmad Zeeshan 120
4 DamithSL 115
0 OriginalGriff 5,695
1 DamithSL 4,591
2 Maciej Los 4,012
3 Kornfeld Eliyahu Peter 3,480
4 Sergey Alexandrovich Kryukov 3,190


Advertise | Privacy | Mobile
Web01 | 2.8.141220.1 | Last Updated 14 Dec 2010
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100