📄 tsubtitledvd.cpp
字号:
}
void TsubtitleDVD::createImage(const TspuPlane src[3],const CRect &rcclip,CRect rectReal,const TrenderedSubtitleLines::TprintPrefs &prefs) const
{
lines.clear();
rectReal.bottom++;rectReal.right++;
#ifdef __SSE2__
if (Tconfig::cpu_flags&FF_CPU_SSE2)
image=new TspuImageSimd<Tsse2>(src,rcclip,rectReal,parent->rectOrig,prefs);
else
#endif
image=new TspuImageSimd<Tmmx>(src,rcclip,rectReal,parent->rectOrig,prefs);
lines.add(new TrenderedSubtitleLine(image),NULL);
}
void TsubtitleDVD::linesprint(const TrenderedSubtitleLines::TprintPrefs &prefs) const
{
if (prefs.dvd || !prefs.vobchangeposition)
image->ownprint(prefs);
else
lines.print(prefs);
}
void TsubtitleDVD::print(REFERENCE_TIME time,bool wasseek,Tfont &f,bool forceChange,const TrenderedSubtitleLines::TprintPrefs &prefs) const
{
if (this->offset[0]==DWORD(-1))
return;
if (lines.empty() || changed)
{
changed=false;
const BYTE *p=&*data.begin();
DWORD offset[2]={this->offset[0],this->offset[1]};
AM_PROPERTY_SPHLI sphli=this->sphli;
CPoint pt(sphli.StartX, sphli.StartY);
CRect rc(pt, CPoint(sphli.StopX, sphli.StopY));
if (parent->rectOrig.dx==0)
parent->rectOrig=CRect(0,0,prefs.dx,prefs.dy);
CRect rcclip=parent->rectOrig;
rcclip&=rc;
if (psphli)
{
rcclip&=CRect(psphli->StartX,psphli->StartY,psphli->StopX,psphli->StopY);
sphli=*psphli;
}
TspuPlane *planes=parent->allocPlanes(rcclip);
DPRINTF(_l("rect: [%i,%i] - [%i,%i]"),rcclip.left,rcclip.top,rcclip.Width(),rcclip.Height());
AM_DVD_YUV pal[4];
pal[0]=parent->sppal[parent->fsppal?sphli.ColCon.backcol :0];pal[0].Reserved=sphli.ColCon.backcon;
pal[1]=parent->sppal[parent->fsppal?sphli.ColCon.patcol :1];pal[1].Reserved=sphli.ColCon.patcon;
pal[2]=parent->sppal[parent->fsppal?sphli.ColCon.emph1col:2];pal[2].Reserved=sphli.ColCon.emph1con;
pal[3]=parent->sppal[parent->fsppal?sphli.ColCon.emph2col:3];pal[3].Reserved=sphli.ColCon.emph2con;
int nField=0;
int fAligned=1;
DWORD end[2]={offset[1],(p[2]<<8)|p[3]};
CRect rectReal(INT_MAX/2,INT_MAX/2,INT_MIN/2,INT_MIN/2);
while ((nField==0 && offset[0]<end[0]) || (nField==1 && offset[1]<end[1]))
{
DWORD code;
if ((code=getNibble(p,offset,nField,fAligned))>=0x4 ||
(code=(code<<4) | getNibble(p,offset,nField,fAligned))>=0x10 ||
(code=(code<<4) | getNibble(p,offset,nField,fAligned))>=0x40 ||
(code=(code<<4) | getNibble(p,offset,nField,fAligned))>=0x100)
{
drawPixels(pt,code>>2,pal[code&3],rcclip,rectReal,planes);
if ((pt.x+=code>>2)<rc.right)
continue;
}
drawPixels(pt,rc.right-pt.x,pal[code&3],rcclip,rectReal,planes);
if (!fAligned) getNibble(p,offset,nField,fAligned); // align to byte
pt.x=rc.left;
pt.y++;
nField=1-nField;
}
DPRINTF(_l("rectReal: [%i,%i] - [%i,%i]"),rectReal.left,rectReal.top,rectReal.Width(),rectReal.Height());
createImage(planes,rcclip,rectReal,prefs);
}
linesprint(prefs);
}
void TsubtitleDVD::append(const unsigned char *Idata,unsigned int Idatalen)
{
data.append(Idata,Idatalen);
parse();
}
bool TsubtitleDVD::parse(void)
{
BYTE *p=&*data.begin();
WORD packetsize=short((p[0]<<8)|p[1]);
WORD datasize=short((p[2]<<8)|p[3]);
if (packetsize>data.size() || datasize>packetsize)
return false;
int i,next=datasize;
do
{
i=next;
int pts=(p[i]<<8)|p[i+1];i+=2;
next=(p[i]<<8)|p[i+1];i+=2;
if (next>packetsize || next<datasize)
return false;
for (bool fBreak=false;!fBreak;)
{
int len;
switch(p[i])
{
case 0x00:len=0;break;
case 0x01:len=0;break;
case 0x02:len=0;break;
case 0x03:len=2;break;
case 0x04:len=2;break;
case 0x05:len=6;break;
case 0x06:len=4;break;
default :len=0;break;
}
if (i+len>=packetsize)
{
DPRINTF(_l("Warning: Wrong subpicture parameter block ending"));
break;
}
switch (p[i++])
{
case 0x00: // forced start displaying
forced=true;
break;
case 0x01: // normal start displaying
forced=false;
break;
case 0x02: // stop displaying
stop=start+1024*pts2rt(pts);
break;
case 0x03:
sphli.ColCon.emph2col=p[i]>>4;
sphli.ColCon.emph1col=p[i]&0xf;
sphli.ColCon.patcol =p[i+1]>>4;
sphli.ColCon.backcol=p[i+1]&0xf;
i += 2;
break;
case 0x04:
sphli.ColCon.emph2con=p[i]>>4;
sphli.ColCon.emph1con=p[i]&0xf;
sphli.ColCon.patcon =p[i+1]>>4;
sphli.ColCon.backcon=p[i+1]&0xf;
i += 2;
break;
case 0x05:
sphli.StartX=USHORT((p[i]<<4) + (p[i+1]>>4));
sphli.StopX =USHORT(((p[i+1]&0x0f)<<8) + p[i+2]+1);
sphli.StartY=USHORT((p[i+3]<<4) + (p[i+4]>>4));
sphli.StopY =USHORT(((p[i+4]&0x0f)<<8) + p[i+5]+1);
i += 6;
break;
case 0x06:
offset[0]=(p[i]<<8)|p[i+1];i+=2;
offset[1]=(p[i]<<8)|p[i+1];i+=2;
break;
case 0xff: // end of ctrlblk
fBreak=true;
continue;
default: // skip this ctrlblk
fBreak=true;
break;
}
}
} while (i<=next && i<packetsize);
return true;
}
//===================================== TsubtitleSVCD =====================================
bool TsubtitleSVCD::parse(void)
{
BYTE *p=&*data.begin(),*p0=p;
if (data.size()<2)
return false;
WORD packetsize=WORD((p[0]<<8)|p[1]);p += 2;
if (packetsize>data.size())
return false;
bool duration=!!(*p++&0x04);
*p++; // unknown
if(duration)
{
stop=start+10000LL*((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3])/90;
p+=4;
}
sphli.StartX=sphli.StopX=USHORT((p[0]<<8)|p[1]);p+=2;
sphli.StartY=sphli.StopY=USHORT((p[0]<<8)|p[1]);p+=2;
sphli.StopX=USHORT(sphli.StopX+(p[0]<<8)|p[1]);p+=2;
sphli.StopY=USHORT(sphli.StopY+(p[0]<<8)|p[1]);p+=2;
for (int i=0;i<4;i++)
{
sppal[i].Y=*p++;
sppal[i].U=*p++;
sppal[i].V=*p++;
sppal[i].Reserved=UCHAR(*p++>>4);
}
if (*p++&0xc0)
p+=4; // duration of the shift operation should be here, but it is untested
offset[1]=(p[0]<<8)|p[1];p+=2;
offset[0]=DWORD(p-p0);
offset[1]+=offset[0];
return true;
}
void TsubtitleSVCD::print(REFERENCE_TIME time,bool wasseek,Tfont &f,bool forceChange,const TrenderedSubtitleLines::TprintPrefs &prefs) const
{
if (lines.empty() || changed)
{
changed=false;
const BYTE *p=&*data.begin();
DWORD offset[2]={this->offset[0],this->offset[1]};
CRect rcclip(0,0,prefs.dx,prefs.dy);
/* FIXME: startx/y looks to be wrong in the sample I tested (yes, this one too!)
CPoint pt(m_sphli.StartX, m_sphli.StartY);
CRect rc(pt, CPoint(m_sphli.StopX, m_sphli.StopY));
*/
CSize size(sphli.StopX - sphli.StartX, sphli.StopY - sphli.StartY);
CPoint pt((rcclip.Width() - size.cx) / 2, (rcclip.Height()*3 - size.cy*1) / 4);
CRect rc(pt, size);
int nField=0;
int n=3;
DWORD end[2]={offset[1],(p[2]<<8)|p[3]};
CRect rectReal(INT_MAX/2,INT_MAX/2,INT_MIN/2,INT_MIN/2);
TspuPlane *planes=parent->allocPlanes(rcclip);
while ((nField==0 && offset[0]<end[0]) || (nField==1 && offset[1]<end[1]))
{
BYTE code=getHalfNibble(p,offset,nField,n);
BYTE repeat=BYTE(1+(code==0?getHalfNibble(p,offset,nField,n):0));
drawPixels(pt,repeat,sppal[code&3],rcclip,rectReal,planes);
if ((pt.x+=repeat)<rc.right) continue;
while(n!=3)
getHalfNibble(p,offset,nField,n); // align to byte
pt.x=rc.left;
pt.y++;
nField=1-nField;
}
createImage(planes,rcclip,rectReal,prefs);
}
linesprint(prefs);
}
//===================================== TsubtitleCVD ======================================
bool TsubtitleCVD::parse(void)
{
const BYTE *p=&*data.begin();
WORD packetsize=WORD((p[0]<<8)|p[1]);
WORD datasize=WORD((p[2]<<8)|p[3]);
if (packetsize>data.size() || datasize>packetsize)
return false;
p=&*data.begin()+datasize;
for (int i=datasize,j=packetsize-4;i<=j;i+=4,p+=4)
switch(p[0])
{
case 0x0c:
break;
case 0x04:
stop=start+10000LL*((p[1]<<16)|(p[2]<<8)|p[3])/90;
break;
case 0x17:
sphli.StartX=USHORT(((p[1]&0x0f)<<6) + (p[2]>>2));
sphli.StartY=USHORT(((p[2]&0x03)<<8) + p[3]);
break;
case 0x1f:
sphli.StopX=USHORT(((p[1]&0x0f)<<6) + (p[2]>>2));
sphli.StopY=USHORT(((p[2]&0x03)<<8) + p[3]);
break;
case 0x24:
case 0x25:
case 0x26:
case 0x27:
sppal[0][p[0]-0x24].Y=p[1];
sppal[0][p[0]-0x24].U=p[2];
sppal[0][p[0]-0x24].V=p[3];
break;
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
sppal[1][p[0]-0x2c].Y=p[1];
sppal[1][p[0]-0x2c].U=p[2];
sppal[1][p[0]-0x2c].V=p[3];
break;
case 0x37:
sppal[0][3].Reserved=UCHAR(p[2]>>4);
sppal[0][2].Reserved=UCHAR(p[2]&0xf);
sppal[0][1].Reserved=UCHAR(p[3]>>4);
sppal[0][0].Reserved=UCHAR(p[3]&0xf);
break;
case 0x3f:
sppal[1][3].Reserved=UCHAR(p[2]>>4);
sppal[1][2].Reserved=UCHAR(p[2]&0xf);
sppal[1][1].Reserved=UCHAR(p[3]>>4);
sppal[1][0].Reserved=UCHAR(p[3]&0xf);
break;
case 0x47:
offset[0] = (p[2]<<8)|p[3];
break;
case 0x4f:
offset[1] = (p[2]<<8)|p[3];
break;
default:
break;
}
return true;
}
void TsubtitleCVD::print(REFERENCE_TIME time,bool wasseek,Tfont &f,bool forceChange,const TrenderedSubtitleLines::TprintPrefs &prefs) const
{
if (lines.empty() || changed)
{
changed=false;
const BYTE *p=&*data.begin();
DWORD offset[2]={this->offset[0],this->offset[1]};
CRect rcclip(0,0,prefs.dx,prefs.dy);
/* FIXME: startx/y looks to be wrong in the sample I tested
CPoint pt(m_sphli.StartX, m_sphli.StartY);
CRect rc(pt, CPoint(m_sphli.StopX, m_sphli.StopY));
*/
CSize size(sphli.StopX-sphli.StartX,sphli.StopY-sphli.StartY);
CPoint pt((rcclip.Width() - size.cx) / 2, (rcclip.Height()*3 - size.cy*1) / 4);
CRect rc(pt,size);
int nField=0;
int fAligned=1;
DWORD end[2]={offset[1],(p[2]<<8)|p[3]};
CRect rectReal(INT_MAX/2,INT_MAX/2,INT_MIN/2,INT_MIN/2);
TspuPlane *planes=parent->allocPlanes(rcclip);
while ((nField==0 && offset[0]<end[0]) || (nField==1 && offset[1]<end[1]))
{
BYTE code;
if ((code=getNibble(p,offset,nField,fAligned))>=0x4)
{
drawPixels(pt,code>>2,sppal[0][code&3],rcclip,rectReal,planes);
pt.x+=code>>2;
continue;
}
code=getNibble(p,offset,nField,fAligned);
drawPixels(pt,rc.right-pt.x,sppal[0][code&3],rcclip,rectReal,planes);
if (!fAligned)
getNibble(p,offset,nField,fAligned); // align to byte
pt.x=rc.left;
pt.y++;
nField=1-nField;
}
createImage(planes,rcclip,rectReal,prefs);
}
linesprint(prefs);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -