History

avcodec: add mvha video decoder

Paul B Mahol committed 6 years ago

Commit ed58f841 parent 61dc7ad9 files · +324 −1Browse files

Unified · Split

9 files
  1. Changelog +1 −0
  2. configure +1 −0
  3. libavcodec/Makefile +1 −0
  4. libavcodec/allcodecs.c +1 −0
  5. libavcodec/avcodec.h +1 −0
  6. libavcodec/codec_desc.c +7 −0
  7. libavcodec/mvha.c +310 −0
  8. libavcodec/version.h +1 −1
  9. libavformat/riff.c +1 −0
Changelog+1−0
@@ -26,6 +26,7 @@ version <next>: · 25 unmodified lines
26- AV1 Annex B demuxer26- AV1 Annex B demuxer
27- axcorrelate filter27- axcorrelate filter
28- mvdv decoder28- mvdv decoder
29- mvha decoder
29 30
30 31
31version 4.2:32version 4.2:
configure+1−0
@@ -2779,6 +2779,7 @@ msmpeg4v3_decoder_select="h263_decoder" · 2778 unmodified lines
2779msmpeg4v3_encoder_select="h263_encoder"2779msmpeg4v3_encoder_select="h263_encoder"
2780mss2_decoder_select="mpegvideo qpeldsp vc1_decoder"2780mss2_decoder_select="mpegvideo qpeldsp vc1_decoder"
2781mts2_decoder_select="mss34dsp"2781mts2_decoder_select="mss34dsp"
2782mvha_decoder_deps="zlib"
2782mwsc_decoder_deps="zlib"2783mwsc_decoder_deps="zlib"
2783mxpeg_decoder_select="mjpeg_decoder"2784mxpeg_decoder_select="mjpeg_decoder"
2784nellymoser_decoder_select="mdct sinewin"2785nellymoser_decoder_select="mdct sinewin"
libavcodec/Makefile+1−0
@@ -494,6 +494,7 @@ OBJS-$(CONFIG_MTS2_DECODER) += mss4.o · 493 unmodified lines
494OBJS-$(CONFIG_MVC1_DECODER) += mvcdec.o494OBJS-$(CONFIG_MVC1_DECODER) += mvcdec.o
495OBJS-$(CONFIG_MVC2_DECODER) += mvcdec.o495OBJS-$(CONFIG_MVC2_DECODER) += mvcdec.o
496OBJS-$(CONFIG_MVDV_DECODER) += midivid.o496OBJS-$(CONFIG_MVDV_DECODER) += midivid.o
497OBJS-$(CONFIG_MVHA_DECODER) += mvha.o
497OBJS-$(CONFIG_MWSC_DECODER) += mwsc.o498OBJS-$(CONFIG_MWSC_DECODER) += mwsc.o
498OBJS-$(CONFIG_MXPEG_DECODER) += mxpegdec.o499OBJS-$(CONFIG_MXPEG_DECODER) += mxpegdec.o
499OBJS-$(CONFIG_NELLYMOSER_DECODER) += nellymoserdec.o nellymoser.o500OBJS-$(CONFIG_NELLYMOSER_DECODER) += nellymoserdec.o nellymoser.o
libavcodec/allcodecs.c+1−0
@@ -219,6 +219,7 @@ extern AVCodec ff_mts2_decoder; · 218 unmodified lines
219extern AVCodec ff_mvc1_decoder;219extern AVCodec ff_mvc1_decoder;
220extern AVCodec ff_mvc2_decoder;220extern AVCodec ff_mvc2_decoder;
221extern AVCodec ff_mvdv_decoder;221extern AVCodec ff_mvdv_decoder;
222extern AVCodec ff_mvha_decoder;
222extern AVCodec ff_mwsc_decoder;223extern AVCodec ff_mwsc_decoder;
223extern AVCodec ff_mxpeg_decoder;224extern AVCodec ff_mxpeg_decoder;
224extern AVCodec ff_nuv_decoder;225extern AVCodec ff_nuv_decoder;
libavcodec/avcodec.h+1−0
@@ -459,6 +459,7 @@ enum AVCodecID { · 458 unmodified lines
459 AV_CODEC_ID_VP4,459 AV_CODEC_ID_VP4,
460 AV_CODEC_ID_IMM5,460 AV_CODEC_ID_IMM5,
461 AV_CODEC_ID_MVDV,461 AV_CODEC_ID_MVDV,
462 AV_CODEC_ID_MVHA,
462 463
463 /* various PCM "codecs" */464 /* various PCM "codecs" */
464 AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs465 AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
libavcodec/codec_desc.c+7−0
@@ -1740,6 +1740,13 @@ static const AVCodecDescriptor codec_descriptors[] = { · 1739 unmodified lines
1740 .long_name = NULL_IF_CONFIG_SMALL("MidiVid VQ"),1740 .long_name = NULL_IF_CONFIG_SMALL("MidiVid VQ"),
1741 .props = AV_CODEC_PROP_LOSSY,1741 .props = AV_CODEC_PROP_LOSSY,
1742 },1742 },
1743 {
1744 .id = AV_CODEC_ID_MVHA,
1745 .type = AVMEDIA_TYPE_VIDEO,
1746 .name = "mvha",
1747 .long_name = NULL_IF_CONFIG_SMALL("MidiVid Archive Codec"),
1748 .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
1749 },
1743 1750
1744 /* various PCM "codecs" */1751 /* various PCM "codecs" */
1745 {1752 {
libavcodec/mvha.c+310−0
@@ -0,0 +1,310 @@
1/*
2 * MidiVid Archive codec
3 *
4 * Copyright (c) 2019 Paul B Mahol
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#define CACHED_BITSTREAM_READER !ARCH_X86_32
28#include "libavutil/intreadwrite.h"
29
30#include "avcodec.h"
31#include "bytestream.h"
32#include "get_bits.h"
33#include "internal.h"
34#include "lossless_videodsp.h"
35
36#include <zlib.h>
37
38typedef struct MVHAContext {
39 GetBitContext gb;
40 int nb_symbols;
41
42 uint8_t symb[256];
43 uint32_t prob[256];
44 VLC vlc;
45
46 z_stream zstream;
47 LLVidDSPContext llviddsp;
48} MVHAContext;
49
50typedef struct Node {
51 int16_t sym;
52 int16_t n0;
53 int16_t l, r;
54 uint32_t count;
55} Node;
56
57static void get_tree_codes(uint32_t *bits, int16_t *lens, uint8_t *xlat,
58 Node *nodes, int node,
59 uint32_t pfx, int pl, int *pos)
60{
61 int s;
62
63 s = nodes[node].sym;
64 if (s != -1) {
65 bits[*pos] = (~pfx) & ((1ULL << FFMAX(pl, 1)) - 1);
66 lens[*pos] = FFMAX(pl, 1);
67 xlat[*pos] = s + (pl == 0);
68 (*pos)++;
69 } else {
70 pfx <<= 1;
71 pl++;
72 get_tree_codes(bits, lens, xlat, nodes, nodes[node].l, pfx, pl,
73 pos);
74 pfx |= 1;
75 get_tree_codes(bits, lens, xlat, nodes, nodes[node].r, pfx, pl,
76 pos);
77 }
78}
79
80static int build_vlc(AVCodecContext *avctx, VLC *vlc)
81{
82 MVHAContext *s = avctx->priv_data;
83 Node nodes[512];
84 uint32_t bits[256];
85 int16_t lens[256];
86 uint8_t xlat[256];
87 int cur_node, i, j, pos = 0;
88
89 ff_free_vlc(vlc);
90
91 for (i = 0; i < s->nb_symbols; i++) {
92 nodes[i].count = s->prob[i];
93 nodes[i].sym = s->symb[i];
94 nodes[i].n0 = -2;
95 nodes[i].l = i;
96 nodes[i].r = i;
97 }
98
99 cur_node = s->nb_symbols;
100 j = 0;
101 do {
102 for (i = 0; ; i++) {
103 int new_node = j;
104 int first_node = cur_node;
105 int second_node = cur_node;
106 unsigned nd, st;
107
108 nodes[cur_node].count = -1;
109
110 do {
111 int val = nodes[new_node].count;
112 if (val && (val < nodes[first_node].count)) {
113 if (val >= nodes[second_node].count) {
114 first_node = new_node;
115 } else {
116 first_node = second_node;
117 second_node = new_node;
118 }
119 }
120 new_node += 1;
121 } while (new_node != cur_node);
122
123 if (first_node == cur_node)
124 break;
125
126 nd = nodes[second_node].count;
127 st = nodes[first_node].count;
128 nodes[second_node].count = 0;
129 nodes[first_node].count = 0;
130 if (nd >= UINT32_MAX - st) {
131 av_log(avctx, AV_LOG_ERROR, "count overflow\n");
132 return AVERROR_INVALIDDATA;
133 }
134 nodes[cur_node].count = nd + st;
135 nodes[cur_node].sym = -1;
136 nodes[cur_node].n0 = cur_node;
137 nodes[cur_node].l = first_node;
138 nodes[cur_node].r = second_node;
139 cur_node++;
140 }
141 j++;
142 } while (cur_node - s->nb_symbols == j);
143
144 get_tree_codes(bits, lens, xlat, nodes, cur_node - 1, 0, 0, &pos);
145
146 return ff_init_vlc_sparse(vlc, 12, pos, lens, 2, 2, bits, 4, 4, xlat, 1, 1, 0);
147}
148
149static int decode_frame(AVCodecContext *avctx,
150 void *data, int *got_frame,
151 AVPacket *avpkt)
152{
153 MVHAContext *s = avctx->priv_data;
154 AVFrame *frame = data;
155 uint32_t type, size;
156 int ret;
157
158 if (avpkt->size <= 8)
159 return AVERROR_INVALIDDATA;
160
161 type = AV_RB32(avpkt->data);
162 size = AV_RL32(avpkt->data + 4);
163
164 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
165 return ret;
166
167 if (type == MKTAG('L','Z','Y','V')) {
168 ret = inflateReset(&s->zstream);
169 if (ret != Z_OK) {
170 av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
171 return AVERROR_EXTERNAL;
172 }
173
174 s->zstream.next_in = avpkt->data + 8;
175 s->zstream.avail_in = avpkt->size - 8;
176
177 for (int p = 0; p < 3; p++) {
178 for (int y = 0; y < avctx->height; y++) {
179 s->zstream.next_out = frame->data[p] + (avctx->height - y - 1) * frame->linesize[p];
180 s->zstream.avail_out = avctx->width >> (p > 0);
181
182 ret = inflate(&s->zstream, Z_SYNC_FLUSH);
183 if (ret != Z_OK && ret != Z_STREAM_END) {
184 av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret);
185 return AVERROR_EXTERNAL;
186 }
187 }
188 }
189 } else if (type == MKTAG('H','U','F','Y')) {
190 GetBitContext *gb = &s->gb;
191 int first_symbol, symbol;
192
193 init_get_bits8(gb, avpkt->data + 8, avpkt->size - 8);
194
195 skip_bits(gb, 24);
196
197 first_symbol = get_bits(gb, 8);
198 s->nb_symbols = get_bits(gb, 8) + 1;
199
200 symbol = first_symbol;
201 for (int i = 0; i < s->nb_symbols; symbol++) {
202 int prob;
203
204 if (get_bits1(gb)) {
205 prob = get_bits(gb, 12);
206 } else {
207 prob = get_bits(gb, 3);
208 }
209
210 if (prob) {
211 s->symb[i] = symbol;
212 s->prob[i] = prob;
213 i++;
214 }
215 }
216
217 ret = build_vlc(avctx, &s->vlc);
218 if (ret < 0)
219 return ret;
220
221 for (int p = 0; p < 3; p++) {
222 int width = avctx->width >> (p > 0);
223 ptrdiff_t stride = frame->linesize[p];
224 uint8_t *dst;
225
226 dst = frame->data[p] + (avctx->height - 1) * frame->linesize[p];
227 for (int y = 0; y < avctx->height; y++) {
228 for (int x = 0; x < width; x++) {
229 int v = get_vlc2(gb, s->vlc.table, s->vlc.bits, 3);
230
231 if (v < 0)
232 return AVERROR_INVALIDDATA;
233
234 dst[x] = v;
235 }
236 dst -= stride;
237 }
238 }
239 } else {
240 return AVERROR_INVALIDDATA;
241 }
242
243 for (int p = 0; p < 3; p++) {
244 int left, lefttop;
245 int width = avctx->width >> (p > 0);
246 ptrdiff_t stride = frame->linesize[p];
247 uint8_t *dst;
248
249 dst = frame->data[p] + (avctx->height - 1) * frame->linesize[p];
250 s->llviddsp.add_left_pred(dst, dst, width, 0);
251 dst -= stride;
252 lefttop = left = dst[0];
253 for (int y = 1; y < avctx->height; y++) {
254 s->llviddsp.add_median_pred(dst, dst + stride, dst, width, &left, &lefttop);
255 lefttop = left = dst[0];
256 dst -= stride;
257 }
258 }
259
260 frame->pict_type = AV_PICTURE_TYPE_I;
261 frame->key_frame = 1;
262 *got_frame = 1;
263
264 return avpkt->size;
265}
266
267static av_cold int decode_init(AVCodecContext *avctx)
268{
269 MVHAContext *s = avctx->priv_data;
270 int zret;
271
272 avctx->pix_fmt = AV_PIX_FMT_YUV422P;
273
274 s->zstream.zalloc = Z_NULL;
275 s->zstream.zfree = Z_NULL;
276 s->zstream.opaque = Z_NULL;
277 zret = inflateInit(&s->zstream);
278 if (zret != Z_OK) {
279 av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
280 return AVERROR_EXTERNAL;
281 }
282
283 ff_llviddsp_init(&s->llviddsp);
284
285 return 0;
286}
287
288static av_cold int decode_close(AVCodecContext *avctx)
289{
290 MVHAContext *s = avctx->priv_data;
291
292 inflateEnd(&s->zstream);
293 ff_free_vlc(&s->vlc);
294
295 return 0;
296}
297
298AVCodec ff_mvha_decoder = {
299 .name = "mvha",
300 .long_name = NULL_IF_CONFIG_SMALL("MidiVid Archive Codec"),
301 .type = AVMEDIA_TYPE_VIDEO,
302 .id = AV_CODEC_ID_MVHA,
303 .priv_data_size = sizeof(MVHAContext),
304 .init = decode_init,
305 .close = decode_close,
306 .decode = decode_frame,
307 .capabilities = AV_CODEC_CAP_DR1,
308 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
309 FF_CODEC_CAP_INIT_CLEANUP,
310};
libavcodec/version.h+1−1
@@ -28,7 +28,7 @@ · 27 unmodified lines
28#include "libavutil/version.h"28#include "libavutil/version.h"
29 29
30#define LIBAVCODEC_VERSION_MAJOR 5830#define LIBAVCODEC_VERSION_MAJOR 58
31#define LIBAVCODEC_VERSION_MINOR 6331#define LIBAVCODEC_VERSION_MINOR 64
32#define LIBAVCODEC_VERSION_MICRO 10032#define LIBAVCODEC_VERSION_MICRO 100
33 33
34#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \34#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
libavformat/riff.c+1−0
@@ -490,6 +490,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { · 489 unmodified lines
490 { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') },490 { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') },
491 { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') },491 { AV_CODEC_ID_IMM5, MKTAG('I', 'M', 'M', '5') },
492 { AV_CODEC_ID_MVDV, MKTAG('M', 'V', 'D', 'V') },492 { AV_CODEC_ID_MVDV, MKTAG('M', 'V', 'D', 'V') },
493 { AV_CODEC_ID_MVHA, MKTAG('M', 'V', 'H', 'A') },
493 { AV_CODEC_ID_NONE, 0 }494 { AV_CODEC_ID_NONE, 0 }
494};495};
495 496

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t