[FFmpeg-devel] [PATCH] libcaca output device

Stefano Sabatini stefasab at gmail.com
Sat Jul 21 01:25:32 CEST 2012


On date Friday 2012-07-20 18:12:45 +0000, Paul B Mahol encoded:
> 
> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  configure                |    6 ++
>  doc/outdevs.texi         |   52 +++++++++++
>  libavdevice/Makefile     |    1 +
>  libavdevice/alldevices.c |    1 +
>  libavdevice/caca.c       |  222 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 282 insertions(+), 0 deletions(-)
>  create mode 100644 libavdevice/caca.c
> 
> diff --git a/configure b/configure
> index bc46bb7..3b4d9bc 100755
> --- a/configure
> +++ b/configure
> @@ -173,6 +173,8 @@ 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 caca output device using libcaca
> +                           graphics library [no]

Nit: simpler and on a line (more grep-friendly):
--enable-libcaca         enable textual display using libcaca [no]

>    --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 +1053,7 @@ CONFIG_LIST="
>      libaacplus
>      libass
>      libbluray
> +    libcaca
>      libcdio
>      libcelt
>      libdc1394
> @@ -1693,6 +1696,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 +3316,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 +3693,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}"
> 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.

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.

Maybe add a link to the project (kitch) website: http://caca.zoy.org/wiki/libcaca

> +
> + 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.

Missing list_drivers and list_dither options.

> + 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..f873128
> --- /dev/null
> +++ b/libavdevice/caca.c
> @@ -0,0 +1,222 @@
> +/*

> + * Copyright (c) 2011 Paul B Mahol

Is that so old?

> + *
> + * 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;

Nit++: maybe on a line

> +
> +    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_available_drivers(CACAContext *c)

Nit++: list_drivers is shorter and as meaningful, same below.

> +{
> +    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)                                 \

You could pass thing and things in order to avoid singular/plural
mismatches in the function names (list_dither_color -> list_dither_colors):

stativ void list_dither_## things(...)
...
   av_log(c->ctx, AV_LOG_INFO, "Available " #things ":\n");

> +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 %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_available_drivers(c);
> +        return AVERROR_EXIT;
> +    }

> +    if (c->list_dither) {

> +        if (!strcmp(c->list_dither, "color"))
> +            list_available_dither_color(c);

should all them take plural form?

I mean "-list_dither colors" seems more natural than -list_dither color.

> +        else if (!strcmp(c->list_dither, "charset"))
> +            list_available_dither_charset(c);
> +        else if (!strcmp(c->list_dither, "algorithm"))
> +            list_available_dither_algorithm(c);
> +        else if (!strcmp(c->list_dither, "antialias"))
> +            list_available_dither_antialias(c);

else {
     av_log(s, AV_LOG_ERROR, "Invalid value '%s' for 'list_dither' option\n");
     return AVERROR(EINVAL);
}

> +        return AVERROR_EXIT;
> +    }
> +
> +

nit+10!: double empty line

> +    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);
> +    }
> +
> +    if (!c->window_width || !c->window_height) {
> +        c->window_width  = encctx->width;
> +        c->window_height = encctx->height;
> +    }
> +    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_available_drivers(c);
> +        caca_free_canvas(c->canvas);
> +        return AVERROR(errno);
> +    }
> +
> +    bpp = av_get_bits_per_pixel(&av_pix_fmt_descriptors[encctx->pix_fmt]);
> +    c->dither = caca_create_dither(bpp, encctx->width, encctx->height,
> +                                   bpp * encctx->width / 8,
> +                                   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);

nit+++: vertical align

[...]

Looks cool otherwise (it was in my mental list of fancy todos since a
while). I'll try to come up with a libaa outdev if you are not already
working on it.
-- 
FFmpeg = Forgiving and Frightening Mythic Power Elected God


More information about the ffmpeg-devel mailing list