|
|
| General Lee D. Mented |
| Posted: Feb 11 2004, 08:03 AM |
 |
|
Unregistered

|
I've been doing some codec testing, and I'm not sure what's going on here.
Basicly during compress init, I see vdubmod goes into VideoSequenceCompressor::init(), and from there has a line like this:
lMaxPackedSize = ICCompressGetSize(hic, pbiInput, pbiOutput);
Now, I return a large value for this, usually at least several MB.
Later, when the system has finished init it goes to VideoSequenceCompressor::packFrame() and does this:
res = ICCompress(hic, dwFlagsIn, (LPBITMAPINFOHEADER)pbiOutput, pOutputBuffer, (LPBITMAPINFOHEADER)pbiInput, pBits, &dwChunkId, &dwFlags, lFrameNum, lFrameNum ? lAllowableFrameSize : 0xFFFFFF, lQuality, dwFlagsIn & ICCOMPRESS_KEYFRAME ? NULL : (LPBITMAPINFOHEADER)pbiInput, dwFlagsIn & ICCOMPRESS_KEYFRAME ? NULL : pPrevBuffer);
However, during this function call, the data buffer size I get in lpbiOutput->biSizeImage is much smaller than what I returned for the max frame size.
Is the system allocating the size specified and just reporting the size wrong? Or is it allocating the buffer wrong? I thought I was supposed to get an output buffer of the maximum size I specified and then indicate the actual size by writing it back to that output size field every frame.
It also looks like the wrong value is also getting used in vdubmod's source a few lines before ICCompress is called:
sizeImage = pbiOutput->bmiHeader.biSizeImage;
|
 |
| phaeron |
| Posted: Feb 11 2004, 09:28 AM |
 |
|

Virtualdub Developer
  
Group: Administrator
Posts: 7773
Member No.: 61
Joined: 30-July 02

|
Nope.
A VFW codec is required to set lpbiOutput->biSizeImage on exit from ICM_COMPRESS with the size of the compressed frame. What VirtualDub does is as follows:
1) Save off the value of lpbiOutput->biSizeImage (the sizeImage assignment you refer to). 2) Call the codec to compress one frame. 3) Stash the compressed frame size from lpbiOutput->biSizeImage. 4) Restore lpbiOutput->biSizeImage to its original value from sizeImage.
Thus, when running under VirtualDub, the codec always sees the biSizeImage value that it originally produced from ICM_COMPRESS_GET_FORMAT, not the value of ICM_COMPRESS_GET_SIZE. And indeed, if lpbiOutput->biSizeImage specified the maximum frame size, ICM_COMPRESS_GET_SIZE would be redundant. As it turns out, lpbiOutput->biSizeImage not only doesn't specify the output buffer size on entry to ICM_COMPRESS, but it doesn't specify any useful value at all. The ICSeqCompressFrame*() APIs don't rewrite lpbiOutput->biSizeImage every frame, and so what you get on entry is the last value you wrote into it, the previous frame's compressed size.
You should simply assume that your output buffer is the size that you returned from ICM_COMPRESS_GET_SIZE. Oh, and by the way, don't lie from this message. Huffyuv 2.1.1 returns a value that is "good enough" for its max size... that sometimes isn't good enough if you have a pathological case, and causes the compressor to trash memory. VirtualDub has to explicitly work around this bug. If you return 100K for MAX_SIZE, then you'd better make sure your codec never writes a single byte over 100K.
|
 |
| General Lee D. Mented |
| Posted: Feb 11 2004, 09:59 AM |
 |
|
Unregistered

|
Well that certainly explains the brain damaged behavior I was seeing earlier where it was creating a codec, configuring it, compressing one frame, and then destroying it, then creating another codec. This was driving me nuts because the 2nd time around it wasn't configured anymore so I had null pointers all over the place. So now I have to allocate a ton of space for configuring at least twice so one frame can be decompressed first. Woo.
I was aware of the need to set the image size on exit from ICM_COMPRESS, which was the entire point. The size I need to set is larger than the one that's coming in, and I didn't want to just start writing data off into unallocated memory.
So, how do I know that this particular call to the codec to compress one frame needs to get the maximum possible compressed size? I mean it looks like just another compress call from the codec's view, right? You say don't lie about it but how do I know when it's being asked? If I just start compressing I'm going to generate a result that's very unlikely to be the maximum possible size.
Also, where exactly is it stashing this value as indicated in #3 and for what use?
Also "The ICSeqCompressFrame*() APIs don't rewrite lpbiOutput->biSizeImage every frame, and so what you get on entry is the last value you wrote into it, the previous frame's compressed size." is a serious problem when your frame sizes vary by 10 orders of magnitude and are not predictable in advance as they depend on the input data. Unless it's just the number being saved but the actual memory is still there to be used.
I'm well familliar with the huffyuv case, I read the comments about it and I've seen the huffyuv source way too often. I'm 100% sure I'll never write more than the size of an uncompressed frame * the number of frames in the transform block * the number of bytes of precision to use per sample * 2 for RLE expansion worst case. |
 |
| General Lee D. Mented |
| Posted: Feb 11 2004, 07:01 PM |
 |
