[FFmpeg-devel] [PATCH] correct MPEG video parser not to return incomplete frames

Michael Niedermayer michaelni
Thu Sep 10 05:57:41 CEST 2009


On Sun, Sep 06, 2009 at 05:33:34PM +0200, Ivan Schreter wrote:
> Michael Niedermayer wrote:
>> [...]
>>>> Also the mpeg demuxer returns random trash prior to the first frame, 
>>>> this IS
>>>> a bug in your seeking code. Fix it please! And before you start arguing 
>>>> about
>>>> how unlikely it would cause a problem in mpeg video, it will cause 
>>>> problems
>>>> in mpeg audio as well.
>>>>         
>>> I don't understand what random trash is returned from MPEG demuxer prior 
>>> to first frame. Also, I don't understand why the seeking code should be 
>>> causing this, since it positions the file to start reading at the packet 
>>> with start of a frame. Old seeking code didn't do it differently...
>>>
>>> How can I reproduce the problem? With which sample file?
>>>     
>>
>> any mpeg-ps file created with ffmpeg
>>   
>
> Okaaay... My seeking patches were only applied to mpeg-TS (transport 
> stream). I did no change to mpeg-PS (program stream) yet. So it's 
> DEFINITELY not a bug in my seeking code, as it's not even active there! I 
> wanted to fix the parser first, before activating it there.

the issue applies to TS as much as PS i just havnt checked if TS files
generated by ffmpeg could trigger it, i think that at least in the past
ffmegs TS muxer did not support putting frames over PES packet boundaries


[...]

>> To make it even more clear what the problem is, look at this example, the 
>> seeking code seeks to packet 5, with the expectation that the decoder
>> will decode the first frame in there but there is a startcode emulation
>> in the previous partial frame causing the decoder not only to return noise
>> but also to miss the first complete frame. The only way for the decoder to
>> avoid this is to drop the first few frames but if it does, it starts 
>> decoding
>> later than when the seeking code expects.
>> Its the seeking code that should start a little earlier and discard data
>> to make sure synchronization of frame boundaries did happen
>>   
>
> OK. But the question is, how much earlier? Theoretically, we could have 
> such a bad file, where we can possibly never synchronize, or am I mistaken? 

i belive that you are correct. Its pretty unlikely unless such a file is
created intentionally though


> I'll have to look in the standard for details.
>
>> its what i suggested already previously for fixing the video corner cases
>>   
>
> To which thread/post are you referring?
>
>>>> The goal of the seeking code is to be exact, if now the first frame can 
>>>> be
>>>> invalid without this being detectable the decoder or parser would have 
>>>> to
>>>> discard it and this would break exactness
>>>>         
>>> I agree with you. But again, the parser has to somehow detect the broken 
>>> non-frame. And you disagree with detection of non-frame by detecting 
>>> missing picture start code and slice start code (concretely, for MPEG 
>>> video). So how am I supposed to detect such non-frame, so I can 
>>> initialize AVStream.initial_bytes_to_discard?
>>>     
>>
>> you start a frame or 2 earlier and throw them away, with each the 
>> probability
>> of being off drops
>>   
>
> This basically answers my question above. So you just want to reduce the 
> probability. I.e., I could do it in this way in the ff_gen_syncpoint_search 
> routine:
>
>    * Back off to position X.
>    * Start reading frames from this position and for each stream count
>      number of parsed frames.
>    * When at least 2 frames have been read, only then actually consider
>      the frame for further processing (keyframe detection, timestamp
>      comparison and the like).
>    * Exception: We are already at position 0 in the file (then, it's
>      equivalent starting playing from the beginning, so no frames
>      should be ignored).

this sounds approximately what i had in mind, yes


>
>
> Further, the parser needs to be enhanced to somehow store in-packet 
> position of the frame, so AVStream.initial_bytes_to_discard can be 
> implemented. I suppose, frame start offset in packet can be handled in 
> similar manner as cur_frame_pos. Right?

iam not sure if this is needed, but if it is then yes


