gps/GPSResources/tcpmp/common/helper_video.c

714 lines
15 KiB
C
Executable File

/*****************************************************************************
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: helper_video.c 548 2006-01-08 22:41:57Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#include "common.h"
bool_t EqSubtitle(const subtitle* a, const subtitle* b)
{
return a->FourCC == b->FourCC;
}
bool_t EqAudio(const audio* a, const audio* b)
{
return a->Bits == b->Bits &&
a->Channels == b->Channels &&
a->SampleRate == b->SampleRate &&
a->FracBits == b->FracBits &&
a->Flags == b->Flags &&
a->Format == b->Format;
}
bool_t EqFrac(const fraction* a, const fraction* b)
{
if (a->Den == b->Den && a->Num == b->Num)
return 1;
if (!a->Den) return b->Den==0;
if (!b->Den) return 0;
return (int64_t)b->Den * a->Num == (int64_t)a->Den * b->Num;
}
int BitMaskSize(uint32_t Mask)
{
int i;
for (i=0;Mask;++i)
Mask &= Mask - 1;
return i;
}
int BitMaskPos(uint32_t Mask)
{
int i;
for (i=0;Mask && !(Mask&1);++i)
Mask >>= 1;
return i;
}
int ScaleRound(int v,int Num,int Den)
{
int64_t i;
if (!Den)
return 0;
i = (int64_t)v * Num;
if (i<0)
i-=Den/2;
else
i+=Den/2;
i/=Den;
return (int)i;
}
void FillColor(uint8_t* Dst,int DstPitch,int x,int y,int Width,int Height,int BPP,int Value)
{
if (Width>0 && Height>0)
{
uint16_t *p16,*p16e;
uint32_t *p32,*p32e;
uint8_t* End;
Dst += y*DstPitch + (x*BPP)/8;
End = Dst + Height * DstPitch;
do
{
switch (BPP)
{
case 1:
Value &= 1;
memset(Dst,Value * 0xFF,Width >> 3);
break;
case 2:
Value &= 3;
memset(Dst,Value * 0x55,Width >> 2);
break;
case 4:
Value &= 15;
memset(Dst,Value * 0x11,Width >> 1);
break;
case 8:
memset(Dst,Value,Width);
break;
case 16:
p16 = (uint16_t*)Dst;
p16e = p16+Width;
for (;p16!=p16e;++p16)
*p16 = (uint16_t)Value;
break;
case 32:
p32 = (uint32_t*)Dst;
p32e = p32+Width;
for (;p32!=p32e;++p32)
*p32 = Value;
break;
}
Dst += DstPitch;
}
while (Dst != End);
}
}
bool_t EqBlitFX(const blitfx* a, const blitfx* b)
{
return a->Flags == b->Flags &&
a->Contrast == b->Contrast &&
a->Saturation == b->Saturation &&
a->Brightness == b->Brightness &&
a->Direction == b->Direction &&
a->RGBAdjust[0] == b->RGBAdjust[0] &&
a->RGBAdjust[1] == b->RGBAdjust[1] &&
a->RGBAdjust[2] == b->RGBAdjust[2] &&
a->ScaleX == b->ScaleX &&
a->ScaleY == b->ScaleY;
}
int CombineDir(int Src, int Blit, int Dst)
{
//order of transformations
// SrcMirror
// SrcSwap
// BlitSwap
// BlitMirror
// DstSwap
// DstMirror
//should be combined to a single
// Swap
// Mirror
if (Dst & DIR_SWAPXY)
{
if (Blit & DIR_MIRRORLEFTRIGHT)
Dst ^= DIR_MIRRORUPDOWN;
if (Blit & DIR_MIRRORUPDOWN)
Dst ^= DIR_MIRRORLEFTRIGHT;
}
else
Dst ^= Blit & (DIR_MIRRORUPDOWN|DIR_MIRRORLEFTRIGHT);
Dst ^= Blit & DIR_SWAPXY;
Dst ^= Src & DIR_SWAPXY;
if (Dst & DIR_SWAPXY)
{
if (Src & DIR_MIRRORLEFTRIGHT)
Dst ^= DIR_MIRRORUPDOWN;
if (Src & DIR_MIRRORUPDOWN)
Dst ^= DIR_MIRRORLEFTRIGHT;
}
else
Dst ^= Src & (DIR_MIRRORUPDOWN|DIR_MIRRORLEFTRIGHT);
return Dst;
}
int SurfaceRotate(const video* SrcFormat, const video* DstFormat,
const planes Src, planes Dst, int Dir)
{
blitfx FX;
memset(&FX,0,sizeof(FX));
FX.ScaleX = SCALE_ONE;
FX.ScaleY = SCALE_ONE;
FX.Direction = Dir;
return SurfaceCopy(SrcFormat,DstFormat,Src,Dst,&FX);
}
int SurfaceCopy(const video* SrcFormat, const video* DstFormat,
const planes Src, planes Dst, const blitfx* FX)
{
void* Blit;
rect SrcRect;
rect DstRect;
VirtToPhy(NULL,&SrcRect,SrcFormat);
VirtToPhy(NULL,&DstRect,DstFormat);
Blit = BlitCreate(DstFormat,SrcFormat,FX,NULL);
if (!Blit)
return ERR_NOT_SUPPORTED;
BlitAlign(Blit,&DstRect,&SrcRect);
BlitImage(Blit,Dst,*(const constplanes*)Src,NULL,-1,-1);
BlitRelease(Blit);
return ERR_NONE;
}
int SurfaceAlloc(planes Ptr, const video* p)
{
int i;
for (i=0;i<MAXPLANES;++i)
Ptr[i] = NULL;
if (p->Pixel.Flags & (PF_YUV420|PF_YUV422|PF_YUV444|PF_YUV410))
{
int x,y,s;
PlanarYUV(&p->Pixel,&x,&y,&s);
Ptr[0] = Alloc16(p->Height * p->Pitch);
Ptr[1] = Alloc16((p->Height>>y) * (p->Pitch>>s));
Ptr[2] = Alloc16((p->Height>>y) * (p->Pitch>>s));
if (!Ptr[0] || !Ptr[1] || !Ptr[2])
{
SurfaceFree(Ptr);
return ERR_OUT_OF_MEMORY;
}
return ERR_NONE;
}
Ptr[0] = Alloc16(GetImageSize(p));
return Ptr[0] ? ERR_NONE : ERR_OUT_OF_MEMORY;
}
void SurfaceFree(planes p)
{
int i;
for (i=0;i<MAXPLANES;++i)
{
Free16(p[i]);
p[i] = NULL;
}
}
int DefaultAspect(int Width,int Height)
{
return ASPECT_ONE; //todo?
}
void DefaultPitch(video* p)
{
p->Pitch = p->Width*GetBPP(&p->Pixel);
if (p->Pixel.Flags & PF_RGB)
p->Pitch = ((p->Pitch+31)>>5)*4; // dword align
else
p->Pitch = (p->Pitch+7)>>3; // byte align
}
void DefaultRGB(pixel* p, int BitCount,
int RBits, int GBits, int BBits,
int RGaps, int GGaps, int BGaps)
{
p->Flags = PF_RGB;
p->BitCount = BitCount;
p->BitMask[0] = ((1<<RBits)-1) << (RGaps+GBits+GGaps+BBits+BGaps);
p->BitMask[1] = ((1<<GBits)-1) << (GGaps+BBits+BGaps);
p->BitMask[2] = ((1<<BBits)-1) << (BGaps);
}
bool_t Compressed(const pixel* Fmt)
{
return (Fmt->Flags & PF_FOURCC) && !AnyYUV(Fmt);
}
bool_t PlanarYUV(const pixel* Fmt, int* x, int* y,int *s)
{
if (PlanarYUV420(Fmt))
{
if (x) *x = 1;
if (y) *y = 1;
if (s)
{
if (Fmt->Flags & PF_FOURCC &&
((Fmt->FourCC == FOURCC_IMC2) || (Fmt->FourCC == FOURCC_IMC4)))
*s = 0; // interleaved uv scanlines
else
*s = 1;
}
return 1;
}
if (PlanarYUV422(Fmt))
{
if (x) *x = 1;
if (s) *s = 1;
if (y) *y = 0;
return 1;
}
if (PlanarYUV444(Fmt))
{
if (x) *x = 0;
if (y) *y = 0;
if (s) *s = 0;
return 1;
}
if (PlanarYUV410(Fmt))
{
if (x) *x = 2;
if (s) *s = 2;
if (y) *y = 2;
return 1;
}
if (x) *x = 0;
if (y) *y = 0;
if (s) *s = 0;
return 0;
}
typedef struct rgbfourcc
{
uint32_t FourCC;
int BitCount;
uint32_t BitMask[3];
} rgbfourcc;
static const rgbfourcc RGBFourCC[] =
{
{ FOURCC_RGB32, 32, { 0xFF0000, 0xFF00, 0xFF }},
{ FOURCC_RGB24, 24, { 0xFF0000, 0xFF00, 0xFF }},
{ FOURCC_RGB16, 16, { 0xF800, 0x07E0, 0x001F }},
{ FOURCC_RGB15, 16, { 0x7C00, 0x03E0, 0x001F }},
{ FOURCC_BGR32, 32, { 0xFF, 0xFF00, 0xFF0000 }},
{ FOURCC_BGR24, 24, { 0xFF, 0xFF00, 0xFF0000 }},
{ FOURCC_BGR16, 16, { 0x001F, 0x07E0, 0xF800 }},
{ FOURCC_BGR15, 16, { 0x001F, 0x03E0, 0x7C00 }},
{0},
};
uint32_t DefFourCC(const pixel* Fmt)
{
uint32_t FourCC=0;
if (Fmt->Flags & PF_YUV420)
return FOURCC_I420;
if (Fmt->Flags & PF_YUV422)
return FOURCC_YV16;
if (Fmt->Flags & PF_YUV410)
return FOURCC_YUV9;
if (Fmt->Flags & PF_FOURCC)
{
FourCC = Fmt->FourCC;
if (FourCC == FOURCC_YVU9)
FourCC = FOURCC_YUV9;
if (FourCC == FOURCC_IYUV || FourCC == FOURCC_YV12)
FourCC = FOURCC_I420;
if (FourCC == FOURCC_YUNV || FourCC == FOURCC_V422 || FourCC == FOURCC_YUYV)
FourCC = FOURCC_YUY2;
if (FourCC == FOURCC_Y422 || FourCC == FOURCC_UYNV)
FourCC = FOURCC_UYVY;
}
else
if (Fmt->Flags & PF_RGB)
{
const rgbfourcc *i;
for (i=RGBFourCC;i->FourCC;++i)
if (i->BitCount == Fmt->BitCount &&
i->BitMask[0] == Fmt->BitMask[0] &&
i->BitMask[1] == Fmt->BitMask[1] &&
i->BitMask[2] == Fmt->BitMask[2])
{
FourCC = i->FourCC;
break;
}
}
return FourCC;
}
bool_t PlanarYUV420(const pixel* Fmt)
{
if (Fmt->Flags & PF_YUV420)
return 1;
return (Fmt->Flags & PF_FOURCC) &&
((Fmt->FourCC == FOURCC_YV12) ||
(Fmt->FourCC == FOURCC_IYUV) ||
(Fmt->FourCC == FOURCC_I420) ||
(Fmt->FourCC == FOURCC_IMC2) ||
(Fmt->FourCC == FOURCC_IMC4));
}
bool_t PlanarYUV410(const pixel* Fmt)
{
if (Fmt->Flags & PF_YUV410)
return 1;
return (Fmt->Flags & PF_FOURCC) &&
((Fmt->FourCC == FOURCC_YVU9) ||
(Fmt->FourCC == FOURCC_YUV9));
}
bool_t PlanarYUV422(const pixel* Fmt)
{
if (Fmt->Flags & PF_YUV422)
return 1;
return (Fmt->Flags & PF_FOURCC) && (Fmt->FourCC == FOURCC_YV16);
}
bool_t PlanarYUV444(const pixel* Fmt)
{
return (Fmt->Flags & PF_YUV444) != 0;
}
bool_t PackedYUV(const pixel* Fmt)
{
return (Fmt->Flags & PF_FOURCC) &&
((Fmt->FourCC == FOURCC_YUY2) ||
(Fmt->FourCC == FOURCC_YUNV) ||
(Fmt->FourCC == FOURCC_V422) ||
(Fmt->FourCC == FOURCC_YUYV) ||
(Fmt->FourCC == FOURCC_VYUY) ||
(Fmt->FourCC == FOURCC_UYVY) ||
(Fmt->FourCC == FOURCC_Y422) ||
(Fmt->FourCC == FOURCC_YVYU) ||
(Fmt->FourCC == FOURCC_UYNV));
}
bool_t AnyYUV(const pixel* Fmt)
{
return PlanarYUV420(Fmt) ||
PlanarYUV410(Fmt) ||
PlanarYUV422(Fmt) ||
PlanarYUV444(Fmt) ||
PackedYUV(Fmt);
}
uint32_t RGBToFormat(rgbval_t RGB, const pixel* Fmt)
{
uint32_t v;
int R,G,B;
int Y,U,V;
int Pos[3];
R = (INT32LE(RGB) >> 0) & 255;
G = (INT32LE(RGB) >> 8) & 255;
B = (INT32LE(RGB) >> 16) & 255;
if (AnyYUV(Fmt))
{
Y = ((2105 * R) + (4128 * G) + (802 * B))/0x2000 + 16;
V = ((3596 * R) - (3015 * G) - (582 * B))/0x2000 + 128;
U = (-(1212 * R) - (2384 * G) + (3596 * B))/0x2000 + 128;
if (Fmt->Flags & PF_INVERTED)
{
Y ^= 255;
U ^= 255;
V ^= 255;
}
v = (Fmt->BitMask[0] / 255) * Y;
v += (Fmt->BitMask[1] / 255) * U;
v += (Fmt->BitMask[2] / 255) * V;
}
else
{
if (Fmt->Flags & PF_INVERTED)
{
R ^= 255;
G ^= 255;
B ^= 255;
}
Pos[0] = BitMaskPos(Fmt->BitMask[0]) + BitMaskSize(Fmt->BitMask[0]);
Pos[1] = BitMaskPos(Fmt->BitMask[1]) + BitMaskSize(Fmt->BitMask[1]);
Pos[2] = BitMaskPos(Fmt->BitMask[2]) + BitMaskSize(Fmt->BitMask[2]);
v = ((R << Pos[0]) & (Fmt->BitMask[0] << 8)) |
((G << Pos[1]) & (Fmt->BitMask[1] << 8)) |
((B << Pos[2]) & (Fmt->BitMask[2] << 8));
v >>= 8;
}
return v;
}
void FillInfo(pixel* Fmt)
{
Fmt->BitCount = GetBPP(Fmt);
if (PlanarYUV(Fmt,NULL,NULL,NULL))
{
if (Fmt->Flags & (PF_YUV420|PF_YUV422|PF_YUV444|PF_YUV410))
{
Fmt->BitMask[0] = 0x000000FF;
Fmt->BitMask[1] = 0x0000FF00;
Fmt->BitMask[2] = 0x00FF0000;
}
else
switch (Fmt->FourCC)
{
case FOURCC_IMC4:
case FOURCC_I420:
case FOURCC_IYUV:
case FOURCC_YUV9:
Fmt->BitMask[0] = 0x000000FF;
Fmt->BitMask[1] = 0x0000FF00;
Fmt->BitMask[2] = 0x00FF0000;
break;
case FOURCC_IMC2:
case FOURCC_YV16:
case FOURCC_YV12:
case FOURCC_YVU9:
Fmt->BitMask[0] = 0x000000FF;
Fmt->BitMask[1] = 0x00FF0000;
Fmt->BitMask[2] = 0x0000FF00;
break;
}
}
else
if (PackedYUV(Fmt))
switch (Fmt->FourCC)
{
case FOURCC_YUY2:
case FOURCC_YUNV:
case FOURCC_V422:
case FOURCC_YUYV:
Fmt->BitMask[0] = 0x00FF00FF;
Fmt->BitMask[1] = 0x0000FF00;
Fmt->BitMask[2] = 0xFF000000;
break;
case FOURCC_YVYU:
Fmt->BitMask[0] = 0x00FF00FF;
Fmt->BitMask[1] = 0xFF000000;
Fmt->BitMask[2] = 0x0000FF00;
break;
case FOURCC_UYVY:
case FOURCC_Y422:
case FOURCC_UYNV:
Fmt->BitMask[0] = 0xFF00FF00;
Fmt->BitMask[1] = 0x000000FF;
Fmt->BitMask[2] = 0x00FF0000;
break;
}
}
int GetImageSize(const video* p)
{
int Size = p->Pitch * p->Height;
if (PlanarYUV420(&p->Pixel))
Size = (Size*3)/2; //1:0.25:0.25
else
if (PlanarYUV422(&p->Pixel))
Size *= 2; //1:0.5:0.5
else
if (PlanarYUV444(&p->Pixel))
Size *= 3; //1:1:1
return Size;
}
int GetBPP(const pixel* Fmt)
{
if (Fmt->Flags & (PF_RGB | PF_PALETTE))
return Fmt->BitCount;
if (PlanarYUV(Fmt,NULL,NULL,NULL))
return 8;
if (PackedYUV(Fmt))
return 16;
return 0;
}
bool_t EqPoint(const point* a, const point* b)
{
return a->x==b->x && a->y==b->y;
}
bool_t EqRect(const rect* a, const rect* b)
{
return a->x==b->x && a->y==b->y && a->Width==b->Width && a->Height==b->Height;
}
bool_t EqPixel(const pixel* a, const pixel* b)
{
if (a->Flags != b->Flags)
return 0;
if ((a->Flags & PF_PALETTE) &&
a->BitCount != b->BitCount)
return 0;
if ((a->Flags & PF_RGB) &&
(a->BitCount != b->BitCount ||
a->BitMask[0] != b->BitMask[0] ||
a->BitMask[1] != b->BitMask[1] ||
a->BitMask[2] != b->BitMask[2]))
return 0;
if ((a->Flags & PF_FOURCC) && a->FourCC != b->FourCC)
return 0;
return 1;
}
bool_t EqVideo(const video* a, const video* b)
{
// no direction check here!
return a->Width == b->Width &&
a->Height == b->Height &&
a->Pitch == b->Pitch &&
EqPixel(&a->Pixel,&b->Pixel);
}
void ClipRectPhy(rect* Physical, const video* p)
{
if (Physical->x < 0)
{
Physical->Width += Physical->x;
Physical->x = 0;
}
if (Physical->y < 0)
{
Physical->Height += Physical->y;
Physical->y = 0;
}
if (Physical->x + Physical->Width > p->Width)
{
Physical->Width = p->Width - Physical->x;
if (Physical->Width < 0)
{
Physical->Width = 0;
Physical->x = 0;
}
}
if (Physical->y + Physical->Height > p->Height)
{
Physical->Height = p->Height - Physical->y;
if (Physical->Height < 0)
{
Physical->Height = 0;
Physical->y = 0;
}
}
}
void VirtToPhy(const rect* Virtual, rect* Physical, const video* p)
{
if (Virtual)
{
*Physical = *Virtual;
if (p->Pixel.Flags & PF_PIXELDOUBLE)
{
Physical->x >>= 1;
Physical->y >>= 1;
Physical->Width >>= 1;
Physical->Height >>= 1;
}
if (p->Direction & DIR_SWAPXY)
SwapRect(Physical);
if (p->Direction & DIR_MIRRORLEFTRIGHT)
Physical->x = p->Width - Physical->x - Physical->Width;
if (p->Direction & DIR_MIRRORUPDOWN)
Physical->y = p->Height - Physical->y - Physical->Height;
ClipRectPhy(Physical,p);
}
else
{
Physical->x = 0;
Physical->y = 0;
Physical->Width = p->Width;
Physical->Height = p->Height;
}
}
void PhyToVirt(const rect* Physical, rect* Virtual, const video* p)
{
if (Physical)
*Virtual = *Physical;
else
{
Virtual->x = 0;
Virtual->y = 0;
Virtual->Width = p->Width;
Virtual->Height = p->Height;
}
if (p->Direction & DIR_MIRRORLEFTRIGHT)
Virtual->x = p->Width - Virtual->x - Virtual->Width;
if (p->Direction & DIR_MIRRORUPDOWN)
Virtual->y = p->Height - Virtual->y - Virtual->Height;
if (p->Direction & DIR_SWAPXY)
SwapRect(Virtual);
if (p->Pixel.Flags & PF_PIXELDOUBLE)
{
Virtual->x <<= 1;
Virtual->y <<= 1;
Virtual->Width <<= 1;
Virtual->Height <<= 1;
}
}