[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