[Ffmpeg-devel] tiff encoder (qualification task for GSoC)

Bartlomiej Wolowiec b.wolowiec
Sat Mar 31 12:20:46 CEST 2007


On Friday 30 March 2007 23:09, Michael Niedermayer wrote:
> no, the code is much more complex than needed, there are many ways this
> can be implemeneted, one is to reserve space for the IFD and write
> everything immedeatly, this will need 2 lines of code to calculate the IFD
> size
> another is to store data immedeatly and store the IFD in a seperate array
> like s->entries (but not in this odd custom format) then at the end just
> memcpy it to its final place

Ok, I have chosen second option. 

> > +/// Array containing the number of bytes of luma corresponding to
> > chrominance +static const int YUV_Y[PIX_FMT_NB] = {
> > +    [PIX_FMT_YUV411P] = 4,
> > +    [PIX_FMT_YUV422P] = 2,
> > +    [PIX_FMT_YUV444P] = 1,
> > +};
> > +
> > +/// Horizontal subsampling
> > +static const int YUV_SUBSAMPLING_HORIZ[PIX_FMT_NB] = {
> > +    [PIX_FMT_YUV411P] = 4,
> > +    [PIX_FMT_YUV422P] = 2,
> > +    [PIX_FMT_YUV444P] = 1,
> > +};
> > +
> > +/// Vertical subsampling
> > +static const int YUV_SUBSAMPLING_VERT[PIX_FMT_NB] = {
> > +    [PIX_FMT_YUV411P] = 1,
> > +    [PIX_FMT_YUV422P] = 1,
> > +    [PIX_FMT_YUV444P] = 1,
> > +};
>
> duplicate table, int8_t is enough for them, no need to waste
> PIX_FMT_NB*sizeof(int) space
>
> PIX_FMT_YUV420P is missing
>
> see avcodec_get_chroma_sub_sample()
>

Ok, I have removed these tables from code.

> > +
> > +/**
> > + * Put n values to buffer
> > + *
> > + * @param p Pointer to pointer to output buffer
> > + * @param n Number of values
> > + * @param val Pointer to values
> > + * @param type type of values
> > + */
> > +static void tnput(uint8_t ** p, int n, uint8_t * val, enum TiffTypes
> > type) +{
> > +    int i;
> > +    for (i = 0; i < n; i++) {
> > +        switch (type) {
> > +        case TIFF_STRING:
> > +        case TIFF_BYTE:
> > +            bytestream_put_byte(p, *val);
> > +            val++;
> > +            break;
> > +        case TIFF_SHORT:
> > +            bytestream_put_le16(p, *((uint16_t *) val));
> > +            val += 2;
> > +            break;
> > +        case TIFF_LONG:
> > +            bytestream_put_le32(p, *((uint32_t *) val));
> > +            val += 4;
> > +            break;
> > +        case TIFF_RATIONAL:
> > +            bytestream_put_le32(p, *((uint32_t *) val));
> > +            val += 4;
> > +            bytestream_put_le32(p, *((uint32_t *) val));
> > +            val += 4;
> > +            break;
> > +        default:
> > +            assert(0 && "not implemented");
> > +        }
> > +    }
> > +}
>
> this function can easily be implemented in a quarter of the code

hmm.. I remove val+=, but I don't know how can I simplify it more.

>
>
> [...]
>
> > +            //reverse (LE)
> > +            for (i = 0; i < entry->count / 2; i++) {
> > +                for (j = 0; j < ts; j++) {
> > +                    tmp = *(ptr + i * ts + j);
> > +                    *(ptr + i * ts + j) =
> > +                        *(ptr + ((entry->count - i - 1) * ts) + j);
> > +                    *(ptr + ((entry->count - i - 1) * ts) + j) = tmp;
> > +                }
> > +            }
> > +            tnput(buf, entry->count, entry->val, entry->type);
>
> you reshuffle the data twice here

I don't exactly understand what do you mean. If data size is less than four 
bytes, the data is written in offset field, but firstly I should reverse it.

> [...]
>
> > +    case TIFF_PACKBITS:
> > +
> > +        from = src;
> > +        val = *(src++);
> > +        while (src < end) {
> > +            // max 128 bytes in direct copy
> > +            if (src - from >= 127) {
> > +                *(dst++) = src - from - 1;
> > +                memcpy(dst, from, src - from);
> > +                dst += src - from;
> > +                from = src;
> > +            }
> > +            if (val == *src) {
> > +                // how long is run ?
> > +                run_end = src;
> > +                while (run_end < end && *run_end == val
> > +                       && run_end - from < 128)
> > +                    run_end++;
> > +
> > +                if (run_end - src == 1 && src - from >= 2) {
> > +                    src++;
> > +                } else {
> > +
> > +                    // write bytes from buffer
> > +                    if (src - from >= 2) {
> > +                        *(dst++) = src - from - 2;
> > +                        memcpy(dst, from, src - from - 1);
> > +                        dst += src - from - 1;
> > +                        from = src - 1;
> > +                    }
> > +
> > +                    src = run_end;
> > +
> > +                    *(dst++) = from - src + 1;
> > +                    *(dst++) = val;
> > +                    from = src;
> > +                }
> > +            }
> > +            val = *src;
> > +            src++;
> > +        }
> > +        // write buffer
> > +        src = FFMIN(src, end);
> > +        if (src - from > 0) {
> > +            *(dst++) = src - from - 1;
> > +            for (; from != src; from++) {
> > +                *(dst++) = *from;
> > +            }
> > +        }
>
> this is duplicate relative to targaenc.c

But targa_encode_rle use a little different coding. It takes the bpp argument 
and my tests showed that it is slower for bpp=1...

> [...]
>
> > +    if (buf_size <
> > +        (((s->height * s->width * s->bpp >> 3) * 129) >> 7) + 128 +
> > +        TIFF_MAX_ENTRY * 12 + strips * 8) {
> > +        av_log(s->avctx, AV_LOG_ERROR, "Buffer is too small\n");
> > +        return -1;
> > +    }
>
> this check is buggy

Ok, I added check_size to my code.

> > +        for (i = 0; i < strips; i++) {
> > +            strip_offsets[i] = s->offset + ptr - buf;
> > +            zn = 0;
> > +            for (j = 0; j < s->rps && i * s->rps + j < s->height; j++) {
> > +                memcpy(zbuf + j * bpr,
> > +                       p->data[0] + (i * s->rps + j) * p->linesize[0],
> > +                       bpr);
> > +                zn += bpr;
> > +            }
> > +            if ((n = encode_strip(s, zbuf, ptr, zn, s->compr)) < 0) {
> > +                av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
> > +                av_free(strip_sizes);
> > +                av_free(strip_offsets);
> > +                av_free(zbuf);
> > +                return -1;
> > +            }
> > +            ptr += n;
> > +            strip_sizes[i] = ptr - buf - strip_offsets[i] + s->offset;
> > +        }
>
> whats the strip loop good for? deflate is encoded as single strip
>
> also the av_free(strip*) return -1 occurs 3 times in the code

I moved strip* to TiffContext and now av_free is in tiff_encoder_end.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: tiff.patch
Type: text/x-diff
Size: 36504 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20070331/9664080d/attachment.patch>



More information about the ffmpeg-devel mailing list