diff options
| author | Thomas Reufer <thomas@reufer.ch> | 2014-10-06 12:45:17 +0200 |
|---|---|---|
| committer | Thomas Reufer <thomas@reufer.ch> | 2014-10-06 12:45:17 +0200 |
| commit | 5249b7a1795e554ffab7e2fb7b5626d0f5eddf0e (patch) | |
| tree | adbf8fbda3709480b890839be015fdf5e99e2844 | |
| parent | 50ae3a6c391be3150e2803a82d5af06f1c80ecb2 (diff) | |
| download | vdr-plugin-rpihddevice-5249b7a1795e554ffab7e2fb7b5626d0f5eddf0e.tar.gz vdr-plugin-rpihddevice-5249b7a1795e554ffab7e2fb7b5626d0f5eddf0e.tar.bz2 | |
introduce HDMI mode settings and move display handling to cRpiDisplay
| -rw-r--r-- | display.c | 347 | ||||
| -rw-r--r-- | display.h | 78 | ||||
| -rw-r--r-- | omx.c | 4 | ||||
| -rw-r--r-- | omxdevice.c | 2 | ||||
| -rw-r--r-- | ovgosd.c | 5 | ||||
| -rw-r--r-- | rpihddevice.c | 2 | ||||
| -rw-r--r-- | setup.c | 83 | ||||
| -rw-r--r-- | setup.h | 14 |
8 files changed, 401 insertions, 134 deletions
@@ -9,98 +9,337 @@ #include <vdr/tools.h> +extern "C" { +#include "interface/vmcs_host/vc_tvservice.h" #include "interface/vmcs_host/vc_dispmanx.h" +} + +cRpiDisplay* cRpiDisplay::s_instance = 0; -#define ALIGN_UP(value, align) (((value) & (align-1)) ? \ - (((value) + (align-1)) & ~(align-1)) : (value)) +class cRpiDisplay::cHandles +{ +public: -DISPMANX_DISPLAY_HANDLE_T cRpiDisplay::s_display = 0; -DISPMANX_UPDATE_HANDLE_T cRpiDisplay::s_update = 0; + DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_UPDATE_HANDLE_T update; +}; -int cRpiDisplay::Open(int device) +cRpiDisplay* cRpiDisplay::GetInstance(void) { - s_display = vc_dispmanx_display_open(device); - if (!s_display) + if (!s_instance) { - ELOG("failed to open display!"); - return -1; + TV_DISPLAY_STATE_T tvstate; + memset(&tvstate, 0, sizeof(TV_DISPLAY_STATE_T)); + + if (!vc_tv_get_display_state(&tvstate)) + { + // HDMI + if (tvstate.state & (VC_HDMI_HDMI | VC_HDMI_DVI)) + s_instance = new cRpiHDMIDisplay( + tvstate.display.hdmi.width, + tvstate.display.hdmi.height, + tvstate.display.hdmi.frame_rate, + tvstate.display.hdmi.group, + tvstate.display.hdmi.mode); + else + s_instance = new cRpiCompositeDisplay( + tvstate.display.sdtv.width, + tvstate.display.sdtv.height, + tvstate.display.sdtv.frame_rate); + } + else + { + ELOG("failed to get display parameters!"); + return false; + } } - s_update = vc_dispmanx_update_start(0); - if (s_update == DISPMANX_NO_HANDLE) + return s_instance; +} + +void cRpiDisplay::DropInstance(void) +{ + delete s_instance; + s_instance = 0; +} + +cRpiDisplay::cRpiDisplay(int width, int height, int frameRate, + cRpiVideoPort::ePort port) : + m_width(width), + m_height(height), + m_frameRate(frameRate), + m_interlaced(false), + m_port(port), + m_handles(new cHandles()) +{ + m_handles->display = vc_dispmanx_display_open( + m_port == cRpiVideoPort::eHDMI ? 0 : 1); + + if (m_handles->display) { - ELOG("failed to start display update!"); - Close(); - return -1; + m_handles->update = vc_dispmanx_update_start(0); + if (m_handles->update == DISPMANX_NO_HANDLE) + ELOG("failed to start display update!"); } - return 0; + else + ELOG("failed to open display!"); } -void cRpiDisplay::Close(void) +cRpiDisplay::~cRpiDisplay() { - if (s_display) - vc_dispmanx_display_close(s_display); + if (m_handles->display) + vc_dispmanx_display_close(m_handles->display); - s_display = 0; + delete m_handles; } int cRpiDisplay::GetSize(int &width, int &height) { - if (!s_display) - return -1; + cRpiDisplay* instance = GetInstance(); + if (instance) + { + width = instance->m_width; + height = instance->m_height; + return 0; + } + return -1; +} - DISPMANX_MODEINFO_T info; - memset(&info, 0, sizeof(info)); +int cRpiDisplay::GetSize(int &width, int &height, double &aspect) +{ + cRpiDisplay* instance = GetInstance(); + if (instance) + { + width = instance->m_width; + height = instance->m_height; + aspect = (double)width / height; + return 0; + } + return -1; +} - if (vc_dispmanx_display_get_info(s_display, &info)) +int cRpiDisplay::Get(int &width, int &height, int &frameRate, bool &interlaced) +{ + cRpiDisplay* instance = GetInstance(); + if (instance) { - ELOG("failed to get display info!"); - return -1; + width = instance->m_width; + height = instance->m_height; + frameRate = instance->m_frameRate; + interlaced = instance->m_interlaced; + return 0; } + return -1; +} + +int cRpiDisplay::Set(int width, int height, int frameRate, bool interlaced) +{ + cRpiDisplay* instance = GetInstance(); + if (instance) + return instance->SetMode(width, height, frameRate, interlaced); + + return -1; +} + +cRpiVideoPort::ePort cRpiDisplay::GetVideoPort(void) +{ + cRpiDisplay* instance = GetInstance(); + if (instance) + return instance->m_port; - width = info.width; - height = info.height; + return cRpiVideoPort::eComposite; +} - return 0; +bool cRpiDisplay::IsProgressive(void) +{ + cRpiDisplay* instance = GetInstance(); + if (instance) + return !instance->m_interlaced; + + return false; } int cRpiDisplay::AddElement(DISPMANX_ELEMENT_HANDLE_T &element, int width, int height, int layer) { - if (!s_display) - return -1; - - VC_RECT_T dstRect = { 0, 0, width, height }; - VC_RECT_T srcRect = { 0, 0, width << 16, height << 16 }; + cRpiDisplay* instance = GetInstance(); + if (instance) + { + VC_RECT_T dstRect = { 0, 0, width, height }; + VC_RECT_T srcRect = { 0, 0, width << 16, height << 16 }; - element = vc_dispmanx_element_add(s_update, s_display, layer, &dstRect, 0, - &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0); + element = vc_dispmanx_element_add(instance->m_handles->update, + instance->m_handles->display, layer, &dstRect, 0, &srcRect, + DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T)0); - if (!element) - { - ELOG("failed to add display element!"); - return -1; - } + if (!element) + { + ELOG("failed to add display element!"); + return -1; + } - vc_dispmanx_update_submit_sync(s_update); - return 0; + vc_dispmanx_update_submit_sync(instance->m_handles->update); + return 0; + } + return -1; } int cRpiDisplay::Snapshot(uint8_t* frame, int width, int height) { - if (!s_display) - return -1; + cRpiDisplay* instance = GetInstance(); + if (instance) + { + uint32_t image; + DISPMANX_RESOURCE_HANDLE_T res = vc_dispmanx_resource_create( + VC_IMAGE_RGB888, width, height, &image); - uint32_t image; - DISPMANX_RESOURCE_HANDLE_T res = vc_dispmanx_resource_create( - VC_IMAGE_RGB888, width, height, &image); + vc_dispmanx_snapshot(instance->m_handles->display, res, + (DISPMANX_TRANSFORM_T)(DISPMANX_SNAPSHOT_PACK)); - vc_dispmanx_snapshot(s_display, res, - (DISPMANX_TRANSFORM_T)(DISPMANX_SNAPSHOT_PACK)); + VC_RECT_T rect = { 0, 0, width, height }; + vc_dispmanx_resource_read_data(res, &rect, frame, width * 3); - VC_RECT_T rect = { 0, 0, width, height }; - vc_dispmanx_resource_read_data(res, &rect, frame, width * 3); + vc_dispmanx_resource_delete(res); + return 0; + } + return -1; +} + +/* ------------------------------------------------------------------------- */ + +#define HDMI_MAX_MODES 64 + +class cRpiHDMIDisplay::ModeList { +public: + + TV_SUPPORTED_MODE_NEW_T modes[HDMI_MAX_MODES]; + int nModes; +}; + +cRpiHDMIDisplay::cRpiHDMIDisplay(int width, int height, int frameRate, + int group, int mode) : + cRpiDisplay(width, height, frameRate, cRpiVideoPort::eHDMI), + m_modes(new cRpiHDMIDisplay::ModeList()), + m_group(group), + m_mode(mode), + m_startGroup(group), + m_startMode(mode), + m_modified(false) +{ + + m_modes->nModes = vc_tv_hdmi_get_supported_modes_new(HDMI_RES_GROUP_CEA, + m_modes->modes, HDMI_MAX_MODES, NULL, NULL); + + m_modes->nModes += vc_tv_hdmi_get_supported_modes_new(HDMI_RES_GROUP_DMT, + &m_modes->modes[m_modes->nModes], HDMI_MAX_MODES - m_modes->nModes, + NULL, NULL); + + if (m_modes->nModes) + { + DLOG("supported HDMI modes:"); + for (int i = 0; i < m_modes->nModes; i++) + { + DLOG("%s[%02d]: %4dx%4d@%2d%s | %s | %3d.%03dMHz%s%s", + m_modes->modes[i].group == HDMI_RES_GROUP_CEA ? "CEA" : + m_modes->modes[i].group == HDMI_RES_GROUP_DMT ? "DMT" : "---", + m_modes->modes[i].code, + m_modes->modes[i].width, + m_modes->modes[i].height, + m_modes->modes[i].frame_rate, + m_modes->modes[i].scan_mode ? "i" : "p", + m_modes->modes[i].aspect_ratio == HDMI_ASPECT_4_3 ? " 4:3 " : + m_modes->modes[i].aspect_ratio == HDMI_ASPECT_14_9 ? "14:9 " : + m_modes->modes[i].aspect_ratio == HDMI_ASPECT_16_9 ? "16:9 " : + m_modes->modes[i].aspect_ratio == HDMI_ASPECT_5_4 ? " 5:4 " : + m_modes->modes[i].aspect_ratio == HDMI_ASPECT_16_10 ? "16:10" : + m_modes->modes[i].aspect_ratio == HDMI_ASPECT_15_9 ? "15:9 " : + m_modes->modes[i].aspect_ratio == HDMI_ASPECT_21_9 ? "21:9 " : + "unknown aspect ratio", + m_modes->modes[i].pixel_freq / 1000000, + m_modes->modes[i].pixel_freq % 1000000 / 1000, + m_modes->modes[i].native ? " (native)" : "", + m_modes->modes[i].code == m_mode && + m_modes->modes[i].group == m_group ? " (current)" : ""); + + // update initial parameters + if (m_modes->modes[i].code == m_mode && + m_modes->modes[i].group == m_group) + { + m_width = m_modes->modes[i].width; + m_height = m_modes->modes[i].height; + m_frameRate = m_modes->modes[i].frame_rate; + m_interlaced = m_modes->modes[i].scan_mode; + } + } + } + else + ELOG("failed to read HDMI EDID information!"); + +} + +cRpiHDMIDisplay::~cRpiHDMIDisplay() +{ + // if mode has been changed, set back to previous state + if (m_modified) + SetMode(m_startGroup, m_startMode); + + delete m_modes; +} + +int cRpiHDMIDisplay::SetMode(int width, int height, int frameRate, + bool interlaced) +{ + for (int i = 0; i < m_modes->nModes; i++) + { + if (m_modes->modes[i].width == width && + m_modes->modes[i].height == height && + m_modes->modes[i].frame_rate == frameRate && + m_modes->modes[i].scan_mode == interlaced) + { + DLOG("setting HDMI mode to %dx%d@%2d%s", width, height, + frameRate, interlaced ? "i" : "p"); + + m_width = width; + m_height = height; + m_frameRate = frameRate; + m_interlaced = interlaced; + return SetMode(m_modes->modes[i].group, m_modes->modes[i].code); + } + } + + DLOG("failed to set HDMI mode to %dx%d@%2d%s", + width, height, frameRate, interlaced ? "i" : "p"); + return -1; +} + +int cRpiHDMIDisplay::SetMode(int group, int mode) +{ + int ret = 0; + if (group != m_group || mode != m_mode) + { + DBG("cHDMI::SetMode(%s, %d)", + group == HDMI_RES_GROUP_DMT ? "DMT" : + group == HDMI_RES_GROUP_CEA ? "CEA" : "unknown", mode); + + ret = vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, + (HDMI_RES_GROUP_T)group, mode); + if (ret) + ELOG("failed to set HDMI mode!"); + else + { + m_group = group; + m_mode = mode; + m_modified = true; + } + } + return ret; +} + +/* ------------------------------------------------------------------------- */ + +cRpiCompositeDisplay::cRpiCompositeDisplay(int width, int height, + int frameRate) : + cRpiDisplay(width, height, frameRate, cRpiVideoPort::eComposite) +{ - vc_dispmanx_resource_delete(res); - return 0; } @@ -7,26 +7,96 @@ #ifndef DISPLAY_H #define DISPLAY_H +#include "tools.h" + +extern "C" { #include "interface/vmcs_host/vc_dispmanx_types.h" +} class cRpiDisplay { public: - static int Open(int device); - static void Close(void); + static cRpiDisplay* GetInstance(void); + static void DropInstance(void); static int GetSize(int &width, int &height); + static int GetSize(int &width, int &height, double &aspect); + + static cRpiVideoPort::ePort GetVideoPort(void); + static bool IsProgressive(void); + + static int Get(int &width, int &height, int &frameRate, bool &interlaced); + static int Set(int width, int height, int frameRate, bool interlaced); + static int AddElement(DISPMANX_ELEMENT_HANDLE_T &element, int width, int height, int layer); static int Snapshot(uint8_t* frame, int width, int height); +protected: + + cRpiDisplay(int width, int height, int frameRate, + cRpiVideoPort::ePort port); + virtual ~cRpiDisplay(); + + virtual int SetMode(int width, int height, int frameRate, bool interlaced) { + return 0; + } + + int m_width; + int m_height; + int m_frameRate; + bool m_interlaced; + cRpiVideoPort::ePort m_port; + + static cRpiDisplay *s_instance; + +private: + + cRpiDisplay(const cRpiDisplay&); + cRpiDisplay& operator= (const cRpiDisplay&); + + class cHandles; + cHandles *m_handles; +}; + +class cRpiHDMIDisplay : public cRpiDisplay +{ + +public: + + cRpiHDMIDisplay(int width, int height, int frameRate, int group, int mode); + virtual ~cRpiHDMIDisplay(); + private: - static DISPMANX_DISPLAY_HANDLE_T s_display; - static DISPMANX_UPDATE_HANDLE_T s_update; + virtual int SetMode(int width, int height, int frameRate, bool interlaced); + int SetMode(int group, int mode); + + class ModeList; + ModeList *m_modes; + + int m_group; + int m_mode; + + int m_startGroup; + int m_startMode; + bool m_modified; +}; + +class cRpiCompositeDisplay : public cRpiDisplay +{ + +public: + + cRpiCompositeDisplay(int width, int height, int frameRate); + +private: + virtual int SetMode(int width, int height, int frameRate, bool interlaced) { + return 0; + } }; #endif @@ -5,7 +5,7 @@ */ #include "omx.h" -#include "setup.h" +#include "display.h" #include <vdr/tools.h> #include <vdr/thread.h> @@ -249,7 +249,7 @@ void cOmx::HandlePortSettingsChanged(unsigned int portId) OMX_INIT_STRUCT(filterparam); filterparam.nPortIndex = 191; filterparam.eImageFilter = OMX_ImageFilterNone; - if (cRpiSetup::IsDisplayProgressive() && m_videoFormat.interlaced) + if (cRpiDisplay::IsProgressive() && m_videoFormat.interlaced) { filterparam.nNumParams = 1; filterparam.nParams[0] = 3; diff --git a/omxdevice.c b/omxdevice.c index 0b26390..c696f93 100644 --- a/omxdevice.c +++ b/omxdevice.c @@ -105,7 +105,7 @@ int cOmxDevice::DeInit(void) void cOmxDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect) { - cRpiSetup::GetDisplaySize(Width, Height, PixelAspect); + cRpiDisplay::GetSize(Width, Height, PixelAspect); } void cOmxDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect) @@ -144,7 +144,7 @@ public: m_height(0), m_aspect(0) { - cRpiSetup::GetDisplaySize(m_width, m_height, m_aspect); + cRpiDisplay::GetSize(m_width, m_height, m_aspect); Start(); } @@ -206,7 +206,6 @@ protected: if (context == EGL_NO_CONTEXT) ELOG("failed to create EGL rendering context!"); - cRpiDisplay::Open(0 /* LCD */); DISPMANX_ELEMENT_HANDLE_T dispmanElement; cRpiDisplay::AddElement(dispmanElement, m_width, m_height, 2); @@ -278,8 +277,6 @@ protected: eglDestroyContext(display, context); eglTerminate(display); - cRpiDisplay::Close(); - DLOG("cOvg() thread ended"); } diff --git a/rpihddevice.c b/rpihddevice.c index 074b5be..664757c 100644 --- a/rpihddevice.c +++ b/rpihddevice.c @@ -10,6 +10,7 @@ #include "ovgosd.h" #include "omxdevice.h" #include "setup.h" +#include "display.h" #include "tools.h" static const char *VERSION = "0.0.9"; @@ -48,6 +49,7 @@ cPluginRpiHdDevice::cPluginRpiHdDevice(void) : cPluginRpiHdDevice::~cPluginRpiHdDevice() { cRpiSetup::DropInstance(); + cRpiDisplay::DropInstance(); } bool cPluginRpiHdDevice::Initialize(void) @@ -5,6 +5,7 @@ */ #include "setup.h" +#include "display.h" #include <vdr/tools.h> #include <vdr/menuitems.h> @@ -13,23 +14,7 @@ #include "interface/vchiq_arm/vchiq_if.h" #include "interface/vmcs_host/vc_tvservice.h" -cRpiSetup* cRpiSetup::s_instance = 0; - -cRpiSetup* cRpiSetup::GetInstance(void) -{ - if (!s_instance) - s_instance = new cRpiSetup(); - - return s_instance; -} - -void cRpiSetup::DropInstance(void) -{ - delete s_instance; - s_instance = 0; - - bcm_host_deinit(); -} +/* ------------------------------------------------------------------------- */ class cRpiSetupPage : public cMenuSetupPage { @@ -116,6 +101,26 @@ const char *const cRpiSetupPage::s_audioport[] = const char *const cRpiSetupPage::s_videoframing[] = { tr("box"), tr("crop"), tr("stretch") }; +/* ------------------------------------------------------------------------- */ + +cRpiSetup* cRpiSetup::s_instance = 0; + +cRpiSetup* cRpiSetup::GetInstance(void) +{ + if (!s_instance) + s_instance = new cRpiSetup(); + + return s_instance; +} + +void cRpiSetup::DropInstance(void) +{ + delete s_instance; + s_instance = 0; + + bcm_host_deinit(); +} + bool cRpiSetup::HwInit(void) { cRpiSetup* instance = GetInstance(); @@ -134,40 +139,14 @@ bool cRpiSetup::HwInit(void) } } - TV_DISPLAY_STATE_T tvstate; - memset(&tvstate, 0, sizeof(TV_DISPLAY_STATE_T)); - if (!vc_tv_get_display_state(&tvstate)) + int width, height; + if (!cRpiDisplay::GetSize(width, height)) { - int height = 0, width = 0; - bool progressive = false; - cRpiVideoPort::ePort port = cRpiVideoPort::eComposite; - - // HDMI - if ((tvstate.state & (VC_HDMI_HDMI | VC_HDMI_DVI))) - { - progressive = tvstate.display.hdmi.scan_mode == 0; - height = tvstate.display.hdmi.height; - width = tvstate.display.hdmi.width; - port = cRpiVideoPort::eHDMI; - } - else - { - height = tvstate.display.sdtv.height; - width = tvstate.display.sdtv.width; - } - - ILOG("using %s video output at %dx%d%s", - cRpiVideoPort::Str(port), width, height, progressive ? "p" : "i"); - - instance->m_isProgressive = progressive; - instance->m_displayHeight = height; - instance->m_displayWidth = width; + ILOG("HwInit() done, using %s video out at %dx%d", + cRpiVideoPort::Str(cRpiDisplay::GetVideoPort()), width, height); } else - { - ELOG("failed to get display parameters!"); - return false; - } + ELOG("failed to get video port information!"); return true; } @@ -218,14 +197,6 @@ bool cRpiSetup::IsAudioFormatSupported(cAudioCodec::eCodec codec, return false; } -int cRpiSetup::GetDisplaySize(int &width, int &height, double &aspect) -{ - height = GetInstance()->m_displayHeight; - width = GetInstance()->m_displayWidth; - aspect = (double)width / height; - return 0; -} - void cRpiSetup::SetHDMIChannelMapping(bool passthrough, int channels) { char command[80], response[80]; @@ -70,13 +70,8 @@ public: codec == cVideoCodec::eH264 ? true : false; } - static int GetDisplaySize(int &width, int &height, double &aspect); - static void SetHDMIChannelMapping(bool passthrough, int channels); - static bool IsDisplayProgressive(void) { - return GetInstance()->m_isProgressive; } - static cRpiSetup* GetInstance(void); static void DropInstance(void); @@ -92,16 +87,13 @@ private: cRpiSetup() : m_mpeg2Enabled(false), - m_isProgressive(false), - m_displayHeight(0), - m_displayWidth(0), m_onAudioSetupChanged(0), m_onAudioSetupChangedData(0), m_onVideoSetupChanged(0), m_onVideoSetupChangedData(0) { } - virtual ~cRpiSetup() { } + virtual ~cRpiSetup() { }; static cRpiSetup* s_instance; @@ -109,10 +101,6 @@ private: VideoParameters m_video; bool m_mpeg2Enabled; - bool m_isProgressive; - - int m_displayHeight; - int m_displayWidth; void (*m_onAudioSetupChanged)(void*); void *m_onAudioSetupChangedData; |
