# HG changeset patch # User melanson # Date 1109643898 0 # Node ID eace30b706016dea49114fa8c9c4b11ed8fd2220 # Parent f6a13db551aa4337db654a200cc5ae93afe4aced go LOCO, courtesy of Kostya Shishkov diff -r f6a13db551aa -r eace30b70601 Makefile --- a/Makefile Mon Feb 28 05:27:21 2005 +0000 +++ b/Makefile Tue Mar 01 02:24:58 2005 +0000 @@ -22,7 +22,7 @@ smc.o parser.o flicvideo.o truemotion1.o vmdav.o lcl.o qtrle.o g726.o \ flac.o vp3dsp.o integer.o snow.o tscc.o sonic.o ulti.o h264idct.o \ qdrw.o xl.o rangecoder.o png.o pnm.o qpeg.o vc9.o h263.o h261.o \ - msmpeg4.o h263dec.o svq1.o rv10.o wmadec.o indeo3.o shorten.o + msmpeg4.o h263dec.o svq1.o rv10.o wmadec.o indeo3.o shorten.o loco.o AMROBJS= ifeq ($(AMR_NB),yes) diff -r f6a13db551aa -r eace30b70601 allcodecs.c --- a/allcodecs.c Mon Feb 28 05:27:21 2005 +0000 +++ b/allcodecs.c Tue Mar 01 02:24:58 2005 +0000 @@ -125,6 +125,7 @@ register_avcodec(&qdraw_decoder); register_avcodec(&xl_decoder); register_avcodec(&qpeg_decoder); + register_avcodec(&loco_decoder); #ifdef CONFIG_FAAD register_avcodec(&aac_decoder); register_avcodec(&mpeg4aac_decoder); diff -r f6a13db551aa -r eace30b70601 avcodec.h --- a/avcodec.h Mon Feb 28 05:27:21 2005 +0000 +++ b/avcodec.h Tue Mar 01 02:24:58 2005 +0000 @@ -17,7 +17,7 @@ #define FFMPEG_VERSION_INT 0x000409 #define FFMPEG_VERSION "0.4.9-pre1" -#define LIBAVCODEC_BUILD 4743 +#define LIBAVCODEC_BUILD 4744 #define LIBAVCODEC_VERSION_INT FFMPEG_VERSION_INT #define LIBAVCODEC_VERSION FFMPEG_VERSION @@ -104,7 +104,7 @@ CODEC_ID_RV40, CODEC_ID_VC9, CODEC_ID_WMV3, - + CODEC_ID_LOCO, /* various pcm "codecs" */ CODEC_ID_PCM_S16LE= 0x10000, @@ -2010,6 +2010,7 @@ extern AVCodec xl_decoder; extern AVCodec qpeg_decoder; extern AVCodec shorten_decoder; +extern AVCodec loco_decoder; /* pcm codecs */ #define PCM_CODEC(id, name) \ diff -r f6a13db551aa -r eace30b70601 loco.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loco.c Tue Mar 01 02:24:58 2005 +0000 @@ -0,0 +1,319 @@ +/* + * LOCO codec + * Copyright (c) 2005 Konstantin Shishkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/** + * @file loco.c + * LOCO codec. + */ + +#include "avcodec.h" +#include "common.h" +#include "bitstream.h" +#include "golomb.h" + +enum LOCO_MODE {LOCO_UNKN=0, LOCO_CYUY2=-1, LOCO_CRGB=-2, LOCO_CYV12=-3, + LOCO_YUY2=1, LOCO_UYVY=2, LOCO_RGB=3, LOCO_RGBA=4, LOCO_YV12=5}; + +typedef struct LOCOContext{ + AVCodecContext *avctx; + AVFrame pic; + int lossy; + int mode; +} LOCOContext; + +typedef struct RICEContext{ + GetBitContext gb; + int save, run, run2; /* internal rice decoder state */ + int sum, count; /* sum and count for getting rice parameter */ +}RICEContext; + +/* could use get_sr_golomb() but is behaves differently on numbers like Rice(2, -64) */ +static inline int get_rice(GetBitContext *gb, int K) +{ + int i; + int V = 0; + for(i = 0; !get_bits1(gb); i++); + V = i; + for(i = 0; i < K; i++) V = (V << 1) | get_bits1(gb); + if(V & 1) return (V + 1) >> 1; + return -(V >> 1); +} + +static inline int get_u_rice(GetBitContext *gb, int K) +{ + int i; + int V = 0; + for(i = 0; !get_bits1(gb); i++); + V = i; + for(i = 0; i < K; i++) V = (V << 1) | get_bits1(gb); + return V; +} + +static int loco_get_rice_param(RICEContext *r) +{ + int cnt = 0; + int val = r->count; + + while(r->sum > val && cnt < 9) { + val <<= 1; + cnt++; + } + + return cnt; +} + +static inline void loco_update_rice_param(RICEContext *r, int val) +{ + if (val < 0) + val = -val; + r->sum += val; + r->count++; + + if(r->count == 16) { + r->sum >>= 1; + r->count >>= 1; + } +} + +static inline int loco_get_rice(RICEContext *r) +{ + int v; + + if (r->run > 0) { /* we have zero run */ + r->run--; + return 0; + } + v = -get_rice(&r->gb, loco_get_rice_param(r)); + if (!v) { + if (r->save >= 0) { + r->run = get_u_rice(&r->gb, 2); + if(r->run > 1) + r->save += r->run + 1; + else + r->save -= 3; + } + else + r->run2++; + } else if (r->run2 > 0) { + if (r->run2 > 2) + r->save += r->run2; + else + r->save -= 3; + r->run2 = 0; + } + + return v; +} + +/* LOCO main predictor - LOCO-I/JPEG-LS predictor */ +static inline int loco_predict(uint8_t* data, int stride, int step) +{ + int max_ab, min_ab; + int a, b, c; + + a = data[-stride]; + b = data[-step]; + c = data[-stride - step]; + + max_ab = (a > b) ? a : b; + min_ab = (a < b) ? a : b; + + if (c >= max_ab) return min_ab; + if (c <= min_ab) return max_ab; + return (a + b - c); +} + +static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int height, + int stride, uint8_t *buf, int buf_size, int step) +{ + RICEContext rc; + int val; + int i, j; + + init_get_bits(&rc.gb, buf, buf_size*8); + rc.save = 0; + rc.run = 0; + rc.run2 = 0; + + rc.sum = 8; + rc.count = 1; + + /* restore top left pixel */ + val = loco_get_rice(&rc); + loco_update_rice_param(&rc, val); + if (val < 0) val -= l->lossy; + if (val > 0) val += l->lossy; + data[0] = 128 + val; + /* restore top line */ + for (i = 1; i < width; i++) { + val = loco_get_rice(&rc); + loco_update_rice_param(&rc, val); + if (val < 0) val -= l->lossy; + if (val > 0) val += l->lossy; + data[i * step] = data[i * step - step] + val; + } + data += stride; + for (j = 1; j < height; j++) { + /* restore left column */ + val = loco_get_rice(&rc); + loco_update_rice_param(&rc, val); + if (val < 0) val -= l->lossy; + if (val > 0) val += l->lossy; + data[0] = data[-stride] + val; + /* restore all other pixels */ + for (i = 1; i < width; i++) { + val = loco_get_rice(&rc); + loco_update_rice_param(&rc, val); + if (val < 0) val -= l->lossy; + if (val > 0) val += l->lossy; + data[i * step] = loco_predict(&data[i * step], stride, step) + val; + } + data += stride; + } + + return ((get_bits_count(&rc.gb) + 7) >> 3); +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + LOCOContext * const l = avctx->priv_data; + AVFrame * const p= (AVFrame*)&l->pic; + int decoded; + + if(p->data[0]) + avctx->release_buffer(avctx, p); + + p->reference = 0; + if(avctx->get_buffer(avctx, p) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + p->key_frame = 1; + + switch(l->mode) { + case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY: + decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height, + p->linesize[1], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height, + p->linesize[2], buf, buf_size, 1); + break; + case LOCO_CYV12: case LOCO_YV12: + decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2, + p->linesize[1], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2, + p->linesize[2], buf, buf_size, 1); + break; + case LOCO_CRGB: case LOCO_RGB: + decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 3); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 3); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 3); + break; + case LOCO_RGBA: + decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 3, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + break; + } + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = l->pic; + + return buf_size; +} + +static int decode_init(AVCodecContext *avctx){ + LOCOContext * const l = avctx->priv_data; + int version; + + l->avctx = avctx; + if (avctx->extradata_size < 12) { + av_log(avctx, AV_LOG_ERROR, "Extradata size must be >= 12 instead of %i\n", + avctx->extradata_size); + return -1; + } + version = LE_32(avctx->extradata); + switch(version) { + case 1: + l->lossy = 0; + break; + case 2: + l->lossy = LE_32(avctx->extradata + 8); + break; + default: + l->lossy = LE_32(avctx->extradata + 8); + av_log(avctx, AV_LOG_INFO, "This is LOCO codec version %i, please upload file for study\n", version); + } + + l->mode = LE_32(avctx->extradata + 4); + switch(l->mode) { + case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY: + avctx->pix_fmt = PIX_FMT_YUV422P; + break; + case LOCO_CRGB: case LOCO_RGB: + avctx->pix_fmt = PIX_FMT_BGR24; + break; + case LOCO_CYV12: case LOCO_YV12: + avctx->pix_fmt = PIX_FMT_YUV420P; + break; + case LOCO_RGBA: + avctx->pix_fmt = PIX_FMT_RGBA32; + break; + default: + av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode); + return -1; + } + + return 0; +} + +AVCodec loco_decoder = { + "loco", + CODEC_TYPE_VIDEO, + CODEC_ID_LOCO, + sizeof(LOCOContext), + decode_init, + NULL, + NULL, + decode_frame, + CODEC_CAP_DR1, +};