Переделка поддержки кодировок файлов субтитров

Автор V0lt, 03 сентября 2025, 17:38:02

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

V0lt

Вообще однобайтные кодировки (и не только однобайтные, вспомним иероглифы) - зло. Потому что кодировку обычно никак не прописывают в файлах субтиров. Но с ними приходиться работать.

Тут нужны определения.

Сharacter Set - набор символов и ничего более. Бывают наборы для латиницы, кириллицы, греческих символов и других. Как параметр используется в структуре LOGFONT (см. lfCharSet)

Code Page - это собственно кодировка символов. Сопоставление бинарных значений с конкретными символами.


Что мы имеем сейчас.

С настройками по умолчанию MPC-BE читает файл с системной кодировкой. Для русской локали это Windows-1251, для других языков что-то свое.

Если нужно переопределить кодировку, то в настройках MPC-BE можно поменять набор символов для стиля субтитров по умолчанию. Это очень странный способ, но он часто срабатывает. Набору символов с помощью функции TranslateCharsetInfo сопоставляется определенная кодировка символов.

Проблема возникает, если у вас субтитры в нестандартной кодировке. Возьмем пример из недавнего баг-репорта. У китайцев ранее использовался набор символов GB2312, сейчас появился GB18030. Для этих наборов символов используются немного разные кодировки и соответственно некоторые иероглифы GB18030 не будут отображены.

С кириллицой проблем нет. Тестовые субтитры всегда писали в Windows-1251, других не встречал. Иначе были бы проблемы с аппаратными плеерами.

V0lt

Что делать юзерам?

Для юзеров хорошим решением может оказаться сохранение файлов субтитров в формате UTF-8. На современных плеерах для Windows, Linux и Android проблем быть не должно.
Если юзеру нужно смотреть субтитры на старом оборудование (вопрос зачем поднимать не будем), то скорее всего он и так знает, какая там должны быть кодировки и форматы.

Для субтитров, встроенных в видеофайл MKV, проблем быть не должно, потому что они хранятся в UTF-8. Если делает MKV с субтитрами самостоятельно, то обязательно проверьте результат на плеере.

V0lt

#2
Что хочется сделать в MPC-BE?

1. Набор символов НЕ должен определять кодировку. Соответствующая настройка выбора набора символов будет удалена или заменена выбором кодировки.

2. Кодировка будет определять набор символов. Потому что набор символов много где используется: LOGFONT, в полях стилей SSA/ASS и др.

3. Разобраться со полем "Encoding" в стилях SSA/ASS, в котором прописывается набор символов.
- В чем смысл этого поля?
- Что если кодировка файла русская (Windows-1251), а в поле "Encoding" прописан греческий набор символов?
- Что должно быть в поле "Encoding", если файл субтитров сохранен в UTF-8?

4. Разобраться, зачем в LOGFONT прописывают конкретный набор символов, когда у нас есть шрифты с несколькими наборами символов и уже кучу лет Юникод. Я не нашел ответа в доках MicroSoft. :-|

5. Упростить чтение файлов текстовых субтитров. И ничего не сломать. Ха-ха. Привет азиатским иероглифам.

6. Aleksoid1978 предлагает сделать автоопределение кодировки. У меня есть сомнения:
- Не особо то и нужно. Обычно хватает получить кодировку из системы. В редких случаях придется один раз указать вручную. Сомневаюсь, что есть пользователи, которые смотрят субтитры на нескольких языках (английский не в чет) да еще без UTF-8.
- Автоопределение кодировки ошибается. Если сейчас юзер может спокойно смотреть на системной или выбранной кодировке, то автоопределение кодировки начнет изредка портить ему настроение. А если не повезет, то и чаще.

Aleksoid1978

#3
Ну такой подход - "вряд ли смотрят на нескольких языках" - плохой, всякое бывает.
По мимо пользователей есть еще и разрабы, вот дадут что-то со словами "показывает не корректно", а мы и проверить не сможем, т.к. язык системы не тот.

Вот несколько субтитров в разных кодировках, по дефолту показывает только UTF-8 и CP1251, KOI-8 и GB18030 вообще ни как не показывает корректно, Японские - если только выбрать в настройках (но это надо еще узнать что это именно такая кодировка).
Разные сабы

А я же предлагаю самое нормальное решение - определение кодировки и конвертация в UTF16(wide строку) сразу при открытии и чтении строк. Это еще и код упростит/улучшит.

