Initial vdpau osd support.

This commit is contained in:
Johns 2011-12-22 21:25:38 +01:00
parent afd7dfe402
commit 18e9e2f69e
1 changed files with 276 additions and 141 deletions

417
video.c
View File

@ -42,7 +42,7 @@
//#define USE_VAAPI ///< enable vaapi support
//#define USE_VDPAU ///< enable vdpau support
#define noUSE_BITMAP
#define noUSE_BITMAP ///< use vdpau bitmap surface
#define USE_VIDEO_THREAD
@ -2799,11 +2799,11 @@ static void VaapiDisplayHandlerThread(void)
// VA-API OSD
//----------------------------------------------------------------------------
/**
** Clear subpicture image.
**
** @note looked by caller
*/
///
/// Clear subpicture image.
///
/// @note looked by caller
///
static void VaapiOsdClear(void)
{
void *image_buffer;
@ -2829,11 +2829,17 @@ static void VaapiOsdClear(void)
}
}
/**
** Upload ARGB to subpicture image.
**
** @note looked by caller
*/
///
/// Upload ARGB to subpicture image.
///
/// @param x x position of image in osd
/// @param y y position of image in osd
/// @param width width of image
/// @param height height of image
/// @param argb argb image
///
/// @note looked by caller
///
static void VaapiUploadImage(int x, int y, int width, int height,
const uint8_t * argb)
{
@ -2869,11 +2875,14 @@ static void VaapiUploadImage(int x, int y, int width, int height,
}
}
/**
** VA-API initialize OSD.
**
** @note subpicture is unusable, it can be scaled with the video image.
*/
///
/// VA-API initialize OSD.
///
/// @param width osd width
/// @param height osd height
///
/// @note subpicture is unusable, it can be scaled with the video image.
///
static void VaapiOsdInit(int width, int height)
{
VAImageFormat *formats;
@ -2888,7 +2897,6 @@ static void VaapiOsdInit(int width, int height)
Debug(3, "video/vaapi: osd already setup\n");
return;
}
if (!VaDisplay) {
Debug(3, "video/vaapi: va-api not setup\n");
return;
@ -2937,6 +2945,7 @@ static void VaapiOsdInit(int width, int height)
//VaapiUnscaledOsd = 0;
//Info(_("video/vaapi: unscaled osd disabled\n"));
// FIXME: lock
if (vaCreateImage(VaDisplay, &formats[u], width, height,
&VaOsdImage) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't create osd image\n"));
@ -2957,6 +2966,7 @@ static void VaapiOsdInit(int width, int height)
// FIXME: must store format, to convert ARGB to it.
VaapiOsdClear();
// FIXME: unlock
}
#endif
@ -3048,6 +3058,22 @@ static VdpOutputSurface VdpauSurfacesRb[OUTPUT_SURFACES_MAX];
static int VdpauSurfaceIndex; ///< current display surface
static int VdpauSurfaceNotStart; ///< not the first surface
static int VdpauOsdWidth; ///< width of osd surface
static int VdpauOsdHeight; ///< height of osd surface
#ifdef USE_BITMAP
/// bitmap surfaces for osd
static VdpBitmapSurface VdpauOsdBitmapSurface[2] = {
VDP_INVALID_HANDLE, VDP_INVALID_HANDLE
};
#else
/// output surfaces for osd
static VdpOutputSurface VdpauOsdOutputSurface[2] = {
VDP_INVALID_HANDLE, VDP_INVALID_HANDLE
};
#endif
static int VdpauOsdSurfaceIndex; ///< index into double buffered osd
///
/// Function pointer of the VDPAU device.
///
@ -4038,13 +4064,13 @@ static void VdpauSetup(VdpauDecoder * decoder,
// FIXME: reset output ring buffer
}
/**
** Render a ffmpeg frame.
**
** @param decoder VDPAU decoder
** @param video_ctx ffmpeg video codec context
** @param frame frame to display
*/
///
/// Render a ffmpeg frame.
///
/// @param decoder VDPAU decoder
/// @param video_ctx ffmpeg video codec context
/// @param frame frame to display
///
static void VdpauRenderFrame(VdpauDecoder * decoder,
const AVCodecContext * video_ctx, const AVFrame * frame)
{
@ -4180,105 +4206,18 @@ static void VdpauRenderFrame(VdpauDecoder * decoder,
atomic_inc(&decoder->SurfacesFilled);
}
#if 0
///
/// Render osd surface to output surface.
///
/// FIXME: must split render / upload / display
///
static void VdpauMixOsd(void)
{
VdpOutputSurfaceRenderBlendState blend_state;
VdpRect source_rect;
VdpRect output_rect;
VdpStatus status;
static char *image;
void const *data[1];
uint32_t pitches[1];
static int count;
static int surface_index;
int i;
uint32_t start;
uint32_t end;
#ifdef USE_BITMAP
static VdpBitmapSurface bitmap_surface[2];
if (!bitmap_surface[0]) {
for (i = 0; i < 2; ++i) {
status =
VdpauBitmapSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
OsdWidth, OsdHeight, VDP_TRUE, bitmap_surface + i);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create bitmap surface: %s\n"),
VdpauGetErrorString(status));
}
}
}
#else
static VdpOutputSurface output_surface[2];
if (!output_surface[0]) {
for (i = 0; i < 2; ++i) {
status =
VdpauOutputSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
OsdWidth, OsdHeight, output_surface + i);
if (status != VDP_STATUS_OK) {
Fatal(_("video/vdpau: can't create output surface: %s\n"),
VdpauGetErrorString(status));
}
}
}
#endif
if (!image) {
image = calloc(4, OsdWidth * OsdHeight);
}
if (1 || count < 10) {
memset(image, 0x00, 4 * OsdWidth * OsdHeight);
//GfxConvert(image, 0, OsdWidth * 4);
//
// upload changed osd image (99ms for a 1920x1080 !frequently_accessed)
// (5ms - 10ms with frequently_accessed = true)
//
if (0) {
count++;
source_rect.x0 = 0;
source_rect.y0 = (OsdHeight * (count & 7)) / 8;
source_rect.x1 = source_rect.x0 + OsdWidth;
source_rect.y1 = source_rect.y0 + OsdHeight / 8;
data[0] = image + ((OsdHeight * (count & 7)) / 8) * OsdWidth * 4;
} else {
source_rect.x0 = 0;
source_rect.y0 = 0;
source_rect.x1 = source_rect.x0 + OsdWidth;
source_rect.y1 = source_rect.y0 + OsdHeight;
data[0] = image;
}
pitches[0] = OsdWidth * 4;
uint32_t start = GetMsTicks();
#ifdef USE_BITMAP
status =
VdpauBitmapSurfacePutBitsNative(bitmap_surface[surface_index],
data, pitches, &source_rect);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: bitmap surface put bits failed: %s\n"),
VdpauGetErrorString(status));
}
#else
status =
VdpauOutputSurfacePutBitsNative(output_surface[surface_index],
data, pitches, &source_rect);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: output surface put bits failed: %s\n"),
VdpauGetErrorString(status));
}
#endif
uint32_t end = GetMsTicks();
Debug(3, "upload %d ms\n", end - start);
}
//
// blend overlay over output
//
@ -4298,44 +4237,45 @@ static void VdpauMixOsd(void)
source_rect.x0 = 0;
source_rect.y0 = 0;
source_rect.x1 = OsdWidth;
source_rect.y1 = OsdHeight;
source_rect.x1 = VdpauOsdWidth;
source_rect.y1 = VdpauOsdHeight;
output_rect.x0 = 0;
output_rect.y0 = 0;
output_rect.x1 = VideoWindowWidth;
output_rect.y1 = VideoWindowHeight;
uint32_t start = GetMsTicks();
start = GetMsTicks();
VdpauOsdSurfaceIndex = 1;
#ifdef USE_BITMAP
status =
VdpauOutputSurfaceRenderBitmapSurface(VdpauSurfacesRb
[VdpauSurfaceIndex], &output_rect, bitmap_surface[!surface_index],
&source_rect, NULL, &blend_state, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
VdpauOutputSurfaceRenderBitmapSurface(dpauSurfacesRb
[VdpauSurfaceIndex], &output_rect,
VdpauOsdBitmapSurface[!VdpauOsdSurfaceIndex], &source_rect, NULL,
&blend_state, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't render bitmap surface: %s\n"),
VdpauGetErrorString(status));
}
#else
status
status =
VdpauOutputSurfaceRenderOutputSurface(VdpauSurfacesRb
[VdpauSurfaceIndex], &output_rect, output_surface[!surface_index],
&source_rect, NULL, &blend_state, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
[VdpauSurfaceIndex], &output_rect,
VdpauOsdOutputSurface[!VdpauOsdSurfaceIndex], &source_rect, NULL,
&blend_state, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't render output surface: %s\n"),
VdpauGetErrorString(status));
}
#endif
uint32_t end = GetMsTicks();
end = GetMsTicks();
Debug(3, "render %d ms\n", end - start);
//Debug(3, "video:/vdpau: osd render %d ms\n", end - start);
surface_index = !surface_index;
VdpauOsdSurfaceIndex = !VdpauOsdSurfaceIndex;
}
#endif
///
/// Render video surface to output surface.
///
@ -4513,11 +4453,10 @@ static void VdpauDisplayFrame(void)
}
}
#if 0
if (OsdShow) {
VdpauMixOsd();
}
#endif
//
// add osd to surface
//
VdpauMixOsd();
//
// place surface in presentation queue
@ -4706,6 +4645,176 @@ static void VdpauDisplayHandlerThread(void)
#endif
//----------------------------------------------------------------------------
// VDPAU OSD
//----------------------------------------------------------------------------
///
/// Clear subpicture image.
///
/// @note looked by caller
///
static void VdpauOsdClear(void)
{
VdpStatus status;
void *image;
void const *data[1];
uint32_t pitches[1];
VdpRect dst_rect;
// osd image available?
#ifdef USE_BITMAP
if (VdpauOsdBitmapSurface[VdpauOsdSurfaceIndex] == VDP_INVALID_HANDLE) {
return;
}
#else
if (VdpauOsdOutputSurface[VdpauOsdSurfaceIndex] == VDP_INVALID_HANDLE) {
return;
}
#endif
Debug(3, "video/vdpau: clear image\n");
image = calloc(4, VdpauOsdWidth * VdpauOsdHeight);
dst_rect.x0 = 0;
dst_rect.y0 = 0;
dst_rect.x1 = dst_rect.x0 + VdpauOsdWidth;
dst_rect.y1 = dst_rect.y0 + VdpauOsdHeight;
data[0] = image;
pitches[0] = VdpauOsdWidth * 4;
#ifdef USE_BITMAP
status =
VdpauBitmapSurfacePutBitsNative(VdpauOsdBitmapSurface
[VdpauOsdSurfaceIndex], data, pitches, &dst_rect);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: bitmap surface put bits failed: %s\n"),
VdpauGetErrorString(status));
}
#else
status =
VdpauOutputSurfacePutBitsNative(VdpauOsdOutputSurface
[VdpauOsdSurfaceIndex], data, pitches, &dst_rect);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: output surface put bits failed: %s\n"),
VdpauGetErrorString(status));
}
#endif
free(image);
}
///
/// Upload ARGB to subpicture image.
///
/// @param x x position of image in osd
/// @param y y position of image in osd
/// @param width width of image
/// @param height height of image
/// @param argb argb image
///
/// @note looked by caller
///
static void VdpauUploadImage(int x, int y, int width, int height,
const uint8_t * argb)
{
VdpStatus status;
void const *data[1];
uint32_t pitches[1];
VdpRect dst_rect;
// osd image available?
#ifdef USE_BITMAP
if (VdpauOsdBitmapSurface[VdpauOsdSurfaceIndex] == VDP_INVALID_HANDLE) {
return;
}
#else
if (VdpauOsdOutputSurface[VdpauOsdSurfaceIndex] == VDP_INVALID_HANDLE) {
return;
}
#endif
Debug(3, "video/vdpau: upload image\n");
dst_rect.x0 = x;
dst_rect.y0 = y;
dst_rect.x1 = dst_rect.x0 + width;
dst_rect.y1 = dst_rect.y0 + height;
data[0] = argb;
pitches[0] = width * 4;
#ifdef USE_BITMAP
status =
VdpauBitmapSurfacePutBitsNative(VdpauOsdBitmapSurface
[VdpauOsdSurfaceIndex], data, pitches, &dst_rect);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: bitmap surface put bits failed: %s\n"),
VdpauGetErrorString(status));
}
#else
status =
VdpauOutputSurfacePutBitsNative(VdpauOsdOutputSurface
[VdpauOsdSurfaceIndex], data, pitches, &dst_rect);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: output surface put bits failed: %s\n"),
VdpauGetErrorString(status));
}
#endif
}
///
/// VDPAU initialize OSD.
///
/// @param width osd width
/// @param height osd height
///
static void VdpauOsdInit(int width, int height)
{
int i;
VdpStatus status;
if (!VdpauDevice) {
Debug(3, "video/vdpau: vdpau not setup\n");
}
VdpauOsdWidth = width;
VdpauOsdHeight = height;
//
// create bitmap/surface for osd
//
#ifdef USE_BITMAP
if (VdpauOsdBitmapSurface[0] == VDP_INVALID_HANDLE) {
for (i = 0; i < 2; ++i) {
status =
VdpauBitmapSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
width, height, VDP_TRUE, VdpauOsdBitmapSurface + i);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create bitmap surface: %s\n"),
VdpauGetErrorString(status));
}
}
}
#else
if (VdpauOsdOutputSurface[0] == VDP_INVALID_HANDLE) {
for (i = 0; i < 2; ++i) {
status =
VdpauOutputSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
width, height, VdpauOsdOutputSurface + i);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create output surface: %s\n"),
VdpauGetErrorString(status));
}
}
}
#endif
Debug(3, "video/vdpau: osd surfaces created\n");
VdpauOsdClear();
}
#endif
//----------------------------------------------------------------------------
@ -4716,12 +4825,12 @@ static void VdpauDisplayHandlerThread(void)
static int OsdWidth; ///< osd width
static int OsdHeight; ///< osd height
/**
** Clear the OSD.
**
** @todo I use glTexImage2D to clear the texture, are there faster and
** better ways to clear a texture?
*/
///
/// Clear the OSD.
///
/// @todo I use glTexImage2D to clear the texture, are there faster and
/// better ways to clear a texture?
///
void VideoOsdClear(void)
{
VideoThreadLock();
@ -4747,13 +4856,26 @@ void VideoOsdClear(void)
VideoThreadUnlock();
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
VdpauOsdClear();
VideoThreadUnlock();
return;
}
#endif
VideoThreadUnlock();
}
/**
** Draw an OSD ARGB image.
*/
///
/// Draw an OSD ARGB image.
///
/// @param x x position of image in osd
/// @param y y position of image in osd
/// @param width width of image
/// @param height height of image
/// @param argb argb image
///
void VideoOsdDrawARGB(int x, int y, int height, int width,
const uint8_t * argb)
{
@ -4772,6 +4894,13 @@ void VideoOsdDrawARGB(int x, int y, int height, int width,
VideoThreadUnlock();
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
VdpauUploadImage(x, y, height, width, argb);
VideoThreadUnlock();
return;
}
#endif
(void)x;
(void)y;
@ -4832,6 +4961,12 @@ void VideoOsdInit(void)
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
VdpauOsdInit(OsdWidth, OsdHeight);
return;
}
#endif
}
#if 0