[FFmpeg-devel] x11 output device for libavdevice

Paul B Mahol onemda at gmail.com
Thu Apr 11 10:42:14 CEST 2013


On 4/11/13, Moguillansky, Jeff <Jeff.Moguillansky at am.sony.com> wrote:
> Hi,
> Let me know if this is better.
> Here's a patch file.
> I added error handling, fixed the includes, and got rid of the for loop.
> I'm not sure how to modify configure script (I just modified the generated
> makefiles)?
>
> Thanks,
> Jeff


Please stop top posting. Also read http://ffmpeg.org/contact.html

> From f6e30e8180c01e655f87c033b518cdf009e2ebe2 Mon Sep 17 00:00:00 2001
> From: JeffMoguillansky <Jeff.Moguillansky at am.sony.com>
> Date: Wed, 10 Apr 2013 17:49:48 -0700
> Subject: [PATCH 1/2] Implementing x11 output device

Sqush both patches into one, no point in separation.
>
> ---
>  libavdevice/x11.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 135 insertions(+)
>  create mode 100644 libavdevice/x11.c
>
> diff --git a/libavdevice/x11.c b/libavdevice/x11.c
> new file mode 100644
> index 0000000..8d6bd37
> --- /dev/null
> +++ b/libavdevice/x11.c
> @@ -0,0 +1,135 @@
> +/*
> + * 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 <sys/shm.h>
> +#include <xorg/fourcc.h>

I dont have this header installed.
When I said there is better way to write I420 I expected you to reuse
ffmpeg code.

> +#include "libavutil/avstring.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;

Tabs are not allowed at all in code.

> +} X11Data;
> +
> +typedef struct {
> +    AVClass *class;
> +    char *window_title;
> +    X11Data *data;
> +} X11Context;
> +
> +#define OFFSET(x) offsetof(X11Context,x)
> +#define V(s) if (!(s)) { av_log(NULL, AV_LOG_ERROR, "[%s][%d]: ERROR: %s failed\n", __FUNCTION__,__LINE__,#s); return AVERROR_UNKNOWN; }
> +
> +static int x11_write_header(AVFormatContext *s) {

Again style issue.
> +    X11Context *x11 = s->priv_data;

Weird identation.

> +	X11Data *data = (X11Data*)calloc(1,sizeof(X11Data));
> +	unsigned int p_num_adaptors;
> +	XvAdaptorInfo *ai = NULL;
> +	AVCodecContext *pCodecCtx = s->streams[0]->codec;
> +	x11->data = data;
> +	if (!x11->window_title) x11->window_title = av_strdup("");
> +	data->width = pCodecCtx->width; data->height = pCodecCtx->height;
> +	V((data->dpy = XOpenDisplay(NULL)) != NULL);
> +	data->window = XCreateSimpleWindow(data->dpy, DefaultRootWindow(data->dpy),0, 0,data->width,data->height,0,0,0);
> +	XStoreName(data->dpy, data->window, x11->window_title);
> +	XMapWindow(data->dpy, data->window);
> +	V(XvQueryAdaptors(data->dpy, DefaultRootWindow(data->dpy),&p_num_adaptors, &ai) == Success);
> +	data->xv_port = ai[0].base_id;
> +	V((data->gc = XCreateGC(data->dpy, data->window, 0, 0)) != NULL);
> +	V((data->yuv_image = XvShmCreateImage(data->dpy, data->xv_port, FOURCC_I420 , 0, data->width, data->height, &data->yuv_shminfo)) != NULL);
> +	V((data->yuv_shminfo.shmid = shmget(IPC_PRIVATE, data->yuv_image->data_size, IPC_CREAT | 0777)) != -1);
> +	V((data->yuv_image->data = (char*)shmat(data->yuv_shminfo.shmid, 0, 0)) != NULL);
> +	data->yuv_shminfo.shmaddr = data->yuv_image->data;
> +	data->yuv_shminfo.readOnly = False;
> +	V(XShmAttach(data->dpy, &data->yuv_shminfo) != 0);
> +	return 0;
> +}
> +
> +static int x11_write_packet(AVFormatContext *s, AVPacket *pkt) {
> +	X11Context *x11 = NULL;
> +	X11Data *data = NULL;
> +	XvImage	*img = NULL;
> +	int	y, h;
> +	XWindowAttributes attr;
> +	AVPicture pict;
> +	AVCodecContext *pCodecCtx = s->streams[0]->codec;
> +	V((x11 = s->priv_data) != NULL);
> +	V((data = x11->data) != NULL);
> +	V((img = data->yuv_image) != NULL);
> +	h = img->height / 2;
> +	avpicture_fill(&pict, pkt->data, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
> +	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]);
> +	}
> +	XGetWindowAttributes(data->dpy, data->window,&attr);
> +	V(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);
> +	XSync(data->dpy,True);
> +	return 0;
> +}
> +
> +static int x11_write_trailer(AVFormatContext *s) {
> +	X11Context *x11 = NULL;
> +	X11Data *data = NULL;
> +	V((x11 = s->priv_data) != NULL);
> +	V((data = x11->data) != NULL);
> +	av_freep(&x11->window_title);
> +	XShmDetach(data->dpy,&data->yuv_shminfo);
> +	shmdt(data->yuv_image->data);
> +	XFree(data->yuv_image);
> +	XCloseDisplay(data->dpy);
> +	if (x11->data) { free(x11->data); x11->data = NULL; }
> +	
> +	return 0;
> +}
> +
> +static const AVOption options[] = {
> +    { "window_title", "set X11 window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
> +	{ NULL },
> +};
> +
> +static const AVClass x11_class = {
> +    .class_name = "x11 outdev",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +AVOutputFormat ff_x11_muxer = {
> +    .name           = "x11",

but you are using XV extension, and not using x11 at all.

So device,file, etc should be named xv instead.

> +    .long_name      = NULL_IF_CONFIG_SMALL("x11 output device"),
> +    .priv_data_size = sizeof(X11Context),
> +    .audio_codec    = AV_CODEC_ID_NONE,
> +    .video_codec    = AV_CODEC_ID_RAWVIDEO,
> +    .write_header   = x11_write_header,
> +    .write_packet   = x11_write_packet,
> +    .write_trailer  = x11_write_trailer,
> +    .flags          = AVFMT_NOFILE,
> +    .priv_class     = &x11_class,
> +};
> --
> 1.7.10.4
>
>
> From 2506039ecc826d05e5bbe05a96313cf3257c3d0d Mon Sep 17 00:00:00 2001
> From: JeffMoguillansky <Jeff.Moguillansky at am.sony.com>
> Date: Wed, 10 Apr 2013 17:56:21 -0700
> Subject: [PATCH 2/2] Implementing x11 output

As already mentioned this one should be squashed in previous commit.
>
> ---
>  libavdevice/Makefile     |    1 +
>  libavdevice/alldevices.c |    1 +
>  2 files changed, 2 insertions(+)
>
> diff --git a/libavdevice/Makefile b/libavdevice/Makefile
> index efffa8b..8af4079 100644
> --- a/libavdevice/Makefile
> +++ b/libavdevice/Makefile
>  OBJS-$(CONFIG_OSS_OUTDEV)                += oss_audio.o
>  OBJS-$(CONFIG_PULSE_INDEV)               += pulse.o
>  OBJS-$(CONFIG_SDL_OUTDEV)                += sdl.o
> +OBJS-$(CONFIG_X11_OUTDEV)                += x11.o

Broken alphabetical order.

>  OBJS-$(CONFIG_SNDIO_INDEV)               += sndio_common.o sndio_dec.o
>  OBJS-$(CONFIG_SNDIO_OUTDEV)              += sndio_common.o sndio_enc.o
>  OBJS-$(CONFIG_V4L2_INDEV)                += v4l2.o timefilter.o
> diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
> index daa6638..e367423 100644
> --- a/libavdevice/alldevices.c
> +++ b/libavdevice/alldevices.c
> @@ -59,6 +59,7 @@ void avdevice_register_all(void)
>      REGISTER_INOUTDEV(OSS,              oss);
>      REGISTER_INDEV   (PULSE,            pulse);
>      REGISTER_OUTDEV  (SDL,              sdl);
> +    REGISTER_OUTDEV	 (x11,				x11);

Again tabs, and broken vertical alignment

>      REGISTER_INOUTDEV(SNDIO,            sndio);
>      REGISTER_INDEV   (V4L2,             v4l2);
>  //    REGISTER_INDEV   (V4L,              v4l
> --
> 1.7.10.4
>

> ________________________________________
> From: ffmpeg-devel-bounces at ffmpeg.org [ffmpeg-devel-bounces at ffmpeg.org] on
> behalf of Paul B Mahol [onemda at gmail.com]
> Sent: Wednesday, April 10, 2013 4:30 PM
> To: FFmpeg development discussions and patches
> Subject: Re: [FFmpeg-devel] x11 output device for libavdevice
>
> On 4/10/13, Moguillansky, Jeff <Jeff.Moguillansky at am.sony.com> wrote:
>> Hello,
>> I really like the libavdevice code.  I implemented an X11 output device
>> for
>> libavdevice.  I would like to request if it's possible to add this to the
>> main branch?  It uses XVideo extension for hardware acceleration and it
>> supports window resizing.
>>
>> To use (with video and audio output):
>> ffmpeg -i <input file> -f x11 "Output" -f alsa "default"
>>
>> Here's my code:
>
> First normal way to send code is via patch.
>
>>
>> libavdevice/x11.c:
>>
>> /*
>>  * Copyright (c) 2011 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 "libavutil/avstring.h"
>> #include "libavutil/opt.h"
>> #include "libavutil/parseutils.h"
>> #include "libavutil/pixdesc.h"
>> #include "avdevice.h"
>> #include <X11/Xlib.h>
>> #include <X11/extensions/Xv.h>
>> #include <X11/extensions/Xvlib.h>
>> #include <sys/shm.h>
>
> Wrong order of headers. <> ones goes first.
>
>>
>> typedef struct {
>>       GC gc; Window window; Display* dpy; XvImage* yuv_image[1];
>> XShmSegmentInfo
>> yuv_shminfo[1];
>>       int xv_port, width, height;
>> } X11Data;
>>
>> typedef struct {
>>     AVClass *class;
>>     char *window_title;
>>     X11Data *data;
>> } X11Context;
>>
>> #define OFFSET(x) offsetof(X11Context,x)
>>
>> static int x11_write_header(AVFormatContext *s) {
>
> If you looked at other files in libavdevice, you would notice they do
> not use such coding style.
>
>>       X11Context *x11 = s->priv_data;
>>       X11Data *data = (X11Data*)calloc(1,sizeof(X11Data));
>>       unsigned int p_num_adaptors;
>>       int j;
>>       XvAdaptorInfo *ai;
>>       AVCodecContext *pCodecCtx = s->streams[0]->codec;
>>       x11->data = data;
>>       if (!x11->window_title) x11->window_title = av_strdup("");
>>       data->width = pCodecCtx->width; data->height = pCodecCtx->height;
>>       data->dpy = XOpenDisplay(NULL);
>>       data->window = XCreateSimpleWindow(data->dpy,
>> DefaultRootWindow(data->dpy),0, 0,data->width,data->height,0,0,0);
>>       XStoreName(data->dpy, data->window, x11->window_title);
>>       XMapWindow(data->dpy, data->window);
>>       XvQueryAdaptors(data->dpy,
>> DefaultRootWindow(data->dpy),&p_num_adaptors,
>> &ai);
>>       data->xv_port = ai[0].base_id;
>>       data->gc = XCreateGC(data->dpy, data->window, 0, 0);
>
> Can any of those fail? If yes, it will segv on next call which is far
> from being robust.
>
>>       for (j = 0; j<1; j++) {
>
> What is point of this loop?
>
>>               data->yuv_image[j] = XvShmCreateImage(data->dpy,
>> data->xv_port+j,
>> ('I'|('4'<<8)|('2'<<16)|'0'<<24) , 0, data->width, data->height,
>
> Probably other format can be queried and supported to. Beside there is
> nicer way to write I420.
>
>> &data->yuv_shminfo[j]);
>>               data->yuv_shminfo[j].shmid = shmget(IPC_PRIVATE,
>> data->yuv_image[j]->data_size, IPC_CREAT | 0777);
>>               data->yuv_image[j]->data =
>> (char*)shmat(data->yuv_shminfo[j].shmid, 0, 0);
>> data->yuv_shminfo[j].shmaddr = data->yuv_image[j]->data;
>>               data->yuv_shminfo[j].readOnly = False;
>>       }
>>       XShmAttach(data->dpy, &data->yuv_shminfo[0]);
>>       return 0;
>> }
>>
>> static int x11_write_packet(AVFormatContext *s, AVPacket *pkt) {
>>       X11Context *x11 = s->priv_data;
>>       X11Data *data = x11->data;
>>       XvImage *img = data->yuv_image[0];
>>       int     y, h = img->height / 2;
>>       XWindowAttributes attr;
>>       AVPicture pict;
>>       AVCodecContext *pCodecCtx = s->streams[0]->codec;
>>       avpicture_fill(&pict, pkt->data, pCodecCtx->pix_fmt,
>> pCodecCtx->width,
>> pCodecCtx->height);
>>       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]);
>>       }
>>       XGetWindowAttributes(data->dpy, data->window,&attr);
>>       XvShmPutImage(data->dpy, data->xv_port, data->window, data->gc,
>> data->yuv_image[0],0, 0, data->width, data->height,0, 0,
>> attr.width,attr.height, True);
>>       XSync(data->dpy,True);
>>       return 0;
>> }
>>
>> static int x11_write_trailer(AVFormatContext *s) {
>>       X11Context *x11 = s->priv_data;
>>       X11Data *data = x11->data;
>>       int j;
>>       av_freep(&x11->window_title);
>>       XShmDetach(data->dpy,&data->yuv_shminfo[0]);
>>       for (j = 0; j<1; j++) {
>>               shmdt(data->yuv_image[j]->data);
>>               XFree(data->yuv_image[j]);
>>       }
>>       XCloseDisplay(data->dpy);
>>
>>       return 0;
>> }
>>
>> static const AVOption options[] = {
>>     { "window_title", "set X11 window title", OFFSET(window_title),
>> AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
>>       { NULL },
>> };
>>
>> static const AVClass x11_class = {
>>     .class_name = "x11 outdev",
>>     .item_name  = av_default_item_name,
>>     .option     = options,
>>     .version    = LIBAVUTIL_VERSION_INT,
>> };
>>
>> AVOutputFormat ff_x11_muxer = {
>>     .name           = "x11",
>>     .long_name      = NULL_IF_CONFIG_SMALL("x11 output device"),
>>     .priv_data_size = sizeof(X11Context),
>>     .audio_codec    = AV_CODEC_ID_NONE,
>>     .video_codec    = AV_CODEC_ID_RAWVIDEO,
>>     .write_header   = x11_write_header,
>>     .write_packet   = x11_write_packet,
>>     .write_trailer  = x11_write_trailer,
>>     .flags          = AVFMT_NOFILE | AVFMT_VARIABLE_FPS |
>> AVFMT_NOTIMESTAMPS,
>>     .priv_class     = &x11_class,
>> };
>>
>>
>>
>>
>> ....
>> here's the other modifications:
>> libavdevice/alldevices.c:
>> void avdevice_register_all(void) {
>>   ...
>> REGISTER_OUTDEV (X11, x11);
>>   ...
>> }
>>
>> libavdevice/Makefile:
>> ...
>> OBJS-$(CONFIG_X11_OUTDEV)                += x11.o
>>
>>
>> ffmpeg/config.mak:
>> EXTRALIBS=... -lX11 -lXv ...
>>
>> ffmpeg/config.h:
>> ...
>> #define CONFIG_X11_OUTDEV 1
>>
>>
>>
>>
>> Thanks,
>> Jeff
>
> Please tell us if you do NOT plan to work on above mentioned code issues.
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>


More information about the ffmpeg-devel mailing list