[FFmpeg-devel] x11 output device for libavdevice

Stefano Sabatini stefasab at gmail.com
Wed Apr 17 00:57:07 CEST 2013


On date Tuesday 2013-04-16 22:24:34 +0000, Moguillansky, Jeff encoded:
> Hi Paul,
> here's a new patch,

please use git format and send in attachment the generated patch, it's
usually easier to handle than copy&paste from the mail text.

> please let me know what's next.
> Thanks,
> Jeff

> diff --git a/configure b/configure
> index a0e6b47..90dc430 100755
> --- a/configure
> +++ b/configure
> @@ -238,6 +238,7 @@ External library support:
>    --enable-opencl          enable OpenCL code
>    --enable-openssl         enable openssl [no]
>    --enable-x11grab         enable X11 grabbing [no]
> +  --enable-xv              enable Xv video display
>    --enable-zlib            enable zlib [autodetect]
>  
>  Advanced options (experts only):
> @@ -1190,6 +1191,7 @@ EXTERNAL_LIBRARY_LIST="
>      opencl
>      openssl
>      x11grab
> +    xv
>      zlib
>  "
>  
> @@ -2046,6 +2048,7 @@ openal_indev_deps="openal"
>  oss_indev_deps_any="soundcard_h sys_soundcard_h"
>  oss_outdev_deps_any="soundcard_h sys_soundcard_h"
>  pulse_indev_deps="libpulse"
> +xvideo_outdev_deps="xv"

alphabetical order

>  sdl_outdev_deps="sdl"
>  sndio_indev_deps="sndio_h"
>  sndio_outdev_deps="sndio_h"
> @@ -4051,6 +4054,7 @@ else
>    fi
>  fi
>  enabled sdl && add_cflags $sdl_cflags && add_extralibs $sdl_libs
> +enabled xv && require2 xv "X11/Xlib.h X11/extensions/Xvlib.h" XvGetPortAttribute -lXv
>  
>  texi2html --help 2> /dev/null | grep -q 'init-file' && enable texi2html || disable texi2html
>  makeinfo --version > /dev/null 2>&1 && enable makeinfo  || disable makeinfo
> diff --git a/libavdevice/Makefile b/libavdevice/Makefile
> index efffa8b..83728cc 100644
> --- a/libavdevice/Makefile
> +++ b/libavdevice/Makefile
> @@ -36,6 +36,7 @@ OBJS-$(CONFIG_V4L2_INDEV)                += v4l2.o timefilter.o
>  OBJS-$(CONFIG_V4L_INDEV)                 += v4l.o
>  OBJS-$(CONFIG_VFWCAP_INDEV)              += vfwcap.o
>  OBJS-$(CONFIG_X11GRAB_INDEV)             += x11grab.o
> +OBJS-$(CONFIG_XVIDEO_OUTDEV)             += xvideo.o
>  
>  # external libraries
>  OBJS-$(CONFIG_LIBCDIO_INDEV)             += libcdio.o
> diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
> index daa6638..bd4e341 100644
> --- a/libavdevice/alldevices.c
> +++ b/libavdevice/alldevices.c
> @@ -64,6 +64,7 @@ void avdevice_register_all(void)
>  //    REGISTER_INDEV   (V4L,              v4l
>      REGISTER_INDEV   (VFWCAP,           vfwcap);
>      REGISTER_INDEV   (X11GRAB,          x11grab);
> +    REGISTER_OUTDEV  (XVIDEO,           xvideo);
>  
>      /* external libraries */
>      REGISTER_INDEV   (LIBCDIO,          libcdio);
> diff --git a/libavdevice/xvideo.c b/libavdevice/xvideo.c
> new file mode 100644
> index 0000000..f6ec205
> --- /dev/null
> +++ b/libavdevice/xvideo.c
> @@ -0,0 +1,188 @@
> +/*

> + * XVideo output device

nit: put file description to a separate doxy:
/** @file
 * XVideo output device
 */

