[FFmpeg-devel] Animated GIF support
Michael Niedermayer
michaelni at gmx.at
Sat Aug 25 23:47:53 CEST 2012
On Mon, Aug 13, 2012 at 12:57:13PM +0400, Vitaliy Sugrobov wrote:
>
> > On Mon, 13 Aug 2012 06:15:35 +0400, Vitaliy Sugrobov wrote:
> > >
> > >Hi. I would like to participate in development of animated gif decoding support. Actually i've already implemented this feature by adding gif demuxer and slightly
> >
> > post your patch so we can take a look so far :)
>
> Here it is.For now conversion from animated gif to something other works only with -f gif option e.g.-f gif -i animation.gif out.mp4By the way: without -f option input treated as still image intended to be read with image2 demuxer. I think this is because of libavformat/img2dec.c:read_probe() which called without opening the file and seeks for one of the acceptable image extensions in the file name. It accepts ".gif" substring contained in the filename and returns some score. Then ffmpeg sees that it got non-zero score and proceeds not bothering to open the file and check its actual contents. Thats why my gif_probe() doesn't even have a change to be invoked.
> So the main question remains the same: how should i instruct ffmpeg that some frames should be displayed for longer than others in order to respect variable gif delays?
seting AVPacket.duration and .pts shoudl be fine
[...]
> +static int gif_read_packet(AVFormatContext *s, AVPacket *pkt) {
> + GIFDemuxContext *gdc = s->priv_data;
> + AVIOContext *pb = s->pb;
> + int packed_fields, block_label, ct_size;
> + int64_t frame_start = avio_tell(pb), frame_end;
> + int ret = AVERROR_EOF;
> +
> + if(!gdc->header_parsed) {
> + /* skip 6 bytes of magick, 2 of width and 2 of height */
> + avio_skip(pb, 10);
> + packed_fields = avio_r8(pb);
> + avio_skip(pb, 2);
> +
> + /* glogal color table presence */
> + if(packed_fields & 0x80) {
> + ct_size = 3 * (1 << ((packed_fields & 0x07) + 1));
> + avio_skip(pb, ct_size);
> + }
> +
> + gdc->header_parsed = 1;
> + }
> +
> + while(GIF_TRAILER != (block_label = avio_r8(pb)) && !url_feof(pb)) {
> + if(block_label == GIF_EXTENSION_INTRODUCER) {
> + if ((ret = gif_read_ext (s)) < 0 )
> + return ret;
> + } else if(block_label == GIF_IMAGE_SEPARATOR) {
> + /* skip to last byte of Image Descriptor header */
> + avio_skip(pb, 8);
> + packed_fields = avio_r8(pb);
> +
> + /* local color table presence */
> + if (packed_fields & 0x80) {
> + ct_size = 3 * (1 << ((packed_fields & 0x07) + 1));
> + avio_skip(pb, ct_size);
> + }
> +
> + if (avio_r8(pb) < 1) {
> + av_log(s, AV_LOG_ERROR, "lzw minimum code size must be >= 1\n");
> + return AVERROR_INVALIDDATA;
> + }
> +
> + gif_skip_subblocks(pb);
> + frame_end = avio_tell(pb);
> +
> + if(avio_seek(pb, frame_start, SEEK_SET) != frame_start)
> + return AVERROR(EIO);
seeking back can fail on non seekable input
> +
> + ret = av_get_packet(pb, pkt, (int)(frame_end - frame_start));
> + if(ret < 0)
> + return ret;
> +
> + pkt->stream_index = 0;
> + /* total_duration and delay are in hundredths of second.
> + * Earlier, in gif_read_header() we set time base to 1/25,
> + * so in order to convert from gif timings to out time base,
> + * we divide them by 4. */
> + pkt->pts = gdc->total_duration / 4;
> + pkt->dts = gdc->frame_idx;
pts == dts for gif
> + pkt->duration = gdc->delay / 4;
the division by 4 looks wrong, the full precission field should be
used. If that means a timebase of 1/100, then it should be set to
1/100
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
The real ebay dictionary, page 1
"Used only once" - "Some unspecified defect prevented a second use"
"In good condition" - "Can be repaird by experienced expert"
"As is" - "You wouldnt want it even if you were payed for it, if you knew ..."
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120825/e75b4505/attachment.asc>
More information about the ffmpeg-devel
mailing list