Hi,

I developed an HNM4/HNM4A demuxer & video decoder for libav a while back, and now cleaned it up. Samples can be found here: http://samples.mplayerhq.hu/game-formats/hnm/losteden-hnm4/
I have more samples, i can upload those if needed.

First time contributor, so if the format of the patch is wrong, or something in the code, just tell me. Also I think it should work on big endian platforms, but couldnt test because i dont have access to a BE device.


 libavcodec/Makefile      |   1 +
 libavcodec/allcodecs.c   |   1 +
 libavcodec/avcodec.h     |   1 +
libavcodec/hnm4video.c | 483 +++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/Makefile     |   1 +
 libavformat/allformats.c |   1 +
 libavformat/hnm.c        | 203 ++++++++++++++++++++
 7 files changed, 691 insertions(+)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 8e0d60d..f64a56f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -197,6 +197,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o \ h264_loopfilter.o h264_direct.o \ cabac.o h264_sei.o h264_ps.o \ h264_refs.o h264_cavlc.o h264_cabac.o
+OBJS-$(CONFIG_HNM4_VIDEO_DECODER)      += hnm4video.o
 OBJS-$(CONFIG_HUFFYUV_DECODER)         += huffyuv.o huffyuvdec.o
 OBJS-$(CONFIG_HUFFYUV_ENCODER)         += huffyuv.o huffyuvenc.o
 OBJS-$(CONFIG_IAC_DECODER)             += imc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 55d7957..b62efb9 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -153,6 +153,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(H263I,             h263i);
     REGISTER_ENCODER(H263P,             h263p);
     REGISTER_DECODER(H264,              h264);
