FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/magicyuvenc.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 0 373 0.0%
Functions: 0 16 0.0%
Branches: 0 184 0.0%

Line Branch Exec Source
1 /*
2 * MagicYUV encoder
3 * Copyright (c) 2017 Paul B Mahol
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 #include <stdlib.h>
23 #include <string.h>
24
25 #include "libavutil/cpu.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/opt.h"
28 #include "libavutil/pixdesc.h"
29 #include "libavutil/qsort.h"
30
31 #include "avcodec.h"
32 #include "bytestream.h"
33 #include "codec_internal.h"
34 #include "encode.h"
35 #include "put_bits.h"
36 #include "lossless_videoencdsp.h"
37
38 #define MAGICYUV_EXTRADATA_SIZE 32
39
40 typedef enum Prediction {
41 LEFT = 1,
42 GRADIENT,
43 MEDIAN,
44 } Prediction;
45
46 typedef struct HuffEntry {
47 uint8_t len;
48 uint32_t code;
49 } HuffEntry;
50
51 typedef struct PTable {
52 int value; ///< input value
53 int64_t prob; ///< number of occurences of this value in input
54 } PTable;
55
56 typedef struct Slice {
57 unsigned pos;
58 unsigned size;
59 uint8_t *slice;
60 uint8_t *bitslice;
61 PTable counts[256];
62 } Slice;
63
64 typedef struct MagicYUVContext {
65 const AVClass *class;
66 int frame_pred;
67 int planes;
68 uint8_t format;
69 int slice_height;
70 int nb_slices;
71 int correlate;
72 int hshift[4];
73 int vshift[4];
74 unsigned bitslice_size;
75 uint8_t *decorrelate_buf[2];
76 Slice *slices;
77 HuffEntry he[4][256];
78 LLVidEncDSPContext llvidencdsp;
79 void (*predict)(struct MagicYUVContext *s, const uint8_t *src, uint8_t *dst,
80 ptrdiff_t stride, int width, int height);
81 } MagicYUVContext;
82
83 static void left_predict(MagicYUVContext *s,
84 const uint8_t *src, uint8_t *dst, ptrdiff_t stride,
85 int width, int height)
86 {
87 uint8_t prev = 0;
88 int i, j;
89
90 for (i = 0; i < width; i++) {
91 dst[i] = src[i] - prev;
92 prev = src[i];
93 }
94 dst += width;
95 src += stride;
96 for (j = 1; j < height; j++) {
97 prev = src[-stride];
98 for (i = 0; i < width; i++) {
99 dst[i] = src[i] - prev;
100 prev = src[i];
101 }
102 dst += width;
103 src += stride;
104 }
105 }
106
107 static void gradient_predict(MagicYUVContext *s,
108 const uint8_t *src, uint8_t *dst, ptrdiff_t stride,
109 int width, int height)
110 {
111 int left = 0, top, lefttop;
112 int i, j;
113
114 for (i = 0; i < width; i++) {
115 dst[i] = src[i] - left;
116 left = src[i];
117 }
118 dst += width;
119 src += stride;
120 for (j = 1; j < height; j++) {
121 top = src[-stride];
122 left = src[0] - top;
123 dst[0] = left;
124 for (i = 1; i < width; i++) {
125 top = src[i - stride];
126 lefttop = src[i - (stride + 1)];
127 left = src[i-1];
128 dst[i] = (src[i] - top) - left + lefttop;
129 }
130 dst += width;
131 src += stride;
132 }
133 }
134
135 static void median_predict(MagicYUVContext *s,
136 const uint8_t *src, uint8_t *dst, ptrdiff_t stride,
137 int width, int height)
138 {
139 int left = 0, lefttop;
140 int i, j;
141
142 for (i = 0; i < width; i++) {
143 dst[i] = src[i] - left;
144 left = src[i];
145 }
146 dst += width;
147 src += stride;
148 for (j = 1; j < height; j++) {
149 left = lefttop = src[-stride];
150 s->llvidencdsp.sub_median_pred(dst, src - stride, src, width, &left, &lefttop);
151 dst += width;
152 src += stride;
153 }
154 }
155
156 static av_cold int magy_encode_init(AVCodecContext *avctx)
157 {
158 MagicYUVContext *s = avctx->priv_data;
159 PutByteContext pb;
160
161 switch (avctx->pix_fmt) {
162 case AV_PIX_FMT_GBRP:
163 avctx->codec_tag = MKTAG('M', '8', 'R', 'G');
164 s->correlate = 1;
165 s->format = 0x65;
166 break;
167 case AV_PIX_FMT_GBRAP:
168 avctx->codec_tag = MKTAG('M', '8', 'R', 'A');
169 s->correlate = 1;
170 s->format = 0x66;
171 break;
172 case AV_PIX_FMT_YUV420P:
173 avctx->codec_tag = MKTAG('M', '8', 'Y', '0');
174 s->hshift[1] =
175 s->vshift[1] =
176 s->hshift[2] =
177 s->vshift[2] = 1;
178 s->format = 0x69;
179 break;
180 case AV_PIX_FMT_YUV422P:
181 avctx->codec_tag = MKTAG('M', '8', 'Y', '2');
182 s->hshift[1] =
183 s->hshift[2] = 1;
184 s->format = 0x68;
185 break;
186 case AV_PIX_FMT_YUV444P:
187 avctx->codec_tag = MKTAG('M', '8', 'Y', '4');
188 s->format = 0x67;
189 break;
190 case AV_PIX_FMT_YUVA444P:
191 avctx->codec_tag = MKTAG('M', '8', 'Y', 'A');
192 s->format = 0x6a;
193 break;
194 case AV_PIX_FMT_GRAY8:
195 avctx->codec_tag = MKTAG('M', '8', 'G', '0');
196 s->format = 0x6b;
197 break;
198 }
199
200 ff_llvidencdsp_init(&s->llvidencdsp);
201
202 s->planes = av_pix_fmt_count_planes(avctx->pix_fmt);
203
204 s->nb_slices = (avctx->slices <= 0) ? av_cpu_count() : avctx->slices;
205 s->nb_slices = FFMIN(s->nb_slices, avctx->height >> s->vshift[1]);
206 s->nb_slices = FFMAX(1, s->nb_slices);
207 s->slice_height = FFALIGN((avctx->height + s->nb_slices - 1) / s->nb_slices, 1 << s->vshift[1]);
208 s->nb_slices = (avctx->height + s->slice_height - 1) / s->slice_height;
209 s->slices = av_calloc(s->nb_slices * s->planes, sizeof(*s->slices));
210 if (!s->slices)
211 return AVERROR(ENOMEM);
212
213 if (s->correlate) {
214 size_t max_align = av_cpu_max_align();
215 size_t aligned_width = FFALIGN(avctx->width, max_align);
216 s->decorrelate_buf[0] = av_calloc(2U * (s->nb_slices * s->slice_height),
217 aligned_width);
218 if (!s->decorrelate_buf[0])
219 return AVERROR(ENOMEM);
220 s->decorrelate_buf[1] = s->decorrelate_buf[0] + (s->nb_slices * s->slice_height) * aligned_width;
221 }
222
223 s->bitslice_size = avctx->width * s->slice_height + 2;
224 for (int n = 0; n < s->nb_slices; n++) {
225 for (int i = 0; i < s->planes; i++) {
226 Slice *sl = &s->slices[n * s->planes + i];
227
228 sl->bitslice = av_malloc(s->bitslice_size + AV_INPUT_BUFFER_PADDING_SIZE);
229 sl->slice = av_malloc(avctx->width * (s->slice_height + 2) +
230 AV_INPUT_BUFFER_PADDING_SIZE);
231 if (!sl->slice || !sl->bitslice) {
232 av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer.\n");
233 return AVERROR(ENOMEM);
234 }
235 }
236 }
237
238 switch (s->frame_pred) {
239 case LEFT: s->predict = left_predict; break;
240 case GRADIENT: s->predict = gradient_predict; break;
241 case MEDIAN: s->predict = median_predict; break;
242 }
243
244 avctx->extradata_size = MAGICYUV_EXTRADATA_SIZE;
245
246 avctx->extradata = av_mallocz(avctx->extradata_size +
247 AV_INPUT_BUFFER_PADDING_SIZE);
248
249 if (!avctx->extradata) {
250 av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata.\n");
251 return AVERROR(ENOMEM);
252 }
253
254 bytestream2_init_writer(&pb, avctx->extradata, MAGICYUV_EXTRADATA_SIZE);
255 bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y'));
256 bytestream2_put_le32(&pb, 32);
257 bytestream2_put_byte(&pb, 7);
258 bytestream2_put_byte(&pb, s->format);
259 bytestream2_put_byte(&pb, 12);
260 bytestream2_put_byte(&pb, 0);
261
262 bytestream2_put_byte(&pb, 0);
263 bytestream2_put_byte(&pb, 0);
264 bytestream2_put_byte(&pb, 32);
265 bytestream2_put_byte(&pb, 0);
266
267 bytestream2_put_le32(&pb, avctx->width);
268 bytestream2_put_le32(&pb, avctx->height);
269 bytestream2_put_le32(&pb, avctx->width);
270 bytestream2_put_le32(&pb, avctx->height);
271
272 return 0;
273 }
274
275 static void calculate_codes(HuffEntry *he, uint16_t codes_count[33])
276 {
277 for (unsigned i = 32, nb_codes = 0; i > 0; i--) {
278 uint16_t curr = codes_count[i]; // # of leafs of length i
279 codes_count[i] = nb_codes / 2; // # of non-leaf nodes on level i
280 nb_codes = codes_count[i] + curr; // # of nodes on level i
281 }
282
283 for (unsigned i = 0; i < 256; i++) {
284 he[i].code = codes_count[he[i].len];
285 codes_count[he[i].len]++;
286 }
287 }
288
289 static void count_usage(const uint8_t *src, int width,
290 int height, PTable *counts)
291 {
292 for (int j = 0; j < height; j++) {
293 for (int i = 0; i < width; i++)
294 counts[src[i]].prob++;
295 src += width;
296 }
297 }
298
299 typedef struct PackageMergerList {
300 int nitems; ///< number of items in the list and probability ex. 4
301 int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13
302 int probability[514]; ///< probability of each item 3, 8, 18, 46
303 int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E
304 } PackageMergerList;
305
306 static int compare_by_prob(const void *a, const void *b)
307 {
308 const PTable *a2 = a;
309 const PTable *b2 = b;
310 return a2->prob - b2->prob;
311 }
312
313 static void magy_huffman_compute_bits(PTable *prob_table, HuffEntry *distincts,
314 uint16_t codes_counts[33],
315 int size, int max_length)
316 {
317 PackageMergerList list_a, list_b, *to = &list_a, *from = &list_b, *temp;
318 int times, i, j, k;
319 int nbits[257] = {0};
320 int min;
321
322 av_assert0(max_length > 0);
323
324 to->nitems = 0;
325 from->nitems = 0;
326 to->item_idx[0] = 0;
327 from->item_idx[0] = 0;
328 AV_QSORT(prob_table, size, PTable, compare_by_prob);
329
330 for (times = 0; times <= max_length; times++) {
331 to->nitems = 0;
332 to->item_idx[0] = 0;
333
334 j = 0;
335 k = 0;
336
337 if (times < max_length) {
338 i = 0;
339 }
340 while (i < size || j + 1 < from->nitems) {
341 to->nitems++;
342 to->item_idx[to->nitems] = to->item_idx[to->nitems - 1];
343 if (i < size &&
344 (j + 1 >= from->nitems ||
345 prob_table[i].prob <
346 from->probability[j] + from->probability[j + 1])) {
347 to->items[to->item_idx[to->nitems]++] = prob_table[i].value;
348 to->probability[to->nitems - 1] = prob_table[i].prob;
349 i++;
350 } else {
351 for (k = from->item_idx[j]; k < from->item_idx[j + 2]; k++) {
352 to->items[to->item_idx[to->nitems]++] = from->items[k];
353 }
354 to->probability[to->nitems - 1] =
355 from->probability[j] + from->probability[j + 1];
356 j += 2;
357 }
358 }
359 temp = to;
360 to = from;
361 from = temp;
362 }
363
364 min = (size - 1 < from->nitems) ? size - 1 : from->nitems;
365 for (i = 0; i < from->item_idx[min]; i++) {
366 nbits[from->items[i]]++;
367 }
368
369 for (i = 0; i < size; i++) {
370 distincts[i].len = nbits[i];
371 codes_counts[nbits[i]]++;
372 }
373 }
374
375 static int count_plane_slice(AVCodecContext *avctx, int n, int plane)
376 {
377 MagicYUVContext *s = avctx->priv_data;
378 Slice *sl = &s->slices[n * s->planes + plane];
379 const uint8_t *dst = sl->slice;
380 PTable *counts = sl->counts;
381 const int slice_height = s->slice_height;
382 const int last_height = FFMIN(slice_height, avctx->height - n * slice_height);
383 const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height;
384
385 memset(counts, 0, sizeof(sl->counts));
386
387 count_usage(dst, AV_CEIL_RSHIFT(avctx->width, s->hshift[plane]),
388 AV_CEIL_RSHIFT(height, s->vshift[plane]), counts);
389
390 return 0;
391 }
392
393 static int encode_table(AVCodecContext *avctx,
394 PutBitContext *pb, HuffEntry *he, int plane)
395 {
396 MagicYUVContext *s = avctx->priv_data;
397 PTable counts[256] = { {0} };
398 uint16_t codes_counts[33] = { 0 };
399
400 for (int n = 0; n < s->nb_slices; n++) {
401 Slice *sl = &s->slices[n * s->planes + plane];
402 PTable *slice_counts = sl->counts;
403
404 for (int i = 0; i < 256; i++)
405 counts[i].prob = slice_counts[i].prob;
406 }
407
408 for (int i = 0; i < 256; i++) {
409 counts[i].prob++;
410 counts[i].value = i;
411 }
412
413 magy_huffman_compute_bits(counts, he, codes_counts, 256, 12);
414
415 calculate_codes(he, codes_counts);
416
417 for (int i = 0; i < 256; i++) {
418 put_bits(pb, 1, 0);
419 put_bits(pb, 7, he[i].len);
420 }
421
422 return 0;
423 }
424
425 static int encode_plane_slice_raw(const uint8_t *src, uint8_t *dst, unsigned dst_size,
426 int width, int height, int prediction)
427 {
428 unsigned count = width * height;
429
430 dst[0] = 1;
431 dst[1] = prediction;
432
433 memcpy(dst + 2, src, count);
434 count += 2;
435 AV_WN32(dst + count, 0);
436 if (count & 3)
437 count += 4 - (count & 3);
438
439 return count;
440 }
441
442 static int encode_plane_slice(const uint8_t *src, uint8_t *dst, unsigned dst_size,
443 int width, int height, HuffEntry *he, int prediction)
444 {
445 const uint8_t *osrc = src;
446 PutBitContext pb;
447 int count;
448
449 init_put_bits(&pb, dst, dst_size);
450
451 put_bits(&pb, 8, 0);
452 put_bits(&pb, 8, prediction);
453
454 for (int j = 0; j < height; j++) {
455 for (int i = 0; i < width; i++) {
456 const int idx = src[i];
457 const int len = he[idx].len;
458 if (put_bits_left(&pb) < len + 32)
459 return encode_plane_slice_raw(osrc, dst, dst_size, width, height, prediction);
460 put_bits(&pb, len, he[idx].code);
461 }
462
463 src += width;
464 }
465
466 count = put_bits_count(&pb) & 0x1F;
467
468 if (count)
469 put_bits(&pb, 32 - count, 0);
470
471 flush_put_bits(&pb);
472
473 return put_bytes_output(&pb);
474 }
475
476 static int encode_slice(AVCodecContext *avctx, void *tdata,
477 int n, int threadnr)
478 {
479 MagicYUVContext *s = avctx->priv_data;
480 const int slice_height = s->slice_height;
481 const int last_height = FFMIN(slice_height, avctx->height - n * slice_height);
482 const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height;
483
484 for (int i = 0; i < s->planes; i++) {
485 Slice *sl = &s->slices[n * s->planes + i];
486
487 sl->size =
488 encode_plane_slice(sl->slice,
489 sl->bitslice,
490 s->bitslice_size,
491 AV_CEIL_RSHIFT(avctx->width, s->hshift[i]),
492 AV_CEIL_RSHIFT(height, s->vshift[i]),
493 s->he[i], s->frame_pred);
494 }
495
496 return 0;
497 }
498
499 static int predict_slice(AVCodecContext *avctx, void *tdata,
500 int n, int threadnr)
501 {
502 size_t max_align = av_cpu_max_align();
503 const int aligned_width = FFALIGN(avctx->width, max_align);
504 MagicYUVContext *s = avctx->priv_data;
505 const int slice_height = s->slice_height;
506 const int last_height = FFMIN(slice_height, avctx->height - n * slice_height);
507 const int height = (n < (s->nb_slices - 1)) ? slice_height : last_height;
508 const int width = avctx->width;
509 AVFrame *frame = tdata;
510
511 if (s->correlate) {
512 uint8_t *decorrelated[2] = { s->decorrelate_buf[0] + n * slice_height * aligned_width,
513 s->decorrelate_buf[1] + n * slice_height * aligned_width };
514 const int decorrelate_linesize = aligned_width;
515 const uint8_t *const data[4] = { decorrelated[0], frame->data[0] + n * slice_height * frame->linesize[0],
516 decorrelated[1], s->planes == 4 ? frame->data[3] + n * slice_height * frame->linesize[3] : NULL };
517 const uint8_t *r, *g, *b;
518 const int linesize[4] = { decorrelate_linesize, frame->linesize[0],
519 decorrelate_linesize, frame->linesize[3] };
520
521 g = frame->data[0] + n * slice_height * frame->linesize[0];
522 b = frame->data[1] + n * slice_height * frame->linesize[1];
523 r = frame->data[2] + n * slice_height * frame->linesize[2];
524
525 for (int i = 0; i < height; i++) {
526 s->llvidencdsp.diff_bytes(decorrelated[0], b, g, width);
527 s->llvidencdsp.diff_bytes(decorrelated[1], r, g, width);
528 g += frame->linesize[0];
529 b += frame->linesize[1];
530 r += frame->linesize[2];
531 decorrelated[0] += decorrelate_linesize;
532 decorrelated[1] += decorrelate_linesize;
533 }
534
535 for (int i = 0; i < s->planes; i++) {
536 Slice *sl = &s->slices[n * s->planes + i];
537
538 s->predict(s, data[i], sl->slice, linesize[i],
539 frame->width, height);
540 }
541 } else {
542 for (int i = 0; i < s->planes; i++) {
543 Slice *sl = &s->slices[n * s->planes + i];
544
545 s->predict(s, frame->data[i] + n * (slice_height >> s->vshift[i]) * frame->linesize[i],
546 sl->slice,
547 frame->linesize[i],
548 AV_CEIL_RSHIFT(frame->width, s->hshift[i]),
549 AV_CEIL_RSHIFT(height, s->vshift[i]));
550 }
551 }
552
553 for (int p = 0; p < s->planes; p++)
554 count_plane_slice(avctx, n, p);
555
556 return 0;
557 }
558
559 static int magy_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
560 const AVFrame *frame, int *got_packet)
561 {
562 MagicYUVContext *s = avctx->priv_data;
563 const int width = avctx->width, height = avctx->height;
564 const int slice_height = s->slice_height;
565 unsigned tables_size;
566 PutBitContext pbit;
567 PutByteContext pb;
568 int pos, ret = 0;
569
570 ret = ff_alloc_packet(avctx, pkt, (256 + 4 * s->nb_slices + width * height) *
571 s->planes + 256);
572 if (ret < 0)
573 return ret;
574
575 bytestream2_init_writer(&pb, pkt->data, pkt->size);
576 bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y'));
577 bytestream2_put_le32(&pb, 32); // header size
578 bytestream2_put_byte(&pb, 7); // version
579 bytestream2_put_byte(&pb, s->format);
580 bytestream2_put_byte(&pb, 12); // max huffman length
581 bytestream2_put_byte(&pb, 0);
582
583 bytestream2_put_byte(&pb, 0);
584 bytestream2_put_byte(&pb, 0);
585 bytestream2_put_byte(&pb, 32); // coder type
586 bytestream2_put_byte(&pb, 0);
587
588 bytestream2_put_le32(&pb, avctx->width);
589 bytestream2_put_le32(&pb, avctx->height);
590 bytestream2_put_le32(&pb, avctx->width);
591 bytestream2_put_le32(&pb, slice_height);
592 bytestream2_put_le32(&pb, 0);
593
594 for (int i = 0; i < s->planes; i++) {
595 bytestream2_put_le32(&pb, 0);
596 for (int j = 1; j < s->nb_slices; j++)
597 bytestream2_put_le32(&pb, 0);
598 }
599
600 bytestream2_put_byte(&pb, s->planes);
601
602 for (int i = 0; i < s->planes; i++) {
603 for (int n = 0; n < s->nb_slices; n++)
604 bytestream2_put_byte(&pb, n * s->planes + i);
605 }
606
607 avctx->execute2(avctx, predict_slice, (void *)frame, NULL, s->nb_slices);
608
609 init_put_bits(&pbit, pkt->data + bytestream2_tell_p(&pb), bytestream2_get_bytes_left_p(&pb));
610
611 for (int i = 0; i < s->planes; i++)
612 encode_table(avctx, &pbit, s->he[i], i);
613
614 tables_size = put_bytes_count(&pbit, 1);
615 bytestream2_skip_p(&pb, tables_size);
616
617 avctx->execute2(avctx, encode_slice, NULL, NULL, s->nb_slices);
618
619 for (int n = 0; n < s->nb_slices; n++) {
620 for (int i = 0; i < s->planes; i++) {
621 Slice *sl = &s->slices[n * s->planes + i];
622
623 sl->pos = bytestream2_tell_p(&pb);
624
625 bytestream2_put_buffer(&pb, sl->bitslice, sl->size);
626 }
627 }
628
629 pos = bytestream2_tell_p(&pb);
630 bytestream2_seek_p(&pb, 32, SEEK_SET);
631 bytestream2_put_le32(&pb, s->slices[0].pos - 32);
632 for (int i = 0; i < s->planes; i++) {
633 for (int n = 0; n < s->nb_slices; n++) {
634 Slice *sl = &s->slices[n * s->planes + i];
635
636 bytestream2_put_le32(&pb, sl->pos - 32);
637 }
638 }
639 bytestream2_seek_p(&pb, pos, SEEK_SET);
640
641 pkt->size = bytestream2_tell_p(&pb);
642
643 *got_packet = 1;
644
645 return 0;
646 }
647
648 static av_cold int magy_encode_close(AVCodecContext *avctx)
649 {
650 MagicYUVContext *s = avctx->priv_data;
651
652 for (int i = 0; i < s->planes * s->nb_slices && s->slices; i++) {
653 Slice *sl = &s->slices[i];
654
655 av_freep(&sl->slice);
656 av_freep(&sl->bitslice);
657 }
658 av_freep(&s->slices);
659 av_freep(&s->decorrelate_buf);
660
661 return 0;
662 }
663
664 #define OFFSET(x) offsetof(MagicYUVContext, x)
665 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
666 static const AVOption options[] = {
667 { "pred", "Prediction method", OFFSET(frame_pred), AV_OPT_TYPE_INT, {.i64=LEFT}, LEFT, MEDIAN, VE, .unit = "pred" },
668 { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LEFT }, 0, 0, VE, .unit = "pred" },
669 { "gradient", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = GRADIENT }, 0, 0, VE, .unit = "pred" },
670 { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MEDIAN }, 0, 0, VE, .unit = "pred" },
671 { NULL},
672 };
673
674 static const AVClass magicyuv_class = {
675 .class_name = "magicyuv",
676 .item_name = av_default_item_name,
677 .option = options,
678 .version = LIBAVUTIL_VERSION_INT,
679 };
680
681 const FFCodec ff_magicyuv_encoder = {
682 .p.name = "magicyuv",
683 CODEC_LONG_NAME("MagicYUV video"),
684 .p.type = AVMEDIA_TYPE_VIDEO,
685 .p.id = AV_CODEC_ID_MAGICYUV,
686 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
687 AV_CODEC_CAP_SLICE_THREADS |
688 AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
689 .priv_data_size = sizeof(MagicYUVContext),
690 .p.priv_class = &magicyuv_class,
691 .init = magy_encode_init,
692 .close = magy_encode_close,
693 FF_CODEC_ENCODE_CB(magy_encode_frame),
694 .p.pix_fmts = (const enum AVPixelFormat[]) {
695 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P,
696 AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GRAY8,
697 AV_PIX_FMT_NONE
698 },
699 .color_ranges = AVCOL_RANGE_MPEG, /* FIXME: implement tagging */
700 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
701 };
702