2 * Kega Game Video (KGV1) decoder
3 * Copyright (c) 2010 Daniel Verkamp
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * Kega Game Video decoder
27 #include "libavutil/common.h"
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/imgutils.h"
34 uint16_t *frame_buffer
;
35 uint16_t *last_frame_buffer
;
38 static void decode_flush(AVCodecContext
*avctx
)
40 KgvContext
* const c
= avctx
->priv_data
;
42 av_freep(&c
->frame_buffer
);
43 av_freep(&c
->last_frame_buffer
);
46 static int decode_frame(AVCodecContext
*avctx
, void *data
, int *got_frame
,
49 AVFrame
*frame
= data
;
50 const uint8_t *buf
= avpkt
->data
;
51 const uint8_t *buf_end
= buf
+ avpkt
->size
;
52 KgvContext
* const c
= avctx
->priv_data
;
55 int outcnt
= 0, maxcnt
;
59 return AVERROR_INVALIDDATA
;
65 if (w
!= avctx
->width
|| h
!= avctx
->height
) {
66 av_freep(&c
->frame_buffer
);
67 av_freep(&c
->last_frame_buffer
);
68 if ((res
= ff_set_dimensions(avctx
, w
, h
)) < 0)
72 if (!c
->frame_buffer
) {
73 c
->frame_buffer
= av_mallocz(avctx
->width
* avctx
->height
* 2);
74 c
->last_frame_buffer
= av_mallocz(avctx
->width
* avctx
->height
* 2);
75 if (!c
->frame_buffer
|| !c
->last_frame_buffer
) {
77 return AVERROR(ENOMEM
);
83 if ((res
= ff_get_buffer(avctx
, frame
, 0)) < 0)
85 out
= (uint8_t*)c
->frame_buffer
;
86 prev
= (uint8_t*)c
->last_frame_buffer
;
88 for (i
= 0; i
< 8; i
++)
91 while (outcnt
< maxcnt
&& buf_end
- 2 >= buf
) {
92 int code
= AV_RL16(buf
);
95 if (!(code
& 0x8000)) {
96 AV_WN16A(&out
[2 * outcnt
], code
); // rgb555 pixel coded directly
101 if ((code
& 0x6000) == 0x6000) {
102 // copy from previous frame
103 int oidx
= (code
>> 10) & 7;
106 count
= (code
& 0x3FF) + 3;
108 if (offsets
[oidx
] < 0) {
109 if (buf_end
- 3 < buf
)
111 offsets
[oidx
] = AV_RL24(buf
);
115 start
= (outcnt
+ offsets
[oidx
]) % maxcnt
;
117 if (maxcnt
- start
< count
|| maxcnt
- outcnt
< count
)
121 av_log(avctx
, AV_LOG_ERROR
,
122 "Frame reference does not exist\n");
126 memcpy(out
+ 2 * outcnt
, prev
+ 2 * start
, 2 * count
);
128 // copy from earlier in this frame
129 int offset
= (code
& 0x1FFF) + 1;
131 if (!(code
& 0x6000)) {
133 } else if ((code
& 0x6000) == 0x2000) {
136 if (buf_end
- 1 < buf
)
141 if (outcnt
< offset
|| maxcnt
- outcnt
< count
)
144 av_memcpy_backptr(out
+ 2 * outcnt
, 2 * offset
, 2 * count
);
151 av_log(avctx
, AV_LOG_DEBUG
, "frame finished with %d diff\n", outcnt
- maxcnt
);
153 av_image_copy_plane(frame
->data
[0], frame
->linesize
[0],
154 (const uint8_t*)c
->frame_buffer
, avctx
->width
* 2,
155 avctx
->width
* 2, avctx
->height
);
156 FFSWAP(uint16_t *, c
->frame_buffer
, c
->last_frame_buffer
);
163 static av_cold
int decode_init(AVCodecContext
*avctx
)
165 avctx
->pix_fmt
= AV_PIX_FMT_RGB555
;
170 static av_cold
int decode_end(AVCodecContext
*avctx
)
176 AVCodec ff_kgv1_decoder
= {
178 .long_name
= NULL_IF_CONFIG_SMALL("Kega Game Video"),
179 .type
= AVMEDIA_TYPE_VIDEO
,
180 .id
= AV_CODEC_ID_KGV1
,
181 .priv_data_size
= sizeof(KgvContext
),
184 .decode
= decode_frame
,
185 .flush
= decode_flush
,
186 .capabilities
= CODEC_CAP_DR1
,