2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
25 #include "..\..\include\unrar\unrar.h"
26 #include "VobSubFile.h"
30 struct lang_type
{unsigned short id
; LPCSTR lang_long
;} lang_tbl
[] =
32 {'--', "(Not detected)"},
33 {'cc', "Closed Caption"},
41 {'az', "Azerbaijani"},
43 {'be', "Byelorussian"},
47 {'bn', "Bengali; Bangla"},
70 {'gd', "Scots Gaelic"},
80 {'ia', "Interlingua"},
82 {'ie', "Interlingue"},
94 {'kl', "Greenlandic"},
104 {'lt', "Lithuanian"},
105 {'lv', "Latvian, Lettish"},
108 {'mk', "Macedonian"},
118 {'nl', "Nederlands"},
121 {'om', "(Afan) Oromo"},
125 {'ps', "Pashto, Pushto"},
128 {'rm', "Rhaeto-Romance"},
132 {'rw', "Kinyarwanda"},
136 {'sh', "Serbo-Croatian"},
167 {'vi', "Vietnamese"},
171 {'yi', "Yiddish"}, // formerly ji
178 int find_lang(unsigned short id
)
180 int mid
, lo
= 0, hi
= countof(lang_tbl
) - 1;
184 mid
= (lo
+ hi
) >> 1;
185 if(id
< lang_tbl
[mid
].id
) hi
= mid
;
186 else if(id
> lang_tbl
[mid
].id
) lo
= mid
+ 1;
190 return(id
== lang_tbl
[lo
].id
? lo
: 0);
193 CString
FindLangFromId(WORD id
)
195 return CString(lang_tbl
[find_lang(id
)].lang_long
);
202 CVobSubFile::CVobSubFile(CCritSec
* pLock
)
203 : CSubPicProviderImpl(pLock
)
208 CVobSubFile::~CVobSubFile()
214 bool CVobSubFile::Copy(CVobSubFile
& vsf
)
218 *(CVobSubSettings
*)this = *(CVobSubSettings
*)&vsf
;
219 m_title
= vsf
.m_title
;
220 m_iLang
= vsf
.m_iLang
;
222 m_sub
.SetLength(vsf
.m_sub
.GetLength());
225 for(int i
= 0; i
< 32; i
++)
227 SubLang
& src
= vsf
.m_langs
[i
];
228 SubLang
& dst
= m_langs
[i
];
234 for(size_t j
= 0; j
< src
.subpos
.GetCount(); j
++)
236 SubPos
& sp
= src
.subpos
[j
];
237 if(!sp
.fValid
) continue;
239 if(sp
.filepos
!= vsf
.m_sub
.Seek(sp
.filepos
, CFile::begin
))
242 sp
.filepos
= m_sub
.GetPosition();
245 vsf
.m_sub
.Read(buff
, 2048);
246 m_sub
.Write(buff
, 2048);
248 WORD packetsize
= (buff
[buff
[0x16]+0x18]<<8) | buff
[buff
[0x16]+0x19];
250 for(int k
= 0, size
, sizeleft
= packetsize
- 4;
252 k
+= size
, sizeleft
-= size
)
254 int hsize
= buff
[0x16]+0x18 + ((buff
[0x15]&0x80) ? 4 : 0);
255 size
= min(sizeleft
, 2048 - hsize
);
259 while(vsf
.m_sub
.Read(buff
, 2048))
261 if(!(buff
[0x15]&0x80) && buff
[buff
[0x16]+0x17] == (i
|0x20)) break;
264 m_sub
.Write(buff
, 2048);
272 m_sub
.SetLength(m_sub
.GetPosition());
279 void CVobSubFile::TrimExtension(CString
& fn
)
281 int i
= fn
.ReverseFind('.');
284 CString ext
= fn
.Mid(i
).MakeLower();
285 if(ext
== _T(".ifo") || ext
== _T(".idx") || ext
== _T(".sub")
286 || ext
== _T(".sst") || ext
== _T(".son") || ext
== _T(".rar"))
291 bool CVobSubFile::Open(CString fn
)
300 if(!ReadIdx(fn
+ _T(".idx"), ver
))
303 if(ver
< 6 && !ReadIfo(fn
+ _T(".ifo")))
306 if(!ReadSub(fn
+ _T(".sub")) && !ReadRar(fn
+ _T(".rar")))
311 for(int i
= 0; i
< 32; i
++)
313 CAtlArray
<SubPos
>& sp
= m_langs
[i
].subpos
;
315 for(int j
= 0; j
< sp
.GetCount(); j
++)
317 sp
[j
].stop
= sp
[j
].start
;
318 sp
[j
].fForced
= false;
320 int packetsize
= 0, datasize
= 0;
321 BYTE
* buff
= GetPacket(j
, packetsize
, datasize
, i
);
324 m_img
.delay
= j
< (sp
.GetCount()-1) ? sp
[j
+1].start
- sp
[j
].start
: 3000;
325 m_img
.GetPacketInfo(buff
, packetsize
, datasize
);
326 if(j
< (sp
.GetCount()-1)) m_img
.delay
= min(m_img
.delay
, sp
[j
+1].start
- sp
[j
].start
);
328 sp
[j
].stop
= sp
[j
].start
+ m_img
.delay
;
329 sp
[j
].fForced
= m_img
.fForced
;
331 if(j
> 0 && sp
[j
-1].stop
> sp
[j
].start
)
332 sp
[j
-1].stop
= sp
[j
].start
;
347 bool CVobSubFile::Save(CString fn
, SubFormat sf
)
351 CVobSubFile
vsf(NULL
);
357 case VobSub
: return vsf
.SaveVobSub(fn
); break;
358 case WinSubMux
: return vsf
.SaveWinSubMux(fn
); break;
359 case Scenarist
: return vsf
.SaveScenarist(fn
); break;
360 case Maestro
: return vsf
.SaveMaestro(fn
); break;
367 void CVobSubFile::Close()
374 for(int i
= 0; i
< 32; i
++)
377 m_langs
[i
].name
.Empty();
378 m_langs
[i
].alt
.Empty();
379 m_langs
[i
].subpos
.RemoveAll();
385 bool CVobSubFile::ReadIdx(CString fn
, int& ver
)
393 int id
= -1, delay
= 0, vobid
= -1, cellid
= -1;
394 __int64 celltimestamp
= 0;
397 for(int line
= 0; !fError
&& f
.ReadString(str
); line
++)
403 TCHAR buff
[] = _T("VobSub index file, v");
405 const TCHAR
* s
= str
;
407 int i
= str
.Find(buff
);
408 if(i
< 0 || _stscanf(&s
[i
+_tcslen(buff
)], _T("%d"), &ver
) != 1
409 || ver
> VOBSUBIDXVER
)
411 AfxMessageBox(_T("Wrong file version!"));
416 else if(!str
.GetLength())
420 else if(str
[0] == _T('#'))
422 TCHAR buff
[] = _T("Vob/Cell ID:");
424 const TCHAR
* s
= str
;
426 int i
= str
.Find(buff
);
429 _stscanf(&s
[i
+_tcslen(buff
)], _T("%d, %d (PTS: %d)"), &vobid
, &cellid
, &celltimestamp
);
435 int i
= str
.Find(':');
438 CString entry
= str
.Left(i
).MakeLower();
442 if(str
.IsEmpty()) continue;
444 if(entry
== _T("size"))
447 if(_stscanf(str
, _T("%dx%d"), &x
, &y
) != 2) fError
= true;
451 else if(entry
== _T("org"))
453 if(_stscanf(str
, _T("%d,%d"), &m_x
, &m_y
) != 2) fError
= true;
454 else m_org
= CPoint(m_x
, m_y
);
456 else if(entry
== _T("scale"))
461 if(_stscanf(str
, _T("%d%%"), &scale
) != 1) fError
= true;
462 m_scale_x
= m_scale_y
= scale
;
466 if(_stscanf(str
, _T("%d%%,%d%%"), &m_scale_x
, &m_scale_y
) != 2) fError
= true;
469 else if(entry
== _T("alpha"))
471 if(_stscanf(str
, _T("%d"), &m_alpha
) != 1) fError
= true;
473 else if(entry
== _T("smooth"))
477 if(str
.Find(_T("old")) >= 0 || str
.Find(_T("2")) >= 0) m_fSmooth
= 2;
478 else if(str
.Find(_T("on")) >= 0 || str
.Find(_T("1")) >= 0) m_fSmooth
= 1;
479 else if(str
.Find(_T("off")) >= 0 || str
.Find(_T("0")) >= 0) m_fSmooth
= 0;
482 else if(entry
== _T("fadein/out"))
484 if(_stscanf(str
, _T("%d,%d"), &m_fadein
, &m_fadeout
) != 2) fError
= true;
486 else if(entry
== _T("align"))
491 for(CString token
= str
.Tokenize(_T(" "), i
);
492 j
< 3 && !fError
&& !token
.IsEmpty();
493 token
= str
.Tokenize(_T(" "), i
), j
++)
497 if(token
== _T("on") || token
== _T("1")) m_fAlign
= true;
498 else if(token
== _T("off") || token
== _T("0")) m_fAlign
= false;
503 if(token
== _T("at")) {j
--; continue;}
505 if(token
== _T("left")) m_alignhor
= 0;
506 else if(token
== _T("center")) m_alignhor
= 1;
507 else if(token
== _T("right")) m_alignhor
= 2;
512 if(token
== _T("top")) m_alignver
= 0;
513 else if(token
== _T("center")) m_alignver
= 1;
514 else if(token
== _T("bottom")) m_alignver
= 2;
519 else if(entry
== _T("time offset"))
521 bool fNegative
= false;
522 if(str
[0] == '-') fNegative
= true;
523 str
.TrimLeft(_T("+-"));
527 int n
= _stscanf(str
, _T("%d%c%d%c%d%c%d"), &hh
, &c
, &mm
, &c
, &ss
, &c
, &ms
);
530 ? hh
* (fNegative
? -1 : 1)
532 ? (hh
*60*60*1000 + mm
*60*1000 + ss
*1000 + ms
) * (fNegative
? -1 : 1)
535 else if(entry
== _T("forced subs"))
539 if(str
.Find(_T("on")) >= 0 || str
.Find(_T("1")) >= 0) m_fOnlyShowForcedSubs
= true;
540 else if(str
.Find(_T("off")) >= 0 || str
.Find(_T("0")) >= 0) m_fOnlyShowForcedSubs
= false;
543 else if(entry
== _T("langidx"))
545 if(_stscanf(str
, _T("%d"), &m_iLang
) != 1) fError
= true;
547 else if(entry
== _T("palette"))
549 if(_stscanf(str
, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"),
550 &m_orgpal
[0], &m_orgpal
[1], &m_orgpal
[2], &m_orgpal
[3],
551 &m_orgpal
[4], &m_orgpal
[5], &m_orgpal
[6], &m_orgpal
[7],
552 &m_orgpal
[8], &m_orgpal
[9], &m_orgpal
[10], &m_orgpal
[11],
553 &m_orgpal
[12], &m_orgpal
[13], &m_orgpal
[14], &m_orgpal
[15]
554 ) != 16) fError
= true;
556 else if(entry
== _T("custom colors"))
560 if(str
.Find(_T("on")) == 0 || str
.Find(_T("1")) == 0) m_fCustomPal
= true;
561 else if(str
.Find(_T("off")) == 0 || str
.Find(_T("0")) == 0) m_fCustomPal
= false;
564 i
= str
.Find(_T("tridx:"));
565 if(i
< 0) {fError
= true; continue;}
566 str
= str
.Mid(i
+ (int)_tcslen(_T("tridx:")));
569 if(_stscanf(str
, _T("%x"), &tridx
) != 1) {fError
= true; continue;}
570 tridx
= ((tridx
&0x1000)>>12) | ((tridx
&0x100)>>7) | ((tridx
&0x10)>>2) | ((tridx
&1)<<3);
572 i
= str
.Find(_T("colors:"));
573 if(i
< 0) {fError
= true; continue;}
574 str
= str
.Mid(i
+ (int)_tcslen(_T("colors:")));
577 if(_stscanf(str
, _T("%x,%x,%x,%x"), &pal
[0], &pal
[1], &pal
[2], &pal
[3]) != 4) {fError
= true; continue;}
579 SetCustomPal(pal
, tridx
);
581 else if(entry
== _T("id"))
585 int langid
= ((str
[0]&0xff)<<8)|(str
[1]&0xff);
587 i
= str
.Find(_T("index:"));
588 if(i
< 0) {fError
= true; continue;}
589 str
= str
.Mid(i
+ (int)_tcslen(_T("index:")));
591 if(_stscanf(str
, _T("%d"), &id
) != 1 || id
< 0 || id
>= 32) {fError
= true; continue;}
593 m_langs
[id
].id
= langid
;
594 m_langs
[id
].name
= lang_tbl
[find_lang(langid
)].lang_long
;
595 m_langs
[id
].alt
= lang_tbl
[find_lang(langid
)].lang_long
;
599 else if(id
>= 0 && entry
== _T("alt"))
601 m_langs
[id
].alt
= str
;
603 else if(id
>= 0 && entry
== _T("delay"))
605 bool fNegative
= false;
606 if(str
[0] == '-') fNegative
= true;
607 str
.TrimLeft(_T("+-"));
611 if(_stscanf(str
, _T("%d%c%d%c%d%c%d"), &hh
, &c
, &mm
, &c
, &ss
, &c
, &ms
) != 4+3) {fError
= true; continue;}
613 delay
+= (hh
*60*60*1000 + mm
*60*1000 + ss
*1000 + ms
) * (fNegative
? -1 : 1);
615 else if(id
>= 0 && entry
== _T("timestamp"))
621 sb
.celltimestamp
= celltimestamp
;
624 bool fNegative
= false;
625 if(str
[0] == '-') fNegative
= true;
626 str
.TrimLeft(_T("+-"));
630 if(_stscanf(str
, _T("%d%c%d%c%d%c%d"), &hh
, &c
, &mm
, &c
, &ss
, &c
, &ms
) != 4+3) {fError
= true; continue;}
632 sb
.start
= (hh
*60*60*1000 + mm
*60*1000 + ss
*1000 + ms
) * (fNegative
? -1 : 1) + delay
;
634 i
= str
.Find(_T("filepos:"));
635 if(i
< 0) {fError
= true; continue;}
636 str
= str
.Mid(i
+ (int)_tcslen(_T("filepos:")));
638 if(_stscanf(str
, _T("%I64x"), &sb
.filepos
) != 1) {fError
= true; continue;}
640 if(delay
< 0 && m_langs
[id
].subpos
.GetCount() > 0)
642 __int64 ts
= m_langs
[id
].subpos
[m_langs
[id
].subpos
.GetCount()-1].start
;
646 delay
+= (int)(ts
- sb
.start
);
651 m_langs
[id
].subpos
.Add(sb
);
659 bool CVobSubFile::ReadSub(CString fn
)
662 if(!f
.Open(fn
, CFile::modeRead
|CFile::typeBinary
|CFile::shareDenyWrite
))
665 m_sub
.SetLength(f
.GetLength());
670 while((len
= f
.Read(buff
, sizeof(buff
))) > 0 && *(DWORD
*)buff
== 0xba010000)
671 m_sub
.Write(buff
, len
);
676 static unsigned char* RARbuff
= NULL
;
677 static unsigned int RARpos
= 0;
679 static int PASCAL
MyProcessDataProc(unsigned char* Addr
, int Size
)
683 memcpy(&RARbuff
[RARpos
], Addr
, Size
);
689 bool CVobSubFile::ReadRar(CString fn
)
691 HMODULE h
= LoadLibrary(_T("unrar.dll"));
692 if(!h
) return(false);
694 RAROpenArchiveEx OpenArchiveEx
= (RAROpenArchiveEx
)GetProcAddress(h
, "RAROpenArchiveEx");
695 RARCloseArchive CloseArchive
= (RARCloseArchive
)GetProcAddress(h
, "RARCloseArchive");
696 RARReadHeaderEx ReadHeaderEx
= (RARReadHeaderEx
)GetProcAddress(h
, "RARReadHeaderEx");
697 RARProcessFile ProcessFile
= (RARProcessFile
)GetProcAddress(h
, "RARProcessFile");
698 RARSetChangeVolProc SetChangeVolProc
= (RARSetChangeVolProc
)GetProcAddress(h
, "RARSetChangeVolProc");
699 RARSetProcessDataProc SetProcessDataProc
= (RARSetProcessDataProc
)GetProcAddress(h
, "RARSetProcessDataProc");
700 RARSetPassword SetPassword
= (RARSetPassword
)GetProcAddress(h
, "RARSetPassword");
702 if(!(OpenArchiveEx
&& CloseArchive
&& ReadHeaderEx
&& ProcessFile
703 && SetChangeVolProc
&& SetProcessDataProc
&& SetPassword
))
709 struct RAROpenArchiveDataEx ArchiveDataEx
;
710 memset(&ArchiveDataEx
, 0, sizeof(ArchiveDataEx
));
712 ArchiveDataEx
.ArcNameW
= (LPTSTR
)(LPCTSTR
)fn
;
714 if(wcstombs(fnA
, fn
, fn
.GetLength()+1) == -1) fnA
[0] = 0;
715 ArchiveDataEx
.ArcName
= fnA
;
717 ArchiveDataEx
.ArcName
= (LPTSTR
)(LPCTSTR
)fn
;
719 ArchiveDataEx
.OpenMode
= RAR_OM_EXTRACT
;
720 ArchiveDataEx
.CmtBuf
= 0;
721 HANDLE hrar
= OpenArchiveEx(&ArchiveDataEx
);
728 SetProcessDataProc(hrar
, MyProcessDataProc
);
730 struct RARHeaderDataEx HeaderDataEx
;
731 HeaderDataEx
.CmtBuf
= NULL
;
733 while(ReadHeaderEx(hrar
, &HeaderDataEx
) == 0)
736 CString
subfn(HeaderDataEx
.FileNameW
);
738 CString
subfn(HeaderDataEx
.FileName
);
741 if(!subfn
.Right(4).CompareNoCase(_T(".sub")))
743 CAutoVectorPtr
<BYTE
> buff
;
744 if(!buff
.Allocate(HeaderDataEx
.UnpSize
))
754 if(ProcessFile(hrar
, RAR_TEST
, NULL
, NULL
))
762 m_sub
.SetLength(HeaderDataEx
.UnpSize
);
764 m_sub
.Write(buff
, HeaderDataEx
.UnpSize
);
773 ProcessFile(hrar
, RAR_SKIP
, NULL
, NULL
);
782 #define ReadBEdw(var) \
783 f.Read(&((BYTE*)&var)[3], 1); \
784 f.Read(&((BYTE*)&var)[2], 1); \
785 f.Read(&((BYTE*)&var)[1], 1); \
786 f.Read(&((BYTE*)&var)[0], 1); \
788 bool CVobSubFile::ReadIfo(CString fn)
791 if(!f
.Open(fn
, CFile::modeRead
|CFile::typeBinary
|CFile::shareDenyWrite
))
796 f
.Seek(0xc0+0x0c, SEEK_SET
);
801 f
.Seek(pos
*0x800 + 0x0c, CFile::begin
);
808 f
.Seek(pos
*0x800 + offset
+ 0xa4, CFile::begin
);
810 for(int i
= 0; i
< 16; i
++)
821 m_orgpal
[i
].rgbRed
= (BYTE
)min(max(1.0*y
+ 1.4022*(u
-128), 0), 255);
822 m_orgpal
[i
].rgbGreen
= (BYTE
)min(max(1.0*y
- 0.3456*(u
-128) - 0.7145*(v
-128), 0), 255);
823 m_orgpal
[i
].rgbBlue
= (BYTE
)min(max(1.0*y
+ 1.7710*(v
-128), 0) , 255);
829 bool CVobSubFile::WriteIdx(CString fn
)
832 if(!f
.Save(fn
, CTextFile::ASCII
))
836 str
.Format(_T("# VobSub index file, v%d (do not modify this line!)\n"), VOBSUBIDXVER
);
839 f
.WriteString(_T("# \n"));
840 f
.WriteString(_T("# To repair desyncronization, you can insert gaps this way:\n"));
841 f
.WriteString(_T("# (it usually happens after vob id changes)\n"));
842 f
.WriteString(_T("# \n"));
843 f
.WriteString(_T("#\t delay: [sign]hh:mm:ss:ms\n"));
844 f
.WriteString(_T("# \n"));
845 f
.WriteString(_T("# Where:\n"));
846 f
.WriteString(_T("#\t [sign]: +, - (optional)\n"));
847 f
.WriteString(_T("#\t hh: hours (0 <= hh)\n"));
848 f
.WriteString(_T("#\t mm/ss: minutes/seconds (0 <= mm/ss <= 59)\n"));
849 f
.WriteString(_T("#\t ms: milliseconds (0 <= ms <= 999)\n"));
850 f
.WriteString(_T("# \n"));
851 f
.WriteString(_T("#\t Note: You can't position a sub before the previous with a negative value.\n"));
852 f
.WriteString(_T("# \n"));
853 f
.WriteString(_T("# You can also modify timestamps or delete a few subs you don't like.\n"));
854 f
.WriteString(_T("# Just make sure they stay in increasing order.\n"));
855 f
.WriteString(_T("\n"));
856 f
.WriteString(_T("\n"));
860 f
.WriteString(_T("# Settings\n\n"));
862 f
.WriteString(_T("# Original frame size\n"));
863 str
.Format(_T("size: %dx%d\n\n"), m_size
.cx
, m_size
.cy
);
866 f
.WriteString(_T("# Origin, relative to the upper-left corner, can be overloaded by aligment\n"));
867 str
.Format(_T("org: %d, %d\n\n"), m_x
, m_y
);
870 f
.WriteString(_T("# Image scaling (hor,ver), origin is at the upper-left corner or at the alignment coord (x, y)\n"));
871 str
.Format(_T("scale: %d%%, %d%%\n\n"), m_scale_x
, m_scale_y
);
874 f
.WriteString(_T("# Alpha blending\n"));
875 str
.Format(_T("alpha: %d%%\n\n"), m_alpha
);
878 f
.WriteString(_T("# Smoothing for very blocky images (use OLD for no filtering)\n"));
879 str
.Format(_T("smooth: %s\n\n"), m_fSmooth
== 0 ? _T("OFF") : m_fSmooth
== 1 ? _T("ON") : _T("OLD"));
882 f
.WriteString(_T("# In millisecs\n"));
883 str
.Format(_T("fadein/out: %d, %d\n\n"), m_fadein
, m_fadeout
);
886 f
.WriteString(_T("# Force subtitle placement relative to (org.x, org.y)\n"));
887 str
.Format(_T("align: %s %s %s\n\n"),
888 m_fAlign
? _T("ON at") : _T("OFF at"),
889 m_alignhor
== 0 ? _T("LEFT") : m_alignhor
== 1 ? _T("CENTER") : m_alignhor
== 2 ? _T("RIGHT") : _T(""),
890 m_alignver
== 0 ? _T("TOP") : m_alignver
== 1 ? _T("CENTER") : m_alignver
== 2 ? _T("BOTTOM") : _T(""));
893 f
.WriteString(_T("# For correcting non-progressive desync. (in millisecs or hh:mm:ss:ms)\n"));
894 f
.WriteString(_T("# Note: Not effective in DirectVobSub, use \"delay: ... \" instead.\n"));
895 str
.Format(_T("time offset: %d\n\n"), m_toff
);
898 f
.WriteString(_T("# ON: displays only forced subtitles, OFF: shows everything\n"));
899 str
.Format(_T("forced subs: %s\n\n"), m_fOnlyShowForcedSubs
? _T("ON") : _T("OFF"));
902 f
.WriteString(_T("# The original palette of the DVD\n"));
903 str
.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n\n"),
904 *((unsigned int*)&m_orgpal
[0])&0xffffff,
905 *((unsigned int*)&m_orgpal
[1])&0xffffff,
906 *((unsigned int*)&m_orgpal
[2])&0xffffff,
907 *((unsigned int*)&m_orgpal
[3])&0xffffff,
908 *((unsigned int*)&m_orgpal
[4])&0xffffff,
909 *((unsigned int*)&m_orgpal
[5])&0xffffff,
910 *((unsigned int*)&m_orgpal
[6])&0xffffff,
911 *((unsigned int*)&m_orgpal
[7])&0xffffff,
912 *((unsigned int*)&m_orgpal
[8])&0xffffff,
913 *((unsigned int*)&m_orgpal
[9])&0xffffff,
914 *((unsigned int*)&m_orgpal
[10])&0xffffff,
915 *((unsigned int*)&m_orgpal
[11])&0xffffff,
916 *((unsigned int*)&m_orgpal
[12])&0xffffff,
917 *((unsigned int*)&m_orgpal
[13])&0xffffff,
918 *((unsigned int*)&m_orgpal
[14])&0xffffff,
919 *((unsigned int*)&m_orgpal
[15])&0xffffff);
922 int tridx
= (!!(m_tridx
&1))*0x1000 + (!!(m_tridx
&2))*0x100 + (!!(m_tridx
&4))*0x10 + (!!(m_tridx
&8));
924 f
.WriteString(_T("# Custom colors (transp idxs and the four colors)\n"));
925 str
.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06x\n\n"),
926 m_fCustomPal
? _T("ON") : _T("OFF"),
928 *((unsigned int*)&m_cuspal
[0])&0xffffff,
929 *((unsigned int*)&m_cuspal
[1])&0xffffff,
930 *((unsigned int*)&m_cuspal
[2])&0xffffff,
931 *((unsigned int*)&m_cuspal
[3])&0xffffff);
934 f
.WriteString(_T("# Language index in use\n"));
935 str
.Format(_T("langidx: %d\n\n"), m_iLang
);
940 for(int i
= 0; i
< 32; i
++)
942 SubLang
& sl
= m_langs
[i
];
944 CAtlArray
<SubPos
>& sp
= sl
.subpos
;
945 if(sp
.IsEmpty() && !sl
.id
) continue;
947 str
.Format(_T("# %s\n"), sl
.name
);
951 if(!sl
.id
) sl
.id
= '--';
952 str
.Format(_T("id: %c%c, index: %d\n"), sl
.id
>>8, sl
.id
&0xff, i
);
955 str
.Format(_T("# Decomment next line to activate alternative name in DirectVobSub / Windows Media Player 6.x\n"));
957 str
.Format(_T("alt: %s\n"), sl
.alt
);
958 if(sl
.name
== sl
.alt
) str
= _T("# ") + str
;
961 char vobid
= -1, cellid
= -1;
963 for(size_t j
= 0; j
< sp
.GetCount(); j
++)
965 if(!sp
[j
].fValid
) continue;
967 if(sp
[j
].vobid
!= vobid
|| sp
[j
].cellid
!= cellid
)
969 str
.Format(_T("# Vob/Cell ID: %d, %d (PTS: %d)\n"), sp
[j
].vobid
, sp
[j
].cellid
, sp
[j
].celltimestamp
);
972 cellid
= sp
[j
].cellid
;
975 str
.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64x\n"),
976 sp
[j
].start
< 0 ? _T("-") : _T(""),
977 abs(int((sp
[j
].start
/1000/60/60)%60)),
978 abs(int((sp
[j
].start
/1000/60)%60)),
979 abs(int((sp
[j
].start
/1000)%60)),
980 abs(int((sp
[j
].start
)%1000)),
985 f
.WriteString(_T("\n"));
991 bool CVobSubFile::WriteSub(CString fn
)
994 if(!f
.Open(fn
, CFile::modeCreate
|CFile::modeWrite
|CFile::typeBinary
|CFile::shareDenyWrite
))
997 if(m_sub
.GetLength() == 0)
998 return(true); // nothing to do...
1000 m_sub
.SeekToBegin();
1004 while((len
= m_sub
.Read(buff
, sizeof(buff
))) > 0 && *(DWORD
*)buff
== 0xba010000)
1012 BYTE
* CVobSubFile::GetPacket(int idx
, int& packetsize
, int& datasize
, int iLang
)
1016 if(iLang
< 0 || iLang
>= 32) iLang
= m_iLang
;
1017 CAtlArray
<SubPos
>& sp
= m_langs
[iLang
].subpos
;
1021 if(idx
< 0 || idx
>= sp
.GetCount())
1024 if(m_sub
.Seek(sp
[idx
].filepos
, CFile::begin
) != sp
[idx
].filepos
)
1028 if(sizeof(buff
) != m_sub
.Read(buff
, sizeof(buff
)))
1031 BYTE offset
= buff
[0x16];
1033 // let's check a few things to make sure...
1034 if(*(DWORD
*)&buff
[0x00] != 0xba010000
1035 || *(DWORD
*)&buff
[0x0e] != 0xbd010000
1036 || !(buff
[0x15] & 0x80)
1037 || (buff
[0x17] & 0xf0) != 0x20
1038 || (buff
[buff
[0x16] + 0x17] & 0xe0) != 0x20
1039 || (buff
[buff
[0x16] + 0x17] & 0x1f) != iLang
)
1042 packetsize
= (buff
[buff
[0x16] + 0x18] << 8) + buff
[buff
[0x16] + 0x19];
1043 datasize
= (buff
[buff
[0x16] + 0x1a] << 8) + buff
[buff
[0x16] + 0x1b];
1045 ret
= new BYTE
[packetsize
];
1048 int i
= 0, sizeleft
= packetsize
;
1051 i
+= size
, sizeleft
-= size
)
1053 int hsize
= 0x18 + buff
[0x16];
1054 size
= min(sizeleft
, 0x800 - hsize
);
1055 memcpy(&ret
[i
], &buff
[hsize
], size
);
1057 if(size
!= sizeleft
)
1059 while(m_sub
.Read(buff
, sizeof(buff
)))
1061 if(/*!(buff[0x15] & 0x80) &&*/ buff
[buff
[0x16] + 0x17] == (iLang
|0x20))
1067 if(i
!= packetsize
|| sizeleft
> 0)
1068 delete [] ret
, ret
= NULL
;
1075 bool CVobSubFile::GetFrame(int idx
, int iLang
)
1077 if(iLang
< 0 || iLang
>= 32) iLang
= m_iLang
;
1078 CAtlArray
<SubPos
>& sp
= m_langs
[iLang
].subpos
;
1080 if(idx
< 0 || idx
>= sp
.GetCount())
1083 if(m_img
.iLang
!= iLang
|| m_img
.iIdx
!= idx
)
1085 int packetsize
= 0, datasize
= 0;
1086 CAutoVectorPtr
<BYTE
> buff
;
1087 buff
.Attach(GetPacket(idx
, packetsize
, datasize
, iLang
));
1088 if(!buff
|| packetsize
<= 0 || datasize
<= 0) return(false);
1090 m_img
.start
= sp
[idx
].start
;
1091 m_img
.delay
= idx
< (sp
.GetCount()-1)
1092 ? sp
[idx
+1].start
- sp
[idx
].start
1095 bool ret
= m_img
.Decode(buff
, packetsize
, datasize
, m_fCustomPal
, m_tridx
, m_orgpal
, m_cuspal
, true);
1097 if(idx
< (sp
.GetCount()-1))
1098 m_img
.delay
= min(m_img
.delay
, sp
[idx
+1].start
- m_img
.start
);
1100 if(!ret
) return(false);
1103 m_img
.iLang
= iLang
;
1106 return(m_fOnlyShowForcedSubs
? m_img
.fForced
: true);
1109 bool CVobSubFile::GetFrameByTimeStamp(__int64 time
)
1111 return(GetFrame(GetFrameIdxByTimeStamp(time
)));
1114 int CVobSubFile::GetFrameIdxByTimeStamp(__int64 time
)
1116 if(m_iLang
< 0 || m_iLang
>= 32)
1119 CAtlArray
<SubPos
>& sp
= m_langs
[m_iLang
].subpos
;
1121 int i
= 0, j
= (int)sp
.GetCount() - 1, ret
= -1;
1123 if(j
>= 0 && time
>= sp
[j
].start
)
1128 int mid
= (i
+ j
) >> 1;
1129 int midstart
= (int)sp
[mid
].start
;
1131 if(time
== midstart
) {ret
= mid
; break;}
1132 else if(time
< midstart
) {ret
= -1; if(j
== mid
) mid
--; j
= mid
;}
1133 else if(time
> midstart
) {ret
= mid
; if(i
== mid
) mid
++; i
= mid
;}
1141 STDMETHODIMP
CVobSubFile::NonDelegatingQueryInterface(REFIID riid
, void** ppv
)
1143 CheckPointer(ppv
, E_POINTER
);
1150 __super::NonDelegatingQueryInterface(riid
, ppv
);
1155 // TODO: return segments for the fade-in/out time (with animated set to "true" of course)
1157 STDMETHODIMP_(POSITION
) CVobSubFile::GetStartPosition(REFERENCE_TIME rt
, double fps
)
1161 int i
= GetFrameIdxByTimeStamp(rt
);
1166 if(rt
>= (m_img
.start
+ m_img
.delay
))
1172 return((POSITION
)(i
+1));
1175 STDMETHODIMP_(POSITION
) CVobSubFile::GetNext(POSITION pos
)
1178 return(GetFrame(i
) ? (POSITION
)(i
+1) : NULL
);
1181 STDMETHODIMP_(REFERENCE_TIME
) CVobSubFile::GetStart(POSITION pos
, double fps
)
1184 return(GetFrame(i
) ? 10000i64
*m_img
.start
: 0);
1187 STDMETHODIMP_(REFERENCE_TIME
) CVobSubFile::GetStop(POSITION pos
, double fps
)
1190 return(GetFrame(i
) ? 10000i64
*(m_img
.start
+ m_img
.delay
) : 0);
1193 STDMETHODIMP_(bool) CVobSubFile::IsAnimated(POSITION pos
)
1198 STDMETHODIMP
CVobSubFile::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, RECT
& bbox
)
1200 if(spd
.bpp
!= 32) return E_INVALIDARG
;
1204 if(!GetFrame(GetFrameIdxByTimeStamp(rt
)))
1207 if(rt
>= (m_img
.start
+ m_img
.delay
))
1210 return __super::Render(spd
, bbox
);
1215 STDMETHODIMP
CVobSubFile::GetClassID(CLSID
* pClassID
)
1217 return pClassID
? *pClassID
= __uuidof(this), S_OK
: E_POINTER
;
1222 STDMETHODIMP_(int) CVobSubFile::GetStreamCount()
1224 int iStreamCount
= 0;
1225 for(int i
= 0; i
< 32; i
++)
1226 if(m_langs
[i
].subpos
.GetCount()) iStreamCount
++;
1227 return(iStreamCount
);
1230 STDMETHODIMP
CVobSubFile::GetStreamInfo(int iStream
, WCHAR
** ppName
, LCID
* pLCID
)
1232 for(int i
= 0; i
< 32; i
++)
1234 SubLang
& sl
= m_langs
[i
];
1236 if(sl
.subpos
.IsEmpty() || iStream
-- > 0)
1241 if(!(*ppName
= (WCHAR
*)CoTaskMemAlloc((sl
.alt
.GetLength()+1)*sizeof(WCHAR
))))
1242 return E_OUTOFMEMORY
;
1244 wcscpy(*ppName
, CStringW(sl
.alt
));
1249 *pLCID
= 0; // TODO: make lcid out of "sl.id"
1258 STDMETHODIMP_(int) CVobSubFile::GetStream()
1262 for(int i
= 0; i
< m_iLang
; i
++)
1263 if(!m_langs
[i
].subpos
.IsEmpty()) iStream
++;
1268 STDMETHODIMP
CVobSubFile::SetStream(int iStream
)
1270 for(int i
= 0; i
< 32; i
++)
1272 CAtlArray
<SubPos
>& sp
= m_langs
[i
].subpos
;
1274 if(sp
.IsEmpty() || iStream
-- > 0)
1284 return iStream
< 0 ? S_OK
: E_FAIL
;
1287 STDMETHODIMP
CVobSubFile::Reload()
1290 if(!CFile::GetStatus(m_title
+ _T(".idx"), s
)) return E_FAIL
;
1291 return !m_title
.IsEmpty() && Open(m_title
) ? S_OK
: E_FAIL
;
1296 static void PixelAtBiLinear(RGBQUAD
& c
, int x
, int y
, CVobSubImage
& src
)
1298 int w
= src
.rect
.Width(),
1299 h
= src
.rect
.Height();
1301 int x1
= (x
>> 16), y1
= (y
>> 16) * w
,
1302 x2
= min(x1
+ 1, w
-1), y2
= min(y1
+ w
, (h
-1)*w
);
1304 RGBQUAD
* ptr
= src
.lpPixels
;
1306 RGBQUAD c11
= ptr
[y1
+ x1
], c12
= ptr
[y1
+ x2
],
1307 c21
= ptr
[y2
+ x1
], c22
= ptr
[y2
+ x2
];
1309 __int64 u2
= x
& 0xffff,
1314 int v1u1
= int(v1
*u1
>> 16) * c11
.rgbReserved
,
1315 v1u2
= int(v1
*u2
>> 16) * c12
.rgbReserved
,
1316 v2u1
= int(v2
*u1
>> 16) * c21
.rgbReserved
,
1317 v2u2
= int(v2
*u2
>> 16) * c22
.rgbReserved
;
1319 c
.rgbRed
= (c11
.rgbRed
* v1u1
+ c12
.rgbRed
* v1u2
1320 + c21
.rgbRed
* v2u1
+ c22
.rgbRed
* v2u2
) >> 24;
1321 c
.rgbGreen
= (c11
.rgbGreen
* v1u1
+ c12
.rgbGreen
* v1u2
1322 + c21
.rgbGreen
* v2u1
+ c22
.rgbGreen
* v2u2
) >> 24;
1323 c
.rgbBlue
= (c11
.rgbBlue
* v1u1
+ c12
.rgbBlue
* v1u2
1324 + c21
.rgbBlue
* v2u1
+ c22
.rgbBlue
* v2u2
) >> 24;
1325 c
.rgbReserved
= (v1u1
+ v1u2
1326 + v2u1
+ v2u2
) >> 16;
1329 static void StretchBlt(SubPicDesc
& spd
, CRect dstrect
, CVobSubImage
& src
)
1331 if(dstrect
.IsRectEmpty()) return;
1333 if((dstrect
& CRect(0, 0, spd
.w
, spd
.h
)).IsRectEmpty()) return;
1335 int sw
= src
.rect
.Width(),
1336 sh
= src
.rect
.Height(),
1337 dw
= dstrect
.Width(),
1338 dh
= dstrect
.Height();
1342 srcdx
= (sw
<< 16) / dw
>> 1,
1343 srcdy
= (sh
<< 16) / dh
>> 1;
1345 if(dstrect
.left
< 0) {srcx
= -dstrect
.left
* (srcdx
<<1); dstrect
.left
= 0;}
1346 if(dstrect
.top
< 0) {srcy
= -dstrect
.top
* (srcdy
<<1); dstrect
.top
= 0;}
1347 if(dstrect
.right
> spd
.w
) {dstrect
.right
= spd
.w
;}
1348 if(dstrect
.bottom
> spd
.h
) {dstrect
.bottom
= spd
.h
;}
1350 if((dstrect
& CRect(0, 0, spd
.w
, spd
.h
)).IsRectEmpty()) return;
1352 dw
= dstrect
.Width();
1353 dh
= dstrect
.Height();
1355 for(int y
= dstrect
.top
; y
< dstrect
.bottom
; y
++, srcy
+= (srcdy
<<1))
1357 RGBQUAD
* ptr
= (RGBQUAD
*)&((BYTE
*)spd
.bits
)[y
*spd
.pitch
] + dstrect
.left
;
1358 RGBQUAD
* endptr
= ptr
+ dw
;
1360 for(int sx
= srcx
; ptr
< endptr
; sx
+= (srcdx
<<1), ptr
++)
1362 // PixelAtBiLinear(*ptr, sx, srcy, src);
1366 PixelAtBiLinear(cc
[0], sx
, srcy
, src
);
1367 PixelAtBiLinear(cc
[1], sx
+srcdx
, srcy
, src
);
1368 PixelAtBiLinear(cc
[2], sx
, srcy
+srcdy
, src
);
1369 PixelAtBiLinear(cc
[3], sx
+srcdx
, srcy
+srcdy
, src
);
1371 ptr
->rgbRed
= (cc
[0].rgbRed
+ cc
[1].rgbRed
+ cc
[2].rgbRed
+ cc
[3].rgbRed
) >> 2;
1372 ptr
->rgbGreen
= (cc
[0].rgbGreen
+ cc
[1].rgbGreen
+ cc
[2].rgbGreen
+ cc
[3].rgbGreen
) >> 2;
1373 ptr
->rgbBlue
= (cc
[0].rgbBlue
+ cc
[1].rgbBlue
+ cc
[2].rgbBlue
+ cc
[3].rgbBlue
) >> 2;
1374 ptr
->rgbReserved
= (cc
[0].rgbReserved
+ cc
[1].rgbReserved
+ cc
[2].rgbReserved
+ cc
[3].rgbReserved
) >> 2;
1376 ptr
->rgbRed
= ptr
->rgbRed
* ptr
->rgbReserved
>> 8;
1377 ptr
->rgbGreen
= ptr
->rgbGreen
* ptr
->rgbReserved
>> 8;
1378 ptr
->rgbBlue
= ptr
->rgbBlue
* ptr
->rgbReserved
>> 8;
1379 ptr
->rgbReserved
= ~ptr
->rgbReserved
;
1389 void CVobSubSettings::InitSettings()
1391 m_size
.SetSize(720, 480);
1392 m_toff
= m_x
= m_y
= 0;
1393 m_org
.SetPoint(0, 0);
1394 m_scale_x
= m_scale_y
= m_alpha
= 100;
1395 m_fadein
= m_fadeout
= 50;
1398 m_alignhor
= m_alignver
= 0;
1399 m_fOnlyShowForcedSubs
= false;
1400 m_fCustomPal
= false;
1402 memset(m_orgpal
, 0, sizeof(m_orgpal
));
1403 memset(m_cuspal
, 0, sizeof(m_cuspal
));
1406 bool CVobSubSettings::GetCustomPal(RGBQUAD
* cuspal
, int& tridx
)
1408 memcpy(cuspal
, m_cuspal
, sizeof(RGBQUAD
)*4);
1410 return(m_fCustomPal
);
1413 void CVobSubSettings::SetCustomPal(RGBQUAD
* cuspal
, int tridx
)
1415 memcpy(m_cuspal
, cuspal
, sizeof(RGBQUAD
)*4);
1416 m_tridx
= tridx
& 0xf;
1417 for(int i
= 0; i
< 4; i
++) m_cuspal
[i
].rgbReserved
= (tridx
&(1<<i
)) ? 0 : 0xff;
1421 void CVobSubSettings::GetDestrect(CRect
& r
)
1423 int w
= MulDiv(m_img
.rect
.Width(), m_scale_x
, 100);
1424 int h
= MulDiv(m_img
.rect
.Height(), m_scale_y
, 100);
1428 r
.left
= MulDiv(m_img
.rect
.left
, m_scale_x
, 100);
1429 r
.right
= MulDiv(m_img
.rect
.right
, m_scale_x
, 100);
1430 r
.top
= MulDiv(m_img
.rect
.top
, m_scale_y
, 100);
1431 r
.bottom
= MulDiv(m_img
.rect
.bottom
, m_scale_y
, 100);
1437 case 0: r
.left
= 0; r
.right
= w
; break; // left
1438 case 1: r
.left
= -(w
>>1); r
.right
= -(w
>>1) + w
; break; // center
1439 case 2: r
.left
= -w
; r
.right
= 0; break; // right
1441 r
.left
= MulDiv(m_img
.rect
.left
, m_scale_x
, 100);
1442 r
.right
= MulDiv(m_img
.rect
.right
, m_scale_x
, 100);
1448 case 0: r
.top
= 0; r
.bottom
= h
; break; // top
1449 case 1: r
.top
= -(h
>>1); r
.bottom
= -(h
>>1) + h
; break; // center
1450 case 2: r
.top
= -h
; r
.bottom
= 0; break; // bottom
1452 r
.top
= MulDiv(m_img
.rect
.top
, m_scale_y
, 100);
1453 r
.bottom
= MulDiv(m_img
.rect
.bottom
, m_scale_y
, 100);
1461 void CVobSubSettings::GetDestrect(CRect
& r
, int w
, int h
)
1465 r
.left
= MulDiv(r
.left
, w
, m_size
.cx
);
1466 r
.right
= MulDiv(r
.right
, w
, m_size
.cx
);
1467 r
.top
= MulDiv(r
.top
, h
, m_size
.cy
);
1468 r
.bottom
= MulDiv(r
.bottom
, h
, m_size
.cy
);
1471 void CVobSubSettings::SetAlignment(bool fAlign
, int x
, int y
, int hor
, int ver
)
1473 if(m_fAlign
= fAlign
)
1475 m_org
.x
= MulDiv(m_size
.cx
, x
, 100);
1476 m_org
.y
= MulDiv(m_size
.cy
, y
, 100);
1477 m_alignhor
= min(max(hor
, 0), 2);
1478 m_alignver
= min(max(ver
, 0), 2);
1489 HRESULT
CVobSubSettings::Render(SubPicDesc
& spd
, RECT
& bbox
)
1492 GetDestrect(r
, spd
.w
, spd
.h
);
1493 StretchBlt(spd
, r
, m_img
);
1495 CRenderedTextSubtitle rts(NULL);
1496 rts.CreateDefaultStyle(DEFAULT_CHARSET);
1497 rts.m_dstScreenSize.SetSize(m_size.cx, m_size.cy);
1499 m_img.Polygonize(assstr, false);
1500 REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay);
1501 rts.Add(assstr, true, rtStart, rtStop);
1502 rts.Render(spd, (rtStart+rtStop)/2, 25, r);
1504 r
&= CRect(CPoint(0, 0), CSize(spd
.w
, spd
.h
));
1506 return !r
.IsRectEmpty() ? S_OK
: S_FALSE
;
1509 /////////////////////////////////////////////////////////
1511 static bool CompressFile(CString fn
)
1513 if(GetVersion() < 0)
1518 HANDLE h
= CreateFile(fn
, GENERIC_WRITE
|GENERIC_READ
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, FILE_FLAG_SEQUENTIAL_SCAN
, 0);
1519 if(h
!= INVALID_HANDLE_VALUE
)
1521 USHORT us
= COMPRESSION_FORMAT_DEFAULT
;
1522 DWORD nBytesReturned
;
1523 b
= DeviceIoControl(h
, FSCTL_SET_COMPRESSION
, (LPVOID
)&us
, 2, NULL
, 0, (LPDWORD
)&nBytesReturned
, NULL
);
1530 bool CVobSubFile::SaveVobSub(CString fn
)
1532 return WriteIdx(fn
+ _T(".idx")) && WriteSub(fn
+ _T(".sub"));
1535 bool CVobSubFile::SaveWinSubMux(CString fn
)
1540 if(!f
.Open(fn
+ _T(".sub"), CFile::modeCreate
|CFile::modeWrite
|CFile::typeText
|CFile::shareDenyWrite
))
1545 CAutoVectorPtr
<BYTE
> p4bpp
;
1546 if(!p4bpp
.Allocate(720*576/2))
1549 CAtlArray
<SubPos
>& sp
= m_langs
[m_iLang
].subpos
;
1550 for(int i
= 0; i
< sp
.GetCount(); i
++)
1552 if(!GetFrame(i
)) continue;
1554 int pal
[4] = {0, 1, 2, 3};
1556 for(int j
= 0; j
< 5; j
++)
1558 if(j
== 4 || !m_img
.pal
[j
].tr
)
1561 memset(p4bpp
, (j
<<4)|j
, 720*576/2);
1562 pal
[j
] ^= pal
[0], pal
[0] ^= pal
[j
], pal
[j
] ^= pal
[0];
1567 int tr
[4] = {m_img
.pal
[pal
[0]].tr
, m_img
.pal
[pal
[1]].tr
, m_img
.pal
[pal
[2]].tr
, m_img
.pal
[pal
[3]].tr
};
1573 uipal
[0] = *((DWORD
*)&m_img
.orgpal
[m_img
.pal
[pal
[0]].pal
]);
1574 uipal
[1] = *((DWORD
*)&m_img
.orgpal
[m_img
.pal
[pal
[1]].pal
]);
1575 uipal
[2] = *((DWORD
*)&m_img
.orgpal
[m_img
.pal
[pal
[2]].pal
]);
1576 uipal
[3] = *((DWORD
*)&m_img
.orgpal
[m_img
.pal
[pal
[3]].pal
]);
1580 uipal
[0] = *((DWORD
*)&m_img
.cuspal
[pal
[0]]) & 0xffffff;
1581 uipal
[1] = *((DWORD
*)&m_img
.cuspal
[pal
[1]]) & 0xffffff;
1582 uipal
[2] = *((DWORD
*)&m_img
.cuspal
[pal
[2]]) & 0xffffff;
1583 uipal
[3] = *((DWORD
*)&m_img
.cuspal
[pal
[3]]) & 0xffffff;
1586 CAtlMap
<DWORD
,BYTE
> palmap
;
1587 palmap
[uipal
[0]] = 0;
1588 palmap
[uipal
[1]] = 1;
1589 palmap
[uipal
[2]] = 2;
1590 palmap
[uipal
[3]] = 3;
1592 uipal
[0] = 0xff; // blue background
1594 int w
= m_img
.rect
.Width()-2;
1595 int h
= m_img
.rect
.Height()-2;
1596 int pitch
= (((w
+1)>>1) + 3) & ~3;
1598 for(int y
= 0; y
< h
; y
++)
1600 DWORD
* p
= (DWORD
*)&m_img
.lpPixels
[(y
+1)*(w
+2)+1];
1602 for(int x
= 0; x
< w
; x
++, p
++)
1608 DWORD uic
= *p
& 0xffffff;
1609 palmap
.Lookup(uic
, c
);
1612 BYTE
& c4bpp
= p4bpp
[(h
-y
-1)*pitch
+(x
>>1)];
1613 c4bpp
= (x
&1) ? ((c4bpp
&0xf0)|c
) : ((c4bpp
&0x0f)|(c
<<4));
1617 int t1
= m_img
.start
, t2
= t1
+ m_img
.delay
/*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/;
1621 if(t2
<= 0) continue;
1625 bmpfn
.Format(_T("%s_%06d.bmp"), fn
, i
+1);
1628 str
.Format(_T("%s\t%02d:%02d:%02d:%02d %02d:%02d:%02d:%02d\t%03d %03d %03d %03d %d %d %d %d\n"),
1630 t1
/1000/60/60, (t1
/1000/60)%60, (t1
/1000)%60, (t1
%1000)/10,
1631 t2
/1000/60/60, (t2
/1000/60)%60, (t2
/1000)%60, (t2
%1000)/10,
1632 m_img
.rect
.Width(), m_img
.rect
.Height(), m_img
.rect
.left
, m_img
.rect
.top
,
1633 (tr
[0]<<4)|tr
[0], (tr
[1]<<4)|tr
[1], (tr
[2]<<4)|tr
[2], (tr
[3]<<4)|tr
[3]);
1636 BITMAPFILEHEADER fhdr
=
1639 sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
) + 16*sizeof(RGBQUAD
) + pitch
*h
,
1641 sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
) + 16*sizeof(RGBQUAD
)
1644 BITMAPINFOHEADER ihdr
=
1646 sizeof(BITMAPINFOHEADER
),
1654 if(bmp
.Open(bmpfn
, CFile::modeCreate
|CFile::modeWrite
|CFile::typeBinary
|CFile::shareDenyWrite
))
1656 bmp
.Write(&fhdr
, sizeof(fhdr
));
1657 bmp
.Write(&ihdr
, sizeof(ihdr
));
1658 bmp
.Write(uipal
, sizeof(RGBQUAD
)*16);
1659 bmp
.Write(p4bpp
, pitch
*h
);
1662 CompressFile(bmpfn
);
1669 bool CVobSubFile::SaveScenarist(CString fn
)
1674 if(!f
.Open(fn
+ _T(".sst"), CFile::modeCreate
|CFile::modeWrite
|CFile::typeText
|CFile::shareDenyWrite
))
1679 fn
.Replace('\\', '/');
1680 CString title
= fn
.Mid(fn
.ReverseFind('/')+1);
1682 TCHAR buff
[MAX_PATH
], * pFilePart
= buff
;
1683 if(GetFullPathName(fn
, MAX_PATH
, buff
, &pFilePart
) == 0)
1686 CString fullpath
= CString(buff
).Left(pFilePart
- buff
);
1687 fullpath
.TrimRight(_T("\\/"));
1688 if(fullpath
.IsEmpty())
1692 str
+= _T("st_format\t2\n");
1693 str
+= _T("Display_Start\t%s\n");
1694 str
+= _T("TV_Type\t\t%s\n");
1695 str
+= _T("Tape_Type\tNON_DROP\n");
1696 str
+= _T("Pixel_Area\t(0 %d)\n");
1697 str
+= _T("Directory\t%s\n");
1698 str
+= _T("Subtitle\t%s\n");
1699 str
+= _T("Display_Area\t(0 2 719 %d)\n");
1700 str
+= _T("Contrast\t(15 15 15 0)\n");
1702 str
+= _T("PA\t(0 0 255 - - - )\n");
1703 str
+= _T("E1\t(255 0 0 - - - )\n");
1704 str
+= _T("E2\t(0 0 0 - - - )\n");
1705 str
+= _T("BG\t(255 255 255 - - - )\n");
1707 str
+= _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n");
1709 !m_fOnlyShowForcedSubs
? _T("non_forced") : _T("forced"),
1710 m_size
.cy
== 480 ? _T("NTSC") : _T("PAL"),
1714 m_size
.cy
== 480 ? 479 : 574);
1716 f
.WriteString(str2
);
1740 BITMAPFILEHEADER fhdr
=
1743 sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
) + 16*sizeof(RGBQUAD
) + 360*(m_size
.cy
-2),
1745 sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
) + 16*sizeof(RGBQUAD
)
1748 BITMAPINFOHEADER ihdr
=
1750 sizeof(BITMAPINFOHEADER
),
1751 720, m_size
.cy
-2, 1, 4, 0,
1757 bool fCustomPal
= m_fCustomPal
;
1758 m_fCustomPal
= true;
1759 RGBQUAD tempCusPal
[4], newCusPal
[4+12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}};
1760 memcpy(tempCusPal
, m_cuspal
, sizeof(tempCusPal
));
1761 memcpy(m_cuspal
, newCusPal
, sizeof(m_cuspal
));
1763 CAutoVectorPtr
<BYTE
> p4bpp
;
1764 if(!p4bpp
.Allocate((m_size
.cy
-2)*360))
1769 for(int i
= 0; i
< 16; i
++)
1771 int idx
= 0, maxdif
= 255*255*3+1;
1773 for(int j
= 0; j
< 16 && maxdif
; j
++)
1775 int rdif
= pal
[j
].rgbRed
- m_orgpal
[i
].rgbRed
;
1776 int gdif
= pal
[j
].rgbGreen
- m_orgpal
[i
].rgbGreen
;
1777 int bdif
= pal
[j
].rgbBlue
- m_orgpal
[i
].rgbBlue
;
1779 int dif
= rdif
*rdif
+ gdif
*gdif
+ bdif
*bdif
;
1780 if(dif
< maxdif
) {maxdif
= dif
; idx
= j
;}
1783 colormap
[i
] = idx
+1;
1786 int pc
[4] = {1, 1, 1, 1}, pa
[4] = {15, 15, 15, 0};
1788 CAtlArray
<SubPos
>& sp
= m_langs
[m_iLang
].subpos
;
1789 for(int i
= 0, k
= 0; i
< sp
.GetCount(); i
++)
1791 if(!GetFrame(i
)) continue;
1793 for(int j
= 0; j
< 5; j
++)
1795 if(j
== 4 || !m_img
.pal
[j
].tr
)
1798 memset(p4bpp
, (j
<<4)|j
, (m_size
.cy
-2)*360);
1803 for(int y
= max(m_img
.rect
.top
+1, 2); y
< m_img
.rect
.bottom
-1; y
++)
1805 ASSERT(m_size
.cy
-y
-1 >= 0);
1806 if(m_size
.cy
-y
-1 < 0) break;
1808 DWORD
* p
= (DWORD
*)&m_img
.lpPixels
[(y
-m_img
.rect
.top
)*m_img
.rect
.Width()+1];
1810 for(int x
= m_img
.rect
.left
+1; x
< m_img
.rect
.right
-1; x
++, p
++)
1812 DWORD rgb
= *p
&0xffffff;
1813 BYTE c
= rgb
== 0x0000ff ? 0 : rgb
== 0xff0000 ? 1 : rgb
== 0x000000 ? 2 : 3;
1814 BYTE
& c4bpp
= p4bpp
[(m_size
.cy
-y
-1)*360+(x
>>1)];
1815 c4bpp
= (x
&1) ? ((c4bpp
&0xf0)|c
) : ((c4bpp
&0x0f)|(c
<<4));
1820 bmpfn
.Format(_T("%s_%04d.bmp"), fn
, i
+1);
1821 title
= bmpfn
.Mid(bmpfn
.ReverseFind('/')+1);
1824 int c
[4] = {colormap
[m_img
.pal
[1].pal
], colormap
[m_img
.pal
[2].pal
], colormap
[m_img
.pal
[0].pal
], colormap
[m_img
.pal
[3].pal
]};
1825 c
[0]^=c
[1], c
[1]^=c
[0], c
[0]^=c
[1];
1827 if(memcmp(pc
, c
, sizeof(c
)))
1829 memcpy(pc
, c
, sizeof(c
));
1830 str
.Format(_T("Color\t (%d %d %d %d)\n"), c
[0], c
[1], c
[2], c
[3]);
1835 int a
[4] = {m_img
.pal
[1].tr
, m_img
.pal
[2].tr
, m_img
.pal
[0].tr
, m_img
.pal
[3].tr
};
1836 a
[0]^=a
[1], a
[1]^=a
[0], a
[0]^=a
[1];
1838 if(memcmp(pa
, a
, sizeof(a
)))
1840 memcpy(pa
, a
, sizeof(a
));
1841 str
.Format(_T("Contrast (%d %d %d %d)\n"), a
[0], a
[1], a
[2], a
[3]);
1845 int t1
= sp
[i
].start
;
1846 int h1
= t1
/1000/60/60, m1
= (t1
/1000/60)%60, s1
= (t1
/1000)%60;
1847 int f1
= (int)((m_size
.cy
==480?29.97:25)*(t1
%1000)/1000);
1849 int t2
= sp
[i
].stop
;
1850 int h2
= t2
/1000/60/60, m2
= (t2
/1000/60)%60, s2
= (t2
/1000)%60;
1851 int f2
= (int)((m_size
.cy
==480?29.97:25)*(t2
%1000)/1000);
1853 if(t2
<= 0) continue;
1856 if(h1
== h2
&& m1
== m2
&& s1
== s2
&& f1
== f2
)
1859 if(f2
== (m_size
.cy
==480?30:25)) {f2
= 0; s2
++; if(s2
== 60) {s2
= 0; m2
++; if(m2
== 60) {m2
= 0; h2
++;}}}
1862 if(i
< sp
.GetCount()-1)
1864 int t3
= sp
[i
+1].start
;
1865 int h3
= t3
/1000/60/60, m3
= (t3
/1000/60)%60, s3
= (t3
/1000)%60;
1866 int f3
= (int)((m_size
.cy
==480?29.97:25)*(t3
%1000)/1000);
1868 if(h3
== h2
&& m3
== m2
&& s3
== s2
&& f3
== f2
)
1871 if(f2
== -1) {f2
= (m_size
.cy
==480?29:24); s2
--; if(s2
== -1) {s2
= 59; m2
--; if(m2
== -1) {m2
= 59; if(h2
> 0) h2
--;}}}
1875 if(h1
== h2
&& m1
== m2
&& s1
== s2
&& f1
== f2
)
1878 str
.Format(_T("%04d\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"),
1886 if(bmp
.Open(bmpfn
, CFile::modeCreate
|CFile::modeWrite
|CFile::modeRead
|CFile::typeBinary
))
1888 bmp
.Write(&fhdr
, sizeof(fhdr
));
1889 bmp
.Write(&ihdr
, sizeof(ihdr
));
1890 bmp
.Write(newCusPal
, sizeof(RGBQUAD
)*16);
1891 bmp
.Write(p4bpp
, 360*(m_size
.cy
-2));
1894 CompressFile(bmpfn
);
1898 m_fCustomPal
= fCustomPal
;
1899 memcpy(m_cuspal
, tempCusPal
, sizeof(m_cuspal
));
1904 bool CVobSubFile::SaveMaestro(CString fn
)
1909 if(!f
.Open(fn
+ _T(".son"), CFile::modeCreate
|CFile::modeWrite
|CFile::typeText
|CFile::shareDenyWrite
))
1914 fn
.Replace('\\', '/');
1915 CString title
= fn
.Mid(fn
.ReverseFind('/')+1);
1917 TCHAR buff
[MAX_PATH
], * pFilePart
= buff
;
1918 if(GetFullPathName(fn
, MAX_PATH
, buff
, &pFilePart
) == 0)
1921 CString fullpath
= CString(buff
).Left(pFilePart
- buff
);
1922 fullpath
.TrimRight(_T("\\/"));
1923 if(fullpath
.IsEmpty())
1927 str
+= _T("st_format\t2\n");
1928 str
+= _T("Display_Start\t%s\n");
1929 str
+= _T("TV_Type\t\t%s\n");
1930 str
+= _T("Tape_Type\tNON_DROP\n");
1931 str
+= _T("Pixel_Area\t(0 %d)\n");
1932 str
+= _T("Directory\t%s\n");
1933 str
+= _T("Subtitle\t%s\n");
1934 str
+= _T("Display_Area\t(0 2 719 %d)\n");
1935 str
+= _T("Contrast\t(15 15 15 0)\n");
1937 str
+= _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n");
1939 !m_fOnlyShowForcedSubs
? _T("non_forced") : _T("forced"),
1940 m_size
.cy
== 480 ? _T("NTSC") : _T("PAL"),
1944 m_size
.cy
== 480 ? 479 : 574);
1946 f
.WriteString(str2
);
1970 BITMAPFILEHEADER fhdr
=
1973 sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
) + 16*sizeof(RGBQUAD
) + 360*(m_size
.cy
-2),
1975 sizeof(BITMAPFILEHEADER
) + sizeof(BITMAPINFOHEADER
) + 16*sizeof(RGBQUAD
)
1978 BITMAPINFOHEADER ihdr
=
1980 sizeof(BITMAPINFOHEADER
),
1981 720, m_size
.cy
-2, 1, 4, 0,
1987 bool fCustomPal
= m_fCustomPal
;
1988 m_fCustomPal
= true;
1989 RGBQUAD tempCusPal
[4], newCusPal
[4+12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}};
1990 memcpy(tempCusPal
, m_cuspal
, sizeof(tempCusPal
));
1991 memcpy(m_cuspal
, newCusPal
, sizeof(m_cuspal
));
1993 CAutoVectorPtr
<BYTE
> p4bpp
;
1994 if(!p4bpp
.Allocate((m_size
.cy
-2)*360))
1998 for(int i
= 0; i
< 16; i
++)
2002 if(spf
.Open(fn
+ _T(".spf"), CFile::modeCreate
|CFile::modeWrite
|CFile::typeBinary
))
2004 for(int i
= 0; i
< 16; i
++)
2006 COLORREF c
= (m_orgpal
[i
].rgbBlue
<<16) | (m_orgpal
[i
].rgbGreen
<<8) | m_orgpal
[i
].rgbRed
;
2007 spf
.Write(&c
, sizeof(COLORREF
));
2013 int pc
[4] = {1,1,1,1}, pa
[4] = {15,15,15,0};
2015 CAtlArray
<SubPos
>& sp
= m_langs
[m_iLang
].subpos
;
2016 for(int i
= 0, k
= 0; i
< sp
.GetCount(); i
++)
2018 if(!GetFrame(i
)) continue;
2020 for(int j
= 0; j
< 5; j
++)
2022 if(j
== 4 || !m_img
.pal
[j
].tr
)
2025 memset(p4bpp
, (j
<<4)|j
, (m_size
.cy
-2)*360);
2030 for(int y
= max(m_img
.rect
.top
+1, 2); y
< m_img
.rect
.bottom
-1; y
++)
2032 ASSERT(m_size
.cy
-y
-1 >= 0);
2033 if(m_size
.cy
-y
-1 < 0) break;
2035 DWORD
* p
= (DWORD
*)&m_img
.lpPixels
[(y
-m_img
.rect
.top
)*m_img
.rect
.Width()+1];
2037 for(int x
= m_img
.rect
.left
+1; x
< m_img
.rect
.right
-1; x
++, p
++)
2039 DWORD rgb
= *p
&0xffffff;
2040 BYTE c
= rgb
== 0x0000ff ? 0 : rgb
== 0xff0000 ? 1 : rgb
== 0x000000 ? 2 : 3;
2041 BYTE
& c4bpp
= p4bpp
[(m_size
.cy
-y
-1)*360+(x
>>1)];
2042 c4bpp
= (x
&1) ? ((c4bpp
&0xf0)|c
) : ((c4bpp
&0x0f)|(c
<<4));
2047 bmpfn
.Format(_T("%s_%04d.bmp"), fn
, i
+1);
2048 title
= bmpfn
.Mid(bmpfn
.ReverseFind('/')+1);
2051 int c
[4] = {colormap
[m_img
.pal
[1].pal
], colormap
[m_img
.pal
[2].pal
], colormap
[m_img
.pal
[0].pal
], colormap
[m_img
.pal
[3].pal
]};
2053 if(memcmp(pc
, c
, sizeof(c
)))
2055 memcpy(pc
, c
, sizeof(c
));
2056 str
.Format(_T("Color\t (%d %d %d %d)\n"), c
[0], c
[1], c
[2], c
[3]);
2061 int a
[4] = {m_img
.pal
[1].tr
, m_img
.pal
[2].tr
, m_img
.pal
[0].tr
, m_img
.pal
[3].tr
};
2063 if(memcmp(pa
, a
, sizeof(a
)))
2065 memcpy(pa
, a
, sizeof(a
));
2066 str
.Format(_T("Contrast (%d %d %d %d)\n"), a
[0], a
[1], a
[2], a
[3]);
2070 int t1
= sp
[i
].start
;
2071 int h1
= t1
/1000/60/60, m1
= (t1
/1000/60)%60, s1
= (t1
/1000)%60;
2072 int f1
= (int)((m_size
.cy
==480?29.97:25)*(t1
%1000)/1000);
2074 int t2
= sp
[i
].stop
;
2075 int h2
= t2
/1000/60/60, m2
= (t2
/1000/60)%60, s2
= (t2
/1000)%60;
2076 int f2
= (int)((m_size
.cy
==480?29.97:25)*(t2
%1000)/1000);
2078 if(t2
<= 0) continue;
2081 if(h1
== h2
&& m1
== m2
&& s1
== s2
&& f1
== f2
)
2084 if(f2
== (m_size
.cy
==480?30:25)) {f2
= 0; s2
++; if(s2
== 60) {s2
= 0; m2
++; if(m2
== 60) {m2
= 0; h2
++;}}}
2087 if(i
< sp
.GetCount()-1)
2089 int t3
= sp
[i
+1].start
;
2090 int h3
= t3
/1000/60/60, m3
= (t3
/1000/60)%60, s3
= (t3
/1000)%60;
2091 int f3
= (int)((m_size
.cy
==480?29.97:25)*(t3
%1000)/1000);
2093 if(h3
== h2
&& m3
== m2
&& s3
== s2
&& f3
== f2
)
2096 if(f2
== -1) {f2
= (m_size
.cy
==480?29:24); s2
--; if(s2
== -1) {s2
= 59; m2
--; if(m2
== -1) {m2
= 59; if(h2
> 0) h2
--;}}}
2100 if(h1
== h2
&& m1
== m2
&& s1
== s2
&& f1
== f2
)
2103 str
.Format(_T("%04d\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"),
2111 if(bmp
.Open(bmpfn
, CFile::modeCreate
|CFile::modeWrite
|CFile::typeBinary
))
2113 bmp
.Write(&fhdr
, sizeof(fhdr
));
2114 bmp
.Write(&ihdr
, sizeof(ihdr
));
2115 bmp
.Write(newCusPal
, sizeof(RGBQUAD
)*16);
2116 bmp
.Write(p4bpp
, 360*(m_size
.cy
-2));
2119 CompressFile(bmpfn
);
2123 m_fCustomPal
= fCustomPal
;
2124 memcpy(m_cuspal
, tempCusPal
, sizeof(m_cuspal
));
2133 CVobSubStream::CVobSubStream(CCritSec
* pLock
)
2134 : CSubPicProviderImpl(pLock
)
2138 CVobSubStream::~CVobSubStream()
2142 void CVobSubStream::Open(CString name
, BYTE
* pData
, int len
)
2144 CAutoLock
cAutoLock(&m_csSubPics
);
2148 CAtlList
<CString
> lines
;
2149 Explode(CString(CStringA((CHAR
*)pData
, len
)), lines
, '\n');
2150 while(lines
.GetCount())
2152 CAtlList
<CString
> sl
;
2153 Explode(lines
.RemoveHead(), sl
, ':', 2);
2154 if(sl
.GetCount() != 2) continue;
2155 CString key
= sl
.GetHead();
2156 CString value
= sl
.GetTail();
2157 if(key
== _T("size"))
2158 _stscanf(value
, _T("%dx %d"), &m_size
.cx
, &m_size
.cy
);
2159 else if(key
== _T("org"))
2160 _stscanf(value
, _T("%d, %d"), &m_org
.x
, &m_org
.y
);
2161 else if(key
== _T("scale"))
2162 _stscanf(value
, _T("%d%%, %d%%"), &m_scale_x
, &m_scale_y
);
2163 else if(key
== _T("alpha"))
2164 _stscanf(value
, _T("%d%%"), &m_alpha
);
2165 else if(key
== _T("smooth"))
2167 value
== _T("0") || value
== _T("OFF") ? 0 :
2168 value
== _T("1") || value
== _T("ON") ? 1 :
2169 value
== _T("2") || value
== _T("OLD") ? 2 :
2171 else if(key
== _T("align"))
2173 Explode(value
, sl
, ' ');
2174 if(sl
.GetCount() == 4) sl
.RemoveAt(sl
.FindIndex(1));
2175 if(sl
.GetCount() == 3)
2177 m_fAlign
= sl
.RemoveHead() == _T("ON");
2178 CString hor
= sl
.GetHead(), ver
= sl
.GetTail();
2179 m_alignhor
= hor
== _T("LEFT") ? 0 : hor
== _T("CENTER") ? 1 : hor
== _T("RIGHT") ? 2 : 1;
2180 m_alignver
= ver
== _T("TOP") ? 0 : ver
== _T("CENTER") ? 1 : ver
== _T("BOTTOM") ? 2 : 2;
2183 else if(key
== _T("fade in/out"))
2184 _stscanf(value
, _T("%d%, %d%"), &m_fadein
, &m_fadeout
);
2185 else if(key
== _T("time offset"))
2186 m_toff
= _tcstol(value
, NULL
, 10);
2187 else if(key
== _T("forced subs"))
2188 m_fOnlyShowForcedSubs
= value
== _T("1") || value
== _T("ON");
2189 else if(key
== _T("palette"))
2191 Explode(value
, sl
, ',', 16);
2192 for(int i
= 0; i
< 16 && sl
.GetCount(); i
++)
2193 *(DWORD
*)&m_orgpal
[i
] = _tcstol(sl
.RemoveHead(), NULL
, 16);
2195 else if(key
== _T("custom colors"))
2197 m_fCustomPal
= Explode(value
, sl
, ',', 3) == _T("ON");
2198 if(sl
.GetCount() == 3)
2201 CAtlList
<CString
> tridx
, colors
;
2202 Explode(sl
.RemoveHead(), tridx
, ':', 2);
2203 if(tridx
.RemoveHead() == _T("tridx"))
2206 _stscanf(tridx
.RemoveHead(), _T("%c%c%c%c"), &tr
[0], &tr
[1], &tr
[2], &tr
[3]);
2207 for(int i
= 0; i
< 4; i
++)
2208 m_tridx
|= ((tr
[i
]=='1')?1:0)<<i
;
2210 Explode(sl
.RemoveHead(), colors
, ':', 2);
2211 if(colors
.RemoveHead() == _T("colors"))
2213 Explode(colors
.RemoveHead(), colors
, ',', 4);
2214 for(int i
= 0; i
< 4 && colors
.GetCount(); i
++)
2215 *(DWORD
*)&m_cuspal
[i
] = _tcstol(colors
.RemoveHead(), NULL
, 16);
2222 void CVobSubStream::Add(REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, BYTE
* pData
, int len
)
2224 if(len
<= 4 || ((pData
[0]<<8)|pData
[1]) != len
) return;
2227 vsi
.GetPacketInfo(pData
, (pData
[0]<<8)|pData
[1], (pData
[2]<<8)|pData
[3]);
2229 CAutoPtr
<SubPic
> p(new SubPic());
2231 p
->tStop
= vsi
.delay
> 0 ? (tStart
+ 10000i64
*vsi
.delay
) : tStop
;
2232 p
->pData
.SetCount(len
);
2233 memcpy(p
->pData
.GetData(), pData
, p
->pData
.GetCount());
2235 CAutoLock
cAutoLock(&m_csSubPics
);
2236 while(m_subpics
.GetCount() && m_subpics
.GetTail()->tStart
>= tStart
)
2238 m_subpics
.RemoveTail();
2241 m_subpics
.AddTail(p
);
2244 void CVobSubStream::RemoveAll()
2246 CAutoLock
cAutoLock(&m_csSubPics
);
2247 m_subpics
.RemoveAll();
2251 STDMETHODIMP
CVobSubStream::NonDelegatingQueryInterface(REFIID riid
, void** ppv
)
2253 CheckPointer(ppv
, E_POINTER
);
2260 __super::NonDelegatingQueryInterface(riid
, ppv
);
2265 STDMETHODIMP_(POSITION
) CVobSubStream::GetStartPosition(REFERENCE_TIME rt
, double fps
)
2267 CAutoLock
cAutoLock(&m_csSubPics
);
2268 POSITION pos
= m_subpics
.GetTailPosition();
2269 for(; pos
; m_subpics
.GetPrev(pos
))
2271 SubPic
* sp
= m_subpics
.GetAt(pos
);
2272 if(sp
->tStart
<= rt
)
2274 if(sp
->tStop
<= rt
) m_subpics
.GetNext(pos
);
2281 STDMETHODIMP_(POSITION
) CVobSubStream::GetNext(POSITION pos
)
2283 CAutoLock
cAutoLock(&m_csSubPics
);
2284 m_subpics
.GetNext(pos
);
2288 STDMETHODIMP_(REFERENCE_TIME
) CVobSubStream::GetStart(POSITION pos
, double fps
)
2290 CAutoLock
cAutoLock(&m_csSubPics
);
2291 return m_subpics
.GetAt(pos
)->tStart
;
2294 STDMETHODIMP_(REFERENCE_TIME
) CVobSubStream::GetStop(POSITION pos
, double fps
)
2296 CAutoLock
cAutoLock(&m_csSubPics
);
2297 return m_subpics
.GetAt(pos
)->tStop
;
2300 STDMETHODIMP_(bool) CVobSubStream::IsAnimated(POSITION pos
)
2305 STDMETHODIMP
CVobSubStream::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, double fps
, RECT
& bbox
)
2307 if(spd
.bpp
!= 32) return E_INVALIDARG
;
2309 POSITION pos
= m_subpics
.GetTailPosition();
2310 for(; pos
; m_subpics
.GetPrev(pos
))
2312 SubPic
* sp
= m_subpics
.GetAt(pos
);
2313 if(sp
->tStart
<= rt
&& rt
< sp
->tStop
)
2315 if(m_img
.iIdx
!= (int)pos
)
2317 BYTE
* pData
= sp
->pData
.GetData();
2319 pData
, (pData
[0]<<8)|pData
[1], (pData
[2]<<8)|pData
[3],
2320 m_fCustomPal
, m_tridx
, m_orgpal
, m_cuspal
, true);
2321 m_img
.iIdx
= (int)pos
;
2324 return __super::Render(spd
, bbox
);
2333 STDMETHODIMP
CVobSubStream::GetClassID(CLSID
* pClassID
)
2335 return pClassID
? *pClassID
= __uuidof(this), S_OK
: E_POINTER
;
2340 STDMETHODIMP_(int) CVobSubStream::GetStreamCount()
2345 STDMETHODIMP
CVobSubStream::GetStreamInfo(int i
, WCHAR
** ppName
, LCID
* pLCID
)
2347 CAutoLock
cAutoLock(&m_csSubPics
);
2351 if(!(*ppName
= (WCHAR
*)CoTaskMemAlloc((m_name
.GetLength()+1)*sizeof(WCHAR
))))
2352 return E_OUTOFMEMORY
;
2353 wcscpy(*ppName
, CStringW(m_name
));
2364 STDMETHODIMP_(int) CVobSubStream::GetStream()
2369 STDMETHODIMP
CVobSubStream::SetStream(int iStream
)
2371 return iStream
== 0 ? S_OK
: E_FAIL
;