Finished rewrite of video code, to support modules.

This commit is contained in:
Johns 2012-01-30 15:58:21 +01:00
parent e613ff1f7e
commit dab31e2367
5 changed files with 251 additions and 219 deletions

View File

@ -1,6 +1,7 @@
User johns User johns
Date: Date:
Finished rewrite of video code, to support output modules.
Add aspect change support to software decoder path. Add aspect change support to software decoder path.
Repair software decoder with vaapi vdpau backend. Repair software decoder with vaapi vdpau backend.
Add workaround for Intel VA-API MPEG GPU hung. Add workaround for Intel VA-API MPEG GPU hung.

3
Todo
View File

@ -24,6 +24,7 @@ missing:
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?) zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)? ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop and restart X11 suspend output / energie saver: stop and restart X11
suspend plugin didn't restore full-screen (is this wanted?)
Option deinterlace off / deinterlace force! Option deinterlace off / deinterlace force!
Make output drivers better modular (under construction). Make output drivers better modular (under construction).
@ -74,6 +75,8 @@ libva-xvba-driver:
x11: x11:
disable screensaver disable screensaver
skip multiple configure-notify, handle only the last one.
support embedded mode
audio: audio:
write TS -> PES parser, which feeds audio before the next start packet write TS -> PES parser, which feeds audio before the next start packet

View File

