View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000062 | JVT JM H.264/AVC reference software | decoder | public | 2007-07-06 04:35 | 2011-11-15 21:54 |
Reporter | Peter Farkas | Assigned To | Karsten Suehring | ||
Priority | normal | Severity | major | Reproducibility | always |
Status | assigned | Resolution | open | ||
Product Version | JM 12.2 | ||||
Target Version | JM 18.2 | ||||
Summary | 0000062: while loops in ldecod.c and image.c do not behave as expected | ||||
Description | This may not be a bug strictly speaking, since the decoding seems to be performed correctly. However, the program does not behave as one would expect it to behave. I suspect that this is not the intended behaviour. If it is, then the program should be changed, since the way it stands now is misleading. Or else, an explanation should be provided. Specificly, I am looking at the loops while (decode_one_frame(img, input, snr) != EOS) ; in ldecod.c, and int decode_one_frame(...) { . . . . . . . . while ((currSlice->next_header != EOS && currSlice->next_header != SOP)) { . . . . . . . } exit_picture(); return (SOP); } in image.c. One would think that each call to decode_one_frame would decode one frame, untill EOS is reached, and passes through the body inside the loop in decode_one_frame would decode one frame after which execution returns to the caller. However, this is not the case. In reality, decode_one_frame is called only once, and the loop inside decode_one_frame does the decoding of all the frames. Indeed, currSlice->next_header never equals SOP. This can be easily seen with a debugger, or by inserting some print statements. I modified the loops in the following way: int status = 4444; while (status != EOS) { printf("in loop in ldecod.c, counter1 = %d\n", counter1++); status = decode_one_frame(img, input, snr); } for the loop in in ldecod.c, and while ((currSlice->next_header != EOS && currSlice->next_header != SOP)) { printf( "beginning of loop in image.c, counter2 = %d " "currSlice->next_header = %d\n", counter2, currSlice->next_header); . . . . . . . . printf( "end of loop in image.c, counter2 = %d " "currSlice->next_header = %d\n", counter2++, currSlice->next_header); } for the loop in in image.c (with the necessary declarations, of course). The output (to stdout) looks like this: . . . . . . . . in loop in ldecod.c, counter1 = 0 beginning of loop in image.c, counter2 = 0 currSlice->next_header = -8888 0000(I) 0 0 28 0.0000 0.0000 0.0000 4:2:0 42 end of loop in image.c, counter2 = 0 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 1 currSlice->next_header = -8888 0000(P) 2 1 28 0.0000 0.0000 0.0000 4:2:0 14 0000(P) 4 2 28 0.0000 0.0000 0.0000 4:2:0 18 end of loop in image.c, counter2 = 1 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 2 currSlice->next_header = -8888 0000(P) 6 3 28 0.0000 0.0000 0.0000 4:2:0 12 0000(P) 8 4 28 0.0000 0.0000 0.0000 4:2:0 18 end of loop in image.c, counter2 = 2 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 3 currSlice->next_header = -8888 0000(P) 10 5 28 0.0000 0.0000 0.0000 4:2:0 12 0000(P) 12 6 28 0.0000 0.0000 0.0000 4:2:0 17 end of loop in image.c, counter2 = 3 currSlice->next_header = -8888 . . . . . . . . beginning of loop in image.c, counter2 = 148 currSlice->next_header = -8888 0000(P) 590 7 28 0.0000 0.0000 0.0000 4:2:0 13 0000(P) 592 8 28 0.0000 0.0000 0.0000 4:2:0 17 end of loop in image.c, counter2 = 148 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 149 currSlice->next_header = -8888 0000(P) 594 9 28 0.0000 0.0000 0.0000 4:2:0 13 0000(P) 596 10 28 0.0000 0.0000 0.0000 4:2:0 16 end of loop in image.c, counter2 = 149 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 150 currSlice->next_header = -8888 0000(P) 598 11 28 0.0000 0.0000 0.0000 4:2:0 13 . . . . . . . . I conclude that there is only one call to decode_one_frame, and that two frames are decoded per pass through the body of the loop in decode_one_frame. Here is another argument to support my point: We can search for next_header in the full program, and we see that it is never set. Indeed, "grep next_header *" yields image.c: currSlice->next_header = -8888; // initialized to an impossible value for debugging -- correct value is taken from slice header image.c: while ((currSlice->next_header != EOS && currSlice->next_header != SOP)) I suspect that to make the code work as expected, currSlice->next_header would need to be set someplace, for example in exit_macroblock before returning TRUE. | ||||
Additional Information | The compilation and run was done on an UltraSPARC III+ system, with Solaris 9, and using a version of the gcc compiler. I marked the severity as major because this issue gives the impression that the decoder's architecture is not well thought out, or that the code is not behaving according to the architectural plan. One could suspect that maybe the version of foreman_qcif.264 I used is somehow corrupted. This is probably not the case. The same behaviour can be seen with many other streams, in particular with the stream test.264 I created by using lencod.exe, encoder_baseline.cfg and foreman_part_qcif.yuv which come with the JM_12.2 package. | ||||
Tags | No tags attached. | ||||
duplicate of | 0000035 | closed | Karsten Suehring | decode_one_frame() now decodes all frames! |
parent of | 0000189 | confirmed | Karsten Suehring | Crash in JM 16.1 Decoder |
parent of | 0000087 | confirmed | Karsten Suehring | decoder quits when partitions are missing (duplicate frame_num in short term ...) |
parent of | 0000140 | acknowledged | Lossy DP videos fail to decode. | |
related to | 0000250 | confirmed | "Warning: RTP sequence number discontinuity detected" | |
Not all the children of this issue are yet resolved or closed. |
|
I am very sorry, because of a cut and paste error, there are some inaccuracies in my report. The essence of the bug report stands as stated, however, there is an error in the details. I said that "two frames are decoded per pass through the body of the loop in decode_one_frame". This is not true. Only one frame is decoded per pass through the body of the loop. The output (to stdout) I gave in the report is wrong. The corrected output (which exhibits the problem I reported) is: . . . . . . . . in loop in ldecod.c, counter1 = 0 beginning of loop in image.c, counter2 = 0 currSlice->next_header = -8888 end of loop in image.c, counter2 = 0 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 1 currSlice->next_header = -8888 0000(I) 0 0 28 0.0000 0.0000 0.0000 4:2:0 42 end of loop in image.c, counter2 = 1 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 2 currSlice->next_header = -8888 0000(P) 2 1 28 0.0000 0.0000 0.0000 4:2:0 17 end of loop in image.c, counter2 = 2 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 3 currSlice->next_header = -8888 0000(P) 4 2 28 0.0000 0.0000 0.0000 4:2:0 17 end of loop in image.c, counter2 = 3 currSlice->next_header = -8888 . . . . . . . . beginning of loop in image.c, counter2 = 298 currSlice->next_header = -8888 0000(P) 594 9 28 0.0000 0.0000 0.0000 4:2:0 17 end of loop in image.c, counter2 = 298 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 299 currSlice->next_header = -8888 0000(P) 596 10 28 0.0000 0.0000 0.0000 4:2:0 17 end of loop in image.c, counter2 = 299 currSlice->next_header = -8888 beginning of loop in image.c, counter2 = 300 currSlice->next_header = -8888 0000(P) 598 11 28 0.0000 0.0000 0.0000 4:2:0 15 . . . . . . . . Again, sorry about the confusion caused by my error, I am very embarassed, and I apologize. The fact still remains that the looping is done not in main in ldecod.c, but in decode_one_frame in image.c. |
|
Here is a change in the code which works in some cases: In the function exit_macroblock in macroblock.c I changed img->num_dec_mb++; if (img->num_dec_mb == img->PicSizeInMbs) { return TRUE; } // ask for last mb in the slice UVLC else . . . . . . . . (at the beginning of the function) to img->num_dec_mb++; if (img->num_dec_mb == img->PicSizeInMbs) { Slice *currSlice = img->currentSlice; if (currSlice->next_header != EOS) currSlice->next_header = SOP; return TRUE; } // ask for last mb in the slice UVLC else . . . . . . . . I don't know whether this fix is good in general, but makes things work as expected in some cases I tried. |
|
It's known behavior for many (really many) versions now. I planned to restructure the main decoding loop, but didn't have time yet. |
|
This strange decode_one_frame() logic also appears to be the cause of decoder's failure to decode bit streams in which the frame sizes change. Since decode_one_frame() never exits img->num_dec_mb never gets reset to zero. This causes the logic in exit_macroblock() to fail if the frame size changes. For example, if the initial frame size is CIF (22 x 18 macroblocks) then img->PicSizeInMbs will initially be 396 macroblocks. When the first frame has been decoded img->num_dec_mb will also be 396 macroblocks If the frame size changes to VGA (40 x 30 macroblocks) on the second frame then img->PicSizeInMbs will be updated to be 1200 macroblocks. However img->num_dec_mb will not be reset to zero. Consequently in exit_macroblock() the logic: if (img->num_dec_mb == img->PicSizeInMbs) { return TRUE; } will return TRUE on the 804th (1200 – 396) macroblock of the second frame. This results in a decode failure. |
|
I already have re-enabled a reset for num_dec_mb in the init_picture() funtion in my development tree. Based on the standard text there is actually no rule to detect the beginning of a new picture based on the number of macroblocks. This is purely done based on syntax elements in the slice header. So we might be adding some logic here that allow the decoder to process streams that are actually not compliant to the spec (i.e. streams with incorrect header syntax elements). The situation gets even more complicated when we think about streams with errors... |
Date Modified | Username | Field | Change |
---|---|---|---|
2007-07-06 04:35 | Peter Farkas | New Issue | |
2007-07-06 21:07 | Peter Farkas | Note Added: 0000080 | |
2007-07-06 21:11 | Peter Farkas | Note Edited: 0000080 | |
2007-07-08 00:46 | Peter Farkas | Note Added: 0000081 | |
2007-07-08 21:32 | Karsten Suehring | Relationship added | duplicate of 0000035 |
2007-07-08 21:35 | Karsten Suehring | Note Added: 0000082 | |
2007-07-08 21:35 | Karsten Suehring | Status | new => acknowledged |
2007-08-08 15:04 | Karsten Suehring | Status | acknowledged => assigned |
2007-08-08 15:04 | Karsten Suehring | Assigned To | => Karsten Suehring |
2008-05-29 09:20 | Eamon O'Dea | Note Added: 0000197 | |
2008-06-02 11:01 | Karsten Suehring | Note Added: 0000204 | |
2011-04-06 15:45 | Karsten Suehring | Relationship added | related to 0000250 |
2011-04-14 15:28 | Karsten Suehring | Relationship added | parent of 0000189 |
2011-05-18 15:43 | Karsten Suehring | Target Version | => JM 18.1 |
2011-05-19 13:37 | Karsten Suehring | Relationship added | parent of 0000087 |
2011-05-21 11:10 | Karsten Suehring | Relationship added | parent of 0000140 |
2011-11-15 21:54 | Karsten Suehring | Target Version | JM 18.1 => JM 18.2 |