[FFmpeg-devel] x11 output device for libavdevice
Clément Bœsch
ubitux at gmail.com
Sat Apr 13 01:47:45 CEST 2013
On Fri, Apr 12, 2013 at 11:31:37PM +0000, Moguillansky, Jeff wrote:
> Thanks,
> how about this one?
> Jeff
> 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
>
Missing configure x11 dependencies: it will likely break compilation with
system without X11.
> # external libraries
> OBJS-$(CONFIG_LIBCDIO_INDEV) += libcdio.o
> diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
> index daa6638..5680796 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..d7a1131
> --- /dev/null
> +++ b/libavdevice/xvideo.c
> @@ -0,0 +1,155 @@
> +/*
> + * 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 "libavutil/avstring.h"
> +#include "libavutil/mem.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/parseutils.h"
> +#include "libavutil/pixdesc.h"
> +#include "avdevice.h"
> +#include "libavfilter/libmpcodecs/img_format.h"
> +
libavdevice must not depend on libavfilter. And especially not in the
libmpcodecs wrapper.
> +typedef struct {
> + GC gc;
> + Window window;
> + Display* dpy;
> + XvImage* yuv_image;
> + XShmSegmentInfo yuv_shminfo;
Trailing whitespace here and in various other parts of the file.
> + int xv_port, width, height;
> +} XVideoData;
> +
> +typedef struct {
> + AVClass *class;
> + char *window_title;
> + XVideoData *data;
> +} XVideoContext;
> +
> +#define OFFSET(x) offsetof(XVideoContext,x)
> +
> +#define VERIFY(s) if (!(s)) { av_log(NULL, AV_LOG_ERROR, "[%s][%d]: ERROR: %s failed\n", __FUNCTION__,__LINE__,#s); return AVERROR_UNKNOWN; }
> +
Some meaningful error management instead of this would be greatly
appreciated.
Also, av_log should be using the context for logging.
> +static int xvideo_write_header(AVFormatContext *s) {
style: \n between ) and { for functions.
> + XVideoContext *xvideo = s->priv_data;
> + XVideoData *data = av_mallocz(sizeof(XVideoData));
> + unsigned int p_num_adaptors;
> + XvAdaptorInfo *ai = NULL;
> + AVCodecContext *pCodecCtx = s->streams[0]->codec;
pleaseAvoidCamelCaseForVariables
Also adding some respiration spacing between declarations and code (here)
would be appreciated.
> + VERIFY(pCodecCtx->codec_tag == IMGFMT_I420);
> + VERIFY(s->nb_streams == 1);
> + xvideo->data = data;
return AVERROR(ENOMEM) here if !data
> + if (!xvideo->window_title) xvideo->window_title = av_strdup("");
style: please break that line
Also return AVERROR(ENOMEM) if xvideo->window_title is NULL after this
step.
> + data->width = pCodecCtx->width;
> + data->height = pCodecCtx->height;
> + data->dpy = XOpenDisplay(NULL);
> + VERIFY(data->dpy != NULL);
> + data->window = XCreateSimpleWindow(data->dpy, DefaultRootWindow(data->dpy),0, 0,data->width,data->height,0,0,0);
style: inconsistent packed spacing
> + XStoreName(data->dpy, data->window, xvideo->window_title);
> + XMapWindow(data->dpy, data->window);
> + VERIFY(XvQueryAdaptors(data->dpy, DefaultRootWindow(data->dpy),&p_num_adaptors, &ai) == Success);
> + data->xv_port = ai[0].base_id;
> + data->gc = XCreateGC(data->dpy, data->window, 0, 0);
> + VERIFY(data->gc != NULL);
> + data->yuv_image = XvShmCreateImage(data->dpy, data->xv_port, IMGFMT_I420 , 0, data->width, data->height, &data->yuv_shminfo);
> + VERIFY(data->yuv_image != NULL);
> + data->yuv_shminfo.shmid = shmget(IPC_PRIVATE, data->yuv_image->data_size, IPC_CREAT | 0777);
> + VERIFY(data->yuv_shminfo.shmid != -1);
> + data->yuv_image->data = (char*)shmat(data->yuv_shminfo.shmid, 0, 0);
> + VERIFY(data->yuv_image->data != NULL);
> + data->yuv_shminfo.shmaddr = data->yuv_image->data;
> + data->yuv_shminfo.readOnly = False;
> + VERIFY(XShmAttach(data->dpy, &data->yuv_shminfo) != 0);
> + return 0;
> +}
> +
> +static int xvideo_write_packet(AVFormatContext *s, AVPacket *pkt) {
> + XVideoContext *xvideo = NULL;
> + XVideoData *data = NULL;
> + XvImage *img = NULL;
> + int y, h;
> + XWindowAttributes attr;
> + AVPicture pict;
> + AVCodecContext *pCodecCtx = s->streams[0]->codec;
> + xvideo = s->priv_data;
> + VERIFY(xvideo != NULL);
This check is not needed
> + data = xvideo->data;
> + VERIFY(data != NULL);
Assuming the check I mentioned in the previous version, you can
av_assert0() here or just drop that check completely.
> + img = data->yuv_image;
> + VERIFY(img != NULL);
You already checked for this in the previous function. av_assert0() if
you're paranoid, or just drop that check
> + h = img->height / 2;
> + avpicture_fill(&pict, pkt->data, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
> + VERIFY(pict.linesize[0] == img->pitches[0] && pict.linesize[1] == img->pitches[1] && pict.linesize[2] == img->pitches[2]);
> + 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]);
^
inconsistent spacing
breaking alignment
> + }
> + XGetWindowAttributes(data->dpy, data->window,&attr);
> + VERIFY(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);
style: some weird inconsistent spacing around commas here.
> + return 0;
> +}
> +
> +static int xvideo_write_trailer(AVFormatContext *s) {
> + XVideoContext *xvideo = NULL;
> + XVideoData *data = NULL;
Unnecessary NULL assignment; assign them directly to s->priv_data and
xvideo->data.
> + xvideo = s->priv_data;
> + VERIFY(xvideo != NULL);
> + data = xvideo->data;
> + VERIFY(data != NULL);
Unnecessary checks.
> + av_freep(&xvideo->window_title);
> + 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; }
> +
Unnecessary if
also, trailing whitespace in the line below
> + 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,
> + .priv_class = &xvideo_class,
> +};
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
--
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20130413/d34be708/attachment.asc>
More information about the ffmpeg-devel
mailing list