1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * GIF parser 3cabdff1aSopenharmony_ci * Copyright (c) 2018 Paul B Mahol 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 parser 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/bswap.h" 28cabdff1aSopenharmony_ci#include "libavutil/common.h" 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include "gif.h" 31cabdff1aSopenharmony_ci#include "parser.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_citypedef enum GIFParseStates { 34cabdff1aSopenharmony_ci GIF_HEADER = 1, 35cabdff1aSopenharmony_ci GIF_EXTENSION, 36cabdff1aSopenharmony_ci GIF_EXTENSION_BLOCK, 37cabdff1aSopenharmony_ci GIF_IMAGE, 38cabdff1aSopenharmony_ci GIF_IMAGE_BLOCK, 39cabdff1aSopenharmony_ci} gif_states; 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_citypedef struct GIFParseContext { 42cabdff1aSopenharmony_ci ParseContext pc; 43cabdff1aSopenharmony_ci unsigned found_sig; 44cabdff1aSopenharmony_ci int found_start; 45cabdff1aSopenharmony_ci int found_end; 46cabdff1aSopenharmony_ci int index; 47cabdff1aSopenharmony_ci int state; 48cabdff1aSopenharmony_ci int gct_flag; 49cabdff1aSopenharmony_ci int gct_size; 50cabdff1aSopenharmony_ci int block_size; 51cabdff1aSopenharmony_ci int etype; 52cabdff1aSopenharmony_ci int delay; 53cabdff1aSopenharmony_ci} GIFParseContext; 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_cistatic int gif_find_frame_end(GIFParseContext *g, const uint8_t *buf, 56cabdff1aSopenharmony_ci int buf_size, void *logctx) 57cabdff1aSopenharmony_ci{ 58cabdff1aSopenharmony_ci int index, next = END_NOT_FOUND; 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci for (index = 0; index < buf_size; index++) { 61cabdff1aSopenharmony_ci if (!g->state) { 62cabdff1aSopenharmony_ci if (!memcmp(buf + index, gif87a_sig, 6) || 63cabdff1aSopenharmony_ci !memcmp(buf + index, gif89a_sig, 6)) { 64cabdff1aSopenharmony_ci g->state = GIF_HEADER; 65cabdff1aSopenharmony_ci g->found_sig++; 66cabdff1aSopenharmony_ci } else if (buf[index] == GIF_EXTENSION_INTRODUCER) { 67cabdff1aSopenharmony_ci g->state = GIF_EXTENSION; 68cabdff1aSopenharmony_ci g->found_start = 1; 69cabdff1aSopenharmony_ci } else if (buf[index] == GIF_IMAGE_SEPARATOR) { 70cabdff1aSopenharmony_ci g->state = GIF_IMAGE; 71cabdff1aSopenharmony_ci } else if (buf[index] == GIF_TRAILER) { 72cabdff1aSopenharmony_ci g->state = 0; 73cabdff1aSopenharmony_ci g->found_end = 1; 74cabdff1aSopenharmony_ci g->found_sig = 0; 75cabdff1aSopenharmony_ci } else { 76cabdff1aSopenharmony_ci g->found_sig = 0; 77cabdff1aSopenharmony_ci } 78cabdff1aSopenharmony_ci } 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci if (g->state == GIF_HEADER) { 81cabdff1aSopenharmony_ci if (g->index == 10) { 82cabdff1aSopenharmony_ci g->gct_flag = !!(buf[index] & 0x80); 83cabdff1aSopenharmony_ci g->gct_size = 3 * (1 << ((buf[index] & 0x07) + 1)); 84cabdff1aSopenharmony_ci } 85cabdff1aSopenharmony_ci if (g->index >= 12 + g->gct_flag * g->gct_size) { 86cabdff1aSopenharmony_ci g->state = 0; 87cabdff1aSopenharmony_ci g->index = 0; 88cabdff1aSopenharmony_ci g->gct_flag = 0; 89cabdff1aSopenharmony_ci g->gct_size = 0; 90cabdff1aSopenharmony_ci continue; 91cabdff1aSopenharmony_ci } 92cabdff1aSopenharmony_ci g->index++; 93cabdff1aSopenharmony_ci } else if (g->state == GIF_EXTENSION) { 94cabdff1aSopenharmony_ci if (g->found_start && g->found_end && g->found_sig) { 95cabdff1aSopenharmony_ci next = index; 96cabdff1aSopenharmony_ci g->found_start = 0; 97cabdff1aSopenharmony_ci g->found_end = 0; 98cabdff1aSopenharmony_ci g->index = 0; 99cabdff1aSopenharmony_ci g->gct_flag = 0; 100cabdff1aSopenharmony_ci g->gct_size = 0; 101cabdff1aSopenharmony_ci g->state = 0; 102cabdff1aSopenharmony_ci break; 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci if (g->index == 1) { 105cabdff1aSopenharmony_ci g->etype = buf[index]; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci if (g->index >= 2) { 108cabdff1aSopenharmony_ci g->block_size = buf[index]; 109cabdff1aSopenharmony_ci g->index = 0; 110cabdff1aSopenharmony_ci g->state = GIF_EXTENSION_BLOCK; 111cabdff1aSopenharmony_ci continue; 112cabdff1aSopenharmony_ci } 113cabdff1aSopenharmony_ci g->index++; 114cabdff1aSopenharmony_ci } else if (g->state == GIF_IMAGE_BLOCK) { 115cabdff1aSopenharmony_ci if (!g->index) 116cabdff1aSopenharmony_ci g->block_size = buf[index]; 117cabdff1aSopenharmony_ci if (g->index >= g->block_size) { 118cabdff1aSopenharmony_ci g->index = 0; 119cabdff1aSopenharmony_ci if (!g->block_size) { 120cabdff1aSopenharmony_ci g->state = 0; 121cabdff1aSopenharmony_ci g->found_end = 1; 122cabdff1aSopenharmony_ci } 123cabdff1aSopenharmony_ci continue; 124cabdff1aSopenharmony_ci } 125cabdff1aSopenharmony_ci g->index++; 126cabdff1aSopenharmony_ci } else if (g->state == GIF_EXTENSION_BLOCK) { 127cabdff1aSopenharmony_ci if (g->etype == GIF_GCE_EXT_LABEL) { 128cabdff1aSopenharmony_ci if (g->index == 0) 129cabdff1aSopenharmony_ci g->delay = 0; 130cabdff1aSopenharmony_ci if (g->index >= 1 && g->index <= 2) { 131cabdff1aSopenharmony_ci g->delay |= buf[index] << (8 * (g->index - 1)); 132cabdff1aSopenharmony_ci } 133cabdff1aSopenharmony_ci } 134cabdff1aSopenharmony_ci if (g->index >= g->block_size) { 135cabdff1aSopenharmony_ci g->block_size = buf[index]; 136cabdff1aSopenharmony_ci g->index = 0; 137cabdff1aSopenharmony_ci if (!g->block_size) 138cabdff1aSopenharmony_ci g->state = 0; 139cabdff1aSopenharmony_ci continue; 140cabdff1aSopenharmony_ci } 141cabdff1aSopenharmony_ci g->index++; 142cabdff1aSopenharmony_ci } else if (g->state == GIF_IMAGE) { 143cabdff1aSopenharmony_ci if (g->index == 8) { 144cabdff1aSopenharmony_ci g->gct_flag = !!(buf[index] & 0x80); 145cabdff1aSopenharmony_ci g->gct_size = 3 * (1 << ((buf[index] & 0x07) + 1)); 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci if (g->index >= 10 + g->gct_flag * g->gct_size) { 148cabdff1aSopenharmony_ci g->state = GIF_IMAGE_BLOCK; 149cabdff1aSopenharmony_ci g->index = 0; 150cabdff1aSopenharmony_ci g->gct_flag = 0; 151cabdff1aSopenharmony_ci g->gct_size = 0; 152cabdff1aSopenharmony_ci continue; 153cabdff1aSopenharmony_ci } 154cabdff1aSopenharmony_ci g->index++; 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci } 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci return next; 159cabdff1aSopenharmony_ci} 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_cistatic int gif_parse(AVCodecParserContext *s, AVCodecContext *avctx, 162cabdff1aSopenharmony_ci const uint8_t **poutbuf, int *poutbuf_size, 163cabdff1aSopenharmony_ci const uint8_t *buf, int buf_size) 164cabdff1aSopenharmony_ci{ 165cabdff1aSopenharmony_ci GIFParseContext *g = s->priv_data; 166cabdff1aSopenharmony_ci int next; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci next = gif_find_frame_end(g, buf, buf_size, avctx); 169cabdff1aSopenharmony_ci if (ff_combine_frame(&g->pc, next, &buf, &buf_size) < 0) { 170cabdff1aSopenharmony_ci *poutbuf = NULL; 171cabdff1aSopenharmony_ci *poutbuf_size = 0; 172cabdff1aSopenharmony_ci return buf_size; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci s->duration = g->delay; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci *poutbuf = buf; 178cabdff1aSopenharmony_ci *poutbuf_size = buf_size; 179cabdff1aSopenharmony_ci return next; 180cabdff1aSopenharmony_ci} 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ciconst AVCodecParser ff_gif_parser = { 183cabdff1aSopenharmony_ci .codec_ids = { AV_CODEC_ID_GIF }, 184cabdff1aSopenharmony_ci .priv_data_size = sizeof(GIFParseContext), 185cabdff1aSopenharmony_ci .parser_parse = gif_parse, 186cabdff1aSopenharmony_ci .parser_close = ff_parse_close, 187cabdff1aSopenharmony_ci}; 188