loco.c
Go to the documentation of this file.
1 /*
2  * LOCO codec
3  * Copyright (c) 2005 Konstantin Shishkov
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
27 #include "avcodec.h"
28 #include "get_bits.h"
29 #include "golomb.h"
30 #include "mathops.h"
31 
34 
35 typedef struct LOCOContext{
38  int lossy;
39  int mode;
40 } LOCOContext;
41 
42 typedef struct RICEContext{
44  int save, run, run2; /* internal rice decoder state */
45  int sum, count; /* sum and count for getting rice parameter */
46  int lossy;
48 
50 {
51  int cnt = 0;
52  int val = r->count;
53 
54  while(r->sum > val && cnt < 9) {
55  val <<= 1;
56  cnt++;
57  }
58 
59  return cnt;
60 }
61 
62 static inline void loco_update_rice_param(RICEContext *r, int val)
63 {
64  r->sum += val;
65  r->count++;
66 
67  if(r->count == 16) {
68  r->sum >>= 1;
69  r->count >>= 1;
70  }
71 }
72 
73 static inline int loco_get_rice(RICEContext *r)
74 {
75  int v;
76  if (r->run > 0) { /* we have zero run */
77  r->run--;
79  return 0;
80  }
81  v = get_ur_golomb_jpegls(&r->gb, loco_get_rice_param(r), INT_MAX, 0);
82  loco_update_rice_param(r, (v+1)>>1);
83  if (!v) {
84  if (r->save >= 0) {
85  r->run = get_ur_golomb_jpegls(&r->gb, 2, INT_MAX, 0);
86  if(r->run > 1)
87  r->save += r->run + 1;
88  else
89  r->save -= 3;
90  }
91  else
92  r->run2++;
93  } else {
94  v = ((v>>1) + r->lossy) ^ -(v&1);
95  if (r->run2 > 0) {
96  if (r->run2 > 2)
97  r->save += r->run2;
98  else
99  r->save -= 3;
100  r->run2 = 0;
101  }
102  }
103 
104  return v;
105 }
106 
107 /* LOCO main predictor - LOCO-I/JPEG-LS predictor */
108 static inline int loco_predict(uint8_t* data, int stride, int step)
109 {
110  int a, b, c;
111 
112  a = data[-stride];
113  b = data[-step];
114  c = data[-stride - step];
115 
116  return mid_pred(a, a + b - c, b);
117 }
118 
119 static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int height,
120  int stride, const uint8_t *buf, int buf_size, int step)
121 {
122  RICEContext rc;
123  int val;
124  int i, j;
125 
126  init_get_bits(&rc.gb, buf, buf_size*8);
127  rc.save = 0;
128  rc.run = 0;
129  rc.run2 = 0;
130  rc.lossy = l->lossy;
131 
132  rc.sum = 8;
133  rc.count = 1;
134 
135  /* restore top left pixel */
136  val = loco_get_rice(&rc);
137  data[0] = 128 + val;
138  /* restore top line */
139  for (i = 1; i < width; i++) {
140  val = loco_get_rice(&rc);
141  data[i * step] = data[i * step - step] + val;
142  }
143  data += stride;
144  for (j = 1; j < height; j++) {
145  /* restore left column */
146  val = loco_get_rice(&rc);
147  data[0] = data[-stride] + val;
148  /* restore all other pixels */
149  for (i = 1; i < width; i++) {
150  val = loco_get_rice(&rc);
151  data[i * step] = loco_predict(&data[i * step], stride, step) + val;
152  }
153  data += stride;
154  }
155 
156  return (get_bits_count(&rc.gb) + 7) >> 3;
157 }
158 
159 static int decode_frame(AVCodecContext *avctx,
160  void *data, int *data_size,
161  AVPacket *avpkt)
162 {
163  const uint8_t *buf = avpkt->data;
164  int buf_size = avpkt->size;
165  LOCOContext * const l = avctx->priv_data;
166  AVFrame * const p= (AVFrame*)&l->pic;
167  int decoded;
168 
169  if(p->data[0])
170  avctx->release_buffer(avctx, p);
171 
172  p->reference = 0;
173  if(avctx->get_buffer(avctx, p) < 0){
174  av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
175  return -1;
176  }
177  p->key_frame = 1;
178 
179  switch(l->mode) {
180  case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY:
181  decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
182  p->linesize[0], buf, buf_size, 1);
183  buf += decoded; buf_size -= decoded;
184  decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height,
185  p->linesize[1], buf, buf_size, 1);
186  buf += decoded; buf_size -= decoded;
187  decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height,
188  p->linesize[2], buf, buf_size, 1);
189  break;
190  case LOCO_CYV12: case LOCO_YV12:
191  decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
192  p->linesize[0], buf, buf_size, 1);
193  buf += decoded; buf_size -= decoded;
194  decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2,
195  p->linesize[2], buf, buf_size, 1);
196  buf += decoded; buf_size -= decoded;
197  decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2,
198  p->linesize[1], buf, buf_size, 1);
199  break;
200  case LOCO_CRGB: case LOCO_RGB:
201  decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height,
202  -p->linesize[0], buf, buf_size, 3);
203  buf += decoded; buf_size -= decoded;
204  decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height,
205  -p->linesize[0], buf, buf_size, 3);
206  buf += decoded; buf_size -= decoded;
207  decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height,
208  -p->linesize[0], buf, buf_size, 3);
209  break;
210  case LOCO_RGBA:
211  decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
212  p->linesize[0], buf, buf_size, 4);
213  buf += decoded; buf_size -= decoded;
214  decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height,
215  p->linesize[0], buf, buf_size, 4);
216  buf += decoded; buf_size -= decoded;
217  decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height,
218  p->linesize[0], buf, buf_size, 4);
219  buf += decoded; buf_size -= decoded;
220  decoded = loco_decode_plane(l, p->data[0] + 3, avctx->width, avctx->height,
221  p->linesize[0], buf, buf_size, 4);
222  break;
223  }
224 
225  *data_size = sizeof(AVFrame);
226  *(AVFrame*)data = l->pic;
227 
228  return buf_size;
229 }
230 
231 static av_cold int decode_init(AVCodecContext *avctx){
232  LOCOContext * const l = avctx->priv_data;
233  int version;
234 
235  l->avctx = avctx;
236  if (avctx->extradata_size < 12) {
237  av_log(avctx, AV_LOG_ERROR, "Extradata size must be >= 12 instead of %i\n",
238  avctx->extradata_size);
239  return -1;
240  }
241  version = AV_RL32(avctx->extradata);
242  switch(version) {
243  case 1:
244  l->lossy = 0;
245  break;
246  case 2:
247  l->lossy = AV_RL32(avctx->extradata + 8);
248  break;
249  default:
250  l->lossy = AV_RL32(avctx->extradata + 8);
251  av_log_ask_for_sample(avctx, "This is LOCO codec version %i.\n", version);
252  }
253 
254  l->mode = AV_RL32(avctx->extradata + 4);
255  switch(l->mode) {
256  case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY:
257  avctx->pix_fmt = PIX_FMT_YUV422P;
258  break;
259  case LOCO_CRGB: case LOCO_RGB:
260  avctx->pix_fmt = PIX_FMT_BGR24;
261  break;
262  case LOCO_CYV12: case LOCO_YV12:
263  avctx->pix_fmt = PIX_FMT_YUV420P;
264  break;
265  case LOCO_CRGBA: case LOCO_RGBA:
266  avctx->pix_fmt = PIX_FMT_RGB32;
267  break;
268  default:
269  av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode);
270  return -1;
271  }
272  if(avctx->debug & FF_DEBUG_PICT_INFO)
273  av_log(avctx, AV_LOG_INFO, "lossy:%i, version:%i, mode: %i\n", l->lossy, version, l->mode);
274 
275  return 0;
276 }
277 
278 static av_cold int decode_end(AVCodecContext *avctx){
279  LOCOContext * const l = avctx->priv_data;
280  AVFrame *pic = &l->pic;
281 
282  if (pic->data[0])
283  avctx->release_buffer(avctx, pic);
284 
285  return 0;
286 }
287 
289  .name = "loco",
290  .type = AVMEDIA_TYPE_VIDEO,
291  .id = CODEC_ID_LOCO,
292  .priv_data_size = sizeof(LOCOContext),
293  .init = decode_init,
294  .close = decode_end,
295  .decode = decode_frame,
296  .capabilities = CODEC_CAP_DR1,
297  .long_name = NULL_IF_CONFIG_SMALL("LOCO"),
298 };