ffmpeg-sixel.patch - randomcrap - random crap programs of varying quality
(HTM) git clone git://git.codemadness.org/randomcrap
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
ffmpeg-sixel.patch (21941B)
---
1 commit 27c01dfbebbe4c5e4260943778d1ba4118ffe948
2 Author: Hiltjo Posthuma <hiltjo@codemadness.org>
3 Date: Sun Aug 28 20:21:39 2016 +0200
4
5 rebase sixel changes from ffmpeg-sixel on latest ffmpeg-git
6
7 a few minor things like documentation are still missing.
8
9 diff --git a/configure b/configure
10 index 52931c3..2d96bc1 100755
11 --- a/configure
12 +++ b/configure
13 @@ -252,6 +252,7 @@ External library support:
14 --enable-librtmp enable RTMP[E] support via librtmp [no]
15 --enable-libschroedinger enable Dirac de/encoding via libschroedinger [no]
16 --enable-libshine enable fixed-point MP3 encoding via libshine [no]
17 + --enable-libsixel enable SIXEL terminal support using libsixel
18 --enable-libsmbclient enable Samba protocol via libsmbclient [no]
19 --enable-libsnappy enable Snappy compression, needed for hap encoding [no]
20 --enable-libsoxr enable Include libsoxr resampling [no]
21 @@ -1513,6 +1514,7 @@ EXTERNAL_LIBRARY_LIST="
22 librubberband
23 libschroedinger
24 libshine
25 + libsixel
26 libsmbclient
27 libsnappy
28 libsoxr
29 @@ -2927,6 +2929,7 @@ pulse_indev_deps="libpulse"
30 pulse_outdev_deps="libpulse"
31 qtkit_indev_extralibs="-framework QTKit -framework Foundation -framework QuartzCore"
32 qtkit_indev_select="qtkit"
33 +sixel_outdev_deps="libsixel"
34 sdl_outdev_deps="sdl"
35 sndio_indev_deps="sndio_h"
36 sndio_outdev_deps="sndio_h"
37 @@ -5703,6 +5706,7 @@ enabled librtmp && require_pkg_config librtmp librtmp/rtmp.h RTMP_Sock
38 enabled librubberband && require_pkg_config "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new
39 enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init
40 enabled libshine && require_pkg_config shine shine/layer3.h shine_encode_buffer
41 +enabled libsixel && require_pkg_config libsixel sixel.h sixel_dither_get_num_of_histogram_colors
42 enabled libsmbclient && { use_pkg_config smbclient libsmbclient.h smbc_init ||
43 require smbclient libsmbclient.h smbc_init -lsmbclient; }
44 enabled libsnappy && require snappy snappy-c.h snappy_compress -lsnappy
45 diff --git a/doc/outdevs.texi b/doc/outdevs.texi
46 index e68653f..354afa2 100644
47 --- a/doc/outdevs.texi
48 +++ b/doc/outdevs.texi
49 @@ -371,6 +371,75 @@ SDL window, forcing its size to the qcif format:
50 ffmpeg -i INPUT -vcodec rawvideo -pix_fmt yuv420p -window_size qcif -f sdl "SDL output"
51 @end example
52
53 +@section SIXEL
54 +
55 +SIXEL output device.
56 +
57 +This output device allows one to show a video stream in SIXEL terminals.
58 +
59 +To enable this output device you need to configure FFmpeg with
60 +@code{--enable-libsixel}.
61 +libsixel is a codec library that outputs SIXEL control sequences.
62 +
63 +For more information about libsixel, check:
64 +@url{http://saitoha.github.io/libsixel/}
65 +
66 +@subsection Options
67 +
68 +@table @option
69 +
70 +@item left
71 +Set the left position in cells to display @command{ffmpeg} output.
72 +
73 +@item top
74 +Set the top position in cells to display @command{ffmpeg} output.
75 +
76 +@item reqcolors
77 +Set the limit number of colors.
78 +
79 +@item fixedpal
80 +If set to @option{true}, built-in fixed palette is used to apply color quantization.
81 +
82 +@item diffuse
83 +Select dithering algorithm.
84 +@option{none}
85 +@option{fs}
86 +@option{atkinson}
87 +@option{jajuni}
88 +@option{stucki}
89 +@option{burkes}
90 +
91 +@item scene-threshold
92 +
93 +@item dropframe
94 +
95 +@item ignoredelay
96 +
97 +@end table
98 +
99 +@subsection Examples
100 +
101 +@itemize
102 +@item
103 +The following command shows the @command{ffmpeg} output is a
104 +SIXEL terminal,
105 +@example
106 +ffmpeg -i INPUT -vcodec rawvideo -pix_fmt rgb24 -s 640x480 -f sixel -
107 +@end example
108 +
109 +@item
110 +Show the list of available drivers and exit:
111 +@example
112 +ffmpeg -i INPUT -vcodec rawvideo -pix_fmt rgb24 -s 640x480 -reqcolors 16 -f sixel -
113 +@end example
114 +
115 +@item
116 +Show the list of available dither colors and exit:
117 +@example
118 +ffmpeg -i INPUT -pix_fmt rgb24 -f caca -list_dither colors -
119 +@end example
120 +@end itemize
121 +
122 @section sndio
123
124 sndio audio output device.
125 diff --git a/libavdevice/Makefile b/libavdevice/Makefile
126 index 585827b..72dd2a3 100644
127 --- a/libavdevice/Makefile
128 +++ b/libavdevice/Makefile
129 @@ -41,6 +41,7 @@ OBJS-$(CONFIG_PULSE_OUTDEV) += pulse_audio_enc.o \
130 pulse_audio_common.o
131 OBJS-$(CONFIG_QTKIT_INDEV) += qtkit.o
132 OBJS-$(CONFIG_SDL_OUTDEV) += sdl.o
133 +OBJS-$(CONFIG_SIXEL_OUTDEV) += sixel.o
134 OBJS-$(CONFIG_SNDIO_INDEV) += sndio_dec.o sndio.o
135 OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_enc.o sndio.o
136 OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o v4l2-common.o timefilter.o
137 diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
138 index 26aecf2..d2a7c8b 100644
139 --- a/libavdevice/alldevices.c
140 +++ b/libavdevice/alldevices.c
141 @@ -64,6 +64,7 @@ void avdevice_register_all(void)
142 REGISTER_INOUTDEV(PULSE, pulse);
143 REGISTER_INDEV (QTKIT, qtkit);
144 REGISTER_OUTDEV (SDL, sdl);
145 + REGISTER_OUTDEV (SIXEL, sixel);
146 REGISTER_INOUTDEV(SNDIO, sndio);
147 REGISTER_INOUTDEV(V4L2, v4l2);
148 // REGISTER_INDEV (V4L, v4l
149 diff --git a/libavdevice/sixel.c b/libavdevice/sixel.c
150 new file mode 100644
151 index 0000000..3389611
152 --- /dev/null
153 +++ b/libavdevice/sixel.c
154 @@ -0,0 +1,453 @@
155 +/*
156 + * Copyright (c) 2014 Hayaki Saito
157 + *
158 + * This file is part of FFmpeg.
159 + *
160 + * FFmpeg is free software; you can redistribute it and/or
161 + * modify it under the terms of the GNU Lesser General Public
162 + * License as published by the Free Software Foundation; either
163 + * version 2.1 of the License, or (at your option) any later version.
164 + *
165 + * FFmpeg is distributed in the hope that it will be useful,
166 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
167 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
168 + * Lesser General Public License for more details.
169 + *
170 + * You should have received a copy of the GNU Lesser General Public
171 + * License along with FFmpeg; if not, write to the Free Software
172 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
173 + */
174 +
175 +#include <stdio.h>
176 +#include <unistd.h>
177 +#include <sys/signal.h>
178 +#include <termios.h>
179 +#include <sys/ioctl.h>
180 +#include <sys/select.h>
181 +#include <sixel.h>
182 +#include "libavutil/opt.h"
183 +#include "libavutil/pixdesc.h"
184 +#include "avdevice.h"
185 +#include "libavutil/time.h"
186 +
187 +#if !defined(SIXELAPI)
188 +# define LIBSIXEL_LEGACY_API
189 +# define SIXEL_OK (0)
190 +# define SIXEL_FALSE (-1)
191 +# define SIXEL_SUCCEEDED(status) (((status) & 0x1000) == 0)
192 +# define SIXEL_FAILED(status) (((status) & 0x1000) != 0)
193 +typedef int SIXELSTATUS;
194 +#endif
195 +
196 +typedef struct SIXELContext {
197 + AVClass *class;
198 + AVRational time_base; /* time base */
199 + int64_t time_frame; /* current time */
200 + AVRational framerate;
201 + int top;
202 + int left;
203 + int reqcolors;
204 + sixel_output_t *output;
205 + sixel_dither_t *dither;
206 + sixel_dither_t *testdither;
207 + int fixedpal;
208 + enum methodForDiffuse diffuse;
209 + int threshold;
210 + int dropframe;
211 + int ignoredelay;
212 +} SIXELContext;
213 +
214 +static FILE *sixel_output_file = NULL;
215 +
216 +static int detect_scene_change(SIXELContext *const c)
217 +{
218 + int score;
219 + int i;
220 + unsigned int r = 0;
221 + unsigned int g = 0;
222 + unsigned int b = 0;
223 + static unsigned int average_r = 0;
224 + static unsigned int average_g = 0;
225 + static unsigned int average_b = 0;
226 + static int previous_histgram_colors = 0;
227 + int histgram_colors = 0;
228 + int palette_colors = 0;
229 + unsigned char const* palette;
230 +
231 + histgram_colors = sixel_dither_get_num_of_histogram_colors(c->testdither);
232 +
233 + if (c->dither == NULL)
234 + goto detected;
235 +
236 + /* detect scene change if number of colors increses 20% */
237 + if (previous_histgram_colors * 6 < histgram_colors * 5)
238 + goto detected;
239 +
240 + /* detect scene change if number of colors decreses 20% */
241 + if (previous_histgram_colors * 4 > histgram_colors * 5)
242 + goto detected;
243 +
244 + palette_colors = sixel_dither_get_num_of_palette_colors(c->testdither);
245 + palette = sixel_dither_get_palette(c->testdither);
246 +
247 + /* compare color difference between current
248 + * palette and previous one */
249 + for (i = 0; i < palette_colors; i++) {
250 + r += palette[i * 3 + 0];
251 + g += palette[i * 3 + 1];
252 + b += palette[i * 3 + 2];
253 + }
254 + score = (r - average_r) * (r - average_r)
255 + + (g - average_g) * (g - average_g)
256 + + (b - average_b) * (b - average_b);
257 + if (score > c->threshold * palette_colors
258 + * palette_colors)
259 + goto detected;
260 +
261 + return 0;
262 +
263 +detected:
264 + previous_histgram_colors = histgram_colors;
265 + average_r = r;
266 + average_g = g;
267 + average_b = b;
268 + return 1;
269 +}
270 +
271 +static SIXELSTATUS prepare_static_palette(SIXELContext *const c,
272 + AVCodecContext *const codec)
273 +{
274 + if (c->dither) {
275 + sixel_dither_set_body_only(c->dither, 1);
276 + } else {
277 + c->dither = sixel_dither_get(BUILTIN_XTERM256);
278 + if (c->dither == NULL)
279 + return SIXEL_FALSE;
280 + sixel_dither_set_diffusion_type(c->dither, c->diffuse);
281 + }
282 + return SIXEL_OK;
283 +}
284 +
285 +
286 +static void scroll_on_demand(int pixelheight,
287 + int specified_top,
288 + int specified_left)
289 +{
290 + struct winsize size = {0, 0, 0, 0};
291 + struct termios old_termios;
292 + struct termios new_termios;
293 + int top = 0;
294 + int left = 0;
295 + int cellheight;
296 + int scroll;
297 + fd_set rfds;
298 + struct timeval tv;
299 + int ret = 0;
300 +
301 + ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
302 + if (size.ws_ypixel <= 0) {
303 + fprintf(sixel_output_file, "\033[H\0337");
304 + return;
305 + }
306 + /* set the terminal to cbreak mode */
307 + tcgetattr(STDIN_FILENO, &old_termios);
308 + memcpy(&new_termios, &old_termios, sizeof(old_termios));
309 + new_termios.c_lflag &= ~(ECHO | ICANON);
310 + new_termios.c_cc[VMIN] = 1;
311 + new_termios.c_cc[VTIME] = 0;
312 + tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_termios);
313 +
314 + /* request cursor position report */
315 + fprintf(sixel_output_file, "\033[6n");
316 + /* wait 1 sec */
317 + tv.tv_sec = 1;
318 + tv.tv_usec = 0;
319 + FD_ZERO(&rfds);
320 + FD_SET(STDIN_FILENO, &rfds);
321 + ret = select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv);
322 + if (ret != (-1)) {
323 + if (scanf("\033[%d;%dR", &top, &left) == 2) {
324 + if (specified_top > 0)
325 + top = specified_top;
326 + if (specified_left > 0)
327 + left = specified_left;
328 + fprintf(sixel_output_file, "\033[%d;%dH", top, left);
329 + cellheight = pixelheight * size.ws_row / size.ws_ypixel + 1;
330 + scroll = cellheight + top - size.ws_row + 1;
331 + if (scroll > 0) {
332 + fprintf(sixel_output_file, "\033[%dS\033[%dA", scroll, scroll);
333 + }
334 + fprintf(sixel_output_file, "\0337");
335 + } else {
336 + if (specified_top > 0)
337 + top = specified_top;
338 + if (specified_left > 0)
339 + left = specified_left;
340 + if (top < 1)
341 + top = 1;
342 + if (left < 1)
343 + left = 1;
344 + fprintf(sixel_output_file, "\033[%d;%dH\0337", top, left);
345 + }
346 + }
347 +
348 + tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_termios);
349 +}
350 +
351 +
352 +static SIXELSTATUS prepare_dynamic_palette(SIXELContext *const c,
353 + AVCodecContext *const codec,
354 + AVPacket *const pkt)
355 +{
356 + SIXELSTATUS status = SIXEL_FALSE;
357 +
358 + /* create histgram and construct color palette
359 + * with median cut algorithm. */
360 + status = sixel_dither_initialize(c->testdither, pkt->data,
361 + codec->width, codec->height, 3,
362 + LARGE_NORM, REP_CENTER_BOX,
363 + QUALITY_LOW);
364 + if (SIXEL_FAILED(status))
365 + return status;
366 +
367 + /* check whether the scence is changed. use old palette
368 + * if scene is not changed. */
369 + if (detect_scene_change(c)) {
370 + if (c->dither)
371 + sixel_dither_unref(c->dither);
372 + c->dither = c->testdither;
373 +#if defined(LIBSIXEL_LEGACY_API)
374 + c->testdither = sixel_dither_create(c->reqcolors);
375 + if (c->testdither == NULL)
376 + return SIXEL_FALSE;
377 +#else
378 + status = sixel_dither_new(&c->testdither, c->reqcolors, NULL);
379 + if (SIXEL_FAILED(status))
380 + return status;
381 +#endif
382 + sixel_dither_set_diffusion_type(c->dither, c->diffuse);
383 + } else {
384 + sixel_dither_set_body_only(c->dither, 1);
385 + }
386 +
387 + return status;
388 +}
389 +
390 +static int sixel_write(char *data, int size, void *priv)
391 +{
392 + return fwrite(data, 1, size, (FILE *)priv);
393 +}
394 +
395 +static int sixel_write_header(AVFormatContext *s)
396 +{
397 + SIXELContext *c = s->priv_data;
398 + AVCodecContext *codec = s->streams[0]->codec;
399 + SIXELSTATUS status = SIXEL_FALSE;
400 +
401 + if (s->nb_streams > 1
402 + || codec->codec_type != AVMEDIA_TYPE_VIDEO
403 + || codec->codec_id != AV_CODEC_ID_RAWVIDEO) {
404 + av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
405 + return AVERROR(EINVAL);
406 + }
407 +
408 + if (codec->pix_fmt != AV_PIX_FMT_RGB24) {
409 + av_log(s, AV_LOG_ERROR,
410 + "Unsupported pixel format '%s', choose rgb24\n",
411 + av_get_pix_fmt_name(codec->pix_fmt));
412 + return AVERROR(EINVAL);
413 + }
414 +
415 + if (!s->filename || strcmp(s->filename, "pipe:") == 0) {
416 + sixel_output_file = stdout;
417 +#if defined(LIBSIXEL_LEGACY_API)
418 + c->output = sixel_output_create(sixel_write, stdout);
419 + status = c->output == NULL ? SIXEL_FALSE: SIXEL_OK;
420 +#else
421 + status = sixel_output_new(&c->output, sixel_write, stdout, NULL);
422 +#endif
423 + } else {
424 + sixel_output_file = fopen(s->filename, "w");
425 +#if defined(LIBSIXEL_LEGACY_API)
426 + c->output = sixel_output_create(sixel_write, sixel_output_file);
427 + status = c->output == NULL ? SIXEL_FALSE: SIXEL_OK;
428 +#else
429 + status = sixel_output_new(&c->output, sixel_write, sixel_output_file, NULL);
430 +#endif
431 + }
432 +
433 + if (SIXEL_FAILED(status)) {
434 +#if !defined(LIBSIXEL_LEGACY_API)
435 + av_log(s, AV_LOG_ERROR, "%s\n", sixel_helper_format_error(status));
436 +#endif
437 + return AVERROR_EXTERNAL;
438 + }
439 +
440 + if (isatty(fileno(sixel_output_file))) {
441 + fprintf(sixel_output_file, "\033[?25l"); /* hide cursor */
442 + } else {
443 + c->ignoredelay = 1;
444 + }
445 +
446 + /* don't use private color registers for each frame. */
447 + fprintf(sixel_output_file, "\033[?1070l");
448 +
449 + c->dither = NULL;
450 +#if defined(LIBSIXEL_LEGACY_API)
451 + c->testdither = sixel_dither_create(c->reqcolors);
452 + status = c->testdither == NULL ? SIXEL_FALSE: SIXEL_OK;
453 +#else
454 + status = sixel_dither_new(&c->testdither, c->reqcolors, NULL);
455 +#endif
456 +
457 + if (SIXEL_FAILED(status)) {
458 +#if !defined(LIBSIXEL_LEGACY_API)
459 + av_log(s, AV_LOG_ERROR, "%s\n", sixel_helper_format_error(status));
460 +#endif
461 + return AVERROR_EXTERNAL;
462 + }
463 +
464 + c->time_base = s->streams[0]->codec->time_base;
465 + c->time_frame = av_gettime() / av_q2d(c->time_base);
466 +
467 + return 0;
468 +}
469 +
470 +static int sixel_write_packet(AVFormatContext *s, AVPacket *pkt)
471 +{
472 + SIXELContext * const c = s->priv_data;
473 + AVCodecContext * const codec = s->streams[0]->codec;
474 + int64_t curtime, delay;
475 + struct timespec ts;
476 + int late_threshold;
477 + static int dirty = 0;
478 + SIXELSTATUS status = SIXEL_FALSE;
479 +
480 + if (!c->ignoredelay) {
481 + /* calculate the time of the next frame */
482 + c->time_frame += INT64_C(1000000);
483 + curtime = av_gettime();
484 + delay = c->time_frame * av_q2d(c->time_base) - curtime;
485 + if (delay <= 0) {
486 + if (c->dropframe) {
487 + /* late threshold of dropping this frame */
488 + late_threshold = INT64_C(-1000000) * av_q2d(c->time_base);
489 + if (delay < late_threshold)
490 + return 0;
491 + }
492 + } else {
493 + ts.tv_sec = delay / 1000000;
494 + ts.tv_nsec = (delay % 1000000) * 1000;
495 + nanosleep(&ts, NULL);
496 + }
497 + }
498 +
499 + if (dirty == 0) {
500 + scroll_on_demand(codec->height, c->top, c->left);
501 + dirty = 1;
502 + }
503 + fprintf(sixel_output_file, "\0338");
504 +
505 + if (c->fixedpal) {
506 + status = prepare_static_palette(c, codec);
507 + } else {
508 + status = prepare_dynamic_palette(c, codec, pkt);
509 + }
510 + if (SIXEL_FAILED(status)) {
511 +#if !defined(LIBSIXEL_LEGACY_API)
512 + av_log(s, AV_LOG_ERROR, "%s\n", sixel_helper_format_error(status));
513 +#endif
514 + return AVERROR_EXTERNAL;
515 + }
516 + status = sixel_encode(pkt->data, codec->width, codec->height,
517 + PIXELFORMAT_RGB888,
518 + c->dither, c->output);
519 + if (SIXEL_FAILED(status)) {
520 +#if !defined(LIBSIXEL_LEGACY_API)
521 + av_log(s, AV_LOG_ERROR, "%s\n", sixel_helper_format_error(status));
522 +#endif
523 + return AVERROR_EXTERNAL;
524 + }
525 + fflush(sixel_output_file);
526 + return 0;
527 +}
528 +
529 +static int sixel_write_trailer(AVFormatContext *s)
530 +{
531 + SIXELContext * const c = s->priv_data;
532 +
533 + if (isatty(fileno(sixel_output_file))) {
534 + fprintf(sixel_output_file,
535 + "\033\\" /* terminate DCS sequence */
536 + "\033[?25h"); /* show cursor */
537 + }
538 +
539 + fflush(sixel_output_file);
540 + if (sixel_output_file && sixel_output_file != stdout) {
541 + fclose(sixel_output_file);
542 + sixel_output_file = NULL;
543 + }
544 + if (c->output) {
545 + sixel_output_unref(c->output);
546 + c->output = NULL;
547 + }
548 + if (c->testdither) {
549 + sixel_dither_unref(c->testdither);
550 + c->testdither = NULL;
551 + }
552 + if (c->dither) {
553 + sixel_dither_unref(c->dither);
554 + c->dither = NULL;
555 + }
556 +
557 + return 0;
558 +}
559 +
560 +#define OFFSET(x) offsetof(SIXELContext, x)
561 +#define ENC AV_OPT_FLAG_ENCODING_PARAM
562 +static const AVOption options[] = {
563 + { "left", "left position", OFFSET(left), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 256, ENC },
564 + { "top", "top position", OFFSET(top), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 256, ENC },
565 + { "reqcolors", "number of colors", OFFSET(reqcolors), AV_OPT_TYPE_INT, {.i64 = 16}, 2, 256, ENC },
566 + { "fixedpal", "use fixed palette", OFFSET(fixedpal), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC, "fixedpal" },
567 + { "true", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, ENC, "fixedpal" },
568 + { "false", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, ENC, "fixedpal" },
569 + { "diffuse", "dithering method", OFFSET(diffuse), AV_OPT_TYPE_INT, {.i64 = DIFFUSE_ATKINSON}, 1, 6, ENC, "diffuse" },
570 + { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = DIFFUSE_NONE}, 0, 0, ENC, "diffuse" },
571 + { "fs", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = DIFFUSE_FS}, 0, 0, ENC, "diffuse" },
572 + { "atkinson", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = DIFFUSE_ATKINSON}, 0, 0, ENC, "diffuse" },
573 + { "jajuni", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = DIFFUSE_JAJUNI}, 0, 0, ENC, "diffuse" },
574 + { "stucki", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = DIFFUSE_STUCKI}, 0, 0, ENC, "diffuse" },
575 + { "burkes", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = DIFFUSE_BURKES}, 0, 0, ENC, "diffuse" },
576 +#if 0 /* for debugging */
577 + { "scene-threshold", "scene change threshold", OFFSET(threshold), AV_OPT_TYPE_INT, {.i64 = 500}, 0, 10000,ENC },
578 + { "dropframe", "drop late frames", OFFSET(dropframe), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, ENC, "dropframe" },
579 + { "true", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, ENC, "dropframe" },
580 + { "false", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, ENC, "dropframe" },
581 + { "ignoredelay", "ignore frame timestamp", OFFSET(ignoredelay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC, "ignoredelay" },
582 + { "true", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, ENC, "ignoredelay" },
583 + { "false", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, ENC, "ignoredelay" },
584 +#endif
585 + { NULL },
586 +};
587 +
588 +static const AVClass sixel_class = {
589 + .class_name = "sixel_outdev",
590 + .item_name = av_default_item_name,
591 + .option = options,
592 + .version = LIBAVUTIL_VERSION_INT,
593 + .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
594 +};
595 +
596 +AVOutputFormat ff_sixel_muxer = {
597 + .name = "sixel",
598 + .long_name = NULL_IF_CONFIG_SMALL("SIXEL terminal device"),
599 + .priv_data_size = sizeof(SIXELContext),
600 + .audio_codec = AV_CODEC_ID_NONE,
601 + .video_codec = AV_CODEC_ID_RAWVIDEO,
602 + .write_header = sixel_write_header,
603 + .write_packet = sixel_write_packet,
604 + .write_trailer = sixel_write_trailer,
605 + .flags = AVFMT_NOFILE, /* | AVFMT_VARIABLE_FPS, */
606 + .priv_class = &sixel_class,
607 +};
608