[FFmpeg-cvslog] avcodec/flicvideo: add 1bit support
Paul B Mahol
git at videolan.org
Sun Oct 1 19:47:18 EEST 2023
ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sun Oct 1 18:27:26 2023 +0200| [873ce68f54505118de48675d5c3d4b65a264489e] | committer: Paul B Mahol
avcodec/flicvideo: add 1bit support
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=873ce68f54505118de48675d5c3d4b65a264489e
---
libavcodec/flicvideo.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 197 insertions(+), 1 deletion(-)
diff --git a/libavcodec/flicvideo.c b/libavcodec/flicvideo.c
index f0d32bab38..6ce033ba40 100644
--- a/libavcodec/flicvideo.c
+++ b/libavcodec/flicvideo.c
@@ -144,6 +144,7 @@ static av_cold int flic_decode_init(AVCodecContext *avctx)
}
switch (depth) {
+ case 1 : avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; break;
case 8 : avctx->pix_fmt = AV_PIX_FMT_PAL8; break;
case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break;
case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break;
@@ -162,6 +163,198 @@ static av_cold int flic_decode_init(AVCodecContext *avctx)
return 0;
}
+static int flic_decode_frame_1BPP(AVCodecContext *avctx,
+ AVFrame *rframe, int *got_frame,
+ const uint8_t *buf, int buf_size)
+{
+ FlicDecodeContext *s = avctx->priv_data;
+
+ GetByteContext g2;
+ ptrdiff_t pixel_ptr;
+
+ unsigned int frame_size;
+ int num_chunks;
+
+ unsigned int chunk_size;
+ int chunk_type;
+
+ int i, j, ret, direction;
+
+ int lines;
+ int compressed_lines;
+ int starting_line;
+ int line_packets;
+ ptrdiff_t y_ptr;
+ int byte_run;
+ int pixel_skip;
+ int pixel_countdown;
+ unsigned char *pixels;
+ ptrdiff_t pixel_limit;
+
+ bytestream2_init(&g2, buf, buf_size);
+
+ if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
+ return ret;
+
+ direction = s->frame->linesize[0] > 0;
+ pixels = s->frame->data[0];
+ pixel_limit = s->avctx->height * s->frame->linesize[0];
+ if (buf_size < 16 || buf_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
+ return AVERROR_INVALIDDATA;
+ frame_size = bytestream2_get_le32(&g2);
+ if (frame_size > buf_size)
+ frame_size = buf_size;
+ bytestream2_skip(&g2, 2); /* skip the magic number */
+ num_chunks = bytestream2_get_le16(&g2);
+ bytestream2_skip(&g2, 8); /* skip padding */
+
+ if (frame_size < 16)
+ return AVERROR_INVALIDDATA;
+
+ frame_size -= 16;
+
+ /* iterate through the chunks */
+ while ((frame_size >= 6) && (num_chunks > 0) &&
+ bytestream2_get_bytes_left(&g2) >= 4) {
+ int stream_ptr_after_chunk;
+ chunk_size = bytestream2_get_le32(&g2);
+ if (chunk_size > frame_size) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size);
+ chunk_size = frame_size;
+ }
+ stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size;
+
+ chunk_type = bytestream2_get_le16(&g2);
+
+ switch (chunk_type) {
+ case FLI_BRUN:
+ /* Byte run compression: This chunk type only occurs in the first
+ * FLI frame and it will update the entire frame. */
+ y_ptr = 0;
+ for (lines = 0; lines < s->avctx->height; lines++) {
+ pixel_ptr = y_ptr;
+ /* disregard the line packets; instead, iterate through all
+ * pixels on a row */
+ bytestream2_skip(&g2, 1);
+ pixel_countdown = (s->avctx->width + 7) >> 3;
+ while (pixel_countdown > 0) {
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
+ byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
+ if (!byte_run) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (byte_run > 0) {
+ int value = bytestream2_get_byte(&g2);
+ CHECK_PIXEL_PTR(byte_run);
+ for (j = 0; j < byte_run; j++) {
+ pixels[pixel_ptr++] = value;
+ pixel_countdown--;
+ if (pixel_countdown < 0)
+ av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
+ pixel_countdown, lines);
+ }
+ } else { /* copy bytes if byte_run < 0 */
+ byte_run = -byte_run;
+ CHECK_PIXEL_PTR(byte_run);
+ if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
+ break;
+ for (j = 0; j < byte_run; j++) {
+ pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
+ pixel_countdown--;
+ if (pixel_countdown < 0)
+ av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
+ pixel_countdown, lines);
+ }
+ }
+ }
+
+ y_ptr += s->frame->linesize[0];
+ }
+ break;
+
+ case FLI_LC:
+ /* line compressed */
+ starting_line = bytestream2_get_le16(&g2);
+ if (starting_line >= s->avctx->height)
+ return AVERROR_INVALIDDATA;
+ y_ptr = 0;
+ y_ptr += starting_line * s->frame->linesize[0];
+
+ compressed_lines = bytestream2_get_le16(&g2);
+ while (compressed_lines > 0) {
+ pixel_ptr = y_ptr;
+ CHECK_PIXEL_PTR(0);
+ pixel_countdown = (s->avctx->width + 7) >> 3;
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
+ line_packets = bytestream2_get_byte(&g2);
+ if (line_packets > 0) {
+ for (i = 0; i < line_packets; i++) {
+ /* account for the skip bytes */
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
+ pixel_skip = bytestream2_get_byte(&g2);
+ pixel_ptr += pixel_skip;
+ pixel_countdown -= pixel_skip;
+ byte_run = sign_extend(bytestream2_get_byte(&g2),8);
+ if (byte_run > 0) {
+ CHECK_PIXEL_PTR(byte_run);
+ if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
+ break;
+ for (j = 0; j < byte_run; j++, pixel_countdown--) {
+ pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
+ }
+ } else if (byte_run < 0) {
+ int value = bytestream2_get_byte(&g2);
+ byte_run = -byte_run;
+ CHECK_PIXEL_PTR(byte_run);
+ for (j = 0; j < byte_run; j++, pixel_countdown--) {
+ pixels[pixel_ptr++] = value;
+ }
+ }
+ }
+ }
+
+ y_ptr += s->frame->linesize[0];
+ compressed_lines--;
+ }
+ break;
+
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
+ break;
+ }
+
+ if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) {
+ bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2));
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Chunk overread\n");
+ break;
+ }
+
+ frame_size -= chunk_size;
+ num_chunks--;
+ }
+
+ /* by the end of the chunk, the stream ptr should equal the frame
+ * size (minus 1 or 2, possibly); if it doesn't, issue a warning */
+ if (bytestream2_get_bytes_left(&g2) > 2)
+ av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
+ "and final chunk ptr = %d\n", buf_size,
+ buf_size - bytestream2_get_bytes_left(&g2));
+
+ if ((ret = av_frame_ref(rframe, s->frame)) < 0)
+ return ret;
+
+ *got_frame = 1;
+
+ return buf_size;
+}
+
static int flic_decode_frame_8BPP(AVCodecContext *avctx,
AVFrame *rframe, int *got_frame,
const uint8_t *buf, int buf_size)
@@ -1092,7 +1285,10 @@ static int flic_decode_frame(AVCodecContext *avctx, AVFrame *frame,
{
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
- if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+ if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK) {
+ return flic_decode_frame_1BPP(avctx, frame, got_frame,
+ buf, buf_size);
+ } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
return flic_decode_frame_8BPP(avctx, frame, got_frame,
buf, buf_size);
} else if ((avctx->pix_fmt == AV_PIX_FMT_RGB555) ||
More information about the ffmpeg-cvslog
mailing list