[FFmpeg-cvslog] avformat/westwood_vqa: Store VQFL codebook chunks
Pekka Väänänen
git at videolan.org
Thu Oct 14 11:01:42 EEST 2021
ffmpeg | branch: master | Pekka Väänänen <pekka.vaananen at iki.fi> | Wed Sep 22 15:42:23 2021 +0300| [4d52e36bd002721d77f50cd18ddb9d44cd690f01] | committer: Paul B Mahol
avformat/westwood_vqa: Store VQFL codebook chunks
High color 15-bit VQA3 video streams contain high level chunks with
only codebook updates that shouldn't be considered new frames. Now
the demuxer stores a reference to such VQFL chunks and returns them
later along with a VQFR chunk with full frame data.
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=4d52e36bd002721d77f50cd18ddb9d44cd690f01
---
libavformat/westwood_vqa.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c
index 77df007c11..bc4f53d4e3 100644
--- a/libavformat/westwood_vqa.c
+++ b/libavformat/westwood_vqa.c
@@ -1,6 +1,7 @@
/*
* Westwood Studios VQA Format Demuxer
- * Copyright (c) 2003 The FFmpeg project
+ * Copyright (c) 2003 Mike Melanson <melanson at pcisys.net>
+ * Copyright (c) 2021 Pekka Väänänen <pekka.vaananen at iki.fi>
*
* This file is part of FFmpeg.
*
@@ -30,6 +31,7 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#define FORM_TAG MKBETAG('F', 'O', 'R', 'M')
@@ -40,6 +42,7 @@
#define SND1_TAG MKBETAG('S', 'N', 'D', '1')
#define SND2_TAG MKBETAG('S', 'N', 'D', '2')
#define VQFR_TAG MKBETAG('V', 'Q', 'F', 'R')
+#define VQFL_TAG MKBETAG('V', 'Q', 'F', 'L')
/* don't know what these tags are for, but acknowledge their existence */
#define CINF_TAG MKBETAG('C', 'I', 'N', 'F')
@@ -60,6 +63,8 @@ typedef struct WsVqaDemuxContext {
int sample_rate;
int audio_stream_index;
int video_stream_index;
+ int64_t vqfl_chunk_pos;
+ int vqfl_chunk_size;
} WsVqaDemuxContext;
static int wsvqa_probe(const AVProbeData *p)
@@ -120,6 +125,8 @@ static int wsvqa_read_header(AVFormatContext *s)
wsvqa->channels = header[26];
wsvqa->bps = header[27];
wsvqa->audio_stream_index = -1;
+ wsvqa->vqfl_chunk_pos = 0;
+ wsvqa->vqfl_chunk_size = 0;
s->ctx_flags |= AVFMTCTX_NOHEADER;
@@ -172,7 +179,22 @@ static int wsvqa_read_packet(AVFormatContext *s,
skip_byte = chunk_size & 0x01;
- if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
+ if (chunk_type == VQFL_TAG) {
+ /* Each VQFL chunk carries only a codebook update inside which must be applied
+ * before the next VQFR is rendered. That's why we stash the VQFL offset here
+ * so it can be combined with the next VQFR packet. This way each packet
+ * includes a whole frame as expected. */
+ wsvqa->vqfl_chunk_pos = avio_tell(pb);
+ wsvqa->vqfl_chunk_size = (int)(chunk_size);
+ if (wsvqa->vqfl_chunk_size < 0 || wsvqa->vqfl_chunk_size > 3 * (1 << 20))
+ return AVERROR_INVALIDDATA;
+ /* We need a big seekback buffer because there can be SNxx, VIEW and ZBUF
+ * chunks (<512 KiB total) in the stream before we read VQFR (<256 KiB) and
+ * seek back here. */
+ ffio_ensure_seekback(pb, wsvqa->vqfl_chunk_size + (512 + 256) * 1024);
+ avio_skip(pb, chunk_size + skip_byte);
+ continue;
+ } else if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
(chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
ret= av_get_packet(pb, pkt, chunk_size);
@@ -235,6 +257,28 @@ static int wsvqa_read_packet(AVFormatContext *s,
}
break;
case VQFR_TAG:
+ /* if a new codebook is available inside an earlier a VQFL chunk then
+ * append it to 'pkt' */
+ if (wsvqa->vqfl_chunk_size > 0) {
+ int64_t current_pos = pkt->pos;
+
+ if (avio_seek(pb, wsvqa->vqfl_chunk_pos, SEEK_SET) < 0)
+ return AVERROR(EIO);
+
+ /* the decoder expects chunks to be 16-bit aligned */
+ if (wsvqa->vqfl_chunk_size % 2 == 1)
+ wsvqa->vqfl_chunk_size++;
+
+ if (av_append_packet(pb, pkt, wsvqa->vqfl_chunk_size) < 0)
+ return AVERROR(EIO);
+
+ if (avio_seek(pb, current_pos, SEEK_SET) < 0)
+ return AVERROR(EIO);
+
+ wsvqa->vqfl_chunk_pos = 0;
+ wsvqa->vqfl_chunk_size = 0;
+ }
+
pkt->stream_index = wsvqa->video_stream_index;
pkt->duration = 1;
break;
More information about the ffmpeg-cvslog
mailing list