see sdl.c for example

> + * Copyright (c) 2013 Jeff Moguillansky
> + *
> + * 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 <X11/Xlib.h>
> +#include <X11/extensions/Xv.h>
> +#include <X11/extensions/Xvlib.h>
> +#include <X11/extensions/XShm.h>
> +#include <sys/shm.h>
> +
> +#include "libavutil/avstring.h"
> +#include "libavutil/common.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/parseutils.h"
> +#include "libavutil/pixdesc.h"
> +#include "avdevice.h"
> +

> +typedef struct {
> +    GC gc;
> +    Window window;
> +    Display* dpy;
> +    XvImage* yuv_image;
> +    XShmSegmentInfo yuv_shminfo;
> +    int xv_port, width, height;
> +} XVideoData;
> +
> +typedef struct {
> +    AVClass *class;
> +    char *window_title;
> +    XVideoData *data;
> +} XVideoContext;

any reason not to merge the two structures

> +
> +#define OFFSET(x) offsetof(XVideoContext,x)

Nit: this could be defined close to the option array.

> +
> +static int xvideo_write_header(AVFormatContext *s)
> +{
> +    XVideoContext *xvideo = s->priv_data;
> +    XVideoData *data = (XVideoData*)calloc(1,sizeof(XVideoData));

missing NULL check, and it could be avoided by merging XVideoData in
XVideoContext. Also unneded cast.

> +    unsigned int p_num_adaptors;
> +    XvAdaptorInfo *ai = NULL;
> +    XvImageFormatValues *fv = NULL;
> +    int num_formats = 0, j, format_I420_supported = 0;
> +    AVCodecContext *ctx = s->streams[0]->codec;
> +    xvideo->data = data;
> +
> +    data->width = ctx->width;
> +    data->height = ctx->height;
> +    data->dpy = XOpenDisplay(NULL);
> +

> +    data->window = XCreateSimpleWindow(data->dpy, DefaultRootWindow(data->dpy), 
> +        0, 0, data->width, data->height, 0, 0, 0
> +    );

nit: weird indent

> +
> +    if (!xvideo->window_title)
> +        xvideo->window_title = av_strdup(s->filename);

missing NULL check

> +
> +    XStoreName(data->dpy, data->window, xvideo->window_title);
> +    XMapWindow(data->dpy, data->window);
> +
> +    if (XvQueryAdaptors(data->dpy, DefaultRootWindow(data->dpy), 
> +        &p_num_adaptors, &ai) != Success)
> +        return AVERROR_UNKNOWN;

AVERROR_EXTERNAL

also there is some way to return an error string from xv? (not blocking)


> +    data->xv_port = ai[0].base_id;
> +    
> +    fv = XvListImageFormats(data->dpy, data->xv_port, &num_formats);

> +    if (fv == NULL)
> +		return AVERROR_UNKNOWN;

nit: if (!fv)

AVERROR_EXTERNAL, here and below

> +    for (j = 0; j<num_formats; j++) {
> +		if (fv[j].id == MKTAG('I','4','2','0')) { format_I420_supported = 1; break; }
> +	}

weird indent

> +	XFree(fv);
> +	if (!format_I420_supported)
> +		return AVERROR_UNKNOWN;
> +	
> +    data->gc = XCreateGC(data->dpy, data->window, 0, 0);
> +    data->yuv_image = XvShmCreateImage(data->dpy, data->xv_port, 
> +        MKTAG('I','4','2','0'), 0, data->width, data->height, &data->yuv_shminfo
> +    );
> +    data->yuv_shminfo.shmid = shmget(IPC_PRIVATE, data->yuv_image->data_size, IPC_CREAT | 0777);
> +    data->yuv_shminfo.shmaddr = (char *) shmat(data->yuv_shminfo.shmid, 0,0);
> +    data->yuv_image->data = data->yuv_shminfo.shmaddr;
> +    data->yuv_shminfo.readOnly = False;
> +
> +    XShmAttach(data->dpy, &data->yuv_shminfo);
> +    XSync(data->dpy, False);
> +    shmctl(data->yuv_shminfo.shmid, IPC_RMID, 0);
> +
> +    return 0;
> +}
> +
> +static int xvideo_write_packet(AVFormatContext *s, AVPacket *pkt)
> +{
> +    XVideoContext *xvideo = s->priv_data;
> +    XVideoData *data = xvideo->data;
> +    XvImage *img = NULL;
> +    XWindowAttributes attr;
> +    AVPicture pict;
> +    AVCodecContext *ctx = s->streams[0]->codec;
> +    int y, h;
> +
> +    img = data->yuv_image;
> +    h = img->height / 2;
> +    avpicture_fill(&pict, pkt->data, ctx->pix_fmt, ctx->width, ctx->height);

av_image_fill_arrays()?

> +

> +    for (y = 0; y < img->height; y++) {
> +        memcpy(&img->data[img->offsets[0] + (y * img->pitches[0])], 
> +            &pict.data[0][y * pict.linesize[0]], img->pitches[0]);
> +    }
> +
> +    for (y = 0; y < h; ++y) {
> +        memcpy(&img->data[img->offsets[1] + (y * img->pitches[1])], 
> +            &pict.data[1][y * pict.linesize[1]], img->pitches[1]);
> +        memcpy(&img->data[img->offsets[2] + (y * img->pitches[2])], 
> +            &pict.data[2][y * pict.linesize[2]], img->pitches[2]);
> +    }

av_image_copy()?


> +
> +    XGetWindowAttributes(data->dpy, data->window, &attr);
> +
> +    if (XvShmPutImage(data->dpy, data->xv_port, data->window, data->gc, 
> +        data->yuv_image, 0, 0, data->width, data->height, 0, 0, 
> +        attr.width,attr.height, True) != Success)
> +        return AVERROR_UNKNOWN;
> +    return 0;
> +}
> +
> +static int xvideo_write_trailer(AVFormatContext *s)
> +{
> +    XVideoContext *xvideo = s->priv_data;
> +    XVideoData *data = xvideo->data;
> +

> +    av_freep(&xvideo->window_title);

unneded (will be freed automatically when the context is closed)


> +    XShmDetach(data->dpy, &data->yuv_shminfo);
> +    shmdt(data->yuv_image->data);
> +    XFree(data->yuv_image);
> +    XCloseDisplay(data->dpy);
> +
> +    if (xvideo->data) {
> +        free(xvideo->data);
> +        xvideo->data = NULL;

av_freep, also you can avoid this altogether if you merge the
structure in the context

> +    }
> +
> +    return 0;
> +}
> +
> +static const AVOption options[] = {
> +    { "window_title", "set window title", OFFSET(window_title), 
> +        AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM 
> +    }, 
> +    { NULL },
> +};
> +
> +static const AVClass xvideo_class = {
> +    .class_name = "xvideo outdev",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +AVOutputFormat ff_xvideo_muxer = {
> +    .name           = "xv",
> +    .long_name      = NULL_IF_CONFIG_SMALL("XVideo output device"),
> +    .priv_data_size = sizeof(XVideoContext),
> +    .audio_codec    = AV_CODEC_ID_NONE,
> +    .video_codec    = AV_CODEC_ID_RAWVIDEO,
> +    .write_header   = xvideo_write_header,
> +    .write_packet   = xvideo_write_packet,
> +    .write_trailer  = xvideo_write_trailer,
> +    .flags          = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
> +    .priv_class     = &xvideo_class,

Missing docs in doc/outdevs.texi.
-- 
FFmpeg = Furious and Faithful Muttering Puritan Emblematic Gospel


More information about the ffmpeg-devel mailing list