diff --git a/libavdevice/xv.c b/libavdevice/xv.c index 23c876114b..4492df02d3 100644 --- a/libavdevice/xv.c +++ b/libavdevice/xv.c @@ -51,18 +51,43 @@ typedef struct { char *display_name; XvImage* yuv_image; + enum AVPixelFormat image_format; int image_width, image_height; XShmSegmentInfo yuv_shminfo; int xv_port; } XVContext; +typedef struct XVTagFormatMap +{ + int tag; + enum AVPixelFormat format; +} XVTagFormatMap; + +static XVTagFormatMap tag_codec_map[] = { + { MKTAG('I','4','2','0'), AV_PIX_FMT_YUV420P }, + { MKTAG('U','Y','V','Y'), AV_PIX_FMT_UYVY422 }, + { MKTAG('Y','U','Y','2'), AV_PIX_FMT_YUYV422 }, + { 0, AV_PIX_FMT_NONE } +}; + +static int xv_get_tag_from_format(enum AVPixelFormat format) +{ + XVTagFormatMap *m = tag_codec_map; + int i; + for (i = 0; m->tag; m = &tag_codec_map[++i]) { + if (m->format == format) + return m->tag; + } + return 0; +} + static int xv_write_header(AVFormatContext *s) { XVContext *xv = s->priv_data; unsigned int num_adaptors; XvAdaptorInfo *ai; XvImageFormatValues *fv; - int num_formats = 0, j; + int num_formats = 0, j, tag; AVCodecContext *encctx = s->streams[0]->codec; if ( s->nb_streams > 1 @@ -72,6 +97,14 @@ static int xv_write_header(AVFormatContext *s) return AVERROR(EINVAL); } + if (!(tag = xv_get_tag_from_format(encctx->pix_fmt))) { + av_log(s, AV_LOG_ERROR, + "Unsupported pixel format '%s', only yuv420p, uyvy422, yuyv422 are currently supported\n", + av_get_pix_fmt_name(encctx->pix_fmt)); + return AVERROR_PATCHWELCOME; + } + xv->image_format = encctx->pix_fmt; + xv->display = XOpenDisplay(xv->display_name); if (!xv->display) { av_log(s, AV_LOG_ERROR, "Could not open the X11 display '%s'\n", xv->display_name); @@ -100,18 +133,11 @@ static int xv_write_header(AVFormatContext *s) xv->xv_port = ai[0].base_id; XvFreeAdaptorInfo(ai); - if (encctx->pix_fmt != AV_PIX_FMT_YUV420P) { - av_log(s, AV_LOG_ERROR, - "Unsupported pixel format '%s', only yuv420p is currently supported\n", - av_get_pix_fmt_name(encctx->pix_fmt)); - return AVERROR_PATCHWELCOME; - } - fv = XvListImageFormats(xv->display, xv->xv_port, &num_formats); if (!fv) return AVERROR_EXTERNAL; for (j = 0; j < num_formats; j++) { - if (fv[j].id == MKTAG('I','4','2','0')) { + if (fv[j].id == tag) { break; } } @@ -119,15 +145,15 @@ static int xv_write_header(AVFormatContext *s) if (j >= num_formats) { av_log(s, AV_LOG_ERROR, - "Device does not support pixel format yuv420p, aborting\n"); + "Device does not support pixel format %s, aborting\n", + av_get_pix_fmt_name(encctx->pix_fmt)); return AVERROR(EINVAL); } xv->gc = XCreateGC(xv->display, xv->window, 0, 0); xv->image_width = encctx->width; xv->image_height = encctx->height; - xv->yuv_image = XvShmCreateImage(xv->display, xv->xv_port, - MKTAG('I','4','2','0'), 0, + xv->yuv_image = XvShmCreateImage(xv->display, xv->xv_port, tag, 0, xv->image_width, xv->image_height, &xv->yuv_shminfo); xv->yuv_shminfo.shmid = shmget(IPC_PRIVATE, xv->yuv_image->data_size, IPC_CREAT | 0777); @@ -157,7 +183,7 @@ static int xv_write_packet(AVFormatContext *s, AVPacket *pkt) avpicture_fill(&pict, pkt->data, ctx->pix_fmt, ctx->width, ctx->height); av_image_copy(data, img->pitches, (const uint8_t **)pict.data, pict.linesize, - AV_PIX_FMT_YUV420P, img->width, img->height); + xv->image_format, img->width, img->height); XGetWindowAttributes(xv->display, xv->window, &window_attrs); if (XvShmPutImage(xv->display, xv->xv_port, xv->window, xv->gc,