|
|
|
@@ -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, |
|
|
|
|