1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * GIF demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2012 Vitaliy E Sugrobov 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * GIF demuxer. 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "avformat.h" 28cabdff1aSopenharmony_ci#include "libavutil/bprint.h" 29cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 30cabdff1aSopenharmony_ci#include "libavutil/opt.h" 31cabdff1aSopenharmony_ci#include "internal.h" 32cabdff1aSopenharmony_ci#include "libavcodec/gif.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_citypedef struct GIFDemuxContext { 35cabdff1aSopenharmony_ci const AVClass *class; 36cabdff1aSopenharmony_ci /** 37cabdff1aSopenharmony_ci * Time span in hundredths of second before 38cabdff1aSopenharmony_ci * the next frame should be drawn on screen. 39cabdff1aSopenharmony_ci */ 40cabdff1aSopenharmony_ci int delay; 41cabdff1aSopenharmony_ci /** 42cabdff1aSopenharmony_ci * Minimum allowed delay between frames in hundredths of 43cabdff1aSopenharmony_ci * second. Values below this threshold considered to be 44cabdff1aSopenharmony_ci * invalid and set to value of default_delay. 45cabdff1aSopenharmony_ci */ 46cabdff1aSopenharmony_ci int min_delay; 47cabdff1aSopenharmony_ci int max_delay; 48cabdff1aSopenharmony_ci int default_delay; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci /** 51cabdff1aSopenharmony_ci * loop options 52cabdff1aSopenharmony_ci */ 53cabdff1aSopenharmony_ci int total_iter; 54cabdff1aSopenharmony_ci int iter_count; 55cabdff1aSopenharmony_ci int ignore_loop; 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci int nb_frames; 58cabdff1aSopenharmony_ci int last_duration; 59cabdff1aSopenharmony_ci} GIFDemuxContext; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci/** 62cabdff1aSopenharmony_ci * Major web browsers display gifs at ~10-15fps when rate 63cabdff1aSopenharmony_ci * is not explicitly set or have too low values. We assume default rate to be 10. 64cabdff1aSopenharmony_ci * Default delay = 100hundredths of second / 10fps = 10hos per frame. 65cabdff1aSopenharmony_ci */ 66cabdff1aSopenharmony_ci#define GIF_DEFAULT_DELAY 10 67cabdff1aSopenharmony_ci/** 68cabdff1aSopenharmony_ci * By default delay values less than this threshold considered to be invalid. 69cabdff1aSopenharmony_ci */ 70cabdff1aSopenharmony_ci#define GIF_MIN_DELAY 2 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_cistatic int gif_probe(const AVProbeData *p) 73cabdff1aSopenharmony_ci{ 74cabdff1aSopenharmony_ci /* check magick */ 75cabdff1aSopenharmony_ci if (memcmp(p->buf, gif87a_sig, 6) && memcmp(p->buf, gif89a_sig, 6)) 76cabdff1aSopenharmony_ci return 0; 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci /* width or height contains zero? */ 79cabdff1aSopenharmony_ci if (!AV_RL16(&p->buf[6]) || !AV_RL16(&p->buf[8])) 80cabdff1aSopenharmony_ci return 0; 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 83cabdff1aSopenharmony_ci} 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_cistatic int resync(AVIOContext *pb) 86cabdff1aSopenharmony_ci{ 87cabdff1aSopenharmony_ci int i; 88cabdff1aSopenharmony_ci for (i = 0; i < 6; i++) { 89cabdff1aSopenharmony_ci int b = avio_r8(pb); 90cabdff1aSopenharmony_ci if (b != gif87a_sig[i] && b != gif89a_sig[i]) 91cabdff1aSopenharmony_ci i = -(b != 'G'); 92cabdff1aSopenharmony_ci if (avio_feof(pb)) 93cabdff1aSopenharmony_ci return AVERROR_EOF; 94cabdff1aSopenharmony_ci } 95cabdff1aSopenharmony_ci return 0; 96cabdff1aSopenharmony_ci} 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_cistatic int gif_skip_subblocks(AVIOContext *pb) 99cabdff1aSopenharmony_ci{ 100cabdff1aSopenharmony_ci int sb_size, ret = 0; 101cabdff1aSopenharmony_ci 102cabdff1aSopenharmony_ci while (0x00 != (sb_size = avio_r8(pb))) { 103cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, sb_size)) < 0) 104cabdff1aSopenharmony_ci return ret; 105cabdff1aSopenharmony_ci } 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_ci return ret; 108cabdff1aSopenharmony_ci} 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_cistatic int gif_read_header(AVFormatContext *s) 111cabdff1aSopenharmony_ci{ 112cabdff1aSopenharmony_ci GIFDemuxContext *gdc = s->priv_data; 113cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 114cabdff1aSopenharmony_ci AVStream *st; 115cabdff1aSopenharmony_ci int type, width, height, ret, n, flags; 116cabdff1aSopenharmony_ci int64_t nb_frames = 0, duration = 0; 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci if ((ret = resync(pb)) < 0) 119cabdff1aSopenharmony_ci return ret; 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci gdc->delay = gdc->default_delay; 122cabdff1aSopenharmony_ci width = avio_rl16(pb); 123cabdff1aSopenharmony_ci height = avio_rl16(pb); 124cabdff1aSopenharmony_ci flags = avio_r8(pb); 125cabdff1aSopenharmony_ci avio_skip(pb, 1); 126cabdff1aSopenharmony_ci n = avio_r8(pb); 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci if (width == 0 || height == 0) 129cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 132cabdff1aSopenharmony_ci if (!st) 133cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci if (flags & 0x80) 136cabdff1aSopenharmony_ci avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1))); 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci while ((type = avio_r8(pb)) != GIF_TRAILER) { 139cabdff1aSopenharmony_ci if (avio_feof(pb)) 140cabdff1aSopenharmony_ci break; 141cabdff1aSopenharmony_ci if (type == GIF_EXTENSION_INTRODUCER) { 142cabdff1aSopenharmony_ci int subtype = avio_r8(pb); 143cabdff1aSopenharmony_ci if (subtype == GIF_COM_EXT_LABEL) { 144cabdff1aSopenharmony_ci AVBPrint bp; 145cabdff1aSopenharmony_ci int block_size; 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_ci av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); 148cabdff1aSopenharmony_ci while ((block_size = avio_r8(pb)) != 0) { 149cabdff1aSopenharmony_ci avio_read_to_bprint(pb, &bp, block_size); 150cabdff1aSopenharmony_ci } 151cabdff1aSopenharmony_ci av_dict_set(&s->metadata, "comment", bp.str, 0); 152cabdff1aSopenharmony_ci av_bprint_finalize(&bp, NULL); 153cabdff1aSopenharmony_ci } else if (subtype == GIF_GCE_EXT_LABEL) { 154cabdff1aSopenharmony_ci int block_size = avio_r8(pb); 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci if (block_size == 4) { 157cabdff1aSopenharmony_ci int delay; 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci avio_skip(pb, 1); 160cabdff1aSopenharmony_ci delay = avio_rl16(pb); 161cabdff1aSopenharmony_ci if (delay < gdc->min_delay) 162cabdff1aSopenharmony_ci delay = gdc->default_delay; 163cabdff1aSopenharmony_ci delay = FFMIN(delay, gdc->max_delay); 164cabdff1aSopenharmony_ci duration += delay; 165cabdff1aSopenharmony_ci avio_skip(pb, 1); 166cabdff1aSopenharmony_ci } else { 167cabdff1aSopenharmony_ci avio_skip(pb, block_size); 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci gif_skip_subblocks(pb); 170cabdff1aSopenharmony_ci } else { 171cabdff1aSopenharmony_ci gif_skip_subblocks(pb); 172cabdff1aSopenharmony_ci } 173cabdff1aSopenharmony_ci } else if (type == GIF_IMAGE_SEPARATOR) { 174cabdff1aSopenharmony_ci avio_skip(pb, 8); 175cabdff1aSopenharmony_ci flags = avio_r8(pb); 176cabdff1aSopenharmony_ci if (flags & 0x80) 177cabdff1aSopenharmony_ci avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1))); 178cabdff1aSopenharmony_ci avio_skip(pb, 1); 179cabdff1aSopenharmony_ci gif_skip_subblocks(pb); 180cabdff1aSopenharmony_ci nb_frames++; 181cabdff1aSopenharmony_ci } else { 182cabdff1aSopenharmony_ci break; 183cabdff1aSopenharmony_ci } 184cabdff1aSopenharmony_ci } 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci /* GIF format operates with time in "hundredths of second", 187cabdff1aSopenharmony_ci * therefore timebase is 1/100 */ 188cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, 100); 189cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 190cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_GIF; 191cabdff1aSopenharmony_ci st->codecpar->width = width; 192cabdff1aSopenharmony_ci st->codecpar->height = height; 193cabdff1aSopenharmony_ci st->start_time = 0; 194cabdff1aSopenharmony_ci st->duration = duration; 195cabdff1aSopenharmony_ci st->nb_frames = nb_frames; 196cabdff1aSopenharmony_ci if (n) { 197cabdff1aSopenharmony_ci st->codecpar->sample_aspect_ratio.num = n + 15; 198cabdff1aSopenharmony_ci st->codecpar->sample_aspect_ratio.den = 64; 199cabdff1aSopenharmony_ci } 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_ci /* jump to start because gif decoder needs header data too */ 202cabdff1aSopenharmony_ci if (avio_seek(pb, 0, SEEK_SET) != 0) 203cabdff1aSopenharmony_ci return AVERROR(EIO); 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci return 0; 206cabdff1aSopenharmony_ci} 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_cistatic int gif_read_ext(AVFormatContext *s) 209cabdff1aSopenharmony_ci{ 210cabdff1aSopenharmony_ci GIFDemuxContext *gdc = s->priv_data; 211cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 212cabdff1aSopenharmony_ci int sb_size, ext_label = avio_r8(pb); 213cabdff1aSopenharmony_ci int ret; 214cabdff1aSopenharmony_ci 215cabdff1aSopenharmony_ci if (ext_label == GIF_GCE_EXT_LABEL) { 216cabdff1aSopenharmony_ci if ((sb_size = avio_r8(pb)) < 4) { 217cabdff1aSopenharmony_ci av_log(s, AV_LOG_FATAL, "Graphic Control Extension block's size less than 4.\n"); 218cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 219cabdff1aSopenharmony_ci } 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci /* skip packed fields */ 222cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, 1)) < 0) 223cabdff1aSopenharmony_ci return ret; 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci gdc->delay = avio_rl16(pb); 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_ci if (gdc->delay < gdc->min_delay) 228cabdff1aSopenharmony_ci gdc->delay = gdc->default_delay; 229cabdff1aSopenharmony_ci gdc->delay = FFMIN(gdc->delay, gdc->max_delay); 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci /* skip the rest of the Graphic Control Extension block */ 232cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, sb_size - 3)) < 0 ) 233cabdff1aSopenharmony_ci return ret; 234cabdff1aSopenharmony_ci } else if (ext_label == GIF_APP_EXT_LABEL) { 235cabdff1aSopenharmony_ci uint8_t data[256]; 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci sb_size = avio_r8(pb); 238cabdff1aSopenharmony_ci ret = avio_read(pb, data, sb_size); 239cabdff1aSopenharmony_ci if (ret < 0 || !sb_size) 240cabdff1aSopenharmony_ci return ret; 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci if (sb_size == strlen(NETSCAPE_EXT_STR)) { 243cabdff1aSopenharmony_ci sb_size = avio_r8(pb); 244cabdff1aSopenharmony_ci ret = avio_read(pb, data, sb_size); 245cabdff1aSopenharmony_ci if (ret < 0 || !sb_size) 246cabdff1aSopenharmony_ci return ret; 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci if (sb_size == 3 && data[0] == 1) { 249cabdff1aSopenharmony_ci gdc->total_iter = AV_RL16(data+1); 250cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "Loop count is %d\n", gdc->total_iter); 251cabdff1aSopenharmony_ci 252cabdff1aSopenharmony_ci if (gdc->total_iter == 0) 253cabdff1aSopenharmony_ci gdc->total_iter = -1; 254cabdff1aSopenharmony_ci } 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci } 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci if ((ret = gif_skip_subblocks(pb)) < 0) 259cabdff1aSopenharmony_ci return ret; 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_ci return 0; 262cabdff1aSopenharmony_ci} 263cabdff1aSopenharmony_ci 264cabdff1aSopenharmony_cistatic int gif_read_packet(AVFormatContext *s, AVPacket *pkt) 265cabdff1aSopenharmony_ci{ 266cabdff1aSopenharmony_ci GIFDemuxContext *gdc = s->priv_data; 267cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 268cabdff1aSopenharmony_ci int packed_fields, block_label, ct_size, 269cabdff1aSopenharmony_ci keyframe, frame_parsed = 0, ret; 270cabdff1aSopenharmony_ci int64_t frame_start = avio_tell(pb), frame_end; 271cabdff1aSopenharmony_ci unsigned char buf[6]; 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci if ((ret = avio_read(pb, buf, 6)) == 6) { 274cabdff1aSopenharmony_ci keyframe = memcmp(buf, gif87a_sig, 6) == 0 || 275cabdff1aSopenharmony_ci memcmp(buf, gif89a_sig, 6) == 0; 276cabdff1aSopenharmony_ci } else if (ret < 0) { 277cabdff1aSopenharmony_ci return ret; 278cabdff1aSopenharmony_ci } else { 279cabdff1aSopenharmony_ci keyframe = 0; 280cabdff1aSopenharmony_ci } 281cabdff1aSopenharmony_ci 282cabdff1aSopenharmony_ci if (keyframe) { 283cabdff1aSopenharmony_ciparse_keyframe: 284cabdff1aSopenharmony_ci /* skip 2 bytes of width and 2 of height */ 285cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, 4)) < 0) 286cabdff1aSopenharmony_ci return ret; 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci packed_fields = avio_r8(pb); 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci /* skip 1 byte of Background Color Index and 1 byte of Pixel Aspect Ratio */ 291cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, 2)) < 0) 292cabdff1aSopenharmony_ci return ret; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci /* global color table presence */ 295cabdff1aSopenharmony_ci if (packed_fields & 0x80) { 296cabdff1aSopenharmony_ci ct_size = 3 * (1 << ((packed_fields & 0x07) + 1)); 297cabdff1aSopenharmony_ci 298cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, ct_size)) < 0) 299cabdff1aSopenharmony_ci return ret; 300cabdff1aSopenharmony_ci } 301cabdff1aSopenharmony_ci } else { 302cabdff1aSopenharmony_ci avio_seek(pb, -ret, SEEK_CUR); 303cabdff1aSopenharmony_ci ret = AVERROR_EOF; 304cabdff1aSopenharmony_ci } 305cabdff1aSopenharmony_ci 306cabdff1aSopenharmony_ci while (GIF_TRAILER != (block_label = avio_r8(pb)) && !avio_feof(pb)) { 307cabdff1aSopenharmony_ci if (block_label == GIF_EXTENSION_INTRODUCER) { 308cabdff1aSopenharmony_ci if ((ret = gif_read_ext (s)) < 0 ) 309cabdff1aSopenharmony_ci goto resync; 310cabdff1aSopenharmony_ci } else if (block_label == GIF_IMAGE_SEPARATOR) { 311cabdff1aSopenharmony_ci /* skip to last byte of Image Descriptor header */ 312cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, 8)) < 0) 313cabdff1aSopenharmony_ci return ret; 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci packed_fields = avio_r8(pb); 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci /* local color table presence */ 318cabdff1aSopenharmony_ci if (packed_fields & 0x80) { 319cabdff1aSopenharmony_ci ct_size = 3 * (1 << ((packed_fields & 0x07) + 1)); 320cabdff1aSopenharmony_ci 321cabdff1aSopenharmony_ci if ((ret = avio_skip(pb, ct_size)) < 0) 322cabdff1aSopenharmony_ci return ret; 323cabdff1aSopenharmony_ci } 324cabdff1aSopenharmony_ci 325cabdff1aSopenharmony_ci /* read LZW Minimum Code Size */ 326cabdff1aSopenharmony_ci if (avio_r8(pb) < 1) { 327cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "lzw minimum code size must be >= 1\n"); 328cabdff1aSopenharmony_ci goto resync; 329cabdff1aSopenharmony_ci } 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci if ((ret = gif_skip_subblocks(pb)) < 0) 332cabdff1aSopenharmony_ci goto resync; 333cabdff1aSopenharmony_ci 334cabdff1aSopenharmony_ci frame_end = avio_tell(pb); 335cabdff1aSopenharmony_ci 336cabdff1aSopenharmony_ci if (avio_seek(pb, frame_start, SEEK_SET) != frame_start) 337cabdff1aSopenharmony_ci return AVERROR(EIO); 338cabdff1aSopenharmony_ci 339cabdff1aSopenharmony_ci ret = av_get_packet(pb, pkt, frame_end - frame_start); 340cabdff1aSopenharmony_ci if (ret < 0) 341cabdff1aSopenharmony_ci return ret; 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_ci if (keyframe) 344cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 345cabdff1aSopenharmony_ci 346cabdff1aSopenharmony_ci pkt->stream_index = 0; 347cabdff1aSopenharmony_ci pkt->duration = gdc->delay; 348cabdff1aSopenharmony_ci 349cabdff1aSopenharmony_ci gdc->nb_frames ++; 350cabdff1aSopenharmony_ci gdc->last_duration = pkt->duration; 351cabdff1aSopenharmony_ci 352cabdff1aSopenharmony_ci /* Graphic Control Extension's scope is single frame. 353cabdff1aSopenharmony_ci * Remove its influence. */ 354cabdff1aSopenharmony_ci gdc->delay = gdc->default_delay; 355cabdff1aSopenharmony_ci frame_parsed = 1; 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_ci break; 358cabdff1aSopenharmony_ci } else { 359cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "invalid block label\n"); 360cabdff1aSopenharmony_ciresync: 361cabdff1aSopenharmony_ci if (!keyframe) 362cabdff1aSopenharmony_ci avio_seek(pb, frame_start, SEEK_SET); 363cabdff1aSopenharmony_ci if ((ret = resync(pb)) < 0) 364cabdff1aSopenharmony_ci return ret; 365cabdff1aSopenharmony_ci frame_start = avio_tell(pb) - 6; 366cabdff1aSopenharmony_ci keyframe = 1; 367cabdff1aSopenharmony_ci goto parse_keyframe; 368cabdff1aSopenharmony_ci } 369cabdff1aSopenharmony_ci } 370cabdff1aSopenharmony_ci 371cabdff1aSopenharmony_ci if ((ret >= 0 && !frame_parsed) || ret == AVERROR_EOF) { 372cabdff1aSopenharmony_ci if (gdc->nb_frames == 1) { 373cabdff1aSopenharmony_ci s->streams[0]->r_frame_rate = (AVRational) {100, gdc->last_duration}; 374cabdff1aSopenharmony_ci } 375cabdff1aSopenharmony_ci /* This might happen when there is no image block 376cabdff1aSopenharmony_ci * between extension blocks and GIF_TRAILER or EOF */ 377cabdff1aSopenharmony_ci if (!gdc->ignore_loop && (block_label == GIF_TRAILER || avio_feof(pb)) 378cabdff1aSopenharmony_ci && (gdc->total_iter < 0 || ++gdc->iter_count < gdc->total_iter)) 379cabdff1aSopenharmony_ci return avio_seek(pb, 0, SEEK_SET); 380cabdff1aSopenharmony_ci return AVERROR_EOF; 381cabdff1aSopenharmony_ci } else 382cabdff1aSopenharmony_ci return ret; 383cabdff1aSopenharmony_ci} 384cabdff1aSopenharmony_ci 385cabdff1aSopenharmony_cistatic const AVOption options[] = { 386cabdff1aSopenharmony_ci { "min_delay" , "minimum valid delay between frames (in hundredths of second)", offsetof(GIFDemuxContext, min_delay) , AV_OPT_TYPE_INT, {.i64 = GIF_MIN_DELAY} , 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM }, 387cabdff1aSopenharmony_ci { "max_gif_delay", "maximum valid delay between frames (in hundredths of seconds)", offsetof(GIFDemuxContext, max_delay) , AV_OPT_TYPE_INT, {.i64 = 65535} , 0, 65535 , AV_OPT_FLAG_DECODING_PARAM }, 388cabdff1aSopenharmony_ci { "default_delay", "default delay between frames (in hundredths of second)" , offsetof(GIFDemuxContext, default_delay), AV_OPT_TYPE_INT, {.i64 = GIF_DEFAULT_DELAY}, 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM }, 389cabdff1aSopenharmony_ci { "ignore_loop" , "ignore loop setting (netscape extension)" , offsetof(GIFDemuxContext, ignore_loop) , AV_OPT_TYPE_BOOL,{.i64 = 1} , 0, 1, AV_OPT_FLAG_DECODING_PARAM }, 390cabdff1aSopenharmony_ci { NULL }, 391cabdff1aSopenharmony_ci}; 392cabdff1aSopenharmony_ci 393cabdff1aSopenharmony_cistatic const AVClass demuxer_class = { 394cabdff1aSopenharmony_ci .class_name = "GIF demuxer", 395cabdff1aSopenharmony_ci .item_name = av_default_item_name, 396cabdff1aSopenharmony_ci .option = options, 397cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 398cabdff1aSopenharmony_ci .category = AV_CLASS_CATEGORY_DEMUXER, 399cabdff1aSopenharmony_ci}; 400cabdff1aSopenharmony_ci 401cabdff1aSopenharmony_ciconst AVInputFormat ff_gif_demuxer = { 402cabdff1aSopenharmony_ci .name = "gif", 403cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"), 404cabdff1aSopenharmony_ci .priv_data_size = sizeof(GIFDemuxContext), 405cabdff1aSopenharmony_ci .read_probe = gif_probe, 406cabdff1aSopenharmony_ci .read_header = gif_read_header, 407cabdff1aSopenharmony_ci .read_packet = gif_read_packet, 408cabdff1aSopenharmony_ci .flags = AVFMT_GENERIC_INDEX, 409cabdff1aSopenharmony_ci .priv_class = &demuxer_class, 410cabdff1aSopenharmony_ci}; 411