00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/intreadwrite.h"
00028 #include "libavutil/imgutils.h"
00029 #include "avcodec.h"
00030
00031 typedef struct {
00032 AVCodecContext *avctx;
00033 AVFrame pic;
00034 uint16_t *prev, *cur;
00035 } KgvContext;
00036
00037 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt)
00038 {
00039 const uint8_t *buf = avpkt->data;
00040 const uint8_t *buf_end = buf + avpkt->size;
00041 KgvContext * const c = avctx->priv_data;
00042 int offsets[7];
00043 uint16_t *out, *prev;
00044 int outcnt = 0, maxcnt;
00045 int w, h, i;
00046
00047 if (avpkt->size < 2)
00048 return -1;
00049
00050 w = (buf[0] + 1) * 8;
00051 h = (buf[1] + 1) * 8;
00052 buf += 2;
00053
00054 if (av_image_check_size(w, h, 0, avctx))
00055 return -1;
00056
00057 if (w != avctx->width || h != avctx->height)
00058 avcodec_set_dimensions(avctx, w, h);
00059
00060 maxcnt = w * h;
00061
00062 out = av_realloc(c->cur, w * h * 2);
00063 if (!out)
00064 return -1;
00065 c->cur = out;
00066
00067 prev = av_realloc(c->prev, w * h * 2);
00068 if (!prev)
00069 return -1;
00070 c->prev = prev;
00071
00072 for (i = 0; i < 7; i++)
00073 offsets[i] = -1;
00074
00075 while (outcnt < maxcnt && buf_end - 2 > buf) {
00076 int code = AV_RL16(buf);
00077 buf += 2;
00078
00079 if (!(code & 0x8000)) {
00080 out[outcnt++] = code;
00081 } else {
00082 int count;
00083 uint16_t *inp;
00084
00085 if ((code & 0x6000) == 0x6000) {
00086
00087 int oidx = (code >> 10) & 7;
00088 int start;
00089
00090 count = (code & 0x3FF) + 3;
00091
00092 if (offsets[oidx] < 0) {
00093 if (buf_end - 3 < buf)
00094 break;
00095 offsets[oidx] = AV_RL24(buf);
00096 buf += 3;
00097 }
00098
00099 start = (outcnt + offsets[oidx]) % maxcnt;
00100
00101 if (maxcnt - start < count)
00102 break;
00103
00104 inp = prev + start;
00105 } else {
00106
00107 int offset = (code & 0x1FFF) + 1;
00108
00109 if (!(code & 0x6000)) {
00110 count = 2;
00111 } else if ((code & 0x6000) == 0x2000) {
00112 count = 3;
00113 } else {
00114 if (buf_end - 1 < buf)
00115 break;
00116 count = 4 + *buf++;
00117 }
00118
00119 if (outcnt < offset)
00120 break;
00121
00122 inp = out + outcnt - offset;
00123 }
00124
00125 if (maxcnt - outcnt < count)
00126 break;
00127
00128 for (i = 0; i < count; i++)
00129 out[outcnt++] = inp[i];
00130 }
00131 }
00132
00133 if (outcnt - maxcnt)
00134 av_log(avctx, AV_LOG_DEBUG, "frame finished with %d diff\n", outcnt - maxcnt);
00135
00136 c->pic.data[0] = (uint8_t *)c->cur;
00137 c->pic.linesize[0] = w * 2;
00138
00139 *data_size = sizeof(AVFrame);
00140 *(AVFrame*)data = c->pic;
00141
00142 FFSWAP(uint16_t *, c->cur, c->prev);
00143
00144 return avpkt->size;
00145 }
00146
00147 static av_cold int decode_init(AVCodecContext *avctx)
00148 {
00149 KgvContext * const c = avctx->priv_data;
00150
00151 c->avctx = avctx;
00152 avctx->pix_fmt = PIX_FMT_RGB555;
00153 avcodec_get_frame_defaults(&c->pic);
00154
00155 return 0;
00156 }
00157
00158 static av_cold int decode_end(AVCodecContext *avctx)
00159 {
00160 KgvContext * const c = avctx->priv_data;
00161
00162 av_freep(&c->cur);
00163 av_freep(&c->prev);
00164
00165 return 0;
00166 }
00167
00168 AVCodec ff_kgv1_decoder = {
00169 .name = "kgv1",
00170 .type = AVMEDIA_TYPE_VIDEO,
00171 .id = CODEC_ID_KGV1,
00172 .priv_data_size = sizeof(KgvContext),
00173 .init = decode_init,
00174 .close = decode_end,
00175 .decode = decode_frame,
00176 .long_name = NULL_IF_CONFIG_SMALL("Kega Game Video"),
00177 };