[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