Improve PlaYUVerPixel and add support for RGBA format
Changes ColorSpace enum Add Alpha channel support in pixel class Add RGBA pixel format to the list of supported formats
This commit is contained in:
@@ -295,7 +295,7 @@ Void FramePropertiesDock::setFrame( PlaYUVerFrame* pcFrame )
|
||||
if( m_iLastFrameType != colorSpace )
|
||||
{
|
||||
m_iLastFrameType = colorSpace;
|
||||
if( colorSpace == PlaYUVerPixel::COLOR_RGB || colorSpace == PlaYUVerPixel::COLOR_ARGB )
|
||||
if( colorSpace == PlaYUVerPixel::COLOR_RGB || colorSpace == PlaYUVerPixel::COLOR_RGBA )
|
||||
{
|
||||
channelCB->clear();
|
||||
channelCB->clear();
|
||||
@@ -303,7 +303,7 @@ Void FramePropertiesDock::setFrame( PlaYUVerFrame* pcFrame )
|
||||
channelCB->insertItem( FirstChannel, QIcon( ":/images/channel-red.png" ), "Red" );
|
||||
channelCB->insertItem( SecondChannel, QIcon( ":/images/channel-green.png" ), "Green" );
|
||||
channelCB->insertItem( ThirdChannel, QIcon( ":/images/channel-blue.png" ), "Blue" );
|
||||
if( colorSpace == PlaYUVerPixel::COLOR_ARGB )
|
||||
if( colorSpace == PlaYUVerPixel::COLOR_RGBA )
|
||||
{
|
||||
channelCB->insertItem( AlphaChannel, QIcon( ":/images/channel-alpha.png" ), "Alpha" );
|
||||
}
|
||||
@@ -513,7 +513,7 @@ Void FramePropertiesDock::slotChannelChanged( Int channel )
|
||||
{
|
||||
if( m_pcFrame->getColorSpace() == PlaYUVerPixel::COLOR_YUV )
|
||||
channel += 1;
|
||||
if( channel == AlphaChannel && m_pcFrame->getColorSpace() != PlaYUVerPixel::COLOR_ARGB )
|
||||
if( channel == AlphaChannel && m_pcFrame->getColorSpace() != PlaYUVerPixel::COLOR_RGBA )
|
||||
channel = ColorChannels;
|
||||
|
||||
switch( channel )
|
||||
|
||||
+24
-20
@@ -977,7 +977,6 @@ Void VideoSubWindow::updatePixelValueStatusBar( const QPoint& pos )
|
||||
{
|
||||
if( m_pcCurrFrame )
|
||||
{
|
||||
PlaYUVerPixel sPixelValue;
|
||||
Int iWidth, iHeight;
|
||||
Int posX = pos.x();
|
||||
Int posY = pos.y();
|
||||
@@ -990,28 +989,33 @@ Void VideoSubWindow::updatePixelValueStatusBar( const QPoint& pos )
|
||||
{
|
||||
strStatus = QString( "(%1,%2) " ).arg( posX ).arg( posY );
|
||||
|
||||
Int ColorSpace = m_pcCurrFrame->getColorSpace();
|
||||
if( ColorSpace == PlaYUVerPixel::COLOR_GRAY )
|
||||
Int colorSpace = m_pcCurrFrame->getColorSpace();
|
||||
PlaYUVerPixel pixelValue = m_pcCurrFrame->getPixelValue( pos.x(), pos.y() );
|
||||
switch( colorSpace )
|
||||
{
|
||||
sPixelValue = m_pcCurrFrame->getPixelValue( pos.x(), pos.y() );
|
||||
strStatus.append( QString( "Y: %1" ).arg( sPixelValue.Y() ) );
|
||||
}
|
||||
if( ColorSpace == PlaYUVerPixel::COLOR_YUV )
|
||||
{
|
||||
sPixelValue = m_pcCurrFrame->getPixelValue( pos.x(), pos.y() );
|
||||
case PlaYUVerPixel::COLOR_GRAY:
|
||||
strStatus.append( QString( "Y: %1" ).arg( pixelValue.Y() ) );
|
||||
break;
|
||||
case PlaYUVerPixel::COLOR_YUV:
|
||||
strStatus.append( QString( "Y: %1 U: %2 V: %3" )
|
||||
.arg( sPixelValue.Y() )
|
||||
.arg( sPixelValue.Cb() )
|
||||
.arg( sPixelValue.Cr() ) );
|
||||
}
|
||||
|
||||
if( ( ColorSpace == PlaYUVerPixel::COLOR_RGB ) )
|
||||
{
|
||||
sPixelValue = m_pcCurrFrame->getPixelValue( pos.x(), pos.y() );
|
||||
.arg( pixelValue.Y() )
|
||||
.arg( pixelValue.Cb() )
|
||||
.arg( pixelValue.Cr() ) );
|
||||
break;
|
||||
case PlaYUVerPixel::COLOR_RGB:
|
||||
strStatus.append( QString( "R: %1 G: %2 B: %3" )
|
||||
.arg( sPixelValue.R() )
|
||||
.arg( sPixelValue.G() )
|
||||
.arg( sPixelValue.B() ) );
|
||||
.arg( pixelValue.R() )
|
||||
.arg( pixelValue.G() )
|
||||
.arg( pixelValue.B() ) );
|
||||
break;
|
||||
case PlaYUVerPixel::COLOR_RGBA:
|
||||
strStatus.append( QString( "R: %1 G: %2 B: %3 A: %4" )
|
||||
.arg( pixelValue.R() )
|
||||
.arg( pixelValue.G() )
|
||||
.arg( pixelValue.B() )
|
||||
.arg( pixelValue.A() ) );
|
||||
|
||||
break;
|
||||
}
|
||||
emit updateStatusBar( strStatus );
|
||||
}
|
||||
|
||||
+12
-4
@@ -541,10 +541,18 @@ Void ViewArea::paintEvent( QPaintEvent* event )
|
||||
else
|
||||
paInter.setPen( QColor( Qt::black ) );
|
||||
|
||||
paInter.drawText( pixelRect, Qt::AlignCenter,
|
||||
"R: " + QString::number( sPixelValue.R() ) + "\n" +
|
||||
"G: " + QString::number( sPixelValue.G() ) + "\n" +
|
||||
"B: " + QString::number( sPixelValue.B() ) );
|
||||
paInter.drawText( pixelRect, Qt::AlignCenter, "R: " + QString::number( sPixelValue.R() ) + "\nG: " + QString::number( sPixelValue.G() ) + "\nB: " + QString::number( sPixelValue.B() ) );
|
||||
}
|
||||
if( ( frFormat == PlaYUVerPixel::COLOR_RGBA ) )
|
||||
{
|
||||
sPixelValue = m_pcCurrFrame->getPixelValue( pixelTopLeft.x(), pixelTopLeft.y() );
|
||||
|
||||
if( ( sPixelValue.R() + sPixelValue.G() + sPixelValue.B() ) < ( m_uiPixelHalfScale * 3 ) )
|
||||
paInter.setPen( QColor( Qt::white ) );
|
||||
else
|
||||
paInter.setPen( QColor( Qt::black ) );
|
||||
|
||||
paInter.drawText( pixelRect, Qt::AlignCenter, "R: " + QString::number( sPixelValue.R() ) + "\nG: " + QString::number( sPixelValue.G() ) + "\nB: " + QString::number( sPixelValue.B() ) + "\nA: " + QString::number( sPixelValue.A() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+73
-95
@@ -41,13 +41,14 @@ std::vector<String> PlaYUVerFrame::supportedColorSpacesListNames()
|
||||
"YUV",
|
||||
"RGB",
|
||||
"GRAY",
|
||||
"ARGB",
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<String> PlaYUVerFrame::supportedPixelFormatListNames()
|
||||
{
|
||||
std::vector<String> formatsList;
|
||||
for( Int i = 0; i < NUMBER_PEL_FORMATS; i++ )
|
||||
for( Int i = 0; i < numberOfFormats(); i++ )
|
||||
{
|
||||
formatsList.push_back( g_PlaYUVerPixFmtDescriptorsMap.at( i ).name );
|
||||
}
|
||||
@@ -57,7 +58,7 @@ std::vector<String> PlaYUVerFrame::supportedPixelFormatListNames()
|
||||
std::vector<String> PlaYUVerFrame::supportedPixelFormatListNames( Int colorSpace )
|
||||
{
|
||||
std::vector<String> formatsList;
|
||||
for( Int i = 0; i < NUMBER_PEL_FORMATS; i++ )
|
||||
for( Int i = 0; i < numberOfFormats(); i++ )
|
||||
{
|
||||
if( g_PlaYUVerPixFmtDescriptorsMap.at( i ).colorSpace == colorSpace )
|
||||
formatsList.push_back( g_PlaYUVerPixFmtDescriptorsMap.at( i ).name );
|
||||
@@ -65,9 +66,14 @@ std::vector<String> PlaYUVerFrame::supportedPixelFormatListNames( Int colorSpace
|
||||
return formatsList;
|
||||
}
|
||||
|
||||
Int PlaYUVerFrame::numberOfFormats()
|
||||
{
|
||||
return g_PlaYUVerPixFmtDescriptorsMap.size();
|
||||
}
|
||||
|
||||
Int PlaYUVerFrame::findPixelFormat( const String& name )
|
||||
{
|
||||
for( Int i = 0; i < NUMBER_PEL_FORMATS; i++ )
|
||||
for( Int i = 0; i < numberOfFormats(); i++ )
|
||||
{
|
||||
if( g_PlaYUVerPixFmtDescriptorsMap.at( i ).name == name )
|
||||
return i;
|
||||
@@ -290,7 +296,7 @@ PlaYUVerPixel PlaYUVerPixel::ConvertPixel( ColorSpace eOutputSpace )
|
||||
Int outA, outB, outC;
|
||||
PlaYUVerPixel outPixel( COLOR_INVALID, 0, 0, 0 );
|
||||
|
||||
if( ColorSpace() == eOutputSpace || eOutputSpace == COLOR_ARGB || eOutputSpace == COLOR_GRAY )
|
||||
if( ColorSpace() == eOutputSpace || eOutputSpace == COLOR_RGBA || eOutputSpace == COLOR_GRAY )
|
||||
return *this;
|
||||
|
||||
if( eOutputSpace == COLOR_RGB )
|
||||
@@ -310,51 +316,6 @@ PlaYUVerPixel PlaYUVerPixel::ConvertPixel( ColorSpace eOutputSpace )
|
||||
return outPixel;
|
||||
}
|
||||
|
||||
static Int getImgMemory( Pel**** array3D, Int dim1, Int dim2, Int log2ChromaHeight, Int log2ChromaWidth )
|
||||
{
|
||||
Int dim0 = 3;
|
||||
Int i;
|
||||
UInt64 total_mem_size = 0;
|
||||
UInt64 mem_size = ( dim1 * dim2 + CHROMASHIFT( dim1, log2ChromaHeight ) * CHROMASHIFT( dim2, log2ChromaWidth ) * 2 );
|
||||
|
||||
total_mem_size += getMem2D<Pel*>( array3D, dim0, dim1 );
|
||||
|
||||
if( ( ( *array3D )[0][0] = (Pel*)xCallocMem( mem_size, sizeof( Pel ) ) ) == NULL )
|
||||
printf( "getImgMemory: array1D" );
|
||||
|
||||
total_mem_size += mem_size * sizeof( Pel );
|
||||
|
||||
// Luma
|
||||
for( i = 1; i < dim1; i++ )
|
||||
( *array3D )[0][i] = ( *array3D )[0][i - 1] + dim2;
|
||||
|
||||
// Chroma
|
||||
( *array3D )[1][0] = ( *array3D )[0][0] + dim2 * dim1;
|
||||
|
||||
dim1 = CHROMASHIFT( dim1, log2ChromaHeight );
|
||||
dim2 = CHROMASHIFT( dim2, log2ChromaWidth );
|
||||
|
||||
for( i = 1; i < dim1; i++ )
|
||||
( *array3D )[1][i] = ( *array3D )[1][i - 1] + dim2;
|
||||
|
||||
( *array3D )[2][0] = ( *array3D )[1][0] + dim2 * dim1;
|
||||
for( i = 1; i < dim1; i++ )
|
||||
( *array3D )[2][i] = ( *array3D )[2][i - 1] + dim2;
|
||||
|
||||
return total_mem_size;
|
||||
}
|
||||
|
||||
Void freeImgMemory( Pel*** array3D )
|
||||
{
|
||||
if( array3D )
|
||||
{
|
||||
if( **array3D )
|
||||
xFreeMem( **array3D );
|
||||
|
||||
freeMem2D( array3D );
|
||||
}
|
||||
}
|
||||
|
||||
struct PlaYUVerFramePrivate
|
||||
{
|
||||
Bool m_bInit;
|
||||
@@ -365,12 +326,8 @@ struct PlaYUVerFramePrivate
|
||||
|
||||
UInt m_uiWidth; //!< Width of the frame
|
||||
UInt m_uiHeight; //!< Height of the frame
|
||||
Int m_iPixelFormat; //!< Pixel format number (it follows the list of
|
||||
//!< supported
|
||||
//! pixel formats)
|
||||
Int m_iNumberChannels; //!< Number of channels
|
||||
Int m_iPixelFormat; //!< Pixel format number (it follows the list of supported pixel formats)
|
||||
UInt m_uiBitsPel; //!< Bits per pixel/channel
|
||||
// Int m_iEndianness; //!< Endiannes of bytes
|
||||
UInt m_uiHalfPelValue; //!< Bits per pixel/channel
|
||||
|
||||
Pel*** m_pppcInputPel;
|
||||
@@ -389,22 +346,22 @@ struct PlaYUVerFramePrivate
|
||||
UInt m_uiHistoSegments;
|
||||
|
||||
/**
|
||||
* Common constructor function of a frame
|
||||
*
|
||||
* @param width width of the frame
|
||||
* @param height height of the frame
|
||||
* @param pel_format pixel format index (always use PixelFormats enum)
|
||||
*
|
||||
*/
|
||||
* Common constructor function of a frame
|
||||
*
|
||||
* @param width width of the frame
|
||||
* @param height height of the frame
|
||||
* @param pel_format pixel format index (always use PixelFormats enum)
|
||||
*
|
||||
*/
|
||||
Void init( UInt width, UInt height, Int pel_format, Int bitsPixel )
|
||||
{
|
||||
m_bInit = false;
|
||||
m_bHasRGBPel = false;
|
||||
m_pppcInputPel = NULL;
|
||||
m_pcARGB32 = NULL;
|
||||
m_uiWidth = width;
|
||||
m_uiHeight = height;
|
||||
m_iPixelFormat = pel_format;
|
||||
m_iNumberChannels = 3;
|
||||
m_uiBitsPel = bitsPixel < 8 ? 8 : bitsPixel;
|
||||
m_uiHalfPelValue = 1 << ( m_uiBitsPel - 1 );
|
||||
|
||||
@@ -414,17 +371,39 @@ struct PlaYUVerFramePrivate
|
||||
}
|
||||
|
||||
m_pcPelFormat = &( g_PlaYUVerPixFmtDescriptorsMap.at( pel_format ) );
|
||||
Int iNumberChannels = m_pcPelFormat->numberChannels;
|
||||
|
||||
m_bHasRGBPel = false;
|
||||
if( m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_GRAY )
|
||||
std::size_t mem_size = 0;
|
||||
std::size_t num_of_ptrs = 0;
|
||||
for( Int ch = 0; ch < iNumberChannels; ch++ )
|
||||
{
|
||||
getImgMemory( &m_pppcInputPel, m_uiHeight, m_uiWidth, 1, 1 );
|
||||
Int ratioW = ch > 0 ? m_pcPelFormat->log2ChromaWidth : 0;
|
||||
Int ratioH = ch > 0 ? m_pcPelFormat->log2ChromaHeight : 0;
|
||||
// Add pointers mem
|
||||
num_of_ptrs += CHROMASHIFT( m_uiHeight, ratioH );
|
||||
// Add pixel mem
|
||||
mem_size += CHROMASHIFT( m_uiHeight, ratioH ) * CHROMASHIFT( m_uiWidth, ratioW ) * sizeof( Pel );
|
||||
}
|
||||
else
|
||||
mem_size += num_of_ptrs * sizeof( Pel* ) + sizeof( Pel** ) * iNumberChannels;
|
||||
|
||||
m_pppcInputPel = (Pel***)xMallocMem( mem_size );
|
||||
|
||||
Pel** pelPtrMem = (Pel**)( m_pppcInputPel + iNumberChannels );
|
||||
Pel* pelMem = (Pel*)( pelPtrMem + num_of_ptrs );
|
||||
for( Int ch = 0; ch < iNumberChannels; ch++ )
|
||||
{
|
||||
getImgMemory( &m_pppcInputPel, m_uiHeight, m_uiWidth, m_pcPelFormat->log2ChromaHeight,
|
||||
m_pcPelFormat->log2ChromaWidth );
|
||||
Int ratioW = ch > 0 ? m_pcPelFormat->log2ChromaWidth : 0;
|
||||
Int ratioH = ch > 0 ? m_pcPelFormat->log2ChromaHeight : 0;
|
||||
m_pppcInputPel[ch] = pelPtrMem;
|
||||
for( UInt h = 0; h < CHROMASHIFT( m_uiHeight, ratioH ); h++ )
|
||||
{
|
||||
*pelPtrMem = pelMem;
|
||||
pelPtrMem++;
|
||||
pelMem += CHROMASHIFT( m_uiWidth, ratioW );
|
||||
}
|
||||
}
|
||||
|
||||
/* Alloc ARGB memory */
|
||||
getMem1D( &m_pcARGB32, m_uiHeight * m_uiWidth * 4 );
|
||||
|
||||
m_puiHistogram = NULL;
|
||||
@@ -434,7 +413,7 @@ struct PlaYUVerFramePrivate
|
||||
m_uiHistoSegments = 1 << m_uiBitsPel;
|
||||
|
||||
if( m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_RGB ||
|
||||
m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_ARGB )
|
||||
m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_RGBA )
|
||||
m_uiHistoChannels = m_pcPelFormat->numberChannels + 1;
|
||||
else
|
||||
m_uiHistoChannels = m_pcPelFormat->numberChannels;
|
||||
@@ -455,7 +434,7 @@ struct PlaYUVerFramePrivate
|
||||
m_bHasHistogram = false;
|
||||
|
||||
if( m_pppcInputPel )
|
||||
freeImgMemory( m_pppcInputPel );
|
||||
xFreeMem( m_pppcInputPel );
|
||||
|
||||
if( m_pcARGB32 )
|
||||
freeMem1D( m_pcARGB32 );
|
||||
@@ -902,6 +881,8 @@ Void PlaYUVerFrame::frameToBuffer( Byte* output_buffer, Int iEndianness )
|
||||
|
||||
Void PlaYUVerFrame::fillRGBBuffer()
|
||||
{
|
||||
#define PEL_ARGB( a, r, g, b ) ( ( a & 0xff ) << 24 ) | ( ( r & 0xff ) << 16 ) | ( ( g & 0xff ) << 8 ) | ( b & 0xff )
|
||||
#define PEL_RGB( r, g, b ) PEL_ARGB( 0xffu, r, g, b )
|
||||
#define CLAMP_YUV2RGB( X ) X = X < 0 ? 0 : X > 255 ? 255 : X;
|
||||
#define YUV2RGB( iY, iU, iV, iR, iG, iB ) \
|
||||
iR = iY + ( ( 1436 * ( iV - 128 ) ) >> 10 ); \
|
||||
@@ -913,21 +894,15 @@ Void PlaYUVerFrame::fillRGBBuffer()
|
||||
|
||||
if( d->m_bHasRGBPel )
|
||||
return;
|
||||
Int iR, iG, iB;
|
||||
Int shiftBits = d->m_uiBitsPel - 8;
|
||||
UInt* pARGB = (UInt*)d->m_pcARGB32;
|
||||
if( d->m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_GRAY )
|
||||
{
|
||||
Pel* pY = d->m_pppcInputPel[LUMA][0];
|
||||
Int iY;
|
||||
for( UInt i = 0; i < d->m_uiHeight * d->m_uiWidth; i++ )
|
||||
{
|
||||
iY = *pY++;
|
||||
iY >>= shiftBits;
|
||||
iR = iY;
|
||||
iG = iY;
|
||||
iB = iY;
|
||||
*pARGB++ = PEL_RGB( iR, iG, iB );
|
||||
*pARGB++ = PEL_RGB( *pY, *pY, *pY );
|
||||
pY++;
|
||||
}
|
||||
}
|
||||
else if( d->m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_RGB )
|
||||
@@ -935,14 +910,17 @@ Void PlaYUVerFrame::fillRGBBuffer()
|
||||
Pel* pR = d->m_pppcInputPel[COLOR_R][0];
|
||||
Pel* pG = d->m_pppcInputPel[COLOR_G][0];
|
||||
Pel* pB = d->m_pppcInputPel[COLOR_B][0];
|
||||
|
||||
for( UInt i = 0; i < d->m_uiHeight * d->m_uiWidth; i++ )
|
||||
{
|
||||
iR = *pR++;
|
||||
iG = *pG++;
|
||||
iB = *pB++;
|
||||
*pARGB++ = PEL_RGB( ( iR >> shiftBits ), ( iG >> shiftBits ), ( iB >> shiftBits ) );
|
||||
}
|
||||
*pARGB++ = PEL_RGB( ( *pR++ ) >> shiftBits, ( *pG++ ) >> shiftBits, ( *pB++ ) >> shiftBits );
|
||||
}
|
||||
else if( d->m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_RGBA )
|
||||
{
|
||||
Pel* pR = d->m_pppcInputPel[COLOR_R][0];
|
||||
Pel* pG = d->m_pppcInputPel[COLOR_G][0];
|
||||
Pel* pB = d->m_pppcInputPel[COLOR_B][0];
|
||||
Pel* pA = d->m_pppcInputPel[COLOR_A][0];
|
||||
for( UInt i = 0; i < d->m_uiHeight * d->m_uiWidth; i++ )
|
||||
*pARGB++ = PEL_ARGB( ( *pA++ ) >> shiftBits, ( *pR++ ) >> shiftBits, ( *pG++ ) >> shiftBits, ( *pB++ ) >> shiftBits );
|
||||
}
|
||||
else if( d->m_pcPelFormat->colorSpace == PlaYUVerPixel::COLOR_YUV )
|
||||
{
|
||||
@@ -959,7 +937,7 @@ Void PlaYUVerFrame::fillRGBBuffer()
|
||||
|
||||
UInt y, x;
|
||||
Int i, j;
|
||||
for( y = 0; y<d->m_uiHeight>> d->m_pcPelFormat->log2ChromaHeight; y++ )
|
||||
for( y = 0; y < CHROMASHIFT( d->m_uiHeight, d->m_pcPelFormat->log2ChromaHeight ); y++ )
|
||||
{
|
||||
for( i = 0; i < 1 << d->m_pcPelFormat->log2ChromaHeight; i++ )
|
||||
{
|
||||
@@ -967,7 +945,7 @@ Void PlaYUVerFrame::fillRGBBuffer()
|
||||
pU = pLineU;
|
||||
pV = pLineV;
|
||||
pARGB = pARGBLine;
|
||||
for( x = 0; x<d->m_uiWidth>> d->m_pcPelFormat->log2ChromaWidth; x++ )
|
||||
for( x = 0; x < CHROMASHIFT( d->m_uiWidth, d->m_pcPelFormat->log2ChromaWidth ); x++ )
|
||||
{
|
||||
iU = *pU++;
|
||||
iU >>= shiftBits;
|
||||
@@ -1041,7 +1019,7 @@ Void PlaYUVerFrame::calcHistogram()
|
||||
{
|
||||
d->m_puiHistogram[*( data[j] ) + j * d->m_uiHistoSegments]++;
|
||||
}
|
||||
if( ( colorSpace == PlaYUVerPixel::COLOR_RGB || colorSpace == PlaYUVerPixel::COLOR_ARGB ) )
|
||||
if( ( colorSpace == PlaYUVerPixel::COLOR_RGB || colorSpace == PlaYUVerPixel::COLOR_RGBA ) )
|
||||
{
|
||||
PlaYUVerPixel currPixel( colorSpace, *( data[COLOR_R] ), *( data[COLOR_G] ), *( data[COLOR_B] ) );
|
||||
luma = currPixel.ConvertPixel( PlaYUVerPixel::COLOR_YUV ).Y();
|
||||
@@ -1090,7 +1068,7 @@ Int getRealHistoChannel( Int colorSpace, Int channel )
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PlaYUVerPixel::COLOR_ARGB:
|
||||
case PlaYUVerPixel::COLOR_RGBA:
|
||||
if( channel != COLOR_R && channel != COLOR_G && channel != COLOR_B && channel != COLOR_A && channel != LUMA )
|
||||
{
|
||||
return -1;
|
||||
@@ -1309,14 +1287,14 @@ Double PlaYUVerFrame::getStdDev( Int channel, UInt start, UInt end )
|
||||
|
||||
/*------------ original
|
||||
|
||||
for ( i = start ; i <= end ; i++ )
|
||||
{
|
||||
dev += ( i - mean ) * ( i - mean ) * d->m_puiHistogram[indexStart +i];
|
||||
}
|
||||
for ( i = start ; i <= end ; i++ )
|
||||
{
|
||||
dev += ( i - mean ) * ( i - mean ) * d->m_puiHistogram[indexStart +i];
|
||||
}
|
||||
|
||||
return sqrt( dev / count );
|
||||
return sqrt( dev / count );
|
||||
|
||||
-----------------------*/
|
||||
-----------------------*/
|
||||
|
||||
for( UInt i = start; i <= end; i++ )
|
||||
{
|
||||
|
||||
+5
-2
@@ -55,7 +55,7 @@ public:
|
||||
COLOR_YUV = 0, //!< YUV
|
||||
COLOR_RGB = 1, //!< RGB
|
||||
COLOR_GRAY = 2, //!< Grayscale
|
||||
COLOR_ARGB = 3, //!< RGB + Alpha
|
||||
COLOR_RGBA = 3, //!< RGB + Alpha
|
||||
COLOR_MAX = 255, //!< Accouunt for future formats
|
||||
};
|
||||
|
||||
@@ -130,7 +130,9 @@ public:
|
||||
RGBp,
|
||||
RGB24,
|
||||
BGR24,
|
||||
NUMBER_PEL_FORMATS
|
||||
RGBA,
|
||||
BGRA,
|
||||
PEL_FMT_MAX = 255,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -147,6 +149,7 @@ public:
|
||||
*/
|
||||
static std::vector<String> supportedPixelFormatListNames();
|
||||
static std::vector<String> supportedPixelFormatListNames( Int colorSpace );
|
||||
static Int numberOfFormats();
|
||||
static Int findPixelFormat( const String& name );
|
||||
|
||||
/**
|
||||
|
||||
+169
-116
@@ -53,148 +53,148 @@
|
||||
Void fillARGB32bufferYUV420p( Pel*** in, UChar* out, UInt width, UInt height, UInt depth )
|
||||
{
|
||||
#ifdef USE_SSE
|
||||
if( ( width % 16 ) == 0 )
|
||||
{
|
||||
uint8_t *yp = in[LUMA][0];
|
||||
uint8_t *up = in[CHROMA_U][0];
|
||||
uint8_t *vp = in[CHROMA_V][0];
|
||||
uint32_t suv = width >> 1;
|
||||
uint32_t *rgb = ( uint32_t* )out;
|
||||
if( ( width % 16 ) == 0 )
|
||||
{
|
||||
uint8_t *yp = in[LUMA][0];
|
||||
uint8_t *up = in[CHROMA_U][0];
|
||||
uint8_t *vp = in[CHROMA_V][0];
|
||||
uint32_t suv = width >> 1;
|
||||
uint32_t *rgb = ( uint32_t* )out;
|
||||
|
||||
__m128i y0r0, y0r1, u0, v0;
|
||||
__m128i y00r0, y01r0, y00r1, y01r1;
|
||||
__m128i u00, u01, v00, v01;
|
||||
__m128i rv00, rv01, gu00, gu01, gv00, gv01, bu00, bu01;
|
||||
__m128i r00, r01, g00, g01, b00, b01;
|
||||
__m128i rgb0123, rgb4567, rgb89ab, rgbcdef;
|
||||
__m128i gbgb;
|
||||
__m128i ysub, uvsub;
|
||||
__m128i zero, facy, facrv, facgu, facgv, facbu;
|
||||
__m128i *srcy128r0, *srcy128r1;
|
||||
__m128i *dstrgb128r0, *dstrgb128r1;
|
||||
__m64 *srcu64, *srcv64;
|
||||
UInt x, y;
|
||||
__m128i y0r0, y0r1, u0, v0;
|
||||
__m128i y00r0, y01r0, y00r1, y01r1;
|
||||
__m128i u00, u01, v00, v01;
|
||||
__m128i rv00, rv01, gu00, gu01, gv00, gv01, bu00, bu01;
|
||||
__m128i r00, r01, g00, g01, b00, b01;
|
||||
__m128i rgb0123, rgb4567, rgb89ab, rgbcdef;
|
||||
__m128i gbgb;
|
||||
__m128i ysub, uvsub;
|
||||
__m128i zero, facy, facrv, facgu, facgv, facbu;
|
||||
__m128i *srcy128r0, *srcy128r1;
|
||||
__m128i *dstrgb128r0, *dstrgb128r1;
|
||||
__m64 *srcu64, *srcv64;
|
||||
UInt x, y;
|
||||
|
||||
ysub = _mm_set1_epi32( 0x00100010 );
|
||||
uvsub = _mm_set1_epi32( 0x00800080 );
|
||||
ysub = _mm_set1_epi32( 0x00100010 );
|
||||
uvsub = _mm_set1_epi32( 0x00800080 );
|
||||
|
||||
facy = _mm_set1_epi32( 0x004a004a );
|
||||
facrv = _mm_set1_epi32( 0x00660066 );
|
||||
facgu = _mm_set1_epi32( 0x00190019 );
|
||||
facgv = _mm_set1_epi32( 0x00340034 );
|
||||
facbu = _mm_set1_epi32( 0x00810081 );
|
||||
facy = _mm_set1_epi32( 0x004a004a );
|
||||
facrv = _mm_set1_epi32( 0x00660066 );
|
||||
facgu = _mm_set1_epi32( 0x00190019 );
|
||||
facgv = _mm_set1_epi32( 0x00340034 );
|
||||
facbu = _mm_set1_epi32( 0x00810081 );
|
||||
|
||||
zero = _mm_set1_epi32( 0x00000000 );
|
||||
zero = _mm_set1_epi32( 0x00000000 );
|
||||
|
||||
for( y = 0; y < height; y += 2 )
|
||||
{
|
||||
for( y = 0; y < height; y += 2 )
|
||||
{
|
||||
|
||||
srcy128r0 = ( __m128i * )( yp + width * y );
|
||||
srcy128r1 = ( __m128i * )( yp + width * y + width );
|
||||
srcu64 = ( __m64 * )( up + suv * ( y / 2 ) );
|
||||
srcv64 = ( __m64 * )( vp + suv * ( y / 2 ) );
|
||||
srcy128r0 = ( __m128i * )( yp + width * y );
|
||||
srcy128r1 = ( __m128i * )( yp + width * y + width );
|
||||
srcu64 = ( __m64 * )( up + suv * ( y / 2 ) );
|
||||
srcv64 = ( __m64 * )( vp + suv * ( y / 2 ) );
|
||||
|
||||
dstrgb128r0 = ( __m128i * )( rgb + width * y );
|
||||
dstrgb128r1 = ( __m128i * )( rgb + width * y + width );
|
||||
dstrgb128r0 = ( __m128i * )( rgb + width * y );
|
||||
dstrgb128r1 = ( __m128i * )( rgb + width * y + width );
|
||||
|
||||
for( x = 0; x < width; x += 16 )
|
||||
{
|
||||
for( x = 0; x < width; x += 16 )
|
||||
{
|
||||
|
||||
u0 = _mm_loadl_epi64( ( __m128i * )srcu64 );
|
||||
srcu64++;
|
||||
v0 = _mm_loadl_epi64( ( __m128i * )srcv64 );
|
||||
srcv64++;
|
||||
u0 = _mm_loadl_epi64( ( __m128i * )srcu64 );
|
||||
srcu64++;
|
||||
v0 = _mm_loadl_epi64( ( __m128i * )srcv64 );
|
||||
srcv64++;
|
||||
|
||||
y0r0 = _mm_load_si128( srcy128r0++ );
|
||||
y0r1 = _mm_load_si128( srcy128r1++ );
|
||||
y0r0 = _mm_load_si128( srcy128r0++ );
|
||||
y0r1 = _mm_load_si128( srcy128r1++ );
|
||||
|
||||
// constant y factors
|
||||
y00r0 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpacklo_epi8( y0r0, zero ), ysub ), facy );
|
||||
y01r0 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpackhi_epi8( y0r0, zero ), ysub ), facy );
|
||||
y00r1 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpacklo_epi8( y0r1, zero ), ysub ), facy );
|
||||
y01r1 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpackhi_epi8( y0r1, zero ), ysub ), facy );
|
||||
// constant y factors
|
||||
y00r0 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpacklo_epi8( y0r0, zero ), ysub ), facy );
|
||||
y01r0 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpackhi_epi8( y0r0, zero ), ysub ), facy );
|
||||
y00r1 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpacklo_epi8( y0r1, zero ), ysub ), facy );
|
||||
y01r1 = _mm_mullo_epi16( _mm_sub_epi16( _mm_unpackhi_epi8( y0r1, zero ), ysub ), facy );
|
||||
|
||||
// expand u and v so they're aligned with y values
|
||||
u0 = _mm_unpacklo_epi8( u0, zero );
|
||||
u00 = _mm_sub_epi16( _mm_unpacklo_epi16( u0, u0 ), uvsub );
|
||||
u01 = _mm_sub_epi16( _mm_unpackhi_epi16( u0, u0 ), uvsub );
|
||||
// expand u and v so they're aligned with y values
|
||||
u0 = _mm_unpacklo_epi8( u0, zero );
|
||||
u00 = _mm_sub_epi16( _mm_unpacklo_epi16( u0, u0 ), uvsub );
|
||||
u01 = _mm_sub_epi16( _mm_unpackhi_epi16( u0, u0 ), uvsub );
|
||||
|
||||
v0 = _mm_unpacklo_epi8( v0, zero );
|
||||
v00 = _mm_sub_epi16( _mm_unpacklo_epi16( v0, v0 ), uvsub );
|
||||
v01 = _mm_sub_epi16( _mm_unpackhi_epi16( v0, v0 ), uvsub );
|
||||
v0 = _mm_unpacklo_epi8( v0, zero );
|
||||
v00 = _mm_sub_epi16( _mm_unpacklo_epi16( v0, v0 ), uvsub );
|
||||
v01 = _mm_sub_epi16( _mm_unpackhi_epi16( v0, v0 ), uvsub );
|
||||
|
||||
// common factors on both rows.
|
||||
rv00 = _mm_mullo_epi16( facrv, v00 );
|
||||
rv01 = _mm_mullo_epi16( facrv, v01 );
|
||||
gu00 = _mm_mullo_epi16( facgu, u00 );
|
||||
gu01 = _mm_mullo_epi16( facgu, u01 );
|
||||
gv00 = _mm_mullo_epi16( facgv, v00 );
|
||||
gv01 = _mm_mullo_epi16( facgv, v01 );
|
||||
bu00 = _mm_mullo_epi16( facbu, u00 );
|
||||
bu01 = _mm_mullo_epi16( facbu, u01 );
|
||||
// common factors on both rows.
|
||||
rv00 = _mm_mullo_epi16( facrv, v00 );
|
||||
rv01 = _mm_mullo_epi16( facrv, v01 );
|
||||
gu00 = _mm_mullo_epi16( facgu, u00 );
|
||||
gu01 = _mm_mullo_epi16( facgu, u01 );
|
||||
gv00 = _mm_mullo_epi16( facgv, v00 );
|
||||
gv01 = _mm_mullo_epi16( facgv, v01 );
|
||||
bu00 = _mm_mullo_epi16( facbu, u00 );
|
||||
bu01 = _mm_mullo_epi16( facbu, u01 );
|
||||
|
||||
// row 0
|
||||
r00 = _mm_srai_epi16( _mm_add_epi16( y00r0, rv00 ), 6 );
|
||||
r01 = _mm_srai_epi16( _mm_add_epi16( y01r0, rv01 ), 6 );
|
||||
g00 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y00r0, gu00 ), gv00 ), 6 );
|
||||
g01 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y01r0, gu01 ), gv01 ), 6 );
|
||||
b00 = _mm_srai_epi16( _mm_add_epi16( y00r0, bu00 ), 6 );
|
||||
b01 = _mm_srai_epi16( _mm_add_epi16( y01r0, bu01 ), 6 );
|
||||
// row 0
|
||||
r00 = _mm_srai_epi16( _mm_add_epi16( y00r0, rv00 ), 6 );
|
||||
r01 = _mm_srai_epi16( _mm_add_epi16( y01r0, rv01 ), 6 );
|
||||
g00 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y00r0, gu00 ), gv00 ), 6 );
|
||||
g01 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y01r0, gu01 ), gv01 ), 6 );
|
||||
b00 = _mm_srai_epi16( _mm_add_epi16( y00r0, bu00 ), 6 );
|
||||
b01 = _mm_srai_epi16( _mm_add_epi16( y01r0, bu01 ), 6 );
|
||||
|
||||
r00 = _mm_packus_epi16( r00, r01 );// rrrr.. saturated
|
||||
g00 = _mm_packus_epi16( g00, g01 );// gggg.. saturated
|
||||
b00 = _mm_packus_epi16( b00, b01 );// bbbb.. saturated
|
||||
r00 = _mm_packus_epi16( r00, r01 );// rrrr.. saturated
|
||||
g00 = _mm_packus_epi16( g00, g01 );// gggg.. saturated
|
||||
b00 = _mm_packus_epi16( b00, b01 );// bbbb.. saturated
|
||||
|
||||
r01 = _mm_unpacklo_epi8( r00, zero );// 0r0r..
|
||||
gbgb = _mm_unpacklo_epi8( b00, g00 );// gbgb..
|
||||
rgb0123 = _mm_unpacklo_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
rgb4567 = _mm_unpackhi_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
r01 = _mm_unpacklo_epi8( r00, zero );// 0r0r..
|
||||
gbgb = _mm_unpacklo_epi8( b00, g00 );// gbgb..
|
||||
rgb0123 = _mm_unpacklo_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
rgb4567 = _mm_unpackhi_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
|
||||
r01 = _mm_unpackhi_epi8( r00, zero );
|
||||
gbgb = _mm_unpackhi_epi8( b00, g00 );
|
||||
rgb89ab = _mm_unpacklo_epi16( gbgb, r01 );
|
||||
rgbcdef = _mm_unpackhi_epi16( gbgb, r01 );
|
||||
r01 = _mm_unpackhi_epi8( r00, zero );
|
||||
gbgb = _mm_unpackhi_epi8( b00, g00 );
|
||||
rgb89ab = _mm_unpacklo_epi16( gbgb, r01 );
|
||||
rgbcdef = _mm_unpackhi_epi16( gbgb, r01 );
|
||||
|
||||
_mm_store_si128( dstrgb128r0++, rgb0123 );
|
||||
_mm_store_si128( dstrgb128r0++, rgb4567 );
|
||||
_mm_store_si128( dstrgb128r0++, rgb89ab );
|
||||
_mm_store_si128( dstrgb128r0++, rgbcdef );
|
||||
_mm_store_si128( dstrgb128r0++, rgb0123 );
|
||||
_mm_store_si128( dstrgb128r0++, rgb4567 );
|
||||
_mm_store_si128( dstrgb128r0++, rgb89ab );
|
||||
_mm_store_si128( dstrgb128r0++, rgbcdef );
|
||||
|
||||
// row 1
|
||||
r00 = _mm_srai_epi16( _mm_add_epi16( y00r1, rv00 ), 6 );
|
||||
r01 = _mm_srai_epi16( _mm_add_epi16( y01r1, rv01 ), 6 );
|
||||
g00 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y00r1, gu00 ), gv00 ), 6 );
|
||||
g01 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y01r1, gu01 ), gv01 ), 6 );
|
||||
b00 = _mm_srai_epi16( _mm_add_epi16( y00r1, bu00 ), 6 );
|
||||
b01 = _mm_srai_epi16( _mm_add_epi16( y01r1, bu01 ), 6 );
|
||||
// row 1
|
||||
r00 = _mm_srai_epi16( _mm_add_epi16( y00r1, rv00 ), 6 );
|
||||
r01 = _mm_srai_epi16( _mm_add_epi16( y01r1, rv01 ), 6 );
|
||||
g00 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y00r1, gu00 ), gv00 ), 6 );
|
||||
g01 = _mm_srai_epi16( _mm_sub_epi16( _mm_sub_epi16( y01r1, gu01 ), gv01 ), 6 );
|
||||
b00 = _mm_srai_epi16( _mm_add_epi16( y00r1, bu00 ), 6 );
|
||||
b01 = _mm_srai_epi16( _mm_add_epi16( y01r1, bu01 ), 6 );
|
||||
|
||||
r00 = _mm_packus_epi16( r00, r01 );// rrrr.. saturated
|
||||
g00 = _mm_packus_epi16( g00, g01 );// gggg.. saturated
|
||||
b00 = _mm_packus_epi16( b00, b01 );// bbbb.. saturated
|
||||
r00 = _mm_packus_epi16( r00, r01 );// rrrr.. saturated
|
||||
g00 = _mm_packus_epi16( g00, g01 );// gggg.. saturated
|
||||
b00 = _mm_packus_epi16( b00, b01 );// bbbb.. saturated
|
||||
|
||||
r01 = _mm_unpacklo_epi8( r00, zero );// 0r0r..
|
||||
gbgb = _mm_unpacklo_epi8( b00, g00 );// gbgb..
|
||||
rgb0123 = _mm_unpacklo_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
rgb4567 = _mm_unpackhi_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
r01 = _mm_unpacklo_epi8( r00, zero );// 0r0r..
|
||||
gbgb = _mm_unpacklo_epi8( b00, g00 );// gbgb..
|
||||
rgb0123 = _mm_unpacklo_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
rgb4567 = _mm_unpackhi_epi16( gbgb, r01 );// 0rgb0rgb..
|
||||
|
||||
r01 = _mm_unpackhi_epi8( r00, zero );
|
||||
gbgb = _mm_unpackhi_epi8( b00, g00 );
|
||||
rgb89ab = _mm_unpacklo_epi16( gbgb, r01 );
|
||||
rgbcdef = _mm_unpackhi_epi16( gbgb, r01 );
|
||||
r01 = _mm_unpackhi_epi8( r00, zero );
|
||||
gbgb = _mm_unpackhi_epi8( b00, g00 );
|
||||
rgb89ab = _mm_unpacklo_epi16( gbgb, r01 );
|
||||
rgbcdef = _mm_unpackhi_epi16( gbgb, r01 );
|
||||
|
||||
_mm_store_si128( dstrgb128r1++, rgb0123 );
|
||||
_mm_store_si128( dstrgb128r1++, rgb4567 );
|
||||
_mm_store_si128( dstrgb128r1++, rgb89ab );
|
||||
_mm_store_si128( dstrgb128r1++, rgbcdef );
|
||||
_mm_store_si128( dstrgb128r1++, rgb0123 );
|
||||
_mm_store_si128( dstrgb128r1++, rgb4567 );
|
||||
_mm_store_si128( dstrgb128r1++, rgb89ab );
|
||||
_mm_store_si128( dstrgb128r1++, rgbcdef );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fillARGB32bufferYUV( in, out, width, height, depth, 1, 1 );
|
||||
}
|
||||
{
|
||||
fillARGB32bufferYUV( in, out, width, height, depth, 1, 1 );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -331,4 +331,57 @@ const std::map<int, PlaYUVerPixFmtDescriptor> g_PlaYUVerPixFmtDescriptorsMap = {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PlaYUVerFrame::BGR24,
|
||||
{
|
||||
"BGR",
|
||||
PlaYUVerPixel::COLOR_RGB,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
ADD_FFMPEG_PEL_FMT( AV_PIX_FMT_BGR24 ),
|
||||
{
|
||||
{0, 2, 3}, /* R */
|
||||
{0, 2, 2}, /* G */
|
||||
{0, 2, 1}, /* B */
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PlaYUVerFrame::RGBA,
|
||||
{
|
||||
"RGBA",
|
||||
PlaYUVerPixel::COLOR_RGBA,
|
||||
4,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
ADD_FFMPEG_PEL_FMT( AV_PIX_FMT_RGBA ),
|
||||
{
|
||||
{0, 3, 1}, /* R */
|
||||
{0, 3, 2}, /* G */
|
||||
{0, 3, 3}, /* B */
|
||||
{0, 3, 4}, /* A */
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
PlaYUVerFrame::BGRA,
|
||||
{
|
||||
"BGRA",
|
||||
PlaYUVerPixel::COLOR_RGBA,
|
||||
4,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
ADD_FFMPEG_PEL_FMT( AV_PIX_FMT_BGRA ),
|
||||
{
|
||||
{0, 3, 3}, /* R */
|
||||
{0, 3, 2}, /* G */
|
||||
{0, 3, 1}, /* B */
|
||||
{0, 3, 4}, /* A */
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
|
||||
#define CHROMARATIO( SIZE, RATIO ) ( RATIO > 1 ? ( ( SIZE + 1 ) / RATIO ) : SIZE )
|
||||
|
||||
#define PEL_RGB( r, g, b ) ( 0xffu << 24 ) | ( ( r & 0xff ) << 16 ) | ( ( g & 0xff ) << 8 ) | ( b & 0xff )
|
||||
|
||||
typedef struct PlaYUVerComponentDescriptor
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -199,7 +199,7 @@ Bool StreamHandlerLibav::openHandler( String strFilename, Bool bInput )
|
||||
}
|
||||
|
||||
m_iPixelFormat = PlaYUVerFrame::NO_FMT;
|
||||
for( Int i = 0; i < PlaYUVerFrame::NUMBER_PEL_FORMATS; i++ )
|
||||
for( Int i = 0; i < PlaYUVerFrame::numberOfFormats(); i++ )
|
||||
{
|
||||
if( g_PlaYUVerPixFmtDescriptorsMap.at( i ).ffmpegPelFormat == auxPixFmt )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user