[FFmpeg-devel] x11 output device for libavdevice

Paul B Mahol onemda at gmail.com
Thu Apr 11 01:30:18 CEST 2013


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.


More information about the ffmpeg-devel mailing list