|
Unregistered

|
Didn't work.
On compress side, it seems ok, I get this result:
Dub/Main: Start. Compressed frame 0: 691200 bytes
On decompress side, I get the following:
VideoSourceAVI: decompressing frame 0 First-chance exception at 0x01795a53 (WARPcore.dll) in VirtualDubMod.exe: 0xC0000005: Access violation reading location 0x010ac000. Unhandled exception at 0x01795a53 (WARPcore.dll) in VirtualDubMod.exe: 0xC0000005: Access violation reading location 0x010ac000.
Now, looking into debug:
lParam1->lpbiInput->biSizeImage = 230400. Where did the 691200 go?
In the actual function in the codec, the byte it's trying to read that's causing the access violation is 311296. The reported size from the getsize function was 29491200.
What's going on? |
 |
| phaeron |
| Posted: Feb 12 2004, 06:19 AM |
 |
|

Virtualdub Developer
  
Group: Administrator
Posts: 7773
Member No.: 61
Joined: 30-July 02

|
Okay, let's take this one step at a time.
- Your codec needs to be reentrant. That is, I should be able to open two codec instances at the same time, and compress simultaneously with both, or decompress simultaneously with both, or compress with one and decompress with the other. Dynamically allocate your structures.
- The application sends you ICM_COMPRESS_GET_SIZE so it can figure out how much memory to allocate for the compression buffer. This is where you say "I need 10MB because I could in theory make a frame that big for the input format you just gave me."
- lpbiOutput->biSizeImage means nothing when you get called with ICM_COMPRESS. It can be anything. Just assume that the host already called ICM_COMPRESS_GET_SIZE to ask you what buffer size is required for the video it's compressing, and that it's giving you a buffer at least that large.
- VirtualDub uses the value of lpbiOutput->biSizeImage that you return from ICM_COMPRESS so it knows how much data from the buffer to write to disk as a frame. Where it stashes that value is irrelevant (it goes somewhere on the stack... whoopee).
- The biSizeImage field that is written to disk in the AVI format is not related to any particular frame -- it is the value that you specified when ICM_COMPRESS_GET_FORMAT was sent. So presumably, you set biSizeImage to 230400 when you gave back the output format for the provided input format.
- Dump the AVI file and check what the size of the frame on disk is. VirtualDub's hex editor will do this if you request the RIFF tree (Ctrl-R).
|
 |
| General Lee D. Mented |
| Posted: Feb 12 2004, 07:01 AM |
 |
|
Unregistered

|
| QUOTE (phaeron @ Feb 12 2004, 12:19 AM) | Okay, let's take this one step at a time.
- Your codec needs to be reentrant. That is, I should be able to open two codec instances at the same time, and compress simultaneously with both, or decompress simultaneously with both, or compress with one and decompress with the other. Dynamically allocate your structures.
- The application sends you ICM_COMPRESS_GET_SIZE so it can figure out how much memory to allocate for the compression buffer. This is where you say "I need 10MB because I could in theory make a frame that big for the input format you just gave me."
- lpbiOutput->biSizeImage means nothing when you get called with ICM_COMPRESS. It can be anything. Just assume that the host already called ICM_COMPRESS_GET_SIZE to ask you what buffer size is required for the video it's compressing, and that it's giving you a buffer at least that large.
- VirtualDub uses the value of lpbiOutput->biSizeImage that you return from ICM_COMPRESS so it knows how much data from the buffer to write to disk as a frame. Where it stashes that value is irrelevant (it goes somewhere on the stack... whoopee).
- The biSizeImage field that is written to disk in the AVI format is not related to any particular frame -- it is the value that you specified when ICM_COMPRESS_GET_FORMAT was sent. So presumably, you set biSizeImage to 230400 when you gave back the output format for the provided input format.
- Dump the AVI file and check what the size of the frame on disk is. VirtualDub's hex editor will do this if you request the RIFF tree (Ctrl-R).
|
Ok then, let's respond 1 at a time.
1. I do dynamically allocate the structures, the problem was I had it only reading the config in decompress_get_format, instead of also in decompress_begin where I init all the structures. So, after the first instance was destroyed there was no config info anymore because the second codec never got a decompress_get_format. Fixed now.
2. ICM_COMPRESS_GET_SIZE has always been returing the correct value.
3. I'm not worried about lpbiOutput->biSizeImage on ICM_COMPRESS, I'm worried about lpbi-Input->biSizeImage on ICM_DECOMPRESS. It's NOT the value I set in lpbiOutput->biSizeImage on ICM_COMPRESS and it's NOT the same as the value virtualdub's debug is outputting during compress. Media player 6.4 does not exhibit this problem, so what's going on?
4. Yes I know this, I've always been setting it and virtualdub is reporting correct results on compress.
5. Ok, I think this is the problem then. I thought it would get the value from ICM_COMPRESS_GET_SIZE and write THAT value to disk. You're saying it writes whatever's in lpOutput->lpbiSizeImage in ICM_COMPRESS_GET_FORMAT. That's most likely not set right then, and I'll go look into it next.
6. I did, the frame size is 691200. |
 |
|