You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	libcaca output device
This commit is contained in:
		
							
								
								
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -173,6 +173,7 @@ External library support: | ||||
|   --enable-libaacplus      enable AAC+ encoding via libaacplus [no] | ||||
|   --enable-libass          enable libass subtitles rendering [no] | ||||
|   --enable-libbluray       enable BluRay reading using libbluray [no] | ||||
|   --enable-libcaca         enable textual display using libcaca | ||||
|   --enable-libcelt         enable CELT decoding via libcelt [no] | ||||
|   --enable-libcdio         enable audio CD grabbing with libcdio | ||||
|   --enable-libdc1394       enable IIDC-1394 grabbing using libdc1394 | ||||
| @@ -1051,6 +1052,7 @@ CONFIG_LIST=" | ||||
|     libaacplus | ||||
|     libass | ||||
|     libbluray | ||||
|     libcaca | ||||
|     libcdio | ||||
|     libcelt | ||||
|     libdc1394 | ||||
| @@ -1693,6 +1695,7 @@ w64_demuxer_deps="wav_demuxer" | ||||
| alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp" | ||||
| alsa_outdev_deps="alsa_asoundlib_h" | ||||
| bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" | ||||
| caca_outdev_deps="libcaca" | ||||
| dshow_indev_deps="IBaseFilter" | ||||
| dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid" | ||||
| dv1394_indev_deps="dv1394 dv_demuxer" | ||||
| @@ -3312,6 +3315,7 @@ enabled libbluray  && require libbluray libbluray/bluray.h bd_open -lbluray | ||||
| enabled libcelt    && require libcelt celt/celt.h celt_decode -lcelt0 && | ||||
|                       { check_lib celt/celt.h celt_decoder_create_custom -lcelt0 || | ||||
|                         die "ERROR: libcelt version must be >= 0.11.0."; } | ||||
| enabled libcaca    && require_pkg_config caca caca.h caca_create_canvas | ||||
| enabled libfaac    && require2 libfaac "stdint.h faac.h" faacEncGetVersion -lfaac | ||||
| enabled libfdk_aac && require  libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac | ||||
| enabled libfreetype && require_pkg_config freetype2 "ft2build.h freetype/freetype.h" FT_Init_FreeType | ||||
| @@ -3688,6 +3692,7 @@ echo "frei0r enabled            ${frei0r-no}" | ||||
| echo "gnutls enabled            ${gnutls-no}" | ||||
| echo "libaacplus enabled        ${libaacplus-no}" | ||||
| echo "libass enabled            ${libass-no}" | ||||
| echo "libcaca enabled           ${libcaca-no}" | ||||
| echo "libcdio support           ${libcdio-no}" | ||||
| echo "libcelt enabled           ${libcelt-no}" | ||||
| echo "libdc1394 support         ${libdc1394-no}" | ||||
|   | ||||
| @@ -22,6 +22,67 @@ A description of the currently available output devices follows. | ||||
|  | ||||
| ALSA (Advanced Linux Sound Architecture) output device. | ||||
|  | ||||
| @section caca | ||||
|  | ||||
| CACA output device. | ||||
|  | ||||
| This output devices allows to show a video stream in CACA window. | ||||
| Only one CACA window is allowed per application, so you can | ||||
| have only one instance of this output device in an application. | ||||
|  | ||||
| To enable this output device you need to configure FFmpeg with | ||||
| @code(--enable-libcaca). | ||||
| libcaca is a graphics library that outputs text instead of pixels. | ||||
|  | ||||
| For more information about libcaca, check: | ||||
| @url{http://caca.zoy.org/wiki/libcaca} | ||||
|  | ||||
| @subsection Options | ||||
|  | ||||
| @table @option | ||||
|  | ||||
| @item window_title | ||||
| Set the CACA window title, if not specified default to the filename | ||||
| specified for the output device. | ||||
|  | ||||
| @item window_size | ||||
| Set the CACA window size, can be a string of the form | ||||
| @var{width}x@var{height} or a video size abbreviation. | ||||
| If not specified it defaults to the size of the input video. | ||||
|  | ||||
| @item driver | ||||
| Set display driver. | ||||
|  | ||||
| @item algorithm | ||||
| Set dithering algorithm. Dithering is necessary | ||||
| because the picture being rendered has usually far more colours than | ||||
| the available palette. | ||||
|  | ||||
| @item antialias | ||||
| Set antialias method. Antialiasing smoothens the rendered | ||||
| image and avoids the commonly seen staircase effect. | ||||
|  | ||||
| @item charset | ||||
| Set which characters are going to be used when rendering text. | ||||
|  | ||||
| @item colors | ||||
| Set colors to be used when rendering text. | ||||
|  | ||||
| @item list_drivers | ||||
| List available drivers. | ||||
|  | ||||
| @item list_dither | ||||
| List available dither options. | ||||
| @end table | ||||
|  | ||||
| @subsection Examples | ||||
|  | ||||
| The following command shows the @command{ffmpeg} output is an | ||||
| CACA window, forcing its size to 80x25: | ||||
| @example | ||||
| ffmpeg -i INPUT -vcodec rawvideo -pix_fmt rgb24 -window_size 80x25 -f caca - | ||||
| @end example | ||||
|  | ||||
| @section oss | ||||
|  | ||||
| OSS (Open Sound System) output device. | ||||
|   | ||||
| @@ -16,6 +16,7 @@ OBJS-$(CONFIG_ALSA_INDEV)                += alsa-audio-common.o \ | ||||
| OBJS-$(CONFIG_ALSA_OUTDEV)               += alsa-audio-common.o \ | ||||
|                                             alsa-audio-enc.o | ||||
| OBJS-$(CONFIG_BKTR_INDEV)                += bktr.o | ||||
| OBJS-$(CONFIG_CACA_OUTDEV)               += caca.o | ||||
| OBJS-$(CONFIG_DSHOW_INDEV)               += dshow.o dshow_enummediatypes.o \ | ||||
|                                             dshow_enumpins.o dshow_filter.o \ | ||||
|                                             dshow_pin.o dshow_common.o | ||||
|   | ||||
| @@ -40,6 +40,7 @@ void avdevice_register_all(void) | ||||
|     /* devices */ | ||||
|     REGISTER_INOUTDEV (ALSA, alsa); | ||||
|     REGISTER_INDEV    (BKTR, bktr); | ||||
|     REGISTER_OUTDEV   (CACA, caca); | ||||
|     REGISTER_INDEV    (DSHOW, dshow); | ||||
|     REGISTER_INDEV    (DV1394, dv1394); | ||||
|     REGISTER_INDEV    (FBDEV, fbdev); | ||||
|   | ||||
							
								
								
									
										227
									
								
								libavdevice/caca.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								libavdevice/caca.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| /* | ||||
|  * Copyright (c) 2012 Paul B Mahol | ||||
|  * | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg 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.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg 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 FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include <caca.h> | ||||
| #include "libavutil/opt.h" | ||||
| #include "libavutil/pixdesc.h" | ||||
| #include "avdevice.h" | ||||
|  | ||||
| typedef struct CACAContext { | ||||
|     AVClass         *class; | ||||
|     AVFormatContext *ctx; | ||||
|     char            *window_title; | ||||
|     int             window_width,  window_height; | ||||
|  | ||||
|     caca_canvas_t   *canvas; | ||||
|     caca_display_t  *display; | ||||
|     caca_dither_t   *dither; | ||||
|  | ||||
|     char            *algorithm, *antialias; | ||||
|     char            *charset, *colors; | ||||
|     char            *driver; | ||||
|  | ||||
|     char            *list_dither; | ||||
|     int             list_drivers; | ||||
| } CACAContext; | ||||
|  | ||||
| static int caca_write_trailer(AVFormatContext *s) | ||||
| { | ||||
|     CACAContext *c = s->priv_data; | ||||
|  | ||||
|     av_freep(&c->window_title); | ||||
|  | ||||
|     caca_free_dither(c->dither); | ||||
|     caca_free_display(c->display); | ||||
|     caca_free_canvas(c->canvas); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void list_drivers(CACAContext *c) | ||||
| { | ||||
|     const char *const *drivers = caca_get_display_driver_list(); | ||||
|     int i; | ||||
|  | ||||
|     av_log(c->ctx, AV_LOG_INFO, "Available drivers:\n"); | ||||
|     for (i = 0; drivers[i]; i += 2) | ||||
|         av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", drivers[i], drivers[i + 1]); | ||||
| } | ||||
|  | ||||
| #define DEFINE_LIST_DITHER(thing, thing_str)                                 \ | ||||
| static void list_dither_## thing(CACAContext *c)                         \ | ||||
| {                                                                            \ | ||||
|     const char *const *thing = caca_get_dither_## thing ##_list(c->dither);  \ | ||||
|     int i;                                                                   \ | ||||
|                                                                              \ | ||||
|     av_log(c->ctx, AV_LOG_INFO, "Available %s:\n", thing_str);               \ | ||||
|     for (i = 0; thing[i]; i += 2)                                            \ | ||||
|         av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", thing[i], thing[i + 1]);    \ | ||||
| } | ||||
|  | ||||
| DEFINE_LIST_DITHER(color, "colors"); | ||||
| DEFINE_LIST_DITHER(charset, "charsets"); | ||||
| DEFINE_LIST_DITHER(algorithm, "algorithms"); | ||||
| DEFINE_LIST_DITHER(antialias, "antialias"); | ||||
|  | ||||
| static int caca_write_header(AVFormatContext *s) | ||||
| { | ||||
|     CACAContext *c = s->priv_data; | ||||
|     AVStream *st = s->streams[0]; | ||||
|     AVCodecContext *encctx = st->codec; | ||||
|     int ret, bpp; | ||||
|  | ||||
|     c->ctx = s; | ||||
|     if (c->list_drivers) { | ||||
|         list_drivers(c); | ||||
|         return AVERROR_EXIT; | ||||
|     } | ||||
|     if (c->list_dither) { | ||||
|         if (!strcmp(c->list_dither, "colors")) { | ||||
|             list_dither_color(c); | ||||
|         } else if (!strcmp(c->list_dither, "charsets")) { | ||||
|             list_dither_charset(c); | ||||
|         } else if (!strcmp(c->list_dither, "algorithms")) { | ||||
|             list_dither_algorithm(c); | ||||
|         } else if (!strcmp(c->list_dither, "antialiases")) { | ||||
|             list_dither_antialias(c); | ||||
|         } else { | ||||
|             av_log(s, AV_LOG_ERROR, | ||||
|                    "Invalid value '%s', for 'list_dither' option\n", | ||||
|                    c->list_dither); | ||||
|             return AVERROR(EINVAL); | ||||
|         } | ||||
|         return AVERROR_EXIT; | ||||
|     } | ||||
|  | ||||
|     if (   s->nb_streams > 1 | ||||
|         || encctx->codec_type != AVMEDIA_TYPE_VIDEO | ||||
|         || encctx->codec_id   != CODEC_ID_RAWVIDEO) { | ||||
|         av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n"); | ||||
|         return AVERROR(EINVAL); | ||||
|     } | ||||
|  | ||||
|     if (encctx->pix_fmt != PIX_FMT_RGB24) { | ||||
|         av_log(s, AV_LOG_ERROR, | ||||
|                "Unsupported pixel format '%s', choose rgb24\n", | ||||
|                av_get_pix_fmt_name(encctx->pix_fmt)); | ||||
|         return AVERROR(EINVAL); | ||||
|     } | ||||
|  | ||||
|     c->canvas = caca_create_canvas(c->window_width, c->window_height); | ||||
|     if (!c->canvas) { | ||||
|         av_log(s, AV_LOG_ERROR, "Failed to create canvas\n"); | ||||
|         return AVERROR(errno); | ||||
|     } | ||||
|  | ||||
|     c->display = caca_create_display_with_driver(c->canvas, c->driver); | ||||
|     if (!c->display) { | ||||
|         av_log(s, AV_LOG_ERROR, "Failed to create display\n"); | ||||
|         list_drivers(c); | ||||
|         caca_free_canvas(c->canvas); | ||||
|         return AVERROR(errno); | ||||
|     } | ||||
|  | ||||
|     if (!c->window_width || !c->window_height) { | ||||
|         c->window_width  = caca_get_canvas_width(c->canvas); | ||||
|         c->window_height = caca_get_canvas_height(c->canvas); | ||||
|     } | ||||
|  | ||||
|     bpp = av_get_bits_per_pixel(&av_pix_fmt_descriptors[encctx->pix_fmt]); | ||||
|     c->dither = caca_create_dither(bpp, encctx->width, encctx->height, | ||||
|                                    bpp / 8 * encctx->width, | ||||
|                                    0x0000ff, 0x00ff00, 0xff0000, 0); | ||||
|     if (!c->dither) { | ||||
|         av_log(s, AV_LOG_ERROR, "Failed to create dither\n"); | ||||
|         ret =  AVERROR(errno); | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     ret  = caca_set_dither_algorithm(c->dither, c->algorithm); | ||||
|     ret += caca_set_dither_antialias(c->dither, c->antialias); | ||||
|     ret +=   caca_set_dither_charset(c->dither, c->charset); | ||||
|     ret +=     caca_set_dither_color(c->dither, c->colors); | ||||
|     if (ret) { | ||||
|         av_log(s, AV_LOG_ERROR, "Invalid value given to one of options\n"); | ||||
|         ret = AVERROR(EINVAL); | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     if (!c->window_title) | ||||
|         c->window_title = av_strdup(s->filename); | ||||
|     caca_set_display_title(c->display, c->window_title); | ||||
|     caca_set_display_time(c->display, av_rescale_q(1, st->codec->time_base, AV_TIME_BASE_Q)); | ||||
|  | ||||
|     return 0; | ||||
|  | ||||
| fail: | ||||
|     caca_write_trailer(s); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int caca_write_packet(AVFormatContext *s, AVPacket *pkt) | ||||
| { | ||||
|     CACAContext *c = s->priv_data; | ||||
|  | ||||
|     caca_dither_bitmap(c->canvas, 0, 0, c->window_width, c->window_height, c->dither, pkt->data); | ||||
|     caca_refresh_display(c->display); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #define OFFSET(x) offsetof(CACAContext,x) | ||||
| #define ENC AV_OPT_FLAG_ENCODING_PARAM | ||||
|  | ||||
| static const AVOption options[] = { | ||||
|     { "window_size",  "set window forced size",  OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL }, 0, 0, ENC}, | ||||
|     { "window_title", "set window title",        OFFSET(window_title), AV_OPT_TYPE_STRING,     {.str = NULL }, 0, 0, ENC }, | ||||
|     { "driver",       "set display driver",      OFFSET(driver),    AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, ENC }, | ||||
|     { "algorithm",    "set dithering algorithm", OFFSET(algorithm), AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC }, | ||||
|     { "antialias",    "set antialias method",    OFFSET(antialias), AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC }, | ||||
|     { "charset",      "set charset used to render output", OFFSET(charset), AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC }, | ||||
|     { "colors",       "set colors used to render output",  OFFSET(colors),  AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC }, | ||||
|     { "list_drivers", "list available drivers",  OFFSET(list_drivers), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1, ENC, "list_drivers" }, | ||||
|     { "true",         NULL, 0, AV_OPT_TYPE_CONST, {.dbl = 1}, 0, 0, ENC, "list_drivers" }, | ||||
|     { "false",        NULL, 0, AV_OPT_TYPE_CONST, {.dbl = 0}, 0, 0, ENC, "list_drivers" }, | ||||
|     { "list_dither", "list available dither options", OFFSET(list_dither), AV_OPT_TYPE_STRING, {.dbl=0}, 0, 1, ENC, "list_dither" }, | ||||
|     { "colors",       NULL, 0, AV_OPT_TYPE_CONST, {.str = "colors"},     0, 0, ENC, "list_dither" }, | ||||
|     { "charsets",     NULL, 0, AV_OPT_TYPE_CONST, {.str = "charsets"},   0, 0, ENC, "list_dither" }, | ||||
|     { "antialiases",  NULL, 0, AV_OPT_TYPE_CONST, {.str = "antialiases"},0, 0, ENC, "list_dither" }, | ||||
|     { "algorithms",   NULL, 0, AV_OPT_TYPE_CONST, {.str = "algorithms"}, 0, 0, ENC, "list_dither" }, | ||||
|     { NULL }, | ||||
| }; | ||||
|  | ||||
| static const AVClass caca_class = { | ||||
|     .class_name = "caca_outdev", | ||||
|     .item_name  = av_default_item_name, | ||||
|     .option     = options, | ||||
|     .version    = LIBAVUTIL_VERSION_INT, | ||||
| }; | ||||
|  | ||||
| AVOutputFormat ff_caca_muxer = { | ||||
|     .name           = "caca", | ||||
|     .long_name      = NULL_IF_CONFIG_SMALL("caca (color ASCII art) output device"), | ||||
|     .priv_data_size = sizeof(CACAContext), | ||||
|     .audio_codec    = CODEC_ID_NONE, | ||||
|     .video_codec    = CODEC_ID_RAWVIDEO, | ||||
|     .write_header   = caca_write_header, | ||||
|     .write_packet   = caca_write_packet, | ||||
|     .write_trailer  = caca_write_trailer, | ||||
|     .flags          = AVFMT_NOFILE, | ||||
|     .priv_class     = &caca_class, | ||||
| }; | ||||
| @@ -28,7 +28,7 @@ | ||||
| #include "libavutil/avutil.h" | ||||
|  | ||||
| #define LIBAVDEVICE_VERSION_MAJOR  54 | ||||
| #define LIBAVDEVICE_VERSION_MINOR   1 | ||||
| #define LIBAVDEVICE_VERSION_MINOR   2 | ||||
| #define LIBAVDEVICE_VERSION_MICRO 100 | ||||
|  | ||||
| #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user