1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2013 Jeff Moguillansky 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci/** 22cabdff1aSopenharmony_ci * @file 23cabdff1aSopenharmony_ci * XVideo output device 24cabdff1aSopenharmony_ci * 25cabdff1aSopenharmony_ci * TODO: 26cabdff1aSopenharmony_ci * - add support to more formats 27cabdff1aSopenharmony_ci */ 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_ci#include <X11/Xlib.h> 30cabdff1aSopenharmony_ci#include <X11/extensions/Xv.h> 31cabdff1aSopenharmony_ci#include <X11/extensions/XShm.h> 32cabdff1aSopenharmony_ci#include <X11/extensions/Xvlib.h> 33cabdff1aSopenharmony_ci#include <sys/shm.h> 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci#include "libavutil/opt.h" 36cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h" 37cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 38cabdff1aSopenharmony_ci#include "libavformat/mux.h" 39cabdff1aSopenharmony_ci#include "avdevice.h" 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_citypedef struct { 42cabdff1aSopenharmony_ci AVClass *class; 43cabdff1aSopenharmony_ci GC gc; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci Window window; 46cabdff1aSopenharmony_ci int64_t window_id; 47cabdff1aSopenharmony_ci char *window_title; 48cabdff1aSopenharmony_ci int window_width, window_height; 49cabdff1aSopenharmony_ci int window_x, window_y; 50cabdff1aSopenharmony_ci int dest_x, dest_y; /**< display area position */ 51cabdff1aSopenharmony_ci unsigned int dest_w, dest_h; /**< display area dimensions */ 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci Display* display; 54cabdff1aSopenharmony_ci char *display_name; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci XvImage* yuv_image; 57cabdff1aSopenharmony_ci enum AVPixelFormat image_format; 58cabdff1aSopenharmony_ci int image_width, image_height; 59cabdff1aSopenharmony_ci XShmSegmentInfo yuv_shminfo; 60cabdff1aSopenharmony_ci int xv_port; 61cabdff1aSopenharmony_ci Atom wm_delete_message; 62cabdff1aSopenharmony_ci} XVContext; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_citypedef struct XVTagFormatMap 65cabdff1aSopenharmony_ci{ 66cabdff1aSopenharmony_ci int tag; 67cabdff1aSopenharmony_ci enum AVPixelFormat format; 68cabdff1aSopenharmony_ci} XVTagFormatMap; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic const XVTagFormatMap tag_codec_map[] = { 71cabdff1aSopenharmony_ci { MKTAG('I','4','2','0'), AV_PIX_FMT_YUV420P }, 72cabdff1aSopenharmony_ci { MKTAG('U','Y','V','Y'), AV_PIX_FMT_UYVY422 }, 73cabdff1aSopenharmony_ci { MKTAG('Y','U','Y','2'), AV_PIX_FMT_YUYV422 }, 74cabdff1aSopenharmony_ci { 0, AV_PIX_FMT_NONE } 75cabdff1aSopenharmony_ci}; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_cistatic int xv_get_tag_from_format(enum AVPixelFormat format) 78cabdff1aSopenharmony_ci{ 79cabdff1aSopenharmony_ci const XVTagFormatMap *m = tag_codec_map; 80cabdff1aSopenharmony_ci int i; 81cabdff1aSopenharmony_ci for (i = 0; m->tag; m = &tag_codec_map[++i]) { 82cabdff1aSopenharmony_ci if (m->format == format) 83cabdff1aSopenharmony_ci return m->tag; 84cabdff1aSopenharmony_ci } 85cabdff1aSopenharmony_ci return 0; 86cabdff1aSopenharmony_ci} 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_cistatic int xv_write_trailer(AVFormatContext *s) 89cabdff1aSopenharmony_ci{ 90cabdff1aSopenharmony_ci XVContext *xv = s->priv_data; 91cabdff1aSopenharmony_ci if (xv->display) { 92cabdff1aSopenharmony_ci XShmDetach(xv->display, &xv->yuv_shminfo); 93cabdff1aSopenharmony_ci if (xv->yuv_image) 94cabdff1aSopenharmony_ci shmdt(xv->yuv_image->data); 95cabdff1aSopenharmony_ci XFree(xv->yuv_image); 96cabdff1aSopenharmony_ci if (xv->gc) 97cabdff1aSopenharmony_ci XFreeGC(xv->display, xv->gc); 98cabdff1aSopenharmony_ci XCloseDisplay(xv->display); 99cabdff1aSopenharmony_ci } 100cabdff1aSopenharmony_ci return 0; 101cabdff1aSopenharmony_ci} 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_cistatic int xv_write_header(AVFormatContext *s) 104cabdff1aSopenharmony_ci{ 105cabdff1aSopenharmony_ci XVContext *xv = s->priv_data; 106cabdff1aSopenharmony_ci unsigned int num_adaptors; 107cabdff1aSopenharmony_ci XvAdaptorInfo *ai; 108cabdff1aSopenharmony_ci XvImageFormatValues *fv; 109cabdff1aSopenharmony_ci XColor fgcolor; 110cabdff1aSopenharmony_ci XWindowAttributes window_attrs; 111cabdff1aSopenharmony_ci int num_formats = 0, j, tag, ret; 112cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[0]->codecpar; 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci if ( s->nb_streams > 1 115cabdff1aSopenharmony_ci || par->codec_type != AVMEDIA_TYPE_VIDEO 116cabdff1aSopenharmony_ci || (par->codec_id != AV_CODEC_ID_WRAPPED_AVFRAME && par->codec_id != AV_CODEC_ID_RAWVIDEO)) { 117cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Only a single raw or wrapped avframe video stream is supported.\n"); 118cabdff1aSopenharmony_ci return AVERROR(EINVAL); 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci if (!(tag = xv_get_tag_from_format(par->format))) { 122cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 123cabdff1aSopenharmony_ci "Unsupported pixel format '%s', only yuv420p, uyvy422, yuyv422 are currently supported\n", 124cabdff1aSopenharmony_ci av_get_pix_fmt_name(par->format)); 125cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 126cabdff1aSopenharmony_ci } 127cabdff1aSopenharmony_ci xv->image_format = par->format; 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci xv->display = XOpenDisplay(xv->display_name); 130cabdff1aSopenharmony_ci if (!xv->display) { 131cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not open the X11 display '%s'\n", xv->display_name); 132cabdff1aSopenharmony_ci return AVERROR(EINVAL); 133cabdff1aSopenharmony_ci } 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci xv->image_width = par->width; 136cabdff1aSopenharmony_ci xv->image_height = par->height; 137cabdff1aSopenharmony_ci if (!xv->window_width && !xv->window_height) { 138cabdff1aSopenharmony_ci AVRational sar = par->sample_aspect_ratio; 139cabdff1aSopenharmony_ci xv->window_width = par->width; 140cabdff1aSopenharmony_ci xv->window_height = par->height; 141cabdff1aSopenharmony_ci if (sar.num) { 142cabdff1aSopenharmony_ci if (sar.num > sar.den) 143cabdff1aSopenharmony_ci xv->window_width = av_rescale(xv->window_width, sar.num, sar.den); 144cabdff1aSopenharmony_ci if (sar.num < sar.den) 145cabdff1aSopenharmony_ci xv->window_height = av_rescale(xv->window_height, sar.den, sar.num); 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci if (!xv->window_id) { 149cabdff1aSopenharmony_ci xv->window = XCreateSimpleWindow(xv->display, DefaultRootWindow(xv->display), 150cabdff1aSopenharmony_ci xv->window_x, xv->window_y, 151cabdff1aSopenharmony_ci xv->window_width, xv->window_height, 152cabdff1aSopenharmony_ci 0, 0, 0); 153cabdff1aSopenharmony_ci if (!xv->window_title) { 154cabdff1aSopenharmony_ci if (!(xv->window_title = av_strdup(s->url))) { 155cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 156cabdff1aSopenharmony_ci goto fail; 157cabdff1aSopenharmony_ci } 158cabdff1aSopenharmony_ci } 159cabdff1aSopenharmony_ci XStoreName(xv->display, xv->window, xv->window_title); 160cabdff1aSopenharmony_ci xv->wm_delete_message = XInternAtom(xv->display, "WM_DELETE_WINDOW", False); 161cabdff1aSopenharmony_ci XSetWMProtocols(xv->display, xv->window, &xv->wm_delete_message, 1); 162cabdff1aSopenharmony_ci XMapWindow(xv->display, xv->window); 163cabdff1aSopenharmony_ci } else 164cabdff1aSopenharmony_ci xv->window = xv->window_id; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci if (XvQueryAdaptors(xv->display, DefaultRootWindow(xv->display), &num_adaptors, &ai) != Success) { 167cabdff1aSopenharmony_ci ret = AVERROR_EXTERNAL; 168cabdff1aSopenharmony_ci goto fail; 169cabdff1aSopenharmony_ci } 170cabdff1aSopenharmony_ci if (!num_adaptors) { 171cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "No X-Video adaptors present\n"); 172cabdff1aSopenharmony_ci return AVERROR(ENODEV); 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci xv->xv_port = ai[0].base_id; 175cabdff1aSopenharmony_ci XvFreeAdaptorInfo(ai); 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci fv = XvListImageFormats(xv->display, xv->xv_port, &num_formats); 178cabdff1aSopenharmony_ci if (!fv) { 179cabdff1aSopenharmony_ci ret = AVERROR_EXTERNAL; 180cabdff1aSopenharmony_ci goto fail; 181cabdff1aSopenharmony_ci } 182cabdff1aSopenharmony_ci for (j = 0; j < num_formats; j++) { 183cabdff1aSopenharmony_ci if (fv[j].id == tag) { 184cabdff1aSopenharmony_ci break; 185cabdff1aSopenharmony_ci } 186cabdff1aSopenharmony_ci } 187cabdff1aSopenharmony_ci XFree(fv); 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci if (j >= num_formats) { 190cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 191cabdff1aSopenharmony_ci "Device does not support pixel format %s, aborting\n", 192cabdff1aSopenharmony_ci av_get_pix_fmt_name(par->format)); 193cabdff1aSopenharmony_ci ret = AVERROR(EINVAL); 194cabdff1aSopenharmony_ci goto fail; 195cabdff1aSopenharmony_ci } 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci xv->gc = XCreateGC(xv->display, xv->window, 0, 0); 198cabdff1aSopenharmony_ci xv->image_width = par->width; 199cabdff1aSopenharmony_ci xv->image_height = par->height; 200cabdff1aSopenharmony_ci xv->yuv_image = XvShmCreateImage(xv->display, xv->xv_port, tag, 0, 201cabdff1aSopenharmony_ci xv->image_width, xv->image_height, &xv->yuv_shminfo); 202cabdff1aSopenharmony_ci xv->yuv_shminfo.shmid = shmget(IPC_PRIVATE, xv->yuv_image->data_size, 203cabdff1aSopenharmony_ci IPC_CREAT | 0777); 204cabdff1aSopenharmony_ci xv->yuv_shminfo.shmaddr = (char *)shmat(xv->yuv_shminfo.shmid, 0, 0); 205cabdff1aSopenharmony_ci xv->yuv_image->data = xv->yuv_shminfo.shmaddr; 206cabdff1aSopenharmony_ci xv->yuv_shminfo.readOnly = False; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci XShmAttach(xv->display, &xv->yuv_shminfo); 209cabdff1aSopenharmony_ci XSync(xv->display, False); 210cabdff1aSopenharmony_ci shmctl(xv->yuv_shminfo.shmid, IPC_RMID, 0); 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_ci XGetWindowAttributes(xv->display, xv->window, &window_attrs); 213cabdff1aSopenharmony_ci fgcolor.red = fgcolor.green = fgcolor.blue = 0; 214cabdff1aSopenharmony_ci fgcolor.flags = DoRed | DoGreen | DoBlue; 215cabdff1aSopenharmony_ci XAllocColor(xv->display, window_attrs.colormap, &fgcolor); 216cabdff1aSopenharmony_ci XSetForeground(xv->display, xv->gc, fgcolor.pixel); 217cabdff1aSopenharmony_ci //force display area recalculation at first frame 218cabdff1aSopenharmony_ci xv->window_width = xv->window_height = 0; 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci return 0; 221cabdff1aSopenharmony_ci fail: 222cabdff1aSopenharmony_ci xv_write_trailer(s); 223cabdff1aSopenharmony_ci return ret; 224cabdff1aSopenharmony_ci} 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_cistatic void compute_display_area(AVFormatContext *s) 227cabdff1aSopenharmony_ci{ 228cabdff1aSopenharmony_ci XVContext *xv = s->priv_data; 229cabdff1aSopenharmony_ci AVRational sar, dar; /* sample and display aspect ratios */ 230cabdff1aSopenharmony_ci AVStream *st = s->streams[0]; 231cabdff1aSopenharmony_ci AVCodecParameters *par = st->codecpar; 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci /* compute overlay width and height from the codec context information */ 234cabdff1aSopenharmony_ci sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 }; 235cabdff1aSopenharmony_ci dar = av_mul_q(sar, (AVRational){ par->width, par->height }); 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci /* we suppose the screen has a 1/1 sample aspect ratio */ 238cabdff1aSopenharmony_ci /* fit in the window */ 239cabdff1aSopenharmony_ci if (av_cmp_q(dar, (AVRational){ xv->dest_w, xv->dest_h }) > 0) { 240cabdff1aSopenharmony_ci /* fit in width */ 241cabdff1aSopenharmony_ci xv->dest_y = xv->dest_h; 242cabdff1aSopenharmony_ci xv->dest_x = 0; 243cabdff1aSopenharmony_ci xv->dest_h = av_rescale(xv->dest_w, dar.den, dar.num); 244cabdff1aSopenharmony_ci xv->dest_y -= xv->dest_h; 245cabdff1aSopenharmony_ci xv->dest_y /= 2; 246cabdff1aSopenharmony_ci } else { 247cabdff1aSopenharmony_ci /* fit in height */ 248cabdff1aSopenharmony_ci xv->dest_x = xv->dest_w; 249cabdff1aSopenharmony_ci xv->dest_y = 0; 250cabdff1aSopenharmony_ci xv->dest_w = av_rescale(xv->dest_h, dar.num, dar.den); 251cabdff1aSopenharmony_ci xv->dest_x -= xv->dest_w; 252cabdff1aSopenharmony_ci xv->dest_x /= 2; 253cabdff1aSopenharmony_ci } 254cabdff1aSopenharmony_ci} 255cabdff1aSopenharmony_ci 256cabdff1aSopenharmony_cistatic int xv_repaint(AVFormatContext *s) 257cabdff1aSopenharmony_ci{ 258cabdff1aSopenharmony_ci XVContext *xv = s->priv_data; 259cabdff1aSopenharmony_ci XWindowAttributes window_attrs; 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_ci XGetWindowAttributes(xv->display, xv->window, &window_attrs); 262cabdff1aSopenharmony_ci if (window_attrs.width != xv->window_width || window_attrs.height != xv->window_height) { 263cabdff1aSopenharmony_ci XRectangle rect[2]; 264cabdff1aSopenharmony_ci xv->dest_w = window_attrs.width; 265cabdff1aSopenharmony_ci xv->dest_h = window_attrs.height; 266cabdff1aSopenharmony_ci compute_display_area(s); 267cabdff1aSopenharmony_ci if (xv->dest_x) { 268cabdff1aSopenharmony_ci rect[0].width = rect[1].width = xv->dest_x; 269cabdff1aSopenharmony_ci rect[0].height = rect[1].height = window_attrs.height; 270cabdff1aSopenharmony_ci rect[0].y = rect[1].y = 0; 271cabdff1aSopenharmony_ci rect[0].x = 0; 272cabdff1aSopenharmony_ci rect[1].x = xv->dest_w + xv->dest_x; 273cabdff1aSopenharmony_ci XFillRectangles(xv->display, xv->window, xv->gc, rect, 2); 274cabdff1aSopenharmony_ci } 275cabdff1aSopenharmony_ci if (xv->dest_y) { 276cabdff1aSopenharmony_ci rect[0].width = rect[1].width = window_attrs.width; 277cabdff1aSopenharmony_ci rect[0].height = rect[1].height = xv->dest_y; 278cabdff1aSopenharmony_ci rect[0].x = rect[1].x = 0; 279cabdff1aSopenharmony_ci rect[0].y = 0; 280cabdff1aSopenharmony_ci rect[1].y = xv->dest_h + xv->dest_y; 281cabdff1aSopenharmony_ci XFillRectangles(xv->display, xv->window, xv->gc, rect, 2); 282cabdff1aSopenharmony_ci } 283cabdff1aSopenharmony_ci } 284cabdff1aSopenharmony_ci 285cabdff1aSopenharmony_ci if (XvShmPutImage(xv->display, xv->xv_port, xv->window, xv->gc, 286cabdff1aSopenharmony_ci xv->yuv_image, 0, 0, xv->image_width, xv->image_height, 287cabdff1aSopenharmony_ci xv->dest_x, xv->dest_y, xv->dest_w, xv->dest_h, True) != Success) { 288cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Could not copy image to XV shared memory buffer\n"); 289cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 290cabdff1aSopenharmony_ci } 291cabdff1aSopenharmony_ci return 0; 292cabdff1aSopenharmony_ci} 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_cistatic int write_picture(AVFormatContext *s, uint8_t *input_data[4], 295cabdff1aSopenharmony_ci int linesize[4]) 296cabdff1aSopenharmony_ci{ 297cabdff1aSopenharmony_ci XVContext *xv = s->priv_data; 298cabdff1aSopenharmony_ci XvImage *img = xv->yuv_image; 299cabdff1aSopenharmony_ci uint8_t *data[4] = { 300cabdff1aSopenharmony_ci img->data + img->offsets[0], 301cabdff1aSopenharmony_ci img->data + img->offsets[1], 302cabdff1aSopenharmony_ci img->data + img->offsets[2] 303cabdff1aSopenharmony_ci }; 304cabdff1aSopenharmony_ci 305cabdff1aSopenharmony_ci /* Check messages. Window might get closed. */ 306cabdff1aSopenharmony_ci if (!xv->window_id) { 307cabdff1aSopenharmony_ci XEvent event; 308cabdff1aSopenharmony_ci while (XPending(xv->display)) { 309cabdff1aSopenharmony_ci XNextEvent(xv->display, &event); 310cabdff1aSopenharmony_ci if (event.type == ClientMessage && event.xclient.data.l[0] == xv->wm_delete_message) { 311cabdff1aSopenharmony_ci av_log(xv, AV_LOG_DEBUG, "Window close event.\n"); 312cabdff1aSopenharmony_ci return AVERROR(EPIPE); 313cabdff1aSopenharmony_ci } 314cabdff1aSopenharmony_ci } 315cabdff1aSopenharmony_ci } 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci av_image_copy(data, img->pitches, (const uint8_t **)input_data, linesize, 318cabdff1aSopenharmony_ci xv->image_format, img->width, img->height); 319cabdff1aSopenharmony_ci return xv_repaint(s); 320cabdff1aSopenharmony_ci} 321cabdff1aSopenharmony_ci 322cabdff1aSopenharmony_cistatic int xv_write_packet(AVFormatContext *s, AVPacket *pkt) 323cabdff1aSopenharmony_ci{ 324cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[0]->codecpar; 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME) { 327cabdff1aSopenharmony_ci AVFrame *frame = (AVFrame *)pkt->data; 328cabdff1aSopenharmony_ci return write_picture(s, frame->data, frame->linesize); 329cabdff1aSopenharmony_ci } else { 330cabdff1aSopenharmony_ci uint8_t *data[4]; 331cabdff1aSopenharmony_ci int linesize[4]; 332cabdff1aSopenharmony_ci 333cabdff1aSopenharmony_ci av_image_fill_arrays(data, linesize, pkt->data, par->format, 334cabdff1aSopenharmony_ci par->width, par->height, 1); 335cabdff1aSopenharmony_ci return write_picture(s, data, linesize); 336cabdff1aSopenharmony_ci } 337cabdff1aSopenharmony_ci} 338cabdff1aSopenharmony_ci 339cabdff1aSopenharmony_cistatic int xv_write_frame(AVFormatContext *s, int stream_index, AVFrame **frame, 340cabdff1aSopenharmony_ci unsigned flags) 341cabdff1aSopenharmony_ci{ 342cabdff1aSopenharmony_ci /* xv_write_header() should have accepted only supported formats */ 343cabdff1aSopenharmony_ci if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) 344cabdff1aSopenharmony_ci return 0; 345cabdff1aSopenharmony_ci return write_picture(s, (*frame)->data, (*frame)->linesize); 346cabdff1aSopenharmony_ci} 347cabdff1aSopenharmony_ci 348cabdff1aSopenharmony_cistatic int xv_control_message(AVFormatContext *s, int type, void *data, size_t data_size) 349cabdff1aSopenharmony_ci{ 350cabdff1aSopenharmony_ci switch(type) { 351cabdff1aSopenharmony_ci case AV_APP_TO_DEV_WINDOW_REPAINT: 352cabdff1aSopenharmony_ci return xv_repaint(s); 353cabdff1aSopenharmony_ci default: 354cabdff1aSopenharmony_ci break; 355cabdff1aSopenharmony_ci } 356cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 357cabdff1aSopenharmony_ci} 358cabdff1aSopenharmony_ci 359cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(XVContext, x) 360cabdff1aSopenharmony_cistatic const AVOption options[] = { 361cabdff1aSopenharmony_ci { "display_name", "set display name", OFFSET(display_name), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, 362cabdff1aSopenharmony_ci { "window_id", "set existing window id", OFFSET(window_id), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM }, 363cabdff1aSopenharmony_ci { "window_size", "set window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, 364cabdff1aSopenharmony_ci { "window_title", "set window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, 365cabdff1aSopenharmony_ci { "window_x", "set window x offset", OFFSET(window_x), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, 366cabdff1aSopenharmony_ci { "window_y", "set window y offset", OFFSET(window_y), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, 367cabdff1aSopenharmony_ci { NULL } 368cabdff1aSopenharmony_ci 369cabdff1aSopenharmony_ci}; 370cabdff1aSopenharmony_ci 371cabdff1aSopenharmony_cistatic const AVClass xv_class = { 372cabdff1aSopenharmony_ci .class_name = "xvideo outdev", 373cabdff1aSopenharmony_ci .item_name = av_default_item_name, 374cabdff1aSopenharmony_ci .option = options, 375cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 376cabdff1aSopenharmony_ci .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT, 377cabdff1aSopenharmony_ci}; 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_ciconst AVOutputFormat ff_xv_muxer = { 380cabdff1aSopenharmony_ci .name = "xv", 381cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("XV (XVideo) output device"), 382cabdff1aSopenharmony_ci .priv_data_size = sizeof(XVContext), 383cabdff1aSopenharmony_ci .audio_codec = AV_CODEC_ID_NONE, 384cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME, 385cabdff1aSopenharmony_ci .write_header = xv_write_header, 386cabdff1aSopenharmony_ci .write_packet = xv_write_packet, 387cabdff1aSopenharmony_ci .write_uncoded_frame = xv_write_frame, 388cabdff1aSopenharmony_ci .write_trailer = xv_write_trailer, 389cabdff1aSopenharmony_ci .control_message = xv_control_message, 390cabdff1aSopenharmony_ci .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS, 391cabdff1aSopenharmony_ci .priv_class = &xv_class, 392cabdff1aSopenharmony_ci}; 393