## ffmpeg / libavcodec / lagarith.c @ b0c8b8a6

History | View | Annotate | Download (14.8 KB)

1 | d267b339 | Carl Eugen Hoyos | ```
/*
``` |
---|---|---|---|

2 | ```
* Lagarith lossless decoder
``` |
||

3 | ```
* Copyright (c) 2009 Nathan Caldwell <saintdev (at) gmail.com>
``` |
||

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 libavcodec/lagarith.c
``` |
||

24 | ```
* Lagarith lossless decoder
``` |
||

25 | ```
* @author Nathan Caldwell
``` |
||

26 | ```
*/
``` |
||

27 | |||

28 | #include "avcodec.h" |
||

29 | #include "get_bits.h" |
||

30 | #include "mathops.h" |
||

31 | #include "dsputil.h" |
||

32 | #include "lagarithrac.h" |
||

33 | |||

34 | ```
enum LagarithFrameType {
``` |
||

35 | FRAME_RAW = 1, /*!< uncompressed */ |
||

36 | FRAME_U_RGB24 = 2, /*!< unaligned RGB24 */ |
||

37 | FRAME_ARITH_YUY2 = 3, /*!< arithmetic coded YUY2 */ |
||

38 | FRAME_ARITH_RGB24 = 4, /*!< arithmetic coded RGB24 */ |
||

39 | FRAME_SOLID_GRAY = 5, /*!< solid grayscale color frame */ |
||

40 | FRAME_SOLID_COLOR = 6, /*!< solid non-grayscale color frame */ |
||

41 | FRAME_OLD_ARITH_RGB = 7, /*!< obsolete arithmetic coded RGB (no longer encoded by upstream since version 1.1.0) */ |
||

42 | FRAME_ARITH_RGBA = 8, /*!< arithmetic coded RGBA */ |
||

43 | FRAME_SOLID_RGBA = 9, /*!< solid RGBA color frame */ |
||

44 | FRAME_ARITH_YV12 = 10, /*!< arithmetic coded YV12 */ |
||

45 | FRAME_REDUCED_RES = 11, /*!< reduced resolution YV12 frame */ |
||

46 | }; |
||

47 | |||

48 | typedef struct LagarithContext { |
||

49 | AVCodecContext *avctx; |
||

50 | AVFrame picture; |
||

51 | DSPContext dsp; |
||

52 | int zeros; /*!< number of consecutive zero bytes encountered */ |
||

53 | int zeros_rem; /*!< number of zero bytes remaining to output */ |
||

54 | } LagarithContext; |
||

55 | |||

56 | ```
/**
``` |
||

57 | ```
* Compute the 52bit mantissa of 1/(double)denom.
``` |
||

58 | ```
* This crazy format uses floats in an entropy coder and we have to match x86
``` |
||

59 | ```
* rounding exactly, thus ordinary floats aren't portable enough.
``` |
||

60 | ```
* @param denom denominator
``` |
||

61 | ```
* @return 52bit mantissa
``` |
||

62 | ```
* @see softfloat_mul
``` |
||

63 | ```
*/
``` |
||

64 | ```
static uint64_t softfloat_reciprocal(uint32_t denom)
``` |
||

65 | { |
||

66 | int shift = av_log2(denom - 1) + 1; |
||

67 | uint64_t ret = (1ULL << 52) / denom; |
||

68 | uint64_t err = (1ULL << 52) - ret * denom; |
||

69 | ret <<= shift; |
||

70 | err <<= shift; |
||

71 | ```
err += denom / 2;
``` |
||

72 | ```
return ret + err / denom;
``` |
||

73 | } |
||

74 | |||

75 | ```
/**
``` |
||

76 | ```
* (uint32_t)(x*f), where f has the given mantissa, and exponent 0
``` |
||

77 | ```
* Used in combination with softfloat_reciprocal computes x/(double)denom.
``` |
||

78 | ```
* @param x 32bit integer factor
``` |
||

79 | ```
* @param mantissa mantissa of f with exponent 0
``` |
||

80 | ```
* @return 32bit integer value (x*f)
``` |
||

81 | ```
* @see softfloat_reciprocal
``` |
||

82 | ```
*/
``` |
||

83 | ```
static uint32_t softfloat_mul(uint32_t x, uint64_t mantissa)
``` |
||

84 | { |
||

85 | ```
uint64_t l = x * (mantissa & 0xffffffff);
``` |
||

86 | ```
uint64_t h = x * (mantissa >> 32);
``` |
||

87 | ```
h += l >> 32;
``` |
||

88 | ```
l &= 0xffffffff;
``` |
||

89 | l += 1 << av_log2(h >> 21); |
||

90 | ```
h += l >> 32;
``` |
||

91 | return h >> 20; |
||

92 | } |
||

93 | |||

94 | ```
static uint8_t lag_calc_zero_run(int8_t x)
``` |
||

95 | { |
||

96 | return (x << 1) ^ (x >> 7); |
||

97 | } |
||

98 | |||

99 | static int lag_decode_prob(GetBitContext *gb, uint32_t *value) |
||

100 | { |
||

101 | static const uint8_t series[] = { 1, 2, 3, 5, 8, 13, 21 }; |
||

102 | ```
int i;
``` |
||

103 | int bit = 0; |
||

104 | int bits = 0; |
||

105 | int prevbit = 0; |
||

106 | ```
unsigned val;
``` |
||

107 | |||

108 | for (i = 0; i < 7; i++) { |
||

109 | ```
if (prevbit && bit)
``` |
||

110 | ```
break;
``` |
||

111 | prevbit = bit; |
||

112 | bit = get_bits1(gb); |
||

113 | ```
if (bit && !prevbit)
``` |
||

114 | bits += series[i]; |
||

115 | } |
||

116 | bits--; |
||

117 | if (bits < 0 || bits > 31) { |
||

118 | ```
*value = 0;
``` |
||

119 | return -1; |
||

120 | } else if (bits == 0) { |
||

121 | ```
*value = 0;
``` |
||

122 | return 0; |
||

123 | } |
||

124 | |||

125 | val = get_bits_long(gb, bits); |
||

126 | ```
val |= 1 << bits;
``` |
||

127 | |||

128 | ```
*value = val - 1;
``` |
||

129 | |||

130 | return 0; |
||

131 | } |
||

132 | |||

133 | static int lag_read_prob_header(lag_rac *rac, GetBitContext *gb) |
||

134 | { |
||

135 | ```
int i, j, scale_factor;
``` |
||

136 | ```
unsigned prob, cumulative_target;
``` |
||

137 | unsigned cumul_prob = 0; |
||

138 | unsigned scaled_cumul_prob = 0; |
||

139 | |||

140 | rac->prob[0] = 0; |
||

141 | ```
rac->prob[257] = UINT_MAX;
``` |
||

142 | ```
/* Read probabilities from bitstream */
``` |
||

143 | for (i = 1; i < 257; i++) { |
||

144 | if (lag_decode_prob(gb, &rac->prob[i]) < 0) { |
||

145 | ```
av_log(rac->avctx, AV_LOG_ERROR, "Invalid probability encountered.\n");
``` |
||

146 | return -1; |
||

147 | } |
||

148 | ```
if ((uint64_t)cumul_prob + rac->prob[i] > UINT_MAX) {
``` |
||

149 | ```
av_log(rac->avctx, AV_LOG_ERROR, "Integer overflow encountered in cumulative probability calculation.\n");
``` |
||

150 | return -1; |
||

151 | } |
||

152 | cumul_prob += rac->prob[i]; |
||

153 | ```
if (!rac->prob[i]) {
``` |
||

154 | ```
if (lag_decode_prob(gb, &prob)) {
``` |
||

155 | ```
av_log(rac->avctx, AV_LOG_ERROR, "Invalid probability run encountered.\n");
``` |
||

156 | return -1; |
||

157 | } |
||

158 | if (prob > 257 - i) |
||

159 | ```
prob = 257 - i;
``` |
||

160 | for (j = 0; j < prob; j++) |
||

161 | ```
rac->prob[++i] = 0;
``` |
||

162 | } |
||

163 | } |
||

164 | |||

165 | ```
if (!cumul_prob) {
``` |
||

166 | ```
av_log(rac->avctx, AV_LOG_ERROR, "All probabilities are 0!\n");
``` |
||

167 | return -1; |
||

168 | } |
||

169 | |||

170 | ```
/* Scale probabilities so cumulative probability is an even power of 2. */
``` |
||

171 | scale_factor = av_log2(cumul_prob); |
||

172 | |||

173 | if (cumul_prob & (cumul_prob - 1)) { |
||

174 | uint64_t mul = softfloat_reciprocal(cumul_prob); |
||

175 | for (i = 1; i < 257; i++) { |
||

176 | rac->prob[i] = softfloat_mul(rac->prob[i], mul); |
||

177 | scaled_cumul_prob += rac->prob[i]; |
||

178 | } |
||

179 | |||

180 | scale_factor++; |
||

181 | ```
cumulative_target = 1 << scale_factor;
``` |
||

182 | |||

183 | ```
if (scaled_cumul_prob > cumulative_target) {
``` |
||

184 | av_log(rac->avctx, AV_LOG_ERROR, |
||

185 | ```
"Scaled probabilities are larger than target!\n");
``` |
||

186 | return -1; |
||

187 | } |
||

188 | |||

189 | scaled_cumul_prob = cumulative_target - scaled_cumul_prob; |
||

190 | |||

191 | for (i = 1; scaled_cumul_prob; i = (i & 0x7f) + 1) { |
||

192 | ```
if (rac->prob[i]) {
``` |
||

193 | rac->prob[i]++; |
||

194 | scaled_cumul_prob--; |
||

195 | } |
||

196 | ```
/* Comment from reference source:
``` |
||

197 | ```
* if (b & 0x80 == 0) { // order of operations is 'wrong'; it has been left this way
``` |
||

198 | ```
* // since the compression change is negligable and fixing it
``` |
||

199 | ```
* // breaks backwards compatibilty
``` |
||

200 | ```
* b =- (signed int)b;
``` |
||

201 | ```
* b &= 0xFF;
``` |
||

202 | ```
* } else {
``` |
||

203 | ```
* b++;
``` |
||

204 | ```
* b &= 0x7f;
``` |
||

205 | ```
* }
``` |
||

206 | ```
*/
``` |
||

207 | } |
||

208 | } |
||

209 | |||

210 | rac->scale = scale_factor; |
||

211 | |||

212 | ```
/* Fill probability array with cumulative probability for each symbol. */
``` |
||

213 | for (i = 1; i < 257; i++) |
||

214 | ```
rac->prob[i] += rac->prob[i - 1];
``` |
||

215 | |||

216 | return 0; |
||

217 | } |
||

218 | |||

219 | static void add_lag_median_prediction(uint8_t *dst, uint8_t *src1, |
||

220 | uint8_t *diff, int w, int *left, |
||

221 | ```
int *left_top)
``` |
||

222 | { |
||

223 | ```
/* This is almost identical to add_hfyu_median_prediction in dsputil.h.
``` |
||

224 | ```
* However the &0xFF on the gradient predictor yealds incorrect output
``` |
||

225 | ```
* for lagarith.
``` |
||

226 | ```
*/
``` |
||

227 | ```
int i;
``` |
||

228 | uint8_t l, lt; |
||

229 | |||

230 | l = *left; |
||

231 | lt = *left_top; |
||

232 | |||

233 | for (i = 0; i < w; i++) { |
||

234 | l = mid_pred(l, src1[i], l + src1[i] - lt) + diff[i]; |
||

235 | lt = src1[i]; |
||

236 | dst[i] = l; |
||

237 | } |
||

238 | |||

239 | *left = l; |
||

240 | *left_top = lt; |
||

241 | } |
||

242 | |||

243 | static void lag_pred_line(LagarithContext *l, uint8_t *buf, |
||

244 | int width, int stride, int line) |
||

245 | { |
||

246 | ```
int L, TL;
``` |
||

247 | |||

248 | ```
if (!line) {
``` |
||

249 | ```
/* Left prediction only for first line */
``` |
||

250 | L = l->dsp.add_hfyu_left_prediction(buf + 1, buf + 1, |
||

251 | width - 1, buf[0]); |
||

252 | ```
return;
``` |
||

253 | } else if (line == 1) { |
||

254 | ```
/* Second line, left predict first pixel, the rest of the line is median predicted */
``` |
||

255 | ```
/* FIXME: In the case of RGB this pixel is top predicted */
``` |
||

256 | TL = buf[-stride]; |
||

257 | ```
} else {
``` |
||

258 | ```
/* Top left is 2 rows back, last pixel */
``` |
||

259 | TL = buf[width - (2 * stride) - 1]; |
||

260 | } |
||

261 | ```
/* Left pixel is actually prev_row[width] */
``` |
||

262 | ```
L = buf[width - stride - 1];
``` |
||

263 | |||

264 | add_lag_median_prediction(buf, buf - stride, buf, |
||

265 | width, &L, &TL); |
||

266 | } |
||

267 | |||

268 | static int lag_decode_line(LagarithContext *l, lag_rac *rac, |
||

269 | uint8_t *dst, int width, int stride, |
||

270 | ```
int esc_count)
``` |
||

271 | { |
||

272 | int i = 0; |
||

273 | int ret = 0; |
||

274 | |||

275 | ```
if (!esc_count)
``` |
||

276 | ```
esc_count = -1;
``` |
||

277 | |||

278 | ```
/* Output any zeros remaining from the previous run */
``` |
||

279 | ```
handle_zeros:
``` |
||

280 | ```
if (l->zeros_rem) {
``` |
||

281 | ```
int count = FFMIN(l->zeros_rem, width - i);
``` |
||

282 | ```
memset(dst + i, 0, count);
``` |
||

283 | i += count; |
||

284 | l->zeros_rem -= count; |
||

285 | } |
||

286 | |||

287 | ```
while (i < width) {
``` |
||

288 | dst[i] = lag_get_rac(rac); |
||

289 | ret++; |
||

290 | |||

291 | ```
if (dst[i])
``` |
||

292 | ```
l->zeros = 0;
``` |
||

293 | ```
else
``` |
||

294 | l->zeros++; |
||

295 | |||

296 | i++; |
||

297 | ```
if (l->zeros == esc_count) {
``` |
||

298 | ```
int index = lag_get_rac(rac);
``` |
||

299 | ret++; |
||

300 | |||

301 | ```
l->zeros = 0;
``` |
||

302 | |||

303 | l->zeros_rem = lag_calc_zero_run(index); |
||

304 | ```
goto handle_zeros;
``` |
||

305 | } |
||

306 | } |
||

307 | ```
return ret;
``` |
||

308 | } |
||

309 | |||

310 | static int lag_decode_zero_run_line(LagarithContext *l, uint8_t *dst, |
||

311 | const uint8_t *src, int width, |
||

312 | ```
int esc_count)
``` |
||

313 | { |
||

314 | int i = 0; |
||

315 | ```
int count;
``` |
||

316 | ```
uint8_t zero_run = 0;
``` |
||

317 | ```
const uint8_t *start = src;
``` |
||

318 | ```
uint8_t mask1 = -(esc_count < 2);
``` |
||

319 | ```
uint8_t mask2 = -(esc_count < 3);
``` |
||

320 | ```
uint8_t *end = dst + (width - 2);
``` |
||

321 | |||

322 | ```
output_zeros:
``` |
||

323 | ```
if (l->zeros_rem) {
``` |
||

324 | count = FFMIN(l->zeros_rem, width - i); |
||

325 | ```
memset(dst, 0, count);
``` |
||

326 | l->zeros_rem -= count; |
||

327 | dst += count; |
||

328 | } |
||

329 | |||

330 | ```
while (dst < end) {
``` |
||

331 | ```
i = 0;
``` |
||

332 | ```
while (!zero_run && dst + i < end) {
``` |
||

333 | i++; |
||

334 | zero_run = |
||

335 | !(src[i] | (src[i + 1] & mask1) | (src[i + 2] & mask2)); |
||

336 | } |
||

337 | ```
if (zero_run) {
``` |
||

338 | ```
zero_run = 0;
``` |
||

339 | i += esc_count; |
||

340 | memcpy(dst, src, i); |
||

341 | dst += i; |
||

342 | l->zeros_rem = lag_calc_zero_run(src[i]); |
||

343 | |||

344 | ```
src += i + 1;
``` |
||

345 | ```
goto output_zeros;
``` |
||

346 | ```
} else {
``` |
||

347 | memcpy(dst, src, i); |
||

348 | src += i; |
||

349 | } |
||

350 | } |
||

351 | ```
return start - src;
``` |
||

352 | } |
||

353 | |||

354 | |||

355 | |||

356 | static int lag_decode_arith_plane(LagarithContext *l, uint8_t *dst, |
||

357 | int width, int height, int stride, |
||

358 | const uint8_t *src, int src_size) |
||

359 | { |
||

360 | int i = 0; |
||

361 | int read = 0; |
||

362 | uint32_t length; |
||

363 | ```
uint32_t offset = 1;
``` |
||

364 | int esc_count = src[0]; |
||

365 | GetBitContext gb; |
||

366 | lag_rac rac; |
||

367 | |||

368 | rac.avctx = l->avctx; |
||

369 | ```
l->zeros = 0;
``` |
||

370 | |||

371 | if (esc_count < 4) { |
||

372 | length = width * height; |
||

373 | if (esc_count && AV_RL32(src + 1) < length) { |
||

374 | ```
length = AV_RL32(src + 1);
``` |
||

375 | ```
offset += 4;
``` |
||

376 | } |
||

377 | |||

378 | ```
init_get_bits(&gb, src + offset, src_size * 8);
``` |
||

379 | |||

380 | if (lag_read_prob_header(&rac, &gb) < 0) |
||

381 | return -1; |
||

382 | |||

383 | lag_rac_init(&rac, &gb, length - stride); |
||

384 | |||

385 | for (i = 0; i < height; i++) |
||

386 | read += lag_decode_line(l, &rac, dst + (i * stride), width, |
||

387 | stride, esc_count); |
||

388 | |||

389 | ```
if (read > length)
``` |
||

390 | av_log(l->avctx, AV_LOG_WARNING, |
||

391 | ```
"Output more bytes than length (%d of %d)\n", read,
``` |
||

392 | length); |
||

393 | } else if (esc_count < 8) { |
||

394 | ```
esc_count -= 4;
``` |
||

395 | if (esc_count > 0) { |
||

396 | ```
/* Zero run coding only, no range coding. */
``` |
||

397 | for (i = 0; i < height; i++) |
||

398 | src += lag_decode_zero_run_line(l, dst + (i * stride), src, |
||

399 | width, esc_count); |
||

400 | ```
} else {
``` |
||

401 | ```
/* Plane is stored uncompressed */
``` |
||

402 | for (i = 0; i < height; i++) { |
||

403 | memcpy(dst + (i * stride), src, width); |
||

404 | src += width; |
||

405 | } |
||

406 | } |
||

407 | } else if (esc_count == 0xff) { |
||

408 | b0c8b8a6 | Reimar DÃ¶ffinger | ```
/* Plane is a solid run of given value */
``` |

409 | d267b339 | Carl Eugen Hoyos | for (i = 0; i < height; i++) |

410 | b0c8b8a6 | Reimar DÃ¶ffinger | ```
memset(dst + i * stride, src[1], width);
``` |

411 | ```
/* Do not apply prediction.
``` |
||

412 | ```
Note: memset to 0 above, setting first value to src[1]
``` |
||

413 | ```
and applying prediction gives the same result. */
``` |
||

414 | return 0; |
||

415 | d267b339 | Carl Eugen Hoyos | ```
} else {
``` |

416 | av_log(l->avctx, AV_LOG_ERROR, |
||

417 | ```
"Invalid zero run escape code! (%#x)\n", esc_count);
``` |
||

418 | return -1; |
||

419 | } |
||

420 | |||

421 | for (i = 0; i < height; i++) { |
||

422 | lag_pred_line(l, dst, width, stride, i); |
||

423 | dst += stride; |
||

424 | } |
||

425 | |||

426 | return 0; |
||

427 | } |
||

428 | |||

429 | ```
/**
``` |
||

430 | ```
* Decode a frame.
``` |
||

431 | ```
* @param avctx codec context
``` |
||

432 | ```
* @param data output AVFrame
``` |
||

433 | ```
* @param data_size size of output data or 0 if no picture is returned
``` |
||

434 | ```
* @param avpkt input packet
``` |
||

435 | ```
* @return number of consumed bytes on success or negative if decode fails
``` |
||

436 | ```
*/
``` |
||

437 | static int lag_decode_frame(AVCodecContext *avctx, |
||

438 | void *data, int *data_size, AVPacket *avpkt) |
||

439 | { |
||

440 | ```
const uint8_t *buf = avpkt->data;
``` |
||

441 | ```
int buf_size = avpkt->size;
``` |
||

442 | LagarithContext *l = avctx->priv_data; |
||

443 | ```
AVFrame *const p = &l->picture;
``` |
||

444 | ```
uint8_t frametype = 0;
``` |
||

445 | uint32_t offset_gu = 0, offset_bv = 0, offset_ry = 9; |
||

446 | |||

447 | AVFrame *picture = data; |
||

448 | |||

449 | if (p->data[0]) |
||

450 | avctx->release_buffer(avctx, p); |
||

451 | |||

452 | ```
p->reference = 0;
``` |
||

453 | ```
p->key_frame = 1;
``` |
||

454 | |||

455 | ```
frametype = buf[0];
``` |
||

456 | |||

457 | ```
offset_gu = AV_RL32(buf + 1);
``` |
||

458 | ```
offset_bv = AV_RL32(buf + 5);
``` |
||

459 | |||

460 | ```
switch (frametype) {
``` |
||

461 | ```
case FRAME_ARITH_YV12:
``` |
||

462 | avctx->pix_fmt = PIX_FMT_YUV420P; |
||

463 | |||

464 | if (avctx->get_buffer(avctx, p) < 0) { |
||

465 | ```
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
``` |
||

466 | return -1; |
||

467 | } |
||

468 | |||

469 | ```
lag_decode_arith_plane(l, p->data[0], avctx->width, avctx->height,
``` |
||

470 | ```
p->linesize[0], buf + offset_ry,
``` |
||

471 | buf_size); |
||

472 | lag_decode_arith_plane(l, p->data[2], avctx->width / 2, |
||

473 | avctx->height / 2, p->linesize[2], |
||

474 | buf + offset_gu, buf_size); |
||

475 | lag_decode_arith_plane(l, p->data[1], avctx->width / 2, |
||

476 | avctx->height / 2, p->linesize[1], |
||

477 | buf + offset_bv, buf_size); |
||

478 | ```
break;
``` |
||

479 | ```
default:
``` |
||

480 | av_log(avctx, AV_LOG_ERROR, |
||

481 | ```
"Unsupported Lagarith frame type: %#x\n", frametype);
``` |
||

482 | return -1; |
||

483 | } |
||

484 | |||

485 | *picture = *p; |
||

486 | ```
*data_size = sizeof(AVFrame);
``` |
||

487 | |||

488 | ```
return buf_size;
``` |
||

489 | } |
||

490 | |||

491 | static av_cold int lag_decode_init(AVCodecContext *avctx) |
||

492 | { |
||

493 | LagarithContext *l = avctx->priv_data; |
||

494 | l->avctx = avctx; |
||

495 | |||

496 | dsputil_init(&l->dsp, avctx); |
||

497 | |||

498 | return 0; |
||

499 | } |
||

500 | |||

501 | static av_cold int lag_decode_end(AVCodecContext *avctx) |
||

502 | { |
||

503 | LagarithContext *l = avctx->priv_data; |
||

504 | |||

505 | if (l->picture.data[0]) |
||

506 | avctx->release_buffer(avctx, &l->picture); |
||

507 | |||

508 | return 0; |
||

509 | } |
||

510 | |||

511 | AVCodec lagarith_decoder = { |
||

512 | ```
"lagarith",
``` |
||

513 | CODEC_TYPE_VIDEO, |
||

514 | CODEC_ID_LAGARITH, |
||

515 | ```
sizeof(LagarithContext),
``` |
||

516 | lag_decode_init, |
||

517 | ```
NULL,
``` |
||

518 | lag_decode_end, |
||

519 | lag_decode_frame, |
||

520 | CODEC_CAP_DR1, |
||

521 | ```
.long_name = NULL_IF_CONFIG_SMALL("Lagarith lossless"),
``` |
||

522 | }; |