+    REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
     REGISTER_ENCDEC (HUFFYUV,           huffyuv);
     REGISTER_DECODER(IDCIN,             idcin);
     REGISTER_DECODER(IFF_BYTERUN1,      iff_byterun1);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index d535308..ae0bfe2 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -274,6 +274,7 @@ enum AVCodecID {
     AV_CODEC_ID_ESCAPE130,
     AV_CODEC_ID_G2M,
     AV_CODEC_ID_WEBP,
+    AV_CODEC_ID_HNM4_VIDEO,

     /* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/hnm4video.c b/libavcodec/hnm4video.c
new file mode 100644
index 0000000..d8d0c39
--- /dev/null
+++ b/libavcodec/hnm4video.c
@@ -0,0 +1,483 @@
+/*
+ * Cryo Interactive Entertainment HNM4 video decoder
+ * Copyright (c) 2012 David Kment
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "libavutil/internal.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+#include <string.h>
+
+#define HNM4_CHUNK_ID_PL 19536
+#define HNM4_CHUNK_ID_IZ 23113
+#define HNM4_CHUNK_ID_IU 21833
+#define HNM4_CHUNK_ID_SD 17491
+
+typedef struct Hnm4VideoContext {
+
+    uint8_t version;
+    uint16_t width;
+    uint16_t height;
+
+    uint8_t *current;
+    uint8_t *previous;
+    uint8_t *buffer1;
+    uint8_t *buffer2;
+    uint8_t *processed;
+    uint8_t *palette;
+} Hnm4VideoContext;
+
+static int getbit(uint8_t *src, uint32_t *brBitsRemaining, uint32_t *brOffset, uint32_t *brQueue) {
+
+    if (*brBitsRemaining == 0) {
+
+        *brQueue = AV_RL32(src + *brOffset);
+        *brOffset += 4;
+        *brBitsRemaining = 32;
+    }
+
+    (*brBitsRemaining)--;
+
+    if (*brQueue & 0x80000000) {
+        *brQueue <<= 1;
+        return 1;
+    }
+    else {
+        *brQueue <<= 1;
+        return 0;
+    }
+}
+
+static void unpack_intraframe(Hnm4VideoContext *hnm, uint8_t *src) {
+
+    uint32_t brBitsRemaining;
+    uint32_t brOffset;
+    uint32_t brQueue;
+
+    uint32_t outputOffset, count, offset;
+    uint16_t word;
+
+    outputOffset = 0;
+    brBitsRemaining = 0;
+    brQueue = 0;
+    brOffset = 0;
+
+    while(1) {
+
+        if (getbit(src, &brBitsRemaining, &brOffset, &brQueue)) {
+
+            hnm->current[outputOffset++] = src[brOffset++];
+
+        } else {
+
+            if (getbit(src, &brBitsRemaining, &brOffset, &brQueue)) {
+
+                word = src[brOffset++];
+                word += src[brOffset++] * 256;
+                count = word & 0x07;
+                offset = 0xffffe000 | (word >> 3);
+
+                if (!count) {count = src[brOffset++];}
+
+                if (!count) {return;}
+
+            } else {
+ count = getbit(src, &brBitsRemaining, &brOffset, &brQueue) << 1; + count |= getbit(src, &brBitsRemaining, &brOffset, &brQueue);
+
+                offset = 0xffffff00 | src[brOffset++];
+            }
+
+            count += 2;
+
+            offset += outputOffset;
+
+            while (count--) {
+                hnm->current[outputOffset++] = hnm->current[offset++];
+            }
+        }
+    }
+}
+
+static void postprocess_current_frame(Hnm4VideoContext *hnm) {
+
+    uint32_t x, y;
+    uint32_t srcX, srcY;
+
+    for(y = 0; y < hnm->height; y++) {
+        srcY = y - (y % 2);
+        srcX = srcY * hnm->width + (y % 2);
+        for(x = 0; x < hnm->width; x++) {
+            hnm->processed[(y * hnm->width) + x] = hnm->current[srcX];
+            srcX += 2;
+        }
+    }
+}
+
+static void copy_processed_frame(Hnm4VideoContext *hnm, AVFrame *frame) {
+
+    uint32_t x, y, srcX;
+
+    for(y = 0; y < hnm->height; y++) {
+        srcX = y * hnm->width;
+        for(x = 0; x < hnm->width; x++) {
+ frame->data[0][(y * frame->linesize[0]) + x] = hnm->processed[srcX++];
+        }
+    }
+}
+
+static void decode_interframe_v4(Hnm4VideoContext *hnm, uint8_t *src) {
+
+    uint32_t readOffset, writeOffset;
+    uint8_t tag;
+    uint32_t count, left;
+    uint8_t previous, backline, backward, swap;
+    int32_t offset;
+
+    readOffset = 0;
+    writeOffset = 0;
+
+    while(1) {
+
+        count = src[readOffset] & 0x1F;
+
+        if(count == 0) {
+
+            tag = src[readOffset++] & 0xE0;
+            tag = tag >> 5;
+
+            if(tag == 0) {
+                hnm->current[writeOffset++] = src[readOffset++];
+                hnm->current[writeOffset++] = src[readOffset++];
+            } else if(tag == 1) {
+                writeOffset += src[readOffset++] * 2;
+            } else if(tag == 2) {
+                count = src[readOffset++];
+                count += src[readOffset++] * 256;
+                count *= 2;
+                writeOffset += count;
+            } else if(tag == 3) {
+                count = src[readOffset++] * 2;
+                while(count > 0) {
+                    hnm->current[writeOffset++] = src[readOffset];
+                    count--;
+                }
+                readOffset++;
+            } else {
+                break;
+            }
+
+        } else {
+
+            previous = src[readOffset] & 0x20;
+            backline = src[readOffset] & 0x40;
+            backward = src[readOffset] & 0x80;
+            swap = src[readOffset+1] & 0x01;
+
+            offset = src[readOffset+1];
+            offset += src[readOffset+2] * 256;
+            offset = (offset >> 1) & 0x7FFF;
+            offset = writeOffset + (offset * 2) - 0x8000;
+
+            left = count;
+
+            if(previous) {
+                while(left > 0) {
+                    if(backline) {
+ hnm->current[writeOffset++] = hnm->previous[offset-(2 * hnm->width)+1]; + hnm->current[writeOffset++] = hnm->previous[offset++];
+                        offset++;
+                    } else {
+ hnm->current[writeOffset++] = hnm->previous[offset++]; + hnm->current[writeOffset++] = hnm->previous[offset++];
+                    }
+                    if(backward) {offset -= 4;}
+                    left--;
+                }
+            } else {
+                while(left > 0) {
+                    if(backline) {
+ hnm->current[writeOffset++] = hnm->current[offset-(2 * hnm->width)+1]; + hnm->current[writeOffset++] = hnm->current[offset++];
+                        offset++;
+                    } else {
+ hnm->current[writeOffset++] = hnm->current[offset++]; + hnm->current[writeOffset++] = hnm->current[offset++];
+                    }
+                    if(backward) {offset -= 4;}
+                    left--;
+                }
+            }
+
+            if(swap) {
+                left = count;
+                writeOffset -= count * 2;
+                while(left > 0) {
+                    swap = hnm->current[writeOffset];
+ hnm->current[writeOffset] = hnm->current[writeOffset + 1];
+                    hnm->current[writeOffset + 1] = swap;
+                    left--;
+                    writeOffset += 2;
+                }
+            }
+
+            readOffset += 3;
+        }
+    }
+}
+
+static void decode_interframe_v4a(Hnm4VideoContext *hnm, uint8_t *src) {
+
+    uint32_t readOffset, writeOffset;
+    uint8_t tag, count;
+    uint8_t previous, delta;
+    uint32_t offset;
+
+    readOffset = 0;
+    writeOffset = 0;
+
+    while(1) {
+
+        count = src[readOffset] & 0x3F;
+
+        if(count == 0) {
+
+            tag = src[readOffset++] & 0xC0;
+            tag = tag >> 6;
+
+            if(tag == 0) {
+                writeOffset += src[readOffset++];
+            } else if(tag == 1) {
+                hnm->current[writeOffset] = src[readOffset++];
+                hnm->current[writeOffset + hnm->width] = src[readOffset++];
+                writeOffset++;
+            } else if(tag == 2) {
+                writeOffset += hnm->width;
+            } else if(tag == 3) {
+                break;
+            }
+
+        } else {
+
+            delta = src[readOffset] & 0x80;
+            previous = src[readOffset] & 0x40;
+
+            offset = writeOffset;
+            offset += src[readOffset + 1];
+            offset += src[readOffset + 2] * 256;
+
+            if(delta) {offset -= 0x10000;}
+
+            if(previous) {
+                while(count > 0) {
+                    hnm->current[writeOffset] = hnm->previous[offset];
+ hnm->current[writeOffset + hnm->width] = hnm->previous[offset + hnm->width];
+                    writeOffset++;
+                    offset++;
+                    count--;
+                }
+            } else {
+                while(count > 0) {
+                    hnm->current[writeOffset] = hnm->current[offset];
+ hnm->current[writeOffset + hnm->width] = hnm->current[offset + hnm->width];
+                    writeOffset++;
+                    offset++;
+                    count--;
+                }
+            }
+
+            readOffset += 3;
+        }
+    }
+}
+
+static void hnm_update_palette(Hnm4VideoContext *hnm, uint8_t *src) {
+
+    uint16_t start, count;
+    uint8_t r, g, b;
+    uint32_t readOffset, writeOffset;
+    int eightBitColors;
+
+    readOffset = 8; // skip first 8 bytes
+    writeOffset = 0;
+
+    eightBitColors = (src[7] & 0x80 && hnm->version == 0x4a);
+
+    while(1) {
+
+        start = src[readOffset++];
+        count = src[readOffset++];
+
+        if(start == 255 && count == 255) {break;}
+
+        if(count == 0) {count = 256;}
+
+        writeOffset = start * 4;
+
+        while(count > 0) {
+            r = src[readOffset++];
+            g = src[readOffset++];
+            b = src[readOffset++];
+
+            if(!eightBitColors) {
+                r <<= 2;
+                g <<= 2;
+                b <<= 2;
+            }
+
+            hnm->palette[writeOffset++] = b;
+            hnm->palette[writeOffset++] = g;
+            hnm->palette[writeOffset++] = r;
+            hnm->palette[writeOffset++] = 0;
+            count--;
+        }
+    }
+}
+
+static void hnm_flip_buffers(Hnm4VideoContext *hnm) {
+
+    uint8_t *temp;
+
+    temp = hnm->current;
+    hnm->current = hnm->previous;
+    hnm->previous = temp;
+}
+
+static int hnm_decode_frame(AVCodecContext *avctx, void *data,
+                            int *got_frame, AVPacket *avpkt) {
+
+    AVFrame *frame = data;
+    Hnm4VideoContext *hnm = avctx->priv_data;
+    int ret;
+    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;
+    }
+
+    chunk_id = AV_RL16(avpkt->data + 4);
+
+    if(chunk_id == HNM4_CHUNK_ID_PL) {
+
+        hnm_update_palette(hnm, avpkt->data);
+    }
+    else if(chunk_id == HNM4_CHUNK_ID_IZ) {
+
+        unpack_intraframe(hnm, avpkt->data + 12);
+
+        memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
+
+        if(hnm->version == 0x4a) {
+            memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
+        } else {
+            postprocess_current_frame(hnm);
+        }
+
+        copy_processed_frame(hnm, frame);
+
+        frame->pict_type = AV_PICTURE_TYPE_I;
+        frame->key_frame = 1;
+
+        frame->palette_has_changed = 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(hnm, avpkt->data + 8);
+            memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
+        } else {
+            decode_interframe_v4(hnm, avpkt->data + 8);
+            postprocess_current_frame(hnm);
+        }
+
+        copy_processed_frame(hnm, frame);
+
+        frame->pict_type = AV_PICTURE_TYPE_P;
+        frame->key_frame = 0;
+
+        frame->palette_has_changed = 1;
+        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(EINVAL);
+    }
+
+    return avpkt->size;
+}
+
+static av_cold int hnm_decode_init(AVCodecContext *avctx) {
+
+    Hnm4VideoContext *hnm = avctx->priv_data;
+
+    hnm->buffer1 = av_mallocz(avctx->width * avctx->height);
+    hnm->buffer2 = av_mallocz(avctx->width * avctx->height);
+    hnm->processed = av_mallocz(avctx->width * avctx->height);
+    hnm->palette = av_mallocz(256 * 4);
+
+    if(hnm->buffer1 == NULL || hnm->buffer2 == NULL
+            || hnm->processed == NULL || hnm->palette == NULL) {
+        av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
+        return AVERROR(ENOMEM);
+    }
+
+    hnm->current = hnm->buffer1;
+    hnm->previous = hnm->buffer2;
+
+    avctx->pix_fmt = AV_PIX_FMT_PAL8;
+    hnm->version = avctx->extradata[0];
+    hnm->width = avctx->width;
+    hnm->height = avctx->height;
+
+    return 0;
+}
+
+static av_cold int hnm_decode_end(AVCodecContext *avctx) {
+
+    Hnm4VideoContext *hnm = avctx->priv_data;
+
+    av_free(hnm->buffer1);
+    av_free(hnm->buffer2);
+    av_free(hnm->processed);
+    av_free(hnm->palette);
+
+    return 0;
+}
+
+AVCodec ff_hnm4_video_decoder = {
+    .name           = "hnm4video",
+    .long_name      = NULL_IF_CONFIG_SMALL("HNM 4 video"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_HNM4_VIDEO,
+    .priv_data_size = sizeof(Hnm4VideoContext),
+    .init           = hnm_decode_init,
+    .close          = hnm_decode_end,
+    .decode         = hnm_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
+};
diff --git a/libavformat/Makefile b/libavformat/Makefile
index f12b493..3ac30eb 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -141,6 +141,7 @@ OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o
 OBJS-$(CONFIG_H264_MUXER)                += rawenc.o
 OBJS-$(CONFIG_HLS_DEMUXER)               += hls.o
 OBJS-$(CONFIG_HLS_MUXER)                 += hlsenc.o
+OBJS-$(CONFIG_HNM_DEMUXER)               += hnm.o
 OBJS-$(CONFIG_IDCIN_DEMUXER)             += idcin.o
 OBJS-$(CONFIG_IFF_DEMUXER)               += iff.o
 OBJS-$(CONFIG_ILBC_DEMUXER)              += ilbc.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 585cf43..289639e 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -118,6 +118,7 @@ void av_register_all(void)
     REGISTER_MUXDEMUX(H263,             h263);
     REGISTER_MUXDEMUX(H264,             h264);
     REGISTER_MUXDEMUX(HLS,              hls);
+    REGISTER_DEMUXER (HNM,              hnm);
     REGISTER_DEMUXER (IDCIN,            idcin);
     REGISTER_DEMUXER (IFF,              iff);
     REGISTER_MUXDEMUX(ILBC,             ilbc);
diff --git a/libavformat/hnm.c b/libavformat/hnm.c
new file mode 100644
index 0000000..6c80c69
--- /dev/null
+++ b/libavformat/hnm.c
@@ -0,0 +1,203 @@
+/*
+ * Cryo Interactive Entertainment HNM4 demuxer
+ * Copyright (c) 2012 David Kment
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+#define HNM4_TAG MKTAG('H', 'N', 'M', '4')
+
+#define HNM4_SAMPLE_RATE 22050
+#define HNM4_FRAME_FPS 24
+
+#define HNM4_CHUNK_ID_PL 19536
+#define HNM4_CHUNK_ID_IZ 23113
+#define HNM4_CHUNK_ID_IU 21833
+#define HNM4_CHUNK_ID_SD 17491
+
+typedef struct Hnm4DemuxContext {
+
+    uint8_t version;
+    uint16_t width;
+    uint16_t height;
+    uint32_t filesize;
+    uint32_t frames;
+    uint32_t taboffset;
+    uint16_t bits;
+    uint16_t channels;
+    uint32_t framesize;
+    uint32_t currentframe;
+
+    int64_t pts;
+
+    uint32_t superchunk_remaining;
+
+    AVPacket vpkt;
+
+} Hnm4DemuxContext;
+
+static int hnm_probe(AVProbeData *p)
+{
+    if(p->buf_size < 4) {
+        return 0;
+    }
+
+    // check for HNM4 header
+    if(AV_RL32(&p->buf[0]) == HNM4_TAG) {
+        return AVPROBE_SCORE_MAX;
+    }
+
+    return 0;
+}
+
+static int hnm_read_header(AVFormatContext *s)
+{
+    Hnm4DemuxContext *hnm = s->priv_data;
+    AVIOContext *pb = s->pb;
+    AVStream *vst;
+
+    /* default context members */
+    hnm->pts = 0;
+    av_init_packet(&hnm->vpkt);
+    hnm->vpkt.data = NULL; hnm->vpkt.size = 0;
+
+    hnm->superchunk_remaining = 0;
+
+    avio_skip(pb, 8);
+    hnm->width = avio_rl16(pb);
+    hnm->height = avio_rl16(pb);
+    hnm->filesize = avio_rl32(pb);
+    hnm->frames = avio_rl32(pb);
+    hnm->taboffset = avio_rl32(pb);
+    hnm->bits = avio_rl16(pb);
+    hnm->channels = avio_rl16(pb);
+    hnm->framesize = avio_rl32(pb);
+    avio_skip(pb, 32);
+
+    hnm->currentframe = 0;
+
+    // TODO: find a better way to detect HNM4A
+    if(hnm->width >= 640) {
+        hnm->version = 0x4a;
+    } else {
+        hnm->version = 0x40;
+    }
+
+    if (!(vst = avformat_new_stream(s, NULL)))
+        return AVERROR(ENOMEM);
+
+    vst->codec->extradata = av_mallocz(1);
+    vst->codec->extradata_size = 1;
+    memcpy(vst->codec->extradata, &hnm->version, 1);
+    vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+    vst->codec->codec_id = AV_CODEC_ID_HNM4_VIDEO;
+    vst->codec->codec_tag = 0;
+    vst->codec->width = hnm->width;
+    vst->codec->height = hnm->height;
+
+    vst->start_time = 0;
+
+    avpriv_set_pts_info(vst, 33, 1, HNM4_FRAME_FPS);
+
+    return 0;
+}
+
+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;
+    uint32_t chunk_size;
+    uint16_t chunk_id;
+
+    if(hnm->currentframe == hnm->frames) {
+        return AVERROR(EPIPE);
+    }
+
+    if(pb->eof_reached ||  (int) avio_tell(pb) >= hnm->filesize) {
+        return AVERROR(EPIPE);
+    }
+
+    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);
+    avio_skip(pb, 1);
+    chunk_id = avio_rl16(pb);
+    avio_skip(pb, 2);
+
+    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;
+    }
+
+    return ret;
+}
+
+static int hnm_read_close(AVFormatContext *s)
+{
+    Hnm4DemuxContext *hnm = s->priv_data;
+
+    if (hnm->vpkt.size > 0)
+        av_free_packet(&hnm->vpkt);
+
+    return 0;
+}
+
+AVInputFormat ff_hnm_demuxer = {
+    .name           = "hnm4movie",
+    .long_name      = NULL_IF_CONFIG_SMALL("HNM4 movie"),
+    .priv_data_size = sizeof(Hnm4DemuxContext),
+    .read_probe     = hnm_probe,
+    .read_header    = hnm_read_header,
+    .read_packet    = hnm_read_packet,
+    .read_close     = hnm_read_close,
+    .flags          = AVFMT_NO_BYTE_SEEK
+};

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

Reply via email to