2 * MidiVid Archive codec
4 * Copyright (c) 2019 Paul B Mahol
6 * This file is part of FFmpeg.
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.
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.
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
23 #define CACHED_BITSTREAM_READER !ARCH_X86_32
24 #include "libavutil/intreadwrite.h"
27 #include "codec_internal.h"
30 #include "lossless_videodsp.h"
31 #include "zlib_wrapper.h"
35 typedef struct MVHAContext
{
44 LLVidDSPContext llviddsp
;
54 static void get_tree_codes(uint32_t *bits
, int16_t *lens
, uint8_t *xlat
,
55 Node
*nodes
, int node
,
56 uint32_t pfx
, int pl
, int *pos
)
62 bits
[*pos
] = (~pfx
) & ((1ULL << FFMAX(pl
, 1)) - 1);
63 lens
[*pos
] = FFMAX(pl
, 1);
64 xlat
[*pos
] = s
+ (pl
== 0);
69 get_tree_codes(bits
, lens
, xlat
, nodes
, nodes
[node
].l
, pfx
, pl
,
72 get_tree_codes(bits
, lens
, xlat
, nodes
, nodes
[node
].r
, pfx
, pl
,
77 static int build_vlc(AVCodecContext
*avctx
, VLC
*vlc
)
79 MVHAContext
*s
= avctx
->priv_data
;
84 int cur_node
, i
, j
, pos
= 0;
88 for (i
= 0; i
< s
->nb_symbols
; i
++) {
89 nodes
[i
].count
= s
->prob
[i
];
90 nodes
[i
].sym
= s
->symb
[i
];
96 cur_node
= s
->nb_symbols
;
101 int first_node
= cur_node
;
102 int second_node
= cur_node
;
105 nodes
[cur_node
].count
= -1;
108 int val
= nodes
[new_node
].count
;
109 if (val
&& (val
< nodes
[first_node
].count
)) {
110 if (val
>= nodes
[second_node
].count
) {
111 first_node
= new_node
;
113 first_node
= second_node
;
114 second_node
= new_node
;
118 } while (new_node
!= cur_node
);
120 if (first_node
== cur_node
)
123 nd
= nodes
[second_node
].count
;
124 st
= nodes
[first_node
].count
;
125 nodes
[second_node
].count
= 0;
126 nodes
[first_node
].count
= 0;
127 if (nd
>= UINT32_MAX
- st
) {
128 av_log(avctx
, AV_LOG_ERROR
, "count overflow\n");
129 return AVERROR_INVALIDDATA
;
131 nodes
[cur_node
].count
= nd
+ st
;
132 nodes
[cur_node
].sym
= -1;
133 nodes
[cur_node
].n0
= cur_node
;
134 nodes
[cur_node
].l
= first_node
;
135 nodes
[cur_node
].r
= second_node
;
139 } while (cur_node
- s
->nb_symbols
== j
);
141 get_tree_codes(bits
, lens
, xlat
, nodes
, cur_node
- 1, 0, 0, &pos
);
143 return ff_vlc_init_sparse(vlc
, 12, pos
, lens
, 2, 2, bits
, 4, 4, xlat
, 1, 1, 0);
146 static int decode_frame(AVCodecContext
*avctx
, AVFrame
*frame
,
147 int *got_frame
, AVPacket
*avpkt
)
149 MVHAContext
*s
= avctx
->priv_data
;
153 if (avpkt
->size
<= 8)
154 return AVERROR_INVALIDDATA
;
156 type
= AV_RB32(avpkt
->data
);
157 size
= AV_RL32(avpkt
->data
+ 4);
159 if (size
< 1 || size
>= avpkt
->size
)
160 return AVERROR_INVALIDDATA
;
162 if (type
== MKTAG('L','Z','Y','V')) {
163 z_stream
*const zstream
= &s
->zstream
.zstream
;
164 ret
= inflateReset(zstream
);
166 av_log(avctx
, AV_LOG_ERROR
, "Inflate reset error: %d\n", ret
);
167 return AVERROR_EXTERNAL
;
170 if ((ret
= ff_get_buffer(avctx
, frame
, 0)) < 0)
173 zstream
->next_in
= avpkt
->data
+ 8;
174 zstream
->avail_in
= avpkt
->size
- 8;
176 for (int p
= 0; p
< 3; p
++) {
177 for (int y
= 0; y
< avctx
->height
; y
++) {
178 zstream
->next_out
= frame
->data
[p
] + (avctx
->height
- y
- 1) * frame
->linesize
[p
];
179 zstream
->avail_out
= avctx
->width
>> (p
> 0);
181 ret
= inflate(zstream
, Z_SYNC_FLUSH
);
182 if (ret
!= Z_OK
&& ret
!= Z_STREAM_END
) {
183 av_log(avctx
, AV_LOG_ERROR
, "Inflate error: %d\n", ret
);
184 return AVERROR_EXTERNAL
;
186 if (zstream
->avail_out
> 0)
187 memset(zstream
->next_out
, 0, zstream
->avail_out
);
190 } else if (type
== MKTAG('H','U','F','Y')) {
191 GetBitContext
*gb
= &s
->gb
;
192 int first_symbol
, symbol
;
194 ret
= init_get_bits8(gb
, avpkt
->data
+ 8, avpkt
->size
- 8);
200 first_symbol
= get_bits(gb
, 8);
201 s
->nb_symbols
= get_bits(gb
, 8) + 1;
203 symbol
= first_symbol
;
204 for (int i
= 0; i
< s
->nb_symbols
; symbol
++) {
207 if (get_bits_left(gb
) < 4)
208 return AVERROR_INVALIDDATA
;
211 prob
= get_bits(gb
, 12);
213 prob
= get_bits(gb
, 3);
223 if (get_bits_left(gb
) < avctx
->height
* avctx
->width
)
224 return AVERROR_INVALIDDATA
;
226 ret
= build_vlc(avctx
, &s
->vlc
);
230 if ((ret
= ff_get_buffer(avctx
, frame
, 0)) < 0)
233 for (int p
= 0; p
< 3; p
++) {
234 int width
= avctx
->width
>> (p
> 0);
235 ptrdiff_t stride
= frame
->linesize
[p
];
238 dst
= frame
->data
[p
] + (avctx
->height
- 1) * frame
->linesize
[p
];
239 for (int y
= 0; y
< avctx
->height
; y
++) {
240 if (get_bits_left(gb
) < width
)
241 return AVERROR_INVALIDDATA
;
242 for (int x
= 0; x
< width
; x
++) {
243 int v
= get_vlc2(gb
, s
->vlc
.table
, s
->vlc
.bits
, 3);
246 return AVERROR_INVALIDDATA
;
254 return AVERROR_INVALIDDATA
;
257 for (int p
= 0; p
< 3; p
++) {
259 int width
= avctx
->width
>> (p
> 0);
260 ptrdiff_t stride
= frame
->linesize
[p
];
263 dst
= frame
->data
[p
] + (avctx
->height
- 1) * frame
->linesize
[p
];
264 s
->llviddsp
.add_left_pred(dst
, dst
, width
, 0);
265 if (avctx
->height
> 1) {
267 lefttop
= left
= dst
[0];
268 for (int y
= 1; y
< avctx
->height
; y
++) {
269 s
->llviddsp
.add_median_pred(dst
, dst
+ stride
, dst
, width
, &left
, &lefttop
);
270 lefttop
= left
= dst
[0];
281 static av_cold
int decode_init(AVCodecContext
*avctx
)
283 MVHAContext
*s
= avctx
->priv_data
;
285 avctx
->pix_fmt
= AV_PIX_FMT_YUV422P
;
287 ff_llviddsp_init(&s
->llviddsp
);
289 return ff_inflate_init(&s
->zstream
, avctx
);
292 static av_cold
int decode_close(AVCodecContext
*avctx
)
294 MVHAContext
*s
= avctx
->priv_data
;
296 ff_inflate_end(&s
->zstream
);
297 ff_vlc_free(&s
->vlc
);
302 const FFCodec ff_mvha_decoder
= {
304 CODEC_LONG_NAME("MidiVid Archive Codec"),
305 .p
.type
= AVMEDIA_TYPE_VIDEO
,
306 .p
.id
= AV_CODEC_ID_MVHA
,
307 .priv_data_size
= sizeof(MVHAContext
),
309 .close
= decode_close
,
310 FF_CODEC_DECODE_CB(decode_frame
),
311 .p
.capabilities
= AV_CODEC_CAP_DR1
,
312 .caps_internal
= FF_CODEC_CAP_INIT_CLEANUP
,