@ -740,6 +740,10 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode)
return true; return true;
} }
/**
** Gets the current System Time Counter, which can be used to
** synchronize audio, video and subtitles.
*/
int64_t cSoftHdDevice::GetSTC(void) int64_t cSoftHdDevice::GetSTC(void)
{ {
//dsyslog("[softhddev]%s:\n", __FUNCTION__); //dsyslog("[softhddev]%s:\n", __FUNCTION__);

449
video.c
View File

@ -201,9 +201,20 @@ typedef struct _video_module_
{ {
const char *Name; ///< video output module name const char *Name; ///< video output module name
char Enabled; ///< flag output module enabled
/// allocate new video hw decoder /// allocate new video hw decoder
VideoHwDecoder *(*const NewHwDecoder)(void); VideoHwDecoder *(*const NewHwDecoder)(void);
void (*const DelHwDecoder) (VideoHwDecoder *); void (*const DelHwDecoder) (VideoHwDecoder *);
unsigned (*const GetSurface) (VideoHwDecoder *);
void (*const ReleaseSurface) (VideoHwDecoder *, unsigned);
enum PixelFormat (*const get_format) (VideoHwDecoder *, AVCodecContext *,
const enum PixelFormat *);
void (*const RenderFrame) (VideoHwDecoder *, const AVCodecContext *,
const AVFrame *);
uint8_t *(*const GrabOutput)(int *, int *, int *);
void (*const SetVideoMode) (void);
void (*const ResetAutoCrop) (void);
void (*const Thread) (void); ///< module display handler thread void (*const Thread) (void); ///< module display handler thread
@ -213,7 +224,7 @@ typedef struct _video_module_
void (*const OsdInit) (int, int); ///< initialize OSD void (*const OsdInit) (int, int); ///< initialize OSD
void (*const OsdExit) (void); ///< cleanup OSD void (*const OsdExit) (void); ///< cleanup OSD
void (*const Init) (const char *); ///< initialize video output module int (*const Init) (const char *); ///< initialize video output module
void (*const Exit) (void); ///< cleanup video output module void (*const Exit) (void); ///< cleanup video output module
} VideoModule; } VideoModule;
@ -327,6 +338,9 @@ static int64_t VideoDeltaPTS; ///< FIXME: fix pts
static void VideoThreadLock(void); ///< lock video thread static void VideoThreadLock(void); ///< lock video thread
static void VideoThreadUnlock(void); ///< unlock video thread static void VideoThreadUnlock(void); ///< unlock video thread
/// update video stream PTS
static void VideoSetPts(int64_t *, int, const AVFrame *);
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// GLX // GLX
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -1032,7 +1046,6 @@ static void AutoCropDetect(AutoCropCtx * autocrop, int width, int height,
#ifdef USE_VAAPI #ifdef USE_VAAPI
static int VideoVaapiEnabled = 1; ///< use VA-API decoder
static int VaapiBuggyVdpau; ///< fix libva-driver-vdpau bugs static int VaapiBuggyVdpau; ///< fix libva-driver-vdpau bugs
static int VaapiBuggyIntel; ///< fix libva-driver-intel bugs static int VaapiBuggyIntel; ///< fix libva-driver-intel bugs
@ -1631,7 +1644,9 @@ static void VaapiDelDecoder(VaapiDecoder * decoder)
/// ///
/// @param display_name x11/xcb display name /// @param display_name x11/xcb display name
/// ///
static void VaapiInit(const char *display_name) /// @returns true if VA-API could be initialized, false otherwise.
///
static int VaapiInit(const char *display_name)
{ {
int major; int major;
int minor; int minor;
@ -1652,9 +1667,7 @@ static void VaapiInit(const char *display_name)
if (!VaDisplay) { if (!VaDisplay) {
Error(_("video/vaapi: Can't connect VA-API to X11 server on '%s'"), Error(_("video/vaapi: Can't connect VA-API to X11 server on '%s'"),
display_name); display_name);
// FIXME: no fatal for plugin return 0;
VideoVaapiEnabled = 0;
return;
} }
if (vaInitialize(VaDisplay, &major, &minor) != VA_STATUS_SUCCESS) { if (vaInitialize(VaDisplay, &major, &minor) != VA_STATUS_SUCCESS) {
@ -1662,8 +1675,7 @@ static void VaapiInit(const char *display_name)
display_name); display_name);
vaTerminate(VaDisplay); vaTerminate(VaDisplay);
VaDisplay = NULL; VaDisplay = NULL;
VideoVaapiEnabled = 0; return 0;
return;
} }
s = vaQueryVendorString(VaDisplay); s = vaQueryVendorString(VaDisplay);
Info(_("video/vaapi: libva %d.%d (%s) initialized\n"), major, minor, s); Info(_("video/vaapi: libva %d.%d (%s) initialized\n"), major, minor, s);
@ -1698,6 +1710,7 @@ static void VaapiInit(const char *display_name)
// //
attr.type = VAConfigAttribRTFormat attr.flags = VA_DISPLAY_ATTRIB_GETTABLE; attr.type = VAConfigAttribRTFormat attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
#endif #endif
return 1;
} }
/// ///
@ -3687,6 +3700,8 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
static void VaapiSyncRenderFrame(VaapiDecoder * decoder, static void VaapiSyncRenderFrame(VaapiDecoder * decoder,
const AVCodecContext * video_ctx, const AVFrame * frame) const AVCodecContext * video_ctx, const AVFrame * frame)
{ {
VideoSetPts(&decoder->PTS, decoder->Interlaced, frame);
if (!atomic_read(&decoder->SurfacesFilled)) { if (!atomic_read(&decoder->SurfacesFilled)) {
Debug(3, "video: new stream frame %d\n", GetMsTicks() - VideoSwitch); Debug(3, "video: new stream frame %d\n", GetMsTicks() - VideoSwitch);
} }
@ -3746,7 +3761,7 @@ static void VaapiSyncRenderFrame(VaapiDecoder * decoder,
static int64_t VaapiGetClock(const VaapiDecoder * decoder) static int64_t VaapiGetClock(const VaapiDecoder * decoder)
{ {
// pts is the timestamp of the latest decoded frame // pts is the timestamp of the latest decoded frame
if ((uint64_t) decoder->PTS == AV_NOPTS_VALUE) { if (!decoder || (uint64_t) decoder->PTS == AV_NOPTS_VALUE) {
return AV_NOPTS_VALUE; return AV_NOPTS_VALUE;
} }
// subtract buffered decoded frames // subtract buffered decoded frames
@ -3759,6 +3774,18 @@ static int64_t VaapiGetClock(const VaapiDecoder * decoder)
1); 1);
} }
///
/// Set VA-API video mode.
///
static void VaapiSetVideoMode(void)
{
int i;
for (i = 0; i < VaapiDecoderN; ++i) {
VaapiUpdateOutput(VaapiDecoders[i]);
}
}
#ifdef USE_VIDEO_THREAD #ifdef USE_VIDEO_THREAD
/// ///
@ -3917,6 +3944,7 @@ static void VaapiOsdInit(int width, int height)
unsigned format_n; unsigned format_n;
unsigned u; unsigned u;
unsigned v; unsigned v;
int i;
static uint32_t wanted_formats[] = static uint32_t wanted_formats[] =
{ VA_FOURCC('B', 'G', 'R', 'A'), VA_FOURCC_RGBA }; { VA_FOURCC('B', 'G', 'R', 'A'), VA_FOURCC_RGBA };
@ -3990,6 +4018,14 @@ static void VaapiOsdInit(int width, int height)
return; return;
} }
// FIXME: must store format, to convert ARGB to it. // FIXME: must store format, to convert ARGB to it.
// restore osd association
for (i = 0; i < VaapiDecoderN; ++i) {
if (VaapiDecoders[i]->InputWidth && VaapiDecoders[i]->InputHeight) {
VaapiAssociate(VaapiDecoders[i], VaapiDecoders[i]->InputWidth,
VaapiDecoders[i]->InputHeight);
}
}
} }
/// ///
@ -4025,8 +4061,19 @@ static void VaapiOsdExit(void)
/// ///
static const VideoModule VaapiModule = { static const VideoModule VaapiModule = {
.Name = "va-api", .Name = "va-api",
.Enabled = 1,
.NewHwDecoder = (VideoHwDecoder * (*const)(void))VaapiNewDecoder, .NewHwDecoder = (VideoHwDecoder * (*const)(void))VaapiNewDecoder,
.DelHwDecoder = (void (*const) (VideoHwDecoder *))VaapiDelDecoder, .DelHwDecoder = (void (*const) (VideoHwDecoder *))VaapiDelDecoder,
.GetSurface = (unsigned (*const) (VideoHwDecoder *))VaapiGetSurface,
.ReleaseSurface =
(void (*const) (VideoHwDecoder *, unsigned))VaapiReleaseSurface,
.get_format = (enum PixelFormat(*const) (VideoHwDecoder *,
AVCodecContext *, const enum PixelFormat *))Vaapi_get_format,
.RenderFrame = (void (*const) (VideoHwDecoder *,
const AVCodecContext *, const AVFrame *))VaapiSyncRenderFrame,
.GrabOutput = NULL,
.SetVideoMode = VaapiSetVideoMode,
.ResetAutoCrop = VaapiResetAutoCrop,
.Thread = VaapiDisplayHandlerThread, .Thread = VaapiDisplayHandlerThread,
.OsdClear = VaapiOsdClear, .OsdClear = VaapiOsdClear,
.OsdDrawARGB = VaapiOsdDrawARGB, .OsdDrawARGB = VaapiOsdDrawARGB,
@ -4113,7 +4160,6 @@ typedef struct _vdpau_decoder_
int FramesDisplayed; ///< number of frames displayed int FramesDisplayed; ///< number of frames displayed
} VdpauDecoder; } VdpauDecoder;
static int VideoVdpauEnabled = 1; ///< use VDPAU decoder
static volatile char VdpauPreemption; ///< flag preemption happened. static volatile char VdpauPreemption; ///< flag preemption happened.
static VdpauDecoder *VdpauDecoders[1]; ///< open decoder streams static VdpauDecoder *VdpauDecoders[1]; ///< open decoder streams
@ -4759,6 +4805,7 @@ static inline void VdpauGetProc(const VdpFuncId id, void *addr,
if (status != VDP_STATUS_OK) { if (status != VDP_STATUS_OK) {
Fatal(_("video/vdpau: Can't get function address of '%s': %s\n"), name, Fatal(_("video/vdpau: Can't get function address of '%s': %s\n"), name,
VdpauGetErrorString(status)); VdpauGetErrorString(status));
// FIXME: rewrite none fatal
} }
} }
@ -4873,7 +4920,9 @@ static void VdpauPreemptionCallback(VdpDevice device, __attribute__ ((unused))
/// ///
/// @param display_name x11/xcb display name /// @param display_name x11/xcb display name
/// ///
static void VdpauInit(const char *display_name) /// @returns true if VDPAU could be initialized, false otherwise.
///
static int VdpauInit(const char *display_name)
{ {
VdpStatus status; VdpStatus status;
VdpGetApiVersion *get_api_version; VdpGetApiVersion *get_api_version;
@ -4891,8 +4940,7 @@ static void VdpauInit(const char *display_name)
if (status != VDP_STATUS_OK) { if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: Can't create vdp device on display '%s'\n"), Error(_("video/vdpau: Can't create vdp device on display '%s'\n"),
display_name); display_name);
VideoVdpauEnabled = 0; return 0;
return;
} }
// get error function first, for better error messages // get error function first, for better error messages
status = status =
@ -4901,9 +4949,8 @@ static void VdpauInit(const char *display_name)
if (status != VDP_STATUS_OK) { if (status != VDP_STATUS_OK) {
Error(_ Error(_
("video/vdpau: Can't get function address of 'GetErrorString'\n")); ("video/vdpau: Can't get function address of 'GetErrorString'\n"));
VideoVdpauEnabled = 0;
// FIXME: destroy_x11 VdpauDeviceDestroy // FIXME: destroy_x11 VdpauDeviceDestroy
return; return 0;
} }
// get destroy device next, for cleaning up // get destroy device next, for cleaning up
VdpauGetProc(VDP_FUNC_ID_DEVICE_DESTROY, &VdpauDeviceDestroy, VdpauGetProc(VDP_FUNC_ID_DEVICE_DESTROY, &VdpauDeviceDestroy,
@ -5269,6 +5316,8 @@ static void VdpauInit(const char *display_name)
// Create presentation queue, only one queue pro window // Create presentation queue, only one queue pro window
// //
VdpauInitOutputQueue(); VdpauInitOutputQueue();
return 1;
} }
/// ///
@ -5506,7 +5555,7 @@ static enum PixelFormat Vdpau_get_format(VdpauDecoder * decoder,
p = VaapiFindProfile(profiles, profile_n, p = VaapiFindProfile(profiles, profile_n,
VAProfileMPEG4AdvancedSimple); VAProfileMPEG4AdvancedSimple);
*/ */
break; goto slow_path;
case CODEC_ID_H264: case CODEC_ID_H264:
// FIXME: can calculate level 4.1 limits // FIXME: can calculate level 4.1 limits
max_refs = 16; max_refs = 16;
@ -5542,12 +5591,12 @@ static enum PixelFormat Vdpau_get_format(VdpauDecoder * decoder,
/* /*
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Main); p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Main);
*/ */
break; goto slow_path;
case CODEC_ID_VC1: case CODEC_ID_VC1:
/* /*
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Advanced); p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Advanced);
*/ */
break; goto slow_path;
default: default:
goto slow_path; goto slow_path;
} }
@ -5664,7 +5713,9 @@ static void VdpauGrabVideoSurface(VdpauDecoder * decoder)
/// ///
/// Grab output surface. /// Grab output surface.
/// ///
/// @param decoder VDPAU hw decoder /// @param ret_size[out] size of allocated surface copy
/// @param ret_width[in,out] width of output
/// @param ret_height[in,out] height of output
/// ///
static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width, static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width,
int *ret_height) int *ret_height)
@ -5715,6 +5766,7 @@ static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width,
case VDP_RGBA_FORMAT_R10G10B10A2: case VDP_RGBA_FORMAT_R10G10B10A2:
case VDP_RGBA_FORMAT_B10G10R10A2: case VDP_RGBA_FORMAT_B10G10R10A2:
case VDP_RGBA_FORMAT_A8: case VDP_RGBA_FORMAT_A8:
default:
Error(_("video/vdpau: unsupported rgba format %d\n"), rgba_format); Error(_("video/vdpau: unsupported rgba format %d\n"), rgba_format);
return NULL; return NULL;
} }
@ -6636,6 +6688,8 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
static void VdpauSyncRenderFrame(VdpauDecoder * decoder, static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
const AVCodecContext * video_ctx, const AVFrame * frame) const AVCodecContext * video_ctx, const AVFrame * frame)
{ {
VideoSetPts(&decoder->PTS, decoder->Interlaced, frame);
if (VdpauPreemption) { // display preempted if (VdpauPreemption) { // display preempted
return; return;
} }
@ -6701,7 +6755,7 @@ static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
static int64_t VdpauGetClock(const VdpauDecoder * decoder) static int64_t VdpauGetClock(const VdpauDecoder * decoder)
{ {
// pts is the timestamp of the latest decoded frame // pts is the timestamp of the latest decoded frame
if ((uint64_t) decoder->PTS == AV_NOPTS_VALUE) { if (!decoder || (uint64_t) decoder->PTS == AV_NOPTS_VALUE) {
return AV_NOPTS_VALUE; return AV_NOPTS_VALUE;
} }
// subtract buffered decoded frames // subtract buffered decoded frames
@ -6762,6 +6816,21 @@ static int VdpauPreemptionRecover(void)
return 1; return 1;
} }
///
/// Set VA-API video mode.
///
static void VdpauSetVideoMode(void)
{
int i;
VdpauExitOutputQueue();
VdpauInitOutputQueue();
for (i = 0; i < VdpauDecoderN; ++i) {
VdpauUpdateOutput(VdpauDecoders[i]);
}
}
#ifdef USE_VIDEO_THREAD #ifdef USE_VIDEO_THREAD
/// ///
@ -7077,8 +7146,19 @@ static void VdpauOsdExit(void)
/// ///
static const VideoModule VdpauModule = { static const VideoModule VdpauModule = {
.Name = "vdpau", .Name = "vdpau",
.Enabled = 1,
.NewHwDecoder = (VideoHwDecoder * (*const)(void))VdpauNewDecoder, .NewHwDecoder = (VideoHwDecoder * (*const)(void))VdpauNewDecoder,
.DelHwDecoder = (void (*const) (VideoHwDecoder *))VdpauDelDecoder, .DelHwDecoder = (void (*const) (VideoHwDecoder *))VdpauDelDecoder,
.GetSurface = (unsigned (*const) (VideoHwDecoder *))VdpauGetSurface,
.ReleaseSurface =
(void (*const) (VideoHwDecoder *, unsigned))VdpauReleaseSurface,
.get_format = (enum PixelFormat(*const) (VideoHwDecoder *,
AVCodecContext *, const enum PixelFormat *))Vdpau_get_format,
.RenderFrame = (void (*const) (VideoHwDecoder *,
const AVCodecContext *, const AVFrame *))VdpauSyncRenderFrame,
.GrabOutput = VdpauGrabOutputSurface,
.SetVideoMode = VdpauSetVideoMode,
.ResetAutoCrop = VdpauResetAutoCrop,
.Thread = VdpauDisplayHandlerThread, .Thread = VdpauDisplayHandlerThread,
.OsdClear = VdpauOsdClear, .OsdClear = VdpauOsdClear,
.OsdDrawARGB = VdpauOsdDrawARGB, .OsdDrawARGB = VdpauOsdDrawARGB,
@ -7378,17 +7458,10 @@ static void VideoDisplayFrame(void)
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
} }
#endif #endif
#ifdef USE_VAAPI
if (VideoVaapiEnabled) { if (VideoUsedModule) {
VaapiDisplayFrame(); VideoUsedModule->DisplayFrame();
return;
} }
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
return;
}
#endif
} }
#endif #endif
@ -7625,6 +7698,21 @@ void VideoDisplayWakeup(void)
// Video API // Video API
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
//----------------------------------------------------------------------------
///
/// Table of all audio modules.
///
static const VideoModule *VideoModules[] = {
#ifdef USE_VDPAU
&VdpauModule,
#endif
#ifdef USE_VAAPI
&VaapiModule,
#endif
//&NoopModule
};
/// ///
/// Video hardware decoder /// Video hardware decoder
/// ///
@ -7671,19 +7759,13 @@ void VideoDelHwDecoder(VideoHwDecoder * decoder)
/// ///
/// @param decoder video hardware decoder /// @param decoder video hardware decoder
/// ///
/// @returns the oldest free surface or invalid surface
///
unsigned VideoGetSurface(VideoHwDecoder * decoder) unsigned VideoGetSurface(VideoHwDecoder * decoder)
{ {
#ifdef USE_VAAPI if (VideoUsedModule) {
if (VideoVaapiEnabled) { return VideoUsedModule->GetSurface(decoder);
return VaapiGetSurface(&decoder->Vaapi);
} }
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
return VdpauGetSurface(&decoder->Vdpau);
}
#endif
(void)decoder;
return -1; return -1;
} }
@ -7699,19 +7781,9 @@ void VideoReleaseSurface(VideoHwDecoder * decoder, unsigned surface)
if (!XlibDisplay) { // no init or failed if (!XlibDisplay) { // no init or failed
return; return;
} }
#ifdef USE_VAAPI if (VideoUsedModule) {
if (VideoVaapiEnabled) { VideoUsedModule->ReleaseSurface(decoder, surface);
VaapiReleaseSurface(&decoder->Vaapi, surface);
return;
} }
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
return VdpauReleaseSurface(&decoder->Vdpau, surface);
}
#endif
(void)decoder;
(void)surface;
} }
/// ///
@ -7724,19 +7796,9 @@ void VideoReleaseSurface(VideoHwDecoder * decoder, unsigned surface)
enum PixelFormat Video_get_format(VideoHwDecoder * decoder, enum PixelFormat Video_get_format(VideoHwDecoder * decoder,
AVCodecContext * video_ctx, const enum PixelFormat *fmt) AVCodecContext * video_ctx, const enum PixelFormat *fmt)
{ {
#ifdef USE_VAAPI if (VideoUsedModule) {
if (VideoVaapiEnabled) { return VideoUsedModule->get_format(decoder, video_ctx, fmt);
return Vaapi_get_format(&decoder->Vaapi, video_ctx, fmt);
} }
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
return Vdpau_get_format(&decoder->Vdpau, video_ctx, fmt);
}
#endif
(void)decoder;
(void)video_ctx;
(void)fmt;
return fmt[0]; return fmt[0];
} }
@ -7797,29 +7859,15 @@ static void VideoSetPts(int64_t * pts_p, int interlaced, const AVFrame * frame)
/// @param video_ctx ffmpeg video codec context /// @param video_ctx ffmpeg video codec context
/// @param frame frame to display /// @param frame frame to display
/// ///
void VideoRenderFrame(VideoHwDecoder * decoder, AVCodecContext * video_ctx, void VideoRenderFrame(VideoHwDecoder * decoder,
AVFrame * frame) const AVCodecContext * video_ctx, const AVFrame * frame)
{ {
if (frame->repeat_pict) { if (frame->repeat_pict) {
Warning("video: repeated pict found, but not handled\n"); Warning(_("video: repeated pict found, but not handled\n"));
} }
#ifdef USE_VAAPI if (VideoUsedModule) {
if (VideoVaapiEnabled) { VideoUsedModule->RenderFrame(decoder, video_ctx, frame);
VideoSetPts(&decoder->Vaapi.PTS, decoder->Vaapi.Interlaced, frame);
VaapiSyncRenderFrame(&decoder->Vaapi, video_ctx, frame);
return;
} }
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
VideoSetPts(&decoder->Vdpau.PTS, decoder->Vdpau.Interlaced, frame);
VdpauSyncRenderFrame(&decoder->Vdpau, video_ctx, frame);
return;
}
#endif
(void)decoder;
(void)video_ctx;
(void)frame;
} }
/// ///
@ -7830,7 +7878,7 @@ void VideoRenderFrame(VideoHwDecoder * decoder, AVCodecContext * video_ctx,
struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder * decoder) struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder * decoder)
{ {
#ifdef USE_VAAPI #ifdef USE_VAAPI
if (VideoVaapiEnabled) { if (VideoUsedModule == &VaapiModule) {
return decoder->Vaapi.VaapiContext; return decoder->Vaapi.VaapiContext;
} }
#endif #endif
@ -7849,7 +7897,7 @@ struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder * decoder)
void VideoDrawRenderState(VideoHwDecoder * hw_decoder, void VideoDrawRenderState(VideoHwDecoder * hw_decoder,
struct vdpau_render_state *vrs) struct vdpau_render_state *vrs)
{ {
if (VideoVdpauEnabled) { if (VideoUsedModule == &VdpauModule) {
VdpStatus status; VdpStatus status;
uint32_t start; uint32_t start;
uint32_t end; uint32_t end;
@ -7900,6 +7948,8 @@ void VideoDrawRenderState(VideoHwDecoder * hw_decoder,
/// ///
/// Video render. /// Video render.
/// ///
/// @FIXME: old, not used and not uptodate code path
///
void VideoDisplayHandler(void) void VideoDisplayHandler(void)
{ {
uint32_t now; uint32_t now;
@ -7919,17 +7969,6 @@ void VideoDisplayHandler(void)
VaapiBlackSurface(VaapiDecoders[0]); VaapiBlackSurface(VaapiDecoders[0]);
return; return;
#ifdef USE_VAAPI
if (VideoVaapiEnabled) {
VaapiDisplayFrame();
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
return;
}
#endif
VideoDisplayFrame(); VideoDisplayFrame();
} }
@ -7944,14 +7983,14 @@ void VideoDisplayHandler(void)
/// ///
int64_t VideoGetClock(void) int64_t VideoGetClock(void)
{ {
#ifdef USE_VAAPI #ifdef USE_VDPAU
if (VideoVaapiEnabled && VaapiDecoders[0]) { if (VideoUsedModule == &VdpauModule) {
return VaapiGetClock(VaapiDecoders[0]); return VdpauGetClock(VdpauDecoders[0]);
} }
#endif #endif
#ifdef USE_VDPAU #ifdef USE_VAAPI
if (VideoVdpauEnabled && VdpauDecoders[0]) { if (VideoUsedModule == &VaapiModule) {
return VdpauGetClock(VdpauDecoders[0]); return VaapiGetClock(VaapiDecoders[0]);
} }
#endif #endif
return 0L; return 0L;
@ -7960,13 +7999,16 @@ int64_t VideoGetClock(void)
/// ///
/// Grab full screen image. /// Grab full screen image.
/// ///
/// @param size[out] size of allocated image
/// @param width[in,out] width of image
/// @param height[in,out] height of image
///
uint8_t *VideoGrab(int *size, int *width, int *height, int write_header) uint8_t *VideoGrab(int *size, int *width, int *height, int write_header)
{ {
Debug(3, "video: grab\n"); Debug(3, "video: grab\n");
#ifdef USE_GRAB #ifdef USE_GRAB
#ifdef USE_VDPAU if (VideoUsedModule && VideoUsedModule->GrabOutput) {
if (VideoVdpauEnabled) {
uint8_t *data; uint8_t *data;
uint8_t *rgb; uint8_t *rgb;
char buf[64]; char buf[64];
@ -7983,79 +8025,80 @@ uint8_t *VideoGrab(int *size, int *width, int *height, int write_header)
scale_width = *width; scale_width = *width;
scale_height = *height; scale_height = *height;
data = VdpauGrabOutputSurface(size, width, height); data = VideoUsedModule->GrabOutput(size, width, height);
#if 1
if (scale_width <= 0) { if (scale_width <= 0) {
scale_width = *width; scale_width = *width;
} }
if (scale_height <= 0) { if (scale_height <= 0) {
scale_height = *height; scale_height = *height;
} }
n = 0; // hardware didn't scale for us, use simple software scaler
if (write_header) { if (scale_width != *width && scale_height != *height) {
n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", scale_width, n = 0;
scale_height); if (write_header) {
} n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n",
rgb = malloc(scale_width * scale_height * 3 + n); scale_width, scale_height);
if (!rgb) { }
Error(_("video: out of memory\n")); rgb = malloc(scale_width * scale_height * 3 + n);
free(data); if (!rgb) {
return NULL; Error(_("video: out of memory\n"));
} free(data);
*size = scale_width * scale_height * 3 + n; return NULL;
memcpy(rgb, buf, n); // header }
*size = scale_width * scale_height * 3 + n;
memcpy(rgb, buf, n); // header
scale_x = (double)*width / scale_width; scale_x = (double)*width / scale_width;
scale_y = (double)*height / scale_height; scale_y = (double)*height / scale_height;
src_y = 0.0; src_y = 0.0;
for (y = 0; y < scale_height; y++) { for (y = 0; y < scale_height; y++) {
int o; int o;
src_x = 0.0; src_x = 0.0;
o = (int)src_y **width; o = (int)src_y **width;
for (x = 0; x < scale_width; x++) { for (x = 0; x < scale_width; x++) {
i = 4 * (o + (int)src_x); i = 4 * (o + (int)src_x);
rgb[n + (x + y * scale_width) * 3 + 0] = data[i + 2]; rgb[n + (x + y * scale_width) * 3 + 0] = data[i + 2];
rgb[n + (x + y * scale_width) * 3 + 1] = data[i + 1]; rgb[n + (x + y * scale_width) * 3 + 1] = data[i + 1];
rgb[n + (x + y * scale_width) * 3 + 2] = data[i + 0]; rgb[n + (x + y * scale_width) * 3 + 2] = data[i + 0];
src_x += scale_x; src_x += scale_x;
}
src_y += scale_y;
} }
src_y += scale_y; *width = scale_width;
*height = scale_height;
// grabed image of correct size convert BGRA -> RGB
} else {
n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", *width,
*height);
rgb = malloc(*width * *height * 3 + n);
if (!rgb) {
Error(_("video: out of memory\n"));
free(data);
return NULL;
}
memcpy(rgb, buf, n); // header
for (i = 0; i < *size / 4; ++i) { // convert bgra -> rgb
rgb[n + i * 3 + 0] = data[i * 4 + 2];
rgb[n + i * 3 + 1] = data[i * 4 + 1];
rgb[n + i * 3 + 2] = data[i * 4 + 0];
}
*size = *width * *height * 3 + n;
} }
*width = scale_width;
*height = scale_height;
free(data); free(data);
#else
n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", *width, *height);
rgb = malloc(*width * *height * 3 + n);
if (!rgb) {
Error(_("video: out of memory\n"));
free(data);
return NULL;
}
memcpy(rgb, buf, n); // header
for (i = 0; i < *size / 4; ++i) { // convert bgra -> rgb
rgb[n + i * 3 + 0] = data[i * 4 + 2];
rgb[n + i * 3 + 1] = data[i * 4 + 1];
rgb[n + i * 3 + 2] = data[i * 4 + 0];
}
free(data);
*size = *width * *height * 3 + n;
#endif
return rgb; return rgb;
} }
#endif
#endif #endif
(void)size; (void)size;
(void)width; (void)width;
@ -8216,8 +8259,14 @@ void VideoSetOutputPosition(int x, int y, int width, int height)
y = (y * VideoWindowHeight) / OsdHeight; y = (y * VideoWindowHeight) / OsdHeight;
width = (width * VideoWindowWidth) / OsdWidth; width = (width * VideoWindowWidth) / OsdWidth;
height = (height * VideoWindowHeight) / OsdHeight; height = (height * VideoWindowHeight) / OsdHeight;
if (VideoThread) {
VideoThreadLock();
}
if (VideoUsedModule) {
// FIXME: what stream?
}
#ifdef USE_VDPAU #ifdef USE_VDPAU
if (VideoVdpauEnabled) { if (VideoUsedModule == &VdpauModule) {
VdpauSetOutputPosition(VdpauDecoders[0], x, y, width, height); VdpauSetOutputPosition(VdpauDecoders[0], x, y, width, height);
} }
#endif #endif
@ -8225,6 +8274,9 @@ void VideoSetOutputPosition(int x, int y, int width, int height)
// FIXME: not supported by vaapi without unscaled OSD, // FIXME: not supported by vaapi without unscaled OSD,
// FIXME: if used to position video inside osd // FIXME: if used to position video inside osd
#endif #endif
if (VideoThread) {
VideoThreadUnlock();
}
} }
/// ///
@ -8248,40 +8300,21 @@ void VideoSetVideoMode( __attribute__ ((unused))
return; // same size nothing todo return; // same size nothing todo
} }
if (!VideoThread) { // thread not yet running VideoOsdExit();
return; // FIXME: must tell VDR that the OsdSize has been changed!
}
//VideoThreadLock(); // FIXME: vaapi can crash
if (VideoThread) {
VideoThreadLock();
}
VideoWindowWidth = width; VideoWindowWidth = width;
VideoWindowHeight = height; VideoWindowHeight = height;
#ifdef USE_VAAPI if (VideoUsedModule) {
if (VideoVaapiEnabled && VaapiDecoders[0]) { VideoUsedModule->SetVideoMode();
VideoOsdExit();
VideoOsdInit();
if (VaapiDecoders[0]->InputWidth && VaapiDecoders[0]->InputHeight) {
VaapiAssociate(VaapiDecoders[0], VaapiDecoders[0]->InputWidth,
VaapiDecoders[0]->InputHeight);
}
VaapiUpdateOutput(VaapiDecoders[0]);
//VideoThreadUnlock();
return;
} }
#endif if (VideoThread) {
#ifdef USE_VDPAU VideoThreadUnlock();
if (VideoVdpauEnabled && VdpauDecoders[0]) {
VdpauExitOutputQueue();
VideoOsdExit();
VideoOsdInit();
VdpauInitOutputQueue();
VdpauUpdateOutput(VdpauDecoders[0]);
//VideoThreadUnlock();
return;
} }
#endif VideoOsdInit();
//VideoThreadUnlock();
} }
/// ///
@ -8406,19 +8439,20 @@ void VideoSetAutoCrop(int interval, int delay, int tolerance)
AutoCropInterval = interval; AutoCropInterval = interval;
AutoCropDelay = delay; AutoCropDelay = delay;
AutoCropTolerance = tolerance; AutoCropTolerance = tolerance;
#ifdef USE_VDPAU
if (VideoVdpauEnabled) { if (VideoThread) {
VdpauResetAutoCrop(); VideoThreadLock();
} }
#endif if (VideoUsedModule) {
#ifdef USE_VAAPI VideoUsedModule->ResetAutoCrop();
if (VideoVaapiEnabled) { }
VaapiResetAutoCrop(); if (VideoThread) {
VideoThreadUnlock();
} }
#endif
#else #else
(void)interval; (void)interval;
(void)delay; (void)delay;
(void)tolerance;
#endif #endif
} }
@ -8518,27 +8552,16 @@ void VideoInit(const char *display_name)
// //
// prepare hardware decoder VA-API/VDPAU // prepare hardware decoder VA-API/VDPAU
// FIXME: make the used output modules configurable
// //
#ifdef USE_VDPAU for (i = 0; i < (int)(sizeof(VideoModules) / sizeof(*VideoModules)); ++i) {
if (VideoVdpauEnabled) { if (VideoModules[i]->Enabled) {
VdpauInit(display_name); if (VideoModules[i]->Init(display_name)) {
if (VideoVdpauEnabled) { VideoUsedModule = VideoModules[i];
VideoUsedModule = &VdpauModule; break;
#ifdef USE_VAAPI }
// disable va-api, if vdpau succeeded
VideoVaapiEnabled = 0;
#endif
} }
} }
#endif
#ifdef USE_VAAPI
if (VideoVaapiEnabled) {
VaapiInit(display_name);
if (VideoVaapiEnabled) {
VideoUsedModule = &VaapiModule;
}
}
#endif
// FIXME: make it configurable from gui // FIXME: make it configurable from gui
VideoHardwareDecoder = -1; VideoHardwareDecoder = -1;

13
video.h
View File

@ -47,16 +47,17 @@ extern unsigned VideoGetSurface(VideoHwDecoder *);
extern void VideoReleaseSurface(VideoHwDecoder *, unsigned); extern void VideoReleaseSurface(VideoHwDecoder *, unsigned);
#ifdef LIBAVCODEC_VERSION #ifdef LIBAVCODEC_VERSION
/// Render a ffmpeg frame.
extern void VideoRenderFrame(VideoHwDecoder *, AVCodecContext *, AVFrame *);
/// Get ffmpeg vaapi context.
extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *);
/// Callback to negotiate the PixelFormat. /// Callback to negotiate the PixelFormat.
extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *, extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
const enum PixelFormat *); const enum PixelFormat *);
/// Render a ffmpeg frame.
extern void VideoRenderFrame(VideoHwDecoder *, const AVCodecContext *,
const AVFrame *);
/// Get ffmpeg vaapi context.
extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *);
#ifdef AVCODEC_VDPAU_H #ifdef AVCODEC_VDPAU_H
/// Draw vdpau render state. /// Draw vdpau render state.
extern void VideoDrawRenderState(VideoHwDecoder *, extern void VideoDrawRenderState(VideoHwDecoder *,