00001 #include "math.h"
00002
00003 #include "compat.h"
00004 #include "mythcorecontext.h"
00005 #include "mythlogging.h"
00006 #include "videocolourspace.h"
00007
00008
00009 #define LOC QString("ColourSpace: ")
00010
00011 Matrix::Matrix(float m11, float m12, float m13, float m14,
00012 float m21, float m22, float m23, float m24,
00013 float m31, float m32, float m33, float m34)
00014 {
00015 m[0][0] = m11; m[0][1] = m12; m[0][2] = m13; m[0][3] = m14;
00016 m[1][0] = m21; m[1][1] = m22; m[1][2] = m23; m[1][3] = m24;
00017 m[2][0] = m31; m[2][1] = m32; m[2][2] = m33; m[2][3] = m34;
00018 m[3][0] = m[3][1] = m[3][2] = m[3][3] = 1.0f;
00019 }
00020
00021 Matrix::Matrix()
00022 {
00023 setToIdentity();
00024 }
00025
00026 void Matrix::setToIdentity(void)
00027 {
00028 for (int i = 0; i < 3; i++)
00029 for (int j = 0; j < 4; j++)
00030 m[i][j] = (i == j) ? 1.0f : 0.0f;
00031 }
00032
00033 void Matrix::scale(float val1, float val2, float val3)
00034 {
00035 Matrix scale;
00036 scale.m[0][0] = val1;
00037 scale.m[1][1] = val2;
00038 scale.m[2][2] = val3;
00039 this->operator *=(scale);
00040 }
00041
00042 void Matrix::translate(float val1, float val2, float val3)
00043 {
00044 Matrix translate;
00045 translate.m[0][3] = val1;
00046 translate.m[1][3] = val2;
00047 translate.m[2][3] = val3;
00048 this->operator *=(translate);
00049 }
00050
00051 Matrix & Matrix::operator*=(const Matrix &r)
00052 {
00053 for (int i = 0; i < 3; i++)
00054 product(i, r);
00055 return *this;
00056 }
00057
00058 void Matrix::product(int row, const Matrix &r)
00059 {
00060 float t0, t1, t2, t3;
00061 t0 = m[row][0] * r.m[0][0] + m[row][1] * r.m[1][0] + m[row][2] * r.m[2][0];
00062 t1 = m[row][0] * r.m[0][1] + m[row][1] * r.m[1][1] + m[row][2] * r.m[2][1];
00063 t2 = m[row][0] * r.m[0][2] + m[row][1] * r.m[1][2] + m[row][2] * r.m[2][2];
00064 t3 = m[row][0] * r.m[0][3] + m[row][1] * r.m[1][3] + m[row][2] * r.m[2][3] + m[row][3];
00065 m[row][0] = t0; m[row][1] = t1; m[row][2] = t2; m[row][3] = t3;
00066 }
00067
00068 void Matrix::debug(void)
00069 {
00070 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("%1 %2 %3 %4")
00071 .arg(m[0][0], 4, 'f', 4, QLatin1Char('0'))
00072 .arg(m[0][1], 4, 'f', 4, QLatin1Char('0'))
00073 .arg(m[0][2], 4, 'f', 4, QLatin1Char('0'))
00074 .arg(m[0][3], 4, 'f', 4, QLatin1Char('0')));
00075 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("%1 %2 %3 %4")
00076 .arg(m[1][0], 4, 'f', 4, QLatin1Char('0'))
00077 .arg(m[1][1], 4, 'f', 4, QLatin1Char('0'))
00078 .arg(m[1][2], 4, 'f', 4, QLatin1Char('0'))
00079 .arg(m[1][3], 4, 'f', 4, QLatin1Char('0')));
00080 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("%1 %2 %3 %4")
00081 .arg(m[2][0], 4, 'f', 4, QLatin1Char('0'))
00082 .arg(m[2][1], 4, 'f', 4, QLatin1Char('0'))
00083 .arg(m[2][2], 4, 'f', 4, QLatin1Char('0'))
00084 .arg(m[2][3], 4, 'f', 4, QLatin1Char('0')));
00085 }
00086
00087 VideoColourSpace::VideoColourSpace(VideoCStd colour_std)
00088 : m_supported_attributes(kPictureAttributeSupported_None),
00089 m_changed(false), m_studioLevels(false), m_brightness(0.0f),
00090 m_contrast(1.0f), m_saturation(1.0f), m_hue(0.0f),
00091 m_colourSpace(colour_std)
00092 {
00093 m_db_settings[kPictureAttribute_Brightness] =
00094 gCoreContext->GetNumSetting("PlaybackBrightness", 50);
00095 m_db_settings[kPictureAttribute_Contrast] =
00096 gCoreContext->GetNumSetting("PlaybackContrast", 50);
00097 m_db_settings[kPictureAttribute_Colour] =
00098 gCoreContext->GetNumSetting("PlaybackColour", 50);
00099 m_db_settings[kPictureAttribute_Hue] =
00100 gCoreContext->GetNumSetting("PlaybackHue", 0);
00101 m_db_settings[kPictureAttribute_StudioLevels] =
00102 gCoreContext->GetNumSetting("PlaybackStudioLevels", 0);
00103
00104 SetBrightness(m_db_settings[kPictureAttribute_Brightness]);
00105 SetContrast(m_db_settings[kPictureAttribute_Contrast]);
00106 SetSaturation(m_db_settings[kPictureAttribute_Colour]);
00107 SetHue(m_db_settings[kPictureAttribute_Hue]);
00108 SetStudioLevels(m_db_settings[kPictureAttribute_StudioLevels]);
00109 }
00110
00111 void VideoColourSpace::SetSupportedAttributes(PictureAttributeSupported supported)
00112 {
00113 m_supported_attributes = supported;
00114 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("PictureAttributes: %1")
00115 .arg(toString(m_supported_attributes)));
00116 }
00117
00118 int VideoColourSpace::GetPictureAttribute(PictureAttribute attribute)
00119 {
00120 if (m_db_settings.contains(attribute))
00121 return m_db_settings.value(attribute);
00122 return -1;
00123 }
00124
00125 int VideoColourSpace::SetPictureAttribute(PictureAttribute attribute, int value)
00126 {
00127 if (!(m_supported_attributes & toMask(attribute)))
00128 return -1;
00129
00130 value = std::min(std::max(value, 0), 100);
00131
00132 switch (attribute)
00133 {
00134 case kPictureAttribute_Brightness:
00135 SetBrightness(value);
00136 break;
00137 case kPictureAttribute_Contrast:
00138 SetContrast(value);
00139 break;
00140 case kPictureAttribute_Colour:
00141 SetSaturation(value);
00142 break;
00143 case kPictureAttribute_Hue:
00144 SetHue(value);
00145 break;
00146 case kPictureAttribute_StudioLevels:
00147 value = std::min(std::max(value, 0), 1);
00148 SetStudioLevels(value > 0);
00149 break;
00150 default:
00151 value = -1;
00152 }
00153
00154 if (value >= 0)
00155 SaveValue(attribute, value);
00156
00157 return value;
00158 }
00159
00160 void VideoColourSpace::Update(void)
00161 {
00162 float luma_range = m_studioLevels ? 255.0f : 219.0f;
00163 float chroma_range = m_studioLevels ? 255.0f : 224.0f;
00164 float luma_offset = m_studioLevels ? 0.0f : -16.0f / 255.0f;
00165 float chroma_offset = -128.0f / 255.0f;
00166
00167 float uvcos = m_saturation * cos(m_hue);
00168 float uvsin = m_saturation * sin(m_hue);
00169 float brightness = m_brightness * 255.0f / luma_range;
00170 float luma_scale = 255.0f / luma_range;
00171 float chroma_scale = 255.0f / chroma_range;
00172
00173 Matrix csc;
00174 switch (m_colourSpace)
00175 {
00176 case kCSTD_SMPTE_240M:
00177 csc = Matrix(1.000f, ( 0.0000f * uvcos) + ( 1.5756f * uvsin),
00178 ( 1.5756f * uvcos) - ( 0.0000f * uvsin), 0.0f,
00179 1.000f, (-0.2253f * uvcos) + ( 0.5000f * uvsin),
00180 ( 0.5000f * uvcos) - (-0.2253f * uvsin), 0.0f,
00181 1.000f, ( 1.8270f * uvcos) + ( 0.0000f * uvsin),
00182 ( 0.0000f * uvcos) - ( 1.8270f * uvsin), 0.0f);
00183 break;
00184
00185 case kCSTD_ITUR_BT_709:
00186 csc = Matrix(1.000f, ( 0.0000f * uvcos) + ( 1.5701f * uvsin),
00187 ( 1.5701f * uvcos) - ( 0.0000f * uvsin), 0.0f,
00188 1.000f, (-0.1870f * uvcos) + (-0.4664f * uvsin),
00189 (-0.4664f * uvcos) - (-0.1870f * uvsin), 0.0f,
00190 1.000f, ( 1.8556f * uvcos) + ( 0.0000f * uvsin),
00191 ( 0.0000f * uvcos) - ( 1.8556f * uvsin), 0.0f);
00192 break;
00193
00194 case kCSTD_ITUR_BT_601:
00195 default:
00196 csc = Matrix(1.000f, ( 0.0000f * uvcos) + ( 1.4030f * uvsin),
00197 ( 1.4030f * uvcos) - ( 0.0000f * uvsin), 0.0f,
00198 1.000f, (-0.3440f * uvcos) + (-0.7140f * uvsin),
00199 (-0.7140f * uvcos) - (-0.3440f * uvsin), 0.0f,
00200 1.000f, ( 1.7730f * uvcos) + ( 0.0000f * uvsin),
00201 ( 0.0000f * uvcos) - ( 1.7730f * uvsin), 0.0f);
00202 }
00203
00204 m_matrix.setToIdentity();
00205 m_matrix.translate(brightness, brightness, brightness);
00206 m_matrix.scale(m_contrast, m_contrast, m_contrast);
00207 m_matrix *= csc;
00208 m_matrix.scale(luma_scale, chroma_scale, chroma_scale);
00209 m_matrix.translate(luma_offset, chroma_offset, chroma_offset);
00210 m_changed = true;
00211 Debug();
00212 }
00213
00214 void VideoColourSpace::Debug(void)
00215 {
00216 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
00217 QString("Brightness: %1 Contrast: %2 Saturation: %3 Hue: %4 "
00218 "StudioLevels: %5")
00219 .arg(m_brightness, 2, 'f', 4, QLatin1Char('0'))
00220 .arg(m_contrast , 2, 'f', 4, QLatin1Char('0'))
00221 .arg(m_saturation, 2, 'f', 4, QLatin1Char('0'))
00222 .arg(m_hue , 2, 'f', 4, QLatin1Char('0'))
00223 .arg(m_studioLevels));
00224 m_matrix.debug();
00225 }
00226
00227 void VideoColourSpace::SetColourSpace(VideoCStd csp)
00228 {
00229 m_colourSpace = csp;
00230 Update();
00231 }
00232
00233 void VideoColourSpace::SetStudioLevels(bool studio)
00234 {
00235 m_studioLevels = studio;
00236 Update();
00237 }
00238
00239 void VideoColourSpace::SetBrightness(int value)
00240 {
00241 m_brightness = (value * 0.02f) - 1.0f;
00242 Update();
00243 }
00244
00245 void VideoColourSpace::SetContrast(int value)
00246 {
00247 m_contrast = value * 0.02f;
00248 Update();
00249 }
00250
00251 void VideoColourSpace::SetHue(int value)
00252 {
00253 m_hue = value * (-3.6f * M_PI / 180.0f);
00254 Update();
00255 }
00256
00257 void VideoColourSpace::SetSaturation(int value)
00258 {
00259 m_saturation = value * 0.02f;
00260 Update();
00261 }
00262
00263 void VideoColourSpace::SaveValue(PictureAttribute attributeType, int value)
00264 {
00265 QString dbName = QString::null;
00266 if (kPictureAttribute_Brightness == attributeType)
00267 dbName = "PlaybackBrightness";
00268 else if (kPictureAttribute_Contrast == attributeType)
00269 dbName = "PlaybackContrast";
00270 else if (kPictureAttribute_Colour == attributeType)
00271 dbName = "PlaybackColour";
00272 else if (kPictureAttribute_Hue == attributeType)
00273 dbName = "PlaybackHue";
00274 else if (kPictureAttribute_StudioLevels == attributeType)
00275 dbName = "PlaybackStudioLevels";
00276
00277 if (!dbName.isEmpty())
00278 gCoreContext->SaveSetting(dbName, value);
00279
00280 m_db_settings[attributeType] = value;
00281 }