04 сентября 2025, 02:44:42
Сейчас там механизм не для Unicode - это просто ужас, чтение файла происходит в wide строку, далее каждый раз при запросе нужной строки для показа - чтение посимвольно как не wide и конвертация в UTF16 на основе charset из настройки. И так каждый раз как будет запрошена строка.
AMD Ryzen 7 7700 /ASRock B650M Pro RS /G.Skill RIPJAWS 32 ГБ /Kingston 1Tb M.2 /RTX 4060 /Samsung U28R550UQI /OLED Philips 55OLED707 /Yamaha RX-V471 + NS-555 + NS-C444 + NS-333 + YST-SW215

V0lt

#4
Цитата: Aleksoid1978 от 04 сентября 2025, 02:42:17Вот несколько субтитров в разных кодировках, по дефолту показывает только UTF-8 и CP1251, KOI-8 и GB18030 вообще ни как не показывает корректно, Японские - если только выбрать в настройках (но это надо еще узнать что это именно такая кодировка).
KOI-8 - это надуманный вариант. В реальности никто такие субтитры не использовал.
Про неродные субтитры на других языках Я уже писал в пункте 6.
GB18030 - тут похоже на баг, который возможно будет поправлен даже без автоопределения.

Цитата: Aleksoid1978 от 04 сентября 2025, 02:42:17Сейчас там механизм не для Unicode - это просто ужас
Согласен. Я об этом смутно упомянул в пункте 5.
Это непросто так сделано, оно связано с реализацией CTextFile, которого тоже придется переделывать. Я как раз добрался до CTextFile...

Aleksoid1978

#5
Ну ладно - подожду все переделки и просто добавлю автодетект с удалением более не нужного кода :)


05 сентября 2025, 09:18:58
Цитата: V0lt от 04 сентября 2025, 19:28:37GB18030 - тут похоже на баг, который возможно будет поправлен даже без автоопределения.

Не выйдет.

05 сентября 2025, 10:23:29
А вот Корейский - его тоже вообще никак не показать у нас, ну кроме как наверное на Корейской винде.
AMD Ryzen 7 7700 /ASRock B650M Pro RS /G.Skill RIPJAWS 32 ГБ /Kingston 1Tb M.2 /RTX 4060 /Samsung U28R550UQI /OLED Philips 55OLED707 /Yamaha RX-V471 + NS-555 + NS-C444 + NS-333 + YST-SW215

V0lt

Цитата: Aleksoid1978 от 05 сентября 2025, 00:11:10А вот Корейский - его тоже вообще никак не показать у нас, ну кроме как наверное на Корейской винде.
На чужом языке спокойно смотрят субтитры в UTF-8. :‑p

В стандартной библиотеке есть что-нибудь универсальное для чтения файлов? std::ifstream?

V0lt

#7
Aleksoid1978, ты просил пример кривого автоопределения кодировки В Notepad++. Старые файлы не нашел, но буквально с первого раза сделал test.win1251.srt. Notepad++ v8.5.4 определяет кодировку, как Macintosh.

07 сентября 2025, 13:43:04
Цитата: Aleksoid1978 от 04 сентября 2025, 02:42:17Разные сабы

Цитата: Aleksoid1978 от 05 сентября 2025, 00:11:10А вот Корейский - его тоже вообще никак не показать у нас, ну кроме как наверное на Корейской винде.
Переименуй пожалуйста эти файлы, чтобы было понятно какие кодировки используются.

Aleksoid1978

AMD Ryzen 7 7700 /ASRock B650M Pro RS /G.Skill RIPJAWS 32 ГБ /Kingston 1Tb M.2 /RTX 4060 /Samsung U28R550UQI /OLED Philips 55OLED707 /Yamaha RX-V471 + NS-555 + NS-C444 + NS-333 + YST-SW215

V0lt

#9
В дополнение к теме.

Некоторый современный софт прописывает в манифесте activeCodePage=UTF-8. Для чего это нужно не очень понятно. Возможно, чтобы обмениваться сообщениями с мультиплатформенным софтом, который недолюбливает широкие строки (UTF-16). Еще это может быть связано с консолью.

Плееру MPC-BE такое изменение в манифесте противопоказано. Функция GetACP() выдаст 65001, а не системную 1251. Идентификатор CP_ACP также будет подразумевать UTF-8. В итоге поломаются все преобразования строк из системной кодировки. Это затронет старые внешние субтитры и теги в формате ID3v1.

В общем ничего не меняем. :-)

13 октября 2025, 07:00:56
PS: Если вы пишите приложение, которому понадобилось прописать activeCodePage=UTF-8 в манифесте, то чтобы получить системную кодировку можно использовать такое код:
UINT value;
int ret = GetLocaleInfoW(GetSystemDefaultLCID(),
    LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
    (LPWSTR)&value, sizeof(value) / sizeof(WCHAR));