Currently, the demuxer would split superchunks into chunk, so e.g. there
would be packets with only palette changes. This breaks the assumption
that there is at least one frame per packet
---
 libavcodec/hnm4video.c |   65 ++++++++++++++++++++++++++++++++++--------------
 libavformat/hnm.c      |   55 ++++------------------------------------
 2 files changed, 51 insertions(+), 69 deletions(-)

diff --git a/libavcodec/hnm4video.c b/libavcodec/hnm4video.c
index b200e89..f4face2 100644
--- a/libavcodec/hnm4video.c
+++ b/libavcodec/hnm4video.c
@@ -62,7 +62,7 @@ static int getbit(GetByteContext *gb, uint32_t *bitbuf, int 
*bits)
     return ret;
 }
 
-static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src,
+static void unpack_intraframe(AVCodecContext *avctx, const uint8_t *src,
                               uint32_t size)
 {
     Hnm4VideoContext *hnm = avctx->priv_data;
@@ -142,7 +142,7 @@ static void copy_processed_frame(AVCodecContext *avctx, 
AVFrame *frame)
     }
 }
 
-static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t 
size)
+static void decode_interframe_v4(AVCodecContext *avctx, const uint8_t *src, 
uint32_t size)
 {
     Hnm4VideoContext *hnm = avctx->priv_data;
     GetByteContext gb;
@@ -244,7 +244,7 @@ static void decode_interframe_v4(AVCodecContext *avctx, 
uint8_t *src, uint32_t s
     }
 }
 
-static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src,
+static void decode_interframe_v4a(AVCodecContext *avctx, const uint8_t *src,
                                   uint32_t size)
 {
     Hnm4VideoContext *hnm = avctx->priv_data;
@@ -310,7 +310,7 @@ static void decode_interframe_v4a(AVCodecContext *avctx, 
uint8_t *src,
     }
 }
 
-static void hnm_update_palette(AVCodecContext *avctx, uint8_t *src,
+static void hnm_update_palette(AVCodecContext *avctx, const uint8_t *src,
                                uint32_t size)
 {
     Hnm4VideoContext *hnm = avctx->priv_data;
@@ -351,26 +351,29 @@ static void hnm_flip_buffers(Hnm4VideoContext *hnm)
     hnm->previous = temp;
 }
 
-static int hnm_decode_frame(AVCodecContext *avctx, void *data,
-                            int *got_frame, AVPacket *avpkt)
+static int hnm_parse_chunk(AVCodecContext *avctx, AVFrame *frame,
+                           const uint8_t *data, int size)
 {
-    AVFrame *frame = data;
     Hnm4VideoContext *hnm = avctx->priv_data;
-    int ret;
+    uint32_t chunk_size;
     uint16_t chunk_id;
 
-    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
-        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
-        return ret;
+    if (size < 8) {
+        av_log(avctx, AV_LOG_ERROR, "Packet too small.\n");
+        return AVERROR_INVALIDDATA;
+    }
+    chunk_size = AV_RL24(data);
+    chunk_id   = AV_RL16(data + 4);
+    if (chunk_size > size) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid chunk size.\n");
+        return AVERROR_INVALIDDATA;
     }
-
-    chunk_id = AV_RL16(avpkt->data + 4);
 
     if (chunk_id == HNM4_CHUNK_ID_PL) {
-        hnm_update_palette(avctx, avpkt->data, avpkt->size);
+        hnm_update_palette(avctx, data, chunk_size);
         frame->palette_has_changed = 1;
     } else if (chunk_id == HNM4_CHUNK_ID_IZ) {
-        unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12);
+        unpack_intraframe(avctx, data + 12, chunk_size - 12);
         memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
         if (hnm->version == 0x4a)
             memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
@@ -380,26 +383,50 @@ static int hnm_decode_frame(AVCodecContext *avctx, void 
*data,
         frame->pict_type = AV_PICTURE_TYPE_I;
         frame->key_frame = 1;
         memcpy(frame->data[1], hnm->palette, 256 * 4);
-        *got_frame = 1;
     } else if (chunk_id == HNM4_CHUNK_ID_IU) {
         if (hnm->version == 0x4a) {
-            decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8);
+            decode_interframe_v4a(avctx, data + 8, chunk_size - 8);
             memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
         } else {
-            decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8);
+            decode_interframe_v4(avctx, data + 8, chunk_size - 8);
             postprocess_current_frame(avctx);
         }
         copy_processed_frame(avctx, frame);
         frame->pict_type = AV_PICTURE_TYPE_P;
         frame->key_frame = 0;
         memcpy(frame->data[1], hnm->palette, 256 * 4);