>
>>
>>   
>>>> [...]
>>>>         
>>>>>> [...]
>>>>>> IIRC our parser misassociates a timestamp in the partial frame case, 
>>>>>> this
>>>>>> has to be fixed _first_. I am against adding new features on top of 
>>>>>> known
>>>>>> bugs.
>>>>>>                   
>>>>> I looked at the code in mpegvideo_parse() and 
>>>>> ff_mpeg1_find_frame_end(). To me, it seems like 
>>>>> ff_mpeg1_find_frame_end() misassociates the timestamp. Namely, the 
>>>>> timestamp is fetched there, but actually the _previous_ frame (or in 
>>>>> this case, a non-frame) is returned from the parsing routine.
>>>>>
>>>>> I'm not sure how to fix this, though. Possibly, instead of fetching the 
>>>>> timestamp in ff_mpeg1_find_frame_end(), it should be done in this way:
>>>>>
>>>>>             
>>>>         
>>>>>    * If the frame starts at offset 0 in the PES packet AND we don't
>>>>>      have anything in the buffer, then fetch the timestamp.
>>>>>             
>>>> sounds like another one of your not always working hacks
>>>>         
>>> Grrrr....
>>>
>>> Man, I'm trying to help! Instead of bashing, make a proposal how to do 
>>> it!
>>>     
>>
>> iam not sure how to implement all the stuff down to the finest detail 
>> without
>> new issues poping up, but iam sure you take this too serious ...
>>
>> the first partial frame has no pic startcode, it cant otherwise it would 
>> be
>> the correct target for the timestamp so  why is our parser associateing 
>> the timestamo with it? ive not had time to look at the actual code more
>> carefully sadly ...
>> The timestamp association rules are quite clear in mpeg, the parser really
>> should not need any black magic to get it right even if it doesnt know if 
>> the
>> first part is a complete frame or not.
>>   
>
> As I understand it, if a packet contains some data with a start code in 
> there, the data before startcode is part of previous frame and the frame 
> with its data starting at the first startcode should get the timestamp 
> specified in this packet.
>
> MPEG video parser fetches the timestamp when finding the new start code. 
> Data before the start code are added to the buffer containing previous 
> frame. This previous frame is returned in this call of the parser, since it 
> has been completely read. But the parser's timestamp is already fetched. So 
> the previous frame will get the timestamp. Next frame just beginning in the 
> packet will not get the correct timestamp.
>
> If the start code is at position 0 in the packet, then the frame will get 
> the correct timestamp.
>
> I suppose, timestamp fetching must be instead postponed by remembering the 
> position of the start code in the file and fetching the timestamp when the 
> buffer is completed instead. I.e., instead of fetching the timestamp in 
> ff_mpeg1_find_frame_end() we'd just store the position on parser context 
> there and fetch the timestamp in mpegvideo_parse() associated with this 
> position just before returning the new frame back. Would you agree with 
> this?
>

> I'm just unsure, how long the association of timestamps with positions is 
> kept in lavf. Possibly, this buffer overflows before the packet is 
> completely constructed, so the timestamp has to be fetched earlier (in the 
> next parser call after returning previous frame).

the buffer can overflow quite quickly in theory, the timestamps thus must
be processed pretty much immedeatly, handling them at the end of a video
frame is not guranteed to work

also the issue with startcode emulation doesnt exist for mpeg1/2 video
just for some audio codecs 


>
> My first patch for mpegvideo_parser.c was incorrect, since it only corrects 
> associating the first timestamp of the first frame by discarding the 
> non-frame at the beginning of the packet. But the remaining frames will 
> also get wrong timestamps, if I see it correctly.
>
>>
>>   
>>> I'm again at the point of simply giving up and investing my limited time 
>>> into something else, where people value the contribution a bit more...
>>>     
>>
>> your contribution is valued but implementing this is not a trivial task 
>> and
>> writing a functioning implementation does take time, you seem to expect 
>> that
>> a quick implementation would fully work
>>   
>
> No. I'm just expecting constructive criticism instead of bashing.
>
> I simply find comments like "sounds like another one of your not always 
> working hacks" or "is complete nonsense" insulting and inappropriate, 
> especially if no constructive criticism follows.

its sometimes hard to provide constructive criticism when one has little
time and the issue at hand is complex.

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Freedom in capitalist society always remains about the same as it was in
ancient Greek republics: Freedom for slave owners. -- Vladimir Lenin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090910/0d73e7d1/attachment.pgp>



More information about the ffmpeg-devel mailing list