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