📄 tsubtitledvd.cpp
字号:
/*
* Copyright (c) 2004-2006 Milan Cutka
* based of CSubpicInputPin by Gabest
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "stdafx.h"
#include "TsubtitleDVD.h"
#include "TsubtitlesTextpinDVD.h"
#include "ffdebug.h"
#include "TspuImage.h"
#include "Tstream.h"
#include "Tconfig.h"
#include "simd.h"
//=================================== TsubtitleDVDparent ==================================
TsubtitleDVDparent::TsubtitleDVDparent(void)
{
psphli=NULL;
fsppal=false;spon=true;
sppal[0].Y=0x00;sppal[0].U=sppal[0].V=0x80;
sppal[1].Y=0xe0;sppal[1].U=sppal[1].V=0x80;
sppal[2].Y=0x80;sppal[2].U=sppal[2].V=0x80;
sppal[3].Y=0x20;sppal[3].U=sppal[3].V=0x80;
delay=0;forced_subs=false;
custom_colors=false;tridx=0;
}
TspuPlane* TsubtitleDVDparent::allocPlanes(const CRect &r)
{
planes[0].alloc(r.Size(),1);
planes[1].alloc(r.Size(),1);
planes[2].alloc(r.Size(),2);
return planes;
}
const char* TsubtitleDVDparent::parseTimestamp(const char* &line,int &ms)
{
while (isspace(*line))
++line;
int forward=1;
if (line[0]=='+')
{
forward = 1;
line++;
}
else if (line[0]=='-')
{
forward = -1;
line++;
}
const char *p = line;
while (isdigit(*p))
++p;
if (p - line == 0)
return NULL;
int h = atoi(line);
if (*p != ':')
return NULL;
line = ++p;
while (isdigit(*p))
++p;
if (p - line == 0)
return NULL;
int m = atoi(line);
if (*p != ':')
return NULL;
line = ++p;
while (isdigit(*p))
++p;
if (p - line == 0)
return NULL;
int s = atoi(line);
if (*p != ':')
return NULL;
line = ++p;
while (isdigit(*p))
++p;
if (p - line == 0)
return NULL;
ms = (atoi(line) + 1000 * (s + 60 * (m + 60 * h)))*forward;
return p;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_delay(const char *line)
{
return parseTimestamp(line,delay)?PARSE_OK:PARSE_ERROR;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_size(const char *line)
{
// size: WWWxHHH
char *p;
while (isspace(*line))
++line;
if (!isdigit(*line))
return PARSE_ERROR;
rectOrig.dx=strtoul(line, &p, 10);
if (*p != 'x')
return PARSE_ERROR;
++p;
rectOrig.dy=strtoul(p, NULL, 10);
return PARSE_OK;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_origin(const char *line)
{
// org: X,Y
char *p;
while (isspace(*line))
++line;
if (!isdigit(*line))
return PARSE_ERROR;
rectOrig.x = strtoul(line, &p, 10);
if (*p != ',')
return PARSE_ERROR;
++p;
rectOrig.y = strtoul(p, NULL, 10);
return PARSE_OK;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_forced_subs(const char *line)
{
const char *p;
p = line;
while (isspace(*p))
++p;
if (_strnicmp("on",p,2) == 0)
{
forced_subs=true;
return PARSE_OK;
}
else if (_strnicmp("off",p,3) == 0)
{
forced_subs=false;
return PARSE_OK;
}
else
return PARSE_ERROR;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_palette(const char *line)
{
// palette: XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX
unsigned int n=0;
PARSE_RES res=PARSE_OK;;
while (1)
{
const char *p;
int r, g, b, tmp;
while (isspace(*line))
++line;
p = line;
while (isxdigit(*p))
++p;
if (p - line != 6)
{
res=PARSE_ERROR;
break;
}
tmp = strtoul(line, NULL, 16);
r = tmp >> 16 & 0xff;
g = tmp >> 8 & 0xff;
b = tmp & 0xff;
YUVcolor yuv(RGB(r,g,b),true);
sppal[n].Y=yuv.Y;
sppal[n].U=yuv.U;
sppal[n].V=yuv.V;
n++;
if (n == 16)
break;
if (*p == ',')
++p;
line = p;
}
if (n>0) fsppal=true;
return res;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_custom(const char *line)
{
//custom colors: OFF/ON(0/1)
if ((strncmp("ON", line + 15, 2) == 0)||strncmp("1", line + 15, 1) == 0)
{
custom_colors=1;
return PARSE_OK;
}
else if ((strncmp("OFF", line + 15, 3) == 0)||strncmp("0", line + 15, 1) == 0)
{
custom_colors=0;
return PARSE_OK;
}
else
return PARSE_ERROR;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_tridx(const char *line)
{
//tridx: XXXX
tridx = strtoul((line + 26), NULL, 16);
tridx = ((tridx&0x1000)>>12) | ((tridx&0x100)>>7) | ((tridx&0x10)>>2) | ((tridx&1)<<3);
return PARSE_OK;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_cuspal(const char *line)
{
//colors: XXXXXX, XXXXXX, XXXXXX, XXXXXX
unsigned int n;
n = 0;
line += 40;
while(1)
{
const char *p;
while (isspace(*line))
++line;
p=line;
while (isxdigit(*p))
++p;
if (p - line !=6)
return PARSE_ERROR;
unsigned int tmp = strtoul(line, NULL, 16);
int r = tmp >> 16 & 0xff;
int g = tmp >> 8 & 0xff;
int b = tmp & 0xff;
YUVcolor yuv(RGB(r,g,b));
cuspal[n].Y=yuv.Y;
cuspal[n].U=yuv.U;
cuspal[n].V=yuv.V;
n++;
if (n==4)
break;
if(*p == ',')
++p;
line = p;
}
return PARSE_OK;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse_one_line(const char *line)
{
if (strncmp("delay:", line, 6) == 0)
return idx_parse_delay( line + 6);
else if (strncmp("size:", line, 5) == 0)
return idx_parse_size( line + 5);
else if (strncmp("org:", line, 4) == 0)
return idx_parse_origin( line + 4);
else if (strncmp("palette:", line, 8) == 0)
return idx_parse_palette( line + 8);
else if (strncmp("custom colors:", line, 14) == 0) //custom colors: ON/OFF, tridx: XXXX, colors: XXXXXX, XXXXXX, XXXXXX,XXXXXX
if (idx_parse_custom(line)==PARSE_OK &&
idx_parse_tridx(line)==PARSE_OK &&
idx_parse_cuspal(line)==PARSE_OK)
return PARSE_OK;
else
return PARSE_ERROR;
else if (strncmp("forced subs:", line, 12) == 0)
return idx_parse_forced_subs( line + 12);
else
return PARSE_IGNORE;
}
TsubtitleDVDparent::PARSE_RES TsubtitleDVDparent::idx_parse(Tstream &fs)
{
while (1)
{
char line[4096];
if (!fs.fgets(line,4096))
return PARSE_OK;
if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#')
continue;
PARSE_RES res=idx_parse_one_line(line);
if (res==PARSE_IGNORE)
{
DPRINTF(_l("idx: ignoring %s"), line);
continue;
}
else if (res==PARSE_ERROR)
{
DPRINTF(_l("idx: ERROR in %s"), line);
return PARSE_ERROR;
}
}
}
//===================================== TsubtitleDVD ======================================
TsubtitleDVD::TsubtitleDVD(REFERENCE_TIME Istart,const unsigned char *Idata,unsigned int Idatalen,TsubtitleDVDparent *Iparent):parent(Iparent)
{
start=Istart;
stop=_I64_MAX;
memset(&sphli,0,sizeof(sphli));
forced=false;
data.append(Idata,Idatalen);
if (parent->psphli && start==pts2rt(parent->psphli->StartPTM))
psphli=new AM_PROPERTY_SPHLI(*parent->psphli);
else
psphli=NULL;
offset[0]=DWORD(-1);
parse();
changed=true;
image=NULL;
}
TsubtitleDVD::~TsubtitleDVD()
{
lines.clear();
}
BYTE TsubtitleDVD::getNibble(const BYTE *p,DWORD *offset,int &nField,int &fAligned)
{
BYTE ret=BYTE((p[offset[nField]]>>(fAligned<<2))&0x0f);
offset[nField]+=1-fAligned;
fAligned=!fAligned;
return ret;
}
BYTE TsubtitleDVD::getHalfNibble(const BYTE *p,DWORD *offset,int &nField,int &n)
{
BYTE ret=BYTE((p[offset[nField]]>>(n<<1))&0x03);
if (!n) offset[nField]++;
n=(n-1+4)&3;
return ret;
}
void TsubtitleDVD::drawPixel(const CPoint &pt,const AM_DVD_YUV &c,CRect &rectReal,TspuPlane plane[3]) const
{
/*
if (c.Reserved==0) return;
BYTE *p=&prefs.dst[0][pt.y*prefs.stride[0]+pt.x];
*p-=(*p-c.Y)*c.Reserved>>4;
// U/V is exchanged? weird but looks true when comparing the outputted colors from other decoders
p=&prefs.dst[1][(pt.y/2)*prefs.stride[1]+(pt.x+1)/2];
*p-=(*p-c.V)*c.Reserved>>4;
p=&prefs.dst[2][(pt.y/2)*prefs.stride[2]+(pt.x+1)/2];
*p-=(*p-c.U)*c.Reserved>>4;
*/
int ptx=pt.x,pty=pt.y;
if (c.Reserved!=0)
{
if (ptx<rectReal.left) rectReal.left=ptx;
if (ptx>rectReal.right) rectReal.right=ptx;
}
plane[0].c[pty*plane[0].stride+ptx]=c.Y;
plane[0].r[pty*plane[0].stride+ptx]=c.Reserved;
if (pty&1) return;
ptx=(ptx+1)/2;pty/=2;
plane[1].c[pty*plane[1].stride+ptx]=c.V;
plane[1].r[pty*plane[1].stride+ptx]=c.Reserved;
plane[2].c[pty*plane[2].stride+ptx]=c.U;
plane[2].r[pty*plane[2].stride+ptx]=c.Reserved;
}
void TsubtitleDVD::drawPixels(CPoint pt,int len,const AM_DVD_YUV &c,const CRect &rc,CRect &rectReal,TspuPlane plane[3]) const
{
if (pt.y < rc.top || pt.y >= rc.bottom) return;
if (pt.x < rc.left) {len -= rc.left - pt.x; pt.x = rc.left;}
if (pt.x + len > rc.right) len = rc.right - pt.x;
if (len <= 0 || pt.x >= rc.right) return;
if (c.Reserved==0)
{
if (IsRectEmpty(&rc))
return;
if (pt.y < rc.top || pt.y >= rc.bottom || pt.x+len < rc.left || pt.x >= rc.right)
return;
}
int y=pt.y-rc.top;
if (c.Reserved!=0)
{
if (y<rectReal.top) rectReal.top=y;
if (y>rectReal.bottom) rectReal.bottom=y;
}
while (len-->0)
{
drawPixel(CPoint(pt.x-rc.left,y),c,rectReal,plane);
pt.x++;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -