Sunday, September 10, 2006

(XBMC) 讓TTF字幕不需播出前載入

XBMC近期版本的字幕播出,有一個很重大的改變,就是在mplayer偵測完字幕檔的編碼之後,就以該編碼(若偵測不出的話,就以使用者的設定編碼)轉成utf-8載入,而不是像之前,只要確定是ansi或utf-8,就直接送上OSD的字幕選單,供使用者選擇。

這個改變原是為了便民,但對台灣的大五碼使用者來說,就不怎麼方便了。因為XBMC的Big5原本就有點怪怪的,過去就發現若字幕中有「裏」這個字,將會導致該句字幕在播出時整段變成亂碼。而這種包含不相容字元的字幕檔,現在則是在載入之前就發生錯誤,導致使用者根本無法從OSD上去選用該字幕。

在知道XBMC有這個問題之後,就不會有選不到字幕時,有著莫名其妙的挫折感,而我個人過去所擁有的字幕檔,也大概都把「裏」改成「裡」,所以遇到不能播出的檔案,除了英文字幕我還搞不太清楚是怎麼回事之外,其實還蠻少的。

但也在那蠻少的檔案當中,還是陸續又找到了兩個不相容字元,一個是全形的符號「/」,一個是「酶」。其中「/」是藏在某個檔案的後面,所以當初沒能發覺,而「酶」這個字則非常罕用,是昨天在看Grey's Anatomy時才在某醫學術語中出現。

個人還是習慣過去的字幕播出方式,說老實話,不是為了Big5的繁中字幕,而是為了能同時切換到英文字幕。研究了好一會的原始碼,並經過了兩次無用的修改和兩次失敗的compile之後,終於修改完成了。現在我自己用的XBMC已經回復到過去一樣,不會在播出之前搶先載入字幕,所以也不會有載入失敗、無法選用的狀況發生,而我也可以自由地在各語言的字幕之中作切換了。

我改動到五個原始檔,以下敘述中提到的行數,以9月10日更新的原始碼版本為主。

一、xbmc\cores\mplayer.cpp
第2037行,改為:bool CMPlayer::GetCurrentSubtitle(CStdStringW& strSubtitle)
第2039行,改為: strSubtitle = L"";
第2056行,改為:strSubtitle += L"\n";
第2059-2062行:
CStdStringA S = sub->text[i];
CStdStringW W;
g_charsetConverter.utf8ToUTF16(S, W, false);
strSubtitle += W;

第323-327行,刪除:
/* try to autodetect any multicharacter charset */
/* then fallback to user specified charset */
m_vecOptions.push_back("-subcp");
strTmp.Format("enca:__:%s", m_subcp.c_str());
m_vecOptions.push_back(strTmp);

第2057行,改為:
g_charsetConverter.subtitleCharsetToUTF16(S, W);
原為:g_charsetConverter.utf8ToUTF16(S, W, false);


二、xbmc\cores\Mplayer.h
第168行,改為:virtual bool GetCurrentSubtitle(CStdStringW& strSubtitle);

三、xbmc\cores\IPlayer.h
第114行,改為:virtual bool GetCurrentSubtitle(CStdStringW& strSubtitle) { strSubtitle = ""; return false; }

四、xbmc\GUIWindowFullScreen.cpp
第684行,改為:CStdStringW subtitleText = L"";
第692行,改為: m_subtitleFont->GetTextExtent(subtitleText.c_str(), &w, &h);
第693、694行刪掉,內容為:
g_charsetConverter.utf8ToUTF16(subtitleText, utf16Sub, false);
m_subtitleFont->GetTextExtent(utf16Sub.c_str(), &w, &h);)

以下行數,因其上有刪行,而以下有增行,故僅當成參考,請參照原程式碼修改。
第699-701行,原為:
CGUILabelControl::WrapText(subtitleText, m_subtitleFont, maxWidth);
g_charsetConverter.utf8ToUTF16(subtitleText, utf16Sub, false);
m_subtitleFont->GetTextExtent(utf16Sub.c_str(), &w, &h);
改為:
CStdString utf8Sub;
g_charsetConverter.utf16toUTF8(subtitleText, utf8Sub);
CGUILabelControl::WrapText(utf8Sub, m_subtitleFont, maxWidth);
g_charsetConverter.utf8ToUTF16(utf8Sub, subtitleText);
m_subtitleFont->GetTextExtent(subtitleText.c_str(), &w, &h);

第709行,原為:
m_subtitleFont->DrawOutlineText(x, y, 0, 0xFF000000, 3, utf16Sub.c_str(), XBFONT_CENTER_X);
改為:
m_subtitleFont->DrawOutlineText(x, y, 0, 0xFF000000, 3, subtitleText.c_str(), XBFONT_CENTER_X);

五、xbmc\cores\mplayer\mplayer.cpp(注意:和第一個檔不一樣喔!)
第509行,加入前一行及下一行,使之成為:
#ifdef _DEBUG
dll.ResolveExport("MemAllocatorCreate", (void**) &pMemAllocatorCreate);
#endif

儲存後重新compile,功能就恢復到舊時習慣的方式了。

P.S. 於2006, 0911修訂。

5 comments:

Anonymous said...

別跟大陸人一般見識吧。

Anonymous said...

哈...
我有先見之明!不參與該討論是對的!!

kaku03 said...

我不會因為那是「大陸人」就怎麼樣,畢竟台灣這裡也很多小白。只不過以一個客人身分,態度還如此這般,的確教人大開眼界……

另,我不確定omen的「先見之明」是什麼?

Anonymous said...

有前例可尋...!
http://www.xbox-sky.org/fid17-tid31444/

加上自相矛盾的說法...
節錄...
用空大家在讨论一下翻译问题,让翻译更准确一点,目前的繁体的翻译,不准确的地方很多,而且我发现翻译的部分是两边对抄,哈哈,我也抄,N多地方我也没把握

*結論就是"態度決定一切"!哈...

kaku03 said...

謝謝omen的開示。其實早在SF以及XBMC官網討論區裡,就已覺得開發小組對那位仁兄似乎很感冒,我很少看到開發小組成員回文的口氣如此不悅,且對其發言常是不予理會(也難怪他要來TvGame360討救兵)。他過去在TvGame360還算客氣,除了愛自我吹捧以外,倒也沒什麼大毛病就是。