-        *got_frame = 1;
         hnm_flip_buffers(hnm);
     } else {
         av_log(avctx, AV_LOG_ERROR, "invalid chunk id: %d\n", chunk_id);
         return AVERROR_INVALIDDATA;
     }
 
+    return chunk_size;
+}
+
+static int hnm_decode_frame(AVCodecContext *avctx, void *data,
+                            int *got_frame, AVPacket *avpkt)
+{
+    AVFrame *frame = data;
+    int ret;
+    const uint8_t *buf = avpkt->data;
+    int       buf_size = avpkt->size;
+
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+        return ret;
+    }
+
+    while (buf_size > 0) {
+        ret = hnm_parse_chunk(avctx, frame, buf, buf_size);
+        if (ret < 0)
+            return ret;
+        buf      += ret;
+        buf_size -= ret;
+    }
+
+    *got_frame = 1;
+
     return avpkt->size;
 }
 
diff --git a/libavformat/hnm.c b/libavformat/hnm.c
index 331a95e..15d0a19 100644
--- a/libavformat/hnm.c
+++ b/libavformat/hnm.c
@@ -45,7 +45,6 @@ typedef struct Hnm4DemuxContext {
     uint16_t channels;
     uint32_t framesize;
     uint32_t currentframe;
-    uint32_t superchunk_remaining;
 } Hnm4DemuxContext;
 
 static int hnm_probe(AVProbeData *p)
@@ -67,9 +66,6 @@ static int hnm_read_header(AVFormatContext *s)
     AVIOContext *pb = s->pb;
     AVStream *vst;
 
-    /* default context members */
-    hnm->superchunk_remaining = 0;
-
     avio_skip(pb, 8);
     hnm->width     = avio_rl16(pb);
     hnm->height    = avio_rl16(pb);
@@ -120,59 +116,18 @@ static int hnm_read_packet(AVFormatContext *s, AVPacket 
*pkt)
 {
     Hnm4DemuxContext *hnm = s->priv_data;
     AVIOContext *pb = s->pb;
-    int ret = 0;
 
-    uint32_t superchunk_size, chunk_size;
-    uint16_t chunk_id;
+    uint32_t superchunk_size;
 
     if (hnm->currentframe == hnm->frames || pb->eof_reached)
         return AVERROR_EOF;
 
-    if (hnm->superchunk_remaining == 0) {
-        /* parse next superchunk */
-        superchunk_size = avio_rl24(pb);
-        avio_skip(pb, 1);
-
-        hnm->superchunk_remaining = superchunk_size - 4;
-    }
-
-    chunk_size = avio_rl24(pb);
+    /* parse next superchunk */
+    superchunk_size = avio_rl24(pb);
     avio_skip(pb, 1);
-    chunk_id = avio_rl16(pb);
-    avio_skip(pb, 2);
-
-    if (chunk_size > hnm->superchunk_remaining) {
-        av_log(s, AV_LOG_ERROR, "invalid chunk size: %u, offset: %u\n",
-               chunk_size, (int) avio_tell(pb));
-        avio_skip(pb, hnm->superchunk_remaining - 8);
-        hnm->superchunk_remaining = 0;
-    }
-
-    switch (chunk_id) {
-    case HNM4_CHUNK_ID_PL:
-    case HNM4_CHUNK_ID_IZ:
-    case HNM4_CHUNK_ID_IU:
-        avio_seek(pb, -8, SEEK_CUR);
-        ret += av_get_packet(pb, pkt, chunk_size);
-        hnm->superchunk_remaining -= chunk_size;
-        if (chunk_id == HNM4_CHUNK_ID_IZ || chunk_id == HNM4_CHUNK_ID_IU)
-            hnm->currentframe++;
-        break;
-
-    case HNM4_CHUNK_ID_SD:
-        avio_skip(pb, chunk_size - 8);
-        hnm->superchunk_remaining -= chunk_size;
-        break;
-
-    default:
-        av_log(s, AV_LOG_WARNING, "unknown chunk found: %d, offset: %d\n",
-               chunk_id, (int) avio_tell(pb));
-        avio_skip(pb, chunk_size - 8);
-        hnm->superchunk_remaining -= chunk_size;
-        break;
-    }
+    hnm->currentframe++;
 
-    return ret;
+    return av_get_packet(pb, pkt, superchunk_size - 4);
 }
 
 AVInputFormat ff_hnm_demuxer = {
-- 
1.7.10.4

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to