Anamitra Ghorui: > This patch implements non interlaced decoding of FLIF16 images with all > transforms except for one, FrameLookback which is being tested. > > Several test files have been attached. The above mentioned transform > and interlaced decoding is being tested and will be implemented shortly. > > The main reason of posting this patch now is to ask advice on deflate > decompression (or inflate) on the metadata segments of the format. > The reference decoder of the format [1] uses lodepng, and by extension, > deflate for generating the metadata segments. Therefore these segments > should be able to be decoded by zlib's deflate routines. However it does > not work and returns saying that the data is invalid. > I have tried isolating the metadata using a hex editor, and then using > zlib's example program [2] to decode it. However it also says that it's > invalid data. > Can you please tell me what I am doing wrong in libavformat/flifdec.c? > > [1]: https://github.com/FLIF-hub/FLIF > [2]: https://zlib.net/zpipe.c > > Co-authored-by: Anamitra Ghorui <agho...@teknik.io> > Co-authored-by: Karhtik K. Khullar <kartikkhullar...@gmail.com> > > Signed-off-by: Anamitra Ghorui <agho...@teknik.io> > ---
[...] > + > +#if 0 > +// CONFIG_ZLIB > +static int flif_inflate(FLIFDemuxContext *s, unsigned char *buf, int > buf_size, > + unsigned char *out_buf, int *out_buf_size) I did not look thoroughly at it at all, but this is already wrong: flif_inflate allocates out_buf and in order to return it, the parameter must be of type unsigned char ** (or uint8_t ** (that is preferred here)). > +{ > + int ret; > + z_stream *stream = &s->stream; > + > + if (!s->active) { > + s->active = 1; > + stream->zalloc = Z_NULL; > + stream->zfree = Z_NULL; > + stream->opaque = Z_NULL; > + stream->avail_in = 0; > + stream->next_in = Z_NULL; > + ret = inflateInit(stream); > + > + if (ret != Z_OK) > + return ret; > + > + *out_buf_size = buf_size; > + out_buf = av_realloc(out_buf, buf_size); > + if (!out_buf) > + return AVERROR(ENOMEM); > + } > + > + stream->next_in = buf; > + stream->avail_in = buf_size; > + if(stream->total_out >= *out_buf_size) { > + out_buf = av_realloc(out_buf, (*out_buf_size) * 2); > + if (!out_buf) > + return AVERROR(ENOMEM); > + *out_buf_size *= 2; > + } > + > + stream->next_out = out_buf + stream->total_out; > + stream->avail_out = *out_buf_size - stream->total_out - 1; // Last byte > should be NULL char > + > + ret = inflate(stream, Z_PARTIAL_FLUSH); > + > + switch (ret) { > + case Z_NEED_DICT: > + case Z_DATA_ERROR: > + (void)inflateEnd(stream); > + return AVERROR(EINVAL); > + case Z_MEM_ERROR: > + (void)inflateEnd(stream); > + return AVERROR(ENOMEM); > + } > + > + if (ret == Z_STREAM_END) { > + ret = 0; > + s->active = 0; > + out_buf[stream->total_out - 1] = '\0'; > + (void) inflateEnd(stream); > + } else > + ret = AVERROR(EAGAIN); > + > + return ret; // Return Z_BUF_ERROR/EAGAN as long as input is incomplete. > +} > + > +#endif > + > +static int flif16_probe(const AVProbeData *p) > +{ > + uint32_t vlist[3] = {0}; > + unsigned int count = 0, pos = 0; > + > + // Magic Number > + if (memcmp(p->buf, flif16_header, 4)) { > + return 0; > + } > + > + for(int i = 0; i < 2 + (((p->buf[4] >> 4) > 4) ? 1 : 0); ++i) { > + while (p->buf[5 + pos] > 127) { > + if (!(count--)) { > + return 0; > + } > + VARINT_APPEND(vlist[i], p->buf[5 + pos]); > + ++pos; > + } > + VARINT_APPEND(vlist[i], p->buf[5 + pos]); > + count = 0; > + } > + > + if (!((vlist[0] + 1) && (vlist[1] + 1))) > + return 0; > + > + if (((p->buf[4] >> 4) > 4) && !(vlist[2] + 2)) > + return 0; > + > + return AVPROBE_SCORE_MAX; > +} > + > +static int flif16_read_header(AVFormatContext *s) > +{ > + // FLIFDemuxContext *dc = s->priv_data; > + GetByteContext gb; > + FLIF16RangeCoder rc; > + > + AVIOContext *pb = s->pb; > + AVStream *st; > + > + uint32_t vlist[3] = {0}; > + uint32_t flag, animated, temp; > + uint32_t bpc = 0; > + // uint8_t tag[5] = {0}; > + uint8_t buf[BUF_SIZE]; > + uint32_t metadata_size = 0; > + // uint8_t *out_buf = NULL; > + // int out_buf_size = 0; > + > + unsigned int count = 4; > + int ret; > + int format; > + int segment = 0, i = 0; > + int64_t duration = 0; > + uint8_t loops = 0; > + uint8_t num_planes; > + uint8_t num_frames; > + > + // Magic Number > + if (avio_rl32(pb) != (*((uint32_t *) flif16_header))) { > + av_log(s, AV_LOG_ERROR, "bad magic number\n"); > + return AVERROR(EINVAL); > + } > + > + st = avformat_new_stream(s, NULL); > + flag = avio_r8(pb); > + animated = (flag >> 4) > 4; > + duration = !animated; > + bpc = avio_r8(pb); // Bytes per channel > + > + num_planes = flag & 0x0F; > + > + for (int i = 0; i < (2 + animated); ++i) { > + while ((temp = avio_r8(pb)) > 127) { > + if (!(count--)) > + return AVERROR_INVALIDDATA; > + VARINT_APPEND(vlist[i], temp); > + } > + VARINT_APPEND(vlist[i], temp); > + count = 4; > + } > + > + > + ++vlist[0]; > + ++vlist[1]; > + if (animated) > + vlist[2] += 2; > + else > + vlist[2] = 1; > + > + num_frames = vlist[2]; > + > + while ((temp = avio_r8(pb))) { > + // Get metadata identifier > + #if 0 > + tag[0] = temp; > + for(int i = 1; i <= 3; ++i) > + tag[i] = avio_r8(pb); > + #else > + avio_skip(pb, 3); > + #endif > + > + // Read varint > + while ((temp = avio_r8(pb)) > 127) { > + if (!(count--)) > + return AVERROR_INVALIDDATA; > + VARINT_APPEND(metadata_size, temp); > + } > + VARINT_APPEND(metadata_size, temp); > + count = 4; > + > + #if 0 > + // CONFIG_ZLIB > + // TODO see why this does not work. > + // Decompression Routines > + while (metadata_size > 0) { > + ret = avio_read(pb, metadata_buf, FFMIN(METADATA_BUF_SIZE, > metadata_size)); > + metadata_size -= ret; > + if((ret = flif_inflate(dc, metadata_buf, ret, out_buf, > &out_buf_size)) < 0 && out_buf here will always be what it was at the beginning, because flif_inflate() works with a copy of out_buf. (C uses call by value.) > + ret != AVERROR(EAGAIN)) { > + av_log(s, AV_LOG_ERROR, "could not decode metadata\n"); > + return ret; > + } > + } > + av_dict_set(&s->metadata, tag, out_buf, 0); > + #else > + avio_skip(pb, metadata_size); > + #endif > + } > + > + #if 0 > + // CONFIG_ZLIB > + if (out_buf) > + av_freep(&out_buf); > + #endif > + > + avio_read(pb, buf, FLIF16_RAC_MAX_RANGE_BYTES); > + ff_flif16_rac_init(&rc, NULL, buf, FLIF16_RAC_MAX_RANGE_BYTES); > + ret = avio_read_partial(pb, buf, BUF_SIZE); > + bytestream2_init(&gb, buf, ret); > + rc.gb = &gb; > + > + while (1) { > + switch (segment) { > + case 0: > + if (bpc == '0') { > + bpc = 0; > + for (; i < num_planes; ++i) { > + RAC_GET(&rc, NULL, 1, 15, &temp, > FLIF16_RAC_UNI_INT8); > + bpc = FFMAX(bpc, (1 << temp) - 1); > + } > + i = 0; > + } else > + bpc = (bpc == '1') ? 255 : 65535; > + // MSG("planes : %d & bpc : %d\n", num_planes, bpc); > + if (num_frames < 2) > + goto end; > + ++segment; > + > + case 1: > + if (num_planes > 3) { > + RAC_GET(&rc, NULL, 0, 1, &temp, FLIF16_RAC_UNI_INT8); > + } > + ++segment; > + > + case 2: > + if (num_frames > 1) { > + RAC_GET(&rc, NULL, 0, 100, &loops, FLIF16_RAC_UNI_INT8); > + } > + loops = (!loops) ? 1 : loops; > + ++segment; > + > + case 3: > + if (num_frames > 1) { > + for (; i < num_frames; ++i) { > + temp = 0; > + RAC_GET(&rc, NULL, 0, 60000, &(temp), > FLIF16_RAC_UNI_INT16); > + duration += temp; > + } > + i = 0; > + } > + goto end; > + } > + > + need_more_data: > + avio_read_partial(pb, buf, BUF_SIZE); > + bytestream2_init(&gb, buf, BUF_SIZE); > + } > + > + end: > + > + if (bpc > 65535) { > + av_log(s, AV_LOG_ERROR, "depth per channel greater than 16 bits not > supported\n"); > + return AVERROR_PATCHWELCOME; > + } > + > + format = flif16_out_frame_type[FFMIN(num_planes, 4)][bpc > 255]; > + > + // The minimum possible delay in a FLIF16 image is 1 millisecond. > + // Therefore time base is 10^-3, i.e. 1/1000 > + avpriv_set_pts_info(st, 64, 1, 1000); > + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; > + st->codecpar->codec_id = AV_CODEC_ID_FLIF16; > + st->codecpar->width = vlist[0]; > + st->codecpar->height = vlist[1]; > + st->codecpar->format = format; > + st->duration = duration * loops; > + st->start_time = 0; > + st->nb_frames = vlist[2]; > + // st->need_parsing = 1; > + > + // Jump to start because flif16 decoder needs header data too > + if (avio_seek(pb, 0, SEEK_SET) != 0) > + return AVERROR(EIO); > + return 0; > +} > + > + > +static int flif16_read_packet(AVFormatContext *s, AVPacket *pkt) > +{ > + AVIOContext *pb = s->pb; > + int ret; > + // FFMIN(BUF_SIZE, avio_size(pb)) > + ret = av_get_packet(pb, pkt, avio_size(pb)); > + return ret; > +} > + > + > +static const AVOption options[] = { > + { NULL } > +}; > + > +static const AVClass demuxer_class = { > + .class_name = "FLIF demuxer", > + .item_name = av_default_item_name, > + .option = options, > + .version = LIBAVUTIL_VERSION_INT, > + .category = AV_CLASS_CATEGORY_DEMUXER, > +}; > + > +AVInputFormat ff_flif_demuxer = { > + .name = "flif", > + .long_name = NULL_IF_CONFIG_SMALL("Free Lossless Image Format > (FLIF)"), > + .priv_data_size = sizeof(FLIFDemuxContext), > + .extensions = "flif", > + .read_probe = flif16_probe, > + .read_header = flif16_read_header, > + .read_packet = flif16_read_packet, > + //.flags = AVFMT_NOTIMESTAMPS, > + .priv_class = &demuxer_class, > +}; > diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c > index a31644c2a8..58e2d368ca 100644 > --- a/libavformat/gifdec.c > +++ b/libavformat/gifdec.c > @@ -268,7 +268,6 @@ static int gif_read_packet(AVFormatContext *s, AVPacket > *pkt) > keyframe, frame_parsed = 0, ret; > int64_t frame_start = avio_tell(pb), frame_end; > unsigned char buf[6]; > - > if ((ret = avio_read(pb, buf, 6)) == 6) { > keyframe = memcmp(buf, gif87a_sig, 6) == 0 || > memcmp(buf, gif89a_sig, 6) == 0; > diff --git a/libavformat/version.h b/libavformat/version.h > index 4724269b3c..a233b67351 100644 > --- a/libavformat/version.h > +++ b/libavformat/version.h > @@ -32,8 +32,8 @@ > // Major bumping may affect Ticket5467, 5421, 5451(compatibility with > Chromium) > // Also please add any ticket numbers that you believe might be affected here > #define LIBAVFORMAT_VERSION_MAJOR 58 > -#define LIBAVFORMAT_VERSION_MINOR 39 > -#define LIBAVFORMAT_VERSION_MICRO 101 > +#define LIBAVFORMAT_VERSION_MINOR 40 > +#define LIBAVFORMAT_VERSION_MICRO 100 > > #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ > LIBAVFORMAT_VERSION_MINOR, \ > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".