diff options
author | Mike Melanson <mike@multimedia.cx> | 2005-03-01 02:24:58 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2005-03-01 02:24:58 +0000 |
commit | 9c7fb60816035a8921e770155cffb11757be7a23 (patch) | |
tree | 7e9ef1c9e2d223216e372b0adaa4bacc7fadecbb | |
parent | 56b31a8ee2fa07d2a26e4fe2976157da6c1af637 (diff) | |
download | ffmpeg-9c7fb60816035a8921e770155cffb11757be7a23.tar.gz |
go LOCO, courtesy of Kostya Shishkov
Originally committed as revision 3995 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | doc/ffmpeg-doc.texi | 1 | ||||
-rw-r--r-- | libavcodec/Makefile | 2 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 1 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 5 | ||||
-rw-r--r-- | libavcodec/loco.c | 319 | ||||
-rw-r--r-- | libavformat/avienc.c | 1 |
7 files changed, 327 insertions, 3 deletions
@@ -10,6 +10,7 @@ version <next> - QPEG video decoder - Nullsoft Video (NSV) file demuxer - Shorten audio decoder +- LOCO video decoder version 0.4.9-pre1: diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi index 249c7b1829..af49c2ca3e 100644 --- a/doc/ffmpeg-doc.texi +++ b/doc/ffmpeg-doc.texi @@ -772,6 +772,7 @@ following image formats are supported: @item IBM Ultimotion @tab @tab X @tab fourcc: ULTI @item Miro VideoXL @tab @tab X @tab fourcc: VIXL @item QPEG @tab @tab X @tab fourccs: QPEG, Q1.0, Q1.1 +@item LOCO @tab @tab X @tab @end multitable @code{X} means that the encoding (resp. decoding) is supported. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index dec7d59ceb..63207693b5 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -22,7 +22,7 @@ OBJS= bitstream.o utils.o mem.o allcodecs.o \ 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 --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 80153bc404..285cfcf225 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -125,6 +125,7 @@ void avcodec_register_all(void) 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 --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index d3a069af7b..b4ab5b3d83 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -17,7 +17,7 @@ extern "C" { #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 @@ enum CodecID { 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 qdraw_decoder; extern AVCodec xl_decoder; extern AVCodec qpeg_decoder; extern AVCodec shorten_decoder; +extern AVCodec loco_decoder; /* pcm codecs */ #define PCM_CODEC(id, name) \ diff --git a/libavcodec/loco.c b/libavcodec/loco.c new file mode 100644 index 0000000000..92af609f40 --- /dev/null +++ b/libavcodec/loco.c @@ -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, +}; diff --git a/libavformat/avienc.c b/libavformat/avienc.c index 8ecff24caf..3fcee51ce4 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -177,6 +177,7 @@ const CodecTag codec_bmp_tags[] = { { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '0') }, { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '1') }, { CODEC_ID_WMV3, MKTAG('W', 'M', 'V', '3') }, + { CODEC_ID_LOCO, MKTAG('L', 'O', 'C', 'O') }, { CODEC_ID_RAWVIDEO, 0 }, { 0, 0 }, }; |