FFmpeg
xv.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Jeff Moguillansky
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * XVideo output device
24  *
25  * TODO:
26  * - add support to more formats
27  */
28 
29 #include <X11/Xlib.h>
30 #include <X11/extensions/Xv.h>
31 #include <X11/extensions/XShm.h>
32 #include <X11/extensions/Xvlib.h>
33 #include <sys/shm.h>
34 
35 #include "libavutil/opt.h"
36 #include "libavutil/pixdesc.h"
37 #include "libavutil/imgutils.h"
38 #include "libavformat/internal.h"
39 #include "avdevice.h"
40 
41 typedef struct {
42  AVClass *class;
43  GC gc;
44 
45  Window window;
46  int64_t window_id;
47  char *window_title;
48  int window_width, window_height;
49  int window_x, window_y;
50  int dest_x, dest_y; /**< display area position */
51  unsigned int dest_w, dest_h; /**< display area dimensions */
52 
53  Display* display;
54  char *display_name;
55 
56  XvImage* yuv_image;
57  enum AVPixelFormat image_format;
58  int image_width, image_height;
59  XShmSegmentInfo yuv_shminfo;
60  int xv_port;
62 } XVContext;
63 
64 typedef struct XVTagFormatMap
65 {
66  int tag;
69 
70 static const XVTagFormatMap tag_codec_map[] = {
71  { MKTAG('I','4','2','0'), AV_PIX_FMT_YUV420P },
72  { MKTAG('U','Y','V','Y'), AV_PIX_FMT_UYVY422 },
73  { MKTAG('Y','U','Y','2'), AV_PIX_FMT_YUYV422 },
74  { 0, AV_PIX_FMT_NONE }
75 };
76 
78 {
79  const XVTagFormatMap *m = tag_codec_map;
80  int i;
81  for (i = 0; m->tag; m = &tag_codec_map[++i]) {
82  if (m->format == format)
83  return m->tag;
84  }
85  return 0;
86 }
87 
89 {
90  XVContext *xv = s->priv_data;
91  if (xv->display) {
92  XShmDetach(xv->display, &xv->yuv_shminfo);
93  if (xv->yuv_image)
94  shmdt(xv->yuv_image->data);
95  XFree(xv->yuv_image);
96  if (xv->gc)
97  XFreeGC(xv->display, xv->gc);
98  XCloseDisplay(xv->display);
99  }
100  return 0;
101 }
102 
104 {
105  XVContext *xv = s->priv_data;
106  unsigned int num_adaptors;
107  XvAdaptorInfo *ai;
108  XvImageFormatValues *fv;
109  XColor fgcolor;
110  XWindowAttributes window_attrs;
111  int num_formats = 0, j, tag, ret;
112  AVCodecParameters *par = s->streams[0]->codecpar;
113 
114  if ( s->nb_streams > 1
115  || par->codec_type != AVMEDIA_TYPE_VIDEO
116  || par->codec_id != AV_CODEC_ID_RAWVIDEO) {
117  av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
118  return AVERROR(EINVAL);
119  }
120 
121  if (!(tag = xv_get_tag_from_format(par->format))) {
122  av_log(s, AV_LOG_ERROR,
123  "Unsupported pixel format '%s', only yuv420p, uyvy422, yuyv422 are currently supported\n",
125  return AVERROR_PATCHWELCOME;
126  }
127  xv->image_format = par->format;
128 
129  xv->display = XOpenDisplay(xv->display_name);
130  if (!xv->display) {
131  av_log(s, AV_LOG_ERROR, "Could not open the X11 display '%s'\n", xv->display_name);
132  return AVERROR(EINVAL);
133  }
134 
135  xv->image_width = par->width;
136  xv->image_height = par->height;
137  if (!xv->window_width && !xv->window_height) {
138  AVRational sar = par->sample_aspect_ratio;
139  xv->window_width = par->width;
140  xv->window_height = par->height;
141  if (sar.num) {
142  if (sar.num > sar.den)
143  xv->window_width = av_rescale(xv->window_width, sar.num, sar.den);
144  if (sar.num < sar.den)
145  xv->window_height = av_rescale(xv->window_height, sar.den, sar.num);
146  }
147  }
148  if (!xv->window_id) {
149  xv->window = XCreateSimpleWindow(xv->display, DefaultRootWindow(xv->display),
150  xv->window_x, xv->window_y,
151  xv->window_width, xv->window_height,
152  0, 0, 0);
153  if (!xv->window_title) {
154  if (!(xv->window_title = av_strdup(s->url))) {
155  ret = AVERROR(ENOMEM);
156  goto fail;
157  }
158  }
159  XStoreName(xv->display, xv->window, xv->window_title);
160  xv->wm_delete_message = XInternAtom(xv->display, "WM_DELETE_WINDOW", False);
161  XSetWMProtocols(xv->display, xv->window, &xv->wm_delete_message, 1);
162  XMapWindow(xv->display, xv->window);
163  } else
164  xv->window = xv->window_id;
165 
166  if (XvQueryAdaptors(xv->display, DefaultRootWindow(xv->display), &num_adaptors, &ai) != Success) {
167  ret = AVERROR_EXTERNAL;
168  goto fail;
169  }
170  if (!num_adaptors) {
171  av_log(s, AV_LOG_ERROR, "No X-Video adaptors present\n");
172  return AVERROR(ENODEV);
173  }
174  xv->xv_port = ai[0].base_id;
175  XvFreeAdaptorInfo(ai);
176 
177  fv = XvListImageFormats(xv->display, xv->xv_port, &num_formats);
178  if (!fv) {
179  ret = AVERROR_EXTERNAL;
180  goto fail;
181  }
182  for (j = 0; j < num_formats; j++) {
183  if (fv[j].id == tag) {
184  break;
185  }
186  }
187  XFree(fv);
188 
189  if (j >= num_formats) {
190  av_log(s, AV_LOG_ERROR,
191  "Device does not support pixel format %s, aborting\n",
193  ret = AVERROR(EINVAL);
194  goto fail;
195  }
196 
197  xv->gc = XCreateGC(xv->display, xv->window, 0, 0);
198  xv->image_width = par->width;
199  xv->image_height = par->height;
200  xv->yuv_image = XvShmCreateImage(xv->display, xv->xv_port, tag, 0,
201  xv->image_width, xv->image_height, &xv->yuv_shminfo);
202  xv->yuv_shminfo.shmid = shmget(IPC_PRIVATE, xv->yuv_image->data_size,
203  IPC_CREAT | 0777);
204  xv->yuv_shminfo.shmaddr = (char *)shmat(xv->yuv_shminfo.shmid, 0, 0);
205  xv->yuv_image->data = xv->yuv_shminfo.shmaddr;
206  xv->yuv_shminfo.readOnly = False;
207 
208  XShmAttach(xv->display, &xv->yuv_shminfo);
209  XSync(xv->display, False);
210  shmctl(xv->yuv_shminfo.shmid, IPC_RMID, 0);
211 
212  XGetWindowAttributes(xv->display, xv->window, &window_attrs);
213  fgcolor.red = fgcolor.green = fgcolor.blue = 0;
214  fgcolor.flags = DoRed | DoGreen | DoBlue;
215  XAllocColor(xv->display, window_attrs.colormap, &fgcolor);
216  XSetForeground(xv->display, xv->gc, fgcolor.pixel);
217  //force display area recalculation at first frame
218  xv->window_width = xv->window_height = 0;
219 
220  return 0;
221  fail:
222  xv_write_trailer(s);
223  return ret;
224 }
225 
227 {
228  XVContext *xv = s->priv_data;
229  AVRational sar, dar; /* sample and display aspect ratios */
230  AVStream *st = s->streams[0];
231  AVCodecParameters *par = st->codecpar;
232 
233  /* compute overlay width and height from the codec context information */
234  sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
235  dar = av_mul_q(sar, (AVRational){ par->width, par->height });
236 
237  /* we suppose the screen has a 1/1 sample aspect ratio */
238  /* fit in the window */
239  if (av_cmp_q(dar, (AVRational){ xv->dest_w, xv->dest_h }) > 0) {
240  /* fit in width */
241  xv->dest_y = xv->dest_h;
242  xv->dest_x = 0;
243  xv->dest_h = av_rescale(xv->dest_w, dar.den, dar.num);
244  xv->dest_y -= xv->dest_h;
245  xv->dest_y /= 2;
246  } else {
247  /* fit in height */
248  xv->dest_x = xv->dest_w;
249  xv->dest_y = 0;
250  xv->dest_w = av_rescale(xv->dest_h, dar.num, dar.den);
251  xv->dest_x -= xv->dest_w;
252  xv->dest_x /= 2;
253  }
254 }
255 
257 {
258  XVContext *xv = s->priv_data;
259  XWindowAttributes window_attrs;
260 
261  XGetWindowAttributes(xv->display, xv->window, &window_attrs);
262  if (window_attrs.width != xv->window_width || window_attrs.height != xv->window_height) {
263  XRectangle rect[2];
264  xv->dest_w = window_attrs.width;
265  xv->dest_h = window_attrs.height;
267  if (xv->dest_x) {
268  rect[0].width = rect[1].width = xv->dest_x;
269  rect[0].height = rect[1].height = window_attrs.height;
270  rect[0].y = rect[1].y = 0;
271  rect[0].x = 0;
272  rect[1].x = xv->dest_w + xv->dest_x;
273  XFillRectangles(xv->display, xv->window, xv->gc, rect, 2);
274  }
275  if (xv->dest_y) {
276  rect[0].width = rect[1].width = window_attrs.width;
277  rect[0].height = rect[1].height = xv->dest_y;
278  rect[0].x = rect[1].x = 0;
279  rect[0].y = 0;
280  rect[1].y = xv->dest_h + xv->dest_y;
281  XFillRectangles(xv->display, xv->window, xv->gc, rect, 2);
282  }
283  }
284 
285  if (XvShmPutImage(xv->display, xv->xv_port, xv->window, xv->gc,
286  xv->yuv_image, 0, 0, xv->image_width, xv->image_height,
287  xv->dest_x, xv->dest_y, xv->dest_w, xv->dest_h, True) != Success) {
288  av_log(s, AV_LOG_ERROR, "Could not copy image to XV shared memory buffer\n");
289  return AVERROR_EXTERNAL;
290  }
291  return 0;
292 }
293 
295  int linesize[4])
296 {
297  XVContext *xv = s->priv_data;
298  XvImage *img = xv->yuv_image;
299  uint8_t *data[3] = {
300  img->data + img->offsets[0],
301  img->data + img->offsets[1],
302  img->data + img->offsets[2]
303  };
304 
305  /* Check messages. Window might get closed. */
306  if (!xv->window_id) {
307  XEvent event;
308  while (XPending(xv->display)) {
309  XNextEvent(xv->display, &event);
310  if (event.type == ClientMessage && event.xclient.data.l[0] == xv->wm_delete_message) {
311  av_log(xv, AV_LOG_DEBUG, "Window close event.\n");
312  return AVERROR(EPIPE);
313  }
314  }
315  }
316 
317  av_image_copy(data, img->pitches, (const uint8_t **)input_data, linesize,
318  xv->image_format, img->width, img->height);
319  return xv_repaint(s);
320 }
321 
323 {
324  AVCodecParameters *par = s->streams[0]->codecpar;
325  uint8_t *data[4];
326  int linesize[4];
327 
328  av_image_fill_arrays(data, linesize, pkt->data, par->format,
329  par->width, par->height, 1);
330  return write_picture(s, data, linesize);
331 }
332 
333 static int xv_write_frame(AVFormatContext *s, int stream_index, AVFrame **frame,
334  unsigned flags)
335 {
336  /* xv_write_header() should have accepted only supported formats */
337  if ((flags & AV_WRITE_UNCODED_FRAME_QUERY))
338  return 0;
339  return write_picture(s, (*frame)->data, (*frame)->linesize);
340 }
341 
342 static int xv_control_message(AVFormatContext *s, int type, void *data, size_t data_size)
343 {
344  switch(type) {
346  return xv_repaint(s);
347  default:
348  break;
349  }
350  return AVERROR(ENOSYS);
351 }
352 
353 #define OFFSET(x) offsetof(XVContext, x)
354 static const AVOption options[] = {
355  { "display_name", "set display name", OFFSET(display_name), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
356  { "window_id", "set existing window id", OFFSET(window_id), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM },
357  { "window_size", "set window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
358  { "window_title", "set window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
359  { "window_x", "set window x offset", OFFSET(window_x), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
360  { "window_y", "set window y offset", OFFSET(window_y), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
361  { NULL }
362 
363 };
364 
365 static const AVClass xv_class = {
366  .class_name = "xvideo outdev",
367  .item_name = av_default_item_name,
368  .option = options,
369  .version = LIBAVUTIL_VERSION_INT,
371 };
372 
374  .name = "xv",
375  .long_name = NULL_IF_CONFIG_SMALL("XV (XVideo) output device"),
376  .priv_data_size = sizeof(XVContext),
377  .audio_codec = AV_CODEC_ID_NONE,
378  .video_codec = AV_CODEC_ID_RAWVIDEO,
381  .write_uncoded_frame = xv_write_frame,
383  .control_message = xv_control_message,
385  .priv_class = &xv_class,
386 };
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:81
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:690
#define NULL
Definition: coverity.c:32
Repaint request message.
Definition: avdevice.h:144
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
static void compute_display_area(AVFormatContext *s)
Definition: xv.c:226
AVOption.
Definition: opt.h:246
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
static const AVOption options[]
Definition: xv.c:354
misc image utilities
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVRational sample_aspect_ratio
Video only.
Definition: avcodec.h:4044
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3968
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:943
int num
Numerator.
Definition: rational.h:59
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align)
Setup the data pointers and linesizes based on the specified image parameters and the provided array...
Definition: imgutils.c:411
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
unsigned int dest_h
display area dimensions
Definition: xv.c:51
GLint GLenum type
Definition: opengl_enc.c:104
static AVPacket pkt
static int xv_write_header(AVFormatContext *s)
Definition: xv.c:103
static int xv_repaint(AVFormatContext *s)
Definition: xv.c:256
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3960
Format I/O context.
Definition: avformat.h:1358
#define img
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
static int xv_write_frame(AVFormatContext *s, int stream_index, AVFrame **frame, unsigned flags)
Definition: xv.c:333
uint8_t
int width
Video only.
Definition: avcodec.h:4034
XShmSegmentInfo yuv_shminfo
Definition: xv.c:59
AVOptions.
Query whether the feature is possible on this stream.
Definition: internal.h:642
int dest_y
display area position
Definition: xv.c:50
static int xv_get_tag_from_format(enum AVPixelFormat format)
Definition: xv.c:77
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1426
enum AVPixelFormat format
Definition: xv.c:67
int window_x
Definition: xv.c:49
static void input_data(MLPEncodeContext *ctx, void *samples)
Wrapper function for inputting data in two different bit-depths.
Definition: mlpenc.c:1275
uint8_t * data
Definition: avcodec.h:1480
#define av_log(a,...)
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:276
int window_width
Definition: xv.c:48
Display * display
Definition: xv.c:53
Main libavdevice API header.
static const AVClass xv_class
Definition: xv.c:365
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
int64_t window_id
Definition: xv.c:46
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
enum AVPixelFormat image_format
Definition: xv.c:57
static int xv_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: xv.c:322
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
char * url
input or output URL.
Definition: avformat.h:1454
Window window
Definition: xv.c:45
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
XvImage * yuv_image
Definition: xv.c:56
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3964
Definition: r3d.c:36
#define fail()
Definition: checkasm.h:122
void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], const uint8_t *src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Copy image in src_data to dst_data.
Definition: imgutils.c:387
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1414
int xv_port
Definition: xv.c:60
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
const char * name
Definition: avformat.h:505
static int xv_write_trailer(AVFormatContext *s)
Definition: xv.c:88
int tag
Definition: xv.c:66
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
int image_height
Definition: xv.c:58
#define s(width, name)
Definition: cbs_vp9.c:257
Stream structure.
Definition: avformat.h:881
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
#define AVFMT_NOTIMESTAMPS
Format does not need / have any timestamps.
Definition: avformat.h:467
Definition: xv.c:41
GC gc
Definition: xv.c:43
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:251
char * display_name
Definition: xv.c:54
int dest_x
Definition: xv.c:50
int image_width
Definition: xv.c:58
Atom wm_delete_message
Definition: xv.c:61
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
int window_y
Definition: xv.c:49
static const XVTagFormatMap tag_codec_map[]
Definition: xv.c:70
static const char * window_title
Definition: ffplay.c:312
Describe the class of an AVClass context structure.
Definition: log.h:67
static int xv_control_message(AVFormatContext *s, int type, void *data, size_t data_size)
Definition: xv.c:342
Definition: f_ebur128.c:91
unsigned int dest_w
Definition: xv.c:51
Rational number (pair of numerator and denominator).
Definition: rational.h:58
int window_height
Definition: xv.c:48
offset must point to two consecutive integers
Definition: opt.h:233
#define flags(name, subs,...)
Definition: cbs_av1.c:561
#define OFFSET(x)
Definition: xv.c:353
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
AVOutputFormat ff_xv_muxer
Definition: xv.c:373
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:463
int den
Denominator.
Definition: rational.h:60
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition: avformat.h:470
void * priv_data
Format private data.
Definition: avformat.h:1386
static int write_picture(AVFormatContext *s, uint8_t *input_data[4], int linesize[4])
Definition: xv.c:294
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:349
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1028
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:2438
char * window_title
Definition: xv.c:47
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
#define MKTAG(a, b, c, d)
Definition: common.h:366
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
This structure stores compressed data.
Definition: avcodec.h:1457