kgv1dec.c
Go to the documentation of this file.
1 /*
2  * Kega Game Video (KGV1) decoder
3  * Copyright (c) 2010 Daniel Verkamp
4  *
5  * This file is part of FFmpeg.
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 /**
23  * @file
24  * Kega Game Video decoder
25  */
26 
27 #include "libavutil/common.h"
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/imgutils.h"
30 #include "avcodec.h"
31 #include "internal.h"
32 
33 typedef struct {
36 } KgvContext;
37 
38 static void decode_flush(AVCodecContext *avctx)
39 {
40  KgvContext * const c = avctx->priv_data;
41 
42  av_frame_unref(&c->prev);
43 }
44 
45 static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
46  AVPacket *avpkt)
47 {
48  AVFrame *frame = data;
49  const uint8_t *buf = avpkt->data;
50  const uint8_t *buf_end = buf + avpkt->size;
51  KgvContext * const c = avctx->priv_data;
52  int offsets[8];
53  uint8_t *out, *prev;
54  int outcnt = 0, maxcnt;
55  int w, h, i, res;
56 
57  if (avpkt->size < 2)
58  return AVERROR_INVALIDDATA;
59 
60  w = (buf[0] + 1) * 8;
61  h = (buf[1] + 1) * 8;
62  buf += 2;
63 
64  if ((res = av_image_check_size(w, h, 0, avctx)) < 0)
65  return res;
66 
67  if (w != avctx->width || h != avctx->height) {
68  av_frame_unref(&c->prev);
69  avcodec_set_dimensions(avctx, w, h);
70  }
71 
72  maxcnt = w * h;
73 
74  if ((res = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
75  return res;
76  out = frame->data[0];
77  if (c->prev.data[0]) {
78  prev = c->prev.data[0];
79  } else {
80  prev = NULL;
81  }
82 
83  for (i = 0; i < 8; i++)
84  offsets[i] = -1;
85 
86  while (outcnt < maxcnt && buf_end - 2 >= buf) {
87  int code = AV_RL16(buf);
88  buf += 2;
89 
90  if (!(code & 0x8000)) {
91  AV_WN16A(&out[2 * outcnt], code); // rgb555 pixel coded directly
92  outcnt++;
93  } else {
94  int count;
95 
96  if ((code & 0x6000) == 0x6000) {
97  // copy from previous frame
98  int oidx = (code >> 10) & 7;
99  int start;
100 
101  count = (code & 0x3FF) + 3;
102 
103  if (offsets[oidx] < 0) {
104  if (buf_end - 3 < buf)
105  break;
106  offsets[oidx] = AV_RL24(buf);
107  buf += 3;
108  }
109 
110  start = (outcnt + offsets[oidx]) % maxcnt;
111 
112  if (maxcnt - start < count || maxcnt - outcnt < count)
113  break;
114 
115  if (!prev) {
116  av_log(avctx, AV_LOG_ERROR,
117  "Frame reference does not exist\n");
118  break;
119  }
120 
121  memcpy(out + 2 * outcnt, prev + 2 * start, 2 * count);
122  } else {
123  // copy from earlier in this frame
124  int offset = (code & 0x1FFF) + 1;
125 
126  if (!(code & 0x6000)) {
127  count = 2;
128  } else if ((code & 0x6000) == 0x2000) {
129  count = 3;
130  } else {
131  if (buf_end - 1 < buf)
132  break;
133  count = 4 + *buf++;
134  }
135 
136  if (outcnt < offset || maxcnt - outcnt < count)
137  break;
138 
139  av_memcpy_backptr(out + 2 * outcnt, 2 * offset, 2 * count);
140  }
141  outcnt += count;
142  }
143  }
144 
145  if (outcnt - maxcnt)
146  av_log(avctx, AV_LOG_DEBUG, "frame finished with %d diff\n", outcnt - maxcnt);
147 
148  av_frame_unref(&c->prev);
149  if ((res = av_frame_ref(&c->prev, frame)) < 0)
150  return res;
151 
152  *got_frame = 1;
153 
154  return avpkt->size;
155 }
156 
158 {
159  KgvContext * const c = avctx->priv_data;
160 
161  c->avctx = avctx;
162  avctx->pix_fmt = AV_PIX_FMT_RGB555;
163  avctx->flags |= CODEC_FLAG_EMU_EDGE;
164 
165  return 0;
166 }
167 
169 {
170  decode_flush(avctx);
171  return 0;
172 }
173 
175  .name = "kgv1",
176  .type = AVMEDIA_TYPE_VIDEO,
177  .id = AV_CODEC_ID_KGV1,
178  .priv_data_size = sizeof(KgvContext),
179  .init = decode_init,
180  .close = decode_end,
181  .decode = decode_frame,
182  .flush = decode_flush,
183  .long_name = NULL_IF_CONFIG_SMALL("Kega Game Video"),
184  .capabilities = CODEC_CAP_DR1,
185 };
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
misc image utilities
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
void avcodec_set_dimensions(AVCodecContext *s, int width, int height)
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
#define AV_RL16
static av_cold int decode_end(AVCodecContext *avctx)
Definition: kgv1dec.c:168
AVFrame prev
Definition: kgv1dec.c:35
output residual component w
uint8_t
#define av_cold
Definition: attributes.h:78
#define CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
uint8_t * data
frame
Definition: stft.m:14
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Spectrum Plot time data
int flags
CODEC_FLAG_*.
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
const char * name
Name of the codec implementation.
static const uint8_t offset[127][2]
Definition: vf_spp.c:70
external API header
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition: imgutils.c:231
AVCodec ff_kgv1_decoder
Definition: kgv1dec.c:174
int width
picture width / height.
#define AV_WN16A(p, v)
Definition: intreadwrite.h:526
static void flush(AVCodecContext *avctx)
NULL
Definition: eval.c:55
or the Software in violation of any applicable export control laws in any jurisdiction Except as provided by mandatorily applicable UPF has no obligation to provide you with source code to the Software In the event Software contains any source code
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: kgv1dec.c:45
main external API structure.
static void close(AVCodecParserContext *s)
Definition: h264_parser.c:375
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void * buf
Definition: avisynth_c.h:594
static void decode_flush(AVCodecContext *avctx)
Definition: kgv1dec.c:38
synthesis window for stochastic i
AVCodecContext * avctx
Definition: kgv1dec.c:34
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:330
static av_cold int decode_init(AVCodecContext *avctx)
Definition: kgv1dec.c:157
#define AV_RL24
int av_frame_ref(AVFrame *dst, AVFrame *src)
Setup a new reference to the data described by an given frame.
Definition: frame.c:228
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
#define CODEC_FLAG_EMU_EDGE
Don&#39;t draw edges.
common internal api header.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:162
common internal and external API header
static double c[64]
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:269
void INT64 INT64 count
Definition: avisynth_c.h:594
void INT64 start
Definition: avisynth_c.h:594
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
deliberately overlapping memcpy implementation
Definition: mem.c:327
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31))))#define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac){}void ff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map){AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);return NULL;}return ac;}in_planar=av_sample_fmt_is_planar(in_fmt);out_planar=av_sample_fmt_is_planar(out_fmt);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;}int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){int use_generic=1;int len=in->nb_samples;int p;if(ac->dc){av_dlog(ac->avr,"%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> out
static int decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: crystalhd.c:868
This structure stores compressed data.
#define AV_GET_BUFFER_FLAG_REF
The decoder will keep a reference to the frame and may reuse it later.