Could someone please point me to a detailed documentation of the vobsub format?
I'd like to directly change the DVD color palette in the .sub file (not by changing the .idx file).
This is necessary when merging two .sub files with different color palettes.
Since Txt2Vobsub can write .sub files, I figure you may know, TrustFm?
Vobsub format -- How to change color palette in .sub file
Moderators: george, roger_rabbit
I think some color indexes are stored in the .sub file, although the palette itself is in the .idx file.
That's why changing the palette in the .idx file will show weird colors.
So one way to correct the color problem is to change those indexes according to the indexes used in the first subtitle.
I think it will work if two palettes have the same colors but in different order, but not if the two palettes have completely different colors.
Do you think there are some other solutions?
P.S. sorry, probably i should have posted this in VobsubMuxer section ... please feel free to move it ...
That's why changing the palette in the .idx file will show weird colors.
So one way to correct the color problem is to change those indexes according to the indexes used in the first subtitle.
I think it will work if two palettes have the same colors but in different order, but not if the two palettes have completely different colors.
Do you think there are some other solutions?
P.S. sorry, probably i should have posted this in VobsubMuxer section ... please feel free to move it ...
Last edited by vince100 on Fri Jun 08, 2007 6:39 pm, edited 1 time in total.
On a second thought, I think it should work regardless.
Just use the color indexes of the first subtitle for the rest of subtitles.
Since the first one should look ok, the rest should look ok too, although maybe a bit different from the original.
The problem now is which bytes store those information (most likely it's two or four bytes with the color indexes of BG-TEXT-ANITALISING-OUTLINE).
Just use the color indexes of the first subtitle for the rest of subtitles.
Since the first one should look ok, the rest should look ok too, although maybe a bit different from the original.
The problem now is which bytes store those information (most likely it's two or four bytes with the color indexes of BG-TEXT-ANITALISING-OUTLINE).
hmm, this is more complicated than i thought --- it turned out each subtitle image has its own color and transparency info.
bool CVobSubImage::Decode(uchar* lpData, int packetsize, int datasize,
bool fCustomPal,
int tridx,
RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/,
bool fTrim)
{
GetPacketInfo(lpData, packetsize, datasize);
if(!Alloc(rect.Width(), rect.Height())) return(false);
lpPixels = lpTemp1;
nPlane = 0;
fAligned = 1;
this->fCustomPal = fCustomPal;
this->orgpal = orgpal;
this->tridx = tridx;
this->cuspal = cuspal;
CPoint p(rect.left, rect.top);
int end0 = nOffset[1];
int end1 = datasize;
while((nPlane == 0 && nOffset[0] < end0) || (nPlane == 1 && nOffset[1] < end1))
{
uint code;
if((code = GetNibble(lpData)) >= 0x4
|| (code = (code << 4) | GetNibble(lpData)) >= 0x10
|| (code = (code << 4) | GetNibble(lpData)) >= 0x40
|| (code = (code << 4) | GetNibble(lpData)) >= 0x100)
{
DrawPixels(p, code >> 2, code & 3);
if((p.x += code >> 2) < rect.right) continue;
}
DrawPixels(p, rect.right - p.x, code & 3);
if(!fAligned) GetNibble(lpData); // align to byte
p.x = rect.left;
p.y++;
nPlane = 1 - nPlane;
}
rect.bottom = min(p.y, rect.bottom);
if(fTrim) TrimSubImage();
return(true);
}
void CVobSubImage::GetPacketInfo(uchar* lpData, int packetsize, int datasize)
{
int nextctrlblk = datasize;
int i;
ushort pal = 0, tr = 0;
do
{
i = nextctrlblk;
int t = (lpData << 8) | lpData[i+1]; i += 2;
nextctrlblk = (lpData << 8) | lpData[i+1]; i += 2;
bool fBreak = false;
while(!fBreak)
{
int len = 0;
switch(lpData)
{
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)
{
TRACE(_T("Warning: Wrong subpicture parameter block ending\n"));
break;
}
switch(lpData[i++])
{
case 0x00: // forced start displaying
fForced = true;
break;
case 0x01: // start displaying
fForced = false;
break;
case 0x02: // stop displaying
nDisplayTime = 1024 * t / 90;
break;
case 0x03:
pal = (lpData << 8) | lpData[i+1]; i += 2;
break;
case 0x04:
tr = (lpData << 8) | lpData[i+1]; i += 2;
break;
case 0x05:
rect = CRect((lpData << 4) + (lpData[i+1] >> 4),
(lpData[i+3] << 4) + (lpData[i+4] >> 4),
((lpData[i+1] & 0x0f) << 8) + lpData[i+2] + 1,
((lpData[i+4] & 0x0f) << 8) + lpData[i+5] + 1);
i += 6;
break;
case 0x06:
nOffset[0] = (lpData << 8) + lpData[i+1]; i += 2;
nOffset[1] = (lpData << 8) + lpData[i+1]; i += 2;
break;
case 0xff: // end of ctrlblk
fBreak = true;
continue;
default: // skip this ctrlblk
fBreak = true;
break;
}
}
}
while(i <= nextctrlblk && i < packetsize && nextctrlblk < packetsize-4);
if(nextctrlblk > packetsize-4)
{
TRACE(_T("Warning: Wrong subpicture parameter block ending\n"));
}
for(i = 0; i < 4; i++)
{
this->pal.pal = (pal >> (i << 2)) & 0xf;
this->pal.tr = (tr >> (i << 2)) & 0xf;
}
}
bool CVobSubImage::Decode(uchar* lpData, int packetsize, int datasize,
bool fCustomPal,
int tridx,
RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/,
bool fTrim)
{
GetPacketInfo(lpData, packetsize, datasize);
if(!Alloc(rect.Width(), rect.Height())) return(false);
lpPixels = lpTemp1;
nPlane = 0;
fAligned = 1;
this->fCustomPal = fCustomPal;
this->orgpal = orgpal;
this->tridx = tridx;
this->cuspal = cuspal;
CPoint p(rect.left, rect.top);
int end0 = nOffset[1];
int end1 = datasize;
while((nPlane == 0 && nOffset[0] < end0) || (nPlane == 1 && nOffset[1] < end1))
{
uint code;
if((code = GetNibble(lpData)) >= 0x4
|| (code = (code << 4) | GetNibble(lpData)) >= 0x10
|| (code = (code << 4) | GetNibble(lpData)) >= 0x40
|| (code = (code << 4) | GetNibble(lpData)) >= 0x100)
{
DrawPixels(p, code >> 2, code & 3);
if((p.x += code >> 2) < rect.right) continue;
}
DrawPixels(p, rect.right - p.x, code & 3);
if(!fAligned) GetNibble(lpData); // align to byte
p.x = rect.left;
p.y++;
nPlane = 1 - nPlane;
}
rect.bottom = min(p.y, rect.bottom);
if(fTrim) TrimSubImage();
return(true);
}
void CVobSubImage::GetPacketInfo(uchar* lpData, int packetsize, int datasize)
{
int nextctrlblk = datasize;
int i;
ushort pal = 0, tr = 0;
do
{
i = nextctrlblk;
int t = (lpData << 8) | lpData[i+1]; i += 2;
nextctrlblk = (lpData << 8) | lpData[i+1]; i += 2;
bool fBreak = false;
while(!fBreak)
{
int len = 0;
switch(lpData)
{
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)
{
TRACE(_T("Warning: Wrong subpicture parameter block ending\n"));
break;
}
switch(lpData[i++])
{
case 0x00: // forced start displaying
fForced = true;
break;
case 0x01: // start displaying
fForced = false;
break;
case 0x02: // stop displaying
nDisplayTime = 1024 * t / 90;
break;
case 0x03:
pal = (lpData << 8) | lpData[i+1]; i += 2;
break;
case 0x04:
tr = (lpData << 8) | lpData[i+1]; i += 2;
break;
case 0x05:
rect = CRect((lpData << 4) + (lpData[i+1] >> 4),
(lpData[i+3] << 4) + (lpData[i+4] >> 4),
((lpData[i+1] & 0x0f) << 8) + lpData[i+2] + 1,
((lpData[i+4] & 0x0f) << 8) + lpData[i+5] + 1);
i += 6;
break;
case 0x06:
nOffset[0] = (lpData << 8) + lpData[i+1]; i += 2;
nOffset[1] = (lpData << 8) + lpData[i+1]; i += 2;
break;
case 0xff: // end of ctrlblk
fBreak = true;
continue;
default: // skip this ctrlblk
fBreak = true;
break;
}
}
}
while(i <= nextctrlblk && i < packetsize && nextctrlblk < packetsize-4);
if(nextctrlblk > packetsize-4)
{
TRACE(_T("Warning: Wrong subpicture parameter block ending\n"));
}
for(i = 0; i < 4; i++)
{
this->pal.pal = (pal >> (i << 2)) & 0xf;
this->pal.tr = (tr >> (i << 2)) & 0xf;
}
}