[FFmpeg-devel] [PATCH] libcaca output device

Stefano Sabatini stefasab at gmail.com
Fri Jul 20 11:22:12 CEST 2012


On date Friday 2012-07-20 02:08:21 +0000, Paul B Mahol encoded:
> 
> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  configure                |   12 ++
>  doc/outdevs.texi         |   52 ++++++++++
>  libavdevice/Makefile     |    1 +
>  libavdevice/alldevices.c |    1 +
>  libavdevice/caca.c       |  252 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 318 insertions(+), 0 deletions(-)
>  create mode 100644 libavdevice/caca.c
> 
> diff --git a/configure b/configure
> index 300f128..2c5d62a 100755
> --- a/configure
> +++ b/configure
> @@ -1230,6 +1230,7 @@ HAVE_LIST="
>      jack_port_get_latency_range
>      kbhit
>      ldbrx
> +    libcaca
>      libdc1394_1
>      libdc1394_2
>      llrint
> @@ -1697,6 +1698,7 @@ fbdev_indev_deps="linux_fb_h"
>  iec61883_indev_deps="libiec61883"
>  jack_indev_deps="jack_jack_h sem_timedwait"
>  lavfi_indev_deps="avfilter"
> +libcaca_outdev_deps="libcaca"
>  libcdio_indev_deps="libcdio"
>  libdc1394_indev_deps="libdc1394"
>  libv4l2_indev_deps="libv4l2"
> @@ -3363,6 +3365,14 @@ if enabled libdc1394; then
>      die "ERROR: No version of libdc1394 found "
>  fi
>  

> +LIBCACA_CONFIG="${cross_prefix}caca-config"
> +if "${LIBCACA_CONFIG}" --version > /dev/null 2>&1; then
> +    libcaca_cflags=$("${LIBCACA_CONFIG}" --cflags)
> +    libcaca_libs=$("${LIBCACA_CONFIG}" --libs)
> +    enable libcaca
> +fi
> +enabled libcaca && add_cflags $libcaca_cflags && add_extralibs $libcaca_libs
> +

The alternative to auto-detection is to require the user to specify
--enable-libcaca, which is consistent with the use of all the other
libraries (but libsdl) and thus recommended (libcaca is not special).

Also I suggest two simpler alternatives to this:
enabled libcaca && require_pkg_config caca caca.h caca_create_canvas

or even simpler:
enabled libcaca && require libcaca caca.h caca_create_canvas -lcaca

provided that libcaca has no complex dependencies.

>  SDL_CONFIG="${cross_prefix}sdl-config"
>  if check_pkg_config sdl SDL_events.h SDL_PollEvent; then
>      check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x010201" $sdl_cflags &&

> @@ -3817,6 +3827,8 @@ HOSTLDFLAGS=$host_ldflags
>  HOSTLIBS=$host_libs
>  TARGET_EXEC=$target_exec
>  TARGET_PATH=$target_path
> +CACA_LIBS=$libcaca_libs
> +CACA_CFLAGS=$libcaca_cflags

Is this still required?

>  SDL_LIBS=$sdl_libs
>  SDL_CFLAGS=$sdl_cflags
>  LIB_INSTALL_EXTRA_CMD=$LIB_INSTALL_EXTRA_CMD
> diff --git a/doc/outdevs.texi b/doc/outdevs.texi
> index 8034a22..71e4986 100644
> --- a/doc/outdevs.texi
> +++ b/doc/outdevs.texi
> @@ -22,6 +22,58 @@ A description of the currently available output devices follows.
>  
>  ALSA (Advanced Linux Sound Architecture) output device.
>  
> + at 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 libcaca installed on your system
> +when configuring your build.
> +libcaca is a graphics library that outputs text instead of pixels.
> +
> + at subsection Options
> +
> + at table @option
> +
> + at item window_title
> +Set the CACA window title, if not specified default to the filename
> +specified for the output device.
> +
> + at item window_size
> +Set the CACA window size, can be a string of the form
> + at var{width}x at var{height} or a video size abbreviation.
> +If not specified it defaults to the size of the input video.
> +
> + at item driver
> +Set display driver.
> +
> + at item algorithm
> +Set dithering algorithm. Dithering is necessary
> +because the picture being rendered has usually far more colours than
> +the available palette.
> +
> + at item antialias
> +Set antialias method. Antialiasing smoothens the rendered
> +image and avoids the commonly seen staircase effect.
> +
> + at item charset
> +Set which characters are going to be used when rendering text.
> +
> + at item colors
> +Set colors to be used when rendering text.
> + at end table
> +
> + at subsection Examples
> +
> +The following command shows the @command{ffmpeg} output is an
> +CACA window, forcing its size to 80x25:
> + at example
> +ffmpeg -i INPUT -vcodec rawvideo -pix_fmt rgb24 -window_size 80x25 -f caca -
> + at end example
> +
>  @section oss
>  
>  OSS (Open Sound System) output device.
> diff --git a/libavdevice/Makefile b/libavdevice/Makefile
> index 4759a82..8f6f843 100644
> --- a/libavdevice/Makefile
> +++ b/libavdevice/Makefile
> @@ -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
> diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
> index 2a0bffb..092e6c5 100644
> --- a/libavdevice/alldevices.c
> +++ b/libavdevice/alldevices.c
> @@ -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);
> diff --git a/libavdevice/caca.c b/libavdevice/caca.c
> new file mode 100644
> index 0000000..09fe192
> --- /dev/null
> +++ b/libavdevice/caca.c
> @@ -0,0 +1,252 @@
> +/*
> + * Copyright (c) 2011 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 {
> +    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;
> +
> +    int             list_antialias, list_algorithms;
> +    int             list_charsets, list_colors;
> +    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 available_drivers(CACAContext *c)

Nit: list_available_drivers

> +{
> +    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]);
> +}
> +

> +static void available_colors(CACAContext *c)
> +{
> +    const char *const *color = caca_get_dither_color_list(c->dither);
> +    int i;
> +
> +    av_log(c->ctx, AV_LOG_INFO, "Available colors:\n");
> +    for (i = 0; color[i]; i += 2)
> +        av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", color[i], color[i + 1]);
> +}
> +
> +static void available_charsets(CACAContext *c)
> +{
> +    const char *const *charset = caca_get_dither_charset_list(c->dither);
> +    int i;
> +
> +    av_log(c->ctx, AV_LOG_INFO, "Available charsets:\n");
> +    for (i = 0; charset[i]; i += 2)
> +        av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", charset[i], charset[i + 1]);
> +}
> +
> +static void available_algorithms(CACAContext *c)
> +{
> +    const char *const *algorithm = caca_get_dither_algorithm_list(c->dither);
> +    int i;
> +
> +    av_log(c->ctx, AV_LOG_INFO, "Available dithering algorithms:\n");
> +    for (i = 0; algorithm[i]; i += 2)
> +        av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", algorithm[i], algorithm[i + 1]);
> +}
> +
> +static void available_antialias(CACAContext *c)
> +{
> +    const char *const *antialias = caca_get_dither_antialias_list(c->dither);
> +    int i;
> +
> +    av_log(c->ctx, AV_LOG_INFO, "Available antialias methods:\n");
> +    for (i = 0; antialias[i]; i += 2)
> +        av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", antialias[i], antialias[i + 1]);
> +}

This can be macrotized:
#define DEFINE_LIST_DITHER(thing, things_str) \
static void list_available_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 dither " things_str " methods:\n"); \
...

DEFINE_LIST_DITHER(color, "colors");
...
DEFINE_LIST_DITHER(antialias, "antialias methods");

or factorized using templating.

> +
> +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)
> +        available_drivers(c);
> +    if (c->list_colors)
> +        available_colors(c);
> +    if (c->list_charsets)
> +        available_charsets(c);
> +    if (c->list_algorithms)
> +        available_algorithms(c);
> +    if (c->list_antialias)
> +        available_antialias(c);

To reduce the number of options, you could have a -list_drivers and
-list_dither thing option, working like this:

int log_dither_list(CACAContext *caca, const char *thing)
{
...
{ "antialias", caca_get_dither_antialias_list, "antialias methods" };
...

for entries[j]
   if (!strcmp(entries[i].thing)) {
      const char *const *list = entries[i].list_fn(caca);
      for (j = 0; list[j]; j += 2)
          av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", list[j], list[j + 1]);
      return AVERROR_EXIT;
   }

log error
return AVERROR(EINVAL);
}

[...]
-- 
FFmpeg = Foolish and Fundamental Meaningless Proud Experimenting Guru


More information about the ffmpeg-devel mailing list