libcaca output device
authorPaul B Mahol <onemda@gmail.com>
Tue, 13 Mar 2012 21:45:46 +0000 (21:45 +0000)
committerPaul B Mahol <onemda@gmail.com>
Sat, 21 Jul 2012 03:33:02 +0000 (03:33 +0000)
configure
doc/outdevs.texi
libavdevice/Makefile
libavdevice/alldevices.c
libavdevice/caca.c [new file with mode: 0644]
libavdevice/version.h

index bc46bb7..09f7714 100755 (executable)
--- a/configure
+++ b/configure
@@ -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-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
   --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
     libaacplus
     libass
     libbluray
+    libcaca
     libcdio
     libcelt
     libdc1394
     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"
 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"
 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 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
 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 "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}"
 echo "libcdio support           ${libcdio-no}"
 echo "libcelt enabled           ${libcelt-no}"
 echo "libdc1394 support         ${libdc1394-no}"
index 8034a22..296ec22 100644 (file)
@@ -22,6 +22,67 @@ A description of the currently available output devices follows.
 
 ALSA (Advanced Linux Sound Architecture) output device.
 
 
 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.
 @section oss
 
 OSS (Open Sound System) output device.
index 4759a82..8f6f843 100644 (file)
@@ -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_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
 OBJS-$(CONFIG_DSHOW_INDEV)               += dshow.o dshow_enummediatypes.o \
                                             dshow_enumpins.o dshow_filter.o \
                                             dshow_pin.o dshow_common.o
index 2a0bffb..092e6c5 100644 (file)
@@ -40,6 +40,7 @@ void avdevice_register_all(void)
     /* devices */
     REGISTER_INOUTDEV (ALSA, alsa);
     REGISTER_INDEV    (BKTR, bktr);
     /* 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);
     REGISTER_INDEV    (DSHOW, dshow);
     REGISTER_INDEV    (DV1394, dv1394);
     REGISTER_INDEV    (FBDEV, fbdev);
diff --git a/libavdevice/caca.c b/libavdevice/caca.c
new file mode 100644 (file)
index 0000000..2cd9e56
--- /dev/null
@@ -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,
+};
index 93a07bd..f2f6ce4 100644 (file)
@@ -28,7 +28,7 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVDEVICE_VERSION_MAJOR  54
 #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, \
 #define LIBAVDEVICE_VERSION_MICRO 100
 
 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \