[FFmpeg-devel] [PATCH] png parser
Peter Holik
peter
Wed Jun 24 17:54:17 CEST 2009
Michael Niedermayer schrieb:
> On Tue, Jun 23, 2009 at 08:51:12AM +0200, Peter Holik wrote:
>> Michael Niedermayer schrieb:
> [...]
>
>> +static int png_parse(AVCodecParserContext *s, AVCodecContext *avctx,
>> + const uint8_t **poutbuf, int *poutbuf_size,
>> + const uint8_t *buf, int buf_size)
>> +{
>> + PNGParseContext *ppc = s->priv_data;
>> + uint32_t *state_ptr;
>> + int next = END_NOT_FOUND;
>> + int i = 0;
>> +
>> + *poutbuf_size = 0;
>> + if (buf_size == 0)
>> + return 0;
>> +
>> + if (!ppc->pc.frame_start_found) {
>> + uint64_t *state64_ptr = &ppc->pc.state64;
>> +
>> + for (; i < buf_size; i++) {
>> + *state64_ptr = (*state64_ptr << 8) | buf[i];
>
> using a local state64 likely is faster than the repeated pointer deref
> i suspect gcc fails to do that optim itself ...
done.
>> + if (*state64_ptr == PNGSIG || *state64_ptr == MNGSIG) {
>> + i++;
>> + if (ppc->pc.index) {
>> + i -= 8;
>> + next = i;
>> + } else {
>> + ppc->pc.frame_start_found = 1;
>> + ppc->chunk_index = 1;
>> + if (i == 8)
>> + break;
>> + else if (i > 8) {
>> + buf += i - 8;
>> + buf_size = 8;
>> + } else /* if (i < 8) */
>> + buf_size = i;
>> + }
>> + ff_combine_frame(&ppc->pc, next, &buf, &buf_size);
>> + return i;
>
> could you explain why this is not just looking like lets say mpeg4:
>
> if(!vop_found){
> for(i=0; i<buf_size; i++){
> state= (state<<8) | buf[i];
> if(state == 0x1B6){
> i++;
> vop_found=1;
> break;
> }
> }
> }
png signature is 8 Bytes
> what is the point of all the special cases?
Because this png parser should filter out good png images.
1. Case
Usually you get a buf starting with a png signature, therefor "i" would be 8
and i skip any special handling.
2. Case
There are some headerbytes at the beginning, that i will drop:
else if (i > 8) {
buf += i - 8;
buf_size = 8;
ff_combine_frame(&ppc->pc, next, &buf, &buf_size);
return i;
here i copy the read signature into my buffer with ff_combine_frame
(and modified buf to start from signature start)
3. Case
The signature starts in the next buf:
the first buf is copied to my buffer with ff_combine_frame
for the next one i know it - ppc->pc.index != NULL
if (ppc->pc.index) {
i -= 8;
next = i;
ff_combine_frame(&ppc->pc, next, &buf, &buf_size);
return i;
and finish my buffer and return, that i have read till to the start of png signature
the next time png_parse is called with a buf starting with a png signature
like 1. Case
4. Case
The signature ends in the next buf and starts in the first buf:
the first buf is copied to my buffer with ff_combine_frame
for the next one i know it - ppc->pc.index != NULL
if (ppc->pc.index) {
i -= 8;
next = i;
ff_combine_frame(&ppc->pc, next, &buf, &buf_size);
return i;
But now "next is NEGATIVE"!
i finish my buffer with ff_combine_frame and return a minus value
(that is set to 0 in av_parser_parse2)
now the magic of "ff_combine_frame" - a negative next means "overread"
ff_combine_frame does
for(;next < 0; next++) pc->overread++;
next time png_parse is called with the same buf and "i" would be < 8
} else /* if (i < 8) */
buf_size = i;
ff_combine_frame(&ppc->pc, next, &buf, &buf_size);
return i;
this time ff_combine_frame fills my buffer with parts of the overread png signature
/* Copy overread bytes from last frame into buffer. */
for(; pc->overread>0; pc->overread--){
pc->buffer[pc->index++]= pc->buffer[pc->overread_index++];
}
and copies the rest of the signature into my buffer.
next time png_parse is called buf starts after the png signature
cu Peter
-------------- next part --------------
A non-text attachment was scrubbed...
Name: png_parser.diff
Type: text/x-diff
Size: 5779 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090624/bc91c45e/attachment.diff>
More information about the ffmpeg-devel
mailing list