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
23 #include "ccdecoder.h"
25 CCDecoder::CCDecoder(CString fn
, CString rawfn
) : m_fn(fn
), m_rawfn(rawfn
)
27 m_sts
.CreateDefaultStyle(ANSI_CHARSET
);
30 m_fEndOfCaption
= false;
31 memset(m_buff
, 0, sizeof(m_buff
));
32 memset(m_disp
, 0, sizeof(m_disp
));
33 m_cursor
= CPoint(0, 0);
35 if(!m_rawfn
.IsEmpty())
39 CCDecoder::~CCDecoder()
41 if(!m_sts
.IsEmpty() && !m_fn
.IsEmpty())
44 m_sts
.SaveAs(m_fn
, EXTSRT
, -1, CTextFile::ASCII
);
45 m_sts
.SaveAs(m_fn
.Left(m_fn
.ReverseFind('.')+1) + _T("utf8.srt"), EXTSRT
, -1, CTextFile::UTF8
);
46 m_sts
.SaveAs(m_fn
.Left(m_fn
.ReverseFind('.')+1) + _T("utf16le.srt"), EXTSRT
, -1, CTextFile::LE16
);
47 m_sts
.SaveAs(m_fn
.Left(m_fn
.ReverseFind('.')+1) + _T("utf16be.srt"), EXTSRT
, -1, CTextFile::BE16
);
51 void CCDecoder::MoveCursor(int x
, int y
)
53 m_cursor
= CPoint(x
, y
);
54 if(m_cursor
.x
< 0) m_cursor
.x
= 0;
55 if(m_cursor
.y
< 0) m_cursor
.y
= 0;
56 if(m_cursor
.x
>= 32) m_cursor
.x
= 0, m_cursor
.y
++;
57 if(m_cursor
.y
>= 16) m_cursor
.y
= 0;
60 void CCDecoder::OffsetCursor(int x
, int y
)
62 MoveCursor(m_cursor
.x
+ x
, m_cursor
.y
+ y
);
65 void CCDecoder::PutChar(WCHAR c
)
67 m_buff
[m_cursor
.y
][m_cursor
.x
] = c
;
71 void CCDecoder::SaveDisp(__int64 time
)
75 for(int row
= 0; row
< 16; row
++)
77 bool fNonEmptyRow
= false;
79 for(int col
= 0; col
< 32; col
++)
83 CStringW
str2(&m_disp
[row
][col
]);
84 if(fNonEmptyRow
) str
+= ' ';
86 col
+= str2
.GetLength();
91 if(fNonEmptyRow
) str
+= '\n';
94 if(str
.IsEmpty()) return;
96 m_sts
.Add(str
, true, (int)m_time
, (int)time
);
99 void CCDecoder::DecodeCC(BYTE
* buff
, int len
, __int64 time
)
101 if(!m_rawfn
.IsEmpty())
103 if(FILE* f
= _tfopen(m_rawfn
, _T("at")))
105 _ftprintf(f
, _T("%02d:%02d:%02d.%03d\n"),
106 (int)(time
/1000/60/60),
107 (int)((time
/1000/60)%60),
108 (int)((time
/1000)%60),
111 for(int i
= 0; i
< len
; i
++)
113 _ftprintf(f
, _T("%02x"), buff
[i
]);
114 if(i
< len
-1) _ftprintf(f
, _T(" "));
115 if(i
> 0 && (i
&15)==15) _ftprintf(f
, _T("\n"));
117 if(len
> 0) _ftprintf(f
, _T("\n\n"));
122 for(int i
= 0; i
< len
; i
++)
124 BYTE c
= buff
[i
]&0x7f;
127 static WCHAR charmap
[0x60] =
129 ' ','!','"','#','$','%','&','\'','(',')',0xE1,'+',',','-','.','/',
130 '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>',0x3F,
131 '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
132 'P','Q','R','S','T','U','V','W','X','Y','Z','[',0xE9,']',0xED,0xF3,
133 0xFA,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
134 'p','q','r','s','t','u','v','w','x','y','z',0xE7,0xF7,'N','n',0x3F
137 PutChar(charmap
[c
- 0x20]);
139 else if(buff
[i
] != 0x80 && i
< len
-1)
141 // codes and special characters are supposed to be doubled
142 if(i
< len
-3 && buff
[i
] == buff
[i
+2] && buff
[i
+1] == buff
[i
+3])
146 if(buff
[i
] == 0x91 && c
>= 0x20 && c
< 0x30) // formating
150 else if(buff
[i
] == 0x91 && c
== 0x39) // transparent space
154 else if(buff
[i
] == 0x91 && c
>= 0x30 && c
< 0x40) // special characters
156 static WCHAR charmap
[0x10] =
158 0x00ae, // (r)egistered
161 0x00bf, // inverted question mark
162 0x2122, // trade mark
167 0x00ff, // transparent space, handled above
176 PutChar(charmap
[c
- 0x30]);
178 else if(buff
[i
] == 0x92 && c
>= 0x20 && c
< 0x40) // extended characters
180 static WCHAR charmap
[0x20] =
189 0x00a1, // inverted !
193 0x00a9, // (c)opyright
195 0x00b7, // . (dot in the middle)
196 0x201c, // inverted "
217 PutChar(charmap
[c
- 0x20]);
219 else if(buff
[i
] == 0x13 && c
>= 0x20 && c
< 0x40) // more extended characters
221 static WCHAR charmap
[0x20] =
244 0x00df, // B (ss in german)
258 PutChar(charmap
[c
- 0x20]);
260 else if(buff
[i
] == 0x94 && buff
[i
+1] == 0xae) // Erase Non-displayed [buffer] Memory
262 memset(m_buff
, 0, sizeof(m_buff
));
264 else if(buff
[i
] == 0x94 && buff
[i
+1] == 0x20) // Resume Caption Loading
266 memset(m_buff
, 0, sizeof(m_buff
));
268 else if(buff
[i
] == 0x94 && buff
[i
+1] == 0x2f) // End Of Caption
270 if(memcmp(m_disp
, m_buff
, sizeof(m_disp
)) != 0)
273 SaveDisp(time
+ (i
/2)*1000/30);
275 m_fEndOfCaption
= true;
276 memcpy(m_disp
, m_buff
, sizeof(m_disp
));
277 m_time
= time
+ (i
/2)*1000/30;
280 else if(buff
[i
] == 0x94 && buff
[i
+1] == 0x2c) // Erase Displayed Memory
284 m_fEndOfCaption
= false;
285 SaveDisp(time
+ (i
/2)*1000/30);
288 memset(m_disp
, 0, sizeof(m_disp
));
290 else if(buff
[i
] == 0x97 && (buff
[i
+1] == 0xa1 || buff
[i
+1] == 0xa2 || buff
[i
+1] == 0x23)) // Tab Over
292 OffsetCursor(buff
[i
+1]&3, 0);
294 else if(buff
[i
] == 0x91 || buff
[i
] == 0x92 || buff
[i
] == 0x15 || buff
[i
] == 0x16
295 || buff
[i
] == 0x97 || buff
[i
] == 0x10 || buff
[i
] == 0x13 || buff
[i
] == 0x94) // curpos, color, underline
301 case 0x91: row
= 0; break;
302 case 0x92: row
= 2; break;
303 case 0x15: row
= 4; break;
304 case 0x16: row
= 6; break;
305 case 0x97: row
= 8; break;
306 case 0x10: row
= 10; break;
307 case 0x13: row
= 12; break;
308 case 0x94: row
= 14; break;
310 if(buff
[i
+1]&0x20) row
++;
312 int col
= buff
[i
+1]&0xe;
313 if(col
== 0 || (col
> 0 && !(buff
[i
+1]&0x10))) col
= 0;
316 MoveCursor(col
, row
);
328 void CCDecoder::ExtractCC(BYTE
* buff
, int len
, __int64 time
)
330 for(int i
= 0; i
< len
-9; i
++)
332 if(*(DWORD
*)&buff
[i
] == 0xb2010000 && *(DWORD
*)&buff
[i
+4] == 0xf8014343)
335 int nBytes
= buff
[i
++]&0x3f;
338 nBytes
= (nBytes
+1)&~1;
340 BYTE
* pData1
= new BYTE
[nBytes
];
341 BYTE
* pData2
= new BYTE
[nBytes
];
345 int nBytes1
= 0, nBytes2
= 0;
347 for(int j
= 0; j
< nBytes
&& i
< 0x800;)
349 if(buff
[i
++] == 0xff)
351 pData1
[nBytes1
++] = buff
[i
++];
352 pData1
[nBytes1
++] = buff
[i
++];
358 if(j
>= nBytes
) break;
360 if(buff
[i
++] == 0xff)
362 pData2
[nBytes2
++] = buff
[i
++];
363 pData2
[nBytes2
++] = buff
[i
++];
371 DecodeCC(pData1
, nBytes1
, time
);
374 DecodeCC(pData2
, nBytes2
, time
);
377 if(pData1
) delete [] pData1
;
378 if(pData2
) delete [] pData2
;