diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e502ef6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "src/contrib/libdvdnav"] + path = src/contrib/libdvdnav + url = https://github.com/xbmc/libdvdnav +[submodule "src/contrib/libdvdcss"] + path = src/contrib/libdvdcss + url = https://github.com/xbmc/libdvdcss +[submodule "src/contrib/libid3tag"] + path = src/contrib/libid3tag + url = https://github.com/tenacityteam/libid3tag +[submodule "src/contrib/libjpeg"] + path = src/contrib/libjpeg + url = https://github.com/thorfdbg/libjpeg +[submodule "src/contrib/libmad"] + path = src/contrib/libmad + url = https://github.com/markjeee/libmad diff --git a/doc/avi-idx.txt b/doc/avi-idx.txt new file mode 100644 index 0000000..ecf633d --- /dev/null +++ b/doc/avi-idx.txt @@ -0,0 +1,92 @@ +Индексы в АВИ. + +ВНИМАНИЕ!!!!!!!!!!!! ИНДЕКС - БЕЗ ДЫРОК!!!!!!!!! + +Варианты: +1) у файла нет индексов +2) есть только расширенный индекс (indx) +3) есть обычный индекс: + а) + - оффсеты относительные (с начала movi) + - оффсеты абсолютные (с начала файла) + б) + - кейфреймам можно доверять + - кейфреймам нельзя доверять + +Из этого всего нам нужно строить наш внутренний индекс. + +--------------------------------- +индекс нужен: +1) для перемотки вперед +2) для перемотки назад +3) для поиска + +ВСЕ ключевые кадры, на которых мы были (при проигрывании), попадают в индекс! + +------------------------------ +А МОЖЕТ, НАМ НУЖЕН ЕДИНЫЙ СВЯЗАННЫЙ СПИСОК КЛЮЧЕВЫХ КАДРОВ??! +- плюсы: + - легко вставлять кадры произвольно, не надо аллокейтить лишнее место + - можно использовать единую кучу-хранилище кадров, и делать ссылки на неё в связанном списке + - список только растёт, не надо ничего удалять. +- минусы: + - нужна доп. инфа о том, является ли след./пред. кадр действительно следующим, или между ними + могут быть ещё кадры + - для поиска нужно обойти в цикле весь список += ДА! +---------------------------------- + +ИНДЕКС = связанный список КЛЮЧЕВЫХ КАДРОВ + +КЛЮЧЕВОЙ КАДР: + - абс. номер кадра, int + * по номеру определяем время кадра (pts) + * находим данные в индексах AVI + - смещение к этому кадру относительно начала файла, int64 + - индексы к next,prev, int + * старший бит = 1 --> между ними больше нет кадров + +--------------------------- +ЗАДАЧИ: +1) добавлять в индекс текущий (проигрываемый) ключевой кадр +2) искать и добавлять следующий(-ие)/предыдущий(-ие) КК +3) искать и добавлять КК по временной метке + +ЗАДАЧА 1. +- храним указатель на последний проигрываемый кадр +- ищем след. кадр в индексе, больший по номеру, чем текущий. +- если текущего в индексе нет, вставляем его перед следущим. +- присваиваем: последний = текущий. + +ЗАДАЧА 2. +1) Если AVI-индекса нет, то: + - предыдущий кадр искать не надо - он уже должен быть в списке + (мы не могли прыгнуть, не заполнив весь индекс от начала до текущего момента) + - для след.кадра - идём по файлу вперёд, кадр за кадром, ищем ключевой + - добавляем его в индекс, если его ещё нет (см. флаг в next/prev). +2) Если есть AVI-индекс, то: + - прыгаем к данным индекса по номеру текущего кадра + - читаем блок данных для последующих/предыдущих индексов + - находим в блоке все ключевые кадры + - добавляем их в наш индекс, если их там ещё нет (см. флаги в next/prev). + +ЗАДАЧА 3. +- вначале пробегаем индекс и ищем 2 КК, между которыми должна находится временная метка. + если между ними больше нет кадров, возвращаем 1-й. +- иначе: +1) Если AVI-индекса нет, то: + - в индексе ищем ближайший к временной метке КК (перед). + - сканируем, начиная с него, вперёд все кадры, и ищем КК _после_ временной метки. + - добавляем всех их в индекс + - возвращаем предпоследний КК. +2) Если есть AVI-индекс, то: + - в индексе ищем ближайший к временной метке КК (перед). + - прыгаем к данным индекса по этому номеру КК + - загружаем весь индекс, начиная с него блоками + - парсим блоки и добавляем все КК, пока не встретим номер кадра, больший чем временная метка + + + + + + diff --git a/doc/divx3-discuss.txt b/doc/divx3-discuss.txt new file mode 100644 index 0000000..4c3aa94 --- /dev/null +++ b/doc/divx3-discuss.txt @@ -0,0 +1,57 @@ +Задача: транскодировать поток дивх3 в мпег4. +Поток состоит из отдельных кадров, каждый из которых транскодируется независимо. Задача сводится к транскодированию кадра. + +Чтобы это сделать, надо дать ответы на 2 вопроса: +1) Что именно хранится в кадре +2) Как именно хранится. +Ответ на 1-й вопрос _почти_ одинаков для дивх3 и мпег4. +Ответ на 2-й вопрос - существенные отличия. + +Хранятся данные в виде последовательности битов. Суть процесса - прочитать биты кадра дивх3, понять, что именно там хранится, и записать это в виде битов в формате мпег4 + +Кадр делится на макроблоки размером 16 x 16 пикселей. +Кадр хранит: +- заголовок (хранится тип кадра, индексы в таблицы с данными, необходимые для работы и т.п.) +- данные всех макроблоков. + +Т.е. фильм разрешения 640x480 содержит 40*30=1200 макроблоков в каждом кадре. + +Каждый макроблок (в дальнейшем - МБ) хранит: +- заголовок МБ +- 6 каналов данных (4 на яркость и 2 на цветность) + +МБ может быть двух видов: +- интра (независим от других кадров) +- интер (строится на основе предыдущих кадров) +Кадры I-frame состоят только из интра-макроблоков, а кадры P-frame могут иметь как те, так и другие. + +Данные каждого канала МБ зависят от типа МБ: +- для интра-МБ хранится DC-уровень (что-то типа "усреднённого цвета" блока) и AC-коэффициенты (отклонения от этого уровня) +- для интер-МБ хранится вектор движения (т.е. куда мы должны передвинуть старый МБ, чтобы получить нынешний) и AC-коэффициенты (чтобы устранить огрехи при таком передвижении и добавить новые детали картинки) +Т.е. общий принцип хранения данных - базовое значение и данные для его коррекции. + +И это справедливо и для дивх3, и для мпег4. Более того, похожий принцип работает и в mpeg1-2. + +Стандарт мпег4 умеет больше, но мы это не рассматриваем. Я рассказываю лишь в рамках, необходимых для транскодера. + +АС-коэффициенты - это как раз то, где заложен "битрейт". Чем больше этих коэффициентов, тем более качественное видео, и тем больше оно занимает. Эти коэффициенты как бы распределяются между всеми пикселями - каждому пикселю достаётся чуть-чуть. Если захочешь узнать про это побольше, вот ключевые слова: +- дискретное косинусное преобразование (DCT) +- преобразование Фурье + +Далее. Основные уровни DC и motion vectors (MV) записываются не напрямую. Для каждого нового МБ по специальному алгоритму определяется "предсказание" - т.е. какое бы там могло бы быть значение DC или MV (на основании соседних МБ и МБ нескольких прошлых кадров). И записывается разница между предсказанным и реальным. +Поэтому, для декодирования, чтобы получить реальное значение этих уровней, нужно параллельно тоже делать предсказания, чтобы прибавить к ним записанную разницу. + +Все эти исхищрения делаются только с одной целью - чтобы записанные в файл данные занимали как можно меньше. Достигается это с помощью особого метода кодирования этих всех чисел. Называется оно: "код переменной длины" (VLC), и используется во всех алгоритмах сжатия данных. Смысл в том, что разные числа кодируются разным количеством бит. + +Все числа в потоке бит идут одно за другим, но, поскольку каждое занимает разное число бит, нам необходимо читать их все подряд. Если хотя бы в одном числе ошибка - все остальные числа будут прочитаны совершенно другими. + +Для работы этого кодирования нужны VLC-таблицы, которые говорят, какие числа какой последовательностью бит кодировать. +Вот вроде бы и всё. +Теперь какие отличия. Отличаются: +- формат записи заголовков кадров и МБ +- методы предсказания DC и MV +- порядок следования AC-коэффициентов +- VLC-таблицы + +------------------------------------- + diff --git a/doc/power.txt b/doc/power.txt new file mode 100644 index 0000000..b80bb4f --- /dev/null +++ b/doc/power.txt @@ -0,0 +1,41 @@ + +В рамках тестирования плеерного кода нашей прошивки провёл +маленький эксперимент, связанный с программным отключением. +(см. также опрос на сайте). + +Померял (косвенно и очень грубо, погрешность оценить трудно ;-)) +потребляемую мощность плеера (даю средние значения): +1. "Родная" прошивка. +- включен, в ждущем режиме: [b]12.5[/b] Вт +- проигрывание DVD: [b]14..15[/b] Вт (*) +- отключен по кнопке пульта ДУ + - с диском: [b]13,2[/b] Вт + - без диска: [b]11,4[/b] Вт + +2. Наша прошивка. +- включен, в ждущем режиме: [b]12,6[/b] Вт +- проигрывание DVD: [b]14..15[/b] Вт (*) +- отключен по кнопке пульта ДУ + - с диском: [b]11,4[/b] Вт (**) + - без диска: [b]11,4[/b] Вт + +3. Процесс прошивки (flash): [b]14.5[/b] Вт + +(*) - сильно колеблется в зависимости от потребления DVD-привода. +(**) - это стало возможным благодаря специально сделанной программной +остановке шпинделя привода при переходе в спящий режим. + +Температурные режимы процессора не мерял, но на ощупь, в спящем режиме +процессор заметно холоднее, как и должно быть (и как у родной прошивки) +- в основном, я думаю, за счёт отключения видео-тракта. + +Выводы: +1) Энергосберегающие возможности спящего режима нашей прошивки не хуже +"родной", и кнопкой Power можно пользоваться. +2) При выключении с пульта (спящий режим) с диском внутри +энергопотребление у нашей прошивки сравнимо со спящим режимом без диска, +шум также отсутствует. Это, как мне кажется, - очко в пользу нашей прошивки +по сравнению с "родной". +3) Кое-какие тонкости отключения, сделанные в "родной" прошивке, могли быть +упущены. В первую очередь, это касается DVI-выхода, которого у меня нет. +Также не уверен на счёт SCART'а. diff --git a/doc/subtitles.txt b/doc/subtitles.txt new file mode 100644 index 0000000..4952abe --- /dev/null +++ b/doc/subtitles.txt @@ -0,0 +1,183 @@ +АЛГОРИТМ: +- читаем весь файл в память +- детектим тим пубтитров по первым 512 байтам. Пробегаем побайтово по данным, для каждого из форматов субтитра. +- тот формат, который оказался _первым_ и есть искомый формат. +- если НЕПУСТЫЕ субтитры пересекаются, надо склеивать их (проверять в отдельном проходе). +- если 2 субтитра идут в одно и то же время, то надо показывать их по очереди кадр за кадром (а не все сразу) + (некоторые субтитры в файлах - с точностью до секунды, и происходят накладки) +- работаем примерно так: + 1) задаём фильтр для поиска записи в виде набора лексем (массив). + - лексема = набор спец.символов маски: + 0 = число + 1 = 1 цифра + 2 = 2 цифры + ... + " " = пробел + \n = \n + - строка? + - для каждой лексемы задаём: + - как трактовать значение + - никак + - секунда начала + - минисекунда конца + - дельта времени начала + ... + - флаги + - обязательно ли должна присутствовать + - + +=========================================================== +Разделители строк: +"\n", "|", "[br]", "\\N" + +=========================== + +ВИДЫ СУБТИТРОВ: + +1) SubRip (.srt) +------------------------------------ +408 +00:57:23,678 --> 00:57:29,845 +I've been looking for you for two days. There are five +wraiths behind you. Where the other four are I do not know. + +------------------------------------ +SUB_SECTION_START: +{ SUB_TOKEN_HOUR1, ":", SUB_TOKEN_MIN1, ":", SUB_TOKEN_SEC1, SUB_TOKEN_OPTIONAL_NEXT, ",", SUB_TOKEN_OPTIONAL_NEXT, SUB_TOKEN_MSEC1," --> ", + SUB_TOKEN_HOUR2, ":", SUB_TOKEN_MIN2, ":", SUB_TOKEN_SEC2, SUB_TOKEN_OPTIONAL_NEXT, ",", SUB_TOKEN_OPTIONAL_NEXT, SUB_TOKEN_MSEC2, "\n", + NULL +} + +SUB_SECTION_END: +"\n\n" + +2) SubViewer 1.0 (.sub) +------------------------------------ +[00:57:23] +I've been looking for you for two days. There are five |wraiths behind you. Where the other four are I do not know. +------------------------------------ +SUB_SECTION_START: +{ "[", SUB_TOKEN_HOUR1, ":", SUB_TOKEN_MIN1, ":", SUB_TOKEN_SEC1, "]\n", + NULL +} + +SUB_SECTION_END: +"\n[" + +3) SubViewer 2.0 (.sub) +------------------------------------ +00:57:23.67,00:57:29.84 +I've been looking for you for two days. There are five [br]wraiths behind you. Where the other four are I do not know. + +------------------------------------ +SUB_SECTION_START: +{ SUB_TOKEN_HOUR1, ":", SUB_TOKEN_MIN1, ":", SUB_TOKEN_SEC1, ".", SUB_TOKEN_DSEC1, ",", + SUB_TOKEN_HOUR2, ":", SUB_TOKEN_MIN2, ":", SUB_TOKEN_SEC2, ".", SUB_TOKEN_DSEC2, "\n", + NULL +} + +SUB_SECTION_END: +"\n\n" + +4) DVDSubtitle (.sub) +------------------------------------ +{T 00:00:21:51 +this is a test! +} +------------------------------------ +SUB_SECTION_START: +{ "{T ", SUB_TOKEN_HOUR1, ":", SUB_TOKEN_MIN1, ":", SUB_TOKEN_SEC1, ":", SUB_TOKEN_DSEC1, "\n", + NULL +} +SUB_SECTION_END: +"}" + +5) DVD Architect (.sub) +------------------------------------ +0407 00:57:23:67 00:57:29:84 I've been looking for you for two days. There are five +wraiths behind you. Where the other four are I do not know. +------------------------------------ +SUB_SECTION_START: +{ SUB_TOKEN_SKIP_DIGITS_4, "\t", SUB_TOKEN_HOUR1, ":", SUB_TOKEN_MIN1, ":", SUB_TOKEN_SEC1, ":", SUB_TOKEN_DSEC1, "\t", + SUB_TOKEN_HOUR2, ":", SUB_TOKEN_MIN2, ":", SUB_TOKEN_SEC2, ":", SUB_TOKEN_DSEC2, "\t", + NULL +} + +SUB_SECTION_END: +"\n\n" + +6) MicroDVD (.sub) +------------------------------------ +{1}{1}29.997 +{103300}{103485}I've been looking for you for two days. There are five |wraiths behind you. Where the other four are I do not know. +------------------------------------ + * N = secs*25.000+msecs*25.000/1000 +SUB_SECTION_START: +{ "{", SUB_TOKEN_FRAMES1, "}{", SUB_TOKEN_FRAMES2, "}", + NULL +} +SUB_SECTION_END: +"\n" + +7) MPSub (.sub) +------------------------------------ +1.67 6.17 +I've been looking for you for two days. There are five +wraiths behind you. Where the other four are I do not know. + +------------------------------------ + * 1st - delta_T (in secs) to wait + * 2nd - delta_T (in secs) to display +SUB_SECTION_START: +{ SUB_TOKEN_DELTA_SECS1, " ", SUB_TOKEN_DELTA_SECS2, "\n", + NULL +} +SUB_SECTION_END: +"\n\n" + +================================================= + +8) TMPlayer (.sub) +------------------------------------ +00:57:23,1=I've been looking for you for two days. There are five +00:57:23,2=wraiths behind you. Where the other four are I do not know. +00:57:29,1= +00:57:29,2= +------------------------------------ +SUB_SECTION_START: +{ + SUB_TOKEN_HOUR1, ":", SUB_TOKEN_MIN1, ":", SUB_TOKEN_SEC1, ",", SUB_TOKEN_LINE_NUMBER, "=", + NULL +} +SUB_SECTION_END: +"\n" + +9) SubSonic (.sub) +------------------------------------ +1 115.68 \ ~:\I've been looking for you for two days. There are five wraiths behind you. Where the other four are I do not know. +1 121.84 +------------------------------------ + ***** период в 256 секунд? +SUB_SECTION_START: +{ + "1 ", SUB_TOKEN_SEC1_256, ".", SUB_TOKEN_DSEC1_256, SUB_TOKEN_SKIP_NEXT_FOR_2, " \ ~:\", + NULL +} +SUB_SECTION_END: +"\n" + +10) SubStation Alpha (.ssa) +------------------------------------ +Dialogue: Marked=0,0:57:23.67,0:57:29.84,Default,NTP,0000,0000,0000,!Effect,I've been looking for you for two days. There are five \Nwraiths behind you. Where the other four are I do not know. +------------------------------------ +SUB_SECTION_START: +{ + SUB_TOKEN_SKIP_TO_NEXT, ",", SUB_TOKEN_HOUR1_1, ":", SUB_TOKEN_MIN1, ":", SUB_TOKEN_SEC1, ".", SUB_TOKEN_DSEC1, ",", + SUB_TOKEN_HOUR2_1, ":", SUB_TOKEN_MIN2, ":", SUB_TOKEN_SEC2, ".", SUB_TOKEN_DSEC2, ",", + SUB_TOKEN_SKIP_TO_NEXT, ",", SUB_TOKEN_SKIP_TO_NEXT, ",", SUB_TOKEN_SKIP_TO_NEXT, ",", + SUB_TOKEN_SKIP_TO_NEXT, ",", SUB_TOKEN_SKIP_TO_NEXT, ",", SUB_TOKEN_SKIP_TO_NEXT, ",", + NULL +} +SUB_SECTION_END: +"\n" + diff --git a/doc/why_our_firmware_is_better.txt b/doc/why_our_firmware_is_better.txt new file mode 100644 index 0000000..04623ce --- /dev/null +++ b/doc/why_our_firmware_is_better.txt @@ -0,0 +1,8 @@ +- возможность подключить жёсткий диск к вашему плееру: полноценная поддержка нескольких разделов в NTFS и FAT +- поддержка файлов AVI размером более 2 Гбайт +- окошко поиска по фильмам AVI и DVD имеет расширенный интерфейс +- более быстрая перемотка для фильмов AVI +- более быстрое воспроизведение фильмов с видео-кодеком DivX3 +- при выключении плеера с пульта, плеер не шумит (если был вставлен диск) и меньше греется во время сна +- список файлов имеет полосу прокрутки для более удобной навигации +- главное: непрекращающаяся поддержка прошивки со стороны разработчиков :-) \ No newline at end of file diff --git a/fonts/Central23.fnt b/fonts/Central23.fnt new file mode 100644 index 0000000..fa756cb Binary files /dev/null and b/fonts/Central23.fnt differ diff --git a/fonts/Central38.fnt b/fonts/Central38.fnt new file mode 100644 index 0000000..bb809b4 Binary files /dev/null and b/fonts/Central38.fnt differ diff --git a/fonts/Cyr24.fnt b/fonts/Cyr24.fnt new file mode 100644 index 0000000..a4642b5 Binary files /dev/null and b/fonts/Cyr24.fnt differ diff --git a/fonts/Cyr27.fnt b/fonts/Cyr27.fnt new file mode 100644 index 0000000..27069b4 Binary files /dev/null and b/fonts/Cyr27.fnt differ diff --git a/fonts/West23.fnt b/fonts/West23.fnt new file mode 100644 index 0000000..a91d4d4 Binary files /dev/null and b/fonts/West23.fnt differ diff --git a/fonts/West36.fnt b/fonts/West36.fnt new file mode 100644 index 0000000..4241a31 Binary files /dev/null and b/fonts/West36.fnt differ diff --git a/img/adjustment.gif b/img/adjustment.gif new file mode 100644 index 0000000..3d42ab6 Binary files /dev/null and b/img/adjustment.gif differ diff --git a/img/audoff.gif b/img/audoff.gif new file mode 100644 index 0000000..e7de905 Binary files /dev/null and b/img/audoff.gif differ diff --git a/img/audon.gif b/img/audon.gif new file mode 100644 index 0000000..76803d9 Binary files /dev/null and b/img/audon.gif differ diff --git a/img/cd.gif b/img/cd.gif new file mode 100644 index 0000000..0332da2 Binary files /dev/null and b/img/cd.gif differ diff --git a/img/close.gif b/img/close.gif new file mode 100644 index 0000000..9bf46ed Binary files /dev/null and b/img/close.gif differ diff --git a/img/defpreview.jpg b/img/defpreview.jpg new file mode 100644 index 0000000..55f40e6 Binary files /dev/null and b/img/defpreview.jpg differ diff --git a/img/dvd.gif b/img/dvd.gif new file mode 100644 index 0000000..f4ac26b Binary files /dev/null and b/img/dvd.gif differ diff --git a/img/dvdicon.gif b/img/dvdicon.gif new file mode 100644 index 0000000..914abaf Binary files /dev/null and b/img/dvdicon.gif differ diff --git a/img/foldericon.gif b/img/foldericon.gif new file mode 100644 index 0000000..782ef4a Binary files /dev/null and b/img/foldericon.gif differ diff --git a/img/fwicon.gif b/img/fwicon.gif new file mode 100644 index 0000000..b538a1e Binary files /dev/null and b/img/fwicon.gif differ diff --git a/img/lib.jpg b/img/lib.jpg new file mode 100644 index 0000000..5c4722f Binary files /dev/null and b/img/lib.jpg differ diff --git a/img/logontsc.jpg b/img/logontsc.jpg new file mode 100644 index 0000000..735a374 Binary files /dev/null and b/img/logontsc.jpg differ diff --git a/img/mediatop.gif b/img/mediatop.gif new file mode 100644 index 0000000..30856a4 Binary files /dev/null and b/img/mediatop.gif differ diff --git a/img/movieicon.gif b/img/movieicon.gif new file mode 100644 index 0000000..6b8a4c3 Binary files /dev/null and b/img/movieicon.gif differ diff --git a/img/movietop.gif b/img/movietop.gif new file mode 100644 index 0000000..dd594fe Binary files /dev/null and b/img/movietop.gif differ diff --git a/img/musicicon.gif b/img/musicicon.gif new file mode 100644 index 0000000..788882d Binary files /dev/null and b/img/musicicon.gif differ diff --git a/img/musictop.gif b/img/musictop.gif new file mode 100644 index 0000000..74a7414 Binary files /dev/null and b/img/musictop.gif differ diff --git a/img/mute.gif b/img/mute.gif new file mode 100644 index 0000000..072bb84 Binary files /dev/null and b/img/mute.gif differ diff --git a/img/open.gif b/img/open.gif new file mode 100644 index 0000000..d6d32b4 Binary files /dev/null and b/img/open.gif differ diff --git a/img/pal.act b/img/pal.act new file mode 100644 index 0000000..679445f Binary files /dev/null and b/img/pal.act differ diff --git a/img/photoff.gif b/img/photoff.gif new file mode 100644 index 0000000..674b143 Binary files /dev/null and b/img/photoff.gif differ diff --git a/img/photon.gif b/img/photon.gif new file mode 100644 index 0000000..6fd9b72 Binary files /dev/null and b/img/photon.gif differ diff --git a/img/picsicon.gif b/img/picsicon.gif new file mode 100644 index 0000000..88d0c97 Binary files /dev/null and b/img/picsicon.gif differ diff --git a/img/picstop.gif b/img/picstop.gif new file mode 100644 index 0000000..717aaf5 Binary files /dev/null and b/img/picstop.gif differ diff --git a/img/play-all.gif b/img/play-all.gif new file mode 100644 index 0000000..97a11d1 Binary files /dev/null and b/img/play-all.gif differ diff --git a/img/play-random.gif b/img/play-random.gif new file mode 100644 index 0000000..eab5cc6 Binary files /dev/null and b/img/play-random.gif differ diff --git a/img/player/angle.gif b/img/player/angle.gif new file mode 100644 index 0000000..c9b742d Binary files /dev/null and b/img/player/angle.gif differ diff --git a/img/player/audio.gif b/img/player/audio.gif new file mode 100644 index 0000000..2cdc75f Binary files /dev/null and b/img/player/audio.gif differ diff --git a/img/player/cancel.gif b/img/player/cancel.gif new file mode 100644 index 0000000..de31e1f Binary files /dev/null and b/img/player/cancel.gif differ diff --git a/img/player/corrupted.gif b/img/player/corrupted.gif new file mode 100644 index 0000000..58294d7 Binary files /dev/null and b/img/player/corrupted.gif differ diff --git a/img/player/fwd.gif b/img/player/fwd.gif new file mode 100644 index 0000000..01bafcc Binary files /dev/null and b/img/player/fwd.gif differ diff --git a/img/player/fwd16x.gif b/img/player/fwd16x.gif new file mode 100644 index 0000000..af5c91e Binary files /dev/null and b/img/player/fwd16x.gif differ diff --git a/img/player/fwd32x.gif b/img/player/fwd32x.gif new file mode 100644 index 0000000..3ee7299 Binary files /dev/null and b/img/player/fwd32x.gif differ diff --git a/img/player/fwd48x.gif b/img/player/fwd48x.gif new file mode 100644 index 0000000..63bbc99 Binary files /dev/null and b/img/player/fwd48x.gif differ diff --git a/img/player/fwd8x.gif b/img/player/fwd8x.gif new file mode 100644 index 0000000..f352a2c Binary files /dev/null and b/img/player/fwd8x.gif differ diff --git a/img/player/fwdfast.gif b/img/player/fwdfast.gif new file mode 100644 index 0000000..212c15a Binary files /dev/null and b/img/player/fwdfast.gif differ diff --git a/img/player/invalid.gif b/img/player/invalid.gif new file mode 100644 index 0000000..2b79e0b Binary files /dev/null and b/img/player/invalid.gif differ diff --git a/img/player/next.gif b/img/player/next.gif new file mode 100644 index 0000000..033f6b4 Binary files /dev/null and b/img/player/next.gif differ diff --git a/img/player/pause.gif b/img/player/pause.gif new file mode 100644 index 0000000..c2c8873 Binary files /dev/null and b/img/player/pause.gif differ diff --git a/img/player/play.gif b/img/player/play.gif new file mode 100644 index 0000000..7d084c8 Binary files /dev/null and b/img/player/play.gif differ diff --git a/img/player/popup.gif b/img/player/popup.gif new file mode 100644 index 0000000..74098e0 Binary files /dev/null and b/img/player/popup.gif differ diff --git a/img/player/prev.gif b/img/player/prev.gif new file mode 100644 index 0000000..ec6c440 Binary files /dev/null and b/img/player/prev.gif differ diff --git a/img/player/return.gif b/img/player/return.gif new file mode 100644 index 0000000..e8e3e51 Binary files /dev/null and b/img/player/return.gif differ diff --git a/img/player/rev.gif b/img/player/rev.gif new file mode 100644 index 0000000..ad31780 Binary files /dev/null and b/img/player/rev.gif differ diff --git a/img/player/rev16x.gif b/img/player/rev16x.gif new file mode 100644 index 0000000..c99cd93 Binary files /dev/null and b/img/player/rev16x.gif differ diff --git a/img/player/rev32x.gif b/img/player/rev32x.gif new file mode 100644 index 0000000..fbe45d9 Binary files /dev/null and b/img/player/rev32x.gif differ diff --git a/img/player/rev48x.gif b/img/player/rev48x.gif new file mode 100644 index 0000000..5ed4a67 Binary files /dev/null and b/img/player/rev48x.gif differ diff --git a/img/player/rev8x.gif b/img/player/rev8x.gif new file mode 100644 index 0000000..b01689d Binary files /dev/null and b/img/player/rev8x.gif differ diff --git a/img/player/revfast.gif b/img/player/revfast.gif new file mode 100644 index 0000000..1821428 Binary files /dev/null and b/img/player/revfast.gif differ diff --git a/img/player/slowfwd2x.gif b/img/player/slowfwd2x.gif new file mode 100644 index 0000000..9192dcf Binary files /dev/null and b/img/player/slowfwd2x.gif differ diff --git a/img/player/slowfwd4x.gif b/img/player/slowfwd4x.gif new file mode 100644 index 0000000..52ef37c Binary files /dev/null and b/img/player/slowfwd4x.gif differ diff --git a/img/player/slowfwd8x.gif b/img/player/slowfwd8x.gif new file mode 100644 index 0000000..f2c00f4 Binary files /dev/null and b/img/player/slowfwd8x.gif differ diff --git a/img/player/stepfwd.gif b/img/player/stepfwd.gif new file mode 100644 index 0000000..9132db2 Binary files /dev/null and b/img/player/stepfwd.gif differ diff --git a/img/player/stop.gif b/img/player/stop.gif new file mode 100644 index 0000000..9b014b6 Binary files /dev/null and b/img/player/stop.gif differ diff --git a/img/player/subtitle.gif b/img/player/subtitle.gif new file mode 100644 index 0000000..b5697c3 Binary files /dev/null and b/img/player/subtitle.gif differ diff --git a/img/player/subtitleoff.gif b/img/player/subtitleoff.gif new file mode 100644 index 0000000..8146276 Binary files /dev/null and b/img/player/subtitleoff.gif differ diff --git a/img/playlist-edit-off.gif b/img/playlist-edit-off.gif new file mode 100644 index 0000000..04c216d Binary files /dev/null and b/img/playlist-edit-off.gif differ diff --git a/img/playlist-edit-on.gif b/img/playlist-edit-on.gif new file mode 100644 index 0000000..b6caaee Binary files /dev/null and b/img/playlist-edit-on.gif differ diff --git a/img/playlist-modes.gif b/img/playlist-modes.gif new file mode 100644 index 0000000..033a930 Binary files /dev/null and b/img/playlist-modes.gif differ diff --git a/img/playlistoff.gif b/img/playlistoff.gif new file mode 100644 index 0000000..84f27c0 Binary files /dev/null and b/img/playlistoff.gif differ diff --git a/img/playliston.gif b/img/playliston.gif new file mode 100644 index 0000000..3b0c92f Binary files /dev/null and b/img/playliston.gif differ diff --git a/img/playlisttop.gif b/img/playlisttop.gif new file mode 100644 index 0000000..80feb8c Binary files /dev/null and b/img/playlisttop.gif differ diff --git a/img/playoff.gif b/img/playoff.gif new file mode 100644 index 0000000..21a57a2 Binary files /dev/null and b/img/playoff.gif differ diff --git a/img/playon.gif b/img/playon.gif new file mode 100644 index 0000000..aafb6a6 Binary files /dev/null and b/img/playon.gif differ diff --git a/img/returnoff.gif b/img/returnoff.gif new file mode 100644 index 0000000..681c1f8 Binary files /dev/null and b/img/returnoff.gif differ diff --git a/img/returnon.gif b/img/returnon.gif new file mode 100644 index 0000000..edc4cf7 Binary files /dev/null and b/img/returnon.gif differ diff --git a/img/screensaver.gif b/img/screensaver.gif new file mode 100644 index 0000000..2048b3c Binary files /dev/null and b/img/screensaver.gif differ diff --git a/img/scroll.gif b/img/scroll.gif new file mode 100644 index 0000000..e2c1aad Binary files /dev/null and b/img/scroll.gif differ diff --git a/img/scrollon.gif b/img/scrollon.gif new file mode 100644 index 0000000..6d7b6fc Binary files /dev/null and b/img/scrollon.gif differ diff --git a/img/selmovieicon.gif b/img/selmovieicon.gif new file mode 100644 index 0000000..af0b3d5 Binary files /dev/null and b/img/selmovieicon.gif differ diff --git a/img/selmusicicon.gif b/img/selmusicicon.gif new file mode 100644 index 0000000..112a806 Binary files /dev/null and b/img/selmusicicon.gif differ diff --git a/img/selpicsicon.gif b/img/selpicsicon.gif new file mode 100644 index 0000000..d02c6e8 Binary files /dev/null and b/img/selpicsicon.gif differ diff --git a/img/selsubticon.gif b/img/selsubticon.gif new file mode 100644 index 0000000..f0708b2 Binary files /dev/null and b/img/selsubticon.gif differ diff --git a/img/setup1.jpg b/img/setup1.jpg new file mode 100644 index 0000000..b398767 Binary files /dev/null and b/img/setup1.jpg differ diff --git a/img/setup2.jpg b/img/setup2.jpg new file mode 100644 index 0000000..002cbeb Binary files /dev/null and b/img/setup2.jpg differ diff --git a/img/ssaver.act b/img/ssaver.act new file mode 100644 index 0000000..604ecee Binary files /dev/null and b/img/ssaver.act differ diff --git a/img/subticon.gif b/img/subticon.gif new file mode 100644 index 0000000..a3c0142 Binary files /dev/null and b/img/subticon.gif differ diff --git a/img/subtoff.gif b/img/subtoff.gif new file mode 100644 index 0000000..d9e0608 Binary files /dev/null and b/img/subtoff.gif differ diff --git a/img/subton.gif b/img/subton.gif new file mode 100644 index 0000000..610dc4c Binary files /dev/null and b/img/subton.gif differ diff --git a/img/upfoldericon.gif b/img/upfoldericon.gif new file mode 100644 index 0000000..57dbd58 Binary files /dev/null and b/img/upfoldericon.gif differ diff --git a/img/vidoff.gif b/img/vidoff.gif new file mode 100644 index 0000000..2086cce Binary files /dev/null and b/img/vidoff.gif differ diff --git a/img/vidon.gif b/img/vidon.gif new file mode 100644 index 0000000..bb5bb82 Binary files /dev/null and b/img/vidon.gif differ diff --git a/img/vmodes/1080iyuv.gif b/img/vmodes/1080iyuv.gif new file mode 100644 index 0000000..d6f4b61 Binary files /dev/null and b/img/vmodes/1080iyuv.gif differ diff --git a/img/vmodes/480pyuv.gif b/img/vmodes/480pyuv.gif new file mode 100644 index 0000000..a8af128 Binary files /dev/null and b/img/vmodes/480pyuv.gif differ diff --git a/img/vmodes/576pyuv.gif b/img/vmodes/576pyuv.gif new file mode 100644 index 0000000..9de3afa Binary files /dev/null and b/img/vmodes/576pyuv.gif differ diff --git a/img/vmodes/720pyuv.gif b/img/vmodes/720pyuv.gif new file mode 100644 index 0000000..7a3b84e Binary files /dev/null and b/img/vmodes/720pyuv.gif differ diff --git a/img/vmodes/ntsccompyc.gif b/img/vmodes/ntsccompyc.gif new file mode 100644 index 0000000..bcb71b8 Binary files /dev/null and b/img/vmodes/ntsccompyc.gif differ diff --git a/img/vmodes/ntsccompyuv.gif b/img/vmodes/ntsccompyuv.gif new file mode 100644 index 0000000..0424d38 Binary files /dev/null and b/img/vmodes/ntsccompyuv.gif differ diff --git a/img/vmodes/ntscscart.gif b/img/vmodes/ntscscart.gif new file mode 100644 index 0000000..9917c5e Binary files /dev/null and b/img/vmodes/ntscscart.gif differ diff --git a/img/vmodes/palcompyc.gif b/img/vmodes/palcompyc.gif new file mode 100644 index 0000000..09ff486 Binary files /dev/null and b/img/vmodes/palcompyc.gif differ diff --git a/img/vmodes/palcompyuv.gif b/img/vmodes/palcompyuv.gif new file mode 100644 index 0000000..e33aa2b Binary files /dev/null and b/img/vmodes/palcompyuv.gif differ diff --git a/img/vmodes/palscart.gif b/img/vmodes/palscart.gif new file mode 100644 index 0000000..cf0c7da Binary files /dev/null and b/img/vmodes/palscart.gif differ diff --git a/img/volbkgrnd.gif b/img/volbkgrnd.gif new file mode 100644 index 0000000..f85006d Binary files /dev/null and b/img/volbkgrnd.gif differ diff --git a/img/volpoint.gif b/img/volpoint.gif new file mode 100644 index 0000000..48621eb Binary files /dev/null and b/img/volpoint.gif differ diff --git a/img/wait.gif b/img/wait.gif new file mode 100644 index 0000000..5437fd0 Binary files /dev/null and b/img/wait.gif differ diff --git a/img/yes.gif b/img/yes.gif new file mode 100644 index 0000000..f5d6835 Binary files /dev/null and b/img/yes.gif differ diff --git a/img/zoomoff.gif b/img/zoomoff.gif new file mode 100644 index 0000000..120e262 Binary files /dev/null and b/img/zoomoff.gif differ diff --git a/img/zoomon.gif b/img/zoomon.gif new file mode 100644 index 0000000..81a0fa8 Binary files /dev/null and b/img/zoomon.gif differ diff --git a/mmsl/adjust.mmsl b/mmsl/adjust.mmsl new file mode 100644 index 0000000..b30d079 --- /dev/null +++ b/mmsl/adjust.mmsl @@ -0,0 +1,341 @@ +///////////////////////////////////////////// +// set current settings: +on load_adjustments > 0 + screen.brightness = settings.brightness + screen.contrast = settings.contrast + screen.saturation = settings.saturation +on load_adjustments == 1 + mute = 1 + player.volume = settings.volume + mute = 0 + +on player.volume == 0 + on load_adjustments == 1 + do_mute = 1 + +///////////////////////////////////////////// +// balloons (open/close/NA/...): + +on show_static_balloon != "" + balloon_timer = -1 + balloon_start_hidden = 0 + restore_timer_balloon = "" + show_balloon = show_static_balloon + +on show_timer_balloon != "" + balloon_timer = 3000 + balloon_start_hidden = 0 + restore_timer_balloon = "" + show_balloon = show_timer_balloon + +on show_fast_balloon != "" + balloon_timer = 1500 + balloon_start_hidden = 0 + restore_timer_balloon = "" + show_balloon = show_fast_balloon + +on show_fast_balloon_and_restore != "" + balloon_timer = 600 + balloon_start_hidden = 0 + restore_timer_balloon = restore_balloon + show_balloon = show_fast_balloon_and_restore + +on show_delayed_balloon != "" + balloon_timer = 300 + balloon_timer2 = 3000 + balloon_start_hidden = 1 + restore_timer_balloon = "" + show_balloon = show_delayed_balloon + balloon.visible = 0 + +on show_balloon == "" + delete .group == "balloon" + +on allow_balloons == 1 + on show_balloon != "" + delete .group == "balloon" + add image balloon + balloon.group = "balloon" + balloon.src = "img/" + show_balloon + ".gif" + balloon.x = screen.right - balloon.width + balloon.y = screen.top + balloon.timer = balloon_timer + +on restore_timer_balloon == "" + on balloon_start_hidden == 0 + on balloon.timer == 0 + delete .group == "balloon" + + on balloon_start_hidden == 1 + on balloon.timer == 0 + balloon.visible = 1 + balloon_start_hidden = 0 + balloon.timer = balloon_timer2 + +on restore_timer_balloon != "" + on balloon.timer == 0 + delete .group == "balloon" + show_static_balloon = restore_timer_balloon + +//////////////////////////// +// balloon text: + +on show_balloon_text != "" + add text balloon_text + balloon_text.group = "balloon" + balloon_text.valign = "center" + balloon_text.font = font2 + balloon_text.x = screen.right - balloon.width + 64 + balloon_text.y = screen.top + 28 + balloon_text.color = colors.yellow + balloon_text.backcolor = -1 + balloon_text.value = show_balloon_text + +/////////////////////////////////////////////// +// video modes: + +on pad.key == "vmode" + screen.switch = "next" + +on screen.tvstandard == "ntsc" && screen.tvout == "composite" + show_timer_balloon = "vmodes/ntsccompyc" +on screen.tvstandard == "ntsc" && screen.tvout == "ypbpr" + show_timer_balloon = "vmodes/ntsccompyuv" +on screen.tvstandard == "ntsc" && screen.tvout == "rgb" + show_timer_balloon = "vmodes/ntscscart" +on screen.tvstandard == "pal" && screen.tvout == "composite" + show_timer_balloon = "vmodes/palcompyc" +on screen.tvstandard == "pal" && screen.tvout == "ypbpr" + show_timer_balloon = "vmodes/palcompyuv" +on screen.tvstandard == "pal" && screen.tvout == "rgb" + show_timer_balloon = "vmodes/palscart" +on screen.tvstandard == "480p" && screen.tvout == "ypbpr" + show_timer_balloon = "vmodes/480pyuv" +on screen.tvstandard == "576p" && screen.tvout == "ypbpr" + show_timer_balloon = "vmodes/576pyuv" +on screen.tvstandard == "720p" && screen.tvout == "ypbpr" + show_timer_balloon = "vmodes/720pyuv" +on screen.tvstandard == "1080i" && screen.tvout == "ypbpr" + show_timer_balloon = "vmodes/1080iyuv" + +on screen.tvstandard != "" + load_adjustments = 2 + +/////////////////////////////////////////////////// +// Brightness/Contrast/Saturation: +on setup == 0 && adjustment == 0 && (drive.mediatype != "dvd" || dvd != 0) + on do_setup == 1 + do_setup = 0 + adjustment = 1 + delete .group == "vol" + delete .group == "volback" + add image adjback + adjback.group = "volback" + adjback.src = "img/adjustment.gif" + adjback.halign="center" + adjback.valign="bottom" + adjback.x = (screen.right + screen.left)/2 + adjback.y = screen.bottom + add rect adjcur + adjcur.group = "volback" + adjcur.x = adjback.x - 100 + adjcur.width = 230 + adjcur.height = 25 + adjcur.round = 5 + adjcur.color = colors.yellow + adjcur.backcolor = -1 + update_adj = 0 + cur_adj = cur_adj // update + +on adjustment == 0 + cur_adj = 0 + screen.update = 1 + +on adjustment == 1 + on adjback.timer == 0 + delete .group == "volback" + delete .group == "vol" + adjustment = 0 + settings.brightness = screen.brightness + settings.contrast = screen.contrast + settings.saturation = screen.saturation + + on cur_adj < 3 + on do_setup == 1 + do_setup = 0 + adjback.timer = 3000 + pad.key = "down" + + on cur_adj == 3 + on do_setup == 1 + adjback.timer = 0 + + on cur_adj >= 0 + adjcur.y = adjback.y - 130 + cur_adj * 30 + + on update_adj == 0 + screen.update = 0 + delete .group == "vol" + + on update_adj == 0 + adjback.timer = 3000 + adj_value = screen.brightness + adjclr = colors.darkblue + (cur_adj == 0) * 250 /* white */ + on update_adj == 1 + adj_value = screen.contrast + adjclr = colors.darkblue + (cur_adj == 1) * 250 /* white */ + on update_adj == 2 + adj_value = screen.saturation + adjclr = colors.darkblue + (cur_adj == 2) * 250 /* white */ + on update_adj == 3 + adj_value = (player.audio_offset + 5000) / 10 + adjclr = colors.darkblue + (cur_adj == 3) * 250 /* white */ + + + on update_adj >= 0 && update_adj < 4 + add rect adj + adj.group = "vol" + adj.x = adjback.x - 95 + adj_value * 212 / 1000 + adj.y = adjback.y - 125 + update_adj * 30 + adj.width = 7 + adj.height = 15 + adj.round = 2 + adj.color = -1 + adj.backcolor = adjclr + update_adj = update_adj + 1 + + on update_adj == 3 + screen.update = 1 + + on cur_adj < 0 + cur_adj = 3 + on cur_adj == 0 + on adj_plus != 0 + screen.brightness = screen.brightness + adj_plus + on cur_adj == 1 + on adj_plus != 0 + screen.contrast = screen.contrast + adj_plus + on cur_adj == 2 + on adj_plus != 0 + screen.saturation = screen.saturation + adj_plus + on cur_adj == 3 + on adj_plus != 0 + player.audio_offset = player.audio_offset + adj_plus * 5 + + + on pad.key == "left" || pad.key == "volume_down" + pad.key = "" + adj_plus = -20 + update_adj = 0 + + on pad.key == "right" || pad.key == "volume_up" + pad.key = "" + adj_plus = 20 + update_adj = 0 + + on pad.key == "up" || pad.key == "prev" + pad.key = "" + cur_adj = (cur_adj - 1) % 4 + update_adj = 0 + + on pad.key == "down" || pad.key == "next" + pad.key = "" + cur_adj = (cur_adj + 1) % 4 + update_adj = 0 + + on pad.key == "cancel" || pad.key == "return" + pad.key = "" + screen.brightness = 500 + screen.contrast = 500 + screen.saturation = 500 + player.audio_offset = 0 + update_adj = 0 + + on pad.key == "enter" + pad.key = "" + adjback.timer = 0 + +/////////////////////////////////////////////////// +// volume: + +on pad.key == "volume_up" + release_mute = 1 + player.volume = player.volume + 10 + +on pad.key == "volume_down" + release_mute = 1 + player.volume = player.volume - 10 + +on pad.key == "mute" + do_mute = 1 +on mute == 0 + on do_mute == 1 + do_mute = 0 + mute = 1 + saved_volume = player.volume + player.volume = 0 + add image muteballoon + muteballoon.group = "mute" + muteballoon.src = "img/mute.gif" + muteballoon.x = screen.right - muteballoon.width + muteballoon.y = screen.top + +on mute == 1 + on do_mute == 1 + do_mute = 0 + release_mute = 1 + + on release_mute == 1 + delete .group == "mute" + player.volume = saved_volume + mute = 0 + +on mute == 0 + on player.volume >= 0 + delete .group == "vol" + delete .group == "volback" + add image volback + volback.group = "volback" + volback.halign="center" + volback.valign="bottom" + volback.x = (screen.right + screen.left)/2 + volback.y = screen.bottom + volback.src = "img/volbkgrnd.gif" + vol_x = 0 + screen.update = 0 + vol_cnt = 0 + on vol_cnt < player.volume + add image vol + vol.group = "vol" + vol.x = volback.x - 90 + vol_x + vol.y = volback.y - 40 + vol.src = "img/volpoint.gif" + vol_x = vol_x + 19 + vol_cnt = vol_cnt + 10 + on vol_cnt >= player.volume + screen.update = 1 + volback.timer = 1000 + +on volback.timer == 0 + delete .group == "vol" + delete .group == "volback" + settings.volume = player.volume + +on player.volume == 0 + on volback.timer == 0 + do_mute = 1 + +/////////////////////////////////////////////////// +// Frame rate autodetect: + +on player.frame_rate == 25000 || player.frame_rate == 50000 + on autodetect_pal_ntsc == 1 + kernel.print = "Autodetect: PAL (" + player.frame_rate + " fps)" + screen.tvstandard = "pal" + autodetect_pal_ntsc = 0 +//on player.frame_rate == 23976 || (player.frame_rate >= 29000 && player.frame_rate <= 30000) || player.frame_rate == 60000 +on autodetect_pal_ntsc == 1 + kernel.print = "Autodetect: NTSC (" + player.frame_rate + " fps)" + screen.tvstandard = "ntsc" + autodetect_pal_ntsc = 0 + diff --git a/mmsl/doc/examples.txt b/mmsl/doc/examples.txt new file mode 100644 index 0000000..b2b5492 --- /dev/null +++ b/mmsl/doc/examples.txt @@ -0,0 +1,159 @@ +*** CONDITIONAL EXPRESSIONS *** + +How to execute a conditional expression only once, in the right place of code? + +// 1. First, the "silly" method: +i = a; +// here we want to check the new value of i: +on i == 4 + kernel.print = "number four!"; +// this will trigger printing "number four" once again if b=4! +i = b; + +// 2. Now, if we want to check only once (right after the 'i' set to 'a') then: +i = a; +// we'll check some unique variable with the same value instead of i: +checking_i = i; +on checking_i == 4 + kernel.print = "number four!"; +// now the block above will not be triggered anymore until checking_i is changed! +i = b; + + +*** LOOPS *** + +Simple loop - call some code N times: + +// 1. Set loop counter and number of repeats: +counter=0; N=10 + +// 2. The loop is a normal 'on' block: +on counter int(val)+4 + * "123" + 4 => 127 + * - otherwise, if one of the operands is string constant, the other is converted to string for concatenation; + * Examples: + * var = "a" + * var + "b" => "ab" + * - otherwise, if one of the operands is integer variable, the other is converted to integer; + * Examples: + * var1 = "2" + * var2 = 3 + * var1 + var2 => 5 + * - otherwise, both operands are considered as strings, and string concatenation used. + * 4. String-to-integer conversion: + * - "10 Monkeys" = 10 + * - "Opera 5" = 0 + * - " 1" = 1 + * - "-55.3" = -55 + * - "+12 15" = 12 + * - "no digits" = 0 + * 5. For other comparison operators (except ==), operands are considered integers + +================================================ +- MMSL Operators + * Arithmetic and Conditional expression operators: + * ::= Operator:: + * ::== Operator:: + * ::&& Operator:: + * ::|| Operator:: + * ::!= Operator:: + * ::> Operator:: + * ::< Operator:: + * ::>= Operator:: + * ::<= Operator:: + * ::+ Operator:: + * ::- Operator:: + * ::* Operator:: + * ::/ Operator:: + * ::% Operator:: + * + * Also special types of operators used for events and object addition and deletion statements: + * ::ON Operator:: + * ::ADD Operator:: + * ::DELETE Operator:: + +================================================ +- = Operator + * Syntax: + * [variable] = [variable or constant] + * Description: + * Simple assignment operator. + * Also the same as '==' in conditions. + * Example: + * a = b + * kernel.print = "Hello" +================================================ +- == Operator + * Syntax: + * [variable or constant] == [variable or constant] + * Description: + * Equality comparison operator. + * Used in conditional expressions. + * See: ::Type conversion::. + * Example: + * a == 5 + * mytext.value == "Hello" +================================================ +- && Operator + * Syntax: + * [expression] && [expression] + * Description: + * Logical-AND operator. + * Used in conditional expressions. + * Example: + * (a == 5) && (b != 3) +================================================ +- || Operator + * Syntax: + * [expression] || [expression] + * Description: + * Logical-OR operator. + * Used in conditional expressions. + * Example: + * (a > 5) || (a < -5) +================================================ +- != Operator + * Syntax: + * [variable or constant] != [variable or constant] + * Description: + * Non-Equality comparison operator. + * Used in conditional expressions. + * See: ::Type conversion::. + * Example: + * a != 5 + * mytext.value != "Hello" +================================================ +- > Operator + * Syntax: + * [integer variable or constant] > [integer variable or constant] + * Description: + * Relational 'greater than' operator. + * Used in conditional expressions. + * Example: + * a > 5 + * var1 > var2 +================================================ +- < Operator + * Syntax: + * [integer variable or constant] < [integer variable or constant] + * Description: + * Relational 'less than' operator. + * Used in conditional expressions. + * Example: + * a < 5 + * var1 < var2 +================================================ +- >= Operator + * Syntax: + * [integer variable or constant] >= [integer variable or constant] + * Description: + * Relational 'greater than or equal' operator. + * Used in conditional expressions. + * Example: + * a >= 5 + * var1 >= var2 +================================================ +- <= Operator + * Syntax: + * [integer variable or constant] <= [integer variable or constant] + * Description: + * Relational 'less than or equal' operator. + * Used in conditional expressions. + * Example: + * a <= 5 + * var1 <= var2 +================================================ +- + Operator + * Syntax: + * [variable or constant] + [variable or constant] + * Description: + * Addition/Concatenation operator. + * Used in arithmetic and conditional expressions. + * See: ::Type conversion::. + * Example: + * a + 5 + * mytext.value + "Hello" +================================================ +- - Operator + * Syntax: + * [integer variable or constant] - [integer variable or constant] + * Description: + * Subtraction operator. + * The subtraction operator (-) subtracts the second operand from the first. + * Both operands are considered integers. + * Used in arithmetic and conditional expressions. + * Example: + * a - 5 + * var1 - var2 +================================================ +- * Operator + * Syntax: + * [integer variable or constant] * [integer variable or constant] + * Description: + * Multiplication operator. + * The multiplication operator (*) causes its two operands to be multiplied. + * Both operands are considered integers. + * Used in arithmetic and conditional expressions. + * Example: + * a * 5 + * var1 * var2 +================================================ +- / Operator + * Syntax: + * [integer variable or constant] / [non-zero integer variable or constant] + * Description: + * Division operator. + * The division operator ( / ) causes the first operand to be divided by the second. + * Both operands are considered integers. + * If second operand is zero, the result is zero (and run-time warning is issued). + * Used in arithmetic and conditional expressions. + * Example: + * a / 5 + * var1 / var2 +================================================ +- % Operator + * Syntax: + * [integer variable or constant] % [non-zero integer variable or constant] + * Description: + * Modulus operator. + * The result of the modulus operator (%) is the remainder when the first operand is divided by the second. + * Both operands are considered integers. + * If second operand is zero, the result is zero (and run-time warning is issued). + * Used in arithmetic and conditional expressions. + * Example: + * a % 5 + * var1 % var2 +================================================ +- ON Operator + * Syntax: + * on [condition] + * [statements...] + * ... + * Description: + * Conditional Event operator. + * Triggers event when one of condition variables is set (to any value) inside MMSL script or by running program. + * When event is triggered, its statements are called - but only if condition of this event and its parent events' conditions are true. + * Object variables are not set implicitly when an object is created (and thus they won't trigger an event). + * Normally, the depending events are triggered immediately after conditional variable is set. + * Call recursion is not allowed directly. When one of triggered event's statements activates the same event, this next call is deferred untill the current event call runs to the end. + * Example: + * i = 1 + * on (i <= 5) + * add text mytxt; mytxt.x = 10; mytxt.y = i * 20; mytxt.value = "String "+i + * i = i + 1 +================================================ +- ADD Operator + * Syntax: + * add [object_type] [object_name] + * Description: + * Add Object operator. + * Creates a new object of given type and adds it to the pool. + * This operator is also some sort of a variable declaration. Thus every object name should be used only once. + * The statement itself can be called many times (when event is repeated), assigning a new object to the same variable each time. Old objects become nameless and cannot be accessed by variables anymore. However, the deletion operator works with all created objects. + * Built-in object types: + * - text + * * Creates a text object + * - image + * * Creates an image object + * - rect + * * Creates a rectangle object + * Example: + * add text hello + * hello.x = 100 + * hello.y = 200 + * hello.value = "Hello, world!" + * Example: + * add rect myrect + * myrect.x = 5; myrect.y = 7; myrect.width = 50; myrect.height = 10; +================================================ +- DELETE Operator + * Syntax: + * delete [condition] + * Description: + * Delete Objects operator. + * Object's variables must be used in comparison conditions (including object's name, type etc). + * Object variables are used as ".variablename", i.e. without object name or prefix. + * Warning! The 'delete' command needs to run through the object list, so it takes some time. + * Warning! On deletion, the object's variables are not triggered. There's no direct way to 'capture' the object deletion in events. + * Warning! If multiple objects match the condition, the deletion order is undetermined. + * Example: + * delete .group=="myrectangle" + * * An object of any type named 'myrectangle' will be deleted. + * Example: + * delete (.type=="rect") + * * All rectangles created will be deleted. + * Example: + * add text t1 + * t1.group = "g" + * add text t2 + * t2.group = "g" + * // ... + * delete (.group == "g") + * * One can use groups for simple deletion of all objects of the same kind + * Example: + * delrect.x1 = 10; delrect.y1 = 10; delrect.x2 = 100; delrect.y2 = 100; + * delete (.x <= delrect.x2 && .y <= delrect.y2 && \ + * .x+.width >= delrect.x1 && .y+.height >= delrect.y1) + * * Deletes all objects intersecting 'delrect' rectangle + * Example: + * delete 1 + * * Deletes all created objects! + * * Be careful using conditionals without object variables: such statement may delete all objects if it's true. +================================================ +- INCLUDE Command + * Syntax: + * include [string constant MMSL filename] + * Description: + * Inserts the code from another MMSL file. + * Include command is pre-processed, so only string constant can be specified as file name, no variables allowed. + * Examples: + * include "file.mmsl" + +================================================ + diff --git a/mmsl/doc/mmsl-misc.txt b/mmsl/doc/mmsl-misc.txt new file mode 100644 index 0000000..5d10be1 --- /dev/null +++ b/mmsl/doc/mmsl-misc.txt @@ -0,0 +1,51 @@ +=================================================================== + +- object + * Special built-in object - always equal to last created/accessed/modified object. + * Cannot be used in 'on' condition + - created + All objects have this member variable. + Set once - after the object's creation + - modified + All objects have this member variable. + Set to modified variable's name + - accessed + All objects have this member variable. + Set to accessed variable's name; Accessing means reading or modification + +- array + - count + - sort="normal", "inverse", "random" + - slice + - insert + - pos + ALIAS: position + * zero-based + - value + * contains a single array element, choosen by pos or jump + - jump + = "first" + = "last" + = "next" + = "prev" + +- string + * Can be used for text strings manipulation. + - value [r/w] + * string value - contains the string itself + - length [r/w] + * Read it to get string length. + * Set it to trim the string. + - from + * Set substring of current string starting from given character position. + * Can be used for character access too. + - find + * Cuts string to found substring + +- timer + - delta + * Time in milliseconds left before triggering timer (updating object) + * Will be set to zero when time elapses + + +=================================================================== diff --git a/mmsl/doc/mmsl-objects1.txt b/mmsl/doc/mmsl-objects1.txt new file mode 100644 index 0000000..96632d4 --- /dev/null +++ b/mmsl/doc/mmsl-objects1.txt @@ -0,0 +1,849 @@ + +- kernel + * Base firmware settings and control. + - power [w/o] + * Can be set by script to switch the player, but normally is set automatically via 'POWER' button. + = 0 + * Set it to turn the player off + = 1 (default) + * Set by default when the player started and initialized or when it is turned on + * When the player is turned off (suspended), mmsl events are not triggered. + = 2 + * halt firmware + - frequency [r/w] + * Get or set CPU frequency (for experts only!) + - chip [r/o] + * Get player chip revision string. + - free_memory [r/o] + * Get free kernel memory, bytes. + - flash_memory [r/o] + * Get Flash memory size, in bytes. + - print [w/o] + * Output a string to debug console (Press 'P/N' to show or hide console on the screen) + - firmware_version [r/o] + * Current version of firmware kernel + - mmsl_version [r/o] + * Current version of MMSL interpreter + - mmsl_errors [r/w] + * Filter console messages + = "none" (default, no error logging) + = "critical" (only critical errors reported) + = "general" (only general & critical errors reported) + = "all" (all errors & warnings) + - run [w/o] + * Run external binary file (Ex: kernel.run="file.bin") + * Maximum 20 arguments allowed (space-separated). + - random [r/o] + * Get a random number (0..32767) + +======================================================================================= + +- screen + * On-screen display (OSD) object with different settings. + * Use separate graphical objects for user interface. + - switch [r/w] + * Turns the screen on or off + = 0 + * The screen is turned off automatically when kenrel.power=0 + = 1 (default) + = "next" + * switch next video mode + - update [r/w] + = 0 + * Turns screen auto-update off + = 1 + * Turns screen auto-update on + = "now" + * Update the screen now + - tvstandard [r/w] + * TV standard. + = "pal" (default) + = "ntsc" + - tvout [r/w] + * TV output. + = "composite" (default) + * Composite/S-Video + = "ypbpr" + * Component/YPbPr + = "rgb" + * Composite/RGB via SCART + - left [r/o] + * TV-safe visible area rectangle left x coordinate, in pixels. + - top [r/o] + * TV-safe visible area rectangle top y coordinate, in pixels. + - right [r/o] + * TV-safe visible area rectangle right x coordinate, in pixels. + - bottom [r/o] + * TV-safe visible area rectangle bottom y coordinate, in pixels. + - palette [r/w] + * External 256-color palette file name (.ACT) + * Also resets all alpha values to defaults (255). + - palidx [w/o] + * Used for setting alpha or color value. See 'palalpha' and 'palcolor'. + = 0-255 + - palalpha [r/w] + * Set new alpha value to the current palette. See 'palidx'. + = 0-255 (255 = opaque, default for all indices) + - palcolor [r/w] + * Set new color value to the current palette. See 'palidx'. + = "#000000"-"#ffffff" or 24-bit integer + - font [r/w] + * Default font used for new text objects. Set it to the font file name (external .FNT file). + - color [r/w] + * Color index for font & drawing operations (default value for new objects) + = 0-255 + - backcolor [r/w] + * Background color index for font & drawing operations (default value for new objects) + = 0-255 + = -1 (default) + * For transparent background ('trcolor' value is used) + - trcolor [r/w] + * Transparent color index + = 0 (default) + - halign [r/w] + * Default horizontal text (and other objects') align, used for created objects + = "left" (default) + = "center" + = "right" + - valign [r/w] + * Default hertical text (and other objects') align, used for created objects + = "top" (default) + = "center" + = "bottom" + - back [r/w] + * JPEG file name for background image + = "" (default) + * For black background + - back_left [r/w] + * Left coordinate of JPEG output rect, in background pixels (0..719). + * Used for picture previews. + = 0 (default) + - back_top [r/w] + * Top coordinate of JPEG output rect, in background pixels (0..479). + * Used for picture previews. + = 0 (default) + - back_right [r/w] + * Right coordinate of JPEG output rect, in background pixels (0..719). + * Used for picture previews. + * For external images (not from flash memory), auto aspect-ration correction is used. + = 719 (default) + - back_bottom [r/w] + * Bottom coordinate of JPEG output rect, in background pixels (0..479). + * Used for picture previews. + = 479 (default) + - preload [w/o] + * Pre-load GIF image in memory. Set it to .gif file path. + = "" (default) + * Set it to empty string to unload all images from memory. + - hzoom [r/w] + * Used to scale background image or video horizontally, in percents + = "in" + = "out" + = 100 (default) + = 10-1000 + * Set zoom value in percents + - vzoom [r/w] + * Used to scale background image or video vertically, in percents + = "in" + = "out" + = 100 (default) + = 10-1000 + * Set zoom value in percents + - hscroll [r/w] + * Horizontal offset for background image or video (<0 for left, >0 for right). + = 0 (default) + - vscroll [r/w] + * Vertical offset for background image or video (<0 for left, >0 for right). + = 0 (default) + - rotate [r/w] + * Used for background image, in degrees + = 0 (default) + = 0,90,180,270 + = "auto" + * Set this to auto-detect image orientation (using Exif data). + - brightness [r/w] + * Set TV brightness + = 0..1000 + = 500 (default) + - contrast [r/w] + * Set TV contrast + = 0..1000 + = 500 (default) + - saturation [r/w] + * Set TV saturation + = 0..1000 + = 500 (default) + - fullscreen [r/w] + * Set OSD fullscreen mode + = 0 (default) + * OSD has 30/31 height by default. + = 1 + * Full height, 480 pixels. + +======================================================================================= + +- pad + * Front panel and IR-remove control object. Needed to process user input. + - key [r/o] + * Key code pressed by user. Keys for IR-remote and front panel are combined. + = "power" + = "eject" + = "one" + = "two" + = "three" + = "four" + = "five" + = "six" + = "seven" + = "eight" + = "nine" + = "zero" + = "cancel" + = "search" + = "enter" + = "osd" + = "subtitle" + = "setup" + = "return" + = "title" + = "pn" + = "menu" + = "ab" + = "repeat" + = "up" + = "down" + = "left" + = "right" + = "volume_down" + = "volume_up" + = "pause" + = "rewind" + = "forward" + = "prev" + = "next" + = "play" + = "stop" + = "slow" + = "audio" + = "vmode" + = "mute" + = "zoom" + = "program" + = "pbc" + = "angle" + - display [w/o] + * To display the string to the front panel. + - set [w/o] + * Set special symbol of the front panel display. + = "play" + * 'Play' symbol. + = "pause" + * 'Pause' symbol. + = "mp3" + * 'MP3' symbol. + = "dvd" + * 'DVD' symbol. + = "s" + * 'SVCD' symbol part. + = "v" + * 'VCD' symbol part. + = "cd" + * 'CD' symbol. + = "dolby" + * Dolby digital sound. + = "dts" + * DTS sound. + = "play_all" + * Play All. + = "play_repeat" + * Play Repeat. + = "pbc" + * VCD Playback Control. + = "camera" + * DVD camera/angle. + = "colon1" + * First ':'. + = "colon2" + * Second ':' + - clear [w/o] + * Clear entire front panel display or one special symbol. + * See also ::pad.set:: for possible special symbol values. + = "all" + * Clear entire display + +======================================================================================= + +- drive + * DVD player's drive object. Helps to detect media types and to control the drive tray. + - mediatype [r/w] + * Inserted disc type. + * You may change media type to force it for some strange discs. + = "none" (default) + = "dvd" + = "iso" + = "audio" + = "mixed" + = "hdd" + - tray [r/w] + * Drive tray status. + = "open" + = "close" + = "toggle" + * Set this to toggle tray status + +======================================================================================= + +- explorer + * File/folder/playlist browser. Helps to create file or item lists. + - charset [r/w] + * Filesystem mount charset (see built-in charsets below) + = "iso8859-1" (default) + = "iso8859-2" + = "cp1251" + = "koi8-r" + - folder [r/w] + * Current source folder for the file or item list. + * If subfolder is set (explorer.folder = explorer.path), current position and list are saved. + * To restore the previous list and position, call: explorer.folder = ".." + = "/" + * root folder for mounted files (CD-ISO mode or HDD) or Audio-CD tracks. + = "cdrom/" + * For mounted files on CD/DVD-ROM drive. Equivalent to "/". + = "hdd/" + * For mounted files on hard disc drive. Equivalent to "/". + = "dvd/" + * for DVD titles and chapters + = "playlist/",... + * Virtual folder for playlist used as explorer.target to gather items. + - target [r/w] + * Current target folder (for item copying). Can be used for play-lists. + = "" (default) + - filter [r/w] + * Allows tracks, files or folders filtering and grouping. + = "up,folder,track,dvd,file" (default) + * Special 'up' folder goes first, then all folders, then CDDA tracks, then special DVD item, then all files. + = "track" + * CD-Audio tracks only + = "file" + * Files only + = "folder" + * Folders only + = "dvd" + * DVD items only + = "" + * No filtering, all items ungrouped. + - mask1 [r/w] + * A filemask to list only some file/item types, separated by commas (ex. "*.avi,*.mpg,*.dat"). + * Several filemasks can be combined. + = "*.*" (default) + - mask2 [r/w] + * A filemask to list only some file/item types, separated by commas (ex. "*.avi,*.mpg,*.dat") + * Several filemasks can be combined. + = "*.*" (default) + - mask3 [r/w] + * A filemask to list only some file/item types, separated by commas (ex. "*.avi,*.mpg,*.dat") + * Several filemasks can be combined. + = "*.*" (default) + - mask4 [r/w] + * A filemask to list only some file/item types, separated by commas (ex. "*.avi,*.mpg,*.dat") + * Several filemasks can be combined. + = "*.*" (default) + - mask5 [r/w] + * A filemask to list only some file/item types, separated by commas (ex. "*.avi,*.mpg,*.dat") + * Several filemasks can be combined. + = "*.*" (default) + - path [r/o] + * Full path to the current file (like "/cdrom/dir/movie_file.avi") or CD-Audio track (like "/cdrom/1.cda"). + * To play, it should be passed to the 'player' object [code: player.source = explorer.path] + - filename [r/o] + * The filename (without extension!) of the current item (like "movie_file") + - extension [r/o] + * Current file/item extension (like ".avi") + * Can be used to detect current file's type. + - drive_letter [r/o] + * Current drive letter (like "C") for hard disc drives. + - type [r/o] + * The type of the current item + = "item" + * A file or media stream. + = "folder" + * Folder + = "up" + * A Special item for up-folder jumps - "..". + = "dvd" + * Special DVD item (it means that the current folder contains a DVD movie). + - maskindex [r/o] + * The index of the mask which included the current item. + = 1-5 + - filesize [r/o] + * Set if current item is a file, a size, in bytes. + * If real filesize greater than 2147483647 bytes (2 Gb limit), + * then the filesize is given as negative value, in kilobytes. + = 0 (default) + * All folders have zero filesize. + - filetime [r/o] + * Set to 'last modified' date & time, if current item is a file + * Folowing string format is used: DD.MM.YYYY HH:MM + = "" (default) + * If filetime is not set or unknown/zero. + - count [r/o] + * Number of items + - sort [r/w] + * Items sorting + = "none" + = "normal" + * Alphabetical sort + = "inverse" + * Inverse alphabetical sort + = "random" + * Shuffle + - position [r/w] + * Current item position (zero-based index). For empty lists, the position is always -1. + = -1 (default) + - command [w/o] + * One can use commands to manipulate with the list and it's items. + = "update" + * Update the list from the current item source folder. + * Call it every time the folder, charset, filter or mask changes. + = "first" + * Jump to the first item. + = "last" + * Jump to the last item. + = "next" + * Move to the next item. Set to explorer.count if moved before the last item. + = "prev" + * Move to the previous item. Set to -1 if moved before the first item. + = "randomize" + * Initialize random sequence and jump to the first random item. + = "nextrandom" + * Move to the next random item (see explorer.command="randomize"). + * Every item is passed through one time. Current item index set to -1 after the last one. + = "prevrandom" + * Move to the previous random item (see explorer.command="randomize"). + * Every item is passed through one time. Current item index set to -1 after the first one reached. + = "remove" + * Remove current item from the list. The next item becomes current. + = "removeall" + * Remove all items from the list. + = "copy" + * Copy current item from source folder to target folder. + * No item duplicates allowed. + * To check item existance in the target folder, use ::explorer.copied::. + * If the item copied, explorer.copied set to 1. + = "copyall" + * Copy all items from source folder to target folder. + * See explorer.command = "copy". + = "targetremove" + * Remove current item from the target folder. + * Equivalent to explorer.command="remove" if the current folder is the same as target. + * If the item removed, explorer.copied set to 0. + = "targetremoveall" + * Remove all items from the target folder. + - find [w/o] + * Find given item path and set current item if found in this folder. + * If not found, the item position is set to -1. + = "" (default) + - copied [r/o] + * Set if the current item was already copied to the current target folder. + = 0 (default) + = 1 + +======================================================================================= + +- player + * Object used to play or show media files on ISO, AudioCD or DVD discs. + * Uses internal code (for DVD and JPEG) or calls external binary players. + * Controlled by commands. Has special functionality for DVD discs. + - source [r/w] + * Media file source - set it to 'explorer.filepath' value for media file play/show + * or to the special folders for disc play (See 'explorer.folder' for details). + * File/disc is not read at this time. Use other commands to start playing or get file/disc info. + - playing [r/w] + * When player starts or stops playing, the player.playing is set to 1 or 0. + * Can be used to detect the player's state. + = 0 (default) + * Playing is stopped. + * Setting player.playing = 0 is equivalent to player.command = "stop" + = 1 + * The player is playing now. + * Setting player.playing = 1 is equivalent to player.command = "play" + - saved [r/o] + * Set for DVD disc if it was already played (a limited number of discs is stored: 5). + = 0 (default) + * The DVD disc is inserted for the first time. + = 1 + * The DVD disc was already played (the main part, not menu!). + - command [w/o] + = "info" + * Get media file info. Fills player variables - 'player.name', 'player.artist' and others. + * This may take some time - file reading is needed. + = "play" + * Starts playing. Call it also after title/chapter is changed. + = "continue" + * Continue playing from saved position. + = "stop" + * Stops playing. + = "pause" + * Pause play + = "step" + * Advance 1 frame. + = "slow" + * Turn on slow forward (1/2). + = "forward" + * Fastforward (and speed up/down for DVD). + = "rewind" + * Rewind (and speed up/down for DVD). + = "prev" + * Skip to previous DVD chapter; or stop playing media file. + = "next" + * Skip to the next DVD chapter; or stop playing media file. + = "press" + * Press 'enter' button for DVD menu. + = "left" + * Move DVD menu highlight left. + = "right" + * Move DVD menu highlight right. + = "up" + * Move DVD menu highlight up. + = "down" + * Move DVD menu highlight down. + = "menu" + * Call default DVD menu ('escape' menu). + = "rootmenu" + * Call root DVD menu. + = "return" + * Return to previous DVD menu. + = "cancel" + * Undo user-set time/title/chapter before play continues. + = "angle" + * Switch next DVD camera angle. + = "audio" + * Switch next DVD audio stream. 'language_audio' is updated. + = "subtitle" + * Switch next DVD subtitles language or turn them off. 'language_subtitle' is updated. + - select [w/o] + * Set selection range markers for the DVD movie or AudioCD. + = "" + = "begin" + = "end" + - repeat [r/w] + * Set repeat mode + = "none" (default) + * Play one time, no repeat. + = "selection" + * Repeat selected fragment. (See 'selection') + = "track" + * Repeat current track (for AudioCDs). + = "all" + * Repeat all disc. + = "random" + * Random play. + - speed [r/w] + * Current playing speed. + = 0 (default) + * Paused or stopped. + = 1 + * Normal play + = 8 + * Forward x8 + = 16 + * Forward x16 + = 32 + * Forward x32 + = 48 + * Forward x48 + = -8 + * Backward x8 + = -16 + * Backward x16 + = -32 + * Backward x32 + = -48 + * Backward x48 + = "1/2" + * Slow forward x1/2 + = "1/4" + * Slow forward x1/4 + = "1/8" + * Slow forward x1/8 + - menu [r/w] + * DVD menu control + = 0 (default) + * We're not in menu (Or set to 1 to resume playback) + = 1 + * We're in menu or not playing (Or set to 1 for menu jump) + = "escape" + * Jump to the root menu or resume playback if in menu + = "title" + * Jump to the title menu + = "root" + * Jump to the root menu + = "subtitle" + * Jump to subtitles selection menu + = "audio" + * Jump to audio selection menu + = "angle" + * Jump to angle/camera selection menu + = "chapters" + * Jump to DVD chapters selection menu + - language_menu [r/w] + * Default language for DVD menu. + * You can set two-letter codes ("en", "fr" etc.) or full strings ("English", "French"). + * Two-letter codes will be automatically converted into the full strings. + = "English" (default) + - language_audio [r/w] + * DVD set default audio language or change current audio stream if playing. + * You can set two-letter codes ("en", "fr" etc.) or full strings ("English", "French"). + * Two-letter codes will be automatically converted into the full strings. + = "English" (default) + - language_subtitle [r/w] + * DVD default subtitle language or change current if playing. + * You can set two-letter codes ("en", "fr" etc.) or full strings ("English", "French"). + * Two-letter codes will be automatically converted into the full strings. + = "English" (default) + = "" + * Set to hide subtitles. + - subtitle_charset [r/w] + * Used in subtitle files processing for video player. Set this before starting play! + = "" (default) + * No processing required. The subtitle file charset corresponds to font charset. + = "koi8-r" + * Translate KOI8-R to default WIN/ISO charset. + - subtitle_wrap [r/w] + * Number of letters in the text string before soft line break. Should be set to fit entire subtitle on the screen. + * Used in subtitle files processing for video player. Set this before starting play! + = 35 (default) + - subtitle [r/o] + * Returns subtitle string that should be currently shown on the screen. + = "" (default) + - angle [r/w] + * DVD camera angle. + = 1 (default) + - volume [r/w] + * Sound volume (0-100). + = 50 (default) + - balance [r/w] + * Volume stereo balance. -100 = left channel only, 100 = right channel only + = 0 (default) + * Centered + = -100..100 + - audio_offset [r/w] + * Number of msecs added to audio for audio/video sync. correction + = 0 (default) + = -5000..5000 + - time [r/w] + * Current playing time, in seconds. + * Also one can set this variable to seek the time position. + = 0 (default) + - title [r/w] + * Current DVD title number (1..99). Set player.command="play" to apply the title/chapter changes. + = 0 (default) + - chapter [r/w] + * Current DVD chapter (part) number (1..999). Set player.command="play" to apply the title/chapter changes. + = 0 (default) + - name [r/o] + * Name of the movie/song or DVD disc. Use player.command="info" before. + = "" (default) + - artist [r/o] + * Move/song artist info, if present. Use player.command="info" before. + = "" (default) + - audio_info [r/o] + * Info about audio data type & quality. Use player.command="info" before. + = "" (default) + - video_info [r/o] + * Info about video data type & quality. Use player.command="info" before. + = "" (default) + - audio_stream [r/o] + * Current audio stream number (1..8) or 0 for no audio. + = 0 (default) + - subtitle_stream [r/o] + * Current subtitle stream number (1..32) or 0 for hidden subtitles. + = 0 (default) + - length [r/o] + * Total length of the movie/song, in seconds. Use player.command="info" before. + = 0 (default) + - num_titles [r/o] + * Total number of titles in DVD. (0..99) + = 0 (default) + - num_chapters [r/o] + * Total number of chapters in current DVD title. (0..999) + = 0 (default) + - width [r/o] + * Video frame width, in pixels. Set for DVD or video file when started playing. + = 0 (default) + - height [r/o] + * Video frame height, in pixels. Set for DVD or video file when started playing. + = 0 (default) + - frame_rate [r/o] + * Video frame rate, in frames per millisecond (for example, 25000 means 25 fps). + = 0 (default) + - color_space [r/o] + * Color space used. Use player.command="info" before. + = "" (default) + = "ycbcr" + = "grayscale" + - debug [r/w] + * Set to 1 for player's debug info output (for internal players only). + = 0 (default) + = 1 + - error [r/o] + * Last error string code. Only non-empty errors trigger the variable. + * Every successful player's action silently clears the error variable. + = "" (default) + * Everything's OK. + = "invalid" + * The command or player operation is currently not allowed. + = "badaudio" + * Unsupported audio format. + = "badvideo" + * Unsupported video codec. + = "wait" + * Player requires some time. It's not actually an error. + = "corrupted" + * Read errors etc. Player-dependant. + +======================================================================================= + +- settings + * Firmware settings stored in EEPROM are controlled by this object. + - command [w/o] + = "defaults" + * Restore default settings + - audioout [r/w] + * Store audio output type. + = "analog" (default) + = "digital" + - tvtype [r/w] + * Used by video player. + = "letterbox" (default) + * 4:3 letterbox + = "panscan" + * 4:3 panscan + = "wide" + * 16:9 + = "vcenter" + * 16:9 panscan + - tvstandard [r/w] + * See ::screen.tvstandard::. + = "pal" (default) + = "ntsc" + = "480p" + = "576p" + = "720p" + = "1080i" + - tvout [r/w] + * See ::screen.tvout::. + = "composite" (default) + * Composite/S-Video + = "ypbpr" + * Component/YPbPr + = "rgb" + * Composite/RGB via SCART + - dvi [r/w] + * DVI Configuration index. (reserved for future use). + - hq_jpeg [r/w] + * High-Quality JPEG viewer mode. + = 0 + * Default + = 1 + - hdd_speed [r/w] + * Change SATA/PATA HDD speed + = "fastest" (default) + = "limited" + * Used for some SATA adapters + = "slow" + * Used for some SATA adapters or PATA HDD drives + - dvd_parental [r/w] + * DVD Parental control level + = 0..8 + - dvd_mv [r/w] + * DVD macrovision check flag + = 0 (default) + = 1 + - dvd_lang_menu [r/w] + * Default DVD menu language code + = "??" + * Two character language code ("en", "fr", ...) + - dvd_lang_audio [r/w] + * Default DVD audio language code + = "??" + * Two character language code ("en", "fr", ...) + - dvd_lang_spu [r/w] + * Default DVD subtitle language code + = "??" + * Two character language code ("en", "fr", ...) + - volume [r/w] + * Store audio volume + = 0..100 + = 50 (default) + - balance [r/w] + * Volume stereo balance. -100 = left channel only, 100 = right channel only + = -100..100 + = 0 (default) + * Centered + - brightness [r/w] + * Store/Load TV brightness (depends on TV mode) + = 0..1000 + = 500 (default) + - contrast [r/w] + * Store/Load TV contrast (depends on TV mode) + = 0..1000 + = 500 (default) + - saturation [r/w] + * Store/Load TV saturation (depends on TV mode) + = 0..1000 + = 500 (default) + - user1 [r/w] + * User-defined integer + - user2 [r/w] + * User-defined integer + - user3 [r/w] + * User-defined integer + - user4 [r/w] + * User-defined integer + - user5 [r/w] + * User-defined integer + - user6 [r/w] + * User-defined integer + - user7 [r/w] + * User-defined integer + - user8 [r/w] + * User-defined integer + - user9 [r/w] + * User-defined integer + - user10 [r/w] + * User-defined integer + - user11 [r/w] + * User-defined integer + - user12 [r/w] + * User-defined integer + - user13 [r/w] + * User-defined integer + - user14 [r/w] + * User-defined integer + - user15 [r/w] + * User-defined integer + - user16 [r/w] + * User-defined integer + +======================================================================================= + +- flash + * Object used for accessing the FLASH memory. + * Flashing begins automatically when both file and address is set. + * Setting file or address during the flashing (when progress < 100) will interrupt/restart the procedure. + * CAUTION! If address is zero, boot loader is overwriten, which can damage your player. + - file [r/w] + * File name of firmware binary. + - address [r/w] + * Starting address to flash. + - progress [r/o] + * Progress indicator, in per cents. + = 0 (default) + = 0..100 + = -1 + * If there was a read or flash error, the progress is set to -1. + = -2 + * Verification failed. + +======================================================================================= diff --git a/mmsl/doc/mmsl-objects2.txt b/mmsl/doc/mmsl-objects2.txt new file mode 100644 index 0000000..b90a4d3 --- /dev/null +++ b/mmsl/doc/mmsl-objects2.txt @@ -0,0 +1,161 @@ + +- image + * Puts a new image (animated picture) object on the screen. + - type [r/o] + * Object's type (set automatically when created). + = "image" + - group [r/w] + * Object's group name. Can be used for grouped objects deletion. + - src [r/w] + * Source image file in .GIF format (normal or animated). + - x [r/w] + * X coordinate, in pixels (see 'halign') + - y [r/w] + * Y coordinate, in pixels (see 'valign') + - visible [r/w] + * If the object is visible on the screen. + = 0 + * Default for empty objects ('new' without arguments) + = 1 + * Default for set-up objects ('new' with arguments) + - width [r/w] + * Image width, in pixels + - height [r/w] + * Image height, in pixels + - hflip [r/w] + * Horizontal image flip. A little more slow than normal image. + = 0 (default) + = 1 + - vflip [r/w] + * Vertical image flip + = 0 (default) + = 1 + - halign [r/w] + * Horizontal image align + = screen.halign (default) + - valign [r/w] + * Vertical image align + = screen.valign (default) + - timer [r/w] + * Sets built-in count-back timer, in msecs. Should be used in 'on' conditionals. + = 0 (default) + +======================================================================================= + +- text + * Puts a new text object on the screen. + - type [r/o] + * Object's type (set automatically when created). + = "text" + - group [r/w] + * Object's group name. Can be used for grouped objects deletion. + - x [r/w] + * X coordinate, in pixels (see 'halign') + - y [r/w] + * Y coordinate, in pixels (see 'valign') + - visible [r/w] + * If the object is visible on the screen. + * Non-visible text objects can be used for string manipulation. + = 0 + * Default for empty objects ('new' without arguments) + = 1 + * Default for set-up objects ('new' with arguments) + - width [r/w] + * Text width, in pixels. /*Set it to format multi-line text.*/ + = 0 + * Set automatically to text extents + - height [r/w] + * Text height, in pixels + - halign [r/w] + * Horizontal text align. + = screen.halign (default) + - valign [r/w] + * Vertical text align. + = screen.valign (default) + - color [r/w] + * Text color. + = screen.color (default) + - backcolor [r/w] + * Text background color. + = screen.backcolor (default) + - value [r/w] + * Text string. + - count [r/w] + * Number of characters in the text string. + * One can change this value to cut the string from the right. + * Text width and height changes if string is cut. + - delete [w/o] + * Delete first N characters from the string. Text width and height changes. + - font [r/w] + * Font name used for this text object + - textalign [r/w] + * Horizontal text align (rows are affected). + = "left" (default) + = "center" + = "right" + - style [r/w] + * Text style (see below). Setting text style changes text width and height. + = "" (default) + * No style, normal text. + = "underline" + * Underlined text. Underline displayed using text color. + = "outline" + * Contrast outline, used for subtitles. + * For outlined text width and height is increased by 1 pixel. + * Background color is used for outline, and transparent is for text background. + - timer [r/w] + * Sets built-in count-back timer, in msecs. Should be used in 'on' conditionals. + = 0 (default) + +======================================================================================= + +- rect + * Puts a new rectangle object on the screen. + - type [r/o] + * Object's type (set automatically when created). + = "rect" + - group [r/w] + * Object's group name. Can be used for grouped objects deletion. + - x [r/w] + * X Coordinate of rectangle offset, in pixels. + * See 'halign'. + - y [r/w] + * Y Coordinate of rectangle offset, in pixels. + * See 'valign'. + - visible [r/w] + * If the object is visible on the screen. + = 0 + * Default for empty objects ('new' without arguments) + = 1 + * Default for set-up objects ('new' with arguments) + - width [r/w] + * Rectangle width, in pixels. + - height [r/w] + * Rectangle height, in pixels. + - linewidth [r/w] + * Border line width, in pixels. + = 1 (default) + = 0 + * For no border. + - color [r/w] + * Is a rectangle border color, palette index + = screen.color (default) + - backcolor [r/w] + * Is a background color, palette index + * Set it to negative value to draw transparent rectangle + = screen.backcolor (default) + - halign [r/w] + * Is a rectangle horizontal align, relative to the given (x,y) center + = screen.halign (default) + - valign [r/w] + * Is a rectangle vertical align, relative to the given (x,y) center + = screen.valign (default) + - round [r/w] + * Draw a rounded rectangle. + * 'round' is a round arc radius, in pixels. + = 0 (default) + - timer [r/w] + * Sets built-in count-back timer, in msecs. Should be used in 'on' conditionals. + = 0 (default) + +======================================================================================= diff --git a/mmsl/doc/mmsl-tricks.txt b/mmsl/doc/mmsl-tricks.txt new file mode 100644 index 0000000..b3df9f6 --- /dev/null +++ b/mmsl/doc/mmsl-tricks.txt @@ -0,0 +1,27 @@ + +1) How to toggle variable states on event: + +/////// This is WRONG way because of cross-triggering: + +on settings.tvstandard == "pal" + on pad.key == "vmode" + settings.tvstandard = "ntsc" + +on settings.tvstandard == "ntsc" + on pad.key == "vmode" + settings.tvstandard = "pal" + +/////// This is RIGHT way: + +on pad.key == "vmode" + toggle_tvstandard = 1 + +on settings.tvstandard == "ntsc" + on toggle_tvstandard == 1 + toggle_tvstandard = 0 + settings.tvstandard = "pal" + +on settings.tvstandard == "pal" + on toggle_tvstandard == 1 + toggle_tvstandard = 0 + settings.tvstandard = "ntsc" diff --git a/mmsl/dvd.mmsl b/mmsl/dvd.mmsl new file mode 100644 index 0000000..9d3971f --- /dev/null +++ b/mmsl/dvd.mmsl @@ -0,0 +1,254 @@ + +screen.back = "" +cancel_setup = 1 +cancel_popup = 1 +pad.clear = "all" +pad.set = "dvd" + +// play dvd by default +set_dvd_source = 1 +on player_source_set == 0 + on set_dvd_source == 1 + player.source = "dvd/" + set_dvd_source = 0 + +player.language_menu = settings.dvd_lang_menu +player.language_audio = settings.dvd_lang_audio +player.language_subtitle = settings.dvd_lang_spu + +screen.preload = font1 +screen.preload = font2 +screen.preload = "img/player/popup.gif" +screen.preload = "img/player/invalid.gif" +screen.preload = "img/player/subtitle.gif" +screen.preload = "img/player/subtitleoff.gif" +screen.preload = "img/player/audio.gif" +screen.preload = "img/player/angle.gif" + +search_title = "DVD Search" +filesize_string = "" +filedate_string = "" + +//player.debug = 1 + +search = 0 + +player.command = "play" + +continue_cnt = 6 +continue_msg = "Playback will continue at saved position\n in " + +test_saved = 1 + +allow_zoom = 1 +allow_osd = 1 + +// play? +on test_saved == 0 + on menu == 0 + on pad.key == "play" + show_fast_balloon = "player/play" + player.command = "play" + on menu != 0 + on player.speed != 1 + on pad.key == "play" + player.command = "play" + on player.speed == 1 + on pad.key == "play" + show_balloon = "" + player.command = "press" + +// stop? +on pad.key == "stop" + dvd = 0 + show_fast_balloon = "player/stop" + auto_close_popup = 0 + show_popup_text = "The current disc position was saved!\nPress [Play] to resume playing.\nPress [Enter] to open file browser.\nPress [Setup] to open setup." + +//////////////////////// +// react on errors: +on player.speed != 0 + on player.error == "invalid" + show_fast_balloon = "player/invalid" + +/////////////////////// +// process keys: + +on pad.key == "forward" + player.command = "forward" + +on pad.key == "rewind" + player.command = "rewind" + +on pad.key == "prev" + show_fast_balloon = "player/prev" + player.command = "prev" + +on pad.key == "next" + show_fast_balloon = "player/next" + player.command = "next" + +on pad.key == "slow" + player.command = "slow" // auto-process slow fwd/rev + +// pause pressed +on player.menu == 0 + allow_zoom = 1 + allow_osd = 1 + on pad.key == "pause" + do_pause = 1 +on player.menu == 1 + cancel.zoom = 1 + allow_zoom = 0 + allow_osd = 0 + on pad.key == "pause" + show_fast_balloon = "player/invalid" + +// -> pause +on player.speed != 0 + on do_pause == 1 + show_static_balloon = "player/pause" + do_pause = 0 + player.command = "pause" + +// already is paused mode -> step +on player.speed == 0 + on do_pause == 1 + restore_balloon = "player/pause" + show_fast_balloon_and_restore = "player/stepfwd" + do_pause = 0 + player.command = "step" + +on search == 0 && zoom_mode == 0 && test_saved == 0 + on pad.key == "return" + show_fast_balloon = "player/return" + player.command = "return" + + on pad.key == "enter" + show_balloon = "" + player.command = "press" + + on pad.key == "left" + player.command = "left" + on pad.key == "right" + player.command = "right" + on pad.key == "up" + player.command = "up" + on pad.key == "down" + player.command = "down" + +on search == 0 + on pad.key == "menu" + zoom_mode = 0 + player.command = "menu" + on pad.key == "title" + zoom_mode = 0 + player.command = "rootmenu" + on pad.key == "angle" + player.command = "angle" + on pad.key == "audio" + player.command = "audio" + on pad.key == "subtitle" + player.command = "subtitle" + +///////////////////////// +on player.saved == 1 + on test_saved == 1 + kernel.print = "Disc position was saved. Continue playback?" + player.command = "pause" + popup_timer = 1000 + auto_close_popup = 0 + show_popup_text = "" + continue_msg + continue_cnt + " seconds" + add image cancel + cancel.group = "popup" + cancel.halign = "center" + cancel.valign = "center" + cancel.src = "img/player/cancel.gif" + cancel.x = popup.x + cancel.y = popup.y + 55 + + on continue_cnt <= 1 + on popuptext.timer == 0 + dvd_continue_play = 1 + + on continue_cnt > 1 + on popuptext.timer == 0 + continue_cnt = continue_cnt - 1 + popuptext.value = "" + continue_msg + continue_cnt + " seconds" + popuptext.timer = 1000 + + on pad.key == "enter" + continue_cnt = 0 + dvd_continue_play = 1 + + on pad.key == "cancel" + cancel_popup = 1 + kernel.print = "Cancel!" + player.command = "play" + test_saved = 0 + + on dvd_continue_play == 1 + cancel_popup = 1 + kernel.print = "Continue!" + player.command = "continue" + test_saved = 0 +on player.saved == 0 + on test_saved == 1 + test_saved = 0 + +///////////////////////// +// display speed: + +on show_balloon != "player/play" && search != 1 + on player.speed == 0 + show_static_balloon = "player/pause" + on player.speed == 1 + show_balloon = "" +on player.speed == 8 + show_static_balloon = "player/fwd8x" +on player.speed == 16 + show_static_balloon = "player/fwd16x" +on player.speed == 32 + show_static_balloon = "player/fwd32x" +on player.speed == 48 + show_static_balloon = "player/fwd48x" +on player.speed == -8 + show_static_balloon = "player/rev8x" +on player.speed == -16 + show_static_balloon = "player/rev16x" +on player.speed == -32 + show_static_balloon = "player/rev32x" +on player.speed == -48 + show_static_balloon = "player/rev48x" +on player.speed == "1/2" + show_static_balloon = "player/slowfwd2x" +on player.speed == "1/4" + show_static_balloon = "player/slowfwd4x" +on player.speed == "1/8" + show_static_balloon = "player/slowfwd8x" + + +///////////////////////////// +// display subtitle/audio languages: + +on player.menu == 0 + on player.subtitle_stream == 0 + show_fast_balloon = "player/subtitleoff" + on player.subtitle_stream > 0 + show_fast_balloon = "player/subtitle" + show_balloon_text = player.language_subtitle + " ("+ player.subtitle_stream + ")" + on player.audio_stream > 0 + show_fast_balloon = "player/audio" + show_balloon_text = player.language_audio + " ("+ player.audio_stream + ")" + + on player.angle > 0 + show_fast_balloon = "player/angle" + show_balloon_text = "Camera " + player.angle + +///////////////////////////// +// PAL/NTSC autodetect: + +on settings.user2 == 1 + on player.frame_rate > 0 + autodetect_pal_ntsc = 1 + diff --git a/mmsl/flash.mmsl b/mmsl/flash.mmsl new file mode 100644 index 0000000..867bb53 --- /dev/null +++ b/mmsl/flash.mmsl @@ -0,0 +1,59 @@ +on flash_firmware != "" + pad.display = "FLASH" + screen.update = "now" + + ft0 = "Upgrading from " + flash_firmware + + add rect fbk + fbk.width = 500 + fbk.height = 150 + fbk.x = (screen.right + screen.left) / 2 - fbk.width / 2 + fbk.y = (screen.top + screen.bottom) / 2 + fbk.valign = "center" + fbk.round = 5 + fbk.color = colors.lightblueback + fbk.backcolor = colors.lightblueback + + add text fte + fte.x = fbk.x + 10 + fte.y = fbk.y - 40 + fte.valign = "center" + fte.font = font1 + fte.color = colors.white + fte.backcolor = fbk.backcolor + fte.value = ft0 + "\nPlease wait..." + + add rect r + r.x = fbk.x + 10 + r.y = fbk.y + r.valign = "center" + r.width = 0 + r.height = 22 + r.color = colors.white + r.backcolor = colors.white + + flash.file = flash_firmware + ft0 = ft0 + " @ 0x" + (flash.address/65536) + ((flash.address%65536)/4096) + "000..." + + on flash.progress == -1 + fte.value = ft0 + "\nERROR!" + pad.display = "Error" + drive.tray = "open" + screen.update = "now" + on flash.progress == -2 + fte.value = ft0 + "\nVerification ERROR! Try again!" + pad.display = "Error" + drive.tray = "open" + screen.update = "now" + + on flash.progress >= 0 + r.width = flash.progress * 480 / 100 + fte.value = ft0 + "\n" + flash.progress + " %" + pad.display = flash.progress + + on flash.progress == 100 + fte.value = ft0 + "\nDONE! PLEASE TURN OFF YOUR PLAYER NOW!" + pad.display = "donE" + drive.tray = "open" + screen.update = "now" + kernel.power = 2 diff --git a/mmsl/iso-info.mmsl b/mmsl/iso-info.mmsl new file mode 100644 index 0000000..65e3d41 --- /dev/null +++ b/mmsl/iso-info.mmsl @@ -0,0 +1,206 @@ +////////////////////////////// +// files info: + +on iso_info == 1 + info_x = 178 + info_y = 125 + + need_info = 0 + + delete .group == "fileinfo" + + add text textsize + textsize.group = "fileinfo" + textsize.visible = 0 + + add text textdate + textdate.group = "fileinfo" + textdate.visible = 0 + + add text photoload + photoload.group = "fileinfo" + photoload.visible = 0 + photoload.value = "Loading..." + photoload.halign = "center" + photoload.valign = "center" + photoload.x = 501 + photoload.y = 174 + +on del_info == 1 + need_info = 0 + textsize.visible = 0 + textdate.visible = 0 + photoload.visible = 0 + delete .group == "infotitle" + delete .group == "infoartist" + delete .group == "infodims" + delete .group == "infoclrs" + delete .group == "infolength" + put_dims = 0 + put_clrs = 0 + put_title = 0 + put_artist = 0 + put_length = 0 + +on in_menu == 0 + on cur_pos != -1 + del_info = 1 +on in_menu == 0 && osd == 0 && explorer.type == "file" + on cur_pos != -1 + info_iy = info_y + 2*23 + put_dims = 0 + put_clrs = 0 + put_title = 0 + put_artist = 0 + put_length = 0 + need_info = 1 + + // output user-friendly file size: + textsize.visible = 1 + textsize.x = info_x + textsize.y = info_y + textsize.timer = 500 // 0.5 sec + + filesize_value = explorer.filesize // see osd.mmsl + textsize.value = "Size: " + filesize_string + + // file modification date: + textdate.x = info_x + textdate.y = textsize.y + textsize.height + textdate.value = "Date: " + explorer.filetime + filedate_string = explorer.filetime + textdate.visible = 1 + textdate.timer = 0 + info_iy = info_iy + 23 + + show_preview = "" + info_path = explorer.path + +on in_menu == 0 && osd == 0 && explorer.type == "track" + on cur_pos != -1 + // first, get some info from CD + info_iy = info_y + 2*23 + need_info = 1 + need_length = 1 + player.source = explorer.path + we_asked_info_for = player.source + player.command = "info" + + info_iy = info_y + 1*23 + put_title = 1 + delete .group == "infotitle" + add text texttitle + texttitle.group = "infotitle" + texttitle.x = info_x + texttitle.y = info_iy + info_iy = info_iy + 23 + texttitle.value = "Track/Total: " + (explorer.filename/10) + (explorer.filename%10) + " / " + (player.num_titles/10) + (player.num_titles%10) + +on need_info == 1 && playing == 0 && show_popup_text == "" + // use a little delay to speed-up cursor move + on textsize.timer == 0 + call_info = 1 + +on explorer.maskindex == 3 // jpeg + on call_info == 1 + show_preview = info_path + textdate.timer = 600 // start timer for preview +on show_preview != "" + on del_info == 1 + show_preview = "" + do_show_preview = "/img/defpreview.jpg" + folder.width = 0 + on textdate.timer == 0 + photoload.visible = 1 + screen.update = "now" + folder.width = 220 + do_show_preview = show_preview + photoload.visible = 0 + + // there was an error + on screen.back == "" + kernel.print = "Preview Error!" + do_show_preview = "/img/defpreview.jpg" + folder.width = 0 + +on do_show_preview != "" + saved_back_right = screen.back_right + saved_back_bottom = screen.back_bottom + + screen.back_left = 460 + screen.back_top = 105 + screen.back_right = 669 + screen.back_bottom = 244 + + screen.back = do_show_preview + + screen.back_left = 0 + screen.back_top = 0 + screen.back_right = saved_back_right + screen.back_bottom = saved_back_bottom + + +on call_info == 1 + call_info = 0 + player.source = info_path + // query player for extended info (we'll receive it when available) + we_asked_info_for = player.source + player.command = "info" + + +on need_info == 1 && osd == 0/* && playing == 0 */ + on put_title == 0 + on player.name != "" + put_title = 1 + delete .group == "infotitle" + add text texttitle + texttitle.group = "infotitle" + texttitle.x = info_x + texttitle.y = info_iy + info_iy = info_iy + 23 + texttitle.value = "Title: " + player.name + + on put_artist == 0 + on player.artist != "" + put_artist = 1 + delete .group == "infoartist" + add text textartist + textartist.group = "infoartist" + textartist.x = info_x + textartist.y = info_iy + info_iy = info_iy + 23 + textartist.value = "Artist: " + player.artist + + on put_dims == 0 + on player.width != 0 && player.height != 0 + put_dims = 1 + delete .group == "infodims" + add text textdims + textdims.group = "infodims" + textdims.x = info_x + textdims.y = info_iy + info_iy = info_iy + 23 + textdims.value = "Resolution: " + player.width + " X " + player.height + + on put_clrs == 0 + on player.color_space != "" + put_clrs = 1 + delete .group == "infoclrs" + add text textclrs + textclrs.group = "infoclrs" + textclrs.x = info_x + textclrs.y = info_iy + info_iy = info_iy + 23 + textclrs.value = "Color Space: " + player.color_space + + on put_length == 0 && need_length == 1 + on player.length > 0 + put_length = 1 + need_length = 0 + delete .group == "infolength" + add text textlength + textlength.group = "infolength" + textlength.x = info_x + textlength.y = info_iy + info_iy = info_iy + 23 + textlength.value = "Length: " + (player.length/36000) + ((player.length/3600)%10) + ":" + (player.length%3600/600) + ((player.length%3600/60)%10) + ":" + ((player.length%60)/10) + ((player.length%60)%10) diff --git a/mmsl/iso-menu.mmsl b/mmsl/iso-menu.mmsl new file mode 100644 index 0000000..165e9da --- /dev/null +++ b/mmsl/iso-menu.mmsl @@ -0,0 +1,383 @@ +////////////////////////////////// +// left menu: + +menu_x = screen.left +menu_y = 100 +menu_item_height = 40 + +add image mplay + mplay.x = menu_x; + mplay.y = menu_y + menu_item_height * 0; + mplay.src = "img/playoff.gif" +add image mplaymode + mplaymode.x = menu_x + 5; + mplaymode.y = menu_y + mplay.height + 5; + set_playmode = 1 + +add image mplaylist + mplaylist.x = menu_x - 5 + mplaylist.y = menu_y + menu_item_height * 2; + mplaylist.src = "img/playlistoff.gif" +add image mplaylistedit + mplaylistedit.x = menu_x - 5 + mplaylistedit.y = mplaylist.y + mplaylist.height; + set_playlistmode = 1 + +add image mplaylistmodes + mplaylistmodes.x = mplaylistedit.x + mplaylistedit.width + mplaylistmodes.y = mplaylist.y + mplaylist.height; + mplaylistmodes.src = "img/playlist-modes.gif" + +mrect_x = screen.left - 5 +mrect_y = menu_y + menu_item_height * 3 + +add image maudio + maudio.x = mrect_x; + maudio.y = mrect_y + menu_item_height * 1; +add image mvideo + mvideo.x = mrect_x; + mvideo.y = mrect_y + menu_item_height * 2; +add image mphoto + mphoto.x = mrect_x; + mphoto.y = mrect_y + menu_item_height * 3; +add image msubt + msubt.x = mrect_x; + msubt.y = mrect_y + menu_item_height * 4; + + +add rect mrect + mrect.x = menu_x - 1 + mrect.y = mrect_y - 2 + mrect.width = 105 + mrect.height = menu_item_height - 2 + mrect.backcolor = -1 + mrect.color = colors.yellow + mrect.round = 5 + mrect.linewidth = 2 + mrect.visible = 0 + +set_mflags = 1 + +on flag_music == 0 + on set_mflags == 1 + maudio.src = "img/audoff.gif" +on flag_music == 1 + on set_mflags == 1 + maudio.src = "img/audon.gif" +on flag_movie == 0 + on set_mflags == 1 + mvideo.src = "img/vidoff.gif" +on flag_movie == 1 + on set_mflags == 1 + mvideo.src = "img/vidon.gif" +on flag_pics == 0 + on set_mflags == 1 + mphoto.src = "img/photoff.gif" +on flag_pics == 1 + on set_mflags == 1 + mphoto.src = "img/photon.gif" +on flag_subt == 0 + on set_mflags == 1 + msubt.src = "img/subtoff.gif" +on flag_subt == 1 + on set_mflags == 1 + msubt.src = "img/subton.gif" +on flag_playlist == 0 + on set_mflags == 1 + mplaylist.src = "img/playlistoff.gif" +on flag_playlist == 1 + on set_mflags == 1 + mplaylist.src = "img/playliston.gif" + +// set "playlist edit" mode - not in playlist! +on playlist_edit == 1 && flag_playlist == 1 + on set_playlistmode == 1 + flag_playlist = 0 + set_mflags = 1 + do_playlist = 1 + do_playlist = 2 +on playlist_edit == 0 + on set_playlistmode == 1 + mplaylistedit.src = "img/playlist-edit-off.gif" + set_playlistmode = 0 +on playlist_edit == 1 + on set_playlistmode == 1 + mplaylistedit.src = "img/playlist-edit-on.gif" + set_playlistmode = 0 + +on play_mode == "all" + on set_playmode == 1 + set_playmode = 0 + mplaymode.src = "img/play-all.gif" +on play_mode == "random" + on set_playmode == 1 + set_playmode = 0 + mplaymode.src = "img/play-random.gif" + +old_menu_pos = -1 + + +/////////////////////////////////////////// +// menu cursor: + +on pad.key == "right" + do_right = 1 + +on in_menu = 1 + on explorer.count > 0 + on menu_cursor_hide == 1 + mrect.visible = 0 + on menu_pos == 0 + mrect.x = mplay.x - 2 + mrect.y = mplay.y - 2 + mrect.width = 105 + mrect.height = 26 + mrect.visible = 1 + on menu_pos == 1 && menu_posx == 0 + mrect.y = mplaymode.y + mrect.x = mplaymode.x - 2 + mrect.width = 28 + mrect.height = 17 + mrect.visible = 1 + on menu_pos == 1 && menu_posx == 1 + mrect.y = mplaymode.y + mrect.x = mplaymode.x + 38 + mrect.width = 57 + mrect.height = 17 + mrect.visible = 1 + on menu_pos == 2 + mrect.y = mplaylist.y + mrect.x = mplaylist.x - 2 + mrect.width = 110 + mrect.height = menu_item_height - 10 + mrect.visible = 1 + on menu_pos == 3 && menu_posx == 0 + mrect.y = mplaylistedit.y + mrect.x = mplaylistedit.x - 2 + mrect.width = mplaylistedit.width + 4 + mrect.height = 20 + mrect.visible = 1 + on menu_pos == 3 && menu_posx == 1 + mrect.y = mplaylistmodes.y + mrect.x = mplaylistmodes.x + 4 + mrect.width = 23 + mrect.height = 20 + mrect.visible = 1 + on menu_pos == 3 && menu_posx == 2 + mrect.y = mplaylistmodes.y + mrect.x = mplaylistmodes.x + 30 + mrect.width = 43 + mrect.height = 20 + mrect.visible = 1 + on menu_pos >= 4 + mrect.y = mrect_y + (menu_pos - 3) * menu_item_height - 2 + mrect.x = menu_x - 1 + mrect.width = 105 + mrect.height = menu_item_height - 2 + mrect.visible = 1 + +///////////////////// +// menu cursor control: +on in_menu = 1 + on menu_pos > 0 + on pad.key == "up" + menu_pos = menu_pos - 1 + menu_posx = 0 + + on (menu_pos == 1 && menu_posx == 0) || (menu_pos == 3 && menu_posx < 2) + on do_right == 1 + do_right = 0 + menu_posx = menu_posx + 1 + + on (menu_pos == 1 && menu_posx == 1) || (menu_pos == 3 && menu_posx > 0) + on pad.key == "left" + menu_posx = menu_posx - 1 + + on menu_pos < 7 + on pad.key == "down" + menu_pos = menu_pos + 1 + menu_posx = 0 + + // pageup/pagedown + on pad.key == "next" + do_next = 1 + on pad.key == "prev" + do_prev = 1 + on menu_pos == 0 || menu_pos == 1 + on do_next == 1 + do_next = 0 + menu_pos = 2 + menu_posx = 0 + on menu_pos == 2 || menu_pos == 3 + on do_next == 1 + do_next = 0 + menu_pos = 4 + menu_posx = 0 + on menu_pos <= 3 + on do_prev == 1 + do_prev = 0 + menu_pos = 0 + menu_posx = 0 + on menu_pos == 4 + on do_prev == 1 + do_prev = 0 + menu_pos = 2 + menu_posx = 0 + on menu_pos >= 4 && menu_pos < 7 + on do_next == 1 + do_next = 0 + menu_pos = menu_pos + 1 + menu_posx = 0 + on menu_pos > 4 && menu_pos <= 6 + on do_prev == 1 + do_prev = 0 + menu_pos = menu_pos - 1 + menu_posx = 0 + +/////////////////////////////////////////// +// menu/list switch: +on in_menu == 0 + on pad.key == "left" + in_menu = 1 + menu_pos = menu_pos + cursor_rect.backcolor = colors.grey + +on in_menu == 1 && explorer.count > 0 && (menu_pos == 0 || menu_pos == 2 || menu_pos >=4 || (menu_pos == 1 && menu_posx == 1) || (menu_pos == 3 && menu_posx == 2)) + on do_right == 1 + do_rignt = 0 + menu_cursor_hide = 1 + in_menu = 0 + cursor_rect.backcolor = colors.yellowback + +/////////////////////////// +// menu actions: +on in_menu == 1 + on pad.key == "enter" + do_enter = 1 + // play all/random (see iso-play.mmsl) + on explorer.count > 0 + on menu_pos == 0 + on do_enter == 1 + menu_cursor_hide = 1 + in_menu = 0 + cursor_rect.backcolor = colors.yellowback + do_start_play_all = 1 + + // playmode all + on menu_pos == 1 && menu_posx == 0 + on do_enter == 1 + do_enter = 0 + play_mode = "all" + set_playmode = 1 + // playmode random + on menu_pos == 1 && menu_posx == 1 + on do_enter == 1 + do_enter = 0 + play_mode = "random" + set_playmode = 1 + // playlist edit + on menu_pos == 3 && menu_posx == 0 + on do_enter == 1 + do_enter = 0 + playlist_edit = 1 - playlist_edit + set_playlistmode = 1 + menu_cursor_hide = 1 + in_menu = 0 + cursor_rect.backcolor = colors.yellowback + // playlist add all + on menu_pos == 3 && menu_posx == 1 + on do_enter == 1 + do_enter = 0 + explorer.command = "copyall" + menu_cursor_hide = 1 + in_menu = 0 + update_list = 1 + // playlist clear + on menu_pos == 3 && menu_posx == 2 + on do_enter == 1 + do_enter = 0 + explorer.command = "targetremoveall" + jump_to_list = 1 + update_list = 1 + on explorer.count > 0 + on jump_to_list == 1 + menu_cursor_hide = 1 + in_menu = 0 + +/////////////////////////////////// +// bottom left menu actions: +on in_menu == 1 + // playlist + on menu_pos == 2 + on pad.key == "enter" + flag_playlist = 1 - flag_playlist + set_mflags = 1 + do_playlist = 1 + do_playlist = 2 + on flag_playlist == 1 + on do_playlist == 1 + do_playlist = 0 + saved_folder = explorer.folder + explorer.folder = "playlist" + header.src = "img/playlisttop.gif" + playlist_edit = 0 + set_playlistmode = 1 + on flag_playlist == 0 + on do_playlist == 1 + do_playlist = 0 + explorer.folder = saved_folder + header.src = "img/mediatop.gif" + on do_playlist == 2 + show_timer_balloon = "wait" + screen.update = "now" + + // we cannot continue playing if folder is changed + do_play_all = 0 + + explorer.command = "update" + need_menu_cursor_hide = 1 + folder_changed = 1 + on explorer.count > 0 + need_menu_cursor_hide = 1 + menu_cursor_hide = 1 + in_menu = 0 + + // music flag + on menu_pos == 4 + on pad.key == "enter" + flag_music = 1 - flag_music + set_mflags_and_update = 1 + + // movie flag + on menu_pos == 5 + on pad.key == "enter" + flag_movie = 1 - flag_movie + set_mflags_and_update = 1 + // pics flag + on menu_pos == 6 + on pad.key == "enter" + flag_pics = 1 - flag_pics + set_mflags_and_update = 1 + // subt flag + on menu_pos == 7 + on pad.key == "enter" + flag_subt = 1 - flag_subt + set_mflags_and_update = 1 + +on set_mflags_and_update == 1 + set_mflags = 1 + show_timer_balloon = "wait" + screen.update = "now" + + // we cannot continue playing if folder is changed + do_play_all = 0 + + explorer.command = "update" + folder_changed = 1 + set_mflags_and_update = 2 + +on explorer.count > 0 + on set_mflags_and_update == 2 + set_mflags_and_update = 0 + menu_cursor_hide = 1 + in_menu = 0 diff --git a/mmsl/iso-photo.mmsl b/mmsl/iso-photo.mmsl new file mode 100644 index 0000000..ed0de01 --- /dev/null +++ b/mmsl/iso-photo.mmsl @@ -0,0 +1,84 @@ + +//////////////////////// +// photo viewer + +on do_show_photo = 1 + do_play = 0 + del_info = 1 + update_list_loop = 0 + pad.display = "JPEG" + delete .group != "mute" && .group != "scr" + screen.update = "now" + save_menu = 1 + in_menu = 2 + play_cur_pos = play_pos + player.source = play_path // for info only + playing = 1 + we_need_info = 1 + allow_zoom = 1 + allow_osd = 1 + screen.back = play_path + restore_osd_for_continue = 1 + start_slideshow = 1 + + on settings.user6 > 0 && do_play_all == 1 + on start_slideshow == 1 + add rect slideshow + slideshow.group = "sldshow" + slideshow.visible = 0 + slideshow.timer = settings.user6 * 1000 + + on slideshow.timer == 0 + delete .group == "sldshow" + pad.key = "next" + + on save_menu == 1 + on in_menu != 2 + old_in_menu = in_menu + + on zoom_mode == 0 + on do_enter == 1 + stop_viewer = 1 + + on pad.key == "stop" || pad.key == "cancel" || pad.key == "return" || stop_viewer == 1 + delete .group == "sldshow" + do_enter = 0 + stop_viewer = 0 + show_fast_balloon = "player/stop" + pad.display = "ISO" + kernel.print = "Restore ISO interface..." + do_show_photo = 0 + cancel_osd = 1 + cancel_zoom = 1 + old_play_osd = osd + allow_zoom = 0 + allow_osd = 0 + do_play_all = 0 + playing = 0 + + in_menu = old_in_menu + redraw_iso = 1 + screen.update = "now" + + // there was an error + on screen.back == "" + kernel.print = "Viewer Error!" + stop_viewer = 1 + show_badphoto_popup = 1 + + on pad.key == "angle" + screen.rotate = screen.rotate+90 + slideshow.timer = settings.user6 * 1000 + + on pad.key == "pbc" + screen.rotate = screen.rotate-90 + slideshow.timer = settings.user6 * 1000 + + on pad.key == "pause" + slideshow.timer = -1 + show_fast_balloon = "player/pause" + + on slideshow.timer < 0 + on pad.key == "play" + slideshow.timer = settings.user6 * 1000 + show_fast_balloon = "player/play" diff --git a/mmsl/iso-play.mmsl b/mmsl/iso-play.mmsl new file mode 100644 index 0000000..9a91546 --- /dev/null +++ b/mmsl/iso-play.mmsl @@ -0,0 +1,397 @@ + +//////////////////////// +// file player control + +on explorer.count > 0 && playing == 0 + on pad.key == "play" + do_start_play_all = 1 + +// play all or random +on play_mode == "all" + on do_start_play_all == 1 + play_first_cmd = "" // "first" + play_next_cmd = "next" + play_prev_cmd = "prev" + play_cmd = play_next_cmd + do_play_all = 1 +on play_mode == "random" + on do_start_play_all == 1 + play_first_cmd = "randomize" + play_next_cmd = "nextrandom" + play_prev_cmd = "prevrandom" + play_cmd = play_next_cmd + do_play_all = 1 + +on do_play_all == 1 + kernel.print = "PLAY " + play_mode + mplay.src = "img/playon.gif" + cur_play_pos = 0 + do_init_play_all = 1 + +on do_play_all == 0 + play_cur_pos = -1 + mplay.src = "img/playoff.gif" + +on do_init_play_all == 1 + saved_pos = explorer.position + explorer.command = play_first_cmd // "first" or "randomize" + cur_play_pos = explorer.position + play_pos = cur_play_pos + play_path = explorer.path + play_mediatype = explorer.maskindex + play_type = explorer.type + explorer.position = saved_pos + do_init_play_all = 2 + +on cur_play_pos < 0 || cur_play_pos >= explorer.count + on do_init_play_all == 2 + do_init_play_all = 0 + do_play_all = 0 +on play_type != "file" && play_type != "track" && play_type != "folder" + on do_init_play_all == 2 + do_init_play_all = 0 + do_continue_play = 1 +on do_init_play_all == 2 + do_init_play_all = 0 + was_continue_play = 0 + do_play = 1 +/////////////////////////////////////////////////// + + +// first, stop previous play +on player.playing == 1 + on do_play == 1 + kernel.print = "STOP PLAYING BEFORE PLAY" + stop_before_play = 1 + player.command = "stop" + +// stop viewer if we don't view pics anymore +on do_show_photo == 1 && play_mediatype != 3 /* photo */ + on do_play == 1 + kernel.print = "STOP VIEWER BEFORE PLAY" + stop_viewer = 1 + +// determine file type +on play_type == "folder" && play_path == "/cdrom/VIDEO_TS" + on do_play == 1 + play_path = "dvd/" + play_type = "dvd" + +on play_type == "track" || play_type == "folder" + on do_play == 1 + do_play = 0 + do_play_audio = 1 + +on play_type == "file" + on explorer.filename == "romfs" && explorer.extension == ".bin" + on do_play == 1 + do_play = 0 + flash_firmware = play_path + + +on play_type == "dvd" + on do_play == 1 + do_play = 0 + update_list_loop = 0 + del_info = 1 + delete .group != "mute" && .group != "scr" + screen.update = "now" + play_cur_pos = play_pos + player.source = play_path + player_source_set = 1 + // start as normal DVD + pad.key = "" + drive.mediatype = "dvd" + +on play_mediatype == 2 /////// audio + on do_play == 1 + do_play_audio = 1 +on play_mediatype == 3 /////// photo + on do_play == 1 + do_show_photo = 1 +on play_mediatype == 4 /////// subtitles + on explorer.copied == 0 + on do_play == 1 + do_play = 0 + explorer.command = "copy" // just add them to playlist + update_list = 1 + on explorer.copied == 1 + on do_play == 1 + do_play = 0 + explorer.command = "targetremove" + update_list = 1 + +/////////////////////////////////////////////////////////////////////// + +on do_play_audio == 0 && do_show_photo == 0 && play_mediatype != 4 && play_type != "folder" + on update_list_loop == 1 + on do_play == 1 + explorer.position = cur_play_pos + on do_play == 1 + update_list_loop = 0 + del_info = 1 + delete .group != "mute" && .group != "scr" + screen.back = "" + screen.update = "now" + screen.update = 1 + allow_zoom = 1 + do_play_video = 1 + +on player.playing == 0 + // disable ISO interface controls when playing video + on do_play_video == 1 + old_in_menu = in_menu + in_menu = 2 + screen.preload = "" + // this is for multiple audio tracks + screen.preload = "img/player/audio.gif" + screen.preload = "img/player/subtitle.gif" + screen.preload = "img/player/subtitleoff.gif" + + add text subtitle + subtitle.halign="center" + subtitle.valign="bottom" + subtitle.x = (screen.right + screen.left) / 2 + subtitle.y = screen.bottom + subtitle.font = font2 + subtitle.color = colors.white + subtitle.backcolor = 1 + subtitle.textalign = "center" + subtitle.style = "outline" + subtitle.value = "" + + on settings.user4 == 0 + on set_sub_charset == 1 + kernel.print = "subt_charset=" + subt_charset + player.subtitle_charset = subt_charset + on settings.user4 == 1 + on set_sub_charset == 1 + player.subtitle_charset = "koi8-r" + + set_sub_charset = 1 + player.subtitle_wrap = 35 + + start_play = 1 + on do_play_audio == 1 + start_play = 1 + + // PLAY! + on start_play == 1 + start_play = 0 + do_play = 0 + kernel.print = "PLAY " + play_path + play_cur_pos = play_pos + player.source = play_path + show_timer_balloon = "player/play" + playing = 1 + we_need_info = 1 + stop_before_play = 0 + player.command = "play" + allow_osd = 1 + restore_osd_for_continue = 1 + +// we want file info for OSD during play +we_asked_info_for != player.source + on we_need_info == 1 + we_asked_info_for = player.source + player.command = "info" + we_need_info = 0 + +on was_continue_play == 1 + on restore_osd_for_continue == 1 + restore_osd_for_continue = 0 + //kernel.print = "player.playing="+player.playing + do_osd = old_play_osd + +on playing == 1 + /////// if playing stopped: + on player.playing == 0 + play_cur_pos = -1 + cancel_search = 1 + tmp_play_osd = osd + cancel_osd = 1 + show_fast_balloon = "player/stop" + pad.clear = "all" + pad.display = "ISO" + // if video stopped - restore GUI + on do_play_video == 1 + on player.playing == 0 + kernel.print = "Restore ISO interface..." + in_menu = old_in_menu + redraw_iso = 1 + screen.update = "now" + on player.playing == 0 + do_play_audio = 0 + do_play_video = 0 + do_show_photo = 0 + cancel_zoom = 1 + allow_zoom = 0 + allow_osd = 0 + playing = 0 + playing_stopped = 1 + stop_before_play = 0 + + on do_continue_play == 0 + on player.source != play_path + play_path = player.source + kernel.print = "PLAY NEXT/PREV: " + play_path + +// in "play all/random" mode, we continue with the next file +on do_play_all == 1 && stop_before_play == 0 + on playing_stopped == 1 + was_continue_play = 0 + old_play_osd = tmp_play_osd // before we canceled + play_cmd = play_next_cmd + do_continue_play = 1 + +// play next/prev file... +on do_play_video == 1 || do_show_photo == 1 || osd == 1 + on play_type != "folder" + on pad.key == "next" + old_play_osd = osd + cancel_osd = 1 + play_cmd = play_next_cmd + do_continue_play = 1 + on pad.key == "prev" + old_play_osd = osd + cancel_osd = 1 + play_cmd = play_prev_cmd + do_continue_play = 1 + on play_type == "folder" + on pad.key == "next" + player.command = "next" + on pad.key == "prev" + player.command = "prev" + +//////// continue playing the next file +on do_continue_play == 1 + saved_pos = explorer.position + explorer.position = cur_play_pos + explorer.command = play_cmd // next or prev (normal/random) + cur_play_pos = explorer.position + + kernel.print = "Continue Play: " + explorer.filename + explorer.extension + play_pos = cur_play_pos + play_path = explorer.path + play_mediatype = explorer.maskindex + play_type = explorer.type + explorer.position = saved_pos + do_continue_play = 2 + +on cur_play_pos < 0 || cur_play_pos >= explorer.count + on do_continue_play == 2 + do_continue_play = 0 + do_play_all = 0 +on play_type != "file" && play_type != "track" && play_type != "folder" + on do_continue_play == 2 + do_continue_play = 1 + +on do_continue_play == 2 + do_continue_play = 0 + screen.update = "now" + was_continue_play = 1 + do_play = 1 + + +/////// player controls: +on playing == 1 + on pad.key == "pause" + do_pause = 1 + on player.speed == 1 + on do_pause == 1 + do_pause = 0 + show_static_balloon = "player/pause" + player.command = "pause" + + on pad.key == "forward" + player.command = "forward" + on pad.key == "rewind" + player.command = "rewind" + + on do_play_audio == 1 + on pad.key == "forward" + show_fast_balloon = "player/fwd" + on pad.key == "rewind" + show_fast_balloon = "player/rev" + + on do_play_video == 1 + on pad.key == "audio" + player.command = "audio" + on pad.key == "subtitle" + player.command = "subtitle" + on pad.key == "angle" + show_fast_balloon = "player/invalid" + + on pad.key == "stop" + kernel.print = "STOP PLAYING" + do_play_all = 0 + stop_before_play = 0 + player.command = "stop" + +// display playing status balloons +on playing == 1 + on do_play_video == 1 + on show_balloon != "player/invalid" + on player.speed == 1 + show_fast_balloon = "player/play" + on player.speed == 4 + show_static_balloon = "player/fwd" + on player.speed == -4 + show_static_balloon = "player/rev" + on player.speed > 4 + show_static_balloon = "player/fwdfast" + on player.speed < -4 + show_static_balloon = "player/revfast" + + // PAL/NTSC autodetect + on settings.user2 == 1 + on player.frame_rate > 0 + autodetect_pal_ntsc = 1 + + on player.subtitle != "" + subtitle.value = player.subtitle + on player.subtitle == "" + subtitle.value = player.subtitle + + on player.subtitle_stream == 0 + show_fast_balloon = "player/subtitleoff" + on player.subtitle_stream > 0 + show_fast_balloon = "player/subtitle" + show_balloon_text = player.language_subtitle + " ("+ player.subtitle_stream + ")" + + + // resume play + on player.speed != 1 && do_show_photo == 0 + on pad.key == "play" + resume_play = 1 + on player.speed == 0 && do_show_photo == 0 + on do_pause == 1 + do_pause = 0 + resume_play = 1 + on resume_play == 1 + cancel_search = 1 + show_fast_balloon = "player/play" + player.command = "play" + + on player.audio_stream > 0 + show_fast_balloon = "player/audio" + show_balloon_text = "Audio "+ player.audio_stream + +//////////////////////// +// react on errors: +on player.error == "invalid" + show_static_balloon = "player/invalid" +on player.error == "corrupted" + show_fast_balloon = "player/corrupted" +on player.error == "wait" + show_fast_balloon = "wait" +on player.error == "badaudio" + show_fast_balloon = "mute" +on player.error == "badvideo" + show_badvideo_popup = 1 +on player.error == "qpel" + qpel_gmc = "QPel"; + show_qpel_gmc_popup = 1 +on player.error == "gmc" + qpel_gmc = "GMC"; + show_qpel_gmc_popup = 1 diff --git a/mmsl/iso.mmsl b/mmsl/iso.mmsl new file mode 100644 index 0000000..ad30999 --- /dev/null +++ b/mmsl/iso.mmsl @@ -0,0 +1,111 @@ +lib_back = "img/lib.jpg" +screen.back = lib_back + +show_preview = "" +pad.clear = "all" +delete .group != "mute" && .group != "scr" +pad.display = "LoAd" +adjustment = 0 +screensaver = 0 +sleep_timer = 0 + +on drive.mediatype == "iso" || drive.mediatype == "mixed" + on explorer.folder == "/cdrom" + on display_pad == 1 + saved_display_pad = "ISO" + on explorer.folder == "/hdd" + on display_pad == 1 + saved_display_pad = "Hdd" + on explorer.drive_letter != "" + on display_pad == 1 + saved_display_pad = explorer.drive_letter + "_ Hdd" +on drive.mediatype == "audio" + on display_pad == 1 + show_timer_balloon = "cd" +on drive.mediatype == "audio" || drive.mediatype == "mixed" + on display_pad == 1 + pad.set = "cd" +on display_pad == 1 + pad.display = saved_display_pad + +search_title = "Time Search" +filesize_string = "" +filedate_string = "" + +iso_info = 1 + +do_init = 1 +on redraw_iso == 0 + on do_init == 1 + iso_init = 1 + +display_pad = 1 + +on drive.mediatype == "iso" || drive.mediatype == "mixed" || drive.mediatype == "audio" + on iso_init == 1 + explorer.folder = "/" +on iso_init == 1 + kernel.print = "Browser Init (" + iso_charset + ")..." + explorer.charset = iso_charset + explorer.target = "/playlist" + + explorer.filter = "up,track,folder,dvd,file" + explorer.sort = "normal" + + music_mask = "*.mp3,*.wav,*.ogg,*.mp2,*.mp1,*.mpa,*.ac3," + movie_mask = "*.avi,*.mpeg,*.mpg,*.m1v,*.m2v,*.dat,*.vob,*.divx,*.mp4,*.3gp," + pics_mask = "*.jpg,*.jpeg," + subt_mask = "*.sub,*.srt,*.ssa,*.txt" + + flag_music = 1 + flag_movie = 1 + flag_pics = 1 + flag_subt = 0 + + flag_playlist = 0 + playlist_edit = 0 + play_mode = "all" + + do_play_audio = 0 + do_play_video = 0 + do_show_photo = 0 + + playing = 0 + do_play_all = 0 + play_cur_pos = -1 + list_offset = 0 + + show_timer_balloon = "wait" + screen.update = "now" + + explorer.command = "update" + +//////////////////////////// +// handle file types: +on flag_movie >= 0 || flag_music >= 0 || flag_pics >= 0 || flag_subt >= 0 + explorer.mask1 = "" + explorer.mask2 = "" + explorer.mask3 = "" + explorer.mask4 = "" + explorer.mask5 = "romfs.bin" + flag_change_mask = 1 +on flag_movie == 1 + on flag_change_mask = 1 + explorer.mask1 = movie_mask +on flag_music == 1 + on flag_change_mask = 1 + explorer.mask2 = music_mask +on flag_pics == 1 + on flag_change_mask = 1 + explorer.mask3 = pics_mask +on flag_subt == 1 + on flag_change_mask = 1 + explorer.mask4 = subt_mask + + +include "list.mmsl" +include "iso-menu.mmsl" +include "iso-info.mmsl" +include "iso-play.mmsl" +include "iso-photo.mmsl" + diff --git a/mmsl/list.mmsl b/mmsl/list.mmsl new file mode 100644 index 0000000..8d56e65 --- /dev/null +++ b/mmsl/list.mmsl @@ -0,0 +1,437 @@ + +////////////////////////////////// +// header pic: + +add image header + header.x = screen.left + header.y = 20 + header.src = "img/mediatop.gif" + +////////////////////////////////// +// upper text: +upper_x = 150+30 +upper_y = 100 + +add text folder + folder.x = upper_x + folder.y = upper_y + folder.value = explorer.folder + + on explorer.folder != "" + folder.value = explorer.folder + +////////////////////////////////// +// list: + +list_x = 148 +list_y = 260 +list_count = 7 +list_item_height = 0 + +add rect play_rect + play_rect.group = "cursor_rect" + play_rect.round = 8 + play_rect.color = -1 + play_rect.color = colors.white + play_rect.backcolor = colors.grey + play_rect.visible = 0 + +add rect cursor_rect + cursor_rect.group = "cursor_rect" + cursor_rect.round=8 + cursor_rect.color = -1 + cursor_rect.backcolor = colors.yellowback + cursor_rect.visible = 0 + +add rect scroll_back + scroll_back.width = 10 + scroll_back.x = screen.right - 15 + scroll_back.y = list_y + scroll_back.height = screen.bottom - list_y - 10 + scroll_back.color = -1 + scroll_back.backcolor = colors.grey + +add image scroll_up + scroll_up.x = screen.right - 15 + scroll_up.y = list_y - 10 + scroll_up.src = "img/scroll.gif" +add image scroll_down + scroll_down.x = screen.right - 15 + scroll_down.y = screen.bottom - 10 + scroll_down.src = "img/scroll.gif" + scroll_down.vflip = 1 + +add rect scroll + scroll.width = scroll_back.width + scroll.height = scroll.width + scroll.x = screen.right - 15 + scroll.color = -1 + scroll.backcolor = colors.white + scroll.round = 5 + scroll.visible = 0 + +list_init = 1 +on iso_init == 1 + on list_init == 1 + list_init = 0 + iso_init = 0 + in_menu = explorer.count == 0 + menu_pos = 0 + explorer.position = list_offset + +folder_changed = 1 + +////////////////////////// +// start folder browsing: + +on folder_changed == 1 + list_offset = 0 + + on explorer.position - list_offset >= list_count + list_offset = explorer.position - list_count + 1 + + folder_changed = 0 + update_list = 1 + +//////////////////////////////////////// +// if user pressed 'ENTER': +on pad.key == "enter" + do_enter = 1 + +////////////////////////// +// update/draw list: + +on update_list == 1 + update_list_loop = 0 + delete .group == "items" + del_info = 1 + osd = 0 + +on explorer.count > 0 + on update_list == 1 + list_iy = list_y + list_pos = list_offset + saved_pos = explorer.position + explorer.position = list_offset + screen.update = 0 + + scroll_back.visible = 1 + scroll_up.visible = 1 + scroll_down.visible = 1 + + update_list_loop = 1 + +on explorer.count == 0 + on update_list == 1 + + scroll_back.visible = 0 + scroll_up.visible = 0 + scroll_down.visible = 0 + scroll.visible = 0 + cursor_rect.visible = 0 + show_balloon = "" + + screen.update = 1 + add text item + item.group = "items" + item.backcolor = -1 + item.x = list_x + 40; item.y = list_y; + item.value = "** No items **" + + +////////////////////////// +// draw 1 list item: + +on explorer.count > 0 + on update_list_loop == 1 + + // draw item icon: + icon_type = explorer.type + + on icon_type == "folder" + draw_icon = "foldericon" + on icon_type == "up" + draw_icon = "upfoldericon" + on explorer.maskindex == 1 // movie + on icon_type == "file" + draw_icon = "movieicon" + on explorer.maskindex == 2 // music + on icon_type == "file" + draw_icon = "musicicon" + on explorer.maskindex == 3 // pics + on icon_type == "file" + draw_icon = "picsicon" + on explorer.maskindex == 4 // subtitles + on icon_type == "file" + draw_icon = "subticon" + on explorer.maskindex == 5 // firmware + on icon_type == "file" + draw_icon = "fwicon" + on icon_type == "track" + draw_icon = "musicicon" + on icon_type == "dvd" + draw_icon = "dvdicon" + + on explorer.copied == 1 + on draw_icon != "" + draw_icon_src = "sel"+draw_icon + on explorer.copied == 0 + on draw_icon != "" + draw_icon_src = draw_icon + on draw_icon_src != "" + add image itemimg + itemimg.group = "items" + itemimg.x = list_x; itemimg.y = list_iy; + itemimg.src = "img/"+draw_icon_src+".gif" + + // print item text + add text item + item.group = "items" + item.backcolor = -1 + item.x = list_x + 40; item.y = list_iy; + set_item_type = explorer.type + on set_item_type == "up" + item.value = "[Up Folder]" + on set_item_type == "folder" + item.value = "[" + explorer.filename+explorer.extension + "]" + on set_item_type == "file" + item.value = explorer.filename+explorer.extension + on set_item_type == "track" + item.value = "Track " + explorer.filename + on set_item_type == "dvd" + item.value = "DVD Movie" + + list_item_height = item.height + list_iy = list_iy + list_item_height + 2 + explorer.command = "next" + list_pos = list_pos+1 + + on (list_pos < explorer.count && list_pos < list_offset + list_count) + update_list_loop = 1 + + on (list_pos >= explorer.count || list_pos >= list_offset + list_count) + explorer.position = saved_pos + update_list_loop = 2 + screen.update = 1 + + // the end of update + on update_list_loop == 2 + clear_balloon = 1 + on show_balloon != "player/stop" + on clear_balloon == 1 + show_balloon = "" + + cancel_popup = 1 + check_popups = 1 + on show_badvideo_popup == 1 + on check_popups == 1 + popup_timer = 4500 + auto_close_popup = 1 + show_popup_text = "Video codec not supported" + show_badvideo_popup = 0 + + on show_qpel_gmc_popup == 1 + on check_popups == 1 + popup_timer = 4500 + auto_close_popup = 1 + show_popup_text = "MPEG-4 Video with " + qpel_gmc + " not supported" + show_qpel_gmc_popup = 0 + + on show_badphoto_popup == 1 + on check_popups == 1 + popup_timer = 4500 + auto_close_popup = 1 + show_popup_text = "Cannot show JPEG file\n(too large or not enough memory)" + show_badphoto_popup = 0 + + update_list_loop = 0 + cur_pos = explorer.position + play_cur_pos = play_cur_pos + +///// move cursor + on cur_pos != -1 + cursor_rect.visible = 1 + cursor_rect.backcolor = colors.yellowback + cursor_rect.x = list_x + 33 + cursor_rect.y = list_y+(cur_pos-list_offset)*(list_item_height+2) + cursor_rect.width = screen.right-list_x - 40 + cursor_rect.height = list_item_height + // move scroller: + scroll.y = list_y + (cur_pos * scroll_back.height) / explorer.count + scroll_height = scroll_back.height / explorer.count + on scroll_height > 5 + scroll.height = scroll_height + on scroll_height <= 5 + scroll.height = 5 + scroll.visible = explorer.count > 1 + +////// move play cursor + on play_cur_pos > -2 + play_rect.visible = 0 + on in_menu != 2 && play_cur_pos >= list_offset && play_cur_pos < list_offset+list_count + on play_cur_pos != -1 + play_rect.visible = 1 + play_rect.x = list_x + 32 + play_rect.y = list_y+(play_cur_pos-list_offset)*(list_item_height+2)-1 + play_rect.width = screen.right - list_x - 40 + play_rect.height = list_item_height+2 + +/////////////////////////////////////////// +// cursor on the list: +on update_list_loop == 0 + on in_menu == 0 + on cur_pos < explorer.count - 1 + // cursor is at the bottom - scroll to the next page + on cur_pos == list_offset + list_count - 1 + on pad.key == "down" + explorer.command="next" + list_offset = explorer.position - list_count + 1 + cur_pos = explorer.position + update_list = 1 + + on (cur_pos - list_offset < list_offset + list_count - 1) + on pad.key == "down" + explorer.command = "next" + cur_pos = explorer.position + + // cursor is at the top - scroll to the prev. page + on cur_pos > 0 && cur_pos == list_offset + on pad.key == "up" + explorer.command = "prev" + list_offset = explorer.position + cur_pos = explorer.position + update_list = 1 + + on cur_pos > 0 + on pad.key == "up" + explorer.command = "prev" + cur_pos = explorer.position + + on pad.key == "next" + scroll_next = 1 + on pad.key == "prev" + scroll_prev = 1 + + on explorer.type == "folder" + on do_enter == 1 + do_enter = 0 + // we cannot continue playing if folder is changed + do_play_all = 0 + + explorer.folder = explorer.path + show_timer_balloon = "wait" + screen.update = "now" + explorer.command = "update" + display_pad = 1 + folder_changed = 1 + + on explorer.type == "up" + on do_enter == 1 + // we cannot continue playing if folder is changed + do_play_all = 0 + + do_enter = 0 + explorer.folder = ".." + show_timer_balloon = "wait" + screen.update = "now" + explorer.command = "update" + display_pad = 1 + folder_changed = 1 + + // play current file + on (explorer.type == "file" || explorer.type == "track" || explorer.type == "dvd") && playlist_edit == 0 + on do_enter == 1 + do_play_all = 0 + do_continue_play = 0 + stop_before_play = 0 + player.command = "stop" + play_pos = explorer.position + cur_play_pos = play_pos + play_next_cmd = "next" + play_prev_cmd = "prev" + play_path = explorer.path + play_mediatype = explorer.maskindex + play_type = explorer.type + do_enter = 0 + do_play_audio = 0 + do_play_video = 0 + do_show_photo = 0 + was_continue_play = 0 + do_play = 1 + + // copy to playlist + on (explorer.type == "file" || explorer.type == "track") && playlist_edit == 1 && explorer.copied == 0 + on do_enter == 1 + do_enter = 0 + explorer.command = "copy" + update_list = 1 + on (explorer.type == "file" || explorer.type == "track") && playlist_edit == 1 && explorer.copied == 1 + on do_enter == 1 + do_enter = 0 + explorer.command = "targetremove" + update_list = 1 + + /////////////////////////////////// + // jump to the first: + on cur_pos > 0 + on pad.key == "return" + explorer.position = 0 + list_offset = 0 + cur_pos = explorer.position + update_list = 1 + on pad.key == "title" + explorer.folder = "/" + explorer.command = "update" + display_pad = 1 + list_offset = 0 + cur_pos = explorer.position + update_list = 1 + + ///////////////////////////////////// + // page down: + on cur_pos <= explorer.count - list_count*2 + on scroll_next == 1 + explorer.position = explorer.position + list_count + list_offset = list_offset + list_count + cur_pos = explorer.position + update_list = 1 + + on cur_pos > explorer.count - list_count*2 && cur_pos < explorer.count - list_count + on scroll_next == 1 + explorer.position = explorer.position + list_count + list_offset = explorer.count - list_count + cur_pos = explorer.position + update_list = 1 + + on cur_pos >= explorer.count - list_count && cur_pos < explorer.count - 1 + on scroll_next == 1 + explorer.position = explorer.count - 1 + list_offset = explorer.count - list_count + on list_offset < 0 + list_offset = 0 + cur_pos = explorer.position + update_list = 1 + + ///////////////////////////////////// + // page up: + on cur_pos >= list_count*2 + on scroll_prev == 1 + explorer.position = explorer.position - list_count + list_offset = list_offset - list_count + cur_pos = explorer.position + update_list = 1 + + on cur_pos < list_count*2 && cur_pos >= list_count + on scroll_prev == 1 + explorer.position = explorer.position - list_count + list_offset = 0 + cur_pos = explorer.position + update_list = 1 + + on cur_pos < list_count && cur_pos > 0 + on scroll_prev == 1 + explorer.position = 0 + list_offset = 0 + cur_pos = explorer.position + update_list = 1 + diff --git a/mmsl/osd.mmsl b/mmsl/osd.mmsl new file mode 100644 index 0000000..92aa02e --- /dev/null +++ b/mmsl/osd.mmsl @@ -0,0 +1,379 @@ +////////////////////////// +/// OSD playing info: + +osd = 0 + +on allow_osd == 1 + on pad.key == "osd" + do_osd = 1 + +on osd == 0 + delete .group == "osd" + + on player.playing == 1 || setup == 1 || do_show_photo == 1 + on do_osd == 1 + real_do_osd = 1 + + on real_do_osd == 1 + kernel.print = "SHOW OSD INFO!" + do_osd = 0 + real_do_osd = 0 + cancel_osd = 0 + osd_old_in_menu = in_menu + in_menu = 2 + osd = 1 + delete .group == "osd" + add rect osdback + osdback.group = "osd" + osdback.halign = "center" + osdback.valign = "center" + osdback.x = (screen.right + screen.left) / 2 + osdback.y = (screen.bottom + screen.top) / 2 + osdback.width = 500 + osdback.height = 320 + osdback.round = 10 + osdback.color = -1 + osdback.backcolor = colors.blueback + + add rect osdframe + osdframe.group = "osd" + osdframe.halign = "center" + osdframe.valign = "center" + osdframe.x = osdback.x + osdframe.y = osdback.y + osdframe.width = osdback.width - 20 + osdframe.height = osdback.height - 20 + osdframe.round = 8 + osdframe.color = colors.yellow + osdframe.backcolor = -1 + + osd_x = osdback.x - osdback.width/2 + 30 + osd_y = osdback.y - osdback.height/2 + 20 + + add text osdhdr + osdhdr.group = "osd" + osdhdr.halign = "center" + osdhdr.x = osdback.x + osdhdr.y = osd_y + osdhdr.backcolor = osdback.backcolor + osdhdr.style = "underline" + osd_draw_header = 1 + + osd_ix = osd_x + osd_offx = 130 + osd_h = 24 + osd_iy = osd_y + osd_h * 2 + + osd_draw_main = 1 + +on drive.mediatype == "dvd" && player.playing == 1 + on osd_draw_header == 1 + osdhdr.value = "DVD Information" + on osd_draw_main == 1 + titletxt = "Title/Total" + print_title = 1 + print_chapter = 1 + print_time = 1 + print_length = 1 + print_audio = 1 + print_video = 1 + print_resolution = 1 + print_fps = 1 + +on drive.mediatype == "iso" || drive.mediatype == "mixed" + on osd_draw_header == 1 + osdhdr.value = "File Information" + on do_show_photo == 1 + on osd_draw_main == 1 + print_filename = 1 + print_filesize = 1 + print_filedate = 1 + print_resolution = 1 + print_clrs = 1 + on do_play_audio == 1 + on osd_draw_main == 1 + print_filename = 1 + print_filesize = 1 + print_time = 1 + print_length = 1 + print_audio = 1 + print_name = 1 + print_artist = 1 + + on do_play_video == 1 + on osd_draw_main == 1 + print_filename = 1 + print_filesize = 1 + print_time = 1 + print_length = 1 + print_audio = 1 + print_video = 1 + print_resolution = 1 + print_fps = 1 + +on play_type == "track" + on osd_draw_header == 1 + osdhdr.value = "Audio CD Information" + on osd_draw_main == 1 + titletxt = "Title/Total" + print_title = 1 + print_time = 1 + print_length = 1 + +on osd == 1 + on do_osd == 1 + do_osd = 0 + cancel_osd = 1 + + on pad.key == "cancel" + do_osd = 0 + cancel_osd = 1 + + on cancel_osd == 1 + in_menu = osd_old_in_menu + osd = 0 + + on print_osd != "" + add text osdtxt + osdtxt.group = "osd" + osdtxt.x = osd_ix + osdtxt.y = osd_iy + osdtxt.backcolor = osdback.backcolor + osdtxt.value = print_osd + + ////////////////////////// + // file name + on play_path != "" + on print_filename == 1 + print_osd = "File Name" + osd_ix = osd_x + osd_offx + print_osd = ":" + osd_ix = osd_x + osd_iy = osd_iy + osd_h + add text osdfname + osdfname.group = "osd" + osdfname.x = osd_ix + 10 + osdfname.y = osd_iy + osdfname.color = colors.yellow + osdfname.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + 5 + + on play_path != "" || print_filename == 1 + osdfname.value = play_path + osdfname.delete = 6 + osdfname.width = 420 + + ////////////////////////// + // file size + on filesize_string != "" + on print_filesize == 1 + print_osd = "File Size" + add text osdfsize + osdfsize.group = "osd" + osdfsize.x = osd_x + osd_offx + osdfsize.y = osd_iy + osdfsize.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on filesize_string != "" || print_filesize == 1 + osdfsize.value = ": " + filesize_string + + //////////////////////////////// + // file date + on filedate_string != "" + on print_filedate == 1 + print_osd = "File Date" + add text osdfdate + osdfdate.group = "osd" + osdfdate.x = osd_x + osd_offx + osdfdate.y = osd_iy + osdfdate.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on filedate_string != "" || print_filedate == 1 + osdfdate.value = ": " + filedate_string + + ////////////////////////// + // file time + on player.time >= 0 + on print_time == 1 + print_osd = "Play Time" + add text osdftime + osdftime.group = "osd" + osdftime.x = osd_x + osd_offx + osdftime.y = osd_iy + osdftime.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.time > 0 || print_time == 1 + osdftime.value = ": " + (player.time/36000) + ((player.time/3600)%10) + ":" + (player.time%3600/600) + ((player.time%3600/60)%10) + ":" + ((player.time%60)/10) + ((player.time%60)%10) + + ////////////////////////// + // file length + on player.length > 0 + on print_length == 1 + print_osd = "Length" + add text osdflength + osdflength.group = "osd" + osdflength.x = osd_x + osd_offx + osdflength.y = osd_iy + osdflength.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.length > 0 || print_length == 1 + osdflength.value = ": " + (player.length/36000) + ((player.length/3600)%10) + ":" + (player.length%3600/600) + ((player.length%3600/60)%10) + ":" + ((player.length%60)/10) + ((player.length%60)%10) + + ////////////////////////// + // audio info + on player.audio_info != "" + on print_audio == 1 + print_osd = "Audio Info" + add text osdaudio + osdaudio.group = "osd" + osdaudio.x = osd_x + osd_offx + osdaudio.y = osd_iy + osdaudio.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.audio_info != "" || print_audio == 1 + osdaudio.value = ": " + player.audio_info + + ////////////////////////// + // video info + on player.video_info != "" + on print_video == 1 + print_osd = "Video Info" + add text osdvideo + osdvideo.group = "osd" + osdvideo.x = osd_x + osd_offx + osdvideo.y = osd_iy + osdvideo.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.video_info != "" || print_video == 1 + osdvideo.value = ": " + player.video_info + + ////////////////////////// + // name + on player.name != "" + on print_name == 1 + print_osd = "Title" + add text osdname + osdname.group = "osd" + osdname.x = osd_x + osd_offx + osdname.y = osd_iy + osdname.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.name != "" || print_name == 1 + osdname.value = ": " + player.name + osdname.width = 315 + + ////////////////////////// + // artist + on player.artist != "" + on print_artist == 1 + print_osd = "Artist" + add text osdartist + osdartist.group = "osd" + osdartist.x = osd_x + osd_offx + osdartist.y = osd_iy + osdartist.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.artist != "" || print_artist == 1 + osdartist.value = ": " + player.artist + osdartist.width = 315 + + ////////////////////////// + // DVD title + on player.title > 0 && player.num_titles > 0 + on print_title == 1 + print_osd = titletxt + add text osdtitle + osdtitle.group = "osd" + osdtitle.x = osd_x + osd_offx + osdtitle.y = osd_iy + osdtitle.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.title > 0 && player.num_titles > 0 || print_title == 1 + osdtitle.value = ": " + (player.title/10) + (player.title%10) + " / " + (player.num_titles/10) + (player.num_titles%10) + + ////////////////////////// + // DVD chapter + on player.chapter > 0 && player.num_chapters > 0 + on print_chapter == 1 + print_osd = "Chapter/Total" + add text osdchapter + osdchapter.group = "osd" + osdchapter.x = osd_x + osd_offx + osdchapter.y = osd_iy + osdchapter.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.chapter > 0 && player.num_chapters > 0 || print_chapter == 1 + osdchapter.value = ": " + (player.chapter/10) + (player.chapter%10) + " / " + (player.num_chapters/10) + (player.num_chapters%10) + + ////////////////////////// + // resolution + on player.width > 0 && player.height > 0 + on print_resolution == 1 + print_osd = "Resolution" + add text osdresolution + osdresolution.group = "osd" + osdresolution.x = osd_x + osd_offx + osdresolution.y = osd_iy + osdresolution.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.width > 0 && player.height > 0 || print_resolution == 1 + osdresolution.value = ": " + player.width + " X " + player.height + + // frame rate + on player.frame_rate > 0 + on print_fps == 1 + print_osd = "Frame Rate" + add text osdfps + osdfps.group = "osd" + osdfps.x = osd_x + osd_offx + osdfps.y = osd_iy + osdfps.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.frame_rate > 0 || print_fps == 1 + osdfps.value = ": " + (player.frame_rate / 1000) + "," + (player.frame_rate % 1000)/100 + (player.frame_rate % 100)/10 + player.frame_rate % 10 + + ////////////////////////// + // color space + on player.color_space != "" + on print_clrs == 1 + print_osd = "Color Space" + add text osdclrs + osdclrs.group = "osd" + osdclrs.x = osd_x + osd_offx + osdclrs.y = osd_iy + osdclrs.backcolor = osdback.backcolor + osd_iy = osd_iy + osd_h + + on player.color_space != "" || print_clrs == 1 + osdclrs.value = ": " + player.color_space + +//////////////////////////////////////////// +// File size formatting: + +on filesize_value < 1000 && filesize_value >= 0 + filesize_string = filesize_value + " bytes" +on filesize_value < 1000000 && filesize_value >= 1000 + filesize_string = (filesize_value/1000) + ","+ ((filesize_value%1000)/100)+((filesize_value%100)/10)+(filesize_value%10)+" bytes" +on filesize_value < 1024000 && filesize_value >= 1000000 + filesize_string = (filesize_value/1024) + " Kbytes" +on filesize_value < 1024000000 && filesize_value >= 1024000 + filesize_string = (filesize_value/1024000) + ","+ (((filesize_value/1024)%1000)/100)+(((filesize_value/1024)%100)/10)+((filesize_value/1024)%10)+" Kbytes" +on filesize_value < 1048576000 && filesize_value >= 1024000000 + filesize_string = (filesize_value/1048576) + " Mbytes" +on filesize_value >= 1048576000 + filesize_string = (filesize_value/1048576000) + ","+ (((filesize_value/1048576)%1000)/100)+(((filesize_value/1048576)%100)/10)+((filesize_value/1048576)%10)+" Mbytes" +// if filesize if negative, it means the huge file, the size is in kilos. +on filesize_value < 0 + filesize_string = (-filesize_value/1048576) + "," + (((-filesize_value/1024)%1000)/100) + " Gbytes" diff --git a/mmsl/popup.mmsl b/mmsl/popup.mmsl new file mode 100644 index 0000000..1e8c3ab --- /dev/null +++ b/mmsl/popup.mmsl @@ -0,0 +1,43 @@ +auto_close_popup = 1 +cancel_popup = 0 + +on show_popup_text != "" + add image popup + popup.group = "popup" + popup.halign = "center" + popup.valign = "center" + popup.src = "img/player/popup.gif" + popup.x = (screen.right + screen.left) / 2 + popup.y = (screen.bottom + screen.top) / 2 - 20 + screen.backcolor = -1 + add text header + header.group = "popup" + header.font = font2 + header.valign = "center" + header.x = popup.x - 185 + header.y = popup.y - 83 + header.value = "Message" + stext_x = popup.x - 170 + stext_y1 = popup.y - 42 + add text popuptext + popuptext.group = "popup" + popuptext.x = stext_x + popuptext.y = stext_y1 + popuptext.font = msgfont + popuptext.value = show_popup_text + popuptext.width = 335 + popuptext.height = 120 + popuptext.timer = popup_timer + + on pad.key == "cancel" + cancel_popup = 1 + +on auto_close_popup == 1 + on popuptext.timer == 0 + cancel_popup = 1 + +on cancel_popup == 1 + delete .group == "popup" + show_popup_text = "" + auto_close_popup = 1 + diff --git a/mmsl/search.mmsl b/mmsl/search.mmsl new file mode 100644 index 0000000..2ea43f4 --- /dev/null +++ b/mmsl/search.mmsl @@ -0,0 +1,367 @@ +//////////////////////////// +// search: +on player.menu == 0 && (player.speed == 0 || player.speed == 1) && player.playing == 1 + on pad.key == "search" + do_search = 1 + +on player.menu == 1 + on pad.key == "search" + show_fast_balloon = "player/invalid" + +on search == 0 + on cancel_search == 1 + cancel_search = 0 + on do_search == 1 + cancel_search = 0 + do_search = 0 + old_allow_osd = allow_osd + allow_osd = 0 + old_allow_zoom = allow_zoom + allow_zoom = 0 + search_old_in_menu = in_menu + in_menu = 2 + search = 1 + show_balloon = "" + player.command = "pause" + add image popup + popup.group = "search" + popup.halign = "center" + popup.valign = "center" + popup.src = "img/player/popup.gif" + popup.x = (screen.right + screen.left) / 2 + popup.y = (screen.bottom + screen.top) / 2 - 20 + screen.backcolor = -1 + add text header + header.group = "search" + header.valign = "center" + header.font = font2 + header.x = popup.x - 185 + header.y = popup.y - 83 + header.value = search_title + stext_x = popup.x - 50 + stext_y1 = popup.y - 42 + stext_y2 = stext_y1 + 20 + + stext_y3 = stext_y1 + stext_y4 = stext_y2 + + stext_yr = stext_y1 + 60 + add rect srect + srect.group = "search" + srect.backcolor = colors.white + srect.linewidth = 0 + + screen.halign = "right" + draw_titles = 1 + add text t; t.group = "search"; t.x = stext_x; t.y = stext_y3; t.value = "Time :" + add text tt; tt.group = "search"; tt.x = stext_x; tt.y = stext_y4; tt.value = "Total Time :" + + screen.halign = "left" + stext_x = stext_x + 20 + + rlength_width = 310 + rlength_height = 10 + + add rect rlength + rlength.group = "search" + rlength.width = rlength_width + 4 + rlength.x = popup.x - 180 + rlength.y = stext_yr + rlength.height = rlength_height + 4 + rlength.linewidth = 1 + rlength.color = colors.white + rlength.backcolor = -1 + + add rect rtime + rtime.group = "search" + rtime.width = rlength_width + rtime.x = rlength.x + 2 + rtime.y = stext_yr + 2 + rtime.height = rlength_height + rtime.linewidth = 0 + rtime.backcolor = colors.yellow + + draw_titles = 2 + + add text time; time.group = "search"; time.color = colors.yellow; time.x = stext_x; time.y = stext_y3; + old_cur_secs = player.time + cur_secs = player.time + + add text fulltime; fulltime.group = "search"; fulltime.x = stext_x; fulltime.y = stext_y4; + fulltime.value = "" + (player.length/36000) + ((player.length/3600)%10) + ":" + (player.length%3600/600) + ((player.length%3600/60)%10) + ":" + ((player.length%60)/10) + ((player.length%60)%10) + + screen.halign = "left" + + sy = 2 + sx = 0 + + draw_titles = 3 + + on set_digit >= 0 + kernel.print = "Jump to " + (set_digit * 10) + "%%!" + player.command = "pause" + player.time = player.length * set_digit / 10 + player.command = "play" + +on drive.mediatype == "dvd" + on draw_titles == 1 + draw_titles = 0 + add text t; t.group = "search"; t.x = stext_x; t.y = stext_y1; t.value = "Title/Total :" + add text ct; ct.group = "search"; ct.x = stext_x; ct.y = stext_y2; ct_value = "Chapter/Total :"; ct.value = ct_value; + stext_y3 = stext_y1 + 50 + stext_y4 = stext_y1 + 70 + stext_yr = stext_y1 + 110 + +on drive.mediatype == "dvd" + on draw_titles == 2 + draw_titles = 0 + add text title; title.group = "search"; title.color = colors.yellow; title.x = stext_x; title.y = stext_y1; + real_title = player.title + cur_title = player.title + + add text t; t.group = "search"; t.x = stext_x + title.width; t.y = stext_y1; t.value = " / " + (player.num_titles/10) + (player.num_titles%10) + + add text chapter; chapter.group = "search"; chapter.color = colors.yellow; chapter.x = stext_x; chapter.y = stext_y2; + cur_chapter = player.chapter + + add text numch; numch.group = "search"; numch.x = stext_x + chapter.width; numch.y = stext_y2; + num_chapters = player.num_chapters + +on drive.mediatype == "dvd" + on draw_titles == 3 + draw_titles = 0 + sy = 1 + sx = 1 - (cur_chapter > 9) + +on search == 1 + on do_search == 1 || pad.key == "cancel" + cancel_search = 1 + on player.playing == 1 + on cancel_search == 1 + player.command = "cancel" // cancel all changes + player.command = "play" + on cancel_search == 1 + delete .group == "search" + in_menu = search_old_in_menu + allow_osd = old_allow_osd + allow_zoom = old_allow_zoom + cancel_search = 0 + search = 0 + + on pad.key == "enter" + delete .group == "search" + player.command = "play" + in_menu = search_old_in_menu + allow_osd = old_allow_osd + allow_zoom = old_allow_zoom + search = 0 + + // update time + on player.length > 0 + on cur_secs > player.length + cur_secs = old_cur_secs + on cur_secs >= 0 + old_cur_secs = cur_secs + s_h1 = (cur_secs/36000) + s_h2 = ((cur_secs/3600)%10) + s_m1 = (cur_secs%3600/600) + s_m2 = ((cur_secs%3600/60)%10) + s_s1 = ((cur_secs%60)/10) + s_s2 = ((cur_secs%60)%10) + time.value = "" + s_h1 + s_h2 + ":" + s_m1 + s_m2 + ":" + s_s1 + s_s2 + rtime.width = cur_secs * rlength_width / player.length + on cur_secs != player.time + on cur_secs >= 0 + player.time = cur_secs + + on update_cur_secs == 1 + cur_secs = (s_h1 * 10 + s_h2) * 3600 + (s_m1 * 10 + s_m2) * 60 + (s_s1 * 10 + s_s2) + + on player.time >= 0 && player.time <= player.length + cur_secs = player.time + on player.length > 0 + on player.time >= 0 && player.time > player.length + cur_secs = player.length + + on cur_title >= 0 + s_t1 = (cur_title/10) + s_t2 = (cur_title%10) + title.value = "" + s_t1 + s_t2 + + on cur_title != player.title + on cur_title >= 0 + player.title = cur_title + + on cur_title != real_title + fulltime.visible = 0 + time.visible = 0 + tt.visible = 0 + + on cur_title == real_title + fulltime.visible = 1 + time.visible = 1 + tt.visible = 1 + + on update_cur_title == 1 + cur_title = s_t1 * 10 + s_t2 + + on cur_chapter >= 0 + s_c1 = (cur_chapter/10) + s_c2 = (cur_chapter%10) + chapter.value = "" + s_c1 + s_c2 + on cur_chapter != player.chapter + on cur_chapter >= 0 + player.chapter = cur_chapter + + on update_cur_chapter == 1 + cur_chapter = s_c1 * 10 + s_c2 + + on player.chapter >= 0 + cur_chapter = player.chapter + + on num_chapters >= 0 + numch.value = " / " + (num_chapters/10) + (num_chapters%10) + + on player.num_chapters >= 0 + num_chapters = player.num_chapters + + on pad.key == "up" + move_up = 1 + on pad.key == "down" + move_down = 1 + + // draw cursor + char_w = 10 + on sy == 0 + on sx >= 0 + srect.x = title.x + sx * char_w + srect.width = char_w+1 + srect.y = title.y+1 + srect.height = title.height-2 + on pad.key == "right" || pad.key == "left" + sx = 1 - sx + on move_down == 1 + move_down = 0 + sy = 1 + sx = 1 + on sx == 0 + on set_digit >= 0 + s_t1 = set_digit + set_digit = -1 + update_cur_title = 1 + sx = sx + 1 + on sx == 1 + on set_digit >= 0 + s_t2 = set_digit + update_cur_title = 1 + on sy == 1 + on sx >= 0 + srect.x = chapter.x + sx * char_w + srect.width = char_w+1 + srect.y = chapter.y+1 + srect.height = chapter.height-2 + on pad.key == "right" || pad.key == "left" + sx = 1 - sx + on move_up == 1 + move_up = 0 + sy = 0 + sx = 1 + on move_down == 1 + move_down = 1 + sy = 2 + sx = 0 + on sx == 0 + on set_digit >= 0 + s_c1 = set_digit + set_digit = -1 + update_cur_chapter = 1 + sx = sx + 1 + on sx == 1 + on set_digit >= 0 + s_c2 = set_digit + update_cur_chapter = 1 + on sy == 2 + on sx < 5 + on pad.key == "right" + sx = sx + 1 + on sx > 0 + on pad.key == "left" + sx = sx - 1 + on drive.mediatype == "dvd" // move to chapters/titles only for DVD + on move_up == 1 + move_up = 0 + sy = 1 + sx = 1 + on sx == 0 || sx == 1 + srect.x = time.x + sx * char_w + srect.width = char_w+1 + srect.y = time.y+1 + srect.height = time.height-2 + on sx == 2 || sx == 3 + srect.x = time.x + 7 + sx * char_w + srect.width = char_w+1 + srect.y = time.y+1 + srect.height = time.height-2 + on sx == 4 || sx == 5 + srect.x = time.x + 14 + sx * char_w + srect.width = char_w+1 + srect.y = time.y+1 + srect.height = time.height-2 + on sx == 0 + on set_digit >= 0 + s_h1 = set_digit + set_digit = -1 + update_cur_secs = 1 + sx = sx + 1 + on sx == 1 + on set_digit >= 0 + s_h2 = set_digit + set_digit = -1 + update_cur_secs = 1 + sx = sx + 1 + on sx == 2 + on set_digit >= 0 && set_digit <= 5 + s_m1 = set_digit + set_digit = -1 + update_cur_secs = 1 + sx = sx + 1 + on sx == 3 + on set_digit >= 0 + s_m2 = set_digit + set_digit = -1 + update_cur_secs = 1 + sx = sx + 1 + on sx == 4 + on set_digit >= 0 && set_digit <= 5 + s_s1 = set_digit + set_digit = -1 + update_cur_secs = 1 + sx = sx + 1 + on sx == 5 + on set_digit >= 0 + s_s2 = set_digit + set_digit = -1 + update_cur_secs = 1 + +on player.playing == 1 + on pad.key == "zero" + set_digit = 0 + on pad.key == "one" + set_digit = 1 + on pad.key == "two" + set_digit = 2 + on pad.key == "three" + set_digit = 3 + on pad.key == "four" + set_digit = 4 + on pad.key == "five" + set_digit = 5 + on pad.key == "six" + set_digit = 6 + on pad.key == "seven" + set_digit = 7 + on pad.key == "eight" + set_digit = 8 + on pad.key == "nine" + set_digit = 9 + diff --git a/mmsl/setup.mmsl b/mmsl/setup.mmsl new file mode 100644 index 0000000..3705f15 --- /dev/null +++ b/mmsl/setup.mmsl @@ -0,0 +1,688 @@ +/* Setup structure: + PAGE 1: + y=0 Analog(1) Digital(2) + y=1 Letterbox(3) Panscan(4) Wide(5) + y=2 C/S-Video(6) YPbPr(7) RGB(8) + y=3 PAL(9) NTSC(10) + y=4 OSD DVD-Menu DVD-Audio DVD-Sub + y=5 En(11) Ru(12) De(13) Fr(14) Es(15) Pl(16) + + settings.user1 - OSD language + settings.user2 - Auto detect PAL/NTSC + settings.user3 - FS charset + settings.user4 - subtitle charset + settings.user5 - screensaver time, in seconds + settings.user6 - photo slide show time, in seconds + settings.user7 - sleep timer, in minutes +*/ + +kernel.print = "Entering SETUP..." + +setup_page = 1 + +on setup_page == 1 + delete .group != "mute" && .group != "scr" + screen.back = "img/setup1.jpg" + adjustment = 0 + + add image ssel1; ssel1.group = "setup"; ssel1.src = "img/yes.gif" + add image ssel2; ssel2.group = "setup"; ssel2.src = "img/yes.gif" + add image ssel3; ssel3.group = "setup"; ssel3.src = "img/yes.gif" + add image ssel4; ssel4.group = "setup"; ssel4.src = "img/yes.gif" + add image ssel5; ssel5.group = "setup"; ssel5.src = "img/yes.gif" + ssel4.visible = 0 + ssel5.visible = 0 + + add rect langrect + langrect.group = "setup" + langrect.width = 109 + langrect.height = 21 + langrect.backcolor = colors.yellowback + langrect.color = -1 + langrect.round = 4 + langrect.visible = 0 + + load_settings = 1 + +on setup_page == 2 + delete .group != "mute" && .group != "scr" + screen.update = "now" + screen.back = "img/setup2.jpg" + + on display_setup_line != "" + add text s2text + s2text.group = "setup" + s2text.x = 70 + s2text.y = setup_line_i + s2text.color = colors.yellow + s2text.value = display_setup_line + setup_line_i = setup_line_i + s2text.height + + setup_line_i = 115 + display_setup_line = "Auto PAL/NTSC detect for video: " + + add text s2text1 + s2text1.group = "setup" + s2text1.x = s2text.x + s2text.width + s2text1.y = s2text.y + s2text1.color = colors.white + + display_setup_line = "Filesystem charset: " + + add text s2text2 + s2text2.group = "setup" + s2text2.x = s2text.x + s2text.width + s2text2.y = s2text.y + s2text2.color = colors.white + + display_setup_line = "Subtitle file charset: " + + add text s2text3 + s2text3.group = "setup" + s2text3.x = s2text.x + s2text.width + s2text3.y = s2text.y + s2text3.color = colors.white + + display_setup_line = "HD Component Out: " + + add text s2text4 + s2text4.group = "setup" + s2text4.x = s2text.x + s2text.width + s2text4.y = s2text.y + s2text4.color = colors.white + + display_setup_line = "HQ Photo Viewer: " + + add text s2text5 + s2text5.group = "setup" + s2text5.x = s2text.x + s2text.width + s2text5.y = s2text.y + s2text5.color = colors.white + + display_setup_line = "Photo Slide Show: " + + add text s2text55 + s2text55.group = "setup" + s2text55.x = s2text.x + s2text.width + s2text55.y = s2text.y + s2text55.color = colors.white + + display_setup_line = "SATA/PATA HDD Speed (needs restart): " + + add text s2text6 + s2text6.group = "setup" + s2text6.x = s2text.x + s2text.width + s2text6.y = s2text.y + s2text6.color = colors.white + + display_setup_line = "Screen Saver: " + + add text s2text7 + s2text7.group = "setup" + s2text7.x = s2text.x + s2text.width + s2text7.y = s2text.y + s2text7.color = colors.white + + display_setup_line = "Sleep Timer: " + + add text s2text8 + s2text8.group = "setup" + s2text8.x = s2text.x + s2text.width + s2text8.y = s2text.y + s2text8.color = colors.white + + load_settings = 2 + +on setup_page != 0 + sel_id = -1 + set_sel_id = -1 + + add rect srect + srect.group = "setup" + srect.width = 80 + srect.height = 25 + srect.backcolor = -1 + srect.color = colors.yellow + srect.round = 5 + srect.linewidth = 2 + +on setup_page == 1 + setup_y = 0 + setup_x = 0 + +on setup_page == 2 + setup_y = 0 + sel_id = 20 + +on cancel_setup == 1 + cancel_setup = 0 + setup = 0 + delete .group != "mute" && .group != "scr" + //screen.back = "" + +/////// load settings +on settings.audioout == "analog" + on load_settings == 1 + sel_id = 1 +on settings.audioout == "digital" + on load_settings == 1 + sel_id = 2 +on settings.tvtype == "letterbox" + on load_settings == 1 + sel_id = 3 +on settings.tvtype == "panscan" + on load_settings == 1 + sel_id = 4 +on settings.tvtype == "wide" + on load_settings == 1 + sel_id = 5 +on settings.tvout == "composite" + on load_settings == 1 + sel_id = 6 +on settings.tvout == "ypbpr" + on load_settings == 1 + sel_id = 7 +on settings.tvout == "rgb" + on load_settings == 1 + sel_id = 8 +on settings.tvstandard == "pal" + on load_settings == 1 + sel_id = 9 +on settings.tvstandard == "ntsc" + on load_settings == 1 + sel_id = 10 + +num_charsets = 2 + +on settings.tvstandard != "pal" && settings.tvstandard != "ntsc" + on load_settings == 2 + settings.user2 = 0 + s2text1.color = colors.lightgrey + +on settings.user2 == 0 + on load_settings == 2 + s2text1.value = "No" +on settings.user2 == 1 + on load_settings == 2 + s2text1.value = "Yes" +on settings.user3 == 0 + on load_settings == 2 + s2text2.value = "Win/ISO" +on settings.user3 == 1 + on load_settings == 2 + s2text2.value = "KOI8-R" +on settings.user4 == 0 + on load_settings == 2 + s2text3.value = "Win/ISO" +on settings.user4 == 1 + on load_settings == 2 + s2text3.value = "KOI8-R" + +on settings.tvstandard == "pal" || settings.tvstandard == "ntsc" + on load_settings == 2 + s2text4.value = "Off" +on settings.tvstandard == "480p" + on load_settings == 2 + s2text4.value = "480P" +on settings.tvstandard == "576p" + on load_settings == 2 + s2text4.value = "576P" +on settings.tvstandard == "720p" + on load_settings == 2 + s2text4.value = "720P" +on settings.tvstandard == "1080i" + on load_settings == 2 + s2text4.value = "1080i" + +on settings.hq_jpeg == 0 + on load_settings == 2 + s2text5.value = "No" +on settings.hq_jpeg == 1 + on load_settings == 2 + s2text5.value = "Yes" + +on settings.hdd_speed == "fastest" + on load_settings == 2 + s2text6.value = "Fastest" +on settings.hdd_speed == "limited" + on load_settings == 2 + s2text6.value = "Limited" +on settings.hdd_speed == "slow" + on load_settings == 2 + s2text6.value = "Slow" + +on settings.user5 < 60 + on load_settings == 2 + set_sel_id = -1 + s2text7.value = settings.user5 + " Secs" +on settings.user5 == 60 + on load_settings == 2 + set_sel_id = -1 + s2text7.value = "1 Min" +on settings.user5 > 60 + on load_settings == 2 + set_sel_id = -1 + s2text7.value = (settings.user5 / 60) + " Mins" +on settings.user5 == 0 + on load_settings == 2 + s2text7.value = "Off" + +on settings.user6 > 0 + on load_settings == 2 + set_sel_id = -1 + s2text55.value = settings.user6 + " Seconds" +on settings.user6 == 0 + on load_settings == 2 + s2text55.value = "Off" + +on settings.user7 > 0 + on load_settings == 2 + set_sel_id = -1 + s2text8.value = settings.user7 + " Mins" +on settings.user7 == 0 + on load_settings == 2 + s2text8.value = "Off" +////// move cursor +on osd == 0 + on pad.key == "right" + smove_x = 1 + on pad.key == "left" + smove_x = -1 + on pad.key == "up" + smove_y = -1 + on pad.key == "down" + smove_y = 1 + on pad.key == "enter" + set_sel = 1 + set_sel_id = sel_id + + on pad.key == "return" + settings.command = "defaults" + screen.tvout = settings.tvout + screen.tvstandard = settings.tvstandard + setup_page = setup_page + +//////////////////////////// +// OSD Info: +on pad.key == "osd" + do_setup_osd = 1 + +on osd == 0 + on do_setup_osd == 1 + do_setup_osd = 0 + do_osd = 1 + +on osd == 1 + on do_setup_osd == 1 + do_setup_osd = 0 + cancel_osd = 1 + on pad.key == "enter" + cancel_osd = 1 + + on osd_draw_header == 1 + osdback.backcolor = colors.lightblueback + osdhdr.backcolor = osdback.backcolor + osdhdr.value = "Player Information" + + on osd_draw_main == 1 + osd_ix = osdback.x + screen.halign = "center" + screen.font = msgfont + setup_print_osd = "*** SigmaPlayer Firmware (Technosonic version) ***" + setup_print_osd = "Copyright (c) SigmaPlayer Team, 2010." + screen.halign = "left" + osd_ix = osd_x + osd_iy = osd_iy + osd_h + setup_print_osd = "Firmware version" + setup_print_osd = "MMSL version" + setup_print_osd = "Chip version" + setup_print_osd = "Core frequency" + setup_print_osd = "Available memory" + setup_print_osd = "FLASH memory" + + osd_iy = osd_y + osd_h * 5 + osd_ix = osd_ix + 190 + setup_print_osd = ": " + kernel.firmware_version + setup_print_osd = ": " + kernel.mmsl_version + setup_print_osd = ": " + kernel.chip + setup_print_osd = ": " + kernel.frequency + " MHz" + filesize_value = kernel.free_memory + setup_print_osd = ": " + filesize_string + filesize_value = kernel.flash_memory + setup_print_osd = ": " + filesize_string + + screen.font = font1 + + on setup_print_osd != "" + print_osd = setup_print_osd + osd_iy = osd_iy + osd_h + +///////// pages: +on setup_page == 1 + on pad.key == "next" + cancel_osd = 1 + setup_page = setup_page + 1 +on setup_page == 2 + on pad.key == "prev" + cancel_osd = 1 + setup_page = setup_page - 1 + +on setup_page == 1 + on (setup_y == 0 || setup_y == 3) && setup_x + smove_x >= 0 && setup_x + smove_x <= 1 + on smove_x != 0 + setup_x = setup_x + smove_x + on (setup_y == 1 || setup_y == 2) && setup_x + smove_x >= 0 && setup_x + smove_x <= 2 + on smove_x != 0 + setup_x = setup_x + smove_x + on setup_y == 4 && setup_x + smove_x >= 0 && setup_x + smove_x <= 3 + on smove_x != 0 + setup_x = setup_x + smove_x + on setup_y == 5 && setup_x + smove_x >= 0 && setup_x + smove_x <= 5 + on smove_x != 0 + setup_x = setup_x + smove_x + // save lang.type selection + on setup_y == 4 + on smove_y == 1 + slang_setup_x = setup_x + setup_y = 5 + setup_x = 0 + smove_y = 0 + on setup_y == 5 + on smove_y == -1 + setup_y = 4 + setup_x = slang_setup_x + smove_y = 0 + on setup_y + smove_y >= 0 && setup_y + smove_y <= 5 + on smove_y != 0 + setup_y = setup_y + smove_y + setup_x = 0 + + // set selection + on setup_y == 0 || setup_y == 1 + on set_sel == 1 + sel_id = 1 + setup_y * 2 + setup_x + on setup_y == 2 || setup_y == 3 + on set_sel == 1 + sel_id = 6 + (setup_y - 2) * 3 + setup_x + on setup_y == 5 + on set_sel == 1 + sel_id = 11 + setup_x + + // set cursor + on setup_y == 0 + on setup_x >= 0 + srect.width = 59 + srect.height = 25 + srect.x = 109 + 203 * setup_x + srect.y = 115 + on setup_y >= 1 && setup_y <= 2 + on setup_x >= 0 + srect.width = 77 - (setup_x * 11) + srect.height = 25 + srect.x = 67 + 160 * setup_x + srect.y = 199 + 62 * (setup_y - 1) + on setup_y == 3 + on setup_x >= 0 + srect.width = 50 + srect.height = 25 + srect.x = 163 + 145 * setup_x + srect.y = 312 + on setup_y == 4 + on setup_x >= 0 + srect.width = 113 + srect.height = 25 + srect.x = 59 + 120 * setup_x + srect.y = 370 + langrect.x = srect.x + 2 + langrect.y = srect.y + 2 + langrect.visible = 1 + slang = setup_x + on setup_y != 4 && setup_y != 5 + langrect.visible = 0 + ssel5.visible = 0 + on setup_y == 5 + on setup_x >= 0 + srect.width = 50 + srect.height = 36 + srect.x = 121 + 62 * setup_x + srect.y = 406 + langrect.visible = 1 + +on setup_page == 2 + // set cursor + on setup_y >= 0 + srect.width = 430 + srect.height = 25 + srect.x = 65 + srect.y = 115 + s2text.height * setup_y + + on setup_y + smove_y >= 0 && setup_y + smove_y <= 8 + on smove_y != 0 + setup_y = setup_y + smove_y + sel_id = 20 + setup_y + set_tv = "" + +on slang == 0 + sel_id = settings.user1 + 11 // OSD lang +on slang == 1 + set_lang = settings.dvd_lang_menu +on slang == 2 + set_lang = settings.dvd_lang_audio +on slang == 3 + set_lang = settings.dvd_lang_spu + +on set_lang == "en" + sel_id = 11 +on set_lang == "ru" + sel_id = 12 +on set_lang == "de" + sel_id = 13 +on set_lang == "fr" + sel_id = 14 +on set_lang == "es" + sel_id = 15 +on set_lang == "pl" + sel_id = 16 + +// set selection cursor +on sel_id == 1 + scur_x = 114; scur_y = 101; + draw_sel = 1 +on sel_id == 2 + scur_x = 319; scur_y = 101; + draw_sel = 1 +on sel_id >= 3 && sel_id <= 5 + scur_x = 82 + 153 * (sel_id-3); scur_y = 188; + draw_sel = 2 +on sel_id >= 6 && sel_id <= 8 + scur_x = 80 + 154 * (sel_id-6); scur_y = 251; + draw_sel = 3 +on sel_id >= 9 && sel_id <= 10 + scur_x = 162 + 145 * (sel_id-9); scur_y = 303; + draw_sel = 4 +on sel_id >= 11 && sel_id <= 16 + scur_x = 120 + 62 * (sel_id-11); scur_y = 398; + draw_sel = 5 + +// draw selection +on draw_sel == 1 + ssel1.x = scur_x; ssel1.y = scur_y +on draw_sel == 2 + ssel2.x = scur_x; ssel2.y = scur_y +on draw_sel == 3 + ssel3.x = scur_x; ssel3.y = scur_y +on draw_sel == 4 + ssel4.x = scur_x; ssel4.y = scur_y + ssel4.visible = 1; +on draw_sel == 5 + ssel5.x = scur_x; ssel5.y = scur_y + ssel5.visible = 1 + +/////////////////// +// save settings +on set_sel_id == 1 + settings.audioout = "analog" +on set_sel_id == 2 + settings.audioout = "digital" +on set_sel_id == 3 + settings.tvtype = "letterbox" + allow_balloons = 0 + screen.tvout = settings.tvout + allow_balloons = 1 +on set_sel_id == 4 + settings.tvtype = "panscan" + allow_balloons = 0 + screen.tvout = settings.tvout + allow_balloons = 1 +on set_sel_id == 5 + settings.tvtype = "wide" + allow_balloons = 0 + screen.tvout = settings.tvout + allow_balloons = 1 +on set_sel_id == 6 + settings.tvout = "composite" + screen.tvout = settings.tvout + saved_tvout = settings.tvout +on set_sel_id == 7 + settings.tvout = "ypbpr" + screen.tvout = settings.tvout + saved_tvout = settings.tvout +on set_sel_id == 8 + settings.tvout = "rgb" + screen.tvout = settings.tvout + saved_tvout = settings.tvout +on set_sel_id == 9 + settings.tvstandard = "pal" + screen.tvstandard = settings.tvstandard +on set_sel_id == 10 + settings.tvstandard = "ntsc" + screen.tvstandard = settings.tvstandard +on slang == 0 + on set_sel_id >= 11 && set_sel_id <= 16 + settings.user1 = set_sel_id - 11 + set_lang = 1 + screen.font = font1 + sel_id = settings.user1 + 11 // OSD lang +on slang != 0 + on set_sel_id == 11 + save_lang = "en" + on set_sel_id == 12 + save_lang = "ru" + on set_sel_id == 13 + save_lang = "de" + on set_sel_id == 14 + save_lang = "fr" + on set_sel_id == 15 + save_lang = "es" + on set_sel_id == 16 + save_lang = "pl" +on slang == 1 + on save_lang != "" + settings.dvd_lang_menu = save_lang +on slang == 2 + on save_lang != "" + settings.dvd_lang_audio = save_lang +on slang == 3 + on save_lang != "" + settings.dvd_lang_spu = save_lang + +on settings.tvstandard == "pal" || settings.tvstandard == "ntsc" + on set_sel_id == 20 + settings.user2 = 1 - settings.user2 + load_settings = 2 + +on set_sel_id == 21 + settings.user3 = settings.user3 + 1 + load_settings = 2 + set_lang = 1 + +on set_sel_id == 22 + settings.user4 = settings.user4 + 1 + load_settings = 2 + set_lang = 1 + +on settings.tvstandard == "pal" || settings.tvstandard == "ntsc" || settings.tvstandard == "" + on set_sel_id == 23 + set_tv = "480p" +on settings.tvstandard == "480p" + on set_sel_id == 23 + set_tv = "576p" +on settings.tvstandard == "576p" + on set_sel_id == 23 + set_tv = "720p" +on settings.tvstandard == "720p" + on set_sel_id == 23 + set_tv = "1080i" +on settings.tvstandard == "1080i" + on set_sel_id == 23 + set_tv = "pal" + +on set_sel_id == 24 + settings.hq_jpeg = settings.hq_jpeg + 1 + load_settings = 2 + +on set_sel_id == 26 + settings.hdd_speed = "next" + load_settings = 2 + +on settings.user5 < 900 + on set_sel_id == 27 + u = settings.user5 + // 30 45 60 120 180 300 600 900 + settings.user5 = u + 15 + (u == 0) * 15 + (u > 45) * 45 + (u > 120) * 60 + (u > 180) * 180 + load_settings = 2 +on settings.user5 >= 900 + on set_sel_id == 27 + settings.user5 = 0 + load_settings = 2 + +on settings.user6 < 60 + on set_sel_id == 25 + u = settings.user6 + // 1 2 3 5 10 15 20 30 60 + settings.user6 = u + 1 + (u == 3) + (u >= 5) * 4 + (u > 15) * 5 + (u > 20) * 20 + load_settings = 2 +on settings.user6 >= 60 + on set_sel_id == 25 + settings.user6 = 0 + load_settings = 2 + +on settings.user7 < 120 + on set_sel_id == 28 + u = settings.user7 + // 15, 30, 45, 60, 90, 120 + settings.user7 = u + 15 + (u > 45) * 15 + load_settings = 2 +on settings.user7 >= 120 + on set_sel_id == 28 + settings.user7 = 0 + load_settings = 2 + +on set_tv == "pal" + settings.tvout = saved_tvout + s2text1.color = colors.white +on set_tv != "pal" && set_tv != "" + settings.tvout = "ypbpr" + settings.user2 = 0 + s2text1.color = colors.lightgrey +on set_tv != "" + set_sel_id = -1 + settings.tvstandard = set_tv + load_settings = 2 + show_timer_balloon = "wait" + screen.update = "now" + s2text4.timer = 1000 + +on set_tv != "" + on s2text4.timer == 0 + screen.tvout = settings.tvout + screen.tvstandard = settings.tvstandard + +on set_tv == "" + s2text4.timer = 0 + show_balloon = "" + +on settings.user3 >= num_charsets + settings.user3 = 0 +on settings.user4 >= num_charsets + settings.user4 = 0 diff --git a/mmsl/ssaver.mmsl b/mmsl/ssaver.mmsl new file mode 100644 index 0000000..bac6ba9 --- /dev/null +++ b/mmsl/ssaver.mmsl @@ -0,0 +1,145 @@ +scr_timeout = settings.user5 * 1000 +scr_timeout2 = settings.user7 * 60000 +scr_small_timeout = 300 +scr_img_timeout = 3000 + +on settings.user5 > -1 + scr_timeout = settings.user5 * 1000 + scr.timer = scr_timeout + +on settings.user7 > -1 + scr_timeout2 = settings.user7 * 60000 + scr2.timer = scr_timeout2 + +add rect scr + scr.group = "scr" + scr.visible = 0 + scr.timer = scr_timeout + +add text scr2 + scr2.group = "scr" + scr2.visible = 0 + scr2.timer = scr_timeout2 + +on sleep_timer == 1 + on pad.key != "" + pad.key = "" + sleep_timer = 0 + +on screensaver == 1 + on pad.key != "" + pad.key = "" + screensaver = 0 + scr2.timer = scr_timeout2 + +on screensaver == 0 + scrimg.visible = 0 + set_def_palette = 1 + screen.fullscreen = 0 + scr.visible = 0 + scr.timer = scr_timeout + +on sleep_timer == 0 + scr.timer = scr_timeout + scr2.timer = scr_timeout2 + cancel_popup = 1 + +on pad.key != "" + scr.timer = scr_timeout + scr2.timer = scr_timeout2 + +on drive.mediatype != "-" + scr.timer = scr_timeout + scr2.timer = scr_timeout2 + +on update_list_loop == 1 + on scr.timer == 0 + scr.timer = scr_small_timeout + on scr2.timer == 0 + scr2.timer = scr_small_timeout + +on (player.playing != 0 && player.speed != 0) || sleep_timer == 1 + on scr.timer == 0 + scr.timer = scr_timeout +on player.playing != 0 && player.speed != 0 + on scr2.timer == 0 + scr2.timer = scr_timeout2 + +on screensaver == 0 && scr_timeout > 0 && sleep_timer == 0 && flash.progress < 1 && (player.playing == 0 || player.speed == 0) + on scr.timer == 0 + screensaver = 1 +on screensaver == 0 && scr_timeout > 0 && sleep_timer == 0 && flash.progress < 1 && (player.playing == 0 || player.speed == 0 || do_play_audio == 1) + on pad.key == "program" + screensaver = 1 + +on sleep_timer == 0 && scr_timeout2 > 0 && flash.progress < 1 && (player.playing == 0 || player.speed == 0) + on scr2.timer == 0 + sleep_timer = 1 + +on screensaver == 1 + on sleep_timer == 1 + screensaver = 0 + + kernel.print = "Starting screensaver..." + + delete .group == "scr" && .type != "text" // trick to avoid deleting of sleep-timer + + add rect scr + scr.group = "scr" + scr.color = 0 + scr.x = 0 + scr.y = 0 + scr.width = 640 + scr.height = 480 + scr.color = 0 + scr.backcolor = 0 + scr.visible = 1 + screen.palette = "img/ssaver.act" + screen.palidx = 0 + screen.palalpha = 255 + + screen.update = "now" + screen.fullscreen = 1 + + add image scrimg + scrimg.group = "scr" + scrimg.src = "img/screensaver.gif" + scrimg.x = 320 - scrimg.width/2 + scrimg.y = 240 - scrimg.height/2 + scrimg.timer = scr_img_timeout + scrimg.visible = 1 + +on sleep_timer == 1 + kernel.print = "Sleep timer ELAPSED!" + continue_cnt = 6 + continue_msg = "Player will be turned off in " + popup_timer = 1000 + auto_close_popup = 0 + show_popup_text = "" + continue_msg + continue_cnt + " seconds" + add image cancel + cancel.group = "popup" + cancel.halign = "center" + cancel.valign = "center" + cancel.src = "img/player/cancel.gif" + cancel.x = popup.x + cancel.y = popup.y + 55 + + on continue_cnt <= 1 + on popuptext.timer == 0 + sleep_timer = 0 + kernel.power = 0 // TURN OFF! + + on continue_cnt > 1 + on popuptext.timer == 0 + continue_cnt = continue_cnt - 1 + popuptext.value = "" + continue_msg + continue_cnt + " seconds" + popuptext.timer = 1000 + + on cancel_popup == 1 + sleep_timer = 0 + +on screensaver == 1 + on scrimg.timer == 0 + scrimg.x = kernel.random % (640-scrimg.width) + scrimg.y = kernel.random % (480-scrimg.height) + scrimg.timer = scr_img_timeout diff --git a/mmsl/startup.mmsl b/mmsl/startup.mmsl new file mode 100644 index 0000000..25cb578 --- /dev/null +++ b/mmsl/startup.mmsl @@ -0,0 +1,284 @@ +// Sigmaplayer Firmware + +kernel.print = "F/W ver " + kernel.firmware_version +kernel.print = "MMSL ver " + kernel.mmsl_version +kernel.print = "TV: " + screen.tvstandard + +// define our colors: +colors.darkblue = 5 +colors.blueback = 6; // =15 +colors.lightblueback = 64; +colors.yellow = 245; +colors.yellowback = 242; +colors.grey = 153; +colors.lightgrey = 247; +colors.white = 255; + +set_def_palette = 1 + +on set_def_palette == 1 + screen.palette = "img/pal.act" + + // define transparent color: + screen.palidx = 0 + screen.palalpha = 0 + screen.palidx = 6 + screen.palalpha = 0x66 + screen.palidx = 15 + screen.palalpha = 0x80 + screen.palidx = 64 + screen.palalpha = 0xc0 + screen.palidx = 153 + screen.palalpha = 0x50 + screen.palidx = 242 + screen.palalpha = 0x80 + + screen.color = colors.white + screen.trcolor = 0 + +def_screen_back = "img/logontsc.jpg" +screen.back = def_screen_back +saved_tvout = settings.tvout +saved_display_pad = "" +allow_balloons = 1 + + + +//////////////////////////////////////////////////// +// Set fonts & charsets: +on set_lang == 1 + font1 = "fonts/West23.fnt" + font2 = "fonts/West36.fnt" + iso_charset = "iso8859-1" + subt_charset = "iso8859-1" +on settings.user3 == 0 // cp1251 + cyr_iso_charset = "cp1251" +on settings.user3 == 1 // koi8-r + cyr_iso_charset = "koi8-r" +on settings.user1 == 1 // 'ru' + on set_lang == 1 + font1 = "fonts/Cyr24.fnt" + font2 = "fonts/Cyr27.fnt" + iso_charset = cyr_iso_charset + subt_charset = cyr_iso_charset +on settings.user1 == 5 // 'pl' + on set_lang == 1 + font1 = "fonts/Central23.fnt" + font2 = "fonts/Central38.fnt" + iso_charset = "iso8859-2" + subt_charset = "iso8859-2" + +settings.user3 = settings.user3 +set_lang = 1 +msgfont = "fonts/Cyr24.fnt" +screen.font = font1 + +/// --- SigmaPlayer PATCH for Russian defaults: +check_default_lang = 1 +on settings.user16 == 0 + on check_default_lang == 1 + kernel.print = "Setting Russian defaults" + settings.user1 = 1 // 'ru' + settings.user16 = 1 + set_lang = 1 + screen.font = font1 +/// --- + +restore_timer_balloon = "" + +startup = 1 +redraw_iso = 0 +allow_zoom = 0 +allow_osd = 0 + +load_adjustments = 1 +adjustment = 0 +player_source_set = 0 + +// screen saver +include "ssaver.mmsl" + +//////////////////////////////////////////////////// +// tray open/close & media detect +on pad.key == "eject" + do_eject = 1 +on drive.tray == "open" + on startup == 1 + open_tray = 1 + + on do_eject == 1 + do_eject = 0 + pad.clear = "all" + pad.display = "CLOSE" + show_timer_balloon = "close" + drive.tray = "toggle" + +on drive.tray == "close" + on do_eject == 1 + do_eject = 0 + open_tray = 1 + drive.tray = "toggle" + +///////////////////////////// +// OPEN tray +on open_tray == 1 + last_tray = "open" + + cleanup_all = 1 + + pad.display = "OPEN" + show_static_balloon = "open" + +on last_tray == "open" + on drive.tray == "close" + last_tray = "close" + show_balloon = "" + pad.clear = "all" + pad.display = "CLOSE" + +on drive.tray != "open" + on drive.mediatype == "none" + dvd = 0 + iso = 0 + pad.clear = "all" + pad.display = "no dISC" + screen.preload = "" + +on cleanup_all == 1 + delete .group != "mute" && .group != "scr" + dvd = 0 + iso = 0 + setup = 0 + allow_zoom = 0 + cancel_zoom = 1 + cancel_osd = 1 + cancel_popup = 1 + adjustment = 0 + player_source_set = 0 + screen.update = 1 + pad.clear = "all" + screen.back = def_screen_back + screen.preload = "" // clear picture cache (memory saving) + + +////////////////////////////////////////////////////// +on pad.key == "setup" + do_setup = 1 +on drive.mediatype == "none" // && drive.tray != "open" + on setup == 0 + on do_setup == 1 + do_setup = 0 + setup = 1 + delete .group != "mute" && .group != "scr" + screen.back = def_screen_back + +//////////////////////////////////////////////////////////// +// volume and display adjustments, messages and balloons: + +include "adjust.mmsl" + + +/// +include "flash.mmsl" + +////////////////////////////////////////////////////// + +on drive.mediatype == "iso" || drive.mediatype == "audio" || drive.mediatype == "mixed" + dvd = 0 + cancel_setup = 1 + iso = 1 + +on redraw_iso == 1 + iso = 1 + +on iso == 1 + kernel.print = "Media: " + drive.mediatype + include "iso.mmsl" + +// clean-up if media changed - delete all objects +on drive.mediatype == "iso" || drive.mediatype == "audio" || drive.mediatype == "mixed" || redraw_iso == 1 + on iso == 0 + player.command = "stop" + playing = 0 + del_info = 1 + pad.clear = "all" + redraw_iso = 0 + cancel_search = 1 + cancel_osd = 1 + cancel_popup = 1 + adjustment = 0 + do_play_audio = 0 + do_play_video = 0 + do_show_photo = 0 + delete .group != "mute" && .group != "scr" + screen.preload = "" // clear picture cache (memory saving) + screensaver = 0 + sleep_timer = 0 + screen.update = 1 + +////////////////////////////////////////////////////// +// some DVD-related controls +on drive.mediatype == "dvd" + iso = 0 + cancel_setup = 1 + dvd = 1 + + on dvd == 0 + // always stop playing if media changed + player.command = "stop" + cancel_search = 1 + cancel_osd = 1 + cancel_popup = 1 + cancel_zoom = 1 + adjustment = 0 + delete .group != "mute" && .group != "scr" + screen.back = def_screen_back + screen.preload = "" // clear picture cache (memory saving) + allow_zoom = 0 + allow_osd = 0 + screen.update = 1 + + on pad.key == "play" + dvd = 1 + + on setup == 0 + on pad.key == "enter" + cleanup_all = 1 + drive.mediatype = "iso" + + on do_setup == 1 + do_setup = 0 + setup = 1 + +on dvd == 1 + kernel.print = "Media: DVD" + show_timer_balloon = "dvd" + include "dvd.mmsl" + +on setup == 1 + on do_setup == 1 + do_setup = 0 + cancel_setup = 1 + drive.mediatype = "" + include "setup.mmsl" + +//////////////////////////////////////////////////////////// +// include search dialog, common for DVD and file player: + +include "search.mmsl" + +//////////////////////////////////////////////////////////// +// include OSD info support, common for DVD and file player: + +include "osd.mmsl" + +//////////////////////////////////////////////////////////// +// include zoom/scroll support, common for DVD and file player: + +include "zoom.mmsl" + +//////////////////////////////////////////////////////////// +// include Text popup support: + +include "popup.mmsl" + diff --git a/mmsl/startup.mmso b/mmsl/startup.mmso new file mode 100644 index 0000000..4051e54 Binary files /dev/null and b/mmsl/startup.mmso differ diff --git a/mmsl/zoom.mmsl b/mmsl/zoom.mmsl new file mode 100644 index 0000000..bd2d602 --- /dev/null +++ b/mmsl/zoom.mmsl @@ -0,0 +1,73 @@ +//////////////////////////// +// display zoom/scroll: + +zoom_mode = 0 + +on do_cancel_zoom == 1 + screen.update = 0 + screen.hzoom = 100 + screen.vzoom = 100 + screen.hscroll = 0 + screen.hscroll = 0 + screen.update = 1 + +on cancel_zoom == 1 + do_cancel_zoom = 1 + zoom_mode = 0 + +on allow_zoom == 1 + on pad.key == "zoom" + do_zoom = 1 + + on do_zoom == 1 + do_cancel_zoom = 1 + + on zoom_mode == 0 + on do_zoom == 1 + do_zoom = 0 + zoom_mode = 1 + show_fast_balloon = "zoomon" + on zoom_mode != 0 + on pad.key == "enter" + do_scroll = 1 + + on do_zoom == 1 + do_zoom = 0 + zoom_mode = 0 + show_fast_balloon = "zoomoff" + + on zoom_mode == 1 + on do_scroll == 1 + do_scroll = 0 + zoom_mode = 2 + show_fast_balloon = "scrollon" + on zoom_mode == 2 + on do_scroll == 1 + do_scroll = 0 + zoom_mode = 1 + show_fast_balloon = "zoomon" + + on zoom_mode == 2 + on pad.key == "left" + screen.hscroll = screen.hscroll - 30 + on pad.key == "right" + screen.hscroll = screen.hscroll + 30 + on pad.key == "up" + screen.vscroll = screen.vscroll - 30 + on pad.key == "down" + screen.vscroll = screen.vscroll + 30 + on zoom_mode == 1 + on pad.key == "left" + screen.update = 0 + screen.hzoom = "in" + screen.vzoom = "in" + screen.update = 1 + on pad.key == "right" + screen.update = 0 + screen.hzoom = "out" + screen.vzoom = "out" + screen.update = 1 + on pad.key == "up" + screen.vzoom = "in" + on pad.key == "down" + screen.vzoom = "out" diff --git a/src/COPYING b/src/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/src/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..83a438f --- /dev/null +++ b/src/Makefile @@ -0,0 +1,138 @@ +######################################################################### +# +# SigmaPlayer source project - makefile +# \file Makefile +# \author bombur +# \version 0.3 +# \date 11.12.2008 4.05.2007 4.07.2004 +# +########################################################################## + + +########################################################################## + +MAIN_SRC := init.cpp + +PROJECT_SRC := \ + divx.c \ + module.cpp \ + module-dvd.cpp \ + module-init.cpp \ + audio.cpp \ + video.cpp \ + avi.cpp \ + mpg.cpp \ + bitstream.cpp \ + cdda.cpp \ + media.cpp \ + script.cpp \ + script-explorer.cpp \ + script-objects.cpp \ + script-player.cpp \ + player.cpp \ + subtitle.cpp \ + settings.cpp + +GUI_SRC := \ + gui/window.cpp \ + gui/console.cpp \ + gui/res.cpp \ + gui/jpeg.cpp \ + gui/giflib.cpp \ + gui/image.cpp \ + gui/rect.cpp \ + gui/text.cpp \ + gui/font.cpp + +MMSL_SRC := \ + mmsl/mmsl.cpp \ + mmsl/mmsl-file.cpp + +ifeq "$(PLAYER_MODEL)" "Technosonic" +SPCFLAGS += -DSP_PLAYER_TECHNOSONIC=1 +LIBSP_SPECIFIC := \ + libsp/MP/sp_module.cpp \ + libsp/MP/sp_fip.cpp \ + libsp/MP/sp_khwl.cpp \ + libsp/MP/sp_cdrom.cpp \ + libsp/MP/sp_eeprom.cpp \ + libsp/MP/sp_i2c.cpp +endif + +ifeq "$(PLAYER_MODEL)" "DreamX108" +SPCFLAGS += -DSP_PLAYER_DREAMX108=1 +LIBSP_SPECIFIC := \ + libsp/MP/sp_module.cpp \ + libsp/MP/sp_fip.cpp \ + libsp/MP/sp_khwl.cpp \ + libsp/MP/sp_cdrom.cpp \ + libsp/MP/sp_eeprom.cpp \ + libsp/MP/sp_i2c.cpp +endif + +ifeq "$(PLAYER_MODEL)" "Mecotek" +SPCFLAGS += -DSP_PLAYER_MECOTEK=1 +LIBSP_SPECIFIC := \ + libsp/MP/sp_module.cpp \ + libsp/MP/sp_fip.cpp \ + libsp/MP/sp_khwl.cpp \ + libsp/MP/sp_cdrom.cpp \ + libsp/MP/sp_eeprom.cpp \ + libsp/MP/sp_i2c.cpp +endif + +LIBSP_SRC := \ + libsp/sp_misc.cpp \ + libsp/sp_msg.cpp \ + libsp/sp_mpeg.cpp \ + libsp/sp_video.cpp \ + libsp/sp_khwl_colors.cpp \ + libsp/sp_flash.cpp \ + libsp/containers/string.cpp \ + libsp/containers/membin.cpp \ + $(LIBSP_SPECIFIC) + +PREBUILD := cd contrib/libjpeg && make && cd ../libmad && make && cd ../.. + +EXTERNAL_STATIC_LINKS_WITH := \ + contrib/libjpeg/libjpeg.a \ + contrib/libmad/.libs/libmad.a + +# contrib/memcpy.o \ +# contrib/memset.o \ +# contrib/setjmp.o \ +# contrib/longjmp.o \ +# contrib/strcmp.o \ +# contrib/strlen.o \ + + +SPINCLUDE = libsp/ +JPEGINCLUDE = contrib/libjpeg/ + +SPCFLAGS += -msoft-float -fno-exceptions -I$(SPINCLUDE) -I$(JPEGINCLUDE) +SPCXXFLAGS += -fpermissive -fno-rtti + +LOCAL_MAKEFILE := Makefile + +TARGET_TYPE := EXECUTABLE + +SRC := $(PROJECT_SRC) $(GUI_SRC) $(MMSL_SRC) $(LIBSP_SRC) + +USE_STD_LIB := 1 + +COMPILKIND = release + +PREPROCESSORFLAGS += -D__STDC_LIMIT_MACROS -DSP_ARM=1 -D_GNU_SOURCE + +MAKE_CLEAN = rm -fr *.gdb && cd contrib/libmad && make clean && cd ../.. +OTHER_CLEAN = contrib/memcpy.o contrib/memset.o contrib/setjmp.o contrib/strlen.o contrib/strcmp.o contrib/longjmp.o contrib/libjpeg/*.o contrib/libjpeg/*.a + +CROSS = arm-elf- +LDFLAGS = -elf2flt="-s262144 -r" -s --static +EXEFLAGS = -msoft-float -lutil -lstdc++ + + +include Makefile.inc + +#divx.o: divx.c +# arm-elf-gcc -I. -I$(SPINCLUDE) -c -O1 -o $@ $< diff --git a/src/Makefile.inc b/src/Makefile.inc new file mode 100644 index 0000000..891fa7e --- /dev/null +++ b/src/Makefile.inc @@ -0,0 +1,330 @@ +######################################################################### +# +# SigmaPlayer source project - makefile additional code +# \file Makefile.inc +# \author bombur +# \version 0.1 +# \date 4.07.2004 +# +########################################################################## + +ifndef DEPEND_FILE + DEPEND_FILE = Makefile.d +endif + +ifndef MAKEFILE_NAME + MAKEFILE_NAME = Makefile +endif + +ifndef LOCAL_MAKEFILE + LOCAL_MAKEFILE = $(MAKEFILE_NAME) +endif + +ifndef CCOMPILER + CCOMPILER := gcc +endif + +ifndef CXXCOMPILER + CXXCOMPILER := g++ +endif + +CC := $(CROSS)$(CCOMPILER) +CXX := $(CROSS)$(CXXCOMPILER) +LD := $(CROSS)$(LD) +OBJCOPY := $(CROSS)objcopy +AR := $(CROSS)ar + +ifndef LINKER + LINKER = $(CC) # must be = and not := +else + LINKER := $(CROSS)$(LINKER) +endif + +LOCALDIR = $(shell pwd) + +MAKEARGS = -f $(MAKEFILE_NAME) +PREPROCESSORFLAGS += $(SPCFLAGS) -I. -D_REENTRANT + +ASFLAGS = $(PREPROCESSORFLAGS) + +ifeq ($(findstring leakchecker, $(COMPILKIND)), leakchecker) +EXEFLAGS += `glib-config --libs glib` +PREPROCESSORFLAGS += -DUSE_LEAK_CHECKER=1 +endif + +ifeq ($(findstring withthreads, $(COMPILKIND)), withthreads) +PREPROCESSORFLAGS += -DWITH_THREADS=1 +LDFLAGS += -lpthread +endif + +ifeq ($(findstring withfeeblemm, $(COMPILKIND)), withfeeblemm) +PREPROCESSORFLAGS += -DWITH_FEEBLEMM=1 +endif + +ifeq ($(findstring withdl, $(COMPILKIND)), withdl) +EXEFLAGS += -ldl -rdynamic +endif + +ifeq ($(findstring kernel, $(COMPILKIND)), kernel) +PREPROCESSORFLAGS += -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB +ifeq ($(findstring uclinux, $(COMPILKIND)), uclinux) +ifndef MUM_KI +MUM_KI=-I$(UCLINUX_KERNEL)/include +endif +ifndef KERNELSTYLE +KERNELSTYLE= \ + -fomit-frame-pointer \ + -fno-strict-aliasing \ + -fno-common \ + -pipe \ + -fno-builtin +PREPROCESSORFLAGS += -D__linux__ +endif +else +ifndef MUM_KI +MUM_KI=-I/usr/src/linux-$(shell uname -r)/include -I/usr/src/linux-2.4/include +endif +ifndef KERNELSTYLE +KERNELSTYLE= \ + -fomit-frame-pointer \ + -fno-strict-aliasing \ + -fno-common \ + -mpreferred-stack-boundary=2 \ + -pipe +endif +endif + +ifndef DISABLE_WARNINGS +CWARNINGS+= \ + -Wno-import \ + -Wunused \ + -Wimplicit \ + -Wmain \ + -Wreturn-type \ + -Wswitch \ + -Wtrigraphs \ + -Wchar-subscripts \ + -Wparentheses \ + -Wpointer-arith \ + -Wcast-align \ +# -Wuninitialized \ + -Wno-uninitialized + -O3 +else +CWARNINGS+= -O3 +endif + +CFLAGS += $(KERNELSTYLE) $(MUM_KI) + +else + +ifeq ($(findstring release, $(COMPILKIND)), release) + + PREPROCESSORFLAGS += -U_DEBUG -DNDEBUG + CFLAGS += -O3 + CXXFLAGS += -O3 + +else + + PREPROCESSORFLAGS += -D_DEBUG=1 + +ifeq "$(CCOMPILER)" "gcc" +ifeq "$(CROSS)" "" + CFLAGS += -gdwarf-2 -g3 + CXXFLAGS += -gdwarf-2 -g3 +endif +else + CFLAGS += -g + CXXFLAGS += -g +endif +endif + + +ifndef DISABLE_WARNINGS +COMMONWARNINGS+= \ + -Wundef \ + -Wall \ + -Wchar-subscripts \ + -Wsign-compare \ + -Wno-uninitialized \ + -O3 +# -Wmissing-prototypes \ +# -Wuninitialized \ +# -Werror +CWARNINGS:=$(COMMONWARNINGS) -Wnested-externs -Wmissing-declarations +CXXWARNINGS:=$(COMMONWARNINGS) -fcheck-new +endif + +ifndef USE_STD_LIB + PREPROCESSORFLAGS += -nostdinc +endif + +endif + +CFLAGS += $(PREPROCESSORFLAGS) $(CWARNINGS) +CXXFLAGS += $(PREPROCESSORFLAGS) $(SPCXXFLAGS) $(CXXWARNINGS) + +TARGET_TYPE := $(strip $(TARGET_TYPE)) + +ifeq "$(TARGET_TYPE)" "LIBRARY" +ifeq ($(findstring static, $(COMPILKIND)), static) +TARGET_TYPE := OBJECT_LIBRARY +else +TARGET_TYPE := SHARED_LIBRARY +endif +endif + +ifeq ($(findstring static, $(COMPILKIND)), static) +STATIC_LINKS_WITH += $(LINKS_WITH) +LDFLAGS += -static +else +ifeq ($(findstring implicit, $(COMPILKIND)), implicit) +IMPLICIT_LINKS_WITH := $(LINKS_WITH) +else +DEPENDS_ON += $(LINKS_WITH) +endif +endif + +ifdef OBJECT_LIBRARY_USE_AR +OBJECT_LIBRARY = $(AR) rc $@ $^ +else +OBJECT_LIBRARY = $(LD) -r $^ -o $@ +endif +SHARED_LIBRARY = $(LINKER) -shared $^ $(LDFLAGS) -o $@ +EXECUTABLE = $(LINKER) $^ $(LDFLAGS) $(EXEFLAGS) -o $@ +DEPEND_COMMAND = $(CC) $(MUM_KI) $(PREPROCESSORFLAGS) -MM -E $(SRC) $(MAIN_SRC) +BINARY_FILE = $(OBJCOPY) -O binary $< $@ + +define MICROCODE + $(SPASM) $^ -o $@ + $(SPBIN) -h $@ +endef + +COPY_FILE_LIST = sed 's/^.*://' | sed 's/\\$$//' | tr ' ' '\n' | sed '/^$$/d' | \ + sed '/^\//d' | \ + sed 's/^\([^/]\)/$(subst /,\/,$(LOCALDIR))\/\1/' | \ + sed '{ : rm_dotdot s/[^/]*\/\.\.\/// ; t rm_dotdot }' | sort -u | \ + xargs cp -f --parents --target-directory=$(1) + +COPY_FILE_LIST2 = sed 's/^.*://' | sed 's/\\$$//' | tr ' ' '\n' | sed '/^$$/d' | \ + sed '/^\//d' | sort -u | \ + xargs -l1 cp -f --parents --target-directory=$(1) + +REDUCE_DIR_TREE = cd $(1) ; x=1 ; while [ $$x -eq 1 ] ; \ + do x=0 ; [ `ls -1 | wc -l` -eq 1 -a -d `ls -1 | head -n 1` ] && \ + y=`ls -1` && mv $$y/* . && rmdir $$y && x=1 ; \ + done ; exit 0 + +SRC := $(strip $(SRC)) +MAIN_SRC := $(strip $(MAIN_SRC)) +OBJ := $(addsuffix .o, $(basename $(SRC))) +MAIN_OBJ := $(addsuffix .o, $(basename $(MAIN_SRC))) +EXE := $(basename $(MAIN_SRC)) +SUBDIR := $(dir $(STATIC_LINKS_WITH) $(IMPLICIT_LINKS_WITH) $(DEPENDS_ON)) + +ifneq ($(findstring clean, $(MAKECMDGOALS)) ,clean) + ifneq "$(SRC) $(MAIN_SRC)" " " + DEPEND := $(shell cat $(DEPEND_FILE) 2>/dev/null) + DEPEND := $(subst \, ,$(DEPEND)) + DEPEND := $(subst :, , $(DEPEND)) + DEPEND := $(filter-out %.o, $(DEPEND)) + DEPEND := $(SRC) $(MAIN_SRC) $(DEPEND) + DEPEND := $(sort $(DEPEND)) + endif +endif + +ifeq "$(TARGET_TYPE)" "OBJFILE" +TARGET := $(OBJ) +endif + +ifeq "$(TARGET_TYPE)" "EXECUTABLE" +TARGET := $(EXE) +endif + +all: prebuild $(SUBDIR) $(TARGET) postbuild + +local: prebuild $(TARGET) postbuild + +ifeq "$(TARGET_TYPE)" "SHARED_LIBRARY" +copy_shared: $(TARGET) $(SUBDIR) + [ -d $(LIBDIR) ] && cp -f $(TARGET) $(LIBDIR) +else +copy_shared: $(SUBDIR) +endif + +ifeq "$(TARGET_TYPE)" "OBJECT_LIBRARY" +$(TARGET): $(OBJ) $(STATIC_LINKS_WITH) $(EXTERNAL_STATIC_LINKS_WITH) + $(OBJECT_LIBRARY) +endif + +ifeq "$(TARGET_TYPE)" "SHARED_LIBRARY" +$(TARGET): $(OBJ) $(STATIC_LINKS_WITH) $(EXTERNAL_STATIC_LINKS_WITH) $(IMPLICIT_LINKS_WITH) + $(SHARED_LIBRARY) +endif + +ifeq "$(TARGET_TYPE)" "EXECUTABLE" +$(TARGET): %: %.o $(OBJ) $(STATIC_LINKS_WITH) $(EXTERNAL_STATIC_LINKS_WITH) $(IMPLICIT_LINKS_WITH) + $(EXECUTABLE) +endif + +ifeq "$(TARGET_TYPE)" "MICROCODE" +$(TARGET): $(SRC) + $(MICROCODE) +endif + +ifeq "$(TARGET_TYPE)" "BINARY_FILE" +$(TARGET): $(EXE) + $(BINARY_FILE) + +$(EXE): %: %.o $(OBJ) $(STATIC_LINKS_WITH) $(EXTERNAL_STATIC_LINKS_WITH) $(IMPLICIT_LINKS_WITH) + $(EXECUTABLE) +endif + +$(STATIC_LINKS_WITH): $(@D) + +$(IMPLICIT_LINKS_WITH): $(@D) + +$(DEPENDS_ON): $(@D) + +$(SUBDIR): + @ echo ---- Subdir $(SRCDIR)$@ + $(MAKE) $(MAKEARGS) -C $@ $(MAKECMDGOALS) SRCDIR=$(SRCDIR)$@ + +$(SRC): + +$(MAIN_SRC): + +prebuild: +ifneq "$(PREBUILD)" "" + @echo "*** Start prebuild step ***" + $(PREBUILD) + @echo "*** Finish prebuild step ***" +endif + +postbuild: +ifneq "$(POSTBUILD)" "" + @echo "*** Start postbuild step ***" + $(POSTBUILD) + @echo "*** Finish postbuild step ***" +endif + +$(DEPEND_FILE): $(DEPEND) $(LOCAL_MAKEFILE) +ifneq "$(TARGET_TYPE)" "MICROCODE" +ifneq "$(SRC) $(MAIN_SRC)" " " + $(DEPEND_COMMAND) | sed 's/:/: $(LOCAL_MAKEFILE)/' > $@ +endif +endif + +ifneq ($(findstring clean, $(MAKECMDGOALS)) ,clean) +-include $(DEPEND_FILE) +endif + +totalclean: + $(MAKE_CLEAN) + $(RM) $(OBJ) $(MAIN_OBJ) $(TARGET) $(DEPEND_FILE) $(OTHER_CLEAN) *~ + +clean: + $(RM) $(OBJ) $(MAIN_OBJ) $(TARGET) $(DEPEND_FILE) *~ + +%.o: %.S + $(CC) -x assembler-with-cpp -c -D__ASSEMBLY__ -o $@ $< diff --git a/src/audio.cpp b/src/audio.cpp new file mode 100644 index 0000000..9ccd1ba --- /dev/null +++ b/src/audio.cpp @@ -0,0 +1,1759 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Audio player source file. + * \file audio.cpp + * \author bombur + * \version 0.1 + * \date 07.03.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "player.h" +#include "media.h" + + +#define AUDIO_USE_FAST_OUTPUT +//#define AUDIO_USE_FAST_OUTPUT_PTR + +#ifdef INTERNAL_AUDIO_PLAYER + +#include + +#define AUDIO_INTERNAL +#include "audio.h" + +static bool audio_msg = true; +#define MSG if (audio_msg) msg + +static Audio *audio = NULL; +static int num_packets = 0, info_cnt = 0, max_info_cnt = 32; + +const int min_avg_num = 10; +const int mp3_mintmpbuf = 16384; +const int mp3_numtmpbuf = mp3_mintmpbuf*8; + +typedef struct AudioDir +{ + SPString path; + DIR *dir; +} AudioDir; + +static SPClassicList *audio_dir_list = NULL; +static SPDLinkedList *audio_prev_list = NULL; + + +#ifdef WIN32 +#define audio_lseek _lseeki64 +#else +#define audio_lseek lseek +#endif + + +// return big-endian 16-bit +static inline WORD mp3_scale(mad_fixed_t sample) +{ + // round + sample += (1L << (MAD_F_FRACBITS - 16)); + + // clip + if (sample >= MAD_F_ONE) + sample = MAD_F_ONE - 1; + else if (sample < -MAD_F_ONE) + sample = -MAD_F_ONE; + + // quantize + return (WORD)(((sample >> (MAD_F_FRACBITS + 1 - 8)) & 0xff) | ((sample >> 5) & 0xff00)); +} + +static int normal_mp3_output(BYTE *data, struct mad_pcm *pcm) +{ + unsigned int nchannels, nsamples; + mad_fixed_t const *left_ch, *right_ch; + + // pcm->samplerate contains the sampling frequency + nchannels = pcm->channels; + nsamples = pcm->length; + left_ch = pcm->samples[0]; + right_ch = pcm->samples[1]; + + WORD *d = (WORD *)data; + if (nchannels == 2) + { + while (nsamples--) + { + *d++ = mp3_scale(*left_ch++); + *d++ = mp3_scale(*right_ch++); + } + } else + { + while (nsamples--) + { + // output sample(s) in 16-bit signed big-endian PCM + *d++ = mp3_scale(*left_ch++); + } + } + return (DWORD)d - (DWORD)data; +} + +#ifdef AUDIO_USE_FAST_OUTPUT + +static const DWORD and1_mask = 0x1FE00000, and2_mask = 0x1FE000; + +static int fast_mp3_output(BYTE *data, struct mad_pcm *pcm) +{ + unsigned int nchannels, nsamples; + mad_fixed_t const *left_ch, *right_ch; + + // pcm->samplerate contains the sampling frequency + nchannels = pcm->channels; + nsamples = pcm->length; + left_ch = pcm->samples[0]; + right_ch = pcm->samples[1]; + + register DWORD and1 = and1_mask, and2 = and2_mask; + if (nchannels == 2) + { + DWORD *bd = (DWORD *)data; + register DWORD d, d1, d2; + + while (nsamples--) + { + d1 = *left_ch++; + d2 = *right_ch++; + d = (d1 & and1) >> 21; + d |= (d2 & and1) >> 5; + d |= (d2 & and2) << 11; + d |= (d1 & and2) >> 5; + *bd++ = d; + } + return (DWORD)bd - (DWORD)data; + } else + { + WORD *bw = (WORD *)data; + DWORD d, d1; + while (nsamples--) + { + d1 = *left_ch++; + d = (d1 & and1) >> 21; + d |= (d1 & and2) >> 5; + *bw++ = (WORD)d; + } + return (DWORD)bw - (DWORD)data; + } +} + +#endif + +//////////////////////////////////////////////////// + +Audio::Audio() +{ + audio_numbufs = 226; + audio_bufsize = 4608; + audio_bufidx = 0; + + audio_samplerate = audio_channels = -1; + samples_per_frame = 1152; + + audio_frame_number = 0; + + bitrate = 0; + out_bps = 1; // avoid div.zero + + avg_bitrate = 0; avg_num = 0; + filesize = 0; + cur_offset = 0; + cur_tmpoffset = 0; + length = 0; + seek_offset = 0; + + needs_resample = false; + resample_packet_size = 4096; + + mp3_tmpbuf = NULL; + mp3_tmppos = 0; mp3_tmpstart = 0; mp3_tmpread = 0; + mp3_want_more = false; + + ac3_scan_header = -1; + ac3_framesize = 0; + ac3_gatherinfo = true; + ac3_gather_always = false; // disabled by video player + + is_partial_packet = false; + is_partial_next_packet = false; + + cur_bitrate = cur_audio_format = -1; + cur_samples = cur_bits = cur_channels = -1; + + playing = false; + stopping = false; + wait = false; + fast = false; + fd = -1; + + saved_pts = 0; + + mux_buf = NULL; + mux_numbufs = 8; + mux_bufsize = 32768; + + audio_fmt = RIFF_AUDIO_UNKNOWN; + fmtex = NULL; + + max_info_cnt = 32; + + mp3_output = NULL; +} + +Audio::~Audio() +{ + SPSafeFree(mp3_tmpbuf); + SPSafeFree(mux_buf); + SPSafeFree(fmtex); +} + +DWORD Audio::GetBE(BYTE *buf, int offset, int numbytes) +{ + DWORD res = 0; + int nb_1 = numbytes - 1; + + buf += offset; + + for (int n = 0; n < numbytes; n++) + { + res |= (*buf++) << (nb_1-- << 3); + } + + return res; +} + +int Audio::SetVbrLength(int total_num_frames, int vbr_filesize) +{ + length = (int)(INT64(1000) * total_num_frames * samples_per_frame / audio_samplerate); + if (vbr_filesize > 0 && (filesize == 0 || vbr_filesize < filesize)) + filesize = vbr_filesize; + if (length > 0) + { + bitrate = (int)(filesize * 8000 / length); + } + if (fd >= 0) + { + script_totaltime_callback(length / 1000); + } + return 0; +} + +int Audio::ParseXingHeader(BYTE *buf, int len) +{ + if (audio_samplerate <= 0) + return -1; + int flags = GetBE(buf, 4, 4); + int offs = 8; + int total_num_frames = 0; + int vbr_filesize = 0; + if (flags & AUDIO_XING_HAS_NUMFRAMES) + { + if (offs + 4 > len) + return -1; + total_num_frames = GetBE(buf, offs, 4); + offs += 4; + } + if (flags & AUDIO_XING_HAS_FILESIZE) + { + if (offs + 4 > len) + return -1; + vbr_filesize = GetBE(buf, offs, 4); + offs += 4; + } + SetVbrLength(total_num_frames, vbr_filesize); + if (flags & AUDIO_XING_HAS_TOC) + { + int table_num = MIN(100, len - offs); + if (table_num < 1) + return -1; + toc_length = length; + seek_toc.SetN(table_num); + for (int i = 0; i < 100; i++, offs++) + seek_toc[i] = (DWORD)(filesize * GetBE(buf, offs, 1) / 256); + } + return 0; +} + +int Audio::ParseVBRIHeader(BYTE *buf, int len) +{ + if (audio_samplerate <= 0) + return -1; + if (len < 26) + return -1; + int total_num_frames = GetBE(buf, 14, 4); + int vbr_filesize = GetBE(buf, 10, 4); + SetVbrLength(total_num_frames, vbr_filesize); + + int table_num = GetBE(buf, 18, 2) + 1; + int scale = GetBE(buf, 20, 2); + int numb = GetBE(buf, 22, 2); + int num_toc_frames = GetBE(buf, 24, 2); + + table_num = MIN(table_num, (len - 26) / numb); + if (table_num < 1) + return 0; + + toc_length = (int)(INT64(1000) * table_num * num_toc_frames * samples_per_frame / audio_samplerate); + seek_toc.SetN(table_num); + DWORD last_pos = 0; + for (int i = 0; i < table_num; i++) + seek_toc[i] = last_pos = last_pos + GetBE(buf, 26 + i * numb, numb) * scale; + return 0; +} + +int Audio::ParseAC3Header(BYTE *buf, int len, bool fill_info) +{ + int sample_rate, channels, lfe; + + // fast&dirty way to get frame size + if (!fill_info) + return mpeg_parse_ac3_header(buf, len, NULL, NULL, NULL, NULL, &ac3_framesize); + + if (mpeg_parse_ac3_header(buf, len, &bitrate, &sample_rate, &channels, &lfe, &ac3_framesize) < 0) + return -1; + + if (bitrate > 0) + { + out_bps = bitrate / 8; + + if (filesize > 0 && length == 0) + { + int new_length = (int)(filesize * 8000 / bitrate); + if (new_length != length) + { + length = new_length; + script_totaltime_callback(length / 1000); + } + } + } + + if (fmtex == NULL) + { + fmtex = (RIFF_WAVEFORMATEX *)SPmalloc(sizeof(RIFF_WAVEFORMATEX)); + memset(fmtex, 0, sizeof(RIFF_WAVEFORMATEX)); + } + if (fmtex != NULL) + { + WORD nch = (WORD)((channels << 8) | lfe); + if (fmtex->n_samples_per_sec != (DWORD)sample_rate || fmtex->n_channels != nch) + { + fmtex->n_samples_per_sec = sample_rate; + fmtex->n_channels = nch; + audio_update_format_string(); + } + } + + if (!audio->ac3_gather_always) + audio->ac3_gatherinfo = false; + + return 0; +} + +int Audio::ParseMp3Packet(MpegPacket *packet, BYTE * &buf, int len) +{ + mp3_stream.error = MAD_ERROR_NONE; + + if (!wait && mp3_want_more) + { + int bl = len; + if (mp3_tmpread > 0) + { + mp3_tmpstart += mp3_tmpread; + if (mp3_tmpstart + mp3_mintmpbuf > mp3_numtmpbuf || + mp3_tmppos + bl > mp3_numtmpbuf) + { + mp3_tmppos -= mp3_tmpstart; + memcpy(mp3_tmpbuf, mp3_tmpbuf + mp3_tmpstart, mp3_tmppos); + cur_tmpoffset += mp3_tmpstart; + mp3_tmpstart = 0; + } + } + if ((bl > 0 && bl < mp3_numtmpbuf) || mp3_tmpread > 0) + { + if (mp3_tmppos + bl > mp3_numtmpbuf) + bl = mp3_numtmpbuf - mp3_tmppos; + if (bl <= 0) + bl = 0; + else + { + // TODO: optimize - remove this memcpy! + memcpy(mp3_tmpbuf + mp3_tmppos, buf, bl); + } + mp3_tmppos += bl; + mad_stream_buffer(&mp3_stream, mp3_tmpbuf + mp3_tmpstart, mp3_tmppos - mp3_tmpstart); + + mp3_want_more = false; + } + mp3_tmpread = 0; + } + do + { + mp3_stream.error = MAD_ERROR_NONE; + if (wait || mad_frame_decode(&mp3_frame, &mp3_stream) == 0) + { + if (!wait) + { + mp3_tmpstart = mp3_stream.this_frame - mp3_tmpbuf; + mp3_tmpread = mp3_stream.next_frame - mp3_stream.this_frame; + mp3_want_more = false; + } + + if (mpeg_find_free_blocks(MPEG_BUFFER_2) == 0) + { + // we'll wait... + wait = true; + return 0; + } + + wait = false; + + BYTE *data = mpeg_getcurbuf(MPEG_BUFFER_2); + mad_synth_frame(&mp3_synth, &mp3_frame); + + cur_offset = cur_tmpoffset + mp3_tmpstart; + + if (audio->avg_num == 0) + { + seek_offset = cur_offset; + if (filesize > 0) + filesize -= seek_offset; + int hdrlen = mp3_stream.bufend - mp3_stream.ptr.byte; + if (hdrlen > 4) + { + if (mp3_frame.header.layer == 0) + audio->samples_per_frame = 384; + else if (mp3_frame.header.layer == 2 && mp3_frame.header.flags & MAD_FLAG_LSF_EXT) + audio->samples_per_frame = 576; + else + audio->samples_per_frame = 1152; + audio_samplerate = mp3_synth.pcm.samplerate; + + if (strncasecmp((char *)mp3_stream.ptr.byte, "Xing", 4) == 0 || + strncasecmp((char *)mp3_stream.ptr.byte, "Info", 4) == 0) + { + audio->ParseXingHeader((BYTE *)mp3_stream.ptr.byte, hdrlen); + } + else if (strncasecmp((char *)mp3_stream.ptr.byte, "VBRI", 4) == 0) + { + audio->ParseVBRIHeader((BYTE *)mp3_stream.ptr.byte, hdrlen); + } + } + audio_update_format_string(); + } + + audio->avg_bitrate = audio->avg_bitrate * audio->avg_num + mp3_frame.header.bitrate; + audio->avg_bitrate /= ++audio->avg_num; + + if (length == 0 && audio->avg_bitrate > 0 && audio->avg_num >= min_avg_num) + { + if (filesize > 0) + { + length = (int)(filesize * 8000 / audio->avg_bitrate); + script_totaltime_callback(length / 1000); + } + + if ((audio->avg_num - min_avg_num) % 1000 == 0) + audio_update_format_string(); + } + + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + + packet->pts = 0; + packet->nframeheaders = 0xffff; + packet->firstaccessunitpointer = 0; + packet->type = 1; + + packet->pData = data; + +#ifdef AUDIO_USE_FAST_OUTPUT_PTR + packet->size = mp3_output(data, &mp3_synth.pcm); +#else +#ifdef AUDIO_USE_FAST_OUTPUT + if (fast) + packet->size = fast_mp3_output(data, &mp3_synth.pcm); + else +#endif + packet->size = normal_mp3_output(data, &mp3_synth.pcm); +#endif + +#if 0 +{ +FILE *fp; +//fp = fopen("out.raw", "ab"); +//fwrite(packet->pData, packet->size, 1, fp); +fp = fopen("out.mp3", "ab"); +fwrite(mp3_stream.this_frame, mp3_tmpread, 1, fp); +fclose(fp); +} +#endif + + if (packet->size > 0) + { + if ((int)mp3_synth.pcm.samplerate != audio_samplerate || + mp3_synth.pcm.channels != audio_channels) + { + MpegAudioPacketInfo defaudioparams; + defaudioparams.type = eAudioFormat_PCM; + defaudioparams.samplerate = mp3_synth.pcm.samplerate; + defaudioparams.numberofbitspersample = 16; + defaudioparams.numberofchannels = mp3_synth.pcm.channels; + defaudioparams.fromstream = TRUE; + mpeg_setaudioparams(&defaudioparams); + + out_bps = defaudioparams.samplerate * defaudioparams.numberofbitspersample + * defaudioparams.numberofchannels / 8; + + audio_samplerate = mp3_synth.pcm.samplerate; + audio_channels = mp3_synth.pcm.channels; + } + + mpeg_setbufidx(MPEG_BUFFER_2, packet); + if (len == 0) + return 1; + return len; + } + } + else if (mp3_stream.error == MAD_ERROR_BUFLEN) + mp3_want_more = true; + } while (MAD_RECOVERABLE(mp3_stream.error)); + + return 0; +} + +int Audio::ParsePCMPacket(MpegPacket *packet, BYTE * &buf, int len) +{ + if (len <= 0) + return 0; + BYTE *out = buf; + int outlen = len, inlen = len; + + if (needs_resample) + { + if (mpeg_find_free_blocks(MPEG_BUFFER_2) == 0) + { + wait = true; + return 0; + } + + wait = false; + out = mpeg_getcurbuf(MPEG_BUFFER_2); + outlen = resample_packet_size; + int numread = mpeg_PCM_resample_to_LPCM(buf, inlen, out, &outlen); + if (numread <= 0) + return 0; + else + { + len = numread; + buf += numread; + } + } else + { + wait = false; + inlen = 0; + mpeg_PCM_to_LPCM(out, outlen); + } + + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + packet->type = 1; + packet->pData = out; + packet->size = outlen; + packet->nframeheaders = 0xffff; + packet->firstaccessunitpointer = 0; + + // increase bufidx + mpeg_setbufidx(needs_resample ? MPEG_BUFFER_2 : MPEG_BUFFER_1, packet); + + return len; +} + +int Audio::ParseAC3Packet(MpegPacket *packet, BYTE * &buf, int len) +{ + if (len <= 0) + { + return 0; + } + + if (ac3_scan_header > 0 && len > 7 - ac3_scan_header) + { + memcpy(ac3_header + ac3_scan_header, buf, 7 - ac3_scan_header); + if (ParseAC3Header(ac3_header, 7, ac3_gatherinfo) < 0) + { + // frankly to say, the rest of saved header may contain the next sync.word, + // but we skip it to keep the code simple. + ac3_scan_header = -1; + } else + { + ac3_framesize -= ac3_scan_header; + ac3_scan_header = 0; + } + } + if (ac3_scan_header != 0) + { + BYTE *b = buf; + int l = len; + for (; l > 0; l--, b++) + { + if (*b == 0x0b) + { + if (l < 7) + { + ac3_scan_header = l; + memcpy(ac3_header, b, ac3_scan_header); + break; + } + if (ParseAC3Header(b, l, ac3_gatherinfo) == 0) + { + ac3_scan_header = 0; + ac3_framesize = (b - buf); + break; + } + } + } + } + + is_partial_packet = is_partial_next_packet; + + is_partial_next_packet = false; + if (ac3_scan_header == 0) + { + if (ac3_framesize >= 0) + { + int left = len; + BYTE *b = buf; + + if (ac3_framesize < left) + { + // limit packet to current framesize, if it is set + len = ac3_framesize; + + left -= ac3_framesize; + b += ac3_framesize; + ac3_framesize = 0; + // find *next* ac3 header + if (ParseAC3Header(b, left, ac3_gatherinfo) < 0) + { + if (left < 7) + { + // the header was just too short + ac3_scan_header = left; + memcpy(ac3_header, b, ac3_scan_header); + // send incomplete next header to the driver + len += left; + } else + { + // did not found, we'll try raw byte search... + msg("AC3: Warning! Frame sync lost!\n"); + ac3_scan_header = -1; + return 0; + } + } + if (len == 0) + { + len = Min(ac3_framesize, left); + if (ac3_framesize >= left) + ac3_framesize -= left; + } + audio_frame_number++; + } + else + { + ac3_framesize -= left; + is_partial_next_packet = true; + } + } + } + + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + packet->type = 1; + packet->pData = buf; + packet->size = len; + +#if 0 +{ +FILE *fp; +fp = fopen("out.ac3", "ab"); +fwrite(packet->pData, packet->size, 1, fp); +fclose(fp); +} +#endif +#if 0 +{ BYTE *pd = packet->pData; +static int num_audio_p = 0; +msg("- [%d, %d] ---------------------------------------------", num_audio_p++, packet->size); + for (int kk = 0; kk < packet->size; kk++) + { + if ((kk % 16) == 0) msg("\n"); + msg("%02x ", *pd++); + + } +msg("\n---\n"); +fflush(stdout); +} +#endif + + packet->nframeheaders = 0xffff; + packet->firstaccessunitpointer = 0; + +#if 0 + if (packet->pts != 0) + msg("[%d,%d]\t\tsize=%d\t\tpts=%d\n", num_packets, packet->type, packet->size, (int)packet->pts); +#endif + + // increase bufidx + mpeg_setbufidx(MPEG_BUFFER_1, packet); + + return len; +} + +int Audio::ParseRawPacket(MpegPacket *packet, BYTE * &buf, int len) +{ + if (len == 0) + return 0; + + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + packet->type = 1; + packet->pData = buf; + packet->size = len; + + packet->nframeheaders = 0xffff; + packet->firstaccessunitpointer = 0; + + // increase bufidx + mpeg_setbufidx(MPEG_BUFFER_1, packet); + return len; +} + +int Audio::Seek(LONGLONG pos, int msecs) +{ + if (pos < 0) + return -1; + khwl_stop(); + + audio_lseek(fd, pos + seek_offset, SEEK_SET); + cur_tmpoffset = pos; + + audio_reset(); + media_skip_buffer(NULL); + + mpeg_setpts(INT64(90) * msecs); + return audio_continue_play(); +} + + +/////////////////////////////////////////////////// + +RIFF_AUDIO_FORMAT audio_get_audio_format(int fmt) +{ + switch (fmt) + { + case 0x50: + return RIFF_AUDIO_MP2; + case 0x55: + return RIFF_AUDIO_MP3; + case 0x0001: + return RIFF_AUDIO_PCM; + case 0x2000: + return RIFF_AUDIO_AC3; + case 0x2001: + return RIFF_AUDIO_DTS; + case 0x674f: + case 0x676f: + case 0x6750: + case 0x6770: + case 0x6751: + case 0x6771: + return RIFF_AUDIO_VORBIS; + } + return RIFF_AUDIO_UNKNOWN; +} + +SPString audio_get_audio_format_string(RIFF_AUDIO_FORMAT fmt) +{ + if (fmt < 7) + { + const char *afmt[] = { "Unknown", "None", "LPCM", "PCM", "MPEGL1", "MPEGL2", "MP3", "AC3", "DTS", "Vorbis" }; + return afmt[fmt + 1]; + } + return SPString(); +} + +int audio_init(RIFF_AUDIO_FORMAT fmt, bool fast) +{ + if (audio != NULL) + audio_deinit(); + + audio = new Audio(); + audio->audio_fmt = fmt; + + bool need_2nd_buf = false; + + if (audio->audio_fmt == RIFF_AUDIO_MP3 || audio->audio_fmt == RIFF_AUDIO_MP2) + { + mad_stream_init(&audio->mp3_stream); + mad_frame_init(&audio->mp3_frame); + mad_synth_init(&audio->mp3_synth); + + audio->fast = fast; + if (fast) + { + audio->mp3_stream.options |= MAD_OPTION_HALFSAMPLERATE; + audio->mp3_output = &fast_mp3_output; + } else + { + audio->mp3_output = &normal_mp3_output; + } + + // allocate MP3 frame buffer + audio->mp3_tmpbuf = (BYTE *)SPmalloc(mp3_numtmpbuf); + if (audio->mp3_tmpbuf == NULL) + { + msg_error("Audio: Cannot allocate stream buffer.\n"); + return 0; + } + + fip_write_special(FIP_SPECIAL_MP3, 1); + + audio->audio_numbufs = 226; + audio->audio_bufsize = 4608; + need_2nd_buf = true; + } + else if (audio->audio_fmt == RIFF_AUDIO_PCM) + { + audio->needs_resample = mpeg_is_resample_needed() == TRUE; + + if (audio->needs_resample) + { + audio->audio_numbufs = 250; + audio->audio_bufsize = audio->resample_packet_size; + need_2nd_buf = true; + } + } + else if (audio->audio_fmt == RIFF_AUDIO_AC3) + { + fip_write_special(FIP_SPECIAL_DOLBY, 1); + } + else if (audio->audio_fmt == RIFF_AUDIO_DTS) + { + fip_write_special(FIP_SPECIAL_DTS, 1); + } + if (need_2nd_buf) + mpeg_setbuffer(MPEG_BUFFER_2, BUF_BASE, audio->audio_numbufs, audio->audio_bufsize); + + audio->audio_bufidx = 0; + + audio_reset(); + + audio_update_format_string(); + + return 1; +} + +int audio_reset() +{ + if (audio != NULL) + { + audio->mp3_want_more = true; + audio->wait = false; + audio->mp3_tmppos = 0; + audio->mp3_tmpstart = 0; + audio->mp3_tmpread = 0; + } + return 0; +} + +int audio_deinit() +{ + if (audio != NULL) + { + if (audio->audio_fmt == RIFF_AUDIO_MP3 || audio->audio_fmt == RIFF_AUDIO_MP2) + { + mad_synth_finish(&audio->mp3_synth); + mad_frame_finish(&audio->mp3_frame); + mad_stream_finish(&audio->mp3_stream); + } + } + SPSafeDelete(audio); + return 1; +} + +int audio_parse_packet(MpegPacket *packet, BYTE * &buf, int len) +{ + if (audio != NULL) + { + switch (audio->audio_fmt) + { + case RIFF_AUDIO_MP3: + case RIFF_AUDIO_MP2: + return audio->ParseMp3Packet(packet, buf, len); + case RIFF_AUDIO_PCM: + return audio->ParsePCMPacket(packet, buf, len); + case RIFF_AUDIO_AC3: + return audio->ParseAC3Packet(packet, buf, len); + default: + return audio->ParseRawPacket(packet, buf, len); + } + } + return 0; +} + +//////////////////////////////////////////////////////// + +int audio_play(char *filepath, bool is_folder, bool continue_next) +{ + if (is_folder) + { + if (filepath != NULL) + audio_delete_filelist(); + filepath = audio_get_next(filepath, continue_next); + if (filepath == NULL) + return -1; + } + + if (filepath == NULL) + { + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + mpeg_setspeed(MPEG_SPEED_NORMAL); + return 0; + } + + if (strncasecmp(filepath, "/cdrom/", 7) != 0 && strncasecmp(filepath, "/hdd/", 5) != 0) + return -1; + + MPEG_NUM_PACKETS = 512; + mpeg_init(MPEG_1, TRUE, TRUE, FALSE); + + int ret = media_open(filepath, MEDIA_TYPE_AUDIO); + if (ret < 0) + { + msg_error("Audio: media open FAILED.\n"); + return ret; + } + MSG("Audio: start...\n"); + + num_packets = 0; + info_cnt = 0; + + audio->mux_buf = (BYTE *)SPmalloc(audio->mux_numbufs * audio->mux_bufsize); + if (audio->mux_buf == NULL) + { + msg_error("Audio: Cannot allocate input buffer.\n"); + return -1; + } + mpeg_setbuffer(MPEG_BUFFER_1, audio->mux_buf, audio->mux_numbufs, audio->mux_bufsize); + + // write dvd-specific FIP stuff... + const char *digits = " 00000"; + fip_write_string(digits); + fip_write_special(FIP_SPECIAL_COLON1, 1); + fip_write_special(FIP_SPECIAL_COLON2, 1); + + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + + script_video_info_callback(""); + + audio->playing = true; + audio->stopping = false; + mpeg_start(); + + if (is_folder) + { + player_update_source(filepath); + } + + return 0; +} + +int audio_continue_play() +{ + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + mpeg_play(); + return 0; +} + +void audio_update_info() +{ + if (audio == NULL) + return; + static int old_secs = 0; + KHWL_TIME_TYPE displ; + displ.pts = 0; + displ.timeres = 90000; + khwl_getproperty(KHWL_TIME_SET, etimSystemTimeClock, sizeof(displ), &displ); + + if ((LONGLONG)displ.pts != audio->saved_pts) + { + if ((LONGLONG)displ.pts >= 0) + { + audio->saved_pts = displ.pts; + + char fip_out[10]; + int secs = (int)(displ.pts / 90000); + if (secs < 0) + secs = 0; + if (secs >= 10*3600) + secs = 10*3600-1; + if (secs != old_secs) + { + script_time_callback(secs); + + fip_out[0] = ' '; + fip_out[1] = ' '; + fip_out[2] = (char)((secs/3600) + '0'); + int secs3600 = secs%3600; + fip_out[3] = (char)(((secs3600/60)/10) + '0'); + fip_out[4] = (char)(((secs3600/60)%10) + '0'); + fip_out[5] = (char)(((secs3600%60)/10) + '0'); + fip_out[6] = (char)(((secs3600%60)%10) + '0'); + fip_out[7] = '\0'; + fip_write_string(fip_out); + + old_secs = secs; + } + } + } +} + +/// Advance playing +int audio_loop() +{ + if (audio == NULL) + return 1; + + if (audio->stopping) + { + if (mpeg_wait(TRUE) == 1) + { + return audio_stop() ? 1 : 0; + } + } + + static BYTE *buf = NULL; + static MEDIA_EVENT event = MEDIA_EVENT_OK; + static int len = 0; + + if (!audio->stopping) + { + if (audio_ready()) + { + buf = NULL; + event = MEDIA_EVENT_OK; + len = 0; + int ret = media_get_next_block(&buf, &event, &len); + if (ret > 0 && buf == NULL) + { + msg_error("Audio: Not initialized. STOP!\n"); + return 1; + } + if (ret == -1) + { + msg_error("Audio: Error getting next block!\n"); + return 1; + } + else if (ret == 0) // wait... + { + return 0; + } + + if (event == MEDIA_EVENT_STOP) + { + MSG("Audio: STOP Event triggered!\n"); + mpeg_play_normal(); + audio->stopping = true; + return 0; + } + } + + // send multiple frames (packets) in one chunk + for (;;) + { + MpegPacket *packet = mpeg_feed_getlast(); + if (packet == NULL) // well, it won't really help + return 0; + + int numread = audio_parse_packet(packet, buf, len); + if (numread == 0) + break; + len -= numread; + buf += numread; + // increase bufidx + mpeg_feed(MPEG_FEED_AUDIO); + num_packets++; + } + } + + if (info_cnt++ > max_info_cnt) + { + info_cnt = 0; + audio_update_info(); + } + + return 0; +} + +BOOL audio_ready() +{ + return audio == NULL || !audio->wait; +} + +/// Pause playing +BOOL audio_pause() +{ + fip_write_special(FIP_SPECIAL_PLAY, 0); + fip_write_special(FIP_SPECIAL_PAUSE, 1); + + mpeg_setspeed(MPEG_SPEED_PAUSE); + + return TRUE; +} + +/// Stop playing +BOOL audio_stop(BOOL continue_next) +{ + if (audio != NULL) + { + if (audio->playing) + { + mpeg_deinit(); + audio->playing = false; + } + audio->stopping = false; + media_close(); + audio_deinit(); + + // check for file list + if (audio_dir_list != NULL) + { + if (audio_play(NULL, true, continue_next == TRUE) >= 0) + return FALSE; + } + } + return TRUE; +} + +int audio_get_bitrate() +{ + if (audio == NULL) + return 0; + // use known/VBR rate + if (audio->bitrate > 0) + return audio->bitrate; + // use average/CBR rate + if (audio->avg_bitrate > 0 && audio->avg_num >= min_avg_num) + return audio->avg_bitrate; + return 0; +} + +int audio_get_output_bps() +{ + if (audio == NULL) + return 0; + if (!audio->is_partial_packet) + return audio->out_bps; + return 0; +} + +/// Seek to given time and play +BOOL audio_seek(int seconds, int from) +{ + if (audio == NULL) + return FALSE; + + // use TOC to search + int msecs = seconds * 1000; + + if (from == SEEK_CUR) + { + // get current pts + int cur_msecs = (int)(mpeg_getpts() / 90); +#if 0 + // get stream pts + int br = audio_get_bitrate(); + if (br > 0) + cur_msecs = (int)(audio->cur_offset * 8000 / br); + else + { + script_error_callback(SCRIPT_ERROR_INVALID); + return FALSE; + } +#endif + msecs += cur_msecs; + } + + if (msecs < 0) + msecs = 0; + + LONGLONG pos = -1; + // use TOC + if (from == SEEK_SET && audio->seek_toc.GetN() > 0 && audio->toc_length > 0 && msecs < audio->toc_length) + { + int numtoc = audio->seek_toc.GetN(); + int idx = numtoc * msecs / audio->toc_length; + LONGLONG p1 = audio->seek_toc[idx]; + LONGLONG p2 = idx < numtoc - 1 ? audio->seek_toc[idx + 1] : audio->filesize; + int delta_toc = audio->toc_length / numtoc; + pos = p1 + (p2 - p1) * (msecs - idx * delta_toc) / delta_toc; + if (audio->bitrate > 0) + msecs = (int)(pos * 8000 / audio->bitrate); + } + // use known/VBR rate + else + { + int br = audio_get_bitrate(); + if (br > 0) + { + pos = (LONGLONG)msecs * br / 8000; + msecs = (int)(pos * 8000 / br); + } else + pos = -1; + } + + if (pos < 0) + { + script_error_callback(SCRIPT_ERROR_INVALID); + return FALSE; + } + return audio->Seek(pos, msecs) == 0; +} + +int audio_forward() +{ + audio_seek(10, SEEK_CUR); + return 0; +} +int audio_rewind() +{ + audio_seek(-10, SEEK_CUR); + return 0; +} + +void audio_setdebug(BOOL ison) +{ + audio_msg = ison == TRUE; +} +BOOL audio_getdebug() +{ + return audio_msg; +} + +// internal funcs used by media +BOOL audio_open(const char *filepath) +{ + if (audio != NULL && audio->fd != -1) + audio_close(); + + script_time_callback(0); + script_audio_info_callback(""); + script_video_info_callback(""); + + if (filepath == NULL) + return FALSE; + int fd = cdrom_open(filepath, O_RDONLY); + if (fd < 0) + { + msg_error("Audio: Cannot open file %s.\n", filepath); + return FALSE; + } + + struct stat64 statbuf; + LONGLONG filesize = 0, cur_offs = 0; + if (cdrom_stat(filepath, &statbuf) >= 0) + filesize = statbuf.st_size; + + // Read first 12 bytes and check that this is an AVI file + RIFF_AUDIO_FORMAT afmt = RIFF_AUDIO_UNKNOWN; + BYTE data[20]; + if (read(fd, data, 16) != 16) + { + msg_error("Audio: Cannot read header.\n"); + return FALSE; + } + RIFF_WAVEFORMATEX *fmtex = NULL; + if (strncasecmp((char *)data, "RIFF", 4) == 0 && strncasecmp((char *)data+8, "WAVE", 4) == 0) + { + MSG("Audio: * WAVE format detected!\n"); + // read WAVE header + if (strncasecmp((char *)data+12, "fmt ", 4) == 0) + { + fmtex = audio_read_formatex(fd, NULL, 0); + if (fmtex != NULL) + afmt = audio_get_audio_format(fmtex->w_format_tag); + } + for (;;) + { + read(fd, data, 8); + if (strncasecmp((char *)data, "data", 4) == 0) + break; + else if (strncasecmp((char *)data, "fact", 4) == 0) + { + int size = GET_DWORD(data + 4); + audio_lseek(fd, size, SEEK_CUR); + } + else + { + audio_lseek(fd, -8, SEEK_CUR); + break; + } + } + cur_offs = audio_lseek(fd, 0, SEEK_CUR); + if (filesize > 0) + filesize -= cur_offs; + } else + { + cur_offs = 0; + SPString fp = filepath; + if (fp.FindNoCase(".mp3") >= 0) + { + MSG("Audio: * MP3 format detected!\n"); + afmt = RIFF_AUDIO_MP3; + + // skip ID3v2 + if (strncasecmp((char *)data, "ID3", 3) == 0 && data[3] < 0xff && data[4] < 0xff) + { + int id3_size = GET_SYNCSAFE_DWORD(data + 6); + if (data[5] & 0x10) // footer present + id3_size += 10; + cur_offs = id3_size + 10; + } + } + else if (fp.FindNoCase(".mp2") >= 0) + { + MSG("Audio: * MPEGL2 format detected!\n"); + afmt = RIFF_AUDIO_MP2; + } + else if (fp.FindNoCase(".mp1") >= 0 || fp.FindNoCase(".mpa") >= 0) + { + MSG("Audio: * MPEGL1 format detected!\n"); + afmt = RIFF_AUDIO_MP1; + } + else if (fp.FindNoCase(".ac3") >= 0) + { + MSG("Audio: * AC-3 format detected!\n"); + afmt = RIFF_AUDIO_AC3; + } + else if (fp.FindNoCase(".ogg") >= 0) + { + MSG("Audio: * OGG Vorbis format detected!\n"); + afmt = RIFF_AUDIO_VORBIS; + } + + audio_lseek(fd, cur_offs, SEEK_SET); + } + + if (afmt == RIFF_AUDIO_UNKNOWN) + { + msg_error("Audio: Unknown audio format!\n"); + return FALSE; + } + + MSG("Audio: Setting audio params.\n"); + audio_setaudioparams(afmt, fmtex, 1); + + if (audio_init(afmt, false) == 0) + return -1; + + audio->fd = fd; + audio->fmtex = fmtex; + audio->filesize = filesize; + audio->cur_offset = 0; + + if (afmt == RIFF_AUDIO_LPCM || afmt == RIFF_AUDIO_PCM) + { + if (audio->fmtex != NULL) + { + audio->bitrate = (audio->fmtex->n_samples_per_sec + * audio->fmtex->w_bits_per_sample + * audio->fmtex->n_channels); + audio_update_format_string(); + if (audio->bitrate > 0) + { + audio->length = (int)(filesize * 8000 / audio->bitrate); + script_totaltime_callback(audio->length / 1000); + } + } + } + + return TRUE; +} + +BOOL audio_close() +{ + if (audio != NULL && audio->fd >= 0) + { + close(audio->fd); + audio->fd = -1; + return TRUE; + } + return FALSE; +} + +int audio_read(BYTE *buf, int *len) +{ + if (audio == NULL || buf == NULL || len == NULL || *len < 1) + return 0; + int n = 0, newlen = 0; + + while (newlen < *len) + { + n = read (audio->fd, buf + newlen, *len - newlen); + if (n == 0) + break; + if (n < 0) + { + if (errno == EINTR) + continue; + else + break; + } + newlen += n; + } + + if (newlen < 1) return 0; + *len = newlen; + return 1; +} + +RIFF_WAVEFORMATEX *audio_read_formatex(int fd, BYTE *buf, int len) +{ + RIFF_WAVEFORMATEX *wfe; + if (len <= 0) + { + if (read(fd, &len, 4) != 4) + return NULL; + } + if (len < 0 || len >= (long)sizeof(RIFF_WAVEFORMATEX)) + len = sizeof(RIFF_WAVEFORMATEX); + wfe = (RIFF_WAVEFORMATEX *)SPmalloc(sizeof(RIFF_WAVEFORMATEX)); + if (wfe != NULL) + { + memset(wfe, 0, sizeof(RIFF_WAVEFORMATEX)); + if (buf != NULL) + memcpy(wfe, buf, len); + else + { + if (read(fd, wfe, len) != len) + { + SPfree(wfe); + return NULL; + } + } + if (wfe->cb_size != 0) + { + wfe = (RIFF_WAVEFORMATEX *)SPrealloc(wfe, sizeof(RIFF_WAVEFORMATEX) + wfe->cb_size); + if (wfe != NULL) + { + if (read(fd, (BYTE *)wfe + sizeof(RIFF_WAVEFORMATEX), wfe->cb_size) != wfe->cb_size) + { + SPfree(wfe); + return NULL; + } + } + } + } + return wfe; +} + +void audio_update_format_string() +{ + if (audio != NULL && audio->audio_fmt != RIFF_AUDIO_UNKNOWN) + { + int br = audio_get_bitrate(); + if (br != audio->cur_bitrate || audio->audio_fmt != audio->cur_audio_format || (audio->fmtex != NULL + && ((int)audio->fmtex->n_samples_per_sec != audio->cur_samples || + (int)audio->fmtex->w_bits_per_sample != audio->cur_bits || + (int)audio->fmtex->n_channels != audio->cur_channels + ))) + { + audio->cur_audio_format = audio->audio_fmt; + audio->cur_bitrate = br; + if (audio->fmtex != NULL) + { + audio->cur_samples = audio->fmtex->n_samples_per_sec; + audio->cur_bits = audio->fmtex->w_bits_per_sample; + audio->cur_channels = audio->fmtex->n_channels; + } + + SPString fmt = audio_get_audio_format_string(audio->audio_fmt); + audio->audio_fmt_str = fmt; + if ((audio->audio_fmt == RIFF_AUDIO_PCM || audio->audio_fmt == RIFF_AUDIO_LPCM) + && audio->fmtex != NULL) + { + audio->audio_fmt_str.Printf(" @ %d Hz, %d bits %s", + audio->fmtex->n_samples_per_sec, + audio->fmtex->w_bits_per_sample, + audio->fmtex->n_channels > 1 ? "stereo" : "mono"); + } + else + { + if (br > 0) + audio->audio_fmt_str.Printf(" @ %d kbps", (br + 500) / 1000); + } + if (audio->audio_fmt == RIFF_AUDIO_AC3 && audio->fmtex != NULL) + { + audio->audio_fmt_str.Printf(", %d Hz, ", audio->fmtex->n_samples_per_sec); + if (audio->fmtex->n_channels == 0x0100) + audio->audio_fmt_str.Printf("mono"); + else if (audio->fmtex->n_channels == 0x0200) + audio->audio_fmt_str.Printf("stereo"); + else + audio->audio_fmt_str.Printf("%d.%d", (audio->fmtex->n_channels >> 8) & 0xff, + audio->fmtex->n_channels & 0xff); + } + MSG("Audio: * Audio format detected: %s.\n", *audio->audio_fmt_str); + script_audio_info_callback(audio->audio_fmt_str); + } + } +} + +int audio_setaudioparams(RIFF_AUDIO_FORMAT fmt, RIFF_WAVEFORMATEX *wfe, int halfrate) +{ + MpegAudioPacketInfo defaudioparams; + + // set audio format + switch (fmt) + { + case RIFF_AUDIO_MP2: + case RIFF_AUDIO_MP3: + defaudioparams.type = eAudioFormat_PCM; + if (wfe != NULL) + wfe->w_bits_per_sample = 16; + max_info_cnt = 20; + break; + case RIFF_AUDIO_AC3: + defaudioparams.type = eAudioFormat_AC3; + if (wfe != NULL) + wfe->w_bits_per_sample = 24; + max_info_cnt = 10; + break; +/* case RIFF_AUDIO_DTS: + defaudioparams.type = eAudioFormat_DTS; + break; +*/ + case RIFF_AUDIO_PCM: + case RIFF_AUDIO_LPCM: + defaudioparams.type = eAudioFormat_PCM; + max_info_cnt = 32; + break; + default: + msg_error("AVI: Audio format %d not supported!\n", fmt); + return -1; + } + + if (wfe != NULL) + { + if (wfe->n_samples_per_sec > 0 && wfe->w_bits_per_sample >= 8 && wfe->n_channels > 0) + { + defaudioparams.samplerate = wfe->n_samples_per_sec / halfrate; + defaudioparams.numberofbitspersample = wfe->w_bits_per_sample; + defaudioparams.numberofchannels = wfe->n_channels; + defaudioparams.fromstream = TRUE; + } else + return -1; + } else + { + defaudioparams.samplerate = 48000; + defaudioparams.numberofbitspersample = 24; + defaudioparams.numberofchannels = 2; + defaudioparams.fromstream = TRUE; + } + + if (mpeg_setaudioparams(&defaudioparams) < 0) + { + return -1; + } + + if (audio != NULL) + { + if (defaudioparams.type == eAudioFormat_AC3) + { + audio->out_bps = 0; // don't guess bitrate + audio->ac3_gatherinfo = true; + } + else + audio->out_bps = defaudioparams.samplerate * defaudioparams.numberofbitspersample + * defaudioparams.numberofchannels / 8; + + if (audio->fmtex == NULL && wfe != NULL) + { + int wfe_size = sizeof(RIFF_WAVEFORMATEX) + wfe->cb_size; + audio->fmtex = (RIFF_WAVEFORMATEX *)SPmalloc(wfe_size); + if (audio->fmtex != NULL) + { + memcpy(audio->fmtex, wfe, wfe_size); + audio_update_format_string(); + } + } + } + + return 0; +} + +void audio_set_ac3_getinfo(bool always) +{ + if (audio != NULL) + audio->ac3_gather_always = always; +} + +//////////////////////////////////////////////////////// + +char *audio_get_next(char *filepath, bool get_next) +{ + static const char *audio_file_ext[] = { ".mp3", ".mp2", ".mp1", ".mpa", ".ac3", ".wav", ".ogg", NULL }; + static char tmp_path[4096]; + + if (audio_dir_list == NULL) + { + if (filepath == NULL) + return NULL; + audio_dir_list = new SPClassicList(); + audio_prev_list = new SPDLinkedList(); + if (audio_dir_list == NULL || audio_prev_list == NULL) + return NULL; + audio_dir_list->Reserve(20); + audio_prev_list->SetSize(10); + tmp_path[0] = '\0'; + AudioDir ad; + ad.dir = NULL; + ad.path = filepath; + audio_dir_list->Add(ad); + } + + if (audio_dir_list->GetN() > 0) + { + if (!get_next) + { + if (audio_prev_list == NULL) + return NULL; + DLElement *el = audio_prev_list->GetLast(); + if (el == NULL) + return NULL; + strcpy(tmp_path, el->GetItem()); + audio_prev_list->Delete(el); + return tmp_path; + } + + for (;;) + { + AudioDir &ad = (*audio_dir_list)[audio_dir_list->GetN() - 1]; + if (ad.dir == NULL) + { + // scan for files + ad.dir = cdrom_opendir(ad.path); + } + if (ad.dir != NULL) + { + struct dirent *d = cdrom_readdir(ad.dir); + if (d == NULL) + { + cdrom_closedir(ad.dir); + audio_dir_list->Remove(audio_dir_list->GetN() - 1); + if (audio_dir_list->GetN() < 1) + break; + continue; + } + if (d->d_name[0] == '.' && d->d_name[1] == '\0') + continue; + + SPString path = ad.path + SPString("/") + SPString(d->d_name); + + struct stat64 statbuf; + if (cdrom_stat(path, &statbuf) < 0) + { + msg("Cannot stat %s\n", *path); + continue; + } + if (S_ISDIR(statbuf.st_mode)) + { + if (d->d_name[0] == '.') // hidden + continue; + AudioDir ad; + ad.dir = NULL; + ad.path = path; + audio_dir_list->Add(ad); + continue; + } + // check for file type + for (int k = 0; audio_file_ext[k] != NULL; k++) + { + if (strstr(d->d_name, audio_file_ext[k]) != NULL) + { + if (tmp_path[0] != '\0') + { + DLElement *el = new DLElement(tmp_path); + if (el == NULL) + return NULL; + audio_prev_list->Add(el); + } + + strcpy(tmp_path, path); + msg("Audio: Playing %s...\n", tmp_path); + return tmp_path; + } + } + } + else + break; + } + } + audio_delete_filelist(); + return NULL; +} + +void audio_delete_filelist() +{ + if (audio_dir_list != NULL) + { + for (int i = 0; i < audio_dir_list->GetN(); i++) + { + AudioDir &ad = (*audio_dir_list)[i]; + cdrom_closedir(ad.dir); + } + SPSafeDelete(audio_dir_list); + } + + if (audio_prev_list != NULL) + { + audio_prev_list->Delete(); + SPSafeDelete(audio_prev_list); + } + +} + + +#endif diff --git a/src/audio.h b/src/audio.h new file mode 100644 index 0000000..140b74f --- /dev/null +++ b/src/audio.h @@ -0,0 +1,264 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Audio player (WAV/MP3) header file + * \file audio.h + * \author bombur + * \version 0.1 + * \date 07.03.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_AUDIO_H +#define SP_AUDIO_H + +// see audio_get_audio_format_string() +typedef enum +{ + RIFF_AUDIO_UNKNOWN = -1, + RIFF_AUDIO_NONE = 0, + RIFF_AUDIO_LPCM, + RIFF_AUDIO_PCM, + RIFF_AUDIO_MP1, + RIFF_AUDIO_MP2, + RIFF_AUDIO_MP3, + RIFF_AUDIO_AC3, + RIFF_AUDIO_DTS, + RIFF_AUDIO_VORBIS, +} RIFF_AUDIO_FORMAT; + +typedef enum +{ + AUDIO_XING_HAS_NUMFRAMES = 0x0001, + AUDIO_XING_HAS_FILESIZE = 0x0002, + AUDIO_XING_HAS_TOC = 0x0004, + AUDIO_XING_HAS_VBR_SCALE = 0x0008, +} AUDIO_XING_FLAGS; + +#ifdef WIN32 +#pragma pack(1) +#endif + +typedef struct ATTRIBUTE_PACKED +{ + WORD w_format_tag; + WORD n_channels; + DWORD n_samples_per_sec; + DWORD n_avg_bytes_per_sec; + WORD n_block_align; + WORD w_bits_per_sample; + WORD cb_size; +} RIFF_WAVEFORMATEX; + +#ifdef WIN32 +#pragma pack() +#endif + +typedef struct RiffAudioTrack +{ + RIFF_WAVEFORMATEX *wfe; // audio format + + DWORD flags; + long mp3rate; // mp3 bitrate kbs + bool a_vbr; // Variable BitRate? + long padrate; // byte rate used for zero padding + + long audio_strn; // Audio stream number + long audio_samples; // Number of samples + LONGLONG audio_bytes; // Total number of bytes of audio data + long audio_chunks; // Chunks of audio data in the file + + char audio_tag[4]; // Tag of audio data + long audio_pos; // Audio position: chunk + + LONGLONG a_codech_off; // absolute offset of audio codec information + LONGLONG a_codecf_off; // absolute offset of audio codec information + +} RiffAudioTrack; + +#ifdef AUDIO_INTERNAL + + +/// Audio player class +class Audio +{ +public: + /// ctor + Audio(); + + /// dtor + ~Audio(); + + int ParseMp3Packet(MpegPacket *packet, BYTE * &buf, int len); + int ParsePCMPacket(MpegPacket *packet, BYTE * &buf, int len); + int ParseAC3Packet(MpegPacket *packet, BYTE * &buf, int len); + int ParseRawPacket(MpegPacket *packet, BYTE * &buf, int len); + + int ParseXingHeader(BYTE *buf, int len); + int ParseVBRIHeader(BYTE *buf, int len); + int ParseAC3Header(BYTE *buf, int len, bool fill_info = true); + + int Seek(LONGLONG pos, int msecs); + +public: + struct mad_stream mp3_stream; + struct mad_frame mp3_frame; + struct mad_synth mp3_synth; + + RIFF_AUDIO_FORMAT audio_fmt; + SPString audio_fmt_str; + + RIFF_WAVEFORMATEX *fmtex; + + int audio_numbufs, audio_bufsize; + int audio_bufidx; + int audio_samplerate, audio_channels; + int samples_per_frame; + + int audio_frame_number; + int is_partial_packet, is_partial_next_packet; + + // for seeking + int bitrate, avg_bitrate, avg_num; + // output bitrate - for PTS calc. + int out_bps; + /// audio data full size, in bytes. + LONGLONG filesize, cur_offset, cur_tmpoffset; + /// audio length, in msecs. + int length; + + // displayed values + int cur_bitrate, cur_audio_format; + int cur_samples, cur_bits, cur_channels; + + bool needs_resample; + bool fast; + int resample_packet_size; + + BYTE *mp3_tmpbuf; + int mp3_tmppos, mp3_tmpstart, mp3_tmpread; + bool mp3_want_more; + bool wait; + + int ac3_scan_header; + BYTE ac3_header[8]; + int ac3_framesize; + bool ac3_gatherinfo, ac3_gather_always; + + BYTE *mux_buf; + int mux_numbufs, mux_bufsize; + + bool playing, stopping; + LONGLONG saved_pts; + int fd; + + SPList seek_toc; + LONGLONG seek_offset; + /// length of TOC, in msecs + int toc_length; + + int (*mp3_output)(BYTE *data, struct mad_pcm *pcm); + +private: + /// Get big-endian number + DWORD GetBE(BYTE *buf, int offset, int numbytes); + /// Set length & filesize from VBR headers data + int SetVbrLength(int total_num_frames, int vbr_filesize); + + +}; +#endif + +#ifdef __cplusplus +//extern "C" { +#endif + +/// Play audio file +int audio_play(char *filepath = NULL, bool is_folder = false, bool continue_next = true); + +/// Advance playing +int audio_loop(); + +/// Pause playing +BOOL audio_pause(); + +/// Stop playing +BOOL audio_stop(BOOL continue_next = TRUE); + +/// Seek to given time and play +BOOL audio_seek(int seconds, int from); + +/// Continue audio play +int audio_continue_play(); + +int audio_forward(); +int audio_rewind(); + +void audio_setdebug(BOOL ison); +BOOL audio_getdebug(); + + +/// Initialize audio player +int audio_init(RIFF_AUDIO_FORMAT fmt, bool fast); +/// Deinitialize audio player +int audio_deinit(); + +/// Get next file name from the list +char *audio_get_next(char *filepath, bool get_next); +/// Delete file list (free memory) +void audio_delete_filelist(); + +/// Return TRUE if audio decoder is ready +BOOL audio_ready(); +/// Reset audio and drop old frames +int audio_reset(); + +// internal funcs used by media +BOOL audio_open(const char *filepath); + +BOOL audio_close(); + +int audio_read(BYTE *buf, int *len); + +/// Parse audio packet +int audio_parse_packet(MpegPacket *packet, BYTE * &buf, int len); + +RIFF_AUDIO_FORMAT audio_get_audio_format(int fmt); + +/// Get format text string +SPString audio_get_audio_format_string(RIFF_AUDIO_FORMAT fmt); + +/// little-endian! +RIFF_WAVEFORMATEX *audio_read_formatex(int fd, BYTE *buf, int len); +/// Set audio params +int audio_setaudioparams(RIFF_AUDIO_FORMAT fmt, RIFF_WAVEFORMATEX *wfe, int halfrate); + +/// Get audio bitrate +int audio_get_bitrate(); + +/// Get audio output bytes-per-second +int audio_get_output_bps(); + +void audio_update_format_string(); + +/// Set by video player to save some CPU resources... +void audio_set_ac3_getinfo(bool always); + +#ifdef __cplusplus +//} +#endif + +#endif // of SP_AUDIO_H diff --git a/src/avi.cpp b/src/avi.cpp new file mode 100644 index 0000000..3a085e0 --- /dev/null +++ b/src/avi.cpp @@ -0,0 +1,1003 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - AVI player source file. + * \file avi.cpp + * \author bombur + * \version 0.1 + * \date 07.03.2007 + * + * Based on AVILIB (C) 1999 Rainer Johanni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "player.h" +#include "media.h" + +#ifdef INTERNAL_VIDEO_PLAYER + +#define VIDEO_INTERNAL + +#include "audio.h" +#include "video.h" +#include "avi.h" + +#include "script-vars.h" + +#define MSG if (video_msg) msg + +VideoAvi::VideoAvi() +{ + type = VIDEO_CONTAINER_AVI; + + video_strn = 0; + avi_flags = 0; + bitmap_info_header = NULL; + video_superindex.idx = NULL; + + memset(video_tag1, 0, 4); + memset(video_tag2, 0, 4); + movi_start = 0; + idx_start = -1; + idx_offset = -1; + + has_indx = false; + num_idx = 0; + + buf_idx = (AviOldIndexEntry *)SPmalloc(MAX(max_buf_idx_size[0], max_buf_idx_size[1])); + buf_idx_size = 0; + + cur_old_buf_idx = 0; + cur_buf_video_idx = 0; + + cur_indx_buf_idx = 0; + cur_indx_buf_pos = 0; + cur_indx_base_offset = 0; + cur_buf_idx_size = 1; +} + +VideoAvi::~VideoAvi() +{ + SPSafeFree(bitmap_info_header); + SPSafeFree(video_superindex.idx); + SPSafeFree(buf_idx); +} + +//////////////////////////////////////////////// + +BOOL VideoAvi::Parse() +{ + long i, n; + BYTE *hdrl_data; + BYTE data[256]; + long header_offset = 0, hdrl_len = 0; + int j; + VIDEO_CHUNK_TYPE lasttag = VIDEO_CHUNK_UNKNOWN; + bool vids_strh_seen = false; + bool vids_strf_seen = false; + bool auds_strh_seen = false; + int num_stream = 0; + LONGLONG oldpos = -1, newpos = -1; + + // Read first 12 bytes and check that this is an AVI file + if (video_read(data, 12) != 12) + { + msg_error("AVI: Read error.\n"); + return FALSE; + } + if (strncasecmp((char *)data, "RIFF", 4) != 0 || strncasecmp((char *)data+8, "AVI ", 4) != 0) + { + msg_error("AVI: File header not found. Wrong file format.\n"); + return FALSE; + } + + // Go through the AVI file and extract the header list, + // the start position of the 'movi' list and an optionally present idx1 tag + + hdrl_data = 0; + movi_start = 0; + idx_start = -1; + + // find all main AVI parts + for (;;) + { + // EOF? + if (video_read(data, 8) != 8) + break; + newpos = video_lseek(0, SEEK_CUR); + if (oldpos == newpos) + { + msg_error("AVI: AVI file is broken.\n"); + return FALSE; + } + oldpos=newpos; + + n = GET_DWORD(data+4); + n = PAD_EVEN(n); + + if (strncasecmp((char *)data, "LIST", 4) == 0) + { + if (video_read(data, 4) != 4) + { + msg_error("AVI: Read error.\n"); + return FALSE; + } + n -= 4; + if (n <= 0) + break; + if (strncasecmp((char *)data, "hdrl", 4) == 0) + { + hdrl_len = n; + hdrl_data = (BYTE *) SPmalloc(n); + if (hdrl_data == NULL) + return FALSE; + + header_offset = (long)video_lseek(0, SEEK_CUR); + if (video_read(hdrl_data, n) != n) + { + msg_error("AVI: Read error.\n"); + return FALSE; + } + } + else if (strncasecmp((char *)data, "movi", 4) == 0) + { + movi_start = video_lseek(0, SEEK_CUR); + if (video_lseek(n, SEEK_CUR) == (LONGLONG)-1) + break; + } + else + { + if (video_lseek(n, SEEK_CUR) == (LONGLONG)-1) + break; + } + } + else if(strncasecmp((char *)data, "idx1", 4) == 0) + { + // n must be a multiple of 16, but the reading does not + // break if this is not the case + num_idx = n / sizeof(AviOldIndexEntry); + idx_start = video_lseek(0, SEEK_CUR); + + if (buf_idx == NULL) + return FALSE; + buf_idx_size = MIN(n, max_buf_idx_size[0]); + // \warning! little-endian ONLY! + if (video_read((BYTE *)buf_idx, buf_idx_size) != buf_idx_size) + { + buf_idx_size = 0; + num_idx = 0; + } + video_lseek(n - buf_idx_size, SEEK_CUR); + } + else + video_lseek(n, SEEK_CUR); + } + + if (hdrl_data == NULL) + { + msg_error("AVI: no AVI header found.\n"); + return FALSE; + } + if (movi_start == 0) + { + msg_error("AVI: no movie data found.\n"); + return FALSE; + } + + // parse header + for (i = 0; i < hdrl_len; ) + { + if (strncasecmp((char *)hdrl_data+i,"LIST", 4) == 0) + { + i+= 12; + continue; + } + + n = GET_DWORD(hdrl_data+i+4); + n = PAD_EVEN(n); + + if (strncasecmp((char *)hdrl_data + i, "avih", 4) == 0) + { + i += 8; + avi_flags = GET_DWORD(hdrl_data+i+12); + if (avi_flags & AVI_FLAG_MUSTUSEINDEX) + { + msg_error("Avi: Reordered stream cannot be played correctly!\n"); + } + if (!(avi_flags & AVI_FLAG_ISINTERLEAVED)) + { + msg_error("Avi: Non-interleaved stream cannot be played correctly!\n"); + } + /* + if (!(avi_flags & AVI_FLAG_TRUSTCKTYPE)) + { + msg("Avi: We cannot trust key-frames? Maybe...\n"); + } + */ + } + else if (strncasecmp((char *)hdrl_data + i, "strh", 4) == 0) + { + i += 8; + if (strncasecmp((char *)hdrl_data + i, "vids", 4) == 0 && !vids_strh_seen) + { + scale = GET_DWORD(hdrl_data+i+20); + rate = GET_DWORD(hdrl_data+i+24); + if (scale != 0) + fps = (float)rate / (float)scale; + video_frames = GET_DWORD(hdrl_data+i+32); + video_strn = num_stream; + vids_strh_seen = true; + lasttag = VIDEO_CHUNK_VIDEO; + } + else if (strncasecmp ((char *)hdrl_data+i,"auds",4) == 0 && ! auds_strh_seen) + { + //inc audio tracks + cur_track = num_tracks; + ++num_tracks; + + if (num_tracks > VIDEO_MAX_AUDIO_TRACKS) + { + msg_error("Avi: Only %d audio tracks supported!\n", VIDEO_MAX_AUDIO_TRACKS); + return FALSE; + } + + track[cur_track].flags = GET_DWORD(hdrl_data+i+8); + track[cur_track].padrate = GET_DWORD(hdrl_data+i+24); + track[cur_track].audio_samples = GET_DWORD(hdrl_data+i+32); + track[cur_track].a_vbr = GET_DWORD(hdrl_data+i+44) == 0; // samplesize -- 0? + track[cur_track].audio_strn = num_stream; + track[cur_track].a_codech_off = header_offset + i; + lasttag = VIDEO_CHUNK_AUDIO; + } + else if (strncasecmp ((char *)hdrl_data+i, "iavs", 4) == 0 && ! auds_strh_seen) + { + msg_error("AVI: DV AVI Type 1 not supported.\n"); + return FALSE; + } + else + lasttag = VIDEO_CHUNK_UNKNOWN; + num_stream++; + } + else if (strncasecmp((char *)hdrl_data+i, "dmlh", 4) == 0) + { + total_frames = GET_DWORD(hdrl_data+i+8); + i += 8; + } + else if (strncasecmp((char *)hdrl_data+i,"strf", 4) == 0) + { + i += 8; + if (lasttag == VIDEO_CHUNK_VIDEO) + { + RIFF_BITMAPINFOHEADER bih; + memcpy(&bih, hdrl_data + i, sizeof(RIFF_BITMAPINFOHEADER)); + bih.bi_size = GET_DWORD((BYTE *)&bih.bi_size); + bitmap_info_header = (RIFF_BITMAPINFOHEADER *)SPmalloc(bih.bi_size); + if (bitmap_info_header != NULL) + { + memcpy(bitmap_info_header, hdrl_data + i, bih.bi_size); + } + + width = GET_DWORD(hdrl_data+i+4); + height = GET_DWORD(hdrl_data+i+8); + memcpy(fourcc, hdrl_data+i+16, 4); fourcc[4] = 0; + + vids_strf_seen = true; + } + else if (lasttag == VIDEO_CHUNK_AUDIO) + { + LONGLONG lpos = video_lseek(0, SEEK_CUR); + video_lseek(header_offset + i + sizeof(RIFF_WAVEFORMATEX), SEEK_SET); + + RIFF_WAVEFORMATEX *wfe = audio_read_formatex(fd, hdrl_data + i, hdrl_len - i); + + video_lseek(lpos, SEEK_SET); + + if (wfe != NULL) + { + track[cur_track].a_codecf_off = header_offset + i; + track[cur_track].mp3rate = 8 * wfe->n_avg_bytes_per_sec / 1000; + int sampsize = MAX(((wfe->w_bits_per_sample + 7) / 8) + * wfe->n_channels, 4); + track[cur_track].audio_bytes = + track[cur_track].audio_samples * sampsize; + } + + track[cur_track].wfe = wfe; + } + } + else if(strncasecmp((char *)hdrl_data+i, "indx", 4) == 0) + { + MSG("AVI: New v2.0 index detected!\n"); + if (!(avi_flags & AVI_FLAG_TRUSTCKTYPE)) + { + msg_error("AVI: Index may contain invalid keyframes!\n"); + } + + if (lasttag == VIDEO_CHUNK_VIDEO) + { + BYTE *a = hdrl_data + i; + memcpy (video_superindex.fcc, a, 4); a += 4; + video_superindex.dwSize = GET_DWORD(a); a += 4; + video_superindex.wLongsPerEntry = GET_WORD(a); a += 2; + video_superindex.bIndexSubType = *a; a += 1; + video_superindex.bIndexType = *a; a += 1; + video_superindex.nEntriesInUse = GET_DWORD(a); a += 4; + memcpy (video_superindex.dwChunkId, a, 4); a += 4; + + // 3 * reserved + a += 4; a += 4; a += 4; + + if (video_superindex.bIndexSubType != 0) + { + msg("AVI: Invalid ODML superindex header.\n"); + } + + int superidx_size = video_superindex.wLongsPerEntry + * video_superindex.nEntriesInUse * sizeof (DWORD); + video_superindex.idx = superidx_size < 256*1024 ? + (AviSuperIndexEntry *)SPmalloc (superidx_size) : NULL; + if (video_superindex.idx != NULL) + { + // position of ix## chunks + for (DWORD j = 0; j < video_superindex.nEntriesInUse; ++j) + { + video_superindex.idx[j].qwOffset = GET_ULONGLONG (a); a += 8; + video_superindex.idx[j].dwSize = GET_DWORD (a); a += 4; + video_superindex.idx[j].dwDuration = GET_DWORD (a); a += 4; + } + has_indx = true; + } + } + i += 8; + } + else if ((strncasecmp((char *)hdrl_data+i,"JUNK", 4) == 0) || + (strncasecmp((char *)hdrl_data+i,"strn", 4) == 0) || + (strncasecmp((char *)hdrl_data+i,"strd", 4) == 0) || + (strncasecmp((char *)hdrl_data+i,"vprp", 4) == 0)) + { + // do not reset lasttag + i += 8; + } else + { + i += 8; + lasttag = VIDEO_CHUNK_UNKNOWN; + } + i += n; + } + + SPfree(hdrl_data); + + if (!vids_strh_seen || !vids_strf_seen) + { + msg_error("AVI: No video found.\n"); + return FALSE; + } + + video_tag1[0] = (char)(video_strn/10 + '0'); + video_tag1[1] = (char)(video_strn%10 + '0'); + video_tag1[2] = 'd'; + video_tag1[3] = bitmap_info_header != NULL + && bitmap_info_header->bi_compression == 0 ? 'b' : 'c'; + + video_tag2[0] = (char)(video_strn/10 + '0'); + video_tag2[1] = (char)(video_strn%10 + '0'); + video_tag2[2] = 'd'; + video_tag2[3] = video_tag1[3] == 'b' ? 'c' : 'b'; + + // Audio tag is set to "99wb" if no audio present + if (track[0].wfe == NULL || track[0].wfe->n_channels < 1) + track[0].audio_strn = 99; + + first_track = -1; + int good_first_track = -1; + for(i = 0, j = 0; j < num_tracks + 1; ++j) + { + if (j == video_strn) + continue; + if (first_track < 0) + first_track = i; + // if not disabled + if (good_first_track < 0 && (track[i].flags & 1) == 0) + good_first_track = i; + track[i].audio_tag[0] = (char)(j/10 + '0'); + track[i].audio_tag[1] = (char)(j%10 + '0'); + track[i].audio_tag[2] = 'w'; + track[i].audio_tag[3] = 'b'; + ++i; + } + + // set first non-disabled track. + // we can change them later with video_set_audio_track(). + if (good_first_track >= 0) + first_track = good_first_track; + + cur_track = first_track; + + video_lseek(movi_start, SEEK_SET); + + // if the file has an idx1, check if this is relative + // to the start of the file or to the start of the 'movi' list + idx_offset = -1; + if (idx_start > 0 && !has_indx) + { + int num_buf_idx = buf_idx_size / sizeof(AviOldIndexEntry); + bool found_av = false; + for (i = 0; i < num_buf_idx; i++) + { + if (strncasecmp((char *)&buf_idx[i].chunkid, (char *)video_tag1, 3) == 0) + { + found_av = true; + break; + } + } + // if no video chunks present in current buffer, search for audio... + if (!found_av) + { + for (i = 0; !found_av && i < num_buf_idx; i++) + { + for (j = 0; j < num_tracks; ++j) + { + if (strncasecmp((char *)&buf_idx[i].chunkid, track[j].audio_tag, 4) == 0) + { + found_av = true; + break; + } + } + } + } + + if (found_av) + { + LONGLONG pos = buf_idx[i].offset; + LONGLONG len = buf_idx[i].size; + if (pos >= 0 && len > 0) + { + video_lseek(pos, SEEK_SET); + if (video_read(data, 8) == 8) + { + // index from start of file? + if (strncasecmp((char *)data, (char *)&buf_idx[i].chunkid, 4) == 0 + && GET_DWORD(data + 4) == len) + { + idx_offset = 0; + } + } + if (idx_offset < 0) + { + video_lseek(pos + movi_start - 4,SEEK_SET); + if (video_read(data, 8) == 8) + { + // index from start of 'movi' list? + if (strncasecmp((char *)data, (char *)&buf_idx[i].chunkid, 4) == 0 + && GET_DWORD((unsigned char *)data+4) == len) + { + idx_offset = movi_start - 4; + } + } + } + } + } + // broken index... + if (idx_offset >= 0) + { + AddIdx1Block(); + } + } + + // Reposition the file + video_lseek(movi_start, SEEK_SET); + abs_video_pos = -1; + video_pos_base = 0; + video_pos = 0; + audio_pos = 0; + cur_key_offs = last_chunk_offs = cur_offs = video_offs = movi_start; + frame_pos = 0; + last_frame_pos = -1; + + return TRUE; +} + +////////////////////////////////////////////////////////////////// + +VIDEO_CHUNK_TYPE VideoAvi::GetNext(BYTE *buf, int buflen, int *pos, int *left, int *len) +{ + // there was a partial chunk read + int tmp_read; + if (chunkleft > 0) + { + *len = MIN(chunkleft, buflen); + + chunkleft -= buflen; + if (chunkleft < 0) + chunkleft = 0; + + if (chunktype != VIDEO_CHUNK_UNKNOWN) + { + if ((tmp_read = video_read(buf, PAD_EVEN(*len))) == 0) + { + return VIDEO_CHUNK_EOF; + } + } else + video_lseek(PAD_EVEN(*len), SEEK_CUR); + + if (chunkleft == 0) + { + if (chunktype == VIDEO_CHUNK_AUDIO_PARTIAL) + return VIDEO_CHUNK_AUDIO; + else if (chunktype == VIDEO_CHUNK_VIDEO_PARTIAL) + return VIDEO_CHUNK_VIDEO; + } + if (chunktype != VIDEO_CHUNK_UNKNOWN) + return chunktype; + + //buf += PAD_EVEN(*len); + //*pos += PAD_EVEN(*len); + //*left -= PAD_EVEN(*len); + } + + *len = 0; + chunktype = VIDEO_CHUNK_UNKNOWN; + //chunkleft = 0; + + int curpos = *pos; + LONGLONG start_offs; + + // in recovery mode, use buffered read + if (look4chunk) + { + buflen = video_read(buf, buflen - curpos); + if (buflen <= 0) + return VIDEO_CHUNK_EOF; + start_offs = cur_offs; + buflen += curpos; + } + + + // we're at the start of the chunk and got chunk header + while (curpos < buflen) + { + // if we got a list tag, ignore it + BYTE hdr_data[8]; + char *hdr = (char *)hdr_data; + + if (!look4chunk) + { + if ((tmp_read = video_read(hdr_data, 8)) == 0) + { + return VIDEO_CHUNK_EOF; + } + } else + { + curpos = (int)(cur_offs - start_offs); + hdr = (char *)(buf + curpos); + } + + cur_offs += 8; + + int n, reallen; + if (strncasecmp(hdr, "RIFF", 4) == 0 || strncasecmp(hdr, "LIST", 4) == 0) + { + ResetRecoveryMode(); + video_lseek(4, SEEK_CUR); + + cur_offs += 4; + continue; + } + if (*left < 8) + { + chunktype = VIDEO_CHUNK_FRAGMENT; + break; + } + + reallen = n = GET_DWORD((BYTE *)hdr + 4); + + //buf += 8; + //*pos += 8; + //*left -= 8; + bool partial = false; + + frame_pos++; + + if (strncasecmp(hdr, video_tag1, 3) == 0) + { +//msg("00dc\n"); +//printf("00dc: [%d] n=%d %d/%d\n", frame_pos, n, *pos, buflen); + abs_video_pos++; + video_pos++; + if (n == 0) + continue; + + ResetRecoveryMode(); + + int read_n; + if (*pos + n > buflen) + { + // XXXXXXXXXXXXXXX + if (no_partial) + { + frame_pos--; + abs_video_pos--; + video_pos--; + video_lseek(-8, SEEK_CUR); + return VIDEO_CHUNK_UNKNOWN; + } + + chunkleft = n - buflen + *pos; + read_n = n = buflen - *pos; + partial = true; + + } else + read_n = PAD_EVEN(n); + + if ((tmp_read = video_read(buf, read_n)) == 0) + { + return VIDEO_CHUNK_EOF; + } + + *len = n; + video_packet_len = reallen; + chunktype = partial ? VIDEO_CHUNK_VIDEO_PARTIAL : VIDEO_CHUNK_VIDEO; + last_chunk_offs = video_offs = cur_offs - 8; + cur_offs += read_n; + last_chunk_len = reallen; + break; + } + else if (cur_track >= 0 && strncasecmp(hdr, track[cur_track].audio_tag, 4) == 0) + { +//msg("01wb\n"); + audio_pos++; + if (n == 0) + continue; + + ResetRecoveryMode(); + + int read_n; + if (*pos + n > buflen) + { + // XXXXXXXXXXXXXXX + if (no_partial) + { + frame_pos--; + audio_pos--; + video_lseek(-8, SEEK_CUR); + return VIDEO_CHUNK_UNKNOWN; + } + + chunkleft = n - buflen + *pos; + read_n = n = buflen - *pos; + partial = true; + } else + read_n = PAD_EVEN(n); + + + if ((tmp_read = video_read(buf, read_n)) == 0) + { + return VIDEO_CHUNK_EOF; + } +#if 0 +{ +FILE *fp = fopen("out-avi.mp3", "ab"); +fwrite(buf, n, 1, fp); +fclose(fp); +} +#endif + *len = n; + chunktype = partial ? VIDEO_CHUNK_AUDIO_PARTIAL : VIDEO_CHUNK_AUDIO; + last_chunk_offs = cur_offs - 8; + cur_offs += read_n; + last_chunk_len = reallen; + track[cur_track].audio_pos++; + break; + } + else + { + if (hdr[0] == 'i' && hdr[1] == 'd' && hdr[2] == 'x' && hdr[3] == '1') + { + ResetRecoveryMode(); + + //chunktype = VIDEO_CHUNK_EOF; + chunktype = VIDEO_CHUNK_UNKNOWN; + //buf += PAD_EVEN(n); + //*pos += PAD_EVEN(n); + //*left -= PAD_EVEN(n); + + cur_offs += PAD_EVEN(n); + video_lseek(cur_offs, SEEK_SET); + + //return chunktype; + continue; + } + else if ((hdr[2] == 'w' && hdr[3] == 'b') || + (hdr[0] == 'i' && hdr[1] == 'x') || + (hdr[0] == 'J' && hdr[1] == 'U' && hdr[2] == 'N' && hdr[3] == 'K')) + { + ResetRecoveryMode(); + + //buf += PAD_EVEN(n); + //*pos += PAD_EVEN(n); + //*left -= PAD_EVEN(n); + chunktype = VIDEO_CHUNK_UNKNOWN; + + video_lseek(PAD_EVEN(n), SEEK_CUR); + + cur_offs += PAD_EVEN(n); + } + // file is corrupted ? + else + { + cur_offs -= 7; + + if (!look4chunk) + { + LONGLONG file_offs = video_lseek(0, SEEK_CUR) - 8; + msg("AVI: File corrupted @ " PRINTF_64d ". Trying to recover...\n", file_offs); + + video_lseek(-7, SEEK_CUR); + + chunkleft = 0; + look4chunk = true; + + script_error_callback(SCRIPT_ERROR_CORRUPTED); + + return VIDEO_CHUNK_RECOVERY; + } + } + } + } + return chunktype; +} + +int VideoAvi::GetNextIndexes() +{ + if ((idx_offset >= 0 && idx_start > 0) || has_indx) + { + media_update_fip(); + + LONGLONG buf_idx_offs; + if (has_indx) + { + cur_buf_idx_size = video_superindex.idx[cur_indx_buf_idx].dwSize; + if (cur_indx_buf_pos >= cur_buf_idx_size) + { + cur_indx_buf_idx++; + cur_indx_buf_pos = 0; + } + if ((DWORD)cur_indx_buf_idx >= video_superindex.nEntriesInUse) + return -1; + + cur_buf_idx_size -= cur_indx_buf_pos; + buf_idx_offs = video_superindex.idx[cur_indx_buf_idx].qwOffset + cur_indx_buf_pos; + } else + { + cur_buf_idx_size = (num_idx - cur_old_buf_idx) * sizeof(AviOldIndexEntry); + buf_idx_offs = idx_start + cur_old_buf_idx * sizeof(AviOldIndexEntry); + } + + buf_idx_size = MIN(max_buf_idx_size[has_indx ? 1 : 0], cur_buf_idx_size); + + if (buf_idx_size < 1) + return -1; + if (video_lseek(buf_idx_offs, SEEK_SET) < 0) + return -1; + buf_idx_size = video_read((BYTE *)buf_idx, buf_idx_size); + //msg("^^^^^^^ read = %d\n", buf_idx_size); + return has_indx ? AddIdx2Block() : AddIdx1Block(); + } + return -1; +} + +int VideoAvi::GetNextKeyFrame() +{ + int n = 0; + LONGLONG curpos = 0; + const int extra_bytes = 5; + BYTE buf[8 + extra_bytes]; + + //*len = 0; + if (buf_idx == NULL) + return -1; + + // we're at the start of the chunk and got chunk header + for (int i = 0; ; i++) + { + // split our task... + if (i > 30) + { + media_update_fip(); + //if (info_cnt++ > 1) + { + // info_cnt = 0; + video_update_info(); + } + last_chunk_offs = curpos; + last_chunk_len = n; + return 0; + } + + curpos = video_lseek(0, SEEK_CUR); + int extra = read(fd, buf, 8 + extra_bytes) - 8; + + if (extra < 0) + break; + if (strncasecmp((char *)buf, "LIST", 4) == 0) + { + video_lseek(4 - extra, SEEK_CUR); + continue; + } + n = GET_DWORD(buf + 4); + frame_pos++; + if (strncasecmp((char *)buf, video_tag1, 3) == 0) + { + abs_video_pos++; + video_pos++; + scr = INT64(90000) * abs_video_pos * scale / rate; + if (video_fmt == RIFF_VIDEO_MPEG4) + { + // VOP start code + if (n > 4 && buf[8] == 0 && buf[9] == 0 && buf[10] == 1 && buf[11] == 0xb6) + { + if ((buf[12] & 0xc0) == 0) // I-frame + { + goto found; + } + } + // or we have to search for it... + else + { + int nleft = n - extra; + while (nleft > 0) + { + int nb = MIN(nleft, max_buf_idx_size[0]); + nb = video_read((BYTE *)buf_idx, nb); + if (nb == 0) + break; + BYTE *b = (BYTE *)buf_idx; + // find VOP start + int vlen = nb; + for (; vlen >= 0 && (b[0] != 0 || b[1] != 0 + || b[2] != 1 || b[3] != 0xb6); vlen--) + { + b++; + } + if (vlen > 0 && (b[4] & 0xc0) == 0) // I-frame + { + goto found; + } + extra += nb; + nleft -= nb; + } + } + } + else if (video_fmt == RIFF_VIDEO_DIV3) + { + // VOP start code + if (n > 2 && (buf[8] & 0xc0) == 0) // I-frame + { + goto found; + } + } + } + /* + else if (cur_track >= 0 && strncasecmp((char *)buf, track[cur_track].audio_tag, 4) == 0) + { + audio_pos++; + } + */ + video_lseek(PAD_EVEN(n) - extra, SEEK_CUR); + } + + MSG("AVI: I-FRAME seek EOF!\n"); + return -1; + +found: + last_chunk_offs = curpos; + last_chunk_len = n; + + cur_key_offs = video_offs = curpos; + video_lseek(video_offs, SEEK_SET); + MSG("AVI: I-FRAME at %d/%d (%d)\n", abs_video_pos, video_frames, curpos); + video_packet_len = n; + AddIndex(abs_video_pos, video_packet_len, video_offs); + return 1; +} + +int VideoAvi::AddIdx1Block() +{ + if (buf_idx == NULL || idx_offset < 0) + return -1; + + AviOldIndexEntry *b = buf_idx; + DWORD chunkid1 = GET_DWORD((BYTE *)video_tag1); + DWORD chunkid2 = GET_DWORD((BYTE *)video_tag2); + for (int i = buf_idx_size / sizeof(AviOldIndexEntry); i > 0; i--, b++) + { + if (b->chunkid == chunkid1 || b->chunkid == chunkid2) + { + if (b->flags & AVI_IDX1_FLAG_KEYFRAME) + { + if (cur_buf_video_idx > last_key_pos + min_delta_keyframes) + { + if (AddIndex(cur_buf_video_idx, b->size, b->offset + idx_offset) < 0) + return -1; + } + } + cur_buf_video_idx++; + } + } + cur_old_buf_idx += buf_idx_size / sizeof(AviOldIndexEntry); + return 0; +} + +int VideoAvi::AddIdx2Block() +{ + if (buf_idx == NULL) + return -1; + + AviNewIndexEntry *b; + int bis = buf_idx_size; + if (cur_indx_buf_pos == 0) // read header + { + AviNewIndex *ni = (AviNewIndex *)buf_newidx; + cur_indx_base_offset = ni->qwBaseOffset - 8; + + b = (AviNewIndexEntry *)(ni + 1); + bis -= sizeof(AviNewIndex); + } + else + b = buf_newidx; + for (int i = bis / sizeof(AviNewIndexEntry); i > 0; i--, b++) + { + if (!(b->size & AVI_IDX2_FLAG_KEYFRAME)) + { + if (cur_buf_video_idx > last_key_pos + min_delta_keyframes) + { + if (AddIndex(cur_buf_video_idx, b->size, cur_indx_base_offset + b->offset) < 0) + return -1; + } + } + cur_buf_video_idx++; + } + + cur_indx_buf_pos += buf_idx_size; + return 0; +} + +void VideoAvi::ResetRecoveryMode() +{ + if (look4chunk) + { + video_lseek(cur_offs, SEEK_SET); + look4chunk = false; + script_update_variable(SCRIPT_VAR_PLAYER_SPEED); + } +} + +#endif diff --git a/src/avi.h b/src/avi.h new file mode 100644 index 0000000..a1347fe --- /dev/null +++ b/src/avi.h @@ -0,0 +1,178 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - AVI player header file + * \file avi.h + * \author bombur + * \version 0.1 + * \date 07.03.2007 + * + * Based on AVILIB (C) 1999 Rainer Johanni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_AVI_H +#define SP_AVI_H + +#include "video.h" + +#ifdef VIDEO_INTERNAL + +#ifdef WIN32 +#pragma pack(1) +#endif + +typedef struct AviOldIndexEntry +{ + DWORD chunkid; + DWORD flags; + DWORD offset; + DWORD size; +} AviOldIndexEntry; + +typedef struct AviNewIndexEntry +{ + DWORD offset; + DWORD size; +} AviNewIndexEntry; + +typedef struct AviSuperIndexEntry +{ + LONGLONG qwOffset; // absolute file offset + DWORD dwSize; // size of index chunk at this offset + DWORD dwDuration; // time span in stream ticks +} AviSuperIndexEntry; + +typedef struct AviSuperIndex +{ + char fcc[4]; + DWORD dwSize; // size of this chunk + WORD wLongsPerEntry; // size of each entry in aIndex array (must be 8 for us) + BYTE bIndexSubType; // future use. must be 0 + BYTE bIndexType; // one of AVI_INDEX_* codes + DWORD nEntriesInUse; // index of first unused member in aIndex array + char dwChunkId[4]; // fcc of what is indexed + DWORD dwReserved[3]; // meaning differs for each index type/subtype. + AviSuperIndexEntry *idx; // where are the ix## chunks +} AviSuperIndex; + +typedef struct AviNewIndex +{ + char fcc[4]; // ’ix##’ + DWORD cb; + WORD wLongsPerEntry; // must be sizeof(aIndex[0])/sizeof(DWORD) + BYTE bIndexSubType; // must be 0 + BYTE bIndexType; // must be AVI_INDEX_OF_CHUNKS + DWORD nEntriesInUse; // + char dwChunkId[4]; // ’##dc’ or ’##db’ or ’##wb' etc.. + LONGLONG qwBaseOffset; // all dwOffsets in aIndex are relative to this + DWORD dwReserved3; // must be 0 +} AviNewIndex; + +typedef struct RIFF_BITMAPINFOHEADER +{ + DWORD bi_size; + DWORD bi_width; + DWORD bi_height; + WORD bi_planes; + WORD bi_bit_count; + DWORD bi_compression; + DWORD bi_size_image; + DWORD bi_x_pels_per_meter; + DWORD bi_y_pels_per_meter; + DWORD bi_clr_used; + DWORD bi_clr_important; +} RIFF_BITMAPINFOHEADER; + +#ifdef WIN32 +#pragma pack() +#endif + +enum AVI_FLAGS +{ + AVI_FLAG_HASINDEX = 0x00000010, // Index at end of file + AVI_FLAG_MUSTUSEINDEX = 0x00000020, + AVI_FLAG_ISINTERLEAVED = 0x00000100, + AVI_FLAG_TRUSTCKTYPE = 0x00000800, // Use CKType to find key frames + AVI_FLAG_WASCAPTUREFILE = 0x00010000, + AVI_FLAG_COPYRIGHTED = 0x00020000, +}; + +enum AVI_IDX1_FLAGS +{ + AVI_IDX1_FLAG_KEYFRAME = 0x00000010, + + AVI_IDX2_FLAG_KEYFRAME = 0x80000000, +}; + + +const int max_buf_idx_size[2] = { 32768 /* idx1 */, 32768/2 /* indx2.0 */ }; +const int index_block_size = 1024; + +/// AVI container player class +class VideoAvi : public Video +{ +public: + /// ctor + VideoAvi(); + + /// dtor + virtual ~VideoAvi(); + +public: + virtual BOOL Parse(); + virtual VIDEO_CHUNK_TYPE GetNext(BYTE *buf, int buflen, int *pos, int *left, int *len); + /// Returns 0 if found, -1 if failed, 1 for EOF. + virtual int GetNextIndexes(); + /// Find next key-frame in raw mode + virtual int GetNextKeyFrame(); + + RIFF_BITMAPINFOHEADER *bitmap_info_header; + + char video_tag1[4], video_tag2[4]; + int video_strn, avi_flags; + LONGLONG movi_start; + LONGLONG idx_start; + LONGLONG idx_offset; // base offset - must be added to idx offsets + int num_idx; + + union + { + AviOldIndexEntry *buf_idx; + AviNewIndexEntry *buf_newidx; + }; + int buf_idx_size; + + bool has_indx; + AviSuperIndex video_superindex; + int cur_indx_buf_idx, cur_indx_buf_pos, cur_buf_idx_size; + LONGLONG cur_indx_base_offset; + + int cur_old_buf_idx, cur_buf_video_idx; + +protected: + int AddIndexBlock(); + int AddIdx1Block(); + int AddIdx2Block(); + + void ResetRecoveryMode(); +}; + +#endif + +/////////////////////////////////////////////////////////////// + +#endif // of SP_AVI_H diff --git a/src/bitstream.cpp b/src/bitstream.cpp new file mode 100644 index 0000000..bc735ea --- /dev/null +++ b/src/bitstream.cpp @@ -0,0 +1,180 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Bitstream reader source file. + * \file bitstream.cpp + * \author bombur + * \version 0.1 + * \date 1.04.2007 + * + * Portions of code taken from libavcodec. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include + +#include + +WORD *dec_buf[MAX_BITSTREAM_BUFS], *dec_b[MAX_BITSTREAM_BUFS]; +int dec_len[MAX_BITSTREAM_BUFS] = { 0 }, dec_next_bitidx_shift[MAX_BITSTREAM_BUFS] = { 0 }; +bool dec_eof[MAX_BITSTREAM_BUFS] = { false }; + +static DWORD *enc_buf = NULL; +BOOL enc_eof = FALSE; +DWORD *enc_b = NULL; +int enc_maxlen = 0; + +bitstream_callback callback_func[MAX_BITSTREAM_BUFS] = { NULL }; + +void bitstream_set_callback(int N, bitstream_callback c) +{ + callback_func[N] = c; +} + +int bitstream_decode_buf_init(int N, BYTE *buf, int len, BOOL read_more) +{ + int bytes = (DWORD)buf & 1; + WORD *b = (WORD *)((DWORD)buf & (~1)); + dec_b[N] = dec_buf[N] = b; + + dec_next_bitidx_shift[N] = bytes * 8; + dec_len[N] = len + bytes; + dec_eof[N] = !read_more; + + return 0; +} + +int bitstream_decode_next(int N, int &dec_left) +{ + if (callback_func[N](BITSTREAM_MODE_INPUT, NULL, 0) < 0) + { + dec_eof[N] = true; + return -1; + } + dec_left = dec_len[N]; + return 0; +} + + +int bitstream_decode_eof(int N, DWORD &dec_v, int &dec_bitidx, int &dec_left) +{ + if (dec_eof[N]) + return -1; + register DWORD next_b; + + if (dec_left == 0) + { + if (bitstream_decode_next(N, dec_left) < 0) + return -1; + next_b = *dec_b[N]++; + + if (dec_next_bitidx_shift[N] == 0) + { + // v = cc dd XX YY + // b2 = 34 12 | 78 56 + dec_v |= BWSWAP(next_b) << (31 - 16 - dec_bitidx); + dec_bitidx += 16; + dec_left -= 2; + + } else // dec_next_bitidx_shift == 8 + { + // v = cc dd XX YY + // b2 = 12 cd | 56 34 + + if (dec_bitidx < 8) + { + dec_v |= (next_b >> 8) << (31 - 8 - dec_bitidx); + next_b = *dec_b[N]++; + dec_v |= BWSWAP(next_b) << (31 - 24 - dec_bitidx); + dec_bitidx += 24; + dec_left -= 4; + } + else // dec_bitidx >= 8 + { + dec_v |= (next_b >> 8) << (31 - 8 - dec_bitidx); + dec_bitidx += 8; + dec_left -= 2; + } + } + } else // dec_left == 1 + { + next_b = *dec_b[N]; + if (bitstream_decode_next(N, dec_left) < 0) + return -1; + + if (dec_next_bitidx_shift[N] == 0) + { + // v = cc dd XX YY + // b1 = cd 12 + // b2 = 56 34 | 9a 78 + + if (dec_bitidx < 8) + { + dec_v |= (next_b & 0xff) << (31 - 8 - dec_bitidx); + next_b = *dec_b[N]++; + dec_v |= BWSWAP(next_b) << (31 - 24 - dec_bitidx); + dec_bitidx += 24; + dec_left -= 2; + } + else // dec_bitidx >= 8 + { + dec_v |= (next_b & 0xff) << (31 - 8 - dec_bitidx); + dec_bitidx += 8; + } + } + else // dec_next_bitidx_shift == 8 + { + // v = cc dd XX YY + // b1 = cd 12 + // b2 = 34 cd | 78 56 + + dec_v |= (next_b & 0xff) << (31 - 8 - dec_bitidx); + next_b = *dec_b[N]++; + dec_v |= (next_b >> 8) << (31 - 16 - dec_bitidx); + dec_bitidx += 16; + dec_left -= 2; + } + } + return 0; +} + +//////////////////////////////////////////////////////////////////// + +int bitstream_encode_buf_init(BYTE *buf, int len) +{ + int bytes = (4 - ((DWORD)buf & 3)) & 3; + enc_b = enc_buf = (DWORD *)(((DWORD)buf + 3) & (~3)); + enc_maxlen = (len & (~3)) - 4 - bytes; + + if (enc_maxlen < 1) + return -1; + + enc_eof = false; + return 0; +} + + +int bitstream_flush_output_callback(BITSTREAM_MODE mode, int enc_len) +{ + // [0] ??? + if (callback_func[0](mode, (BYTE *)enc_buf, enc_len) < 0) + { + enc_eof = true; + return -1; + } + return 0; +} + diff --git a/src/bitstream.h b/src/bitstream.h new file mode 100644 index 0000000..85042d9 --- /dev/null +++ b/src/bitstream.h @@ -0,0 +1,217 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Bitstream reader header file + * \file bitstream.h + * \author bombur + * \version 0.1 + * \date 1.04.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_BITSTREAM_H +#define SP_BITSTREAM_H + +#define MAX_BITSTREAM_BUFS 5 + +#define INLINE SP_INLINE +#define STATIC static + +typedef enum +{ + BITSTREAM_MODE_DONE = 0, + BITSTREAM_MODE_INPUT = 1, + BITSTREAM_MODE_OUTPUT = 2, +} BITSTREAM_MODE; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*bitstream_callback)(BITSTREAM_MODE status, BYTE *outbuf, int outlen); + +void bitstream_set_callback(int N, bitstream_callback); + +int bitstream_decode_buf_init(int N, BYTE *buf, int len, BOOL read_more); +//int bitstream_decode_eof(int N, DWORD &dec_v, int &dec_bitidx, int &dec_left); + +int bitstream_encode_buf_init(BYTE *buf, int len); +int bitstream_flush_output_callback(BITSTREAM_MODE mode, int enc_len); + +///////////////////////////////////////////////////// + +extern WORD *dec_b[MAX_BITSTREAM_BUFS]; +extern int dec_len[MAX_BITSTREAM_BUFS], dec_next_bitidx_shift[MAX_BITSTREAM_BUFS]; +extern DWORD *enc_b; +extern int enc_maxlen; +extern BOOL enc_eof; + +#ifdef __cplusplus +} +#endif + +#define bitstream_show_bits(ret, dec_v, dec_bitidx, n) \ +{\ + ret = dec_v >> (32 - n);\ +} + +#define bitstream_skip_bits(N, dec_v, dec_bitidx, dec_left, n) \ +{ \ + dec_bitidx -= (n); \ + dec_v <<= (n); \ + if (dec_bitidx < 16) \ + { \ + register DWORD next_b = *dec_b[N]++; \ + dec_v |= BWSWAP(next_b) << (31 - 16 - dec_bitidx); \ + dec_bitidx += 16; \ + dec_left -= 2; \ + } \ +} + +#define bitstream_get_bits(ret, N, dec_v, dec_bitidx, dec_left, n) \ +{ \ + bitstream_show_bits(ret, dec_v, dec_bitidx, n); \ + bitstream_skip_bits(N, dec_v, dec_bitidx, dec_left, n); \ +} + +#define bitstream_decode_start(N, dec_v, dec_bitidx, dec_bitleft) \ +{ \ + register DWORD v2; \ + dec_v = *dec_b[N]++; \ + v2 = *dec_b[N]++; \ + dec_v = (BWSWAP(dec_v) << 16) | BWSWAP(v2); \ + dec_bitidx = 31 - dec_next_bitidx_shift[N]; \ + dec_v <<= dec_next_bitidx_shift[N]; \ + dec_bitleft = dec_len[N] - 4; \ +} + +#define bitstream_get_bits1(ret, N, dec_v, dec_bitidx, dec_left) \ +{ \ + bitstream_show_bits(ret, dec_v, dec_bitidx, 1); \ + bitstream_skip_bits(N, dec_v, dec_bitidx, dec_left, 1); \ +} + +#define bitstream_get_bits012(ret, N, dec_v, dec_bitidx, dec_left) \ +{ \ + const DWORD rets[4] = { /*00b*/0, /*01b*/0, /*10b*/1, /*11b*/2 }; \ + const DWORD skips[4] = { 1, 1, 2, 2 }; \ + bitstream_show_bits(ret, dec_v, dec_bitidx, 2); \ + bitstream_skip_bits(N, dec_v, dec_bitidx, dec_left, skips[ret]); \ + ret = rets[ret]; \ +} + +///////////////////////////////////////////////////////////////////////// +#define bitstream_flush_output(mode, enc_v, enc_bitidx, enc_len) \ +{ \ + DWORD enc_tmp = enc_v; \ + register int shift; \ + if (!enc_eof) \ + { \ + BSWAP(enc_tmp); \ + *enc_b++ = enc_tmp; \ + for (shift = 24; enc_bitidx < 31; shift -= 8, enc_bitidx += 8) \ + { \ + enc_len++; \ + } \ + } \ + \ + if (bitstream_flush_output_callback(mode, enc_len) < 0) \ + { \ + enc_bitidx -= 32; \ + enc_len -= 4; \ + return -1; \ + } \ +} + +#define bitstream_encode_next(enc_v, enc_bitidx, enc_len) \ +{ \ + enc_bitidx += 32; \ + enc_len += 4; \ + if (enc_len >= enc_maxlen) \ + { \ + bitstream_flush_output(BITSTREAM_MODE_OUTPUT, enc_v, enc_bitidx, enc_len); \ + enc_len = 0; \ + enc_v = 0; \ + enc_bitidx = 31; \ + } \ + else \ + { \ + BSWAP(enc_v); \ + *enc_b++ = enc_v; \ + enc_v = 0; \ + } \ +} + +#if 1 +#define bitstream_put_bits(n, data, enc_v, enc_bitidx, enc_len) \ +{ \ + register int shift = enc_bitidx + 1 - (n); \ + if (shift >= 0) \ + { \ + enc_v |= (data) << shift; \ + enc_bitidx -= (n); \ + if (enc_bitidx < 0) \ + bitstream_encode_next(enc_v, enc_bitidx, enc_len); \ + } else \ + { \ + shift = -shift; \ + enc_v |= (data) >> shift; \ + enc_bitidx -= (n) - shift; \ + if (enc_bitidx < 0) \ + bitstream_encode_next(enc_v, enc_bitidx, enc_len); \ + enc_v |= (data) << (32 - shift); \ + enc_bitidx -= shift; \ + if (enc_bitidx < 0) \ + bitstream_encode_next(enc_v, enc_bitidx, enc_len); \ + } \ +} +#else +int FORCEINLINE bitstream_put_bits(int n, DWORD data, DWORD &enc_v, int &enc_bitidx, int &enc_len) +{ + register int shift = enc_bitidx + 1 - (n); + if (shift >= 0) + { + enc_v |= (data) << shift; + enc_bitidx -= (n); + if (enc_bitidx < 0) + { + if (bitstream_encode_next(enc_v, enc_bitidx, enc_len) < 0) + return -1; + } + } else + { + shift = -shift; + enc_v |= (data) >> shift; + enc_bitidx -= (n) - shift; + if (enc_bitidx < 0) + { + if (bitstream_encode_next(enc_v, enc_bitidx, enc_len) < 0) + return -1; + } + enc_v |= (data) << (32 - shift); + enc_bitidx -= shift; + if (enc_bitidx < 0) + { + if (bitstream_encode_next(enc_v, enc_bitidx, enc_len) < 0) + return -1; + } + } + return 0; +} +#endif + + +#endif // of SP_BITSTREAM_H diff --git a/src/cdda.cpp b/src/cdda.cpp new file mode 100644 index 0000000..2c150c3 --- /dev/null +++ b/src/cdda.cpp @@ -0,0 +1,553 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CDDA (CD-Audio) player impl. + * \file cdda.cpp + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +#include "script.h" + +#include "cdda.h" +#include "media.h" + + +extern int cdrom_handle; + + +static Cdda *cdda = NULL; + +static bool cdda_msg = true; +#define MSG if (cdda_msg) msg + + +bool cdda_read_track(CddaTrack *track, int i) +{ + struct cdrom_tocentry e; + memset(&e, 0, sizeof(struct cdrom_tocentry)); + e.cdte_track = (BYTE)i; + e.cdte_format = CDROM_MSF; + if (ioctl(cdrom_handle, CDROMREADTOCENTRY, &e) >= 0) + { + if ((e.cdte_ctrl & CDROM_DATA_TRACK) == 0) + { + if (track != NULL) + { + track->idx = i; + track->frame_idx = e.cdte_addr.msf.minute * CD_SECS * CD_FRAMES + + e.cdte_addr.msf.second * CD_FRAMES + e.cdte_addr.msf.frame; + } + return true; + } + } + return false; +} + +Cdda *cdda_open() +{ + int i; + if (cdda != NULL) + return cdda; + +#ifdef WIN32 + // only for real device! + if (cdrom_handle == 2) + { + MCI_OPEN_PARMS mciOpen; + MCI_STATUS_PARMS mciParams; + MCI_SET_PARMS mciSet; + mciOpen.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO; + mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD)&mciOpen); + + mciSet.dwTimeFormat = MCI_FORMAT_MSF; + mciSendCommand(mciOpen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)&mciSet); + + mciParams.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)&mciParams); + int numtr = mciParams.dwReturn; + + cdda = new Cdda(); + cdda->tracks.Reserve(numtr); + + for (i = 0; i < numtr; i++) + { + mciParams.dwItem = MCI_CDA_STATUS_TYPE_TRACK; + mciParams.dwTrack = i + 1; + mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&mciParams); + if (mciParams.dwReturn == MCI_CDA_TRACK_AUDIO) + { + CddaTrack track; + mciParams.dwItem = MCI_STATUS_LENGTH; + mciParams.dwTrack = i + 1; + mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&mciParams); + + track.length = MCI_MSF_MINUTE(mciParams.dwReturn) * CD_SECS * CD_FRAMES + + MCI_MSF_SECOND(mciParams.dwReturn) * CD_FRAMES + + MCI_MSF_FRAME(mciParams.dwReturn); + + mciParams.dwItem = MCI_STATUS_POSITION; + mciParams.dwTrack = i + 1; + mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&mciParams); + + track.frame_idx = MCI_MSF_MINUTE(mciParams.dwReturn) * CD_SECS * CD_FRAMES + + MCI_MSF_SECOND(mciParams.dwReturn) * CD_FRAMES + + MCI_MSF_FRAME(mciParams.dwReturn); + + cdda->tracks.Add(track); + } + } + mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, 0, 0); + return cdda; + } else + { + return NULL; + } +#else + + if (cdrom_handle < 0) + { + msg_error("CDDA: Cannot find opened CD-ROM handle.\n"); + return NULL; + } + + struct cdrom_tochdr toc; + if (ioctl(cdrom_handle, CDROMREADTOCHDR, &toc) < 0) + { + return NULL; + } + + cdda = new Cdda(); + cdda->track1 = toc.cdth_trk0; + cdda->track2 = toc.cdth_trk1; + + cdda->tracks.Reserve(cdda->track2 - cdda->track1 + 1); + int track_idx = 0; + cdda->total_length = 0; + for (i = cdda->track1; i <= cdda->track2; i++) + { + CddaTrack track; + if (cdda_read_track(&track, i)) + { + track_idx = cdda->tracks.Add(track); + if (track_idx > 0) + cdda->tracks[track_idx - 1].length = track.frame_idx - cdda->total_length; + cdda->total_length = track.frame_idx; + } + } + CddaTrack track_leadout; + if (cdda_read_track(&track_leadout, CDROM_LEADOUT)) + { + cdda->tracks[track_idx].length = track_leadout.frame_idx - cdda->total_length; + cdda->total_length = track_leadout.frame_idx; + } + + return cdda; +#endif +} + +BOOL cdda_close() +{ + cdda_stop(); + SPSafeDelete(cdda); + return TRUE; +} + +int cdda_play(char *path) +{ + if (cdrom_handle < 0) + return -1; + if (path == NULL) + { + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + mpeg_setspeed(MPEG_SPEED_NORMAL); + + return 0; + } + + if (strncasecmp(path, "/cdrom/", 7) != 0) + return -1; + + int ret = media_open(path, MEDIA_TYPE_CDDA); + if (ret < 0 || cdda == NULL) + { + msg_error("CDDA: media open FAILED.\n"); + return ret; + } + MSG("CDDA: start...\n"); + + if (strlen(path) > 7) + { + cdda->cur_trackid = atoi(path + 7) - 1; + } else + cdda->cur_trackid = 0; + if (cdda->cur_trackid < 0 || cdda->cur_trackid >= cdda->tracks.GetN()) + return -1; + cdda->cur = cdda->tracks[cdda->cur_trackid].frame_idx; + MSG("CDDA: * Play Track = %d (pos = %d).\n", cdda->cur_trackid+1, cdda->cur); + + cdda->feof = false; + + mpeg_init(MPEG_1, TRUE, FALSE, FALSE); + mpeg_setbuffer(MPEG_BUFFER_1, BUF_BASE, 8, 30576); + + MSG("CDDA: Setting default audio params.\n"); + MpegAudioPacketInfo defaudioparams; + defaudioparams.type = eAudioFormat_PCM; + defaudioparams.samplerate = 44100; + defaudioparams.numberofbitspersample = 16; + defaudioparams.numberofchannels = 2; + defaudioparams.fromstream = 0; + mpeg_setaudioparams(&defaudioparams); + + // write dvd-specific FIP stuff... + fip_write_special(FIP_SPECIAL_CD, 1); + const char *digits = " 00000"; + fip_write_string(digits); + fip_write_special(FIP_SPECIAL_COLON1, 1); + fip_write_special(FIP_SPECIAL_COLON2, 1); + + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + + script_audio_info_callback(""); + script_video_info_callback(""); + + cdda->playing = true; + mpeg_start(); + + return 0; +} + +int cdda_get_length(char *path) +{ + if (path == NULL) + return 0; + if (strncasecmp(path, "/cdrom/", 7) != 0) + return 0; + if (cdda_open() == NULL) + return 0; + int trackid = atoi(path + 7) - 1; + if (trackid < 0 || trackid >= cdda->tracks.GetN()) + return 0; + return cdda->tracks[trackid].length / CD_FRAMES; +} + +int cdda_get_numtracks() +{ + if (cdda_open() == NULL) + return 0; + return cdda->tracks.GetN(); +} + +BOOL cdda_feof() +{ + if (cdda == NULL || cdda->feof) + return TRUE; + return FALSE; +} + +int cdda_read(BYTE *buf, int numblocks) +{ + if (cdrom_handle < 0 || cdda == NULL) + { + return 0; + } + if (cdda->feof) + { + return 0; + } + if (cdda->cur < 0 || cdda->cur_trackid < 0) + { + return 0; + } + + int maxbl = cdda->tracks[cdda->cur_trackid].frame_idx + cdda->tracks[cdda->cur_trackid].length - 1; + + //MSG("CDDA: %5d / %5d [%d]\n", cdda->cur, maxbl, cdda->feof); + + if (cdda->cur + numblocks > maxbl) + { + numblocks = maxbl - cdda->cur; + cdda->feof = true; + } + if (numblocks < 1) + return 0; + cdrom_read_audio rda; + rda.addr.msf.minute = (BYTE)(cdda->cur / CD_FRAMES / CD_SECS); + rda.addr.msf.second = (BYTE)((cdda->cur / CD_FRAMES) % CD_SECS); + rda.addr.msf.frame = (BYTE)(cdda->cur % CD_FRAMES); + rda.addr_format = CDROM_MSF; + rda.nframes = numblocks; + rda.buf = buf; + + if (ioctl(cdrom_handle, CDROMREADAUDIO, &rda) < 0) + return 0; + + // LPCM requires big-endian byte order + mpeg_PCM_to_LPCM(buf, numblocks * MPEG_PACKET_LENGTH); + cdda->cur += numblocks; + return numblocks; +} + +void cdda_update_info() +{ + if (cdda == NULL) + return; + static int old_secs = 0; + KHWL_TIME_TYPE displ; + displ.pts = 0; + displ.timeres = 90000; + if (mpeg_is_displayed()) + khwl_getproperty(KHWL_TIME_SET, etimSystemTimeClock, sizeof(displ), &displ); +// displ.pts -= pts_base; + + if (cdda->old_trackid != cdda->cur_trackid || (LONGLONG)displ.pts != cdda->saved_pts) + { + if (cdda->cur_trackid >= 0 && (LONGLONG)displ.pts >= 0) + { + if (cdda->cur_trackid != cdda->old_trackid) + { + script_totaltime_callback(cdda->tracks[cdda->cur_trackid].length / CD_FRAMES); + + script_cdda_track_callback(cdda->cur_trackid + 1); + + old_secs = -1; + } + + cdda->old_trackid = cdda->cur_trackid; + cdda->saved_pts = displ.pts; + + char fip_out[10]; + int secs = (int)(displ.pts / 90000); + int ccid = cdda->cur_trackid + 1; + if (ccid < 0) + ccid = 0; + if (ccid > 99) + ccid = 99; + if (secs < 0) + secs = 0; + if (secs >= 10*3600) + secs = 10*3600-1; + if (secs != old_secs) + { + script_time_callback(secs); + + fip_out[0] = (char)((ccid / 10) + '0'); + fip_out[1] = (char)((ccid % 10) + '0'); + fip_out[2] = (char)((secs/3600) + '0'); + int secs3600 = secs%3600; + fip_out[3] = (char)(((secs3600/60)/10) + '0'); + fip_out[4] = (char)(((secs3600/60)%10) + '0'); + fip_out[5] = (char)(((secs3600%60)/10) + '0'); + fip_out[6] = (char)(((secs3600%60)%10) + '0'); + fip_out[7] = '\0'; + fip_write_string(fip_out); + + old_secs = secs; + } + } + } +} + + +int cdda_player_loop() +{ + static int info_cnt = 0; + if (cdrom_handle < 0 || cdda == NULL || cdda->cur < 0) + return 1; + + BYTE *buf = NULL; + + MEDIA_EVENT event = MEDIA_EVENT_OK; + int len = 0; + + int ret = media_get_next_block(&buf, &event, &len); + if (ret > 0 && buf == NULL) + { + msg_error("CDDA: Not initialized. STOP!\n"); + return 1; + } + if (ret == -1) + { + msg_error("CDDA: Error getting next block!\n"); + return 1; + } + else if (ret == 0) // wait... + { + return 0; + } + + if (event == MEDIA_EVENT_STOP) + { + MSG("CDDA: STOP Event triggered!\n"); + return 1; + } + BYTE *base = buf; + + MpegPacket *packet = NULL; + packet = mpeg_feed_getlast(); + if (packet == NULL) // well, it won't really help + return 0; + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + + packet->pts = 0;//pts_base; + packet->nframeheaders = 0xffff; + packet->firstaccessunitpointer = 0; + packet->type = 1; + packet->pData = base; + packet->size = MPEG_PACKET_LENGTH; + + // increase bufidx + mpeg_setbufidx(MPEG_BUFFER_1, packet); + + mpeg_feed(MPEG_FEED_AUDIO); + + if (info_cnt++ > 32) + { + info_cnt = 0; + cdda_update_info(); + } + + return 0; +} + +BOOL cdda_pause() +{ + fip_write_special(FIP_SPECIAL_PLAY, 0); + fip_write_special(FIP_SPECIAL_PAUSE, 1); + + mpeg_setspeed(MPEG_SPEED_PAUSE); + + return TRUE; +} + +BOOL cdda_stop() +{ + if (cdda != NULL) + { + if (cdda->playing) + { + mpeg_deinit(); + cdda->playing = false; + } + } + return TRUE; +} + +void cdda_setdebug(BOOL ison) +{ + cdda_msg = ison == TRUE; +} + +BOOL cdda_getdebug() +{ + return cdda_msg; +} + +BOOL cdda_seek(int seconds, int from_frame) +{ + if (cdda != NULL) + { + if (cdda->cur_trackid >= 0 && cdda->cur_trackid < cdda->tracks.GetN()) + { + // start of the current track + if (from_frame < 0) + from_frame = cdda->tracks[cdda->cur_trackid].frame_idx; + + khwl_stop(); + + cdda->cur = from_frame; + cdda->cur += seconds * CD_FRAMES; + int offs = cdda->cur - cdda->tracks[cdda->cur_trackid].frame_idx; + if (offs < 0) + { + cdda->cur = cdda->tracks[cdda->cur_trackid].frame_idx; + offs = 0; + } + if (offs >= cdda->tracks[cdda->cur_trackid].length) + cdda->cur = cdda->tracks[cdda->cur_trackid].frame_idx + cdda->tracks[cdda->cur_trackid].length - 1; + + mpeg_start(); + mpeg_setpts(offs * 90000 / CD_FRAMES); + + return TRUE; + } + } + script_error_callback(SCRIPT_ERROR_INVALID); + return FALSE; +} + +BOOL cdda_seek_track(int track) +{ + int trck = track - 1; + if (cdda == NULL || trck < 0 || trck >= cdda->tracks.GetN()) + { + script_error_callback(SCRIPT_ERROR_INVALID); + return FALSE; + } + khwl_stop(); + cdda->cur_trackid = trck; + cdda->cur = cdda->tracks[trck].frame_idx; + MSG("CDDA: * Playpos = %d.\n", cdda->cur); + + mpeg_start(); + mpeg_setpts(0); + return TRUE; +} + +void cdda_get_cur(int *track) +{ + if (track != NULL && cdda != NULL) + { + *track = cdda->cur_trackid + 1; + } + +} + +void cdda_forward() +{ + if (cdda != NULL) + cdda_seek(20, cdda->cur); +} + +void cdda_rewind() +{ + if (cdda != NULL) + cdda_seek(-20, cdda->cur); +} diff --git a/src/cdda.h b/src/cdda.h new file mode 100644 index 0000000..4e6da3c --- /dev/null +++ b/src/cdda.h @@ -0,0 +1,131 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CDDA (CD-Audio) player header file + * \file cdda.h + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_CDDA_H +#define SP_CDDA_H + +class CddaTrack +{ +public: + /// ctor + CddaTrack() + { + idx = -1; + frame_idx = -1; + length = -1; + } + + int idx; + int frame_idx; + + int length; // in frames +}; + + +class Cdda +{ +public: + /// ctor + Cdda() + { + cur = -1; + track1 = -1; + track2 = -1; + total_length = -1; + + cur_trackid = -1; + old_trackid = -1; + saved_pts = -1; + + feof = false; + playing = false; + } + // current frame + int cur; + + int cur_trackid, old_trackid; + LONGLONG saved_pts; + + // first and last + int track1, track2; + + SPClassicList tracks; + int total_length; // in frames + + bool feof; + bool playing; +}; + + +//////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + +#include + + +Cdda *cdda_open(); +BOOL cdda_close(); + +/// Play CD-Audio disc or track +int cdda_play(char *path); + +/// Get number of tracks +int cdda_get_numtracks(); +/// Get track length, in seconds +int cdda_get_length(char *path); + +/// Advance playing +int cdda_player_loop(); + +/// Pause playing +BOOL cdda_pause(); + +/// Stop playing +BOOL cdda_stop(); + +/// Returns TRUE if track ended. +BOOL cdda_feof(); + +void cdda_setdebug(BOOL ison); +BOOL cdda_getdebug(); + +/// Seek to given time and play +BOOL cdda_seek(int seconds, int from_frame = -1); +BOOL cdda_seek_track(int track); + +void cdda_get_cur(int *track); + +void cdda_forward(); +void cdda_rewind(); + +/// Read CDDA data (used by media) +int cdda_read(BYTE *buf, int numblocks); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_CDDA_H diff --git a/src/contrib/libdvdcss b/src/contrib/libdvdcss new file mode 160000 index 0000000..84a7ba8 --- /dev/null +++ b/src/contrib/libdvdcss @@ -0,0 +1 @@ +Subproject commit 84a7ba82a31f4ac73d93de108ee8eaa2d250cf5e diff --git a/src/contrib/libdvdnav b/src/contrib/libdvdnav new file mode 160000 index 0000000..fca2c93 --- /dev/null +++ b/src/contrib/libdvdnav @@ -0,0 +1 @@ +Subproject commit fca2c93a76c51c175206c64681fb607fba91b8e1 diff --git a/src/contrib/libid3tag b/src/contrib/libid3tag new file mode 160000 index 0000000..0637016 --- /dev/null +++ b/src/contrib/libid3tag @@ -0,0 +1 @@ +Subproject commit 06370167ae94fecaf09e9535dbcc6da421780ff0 diff --git a/src/contrib/libjpeg b/src/contrib/libjpeg new file mode 160000 index 0000000..9e0cea2 --- /dev/null +++ b/src/contrib/libjpeg @@ -0,0 +1 @@ +Subproject commit 9e0cea29d7ba7a2c1e763865391bc94b336da25e diff --git a/src/contrib/libmad b/src/contrib/libmad new file mode 160000 index 0000000..c2f96fa --- /dev/null +++ b/src/contrib/libmad @@ -0,0 +1 @@ +Subproject commit c2f96fa4166446ac99449bdf6905f4218fb7d6b5 diff --git a/src/contrib/longjmp.S b/src/contrib/longjmp.S new file mode 100644 index 0000000..497b571 --- /dev/null +++ b/src/contrib/longjmp.S @@ -0,0 +1,44 @@ +/* longjmp for ARM. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#define _SETJMP_H +#define _ASM +#include + +/* [bombur]: */ +#define __UCLIBC_HAS_SOFT_FLOAT__ + +.globl __longjmp; +.type __longjmp,%function +.align 4; +__longjmp: + mov ip, r0 /* save jmp_buf pointer */ + + movs r0, r1 /* get the return value in place */ + moveq r0, #1 /* can't let setjmp() return zero! */ + +#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__ + lfmfd f4, 4, [ip] ! /* load the floating point regs */ +#else + add ip, ip, #48 /* skip the FP registers */ +#endif + + ldmia ip , {v1-v6, sl, fp, sp, pc} +.size __longjmp,.-__longjmp; diff --git a/src/contrib/memcpy.S b/src/contrib/memcpy.S new file mode 100644 index 0000000..87342f2 --- /dev/null +++ b/src/contrib/memcpy.S @@ -0,0 +1,318 @@ +/* + * linux/arch/arm/lib/memcpy.S + * + * Copyright (C) 1995-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include +#include + + .text + +#define ENTER \ + mov ip,sp ;\ + stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ + sub fp,ip,#4 + +#define EXIT \ + LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) + +#define EXITEQ \ + LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) + +/* + * Prototype: void memcpy(void *to,const void *from,unsigned long n); + * ARM3: cant use memcopy here!!! + */ +ENTRY(memcpy) +ENTRY(memmove) + ENTER + cmp r1, r0 + bcc 19f + subs r2, r2, #4 + blt 6f + ands ip, r0, #3 + bne 7f + ands ip, r1, #3 + bne 8f + +1: subs r2, r2, #8 + blt 5f + subs r2, r2, #0x14 + blt 3f +2: ldmia r1!,{r3 - r9, ip} + stmia r0!,{r3 - r9, ip} + subs r2, r2, #32 + bge 2b + cmn r2, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} + subge r2, r2, #0x10 +3: adds r2, r2, #0x14 +4: ldmgeia r1!, {r3 - r5} + stmgeia r0!, {r3 - r5} + subges r2, r2, #12 + bge 4b +5: adds r2, r2, #8 + blt 6f + subs r2, r2, #4 + ldrlt r3, [r1], #4 + ldmgeia r1!, {r4, r5} + strlt r3, [r0], #4 + stmgeia r0!, {r4, r5} + subge r2, r2, #4 + +6: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1], #1 + ldrgeb r4, [r1], #1 + ldrgtb r5, [r1], #1 + strb r3, [r0], #1 + strgeb r4, [r0], #1 + strgtb r5, [r0], #1 + EXIT + +7: rsb ip, ip, #4 + cmp ip, #2 + ldrb r3, [r1], #1 + ldrgeb r4, [r1], #1 + ldrgtb r5, [r1], #1 + strb r3, [r0], #1 + strgeb r4, [r0], #1 + strgtb r5, [r0], #1 + subs r2, r2, ip + blt 6b + ands ip, r1, #3 + beq 1b + +8: bic r1, r1, #3 + ldr r7, [r1], #4 + cmp ip, #2 + bgt 15f + beq 11f + cmp r2, #12 + blt 10f + sub r2, r2, #12 +9: mov r3, r7, lsr #8 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 9b + adds r2, r2, #12 + blt 100f +10: mov r3, r7, lsr #8 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, lsl #24 + str r3, [r0], #4 + bge 10b +100: sub r1, r1, #3 + b 6b + +11: cmp r2, #12 + blt 13f /* */ + sub r2, r2, #12 +12: mov r3, r7, lsr #16 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7,LSL#16 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 12b + adds r2, r2, #12 + blt 14f +13: mov r3, r7, lsr #16 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, lsl #16 + str r3, [r0], #4 + bge 13b +14: sub r1, r1, #2 + b 6b + +15: cmp r2, #12 + blt 17f + sub r2, r2, #12 +16: mov r3, r7, lsr #24 + ldmia r1!,{r4 - r7} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 16b + adds r2, r2, #12 + blt 18f +17: mov r3, r7, lsr #24 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, lsl#8 + str r3, [r0], #4 + bge 17b +18: sub r1, r1, #1 + b 6b + + +19: add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 24f + ands ip, r0, #3 + bne 25f + ands ip, r1, #3 + bne 26f + +20: subs r2, r2, #8 + blt 23f + subs r2, r2, #0x14 + blt 22f +21: ldmdb r1!, {r3 - r9, ip} + stmdb r0!, {r3 - r9, ip} + subs r2, r2, #32 + bge 21b +22: cmn r2, #16 + ldmgedb r1!, {r3 - r6} + stmgedb r0!, {r3 - r6} + subge r2, r2, #16 + adds r2, r2, #20 + ldmgedb r1!, {r3 - r5} + stmgedb r0!, {r3 - r5} + subge r2, r2, #12 +23: adds r2, r2, #8 + blt 24f + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + ldmgedb r1!, {r4, r5} + strlt r3, [r0, #-4]! + stmgedb r0!, {r4, r5} + subge r2, r2, #4 + +24: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1, #-1]! + ldrgeb r4, [r1, #-1]! + ldrgtb r5, [r1, #-1]! + strb r3, [r0, #-1]! + strgeb r4, [r0, #-1]! + strgtb r5, [r0, #-1]! + EXIT + +25: cmp ip, #2 + ldrb r3, [r1, #-1]! + ldrgeb r4, [r1, #-1]! + ldrgtb r5, [r1, #-1]! + strb r3, [r0, #-1]! + strgeb r4, [r0, #-1]! + strgtb r5, [r0, #-1]! + subs r2, r2, ip + blt 24b + ands ip, r1, #3 + beq 20b + +26: bic r1, r1, #3 + ldr r3, [r1], #0 + cmp ip, #2 + blt 34f + beq 30f + cmp r2, #12 + blt 28f + sub r2, r2, #12 +27: mov r7, r3, lsl #8 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #24 + mov r6, r6, lsl #8 + orr r6, r6, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r4, lsr #24 + mov r4, r4, lsl #8 + orr r4, r4, r3, lsr #24 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 27b + adds r2, r2, #12 + blt 29f +28: mov ip, r3, lsl #8 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, lsr #24 + str ip, [r0, #-4]! + bge 28b +29: add r1, r1, #3 + b 24b + +30: cmp r2, #12 + blt 32f + sub r2, r2, #12 +31: mov r7, r3, lsl #16 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #16 + mov r6, r6, lsl #16 + orr r6, r6, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r4, lsr #16 + mov r4, r4, lsl #16 + orr r4, r4, r3, lsr #16 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 31b + adds r2, r2, #12 + blt 33f +32: mov ip, r3, lsl #16 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, lsr #16 + str ip, [r0, #-4]! + bge 32b +33: add r1, r1, #2 + b 24b + +34: cmp r2, #12 + blt 36f + sub r2, r2, #12 +35: mov r7, r3, lsl #24 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #8 + mov r6, r6, lsl #24 + orr r6, r6, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r4, lsr #8 + mov r4, r4, lsl #24 + orr r4, r4, r3, lsr #8 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 35b + adds r2, r2, #12 + blt 37f +36: mov ip, r3, lsl #24 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, lsr #8 + str ip, [r0, #-4]! + bge 36b +37: add r1, r1, #1 + b 24b + + .align diff --git a/src/contrib/memset.S b/src/contrib/memset.S new file mode 100644 index 0000000..a1795f5 --- /dev/null +++ b/src/contrib/memset.S @@ -0,0 +1,80 @@ +/* + * linux/arch/arm/lib/memset.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include +#include + + .text + .align 5 + .word 0 + +1: subs r2, r2, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r1, [r0], #1 @ 1 + strleb r1, [r0], #1 @ 1 + strb r1, [r0], #1 @ 1 + add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * memzero again. + */ + +ENTRY(memset) + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * we know that the pointer in r0 is aligned to a word boundary. + */ + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + mov r3, r1 + cmp r2, #16 + blt 4f +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! + mov ip, r1 + mov lr, r1 + +2: subs r2, r2, #64 + stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time. + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + bgt 2b + LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go. +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r2, #32 + stmneia r0!, {r1, r3, ip, lr} + stmneia r0!, {r1, r3, ip, lr} + tst r2, #16 + stmneia r0!, {r1, r3, ip, lr} + ldr lr, [sp], #4 + +4: tst r2, #8 + stmneia r0!, {r1, r3} + tst r2, #4 + strne r1, [r0], #4 +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r2, #2 + strneb r1, [r0], #1 + strneb r1, [r0], #1 + tst r2, #1 + strneb r1, [r0], #1 + RETINSTR(mov,pc,lr) diff --git a/src/contrib/setjmp.S b/src/contrib/setjmp.S new file mode 100644 index 0000000..fb99710 --- /dev/null +++ b/src/contrib/setjmp.S @@ -0,0 +1,47 @@ +/* setjmp for ARM. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#define _SETJMP_H +#define _ASM +#include + +/* [bombur]: */ +#ifndef __UCLIBC_HAS_SOFT_FLOAT__ +#define __UCLIBC_HAS_SOFT_FLOAT__ +#endif + +.globl __sigsetjmp; +.type __sigsetjmp,%function +.align 4; +__sigsetjmp: + /* Save registers */ +#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__ + sfmea f4, 4, [r0]! +#else + add r0, r0, #48 /* skip the FP registers */ +#endif + stmia r0, {v1-v6, sl, fp, sp, lr} + + /* Restore pointer to jmp_buf */ + sub r0, r0, #48 + + /* Make a tail call to __sigjmp_save; it takes the same args. */ + B __sigjmp_save (PLT) +.size __sigsetjmp,.-__sigsetjmp; diff --git a/src/contrib/strcmp.S b/src/contrib/strcmp.S new file mode 100644 index 0000000..b2f26d6 --- /dev/null +++ b/src/contrib/strcmp.S @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002 ARM Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Adapted for uClibc from NetBSD strcmp.S, version 1.3 2003/04/05 + * by Erik Andersen + */ + + .text + .global strcmp; + .type strcmp,%function + .align 4; \ + +strcmp: +1: + ldrb r2, [r0], #1 + ldrb r3, [r1], #1 + cmp r2, #1 + cmpcs r2, r3 + beq 1b + sub r0, r2, r3 + mov pc, lr + +.weak strcoll; + strcoll = strcmp + diff --git a/src/contrib/strlen.S b/src/contrib/strlen.S new file mode 100644 index 0000000..65ee94d --- /dev/null +++ b/src/contrib/strlen.S @@ -0,0 +1,80 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Code contributed by Matthew Wilcox + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +/* size_t strlen(const char *S) + * entry: r0 -> string + * exit: r0 = len + */ + + .text + .global strlen; + .type strlen,%function + .align 4; \ + +strlen: + bic r1, r0, $3 @ addr of word containing first byte + ldr r2, [r1], $4 @ get the first word + ands r3, r0, $3 @ how many bytes are duff? + rsb r0, r3, $0 @ get - that number into counter. + beq Laligned @ skip into main check routine if no + @ more +#if __BYTE_ORDER == __BIG_ENDIAN + orr r2, r2, $0xff000000 @ set this byte to non-zero + subs r3, r3, $1 @ any more to do? + orrgt r2, r2, $0x00ff0000 @ if so, set this byte + subs r3, r3, $1 @ more? + orrgt r2, r2, $0x0000ff00 @ then set. +#else + orr r2, r2, $0x000000ff @ set this byte to non-zero + subs r3, r3, $1 @ any more to do? + orrgt r2, r2, $0x0000ff00 @ if so, set this byte + subs r3, r3, $1 @ more? + orrgt r2, r2, $0x00ff0000 @ then set. +#endif +Laligned: @ here, we have a word in r2. Does it + tst r2, $0x000000ff @ contain any zeroes? + tstne r2, $0x0000ff00 @ + tstne r2, $0x00ff0000 @ + tstne r2, $0xff000000 @ + addne r0, r0, $4 @ if not, the string is 4 bytes longer + ldrne r2, [r1], $4 @ and we continue to the next word + bne Laligned @ +Llastword: @ drop through to here once we find a +#if __BYTE_ORDER == __BIG_ENDIAN + tst r2, $0xff000000 @ word that has a zero byte in it + addne r0, r0, $1 @ + tstne r2, $0x00ff0000 @ and add up to 3 bytes on to it + addne r0, r0, $1 @ + tstne r2, $0x0000ff00 @ (if first three all non-zero, 4th + addne r0, r0, $1 @ must be zero) +#else + tst r2, $0x000000ff @ + addne r0, r0, $1 @ + tstne r2, $0x0000ff00 @ and add up to 3 bytes on to it + addne r0, r0, $1 @ + tstne r2, $0x00ff0000 @ (if first three all non-zero, 4th + addne r0, r0, $1 @ must be zero) +#endif + mov pc,lr + +.size strlen,.-strlen; + diff --git a/src/divx-tables.h b/src/divx-tables.h new file mode 100644 index 0000000..8410b04 --- /dev/null +++ b/src/divx-tables.h @@ -0,0 +1,2072 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DivX3/MPEG-4 tables header file + * \file divx-tables.h + * \author bombur + * \version 0.1 + * \date 1.04.2007 + * + * Portions of code taken from libavcodec. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_DIVX_TABLES_H +#define SP_DIVX_TABLES_H + +static const WORD table0_vlc[133][2] = +{ + { 0x1, 2 }, { 0x6, 3 }, { 0xf, 4 }, { 0x16, 5 }, + { 0x20, 6 }, { 0x18, 7 }, { 0x8, 8 }, { 0x9a, 8 }, + { 0x56, 9 }, { 0x13e, 9 }, { 0xf0, 10 }, { 0x3a5, 10 }, + { 0x77, 11 }, { 0x1ef, 11 }, { 0x9a, 12 }, { 0x5d, 13 }, + { 0x1, 4 }, { 0x11, 5 }, { 0x2, 7 }, { 0xb, 8 }, + { 0x12, 9 }, { 0x1d6, 9 }, { 0x27e, 10 }, { 0x191, 11 }, + { 0xea, 12 }, { 0x3dc, 12 }, { 0x13b, 13 }, { 0x4, 5 }, + { 0x14, 7 }, { 0x9e, 8 }, { 0x9, 10 }, { 0x1ac, 11 }, + { 0x1e2, 11 }, { 0x3ca, 12 }, { 0x5f, 13 }, { 0x17, 5 }, + { 0x4e, 7 }, { 0x5e, 9 }, { 0xf3, 10 }, { 0x1ad, 11 }, + { 0xec, 12 }, { 0x5f0, 13 }, { 0xe, 6 }, { 0xe1, 8 }, + { 0x3a4, 10 }, { 0x9c, 12 }, { 0x13d, 13 }, { 0x3b, 6 }, + { 0x1c, 9 }, { 0x14, 11 }, { 0x9be, 12 }, { 0x6, 7 }, + { 0x7a, 9 }, { 0x190, 11 }, { 0x137, 13 }, { 0x1b, 7 }, + { 0x8, 10 }, { 0x75c, 11 }, { 0x71, 7 }, { 0xd7, 10 }, + { 0x9bf, 12 }, { 0x7, 8 }, { 0xaf, 10 }, { 0x4cc, 11 }, + { 0x34, 8 }, { 0x265, 10 }, { 0x9f, 12 }, { 0xe0, 8 }, + { 0x16, 11 }, { 0x327, 12 }, { 0x15, 9 }, { 0x17d, 11 }, + { 0xebb, 12 }, { 0x14, 9 }, { 0xf6, 10 }, { 0x1e4, 11 }, + { 0xcb, 10 }, { 0x99d, 12 }, { 0xca, 10 }, { 0x2fc, 12 }, + { 0x17f, 11 }, { 0x4cd, 11 }, { 0x2fd, 12 }, { 0x4fe, 11 }, + { 0x13a, 13 }, { 0xa, 4 }, { 0x42, 7 }, { 0x1d3, 9 }, + { 0x4dd, 11 }, { 0x12, 5 }, { 0xe8, 8 }, { 0x4c, 11 }, + { 0x136, 13 }, { 0x39, 6 }, { 0x264, 10 }, { 0xeba, 12 }, + { 0x0, 7 }, { 0xae, 10 }, { 0x99c, 12 }, { 0x1f, 7 }, + { 0x4de, 11 }, { 0x43, 7 }, { 0x4dc, 11 }, { 0x3, 8 }, + { 0x3cb, 12 }, { 0x6, 8 }, { 0x99e, 12 }, { 0x2a, 8 }, + { 0x5f1, 13 }, { 0xf, 8 }, { 0x9fe, 12 }, { 0x33, 8 }, + { 0x9ff, 12 }, { 0x98, 8 }, { 0x99f, 12 }, { 0xea, 8 }, + { 0x13c, 13 }, { 0x2e, 8 }, { 0x192, 11 }, { 0x136, 9 }, + { 0x6a, 9 }, { 0x15, 11 }, { 0x3af, 10 }, { 0x1e3, 11 }, + { 0x74, 11 }, { 0xeb, 12 }, { 0x2f9, 12 }, { 0x5c, 13 }, + { 0xed, 12 }, { 0x3dd, 12 }, { 0x326, 12 }, { 0x5e, 13 }, + { 0x16, 7 }, +}; + +static const signed char table0_level[132] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 1, 2, 3, 4, 5, + 6, 7, 8, 1, 2, 3, 4, 5, + 6, 7, 1, 2, 3, 4, 5, 1, + 2, 3, 4, 1, 2, 3, 4, 1, + 2, 3, 1, 2, 3, 1, 2, 3, + 1, 2, 3, 1, 2, 3, 1, 2, + 3, 1, 2, 3, 1, 2, 1, 2, + 1, 1, 1, 1, 1, 1, 2, 3, + 4, 1, 2, 3, 4, 1, 2, 3, + 1, 2, 3, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, +}; + +static const signed char table0_run[132] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 4, 4, 4, 4, 4, 5, + 5, 5, 5, 6, 6, 6, 6, 7, + 7, 7, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, + 12, 13, 13, 13, 14, 14, 15, 15, + 16, 17, 18, 19, 20, 0, 0, 0, + 0, 1, 1, 1, 1, 2, 2, 2, + 3, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, +}; + +/* vlc table 1, for intra chroma and P macro blocks */ + +static const WORD table1_vlc[149][2] = +{ + { 0x4, 3 }, { 0x14, 5 }, { 0x17, 7 }, { 0x7f, 8 }, + { 0x154, 9 }, { 0x1f2, 10 }, { 0xbf, 11 }, { 0x65, 12 }, + { 0xaaa, 12 }, { 0x630, 13 }, { 0x1597, 13 },{ 0x3b7, 14 }, + { 0x2b22, 14 },{ 0xbe6, 15 }, { 0xb, 4 }, { 0x37, 7 }, + { 0x62, 9 }, { 0x7, 11 }, { 0x166, 12 }, { 0xce, 13 }, + { 0x1590, 13 },{ 0x5f6, 14 }, { 0xbe7, 15 }, { 0x7, 5 }, + { 0x6d, 8 }, { 0x3, 11 }, { 0x31f, 12 }, { 0x5f2, 14 }, + { 0x2, 6 }, { 0x61, 9 }, { 0x55, 12 }, { 0x1df, 14 }, + { 0x1a, 6 }, { 0x1e, 10 }, { 0xac9, 12 }, { 0x2b23, 14 }, + { 0x1e, 6 }, { 0x1f, 10 }, { 0xac3, 12 }, { 0x2b2b, 14 }, + { 0x6, 7 }, { 0x4, 11 }, { 0x2f8, 13 }, { 0x19, 7 }, + { 0x6, 11 }, { 0x63d, 13 }, { 0x57, 7 }, { 0x182, 11 }, + { 0x2aa2, 14 },{ 0x4, 8 }, { 0x180, 11 }, { 0x59c, 14 }, + { 0x7d, 8 }, { 0x164, 12 }, { 0x76d, 15 }, { 0x2, 9 }, + { 0x18d, 11 }, { 0x1581, 13 },{ 0xad, 8 }, { 0x60, 12 }, + { 0xc67, 14 }, { 0x1c, 9 }, { 0xee, 13 }, { 0x3, 9 }, + { 0x2cf, 13 }, { 0xd9, 9 }, { 0x1580, 13 },{ 0x2, 11 }, + { 0x183, 11 }, { 0x57, 12 }, { 0x61, 12 }, { 0x31, 11 }, + { 0x66, 12 }, { 0x631, 13 }, { 0x632, 13 }, { 0xac, 13 }, + { 0x31d, 12 }, { 0x76, 12 }, { 0x3a, 11 }, { 0x165, 12 }, + { 0xc66, 14 }, { 0x3, 2 }, { 0x54, 7 }, { 0x2ab, 10 }, + { 0x16, 13 }, { 0x5f7, 14 }, { 0x5, 4 }, { 0xf8, 9 }, + { 0xaa9, 12 }, { 0x5f, 15 }, { 0x4, 4 }, { 0x1c, 10 }, + { 0x1550, 13 },{ 0x4, 5 }, { 0x77, 11 }, { 0x76c, 15 }, + { 0xe, 5 }, { 0xa, 12 }, { 0xc, 5 }, { 0x562, 11 }, + { 0x4, 6 }, { 0x31c, 12 }, { 0x6, 6 }, { 0xc8, 13 }, + { 0xd, 6 }, { 0x1da, 13 }, { 0x7, 6 }, { 0xc9, 13 }, + { 0x1, 7 }, { 0x2e, 14 }, { 0x14, 7 }, { 0x1596, 13 }, + { 0xa, 7 }, { 0xac2, 12 }, { 0x16, 7 }, { 0x15b, 14 }, + { 0x15, 7 }, { 0x15a, 14 }, { 0xf, 8 }, { 0x5e, 15 }, + { 0x7e, 8 }, { 0xab, 8 }, { 0x2d, 9 }, { 0xd8, 9 }, + { 0xb, 9 }, { 0x14, 10 }, { 0x2b3, 10 }, { 0x1f3, 10 }, + { 0x3a, 10 }, { 0x0, 10 }, { 0x58, 10 }, { 0x2e, 9 }, + { 0x5e, 10 }, { 0x563, 11 }, { 0xec, 12 }, { 0x54, 12 }, + { 0xac1, 12 }, { 0x1556, 13 },{ 0x2fa, 13 }, { 0x181, 11 }, + { 0x1557, 13 },{ 0x59d, 14 }, { 0x2aa3, 14 },{ 0x2b2a, 14 }, + { 0x1de, 14 }, { 0x63c, 13 }, { 0xcf, 13 }, { 0x1594, 13 }, + { 0xd, 9 }, +}; + +static const signed char table1_level[148] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 1, + 2, 3, 4, 5, 1, 2, 3, 4, + 1, 2, 3, 4, 1, 2, 3, 4, + 1, 2, 3, 1, 2, 3, 1, 2, + 3, 1, 2, 3, 1, 2, 3, 1, + 2, 3, 1, 2, 3, 1, 2, 1, + 2, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 3, 4, 5, 1, 2, + 3, 4, 1, 2, 3, 1, 2, 3, + 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, +}; + +static const signed char table1_run[148] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 8, 8, + 8, 9, 9, 9, 10, 10, 10, 11, + 11, 11, 12, 12, 12, 13, 13, 14, + 14, 15, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 29, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 3, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13, 14, 14, 15, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, +}; + +/* third vlc table */ + +static const WORD table2_vlc[186][2] = +{ + { 0x1, 2 }, { 0x5, 3 }, { 0xd, 4 }, { 0x12, 5 }, + { 0xe, 6 }, { 0x15, 7 }, { 0x13, 8 }, { 0x3f, 8 }, + { 0x4b, 9 }, { 0x11f, 9 }, { 0xb8, 10 }, { 0x3e3, 10 }, + { 0x172, 11 }, { 0x24d, 12 }, { 0x3da, 12 }, { 0x2dd, 13 }, + { 0x1f55, 13 },{ 0x5b9, 14 }, { 0x3eae, 14 },{ 0x0, 4 }, + { 0x10, 5 }, { 0x8, 7 }, { 0x20, 8 }, { 0x29, 9 }, + { 0x1f4, 9 }, { 0x233, 10 }, { 0x1e0, 11 }, { 0x12a, 12 }, + { 0x3dd, 12 }, { 0x50a, 13 }, { 0x1f29, 13 },{ 0xa42, 14 }, + { 0x1272, 15 },{ 0x1737, 15 },{ 0x3, 5 }, { 0x11, 7 }, + { 0xc4, 8 }, { 0x4b, 10 }, { 0xb4, 11 }, { 0x7d4, 11 }, + { 0x345, 12 }, { 0x2d7, 13 }, { 0x7bf, 13 }, { 0x938, 14 }, + { 0xbbb, 14 }, { 0x95e, 15 }, { 0x13, 5 }, { 0x78, 7 }, + { 0x69, 9 }, { 0x232, 10 }, { 0x461, 11 }, { 0x3ec, 12 }, + { 0x520, 13 }, { 0x1f2a, 13 },{ 0x3e50, 14 },{ 0x3e51, 14 }, + { 0x1486, 15 },{ 0xc, 6 }, { 0x24, 9 }, { 0x94, 11 }, + { 0x8c0, 12 }, { 0xf09, 14 }, { 0x1ef0, 15 },{ 0x3d, 6 }, + { 0x53, 9 }, { 0x1a0, 11 }, { 0x2d6, 13 }, { 0xf08, 14 }, + { 0x13, 7 }, { 0x7c, 9 }, { 0x7c1, 11 }, { 0x4ac, 14 }, + { 0x1b, 7 }, { 0xa0, 10 }, { 0x344, 12 }, { 0xf79, 14 }, + { 0x79, 7 }, { 0x3e1, 10 }, { 0x2d4, 13 }, { 0x2306, 14 }, + { 0x21, 8 }, { 0x23c, 10 }, { 0xfae, 12 }, { 0x23de, 14 }, + { 0x35, 8 }, { 0x175, 11 }, { 0x7b3, 13 }, { 0xc5, 8 }, + { 0x174, 11 }, { 0x785, 13 }, { 0x48, 9 }, { 0x1a3, 11 }, + { 0x49e, 13 }, { 0x2c, 9 }, { 0xfa, 10 }, { 0x7d6, 11 }, + { 0x92, 10 }, { 0x5cc, 13 }, { 0x1ef1, 15 },{ 0xa3, 10 }, + { 0x3ed, 12 }, { 0x93e, 14 }, { 0x1e2, 11 }, { 0x1273, 15 }, + { 0x7c4, 11 }, { 0x1487, 15 },{ 0x291, 12 }, { 0x293, 12 }, + { 0xf8a, 12 }, { 0x509, 13 }, { 0x508, 13 }, { 0x78d, 13 }, + { 0x7be, 13 }, { 0x78c, 13 }, { 0x4ae, 14 }, { 0xbba, 14 }, + { 0x2307, 14 },{ 0xb9a, 14 }, { 0x1736, 15 },{ 0xe, 4 }, + { 0x45, 7 }, { 0x1f3, 9 }, { 0x47a, 11 }, { 0x5dc, 13 }, + { 0x23df, 14 },{ 0x19, 5 }, { 0x28, 9 }, { 0x176, 11 }, + { 0x49d, 13 }, { 0x23dd, 14 },{ 0x30, 6 }, { 0xa2, 10 }, + { 0x2ef, 12 }, { 0x5b8, 14 }, { 0x3f, 6 }, { 0xa5, 10 }, + { 0x3db, 12 }, { 0x93f, 14 }, { 0x44, 7 }, { 0x7cb, 11 }, + { 0x95f, 15 }, { 0x63, 7 }, { 0x3c3, 12 }, { 0x15, 8 }, + { 0x8f6, 12 }, { 0x17, 8 }, { 0x498, 13 }, { 0x2c, 8 }, + { 0x7b2, 13 }, { 0x2f, 8 }, { 0x1f54, 13 },{ 0x8d, 8 }, + { 0x7bd, 13 }, { 0x8e, 8 }, { 0x1182, 13 },{ 0xfb, 8 }, + { 0x50b, 13 }, { 0x2d, 8 }, { 0x7c0, 11 }, { 0x79, 9 }, + { 0x1f5f, 13 },{ 0x7a, 9 }, { 0x1f56, 13 },{ 0x231, 10 }, + { 0x3e4, 10 }, { 0x1a1, 11 }, { 0x143, 11 }, { 0x1f7, 11 }, + { 0x16f, 12 }, { 0x292, 12 }, { 0x2e7, 12 }, { 0x16c, 12 }, + { 0x16d, 12 }, { 0x3dc, 12 }, { 0xf8b, 12 }, { 0x499, 13 }, + { 0x3d8, 12 }, { 0x78e, 13 }, { 0x2d5, 13 }, { 0x1f5e, 13 }, + { 0x1f2b, 13 },{ 0x78f, 13 }, { 0x4ad, 14 }, { 0x3eaf, 14 }, + { 0x23dc, 14 },{ 0x4a, 9 }, +}; + +static const signed char table2_level[185] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 1, 2, 3, 4, 5, 6, 1, + 2, 3, 4, 5, 1, 2, 3, 4, + 1, 2, 3, 4, 1, 2, 3, 4, + 1, 2, 3, 4, 1, 2, 3, 1, + 2, 3, 1, 2, 3, 1, 2, 3, + 1, 2, 3, 1, 2, 3, 1, 2, + 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 4, 5, 6, 1, 2, 3, + 4, 5, 1, 2, 3, 4, 1, 2, + 3, 4, 1, 2, 3, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, +}; + +static const signed char table2_run[185] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 4, 4, 4, 4, 5, + 5, 5, 5, 5, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, + 9, 9, 9, 9, 10, 10, 10, 11, + 11, 11, 12, 12, 12, 13, 13, 13, + 14, 14, 14, 15, 15, 15, 16, 16, + 17, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 0, + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 3, 3, + 3, 3, 4, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, + 14, 15, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 37, +}; + +/* second non intra vlc table */ +static const WORD table4_vlc[169][2] = +{ + { 0x0, 3 }, { 0x3, 4 }, { 0xb, 5 }, { 0x14, 6 }, + { 0x3f, 6 }, { 0x5d, 7 }, { 0xa2, 8 }, { 0xac, 9 }, + { 0x16e, 9 }, { 0x20a, 10 }, { 0x2e2, 10 }, { 0x432, 11 }, + { 0x5c9, 11 }, { 0x827, 12 }, { 0xb54, 12 }, { 0x4e6, 13 }, + { 0x105f, 13 },{ 0x172a, 13 },{ 0x20b2, 14 },{ 0x2d4e, 14 }, + { 0x39f0, 14 },{ 0x4175, 15 },{ 0x5a9e, 15 },{ 0x4, 4 }, + { 0x1e, 5 }, { 0x42, 7 }, { 0xb6, 8 }, { 0x173, 9 }, + { 0x395, 10 }, { 0x72e, 11 }, { 0xb94, 12 }, { 0x16a4, 13 }, + { 0x20b3, 14 },{ 0x2e45, 14 },{ 0x5, 5 }, { 0x40, 7 }, + { 0x49, 9 }, { 0x28f, 10 }, { 0x5cb, 11 }, { 0x48a, 13 }, + { 0x9dd, 14 }, { 0x73e2, 15 },{ 0x18, 5 }, { 0x25, 8 }, + { 0x8a, 10 }, { 0x51b, 11 }, { 0xe5f, 12 }, { 0x9c9, 14 }, + { 0x139c, 15 },{ 0x29, 6 }, { 0x4f, 9 }, { 0x412, 11 }, + { 0x48d, 13 }, { 0x2e41, 14 },{ 0x38, 6 }, { 0x10e, 9 }, + { 0x5a8, 11 }, { 0x105c, 13 },{ 0x39f2, 14 },{ 0x58, 7 }, + { 0x21f, 10 }, { 0xe7e, 12 }, { 0x39ff, 14 },{ 0x23, 8 }, + { 0x2e3, 10 }, { 0x4e5, 13 }, { 0x2e40, 14 },{ 0xa1, 8 }, + { 0x5be, 11 }, { 0x9c8, 14 }, { 0x83, 8 }, { 0x13a, 11 }, + { 0x1721, 13 },{ 0x44, 9 }, { 0x276, 12 }, { 0x39f6, 14 }, + { 0x8b, 10 }, { 0x4ef, 13 }, { 0x5a9b, 15 },{ 0x208, 10 }, + { 0x1cfe, 13 },{ 0x399, 10 }, { 0x1cb4, 13 },{ 0x39e, 10 }, + { 0x39f3, 14 },{ 0x5ab, 11 }, { 0x73e3, 15 },{ 0x737, 11 }, + { 0x5a9f, 15 },{ 0x82d, 12 }, { 0xe69, 12 }, { 0xe68, 12 }, + { 0x433, 11 }, { 0xb7b, 12 }, { 0x2df8, 14 },{ 0x2e56, 14 }, + { 0x2e57, 14 },{ 0x39f7, 14 },{ 0x51a5, 15 },{ 0x3, 3 }, + { 0x2a, 6 }, { 0xe4, 8 }, { 0x28e, 10 }, { 0x735, 11 }, + { 0x1058, 13 },{ 0x1cfa, 13 },{ 0x2df9, 14 },{ 0x4174, 15 }, + { 0x9, 4 }, { 0x54, 8 }, { 0x398, 10 }, { 0x48b, 13 }, + { 0x139d, 15 },{ 0xd, 4 }, { 0xad, 9 }, { 0x826, 12 }, + { 0x2d4c, 14 },{ 0x11, 5 }, { 0x16b, 9 }, { 0xb7f, 12 }, + { 0x51a4, 15 },{ 0x19, 5 }, { 0x21b, 10 }, { 0x16fd, 13 }, + { 0x1d, 5 }, { 0x394, 10 }, { 0x28d3, 14 },{ 0x2b, 6 }, + { 0x5bc, 11 }, { 0x5a9a, 15 },{ 0x2f, 6 }, { 0x247, 12 }, + { 0x10, 7 }, { 0xa35, 12 }, { 0x3e, 6 }, { 0xb7a, 12 }, + { 0x59, 7 }, { 0x105e, 13 },{ 0x26, 8 }, { 0x9cf, 14 }, + { 0x55, 8 }, { 0x1cb5, 13 },{ 0x57, 8 }, { 0xe5b, 12 }, + { 0xa0, 8 }, { 0x1468, 13 },{ 0x170, 9 }, { 0x90, 10 }, + { 0x1ce, 9 }, { 0x21a, 10 }, { 0x218, 10 }, { 0x168, 9 }, + { 0x21e, 10 }, { 0x244, 12 }, { 0x736, 11 }, { 0x138, 11 }, + { 0x519, 11 }, { 0xe5e, 12 }, { 0x72c, 11 }, { 0xb55, 12 }, + { 0x9dc, 14 }, { 0x20bb, 14 },{ 0x48c, 13 }, { 0x1723, 13 }, + { 0x2e44, 14 },{ 0x16a5, 13 },{ 0x518, 11 }, { 0x39fe, 14 }, + { 0x169, 9 }, +}; + +static const signed char table4_level[168] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 1, 2, 3, 4, 5, 6, + 7, 8, 1, 2, 3, 4, 5, 6, + 7, 1, 2, 3, 4, 5, 1, 2, + 3, 4, 5, 1, 2, 3, 4, 1, + 2, 3, 4, 1, 2, 3, 1, 2, + 3, 1, 2, 3, 1, 2, 3, 1, + 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 1, 2, 3, 4, + 5, 1, 2, 3, 4, 1, 2, 3, + 4, 1, 2, 3, 1, 2, 3, 1, + 2, 3, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static const signed char table4_run[168] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 4, 4, 4, 5, 5, + 5, 5, 5, 6, 6, 6, 6, 7, + 7, 7, 7, 8, 8, 8, 9, 9, + 9, 10, 10, 10, 11, 11, 11, 12, + 12, 13, 13, 14, 14, 15, 15, 16, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, + 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13, + 14, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, +}; + +static const WORD inter_vlc[103][2] = +{ + { 0x2, 2 }, { 0xf, 4 }, { 0x15, 6 }, { 0x17, 7 }, + { 0x1f, 8 }, { 0x25, 9 }, { 0x24, 9 }, { 0x21, 10 }, + { 0x20, 10 }, { 0x7, 11 }, { 0x6, 11 }, { 0x20, 11 }, + { 0x6, 3 }, { 0x14, 6 }, { 0x1e, 8 }, { 0xf, 10 }, + { 0x21, 11 }, { 0x50, 12 }, { 0xe, 4 }, { 0x1d, 8 }, + { 0xe, 10 }, { 0x51, 12 }, { 0xd, 5 }, { 0x23, 9 }, + { 0xd, 10 }, { 0xc, 5 }, { 0x22, 9 }, { 0x52, 12 }, + { 0xb, 5 }, { 0xc, 10 }, { 0x53, 12 }, { 0x13, 6 }, + { 0xb, 10 }, { 0x54, 12 }, { 0x12, 6 }, { 0xa, 10 }, + { 0x11, 6 }, { 0x9, 10 }, { 0x10, 6 }, { 0x8, 10 }, + { 0x16, 7 }, { 0x55, 12 }, { 0x15, 7 }, { 0x14, 7 }, + { 0x1c, 8 }, { 0x1b, 8 }, { 0x21, 9 }, { 0x20, 9 }, + { 0x1f, 9 }, { 0x1e, 9 }, { 0x1d, 9 }, { 0x1c, 9 }, + { 0x1b, 9 }, { 0x1a, 9 }, { 0x22, 11 }, { 0x23, 11 }, + { 0x56, 12 }, { 0x57, 12 }, { 0x7, 4 }, { 0x19, 9 }, + { 0x5, 11 }, { 0xf, 6 }, { 0x4, 11 }, { 0xe, 6 }, + { 0xd, 6 }, { 0xc, 6 }, { 0x13, 7 }, { 0x12, 7 }, + { 0x11, 7 }, { 0x10, 7 }, { 0x1a, 8 }, { 0x19, 8 }, + { 0x18, 8 }, { 0x17, 8 }, { 0x16, 8 }, { 0x15, 8 }, + { 0x14, 8 }, { 0x13, 8 }, { 0x18, 9 }, { 0x17, 9 }, + { 0x16, 9 }, { 0x15, 9 }, { 0x14, 9 }, { 0x13, 9 }, + { 0x12, 9 }, { 0x11, 9 }, { 0x7, 10 }, { 0x6, 10 }, + { 0x5, 10 }, { 0x4, 10 }, { 0x24, 11 }, { 0x25, 11 }, + { 0x26, 11 }, { 0x27, 11 }, { 0x58, 12 }, { 0x59, 12 }, + { 0x5a, 12 }, { 0x5b, 12 }, { 0x5c, 12 }, { 0x5d, 12 }, + { 0x5e, 12 }, { 0x5f, 12 }, { 0x3, 7 }, +}; + +static const signed char inter_level[102] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 1, 2, 3, 4, + 5, 6, 1, 2, 3, 4, 1, 2, + 3, 1, 2, 3, 1, 2, 3, 1, + 2, 3, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 3, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, +}; + +static const signed char inter_run[102] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 3, 3, + 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 0, 0, 0, 1, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, +}; + +static const WORD intra_vlc[103][2] = +{ + { 0x2, 2 }, { 0x6, 3 }, { 0xf, 4 }, { 0xd, 5 }, + { 0xc, 5 }, { 0x15, 6 }, { 0x13, 6 }, { 0x12, 6 }, + { 0x17, 7 }, { 0x1f, 8 }, { 0x1e, 8 }, { 0x1d, 8 }, + { 0x25, 9 }, { 0x24, 9 }, { 0x23, 9 }, { 0x21, 9 }, + { 0x21, 10 }, { 0x20, 10 }, { 0xf, 10 }, { 0xe, 10 }, + { 0x7, 11 }, { 0x6, 11 }, { 0x20, 11 }, { 0x21, 11 }, + { 0x50, 12 }, { 0x51, 12 }, { 0x52, 12 }, { 0xe, 4 }, + { 0x14, 6 }, { 0x16, 7 }, { 0x1c, 8 }, { 0x20, 9 }, + { 0x1f, 9 }, { 0xd, 10 }, { 0x22, 11 }, { 0x53, 12 }, + { 0x55, 12 }, { 0xb, 5 }, { 0x15, 7 }, { 0x1e, 9 }, + { 0xc, 10 }, { 0x56, 12 }, { 0x11, 6 }, { 0x1b, 8 }, + { 0x1d, 9 }, { 0xb, 10 }, { 0x10, 6 }, { 0x22, 9 }, + { 0xa, 10 }, { 0xd, 6 }, { 0x1c, 9 }, { 0x8, 10 }, + { 0x12, 7 }, { 0x1b, 9 }, { 0x54, 12 }, { 0x14, 7 }, + { 0x1a, 9 }, { 0x57, 12 }, { 0x19, 8 }, { 0x9, 10 }, + { 0x18, 8 }, { 0x23, 11 }, { 0x17, 8 }, { 0x19, 9 }, + { 0x18, 9 }, { 0x7, 10 }, { 0x58, 12 }, { 0x7, 4 }, + { 0xc, 6 }, { 0x16, 8 }, { 0x17, 9 }, { 0x6, 10 }, + { 0x5, 11 }, { 0x4, 11 }, { 0x59, 12 }, { 0xf, 6 }, + { 0x16, 9 }, { 0x5, 10 }, { 0xe, 6 }, { 0x4, 10 }, + { 0x11, 7 }, { 0x24, 11 }, { 0x10, 7 }, { 0x25, 11 }, + { 0x13, 7 }, { 0x5a, 12 }, { 0x15, 8 }, { 0x5b, 12 }, + { 0x14, 8 }, { 0x13, 8 }, { 0x1a, 8 }, { 0x15, 9 }, + { 0x14, 9 }, { 0x13, 9 }, { 0x12, 9 }, { 0x11, 9 }, + { 0x26, 11 }, { 0x27, 11 }, { 0x5c, 12 }, { 0x5d, 12 }, + { 0x5e, 12 }, { 0x5f, 12 }, { 0x3, 7 }, +}; + +static const signed char intra_level[102] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 1, 2, 3, + 4, 5, 1, 2, 3, 4, 1, 2, + 3, 1, 2, 3, 1, 2, 3, 1, + 2, 3, 1, 2, 1, 2, 1, 1, + 1, 1, 1, 1, 2, 3, 4, 5, + 6, 7, 8, 1, 2, 3, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, +}; + +static const signed char intra_run[102] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 4, 4, + 4, 5, 5, 5, 6, 6, 6, 7, + 7, 7, 8, 8, 9, 9, 10, 11, + 12, 13, 14, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 2, 2, + 3, 3, 4, 4, 5, 5, 6, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, +}; + +static DIVX_RL_TABLE rl_table[6] = +{ + /* intra luminance tables */ + { + 132, + 85, + table0_vlc, + table0_run, + table0_level, + }, + { + 185, + 119, + table2_vlc, + table2_run, + table2_level, + }, + { + 102, + 67, + intra_vlc, + intra_run, + intra_level, + }, + /* intra chrominance / non intra tables */ + { + 148, + 81, + table1_vlc, + table1_run, + table1_level, + }, + { + 168, + 99, + table4_vlc, + table4_run, + table4_level, + }, + { + 102, + 58, + inter_vlc, + inter_run, + inter_level, + }, +}; + +////////////////////////////////////////////////////// + +static const WORD table_mb_intra[64][2] = +{ + { 0x1, 1 },{ 0x17, 6 },{ 0x9, 5 },{ 0x5, 5 }, + { 0x6, 5 },{ 0x47, 9 },{ 0x20, 7 },{ 0x10, 7 }, + { 0x2, 5 },{ 0x7c, 9 },{ 0x3a, 7 },{ 0x1d, 7 }, + { 0x2, 6 },{ 0xec, 9 },{ 0x77, 8 },{ 0x0, 8 }, + { 0x3, 5 },{ 0xb7, 9 },{ 0x2c, 7 },{ 0x13, 7 }, + { 0x1, 6 },{ 0x168, 10 },{ 0x46, 8 },{ 0x3f, 8 }, + { 0x1e, 6 },{ 0x712, 13 },{ 0xb5, 9 },{ 0x42, 8 }, + { 0x22, 7 },{ 0x1c5, 11 },{ 0x11e, 10 },{ 0x87, 9 }, + { 0x6, 4 },{ 0x3, 9 },{ 0x1e, 7 },{ 0x1c, 6 }, + { 0x12, 7 },{ 0x388, 12 },{ 0x44, 9 },{ 0x70, 9 }, + { 0x1f, 6 },{ 0x23e, 11 },{ 0x39, 8 },{ 0x8e, 9 }, + { 0x1, 7 },{ 0x1c6, 11 },{ 0xb6, 9 },{ 0x45, 9 }, + { 0x14, 6 },{ 0x23f, 11 },{ 0x7d, 9 },{ 0x18, 9 }, + { 0x7, 7 },{ 0x1c7, 11 },{ 0x86, 9 },{ 0x19, 9 }, + { 0x15, 6 },{ 0x1db, 10 },{ 0x2, 9 },{ 0x46, 9 }, + { 0xd, 8 },{ 0x713, 13 },{ 0x1da, 10 },{ 0x169, 10 }, +}; + +static const DWORD table_mb_non_intra[128][2] = +{ + { 0x40, 7 },{ 0x13c9, 13 },{ 0x9fd, 12 },{ 0x1fc, 15 }, + { 0x9fc, 12 },{ 0xa83, 18 },{ 0x12d34, 17 },{ 0x83bc, 16 }, + { 0x83a, 12 },{ 0x7f8, 17 },{ 0x3fd, 16 },{ 0x3ff, 16 }, + { 0x79, 13 },{ 0xa82, 18 },{ 0x969d, 16 },{ 0x2a4, 16 }, + { 0x978, 12 },{ 0x543, 17 },{ 0x41df, 15 },{ 0x7f9, 17 }, + { 0x12f3, 13 },{ 0x25a6b, 18 },{ 0x25ef9, 18 },{ 0x3fa, 16 }, + { 0x20ee, 14 },{ 0x969ab, 20 },{ 0x969c, 16 },{ 0x25ef8, 18 }, + { 0x12d2, 13 },{ 0xa85, 18 },{ 0x969e, 16 },{ 0x4bc8, 15 }, + { 0x3d, 12 },{ 0x12f7f, 17 },{ 0x2a2, 16 },{ 0x969f, 16 }, + { 0x25ee, 14 },{ 0x12d355, 21 },{ 0x12f7d, 17 },{ 0x12f7e, 17 }, + { 0x9e5, 12 },{ 0xa81, 18 },{ 0x4b4d4, 19 },{ 0x83bd, 16 }, + { 0x78, 13 },{ 0x969b, 16 },{ 0x3fe, 16 },{ 0x2a5, 16 }, + { 0x7e, 13 },{ 0xa80, 18 },{ 0x2a3, 16 },{ 0x3fb, 16 }, + { 0x1076, 13 },{ 0xa84, 18 },{ 0x153, 15 },{ 0x4bc9, 15 }, + { 0x55, 13 },{ 0x12d354, 21 },{ 0x4bde, 15 },{ 0x25e5, 14 }, + { 0x25b, 10 },{ 0x4b4c, 15 },{ 0x96b, 12 },{ 0x96a, 12 }, + { 0x1, 2 },{ 0x0, 7 },{ 0x26, 6 },{ 0x12b, 9 }, + { 0x7, 3 },{ 0x20f, 10 },{ 0x4, 9 },{ 0x28, 12 }, + { 0x6, 3 },{ 0x20a, 10 },{ 0x128, 9 },{ 0x2b, 12 }, + { 0x11, 5 },{ 0x1b, 11 },{ 0x13a, 9 },{ 0x4ff, 11 }, + { 0x3, 4 },{ 0x277, 10 },{ 0x106, 9 },{ 0x839, 12 }, + { 0xb, 4 },{ 0x27b, 10 },{ 0x12c, 9 },{ 0x4bf, 11 }, + { 0x9, 6 },{ 0x35, 12 },{ 0x27e, 10 },{ 0x13c8, 13 }, + { 0x1, 6 },{ 0x4aa, 11 },{ 0x208, 10 },{ 0x29, 12 }, + { 0x1, 4 },{ 0x254, 10 },{ 0x12e, 9 },{ 0x838, 12 }, + { 0x24, 6 },{ 0x4f3, 11 },{ 0x276, 10 },{ 0x12f6, 13 }, + { 0x1, 5 },{ 0x27a, 10 },{ 0x13e, 9 },{ 0x3e, 12 }, + { 0x8, 6 },{ 0x413, 11 },{ 0xc, 10 },{ 0x4be, 11 }, + { 0x14, 5 },{ 0x412, 11 },{ 0x253, 10 },{ 0x97a, 12 }, + { 0x21, 6 },{ 0x4ab, 11 },{ 0x20b, 10 },{ 0x34, 12 }, + { 0x15, 5 },{ 0x278, 10 },{ 0x252, 10 },{ 0x968, 12 }, + { 0x5, 5 },{ 0xb, 10 },{ 0x9c, 8 },{ 0xe, 10 }, +}; + +static const WORD table0_mv_code[1100] = +{ + 0x0001, 0x0003, 0x0005, 0x0007, 0x0003, 0x0008, 0x000c, 0x0001, + 0x0002, 0x001b, 0x0006, 0x000b, 0x0015, 0x0002, 0x000e, 0x000f, + 0x0014, 0x0020, 0x0022, 0x0025, 0x0027, 0x0029, 0x002d, 0x004b, + 0x004d, 0x0003, 0x0022, 0x0023, 0x0025, 0x0027, 0x0042, 0x0048, + 0x0049, 0x0050, 0x005c, 0x0091, 0x009f, 0x000e, 0x0043, 0x004c, + 0x0054, 0x0056, 0x008c, 0x0098, 0x009a, 0x009b, 0x00b1, 0x00b2, + 0x0120, 0x0121, 0x0126, 0x0133, 0x0139, 0x01a1, 0x01a4, 0x01a5, + 0x01a6, 0x01a7, 0x01ae, 0x01af, 0x000b, 0x0019, 0x0085, 0x0090, + 0x009b, 0x00aa, 0x00af, 0x010c, 0x010e, 0x011c, 0x011e, 0x0133, + 0x0144, 0x0160, 0x0174, 0x0175, 0x0177, 0x0178, 0x0249, 0x024b, + 0x0252, 0x0261, 0x0265, 0x0270, 0x0352, 0x0353, 0x0355, 0x0359, + 0x0010, 0x0011, 0x0013, 0x0034, 0x0035, 0x0036, 0x0037, 0x003d, + 0x003e, 0x0109, 0x0126, 0x0156, 0x021a, 0x021e, 0x023a, 0x023e, + 0x028e, 0x028f, 0x02cf, 0x0491, 0x0494, 0x049f, 0x04a0, 0x04a3, + 0x04a6, 0x04a7, 0x04ad, 0x04ae, 0x04c0, 0x04c4, 0x04c6, 0x04c8, + 0x04c9, 0x04f5, 0x04f6, 0x04f7, 0x0680, 0x0682, 0x0683, 0x0688, + 0x0689, 0x068d, 0x068e, 0x068f, 0x06a2, 0x06a3, 0x06a9, 0x06b0, + 0x06b1, 0x06b4, 0x06b5, 0x0024, 0x0060, 0x0063, 0x0078, 0x0079, + 0x0211, 0x0244, 0x0245, 0x0247, 0x0248, 0x0249, 0x024a, 0x024b, + 0x026b, 0x02af, 0x02b8, 0x02bb, 0x0436, 0x0476, 0x0477, 0x047e, + 0x04c8, 0x04c9, 0x04ca, 0x0514, 0x0586, 0x0587, 0x0598, 0x059d, + 0x05d9, 0x05da, 0x0920, 0x0921, 0x093b, 0x093c, 0x093d, 0x0942, + 0x0943, 0x0944, 0x0945, 0x0959, 0x095e, 0x095f, 0x0982, 0x0983, + 0x098e, 0x098f, 0x09c4, 0x09e7, 0x09e8, 0x09e9, 0x0d02, 0x0d17, + 0x0d18, 0x0d19, 0x0d41, 0x0d42, 0x0d43, 0x0d50, 0x0d5f, 0x0d6d, + 0x0d6e, 0x0d6f, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x041e, 0x041f, 0x0420, 0x0421, + 0x048c, 0x048d, 0x04d3, 0x04d4, 0x04d5, 0x055c, 0x055d, 0x0572, + 0x0573, 0x0574, 0x0575, 0x08de, 0x08df, 0x08fe, 0x08ff, 0x0996, + 0x0a36, 0x0a37, 0x0b08, 0x0b09, 0x0b0a, 0x0b0b, 0x0b32, 0x0b33, + 0x0b34, 0x0b35, 0x0b36, 0x0b37, 0x0b38, 0x0b39, 0x0bb0, 0x0bf7, + 0x0bf8, 0x0bf9, 0x0bfa, 0x0bfb, 0x0bfc, 0x0bfd, 0x0bfe, 0x0bff, + 0x1254, 0x1255, 0x1256, 0x1257, 0x1270, 0x1271, 0x1272, 0x1273, + 0x1274, 0x1275, 0x12ab, 0x12ac, 0x12ad, 0x12ae, 0x12af, 0x12b0, + 0x12b1, 0x1315, 0x1316, 0x1317, 0x13bf, 0x13c0, 0x13c1, 0x13c2, + 0x13c3, 0x13c4, 0x13c5, 0x13c6, 0x13c7, 0x13c8, 0x13c9, 0x13ca, + 0x13cb, 0x13cc, 0x13cd, 0x1a06, 0x1a07, 0x1a28, 0x1a29, 0x1a2a, + 0x1a2b, 0x1a2c, 0x1a2d, 0x1a80, 0x1abb, 0x1abc, 0x1abd, 0x1ad8, + 0x1ad9, 0x0094, 0x0095, 0x0096, 0x0097, 0x00a0, 0x00a1, 0x00a2, + 0x00a3, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836, 0x0837, + 0x0838, 0x0839, 0x083a, 0x083b, 0x0939, 0x093a, 0x093b, 0x093c, + 0x093d, 0x093e, 0x093f, 0x09a0, 0x09a1, 0x09a2, 0x09a3, 0x09a4, + 0x09a5, 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, + 0x11b3, 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, + 0x11bb, 0x132f, 0x1454, 0x1455, 0x1456, 0x1457, 0x1458, 0x1459, + 0x145a, 0x145b, 0x145c, 0x145d, 0x145e, 0x145f, 0x1460, 0x1461, + 0x1462, 0x1463, 0x1464, 0x1465, 0x1466, 0x1467, 0x1468, 0x1469, + 0x146a, 0x146b, 0x17de, 0x17df, 0x17e0, 0x17e1, 0x17e2, 0x17e3, + 0x17e4, 0x17e5, 0x17e6, 0x17e7, 0x17e8, 0x17e9, 0x17ea, 0x17eb, + 0x17ec, 0x17ed, 0x2540, 0x2541, 0x2542, 0x2543, 0x2544, 0x2545, + 0x2546, 0x2547, 0x2548, 0x2549, 0x254a, 0x254b, 0x254c, 0x254d, + 0x254e, 0x254f, 0x2550, 0x2551, 0x2552, 0x2553, 0x2554, 0x2555, + 0x2628, 0x2766, 0x2767, 0x2768, 0x2769, 0x276a, 0x276b, 0x276c, + 0x276d, 0x276e, 0x276f, 0x2770, 0x2771, 0x2772, 0x2773, 0x2774, + 0x2775, 0x2776, 0x2777, 0x2778, 0x2779, 0x277a, 0x277b, 0x277c, + 0x277d, 0x3503, 0x3544, 0x3545, 0x3546, 0x3547, 0x3560, 0x3561, + 0x3562, 0x3563, 0x3564, 0x3565, 0x3566, 0x3567, 0x3568, 0x3569, + 0x356a, 0x356b, 0x356c, 0x356d, 0x356e, 0x356f, 0x3570, 0x3571, + 0x3572, 0x3573, 0x3574, 0x3575, 0x03f0, 0x103d, 0x103e, 0x103f, + 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, + 0x1048, 0x1049, 0x104a, 0x104b, 0x104c, 0x104d, 0x104e, 0x104f, + 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, + 0x1058, 0x1059, 0x105a, 0x105b, 0x105c, 0x105d, 0x105e, 0x105f, + 0x1060, 0x1061, 0x1270, 0x1271, 0x21b8, 0x21b9, 0x21ba, 0x21bb, + 0x21bc, 0x21bd, 0x21be, 0x21bf, 0x21f0, 0x21f1, 0x21f2, 0x21f3, + 0x21f4, 0x21f5, 0x21f6, 0x21f7, 0x21f8, 0x21f9, 0x21fa, 0x21fb, + 0x21fc, 0x21fd, 0x21fe, 0x21ff, 0x2340, 0x2341, 0x2342, 0x2343, + 0x2344, 0x2345, 0x2346, 0x2347, 0x2348, 0x2349, 0x234a, 0x234b, + 0x234c, 0x234d, 0x234e, 0x234f, 0x2350, 0x2351, 0x2352, 0x2353, + 0x2354, 0x2355, 0x2356, 0x2357, 0x265c, 0x2f88, 0x2f89, 0x2f8a, + 0x2f8b, 0x2f8c, 0x2f8d, 0x2f8e, 0x2f8f, 0x2f90, 0x2f91, 0x2f92, + 0x2f93, 0x2f94, 0x2f95, 0x2f96, 0x2f97, 0x2f98, 0x2f99, 0x2f9a, + 0x2f9b, 0x2f9c, 0x2f9d, 0x2f9e, 0x2f9f, 0x2fa0, 0x2fa1, 0x2fa2, + 0x2fa3, 0x2fa4, 0x2fa5, 0x2fa6, 0x2fa7, 0x2fa8, 0x2fa9, 0x2faa, + 0x2fab, 0x2fac, 0x2fad, 0x2fae, 0x2faf, 0x2fb0, 0x2fb1, 0x2fb2, + 0x2fb3, 0x2fb4, 0x2fb5, 0x2fb6, 0x2fb7, 0x2fb8, 0x2fb9, 0x2fba, + 0x2fbb, 0x4c52, 0x4c53, 0x4e28, 0x4e29, 0x4e2a, 0x4e2b, 0x4e2c, + 0x4e2d, 0x4e2e, 0x4e2f, 0x4e30, 0x4e31, 0x4e32, 0x4e33, 0x4e34, + 0x4e35, 0x4e36, 0x4e37, 0x4e38, 0x4e39, 0x4e3a, 0x4e3b, 0x4e3c, + 0x4e3d, 0x4e3e, 0x4e3f, 0x4e80, 0x4e81, 0x4e82, 0x4e83, 0x4e84, + 0x4e85, 0x4e86, 0x4e87, 0x4e88, 0x4e89, 0x4e8a, 0x4e8b, 0x4e8c, + 0x4e8d, 0x4e8e, 0x4e8f, 0x4e90, 0x4e91, 0x4e92, 0x4e93, 0x4e94, + 0x4e95, 0x4e96, 0x4e97, 0x4e98, 0x4e99, 0x4e9a, 0x4e9b, 0x4e9c, + 0x4e9d, 0x4e9e, 0x4e9f, 0x4ea0, 0x4ea1, 0x4ea2, 0x4ea3, 0x4ea4, + 0x4ea5, 0x4ea6, 0x4ea7, 0x4ea8, 0x4ea9, 0x4eaa, 0x4eab, 0x4eac, + 0x4ead, 0x4eae, 0x4eaf, 0x4eb0, 0x4eb1, 0x4eb2, 0x4eb3, 0x4eb4, + 0x4eb5, 0x4eb6, 0x4eb7, 0x4eb8, 0x4eb9, 0x4eba, 0x4ebb, 0x4ebc, + 0x4ebd, 0x4ebe, 0x4ebf, 0x4ec0, 0x4ec1, 0x4ec2, 0x4ec3, 0x4ec4, + 0x4ec5, 0x4ec6, 0x4ec7, 0x4ec8, 0x4ec9, 0x4eca, 0x4ecb, 0x6a04, + 0x6a05, 0x07e2, 0x07e3, 0x07e4, 0x07e5, 0x07e6, 0x07e7, 0x07e8, + 0x07e9, 0x07ea, 0x07eb, 0x07ec, 0x07ed, 0x07ee, 0x07ef, 0x07f0, + 0x07f1, 0x07f2, 0x07f3, 0x07f4, 0x07f5, 0x07f6, 0x07f7, 0x07f8, + 0x07f9, 0x07fa, 0x07fb, 0x07fc, 0x07fd, 0x07fe, 0x07ff, 0x2000, + 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, + 0x2009, 0x200a, 0x200b, 0x200c, 0x200d, 0x200e, 0x200f, 0x2010, + 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, + 0x2019, 0x201a, 0x201b, 0x201c, 0x201d, 0x201e, 0x201f, 0x2020, + 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, + 0x2029, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, + 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, + 0x2039, 0x203a, 0x203b, 0x203c, 0x203d, 0x203e, 0x203f, 0x2040, + 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, + 0x2049, 0x204a, 0x204b, 0x204c, 0x204d, 0x204e, 0x204f, 0x2050, + 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, + 0x2059, 0x205a, 0x205b, 0x205c, 0x205d, 0x205e, 0x205f, 0x2060, + 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, + 0x2069, 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0x2070, + 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, + 0x2079, 0x4cba, 0x4cbb, 0x5d88, 0x5d89, 0x5d8a, 0x5d8b, 0x5d8c, + 0x5d8d, 0x5d8e, 0x5d8f, 0x5db0, 0x5db1, 0x5db2, 0x5db3, 0x5db4, + 0x5db5, 0x5db6, 0x5db7, 0x5db8, 0x5db9, 0x5dba, 0x5dbb, 0x5dbc, + 0x5dbd, 0x5dbe, 0x5dbf, 0x5e40, 0x5e41, 0x5e42, 0x5e43, 0x5e44, + 0x5e45, 0x5e46, 0x5e47, 0x5e48, 0x5e49, 0x5e4a, 0x5e4b, 0x5e4c, + 0x5e4d, 0x5e4e, 0x5e4f, 0x5e50, 0x5e51, 0x5e52, 0x5e53, 0x5e54, + 0x5e55, 0x5e56, 0x5e57, 0x5e58, 0x5e59, 0x5e5a, 0x5e5b, 0x5e5c, + 0x5e5d, 0x5e5e, 0x5e5f, 0x5e60, 0x5e61, 0x5e62, 0x5e63, 0x5e64, + 0x5e65, 0x5e66, 0x5e67, 0x5e68, 0x5e69, 0x5e6a, 0x5e6b, 0x5e6c, + 0x5e6d, 0x5e6e, 0x5e6f, 0x5e70, 0x5e71, 0x5e72, 0x5e73, 0x5e74, + 0x5e75, 0x5e76, 0x5e77, 0x5e78, 0x5e79, 0x5e7a, 0x5e7b, 0x5e7c, + 0x5e7d, 0x5e7e, 0x5e7f, 0x5e80, 0x5e81, 0x5e82, 0x5e83, 0x5e84, + 0x5e85, 0x5e86, 0x5e87, 0x5e88, 0x5e89, 0x5e8a, 0x5e8b, 0x5e8c, + 0x5e8d, 0x5e8e, 0x5e8f, 0x5e90, 0x5e91, 0x5e92, 0x5e93, 0x5e94, + 0x5e95, 0x5e96, 0x5e97, 0x5e98, 0x5e99, 0x5e9a, 0x5e9b, 0x5e9c, + 0x5e9d, 0x5e9e, 0x5e9f, 0x5ea0, 0x5ea1, 0x5ea2, 0x5ea3, 0x5ea4, + 0x5ea5, 0x5ea6, 0x5ea7, 0x5ea8, 0x5ea9, 0x5eaa, 0x5eab, 0x5eac, + 0x5ead, 0x5eae, 0x5eaf, 0x5eb0, 0x5eb1, 0x5eb2, 0x5eb3, 0x5eb4, + 0x5eb5, 0x5eb6, 0x5eb7, 0x5eb8, 0x5eb9, 0x5eba, 0x5ebb, 0x5ebc, + 0x5ebd, 0x5ebe, 0x5ebf, 0x5ec0, 0x5ec1, 0x5ec2, 0x5ec3, 0x5ec4, + 0x5ec5, 0x5ec6, 0x5ec7, 0x5ec8, 0x5ec9, 0x5eca, 0x5ecb, 0x5ecc, + 0x5ecd, 0x5ece, 0x5ecf, 0x5ed0, 0x5ed1, 0x5ed2, 0x5ed3, 0x5ed4, + 0x5ed5, 0x5ed6, 0x5ed7, 0x5ed8, 0x5ed9, 0x5eda, 0x5edb, 0x5edc, + 0x5edd, 0x5ede, 0x5edf, 0x5ee0, 0x5ee1, 0x5ee2, 0x5ee3, 0x5ee4, + 0x5ee5, 0x5ee6, 0x5ee7, 0x5ee8, 0x5ee9, 0x5eea, 0x5eeb, 0x5eec, + 0x5eed, 0x5eee, 0x5eef, 0x5ef0, 0x5ef1, 0x5ef2, 0x5ef3, 0x5ef4, + 0x5ef5, 0x5ef6, 0x5ef7, 0x5ef8, 0x5ef9, 0x5efa, 0x5efb, 0x5efc, + 0x5efd, 0x5efe, 0x5eff, 0x5f00, 0x5f01, 0x5f02, 0x5f03, 0x5f04, + 0x5f05, 0x5f06, 0x5f07, 0x5f08, 0x5f09, 0x5f0a, 0x5f0b, 0x5f0c, + 0x5f0d, 0x5f0e, 0x5f0f, 0x0000, +}; + +static const BYTE table0_mv_bits[1100] = +{ + 1, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 8, +}; + +static const BYTE table0_mvx[1099] = +{ + 32, 32, 31, 32, 33, 31, 33, 31, + 33, 32, 34, 32, 30, 32, 31, 34, + 35, 32, 34, 33, 29, 33, 30, 30, + 31, 31, 35, 29, 33, 35, 33, 34, + 31, 29, 30, 34, 30, 36, 28, 32, + 34, 37, 30, 27, 32, 25, 39, 32, + 34, 32, 35, 35, 35, 31, 35, 29, + 32, 29, 30, 29, 37, 27, 36, 38, + 37, 33, 32, 31, 29, 31, 28, 36, + 33, 30, 34, 33, 33, 28, 27, 25, + 31, 26, 39, 32, 32, 31, 33, 39, + 31, 38, 28, 36, 21, 23, 43, 36, + 34, 41, 30, 25, 28, 31, 30, 34, + 38, 35, 61, 34, 28, 30, 37, 37, + 35, 27, 36, 3, 59, 38, 37, 32, + 31, 29, 26, 33, 37, 33, 27, 27, + 35, 34, 34, 40, 42, 33, 32, 29, + 4, 5, 28, 24, 25, 35, 39, 38, + 32, 23, 27, 32, 30, 35, 26, 34, + 60, 36, 29, 22, 26, 41, 7, 30, + 38, 30, 36, 29, 30, 41, 26, 25, + 32, 34, 24, 39, 1, 25, 39, 32, + 28, 29, 32, 38, 26, 36, 28, 63, + 28, 39, 23, 21, 26, 35, 31, 35, + 57, 31, 29, 29, 28, 30, 27, 35, + 2, 38, 40, 34, 37, 29, 38, 43, + 26, 32, 33, 42, 24, 40, 28, 32, + 32, 32, 36, 32, 43, 25, 21, 31, + 30, 31, 41, 29, 33, 37, 26, 37, + 27, 59, 23, 33, 35, 31, 31, 37, + 38, 39, 32, 23, 32, 27, 37, 36, + 31, 40, 25, 27, 38, 31, 36, 28, + 31, 36, 25, 45, 3, 34, 38, 39, + 40, 38, 30, 32, 19, 24, 25, 26, + 45, 20, 24, 33, 33, 31, 41, 34, + 39, 47, 40, 58, 59, 41, 33, 3, + 17, 61, 42, 30, 26, 29, 36, 61, + 33, 37, 62, 28, 25, 38, 25, 38, + 17, 23, 34, 33, 21, 33, 49, 27, + 32, 23, 27, 22, 24, 22, 39, 43, + 27, 37, 6, 42, 47, 26, 30, 31, + 41, 39, 33, 22, 45, 36, 32, 45, + 19, 22, 30, 5, 5, 17, 29, 22, + 31, 31, 43, 37, 27, 32, 32, 32, + 33, 34, 43, 35, 29, 26, 22, 32, + 19, 32, 25, 31, 41, 49, 28, 34, + 28, 39, 34, 19, 37, 38, 29, 21, + 36, 42, 24, 48, 16, 28, 49, 22, + 34, 31, 38, 39, 44, 11, 35, 30, + 33, 33, 23, 28, 33, 46, 15, 13, + 24, 41, 24, 34, 34, 30, 26, 24, + 14, 60, 21, 29, 39, 23, 35, 37, + 63, 45, 33, 34, 47, 41, 22, 42, + 35, 35, 23, 32, 35, 43, 32, 7, + 31, 41, 20, 31, 16, 13, 63, 25, + 30, 32, 35, 30, 30, 31, 42, 47, + 39, 38, 40, 40, 51, 55, 56, 18, + 21, 39, 39, 33, 17, 41, 23, 24, + 43, 25, 31, 20, 19, 45, 1, 34, + 31, 22, 35, 15, 46, 46, 35, 31, + 28, 29, 29, 23, 41, 27, 14, 53, + 53, 27, 24, 32, 57, 32, 17, 42, + 37, 29, 33, 1, 25, 32, 32, 63, + 26, 40, 44, 36, 31, 39, 20, 20, + 44, 23, 33, 34, 35, 33, 33, 28, + 41, 23, 41, 41, 29, 25, 26, 49, + 29, 24, 37, 49, 50, 51, 51, 26, + 39, 25, 26, 15, 39, 18, 42, 17, + 4, 31, 32, 32, 60, 1, 42, 32, + 0, 12, 19, 35, 21, 41, 17, 26, + 20, 45, 46, 32, 37, 22, 47, 29, + 31, 27, 29, 30, 21, 33, 35, 18, + 25, 33, 50, 51, 42, 2, 15, 51, + 53, 33, 25, 29, 55, 37, 38, 33, + 38, 59, 38, 33, 39, 13, 32, 40, + 61, 61, 32, 9, 44, 3, 31, 29, + 25, 31, 27, 23, 9, 25, 9, 29, + 20, 30, 30, 42, 18, 28, 25, 28, + 28, 21, 29, 43, 29, 43, 26, 44, + 44, 21, 38, 21, 24, 45, 45, 35, + 39, 22, 35, 36, 34, 34, 45, 34, + 29, 31, 46, 25, 46, 16, 17, 31, + 20, 32, 47, 47, 47, 32, 49, 49, + 49, 31, 1, 27, 28, 39, 39, 21, + 36, 23, 51, 2, 40, 51, 32, 53, + 24, 30, 24, 30, 21, 40, 57, 57, + 31, 41, 58, 32, 12, 4, 32, 34, + 59, 31, 32, 13, 9, 35, 26, 35, + 37, 61, 37, 63, 26, 29, 41, 38, + 23, 20, 41, 26, 41, 42, 42, 42, + 26, 26, 26, 26, 1, 26, 37, 37, + 37, 23, 34, 42, 27, 43, 34, 27, + 31, 24, 33, 16, 3, 31, 24, 33, + 24, 4, 44, 44, 11, 44, 31, 13, + 13, 44, 45, 13, 25, 22, 38, 26, + 38, 38, 39, 32, 30, 39, 30, 22, + 32, 26, 30, 47, 47, 47, 19, 47, + 30, 31, 35, 8, 23, 47, 47, 27, + 35, 47, 31, 48, 35, 19, 36, 49, + 49, 33, 31, 39, 27, 39, 49, 49, + 50, 50, 50, 39, 31, 51, 51, 39, + 28, 33, 33, 21, 40, 31, 52, 53, + 40, 53, 9, 33, 31, 53, 54, 54, + 54, 55, 55, 34, 15, 56, 25, 56, + 21, 21, 40, 40, 25, 40, 58, 36, + 5, 41, 41, 12, 60, 41, 41, 37, + 22, 61, 18, 29, 29, 30, 61, 30, + 61, 62, 62, 30, 30, 63, 18, 13, + 30, 23, 19, 20, 20, 41, 13, 2, + 5, 5, 1, 5, 32, 6, 32, 35, + 20, 35, 27, 35, 35, 36, 36, 13, + 36, 41, 41, 41, 3, 30, 42, 27, + 20, 30, 27, 28, 30, 21, 33, 33, + 14, 24, 30, 42, 24, 33, 25, 42, + 43, 14, 43, 43, 14, 43, 7, 36, + 37, 37, 37, 37, 7, 14, 25, 43, + 43, 44, 15, 37, 7, 7, 3, 1, + 8, 15, 15, 8, 44, 44, 44, 45, + 45, 45, 45, 8, 8, 45, 21, 45, + 28, 28, 28, 21, 28, 28, 22, 37, + 46, 46, 37, 8, 29, 37, 29, 22, + 46, 37, 22, 29, 47, 47, 38, 38, + 16, 38, 38, 33, 38, 22, 47, 47, + 29, 25, 16, 0, 48, 1, 34, 48, + 48, 34, 25, 26, 26, 49, 49, 26, + 1, 49, 4, 26, 4, 49, 1, 9, + 49, 49, 49, 10, 49, 17, 38, 17, + 17, 50, 38, 50, 50, 22, 38, 51, + 38, 38, 51, 39, 39, 18, 22, 39, + 51, 22, 52, 52, 52, 39, 53, 53, + 10, 23, 18, 29, 10, 53, 29, 54, + 11, 54, 11, 11, 55, 1, 18, 55, + 55, 55, 55, 55, 55, 29, 34, 18, + 29, 56, 56, 34, 57, 34, 34, 29, + 29, 57, 57, 35, 35, 35, 35, 35, + 39, 35, 59, 59, 18, 59, 39, 30, + 18, 40, 60, 60, 61, 30, 18, 61, + 61, 19, 19, +}; + +static const BYTE table0_mvy[1099] = +{ + 32, 31, 32, 33, 32, 31, 31, 33, + 33, 34, 32, 30, 32, 35, 34, 31, + 32, 29, 33, 30, 32, 34, 33, 31, + 30, 35, 31, 31, 29, 33, 35, 30, + 29, 33, 34, 34, 30, 32, 32, 36, + 29, 32, 35, 32, 28, 32, 32, 27, + 35, 37, 34, 29, 30, 36, 35, 34, + 25, 30, 29, 35, 33, 31, 31, 32, + 31, 28, 39, 28, 29, 37, 31, 33, + 27, 36, 28, 36, 37, 33, 33, 31, + 27, 32, 31, 38, 26, 25, 25, 33, + 39, 31, 34, 30, 32, 32, 32, 34, + 36, 32, 28, 33, 30, 38, 37, 27, + 33, 28, 32, 37, 35, 38, 29, 34, + 27, 29, 29, 32, 32, 34, 35, 3, + 26, 36, 31, 38, 30, 26, 35, 34, + 37, 26, 25, 32, 32, 39, 23, 37, + 32, 32, 29, 32, 29, 36, 29, 30, + 41, 31, 30, 21, 39, 25, 34, 38, + 32, 35, 39, 32, 33, 33, 32, 27, + 29, 25, 28, 27, 26, 31, 30, 35, + 24, 24, 31, 34, 32, 30, 35, 40, + 28, 38, 5, 35, 29, 36, 36, 32, + 38, 30, 33, 31, 35, 26, 23, 38, + 32, 41, 28, 25, 37, 40, 37, 39, + 32, 36, 33, 39, 25, 26, 28, 31, + 28, 42, 23, 31, 33, 31, 39, 1, + 59, 22, 27, 4, 33, 34, 33, 24, + 41, 3, 35, 41, 41, 28, 36, 36, + 28, 33, 35, 21, 23, 21, 22, 37, + 27, 27, 43, 29, 60, 39, 27, 25, + 59, 34, 27, 27, 26, 40, 37, 27, + 61, 26, 39, 33, 31, 22, 37, 25, + 30, 25, 24, 61, 31, 34, 25, 38, + 32, 32, 30, 3, 61, 43, 29, 23, + 28, 32, 28, 32, 31, 34, 5, 33, + 32, 33, 33, 42, 37, 23, 38, 31, + 40, 26, 32, 26, 37, 38, 36, 24, + 29, 30, 20, 22, 29, 24, 32, 41, + 2, 34, 25, 33, 29, 31, 39, 35, + 36, 24, 32, 30, 33, 27, 44, 60, + 30, 36, 19, 34, 31, 24, 16, 35, + 32, 38, 21, 33, 31, 31, 21, 35, + 5, 17, 29, 38, 38, 18, 58, 19, + 43, 41, 30, 41, 43, 39, 29, 7, + 29, 17, 28, 19, 28, 31, 25, 19, + 40, 26, 21, 33, 39, 23, 40, 30, + 39, 34, 35, 32, 32, 24, 33, 30, + 40, 47, 39, 37, 32, 33, 24, 23, + 45, 47, 27, 23, 42, 32, 32, 33, + 36, 37, 37, 17, 18, 22, 40, 38, + 32, 31, 35, 24, 17, 25, 17, 23, + 33, 34, 51, 42, 31, 36, 36, 29, + 21, 22, 37, 44, 43, 25, 47, 33, + 45, 27, 31, 58, 31, 32, 31, 38, + 43, 20, 47, 45, 54, 1, 26, 34, + 38, 14, 22, 24, 33, 34, 32, 32, + 37, 21, 23, 49, 35, 23, 28, 39, + 39, 23, 55, 33, 30, 30, 63, 16, + 42, 28, 13, 33, 33, 35, 19, 46, + 43, 17, 19, 36, 39, 24, 31, 32, + 33, 26, 28, 62, 33, 63, 33, 39, + 19, 49, 17, 31, 43, 13, 15, 29, + 25, 35, 33, 23, 49, 41, 28, 29, + 34, 38, 7, 61, 11, 50, 13, 41, + 19, 47, 25, 26, 15, 42, 41, 29, + 45, 27, 17, 35, 32, 29, 32, 24, + 13, 26, 26, 31, 24, 33, 28, 30, + 31, 11, 45, 46, 33, 33, 35, 57, + 32, 32, 35, 45, 34, 11, 37, 42, + 39, 37, 31, 49, 21, 27, 29, 47, + 53, 40, 51, 16, 26, 1, 40, 30, + 41, 44, 34, 25, 27, 31, 35, 35, + 31, 15, 49, 1, 35, 40, 5, 58, + 21, 29, 22, 59, 45, 31, 9, 26, + 9, 29, 11, 32, 30, 3, 13, 20, + 18, 20, 11, 3, 29, 40, 31, 53, + 30, 17, 20, 37, 31, 42, 47, 47, + 54, 38, 9, 34, 13, 37, 21, 25, + 27, 43, 42, 45, 40, 25, 27, 46, + 22, 25, 53, 20, 2, 14, 39, 15, + 22, 44, 34, 21, 38, 33, 27, 48, + 34, 52, 35, 47, 49, 54, 2, 13, + 23, 52, 29, 45, 22, 49, 54, 21, + 40, 42, 31, 30, 29, 34, 0, 25, + 23, 51, 24, 59, 28, 38, 29, 31, + 2, 13, 31, 8, 31, 33, 12, 45, + 41, 7, 14, 30, 25, 18, 43, 20, + 43, 35, 44, 1, 49, 42, 42, 18, + 41, 38, 41, 44, 53, 11, 20, 25, + 45, 46, 47, 48, 39, 52, 46, 49, + 63, 55, 44, 38, 13, 13, 57, 22, + 51, 16, 12, 28, 35, 57, 25, 20, + 26, 28, 28, 29, 32, 31, 62, 34, + 35, 35, 19, 49, 48, 39, 40, 18, + 43, 46, 11, 6, 48, 19, 49, 41, + 10, 23, 58, 17, 21, 23, 34, 30, + 60, 0, 44, 34, 26, 37, 46, 43, + 49, 59, 4, 34, 59, 37, 22, 25, + 28, 46, 6, 40, 59, 42, 36, 61, + 28, 30, 31, 43, 10, 22, 23, 47, + 20, 52, 55, 36, 25, 16, 1, 11, + 27, 29, 5, 63, 18, 41, 31, 34, + 38, 1, 5, 13, 28, 31, 17, 38, + 39, 41, 36, 37, 22, 39, 33, 43, + 43, 15, 17, 49, 30, 21, 22, 20, + 10, 17, 25, 54, 57, 3, 34, 8, + 36, 25, 31, 14, 15, 19, 29, 25, + 18, 39, 53, 22, 27, 20, 29, 33, + 41, 42, 35, 62, 50, 29, 53, 50, + 35, 55, 42, 61, 63, 4, 7, 42, + 21, 46, 47, 49, 27, 46, 17, 55, + 41, 50, 63, 4, 56, 18, 8, 10, + 18, 51, 63, 36, 55, 18, 5, 55, + 9, 29, 17, 21, 30, 27, 1, 59, + 7, 11, 12, 15, 5, 42, 24, 41, + 43, 7, 27, 22, 25, 31, 30, 37, + 22, 39, 53, 29, 36, 37, 48, 0, + 5, 13, 17, 31, 32, 26, 46, 28, + 44, 45, 46, 53, 49, 51, 3, 41, + 3, 22, 42, 33, 5, 45, 7, 22, + 40, 53, 24, 14, 25, 27, 10, 12, + 34, 16, 17, 53, 20, 26, 39, 45, + 18, 45, 35, 33, 31, 49, 4, 39, + 42, 11, 51, 5, 13, 26, 27, 17, + 52, 30, 0, 22, 12, 34, 62, 36, + 38, 41, 47, 30, 63, 38, 41, 43, + 59, 33, 45, 37, 38, 40, 47, 24, + 48, 49, 30, 1, 10, 22, 49, 15, + 39, 59, 31, 32, 33, 18, 13, 15, + 31, 21, 27, 44, 42, 39, 46, 17, + 26, 32, 30, 31, 0, 30, 34, 9, + 12, 13, 25, 31, 32, 55, 43, 35, + 61, 33, 35, 46, 25, 47, 48, 62, + 63, 38, 61, 1, 2, 5, 7, 9, + 46, 10, 34, 35, 36, 55, 51, 7, + 40, 23, 34, 37, 5, 13, 42, 18, + 25, 27, 28, +}; + +/* motion vector table 1 */ +static const WORD table1_mv_code[1100] = +{ + 0x0000, 0x0007, 0x0009, 0x000f, 0x000a, 0x0011, 0x001a, 0x001c, + 0x0011, 0x0031, 0x0025, 0x002d, 0x002f, 0x006f, 0x0075, 0x0041, + 0x004c, 0x004e, 0x005c, 0x0060, 0x0062, 0x0066, 0x0068, 0x0069, + 0x006b, 0x00a6, 0x00c1, 0x00cb, 0x00cc, 0x00ce, 0x00da, 0x00e8, + 0x00ee, 0x0087, 0x0090, 0x009e, 0x009f, 0x00ba, 0x00ca, 0x00d8, + 0x00db, 0x00df, 0x0104, 0x0109, 0x010c, 0x0143, 0x0145, 0x014a, + 0x0156, 0x015c, 0x01b3, 0x01d3, 0x01da, 0x0103, 0x0109, 0x010b, + 0x0122, 0x0127, 0x0134, 0x0161, 0x0164, 0x0176, 0x0184, 0x018d, + 0x018e, 0x018f, 0x0190, 0x0193, 0x0196, 0x019d, 0x019e, 0x019f, + 0x01a9, 0x01b2, 0x01b4, 0x01ba, 0x01bb, 0x01bc, 0x0201, 0x0202, + 0x0205, 0x0207, 0x020d, 0x0210, 0x0211, 0x0215, 0x021b, 0x021f, + 0x0281, 0x0285, 0x0290, 0x029c, 0x029d, 0x02a2, 0x02a7, 0x02a8, + 0x02aa, 0x02b0, 0x02b1, 0x02b4, 0x02bc, 0x02bf, 0x0320, 0x0326, + 0x0327, 0x0329, 0x032a, 0x0336, 0x0360, 0x0362, 0x0363, 0x0372, + 0x03b2, 0x03bc, 0x03bd, 0x0203, 0x0205, 0x021a, 0x0249, 0x024a, + 0x024c, 0x02c7, 0x02ca, 0x02ce, 0x02ef, 0x030d, 0x0322, 0x0325, + 0x0338, 0x0373, 0x037a, 0x0409, 0x0415, 0x0416, 0x0418, 0x0428, + 0x042d, 0x042f, 0x0434, 0x0508, 0x0509, 0x0510, 0x0511, 0x051c, + 0x051e, 0x0524, 0x0541, 0x0543, 0x0546, 0x0547, 0x054d, 0x0557, + 0x055f, 0x056a, 0x056c, 0x056d, 0x056f, 0x0576, 0x0577, 0x057a, + 0x057b, 0x057c, 0x057d, 0x0600, 0x0601, 0x0603, 0x0614, 0x0616, + 0x0617, 0x061c, 0x061f, 0x0642, 0x0648, 0x0649, 0x064a, 0x064b, + 0x0657, 0x0668, 0x0669, 0x066b, 0x066e, 0x067f, 0x06c2, 0x06c8, + 0x06cb, 0x06de, 0x06df, 0x06e2, 0x06e3, 0x06ef, 0x0748, 0x074b, + 0x076e, 0x076f, 0x077c, 0x0409, 0x0423, 0x0428, 0x0429, 0x042a, + 0x042b, 0x0432, 0x0433, 0x0496, 0x049a, 0x04d5, 0x04db, 0x0581, + 0x0582, 0x058b, 0x058c, 0x058d, 0x0598, 0x0599, 0x059a, 0x059e, + 0x05dd, 0x0619, 0x0632, 0x0633, 0x0648, 0x0672, 0x06a1, 0x06a2, + 0x06a3, 0x06af, 0x06e2, 0x06e3, 0x06e4, 0x0800, 0x0801, 0x0802, + 0x0803, 0x081a, 0x081b, 0x0829, 0x082f, 0x0832, 0x083e, 0x083f, + 0x0852, 0x0853, 0x0858, 0x086b, 0x0877, 0x0878, 0x0879, 0x087a, + 0x087b, 0x0a00, 0x0a01, 0x0a0d, 0x0a0e, 0x0a0f, 0x0a24, 0x0a37, + 0x0a3a, 0x0a3b, 0x0a3e, 0x0a46, 0x0a47, 0x0a4a, 0x0a4b, 0x0a5f, + 0x0a79, 0x0a7a, 0x0a7b, 0x0a80, 0x0a81, 0x0a84, 0x0a85, 0x0a99, + 0x0aa5, 0x0aa6, 0x0ab8, 0x0aba, 0x0abb, 0x0abc, 0x0abd, 0x0ac8, + 0x0ace, 0x0acf, 0x0ad7, 0x0adc, 0x0aeb, 0x0c04, 0x0c25, 0x0c26, + 0x0c27, 0x0c2a, 0x0c2b, 0x0c3a, 0x0c3b, 0x0c3c, 0x0c3d, 0x0ca0, + 0x0cad, 0x0cd4, 0x0cd5, 0x0cfc, 0x0cfd, 0x0d86, 0x0d92, 0x0d93, + 0x0d94, 0x0d95, 0x0db0, 0x0db8, 0x0db9, 0x0dba, 0x0dbb, 0x0dc0, + 0x0dc2, 0x0dc3, 0x0dda, 0x0ddb, 0x0ddc, 0x0ddd, 0x0e92, 0x0e93, + 0x0e94, 0x0e95, 0x0ec7, 0x0ecc, 0x0ece, 0x0ecf, 0x0ed8, 0x0ed9, + 0x0eda, 0x0edb, 0x0808, 0x0809, 0x080a, 0x0810, 0x0811, 0x0844, + 0x0845, 0x0861, 0x0862, 0x0863, 0x086c, 0x0922, 0x0923, 0x092e, + 0x092f, 0x0936, 0x0937, 0x09b1, 0x09b2, 0x09b3, 0x09b4, 0x09b5, + 0x09b8, 0x09b9, 0x09ba, 0x09bb, 0x09bc, 0x09bd, 0x09be, 0x09bf, + 0x0b00, 0x0b15, 0x0b2c, 0x0b2d, 0x0b2e, 0x0b2f, 0x0b36, 0x0bb9, + 0x0c28, 0x0c2a, 0x0c2b, 0x0c2c, 0x0c2d, 0x0c2e, 0x0c2f, 0x0c30, + 0x0c31, 0x0c38, 0x0c60, 0x0c61, 0x0c62, 0x0c63, 0x0c8d, 0x0c8e, + 0x0c8f, 0x0c92, 0x0cbe, 0x0cbf, 0x0ce6, 0x0ce7, 0x0d40, 0x0d41, + 0x0d57, 0x0d58, 0x0d59, 0x0d5a, 0x0d5b, 0x0d5c, 0x0d5d, 0x0d98, + 0x0d99, 0x0d9a, 0x0d9b, 0x0d9c, 0x0d9d, 0x0dad, 0x0dae, 0x0daf, + 0x0dc0, 0x0dc1, 0x0dc2, 0x0dc3, 0x0dca, 0x0dcb, 0x0dec, 0x0ded, + 0x0dee, 0x0def, 0x1018, 0x1022, 0x1023, 0x1030, 0x1031, 0x1032, + 0x1033, 0x1050, 0x1051, 0x105c, 0x1074, 0x1075, 0x1076, 0x1077, + 0x1078, 0x1079, 0x107a, 0x107b, 0x10b2, 0x10b3, 0x10b8, 0x10b9, + 0x10ba, 0x10bb, 0x10d4, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x1404, + 0x1405, 0x1406, 0x1407, 0x1410, 0x1411, 0x1412, 0x1413, 0x1414, + 0x1415, 0x1416, 0x1417, 0x1418, 0x1419, 0x1466, 0x1467, 0x1468, + 0x1469, 0x146a, 0x146b, 0x146c, 0x146d, 0x147e, 0x147f, 0x1488, + 0x1489, 0x148a, 0x148b, 0x14b6, 0x14b7, 0x14b8, 0x14b9, 0x14ba, + 0x14bb, 0x14bc, 0x14bd, 0x14f0, 0x14f1, 0x14f8, 0x14f9, 0x14fa, + 0x14fb, 0x14fc, 0x14fd, 0x14fe, 0x14ff, 0x152a, 0x152b, 0x152c, + 0x152d, 0x152e, 0x152f, 0x1530, 0x1531, 0x1548, 0x1549, 0x154e, + 0x154f, 0x1558, 0x1559, 0x155a, 0x155b, 0x1572, 0x159a, 0x159b, + 0x15ac, 0x15ba, 0x15bb, 0x15d0, 0x15d1, 0x15d2, 0x15d3, 0x15d4, + 0x15d5, 0x181d, 0x181e, 0x181f, 0x1840, 0x1841, 0x1842, 0x1843, + 0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x1861, 0x1862, + 0x1863, 0x1864, 0x1865, 0x1866, 0x1867, 0x1868, 0x1869, 0x186a, + 0x186b, 0x186c, 0x186d, 0x186e, 0x191b, 0x191c, 0x191d, 0x191e, + 0x191f, 0x1942, 0x1943, 0x1944, 0x1945, 0x1946, 0x1947, 0x1958, + 0x1959, 0x19ed, 0x19ee, 0x19ef, 0x19f0, 0x19f1, 0x19f2, 0x19f3, + 0x19f4, 0x19f5, 0x19f6, 0x19f7, 0x1b0e, 0x1b0f, 0x1b62, 0x1b63, + 0x1b64, 0x1b65, 0x1b66, 0x1b67, 0x1b68, 0x1b69, 0x1b6a, 0x1b6b, + 0x1b6c, 0x1b6d, 0x1b6e, 0x1b6f, 0x1b82, 0x1ba8, 0x1ba9, 0x1baa, + 0x1bab, 0x1bac, 0x1bad, 0x1bae, 0x1baf, 0x1bb0, 0x1bb1, 0x1bb2, + 0x1bb3, 0x1d80, 0x1d81, 0x1d82, 0x1d83, 0x1d84, 0x1d85, 0x1d86, + 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b, 0x1d8c, 0x1d8d, 0x1007, + 0x1008, 0x1009, 0x100a, 0x100b, 0x100c, 0x100d, 0x100e, 0x100f, + 0x1016, 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, + 0x1087, 0x10c0, 0x123a, 0x123b, 0x123c, 0x123d, 0x123e, 0x123f, + 0x1240, 0x1241, 0x1242, 0x1243, 0x1350, 0x1352, 0x1353, 0x1358, + 0x1359, 0x135a, 0x135b, 0x135c, 0x135d, 0x135e, 0x135f, 0x1360, + 0x1361, 0x1602, 0x1603, 0x160c, 0x160d, 0x160e, 0x160f, 0x1620, + 0x1621, 0x1622, 0x1623, 0x1624, 0x1625, 0x1626, 0x1627, 0x1628, + 0x1629, 0x166e, 0x166f, 0x167c, 0x167d, 0x167e, 0x167f, 0x1770, + 0x1771, 0x1852, 0x1853, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, + 0x1877, 0x1878, 0x1879, 0x187a, 0x187b, 0x187c, 0x187d, 0x187e, + 0x187f, 0x1918, 0x1919, 0x1926, 0x1927, 0x1970, 0x1971, 0x1972, + 0x1973, 0x1974, 0x1975, 0x1976, 0x1977, 0x1978, 0x1979, 0x197a, + 0x197b, 0x1aa0, 0x1aa1, 0x1aa2, 0x1aa3, 0x1aa4, 0x1aa5, 0x1aa6, + 0x1aa7, 0x1aa8, 0x1aa9, 0x1aaa, 0x1aab, 0x1aac, 0x1aad, 0x1b3c, + 0x1b3d, 0x1b3e, 0x1b3f, 0x1b50, 0x1b51, 0x1b52, 0x1b53, 0x1b54, + 0x1b55, 0x1b56, 0x1b57, 0x1b58, 0x1b59, 0x2032, 0x2033, 0x2034, + 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203a, 0x203b, 0x203c, + 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043, 0x20ba, + 0x20bb, 0x20cc, 0x20cd, 0x20ce, 0x20cf, 0x20e0, 0x20e1, 0x20e2, + 0x20e3, 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x21aa, 0x21ab, 0x21c0, + 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, 0x21c8, + 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, 0x21d0, + 0x21d1, 0x21d2, 0x21d3, 0x2894, 0x2895, 0x2896, 0x2897, 0x2898, + 0x2899, 0x289a, 0x289b, 0x289c, 0x289d, 0x289e, 0x289f, 0x28c0, + 0x28c1, 0x28c2, 0x28c3, 0x28c4, 0x28c5, 0x28c6, 0x28c7, 0x28c8, + 0x28c9, 0x28ca, 0x28cb, 0x2930, 0x2931, 0x2932, 0x2933, 0x2934, + 0x2935, 0x2936, 0x2937, 0x2938, 0x2939, 0x293a, 0x293b, 0x293c, + 0x293d, 0x293e, 0x293f, 0x2960, 0x2961, 0x2962, 0x2963, 0x2964, + 0x2965, 0x2966, 0x2967, 0x2968, 0x2969, 0x296a, 0x296b, 0x2a40, + 0x2a41, 0x2a42, 0x2a43, 0x2a44, 0x2a45, 0x2a46, 0x2a47, 0x2a48, + 0x2a49, 0x2a4a, 0x2a4b, 0x2a4c, 0x2a4d, 0x2a4e, 0x2a4f, 0x2a50, + 0x2a51, 0x2a52, 0x2a53, 0x2ae6, 0x2ae7, 0x2b24, 0x2b25, 0x2b26, + 0x2b27, 0x2b28, 0x2b29, 0x2b2a, 0x2b2b, 0x2b2c, 0x2b2d, 0x2b2e, + 0x2b2f, 0x2b30, 0x2b31, 0x2b32, 0x2b33, 0x2b5a, 0x2b5b, 0x3014, + 0x3015, 0x3016, 0x3017, 0x3020, 0x3021, 0x3022, 0x3023, 0x3024, + 0x3025, 0x3026, 0x3027, 0x3028, 0x3029, 0x302a, 0x302b, 0x302c, + 0x302d, 0x302e, 0x302f, 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, + 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, 0x30c0, 0x30c1, 0x30de, + 0x30df, 0x3218, 0x3219, 0x321a, 0x321b, 0x321c, 0x321d, 0x321e, + 0x321f, 0x3220, 0x3221, 0x3222, 0x3223, 0x3224, 0x3225, 0x3226, + 0x3227, 0x3228, 0x3229, 0x322a, 0x322b, 0x322c, 0x322d, 0x322e, + 0x322f, 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3378, + 0x3379, 0x337a, 0x337b, 0x337c, 0x337d, 0x337e, 0x337f, 0x33c0, + 0x33c1, 0x33c2, 0x33c3, 0x33c4, 0x33c5, 0x33c6, 0x33c7, 0x33c8, + 0x33c9, 0x33ca, 0x33cb, 0x33cc, 0x33cd, 0x33ce, 0x33cf, 0x33d0, + 0x33d1, 0x33d2, 0x33d3, 0x33d4, 0x33d5, 0x33d6, 0x33d7, 0x33d8, + 0x33d9, 0x3706, 0x3707, 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, + 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, 0x373a, 0x373b, 0x373c, + 0x373d, 0x373e, 0x373f, 0x3740, 0x3741, 0x3742, 0x3743, 0x3744, + 0x3745, 0x3746, 0x3747, 0x3748, 0x3749, 0x374a, 0x374b, 0x374c, + 0x374d, 0x374e, 0x374f, 0x3b34, 0x3b35, 0x3b36, 0x3b37, 0x3be8, + 0x3be9, 0x3bea, 0x3beb, 0x3bec, 0x3bed, 0x3bee, 0x3bef, 0x3bf0, + 0x3bf1, 0x3bf2, 0x3bf3, 0x3bf4, 0x3bf5, 0x3bf6, 0x3bf7, 0x3bf8, + 0x3bf9, 0x3bfa, 0x3bfb, 0x3bfc, 0x3bfd, 0x3bfe, 0x3bff, 0x2000, + 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, + 0x2009, 0x200a, 0x200b, 0x200c, 0x200d, 0x202e, 0x202f, 0x2182, + 0x2183, 0x21b4, 0x21b5, 0x21b6, 0x21b7, 0x21b8, 0x21b9, 0x21ba, + 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, 0x2460, 0x2461, 0x2462, + 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246a, + 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x2470, 0x2471, 0x2472, + 0x2473, 0x26a2, 0x26a3, 0x000b, +}; + +static const BYTE table1_mv_bits[1100] = +{ + 2, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 7, 7, 7, 7, 7, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 4, +}; + +static const BYTE table1_mvx[1099] = +{ + 32, 31, 32, 31, 33, 32, 33, 33, + 31, 34, 30, 32, 32, 34, 35, 32, + 34, 33, 29, 30, 30, 32, 31, 31, + 33, 35, 35, 33, 31, 29, 29, 33, + 34, 30, 31, 28, 36, 30, 34, 32, + 32, 37, 32, 32, 25, 27, 39, 32, + 32, 32, 38, 35, 36, 32, 37, 61, + 26, 32, 34, 35, 3, 35, 27, 28, + 29, 34, 28, 37, 31, 36, 32, 27, + 31, 30, 29, 39, 33, 29, 33, 35, + 25, 25, 29, 33, 31, 31, 31, 33, + 32, 30, 32, 32, 41, 39, 33, 36, + 32, 28, 34, 36, 38, 24, 60, 31, + 23, 28, 32, 33, 59, 32, 40, 30, + 5, 34, 32, 38, 32, 30, 43, 4, + 32, 32, 42, 31, 31, 32, 26, 38, + 26, 22, 21, 37, 61, 63, 37, 31, + 32, 33, 2, 1, 23, 33, 41, 27, + 35, 30, 38, 23, 33, 3, 28, 34, + 34, 27, 41, 29, 39, 35, 36, 29, + 32, 27, 30, 32, 24, 61, 37, 26, + 59, 25, 35, 27, 36, 37, 30, 31, + 34, 40, 3, 28, 34, 39, 32, 31, + 32, 30, 24, 28, 35, 36, 26, 32, + 31, 33, 29, 33, 39, 25, 30, 24, + 35, 59, 29, 34, 25, 30, 21, 35, + 43, 40, 32, 29, 5, 28, 31, 62, + 33, 33, 25, 31, 21, 31, 43, 31, + 34, 33, 20, 40, 39, 31, 31, 57, + 38, 32, 42, 33, 32, 31, 32, 29, + 30, 44, 5, 31, 22, 34, 36, 17, + 38, 58, 38, 35, 32, 60, 35, 24, + 32, 38, 16, 45, 42, 32, 31, 29, + 4, 30, 17, 40, 46, 48, 63, 32, + 42, 19, 41, 22, 28, 36, 45, 33, + 33, 32, 29, 7, 41, 42, 18, 33, + 33, 32, 22, 37, 1, 26, 22, 23, + 49, 28, 26, 27, 32, 33, 27, 23, + 28, 36, 15, 6, 34, 27, 31, 26, + 23, 2, 33, 32, 34, 41, 28, 32, + 41, 0, 36, 38, 34, 31, 47, 32, + 17, 31, 39, 33, 37, 51, 30, 47, + 32, 50, 32, 19, 63, 30, 25, 27, + 33, 62, 24, 31, 27, 30, 37, 31, + 45, 32, 39, 20, 46, 47, 35, 19, + 34, 1, 49, 21, 21, 14, 51, 26, + 23, 31, 36, 35, 58, 29, 29, 21, + 20, 42, 13, 28, 12, 40, 31, 33, + 39, 60, 32, 44, 33, 31, 28, 37, + 29, 32, 30, 49, 43, 28, 39, 25, + 32, 48, 2, 15, 20, 25, 31, 28, + 21, 24, 25, 15, 31, 17, 37, 43, + 18, 32, 33, 24, 33, 36, 13, 33, + 31, 39, 11, 31, 33, 32, 39, 37, + 32, 32, 29, 17, 44, 46, 36, 35, + 26, 37, 58, 32, 34, 38, 8, 38, + 38, 22, 29, 25, 16, 35, 32, 35, + 33, 43, 18, 46, 38, 50, 33, 18, + 53, 60, 13, 32, 36, 33, 51, 36, + 43, 45, 27, 42, 29, 24, 30, 25, + 31, 52, 31, 35, 38, 9, 22, 34, + 4, 17, 28, 55, 42, 25, 17, 20, + 47, 34, 33, 16, 40, 25, 16, 30, + 53, 29, 10, 11, 14, 26, 33, 4, + 35, 44, 26, 16, 31, 26, 34, 38, + 29, 31, 30, 24, 22, 61, 32, 9, + 45, 34, 31, 19, 9, 31, 46, 31, + 35, 54, 29, 57, 30, 50, 3, 31, + 63, 34, 47, 41, 51, 18, 31, 14, + 37, 38, 31, 24, 32, 31, 50, 33, + 31, 54, 27, 9, 33, 23, 19, 32, + 29, 29, 33, 28, 47, 49, 30, 47, + 33, 27, 25, 54, 44, 45, 50, 58, + 51, 48, 33, 59, 33, 34, 57, 13, + 26, 33, 13, 48, 30, 11, 7, 56, + 34, 55, 26, 0, 26, 35, 1, 51, + 33, 53, 31, 45, 12, 29, 29, 51, + 31, 48, 2, 6, 34, 30, 28, 33, + 60, 40, 27, 46, 31, 9, 35, 29, + 31, 39, 55, 46, 19, 37, 62, 34, + 30, 16, 19, 49, 41, 41, 39, 37, + 14, 5, 13, 35, 55, 30, 40, 40, + 42, 8, 20, 25, 45, 35, 33, 36, + 54, 38, 27, 37, 62, 40, 15, 59, + 49, 31, 29, 34, 34, 39, 24, 29, + 25, 29, 21, 29, 10, 61, 33, 49, + 35, 34, 3, 38, 39, 29, 7, 41, + 1, 35, 4, 23, 15, 23, 11, 37, + 28, 35, 30, 30, 24, 1, 43, 56, + 8, 34, 42, 24, 45, 30, 20, 23, + 8, 38, 22, 33, 17, 52, 34, 22, + 53, 43, 44, 1, 27, 31, 41, 43, + 41, 30, 31, 36, 30, 5, 55, 31, + 33, 30, 40, 23, 15, 29, 34, 34, + 59, 34, 30, 11, 13, 38, 5, 0, + 30, 42, 5, 30, 29, 34, 10, 44, + 30, 63, 35, 12, 3, 26, 15, 17, + 25, 34, 43, 39, 34, 56, 29, 23, + 30, 12, 30, 10, 35, 9, 24, 58, + 10, 12, 54, 33, 37, 20, 41, 35, + 29, 18, 61, 30, 40, 24, 39, 53, + 62, 26, 29, 33, 34, 53, 49, 21, + 27, 11, 63, 20, 26, 23, 7, 13, + 6, 47, 29, 30, 9, 51, 22, 34, + 21, 25, 33, 56, 57, 30, 38, 51, + 51, 38, 63, 28, 40, 35, 33, 18, + 33, 33, 24, 58, 58, 34, 49, 29, + 43, 4, 1, 4, 42, 35, 35, 30, + 17, 5, 56, 61, 25, 37, 36, 55, + 28, 35, 29, 50, 48, 52, 2, 42, + 34, 40, 46, 46, 43, 35, 29, 48, + 20, 29, 31, 41, 7, 30, 35, 19, + 14, 21, 8, 39, 39, 40, 46, 55, + 34, 6, 30, 34, 37, 25, 37, 33, + 22, 44, 52, 17, 35, 29, 36, 35, + 40, 37, 28, 30, 50, 14, 28, 55, + 6, 23, 19, 14, 30, 3, 30, 28, + 28, 61, 61, 47, 45, 48, 40, 40, + 34, 34, 25, 30, 29, 35, 4, 26, + 53, 50, 26, 41, 27, 59, 27, 38, + 39, 3, 50, 43, 47, 23, 33, 55, + 35, 21, 23, 35, 61, 33, 46, 52, + 35, 34, 24, 30, 43, 16, 37, 21, + 2, 24, 45, 34, 30, 55, 55, 1, + 29, 29, 26, 28, 25, 31, 36, 22, + 17, 30, 52, 2, 44, 44, 57, 26, + 62, 41, 39, 57, 26, 46, 49, 11, + 16, 19, 5, 59, 38, 39, 58, 38, + 25, 49, 50, 22, 28, 59, 9, 59, + 7, 28, 55, 17, 4, 35, 50, 21, + 29, 44, 47, 18, 24, 19, 25, 42, + 35, 3, 51, 35, 16, 35, 30, 63, + 57, 39, 39, 25, 35, 38, 9, 16, + 36, 45, 31, 60, 14, 34, 42, 24, + 0, 37, 18, 61, 57, 37, 28, 53, + 20, 46, 14, 47, 38, 38, 38, 9, + 34, 39, 43, 17, 39, 59, 5, 27, + 0, 12, 27, +}; + +static const BYTE table1_mvy[1099] = +{ + 32, 32, 31, 31, 32, 33, 31, 33, + 33, 32, 32, 30, 34, 31, 32, 29, + 33, 30, 32, 33, 31, 35, 34, 30, + 34, 31, 33, 29, 29, 31, 33, 35, + 30, 30, 35, 32, 32, 34, 34, 28, + 25, 32, 36, 27, 32, 32, 32, 37, + 39, 3, 32, 30, 31, 26, 31, 32, + 32, 38, 29, 29, 32, 34, 31, 31, + 34, 35, 33, 33, 28, 33, 1, 33, + 27, 29, 30, 31, 28, 29, 37, 35, + 31, 33, 35, 27, 36, 37, 25, 25, + 61, 35, 4, 5, 32, 33, 36, 30, + 23, 30, 28, 34, 31, 32, 32, 39, + 32, 34, 21, 39, 32, 59, 32, 28, + 32, 36, 60, 33, 24, 36, 32, 32, + 41, 2, 32, 38, 26, 22, 33, 30, + 31, 32, 32, 30, 31, 32, 29, 3, + 40, 38, 32, 32, 33, 26, 31, 34, + 28, 38, 34, 31, 3, 31, 35, 38, + 27, 35, 33, 28, 29, 27, 29, 27, + 43, 29, 37, 63, 31, 33, 34, 30, + 31, 30, 37, 30, 35, 35, 26, 41, + 37, 31, 33, 28, 26, 30, 42, 24, + 7, 27, 33, 29, 36, 28, 34, 57, + 23, 41, 36, 23, 35, 34, 25, 30, + 25, 33, 25, 25, 29, 24, 33, 39, + 33, 33, 0, 37, 31, 36, 21, 32, + 61, 24, 35, 61, 31, 5, 31, 59, + 39, 21, 32, 30, 34, 22, 40, 32, + 29, 16, 31, 5, 62, 2, 20, 39, + 39, 32, 33, 1, 31, 24, 36, 32, + 36, 32, 28, 26, 6, 31, 38, 34, + 58, 35, 32, 33, 33, 17, 43, 26, + 31, 40, 31, 34, 32, 32, 31, 19, + 30, 32, 29, 33, 38, 38, 32, 59, + 40, 18, 38, 32, 35, 34, 32, 17, + 1, 15, 30, 28, 31, 28, 34, 29, + 32, 27, 35, 27, 49, 22, 37, 34, + 37, 26, 32, 32, 22, 28, 45, 29, + 30, 31, 43, 46, 41, 30, 26, 13, + 34, 32, 27, 38, 42, 42, 33, 47, + 33, 60, 27, 42, 25, 32, 22, 32, + 48, 32, 45, 33, 33, 41, 27, 25, + 19, 31, 35, 19, 36, 42, 27, 17, + 31, 44, 28, 33, 33, 31, 23, 31, + 40, 33, 31, 34, 30, 32, 33, 36, + 35, 47, 37, 41, 31, 23, 41, 29, + 30, 35, 32, 25, 32, 28, 58, 2, + 37, 33, 14, 33, 49, 20, 39, 36, + 21, 9, 23, 33, 35, 24, 39, 37, + 11, 33, 30, 31, 31, 28, 51, 40, + 35, 29, 25, 33, 46, 35, 37, 30, + 30, 8, 63, 28, 15, 40, 33, 45, + 49, 25, 32, 4, 47, 51, 36, 39, + 53, 10, 24, 29, 30, 31, 25, 40, + 38, 38, 33, 56, 23, 27, 32, 37, + 26, 29, 43, 36, 33, 24, 55, 43, + 9, 29, 34, 34, 24, 33, 18, 33, + 33, 30, 31, 50, 24, 60, 30, 39, + 34, 30, 39, 28, 22, 38, 2, 26, + 63, 32, 57, 21, 39, 33, 28, 18, + 30, 34, 22, 33, 29, 41, 30, 34, + 35, 21, 13, 34, 35, 39, 30, 46, + 32, 42, 32, 31, 33, 26, 11, 33, + 22, 31, 25, 31, 53, 27, 43, 25, + 40, 50, 21, 36, 38, 30, 12, 31, + 34, 20, 15, 29, 32, 62, 30, 13, + 17, 32, 19, 31, 20, 31, 30, 7, + 1, 17, 34, 37, 31, 31, 44, 34, + 26, 40, 16, 37, 52, 48, 30, 20, + 18, 33, 38, 29, 7, 25, 30, 54, + 45, 47, 46, 41, 29, 29, 16, 30, + 14, 26, 38, 34, 34, 29, 34, 30, + 29, 30, 57, 30, 4, 46, 33, 29, + 39, 44, 30, 31, 50, 33, 31, 32, + 19, 32, 40, 31, 37, 47, 1, 35, + 16, 31, 0, 35, 33, 1, 17, 34, + 9, 34, 33, 31, 49, 43, 42, 51, + 34, 29, 23, 29, 14, 30, 45, 49, + 11, 24, 31, 28, 35, 41, 30, 44, + 18, 29, 34, 35, 36, 25, 26, 21, + 31, 30, 34, 19, 34, 44, 36, 38, + 25, 31, 28, 23, 37, 3, 55, 41, + 30, 22, 41, 24, 33, 26, 35, 35, + 30, 55, 51, 47, 48, 38, 24, 15, + 21, 50, 25, 46, 30, 29, 10, 34, + 42, 45, 29, 42, 22, 3, 33, 27, + 34, 1, 34, 28, 34, 36, 35, 23, + 23, 13, 58, 3, 26, 63, 25, 31, + 34, 61, 38, 39, 25, 61, 29, 37, + 30, 41, 26, 48, 28, 33, 50, 35, + 30, 37, 29, 29, 40, 6, 39, 28, + 28, 19, 8, 22, 45, 34, 35, 10, + 58, 17, 37, 39, 30, 18, 54, 14, + 29, 16, 59, 30, 35, 23, 35, 30, + 47, 36, 29, 55, 20, 12, 31, 35, + 14, 29, 18, 34, 34, 24, 29, 26, + 22, 2, 27, 23, 8, 30, 55, 38, + 60, 31, 4, 34, 49, 34, 27, 34, + 33, 30, 31, 54, 42, 35, 38, 46, + 44, 26, 27, 9, 39, 25, 21, 29, + 28, 42, 13, 0, 5, 34, 37, 28, + 24, 29, 63, 26, 22, 27, 29, 25, + 33, 25, 61, 0, 35, 25, 36, 15, + 27, 40, 53, 33, 3, 10, 16, 37, + 38, 18, 30, 46, 27, 9, 6, 29, + 62, 8, 42, 28, 29, 3, 25, 16, + 26, 29, 35, 28, 27, 51, 61, 48, + 37, 9, 34, 7, 49, 45, 20, 29, + 21, 5, 5, 29, 28, 34, 29, 24, + 10, 24, 35, 36, 38, 55, 11, 36, + 38, 53, 54, 26, 30, 49, 20, 27, + 30, 39, 33, 41, 49, 22, 38, 38, + 4, 30, 8, 9, 3, 24, 22, 50, + 37, 36, 31, 27, 2, 9, 42, 63, + 25, 19, 44, 1, 28, 28, 48, 30, + 34, 41, 41, 38, 12, 27, 15, 0, + 16, 34, 35, 38, 28, 29, 40, 42, + 51, 52, 45, 54, 59, 59, 42, 44, + 37, 26, 46, 24, 15, 39, 22, 46, + 19, 35, 38, 17, 37, 23, 52, 55, + 50, 37, 26, 11, 37, 12, 24, 30, + 16, 13, 22, 13, 36, 35, 40, 41, + 34, 41, 26, 53, 51, 5, 21, 30, + 2, 63, 41, 20, 1, 56, 21, 24, + 25, 5, 28, 35, 26, 28, 30, 18, + 29, 23, 40, 34, 20, 42, 39, 34, + 28, 61, 38, 27, 62, 9, 36, 17, + 9, 49, 24, 25, 54, 34, 39, 37, + 3, 1, 25, 38, 38, 44, 35, 36, + 12, 60, 36, 38, 40, 25, 43, 39, + 53, 28, 39, 57, 46, 10, 52, 27, + 35, 42, 45, 59, 15, 60, 38, 24, + 23, 39, 12, 29, 24, 0, 20, 16, + 28, 43, 35, 28, 1, 49, 4, 21, + 42, 39, 29, 3, 44, 21, 53, 55, + 11, 5, 3, 39, 53, 28, 25, 19, + 34, 28, 21, +}; + + +const BYTE mvtab[33][2] = +{ + {1,1}, {1,2}, {1,3}, {1,4}, {3,6}, {5,7}, {4,7}, {3,7}, + {11,9}, {10,9}, {9,9}, {17,10}, {16,10}, {15,10}, {14,10}, {13,10}, + {12,10}, {11,10}, {10,10}, {9,10}, {8,10}, {7,10}, {6,10}, {5,10}, + {4,10}, {7,11}, {6,11}, {5,11}, {4,11}, {3,11}, {2,11}, {3,12}, + {2,12} +}; + +static DIVX_MV_TABLE mv_tables[2] = +{ + { + 1099, + table0_mv_code, + table0_mv_bits, + table0_mvx, + table0_mvy, + }, + { + 1099, + table1_mv_code, + table1_mv_bits, + table1_mvx, + table1_mvy, + } +}; + + +static const DWORD table0_dc_lum[120][2] = +{ + { 0x1, 1 },{ 0x1, 2 },{ 0x1, 4 },{ 0x1, 5 }, + { 0x5, 5 },{ 0x7, 5 },{ 0x8, 6 },{ 0xc, 6 }, + { 0x0, 7 },{ 0x2, 7 },{ 0x12, 7 },{ 0x1a, 7 }, + { 0x3, 8 },{ 0x7, 8 },{ 0x27, 8 },{ 0x37, 8 }, + { 0x5, 9 },{ 0x4c, 9 },{ 0x6c, 9 },{ 0x6d, 9 }, + { 0x8, 10 },{ 0x19, 10 },{ 0x9b, 10 },{ 0x1b, 10 }, + { 0x9a, 10 },{ 0x13, 11 },{ 0x34, 11 },{ 0x35, 11 }, + { 0x61, 12 },{ 0x48, 13 },{ 0xc4, 13 },{ 0x4a, 13 }, + { 0xc6, 13 },{ 0xc7, 13 },{ 0x92, 14 },{ 0x18b, 14 }, + { 0x93, 14 },{ 0x183, 14 },{ 0x182, 14 },{ 0x96, 14 }, + { 0x97, 14 },{ 0x180, 14 },{ 0x314, 15 },{ 0x315, 15 }, + { 0x605, 16 },{ 0x604, 16 },{ 0x606, 16 },{ 0xc0e, 17 }, + { 0x303cd, 23 },{ 0x303c9, 23 },{ 0x303c8, 23 },{ 0x303ca, 23 }, + { 0x303cb, 23 },{ 0x303cc, 23 },{ 0x303ce, 23 },{ 0x303cf, 23 }, + { 0x303d0, 23 },{ 0x303d1, 23 },{ 0x303d2, 23 },{ 0x303d3, 23 }, + { 0x303d4, 23 },{ 0x303d5, 23 },{ 0x303d6, 23 },{ 0x303d7, 23 }, + { 0x303d8, 23 },{ 0x303d9, 23 },{ 0x303da, 23 },{ 0x303db, 23 }, + { 0x303dc, 23 },{ 0x303dd, 23 },{ 0x303de, 23 },{ 0x303df, 23 }, + { 0x303e0, 23 },{ 0x303e1, 23 },{ 0x303e2, 23 },{ 0x303e3, 23 }, + { 0x303e4, 23 },{ 0x303e5, 23 },{ 0x303e6, 23 },{ 0x303e7, 23 }, + { 0x303e8, 23 },{ 0x303e9, 23 },{ 0x303ea, 23 },{ 0x303eb, 23 }, + { 0x303ec, 23 },{ 0x303ed, 23 },{ 0x303ee, 23 },{ 0x303ef, 23 }, + { 0x303f0, 23 },{ 0x303f1, 23 },{ 0x303f2, 23 },{ 0x303f3, 23 }, + { 0x303f4, 23 },{ 0x303f5, 23 },{ 0x303f6, 23 },{ 0x303f7, 23 }, + { 0x303f8, 23 },{ 0x303f9, 23 },{ 0x303fa, 23 },{ 0x303fb, 23 }, + { 0x303fc, 23 },{ 0x303fd, 23 },{ 0x303fe, 23 },{ 0x303ff, 23 }, + { 0x60780, 24 },{ 0x60781, 24 },{ 0x60782, 24 },{ 0x60783, 24 }, + { 0x60784, 24 },{ 0x60785, 24 },{ 0x60786, 24 },{ 0x60787, 24 }, + { 0x60788, 24 },{ 0x60789, 24 },{ 0x6078a, 24 },{ 0x6078b, 24 }, + { 0x6078c, 24 },{ 0x6078d, 24 },{ 0x6078e, 24 },{ 0x6078f, 24 }, +}; + +static const DWORD table0_dc_chroma[120][2] = +{ + { 0x0, 2 },{ 0x1, 2 },{ 0x5, 3 },{ 0x9, 4 }, + { 0xd, 4 },{ 0x11, 5 },{ 0x1d, 5 },{ 0x1f, 5 }, + { 0x21, 6 },{ 0x31, 6 },{ 0x38, 6 },{ 0x33, 6 }, + { 0x39, 6 },{ 0x3d, 6 },{ 0x61, 7 },{ 0x79, 7 }, + { 0x80, 8 },{ 0xc8, 8 },{ 0xca, 8 },{ 0xf0, 8 }, + { 0x81, 8 },{ 0xc0, 8 },{ 0xc9, 8 },{ 0x107, 9 }, + { 0x106, 9 },{ 0x196, 9 },{ 0x183, 9 },{ 0x1e3, 9 }, + { 0x1e2, 9 },{ 0x20a, 10 },{ 0x20b, 10 },{ 0x609, 11 }, + { 0x412, 11 },{ 0x413, 11 },{ 0x60b, 11 },{ 0x411, 11 }, + { 0x60a, 11 },{ 0x65f, 11 },{ 0x410, 11 },{ 0x65d, 11 }, + { 0x65e, 11 },{ 0xcb8, 12 },{ 0xc10, 12 },{ 0xcb9, 12 }, + { 0x1823, 13 },{ 0x3045, 14 },{ 0x6089, 15 },{ 0xc110, 16 }, + { 0x304448, 22 },{ 0x304449, 22 },{ 0x30444a, 22 },{ 0x30444b, 22 }, + { 0x30444c, 22 },{ 0x30444d, 22 },{ 0x30444e, 22 },{ 0x30444f, 22 }, + { 0x304450, 22 },{ 0x304451, 22 },{ 0x304452, 22 },{ 0x304453, 22 }, + { 0x304454, 22 },{ 0x304455, 22 },{ 0x304456, 22 },{ 0x304457, 22 }, + { 0x304458, 22 },{ 0x304459, 22 },{ 0x30445a, 22 },{ 0x30445b, 22 }, + { 0x30445c, 22 },{ 0x30445d, 22 },{ 0x30445e, 22 },{ 0x30445f, 22 }, + { 0x304460, 22 },{ 0x304461, 22 },{ 0x304462, 22 },{ 0x304463, 22 }, + { 0x304464, 22 },{ 0x304465, 22 },{ 0x304466, 22 },{ 0x304467, 22 }, + { 0x304468, 22 },{ 0x304469, 22 },{ 0x30446a, 22 },{ 0x30446b, 22 }, + { 0x30446c, 22 },{ 0x30446d, 22 },{ 0x30446e, 22 },{ 0x30446f, 22 }, + { 0x304470, 22 },{ 0x304471, 22 },{ 0x304472, 22 },{ 0x304473, 22 }, + { 0x304474, 22 },{ 0x304475, 22 },{ 0x304476, 22 },{ 0x304477, 22 }, + { 0x304478, 22 },{ 0x304479, 22 },{ 0x30447a, 22 },{ 0x30447b, 22 }, + { 0x30447c, 22 },{ 0x30447d, 22 },{ 0x30447e, 22 },{ 0x30447f, 22 }, + { 0x608880, 23 },{ 0x608881, 23 },{ 0x608882, 23 },{ 0x608883, 23 }, + { 0x608884, 23 },{ 0x608885, 23 },{ 0x608886, 23 },{ 0x608887, 23 }, + { 0x608888, 23 },{ 0x608889, 23 },{ 0x60888a, 23 },{ 0x60888b, 23 }, + { 0x60888c, 23 },{ 0x60888d, 23 },{ 0x60888e, 23 },{ 0x60888f, 23 }, +}; + +/* dc table 1 */ + +static const DWORD table1_dc_lum[120][2] = +{ + { 0x2, 2 },{ 0x3, 2 },{ 0x3, 3 },{ 0x2, 4 }, + { 0x5, 4 },{ 0x1, 5 },{ 0x3, 5 },{ 0x8, 5 }, + { 0x0, 6 },{ 0x5, 6 },{ 0xd, 6 },{ 0xf, 6 }, + { 0x13, 6 },{ 0x8, 7 },{ 0x18, 7 },{ 0x1c, 7 }, + { 0x24, 7 },{ 0x4, 8 },{ 0x6, 8 },{ 0x12, 8 }, + { 0x32, 8 },{ 0x3b, 8 },{ 0x4a, 8 },{ 0x4b, 8 }, + { 0xb, 9 },{ 0x26, 9 },{ 0x27, 9 },{ 0x66, 9 }, + { 0x74, 9 },{ 0x75, 9 },{ 0x14, 10 },{ 0x1c, 10 }, + { 0x1f, 10 },{ 0x1d, 10 },{ 0x2b, 11 },{ 0x3d, 11 }, + { 0x19d, 11 },{ 0x19f, 11 },{ 0x54, 12 },{ 0x339, 12 }, + { 0x338, 12 },{ 0x33d, 12 },{ 0xab, 13 },{ 0xf1, 13 }, + { 0x678, 13 },{ 0xf2, 13 },{ 0x1e0, 14 },{ 0x1e1, 14 }, + { 0x154, 14 },{ 0xcf2, 14 },{ 0x3cc, 15 },{ 0x2ab, 15 }, + { 0x19e7, 15 },{ 0x3ce, 15 },{ 0x19e6, 15 },{ 0x554, 16 }, + { 0x79f, 16 },{ 0x555, 16 },{ 0xf3d, 17 },{ 0xf37, 17 }, + { 0xf3c, 17 },{ 0xf35, 17 },{ 0x1e6d, 18 },{ 0x1e68, 18 }, + { 0x3cd8, 19 },{ 0x3cd3, 19 },{ 0x3cd9, 19 },{ 0x79a4, 20 }, + { 0xf34ba, 25 },{ 0xf34b4, 25 },{ 0xf34b5, 25 },{ 0xf34b6, 25 }, + { 0xf34b7, 25 },{ 0xf34b8, 25 },{ 0xf34b9, 25 },{ 0xf34bb, 25 }, + { 0xf34bc, 25 },{ 0xf34bd, 25 },{ 0xf34be, 25 },{ 0xf34bf, 25 }, + { 0x1e6940, 26 },{ 0x1e6941, 26 },{ 0x1e6942, 26 },{ 0x1e6943, 26 }, + { 0x1e6944, 26 },{ 0x1e6945, 26 },{ 0x1e6946, 26 },{ 0x1e6947, 26 }, + { 0x1e6948, 26 },{ 0x1e6949, 26 },{ 0x1e694a, 26 },{ 0x1e694b, 26 }, + { 0x1e694c, 26 },{ 0x1e694d, 26 },{ 0x1e694e, 26 },{ 0x1e694f, 26 }, + { 0x1e6950, 26 },{ 0x1e6951, 26 },{ 0x1e6952, 26 },{ 0x1e6953, 26 }, + { 0x1e6954, 26 },{ 0x1e6955, 26 },{ 0x1e6956, 26 },{ 0x1e6957, 26 }, + { 0x1e6958, 26 },{ 0x1e6959, 26 },{ 0x1e695a, 26 },{ 0x1e695b, 26 }, + { 0x1e695c, 26 },{ 0x1e695d, 26 },{ 0x1e695e, 26 },{ 0x1e695f, 26 }, + { 0x1e6960, 26 },{ 0x1e6961, 26 },{ 0x1e6962, 26 },{ 0x1e6963, 26 }, + { 0x1e6964, 26 },{ 0x1e6965, 26 },{ 0x1e6966, 26 },{ 0x1e6967, 26 }, +}; + +static const DWORD table1_dc_chroma[120][2] = +{ + { 0x0, 2 },{ 0x1, 2 },{ 0x4, 3 },{ 0x7, 3 }, + { 0xb, 4 },{ 0xd, 4 },{ 0x15, 5 },{ 0x28, 6 }, + { 0x30, 6 },{ 0x32, 6 },{ 0x52, 7 },{ 0x62, 7 }, + { 0x66, 7 },{ 0xa6, 8 },{ 0xc6, 8 },{ 0xcf, 8 }, + { 0x14f, 9 },{ 0x18e, 9 },{ 0x19c, 9 },{ 0x29d, 10 }, + { 0x33a, 10 },{ 0x538, 11 },{ 0x63c, 11 },{ 0x63e, 11 }, + { 0x63f, 11 },{ 0x676, 11 },{ 0xa73, 12 },{ 0xc7a, 12 }, + { 0xcef, 12 },{ 0x14e5, 13 },{ 0x19dd, 13 },{ 0x29c8, 14 }, + { 0x29c9, 14 },{ 0x63dd, 15 },{ 0x33b8, 14 },{ 0x33b9, 14 }, + { 0xc7b6, 16 },{ 0x63d8, 15 },{ 0x63df, 15 },{ 0xc7b3, 16 }, + { 0xc7b4, 16 },{ 0xc7b5, 16 },{ 0x63de, 15 },{ 0xc7b7, 16 }, + { 0xc7b8, 16 },{ 0xc7b9, 16 },{ 0x18f65, 17 },{ 0x31ec8, 18 }, + { 0xc7b248, 24 },{ 0xc7b249, 24 },{ 0xc7b24a, 24 },{ 0xc7b24b, 24 }, + { 0xc7b24c, 24 },{ 0xc7b24d, 24 },{ 0xc7b24e, 24 },{ 0xc7b24f, 24 }, + { 0xc7b250, 24 },{ 0xc7b251, 24 },{ 0xc7b252, 24 },{ 0xc7b253, 24 }, + { 0xc7b254, 24 },{ 0xc7b255, 24 },{ 0xc7b256, 24 },{ 0xc7b257, 24 }, + { 0xc7b258, 24 },{ 0xc7b259, 24 },{ 0xc7b25a, 24 },{ 0xc7b25b, 24 }, + { 0xc7b25c, 24 },{ 0xc7b25d, 24 },{ 0xc7b25e, 24 },{ 0xc7b25f, 24 }, + { 0xc7b260, 24 },{ 0xc7b261, 24 },{ 0xc7b262, 24 },{ 0xc7b263, 24 }, + { 0xc7b264, 24 },{ 0xc7b265, 24 },{ 0xc7b266, 24 },{ 0xc7b267, 24 }, + { 0xc7b268, 24 },{ 0xc7b269, 24 },{ 0xc7b26a, 24 },{ 0xc7b26b, 24 }, + { 0xc7b26c, 24 },{ 0xc7b26d, 24 },{ 0xc7b26e, 24 },{ 0xc7b26f, 24 }, + { 0xc7b270, 24 },{ 0xc7b271, 24 },{ 0xc7b272, 24 },{ 0xc7b273, 24 }, + { 0xc7b274, 24 },{ 0xc7b275, 24 },{ 0xc7b276, 24 },{ 0xc7b277, 24 }, + { 0xc7b278, 24 },{ 0xc7b279, 24 },{ 0xc7b27a, 24 },{ 0xc7b27b, 24 }, + { 0xc7b27c, 24 },{ 0xc7b27d, 24 },{ 0xc7b27e, 24 },{ 0xc7b27f, 24 }, + { 0x18f6480, 25 },{ 0x18f6481, 25 },{ 0x18f6482, 25 },{ 0x18f6483, 25 }, + { 0x18f6484, 25 },{ 0x18f6485, 25 },{ 0x18f6486, 25 },{ 0x18f6487, 25 }, + { 0x18f6488, 25 },{ 0x18f6489, 25 },{ 0x18f648a, 25 },{ 0x18f648b, 25 }, + { 0x18f648c, 25 },{ 0x18f648d, 25 },{ 0x18f648e, 25 },{ 0x18f648f, 25 }, +}; + +static const BYTE divx_log2_tab[256] = +{ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +static const BYTE zigzag_direct[64] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const BYTE alternate_horizontal_scan[64] = +{ + 0, 1, 2, 3, 8, 9, 16, 17, + 10, 11, 4, 5, 6, 7, 15, 14, + 13, 12, 19, 18, 24, 25, 32, 33, + 26, 27, 20, 21, 22, 23, 28, 29, + 30, 31, 34, 35, 40, 41, 48, 49, + 42, 43, 36, 37, 38, 39, 44, 45, + 46, 47, 50, 51, 56, 57, 58, 59, + 52, 53, 54, 55, 60, 61, 62, 63, +}; + +static const BYTE alternate_vertical_scan[64] = +{ + 0, 8, 16, 24, 1, 9, 2, 10, + 17, 25, 32, 40, 48, 56, 57, 49, + 41, 33, 26, 18, 3, 11, 4, 12, + 19, 27, 34, 42, 50, 58, 35, 43, + 51, 59, 20, 28, 5, 13, 6, 14, + 21, 29, 36, 44, 52, 60, 37, 45, + 53, 61, 22, 30, 7, 15, 23, 31, + 38, 46, 54, 62, 39, 47, 55, 63, +}; + +// strange +#if 0 +static const BYTE strange_scan[64] = +{ + /* 0 */ 0, 8, 16, , , , , , /* 7 */ + /* 8 */ 1, , , , , , , , /* 15 */ + /* 16 */ , 17, 48, 27, , , , , /* 23 */ + /* 24 */ , 40, , 19, , , , , /* 31 */ + /* 32 */ , , , , , , , , /* 39 */ + /* 40 */ , 12, , , , , , , /* 47 */ + /* 48 */ 18, , , , , , , , /* 55 */ + /* 56 */ , , , , , , , , /* 63 */ +}; +#endif + +/* dc encoding for mpeg4 */ +static const BYTE DCtab_lum[13][2] = +{ + {3,3}, {3,2}, {2,2}, {2,3}, {1,3}, {1,4}, {1,5}, {1,6}, {1,7}, + {1,8}, {1,9}, {1,10}, {1,11}, +}; + +static const BYTE DCtab_chrom[13][2] = +{ + {3,2}, {2,2}, {1,2}, {1,3}, {1,4}, {1,5}, {1,6}, {1,7}, {1,8}, + {1,9}, {1,10}, {1,11}, {1,12}, +}; + +static const BYTE intra_MCBPC_code[9] = { 1, 1, 2, 3, 1, 1, 2, 3, 1 }; +static const BYTE intra_MCBPC_bits[9] = { 1, 3, 3, 3, 4, 6, 6, 6, 9 }; + +static const BYTE inter_MCBPC_code[28] = { + 1, 3, 2, 5, + 3, 4, 3, 3, + 3, 7, 6, 5, + 4, 4, 3, 2, + 2, 5, 4, 5, + 1, 0, 0, 0, /* Stuffing */ + 2, 12, 14, 15, +}; +static const BYTE inter_MCBPC_bits[28] = { + 1, 4, 4, 6, /* inter */ + 5, 8, 8, 7, /* intra */ + 3, 7, 7, 9, /* interQ */ + 6, 9, 9, 9, /* intraQ */ + 3, 7, 7, 8, /* inter4 */ + 9, 0, 0, 0, /* Stuffing */ + 11, 13, 13, 13,/* inter4Q*/ +}; + +static const BYTE cbpy_tab[16][2] = +{ + {3,4}, {5,5}, {4,5}, {9,4}, {3,5}, {7,4}, {2,6}, {11,4}, + {2,5}, {3,6}, {5,4}, {10,4}, {4,4}, {8,4}, {6,4}, {3,2} +}; + +static BYTE old_y_dc_scale_table[32] = +{ + 0, 8, 8, 8, 8,10,12,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 +}; +static BYTE old_c_dc_scale_table[32] = +{ + 0, 8, 8, 8, 8, 9, 9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22 +}; + +static BYTE mpeg4_y_dc_scale_table[32] = +{ + 0, 8, 8, 8, 8,10,12,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,34,36,38,40,42,44,46 +}; +static BYTE mpeg4_c_dc_scale_table[32] = +{ + 0, 8, 8, 8, 8, 9, 9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,20,21,22,23,24,25 +}; + +static BYTE default_chroma_qscale_table[32] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 +}; + +#endif // of SP_DIVX_TABLES_H diff --git a/src/divx.c b/src/divx.c new file mode 100644 index 0000000..5b8dd10 --- /dev/null +++ b/src/divx.c @@ -0,0 +1,2612 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DivX3->MPEG-4 transcoder source file. + * \file divx.cpp + * \author bombur + * \version 0.1 + * \date 1.04.2007 + * + * Portions of code taken from libavcodec. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include +#include + +#define DIVX_INTERNAL +#include "bitstream.h" +#include "divx.h" +#include "divx-tables.h" + +//#define USE_SLOW_METHOD_LIMIT + +// UNCOMMENT ALL!!! +#define USE_SLOW_METHOD +//#define USE_AC_CORRECTION +//#define USE_ONLY_SLOW_METHOD +//#define DUMP + +//!!!!!!!!!!!!!!!!!!!! +//static int CNT = 0; + +#ifdef DUMP +#define DEBUG_MSG msg +//#define DEBUG_MSG printf +#endif + + +#define INLINE SP_INLINE +#define STATIC static +//#define INLINE +//#define STATIC + +////////////////////////////////////////////////////////////////// + +#ifdef USE_SLOW_METHOD_LIMIT +const int max_allowed_frame_size_for_correct_method = 3750*4; +#endif + +int frame_number; + +static int width, height; +static DWORD pict_type; + +static DWORD qscale, chroma_qscale; +static int enc_y_dc_scale, enc_c_dc_scale; +static BYTE *enc_y_dc_scale_table, *enc_c_dc_scale_table; +static int dec_y_dc_scale, dec_c_dc_scale; +static BYTE *dec_y_dc_scale_table, *dec_c_dc_scale_table; +static BYTE *chroma_qscale_table; + +#ifdef USE_AC_CORRECTION +static int *ac_val_base, *ac_val; +static int ac_size; +static int qmul, qadd; +static DWORD use_acpred; +#endif + +static int mb_width, mb_height, mb_num; +static int slice_height; + +static int use_skip_mb_code; +static int f_code; +static int rl_table_index; +static int rl_chroma_table_index; +static int dc_table_index; +static int mv_table_index; +static int no_rounding; +static BOOL flipflop_rounding; + +static int b8_stride, mb_stride; +static int block_index[6], (*block_index_tbl)[6]; +static BYTE *coded_block_base, *coded_block; +static signed short (*motion_val_base)[2], (*motion_val)[2]; + +static BOOL mb_intra; +static int mb_x, mb_y; +static BOOL mb_skip; +static int first_slice_line; +static int motion_x, motion_y; +static int ac_pred; +static int block_wrap[6]; +static signed short *enc_dc_val_base, *enc_dc_val[3]; +static signed short *dec_dc_val_base, *dec_dc_val[3]; +static signed short old_enc_dc_val, old_dec_dc_val; + +static DWORD block_flags[64], block_flag; +//static int out_block[64]; + +#ifdef DUMP +DWORD block_idx[64], block_run[64]; +#endif + +static DIVX_SCAN_TABLE inter_scantable, intra_scantable; +static DIVX_SCAN_TABLE intra_h_scantable, intra_v_scantable; + +static LONGLONG pts; +static int last_time_div, time_incr_res; + +static DIVX_VLC mb_intra_vlc; +static DIVX_VLC mb_non_intra_vlc; +static DIVX_VLC dc_lum_vlc[2]; +static DIVX_VLC dc_chroma_vlc[2]; +static BYTE uni_DCtab_lum_len[512]; +static BYTE uni_DCtab_chrom_len[512]; +static WORD uni_DCtab_lum_bits[512]; +static WORD uni_DCtab_chrom_bits[512]; + +static DIVX_BITS_LEN *bits_len_tab_cur[3], *bits_len[9]; +static DWORD *bits_len_tab2_cur[3], *bits_len2[9]; + +static DWORD *level_run_tab_cur[3], *level_run[6]; +static DWORD *level_run_tab2_cur[3], *level_run2[6]; + +static DWORD *uni_table[2]; + +/* +#include +void DUMP_FRAME(char *text, ...) +{ + if (frame_number == 772) + { + static FILE *fp = NULL; + if (fp == NULL) + fp = fopen("out.log", "wb"); + va_list args; + va_start(args, text); + vfprintf(fp, text, args); + va_end(args); + //fclose(fp); + } +} +*/ +//#include +//#define DUMP_FRAME gui_update();while(fip_read_button(TRUE) != FIP_KEY_ENTER);msg + + +//////////////////////////////////////////////////// + +STATIC void divx_init_scantable(DIVX_SCAN_TABLE *st, const BYTE *src_scantable) +{ + DWORD i; + int end; + st->scantable = src_scantable; + + for (i = 0; i < 64; i++) + { + st->permutated[i] = src_scantable[i]; + st->inv_permutated[src_scantable[i]] = (BYTE)i; + } + + end = -1; + for (i = 0; i < 64; i++) + { + int j = st->permutated[i]; + if (j > end) + end = j; + st->raster_end[i] = (BYTE)end; + } +} + +static int divx_alloc_vlc_table(DIVX_VLC *vlc, int size) +{ + int index; + index = vlc->table_size; + vlc->table_size += size; + if (vlc->table_size > vlc->table_allocated) + { + vlc->table_allocated += (1 << vlc->bits); + vlc->table = (signed short (*)[2])SPrealloc(vlc->table, + sizeof(signed short) * 2 * vlc->table_allocated); + if (!vlc->table) + return -1; + } + return index; +} + +STATIC INLINE DWORD divx_get_vlc_data(const void *table, int i, int wrap, int size) +{ + const BYTE *ptr = (const BYTE *)table + i * wrap; + switch(size) + { + case 1: + return *(const BYTE *)ptr; + case 2: + return *(const WORD *)ptr; + default: + return *(const DWORD *)ptr; + } +} + +static int divx_build_vlc_table(DIVX_VLC *vlc, int table_nb_bits, + int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + DWORD code_prefix, int n_prefix) +{ + int i, j, k, n, table_size, table_index, nb, n1, index; + DWORD code; + signed short (*table)[2]; + + table_size = 1 << table_nb_bits; + table_index = divx_alloc_vlc_table(vlc, table_size); + if (table_index < 0) + return -1; + table = &vlc->table[table_index]; + + for (i = 0; i < table_size; i++) + { + table[i][1] = 0; //bits + table[i][0] = -1; //codes + } + + // first pass: map codes and compute auxillary table sizes + for (i = 0; i < nb_codes; i++) + { + n = divx_get_vlc_data(bits, i, bits_wrap, bits_size); + code = divx_get_vlc_data(codes, i, codes_wrap, codes_size); + // we accept tables with holes + if (n <= 0) + continue; + // if code matches the prefix, it is in the table + n -= n_prefix; + if (n > 0 && (code >> n) == code_prefix) + { + if (n <= table_nb_bits) + { + // no need to add another table + j = (code << (table_nb_bits - n)) & (table_size - 1); + nb = 1 << (table_nb_bits - n); + for (k = 0; k < nb; k++) + { + if (table[j][1] != 0) // bits + { + return -1; + } + table[j][1] = (signed short)n; //bits + table[j][0] = (signed short)i; //code + j++; + } + } else + { + n -= table_nb_bits; + j = (code >> n) & ((1 << table_nb_bits) - 1); + // compute table size + n1 = -table[j][1]; //bits + if (n > n1) + n1 = n; + table[j][1] = (signed short)-n1; //bits + } + } + } + + // second pass : fill auxiliary tables recursively + for (i = 0; i < table_size; i++) + { + n = table[i][1]; //bits + if (n < 0) + { + n = -n; + if (n > table_nb_bits) + { + n = table_nb_bits; + table[i][1] = (signed short)-n; //bits + } + index = divx_build_vlc_table(vlc, n, nb_codes, + bits, bits_wrap, bits_size, + codes, codes_wrap, codes_size, + (code_prefix << table_nb_bits) | i, + n_prefix + table_nb_bits); + if (index < 0) + return -1; + // note: realloc has been done, so reload tables + table = &vlc->table[table_index]; + table[i][0] = (signed short)index; //code + } + } + return table_index; +} + +static int divx_init_vlc(DIVX_VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size) +{ + vlc->bits = nb_bits; + vlc->table = NULL; + vlc->table_allocated = 0; + vlc->table_size = 0; + + if (divx_build_vlc_table(vlc, nb_bits, nb_codes, + bits, bits_wrap, bits_size, + codes, codes_wrap, codes_size, 0, 0) < 0) + { + SPSafeFree(vlc->table); + return -1; + } + return 0; +} + + +static int divx_init_rl(DIVX_RL_TABLE *rl) +{ + signed char max_level[DIVX_MAX_RUN + 1], max_run[DIVX_MAX_LEVEL + 1]; + BYTE index_run[DIVX_MAX_RUN + 1]; + int last, run, level, start, end, i; + + // compute max_level[], max_run[] and index_run[] + for (last = 0; last < 2; last++) + { + if (last == 0) + { + start = 0; + end = rl->last; + } else + { + start = rl->last; + end = rl->n; + } + + memset(max_level, 0, DIVX_MAX_RUN + 1); + memset(max_run, 0, DIVX_MAX_LEVEL + 1); + memset(index_run, rl->n, DIVX_MAX_RUN + 1); + for (i = start; i < end; i++) + { + run = rl->table_run[i]; + level = rl->table_level[i]; + if (index_run[run] == rl->n) + index_run[run] = (BYTE)i; + if (level > max_level[run]) + max_level[run] = (signed char)level; + if (run > max_run[level]) + max_run[level] = (signed char)run; + } + rl->max_level[last] = (signed char *)SPmalloc(DIVX_MAX_RUN + 1); + if (rl->max_level[last] == NULL) + return -1; + memcpy(rl->max_level[last], max_level, DIVX_MAX_RUN + 1); + + rl->max_run[last] = (signed char *)SPmalloc(DIVX_MAX_LEVEL + 1); + if (rl->max_run[last] == NULL) + return -1; + memcpy(rl->max_run[last], max_run, DIVX_MAX_LEVEL + 1); + + rl->index_run[last] = (BYTE *)SPmalloc(DIVX_MAX_RUN + 1); + if (rl->index_run[last] == NULL) + return -1; + memcpy(rl->index_run[last], index_run, DIVX_MAX_RUN + 1); + } + + return 0; +} + +static void divx_free_rl(DIVX_RL_TABLE *rl) +{ + SPSafeFree(rl->max_level[0]); + SPSafeFree(rl->max_level[1]); + SPSafeFree(rl->max_run[0]); + SPSafeFree(rl->max_run[1]); + SPSafeFree(rl->index_run[0]); + SPSafeFree(rl->index_run[1]); +} + +static int divx_build_ac_tables() +{ + DWORD i, k, data_mask[16]; + for (i = 0; i < 16; i++) + data_mask[i] = ((1 << i) - 1) << (16 - i); + for (i = 0; i < 9; i++) + { + DIVX_BITS_LEN *bits_len_tab = bits_len[i]; + DWORD *bits_len_tab2 = bits_len2[i]; + DWORD *uni_tbl = uni_table[i >= 6 ? 1 : 0]; + DWORD I = (i >= 6) ? i - 3 : i; + DWORD *level_run_tab = level_run[I]; + DWORD *level_run_tab2 = level_run2[I]; + + DWORD ext_idx = 0; + DWORD rt_idx = 4, j; + + int max_level[64*2], max_run[64*2]; + int num = rl_table[I].n, rl_last = rl_table[I].last; + + DWORD ext_next_k = 0, rt_next_k = 0; + DWORD ext_cur_j = 0; + BOOL ext_next_esc4 = FALSE; + int idx; + //const WORD (*vlc)[2] = rl_table[I].table_vlc; + + memset(max_level, 0, 64 * 2 * sizeof(int)); + memset(max_run, 0, 64 * 2 * sizeof(int)); + + for (idx = 0; idx < num; idx++) + { + // no need to add another table + int lev = rl_table[I].table_level[idx]; + int run = rl_table[I].table_run[idx]; + int last = (idx >= rl_last) ? 64 : 0; + + if (max_level[last + run] < lev) + max_level[last + run] = lev; + if (max_run[last + lev] < run) + max_run[last + lev] = run; +/* + DWORD nb = (15 - vlc[idx][1]); + DWORD j = vlc[idx][0] << (nb + 1); + for (int sign = 0; sign <= 1; sign++) + { + DWORD jj = j | (sign << nb); + for (int k = 1 << nb; k > 0; k--, jj++) + { + bits_len_tab[jj>>2].bits = (WORD)idx; + } + } +*/ + } + + for (j = 0; j < (1<<14); j++) + { +/* + short idx0 = bits_len_tab[j].bits; +*/ + for (k = 0; k < 4; k++) + { + DWORD data = (j << 2) | k; + + int idx, left = 16, len = 0; + BOOL found = FALSE, use_esc4 = FALSE, use_1 = FALSE; + DWORD total_num = 0, total_inlen = 0, total_outlen = 0, total_last = 0; + int first_level = 0; + DWORD first_len = 0, first_outlen = 0, first_run = 0, first_last = 0, first_data = 0; + DWORD out_data = 0, esc; + DWORD lrt; +/* + if (idx0 >= 0) + { + idx = idx0; + goto found; + } +*/ + do + { + found = FALSE; + len = 0; + for (idx = 0; idx < num; idx++) + { +/* +found: +*/ + const WORD *vlc = rl_table[I].table_vlc[idx]; + len = vlc[1]; + if (len + 1 > left) + continue; + if ((data & data_mask[len]) == (((DWORD)vlc[0]) << (16 - len))) + { + int level = rl_table[I].table_level[idx]; + int run = rl_table[I].table_run[idx]; + int last = (idx >= rl_table[I].last) ? 1 : 0; + register int index, outlen; + + len++; + + if (data & (1 << (16 - len))) + level = -level; + + index = last*128*64 + run*128 + level + 64; + outlen = uni_tbl[index] >> 24; + + left -= len; + data <<= len; + total_inlen += len; + + total_outlen += outlen; + out_data <<= outlen; + out_data |= uni_tbl[index] & 0xffffff; + + total_last = last; + + if (first_len == 0) + { + first_len = len; + first_outlen = outlen; + first_level = level; + first_run = run; + first_data = out_data; + first_last = last; + } + + total_num++; + + if (outlen > 22) + { + use_esc4 = TRUE; + break; + } + + if (total_num > 0 && (total_outlen > 15 || total_inlen > 14)) + { + use_1 = TRUE; + break; + } + + if (last) + break; + + + found = TRUE; + break; + } + } + } + while (found && total_outlen < 22); + + esc = 0; + if (!use_esc4 && total_num == 0) // search ESC codes + { + const WORD *vlc = rl_table[I].table_vlc[num]; + int len = vlc[1]; + if ((data & data_mask[len]) == (((DWORD)vlc[0]) << (16 - len))) + { + int esc_shift, esc123; + + len++; + esc_shift = 15 - len; + esc123 = (data >> esc_shift) & 3; + + if (esc123 == 0) + { + esc = 3; + len++; + } + else if (esc123 == 1) + { + esc = 2; + len++; + } + else + esc = 1; + first_len = len; + } + } + + // truncate too long seqs + if (use_1 || (total_num == 2 && total_outlen > 15 && first_outlen <= 15)) + { + total_outlen = first_outlen; + total_inlen = first_len; + total_num = 1; + total_last = first_last; + out_data = first_data; + } + + if (i < 6 && !esc) + { + DWORD add_level = max_level[first_last * 64 + (first_run & 63)]; + DWORD add_run = max_run[first_last * 64 + Abs(first_level)]; + + lrt = ((DWORD)first_level & 127) << 25; + lrt |= ((first_len - 1) & 0xf) << 18; + lrt |= (first_last & 1) << 17; + lrt |= (add_level & 31) << 12; + lrt |= (add_run & 63) << 6; + lrt |= (first_run & 63); + + if (first_len > 14) + { + if (k != rt_next_k) + rt_idx = (((rt_idx >> 2) + 1) << 2) | k; + + level_run_tab2[rt_idx] = lrt; + level_run_tab[j] = (rt_idx & ~3); + rt_idx++; + rt_next_k = (k + 1) & 3; + } + else + level_run_tab[j] = lrt; + } + + // esc1-4 + if (esc) + { + bits_len_tab[j].len = (BYTE)esc; + bits_len_tab[j].bits = (WORD)first_len; + level_run_tab[j] = 0; + } + // extended + else if (total_inlen > 14 || total_outlen > 15 || use_esc4) + { + // if one of four extended records has ESC4, then all others should too + + if (ext_cur_j == j) + { + if (!use_esc4 && ext_next_esc4) + use_esc4 = TRUE; + } + + if (k != ext_next_k) + ext_idx = (((ext_idx >> 2) + 1) << 2) | k; + bits_len_tab2[ext_idx] = ((DWORD)total_last << 31) | ((out_data & 0x3FFFFF) << 9) + | ((total_inlen - 1) << 5) | total_outlen; + bits_len_tab[j].len = use_esc4 ? (BYTE)4 : (BYTE)0; + bits_len_tab[j].bits = (WORD)(ext_idx & ~3); + ext_idx++; + ext_next_k = (k + 1) & 3; + + ext_next_esc4 = use_esc4; + ext_cur_j = j; + + } + // normal + else + { + bits_len_tab[j].len = (BYTE)(((total_outlen & 0xf) << 4) | (total_inlen & 0xf)); + bits_len_tab[j].bits = (WORD)(out_data | (total_last << 15)); + } + } + } + msg("DivX3: AC-init[%d]: ext_num=%d, rt_num=%d\n", i, ext_idx, rt_idx); + gui_update(); + } + + + return 0; +} + +static void divx_init_uni_dc_tab(void) +{ + int level, uni_code, uni_len; + + for (level = -256; level < 256; level++) + { + int size, v, l; + // find number of bits + size = 0; + v = Abs(level); + while (v) + { + v >>= 1; + size++; + } + + if (level < 0) + l = (-level) ^ ((1 << size) - 1); + else + l = level; + + // luminance + uni_code = DCtab_lum[size][0]; + uni_len = DCtab_lum[size][1]; + + if (size > 0) + { + uni_code <<= size; uni_code |= l; + uni_len += size; + if (size > 8) + { + uni_code <<= 1; uni_code |= 1; + uni_len++; + } + } + uni_DCtab_lum_bits[level + 256] = (WORD)uni_code; + uni_DCtab_lum_len [level + 256] = (BYTE)uni_len; + + // chrominance + uni_code = DCtab_chrom[size][0]; + uni_len = DCtab_chrom[size][1]; + + if (size > 0) + { + uni_code <<= size; uni_code |= l; + uni_len += size; + if (size > 8) + { + uni_code <<= 1; uni_code |= 1; + uni_len++; + } + } + uni_DCtab_chrom_bits[level + 256] = (WORD)uni_code; + uni_DCtab_chrom_len [level + 256] = (BYTE)uni_len; + } +} + +STATIC INLINE int divx_get_rl_index(const DIVX_RL_TABLE *rl, int last, int run, int level) +{ + DWORD index; + index = rl->index_run[last][run]; + if (index >= rl->n) + return rl->n; + if (level > rl->max_level[last][run]) + return rl->n; + return (int)index + level - 1; +} + +static void divx_init_uni_tabs() +{ + DWORD i; + for (i = 0; i < 2; i++) + { + DIVX_RL_TABLE *rl = &rl_table[i == 0 ? 2 : 5]; + DWORD *uni_tab = uni_table[i]; + int slevel, run, last; + + for (run = 0; run < 64; run++) + { + for (last = 0; last <= 1; last++) + { + const int index = ((last)*128*64 + (run)*128 + 64); + uni_tab[index] = 0; + } + } + + for (slevel = -64; slevel < 64; slevel++) + { + if (slevel == 0) + continue; + for (run = 0; run < 64; run++) + { + for (last = 0; last <= 1; last++) + { + const int index = ((last)*128*64 + (run)*128 + (slevel+64)); + int level = slevel < 0 ? -slevel : slevel; + int sign = slevel < 0 ? 1 : 0; + DWORD bits, len, code; + int level1, run1; + + DWORD out_len = 30; + DWORD out_bits = 0; + + // ESC0 + code = divx_get_rl_index(rl, last, run, level); + bits = rl->table_vlc[code][0]; + len = rl->table_vlc[code][1] + 1; + bits = bits * 2 + sign; + + if (code != rl->n && len < out_len) + { + out_bits = bits; out_len = len; + } + // ESC1 + bits = rl->table_vlc[rl->n][0]; + len = rl->table_vlc[rl->n][1] + 1; + bits = bits*2; + level1 = level - rl->max_level[last][run]; + if (level1 > 0) + { + code = divx_get_rl_index(rl, last, run, level1); + bits <<= rl->table_vlc[code][1]; + len += rl->table_vlc[code][1]; + bits += rl->table_vlc[code][0]; + bits = bits * 2 + sign; + len++; + + if (code != rl->n && len < out_len) + { + out_bits = bits; out_len = len; + } + } + // ESC2 + bits = rl->table_vlc[rl->n][0]; + len = rl->table_vlc[rl->n][1]; + bits = bits * 4 + 2; len+=2; + run1 = run - rl->max_run[last][level] - 1; + if (run1 >= 0) + { + code = divx_get_rl_index(rl, last, run1, level); + bits <<= rl->table_vlc[code][1]; + len += rl->table_vlc[code][1]; + bits += rl->table_vlc[code][0]; + bits = bits * 2 + sign; len++; + + if (code != rl->n && len < out_len) + { + out_bits = bits; out_len = len; + } + } + + uni_tab[index] = (out_len << 24) | (out_bits & 0xffffff); + } + } + } + } +} + +////////////////////////////////////////////////////////////// + +#define divx_get_vlc2(code, dec_v, dec_bitidx, dec_left, table) \ +{ \ + register DWORD index; \ + register int n; \ + \ + bitstream_show_bits(index, dec_v, dec_bitidx, 9); \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if (n < 0) \ + { \ + bitstream_skip_bits(0, dec_v, dec_bitidx, dec_left, 9); \ + bitstream_show_bits(index, dec_v, dec_bitidx, (-n)); \ + index += code; \ + code = table[index][0]; \ + n = table[index][1]; \ + } \ + bitstream_skip_bits(0, dec_v, dec_bitidx, dec_left, n); \ +} + +#define divx_get_vlc3(code, dec_v, dec_bitidx, dec_left, table) \ +{ \ + register DWORD index; \ + register int n; \ + \ + bitstream_show_bits(index, dec_v, dec_bitidx, 9); \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if (n < 0) \ + { \ + register int nb_bits = -n; \ + bitstream_skip_bits(0, dec_v, dec_bitidx, dec_left, 9); \ + \ + bitstream_show_bits(index, dec_v, dec_bitidx, nb_bits); \ + index += code; \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if (n < 0) \ + { \ + bitstream_skip_bits(0, dec_v, dec_bitidx, dec_left, nb_bits); \ + nb_bits = -n; \ + bitstream_show_bits(index, dec_v, dec_bitidx, nb_bits); \ + index += code; \ + code = table[index][0]; \ + n = table[index][1]; \ + } \ + } \ + bitstream_skip_bits(0, dec_v, dec_bitidx, dec_left, n); \ +} + +STATIC INLINE int divx_log2(unsigned int v) +{ + int n = 0; + if (v & 0xffff0000) + { + v >>= 16; + n += 16; + } + if (v & 0xff00) + { + v >>= 8; + n += 8; + } + n += divx_log2_tab[v]; + + return n; +} + +STATIC INLINE int divx_coded_block_pred(int n, BYTE **coded_block_ptr) +{ + int xy, wrap, pred, a, b, c; + + xy = block_index[n]; + wrap = b8_stride; + + a = coded_block[xy - 1 ]; + b = coded_block[xy - 1 - wrap]; + c = coded_block[xy - wrap]; + + if (b == c) + pred = a; + else + pred = c; + + *coded_block_ptr = &coded_block[xy]; + + return pred; +} + +STATIC INLINE int divx_pred_dc(int n, int level, int *dir_ptr, BOOL encoding) +{ + int a, b, c, wrap, pred, scale, ret; + WORD *dc_val; + + // find prediction + if (n < 4) + { + scale = encoding ? enc_y_dc_scale : dec_y_dc_scale; + } else + { + scale = encoding ? enc_c_dc_scale : dec_c_dc_scale; + } + + wrap = block_wrap[n]; + dc_val = (WORD *)((encoding ? enc_dc_val[0] : dec_dc_val[0]) + block_index[n]); + + /* B C + * A X + */ + a = dc_val[ - 1]; + b = dc_val[ - 1 - wrap]; + c = dc_val[ - wrap]; + + if (encoding) + { + if (Abs(a - b) < Abs(b - c)) + { + pred = c; + *dir_ptr = 1; // top + } else + { + pred = a; + *dir_ptr = 0; // left + } + + pred = -(pred + (scale >> 1)) / scale; + + ret = (level + pred); + level *= scale; + + old_enc_dc_val = dc_val[0]; + } else + { + if (scale == 8) + { + a = (a + (8 >> 1)) / 8; + b = (b + (8 >> 1)) / 8; + c = (c + (8 >> 1)) / 8; + } else + { + a = (a + (scale >> 1)) / scale; + b = (b + (scale >> 1)) / scale; + c = (c + (scale >> 1)) / scale; + } + + if (Abs(a - b) <= Abs(b - c)) + { + pred = c; + *dir_ptr = 1; // top + } else + { + pred = a; + *dir_ptr = 0; // left + } + + ret = (level + pred); + level = ret * scale; + + old_dec_dc_val = dc_val[0]; + } + + if (level & (~2047)) + { + if (level < 0) + level = 0; + } + + dc_val[0] = (WORD)level; + + return ret; +} + +#ifdef USE_AC_CORRECTION + +STATIC INLINE DWORD divx_pred_notcoded_ac(int block_i, int block[64], int dec_dc_pred_dir) +{ + int i = block_index[block_i] * 16; + int *ac = ac_val + i; + DWORD non_zero = 0; + + if (ac_pred) + { + if (dec_dc_pred_dir == 0) + { + int *a = ac - 16; + for(i = 1; i < 8; i++) + { +#ifdef DUMP +// DEBUG_MSG("block[%d] = %d\n", i<<3, *a); +#endif + + int level = *a++; + level = (level > 0) ? (level - qadd) / qmul : (level + qadd) / qmul; + block[i<<3] = level; + non_zero |= (DWORD)level; + } + } else + { + int *a = ac - 16 * block_wrap[block_i] + 8; + for(i = 1; i < 8; i++) + { +#ifdef DUMP +// DEBUG_MSG("block[%d] = %d\n", i, *a); +#endif + int level = *a++; + level = (level > 0) ? (level - qadd) / qmul : (level + qadd) / qmul; + block[i] = level; + non_zero |= (DWORD)level; + } + } + } + + int *a = ac, *a8 = a + 8; + for(i = 1; i < 8; i++) + { + int level = block[i<<3]; + level = (level > 0) ? level * qmul + qadd : level * qmul - qadd; + *a++ = level; + + level = block[i]; + level = (level > 0) ? level * qmul + qadd : level * qmul - qadd; + *a8++ = level; + } + + // non-zero if any coefs are non-zero + return non_zero != 0 ? 1 : 0; +} + +STATIC INLINE DWORD divx_pred_ac(int block_i, int *block, int dec_dc_pred_dir) +{ + int i = block_index[block_i] * 16; + int *ac = ac_val + i; + DWORD non_zero = 0; + + if (dec_dc_pred_dir == 0) + { + int *a = ac - 16; + for(i = 1; i < 8; i++) + { +#ifdef DUMP +// DEBUG_MSG("block[%d] = %d + %d\n", i<<3, block[i<<3], *a); +#endif + + int level = block[i<<3]; + level = (level > 0) ? level * qmul + qadd : level * qmul - qadd; + level += *a++; + level = (level > 0) ? (level - qadd) / qmul : (level + qadd) / qmul; + block[i<<3] = level; + non_zero |= (DWORD)level; + } + } else + { + int *a = ac - 16 * block_wrap[block_i] + 8; + for(i = 1; i < 8; i++) + { +#ifdef DUMP +// DEBUG_MSG("block[%d] = %d + %d\n", i, block[i], *a); +#endif + int level = block[i]; + level= (level > 0) ? level * qmul + qadd : level * qmul - qadd; + level += *a++; + level = (level > 0) ? (level - qadd) / qmul : (level + qadd) / qmul; + block[i] = level; + non_zero |= (DWORD)level; + } + } + + int *a = ac, *a8 = a + 8; + for(i = 1; i < 8; i++) + { + int level = block[i<<3]; + level = (level > 0) ? level * qmul + qadd : level * qmul - qadd; + *a++ = level; + + level = block[i]; + level = (level > 0) ? level * qmul + qadd : level * qmul - qadd; + *a8++ = level; + } + + // non-zero if any coefs are non-zero + return non_zero != 0 ? 1 : 0; +} + +STATIC INLINE void divx_pred_flaged_ac(int block_i, int *block, DWORD *block_f, DWORD block_flag, int dec_dc_pred_dir) +{ + int i = block_index[block_i] * 16; + int *ac = ac_val + i; + + int *a = ac, *a8 = a + 8; + for(i = 1; i < 8; i++) + { + if (block_f[i<<3] == block_flag) + { + int level = block[i<<3]; + level = (level > 0) ? level * qmul + qadd : level * qmul - qadd; + *a++ = level; + } + else + *a++ = 0; + if (block_f[i] == block_flag) + { + int level = block[i]; + level = (level > 0) ? level * qmul + qadd : level * qmul - qadd; + *a8++ = level; + } + else + *a8++ = 0; + } +} + +#endif + +#if 0 +STATIC INLINE int divx_put_rl_vlc(DWORD &enc_v, int &enc_bitidx, int &enc_len, int level, int last, int run, DWORD *bits_tab, BYTE *len_tab) +{ + register int index = last*128*64 + (run-1)*128 + level + 64; + if (index >= 0) + return bitstream_put_bits(len_tab[index], bits_tab[index], enc_v, enc_bitidx, enc_len); + return 0; +} +#endif + +#define divx_put_rl_vlc_esc3(enc_v, enc_bitidx, enc_len, level, last, run) \ +{ \ + DWORD d = ((3 << 23) + (3 << 21) + (1 << 13) + 1) + \ + (last << 20) + ((run - 1) << 14) + (((level) & 0xfff) << 1); \ + bitstream_put_bits((7+2+1+6+1+12+1), d, enc_v, enc_bitidx, enc_len); \ +} + +#define divx_encode_dc(enc_v, enc_bitidx, enc_len, level, n) \ +{ \ + level += 256; \ + if (n < 4) /* luminance */ \ + { \ + bitstream_put_bits(uni_DCtab_lum_len[level], uni_DCtab_lum_bits[level], enc_v, enc_bitidx, enc_len); \ + } else /* chrominance */ \ + { \ + bitstream_put_bits(uni_DCtab_chrom_len[level], uni_DCtab_chrom_bits[level], enc_v, enc_bitidx, enc_len); \ + } \ +} + +STATIC INLINE int divx_mid_pred(int a, int b, int c) +{ + if (a > b) + { + if (c > b) + b = (c > a) ? a : c; + } else + { + if (b > c) + b = (c > a) ? c : a; + } + return b; +} + +STATIC INLINE signed short *divx_pred_motion(int *px, int *py) +{ + int wrap; + signed short *A, *B, *C, (*mot_val)[2]; + + wrap = b8_stride; + mot_val = motion_val + block_index[0]; + + A = mot_val[ - 1]; + if (first_slice_line) + { + if (mb_x == 0) + { + *px = *py = 0; + } else + { + *px = A[0]; + *py = A[1]; + } + } else + { + B = mot_val[ - wrap]; + C = mot_val[2 - wrap]; + *px = divx_mid_pred(A[0], B[0], C[0]); + *py = divx_mid_pred(A[1], B[1], C[1]); + } + return *mot_val; +} + +#define divx_decode_motion(dec_v, dec_bitidx, dec_left, mx_ptr, my_ptr) \ +{ \ + DIVX_MV_TABLE *mv = &mv_tables[mv_table_index]; \ + \ + register int code; \ + int mx, my; \ + divx_get_vlc2(code, dec_v, dec_bitidx, dec_left, mv->vlc.table); \ + if (code < 0) \ + return -1; \ + if (code == mv->n) \ + { \ + register DWORD mxmy; \ + bitstream_get_bits(mxmy, 0, dec_v, dec_bitidx, dec_left, 12); \ + mx = mxmy >> 6; \ + my = mxmy & 63; \ + } else \ + { \ + mx = mv->table_mvx[code]; \ + my = mv->table_mvy[code]; \ + } \ + \ + mx += mx_ptr - 32; \ + my += my_ptr - 32; \ + /* \WARNING : they do not do exactly modulo encoding */ \ + if (mx <= -64) \ + mx += 64; \ + else if (mx >= 64) \ + mx -= 64; \ + \ + if (my <= -64) \ + my += 64; \ + else if (my >= 64) \ + my -= 64; \ + \ + mx_ptr = mx; \ + my_ptr = my; \ +} + +#define divx_encode_motion(enc_v, enc_bitidx, enc_len, val, pred, fc) \ +{ \ + register int range, l, bit_size, sign, code, bits; \ + \ + int local_val = val - pred; \ + if (local_val == 0) \ + { \ + code = 0; \ + /*DUMP_FRAME("MOTION ZERO code = %d\n", code);*/ \ + bitstream_put_bits(mvtab[code][1], mvtab[code][0], enc_v, enc_bitidx, enc_len); \ + } else \ + { \ + DWORD d; \ + bit_size = fc - 1; \ + range = 1 << bit_size; \ + /* modulo encoding (not divx3-like!) */ \ + l = range * 32; \ + local_val += l; \ + local_val &= 2*l-1; \ + local_val -= l; \ + sign = local_val >> 31; \ + local_val = (local_val^sign) - sign; \ + sign &= 1; \ + local_val--; \ + code = (local_val >> bit_size) + 1; \ + bits = local_val & (range - 1); \ + \ + /*DUMP_FRAME("MOTION code = %d sign=%d bits=%d bs=%d\n", code, sign, bits, bit_size);*/ \ + \ + d = ((mvtab[code][0] << 1) | sign); \ + bitstream_put_bits(mvtab[code][1] + 1, d, enc_v, enc_bitidx, enc_len); \ + if (bit_size > 0) \ + { \ + bitstream_put_bits(bit_size, bits, enc_v, enc_bitidx, enc_len); \ + } \ + } \ +} + +STATIC INLINE void divx_set_block_index() +{ + block_index[0] = block_index_tbl[mb_y][0]; + block_index[1] = block_index_tbl[mb_y][1]; + block_index[2] = block_index_tbl[mb_y][2]; + block_index[3] = block_index_tbl[mb_y][3]; + block_index[4] = block_index_tbl[mb_y][4]; + block_index[5] = block_index_tbl[mb_y][5]; +} + +STATIC INLINE void divx_update_block_index() +{ + block_index[0] += 2; + block_index[1] += 2; + block_index[2] += 2; + block_index[3] += 2; + block_index[4]++; + block_index[5]++; +} + +STATIC INLINE void divx_update_motion_val() +{ + register int xy = block_index[0]; + register int wrap = b8_stride; + + //DUMP_FRAME("--update_motion_val xy=%d = %d,%d\n", xy, motion_x, motion_y); + + register signed short smx = (signed short)motion_x; + register signed short smy = (signed short)motion_y; + motion_val[xy][0] = smx; + motion_val[xy][1] = smy; + motion_val[xy + 1][0] = smx; + motion_val[xy + 1][1] = smy; + motion_val[xy + wrap][0] = smx; + motion_val[xy + wrap][1] = smy; + motion_val[xy + 1 + wrap][0] = smx; + motion_val[xy + 1 + wrap][1] = smy; +} + +STATIC INLINE void divx_clean_intra_table_entries() +{ + register int wrap = b8_stride; + register int xy = block_index[0]; + register int xy1 = xy + 1, xywrap = xy + wrap, xy1wrap = xy + 1 + wrap; + + coded_block[xy] = coded_block[xy1] = coded_block[xywrap] = coded_block[xy1wrap] = 0; + + dec_dc_val[0][xy] = dec_dc_val[0][xy1] = dec_dc_val[0][xywrap] = dec_dc_val[0][xy1wrap] = 1024; + dec_dc_val[0][xy] = dec_dc_val[0][xy1] = dec_dc_val[0][xywrap] = dec_dc_val[0][xy1wrap] = 1024; + + enc_dc_val[0][xy] = enc_dc_val[0][xy1] = enc_dc_val[0][xywrap] = enc_dc_val[0][xy1wrap] = 1024; + enc_dc_val[0][xy] = enc_dc_val[0][xy1] = enc_dc_val[0][xywrap] = enc_dc_val[0][xy1wrap] = 1024; + + wrap = mb_stride; + xy = mb_x + mb_y * wrap; + dec_dc_val[1][xy] = dec_dc_val[2][xy] = 1024; + enc_dc_val[1][xy] = enc_dc_val[2][xy] = 1024; +} + +///////////////////////////////////////////////////////////////// + +#define divx_encode_mb_header(enc_v, enc_bitidx, enc_len, param_cbp, skip, ac_pred) \ +{ \ + DWORD cbpc = param_cbp & 3; \ + DWORD cbpy = param_cbp >> 2; \ + if (pict_type == DIVX_I_TYPE) \ + { \ + bitstream_put_bits(intra_MCBPC_bits[cbpc], intra_MCBPC_code[cbpc], enc_v, enc_bitidx, enc_len); \ + \ + if (mb_intra) \ + { \ + bitstream_put_bits(1, ac_pred, enc_v, enc_bitidx, enc_len); \ + } \ + else \ + cbpy ^= 0x0F; \ + /*DUMP_FRAME("cbpc=%d cbpy=%d\n", cbpc, cbpy);*/ \ + bitstream_put_bits(cbpy_tab[cbpy][1], cbpy_tab[cbpy][0], enc_v, enc_bitidx, enc_len); \ + } else \ + { \ + bitstream_put_bits(1, (skip ? 1 : 0), enc_v, enc_bitidx, enc_len); \ + if (!skip) \ + { \ + if (mb_intra) \ + cbpc |= 4; \ + bitstream_put_bits(inter_MCBPC_bits[cbpc], inter_MCBPC_code[cbpc], enc_v, enc_bitidx, enc_len); \ + \ + if (mb_intra) \ + { \ + bitstream_put_bits(1, ac_pred, enc_v, enc_bitidx, enc_len); \ + } \ + else \ + cbpy ^= 0x0F; \ + /*DUMP_FRAME("cbpc=%d cbpy=%d\n", cbpc, cbpy);*/ \ + bitstream_put_bits(cbpy_tab[cbpy][1], cbpy_tab[cbpy][0], enc_v, enc_bitidx, enc_len); \ + } \ + } \ +} + +#define divx_decode_picture_header(dec_v, dec_bitidx, dec_left) \ +{ \ + bitstream_get_bits(pict_type, 0, dec_v, dec_bitidx, dec_left, 2); \ + pict_type += 1; \ + if (pict_type != DIVX_I_TYPE && pict_type != DIVX_P_TYPE) \ + return -1; \ + bitstream_get_bits(qscale, 0, dec_v, dec_bitidx, dec_left, 5); \ + if (qscale == 0) \ + return -1; \ + chroma_qscale = chroma_qscale_table[qscale]; \ + enc_y_dc_scale = enc_y_dc_scale_table[qscale]; \ + enc_c_dc_scale = enc_c_dc_scale_table[chroma_qscale]; \ + dec_y_dc_scale = dec_y_dc_scale_table[qscale]; \ + dec_c_dc_scale = dec_c_dc_scale_table[chroma_qscale]; \ + \ + if (pict_type == DIVX_I_TYPE) \ + { \ + DWORD code; \ + bitstream_get_bits(code, 0, dec_v, dec_bitidx, dec_left, 5); \ + if (code < 0x17) \ + return -1; \ + \ + slice_height = mb_height / (code - 0x16); \ + \ + bitstream_get_bits012(rl_chroma_table_index, 0, dec_v, dec_bitidx, dec_left); \ + bitstream_get_bits012(rl_table_index, 0, dec_v, dec_bitidx, dec_left); \ + bitstream_get_bits1(dc_table_index, 0, dec_v, dec_bitidx, dec_left); \ + no_rounding = 1; \ + } else \ + { \ + bitstream_get_bits1(use_skip_mb_code, 0, dec_v, dec_bitidx, dec_left); \ + bitstream_get_bits012(rl_table_index, 0, dec_v, dec_bitidx, dec_left); \ + rl_chroma_table_index = rl_table_index; \ + bitstream_get_bits1(dc_table_index, 0, dec_v, dec_bitidx, dec_left); \ + bitstream_get_bits1(mv_table_index, 0, dec_v, dec_bitidx, dec_left); \ + \ + if(flipflop_rounding) \ + no_rounding ^= 1; \ + else \ + no_rounding = 0; \ + } \ +} + +#define divx_encode_vos_header(enc_v, enc_bitidx, enc_len) \ +{ \ + bitstream_put_bits(32, 0x000001B0, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(8, 0xf5, enc_v, enc_bitidx, enc_len); /* profile: f5=??? 01=MPEG4@SL1 */ \ +} + +#define divx_encode_vol_header(enc_v, enc_bitidx, enc_len) \ +{ \ + const int vo_number = 0; \ + const int vol_number = 0; \ + const int vo_ver_id = 1; \ + const int vo_type = 1; \ + const int aspect_ratio_info = 1; \ + \ + bitstream_put_bits(32, 0x100 + vo_number, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(32, 0x120 + vol_number, enc_v, enc_bitidx, enc_len); \ + \ + bitstream_put_bits(1, 0, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(8, vo_type, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(8, (1<<7)|(vo_ver_id<<3)|1, enc_v, enc_bitidx, enc_len); \ + \ + bitstream_put_bits(4, aspect_ratio_info, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(8, 0xB1, enc_v, enc_bitidx, enc_len); /*10110001b*/ \ + bitstream_put_bits(16, time_incr_res, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(3, 5, enc_v, enc_bitidx, enc_len); /* 101b */ \ + bitstream_put_bits(13, width, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(1, 1, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(13, height, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(1, 1, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(1, 0 /*progressive=1*/, enc_v, enc_bitidx, enc_len); \ + \ + bitstream_put_bits(8, 0x8C, enc_v, enc_bitidx, enc_len); /*10001100b*/ \ + \ + bitstream_put_bits(3, 3, enc_v, enc_bitidx, enc_len); \ +} + +#if 0 +static int divx_encode_gop_header(DWORD &enc_v, int &enc_bitidx, int &enc_len) +{ + bitstream_put_bits(32, 0x000001B3, enc_v, enc_bitidx, enc_len); + + LONGLONG time= pts; + const int AV_TIME_BASE = 1000000; + time= (time * time_incr_res + AV_TIME_BASE/2) / AV_TIME_BASE; + + int seconds = (int)(time / time_incr_res); + int minutes = seconds / 60; seconds %= 60; + int hours = minutes/60; minutes %= 60; hours%=24; + + bitstream_put_bits(5, hours, enc_v, enc_bitidx, enc_len); + bitstream_put_bits(6, minutes, enc_v, enc_bitidx, enc_len); + bitstream_put_bits(1, 1, enc_v, enc_bitidx, enc_len); + bitstream_put_bits(6, seconds, enc_v, enc_bitidx, enc_len); + + return bitstream_put_bits(6, 7, enc_v, enc_bitidx, enc_len); +} +#endif + + +#define divx_encode_picture_header(enc_v, enc_bitidx, enc_len) \ +{ \ + /* VOP header */ \ + int time_increment_bits; \ + int time_div = 0, time_mod = 0, time_incr; \ + \ + bitstream_put_bits(32, 0x000001b6, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(2, pict_type - 1, enc_v, enc_bitidx, enc_len); \ + \ + time_increment_bits = time_incr_res != 0 ? divx_log2(time_incr_res - 1) + 1 : 4; \ + \ + if (time_incr_res > 0) \ + { \ + time_div = (int)(pts / time_incr_res); \ + time_mod = (int)(pts % time_incr_res); \ + } \ + time_incr = time_div - last_time_div; \ + last_time_div = time_div; \ + \ + while (time_incr--) \ + { \ + bitstream_put_bits(1, 1, enc_v, enc_bitidx, enc_len); \ + } \ + bitstream_put_bits(2, 1, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(time_increment_bits, time_mod, enc_v, enc_bitidx, enc_len); \ + bitstream_put_bits(2, 3, enc_v, enc_bitidx, enc_len); \ + if (pict_type == DIVX_P_TYPE) \ + { \ + bitstream_put_bits(1, no_rounding, enc_v, enc_bitidx, enc_len); \ + } \ + \ + bitstream_put_bits(8, qscale & 31, enc_v, enc_bitidx, enc_len); \ + \ + if (pict_type != DIVX_I_TYPE) \ + { \ + bitstream_put_bits(3, f_code, enc_v, enc_bitidx, enc_len); \ + } \ +} + +///////////////////////////////////////////////////////////////// + +int divx_transcode_preinit() +{ + int i; + static const int bits_len2_size[9] = { 600, 800, 10, 1100, 600, 1700, 300, 500, 10 }; + static const int level_run2_size[6] = { 6, 130, 6, 100, 140, 6 }; + + uni_table[0] = (DWORD *)SPmalloc(128*64*2 * sizeof(DWORD)); + uni_table[1] = (DWORD *)SPmalloc(128*64*2 * sizeof(DWORD)); + if (uni_table[0] == NULL || uni_table[1] == NULL) + return -1; + + for (i = 0; i < 9; i++) + { + bits_len[i] = (DIVX_BITS_LEN *)SPmalloc(16484 * sizeof(DIVX_BITS_LEN)); + if (bits_len[i] == NULL) + return -1; + //memset(bits_len[i], 0xff, 16484 * sizeof(DIVX_BITS_LEN)); + bits_len2[i] = (DWORD *)SPmalloc(bits_len2_size[i] * sizeof(DWORD)); + if (bits_len2[i] == NULL) + return -1; + } + + for (i = 0; i < 6; i++) + { + level_run[i] = (DWORD *)SPmalloc(16484 * sizeof(DWORD)); + if (level_run[i] == NULL) + return -1; + level_run2[i] = (DWORD *)SPmalloc(level_run2_size[i] * sizeof(DWORD)); + if (level_run2[i] == NULL) + return -1; + } + + if (divx_init_rl(&rl_table[2]) < 0) + return -1; + if (divx_init_rl(&rl_table[5]) < 0) + return -1; + + return 0; +} + +int divx_transcode_predeinit() +{ + int i; + divx_free_rl(&rl_table[5]); + divx_free_rl(&rl_table[2]); + + SPSafeFree(uni_table[0]); + SPSafeFree(uni_table[1]); + + for (i = 0; i < 6; i++) + { + SPSafeFree(level_run[i]); + SPSafeFree(level_run2[i]); + } + for (i = 0; i < 9; i++) + { + SPSafeFree(bits_len[i]); + SPSafeFree(bits_len2[i]); + } + + return 0; +} + + +int divx_transcode_init(int w, int h, int t) +{ + int i, y_size, c_size, yc_size, b8_array_size; + width = w; + height = h; + mb_width = (width + 15) / 16; + mb_height = (height + 15) / 16; + mb_num = mb_width * mb_height; + no_rounding = 0; + flipflop_rounding = 1; + + b8_stride = mb_width * 2 + 1; + mb_stride = mb_width + 1; + y_size = b8_stride * (2 * mb_height + 1); + c_size = mb_stride * (mb_height + 1); + yc_size = y_size + 2 * c_size; + b8_array_size = b8_stride * mb_height * 2; + + enc_dc_val_base = (signed short *)SPcalloc(yc_size * sizeof(signed short)); + dec_dc_val_base = (signed short *)SPcalloc(yc_size * sizeof(signed short)); + coded_block_base = (BYTE *)SPcalloc(y_size); + motion_val_base = (signed short (*)[2])SPcalloc(2 * (b8_array_size + 2) * sizeof(signed short)); + block_index_tbl = (int (*)[6])SPmalloc(6 * mb_height * sizeof(int)); + + if (enc_dc_val_base == NULL || dec_dc_val_base == NULL || + coded_block_base == NULL || motion_val_base == NULL || block_index_tbl == NULL) + { + return -1; + } + +#ifdef USE_AC_CORRECTION + ac_size = yc_size * sizeof(int) * 16; + ac_val_base = (int *)SPcalloc(ac_size); + if (ac_val_base == NULL) + return -1; + ac_val = ac_val_base + (b8_stride + 1) * 16; +#endif + + block_wrap[0] = block_wrap[1] = block_wrap[2] = block_wrap[3] = b8_stride; + block_wrap[4] = block_wrap[5] = mb_stride; + + enc_dc_val[0] = enc_dc_val_base + b8_stride + 1; + enc_dc_val[1] = enc_dc_val_base + y_size + mb_stride + 1; + enc_dc_val[2] = enc_dc_val[1] + c_size; + dec_dc_val[0] = dec_dc_val_base + b8_stride + 1; + dec_dc_val[1] = dec_dc_val_base + y_size + mb_stride + 1; + dec_dc_val[2] = dec_dc_val[1] + c_size; + for (i = 0; i < yc_size; i++) + { + enc_dc_val_base[i] = 1024; + dec_dc_val_base[i] = 1024; + } + + for (i = 0; i < mb_height; i++) + { + block_index_tbl[i][0] = b8_stride * (i*2 ) - 2; + block_index_tbl[i][1] = b8_stride * (i*2 ) - 1; + block_index_tbl[i][2] = b8_stride * (i*2 + 1) - 2; + block_index_tbl[i][3] = b8_stride * (i*2 + 1) - 1; + block_index_tbl[i][4] = mb_stride * (i + 1) + b8_stride * mb_height*2 - 1; + block_index_tbl[i][5] = mb_stride * (i + mb_height + 2) + b8_stride * mb_height*2 - 1; + } + + coded_block = coded_block_base + b8_stride + 1; + + mb_x = mb_y = 0; + ac_pred = 0; + f_code = 2; + + dec_y_dc_scale_table = old_y_dc_scale_table; + dec_c_dc_scale_table = old_c_dc_scale_table; + enc_y_dc_scale_table = mpeg4_y_dc_scale_table; + enc_c_dc_scale_table = mpeg4_c_dc_scale_table; + chroma_qscale_table = default_chroma_qscale_table; + + if (divx_init_vlc(&mb_intra_vlc, 9, 64, &table_mb_intra[0][1], 4, 2, &table_mb_intra[0][0], 4, 2) < 0) + return -1; + + if (divx_init_vlc(&mb_non_intra_vlc, 9, 128, &table_mb_non_intra[0][1], 8, 4, &table_mb_non_intra[0][0], 8, 4) < 0) + return -1; + + for (i = 0; i < 2; i++) + { + DIVX_MV_TABLE *mv = &mv_tables[i]; + if (divx_init_vlc(&mv->vlc, 9, mv->n + 1, mv->table_mv_bits, 1, + 1, mv->table_mv_code, 2, 2) < 0) + return -1; + } + + if (divx_init_vlc(&dc_lum_vlc[0], 9, 120, &table0_dc_lum[0][1], 8, 4, &table0_dc_lum[0][0], 8, 4) < 0) + return -1; + if (divx_init_vlc(&dc_chroma_vlc[0], 9, 120, &table0_dc_chroma[0][1], 8, 4, &table0_dc_chroma[0][0], 8, 4) < 0) + return -1; + if (divx_init_vlc(&dc_lum_vlc[1], 9, 120, &table1_dc_lum[0][1], 8, 4, &table1_dc_lum[0][0], 8, 4) < 0) + return -1; + if (divx_init_vlc(&dc_chroma_vlc[1], 9, 120, &table1_dc_chroma[0][1], 8, 4, &table1_dc_chroma[0][0], 8, 4) < 0) + return -1; + + divx_init_scantable(&inter_scantable , zigzag_direct); + divx_init_scantable(&intra_scantable , zigzag_direct); + divx_init_scantable(&intra_h_scantable, alternate_horizontal_scan); + divx_init_scantable(&intra_v_scantable, alternate_vertical_scan); + + pts = 0; + time_incr_res = t; + last_time_div = 0; + + divx_init_uni_dc_tab(); + + divx_init_uni_tabs(); + divx_build_ac_tables(); + + // be careful, don't use uni_table! + SPSafeFree(uni_table[0]); + SPSafeFree(uni_table[1]); + + motion_val = motion_val_base + 2; + + block_flag = 1; + memset(block_flags, 0, sizeof(DWORD) * 64); + + frame_number = 0; + return 0; +} + +int divx_transcode_deinit() +{ + SPSafeFree(dc_lum_vlc[0].table); + SPSafeFree(dc_chroma_vlc[0].table); + SPSafeFree(dc_lum_vlc[1].table); + SPSafeFree(dc_chroma_vlc[1].table); + + SPSafeFree(mv_tables[0].vlc.table); + SPSafeFree(mv_tables[1].vlc.table); + + SPSafeFree(mb_intra_vlc.table); + SPSafeFree(mb_non_intra_vlc.table); + +#ifdef USE_AC_CORRECTION + SPSafeFree(ac_val_base); +#endif + + SPSafeFree(block_index_tbl); + SPSafeFree(motion_val_base); + SPSafeFree(coded_block_base); + SPSafeFree(dec_dc_val_base); + SPSafeFree(enc_dc_val_base); + + return 0; +} + +BOOL divx_is_key_frame() +{ + return pict_type == DIVX_I_TYPE; +} + +////////////////////////////////////////////////////// +#ifdef USE_AC_CORRECTION + +int divx_transcode_acpred_mb(DWORD &enc_v, int &ebitidx, int &enc_len, + DWORD &dec_v, int &bitidx, int &left, DWORD cbp) +{ + int blocks[6][64], *block; + int dc_levels[6]; + DWORD block_i; + DWORD block_coded[6]; + DWORD out_cbp = cbp & (~63); + + /// \TODO: move to the frame level + + for (block_i = 0; block_i < 6; block_i++) + { + int ac_i, run_diff; + int *dec_scan_table; + int dec_dc_pred_dir; + + DIVX_BITS_LEN *bits_len_tab; + DWORD *level_run_tab, *level_run_tab2; + DWORD *bits_len_tab2, *uni_tbl; + + int coded = (cbp >> (5 - block_i)) & 1; + int dc_level; + + register int level; + register DWORD run; + + run_diff = 0; + block = blocks[block_i]; + memset(block, 0, sizeof(int) * 64); + + // decode dc + if (block_i < 4) + divx_get_vlc3(level, dec_v, bitidx, left, dc_lum_vlc[dc_table_index].table); + else + divx_get_vlc3(level, dec_v, bitidx, left, dc_chroma_vlc[dc_table_index].table); + + if (level < 0) + return -1; + if (level == 119) + { + register DWORD ret; + bitstream_get_bits(level, 0, dec_v, bitidx, left, 8); + bitstream_get_bits1(ret, 0, dec_v, bitidx, left) + if (ret) + level = -level; + } + else if (level != 0) + { + register DWORD ret; + bitstream_get_bits1(ret, 0, dec_v, bitidx, left) + if (ret) + level = -level; + } + + dc_level = divx_pred_dc(block_i, level, &dec_dc_pred_dir, FALSE); + dc_levels[block_i] = dc_level; + dec_scan_table = (dec_dc_pred_dir == 0) ? + intra_v_scantable.permutated : intra_h_scantable.permutated; + +#ifdef DUMP +// DEBUG_MSG("-----------------\n"); +// DEBUG_MSG("{%d}: DC LEVEL=%d / INTRA=%d\n", block_i, dc_level, mb_intra); +#endif + + if (!coded) + { + DWORD coded = divx_pred_notcoded_ac(block_i, block, dec_dc_pred_dir); + out_cbp |= coded << (5 - block_i); + block_coded[block_i] = coded; + continue; + } + + ac_i = 0; +#ifdef DUMP + //DEBUG_MSG(" DIR: dec=%d, enc=%d\n", dec_dc_pred_dir, enc_dc_pred_dir); +#endif + + DWORD tbl_idx = block_i >> 2; + bits_len_tab = bits_len_tab_cur[tbl_idx]; + bits_len_tab2 = bits_len_tab2_cur[tbl_idx]; + uni_tbl = uni_table[0]; + level_run_tab = level_run_tab_cur[tbl_idx]; + level_run_tab2 = level_run_tab2_cur[tbl_idx]; + + while (ac_i < 64) + { + register DWORD idx, bits, len; + bitstream_show_bits(idx, dec_v, bitidx, 16); + + bits = level_run_tab[idx>>2]; + + if (bits == 0) // esc123 + { + bits = bits_len_tab[idx>>2].bits; + len = bits_len_tab[idx>>2].len; + bitstream_skip_bits(0, dec_v, bitidx, left, bits); + + if (len == 3) // esc3 + { + bitstream_get_bits(bits, 0, dec_v, bitidx, left, (1+6+8)); + level = (bits & 0x80) ? ((bits & 0xff) | 0xffffff00) : (bits & 0x7f); + run = ((bits >> 8) & 63) + 1; + if (bits & 0x4000) + break; + } + else // esc1,esc2 + { + BOOL esc1 = (len & 1); + bitstream_show_bits(idx, dec_v, bitidx, 16); + bits = level_run_tab[idx>>2]; + if ((bits >> 16) == 0) + bits = level_run_tab2[bits | (idx & 3)]; + len = ((bits >> 18) & 0xf) + 1; + bitstream_skip_bits(0, dec_v, bitidx, left, len); + + level = ((int)bits) >> 25; + run = (bits & 63) + 1; + + if (esc1) + { + level = level > 0 ? level + ((bits >> 12) & 31) * qmul : level - ((bits >> 12) & 31) * qmul; + } else + { + run += (bits >> 6) & 63; + run += run_diff; + } + + if (bits & (1 << 17)) + break; + } + } else + { + if ((bits >> 16) == 0) + bits = level_run_tab2[bits | (idx & 3)]; + len = ((bits >> 18) & 0xf) + 1; + bitstream_skip_bits(0, dec_v, bitidx, left, len); + level = ((int)bits) >> 25; + + run = (bits & 63) + 1; + if (bits & (1 << 17)) + break; + } + + ac_i += run; + idx = dec_scan_table[ac_i]; + block[idx] = level; +#ifdef DUMP + //DEBUG_MSG("-> level=%d, run=%d\n", level, run); + block_idx[idx] = ac_i; + block_run[idx] = run; +#endif + } + + + ac_i += run; + +#ifdef DUMP + //DEBUG_MSG("-> level=%d, run=%d\n", level, run); + block_idx[dec_scan_table[ac_i]] = ac_i; + block_run[dec_scan_table[ac_i]] = run; +#endif + + run = dec_scan_table[ac_i]; + block[run] = level; + + // we have reconstructed block at this moment... + coded = divx_pred_ac(block_i, block, dec_dc_pred_dir); + out_cbp |= coded << (5 - block_i); + block_coded[block_i] = coded; + } + + ////////////////////////////////////////////////////////////////////////////// + /// NOW ENCODE!!! + + divx_encode_mb_header(enc_v, ebitidx, enc_len, out_cbp, FALSE, 0); + + for (block_i = 0; block_i < 6; block_i++) + { + register int level; + register DWORD run, i; + int last_non_zero = 0; + int *enc_scan_table; + int enc_dc_pred_dir; + + block = blocks[block_i]; + +#ifdef DUMP + DEBUG_MSG("-----------------\n"); + DEBUG_MSG("{%d}: DC LEVEL=%d / INTRA=%d\n", block_i, dc_levels[block_i], mb_intra); + + for (i = 0; i < 64; i++) + { + if (block[i] != 0) + { + //DEBUG_MSG("[%d] = %d (%d,run=%d)\n", i, block[i], block_idx[i], block_run[i]); + DEBUG_MSG("[%d] = %d\n", i, block[i]); + } + } +#endif + + level = divx_pred_dc(block_i, dc_levels[block_i], &enc_dc_pred_dir, TRUE); + divx_encode_dc(enc_v, ebitidx, enc_len, level, block_i); + + if (!block_coded[block_i]) + continue; + + enc_scan_table = (enc_dc_pred_dir == 0) ? + intra_v_scantable.permutated : intra_h_scantable.permutated; + + // now output the table + level = 0; + run = 0; + for (i = 0; i < 64; i++) + { + register DWORD eidx = enc_scan_table[i]; + + if (block[eidx] != 0) + { + if (level && (int)run > last_non_zero) + { + divx_put_rl_vlc_esc3(enc_v, ebitidx, enc_len, level, 0, run - last_non_zero); + last_non_zero = run; + } + + level = block[eidx]; + run = i; + } + } + + divx_put_rl_vlc_esc3(enc_v, ebitidx, enc_len, level, 1, run - last_non_zero); + } + + return 0; +} + +#endif + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +int divx_transcode(bitstream_callback callback) +{ + int code; + int block[64]; + + register DWORD dec_v; + register int bitidx, left; + register DWORD enc_v = 0; + register int ebitidx = 31; + register int enc_len = 0; + + DWORD *block_f; + + bitstream_set_callback(0, callback); + bitstream_decode_start(0, dec_v, bitidx, left); + + divx_decode_picture_header(dec_v, bitidx, left); + + if (divx_is_key_frame()) + { + divx_encode_vos_header(enc_v, ebitidx, enc_len); + divx_encode_vol_header(enc_v, ebitidx, enc_len); + //if (divx_encode_gop_header(enc_v, ebitidx, len) < 0) + // return -1; + bitstream_flush_output(BITSTREAM_MODE_OUTPUT, enc_v, ebitidx, enc_len); + + enc_v = 0; + ebitidx = 31; + enc_len = 0; + } + divx_encode_picture_header(enc_v, ebitidx, enc_len); + + // process VOP + first_slice_line = 1; + + mb_x = 0; + mb_y = 0; + + bits_len_tab_cur[0] = bits_len[rl_table_index]; + bits_len_tab_cur[1] = bits_len[3 + rl_chroma_table_index]; + bits_len_tab_cur[2] = bits_len[6 + rl_table_index]; + bits_len_tab2_cur[0] = bits_len2[rl_table_index]; + bits_len_tab2_cur[1] = bits_len2[3 + rl_chroma_table_index]; + bits_len_tab2_cur[2] = bits_len2[6 + rl_table_index]; + level_run_tab_cur[0] = level_run[rl_table_index]; + level_run_tab_cur[1] = level_run[3 + rl_chroma_table_index]; + level_run_tab_cur[2] = level_run[3 + rl_table_index]; + level_run_tab2_cur[0] = level_run2[rl_table_index]; + level_run_tab2_cur[1] = level_run2[3 + rl_chroma_table_index]; + level_run_tab2_cur[2] = level_run2[3 + rl_table_index]; + + block_f = block_flags; + +#ifdef USE_AC_CORRECTION + memset(ac_val_base, 0, ac_size); +#endif + + for (; mb_y < mb_height; mb_y++) + { + divx_set_block_index(); + + for (; mb_x < mb_width; mb_x++) + { + // process MB +#ifdef DUMP + DEBUG_MSG("-[%d: %d %d] --------------------------------------------\n", frame_number, mb_x, mb_y); +#endif + + int pred_x, pred_y; + DWORD cbp = 0; + DWORD block_i; + +#ifdef USE_AC_CORRECTION + use_acpred = 1; + + if (!mb_intra) + { + qmul = qscale << 1; + qadd = (qscale - 1) | 1; + +#ifdef DUMP + //DEBUG_MSG("qmul=%d, qadd=%d\n", qmul, qadd); +#endif + + } else + { + qmul = 1; + qadd = 0; + } + +#endif + +/* +if (frame_number == 0 && mb_x == 31 && mb_y == 16) +{ + int kk = 1; +} +*/ + pred_x = 0; + pred_y = 0; + mb_skip = FALSE; + + motion_x = 0; + motion_y = 0; + + divx_update_block_index(); + + if (pict_type == DIVX_I_TYPE) + { + BYTE *coded_val; + int i; + + mb_intra = TRUE; + divx_get_vlc2(code, dec_v, bitidx, left, mb_intra_vlc.table); + + for (i = 0; i < 6; i++) + { + int val = ((code >> (5 - i)) & 1); + if (i < 4) + { + int pred = divx_coded_block_pred(i, &coded_val); + val = val ^ pred; + *coded_val = (BYTE)val; + } + cbp |= val << (5 - i); + } + } + else if (pict_type == DIVX_P_TYPE) + { + if (use_skip_mb_code) + { + register DWORD ret; + bitstream_get_bits1(ret, 0, dec_v, bitidx, left); + if (ret) + { + mb_intra = FALSE; + mb_skip = TRUE; + } + } + if (!mb_skip) + { + divx_get_vlc3(code, dec_v, bitidx, left, mb_non_intra_vlc.table); + if (code < 0) + return -1; + mb_intra = ((~code & 0x40) >> 6) != 0; + cbp = code & 0x3f; + } + } + + if (mb_intra) + { + bitstream_get_bits1(ac_pred, 0, dec_v, bitidx, left); +#ifdef DUMP + DEBUG_MSG("CBP=%d, ACPRED=%d\n", cbp, ac_pred); +#endif + +#ifdef USE_AC_CORRECTION + use_acpred = 1; + + if (use_acpred && ac_pred) + { + if (divx_transcode_acpred_mb(enc_v, ebitidx, enc_len, dec_v, bitidx, left, cbp) < 0) + return -1; + continue; + } +#endif + + } else + { +#ifdef DUMP + //DEBUG_MSG("CBP=%d, intra=%d\n", cbp, mb_intra); +#endif + if (!mb_skip) + { + // predict motion + divx_pred_motion(&pred_x, &pred_y); + + motion_x = pred_x; + motion_y = pred_y; + divx_decode_motion(dec_v, bitidx, left, motion_x, motion_y); +#ifdef DUMP + DEBUG_MSG("MOTION mx=%d my=%d\n", motion_x, motion_y); +#endif + } + + if ((cbp | motion_x | motion_y) == 0) + mb_skip = TRUE; + + } + + divx_encode_mb_header(enc_v, ebitidx, enc_len, cbp, mb_skip, ac_pred); + + if (!mb_intra && !mb_skip) + { + divx_encode_motion(enc_v, ebitidx, enc_len, motion_x, pred_x, f_code); + divx_encode_motion(enc_v, ebitidx, enc_len, motion_y, pred_y, f_code); + } + + for (block_i = 0; block_i < 6; block_i++) + { + int ac_i, run_diff; + int last_non_zero; + int *dec_scan_table, *enc_scan_table; + int *enc_inv_scan_table; + + DIVX_BITS_LEN *bits_len_tab; + DWORD *level_run_tab, *level_run_tab2; + DWORD *bits_len_tab2, *uni_tbl; + + DWORD last_scan = 0; + DWORD coded = (cbp >> (5 - block_i)) & 1; + BOOL the_same_scan_table = TRUE; + int dec_dc_pred_dir, enc_dc_pred_dir; + + if (mb_intra) + { + int level, dc_level; + DWORD tbl_idx; + + run_diff = 0; + + // decode dc + if (block_i < 4) + { + divx_get_vlc3(level, dec_v, bitidx, left, dc_lum_vlc[dc_table_index].table); + } + else + { + divx_get_vlc3(level, dec_v, bitidx, left, dc_chroma_vlc[dc_table_index].table); + } + + if (level < 0) + return -1; + if (level == 119) + { + register DWORD ret; + bitstream_get_bits(level, 0, dec_v, bitidx, left, 8); + bitstream_get_bits1(ret, 0, dec_v, bitidx, left); + if (ret) + level = -level; + } + else if (level != 0) + { + register DWORD ret; + bitstream_get_bits1(ret, 0, dec_v, bitidx, left); + if (ret) + level = -level; + } + + dc_level = divx_pred_dc(block_i, level, &dec_dc_pred_dir, FALSE); +#ifdef DUMP + DEBUG_MSG("-----------------\n"); + DEBUG_MSG("{%d}: DC LEVEL=%d / INTRA=%d\n", block_i, dc_level, mb_intra); +#endif + + level = divx_pred_dc(block_i, dc_level, &enc_dc_pred_dir, TRUE); + divx_encode_dc(enc_v, ebitidx, enc_len, level, block_i); + if (!coded) + continue; + + ac_i = 0; + if (ac_pred && dec_dc_pred_dir != enc_dc_pred_dir) + the_same_scan_table = FALSE; +#ifdef DUMP + //DEBUG_MSG(" DIR: dec=%d, enc=%d\n", dec_dc_pred_dir, enc_dc_pred_dir); +#endif + + tbl_idx = block_i >> 2; + bits_len_tab = bits_len_tab_cur[tbl_idx]; + bits_len_tab2 = bits_len_tab2_cur[tbl_idx]; + uni_tbl = uni_table[0]; + level_run_tab = level_run_tab_cur[tbl_idx]; + level_run_tab2 = level_run_tab2_cur[tbl_idx]; + } else + { + if (!coded) + continue; + + run_diff = 1; + ac_i = -1; + bits_len_tab = bits_len_tab_cur[2]; + bits_len_tab2 = bits_len_tab2_cur[2]; + uni_tbl = uni_table[1]; + level_run_tab = level_run_tab_cur[2]; + level_run_tab2 = level_run_tab2_cur[2]; + } +#ifdef USE_SLOW_METHOD_LIMIT +#ifdef USE_SLOW_METHOD + if (frame_size > max_allowed_frame_size_for_correct_method) +#endif + the_same_scan_table = TRUE; +#endif + +#ifdef USE_ONLY_SLOW_METHOD + if (the_same_scan_table) + { + enc_dc_pred_dir = dec_dc_pred_dir; + the_same_scan_table = FALSE; + } +#endif + + + if (!the_same_scan_table) + { +#ifdef USE_AC_CORRECTION + // ???????????????????????????????? + dec_scan_table = ac_pred ? ((dec_dc_pred_dir == 0) ? + intra_v_scantable.permutated : + intra_h_scantable.permutated) : intra_scantable.permutated; + enc_scan_table = ac_pred ? ((enc_dc_pred_dir == 0) ? + intra_v_scantable.permutated : + intra_h_scantable.permutated) : intra_scantable.permutated; + enc_inv_scan_table = ac_pred ? ((enc_dc_pred_dir == 0) ? + intra_v_scantable.inv_permutated : + intra_h_scantable.inv_permutated) : intra_scantable.inv_permutated; +#else + dec_scan_table = (dec_dc_pred_dir == 0) ? + intra_v_scantable.permutated : // left + intra_h_scantable.permutated; // top + enc_scan_table = (enc_dc_pred_dir == 0) ? + intra_v_scantable.permutated : // left + intra_h_scantable.permutated; // top + enc_inv_scan_table = (enc_dc_pred_dir == 0) ? + intra_v_scantable.inv_permutated : // left + intra_h_scantable.inv_permutated; // top +#endif + } + + last_non_zero = ac_i; + + if (the_same_scan_table) + { + for(;;) + { + register DWORD idx, bits, len; + bitstream_show_bits(idx, dec_v, bitidx, 16); + + bits = bits_len_tab[idx>>2].bits; + len = bits_len_tab[idx>>2].len; + if (len >= 16) // normal (outlen < 16 bits, inlen < 14 bits) + { + bitstream_skip_bits(0, dec_v, bitidx, left, len & 0xf); + len >>= 4; + if (bits & 0x8000) // last + { + bits &= ~0x8000; + bitstream_put_bits(len, bits, enc_v, ebitidx, enc_len); + break; + } + bitstream_put_bits(len, bits, enc_v, ebitidx, enc_len); + } + else // extended || esc123 + { + if (len == 0) // extended (16 bits < outlen < 23 bits) + { + bits = bits_len_tab2[bits | (idx & 3)]; + len = ((bits >> 5) & 0xf) + 1; + bitstream_skip_bits(0, dec_v, bitidx, left, len); + len = (bits & 31); + if (bits & 0x80000000) // last + { + bits = (bits & ~(0x80000000)) >> 9; + bitstream_put_bits(len, bits, enc_v, ebitidx, enc_len); + break; + } + bitstream_put_bits(len, bits >> 9, enc_v, ebitidx, enc_len); + } + else if (len == 4) // extended-"ESC4" (outlen >= 23 bits) + { + DWORD last; + int level; + bits = level_run_tab[idx>>2]; + // if extended (first VLC is longer than 14 bits) + if ((bits >> 16) == 0) + bits = level_run_tab2[bits | (idx & 3)]; + len = ((bits >> 18) & 0xf) + 1; + bitstream_skip_bits(0, dec_v, bitidx, left, len); + + last = (bits & (1 << 17)) << 3; + level = ((int)bits) >> 25; + bits = ((bits & 63) << 14); + bits += ((level & 0xfff) << 1) + last + ((3 << 23) + (3 << 21) + (1 << 13) + 1); + bitstream_put_bits((7+2+1+6+1+12+1), bits, enc_v, ebitidx, enc_len); + if (last) + break; + } + else + { + bitstream_skip_bits(0, dec_v, bitidx, left, bits); + + if (len == 3) // esc3 + { + int level; + DWORD last; + bitstream_get_bits(bits, 0, dec_v, bitidx, left, (1+6+8)); + + level = (bits & 0x80) ? ((bits & 0xff) | 0xffffff00) : (bits & 0x7f); + last = ((bits << 6) & 0x100000); + + bits = last + (((bits >> 8) & 63) << 14); + bits += ((3 << 23) + (3 << 21) + (1 << 13) + 1) + ((level & 0xfff) << 1); + + bitstream_put_bits((7+2+1+6+1+12+1), bits, enc_v, ebitidx, enc_len); + if (last) + break; + } + else // esc1,esc2 + { + BOOL esc1 = (len & 1); + int level; + DWORD run, last; + bitstream_show_bits(idx, dec_v, bitidx, 16); + bits = level_run_tab[idx>>2]; + + // if extended esc1/2 (first VLC is longer than 14 bits) + if ((bits >> 16) == 0) + bits = level_run_tab2[bits | (idx & 3)]; + + len = ((bits >> 18) & 0xf) + 1; + bitstream_skip_bits(0, dec_v, bitidx, left, len); + + /* bits = level(7)+reserved(3)+first_len(4)+first_last(1)+add_level(5)+add_run(6)+run(6) */ + level = ((int)bits) >> 25; + run = (bits & 63) + 1; + last = (bits & (1 << 17)) << 3; + + if (esc1) + { + level = level > 0 ? level + ((bits >> 12) & 31) : level - ((bits >> 12) & 31); + } else + { + run += (bits >> 6) & 63; + run += run_diff; + } + + // now we have level, run, last - output in ESC3 mode + bits = ((3 << 23) + (3 << 21) + (1 << 13) + 1) + last + ((run - 1) << 14) + ((level & 0xfff) << 1); + + // TODO: use uni_tab + bitstream_put_bits((7+2+1+6+1+12+1), bits, enc_v, ebitidx, enc_len); + if (last) + break; + } + continue; + } + } + } + } + else /////////////////////////////////////////////////////////// + { +#ifdef USE_SLOW_METHOD + register int level; + register DWORD run, i; + + while (ac_i < 64) + { + register DWORD idx, bits, len; + bitstream_show_bits(idx, dec_v, bitidx, 16); + + bits = level_run_tab[idx>>2]; + + if (bits == 0) // esc123 + { + bits = bits_len_tab[idx>>2].bits; + len = bits_len_tab[idx>>2].len; + bitstream_skip_bits(0, dec_v, bitidx, left, bits); + + if (len == 3) // esc3 + { + bitstream_get_bits(bits, 0, dec_v, bitidx, left, (1+6+8)); + level = (bits & 0x80) ? ((bits & 0xff) | 0xffffff00) : (bits & 0x7f); + run = ((bits >> 8) & 63) + 1; + if (bits & 0x4000) + break; + } + else // esc1,esc2 + { + BOOL esc1 = (len & 1); + bitstream_show_bits(idx, dec_v, bitidx, 16); + bits = level_run_tab[idx>>2]; + if ((bits >> 16) == 0) + bits = level_run_tab2[bits | (idx & 3)]; + len = ((bits >> 18) & 0xf) + 1; + bitstream_skip_bits(0, dec_v, bitidx, left, len); + + level = ((int)bits) >> 25; + run = (bits & 63) + 1; + + if (esc1) + { + level = level > 0 ? level + ((bits >> 12) & 31) : level - ((bits >> 12) & 31); + } else + { + run += (bits >> 6) & 63; + run += run_diff; + } + + if (bits & (1 << 17)) + break; + } + } else + { + if ((bits >> 16) == 0) + bits = level_run_tab2[bits | (idx & 3)]; + len = ((bits >> 18) & 0xf) + 1; + bitstream_skip_bits(0, dec_v, bitidx, left, len); + level = ((int)bits) >> 25; + + run = (bits & 63) + 1; + if (bits & (1 << 17)) + break; + } + + ac_i += run; + idx = dec_scan_table[ac_i]; + bits = enc_inv_scan_table[idx]; + if (last_scan < bits) + last_scan = bits; + block[idx] = level; + block_f[idx] = block_flag; +#ifdef DUMP + //DEBUG_MSG("-> level=%d, run=%d\n", level, run); + block_idx[idx] = ac_i; + block_run[idx] = run; +#endif + } + + + ac_i += run; + +#ifdef DUMP + //DEBUG_MSG("-> level=%d, run=%d\n", level, run); + block_idx[dec_scan_table[ac_i]] = ac_i; + block_run[dec_scan_table[ac_i]] = run; +#endif + + run = dec_scan_table[ac_i]; + i = enc_inv_scan_table[run]; + if (last_scan < i) + last_scan = i; + block[run] = level; + block_f[run] = block_flag; + + // we have reconstructed block at this moment... +#ifdef DUMP + for (i = 0; i < 64; i++) + { + if (block_f[i] == block_flag) + { + //DEBUG_MSG("[%d] = %d (%d,run=%d)\n", i, block[i], block_idx[i], block_run[i]); + DEBUG_MSG("[%d] = %d\n", i, block[i]); + } + } +#endif + + // now output the table + level = 0; + run = 0; + + for (i = 0; i <= last_scan; i++) + { + register DWORD eidx = enc_scan_table[i]; + + if (block_f[eidx] == block_flag) + { + if (level && (int)run > last_non_zero) + { +#if 0 + if (!((level + 64) & (~127))) // ESC3 + { + idx = (DWORD)(level + 64) + (run - last_non_zero)*128; + last_non_zero = run; + idx = uni_tbl[idx]; + run = idx >> 24; + idx &= 0xffffff; + bitstream_put_bits(run, idx, enc_v, ebitidx, enc_len); + } + else +#endif + { + divx_put_rl_vlc_esc3(enc_v, ebitidx, enc_len, level, 0, run - last_non_zero); + last_non_zero = run; + } + } + level = block[eidx]; + run = i; + } + } + + if (level && (int)run > last_non_zero) + { + +#if 0 + if (!((level + 64) & (~127))) // ESC3 + { + idx = 128*64 + (DWORD)(level + 64) + (run - last_non_zero)*128; + idx = uni_tbl[idx]; + run = idx >> 24; + idx &= 0xffffff; + bitstream_put_bits(run, idx, enc_v, ebitidx, enc_len); + } else +#endif + { + divx_put_rl_vlc_esc3(enc_v, ebitidx, enc_len, level, 1, run - last_non_zero); + } + } + +#ifdef USE_AC_CORRECTION + if (use_acpred && mb_intra) + { + divx_pred_flaged_ac(block_i, block, block_f, block_flag, dec_dc_pred_dir); + } +#endif + + block_flag++; +#endif + } + } + + if (!mb_intra) + divx_clean_intra_table_entries(); + divx_update_motion_val(); + } + first_slice_line = 0; + mb_x = 0; + } + // flush last output bits + bitstream_flush_output(BITSTREAM_MODE_DONE, enc_v, ebitidx, enc_len); + frame_number++; + return 0; + +} + diff --git a/src/divx.h b/src/divx.h new file mode 100644 index 0000000..3cefe00 --- /dev/null +++ b/src/divx.h @@ -0,0 +1,122 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DivX3->MPEG-4 transcoder header file + * \file divx.h + * \author bombur + * \version 0.1 + * \date 1.04.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_DIVX_H +#define SP_DIVX_H + +#include + +#ifdef DIVX_INTERNAL + +#define DIVX_I_TYPE 1 +#define DIVX_P_TYPE 2 + +// run length table +#define DIVX_MAX_RUN 64 +#define DIVX_MAX_LEVEL 64 + +typedef struct DIVX_VLC +{ + int bits; + signed short (*table)[2]; ///< code, bits + int table_size, table_allocated; +} DIVX_VLC; + +typedef struct DIVX_RL_VLC_ELEM +{ + signed short level; + signed char len; + BYTE run; +} DIVX_RL_VLC_ELEM; + +typedef struct DIVX_RL_TABLE +{ + DWORD n; ///< number of entries of table_vlc minus 1 + int last; ///< number of values for last = 0 + const WORD (*table_vlc)[2]; + const signed char *table_run; + const signed char *table_level; + BYTE *index_run[2]; ///< encoding only + signed char *max_level[2]; ///< encoding & decoding + signed char *max_run[2]; ///< encoding & decoding + DIVX_VLC vlc; ///< decoding only + DIVX_RL_VLC_ELEM *rl_vlc[32]; ///< decoding only +} DIVX_RL_TABLE; + +typedef struct DIVX_SCAN_TABLE +{ + const BYTE *scantable; + int permutated[64]; + int inv_permutated[64]; + BYTE raster_end[64]; +} DIVX_SCAN_TABLE; + +typedef struct DIVX_MV_TABLE +{ + int n; + const WORD *table_mv_code; + const BYTE *table_mv_bits; + const BYTE *table_mvx; + const BYTE *table_mvy; + WORD *table_mv_index; /* encoding: convert mv to index in table_mv */ + DIVX_VLC vlc; /* decoding: vlc */ +} DIVX_MV_TABLE; + +//////////////////////////////////////////////// + +#ifdef WIN32 +#pragma pack(1) +#endif + +typedef struct ATTRIBUTE_PACKED +{ + BYTE len; + WORD bits; +} DIVX_BITS_LEN; + +#ifdef WIN32 +#pragma pack() +#endif + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int divx_transcode_preinit(void); +int divx_transcode_predeinit(void); + +int divx_transcode_init(int width, int height, int time_incr_res); +int divx_transcode_deinit(void); + +int divx_transcode(bitstream_callback); + +BOOL divx_is_key_frame(void); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_DIVX_H diff --git a/src/dvd.h b/src/dvd.h new file mode 100644 index 0000000..d2649f6 --- /dev/null +++ b/src/dvd.h @@ -0,0 +1,115 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DVD player header file + * \file dvd.h + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_DVD_H +#define SP_DVD_H + +// must be equal to DVDMenuID_t from dvdtypes.h +typedef enum +{ + DVD_MENU_DEFAULT = -1, + DVD_MENU_ESCAPE = 0, + DVD_MENU_TITLE = 2, + DVD_MENU_ROOT = 3, + DVD_MENU_SUBTITLE = 4, + DVD_MENU_AUDIO = 5, + DVD_MENU_ANGLE = 6, + DVD_MENU_CHAPTERS = 7 +} DVD_MENU_TYPE; + + +//////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/// Open DVD player +int dvd_open(const char *path); +/// Close DVD player +int dvd_close(); +/// Reset DVD player +int dvd_reset(); + +/// Get next data block +int dvd_get_next_block(BYTE **buf, int *event, int *len); +/// Free data block (if cache used). +int dvd_free_block(BYTE *data); + +/// Get DVD error string +char *dvd_error_string(); + +/// Seek to given time and play +BOOL dvd_seek(int seconds); +BOOL dvd_seek_titlepart(int title, int part); +void dvd_get_cur(int *title, int *chapter); +int dvd_getnumchapters(int title); +int dvd_getnumtitles(); + +void dvd_button_play(); + +void dvd_setdeflang_menu(char *); +void dvd_setdeflang_audio(char *); +void dvd_setdeflang_spu(char *); + +/// Play DVD disc (from drive or folder) +int dvd_play(const char *dvdpath, bool play_from_drive); + +/// Stop playing +BOOL dvd_stop(); + +bool dvd_do_command(const SPString & command); + +bool dvd_get_saved(); + +/// Change playing speed +BOOL dvd_setspeed(MPEG_SPEED_TYPE speed); +MPEG_SPEED_TYPE dvd_getspeed(); + +void dvd_setdebug(BOOL ison); +BOOL dvd_getdebug(); + +/// Advance playing +int dvd_player_loop(); + +int dvd_getangle(); +bool dvd_ismenu(); + +// title = 1..99, chapter = 1.999 +// time in seconds +int dvd_get_total_time(int title, int chapter, int *time); +int dvd_get_chapter_for_time(int title, int time, int *chapter); + +void dvd_button_menu(DVD_MENU_TYPE menu = DVD_MENU_DEFAULT); +void dvd_button_angle(int setangl = -1); +void dvd_button_audio(char *setlang = NULL, int startfrom = 0); +void dvd_button_subtitle(char *setlang = NULL, int startfrom = 0); + + +#ifdef __cplusplus +} +#endif + +#endif // of SP_DVD_H diff --git a/src/dvd/Makefile b/src/dvd/Makefile new file mode 100644 index 0000000..32c7821 --- /dev/null +++ b/src/dvd/Makefile @@ -0,0 +1,89 @@ +######################################################################### +# +# SigmaPlayer source project - DVD module makefile +# \file Makefile +# \author bombur +# \version 0.3 +# \date 10.12.2008 +# +########################################################################## + + +########################################################################## + +MAIN_SRC := main.cpp + +PROJECT_SRC := \ + dvd.cpp \ + dvd_player.cpp \ + dvd_misc.c \ + dvd_css.c \ + module.cpp \ + module-dvd.cpp \ + module-init.cpp \ + ../libsp/containers/string.cpp + +PREBUILD := cd ../contrib/libdvdcss && make && cd ../libdvdnav && make && cd ../../dvd + +EXTERNAL_STATIC_LINKS_WITH := \ + ../contrib/memcpy.o \ + ../contrib/strcmp.o \ + ../contrib/strlen.o \ + ../contrib/libdvdnav/src/.libs/libdvdnav.a \ + ../contrib/libdvdcss/src/.libs/libdvdcss.a + +SPINCLUDE = ../libsp/ +DVDINCLUDE = ../contrib/libdvdnav/src/ +DVDINCLUDE1 = ../contrib/libdvdnav/src/dvdread/ +DVDINCLUDE2 = ../contrib/libdvdnav/src/vm/ +DVDINCLUDE3 = ../contrib/libdvdcss/ +DVDINCLUDE4 = ../contrib/libdvdcss/src/ + +ifeq "$(PLAYER_MODEL)" "Technosonic" +SPCFLAGS += -DSP_PLAYER_TECHNOSONIC=1 +LIBSP_SPECIFIC := \ + ../libsp/MP/sp_module.cpp \ + ../libsp/MP/sp_module_crt0.S + +endif + +ifeq "$(PLAYER_MODEL)" "DreamX108" +SPCFLAGS += -DSP_PLAYER_DREAMX108=1 +LIBSP_SPECIFIC := \ + ../libsp/MP/sp_module.cpp \ + ../libsp/MP/sp_module_crt0.S +endif + +ifeq "$(PLAYER_MODEL)" "Mecotek" +SPCFLAGS += -DSP_PLAYER_MECOTEK=1 +LIBSP_SPECIFIC := \ + ../libsp/MP/sp_module.cpp \ + ../libsp/MP/sp_module_crt0.S +endif + +SPCFLAGS += -fno-exceptions -I.. -I$(SPINCLUDE) -I$(DVDINCLUDE) -I$(DVDINCLUDE1) -I$(DVDINCLUDE2) -I$(DVDINCLUDE3) -I$(DVDINCLUDE4) -DDVDNAV_COMPILE=1 -D__UCLIBC_CTOR_DTOR__ -DCOMPILE_MODULE -D_GNU_SOURCE +SPCXXFLAGS += -fpermissive -fno-rtti + +SPCFLAGS += -D_strdup=strdup -D_lseek=lseek -D_read=read -D_open=open -D_close=close + +LOCAL_MAKEFILE := Makefile + +TARGET_TYPE := EXECUTABLE + +SRC := $(PROJECT_SRC) $(LIBSP_SPECIFIC) + +USE_STD_LIB := 1 + +COMPILKIND = release + +PREPROCESSORFLAGS += -D__STDC_LIMIT_MACROS -DSP_ARM=1 + +MAKE_CLEAN = rm -fr *.gdb && cd ../contrib/libdvdnav && make clean && cd ../libdvdcss && make clean && cd ../../dvd + +CROSS = arm-elf- +LDFLAGS = -elf2flt="-s128" -s --static -nostdlib +EXEFLAGS = -lgcc + + +include ../Makefile.inc + diff --git a/src/dvd/dvd-internal.h b/src/dvd/dvd-internal.h new file mode 100644 index 0000000..61cf578 --- /dev/null +++ b/src/dvd/dvd-internal.h @@ -0,0 +1,83 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DVD player INTERNAL header file + * \file dvd/dvd-internal.h + * \author bombur + * \version 0.2 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_DVD_INTERNAL_H +#define SP_DVD_INTERNAL_H + +//////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/// Pause playing +BOOL dvd_pause(); + +/// Continue playing from saved position +BOOL dvd_continue_play(); + +/// Set title (used for navigation) +int dvd_loadtitle(int titl); + +BOOL dvd_zoom_hor(int scale); +BOOL dvd_zoom_ver(int scale); +BOOL dvd_scroll(int offx, int offy); + +char *dvd_getdeflang_menu(); +char *dvd_getdeflang_audio(); +char *dvd_getdeflang_spu(); + +/// Menu button controls +void dvd_button_press(); +void dvd_button_up(); +void dvd_button_down(); +void dvd_button_left(); +void dvd_button_right(); + +void dvd_getstringlang(BYTE *strlang, WORD lang); + +void dvd_button_return(); + +void dvd_button_pause(); +void dvd_button_step(); +void dvd_button_slow(); +void dvd_button_prev(); +void dvd_button_next(); +void dvd_button_fwd(); +void dvd_button_rew(); + +//////////////// +/// internal funcs. + +// used by dvdnav_get_spu_logical_stream() +int dvd_get_spu_mode(KHWL_VIDEOMODE vmode); + +int dvd_savepos(bool reset); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_DVD_INTERNAL_H diff --git a/src/dvd/dvd-langs.inc.cpp b/src/dvd/dvd-langs.inc.cpp new file mode 100644 index 0000000..71e4dc5 --- /dev/null +++ b/src/dvd/dvd-langs.inc.cpp @@ -0,0 +1,170 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DVD language strings header file + * \file dvd/dvd-langs.inc.cpp + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +static DvdLanguage dvdlangs[] = +{ + { "Afar", 0x6161, }, // "aa" + { "Abkhazian", 0x6162, }, // "ab" + { "Afrikaans", 0x6166, }, // "af" + { "Amharic", 0x616d, }, // "am" + { "Arabic", 0x6172, }, // "ar" + { "Assamese", 0x6173, }, // "as" + { "Aymara", 0x6179, }, // "ay" + { "Azerbaijani", 0x617a, }, // "az" + { "Bashkir", 0x6261, }, // "ba" + { "Byelorussian", 0x6265, }, // "be" + { "Bulgarian", 0x6267, }, // "bg" + { "Bihari", 0x6268, }, // "bh" + { "Bislama", 0x6269, }, // "bi" + { "Bengali", 0x626e, }, // "bn" + { "Tibetan", 0x626f, }, // "bo" + { "Breton", 0x6272, }, // "br" + { "Catalan", 0x6361, }, // "ca" + { "Corsican", 0x636f, }, // "co" + { "Czech", 0x6373, }, // "cs" + { "Welsh", 0x6379, }, // "cy" + { "Danish", 0x6461, }, // "da" + { "Deutsch", 0x6465, }, // "de" + { "Bhutani", 0x647a, }, // "dz" + { "Greek", 0x656c, }, // "el" + { "English", 0x656e, }, // "en" + { "Esperanto", 0x656f, }, // "eo" + { "Espanol", 0x6573, }, // "es" + { "Estonian", 0x6574, }, // "et" + { "Basque", 0x6575, }, // "eu" + { "Persian", 0x6661, }, // "fa" + { "Finnish", 0x6669, }, // "fi" + { "Fiji", 0x666a, }, // "fj" + { "Faroese", 0x666f, }, // "fo" + { "Francais", 0x6672, }, // "fr" + { "Frisian", 0x6679, }, // "fy" + { "Irish", 0x6761, }, // "ga" + { "Scots Gaelic", 0x6764, }, // "gd" + { "Galician", 0x676c, }, // "gl" + { "Guarani", 0x676e, }, // "gn" + { "Gujarati", 0x6775, }, // "gu" + { "Hausa", 0x6861, }, // "ha" + { "Hebrew", 0x6865, }, // "he" + { "Hindi", 0x6869, }, // "hi" + { "Croatian", 0x6872, }, // "hr" + { "Magyar", 0x6875, }, // "hu" + { "Armenian", 0x6961, }, // "ia" + { "Indonesian", 0x6964, }, // "id" + { "Interlingue", 0x6965, }, // "ie" + { "Inupiak", 0x696b, }, // "ik" + { "Indonesian", 0x696e, }, // "in" + { "Icelandic", 0x6973, }, // "is" + { "Italian", 0x6974, }, // "it" + { "Inuktitut", 0x6975, }, // "iu" + { "Hebrew", 0x6977, }, // "iw" + { "Japanese", 0x6a61, }, // "ja" + { "Yiddish", 0x6a69, }, // "ji" + { "Javanese", 0x6a77, }, // "jw" + { "Georgian", 0x6b61, }, // "ka" + { "Kazakh", 0x6b6b, }, // "kk" + { "Greenlandic", 0x6b6c, }, // "kl" + { "Cambodian", 0x6b6d, }, // "km" + { "Kannada", 0x6b6e, }, // "kn" + { "Korean", 0x6b6f, }, // "ko" + { "Kashmiri", 0x6b73, }, // "ks" + { "Kurdish", 0x6b75, }, // "ku" + { "Kirghiz", 0x6b79, }, // "ky" + { "Latin", 0x6c61, }, // "la" + { "Lingala", 0x6c6e, }, // "ln" + { "Laothian", 0x6c6f, }, // "lo" + { "Lithuanian", 0x6c74, }, // "lt" + { "Latvian", 0x6c76, }, // "lv" + { "Malagasy", 0x6d67, }, // "mg" + { "Maori", 0x6d69, }, // "mi" + { "Macedonian", 0x6d6b, }, // "mk" + { "Malayalam", 0x6d6c, }, // "ml" + { "Mongolian", 0x6d6e, }, // "mn" + { "Moldavian", 0x6d6f, }, // "mo" + { "Marathi", 0x6d72, }, // "mr" + { "Malay", 0x6d73, }, // "ms" + { "Maltese", 0x6d74, }, // "mt" + { "Burmese", 0x6d79, }, // "my" + { "Nauru", 0x6e61, }, // "na" + { "Nepali", 0x6e65, }, // "ne" + { "Nederlands", 0x6e6c, }, // "nl" + { "Norsk", 0x6e6f, }, // "no" + { "Occitan", 0x6f63, }, // "oc" + { "Oromo", 0x6f6d, }, // "om" + { "Oriya", 0x6f72, }, // "or" + { "Punjabi", 0x7061, }, // "pa" + { "Polish", 0x706c, }, // "pl" + { "Pashto", 0x7073, }, // "ps" + { "Portugues", 0x7074, }, // "pt" + { "Quechua", 0x7175, }, // "qu" + { "Rhaeto-Romance", 0x726d, }, // "rm" + { "Kirundi", 0x726e, }, // "rn" + { "Romanian", 0x726f, }, // "ro" + { "Russian", 0x7275, }, // "ru" + { "Kinyarwanda", 0x7277, }, // "rw" + { "Sanskrit", 0x7361, }, // "sa" + { "Sindhi", 0x7364, }, // "sd" + { "Sangho", 0x7367, }, // "sg" + { "Serbo-Croatian", 0x7368, }, // "sh" + { "Sinhalese", 0x7369, }, // "si" + { "Slovak", 0x736b, }, // "sk" + { "Slovenian", 0x736c, }, // "sl" + { "Samoan", 0x736d, }, // "sm" + { "Shona", 0x736e, }, // "sn" + { "Somali", 0x736f, }, // "so" + { "Albanian", 0x7371, }, // "sq" + { "Serbian", 0x7372, }, // "sr" + { "Siswati", 0x7373, }, // "ss" + { "Sesotho", 0x7374, }, // "st" + { "Sundanese", 0x7375, }, // "su" + { "Svenska", 0x7376, }, // "sv" + { "Swahili", 0x7377, }, // "sw" + { "Tamil", 0x7461, }, // "ta" + { "Telugu", 0x7465, }, // "te" + { "Tajik", 0x7467, }, // "tg" + { "Thai", 0x7468, }, // "th" + { "Tigrinya", 0x7469, }, // "ti" + { "Turkmen", 0x746b, }, // "tk" + { "Tagalog", 0x746c, }, // "tl" + { "Setswana", 0x746e, }, // "tn" + { "Tonga", 0x746f, }, // "to" + { "Turkish", 0x7472, }, // "tr" + { "Tsonga", 0x7473, }, // "ts" + { "Tatar", 0x7474, }, // "tt" + { "Twi", 0x7477, }, // "tw" + { "Uighur", 0x7567, }, // "ug" + { "Ukrainian", 0x756b, }, // "uk" + { "Urdu", 0x7572, }, // "ur" + { "Uzbek", 0x757a, }, // "uz" + { "Vietnamese", 0x7569, }, // "ui" + { "Volapuk", 0x766f, }, // "vo" + { "Wolof", 0x776f, }, // "wo" + { "Xhosa", 0x7868, }, // "xh" + { "Yiddish", 0x7969, }, // "yi" + { "Yoruba", 0x796f, }, // "yo" + { "Zhuang", 0x7a61, }, // "za" + { "Chinese", 0x7a68, }, // "zh" + { "Zulu", 0x7a75, }, // "zu" + { "", 0x0 }, + { "", 0xffff }, +}; diff --git a/src/dvd/dvd.cpp b/src/dvd/dvd.cpp new file mode 100644 index 0000000..0edc94f --- /dev/null +++ b/src/dvd/dvd.cpp @@ -0,0 +1,3157 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DVD player source file. Uses libdvdnav. + * \file dvd/dvd.cpp + * \author bombur + * \version 0.21 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "script.h" + +#include + +#include "dvd-internal.h" +#include "dvd_misc.h" +#include "media.h" +#include "settings.h" + + +class DvdLanguage +{ +public: + const char *str; + WORD code; +}; + + +#include "dvd-langs.inc.cpp" + +///////////////////////////////////// +#define DVD_DEBUG +#define DVD_USE_MACROVISION +// It's a must if we use our buffering!!! +#define DVD_USE_CACHE + +///////////////////////////////////// + +#ifndef DVD_DEBUG +static void empty_msg(char *,...) +{ +} +#define MSG empty_msg +#define MSG_ERROR empty_msg +#else +#define MSG if (dvd_msg) msg +#define MSG_ERROR msg_error +#endif + +////////////////////////////////////////////////////////////////////// + +//#define DVD_PTS_DEBUG 1 +//#define DVD_PACKETS_DEBUG 1 + +const int dvd_num_saved = 5; + +int MPEG_PACKET_LENGTH = 0; + +bool no_spu = false; +bool no_khwl_play = false; +#ifdef WIN32 +bool dvd_msg = true; +#else +bool dvd_msg = false; +#endif + +static int cur_titleid, cur_chapid, cur_titlpos; +static int old_titleid, old_chapid; +static int cur_pack; +static LONGLONG cur_cell_pts = 0, old_cell_pts = 0, cur_cell_length = 0, cur_vobu_pts = 0; +static LONGLONG cur_pgc_length = 0; +static LONGLONG saved_pts = 0; +static int old_vob_id = -1, old_vob_cell_id = -1; +static bool vts_changed = false; +static bool dvd_menu_ahead = false; +static bool need_user_reset = false; +static int number_of_angles = 1; + +static bool dvd_play_from_drive = false; + +static int dvd_skipoffs = 0; +static int num_packets = 0; + +static dvdnav_t *dvd = NULL; +static pci_t *cur_pci = NULL; +static dsi_t *cur_dsi = NULL; + +static DWORD dvd_ID = 0; +static bool dvd_was_saved = false; +static DWORD dvd_saved_pos = 0xffffffff; +static DWORD dvd_saved_title = 0xffffffff; +static int dvd_saved_vmode = -1, dvd_saved_audio_stream = -1, dvd_saved_spu_stream = -1; + +static LONGLONG dvd_vobu_start_ptm = 0; +static LONGLONG pts_base = 0; +static int dvd_vobu_start_pos = 0; +static bool dvd_seamless = true; +static bool dvd_lastbtnupdate = false; + +static bool dvd_not_played_yet = true; +static bool dvd_waiting_to_play = false; + +static int dvd_mv_flags = -1; +static bool dvd_use_mv = true; + +static int read_max_allowed_time = 180; + +extern bool msg_debug; + +extern "C" +{ + int mv_cgms_flags = 0; +} + +static int dvd_read_errors = 0; +static bool wait_for_user = false; +static int wait_pause = 0; +static ULONGLONG wait_time = 0; +static int wait_iter = 0; +static int dvd_cur_button = -1; +static bool dvd_buttons_enabled = false; +static bool dvd_button_selected = false; + +static bool need_to_set_pts = false; +static bool need_to_check_pts = false; +static LONGLONG vobu_sptm = 0; + +static LONGLONG dvd_vobu_last_ptm = 0; + +static bool need_skip = false, was_video = false, can_skip = false; +static int num_skip = 0; + +static bool dvd_scan = false; + +static bool new_frame_size = false; +static int dvd_video_info_cnt = 0; + +static int spu_command = 0; +static MPEG_SPEED_TYPE dvd_speed = MPEG_SPEED_NORMAL; +static KHWL_VIDEOMODE dvd_vmode = KHWL_VIDEOMODE_NORMAL; +static int dvd_spu_channel_letterbox = -1; +static int dvd_spu_channel_panscan = -1; +static KHWL_SPU_BUTTON_TYPE last_upd_but; + +static int dvd_spu_stream = -1, dvd_old_spu_stream = -1; +static int dvd_aud_stream = -1, dvd_old_aud_stream = -1; + +static int forced_spu = -1; +static WORD forced_spu_lang = 0xffff; +static int forced_audio = -1; +static WORD forced_audio_lang = 0xffff; + +static WORD deflang_menu = 0x656e, deflang_audio = 0x656e, deflang_spu = 0x656e; + +static BYTE *dvdlang_lut = NULL; + +static void dvd_clearhighlights(); +static void dvd_spu_enable(bool onoff); +static void dvd_buttons_enable(bool onoff); +static int dvd_player_loop_internal(bool feed = true); + +typedef struct DVD_BUTTON +{ + DWORD left, top, right, bottom; +} DVD_BUTTON; + +const int max_buttons = 256; +DVD_BUTTON cur_buttons[max_buttons]; +int cur_num_buttons = 0; +bool need_to_check_buttons = true; + +//////////////////////////////////////////////////////// +#if 0 + +typedef struct DVD_BUTTON_QUEUE +{ + DVD_BUTTON_QUEUE *next; + int i; + int bn; + int mode; + LONGLONG pts; +} DVD_BUTTON_QUEUE; + +DVD_BUTTON_QUEUE buttons[max_buttons]; +DVD_BUTTON_QUEUE *butqueue_first = NULL, *butqueue_last = NULL; + +void dvd_init_buttons_queue() +{ + for (int i = 0; i < max_buttons; i++) + buttons[i].i = -1; + butqueue_first = NULL; + butqueue_last = NULL; +} + +/// Adds button to the queue. +/// \TODO: Optimise! +void dvd_add_button(int bn, int mode, LONGLONG pts) +{ + DVD_BUTTON_QUEUE *newbut = buttons; + for (int i = 0; i < max_buttons; i++, newbut++) + { + if (newbut->i == -1) + { + if (butqueue_last == NULL) + butqueue_first = newbut; + else + butqueue_last->next = newbut; + butqueue_last = newbut; + newbut->i = i; + newbut->bn = bn; + newbut->mode = mode; + newbut->pts = pts; + newbut->next = NULL; + break; + } + } +} + +void dvd_update_buttons(LONGLONG curpts) +{ + /*if (dvd_cur_button == -1) + { + dvd_clearhighlights(); + return; + } + */ + DVD_BUTTON_QUEUE *cur = butqueue_first, *prev = NULL; + while (cur != NULL) + { + if (cur->pts <= curpts) + { + dvd_update_button(cur->bn, cur->mode); + // remove button from the queue + cur->i = -1; + if (prev == NULL) + butqueue_first = cur->next; + else + prev->next = cur->next; + if (cur == butqueue_last) + butqueue_last = prev; + } else + prev = cur; + cur = cur->next; + } +} + +void dvd_print_buttons_queue() +{ + MSG("DVD: Buttons queue:\n"); + DVD_BUTTON_QUEUE *cur = butqueue_first; + while (cur != NULL) + { + MSG("DVD: but=%d (%d) pts=%d\n", cur->bn, cur->i, cur->pts); + cur = cur->next; + } +} +#endif + +///////////////////////////////////////////////////////////////////////// + +void dvd_invalid() +{ + script_error_callback(SCRIPT_ERROR_INVALID); +} + +void dvd_setdebug(BOOL ison) +{ + dvd_msg = ison == TRUE; +} + +BOOL dvd_getdebug() +{ + return dvd_msg; +} + +void dvd_fip_init() +{ + // write dvd-specific FIP stuff... + fip_write_special(FIP_SPECIAL_DVD, 1); + const char *digits = " 00000"; + fip_write_string(digits); + fip_write_special(FIP_SPECIAL_COLON1, 1); + fip_write_special(FIP_SPECIAL_COLON2, 1); +} + +/////////////////////////////////////////////////////////// + +int dvd_open(const char *path) +{ + if (dvdnav_open(&dvd, path) != DVDNAV_STATUS_OK) + { + msg_error("Media: Couldn't open DVD: %s\n", path); + return -1; + } + + if (dvdnav_set_readahead_flag(dvd, 1) != DVDNAV_STATUS_OK) + { + msg_error("Media: Error on set_readahead_flag: %s\n", dvdnav_err_to_string(dvd)); + return -2; + } + + // set the languages + if (dvdnav_menu_language_select(dvd, dvd_getdeflang_menu()) != DVDNAV_STATUS_OK + || dvdnav_audio_language_select(dvd, dvd_getdeflang_audio()) != DVDNAV_STATUS_OK + || dvdnav_spu_language_select(dvd, dvd_getdeflang_spu()) != DVDNAV_STATUS_OK) + { + msg_error("Media: Error on setting languages: %s\n", dvdnav_err_to_string(dvd)); + return -3; + } + + // set the PGC positioning flag to have position information relatively to the + // whole feature instead of just relatively to the current chapter + if (dvdnav_set_PGC_positioning_flag(dvd, 1) != DVDNAV_STATUS_OK) + { + msg_error("Media: Error on set_PGC_positioning_flag: %s\n", dvdnav_err_to_string(dvd)); + return -4; + } + dvdnav_set_cache_memory(dvd, mpeg_getbufbase()); + + dvd_make_crc_table(); + dvd_was_saved = false; + dvd_saved_pos = 0xffffffff; + dvd_saved_title = 0xffffffff; + dvd_ID = dvd_get_disc_ID(dvd_play_from_drive ? NULL : path); + dvd_get_saved(); + script_player_saved_callback(); + + return 0; +} + +int dvd_close() +{ + if (dvdnav_close(dvd) != DVDNAV_STATUS_OK) + return -1; + return 0; +} + +int dvd_reset() +{ + if (dvdnav_reset(dvd) != DVDNAV_STATUS_OK) + return -1; + return 0; +} + +////////////////////////////////////////////////////////////////// + +int dvd_play(const char *dvdpath, bool play_from_drive) +{ + fip_clear(); + fip_write_string("LoAd"); + + cur_titleid = 0; + cur_chapid = 0; + cur_titlpos = 0; + + old_titleid = 0; + old_chapid = 0; + + cur_cell_pts = 0; cur_cell_length = 0; cur_vobu_pts = 0; + old_cell_pts = 0; + cur_pgc_length = 0; + old_vob_id = -1; + old_vob_cell_id = -1; + vts_changed = false; + + dvd_not_played_yet = true; + dvd_waiting_to_play = false; + + dvd_mv_flags = -1; + + dvd = NULL; + cur_pci = NULL; + cur_dsi = NULL; + dvd_read_errors = 0; + no_spu = false; + + dvd_play_from_drive = play_from_drive; + + MEDIA_TYPES mt = MEDIA_TYPE_DVD; + + // Open the disc or file. + int ret = media_open(dvdpath, mt); + if (ret < 0) + { + MSG_ERROR("DVD: media open FAILED.\n"); + return ret; + } + + MSG("DVD: start...\n"); + + khwl_stop(); + khwl_display_clear(); + + mpeg_init(MPEG_2, FALSE, FALSE, FALSE); + mpeg_setbuffer(MPEG_BUFFER_1, mpeg_getbufbase(), 8, 32768); + +/////////////////////////////////////////////////// + + MPEG_PACKET_LENGTH = mpeg_getpacketlength(); + + num_packets = 0; + + pts_base = 0; + dvd_vobu_start_ptm = 0; + dvd_vobu_start_pos = 0; + need_to_set_pts = false; + need_to_check_pts = false; + saved_pts = 0; + vobu_sptm = 0; + + wait_for_user = false; + wait_pause = 0; + wait_time = 0; + wait_iter = 0; + + need_skip = false; + can_skip = false; + was_video = false; + num_skip = 0; + dvd_menu_ahead = false; + need_user_reset = false; + + dvd_scan = false; + + dvd_seamless = true; + dvd_speed = MPEG_SPEED_NORMAL; + + spu_command = 0; + + dvd_spu_enable(true); + + dvd_buttons_enable(false); + + dvd_spu_channel_letterbox = -1; + dvd_spu_channel_panscan = -1; + dvd_spu_stream = -1; dvd_old_spu_stream = -1; + dvd_aud_stream = -1; dvd_old_aud_stream = -1; + + cur_num_buttons = 0; + need_to_check_buttons = true; + + new_frame_size = false; + dvd_video_info_cnt = 0; + dvd_lastbtnupdate = false; + + forced_spu = -1; + forced_spu_lang = 0xffff; + forced_audio = -1; + forced_audio_lang = 0xffff; + +/////////////////////////////////////////// + SPSafeFree(dvdlang_lut); + dvdlang_lut = (BYTE *)SPcalloc(65536); + for (int i = 0; i < 256; i++) + { + dvdlang_lut[dvdlangs[i].code] = (BYTE)i; + if (dvdlangs[i].code == 0xffff) + break; + } + + MSG("DVD: Setting default audio params.\n"); + MpegAudioPacketInfo defaudioparams; + defaudioparams.type = eAudioFormat_AC3; + defaudioparams.samplerate = 48000; + defaudioparams.fromstream = 0; + mpeg_setaudioparams(&defaudioparams); + + dvd_use_mv = settings_get(SETTING_DVD_MV) != 0; + + dvd_fip_init(); + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + + script_audio_info_callback(""); + script_video_info_callback(""); + + khwl_set_window_zoom(KHWL_ZOOMMODE_DVD); + + return 0; +} + +BOOL dvd_pause() +{ + dvd_button_pause(); + return TRUE; +} + +void dvd_clearhighlights() +{ + MSG("DVD: Clear highlights...\n"); + if (!no_spu) + { + static KHWL_SPU_BUTTON_TYPE but; + memset(&but, 0, sizeof(but)); + khwl_setproperty(KHWL_SUBPICTURE_SET, eSubpictureUpdateButton, sizeof(but), &but); + last_upd_but = but; + } +#if 0 + dvd_init_buttons_queue(); +#endif + dvd_button_selected = false; +} + +void dvd_spu_enable(bool onoff) +{ + if (!no_spu) + { + if (onoff) + spu_command |= KHWL_SPU_ENABLE; + else + spu_command &= ~(KHWL_SPU_ENABLE); + khwl_setproperty(KHWL_SUBPICTURE_SET, eSubpictureCmd, sizeof(spu_command), &spu_command); + } +} + +void dvd_buttons_enable(bool onoff) +{ + if (!no_spu) + { + if (onoff) + { + spu_command |= (KHWL_SPU_ENABLE | KHWL_SPU_BUTTONS_ENABLE); + } else + { + spu_command &= ~(KHWL_SPU_BUTTONS_ENABLE); + dvd_clearhighlights(); + } + khwl_setproperty(KHWL_SUBPICTURE_SET, eSubpictureCmd, sizeof(spu_command), &spu_command); + + dvd_buttons_enabled = onoff; + + MSG("DVD: SPU buttons: %s\n", onoff ? "enable" : "disable"); + } +} + +void dvd_update_button(int bn, int mode) +{ + /// we handle different aspect ratios (like dxr3 does) + if (cur_pci != NULL) + { + if (bn > 0 && bn <= (int)cur_pci->hli.hl_gi.btn_ns) + { + dvd_button_selected = true; + + btni_t *button_ptr = NULL; + int b1 = cur_pci->hli.hl_gi.btngr1_dsp_ty; + int b2 = cur_pci->hli.hl_gi.btngr2_dsp_ty; + int b3 = cur_pci->hli.hl_gi.btngr3_dsp_ty; + MSG("DVD: * button%d: gr1=%d gr2=%d gr3=%d (ngr=%d)\n", bn, b1, b2, b3, cur_pci->hli.hl_gi.btngr_ns); + + DWORD gr = 6, gr_res = 0; + // use a letterbox button group for letterboxed anamorphic menus on tv out + if (dvd_vmode == KHWL_VIDEOMODE_LETTERBOX && dvd_spu_channel_letterbox >= 0) + { + gr = 2; + gr_res = 2; + } + if (dvd_vmode == KHWL_VIDEOMODE_PANSCAN && dvd_spu_channel_panscan >= 0) + { + gr = 4; + gr_res = 4; + } + // (otherwise use a normal 4:3 or widescreen button group) + DWORD i, btns_per_group = cur_pci->hli.hl_gi.btngr_ns == 0 ? 0 : 36 / cur_pci->hli.hl_gi.btngr_ns; + for (i = 0; button_ptr == NULL && i < cur_pci->hli.hl_gi.btngr_ns; i++) + { + int dsp_ty = 0; + switch (i) + { + case 0: + dsp_ty = cur_pci->hli.hl_gi.btngr1_dsp_ty; + break; + case 1: + dsp_ty = cur_pci->hli.hl_gi.btngr2_dsp_ty; + break; + case 2: + dsp_ty = cur_pci->hli.hl_gi.btngr3_dsp_ty; + break; + } + if ((dsp_ty & gr) == gr_res) + button_ptr = &cur_pci->hli.btnit[i * btns_per_group + bn - 1]; + } + bool needs_scale = false; + if (button_ptr == NULL) // this is really bad - we aren't sure that our scaling is good! :-( + { + button_ptr = &cur_pci->hli.btnit[bn - 1]; + needs_scale = true; + MSG("DVD: * Using our scaling...\n"); + } else + { + MSG("DVD: * Button group %d matched!\n", i); + } + + /*if (dvdnav_get_highlight_area(cur_pci, bn, mode, &hl) == DVDNAV_STATUS_OK) + */ + if (button_ptr != NULL) + { + KHWL_SPU_BUTTON_TYPE but; + but.left = button_ptr->x_start; + but.top = button_ptr->y_start; + but.right = button_ptr->x_end+1; + but.bottom = button_ptr->y_end+1; + if (needs_scale) + { + int w, h; + mpeg_getframesize(&w, &h); + khwl_transformcoord(dvd_vmode, &but.left, &but.top, w, h); + khwl_transformcoord(dvd_vmode, &but.right, &but.bottom, w, h); + } + + int pal = 0; + if (button_ptr->btn_coln > 0 && mode > 0) + pal = cur_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode - 1]; + but.color = pal >> 16; + but.contrast = pal & 0xffff; + if (!no_spu) + { + khwl_setproperty(KHWL_SUBPICTURE_SET, eSubpictureUpdateButton, sizeof(but), &but); + last_upd_but = but; + dvd_lastbtnupdate = true; + } + + MSG("DVD: * update_button (%d %d %d %d, %08x)\n", but.left, but.top, but.right, but.bottom, pal); + } + } + } +} + + + +void dvd_getcharlang(BYTE *strlang, WORD lang) +{ + strlang[0] = (BYTE)((lang >> 8) & 0xff); + if (strlang[0] <= 32) + strlang[0] = '?'; + else if (strlang[0] == 0xff) + strlang[0] = '-'; + strlang[1] = (BYTE)(lang & 0xff); + if (strlang[1] <= 32) + strlang[1] = '?'; + else if (strlang[1] == 0xff) + strlang[1] = '-'; + strlang[2] = '\0'; +} + +void dvd_getstringlang(BYTE *strlang, WORD lang) +{ + strlang[0] = (BYTE)((lang >> 8) & 0xff); + if (strlang[0] <= 32) + strlang[0] = '?'; + else if (strlang[0] == 0xff) + strlang[0] = '-'; + strlang[1] = (BYTE)(lang & 0xff); + if (strlang[1] <= 32) + strlang[1] = '?'; + else if (strlang[1] == 0xff) + strlang[1] = '-'; + strlang[2] = '\0'; +} + +WORD dvd_getintlang(BYTE *strlang) +{ + if (strlang[0] <= 32 || strlang[1] <= 32) + return 0xffff; + WORD lang = (WORD)((tolower(strlang[0]) << 8) | tolower(strlang[1])); + return lang; +} + +void dvd_setdeflang_menu(char *l) +{ + deflang_menu = dvd_getintlang((BYTE *)l); +} +char *dvd_getdeflang_menu() +{ + static char l[3]; + dvd_getcharlang((BYTE *)l, deflang_menu); + return l; +} +void dvd_setdeflang_audio(char *l) +{ + deflang_audio = dvd_getintlang((BYTE *)l); +} + +char *dvd_getdeflang_audio() +{ + static char l[3]; + dvd_getcharlang((BYTE *)l, deflang_audio); + return l; +} +void dvd_setdeflang_spu(char * l) +{ + deflang_spu = dvd_getintlang((BYTE *)l); +} +char *dvd_getdeflang_spu() +{ + static char l[3]; + dvd_getcharlang((BYTE *)l, deflang_spu); + return l; +} + +////////////////////////////////////////////////// + +int dvd_get_spu_mode(KHWL_VIDEOMODE vmode) +{ + if (vmode == KHWL_VIDEOMODE_LETTERBOX) + return 1; + else if (vmode == KHWL_VIDEOMODE_PANSCAN) + return 2; + // wide + return 0; +} + +int dvd_get_spu_stream_from_user(int stream_id, WORD lang) +{ + if (stream_id < 0 || lang == 0xffff) + return -1; + // first, test saved stream id + int logstream = dvd_get_spu_logical_stream(dvd, (BYTE)stream_id, dvd_get_spu_mode(dvd_vmode)); + WORD slang = logstream >= 0 ? dvdnav_spu_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + if (logstream >= 0 && slang == lang) + return stream_id; + // it seems that the streams were changed - find by language + for (int stream = 0; stream < 32; stream++) + { + logstream = dvd_get_spu_logical_stream(dvd, (BYTE)stream, dvd_get_spu_mode(dvd_vmode)); + slang = logstream >= 0 ? dvdnav_spu_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + if (logstream >= 0 && slang == lang) + return stream; + } + return -1; +} + +int dvd_get_audio_stream_from_user(int stream_id, WORD lang) +{ + if (stream_id < 0 || lang == 0xffff) + return -1; + // first, test saved stream id + int logstream = dvd_get_audio_logical_stream(dvd, (BYTE)stream_id); + WORD slang = logstream >= 0 ? dvdnav_audio_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + if (logstream >= 0 && slang == lang) + return stream_id; + // it seems that the streams were changed - find by language + for (int stream = 0; stream < 8; stream++) + { + logstream = dvd_get_audio_logical_stream(dvd, (BYTE)stream); + slang = logstream >= 0 ? dvdnav_audio_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + if (logstream >= 0 && slang == lang) + return stream; + } + return -1; +} + +BOOL dvd_setspeed(MPEG_SPEED_TYPE speed) +{ + if (dvd_speed == speed && speed != MPEG_SPEED_STEP) + { + MSG("DVD: Speed %d already set!\n", speed); + return FALSE; + } + + if (!mpeg_setspeed(speed)) + return FALSE; + + dvd_speed = speed; + + need_skip = false; + num_skip = 0; + + // restore pts + if (speed == MPEG_SPEED_NORMAL) + { + need_to_set_pts = true; + } else + { + dvd_clearhighlights(); + need_user_reset = true; + } + + // set 'fip' symbols + if (dvd_speed == MPEG_SPEED_PAUSE) + { + fip_write_special(FIP_SPECIAL_PLAY, 0); + fip_write_special(FIP_SPECIAL_PAUSE, 1); + } + else if (dvd_speed == MPEG_SPEED_STEP) + { + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 1); + } + else if (dvd_speed != MPEG_SPEED_STOP) + { + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + } + + if ((dvd_speed & MPEG_SPEED_FAST_FWD_MASK) == MPEG_SPEED_FAST_FWD_MASK + || (dvd_speed & MPEG_SPEED_FAST_REV_MASK) == MPEG_SPEED_FAST_REV_MASK) + { + need_skip = true; + dvdnav_set_readahead_flag(dvd, 0); + } else + { + dvdnav_set_readahead_flag(dvd, 1); + } + + MSG("DVD: Speed set to %d\n", dvd_speed); + + return TRUE; +} + +MPEG_SPEED_TYPE dvd_getspeed() +{ + return dvd_speed; +} + +void dvd_user_reset() +{ + if (dvd_speed != MPEG_SPEED_NORMAL) + { + MSG("DVD: Resetting speed to normal.\n"); + dvd_setspeed(MPEG_SPEED_NORMAL); + script_speed_callback(); + } + if (mpeg_zoom_reset()) + { + MSG("DVD: Reset zoom&scroll to 0.\n"); + script_zoom_scroll_reset_callback(); + } + need_user_reset = false; +} + +#define VALID_XWDA(offset) \ + (((offset) & SRI_END_OF_CELL) != SRI_END_OF_CELL && \ + ((offset) & 0x80000000)) + +BOOL dvd_skip(dsi_t *dsi) +{ + /* + float stime[19] = { + 120, // 0 | 18 + 60, // 1 | 17 + 30, // 2 | 16 + 10, // 3 | 15 + 7.5, // 4 | 14 + 7, // 5 | 13 + 6.5, // 6 | 12 + 6, // 7 | 11 + 5.5, // 8 | 10 + 5, // 9 | 9 + 4.5, // 10 | 8 + 4, // 11 | 7 + 3.5, // 12 | 6 + 3, // 13 | 5 + 2.5, // 14 | 4 + 2, // 15 | 3 + 1.5, // 16 | 2 + 1, // 17 | 1 + 0.5 // 18 | 0 + }; + */ + + static int saved_bl = 0; + static int lastdelta = -16; + int skip = 0; + switch (dvd_speed) + { + case MPEG_SPEED_NORMAL: + saved_bl = 0; + return TRUE; + case MPEG_SPEED_FWD_8X: // 1 + skip = 18-dvd_skipoffs; + break; + case MPEG_SPEED_FWD_16X: // 2 + skip = 18-1-dvd_skipoffs; + break; + case MPEG_SPEED_FWD_32X: // 4 + skip = 18-3-dvd_skipoffs; + break; + case MPEG_SPEED_FWD_48X: // 6 + skip = 18-5-dvd_skipoffs; + break; + case MPEG_SPEED_REV_8X: + skip = 2+dvd_skipoffs; + break; + case MPEG_SPEED_REV_16X: + skip = 3+dvd_skipoffs; + break; + case MPEG_SPEED_REV_32X: + skip = 5+dvd_skipoffs; + break; + case MPEG_SPEED_REV_48X: + skip = 7+dvd_skipoffs; + break; + default: + return TRUE; + } + + int numbl = 0, lenbl = 0, delta = 0; + dvdnav_get_position(dvd, (unsigned int *)&numbl, (unsigned int *)&lenbl); + if (saved_bl != 0) + { + numbl = saved_bl; + //numbl -= dsi->dsi_gi.vobu_ea; + saved_bl = 0; + } else + { + if ((dvd_speed & MPEG_SPEED_FAST_FWD_MASK) == MPEG_SPEED_FAST_FWD_MASK) + { + while (skip <= 18 && !VALID_XWDA(dsi->vobu_sri.fwda[skip])) + skip++; + if (skip <= 18) + delta = (int)(dsi->vobu_sri.fwda[skip] & SRI_END_OF_CELL); + if (VALID_XWDA(dsi->vobu_sri.next_video)) + { + int nv = (int)(dsi->vobu_sri.next_video & SRI_END_OF_CELL); + if (delta < nv) + delta = nv; + } + } + else if ((dvd_speed & MPEG_SPEED_FAST_REV_MASK) == MPEG_SPEED_FAST_REV_MASK) + { + while (skip >= 0 && !VALID_XWDA(dsi->vobu_sri.bwda[skip])) + skip--; + if (skip >= 0) + delta = -(int)(dsi->vobu_sri.bwda[skip] & SRI_END_OF_CELL); + lastdelta = delta != 0 ? delta : -16; + } + + numbl += delta; + //if (delta < 0 && skip == 0) + if (delta <= 0 && skip <= 0) + { + numbl += lastdelta; // TODO: is it correct? + saved_bl = numbl; + dvdnav_prev_pg_search(dvd); + MSG("DVD: jump_prev_page!\n"); + return TRUE; + //dvdnav_get_position(dvd, (unsigned int *)&newnumbl, (unsigned int *)&lenbl); + //numbl += newnumbl + lenbl; + } else + saved_bl = 0; + + can_skip = false; + was_video = false; + } + if (numbl >= lenbl) + { + can_skip = false; + was_video = false; + return FALSE; + } + + MSG("DVD: (skip=%2d numbl=%8d)\n", skip, numbl); + + if (dvdnav_sector_search(dvd, numbl, SEEK_SET) != DVDNAV_STATUS_OK) + return FALSE; + dvd_seamless = false; + + return TRUE; +} + +void dvd_update_info() +{ + static int old_secs = 0; + unsigned int pos, len; + KHWL_TIME_TYPE displ; + displ.pts = 0; + displ.timeres = 90000; + + if (mpeg_is_displayed()) + khwl_getproperty(KHWL_TIME_SET, etimVideoFrameDisplayedTime, sizeof(displ), &displ); + +#if 0 + dvd_update_buttons(displ.pts); +#endif + if (old_titleid != cur_titleid || old_chapid != cur_chapid || (LONGLONG)displ.pts != saved_pts) + { + if (cur_titleid >= 0 && cur_chapid >= 0 && (LONGLONG)displ.pts >= 0) + { + if (cur_titleid != old_titleid) + { + uint64_t tim; + dvd_get_time(dvd, -1, -1, &tim); + int titlelength = (int)(tim / 90000); + script_totaltime_callback(titlelength); + + int numchapters = 0; + dvdnav_get_number_of_parts(dvd, cur_titleid, &numchapters); + script_dvd_title_callback(cur_titleid, numchapters); + } + if (cur_chapid != old_chapid) + { + script_dvd_chapter_callback(cur_chapid); + } + + old_titleid = cur_titleid; + old_chapid = cur_chapid; + saved_pts = displ.pts; + + dvdnav_get_position_in_title(dvd, &pos, &len); + dvd_vobu_start_pos = pos; + MSG("DVD: -- Title %d, Chapter %d, %d/%d --\n", cur_titleid, cur_chapid, pos, len); + + if (len != 0) + cur_titlpos = 100 * pos / len; + + char fip_out[10]; + int secs = (int)(displ.pts / 90000); + //int secs = (int)((displ.pts + old_cell_pts - pts_base) / 90000); + int ccid = cur_chapid; + if (ccid < 0) + ccid = 0; + if (ccid > 99) + ccid = 99; + if (secs < 0) + secs = 0; + if (secs >= 10*3600) + secs = 10*3600-1; + if (secs != old_secs) + { + script_time_callback(secs); + old_secs = secs; + } + fip_out[0] = (char)((ccid / 10) + '0'); + fip_out[1] = (char)((ccid % 10) + '0'); + fip_out[2] = (char)((secs/3600) + '0'); + int secs3600 = secs%3600; + fip_out[3] = (char)(((secs3600/60)/10) + '0'); + fip_out[4] = (char)(((secs3600/60)%10) + '0'); + fip_out[5] = (char)(((secs3600%60)/10) + '0'); + fip_out[6] = (char)(((secs3600%60)%10) + '0'); + fip_out[7] = '\0'; + /* + sprintf(fip_out, "%02d%1d%02d%02d", ccid, secs/3600, (secs%3600)/60, + (secs%3600)%60); + */ + fip_write_string(fip_out); + } + } +} + +void dvd_update_audio_info(BYTE *buf, int len) +{ + const char *afmt[] = { "Unknown", "MPEG-L1", "MPEG-L2", "Dolby AC3", "PCM", "DTS" }; + MpegAudioPacketInfo apinfo = mpeg_getaudioparams(); + SPString info, subinfo; + if (apinfo.type > 5) + apinfo.type = eAudioFormat_UNKNOWN; + info.Printf("%s", afmt[apinfo.type]); + int lfe = 0, bitrate = 0; + if (apinfo.type != eAudioFormat_UNKNOWN) + { + if (apinfo.type == eAudioFormat_AC3) + { + apinfo.samplerate = 0; + apinfo.numberofchannels = 0; + mpeg_parse_ac3_header(buf, len, &bitrate, NULL/*&apinfo.samplerate*/, + &apinfo.numberofchannels, &lfe, NULL); + } + if (bitrate > 0) + { + subinfo.Printf("%d kbps ", (bitrate + 500) / 1000); + } + if (apinfo.samplerate > 0) + { + subinfo.Printf("%d Hz ", apinfo.samplerate); + } + if (apinfo.numberofbitspersample > 0) + { + subinfo.Printf("%d bits ", apinfo.numberofbitspersample, + apinfo.numberofchannels == 1 ? "mono" : "stereo"); + } + if (apinfo.numberofchannels > 0) + { + if (apinfo.numberofchannels > 2) + subinfo.Printf("%d.%d", apinfo.numberofchannels, lfe); + else + subinfo.Printf("%s", apinfo.numberofchannels == 1 ? "mono" : "stereo"); + } + if (subinfo != "") + info = info + " @ " + subinfo; + } + + script_audio_info_callback(info); +} + +void dvd_update_video_info() +{ + const char *vfmt[] = { "Unknown", "MPEG-1", "MPEG-2", "", "MPEG-4" }; + SPString info; + int vf = mpeg_get_video_format(); + if (vf > 3) + vf = 0; + + info.Printf("%s", vfmt[vf]); + + int rate = (8*mpeg_getrate(FALSE) + 500) / 1000; + if (rate > 0) + info.Printf(" @ %d kbps", rate); + + script_video_info_callback(info); +} + +void dvd_get_cur(int *title, int *chapter) +{ + *title = cur_titleid; + *chapter = cur_chapid; +} + +int dvd_player_loop_internal(bool feed) +{ + int feed_cnt = 0; +get_some_more: + + bool was_feed = false; + + // if user paused before play actually started... + if (dvd_waiting_to_play) + { + dvd_update_info(); + return 0; + } + + dvd_not_played_yet = false; + + if (wait_for_user || wait_pause > 0) + { + // if no more packets + if (mpeg_wait(TRUE)) + { + // update last button highlight + // Some new SPU data could be sent since the last highlight event + // (or resolution/ratio could be changed...) + if (!no_spu && last_upd_but.right != 0 && last_upd_but.bottom != 0) + { + if (dvd_lastbtnupdate) + { + MSG("DVD: Last button update...\n"); + dvd_lastbtnupdate = false; + } + + khwl_setproperty(KHWL_SUBPICTURE_SET, eSubpictureUpdateButton, sizeof(last_upd_but), &last_upd_but); + + // update 1 time + //last_upd_but.right = 0; + } + } + dvd_update_info(); + } + // wait for user commands + if (wait_for_user) + return 0; + + if (wait_pause > 0) + { + const int wait_delay = 300; + int sl = wait_pause < wait_delay ? wait_pause * 1000 : wait_delay * 1000; + usleep(sl); + // now get current 'time' + ULONGLONG newt = clock() * 1000 / CLOCKS_PER_SEC; + + //wait_pause -= (int)(newt - wait_time); + wait_pause -= 300; + + wait_time = newt; + wait_iter++; + if (wait_pause <= 0) // at last! + { + wait_pause = 0; + dvdnav_still_skip(dvd); + MSG("DVD: ...skipped: %d cycles.\n", wait_iter); + } else + return 0; + } + + BYTE *buf = NULL; + + MEDIA_EVENT event = MEDIA_EVENT_OK; + int len = 0; + + int ret = media_get_next_block(&buf, &event, &len); + if (ret > 0 && buf == NULL) + { + MSG_ERROR("DVD: Not initialized. STOP!\n"); + return 1; + } + BYTE *base = buf; + + if (ret == -1) + { + if (need_skip) + { + // perhaps, there was a NAV packet error, so just skip a sector... + if (dvd_skip_sector(dvd) == 0) + return 0; + } + dvd_read_errors++; + MSG_ERROR("DVD: Error getting next block (tries=%d): %s\n", dvd_read_errors, media_geterror()); + need_to_set_pts = true; + if (dvd_read_errors > 3) + { + dvd_read_errors = 0; + if (dvdnav_current_title_info(dvd, &cur_titleid, &cur_chapid) && cur_titleid > 0) + { + dvdnav_part_play(dvd, cur_titleid, ++cur_chapid); + MSG_ERROR("DVD: Too much errors! Skip to next part...\n"); + int next_cur_titleid, next_cur_chapid; + if (!dvdnav_current_title_info(dvd, &next_cur_titleid, &next_cur_chapid)) + next_cur_chapid = -1; + if (cur_chapid != next_cur_chapid) + { + MSG_ERROR("DVD: Cannot skip to next part. Stop playing...\n"); + return 1; + } + return 0; + } else + { + MSG_ERROR("DVD: Too much errors! Stop playing...\n"); + return 1; + } + } + return -1; + } else + if (ret == 0) // wait... + return 0; + if (dvd_read_errors > 0) + dvd_read_errors--; + + if (dvd_scan) + dvd_seamless = false; + +#ifdef DVD_PACKETS_DEBUG + MSG("DVD: ==packet %d (%08x)\n", event, base); +#endif + + switch ((int)event) + { + case DVDNAV_BLOCK_OK: + { + // if started paused, don't fill buffer + if (dvd_speed == MPEG_SPEED_PAUSE && num_packets == 0) + { + return 0; + } + + START_CODE_TYPES sct; + LONGLONG scr = 0; + int cnt = 0; + while ((sct = mpeg_findpacket(buf, base, cnt)) != START_CODE_END) + { + cnt = 0; + bool datapacket = false; + switch (sct) + { + case START_CODE_PACK: + scr = mpeg_parse_program_stream_pack_header(buf, base); + scr += pts_base; + if (scr < 0) + scr = 0; + // this is needed for 'khwl' + scr |= SPTM_SCR_FLAG; + break; + case START_CODE_SYSTEM: + case START_CODE_PCI: + { + int len = (buf[0] << 8) | buf[1]; + if (!mpeg_incParsingBufIndex(buf, base, len + 2)) + goto brk; + break; + } + case START_CODE_MPEG_VIDEO: + case START_CODE_MPEG_AUDIO1: + case START_CODE_MPEG_AUDIO2: + case START_CODE_PRIVATE1: + datapacket = true; + break; + default:; + }; + + if (datapacket) + { + if (dvd_scan) + break; + MpegPacket *packet = NULL; + + if (sct != START_CODE_MPEG_VIDEO && dvd_speed != MPEG_SPEED_NORMAL) + break; + + packet = mpeg_feed_getlast(); + if (packet == NULL) // well, it won't really help + break; + + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + + // delayed stream change for forced streams detection... + if (sct == START_CODE_PRIVATE1 && dvd_spu_stream != dvd_old_spu_stream) + { + /*if (dvd_menu_ahead) // force ">0x80" streams? + dvd_spu_stream &= 0x1f; + mpeg_setspustream(dvd_spu_stream); + MSG("DVD: Set SPU stream: %d (%d)\n", dvd_spu_stream, dvd_old_spu_stream); + dvd_old_spu_stream = dvd_spu_stream; + */ + } + + // delayed stream change for forced streams detection... + /* + if (sct != START_CODE_MPEG_VIDEO && dvd_aud_stream != dvd_old_aud_stream) + { + dvd_old_aud_stream = dvd_aud_stream; + if (dvd_menu_ahead) // force ">0x80" streams? + dvd_aud_stream &= 0x1f; + mpeg_setaudiostream(dvd_aud_stream); + MSG("DVD: Set Audio stream: %d (%d)\n", dvd_aud_stream, dvd_old_aud_stream); + dvd_old_aud_stream = dvd_aud_stream; + } + */ + + packet->pts = pts_base; + if (mpeg_extractpacket(buf, base, packet, sct, FALSE) != 1) + break; + + // sometimes, we get 'fake' packets that 'khwl' doesn't like + if (packet->size < 1) + break; + + if (mpeg_audio_format_changed()) + { + dvd_update_audio_info(buf, 7); + } + + if (packet->flags == 2) + { + if (need_to_check_pts) + { + //if (mpeg_detect_pts_wrap(pts)) + //{ + // need_to_set_pts = true; + // vobu_sptm = packet->pts; + //} + } + + if (new_frame_size) + { + int w, h; + mpeg_getframesize(&w, &h); + if (w != 0 && h != 0) + { + script_framesize_callback(w, h); + new_frame_size = false; + } + int fps = mpeg_get_fps(); + if (fps > 0) + script_framerate_callback(fps); + } + + if (dvd_video_info_cnt++ > 63) + { + dvd_update_video_info(); + dvd_video_info_cnt = 0; + } + } + + packet->scr = scr; + packet->vobu_sptm = (vobu_sptm + pts_base) | SPTM_SCR_FLAG; + + if (feed) + { + if (packet->flags == 2 && packet->type == 0) + { + //MSG("DVD: setpts(%d)\n", packet->pts); + //mpeg_setpts(packet->pts); +#if 0 + LONGLONG stc = mpeg_getpts(); + LONGLONG good_scr = packet->pts; + if (dvd_speed == MPEG_SPEED_NORMAL && stc > good_scr + dvd_good_delta_stc) + { +#ifndef WIN32 + //khwl_pause(); + khwl_stop(); + //pts_base += stc - good_scr; + mpeg_start(); + msg("DVD: Resync (%d > %d)...\n", (int)stc, (int)good_scr); +#endif + } +#endif + + if (need_to_set_pts) + need_to_set_pts = false; + } + + // increase bufidx + mpeg_setbufidx(MPEG_BUFFER_1, packet); + + + if (packet->type == 0 && packet->pts != 0) + { +#ifdef DVD_PTS_DEBUG +#ifdef WIN32 + MSG("DVD: %d (%d) %I64d = %I64d [%I64d]\n", +#else + MSG("DVD: %d (%d) %Ld = %Ld [%Ld]\n", +#endif + num_packets, packet->type, packet->pts - pts_base, + packet->pts, packet->scr & ~SPTM_SCR_FLAG); +#endif + was_video = true; + } + + // send to khwl + mpeg_feed((MPEG_FEED_TYPE)packet->type); + was_feed = true; + + } else + { + // skip + } + num_packets++; + break; // do not find any more packets in this block + } + } +brk: ; + } + break; + case DVDNAV_NOP: + // Nothing to do here. + break; + case DVDNAV_STILL_FRAME: + /* We have reached a still frame. A real player application would wait + * the amount of time specified by the still's length while still handling + * user input to make menus and other interactive stills work. + * A length of 0xff means an indefinite still which has to be skipped + * indirectly by some user interaction. */ + { + if (feed) + { + dvdnav_still_event_t *still_event = (dvdnav_still_event_t *)buf; + if (still_event->length < 0xff) + { + // we'll finish after the next few cycles + wait_time = clock() * 1000 / CLOCKS_PER_SEC; + wait_pause = still_event->length * 1000; + wait_iter = 0; + + MSG("DVD: Waiting %d seconds of still frame\n", still_event->length); + } + else + { + wait_for_user = true; + MSG("DVD: Indefinite length still frame - waiting for user interaction...\n"); + } + dvd_seamless = false; + + if (dvd_speed != MPEG_SPEED_NORMAL) + { + dvd_setspeed(MPEG_SPEED_NORMAL); + script_speed_callback(); + } + mpeg_play(); + + } else + dvdnav_still_skip(dvd); + } + break; + + case DVDNAV_WAIT: + /* We have reached a point in DVD playback, where timing is critical. + * Player application with internal fifos can introduce state + * inconsistencies, because libdvdnav is always the fifo's length + * ahead in the stream compared to what the application sees. + * Such applications should wait until their fifos are empty + * when they receive this type of event. */ + if (feed) + { + MSG("DVD: Skipping wait condition\n"); + mpeg_wait(FALSE); + mpeg_start(); + + MSG("DVD: Skipping DONE\n"); + } + dvdnav_wait_skip(dvd); + break; + + case DVDNAV_SPU_CLUT_CHANGE: + if (feed) + { + if (dvd_speed == MPEG_SPEED_NORMAL) + { + MSG("DVD: CLUT change\n"); + dvd_clearhighlights(); + + need_to_check_buttons = true; + + int *clut = (int *)buf; + if (!no_spu) + { + for (int i = 0; i < 16; i++) + clut[i] = bswap_32(clut[i]); + + khwl_setproperty(KHWL_SUBPICTURE_SET, eSubpictureUpdatePalette, sizeof(KHWL_SPU_PALETTE_ENTRY) * 16, buf); + } + } + } + break; + + case DVDNAV_SPU_STREAM_CHANGE: + { + if (feed) + { + if (dvd_speed == MPEG_SPEED_NORMAL) + { + dvd_clearhighlights(); + + + need_to_check_buttons = true; + + dvdnav_spu_stream_change_event_t *stream_event = + (dvdnav_spu_stream_change_event_t *) buf; + int stream; + if (dvd_vmode == KHWL_VIDEOMODE_LETTERBOX) + { + stream = stream_event->physical_letterbox; + dvd_spu_channel_letterbox = stream; + } + else if (dvd_vmode == KHWL_VIDEOMODE_PANSCAN) + { + stream = stream_event->physical_pan_scan; + dvd_spu_channel_panscan = stream; + } + else + stream = stream_event->physical_wide; + bool in_menu = dvdnav_is_domain_vts(dvd) == 0; + int logstream = (stream & 0x80) == 0 ? + dvd_get_spu_logical_stream(dvd, (BYTE)stream, dvd_get_spu_mode(dvd_vmode)) : -1; + WORD lang = logstream >= 0 ? dvdnav_spu_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + BYTE strlang[3]; + dvd_getcharlang(strlang, lang); + MSG("DVD: SPU stream event: %d (%d %d %d), log=%d, lang='%c%c'\n", stream, + stream_event->physical_wide, stream_event->physical_letterbox, stream_event->physical_pan_scan, + logstream, strlang[0], strlang[1]); + + // reset saved pos if user entered menu + if (in_menu) + { + dvd_savepos(true); + } + + // \TODO: handle dvd_menu_ahead + + // drop current stream if not user-defined + if (!in_menu && (stream & 0x80) == 0x80 && forced_spu == -1) + { + dvd_spu_stream = -1; + lang = 0xffff; + logstream = -1; + MSG("DVD: - Dropping SPU stream to %d (was %d)\n", dvd_spu_stream, dvd_old_spu_stream); + } + // accept any stream in menu or only valid language streams otherwise + else if ((/*logstream >= 0 && lang != 0xffff && */forced_spu == -1) || in_menu) + { + dvd_spu_stream = stream; + MSG("DVD: - Set SPU stream: %d (was %d)\n", dvd_spu_stream, dvd_old_spu_stream); +/* + if (!in_menu) + { + forced_spu = -1; + forced_spu_lang = 0xffff; + MSG("DVD: - Resetting user's subtitle choice.\n"); + } +*/ + } + // set user-forced value in all other cases + else + { + dvd_spu_stream = dvd_get_spu_stream_from_user(forced_spu, forced_spu_lang); + + logstream = dvd_get_spu_logical_stream(dvd, (BYTE)dvd_spu_stream, dvd_get_spu_mode(dvd_vmode)); + lang = logstream >= 0 ? dvdnav_spu_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + dvd_getcharlang(strlang, lang); + + MSG("DVD: - User-ignoring SPU stream! (user set %d,'%c%c')\n", dvd_spu_stream, strlang[0], strlang[1]); + } + + script_spu_stream_callback(logstream >= 0 ? logstream+1 : 0); + script_spu_lang_callback(dvdlangs[dvdlang_lut[lang]].str); + + mpeg_setspustream(dvd_spu_stream); + dvd_old_spu_stream = dvd_spu_stream; + } + } + break; + } + + case DVDNAV_AUDIO_STREAM_CHANGE: + { + if (feed) + { + if (dvd_speed == MPEG_SPEED_NORMAL) + { + dvdnav_audio_stream_change_event_t *stream_event = + (dvdnav_audio_stream_change_event_t *) buf; + BYTE strlang[3]; + + int stream = stream_event->physical; + bool in_menu = dvdnav_is_domain_vts(dvd) == 0; + int logstream = dvd_get_audio_logical_stream(dvd, (BYTE)stream); + WORD lang = logstream >= 0 ? dvdnav_audio_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + dvd_getcharlang(strlang, lang); + + MSG("DVD: Audio stream change event (%d), log=%d, lang='%c%c'\n", stream, + logstream, strlang[0], strlang[1]); + // we don't care about the language, we just need a valid logical stream. + if (forced_audio == -1/*logstream >= 0*/ || in_menu) + { + dvd_aud_stream = stream; + MSG("DVD: - Audio stream change: %d\n", stream); +/* + if (!in_menu) + { + forced_audio = -1; + forced_audio_lang = 0xffff; + MSG("DVD: - Resetting user's audio choice.\n"); + } +*/ + } + else + { + dvd_aud_stream = dvd_get_audio_stream_from_user(forced_audio, forced_audio_lang); + + logstream = dvd_get_audio_logical_stream(dvd, (BYTE)dvd_spu_stream); + lang = logstream >= 0 ? dvdnav_audio_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + dvd_getcharlang(strlang, lang); + + MSG("DVD: - User-ignoring audio stream! (user set %d,'%c%c')\n", dvd_aud_stream, strlang[0], strlang[1]); + } + + script_audio_stream_callback(logstream >= 0 ? logstream+1 : 0); + script_audio_lang_callback(dvdlangs[dvdlang_lut[lang]].str); + + mpeg_setaudiostream(dvd_aud_stream); + } + } + break; + } + + case DVDNAV_HIGHLIGHT: + { + if (feed) + { + //dvdnav_highlight_area_t hl; + dvdnav_highlight_event_t *highlight_event = (dvdnav_highlight_event_t *)buf; + MSG("DVD: Selected button %d (pts=%d)\n", highlight_event->buttonN, (int)highlight_event->pts); + + //dvdnav_get_current_highlight(dvd, &dvd_cur_button); + dvd_cur_button = highlight_event->buttonN; + + dvd_update_button(highlight_event->buttonN, highlight_event->display); + /*dvd_add_button(highlight_event->buttonN, highlight_event->display, + (LONGLONG)(signed int)highlight_event->pts + pts_base); + */ + + // try updating immediately? + //if (mpeg_is_playing()) + // dvd_update_info(); + } + break; + } + + case DVDNAV_VTS_CHANGE: + { + // Some status information like video aspect and video scale permissions do + // not change inside a VTS. Therefore this event can be used to query such + // information only when necessary and update the decoding/displaying accordingly. + + vts_changed = true; + if (feed) + { + int aspect = dvdnav_get_video_aspect(dvd); + int permission = dvdnav_get_video_scale_permission(dvd); + + const char *asp[] = { "4:3", "? (#1)", "? (#2)", "16:9" }; + MSG("DVD: VTS change. Aspect = %s (Perm = %x)\n", asp[aspect], permission); + + if (dvd_speed == MPEG_SPEED_NORMAL) + khwl_stop(); + + dvd_buttons_enable(false); + + need_to_check_buttons = true; + + cur_titleid = 0; + cur_chapid = 0; + + // change video mode + int tvtype = settings_get(SETTING_TVTYPE); + dvd_vmode = KHWL_VIDEOMODE_NORMAL; + if (aspect == 0) + { + if (tvtype == 0 || tvtype == 1) + dvd_vmode = KHWL_VIDEOMODE_NORMAL; + else + { + if ((permission & 3) == 0) + dvd_vmode = (tvtype == 2) ? KHWL_VIDEOMODE_HCENTER : KHWL_VIDEOMODE_VCENTER; + else if ((permission & 2) == 2) + dvd_vmode = KHWL_VIDEOMODE_HCENTER; + else + dvd_vmode = KHWL_VIDEOMODE_VCENTER; + } + } + else if (aspect == 3) + { + if (tvtype == 2 || tvtype == 3) + dvd_vmode = KHWL_VIDEOMODE_WIDE; + else + { + if ((permission & 3) == 0) + dvd_vmode = (tvtype == 0) ? KHWL_VIDEOMODE_LETTERBOX : KHWL_VIDEOMODE_PANSCAN; + else if ((permission & 1) == 1) + dvd_vmode = KHWL_VIDEOMODE_PANSCAN; + else + dvd_vmode = KHWL_VIDEOMODE_LETTERBOX; + + } + } + MSG("DVD: set vmode = %d\n", dvd_vmode); + + khwl_display_clear(); + khwl_setvideomode(dvd_vmode, TRUE); + new_frame_size = true; + + script_dvd_menu_callback(dvdnav_is_domain_vts(dvd) != 1); + + if (dvd_speed == MPEG_SPEED_NORMAL) + { + mpeg_resetstreams(); + mpeg_start(); + } + dvd_seamless = false; + } + break; + } + + case DVDNAV_CELL_CHANGE: + /* Some status information like the current Title and Part numbers do not + * change inside a cell. Therefore this event can be used to query such + * information only when necessary and update the decoding/displaying + * accordingly. */ + { + dvdnav_cell_change_event_t *cell_change = (dvdnav_cell_change_event_t *)buf; + + int tt, ptt; + if (dvdnav_current_title_info(dvd, &tt, &ptt) == DVDNAV_STATUS_ERR) + break; + //dvdnav_get_position(dvd, (uint32_t *)&pos, (uint32_t *)&len); + MSG("DVD: Cell change event: (Title %d, Chapter %d)\n", tt, ptt); + //MSG("DVD: Title %d, Chapter %d\n", cell_change->pgN, cell_change->cellN); + MSG("DVD: - p_s=%d p_l=%d pgc_l=%d c_s=%d c_l=%d\n", (int)cell_change->pg_start, (int)cell_change->pg_length, + (int)cell_change->pgc_length, (int)cell_change->cell_start, (int)cell_change->cell_length); + + cur_titleid = tt;//cell_change->pgN; + cur_chapid = ptt;//cell_change->cellN; + + cur_cell_pts = cell_change->cell_start; + cur_cell_length = cell_change->cell_length; + cur_pgc_length = cell_change->pgc_length; + + if (feed) + { + if (dvd_speed == MPEG_SPEED_NORMAL) + { + dvd_update_info(); + need_to_check_pts = true; + + } + //MSG("DVD: At position %.0f%%%% inside the feature\n", 100 * (double)pos / (double)len); + } + break; + } + + case DVDNAV_NAV_PACKET: + /* A NAV packet provides PTS discontinuity information, angle linking information and + * button definitions for DVD menus. Angles are handled completely inside libdvdnav. + * For the menus to work, the NAV packet information has to be passed to the overlay + * engine of the player so that it knows the dimensions of the button areas. */ + { + /* Applications with fifos should not use these functions to retrieve NAV packets, + * they should implement their own NAV handling, because the packet you get from these + * functions will already be ahead in the stream which can cause state inconsistencies. + * Applications with fifos should therefore pass the NAV packet through the fifo + * and decoding pipeline just like any other data. */ + + cur_pci = dvdnav_get_current_nav_pci(dvd); + cur_dsi = dvdnav_get_current_nav_dsi(dvd); + + if (was_video) + { + was_video = false; + can_skip = true; + } + + //if (!need_skip) + { + LONGLONG cell_pts = old_cell_pts; + bool vob_changed = false; + if (cur_dsi->dsi_gi.vobu_vob_idn != old_vob_id || + cur_dsi->dsi_gi.vobu_c_idn != old_vob_cell_id || vts_changed) + { + //if (!vts_changed) + cell_pts = cur_cell_pts; + + // patch for weird DVDs... + if (cur_pci->pci_gi.vobu_s_ptm > cell_pts) + cell_pts = 0; + + if (cur_dsi->dsi_gi.vobu_vob_idn != old_vob_id) + { + MSG("DVD: ** VOB changed!\n"); + vob_changed = true; + } + + old_vob_id = cur_dsi->dsi_gi.vobu_vob_idn; + old_vob_cell_id = cur_dsi->dsi_gi.vobu_c_idn; + MSG("DVD: ** VOBU: cell changed! newvts=%d\n", (int)vts_changed); + MSG("DVD: * vob_id: %d, cell_id: %d\n", (int)cur_dsi->dsi_gi.vobu_vob_idn, + (int)cur_dsi->dsi_gi.vobu_c_idn); + MSG("DVD: * start=%d, end=%d (old=%d), cell_pts=%d)\n", + (int)cur_pci->pci_gi.vobu_s_ptm, (int)cur_pci->pci_gi.vobu_e_ptm, + (int)dvd_vobu_last_ptm, (int)cur_cell_pts); + MSG("DVD: * vob: %d, s=%d, e=%d\n", (int)cur_vobu_pts, (int)cur_dsi->sml_pbi.vob_v_s_s_ptm, + (int)cur_dsi->sml_pbi.vob_v_e_e_ptm); + + if (cell_pts < pts_base) + { + if (!dvd_seamless && !need_skip && !dvd_scan && dvd_speed == MPEG_SPEED_NORMAL) + { + khwl_stop(); + mpeg_start(); + } + } + + // see if we have more than 1 angle + int ca, na = 1; + dvdnav_get_angle_info(dvd, &ca, &na); + if (na != number_of_angles) + { + MSG("DVD: Angles detected: %d!\n", na); + + fip_write_special(FIP_SPECIAL_CAMERA, na > 1 ? 1 : 0); + + // turn off read-ahead? + if (na > 1) + { + MSG("DVD: * read-ahead = off\n"); + dvdnav_set_readahead_flag(dvd, 0); + } + else if (!need_skip) + { + MSG("DVD: * read-ahead = on\n"); + dvdnav_set_readahead_flag(dvd, 1); + } + + number_of_angles = na; + } + +#if 0 + // save current position on cell boundary + if (cur_vobu_pts != 0) + dvd_savepos(false); +#endif + } + vts_changed = false; + old_cell_pts = cell_pts; + + cur_vobu_pts = cur_pci->pci_gi.vobu_s_ptm + cell_pts; + + if (cur_pci->pci_gi.vobu_s_ptm != dvd_vobu_last_ptm) + { + vobu_sptm = cur_pci->pci_gi.vobu_s_ptm; + LONGLONG delta = dvd_vobu_last_ptm - vobu_sptm; + + LONGLONG oldptsbase = pts_base; + // don't change pts for multi-angle vobu changes + if (dvd_seamless) + { + if (number_of_angles <= 1) + pts_base += delta; + + MSG("DVD: * pts_base=%d (old=%d)\n", (int)pts_base, (int)oldptsbase); + } + else + { + if (delta != 0 && !need_skip && !dvd_scan && dvd_speed == MPEG_SPEED_NORMAL) + { + khwl_stop(); + mpeg_start(); + need_to_set_pts = true; + } + LONGLONG et = dvdnav_convert_time(&cur_pci->pci_gi.e_eltm); // &cur_dsi->dsi_gi.c_eltm + + pts_base = et + cur_cell_pts - vobu_sptm; + + MSG("DVD: Cell PTS = %d + %d, VOBU_s_ptm=%d.\n", + (int)et, (int)cur_cell_pts, (int)vobu_sptm); + MSG("DVD: * pts_base = %d (old=%d)\n", (int)pts_base, + (int)oldptsbase); + + } + + dvd_seamless = true; + +#ifdef DVD_USE_MACROVISION + // Macrovision APS + int apstb = (cur_pci->pci_gi.vobu_cat >> 14) & 3; + int mv_flags = (mv_cgms_flags << 2) | apstb; + if (dvd_mv_flags != mv_flags) + { + if (dvd_use_mv) + { + MSG("DVD: Macrovision flag (%d) set.\n", mv_flags); + khwl_setproperty(KHWL_VIDEO_SET, evMacrovisionFlags, sizeof(int), &mv_flags); + } else + { + MSG("DVD: Macrovision flag (%d) SKIPPED.\n", mv_flags); + } + dvd_mv_flags = mv_flags; + } +#endif + + if (delta != 0) + { + /*need_to_set_pts = true;*/ + } + } + dvd_vobu_start_ptm = cur_pci->pci_gi.vobu_s_ptm; + dvd_vobu_last_ptm = cur_pci->pci_gi.vobu_e_ptm; + + } + + if (need_skip && can_skip) + { + /////////// TODO: this is experimental! +#if 0 + KHWL_TIME_TYPE displ; + displ.pts = 0; + displ.timeres = 90000; + khwl_getproperty(KHWL_TIME_SET, etimVideoFrameDisplayedTime, sizeof(displ), &displ); + if (displ.pts >= (ULONGLONG)pts) +#endif + { + if (!dvd_skip(cur_dsi)) + { + MSG_ERROR("DVD: Error seeking next block/program: %s\n", media_geterror()); + media_free_block(base); + dvd_setspeed(MPEG_SPEED_NORMAL); + script_speed_callback(); + return -1; + } + } + break; + } + + if (feed) + { + int button; + + // compare current buttons and old buttons + + bool thesame = true; + if (cur_num_buttons != cur_pci->hli.hl_gi.btn_ns) + thesame = false; + else if (need_to_check_buttons) + { + for (button = 0; button < cur_num_buttons; button++) + { + DVD_BUTTON &b = cur_buttons[button]; + btni_t *btni = &(cur_pci->hli.btnit[button]); + if (b.left != btni->x_start || b.top != btni->y_start || + b.right != btni->x_end || b.bottom != btni->y_end) + { + thesame = false; + break; + } + } + } + need_to_check_buttons = false; + + if (cur_pci->hli.hl_gi.hli_ss == 1) + { + MSG("DVD: ! Menu ahead (was=%d)!\n", dvd_menu_ahead); + // patch for non-accurate menus + //if (dvd_menu_ahead && (cur_num_buttons == cur_pci->hli.hl_gi.btn_ns)) + // thesame = true; + dvd_menu_ahead = true; + + if (forced_spu != -1) + { + MSG("DVD: Resetting user's subtitle choice to -1\n"); + forced_spu = -1; + forced_spu_lang = 0xffff; + } + if (forced_audio != -1) + { + MSG("DVD: Resetting user's audio choice to -1\n"); + forced_audio = -1; + forced_audio_lang = 0xffff; + } + + // special 'allow all' mode + if (dvd_spu_stream < 0) + { + MSG("DVD: Enabling 'allow-all-streams' SPU mode.\n"); + mpeg_setspustream(-2); + } + + need_user_reset = true; + + } else + { + if (dvd_menu_ahead) + { + MSG("DVD: ! Menu end!\n"); + dvd_menu_ahead = false; + + // restore current SPU stream + MSG("DVD: Restoring SPU stream to %d.\n", dvd_spu_stream); + mpeg_setspustream(dvd_spu_stream); + } + } + + if (!dvdnav_is_domain_vts(dvd) && need_user_reset) + { + dvd_user_reset(); + } + + if (!thesame) + cur_num_buttons = cur_pci->hli.hl_gi.btn_ns; + + if (cur_pci->hli.hl_gi.btn_ns > 0) + { + if (!thesame) + { + MSG("DVD: Found %i DVD menu buttons...\n", cur_pci->hli.hl_gi.btn_ns); + + for (button = 0; button < cur_pci->hli.hl_gi.btn_ns; button++) + { + btni_t *btni = &(cur_pci->hli.btnit[button]); + MSG("DVD: Button %i top-left @ (%i,%i), bottom-right @ (%i,%i)\n", + button + 1, btni->x_start, btni->y_start, btni->x_end, btni->y_end); + + cur_buttons[button].left = btni->x_start; + cur_buttons[button].top = btni->y_start; + cur_buttons[button].right = btni->x_end; + cur_buttons[button].bottom = btni->y_end; + } + } + if (!dvd_buttons_enabled) + dvd_buttons_enable(true); + if (cur_pci->hli.hl_gi.fosl_btnn > 0) + { + if (dvd_cur_button != cur_pci->hli.hl_gi.fosl_btnn) + { + MSG("DVD: * force button = %d!\n", cur_pci->hli.hl_gi.fosl_btnn); + } + dvd_cur_button = cur_pci->hli.hl_gi.fosl_btnn; + + } + if (!dvd_button_selected) + { + //dvdnav_get_current_highlight(dvd, &dvd_cur_button); + MSG("DVD: * selecting button = %d:\n", dvd_cur_button); + if (dvd_cur_button > cur_num_buttons) + dvd_cur_button = cur_num_buttons - 1; + else if (dvd_cur_button < 1) + dvd_cur_button = 1; + dvdnav_button_select(dvd, cur_pci, dvd_cur_button); + } + + } else + { + if (dvd_buttons_enabled) + dvd_buttons_enable(false); + } + dvd_update_info(); + } + break; + } + + case DVDNAV_HOP_CHANNEL: + { + // This event is issued whenever a non-seamless operation has been executed. + // Applications with fifos should drop the fifos content to speed up responsiveness. + + if (feed) + { + if (dvd_speed == MPEG_SPEED_NORMAL) + { + MSG("DVD: HOP channel!\n"); + + khwl_stop(); + dvd_buttons_enable(false); + need_to_check_buttons = true; + + mpeg_start(); + + // \TODO: this is a test... + mpeg_setpts(0); + dvd_seamless = false; + } + } + break; + } + + case DVDNAV_STOP: + { + // Playback should end here. + if (feed) + { + MSG("DVD: STOP!!!\n"); + } + // we may not free the block + dvd_savepos(true); + return 1; + } + + default: // skip + MSG_ERROR("DVD: Unknown event (%i)\n", event); + break; + } + + // don't forget to free not used block! + // NOTE: it does nothing if our cache is used! + media_free_block(base); + + if (was_feed && feed_cnt++ < 2) + goto get_some_more; + + return 0; +} + +int dvd_player_loop() +{ + return dvd_player_loop_internal(true); +} + +int dvd_get_next_block(BYTE **buf, int *event, int *len) +{ + struct timeval tv1, tv2; + // measure time (see below) + BOOL need_measure = (dvd_speed == MPEG_SPEED_NORMAL) ? mpeg_is_playing() : FALSE; + if (need_measure) + gettimeofday(&tv1, NULL); + +#ifndef DVD_USE_CACHE + if (dvdnav_get_next_block(dvd, *buf, event, len) == DVDNAV_STATUS_ERR) + return -1; + return 1; +#else + dvdnav_reset_cache_flag(dvd); + if (dvdnav_get_next_cache_block(dvd, buf, (int *)event, len) == DVDNAV_STATUS_ERR) + return -1; + + // we check if decoder waits too long - audio/video mistiming will happen then (only raw-read counts) + if (need_measure && *event == DVDNAV_BLOCK_OK) + { + // we don't check mpeg_feed_getstackdepth(). It may not be empty if long delay occurs. + // we just check if we read from disk way too long... + gettimeofday(&tv2, NULL); + int read_dtime = (int)((tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000); + if (read_dtime > read_max_allowed_time) + { + msg("DVD: Disc read Time (%d msec) > limit!\n", read_dtime); + khwl_stop(); + mpeg_start(); + msg("DVD: Resync...\n"); + } + } + + return dvdnav_get_cache_flag(dvd); +#endif +} + +int dvd_free_block(BYTE *data) +{ +#ifdef DVD_USE_CACHE + if (dvdnav_free_cache_block(dvd, data) != DVDNAV_STATUS_OK) + return -1; +#endif + return 0; +} + +BOOL dvd_stop() +{ + mpeg_deinit(); + + dvd_savepos(false); + dvd_not_played_yet = true; + + SPSafeFree(dvdlang_lut); + + dvd_spu_enable(false); + + if (dvd != NULL) + { + if (media_close() < 0) + { + MSG_ERROR("DVD: Error on dvdnav_close: %s\n", dvdnav_err_to_string(dvd)); + return FALSE; + } + } + + fip_clear(); + dvd_fip_init(); + khwl_setvideomode(KHWL_VIDEOMODE_NONE, TRUE); + + dvd = NULL; + + cur_pack = -1; + + return TRUE; +} + +bool dvd_end_still(bool skipstill = true) +{ + dvd_user_reset(); + /* + if (wait_for_user) + need_to_set_pts = true; + */ + wait_for_user = false; + bool ret = false; + if (wait_pause > 0) + { + if (skipstill) + { + MSG("DVD: Fast-skipping still frame...\n"); + dvdnav_still_skip(dvd); + // we don't need to do anything more... + ret = true; + } + wait_pause = 0; + } + + mpeg_start(); + return ret; +} + +int dvd_getnumtitles() +{ + int titl = 0; + dvdnav_get_number_of_titles(dvd, &titl); + return titl; +} + +int dvd_getnumchapters(int title) +{ + int chap; + dvdnav_get_number_of_parts(dvd, title, &chap); + return chap; +} + +BOOL dvd_seek_titlepart(int title, int part) +{ + if (title < 1 || part < 1) + return FALSE; + dvd_end_still(); + dvd_setspeed(MPEG_SPEED_NORMAL); + script_speed_callback(); + + MSG("DVD: seek to title %d, part %d.\n", title, part); + + if (!dvdnav_is_domain_vts(dvd)) + { + MSG_ERROR("DVD: Cannot seek - not in play!\n"); + return FALSE; + } + if (dvdnav_part_play(dvd, title, part) != DVDNAV_STATUS_OK) + { + MSG_ERROR("DVD: seek error.\n"); + return FALSE; + } + return TRUE; +} + +BOOL dvd_seek(int seconds) +{ + if (seconds < 0) + return FALSE; + + dvd_end_still(); + dvd_setspeed(MPEG_SPEED_NORMAL); + script_speed_callback(); + MSG("DVD: Seek to %d secs...\n", seconds); + + LONGLONG newpts = seconds * 90000; + + if (dvdnav_time_search(dvd, newpts) != DVDNAV_STATUS_OK) + { + MSG_ERROR("DVD: seek error.\n"); + return FALSE; + } + +#ifdef MY_SEARCH + bool simpleseek = false; + if (!dvdnav_is_domain_vts(dvd)) + { + MSG_ERROR("DVD: Cannot seek - not in play!\n"); + return FALSE; + //simpleseek = true; + } + + bool needs_restore = false; + LONGLONG cur_vobu_pts0 = 0; + int base_titleid = 1, base_chapid = 1; + int num_parts = 0; + int raf = 0; + + dvdnav_current_title_info(dvd, &cur_titleid, &cur_chapid); + base_titleid = cur_titleid; + base_chapid = cur_chapid; + + /// \TODO: don't start from beginning in all cases + if (dvdnav_title_play(dvd, cur_titleid) != DVDNAV_STATUS_OK) + goto err; + dvdnav_current_title_info(dvd, &cur_titleid, &cur_chapid); + dvdnav_get_number_of_parts(dvd, cur_titleid, &num_parts); + + old_cell_pts = 0; + old_vob_id = -1; + + // use navigation info + dvd_scan = true; + + dvdnav_get_readahead_flag(dvd, &raf); + dvdnav_set_readahead_flag(dvd, 0); + + //if (newpts < cur_vobu_pts || !simpleseek) + { + cur_vobu_pts = -1; + while (cur_vobu_pts == -1) + dvd_player_loop_internal(false); + } + cur_vobu_pts0 = cur_vobu_pts; + + //while (true) + { + // search start chapter + LONGLONG last_ptm = cur_cell_pts; + while (cur_cell_pts < newpts) + { + if (last_ptm > cur_cell_pts) + { + needs_restore = true; + goto err; + } + last_ptm = cur_cell_pts; + MSG("DVD: jump to part %d...\n", cur_chapid); + dvdnav_part_play(dvd, cur_titleid, ++cur_chapid); + cur_cell_pts = -1; + while (cur_cell_pts == -1) + dvd_player_loop_internal(false); + if (cur_chapid >= num_parts) + break; + } + if (cur_chapid > 0) + { + dvdnav_part_play(dvd, cur_titleid, --cur_chapid); + cur_cell_pts = -1; + while (cur_cell_pts == -1) + dvd_player_loop_internal(false); + } + // now we know the chapter! + const int numdirs = 3; + int dir = 0, sks[3] = { 18-16, 12, 18-4 }; + int lastskip = 400; + // zig-zag iterations + while (true) + { + int from = SEEK_CUR, skip = 0, sk = sks[dir]; + if (dir % 2 == 0) + { + while (sk < 19 && !VALID_XWDA(cur_dsi->vobu_sri.fwda[sk])) + sk++; + if (sk < 19) + skip = cur_dsi->vobu_sri.fwda[sk] & SRI_END_OF_CELL; + else + skip = lastskip; + lastskip = skip; + if (skip == 0) + break; + } else + { + while (sk > 0 && !VALID_XWDA(cur_dsi->vobu_sri.bwda[sk])) + sk--; + if (sk > 0) + skip = cur_dsi->vobu_sri.bwda[sk] & SRI_END_OF_CELL; + else + skip = lastskip; + lastskip = skip; + if (skip == 0) + break; + + unsigned int curpos = 0, curlen = 0; + if (dvdnav_get_position(dvd, &curpos, &curlen) != DVDNAV_STATUS_OK) + goto err; + skip = curpos - skip; + from = SEEK_SET; + } + + if (media_seek(dvd, skip, from) == -1) + goto err; + cur_vobu_pts = -1; + while (cur_vobu_pts == -1) + dvd_player_loop_internal(false); + + if (dir == numdirs - 1 && cur_vobu_pts >= newpts) + break; + else if ((dir % 2) == 0 && cur_vobu_pts >= newpts) + dir++; + else if ((dir % 2) == 1 && cur_vobu_pts < newpts) + dir++; + + } + } +err: + if (needs_restore) + { + MSG_ERROR("DVD: Cannot seek - restore pos!\n"); + dvdnav_part_play(dvd, base_titleid, base_chapid); + //media_rewind(dvd); + } + dvdnav_set_readahead_flag(dvd, raf); + dvd_scan = false; +#endif + + MSG("DVD: seek DONE!\n"); + + khwl_stop(); + dvd_buttons_enable(false); + //need_to_set_pts = true; + mpeg_start(); + + dvd_seamless = false; + + return TRUE; + +#if 0 + dvd_scan = true; + while (mpeg_getrate() == 0) + dvd_player_loop_internal(false); + dvd_scan = false; + + int rate = mpeg_getrate(); + MSG("DVD: mpeg_rate = %d\n", rate); + + int delta, from; + LONGLONG old_pts = dvd_vobu_start_ptm;//= pts - pts_base; + if (old_pts != 0 && simpleseek) + { + LONGLONG d = (newpts - old_pts) * (rate * 50) / 90000; + delta = (int)(d / 2048); // align to packet's boundary + + delta += dvd_vobu_start_pos; + + from = SEEK_SET;//SEEK_CUR; + + } else + { + LONGLONG d = newpts * (rate * 50) / 90000; + delta = (int)(d / 2048); // align to packet's boundary + from = SEEK_SET; + } + if (media_seek(dvd, delta, from) == -1) + return FALSE; +#endif + + return TRUE; +} + + +void dvd_button_press() +{ + dvd_end_still(false); + if (cur_pci != NULL) + { + MSG("DVD: Activating current button...\n"); + // handle mode2 updates + int button; + dvdnav_get_current_highlight(dvd, &button); + dvd_update_button(button, 2); + + dvdnav_button_activate(dvd, dvdnav_get_current_nav_pci(dvd)); + + } +} + +void dvd_button_up() +{ + dvd_end_still(false); + if (cur_pci != NULL) + { + MSG("DVD: Selecting upper button...\n"); + dvdnav_upper_button_select(dvd, dvdnav_get_current_nav_pci(dvd)); + } +} + +void dvd_button_down() +{ + dvd_end_still(false); + if (cur_pci != NULL) + { + MSG("DVD: Selecting lower button...\n"); + dvdnav_lower_button_select(dvd, dvdnav_get_current_nav_pci(dvd)); + } +} + +void dvd_button_left() +{ + dvd_end_still(false); + if (cur_pci != NULL) + { + MSG("DVD: Selecting left button...\n"); + dvdnav_left_button_select(dvd, dvdnav_get_current_nav_pci(dvd)); + } +} + +void dvd_button_right() +{ + dvd_end_still(false); + if (cur_pci != NULL) + { + MSG("DVD: Selecting right button...\n"); + dvdnav_right_button_select(dvd, dvdnav_get_current_nav_pci(dvd)); + } +} + +void dvd_button_menu(DVD_MENU_TYPE menu) +{ + dvd_end_still(false); + if (menu == DVD_MENU_DEFAULT) + { + if (dvdnav_is_domain_vts(dvd)) + { + dvdnav_menu_call(dvd, DVD_MENU_Root/*DVD_MENU_Part*/); // we want VTSM, not VMGM ! + } else + dvdnav_menu_call(dvd, DVD_MENU_Escape); + } else + dvdnav_menu_call(dvd, (DVDMenuID_t)menu); + +} + +bool dvd_ismenu() +{ + return dvdnav_is_domain_vts(dvd) != 1; +} + +void dvd_button_angle(int setangl) +{ + int num = 0, current = 0; + dvdnav_get_angle_info(dvd, ¤t, &num); + + if (num != 0) + { + if (setangl >= 0) + current = setangl; + else + { + current++; + if (current > num) + current = 1; + } + if (dvdnav_angle_change(dvd, current)) + return; + } + dvd_invalid(); +} + +int dvd_getangle() +{ + int num = 0, current = 0; + dvdnav_get_angle_info(dvd, ¤t, &num); + return current; +} + +void dvd_button_audio(char *setlang, int startfrom) +{ + if (dvdnav_is_domain_vts(dvd)) + { + WORD setl = 0xffff; + if (setlang == NULL) + { + MSG("DVD: dvd_audio (%d)\n", startfrom); + setl = 0xffff; + } + else + { + MSG("DVD: dvd_audio %s\n", setlang); + setl = dvd_getintlang((BYTE *)setlang); + } + int audiostream = -1, logstream = -1; + WORD lang = 0xffff, firstlang = 0xffff; + bool wasany = false, found = false; + int firstaudiostream = -1, firstlogstream = -1; + int curaudiostream = mpeg_getaudiostream(); + for (audiostream = startfrom; audiostream < 8; audiostream++) + { + logstream = dvd_get_audio_logical_stream(dvd, (BYTE)audiostream); + lang = logstream >= 0 ? dvdnav_audio_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + if (logstream >= 0 /*&& lang != 0xffff*/) + { + wasany = true; + if (firstaudiostream == -1) + { + firstaudiostream = audiostream; + firstlogstream = logstream; + firstlang = lang; + } + if ((setl == 0xffff && audiostream > curaudiostream) || + (setl != 0xffff && lang == setl)) + { + found = true; + break; + } + } + } + if (!wasany) + { + MSG("DVD: No audio streams found.\n"); + dvd_invalid(); + return; + } + // set to the first if we didn't found any valid stream after the current + if (!found) + { + audiostream = firstaudiostream; + logstream = firstlogstream; + lang = firstlang; + } +/* + // -2 means that we don't want any audio + forced_audio = audiostream == -1 ? -2 : audiostream; + forced_audio_lang = lang; + mpeg_setaudiostream(audiostream); +*/ + dvd_set_audio_stream(dvd, audiostream); + + BYTE strlang[3]; + dvd_getcharlang(strlang, lang); + MSG("DVD: setaudiostream = %d, lang='%c%c'\n", audiostream, strlang[0], strlang[1]); + script_audio_stream_callback(logstream >= 0 ? logstream+1 : 0); + script_audio_lang_callback(dvdlangs[dvdlang_lut[lang]].str); + + } else + dvd_invalid(); +} + +void dvd_button_subtitle(char *setlang, int startfrom) +{ + if (dvdnav_is_domain_vts(dvd)) + { + WORD setl = 0xffff; + int spustream = -1, logstream = -1, curstream = -1; + if (setlang == NULL) + { + MSG("DVD: dvd_subtitle (%d)\n", startfrom); + setl = 0xffff; + + curstream = mpeg_getspustream(); + logstream = dvd_get_spu_logical_stream(dvd, (BYTE)curstream, dvd_get_spu_mode(dvd_vmode)); + if (logstream < 0) + curstream = -1; + } + else + { + MSG("DVD: dvd_subtitle %s\n", setlang); + setl = dvd_getintlang((BYTE *)setlang); + } + WORD lang = 0xffff; + bool wasany = false, found = false; + for (spustream = startfrom; spustream < 32; spustream++) + { + logstream = dvd_get_spu_logical_stream(dvd, (BYTE)spustream, dvd_get_spu_mode(dvd_vmode)); + lang = logstream >= 0 ? dvdnav_spu_stream_to_lang(dvd, (BYTE)logstream) : (WORD)0xffff; + if (logstream >= 0/* && lang != 0xffff*/) + { + wasany = true; + if ((setl == 0xffff && spustream > curstream) || + (setl != 0xffff && lang == setl)) + { + found = true; + break; + } + } + } + if (!wasany) + { + MSG("DVD: No subtitle streams found.\n"); + dvd_invalid(); + return; + } + // switch off if we didn't found any valid stream after the current + if (!found) + { + spustream = -1; + logstream = -1; + lang = 0xffff; + } +/* + // -2 means that we don't want any subtitles + forced_spu = spustream == -1 ? -2 : spustream; + forced_spu_lang = lang; + mpeg_setspustream(spustream); +*/ + dvd_set_spu_stream(dvd, spustream, dvd_get_spu_mode(dvd_vmode)); + + BYTE strlang[3]; + dvd_getcharlang(strlang, lang); + MSG("DVD: setspustream = %d, lang='%c%c'\n", spustream, strlang[0], strlang[1]); + script_spu_stream_callback(logstream >= 0 ? logstream+1 : 0); + script_spu_lang_callback(dvdlangs[dvdlang_lut[lang]].str); + + } else + dvd_invalid(); +} + +void dvd_button_return() +{ + MSG("DVD: dvd_go_up\n"); + if (!dvdnav_is_domain_vts(dvd)) + { + dvd_end_still(); // true + if (!dvdnav_go_up(dvd)) + dvd_invalid(); + } else + { + dvd_invalid(); + } +} + + +void dvd_button_prev() +{ + if (!dvd_end_still()) + { + if (dvdnav_current_title_info(dvd, &cur_titleid, &cur_chapid) && cur_titleid > 0) + { + dvdnav_part_play(dvd, cur_titleid, --cur_chapid); + MSG("DVD: dvd_jump_prev\n"); + return; + } + dvd_invalid(); + } +} + +void dvd_button_next() +{ + if (!dvd_end_still()) + { + MSG("DVD: dvd_jump_next\n"); + if (dvdnav_current_title_info(dvd, &cur_titleid, &cur_chapid) && cur_titleid > 0) + { + if (!dvdnav_part_play(dvd, cur_titleid, ++cur_chapid)) + dvd_invalid(); + } else + { + if (!dvdnav_next_pg_search(dvd)) + dvd_invalid(); + } + } +} + +static void dvd_st_spd(MPEG_SPEED_TYPE spd, int mode) +{ + int sp = (int)spd; + if (mode > 0) + sp++; + else if (mode < 0) + sp--; + if (dvd_setspeed((MPEG_SPEED_TYPE)sp)) + { + MSG("DVD: dvd_speed = 0x%3x\n", sp); + } else + dvd_invalid(); +} + +void dvd_button_slow() +{ + if (dvdnav_is_domain_vts(dvd)) + { + MSG("DVD: dvd_button_slow\n"); + if (dvd_speed == MPEG_SPEED_SLOW_FWD_8X || dvd_speed == MPEG_SPEED_NORMAL) + dvd_st_spd(MPEG_SPEED_SLOW_FWD_2X, 0); + else if (dvd_speed == MPEG_SPEED_SLOW_REV_8X) + dvd_st_spd(MPEG_SPEED_SLOW_REV_2X, 0); + else if ((dvd_speed & MPEG_SPEED_SLOW_FWD_MASK) == MPEG_SPEED_SLOW_FWD_MASK) + dvd_button_rew(); + else if ((dvd_speed & MPEG_SPEED_SLOW_REV_MASK) == MPEG_SPEED_SLOW_REV_MASK) + dvd_button_fwd(); + else + dvd_invalid(); + } + else + dvd_invalid(); +} + +void dvd_button_fwd() +{ + if (dvdnav_is_domain_vts(dvd)) + { + if (dvd_speed == MPEG_SPEED_REV_8X || dvd_speed == MPEG_SPEED_NORMAL || dvd_speed == MPEG_SPEED_PAUSE) + dvd_st_spd(MPEG_SPEED_FWD_8X, 0); + else if (dvd_speed >= MPEG_SPEED_FWD_8X && dvd_speed < MPEG_SPEED_FWD_48X) + dvd_st_spd(dvd_speed, 1); + else if (dvd_speed > MPEG_SPEED_REV_8X && dvd_speed <= MPEG_SPEED_REV_48X) + dvd_st_spd(dvd_speed, -1); + // use it in slow mode too + else if (dvd_speed == MPEG_SPEED_SLOW_REV_2X) + dvd_st_spd(MPEG_SPEED_SLOW_FWD_2X, 0); + else if (dvd_speed > MPEG_SPEED_SLOW_FWD_2X && dvd_speed <= MPEG_SPEED_SLOW_FWD_8X) + dvd_st_spd(dvd_speed, -1); + else if (dvd_speed >= MPEG_SPEED_SLOW_REV_2X && dvd_speed < MPEG_SPEED_SLOW_REV_8X) + dvd_st_spd(dvd_speed, 1); + else + dvd_invalid(); + } else + dvd_invalid(); +} + +void dvd_button_rew() +{ + if (dvdnav_is_domain_vts(dvd)) + { + if (dvd_speed == MPEG_SPEED_FWD_8X || dvd_speed == MPEG_SPEED_NORMAL || dvd_speed == MPEG_SPEED_PAUSE) + dvd_st_spd(MPEG_SPEED_REV_8X, 0); + else if (dvd_speed >= MPEG_SPEED_REV_8X && dvd_speed < MPEG_SPEED_REV_48X) + dvd_st_spd(dvd_speed, 1); + else if (dvd_speed > MPEG_SPEED_FWD_8X && dvd_speed <= MPEG_SPEED_FWD_48X) + dvd_st_spd(dvd_speed, -1); + // use it in slow mode too + /* + // don't use slow rev mode - it's not ready?.. + else if (dvd_speed == MPEG_SPEED_SLOW_FWD_2X) + dvd_st_spd(MPEG_SPEED_SLOW_REV_2X, 0); + */ + else if (dvd_speed > MPEG_SPEED_SLOW_REV_2X && dvd_speed <= MPEG_SPEED_SLOW_REV_8X) + dvd_st_spd(dvd_speed, -1); + else if (dvd_speed >= MPEG_SPEED_SLOW_FWD_2X && dvd_speed < MPEG_SPEED_SLOW_FWD_8X) + dvd_st_spd(dvd_speed, 1); + else + dvd_invalid(); + } else + dvd_invalid(); +} + +void dvd_button_play() +{ + if (dvd_waiting_to_play) + { + dvd_waiting_to_play = false; + dvd_setspeed(MPEG_SPEED_NORMAL); + MSG("DVD: dvd_waiting_to_play = false\n"); + } + if (dvdnav_is_domain_vts(dvd)) + { + dvd_setspeed(MPEG_SPEED_NORMAL); + MSG("DVD: dvd_play\n"); + } else + dvd_invalid(); +} + +void dvd_button_pause() +{ + if (dvd_not_played_yet) + { + dvd_waiting_to_play = true; + dvd_setspeed(MPEG_SPEED_PAUSE); + MSG("DVD: dvd_waiting_to_play = true\n"); + return; + } else + if (dvdnav_is_domain_vts(dvd)) + { + if (dvd_speed == MPEG_SPEED_PAUSE || dvd_speed == MPEG_SPEED_STEP) + { + dvd_setspeed(MPEG_SPEED_STEP); + MSG("DVD: dvd_step\n"); + } + else + { + MSG("DVD: dvd_pause\n"); + dvd_setspeed(MPEG_SPEED_PAUSE); + dvd_savepos(false); + } + } else + dvd_invalid(); +} + +void dvd_button_step() +{ + if (dvdnav_is_domain_vts(dvd)) + { + dvd_setspeed(MPEG_SPEED_STEP); + MSG("DVD: dvd_step\n"); + } else + dvd_invalid(); +} + + +BOOL dvd_zoom_hor(int scale) +{ + if (dvdnav_is_domain_vts(dvd)) + { + MSG("DVD: Zoomed set to %d.\n", scale); + mpeg_zoom_hor(scale); + return TRUE; + } else + dvd_invalid(); + need_user_reset = true; + return FALSE; +} + +BOOL dvd_zoom_ver(int scale) +{ + if (dvdnav_is_domain_vts(dvd)) + { + MSG("DVD: Zoomed set to %d.\n", scale); + mpeg_zoom_ver(scale); + return TRUE; + } else + dvd_invalid(); + need_user_reset = true; + return FALSE; +} + +BOOL dvd_scroll(int offsetx, int offsety) +{ + if (dvdnav_is_domain_vts(dvd)) + { + MSG("DVD: Scroll set to %d,%d.\n", offsetx, offsety); + mpeg_scroll(offsetx, offsety); + return TRUE; + } else + dvd_invalid(); + need_user_reset = true; + return FALSE; +} + +int dvd_get_total_time(int title, int chapter, int *tim) +{ + uint64_t time; + int ret = dvd_get_time(dvd, title - 1, chapter - 1, &time); + *tim = (int)(time / 90000); + return ret; +} + +int dvd_get_chapter_for_time(int title, int time, int *chapter) +{ + int chap; + int ret = dvd_get_chapter(dvd, title - 1, (uint64_t)time * 90000, &chap); + *chapter = chap + 1; + return ret; +} + +char *dvd_error_string() +{ + return (char *)dvdnav_err_to_string(dvd); +} + +int dvd_savepos(bool reset) +{ + DWORD pos = 0, title = 0, lenbl = 0; + DWORD data1, data2; + if (reset) + { + pos = 0xffffffff; + title = 0xffffffff; + data1 = data2 = 0xffffffff; + // if already reset + if (dvd_saved_pos == pos && dvd_saved_title == title) + return 0; + MSG("DVD: Resetting saved movie position.\n"); + } else + { + if (!dvdnav_is_domain_vts(dvd)) + return -1; + if (dvdnav_get_position(dvd, (unsigned int *)&pos, (unsigned int *)&lenbl) != DVDNAV_STATUS_OK) + return -1; + int ch; + if (dvdnav_current_title_info(dvd, (int *)&title, &ch) != DVDNAV_STATUS_OK) + return FALSE; + + // in menu or somewhere? + if (pos == 0 || title == 0) + return -1; + + dvd_saved_vmode = dvd_vmode; + dvd_saved_audio_stream = mpeg_getaudiostream(); + dvd_saved_spu_stream = mpeg_getspustream(); + data1 = dvd_saved_vmode & 0xff; + data1 |= (((dvd_saved_audio_stream + 128) & 0xff) << 8); + data1 |= (((dvd_saved_spu_stream + 128) & 0xff) << 16); + } + + if (!dvd_was_saved && !reset) + { + DWORD id = settings_get(SETTING_DVD_ID1); + DWORD titlepos = settings_get(SETTING_DVD_POS1); + DWORD ddata1 = settings_get(SETTING_DVD_DATA11); + DWORD ddata2 = settings_get(SETTING_DVD_DATA12); + // shift other saved positions + // we use this loop order to detect saved pos and break - this saves the last item + for (int i = 1; i < dvd_num_saved; i++) + { + if (id == dvd_ID && titlepos != 0xffffffff) + break; + DWORD oldid = settings_get((SETTING_SET)(SETTING_DVD_ID1 + i * 4)); + DWORD oldtitlepos = settings_get((SETTING_SET)(SETTING_DVD_POS1 + i * 4)); + DWORD olddata1 = settings_get((SETTING_SET)(SETTING_DVD_DATA11 + i * 4)); + DWORD olddata2 = settings_get((SETTING_SET)(SETTING_DVD_DATA12 + i * 4)); + settings_set((SETTING_SET)(SETTING_DVD_ID1 + i * 4), id); + settings_set((SETTING_SET)(SETTING_DVD_POS1 + i * 4), titlepos); + settings_set((SETTING_SET)(SETTING_DVD_DATA11 + i * 4), ddata1); + settings_set((SETTING_SET)(SETTING_DVD_DATA12 + i * 4), ddata2); + id = oldid; + titlepos = oldtitlepos; + ddata1 = olddata1; + ddata2 = olddata2; + } + settings_set(SETTING_DVD_ID1, dvd_ID); + dvd_was_saved = true; + } + + dvd_saved_pos = pos; + dvd_saved_title = title; + settings_set(SETTING_DVD_POS1, ((title & 0xff) << 24) | (pos & 0xffffff)); + settings_set(SETTING_DVD_DATA11, data1); + script_player_saved_callback(); + MSG("DVD: Saving pos = %d/%d, vmode=%d, spu=%d, aud=%d\n", dvd_saved_title, dvd_saved_pos, + dvd_saved_vmode, dvd_saved_spu_stream, dvd_saved_audio_stream); + return 0; +} + +bool dvd_get_saved() +{ + dvd_saved_pos = 0xffffffff; + dvd_saved_title = 0xffffffff; + dvd_saved_vmode = -1; dvd_saved_audio_stream = -1; dvd_saved_spu_stream = -1; + for (int i = 0; i < dvd_num_saved; i++) + { + DWORD id = (DWORD)settings_get((SETTING_SET)(SETTING_DVD_ID1 + i * 4)); + if (dvd_ID == id) + { + DWORD titlepos = (DWORD)settings_get((SETTING_SET)(SETTING_DVD_POS1 + i * 4)); + if (titlepos != 0xffffffff) // not-empty slot + { + dvd_saved_pos = titlepos & 0xffffff; + dvd_saved_title = (titlepos >> 24) & 0xff; + DWORD data1 = (DWORD)settings_get((SETTING_SET)(SETTING_DVD_DATA11 + i * 4)); + dvd_saved_vmode = data1 & 0xff; + dvd_saved_audio_stream = ((data1 >> 8) & 0xff) - 128; + dvd_saved_spu_stream = ((data1 >> 16) & 0xff) - 128; + break; + } + } + } + return dvd_saved_pos != 0xffffffff && dvd_saved_title != 0xffffffff && dvd_saved_title != 0xff; +} + +BOOL dvd_continue_play() +{ + if (dvd_saved_pos == 0xffffffff || dvd_saved_title == 0xffffffff || dvd_saved_title == 0xff) + return FALSE; + + wait_for_user = false; + wait_pause = 0; + dvd_reset_vm(dvd); + dvdnav_title_play(dvd, dvd_saved_title); + + // TODO: find a better solution... + bool old_dvd_waiting_to_play = dvd_waiting_to_play; + dvd_waiting_to_play = false; + for (int i = 0; i < 10; i++) + { + dvd_player_loop_internal(false); + } + dvd_waiting_to_play = old_dvd_waiting_to_play; + + if (dvdnav_current_title_info(dvd, &cur_titleid, &cur_chapid) != DVDNAV_STATUS_OK) + return FALSE; + if (dvdnav_sector_search(dvd, dvd_saved_pos, SEEK_SET) != DVDNAV_STATUS_OK) + return FALSE; + + old_titleid = -1; + old_chapid = -1; + saved_pts = -1; + msg("DVD: Continue play from saved pos = %d, title=%d\n", dvd_saved_pos, dvd_saved_title); + + script_dvd_menu_callback(dvdnav_is_domain_vts(dvd) != 1); + + // set other saved params + msg("DVD: restore vmode = %d, aID=%d, sID=%d\n", dvd_saved_vmode, + dvd_saved_audio_stream, dvd_saved_spu_stream); + + // restore aspect ratio & vmode + dvd_vmode = (KHWL_VIDEOMODE)dvd_saved_vmode; + khwl_display_clear(); + khwl_setvideomode(dvd_vmode, TRUE); + new_frame_size = true; + + // restore audio stream + mpeg_setaudiostream(-1); + if (dvd_saved_audio_stream >= 0) + dvd_button_audio(NULL, dvd_saved_audio_stream); + // sanity check + if (mpeg_getaudiostream() < 0) + mpeg_setaudiostream(0); + + // restore SPU stream + mpeg_setspustream(-1); + if (dvd_saved_spu_stream >= 0) + dvd_button_subtitle(NULL, dvd_saved_spu_stream); + + return TRUE; +} diff --git a/src/dvd/dvd_css.c b/src/dvd/dvd_css.c new file mode 100644 index 0000000..94608a2 --- /dev/null +++ b/src/dvd/dvd_css.c @@ -0,0 +1,528 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - libdvdcss hardware CSS replacement + * (parts of code from libdvdcss) + * \file dvd/dvd_css.c + * \author bombur + * \version 0.1 + * \date 7.02.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include + +#include "config.h" + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#pragma warning(disable: 4201) +#include +#pragma warning(default: 4201) +#else +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include + +#ifdef HAVE_LIMITS_H +# include +#endif + +// these are from libdvdcss: +#include "dvdcss/dvdcss.h" +#include "common.h" +#include "css.h" +#ifdef WIN32 +#pragma warning(disable: 4200) +#pragma warning(disable: 4201) +#pragma warning(disable: 4214) +#endif +#include "ioctl.h" +#ifdef WIN32 +#pragma warning(default: 4200) +#pragma warning(default: 4201) +#pragma warning(default: 4214) +#endif +#include "device.h" +#include "libdvdcss.h" + +#include +#include + +///////////////////////////////////////////// +#ifdef DVDCSS_USE_EXTERNAL_CSS + +///////////////////////// +//#define OUR_DEBUG_OUTPUT +///////////////////////// + +#ifdef OUR_DEBUG_OUTPUT +void msg(char *text, ...); +#define debug_error(e) msg("dvdcss err: %s\n", e) +#define debug_msg(m) msg("dvdcss: %s\n", m) +#else +#define debug_error(e) +//_dvdcss_error( dvdcss, e) +#define debug_msg(m) +//_dvdcss_debug( dvdcss, m) +#endif + + +extern int mv_cgms_flags; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int GetBusKey ( dvdcss_t ); +static int GetASF ( dvdcss_t ); +static int ReadTitleKey(int i_fd, int *pi_agid, int i_pos, uint8_t *p_key, int *cgms_flags); + + +/***************************************************************************** + * _dvdcss_test: check if the disc is encrypted or not + *****************************************************************************/ +int _dvdcss_test( dvdcss_t dvdcss ) +{ + int i_ret, i_copyright; + + i_ret = ioctl_ReadCopyright( dvdcss->i_fd, 0 /* i_layer */, &i_copyright ); + +#ifdef WIN32 + if( i_ret < 0 ) + { + /* Maybe we didn't have enough priviledges to read the copyright + * (see ioctl_ReadCopyright comments). + * Apparently, on unencrypted DVDs _dvdcss_disckey() always fails, so + * we can check this as a work-around. */ + i_ret = 0; + if( _dvdcss_disckey( dvdcss ) < 0 ) + i_copyright = 0; + else + i_copyright = 1; + } +#endif + + if( i_ret < 0 ) + { + /* Since it's the first ioctl we try to issue, we add a notice */ + debug_error("css error: ioctl_ReadCopyright failed, " + "make sure there is a DVD in the drive, and that " + "you have used the correct device node." ); + + return i_ret; + } + + return i_copyright; +} + +/***************************************************************************** + * GetBusKey : Go through the CSS Authentication process + ***************************************************************************** + * It simulates the mutual authentication between logical unit and host, + * and stops when a session key (called bus key) has been established. + * Always do the full auth sequence. Some drives seem to lie and always + * respond with ASF=1. For instance the old DVD roms on Compaq Armada says + * that ASF=1 from the start and then later fail with a 'read of scrambled + * block without authentication' error. + *****************************************************************************/ +static int GetBusKey( dvdcss_t dvdcss ) +{ + uint8_t p_challenge[2*KEY_SIZE]; + uint8_t p_challenge2[2*KEY_SIZE]; + dvd_key_t p_key1; + dvd_key_t p_key2; + char psz_warning[80]; + int i_ret = -1; + int i; + + debug_msg("requesting AGID" ); + i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + + /* We might have to reset hung authentication processes in the drive + by invalidating the corresponding AGID'. As long as we haven't got + an AGID, invalidate one (in sequence) and try again. */ + for( i = 0; i_ret == -1 && i < 4 ; ++i ) + { + sprintf( psz_warning, + "ioctl ReportAgid failed, invalidating AGID %d", i ); + debug_msg(psz_warning ); + + /* This is really _not good_, should be handled by the OS. + Invalidating an AGID could make another process fail some + where in it's authentication process. */ + dvdcss->css.i_agid = i; + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + + debug_msg("requesting AGID (2)" ); + i_ret = ioctl_ReportAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + } + + /* Unable to authenticate without AGID */ + if( i_ret == -1 ) + { + debug_error("ioctl ReportAgid failed, fatal" ); + return -1; + } + + /* Get challenge from host */ + khwl_getproperty(KHWL_DECODER_SET, edecCSSChlg, sizeof(p_challenge), p_challenge); + + /* Send challenge to LU */ + if( ioctl_SendChallenge( dvdcss->i_fd, + &dvdcss->css.i_agid, p_challenge) < 0 ) + { + debug_error("ioctl SendChallenge failed" ); + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + return -1; + } + + /* Get key1 from LU */ + if( ioctl_ReportKey1( dvdcss->i_fd, &dvdcss->css.i_agid, p_key1) < 0) + { + debug_error("ioctl ReportKey1 failed" ); + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + return -1; + } + + /* Send key1 to host */ + khwl_setproperty(KHWL_DECODER_SET, edecCSSKey1, KEY_SIZE, p_key1); + + /* Get challenge from LU */ + if( ioctl_ReportChallenge( dvdcss->i_fd, + &dvdcss->css.i_agid, p_challenge2) < 0 ) + { + debug_error("ioctl ReportKeyChallenge failed" ); + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + return -1; + } + + /* Send challenge to host */ + khwl_setproperty(KHWL_DECODER_SET, edecCSSChlg2, sizeof(p_challenge2), p_challenge2); + + /* Get key2 from host */ + khwl_getproperty(KHWL_DECODER_SET, edecCSSKey2, sizeof(p_key2), p_key2); + + /* Send key2 to LU */ + if( ioctl_SendKey2( dvdcss->i_fd, &dvdcss->css.i_agid, p_key2) < 0 ) + { + debug_error("AUTH: ioctl SendKey2 failed" ); + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + return -1; + } + + /* The drive has accepted us as authentic. */ + debug_msg("AUTH established" ); + + return 0; +} + +/***************************************************************************** + * _dvdcss_title: crack or decrypt the current title key if needed + ***************************************************************************** + * This function should only be called by dvdcss->pf_seek and should eventually + * not be external if possible. + *****************************************************************************/ +int _dvdcss_title ( dvdcss_t dvdcss, int i_block ) +{ + dvd_key_t p_title_key; + int i_ret = -1; + +// debug_msg("_dvdcss_title() start" ); + + if( ! dvdcss->b_scrambled ) + { + debug_msg("_dvdcss_title() end (not scrambled)" ); + return 0; + } + +// debug_msg("_dvdcss_title() 2" ); + + /* Crack or decrypt CSS title key for current VTS */ + i_ret = _dvdcss_titlekey( dvdcss, i_block, p_title_key ); + + if( i_ret < 0 ) + { + debug_error("fatal error in vts css key" ); + return i_ret; + } + + memcpy( dvdcss->css.p_title_key, p_title_key, KEY_SIZE ); + + debug_msg("_dvdcss_title() end" ); + + return 0; +} + +/***************************************************************************** + * _dvdcss_disckey: get disc key. + ***************************************************************************** + * This function should only be called if DVD ioctls are present. + * It will set dvdcss->i_method = DVDCSS_METHOD_TITLE if it fails to find + * a valid disc key. + * Two decryption methods are offered: + * -disc key hash crack, + * -decryption with player keys if they are available. + *****************************************************************************/ +int _dvdcss_disckey( dvdcss_t dvdcss ) +{ + unsigned char p_buffer[ DVD_DISCKEY_SIZE ]; + + debug_msg("disckey start" ); + + if( GetBusKey( dvdcss ) < 0 ) + { + return -1; + } + + /* Get encrypted disc key */ + if( ioctl_ReadDiscKey( dvdcss->i_fd, &dvdcss->css.i_agid, p_buffer) < 0 ) + { + debug_error("ioctl ReadDiscKey failed" ); + return -1; + } + + /* This should have invalidated the AGID and got us ASF=1. */ + if( GetASF( dvdcss ) != 1 ) + { + /* Region mismatch (or region not set) is the most likely source. */ + _dvdcss_error( dvdcss, + "ASF not 1 after reading disc key (region mismatch?)" ); + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + return -1; + } + + /* Set disc key to the host */ + khwl_setproperty(KHWL_DECODER_SET, edecCSSDiscKey, sizeof(p_buffer), p_buffer); + + debug_msg("disckey success" ); + + return 0; +} + + +/**************************************************************************** + * ReadTitleKey() + * This is an extended version of ioctl_ReadTitleKey() with CGMS support. + ****************************************************************************/ +int ReadTitleKey(int i_fd, int *pi_agid, int i_pos, uint8_t *p_key, int *cgms_flags) +{ + int i_ret = 0; + int cpm = 0, cp_sec = 0, cgms = 0; + +#ifdef WIN32 + if( WIN2K ) /* NT/2k/XP */ + { + DWORD tmp; + uint8_t buffer[DVD_TITLE_KEY_LENGTH]; + PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer; + + memset( &buffer, 0, sizeof( buffer ) ); + + key->KeyLength = DVD_TITLE_KEY_LENGTH; + key->SessionId = *pi_agid; + key->KeyType = DvdTitleKey; + key->KeyFlags = 0; + key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos * 2048; + + i_ret = DeviceIoControl( (HANDLE)i_fd, IOCTL_DVD_READ_KEY, key, + key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1; + + memcpy( p_key, key->KeyData, DVD_KEY_SIZE ); + + cpm = (key->KeyFlags >> 7) & 1; + cp_sec = (key->KeyFlags >> 6) & 1; + cgms = (key->KeyFlags >> 4) & 3; + } else + { + debug_msg("Cannot get Macrovision flags for this Windows version."); + } +#else + dvd_authinfo auth_info; + + memset( &auth_info, 0, sizeof( auth_info ) ); + auth_info.type = DVD_LU_SEND_TITLE_KEY; + auth_info.lstk.agid = *pi_agid; + auth_info.lstk.lba = i_pos; + + i_ret = ioctl(i_fd, DVD_AUTH, &auth_info ); + + memcpy( p_key, auth_info.lstk.title_key, DVD_KEY_SIZE ); + + cpm = (auth_info.lstk.cpm & 1); + cp_sec = (auth_info.lstk.cp_sec & 1); + cgms = (auth_info.lstk.cgms & 3); +#endif + +#ifdef OUR_DEBUG_OUTPUT + msg("dvdcss: MV/CGMS Flags = (%d %d %d)\n", cpm, cp_sec, cgms); +#endif + + *cgms_flags = cgms; + + return i_ret; +} + + +/***************************************************************************** + * _dvdcss_titlekey: get title key. + *****************************************************************************/ +int _dvdcss_titlekey( dvdcss_t dvdcss, int i_pos, dvd_key_t p_title_key ) +{ + static uint8_t p_garbage[ DVDCSS_BLOCK_SIZE ]; /* we never read it back */ + uint8_t p_key[ KEY_SIZE ]; + int i_ret = 0; + + debug_msg("titlekey start" ); + + if (dvdcss->b_ioctls) + { + /* We need to authenticate again every time to get a new session key */ + if( GetBusKey( dvdcss ) < 0 ) + { + return -1; + } + + /* Get encrypted title key */ + i_ret = ReadTitleKey( dvdcss->i_fd, &dvdcss->css.i_agid, i_pos+1, p_key, &mv_cgms_flags); + if (i_ret < 0) + { + /* We need to authenticate again every time to get a new session key */ + if( GetBusKey( dvdcss ) < 0 ) + { + return -1; + } + + /* Get encrypted title key */ + i_ret = ReadTitleKey( dvdcss->i_fd, &dvdcss->css.i_agid, i_pos, p_key, &mv_cgms_flags); + if (i_ret < 0 ) + { + debug_error("ioctl ReadTitleKey failed (region mismatch?)" ); + } + } + + if (i_ret >= 0) + { + khwl_setproperty(KHWL_DECODER_SET, edecCSSTitleKey, sizeof(p_key), p_key); + memcpy( p_title_key, p_key, KEY_SIZE ); + debug_msg("Titlekey set OK!" ); + } else + { + debug_msg("Titlekey not found!"); + } + + /* Test ASF, it will be reset to 0 if we got a Region error */ + switch( GetASF( dvdcss ) ) + { + case -1: + /* An error getting the ASF status, something must be wrong. */ + debug_msg("lost ASF requesting title key" ); + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + i_ret = -1; + break; + + case 0: + /* This might either be a title that has no key, + * or we encountered a region error. */ + debug_msg("lost ASF requesting title key" ); + break; + + case 1: + /* Drive status is ok. */ + /* If the title key request failed, but we did not loose ASF, + * we might stil have the AGID. Other code assume that we + * will not after this so invalidate it(?). */ + if( i_ret < 0 ) + { + debug_msg("Invalidating Agid (in title key)" ); + ioctl_InvalidateAgid( dvdcss->i_fd, &dvdcss->css.i_agid ); + } + break; + } + + /* The title key request failed */ + if (i_ret < 0) + { + debug_msg("titlekey error - resetting drive " ); + + /* Read an unscrambled sector and reset the drive */ + dvdcss->pf_seek( dvdcss, 0 ); + dvdcss->pf_read( dvdcss, p_garbage, 1 ); + dvdcss->pf_seek( dvdcss, 0 ); + + // we don't have a cracking mechanism anyway ???? + _dvdcss_disckey( dvdcss ); + + /* Fallback */ + } + } + + return i_ret; +} + +// we do nothing! All work is done in hardware! +int _dvdcss_unscramble( dvd_key_t p_key, uint8_t *p_sec ) +{ + return 0; +} + +/* Following functions are local */ + +/***************************************************************************** + * GetASF : Get Authentication success flag + ***************************************************************************** + * Returns : + * -1 on ioctl error, + * 0 if the device needs to be authenticated, + * 1 either. + *****************************************************************************/ +static int GetASF( dvdcss_t dvdcss ) +{ + int i_asf = 0; + + if( ioctl_ReportASF( dvdcss->i_fd, NULL, &i_asf ) != 0 ) + { + /* The ioctl process has failed */ + debug_error("GetASF fatal error" ); + return -1; + } + + if( i_asf ) + { + debug_msg("GetASF authenticated, ASF=1" ); + } + else + { + debug_msg("GetASF not authenticated, ASF=0" ); + } + + return i_asf; +} + +#endif // DVDCSS_USE_EXTERNAL_CSS diff --git a/src/dvd/dvd_misc.c b/src/dvd/dvd_misc.c new file mode 100644 index 0000000..bcaf014 --- /dev/null +++ b/src/dvd/dvd_misc.c @@ -0,0 +1,696 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - libdvdnav cache replacement + * \file dvd/dvd_misc.c + * \author bombur + * \version 0.1 + * \date 1.02.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "dvdnav.h" +#include "dvdnav_internal.h" +#include "read_cache.h" + +#include "dvd_misc.h" + +#include +#include +#include +#include +#include "media.h" + + +///////////// DVD Caching... +/* + [bombur]: let me describe the situation. + - dvdnav_read_cache_block() is called several times + - we have 8 buffers; each contains 16 blocks max. + - we won't precache at the vobu start + - we won't allocate any buffers or memory here +*/ + +/////////////////////// +//#define NO_CACHE +/////////////////////// + +// must be equal to MPEG_NUM_BUFS +#define READ_CACHE_CHUNKS 8 + +// must be equal to MPEG_BUF_SIZE +#define READ_CACHE_BUF_SIZE 32768 + +#define READ_AHEAD_SIZE (READ_CACHE_BUF_SIZE / DVD_VIDEO_LB_LEN) + +typedef struct read_cache_chunk_s +{ + uint8_t *cache_buffer; + int32_t cache_start_sector; /* -1 means cache invalid */ + int32_t cache_read_count; /* this many sectors are already read */ + size_t cache_block_count; /* this many sectors will go in this chunk */ + size_t cache_malloc_size; + int cache_missed; // used when a cache-missed block was written +} read_cache_chunk_t; + +struct read_cache_s +{ + read_cache_chunk_t chunk[16 /*READ_CACHE_CHUNKS */]; + int current; + int last_sector; + int wait_for_new_buffer; + int called_flag; + + int range_start; // save VOBU sector range to avoid unused cache + int range_count; + + /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ + dvdnav_t *dvd_self; +}; + +read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) +{ + read_cache_t *self; + int i; + + self = (read_cache_t *)malloc(sizeof(read_cache_t)); + + if(self) + { + self->current = 0; + self->dvd_self = dvd_self; + + self->wait_for_new_buffer = 1; + self->called_flag = 0; + self->last_sector = 0; + self->range_start = 0; + self->range_count = 0; + + dvdnav_read_cache_clear(self); + for (i = 0; i < READ_CACHE_CHUNKS; i++) + { + self->chunk[i].cache_buffer = NULL; + self->chunk[i].cache_read_count = 0; + self->chunk[i].cache_block_count = READ_AHEAD_SIZE; + } + } + + return self; +} + +void dvdnav_read_cache_free(read_cache_t* self) +{ + dvdnav_t *tmp; + + /* all buffers returned, free everything */ + tmp = self->dvd_self; + free(self); + free(tmp); +} + +/* This function MUST be called whenever self->file changes. */ +void dvdnav_read_cache_clear(read_cache_t *self) +{ + return; +} + +/* This function is called just after reading the NAV packet. */ +void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count) +{ + self->range_start = sector; + self->range_count = block_count; + return; +} + +// This is our function - pass 'khwl' buffer pointers +int dvdnav_set_cache_memory(dvdnav_t* dvd_self, uint8_t *block_mem) +{ + read_cache_t *self; + int i; + + self = dvd_self->cache; + + if (self) + { + for (i = 0; i < READ_CACHE_CHUNKS; i++) + { + self->chunk[i].cache_buffer = block_mem; + self->chunk[i].cache_malloc_size = READ_CACHE_BUF_SIZE; + block_mem += READ_CACHE_BUF_SIZE; + } + } + return DVDNAV_STATUS_OK; +} + +void dvdnav_reset_cache_flag(dvdnav_t* dvd_self) +{ + if (dvd_self->cache) + dvd_self->cache->called_flag = 0; +} +int dvdnav_get_cache_flag(dvdnav_t* dvd_self) +{ + return (dvd_self->cache != NULL) ? dvd_self->cache->called_flag : 0; +} + +int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf) +{ + int i, use, count; + int32_t res; + + if(!self) + return 0; + + self->called_flag = 1; + +retry: + use = -1; +#ifndef NO_CACHE + // sorry, our read-ahead cache works with only 1 block at a time + if(self->dvd_self->use_read_ahead && block_count == 1) + { + // find our chunk - try the current chunk first + read_cache_chunk_t cur = self->chunk[self->current]; + if (*buf >= cur.cache_buffer && *buf < (cur.cache_buffer + cur.cache_malloc_size)) + use = self->current; + else + { + // search others + for (i = 0; i < READ_CACHE_CHUNKS; i++) + { + if (*buf >= self->chunk[i].cache_buffer && + *buf < (self->chunk[i].cache_buffer + self->chunk[i].cache_malloc_size)) + use = i; + } + } + } +#endif + if (use >= 0) + { + read_cache_chunk_t *chunk; + chunk = &self->chunk[use]; + self->current = use; + self->last_sector = sector; + // this is not the first buffer, so try searching the cache + if (*buf != chunk->cache_buffer) + { + // we want to return already filled buf - so we check the sector bounds + if (!chunk->cache_missed && sector >= chunk->cache_start_sector && + sector < (chunk->cache_start_sector + chunk->cache_read_count) && + sector + block_count <= chunk->cache_start_sector + chunk->cache_block_count) + { + if (*buf == chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN) + { + return DVD_VIDEO_LB_LEN; + } + } + // ask another free buf + msg("--cache skip\n"); + if (media_skip_buffer(buf)) + goto retry; + // if not, then cache-miss + } + else + { + // start a new chunk - read it entirely + chunk->cache_missed = 0; + chunk->cache_start_sector = sector; + + count = chunk->cache_block_count; + +#if 0 + // if we don't want to get out of VOBU range... + if (self->range_count > 0) + { + if (sector >= self->range_start + && sector < self->range_start + self->range_count + && sector + count >= self->range_start + self->range_count) + { + count = self->range_start + self->range_count - sector; + msg("--cache limited to %d\n", count); + } + } +#endif + + chunk->cache_read_count = (int32_t)DVDReadBlocks(self->dvd_self->file, + chunk->cache_start_sector, + count, + chunk->cache_buffer); + if (chunk->cache_read_count > 0) + { + self->wait_for_new_buffer = 0; + if (*buf == chunk->cache_buffer) + { + return DVD_VIDEO_LB_LEN; + } + } + else + return 0; + } + chunk->cache_missed = 1; + } + + if (self->dvd_self->use_read_ahead) + { + // cache miss... + msg("--cache miss\n"); + } + res = (int32_t)DVDReadBlocks(self->dvd_self->file, + sector, 1, *buf) * DVD_VIDEO_LB_LEN; + + return res; + +} + +dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) +{ + read_cache_t *cache; + + if (!self) + return DVDNAV_STATUS_ERR; + + cache = self->cache; + if (!cache) + return DVDNAV_STATUS_ERR; + + return DVDNAV_STATUS_OK; +} + +int8_t dvd_get_audio_logical_stream(dvdnav_t *dvd, uint8_t audio_num) +{ + int audioN; + if(!dvd) + { + //printerr("Passed a NULL pointer."); + return -1; + } + if(!dvd->started) + { + //printerr("Virtual DVD machine not started."); + return -1; + } + + pthread_mutex_lock(&dvd->vm_lock); + if (!dvd->vm->state.pgc) + { + //printerr("No current PGC."); + pthread_mutex_unlock(&dvd->vm_lock); + return -1; + } + + for (audioN = 0; audioN < 8; audioN++) + { + if (vm_get_audio_stream(dvd->vm, audioN) == audio_num) + { + pthread_mutex_unlock(&dvd->vm_lock); + return audioN; + } + } + + pthread_mutex_unlock(&dvd->vm_lock); + return -1; +} + + +/// This is almost exact copy of 'libdvdnav' function, except aspect mode +int8_t dvd_get_spu_logical_stream(dvdnav_t *dvd, uint8_t subp_num, int mode) +{ + int subpN; + + if(!dvd) + { + //printerr("Passed a NULL pointer."); + return -1; + } + if(!dvd->started) + { + //printerr("Virtual DVD machine not started."); + return -1; + } + + if (!dvd->vm->state.pgc) + { + //printerr("No current PGC."); + return -1; + } + for (subpN = 0; subpN < 32; subpN++) + { + if (vm_get_subp_stream(dvd->vm, subpN, mode) == subp_num) + return subpN; + } + return -1; +} + +int dvd_set_spu_stream(dvdnav_t *dvd, int stream, int mode) +{ + int source_aspect = vm_get_video_aspect(dvd->vm); + int req_s, subpN, streamN = -1; + + if((dvd->vm->state).domain != VTS_DOMAIN) + return 0; + + for (req_s = stream; req_s >= 0 && req_s < 32; req_s++) + { + for (subpN = 0; subpN < 32; subpN++) + { + /* Is this logical stream present */ + if ((dvd->vm->state).pgc->subp_control[subpN] & (1<<31)) + { + if(source_aspect == 0) /* 4:3 */ + streamN = ((dvd->vm->state).pgc->subp_control[subpN] >> 24) & 0x1f; + if (source_aspect == 3) /* 16:9 */ + { + switch (mode) + { + case 0: + streamN = ((dvd->vm->state).pgc->subp_control[subpN] >> 16) & 0x1f; + break; + case 1: + streamN = ((dvd->vm->state).pgc->subp_control[subpN] >> 8) & 0x1f; + break; + case 2: + streamN = (dvd->vm->state).pgc->subp_control[subpN] & 0x1f; + } + } + // that's it! + if (streamN == req_s) + { + (dvd->vm->state).SPST_REG &= ~0x7f; // Keep other bits. + (dvd->vm->state).SPST_REG |= 0x40; // Turn it on + (dvd->vm->state).SPST_REG |= subpN; + return 1; + } + } + } + } + // not found, Turn it off + (dvd->vm->state).SPST_REG &= ~0x40; + return 1; +} + +int dvd_set_audio_stream(dvdnav_t *dvd, int stream) +{ + int req_s, audioN; + + if((dvd->vm->state).domain != VTS_DOMAIN) + return 0; + + for (req_s = stream; req_s >= 0 && req_s < 8; req_s++) + { + for (audioN = 0; audioN < 8; audioN++) + { + if((dvd->vm->state).pgc->audio_control[audioN] & (1<<15)) + { + int streamN = ((dvd->vm->state).pgc->audio_control[audioN] >> 8) & 0x07; + if (streamN == req_s) + { + (dvd->vm->state).AST_REG = audioN; + return 1; + } + } + } + } + // not found, + (dvd->vm->state).AST_REG = 15; // non-existant? + return 1; +} + + +int dvd_get_time(dvdnav_t *dvd, int title, int chapter, uint64_t *time) +{ + uint64_t length = 0; + uint32_t first_cell_nr, last_cell_nr, cell_nr; + int cur_title, cur_part; + cell_playback_t *cell; + dvd_state_t *state; + int ttn; + + *time = 0; + + pthread_mutex_lock(&dvd->vm_lock); + + if (!dvd->vm->vmgi) + { + //printerr("Bad VM state."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + if (!dvd->started) + { + /* don't report an error but be nice */ + vm_start(dvd->vm); + dvd->started = 1; + } + + if(dvd->position_current.still != 0) + { + //printerr("Cannot seek in a still frame."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + + state = &(dvd->vm->state); + if(!state->pgc) + { + //printerr("No current PGC."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + + dvdnav_current_title_info(dvd, &cur_title, &cur_part); + if (title >= 0 && title + 1 != cur_title) + { + //printerr("Cannot seek in a still frame."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + + first_cell_nr = 1; + if (title < 0 || chapter < 0) + last_cell_nr = state->pgc->nr_of_cells; + else + { + vts_ptt_srpt_t *vts_ptt_srpt = dvd->vm->vtsi->vts_ptt_srpt; + if (chapter == 0) + last_cell_nr = 0; + else + { + last_cell_nr = state->pgc->nr_of_cells; + chapter--; + ttn = dvd->vm->vmgi->tt_srpt->title[title].vts_ttn - 1; + if (ttn >= 0 && ttn < vts_ptt_srpt->nr_of_srpts) + { + if (chapter < vts_ptt_srpt->title[ttn].nr_of_ptts) + { + int pgN = vts_ptt_srpt->title[ttn].ptt[chapter].pgn; // state->pgN + if(pgN < state->pgc->nr_of_programs) + last_cell_nr = state->pgc->program_map[pgN] - 1; + else + last_cell_nr = state->pgc->nr_of_cells; + } + } + } + } + + length = 0; + for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr); cell_nr ++) + { + cell = &(state->pgc->cell_playback[cell_nr-1]); + length += dvdnav_convert_time(&cell->playback_time); + } + + *time = length; + + pthread_mutex_unlock(&dvd->vm_lock); + return 1; +} + +int dvd_get_chapter(dvdnav_t *dvd, int title, uint64_t time, int *chapter) +{ + uint64_t length = 0; + uint32_t last_cell_nr, cell_nr; + int32_t found = 0; + int chap = 0; + int cur_title, cur_part; + cell_playback_t *cell; + dvd_state_t *state; + vts_ptt_srpt_t *vts_ptt_srpt = dvd->vm->vtsi->vts_ptt_srpt; + int ttn; + + *chapter = 0; + + pthread_mutex_lock(&dvd->vm_lock); + + if (!dvd->vm->vmgi) + { + //printerr("Bad VM state."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + if (!dvd->started) + { + /* don't report an error but be nice */ + vm_start(dvd->vm); + dvd->started = 1; + } + + if (dvd->position_current.still != 0) + { + //printerr("Cannot seek in a still frame."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + + dvdnav_current_title_info(dvd, &cur_title, &cur_part); + if (title + 1 != cur_title) + { + //printerr("Cannot seek in a still frame."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + + state = &(dvd->vm->state); + if (!state->pgc || title < 0) + { + //printerr("No current PGC."); + pthread_mutex_unlock(&dvd->vm_lock); + return DVDNAV_STATUS_ERR; + } + + + last_cell_nr = state->pgc->nr_of_cells; + cell_nr = 1; + length = 0; + ttn = dvd->vm->vmgi->tt_srpt->title[title].vts_ttn - 1; + if (ttn >= 0 && ttn < vts_ptt_srpt->nr_of_srpts) + { + for (chap = 0; chap < vts_ptt_srpt->title[ttn].nr_of_ptts; chap++) + { + int pgN = vts_ptt_srpt->title[ttn].ptt[chap].pgn; // state->pgN + if(pgN < state->pgc->nr_of_programs) + last_cell_nr = state->pgc->program_map[pgN] - 1; + else + last_cell_nr = state->pgc->nr_of_cells; + for(; (cell_nr <= last_cell_nr) && !found; cell_nr ++) + { + cell = &(state->pgc->cell_playback[cell_nr-1]); + length += dvdnav_convert_time(&cell->playback_time); + if (length > time) + { + found = 1; + break; + } + } + if (found) + break; + } + } + + *chapter = chap; + + pthread_mutex_unlock(&dvd->vm_lock); + return 1; +} + +// declared in vm.c +extern uint8_t dvd_name_data[DVD_VIDEO_LB_LEN]; + +static uint32_t crc_table[256]; + +void dvd_make_crc_table() +{ + uint32_t c, poly; // polynomial exclusive-or pattern + uint32_t n, k; + // make exclusive-or pattern from polynomial (0xedb88320L) + static const uint8_t p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 }; + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(uint8_t); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = n; + for (k = 0; k < 8; k++) + c = (c & 1) ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } +} + +uint32_t dvd_get_disc_ID(const char *use_name) +{ + int i, l; + uint32_t crc32 = 0xffffffffL; + uint8_t *data; + + if (use_name != NULL) + { + data = (uint8_t *)use_name; + l = strlen(use_name); + } else + { + data = dvd_name_data; + l = 128; + } + + for(i = 0; i < l; i++) + { + register uint8_t c = data[i]; + crc32 = crc_table[(crc32 & 0xff) ^ c] ^ (crc32 >> 8); + } + crc32 ^= 0xffffffffL; + +#if 0 + { + char d[130]; + for (i = 0; i < l; i++) + { + if (data[i] >= 32 && data[i] < 127) + d[i] = data[i]; + else + d[i] = ' '; + } + d[l] = '\0'; + msg("* [%s]\n", d); + } +#endif + msg("* DVD: ID = %8x\n", crc32); + return crc32; +} + +void dvd_reset_vm(dvdnav_t *dvd) +{ + vm_reset(dvd->vm, NULL); + dvd->position_current.still = 0; + dvd->sync_wait = 0; +} + +int dvd_skip_sector(dvdnav_t *dvd) +{ + if (dvd->nav_packet_error) + { + dvd->vobu.vobu_start ++; + return 0; + } + return -1; +} diff --git a/src/dvd/dvd_misc.h b/src/dvd/dvd_misc.h new file mode 100644 index 0000000..4d7e911 --- /dev/null +++ b/src/dvd/dvd_misc.h @@ -0,0 +1,76 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - libdvdnav cache replacement header file + * \file dvd/dvd_misc.h + * \author bombur + * \version 0.1 + * \date 1.02.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + + +#ifndef SP_DVD_MISC_H +#define SP_DVD_MISC_H + +#ifdef __cplusplus +extern "C" { +#endif + +// all basic funcs are already in + +/// Set memory chunk enough to hold MPEG_NUM_BUFS cache buffers +int dvdnav_set_cache_memory(dvdnav_t* dvd_self, uint8_t *block_mem); + +// used to determine if dvdnav_read_cache_block() was called +// (we want to pass a new block only if the real data was returned) +void dvdnav_reset_cache_flag(dvdnav_t* dvd_self); +int dvdnav_get_cache_flag(dvdnav_t* dvd_self); + + +// defined in dvd_misc.c because of dvdnav_internal.h + +// like dvdnav function, but uses 'mode' +int8_t dvd_get_spu_logical_stream(dvdnav_t *dvd, uint8_t subp_num, int mode); +// like dvdnav function +int8_t dvd_get_audio_logical_stream(dvdnav_t *dvd, uint8_t audio_num); + +/// set spu stream to vm register (tricky!) +int dvd_set_spu_stream(dvdnav_t *dvd, int stream, int mode); + +/// set audio stream vm register (tricky!) +int dvd_set_audio_stream(dvdnav_t *dvd, int stream); + +/// time in PTS, title/chapter - 0-based. +int dvd_get_time(dvdnav_t *dvd, int title, int chapter, uint64_t *time); +/// time in PTS, title/chapter - 0-based. +int dvd_get_chapter(dvdnav_t *dvd, int title, uint64_t time, int *chapter); + +int64_t dvdnav_convert_time(dvd_time_t *time); + +// Disc ID (CRC32) stuff: +void dvd_make_crc_table(); +uint32_t dvd_get_disc_ID(const char *use_name); + +void dvd_reset_vm(dvdnav_t *dvd); + +int dvd_skip_sector(dvdnav_t *dvd); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_DVD_MISC_H diff --git a/src/dvd/dvd_player.cpp b/src/dvd/dvd_player.cpp new file mode 100644 index 0000000..5d7d6e7 --- /dev/null +++ b/src/dvd/dvd_player.cpp @@ -0,0 +1,139 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DVD player wrapper impl. + * \file dvd/dvd_player.cpp + * \author bombur + * \version 0.1 + * \date 12.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "dvd-internal.h" + +#include + +bool dvd_do_command(const SPString & command) +{ + if (command.CompareNoCase("continue") == 0) + { + dvd_continue_play(); + dvd_button_play(); + script_update_variable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("pause") == 0) + { + dvd_button_pause(); + script_update_variable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("step") == 0) + { + dvd_button_step(); + return true; + } + else if (command.CompareNoCase("slow") == 0) + { + dvd_button_slow(); + script_update_variable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("forward") == 0) + { + dvd_button_fwd(); + script_update_variable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("rewind") == 0) + { + dvd_button_rew(); + script_update_variable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("prev") == 0) + { + dvd_button_prev(); return true; + } + else if (command.CompareNoCase("next") == 0) + { + dvd_button_next(); return true; + } + else if (command.CompareNoCase("press") == 0) + { + dvd_button_press(); return true; + } + else if (command.CompareNoCase("left") == 0) + { + dvd_button_left(); return true; + } + else if (command.CompareNoCase("right") == 0) + { + dvd_button_right(); return true; + } + else if (command.CompareNoCase("up") == 0) + { + dvd_button_up(); return true; + } + else if (command.CompareNoCase("down") == 0) + { + dvd_button_down(); return true; + } + else if (command.CompareNoCase("menu") == 0) + { + dvd_button_menu(); return true; + } + else if (command.CompareNoCase("rootmenu") == 0) + { + dvd_button_menu(DVD_MENU_ROOT); return true; + } + else if (command.CompareNoCase("return") == 0) + { + dvd_button_return(); return true; + } + else if (command.CompareNoCase("angle") == 0) + { + dvd_button_angle(); return true; + } + else if (command.CompareNoCase("audio") == 0) + { + dvd_button_audio(); + script_update_variable(SCRIPT_VAR_PLAYER_LANGUAGE_AUDIO); + script_update_variable(SCRIPT_VAR_PLAYER_AUDIO_STREAM); + return true; + } + else if (command.CompareNoCase("subtitle") == 0) + { + dvd_button_subtitle(); + script_update_variable(SCRIPT_VAR_PLAYER_LANGUAGE_SUBTITLE); + script_update_variable(SCRIPT_VAR_PLAYER_SUBTITLE_STREAM); + return true; + } + return false; +} diff --git a/src/dvd/main.cpp b/src/dvd/main.cpp new file mode 100644 index 0000000..65fe4b6 --- /dev/null +++ b/src/dvd/main.cpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DVD player module main source file. + * \file dvd/main.cpp + * \author bombur + * \version 0.21 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include + +extern "C" +{ + extern MODULE_FUNC_TABLE dvd_funcs[]; + extern MODULE_FUNC_TABLE init_funcs[]; + extern MODULE_DESC module_dvd_desc; +}; + +int main(int argc, char *argv[]) +{ + if (argc > 1) + { + module_start(argv[1], &module_dvd_desc, dvd_funcs, init_funcs); + module_wait(); + } + + return 0; +} diff --git a/src/dvd/module-dvd.cpp b/src/dvd/module-dvd.cpp new file mode 100644 index 0000000..9ed60e3 --- /dev/null +++ b/src/dvd/module-dvd.cpp @@ -0,0 +1 @@ +#include "../module-dvd.cpp" diff --git a/src/dvd/module-init.cpp b/src/dvd/module-init.cpp new file mode 100644 index 0000000..84b3f24 --- /dev/null +++ b/src/dvd/module-init.cpp @@ -0,0 +1 @@ +#include "../module-init.cpp" diff --git a/src/dvd/module.cpp b/src/dvd/module.cpp new file mode 100644 index 0000000..ae62f76 --- /dev/null +++ b/src/dvd/module.cpp @@ -0,0 +1 @@ +#include "../module.cpp" diff --git a/src/gui/console.cpp b/src/gui/console.cpp new file mode 100644 index 0000000..4826930 --- /dev/null +++ b/src/gui/console.cpp @@ -0,0 +1,238 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - console class header file + * \file console.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include +#include + +Console *console = NULL; + +Console::Console(int cols, int rows) +{ + if (cols < 1) + cols = 1; + if (rows < 1) + rows = 1; + numrows = rows; + numcols = cols; + str = (char **)SPmalloc(numrows * sizeof(char *)); + str[0] = (char *)SPmalloc(numrows * numcols * sizeof(char)); + slen = (int *)SPmalloc(numrows * sizeof(int)); + for (int i = 1; i < numrows; i++) + str[i] = str[i - 1] + numcols * sizeof(char); + num = numrows; + + width = 0; + height = 0; + + font = NULL; +#ifdef CONSOLE_USE_FONT_8x8 + SetFont(CONSOLE_FONT_8x8); +#else + SetFont(CONSOLE_FONT_8x16); +#endif +} + +bool Console::SetFont(CONSOLE_FONT_TYPE type) +{ + switch (type) + { + case CONSOLE_FONT_8x8: + cur_fnt = (BYTE *)font8x8; + font_width = 8; + font_height = 8; + break; + case CONSOLE_FONT_8x16: + cur_fnt = (BYTE *)font8x16; + font_width = 8; + font_height = 16; + break; + default: + return false; + } + + if (font != NULL) + SPfree(font); + + font = (BYTE *)SPmalloc(font_width * font_height * 256); + + UpdateFont(); + + // sorry, console size will change if font changes + width = numcols * font_width; + height = numrows * font_height; + + // center left-bottom + x = gui.left; + y = gui.bottom - height; + + dirty = true; + + return true; +} + +void Console::UpdateFont() +{ + int siz = font_width * font_height; + int chsiz = ((font_width + 7) / 8); + BYTE c1 = (BYTE)gui.GetWhiteColor(); + BYTE c2 = (BYTE)gui.GetTransparentColor(); + for (int i = 0; i < 256; i++) + { + BYTE *ff = font + i * siz; + BYTE *sff = cur_fnt + i * chsiz * font_height; + for (int j = 0; j < siz; j++) + *ff++ = ((sff[j / font_width] >> (font_width - 1 - j % font_width)) & 1) != 0 ? c1 : c2; + } +} + +Console::~Console() +{ + if (font != NULL) + SPfree(font); + + SPfree(str[0]); + SPfree(str); + SPfree(slen); +} + +bool Console::Printf(char *s) +{ + char *start = s; + for (; *s != '\0'; s++) + { + switch (*s) + { + case '\r': + continue; + case '\n': + AddString(start, s - start); + start = s + 1; + continue; + // TODO: add tabs + } + } + if (s != start) + AddString(start, s - start); + + return false; +} + +bool Console::AddString(const char *s, int len) +{ + if (num > 0) + num--; + else + { + // shift pointers + for (int iy = 0; iy < numrows - 1; iy++) + { + strncpy(str[iy], str[iy + 1], slen[iy + 1]); + slen[iy] = slen[iy + 1]; + } + } + int last = numrows - num - 1; + + if (len == 0) + len = 99999; + int sl, sll; + for (sl = 0, sll = 0; s[sl] != '\0' && sl < len && sl < numcols; sl++) + { + if (s[sl] == '\r' || s[sl] == '\n') + continue; + str[last][sll++] = s[sl]; + } + slen[last] = sll; + dirty = true; + return true; +} + +bool Console::Update(Context *context, int x1, int y1, int x2, int y2) +{ + if (font == NULL || context == NULL) + return false; + if (num == numrows) + return false; + int nx = MIN((x2 + font_width - 1) / font_width, numcols), ny = MIN((y2 + font_height - 1) / font_height, numrows); + int charsize = font_width * font_height; + int xx = (x1 / font_width) * font_width; + BYTE *d = context->data + xx; + BYTE trc = (BYTE)gui.GetTransparentColor(); + for (int iy = MAX(y1 / font_height, num), yy = iy * font_height; iy < ny; iy++, yy += font_height) + { + int iiy = iy - num; + BYTE *dst = d + yy * context->pitch; + char *s = str[iiy]; + int fy2 = MIN(font_height - 1, y2 - yy); + int fx = x1 - xx; + int dx = xx; + for (int ix = x1 / font_width; ix < MIN(nx, slen[iiy]); ix++) + { + int xxi = ix * font_width; + int fw = x2 - xxi + 1 < font_width ? x2 - xxi + 1 : font_width; + BYTE *base = font + (BYTE)s[ix] * charsize; + for (int fy = MAX(y1 - yy, 0); fy <= fy2; fy++) + memcpy(dst + fy * context->pitch + fx, base + fy * font_width + fx, fw); + fx = 0; + dst += fw; + dx += fw; + } + // finish the line + int pad = x2 + 1 - dx - fx; + if (pad > 0) + { + for (int fy = MAX(0, y1 - yy); fy <= fy2; fy++) + memset(dst + fy * context->pitch + fx, trc, pad); + } + } + return true; +} + +bool Console::TextOut(Context *context, char *str, int nx) +{ + if (font == NULL || context == NULL) + return false; + int charsize = font_width * font_height; + BYTE *dst = context->data; + int ix, nnx = (nx < 1) ? 9999 : nx; + for (ix = 0; str[ix] && ix < nnx; ix++) + { + BYTE *base = font + str[ix] * charsize; + for (int fy = 0; fy < font_height; fy++) + memcpy(dst + fy * context->pitch, base + fy * font_width, font_width); + dst += font_width; + } + // finish the line + if (nx > ix) + { + int pad = (nx - ix) * font_width; + BYTE trc = (BYTE)gui.GetTransparentColor(); + for (int fy = 0; fy < font_height; fy++) + memset(dst + fy * context->pitch, trc, pad); + } + return true; +} diff --git a/src/gui/console.h b/src/gui/console.h new file mode 100644 index 0000000..cb10a2a --- /dev/null +++ b/src/gui/console.h @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - console class header file + * \file console.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_CONSOLE_H +#define SP_CONSOLE_H + +#include + +enum CONSOLE_FONT_TYPE +{ + CONSOLE_FONT_8x8 = 0, + CONSOLE_FONT_8x16 +}; + +/// Console class +class Console : public Window +{ +public: + /// ctor + Console(int cols = 80, int rows = 20); + + /// dtor + virtual ~Console(); + + /// Formatted string output + bool Printf(char *str); + + /// add one string ('\n' are ignored) + bool AddString(const char *str, int len = 0); + + /// change font + bool SetFont(CONSOLE_FONT_TYPE type); + /// call this if palette changed + void UpdateFont(); + + /// Update part of window in LOCAL coords + virtual bool Update(Context *context, int x1, int y1, int x2, int y2); + + /// Debug output (called from window) + bool TextOut(Context *context, char *str, int nx = 0); + +public: + /// string data + char **str; + /// cached string lengths + int *slen; + /// console dims in chars + int numrows, numcols; + /// number of non-filled strings (from top to the first string) + int num; + /// rastered font + BYTE *font; + /// bitfont + BYTE *cur_fnt; + int font_width, font_height; +}; + +extern Console *console; + +#endif // of SP_CONSOLE_H diff --git a/src/gui/console_font.inc.cpp b/src/gui/console_font.inc.cpp new file mode 100644 index 0000000..4a16cf9 --- /dev/null +++ b/src/gui/console_font.inc.cpp @@ -0,0 +1,800 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - console built-in font source file + * \file console_font.inc.cpp + * \author bombur + * \version 0.1 + * \date 14.02.2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +unsigned char font8x8[] = +{ + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, + 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, + 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0xD6, 0x10, 0x38, + 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x10, 0x38, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, + 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, + 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, + 0x7E, 0xC3, 0x78, 0xCC, 0xCC, 0x78, 0x8C, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, + 0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00, + 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, + 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, + 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x30, 0x60, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, + 0x78, 0xCC, 0xDC, 0xFC, 0xEC, 0xCC, 0x78, 0x00, + 0x30, 0xF0, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, + 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x00, + 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, + 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, + 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x00, + 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x70, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, + 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, + 0xFC, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xFC, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00, + 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, + 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, + 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, + 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, + 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, + 0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0xE6, 0x00, + 0x78, 0xCC, 0xE0, 0x38, 0x1C, 0xCC, 0x78, 0x00, + 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, + 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, + 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xFE, 0xCC, 0x98, 0x30, 0x62, 0xC6, 0xFE, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0xBC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, + 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x18, 0x00, 0x78, 0x18, 0x18, 0x18, 0xD8, 0x70, + 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, + 0x00, 0x00, 0xD8, 0x6C, 0x6C, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00, + 0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, + 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, + 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x72, 0x9C, 0x00, 0x72, 0x9C, 0x00, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0x0C, 0x38, 0x60, 0x7C, 0x00, 0x00, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x7E, 0xC3, 0x78, 0xCC, 0xCC, 0x78, 0x8C, 0xF8, + 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00, + 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0xE6, 0x00, + 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00, + 0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70, + 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00, + 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0x00, 0x00, 0x7C, 0xC0, 0xC0, 0x7C, 0x06, 0x3C, + 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, + 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xCC, 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0x00, + 0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00, + 0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00, + 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00, + 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00, + 0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xFC, 0x0C, 0xF8, + 0xC6, 0x38, 0x7C, 0xC6, 0xC6, 0x7C, 0x38, 0x00, + 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18, + 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00, + 0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x00, + 0xF0, 0xD8, 0xD8, 0xF4, 0xCC, 0xDE, 0xCC, 0x0E, + 0x0E, 0x1B, 0x18, 0x7E, 0x18, 0x18, 0xD8, 0x70, + 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00, + 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00, + 0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00, + 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00, + 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, + 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x7E, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00, + 0xC6, 0xCC, 0xD8, 0x3E, 0x63, 0xCE, 0x98, 0x1F, + 0xC6, 0xCC, 0xD8, 0xF3, 0x67, 0xCF, 0x9F, 0x03, + 0x00, 0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x18, + 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, + 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00, + 0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0, + 0x00, 0xFE, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, + 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, + 0xFE, 0x66, 0x30, 0x18, 0x30, 0x66, 0xFE, 0x00, + 0x00, 0x00, 0x7E, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0, + 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC, + 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00, + 0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00, + 0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0, + 0x3C, 0x60, 0xC0, 0xFC, 0xC0, 0x60, 0x3C, 0x00, + 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, +}; + + +unsigned char font8x16[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xA5, + 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xDB, + 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, + 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, + 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, + 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, + 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, + 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, + 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, + 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, + 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x1E, 0x06, 0x0E, 0x1A, 0x78, 0xCC, + 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, + 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, + 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, + 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, + 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, + 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, + 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, + 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, + 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, + 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, + 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, + 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, + 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, + 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, + 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, + 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, + 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, + 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, + 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, + 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, + 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, + 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, + 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, + 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, + 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x06, + 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, + 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, + 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, + 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, + 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, + 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, + 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, + 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, + 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, + 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, + 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, + 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, + 0xD6, 0xFE, 0xEE, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, + 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, + 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, + 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, + 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, + 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, + 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, + 0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, + 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, + 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6, + 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, + 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, + 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, + 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, + 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, + 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, + 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, + 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, + 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, + 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x42, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, + 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x6C, 0x00, 0xFE, 0x62, 0x60, 0x68, 0x78, + 0x68, 0x60, 0x62, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, + 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, + 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, + 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xC6, 0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x42, 0x99, 0xA5, 0xA1, + 0xA5, 0x99, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, + 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, + 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1E, 0x36, 0x66, 0xC6, 0xC6, 0xFE, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x62, 0x62, 0x60, 0x7C, 0x66, + 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, + 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x62, 0x62, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0xFF, 0xC3, 0x81, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, + 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xD6, 0xD6, 0x54, 0x54, 0x7C, 0x7C, + 0x54, 0xD6, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, + 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xCE, 0xCE, 0xD6, 0xE6, + 0xE6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x38, 0xC6, 0xC6, 0xCE, 0xCE, 0xD6, 0xE6, + 0xE6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, + 0x6C, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1E, 0x36, 0x66, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, + 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, + 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3C, 0x18, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0x7E, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, + 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xFE, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, + 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xFF, 0x03, 0x03, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0xB0, 0x30, 0x30, 0x3E, 0x33, + 0x33, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xF3, 0xDB, + 0xDB, 0xDB, 0xDB, 0xF3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x7C, 0x66, + 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x26, 0x3E, 0x26, + 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xCE, 0xDB, 0xDB, 0xDB, 0xFB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xCE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x3E, + 0x66, 0x66, 0x66, 0xE7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, + 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x3C, 0x60, 0x60, 0x7C, 0x66, + 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, + 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x32, 0x32, + 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x36, 0x36, + 0x66, 0x66, 0x66, 0xFF, 0xC3, 0xC3, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0x54, + 0x7C, 0x54, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x06, + 0x0C, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xCE, + 0xD6, 0xE6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x38, 0xC6, 0xC6, 0xCE, + 0xD6, 0xE6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x6C, 0x78, + 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x36, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, 0xFE, + 0xFE, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, + 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x5A, 0x18, + 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x7E, 0xDB, + 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, + 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xFE, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xC6, 0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xFE, 0x03, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0x30, + 0x3E, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, + 0xF6, 0xDE, 0xDE, 0xF6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, + 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x06, + 0x1E, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xDB, 0xDB, + 0xFB, 0xDB, 0xDB, 0xCE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xCC, 0xCC, + 0xFC, 0x6C, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/gui/font.cpp b/src/gui/font.cpp new file mode 100644 index 0000000..b398764 --- /dev/null +++ b/src/gui/font.cpp @@ -0,0 +1,467 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - font & font manager class impl. + * \file font.cpp + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include +#include + +#include +#include + +FontManager *guifonts = NULL; + +#define DFF_FIXED 0x0001 // font is fixed pitch +#define DFF_PROPORTIONAL 0x0002 // font is proportional pitch +#define DFF_ABCFIXED 0x0004 // font is an ABC fixed font +#define DFF_ABCPROPORTIONAL 0x0008 // font is an ABC pro-portional font +#define DFF_1COLOR 0x0010 // font is one color +#define DFF_16COLOR 0x0020 // font is 16 color +#define DFF_256COLOR 0x0040 // font is 256 color +#define DFF_RGBCOLOR 0x0080 // font is RGB color + +#ifdef WIN32 +#pragma pack(1) +#endif + +typedef struct FntHeader +{ + WORD ver; + DWORD size; + BYTE copy[60]; + WORD type; + WORD points; + WORD vres, hres; + WORD ascent; + WORD ilead, elead; + BYTE italic, underl, strike; + WORD weight; + BYTE charset; + WORD pixwidth, pixheight; + BYTE pitchfamily; + WORD avgwidth; + WORD maxwidth; + BYTE first, last, def, brk; + WORD widthbytes; + DWORD device, face, bitsptr, bits; + BYTE flags; +} ATTRIBUTE_PACKED FntHeader; + +#ifdef WIN32 +#pragma pack() +#endif + + +const int get_ith_font = 1; + +///////////////////////////////////////////////////////////////////////// + +Font::Font() +{ + num = 0; + data = NULL; + widths = NULL; + height = 0; + baseline = 0; + + unloaded = false; +} + +Font::~Font() +{ + Unload(); +} + +BOOL Font::Load() +{ + Unload(); + + if (name == NULL) + return FALSE; + FILE *fp = fopen(name, "rb"); + if (fp == FALSE) + { + msg_error("Font file '%s' not found.\n", name); + return FALSE; + } + WORD magic; + if (fread(&magic, sizeof(WORD), 1, fp) != 1) + { + msg_error("Cannot read from font file '%s'.\n", name); + return FALSE; + } + int base = 0; + if (magic == 0x5a4d) ///////////////////// .FON + { + fseek(fp, 0, SEEK_END); + DWORD siz = ftell(fp); + fseek(fp, 0x3c, SEEK_SET); + DWORD offs = 0; + int ret = fread(&offs, sizeof(DWORD), 1, fp); + if (ret != 1 || offs < 0x40 || offs >= siz) + { + msg_error("Cannot read .FON header for '%s'.\n", name); + return FALSE; + } + fseek(fp, offs, SEEK_SET); + WORD ne; + fread(&ne, sizeof(WORD), 1, fp); + if (ne != 0x454e) + { + msg_error("Unknown .FON format for '%s'.\n", name); + return FALSE; + } + fseek(fp, offs + 0x24, SEEK_SET); + WORD res_offs; + fread(&res_offs, sizeof(WORD), 1, fp); + if (res_offs >= siz) + { + return FALSE; + } + fseek(fp, offs + res_offs, SEEK_SET); + WORD res_shift; + fread(&res_shift, sizeof(WORD), 1, fp); + if (res_shift > 32) + { + return FALSE; + } + bool found = false; + for (int r = 0, f = 0; ; r++) + { + fseek(fp, offs + res_offs + 2 + r * 0x14, SEEK_SET); + WORD type; + fread(&type, sizeof(WORD), 1, fp); + if (type == 0) + break; + if (type == 0x8008) // get first font + { + fseek(fp, 6, SEEK_CUR); + WORD dir_offs; + fread(&dir_offs, sizeof(WORD), 1, fp); + base = dir_offs << res_shift; + found = true; + if (++f == get_ith_font) + { + break; + } + } + } + if (!found) + { + msg_error("No fonts found in .FON file '%s'.\n", name); + return FALSE; + } + } + ///////////////////// .FNT + FntHeader h; + fseek(fp, base, SEEK_SET); + if (fread((void *)&h, sizeof(h), 1, fp) != 1) + { + msg_error("Cannot read font header for '%s'\n", name); + return FALSE; + } + + int first = 0, last = 0, ver = 3, avgwidth = 0; + if (h.ver < 0x0100 || h.ver > 0x0300) + { + msg_error("Unknown font format for '%s'\n", name); + return FALSE; + } + if ((h.type & 1) == 1) + { + msg_error("Vector fonts not supported ('%s')\n", name); + return FALSE; + } + if (h.maxwidth > 64) + { + msg_error("Max. width for raster fonts supported is 64. ('%s')\n", name); + return FALSE; + } + /* + if ((h.flags & DFF_ABCFIXED) || (h.flags & DFF_ABCPROPORTIONAL)) + { + // skip ABC + fseek(fp, 3 * 2, SEEK_CUR); + } + if ((h.flags & DFF_1COLOR) != DFF_1COLOR) + { + // skip color offset + fseek(fp, 4, SEEK_CUR); + } + + //fseek(fp, 16, SEEK_CUR); + if ((h.flags & DFF_16COLOR) == DFF_16COLOR || + (h.flags & DFF_256COLOR) == DFF_256COLOR || + (h.flags & DFF_RGBCOLOR) == DFF_RGBCOLOR) + { + msg_error("Only black-white fonts supported."); + return FALSE; + } + */ + + num = h.last + 1; + if (num < 1) + { + msg_error("No characters found in font '%s'\n", name); + return FALSE; + } + if (num > 256) + { + msg_error("Font '%s' contains more than 256 characters (%d). Truncating...\n", + name, num); + num = 256; + } + + if (h.pixheight < 1 || h.pixheight > 255) + { + msg_error("Wrong font height %d for '%s'.\n", h.pixheight, name); + return FALSE; + } + height = h.pixheight; + baseline = h.ascent + 1; // we add 1 for underline distance! + if (baseline < 1) + baseline = 1; + if (baseline >= height) + baseline = height - 1; + first = h.first; + last = h.last; + ver = h.ver; + avgwidth = h.avgwidth; + + // reading chartable + int i; + widths = new int [num]; + if (widths == NULL) + return FALSE; + data = new ULONGLONG* [num]; + if (data == NULL) + return FALSE; + + data[0] = (ULONGLONG *)SPmalloc(num * height * sizeof(ULONGLONG)); + if (data[0] == NULL) + return FALSE; + + // temp allocs + int *off = new int [num]; + if (off == NULL) + return FALSE; + BYTE *tmpdata = new BYTE [height * 8]; + if (tmpdata == NULL) + { + delete [] off; + return FALSE; + } + + int num_allocs = 0; + for (i = 0; i < num; i++) + { + DWORD w = 0; + if (i >= first && i <= last) + { + if (fread(&w, 2, 1, fp) != 1) + w = 0; + if (ver == 0x0200) + { + WORD of; + if (fread(&of, 2, 1, fp) != 1) + off[i] = -1; + else + off[i] = of; + } else + { + if (fread(&(off[i]), 4, 1, fp) != 1) + off[i] = -1; + } + } else + off[i] = -1; + // skip too wide characters + if (w > 64 || off[i] <= 0) + w = 0; + widths[i] = w; + if (w > 0) + { + data[i] = data[0] + num_allocs * height; + num_allocs++; + + memset(data[i], 0, sizeof(ULONGLONG) * height); + } else if (i > 0) + data[i] = NULL; + } + + // now read symbols + for (i = 0; i < num; i++) + { + if (widths[i] < 1 || off[i] < 0) + continue; + ULONGLONG *d = data[i]; + if (d == NULL) + continue; + int numbytes = ((widths[i] + 7) / 8 + 1) / 2 * 2; + if (fseek(fp, off[i] + base, SEEK_SET) != 0) + continue; + if (fread(tmpdata, height * numbytes, 1, fp) != 1) + continue; + for (int j = 0; j < numbytes; j++) + { + for (int k = 0; k < height; k++) + { + ULONGLONG tmpd = tmpdata[j * height + k]; + for (int l = 0; l < 8; l++) + d[k] |= ((tmpd >> (7 - l)) & 1) << (j * 8 + l); + } + } + } + + delete [] tmpdata; + delete [] off; + + // fix space symbol + if (widths[32] == 0) + { + widths[32] = avgwidth; + data[32] = data[0] + num_allocs * height; + num_allocs++; + + for (i = 0; i < height; i++) + { + data[32][i] = 0; + } + } + + data[0] = (ULONGLONG *)SPrealloc(data[0], (num_allocs + 1) * height * sizeof(ULONGLONG)); + if (data[0] == NULL) + return FALSE; + for (int k = 1, na = 0; k < num; k++) + { + if (data[k] != NULL) + data[k] = data[0] + (na++) * height; + } + + +// msg("FONT %s loaded OK.\n", name); + + unloaded = false; + return TRUE; +} + +BOOL Font::Unload() +{ + if (data != NULL) + { + //for (int i = 0; i < num; i++) + // SPSafeDeleteArray(data[i]); + SPSafeFree(data[0]); + } + SPSafeDeleteArray(data); + SPSafeDeleteArray(widths); + num = 0; + + unloaded = true; + return TRUE; +} + + +/////////////////////////////////////////////////////////////////// + +FontManager::FontManager() +{ + fonthash.SetN(resource_num_hash); + def = NULL; +} + +FontManager::~FontManager() +{ + SPSafeDelete(def); +} + +Font *FontManager::GetFont(char *fname) +{ + if (fname == NULL || fname[0] == '\0') + return GetDefaultFont(); + + static Font testfont; + testfont.SetConstName(fname); + Font *fnt = fonthash.Get(testfont); + testfont.name = NULL; + if (fnt != NULL) + return fnt; + + fnt = new Font(); + fnt->SetName(fname); + if (!fnt->Load()) + { + delete fnt; + return NULL; + } + + fonthash.Add(fnt); + return fnt; +} + +Font *FontManager::GetDefaultFont() +{ + if (def != NULL) + return def; + if (console == NULL || console->cur_fnt == NULL) + { + msg_error("Default font not found.\n"); + return NULL; + } + def = new Font(); + if (def == NULL) + return NULL; + + def->num = 256; + def->height = console->font_height; + def->widths = new int [def->num]; + def->data = new ULONGLONG* [def->num]; + int chsiz = ((console->font_width + 7) / 8); + for (int i = 0; i < def->num; i++) + { + BYTE *d = console->cur_fnt + i * chsiz * def->height; + def->data[i] = new ULONGLONG [def->height]; + def->widths[i] = console->font_width; + int fw = console->font_width - 1; + for (int x = 0; x < def->height; x++) + { + def->data[i][x] = 0; + for (int k = 0; k < console->font_width; k++) + def->data[i][x] |= ((d[x] >> (fw - k)) & 1) << k; + } + } + return def; +} + +BOOL FontManager::ClearFontData() +{ + Font *cur = fonthash.GetFirst(); + while (cur != NULL) + { + cur->Unload(); + cur = fonthash.GetNext(*cur); + } + return TRUE; +} diff --git a/src/gui/font.h b/src/gui/font.h new file mode 100644 index 0000000..8e40465 --- /dev/null +++ b/src/gui/font.h @@ -0,0 +1,85 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - font & font manager class header file + * \file gui/font.h + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FONT_H +#define SP_FONT_H + +#include + +/// Font object +class Font : public Resource +{ +public: + /// ctor + Font(); + /// dtor + ~Font(); + + BOOL Load(); + BOOL Unload(); + +public: + /// number of characters + int num; + /// bit data (width=64 max.) [num][height] + ULONGLONG **data; + /// font char widths array + int *widths; + /// font height + int height; + /// font baseline + int baseline; + + bool unloaded; +}; + +/// Font manager +class FontManager +{ +public: + /// ctor + FontManager(); + /// dtor + ~FontManager(); + + Font *GetDefaultFont(); + + Font *GetFont(char *fname); + + // Clear font cache + BOOL ClearFontData(); + +public: + SPHashListAbstract fonthash; + Font *def; + +protected: + Font *LoadFont(char *fname); +}; + + +extern FontManager *guifonts; + + +#endif // of SP_FONT_H diff --git a/src/gui/giflib.cpp b/src/gui/giflib.cpp new file mode 100644 index 0000000..efcb277 --- /dev/null +++ b/src/gui/giflib.cpp @@ -0,0 +1,881 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - GIF (ani-gif) library source file + * \file giflib.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * Parts of the code taken from GIFLib, (C) Scott Heiman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include + +#include +#include + + +const BYTE IMAGESEP = 0x2C; +const BYTE EXTENSIONINTRODUCER = 0x21; +const BYTE EOGF = 0x3B; + +const BYTE GRAPHIC_CONTROL_LABEL = 0xF9; +const BYTE COMMENT_LABEL = 0xFE; +const BYTE PLAIN_TEXT_LABEL = 0x01; +const BYTE APPLICATION_EXTENSION_LABEL = 0xFF; + +char errormsg[256]; + +static void err(const char *str) +{ + if (str != errormsg) + strcpy(errormsg, str); + msg_error("Gif error: %s\n", str); +} + +/// inequality operator for ColorStruct +inline bool operator != (const ColorStruct &a, const ColorStruct &b) +{ + return (a.Red != b.Red || a.Green != b.Green || a.Blue != b.Blue); +} + +/// a nice, generic read function for binary files +template +bool SafeRead (T *data, unsigned int NumItems, FILE *file) +{ + if (fread((void *)data, sizeof(T), NumItems, file) != NumItems) + { + if (feof(file)) + err("Unexpected end-of-file in SafeRead"); + else + err("Failed to read data in SafeRead"); + return false; + } + return true; +} + +#if defined(__GNUC__) +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#define ATTRIBUTE_PACKED __attribute__ ((packed)) +#endif +#endif +#ifdef WIN32 +#pragma pack(1) +#define ATTRIBUTE_PACKED +#endif + + +typedef struct GraphicControlStruct +{ + BYTE BlockSize; + BYTE PackedField; + WORD DelayTime; + BYTE TransparentColorIndex; + BYTE BlockTerminator; +} ATTRIBUTE_PACKED GraphicControl; + +typedef struct LogicalScreenDescriptorStruct +{ + WORD Width; + WORD Height; + BYTE PackedField; // see comments above in LSDField + BYTE BackgroundColorIndex; + BYTE PixelAspectRatio; +} ATTRIBUTE_PACKED LSD; + +typedef struct ImageDescriptorStruct +{ + WORD Left; + WORD Top; + WORD Width; + WORD Height; + BYTE Field; // see comments above in IDField +} ATTRIBUTE_PACKED ImageDescriptor; + +typedef struct ApplicationExtensionStruct +{ + BYTE BlockSize; //should always be 11 + char Identifier[8]; + BYTE AuthenticationCode[3]; +} ATTRIBUTE_PACKED ApplicationExtension; + +typedef struct PlainTextStruct +{ + BYTE BlockSize; // should always be 12 + WORD TextGridLeftPosition; + WORD TextGridTopPosition; + WORD TextGridTopWidth; + WORD TextGridTopHeight; + BYTE CharacterCellWidth; + BYTE CharacterCellHeight; + BYTE TextForegroundColorIndex; + BYTE TextBackgroundColorIndex; +} ATTRIBUTE_PACKED PlainTextExtension; + + +#ifdef WIN32 +#pragma pack() +#endif + + +char *fname = NULL; +/// ReadFile opens a GIF and stores the information in memory +bool GIFData::ReadFile(const char *filename) +{ + FILE *file; + { + file = fopen(filename, "rb"); + if (file == NULL) + { + sprintf(errormsg, "Could not open %s", filename); + err(errormsg); + goto err; + } + + fname = (char *)filename; + // check for signature + if (!SafeRead(Version, 3, file)) + return false; + Version[3] = 0; + if (strcmp(Version, "GIF") != 0) + { + sprintf(errormsg, "%s is not a .GIF file", filename); + err(errormsg); + return false; + } + + // get Version + if (!SafeRead(Version, 3, file)) + return false; + + // extract LogicalScreenDescriptor + LSD lsd; + if (!SafeRead(&lsd, 1, file)) + return false; + GlobalWidth = lsd.Width; + GlobalHeight = lsd.Height; + PixelDepth = (BYTE)(((lsd.PackedField & 0x70)>>4) + 1); + + // get the global color table if 1 is present + if ((lsd.PackedField & 0x80) > 0) + { + GlobalNumColors = (WORD)(1 << (int)((lsd.PackedField & 0x07) + 1)); + GlobalColorTable = new ColorStruct[GlobalNumColors]; + if (GlobalColorTable == NULL) + { + err("Could not allocate memory for color table"); + return false; + } + + if (!SafeRead(GlobalColorTable, GlobalNumColors, file)) + return false; + BackgroundColorIndex = lsd.BackgroundColorIndex; + } + else + { + BackgroundColorIndex = 0;//-1; + GlobalNumColors = 0; + } + + // practice has shown that if (1 << PixelDepth) is < GlobalNumColors + // then PixelDepth needs to be corrected + if ((1 << PixelDepth) < GlobalNumColors) + { + if (GlobalNumColors < 5) + PixelDepth = 2; + else if (GlobalNumColors < 9) + PixelDepth = 3; + else if (GlobalNumColors < 17) + PixelDepth = 4; + else if (GlobalNumColors < 33) + PixelDepth = 5; + else if (GlobalNumColors < 65) + PixelDepth = 6; + else if (GlobalNumColors < 129) + PixelDepth = 7; + else + PixelDepth = 8; + } + // read images + BYTE DataByte; + if (!SafeRead(&DataByte, 1, file)) + return false; + while (DataByte != EOGF) + { + switch (DataByte) + { + case EXTENSIONINTRODUCER: + ReadExtension(file); + break; + case IMAGESEP: + if (!ReadImage(file)) + goto err; + break; + default: + /*err("Unknown instruction")*/; + } + if (!SafeRead(&DataByte, 1, file)) + // [bombur]: the file is broken but let's give it a chance... + break; + } + + + // if more than 1 image exists then remove unneeded images + /*vector::iterator image = Images.begin(); + + while (image != Images.end() && Images.size() > 1) + { + if (image->DelayTime == 0) + image = Images.erase(image); + else + image++; + }*/ + + if (numImages < 1) + goto err; + fclose(file); + return true; + } +err: + if (file != NULL) + { + fclose(file); + } + return false; +} + + +bool GIFData::ReadExtension(FILE *file) +{ + BYTE block; + BYTE data[256]; + + BYTE Label; + if (!SafeRead(&Label, 1, file)) + return false; + + switch (Label) + { + case GRAPHIC_CONTROL_LABEL: + { + GraphicControl GC; + UseGC = true; + if (!SafeRead(&GC, 1, file)) + return false; + TransparentColorFlag = (GC.PackedField & 0x01) > 0; + if (TransparentColorFlag) + TransparentColorIndex = GC.TransparentColorIndex; + DelayTime = (WORD)(10 * GC.DelayTime); + // [bombur]: I guess it's better... + if (DelayTime < 10) + DelayTime = 100; + DisposalMethod = (WORD)((GC.PackedField & 0x1C) >> 2); + break; + } + // comment labels are read, but ignored. + case COMMENT_LABEL: + if (!SafeRead(&block, 1, file)) + return false; + while (block != 0) + { + if (!SafeRead(data, (unsigned)block, file)) + return false; + if (!SafeRead(&block, 1, file)) + return false; + } + break; + // plain text labels are read, but ignored. + case PLAIN_TEXT_LABEL: + { + PlainTextExtension pte; + if (!SafeRead(&pte, 1, file)) + return false; + if (!SafeRead(&block, 1, file)) + return false; + while (block > 0) + { + //memset((void *)data, 0, 256); + if (!SafeRead(data, (unsigned)block, file)) + return false; + if (!SafeRead(&block, 1, file)) + return false; + } + break; + } + // application extension labels are read, but ignored. + case APPLICATION_EXTENSION_LABEL: + { + ApplicationExtension AE; + if (!SafeRead(&AE, 1, file)) + return false; + if (!SafeRead(&block, 1, file)) + return false; + while (block != 0) + { + if (!SafeRead(data, (unsigned)block, file)) + return false; + if (!SafeRead(&block, 1, file)) + return false; + } + break; + } + default: + /*err("Unknown Extension")*/; + } + return true; +} + + +GIFImage *GIFData::GetImage(int index) +{ + if (index < 0 || index >= (int)numImages) + { + err("Invalid index in GetImage()"); + return NULL; + } + + return Images[index]; +} + + +bool GIFData::ReadImage(FILE *file) +{ + ImageDescriptor id; + if (!SafeRead(&id, 1, file)) + return false; + + // [bombur]: check if file is corrupt + if (id.Left > 1000 || id.Top > 1000 || id.Width > 5000 || id.Height > 5000) + return false; + + GIFImage *image = new GIFImage(this, id.Left, id.Top, id.Width, id.Height, + PixelDepth, (id.Field & 0x40) > 0, + TransparentColorFlag && UseGC ? TransparentColorIndex : -1, + UseGC ? DelayTime : 0, DisposalMethod); + + //if a local color table is present, then read it in, otherwise copy + // the global color table. + if (id.Field & 0x80) + { + DWORD NC = 1 << ((id.Field & 0x07) + 1); + image->ReadColorTable(NC, file); + msg_error("Gif: Multiple palettes not supported for file %s\n", fname); + } + else + image->CopyColorTable(GlobalNumColors, GlobalColorTable); + + // decode the bits + if (image->ReadBits(file)) + { + + // save the image in the array + Images = (GIFImage **)SPrealloc((void *)Images, (numImages + 1) * sizeof(GIFImage *)); + Images[numImages] = image; + numImages++; + } + UseGC = false; + return true; +} + + +// GIFImage functions +GIFImage::GIFImage(const GIFImage &g) +{ + typedef BYTE *pUChar; + + ColorTable = NULL; + ppBits = NULL; + + Parent = g.Parent; + Left = g.Left; + Top = g.Top; + Height = g.Height; + Width = g.Width; + ImageHeight = g.ImageHeight; + ImageWidth = g.ImageWidth; + PixelDepth = g.PixelDepth; + ImagePixelDepth = g.ImagePixelDepth; + NumColors = g.NumColors; + ScanLineWidth = g.ScanLineWidth; + Interlaced = g.Interlaced; + DelayTime = g.DelayTime; + DisposalMethod = g.DisposalMethod; + BackgroundColorIndex = g.BackgroundColorIndex; + TransparentColorIndex = g.TransparentColorIndex; + + // copy color table if 1 exists + if (g .ColorTable) + { + ColorTable = new ColorStruct[NumColors]; + if (ColorTable == NULL) + err("Could not allocate memory for color table in copy ctor"); + else + memcpy((void *)ColorTable, (void *)g.ColorTable, + NumColors*sizeof(ColorStruct)); + } + + // copy bits + // assumes complete memory has been allocated for g.ppBits + if (g.ppBits) + { + ppBits = new pUChar[ImageHeight]; + if (ppBits != NULL) + { + MakeBitmap(); + memcpy((void *)ppBits[0], (void *)g.ppBits[0], ImageWidth*ImageHeight); + } + } + else + { + ppBits = NULL; + } +} + + +GIFImage::GIFImage(GIFData *parent, int l, int t, int w, int h, int pd, + bool inter, int TCIndex, int dt, WORD dm, + bool /*bmp*/) +{ + Parent = parent; + Left = (WORD)l; + Top = (WORD)t; + Width = (WORD)w; + Height = (WORD)h; + PixelDepth = (BYTE)pd; + ImageWidth = Parent->GlobalWidth; + ImageHeight = Parent->GlobalHeight; + Interlaced = inter; + ppBits = 0; + ColorTable = 0; + DelayTime = (WORD)dt; + TransparentColorIndex = (short)TCIndex; + BackgroundColorIndex = 0;//-1; + DisposalMethod = dm; + + NumColors = (WORD)(1 << pd); + ColorTable = new ColorStruct[NumColors]; + if (ColorTable == NULL) + err("Could not allocate memory for color table in ctor"); + else + memset((void *)ColorTable, 0, NumColors*sizeof(ColorStruct)); + + // calculate the width of a scan line in bytes + switch (PixelDepth) + { + case 1: + ImagePixelDepth = 1; + break; + case 2: + case 3: + case 4: + ImagePixelDepth = 4; + break; + default: + ImagePixelDepth = 8; + break; + } + + ScanLineWidth = (ImageWidth * ImagePixelDepth + 7) / 8; + // [bombur]: we don't need pitch align + /* + if (ScanLineWidth % 4) + ScanLineWidth += (4 - ScanLineWidth % 4); + */ + + // allocate memory for bitmap pixels + typedef BYTE *pUChar; + ppBits = new pUChar[ImageHeight]; + if (ppBits == NULL) + err("Could not allocate memory for bitmap in ctor"); +} + +/// dtor +GIFImage::~GIFImage() +{ + if (ColorTable) + delete [] ColorTable; + + if (ppBits) + { + if (ppBits[0] != NULL) + delete [] ppBits[0]; + delete [] ppBits; + } +} + +BYTE *GIFImage::GetScanLine(int index) const +{ + if (index < 0 || index >= (int)Height) + { + // err("Illegal index in GIFImage::GetScanLine"); + return 0; + } + + return ppBits[index]; +} + +// taken out from ReadBits() to fit the stack... +#define MaxStackSize 4096 +#define NullCode (-1) + +static short prefix[MaxStackSize]; + +static BYTE block_size, data_size, first, packet[256], + pixel_stack[MaxStackSize+1], suffix[MaxStackSize], *top_stack, + *q_buffer; + + +/// This function decodes the GIF data. The logic was taken from +/// the ImageMagick source code. ;-) +bool GIFImage::ReadBits(FILE *file) +{ + DWORD dbgcnt; + int index, available, bits, code, clear, code_mask, code_size, + count, end_of_information, in_code, old_code; + + register DWORD i; + + register BYTE *c, *q; + + register DWORD datum; + + // [bombur]: + int pitch = ImageWidth;// (ImageWidth + 7)/8*8; + + // Initialize GIF data stream decoder. + q_buffer = new BYTE[Height*pitch]; + if (q_buffer == NULL) + { + err("Memory Allocation Error in ReadBits"); + return false; + } + + dbgcnt = 0; + if (!SafeRead(&data_size, 1, file)) + return false; + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = NullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) + { + prefix[code] = 0; + suffix[code] = (BYTE) code; + } + // Decode GIF pixel stream. + datum = 0; + bits = 0; + c = 0; + count = 0; + first = 0; + top_stack = pixel_stack; + q = q_buffer; + + int qline = 0; + while (q < q_buffer + Height*pitch) + { + if (top_stack == pixel_stack) + { + if (bits < code_size) + { + // Load bytes until there is enough bits for a code. + if (count == 0) + { + // Read a new data block. + if (!SafeRead(&block_size, 1, file)) + return false; + count = block_size; + if (!SafeRead(packet, (unsigned)block_size, file)) + return false; + if (count <= 0) + break; + c = packet; + } + datum += (*c) << bits; + bits += 8; + c++; + count--; + continue; + } + // Get the next code. + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + // Interpret the code + if ((code > available) || (code == end_of_information)) + break; + if (code == clear) + { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = NullCode; + continue; + } + if (old_code == NullCode) + { + *top_stack++ = suffix[code]; + old_code = code; + first = (BYTE) code; + continue; + } + in_code = code; + if (code >= available) + { + *top_stack++ = first; + code = old_code; + } + while (code >= clear) + { + *top_stack++ = suffix[code]; + code = prefix[code]; + } + first = suffix[code]; + // Add a new string to the string table, + if (available >= MaxStackSize) + break; + *top_stack++ = first; + prefix[available] = (short)old_code; + suffix[available] = first; + available++; + if (((available & code_mask) == 0) && (available < MaxStackSize)) + { + code_size++; + code_mask+=available; + } + old_code = in_code; + } + // Pop a pixel off the pixel stack. + top_stack--; + index = (*top_stack); + *q = (BYTE)index; + q++; + qline++; + if (qline >= (int)Width) + { + q += pitch - Width; + qline = 0; + } + dbgcnt++; + } + + if (dbgcnt < Width * Height) + { + delete [] q_buffer; + err("Corrupt .GIF image"); + return false; + } + + if (Interlaced) + { + static const int + interlace_rate[4] = { 8, 8, 4, 2 }, + interlace_start[4] = { 0, 4, 2, 1 }; + + BYTE *i_buffer = new BYTE[Height*pitch]; + if (!i_buffer) + { + delete [] q_buffer; + err("Memory allocation error"); + return false; + } + + memcpy((void *)i_buffer, (void *)q_buffer, Height*pitch); + memset((void *)q_buffer, 0, Height*pitch); + + int row = 0; + for (int pass = 0; pass < 4; pass++) + { + DWORD j = interlace_start[pass]; + while (j < Height) + { + BYTE *p = i_buffer + row * pitch; + q = q_buffer + j * pitch; + memcpy((void *)q, (void *)p, Width); + row++; + j += interlace_rate[pass]; + } + } + + delete [] i_buffer; + } + + // create the array to store the entire unpacked image + BYTE **unpackedBits = ppBits; + + // if this is not the 1st image... + if (Parent->numImages > 0) + { + int last; + for (last = Parent->numImages - 1; last >= 0 && Parent->Images[last]->DisposalMethod == 3; last--) + ; + GIFImage *lastImage = Parent->Images[last]; + + // unpackedBits is initialized to the previous image + lastImage->GetUnpackedBitArray(unpackedBits); + if (lastImage->DisposalMethod == 2) + { + for (DWORD i = lastImage->Top; i < lastImage->Height + lastImage->Top; i++) + { + BYTE *p = unpackedBits[i]; + memset((void *)(p+lastImage->Left), BackgroundColorIndex, + lastImage->Width); + } + } + } + else /*if (UseBitmap)*/ + { + memset((void *)unpackedBits[0], BackgroundColorIndex, pitch * ImageHeight); + } + + // add the subimage + q = q_buffer; + // if no transparent pixels are present then overwrite the existing image... + if (TransparentColorIndex == -1) + { + for (i = Top; i < Top + Height; i++) + { + memcpy((void *)(unpackedBits[i]+Left), (void *)q, Width); + q += pitch; + } + } + // ... otherwise, only overwrite non-transparent pixels + else + { + for (i = Top; i < Top + Height; i++) + { + BYTE *oldImage = unpackedBits[i]+Left; + /* + if (UseBitmap)*/ + { + for (BYTE *newImage = q; newImage < q + Width; newImage++, oldImage++) + { + if ((short)(*newImage) != TransparentColorIndex) + *oldImage = *newImage; + } + } + /*else + memcpy((void *)oldImage, (void *)q, Width); + */ + q += pitch; + } + } + + delete [] q_buffer; + + // read the terminator + SafeRead(&block_size, 1, file); + /* + if (block_size != 0) + err("Terminator was not found in the expected location"); + */ + return true; +} + +/// Read the color table from the GIF file and copy it to the bitmap (if one is present) +void GIFImage::ReadColorTable(DWORD NC, FILE *file) +{ + NumColors = (WORD)NC; + SafeRead(ColorTable, NC, file); +/* + // mess with transparency & background if we are creating a bitmap + // set the transparent color to the screen color if this is the first image + if (TransparentColorIndex > -1 && Parent->numImages == 0) + ColorTable[TransparentColorIndex] = Parent->ScreenColor; + + // if the color table contains the screen color then set the + // background color index to the appropriate value; otherwise, + // set it to the parent's background color index + bool NotFound = true; + + while (++BackgroundColorIndex < NumColors && NotFound) + NotFound = ColorTable[BackgroundColorIndex] != Parent->ScreenColor; + + if (NotFound) + BackgroundColorIndex = (int)Parent->BackgroundColorIndex; + else + BackgroundColorIndex--; +*/ + MakeBitmap(); +} + + +/// This function copies the global color table to the image color table and +/// create the bitmap. +void GIFImage::CopyColorTable(WORD GlobalNumColors, ColorStruct *GlobalColorTable) +{ + NumColors = GlobalNumColors; + memcpy((void *)ColorTable, (void *)GlobalColorTable, + GlobalNumColors*sizeof(ColorStruct)); + + // mess with transparency & background if we are creating a bitmap + // set the transparent color to the screen color if this is the first image + // [bombur]: + if (TransparentColorIndex > -1 ) // && Parent->numImages == 0 + ColorTable[TransparentColorIndex] = Parent->ScreenColor; +/* + // if the color table contains the screen color then set the + // background color index to the appropriate value; otherwise, + // set it to the parent's background color index + bool NotFound = true; + while (++BackgroundColorIndex < NumColors && NotFound) + NotFound = ColorTable[BackgroundColorIndex] != Parent->ScreenColor; + + if (NotFound) + BackgroundColorIndex = (int)Parent->BackgroundColorIndex; + else + BackgroundColorIndex--; +*/ + + MakeBitmap(); +} + +/// This function creates the bitmap. This function assumes that the color +/// table has already been stored in memory. +bool GIFImage::MakeBitmap() +{ + ppBits[0] = new BYTE[ImageWidth*ImageHeight]; + if (ppBits[0] == NULL) + { + err("Memory Allocation Error"); + return false; + } + + for (DWORD i = 1; i < ImageHeight; i++) + ppBits[i] = ppBits[i-1] + ImageWidth; + + return true; +} + +void GIFImage::GetUnpackedBitArray(BYTE **bits) +{ + if (bits == NULL) + return; + for (DWORD i = 0; i < ImageHeight; i++) + { + memcpy((void *)(bits[i]), (void *)(ppBits[i]), ImageWidth); + } +} + diff --git a/src/gui/giflib.h b/src/gui/giflib.h new file mode 100644 index 0000000..c083836 --- /dev/null +++ b/src/gui/giflib.h @@ -0,0 +1,245 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - GIF (ani-gif) library header file + * \file giflib.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * Parts of the code taken from GIFLib, (C) Scott Heiman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_GIFLIB_H +#define SP_GIFLIB_H + +#include + +#ifdef WIN32 +#pragma pack(1) +#endif + +typedef struct ColorStruct +{ + BYTE Red; + BYTE Green; + BYTE Blue; + +} ATTRIBUTE_PACKED ColorStruct; + +#ifdef WIN32 +#pragma pack() +#endif + +class GIFData; + +/// Contains GIF image +class GIFImage +{ +public: + friend class GIFData; + /// ctor + GIFImage() + { + Parent = 0; + Left = Top = 0; + Height = Width = 0; + ImagePixelDepth = PixelDepth = 0; + NumColors = 0; + ScanLineWidth = 0; + ColorTable = 0; + ppBits = 0; + Interlaced = false; + TransparentColorIndex = BackgroundColorIndex = -1; + DelayTime = 0; + DisposalMethod = 0; + } + + /// ctor used by GIFData to create a GIFImage + GIFImage (GIFData *parent, int l, int t, int w, int h, int pd, + bool inter, int TCIndex = -1, int dt = 0, WORD dm = 0, + bool bmp = true); + /// copy ctor + GIFImage (const GIFImage &g); + /// dtor + ~GIFImage(); + + /// Access functions + WORD GetWidth() const { return (WORD)ImageWidth; } + WORD GetHeight() const { return (WORD)ImageHeight; } + BYTE BitsPerPixel() const { return PixelDepth; } + BYTE ImageBitsPerPixel() const { return ImagePixelDepth; } + WORD GetNumColors() const { return NumColors; } + ColorStruct *GetColorTable() const { return ColorTable; } + + BYTE *GetData() { BYTE *d = ppBits[0]; ppBits[0] = NULL; return d; } + + BYTE *GetScanLine (int index) const; + DWORD GetScanLineWidth() const { return ScanLineWidth; } + WORD GetTimeDelay() const { return DelayTime; } + + void GetUnpackedBitArray (BYTE **bits); + + short GetBackgroundColorIndex() const { return BackgroundColorIndex; } + short GetTransparentColorIndex() const { return TransparentColorIndex; } + + /// Access functions used by the multimedia timer callback function + BOOL EraseBkgnd() const { return DisposalMethod == 2 ? TRUE : FALSE; } + +protected: + /// the GIFData object that owns this image + GIFData *Parent; + /// bytes needed to store 1 line of data in an HBITMAP + DWORD ScanLineWidth; + /// Width and height of the subimage in pixels + DWORD Height; + DWORD Width; + /// Width and height of the merged image in pixels + DWORD ImageHeight; + DWORD ImageWidth; + /// the location of the upper, left corner of the image relative to Image[0] + WORD Left; + WORD Top; + /// the number of bits needed to define all colors in the image + BYTE PixelDepth; + /// the number of bits needed to define all of the colors in the HBITMAP. + /// must be 1, 4, or 8 (I have not seen any 24 or 32 bit GIFs) + BYTE ImagePixelDepth; + /// number of colors in the local color table + WORD NumColors; + /// the local color table + ColorStruct *ColorTable; + /// an 2-D array of bits that define the image. If UseBitmap == true then + /// the array is dimensioned as required by an HBITMAP; otherwise, the + /// dimensions are ppBits[ImageHeight][ImageWidth] + BYTE **ppBits; + /// true if the image is interlaced + bool Interlaced; + /// the index in the local color table that is transparent. + /// set to -1 if there is no transparent color + short TransparentColorIndex; + /// background color index + /// set to -1 if there is no background color + short BackgroundColorIndex; + /// the time that this image is displayed if it is an animated GIF + WORD DelayTime; + /// the disposal method. Determines how the image is drawn if the GIF + /// is animated. + /// DisposalMethod Action + /// 0 Nothing special. Treat as DisposalMethod == 1 + /// 1 image remains in place + /// 2 background is restored before merging w/ nxt img + /// 3 image is retained and merged with next image + WORD DisposalMethod; + + /// create hBitmap + bool MakeBitmap(); + /// used to copy the GIFData's global color table into the local color table + void CopyColorTable (WORD GlobalNumColors, + ColorStruct *GlobalColorTable); + /// reads the local color table from the GIF file + void ReadColorTable (DWORD NC, FILE *file); + /// decodes the bit data from the GIF file + bool ReadBits (FILE *file); +}; + +/// Contains entire GIF data (from file) +class GIFData +{ +public: + /// ctor + GIFData() + { + Images = (GIFImage **)SPmalloc(sizeof(GIFImage *)); + numImages = 0; + GlobalWidth = GlobalHeight = 0; + PixelDepth = 0; + GlobalNumColors = 0; + GlobalColorTable = 0; + TransparentColorIndex = BackgroundColorIndex = 0; + TransparentColorFlag = false; + UseGC = false; + DelayTime = 0; + ScreenColor.Red = 0/*GetRValue( color )*/; + ScreenColor.Green = 0/*GetGValue( color )*/; + ScreenColor.Blue = 0/*GetBValue( color )*/; + } + + /// dtor + ~GIFData() + { + if (GlobalColorTable != NULL) + delete [] GlobalColorTable; + for (int i = 0; i < numImages; i++) + delete Images[i]; + SPfree(Images); + } + + /// access functions + WORD GetWidth() const { return GlobalWidth; } + WORD GetHeight() const { return GlobalHeight; } + BYTE BitsPerPixel() const { return PixelDepth; } + BYTE GetNumColors() const { return (char)GlobalNumColors; } + ColorStruct *GetColorTable() const { return GlobalColorTable; } + + GIFImage *GetImage(int index); + DWORD GetNumImages() const { return numImages; } + + /// reads a GIF and stores the contents in memory + bool ReadFile (const char *filename); + + friend class GIFImage; + +protected: + /// the height and width of the largest image in the group + WORD GlobalHeight; + WORD GlobalWidth; + /// the number of pixels needed to access all colors used by the image + BYTE PixelDepth; + /// the number of colors in the global color table + WORD GlobalNumColors; + /// the global color table + ColorStruct *GlobalColorTable; + /// the version number + char Version[4]; + /// the index to the background color + BYTE BackgroundColorIndex; + /// an array to hold all of the images in the GIF + GIFImage **Images; + int numImages; + /// --- the following variables are used to hold graphic control information + /// true if a graphic control extension was be used with the next image + bool UseGC; + /// the index to the transparent color + BYTE TransparentColorIndex; + /// true if a transparent color is present + bool TransparentColorFlag; + /// the time that an image will be displayed + WORD DelayTime; + /// the disposal method for the next GIF image + WORD DisposalMethod; + /// screen color + ColorStruct ScreenColor; + + /// reads GIF extensions + bool ReadExtension (FILE *file); + /// reads the color table and bits for each image + bool ReadImage (FILE *file); +}; + + +#endif // of SP_GIFLIB_H diff --git a/src/gui/image.cpp b/src/gui/image.cpp new file mode 100644 index 0000000..41e463c --- /dev/null +++ b/src/gui/image.cpp @@ -0,0 +1,304 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - image class impl. + * \file image.cpp + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include +#include + +ImageManager *guiimg = NULL; + + +ImageData::ImageData() +{ + data = NULL; + dt = NULL; + num_frames = 0; + width = height = 0; + total_time = 0; + + unloaded = false; +} + +ImageData::~ImageData() +{ + Unload(); +} + +BOOL ImageData::Load() +{ + Unload(); + GIFData *gifdata = new GIFData(); + if (gifdata == NULL) + return FALSE; + if (!gifdata->ReadFile(name)) + { + delete gifdata; + return FALSE; + } + + data = (BYTE **)SPmalloc(sizeof(BYTE *) * (gifdata->GetNumImages() + 1)); + +#if 0 + msg("+LOAD %s...\n", name); + SPMemoryManager &memManager = SPMemoryManager::GetHandle(); + FILE *fp = fopen("sp_log.txt", "at"); + memManager.DumpLastAlloc(fp); + fclose(fp); +#endif + + + if (data == NULL || gifdata->GetNumImages() < 1) + { + msg_error("Image: image data not found for %s.\n", name); + delete gifdata; + return FALSE; + } + num_frames = gifdata->GetNumImages(); + width = gifdata->GetWidth(); + height = gifdata->GetHeight(); + dt = new int [num_frames]; + total_time = 0; + for (int i = 0; i < (int)gifdata->GetNumImages(); i++) + { + GIFImage *img = gifdata->GetImage(i); + if (img == NULL) + { + delete gifdata; + return FALSE; + } + if (img->GetWidth() != gifdata->GetWidth() || img->GetHeight() != gifdata->GetHeight()) + { + delete gifdata; + return FALSE; + } + data[i] = img->GetData(); + dt[i] = img->GetTimeDelay(); + total_time += dt[i]; + } + delete gifdata; + +// msg("GIF %s loaded OK.\n", name); + + unloaded = false; + return TRUE; +} + +BOOL ImageData::Unload() +{ + if (data != NULL) + { +#if 0 +msg("-UNLOAD %s...\n", name); +#endif + for (int i = 0; i < num_frames; i++) + { + SPSafeDeleteArray(data[i]); + } + } + SPSafeFree(data); + SPSafeDeleteArray(dt); + unloaded = true; + return TRUE; +} + +////////////////////////////////////////////////////////////////////////// + +Image::Image() +{ + img = NULL; + flipx = flipy = false; + cur_frame = 0; + last_time = -1; + + updateobj = NULL; +} + +Image::~Image() +{ +} + +bool Image::SetSource(char *fname) +{ + img = guiimg->GetImageData(fname); + if (img == NULL) + return false; + SetWidth(img->width); + SetHeight(img->height); + auto_width = img->width; + auto_height = img->height; + dirty = true; + return true; +} + +void Image::SetFlipX(bool fx) +{ + flipx = fx; + dirty = true; +} + +void Image::SetFlipY(bool fy) +{ + flipy = fy; + dirty = true; +} + +bool Image::Update(int curtime) +{ + int oldcf = cur_frame; + if (last_time < 0 || img == NULL || img->total_time == 0) + { + cur_frame = 0; + last_time = curtime; + } else + { + int dt = (curtime - last_time) % img->total_time; + for (int i = 0, cf = cur_frame; i < img->num_frames; i++) + { + cf = (cf + 1) % img->num_frames; + int d = img->dt[cf]; + if (d > dt) + break; + cur_frame = cf; + last_time = curtime; + dt -= d; + if (dt <= 0) + break; + } + } + + if (cur_frame != oldcf) + dirty = true; + return true; +} + +bool Image::Update(Context *context, int x1, int y1, int x2, int y2) +{ + if (img == NULL || context == NULL) + return false; + if (img->unloaded) + { + if (!img->Load()) + return false; + } + if (img->data == NULL || img->num_frames < 1) + return false; + if (cur_frame < 0) + cur_frame = 0; + cur_frame %= img->num_frames; + + if (img->width < 1 || img->height < 1) + return false; + if (x1 >= img->width) + return false; + if (y1 >= img->height) + return false; + if (x2 >= img->width) x2 = img->width - 1; + if (y2 >= img->height) y2 = img->height - 1; + + BYTE *sd = img->data[cur_frame] + (flipy ? img->height-y1-1 : y1) * img->width + (flipx ? x2 : x1); + BYTE *dd = context->data + y1 * context->pitch + x1; + int len = x2 - x1 + 1; + int iw = (flipy) ? -img->width : img->width; + + if (flipx) + { + for (int iy = y1; iy <= y2; iy++) + { + register BYTE *sdi = sd; + register BYTE *ddi = dd; + for (int ix = len - 1; ix >= 0; ix--) + *ddi++ = *--sdi; + dd += context->pitch; + sd += iw; + } + } else + { + for (int iy = y1; iy <= y2; iy++) + { + memcpy(dd, sd, len); + dd += context->pitch; + sd += iw; + } + } + + return true; +} + +////////////////////////////////////////////////////////////////////////// + +ImageManager::ImageManager() +{ + datahash.SetN(resource_num_hash); +} + +ImageManager::~ImageManager() +{ +} + +BOOL ImageManager::ClearImageData() +{ + ImageData *cur = datahash.GetFirst(); + while (cur != NULL) + { + cur->Unload(); + cur = datahash.GetNext(*cur); + } + return TRUE; +} + +ImageData *ImageManager::GetImageData(char *fname) +{ + // first, search the hash + static ImageData testdata; + testdata.SetConstName(fname); + ImageData *dat = datahash.Get(testdata); + testdata.name = NULL; + if (dat != NULL) + return dat; + ImageData *newdat = new ImageData(); + newdat->SetName(fname); + if (!newdat->Load()) + { + delete newdat; + return NULL; + } + + datahash.Add(newdat); + + return newdat; +} + +void ImageManager::DumpImages() +{ + ImageData *cur = datahash.GetFirst(); + while (cur != NULL) + { + if (!cur->unloaded) + msg("IMAGE %s\n", cur->name); + cur = datahash.GetNext(*cur); + } +} diff --git a/src/gui/image.h b/src/gui/image.h new file mode 100644 index 0000000..8dd70c7 --- /dev/null +++ b/src/gui/image.h @@ -0,0 +1,111 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - image class header file + * \file image.h + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_IMAGE_H +#define SP_IMAGE_H + +#include +#include + +/// Image data class (incl. animation frames) +class ImageData : public Resource +{ +public: + /// ctor + ImageData(); + /// dtor + ~ImageData(); + + BOOL Load(); + BOOL Unload(); + +public: + BYTE **data; // BYTE *data[num_frames]; + int num_frames; + int width, height; // all frames have the same size + + /// delta time for each frame, in milliseconds + int *dt; + int total_time; + + bool unloaded; +}; + +/// Image window class +class Image : public Window +{ +public: + /// ctor + Image(); + /// dtor + virtual ~Image(); + + virtual bool Update(int curtime); + + /// Update part of image (rect in LOCAL window coords) + virtual bool Update(Context *context, int x1, int y1, int x2, int y2); + +public: + + bool SetSource(char *fname); + + void SetFlipX(bool); + void SetFlipY(bool); + + /// Pointer to the image data used + ImageData *img; + /// Current frame index + int cur_frame; + int last_time; + bool flipx, flipy; + + /// update queue object (used by script) + friend class ScriptTimerObject; + ScriptTimerObject *updateobj; +}; + +/// Image manager class (contains all image data and other info) +class ImageManager +{ +public: + /// ctor + ImageManager(); + /// dtor + ~ImageManager(); + +public: + + // Clear image cache + BOOL ClearImageData(); + + ImageData *GetImageData(char *fname); + + SPHashListAbstract datahash; + + void DumpImages(); +}; + +extern ImageManager *guiimg; + +#endif // of SP_IMAGE_H diff --git a/src/gui/jpeg.cpp b/src/gui/jpeg.cpp new file mode 100644 index 0000000..11b22a2 --- /dev/null +++ b/src/gui/jpeg.cpp @@ -0,0 +1,819 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - JPEG file display source file + * \file jpeg.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include "jpeg.h" + +//#define JPEG_USE_MMAP + +const int YUV_BUFFER_MARGIN = 16; +const int EXIF_JPEG_MARKER = JPEG_APP0 + 1; +const char *EXIF_IDENT_STRING = "Exif\000\000"; +enum +{ + JPEG_BIG_ENDIAN = 0, + JPEG_LITTLE_ENDIAN +}; + +static BYTE *Y = NULL, *UV = NULL; +static int cur_w = 0, cur_h = 0; +static jmp_buf setjmp_buffer; +static FILE *jpegfile = NULL; + +const int frame_width = 720, frame_height = 480; + +/// \WARNING! Works only on little-endian systems! +static inline WORD jpeg_exif_get16(BYTE *ptr, DWORD endian) +{ + if (endian == JPEG_BIG_ENDIAN) + return (WORD)((ptr[0] << 8) | ptr[1]); + return (WORD)((ptr[1] << 8) | ptr[0]); +} + +/// \WARNING! Works only on little-endian systems! +static inline DWORD jpeg_exif_get32(BYTE *ptr, DWORD endian) +{ + if (endian == JPEG_BIG_ENDIAN) + return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; + return (ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]; +} + + +void jpeg_dealloc() +{ + if (Y != NULL) + { +#ifdef JPEG_USE_MMAP + munmap(Y - YUV_BUFFER_MARGIN, cur_w * cur_h + YUV_BUFFER_MARGIN); +#else + SPfree(Y - YUV_BUFFER_MARGIN); +#endif + Y = NULL; + } + if (UV != NULL) + { +#ifdef JPEG_USE_MMAP + munmap(UV - YUV_BUFFER_MARGIN, cur_w * cur_h / 2 + YUV_BUFFER_MARGIN); +#else + SPfree(UV - YUV_BUFFER_MARGIN); +#endif + UV = NULL; + } +} + +BOOL jpeg_alloc_yuv(int w, int h) +{ + if (w != cur_w || h != cur_h || Y == NULL || UV == NULL) + { + jpeg_dealloc(); +#ifdef JPEG_USE_MMAP + Y = (BYTE *)mmap(0, (w * h) + YUV_BUFFER_MARGIN, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); + UV = (BYTE *)mmap(0, (w * h / 2) + YUV_BUFFER_MARGIN, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); +#else + Y = (BYTE *)SPmalloc((w * h) + YUV_BUFFER_MARGIN); + UV = (BYTE *)SPmalloc((w * h / 2) + YUV_BUFFER_MARGIN); +#endif + if (Y == NULL || UV == NULL) + return FALSE; + Y += YUV_BUFFER_MARGIN; + UV += YUV_BUFFER_MARGIN; + cur_w = w; + cur_h = h; + } + return TRUE; +} + +BOOL jpeg_init() +{ + return TRUE; +} + +BOOL jpeg_deinit() +{ + return TRUE; +} + +//jmp_buf jpg_err; +bool was_error = false; + +void jpeg_error_exit (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + // Create the message + (*cinfo->err->format_message) (cinfo, buffer); + msg_error("Jpeg error: %s\n", buffer); + was_error = true; + longjmp(setjmp_buffer, 1); +} + +BOOL jpeg_show (char *filename, int hscale, int vscale, int offsx, int offsy, int *param_rot) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + JSAMPARRAY scanline; + int nb_lines_buffer, nb_lines_read, line_size; + int i, j, k; + +#ifdef WIN32 + if (filename[0] == '/') filename++; +#endif + + bool is_external_img = (memcmp(filename, "/img/", 5) != 0 && memcmp(filename, "img/", 4) != 0); + + int frame_left, frame_top, frame_right, frame_bottom; + khwl_get_window_frame(&frame_left, &frame_top, &frame_right, &frame_bottom); + int frame_width, frame_height; + + KHWL_WINDOW maxdst; + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(maxdst), &maxdst); + + frame_width = ::frame_width; + frame_height = ::frame_height; + + int frame_w = frame_right - frame_left + 1; + int frame_h = frame_bottom - frame_top + 1; + + bool no_rescale = frame_w == frame_width && frame_h == frame_height, partial_rescale = false; +#if 0 + if (no_rescale && is_external_img) + { + khwl_display_clear(); + } +#endif + + was_error = false; + + jpegfile = fopen(filename, "rb"); + if (jpegfile == NULL) + { + printf("Can't open source file %s\n", filename); + return FALSE; + } + + cinfo.err = jpeg_std_error(&jerr); + cinfo.err->error_exit = jpeg_error_exit; + + if (setjmp(setjmp_buffer)) + { + fclose(jpegfile); + return FALSE; + } + + jpeg_create_decompress(&cinfo); + jpeg_save_markers(&cinfo, EXIF_JPEG_MARKER, 0xffff); + jpeg_stdio_src(&cinfo, jpegfile); + jpeg_read_header(&cinfo, TRUE); + + const WORD orientation_tag_id = 0x112; + + // get Exif data (orientation) + int rot = param_rot != NULL ? *param_rot : 0; + for (jpeg_saved_marker_ptr mark = cinfo.marker_list; mark != NULL; mark = mark->next) + { + switch (mark->marker) + { + case EXIF_JPEG_MARKER: + if (mark->data_length < (6+4*3+2+12)) // 1 tag at least... + break; + if (memcmp (mark->data, EXIF_IDENT_STRING, 6) != 0) + break; + + BYTE *d = mark->data + 6; + for (DWORD i = 6; i < 16; d++, i++) + { + DWORD endian = 0; + static const char leth[] = {0x49, 0x49, 0x2a, 0x00}; + static const char beth[] = {0x4d, 0x4d, 0x00, 0x2a}; + + if (memcmp (d, leth, 4) == 0) + endian = JPEG_LITTLE_ENDIAN; + else if (memcmp (d, beth, 4) == 0) + endian = JPEG_BIG_ENDIAN; + else + continue; + + i += jpeg_exif_get32(d + 4, endian); + d = mark->data + i; + if ((i + 2) > mark->data_length) + return 0; + WORD tags = jpeg_exif_get16(d, endian); + if ((i + 2 + tags * 12) > mark->data_length) + return 0; + for (d += 2; tags--; d += 12) + { + WORD tag_id = jpeg_exif_get16(d, endian); + if (tag_id == orientation_tag_id) + { + WORD type = jpeg_exif_get16(d + 2, endian); + DWORD count = jpeg_exif_get32(d + 4, endian); + + if (type == 3 && count == 1) + { + int orientation = jpeg_exif_get16(d + 8, endian); + if (rot < 0) // set only if rotation is undefined + { + switch (orientation) + { + case 1: rot = 0; break; + case 3: rot = 2; break; + case 6: rot = 1; break; + case 8: rot = 3; break; + } + } + break; + } + } + } + break; + } + break; + } + } + if (rot < 0 || rot > 3) + rot = 0; + + cinfo.out_color_space = JCS_YCbCr; + cinfo.dct_method = JDCT_IFAST; + cinfo.scale_num = 1; + cinfo.quantize_colors = FALSE; + + // Set it to 2 to use down-scaling for all big JPEGs (more quality), or set to 1 for default up-scaling. + int mul = settings_get(SETTING_HQ_JPEG) ? 2 : 1; + //if (rot == 0) mul = 1; + + int rotated_frame_w = (rot == 0 || rot == 2) ? frame_w : frame_h; + int rotated_frame_h = (rot == 0 || rot == 2) ? frame_h : frame_w; + int rotated_frame_width = (rot == 0 || rot == 2) ? frame_width : frame_height; + int rotated_frame_height = (rot == 0 || rot == 2) ? frame_height : frame_width; + + int scalefac = 1; + while (scalefac < 32 && (((int)cinfo.image_width / (mul*scalefac)) > rotated_frame_w + || ((int)cinfo.image_height / (mul*scalefac)) > rotated_frame_h)) + { + scalefac = scalefac * 2; + } + if (scalefac > 8) + { + scalefac = 8; + if ((int)cinfo.image_width / scalefac > rotated_frame_width || + (int)cinfo.image_height / scalefac > rotated_frame_height) + { + return FALSE; + } + } + + cinfo.scale_denom = scalefac; + + jpeg_start_decompress(&cinfo); + + if (was_error) + return FALSE; + + if ((int)cinfo.output_width > rotated_frame_width * mul || (int)cinfo.output_height > rotated_frame_height * mul + || (int)cinfo.output_width < 1 || (int)cinfo.output_height < 1) + { + return FALSE; + } + if ((int)cinfo.output_width > rotated_frame_width || (int)cinfo.output_height > rotated_frame_height) + { + no_rescale = false; + partial_rescale = true; + } + + int scaled_width = (int)cinfo.image_width; + int scaled_height = (int)cinfo.image_height; + + int rescale_width, rescale_height; + if (!no_rescale) + { + if ((int)cinfo.output_width < 3 || (int)cinfo.output_height < 3) + return FALSE; + rescale_width = rotated_frame_h * scaled_width / scaled_height; + rescale_height = rotated_frame_w * scaled_height / scaled_width; + + if (rescale_width > rotated_frame_w) + rescale_width = rotated_frame_w; + else + rescale_height = rotated_frame_h; + + while (scaled_width < rescale_width / 5 || scaled_height < rescale_height / 5) + { + rescale_width /= 2; + rescale_height /= 2; + } + + + scaled_width = rescale_width; + scaled_height = rescale_height; + } else + { + rescale_width = cinfo.output_width; + rescale_height = cinfo.output_height; + } + + if (!jpeg_alloc_yuv(frame_width, frame_height)) + { + msg("jpeg: Memory ERROR!\n"); + msg_sysinfo(); + jpeg_dealloc(); + return FALSE; + } + + line_size = cinfo.output_width * cinfo.output_components; + nb_lines_buffer = 1; + + scanline = (JSAMPARRAY) SPmalloc(nb_lines_buffer * sizeof(JSAMPROW)); + if (scanline == NULL) + return FALSE; + for (i = 0; i < nb_lines_buffer; i++) + { + scanline[i] = (JSAMPROW) SPmalloc((line_size + 1) * sizeof(JSAMPLE)); + if (scanline[i] == NULL) + return FALSE; + } + + int jmul, imgwidth, imgheight, imglf = 0, imgtp = 0; + int maxj = rotated_frame_h; + + imgtp = MAX((rotated_frame_w - rescale_width) / 2, 0); + imglf = MAX((rotated_frame_h - rescale_height) / 2, 0); + + if (partial_rescale) + { + imgwidth = (int)cinfo.output_width; + imgheight = (int)cinfo.output_height; + } else + { + if (rot == 0 || rot == 2) + { + imgwidth = MIN((int)cinfo.output_width, frame_width); + imgheight = MIN((int)cinfo.output_height, frame_height); + } else + { + imgwidth = MIN((int)cinfo.output_width, frame_height); + imgheight = MIN((int)cinfo.output_height, frame_width); + } + } + + if (rot == 0 || rot == 3) + { + j = 0; + jmul = 1; + } + else + { + j = maxj - 1; + jmul = -1; + } + + int jd = 0, oldj = -1, jstep = 1; + bool read_scan = true; + + for (i = 0; j >= 0 && j < maxj; ) + { + int imgw = 0; + if (i >= imglf && i < imgheight + imglf) + { + if (read_scan) + { + nb_lines_read = jpeg_read_scanlines(&cinfo, scanline, nb_lines_buffer); + if (nb_lines_read < 1) + break; + } + imgw = imgwidth; + } + if (read_scan) + i++; + + BYTE *y; + BYTE *uv; + JSAMPROW sl = *scanline; + + if (j != oldj) + { + if (rot == 0) + { + y = Y + j * frame_width; + uv = UV + j / 2 * frame_width; + BYTE *scl = sl; + for (k = 0; k < imgtp; k++) + { + *y++ = 0; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv++ = 128; + *uv++ = 128; + } + } + if (no_rescale) + { + for (int kk = 0; kk < imgw; kk++, k++) + { + *y++ = *scl; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv++ = scl[1]; + *uv++ = scl[2]; + } + scl += 3; + } + } else + { + int d = 0; + for (int kk = 0; kk < imgw; k++) + { + *y++ = *scl; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv++ = scl[1]; + *uv++ = scl[2]; + } + d += imgw; + while (d >= rescale_width) + { + scl += 3; + kk++; + d -= rescale_width; + } + } + } + for ( ; k < frame_w; k++) + { + *y++ = 0; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv++ = 128; + *uv++ = 128; + } + } + } + else if (rot == 1) + { + y = Y + j; + uv = UV + j; + for (k = 0; k < imgtp; k++) + { + *y = 0; + y += frame_width; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = 128; + *(uv+1) = 128; + uv += frame_width; + } + } + if (no_rescale) + { + for (int kk = 0; kk < imgw; kk++, k++) + { + BYTE *scl = sl + kk * 3; + *y = *scl; + y += frame_width; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = scl[1]; + *(uv+1) = scl[2]; + uv += frame_width; + } + } + } else + { + BYTE *scl = sl; + int d = 0; + for (int kk = 0; kk < imgw; k++) + { + *y = *scl; + y += frame_width; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = scl[1]; + *(uv+1) = scl[2]; + uv += frame_width; + } + d += imgw; + while (d >= rescale_width) + { + scl += 3; + kk++; + d -= rescale_width; + } + } + } + for ( ; k < frame_h; k++) + { + *y = 0; + y += frame_width; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = 128; + *(uv+1) = 128; + uv += frame_width; + } + } + } + else if (rot == 2) + { + y = Y + (j) * frame_width + frame_w; + uv = UV + (j / 2) * frame_width + frame_w; + + k = frame_w; + + for ( ; k > frame_w - imgtp; ) + { + k--; + *--y = 0; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *--uv = 128; + *--uv = 128; + } + } + + if (no_rescale) + { + BYTE *scl = sl; + for (int kk = 0; kk < imgw; kk++ ) + { + k--; + *--y = *scl; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *--uv = scl[2]; + *--uv = scl[1]; + } + scl += 3; + } + } else + { + BYTE *scl = sl; + int d = 0; + for (int kk = 0; kk < imgw; ) + { + *--y = *scl; + k--; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *--uv = scl[2]; + *--uv = scl[1]; + } + d += imgw; + while (d >= rescale_width) + { + scl += 3; + kk++; + d -= rescale_width; + } + } + } + + for (; k > 0; k--) + { + *--y = 0; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *--uv = 128; + *--uv = 128; + } + } + + } + else if (rot == 3) + { + y = Y + j; + uv = UV + j; + int iw = (int)cinfo.output_width; + for (k = frame_h; k > frame_h - imgtp; ) + { + *y = 0; + y += frame_width; + k--; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = 128; + *(uv+1) = 128; + uv += frame_width; + } + } + if (no_rescale) + { + BYTE *scl = sl + (iw - 1) * 3; + for (int kk = iw - 1; kk >= (iw - imgw); kk--) + { + *y = *scl; + y += frame_width; + k--; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = scl[1]; + *(uv+1) = scl[2]; + uv += frame_width; + } + scl -= 3; + } + } else + { + BYTE *scl = sl + (iw - 1) * 3; + int d = 0; + for (int kk = iw - 1; kk >= (iw - imgw); ) + { + *y = *scl; + y += frame_width; + k--; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = scl[1]; + *(uv+1) = scl[2]; + uv += frame_width; + } + d += imgw; + while (d >= rescale_width) + { + scl -= 3; + kk--; + d -= rescale_width; + } + } + } + for (; k > 0; ) + { + *y = 0; + y += frame_width; + k--; + if (((j & 1) == 0) && ((k & 1) == 0)) + { + *uv = 128; + *(uv+1) = 128; + uv += frame_width; + } + } + } + oldj = j; + } + + if (!no_rescale) + { + if (imgw == 0) + jstep = 1; + else + { + jstep--; + read_scan = false; + if (jstep <= 0) + { + jstep = 0; + jd += rescale_height; + while (jd >= imgheight) + { + jd -= imgheight; + jstep++; + } + } + if (jstep <= 1) + read_scan = true; + } + } else + { + // if no rescale, then we use hardware scaling + //if (i >= imgheight) + // break; + } + + if (jstep > 0) + { + j += jmul; + } + } + + for (i = 0; i < nb_lines_buffer; i++) + SPfree(scanline[i]); + SPfree(scanline); + + KHWL_YUV_FRAME f; + + if (no_rescale || partial_rescale) + { + int scaleto_width, scaleto_height; + if (partial_rescale) + { + scaleto_width = frame_w; + scaleto_height = frame_h; + } else + { + scaleto_width = MAX((int)cinfo.output_width, frame_width / 5); + scaleto_height = MAX((int)cinfo.output_height, frame_height / 4); +#if 0 + if (scaleto_width > scaleto_height) + scaleto_height = scaleto_width * frame_height / frame_width; + else + scaleto_width = scaleto_height * frame_width / frame_height; +#endif + if (rot == 1 || rot == 3) + Swap(scaleto_width, scaleto_height); + + } + + KHWL_VIDEOMODE vmode = KHWL_VIDEOMODE_NORMAL; + // for external images, use aspect-ratio correction + if (is_external_img) + { + int tvtype = settings_get(SETTING_TVTYPE); + if (tvtype == 2 || tvtype == 3) + vmode = KHWL_VIDEOMODE_WIDE; + } else + vmode = KHWL_VIDEOMODE_NONE; + khwl_setvideomode(vmode, FALSE); + khwl_set_window_zoom(KHWL_ZOOMMODE_YUV); + khwl_set_window(scaleto_width, scaleto_height, + frame_width, frame_height, hscale, vscale, offsx, offsy); + } + + int maxi = frame_width * (frame_bottom - frame_top + 1); + int chunk_n = (frame_right - frame_left + 1); + int chunk_width = frame_width; + if (no_rescale) + { + chunk_n *= 32; + chunk_width *= 32; + } + + int offs = frame_width * frame_top + frame_left; + int offs2 = frame_width / 2 * frame_top + frame_left; + int maxi2 = maxi / 2; + + for (i = 0; i < maxi; i += chunk_width) + { + f.y_buf = Y + i; + f.y_offs = offs + i; + f.y_num = maxi - i < chunk_n ? maxi - i : chunk_n; + f.uv_buf = NULL; + f.uv_offs = 0; + f.uv_num = 0; + khwl_displayYUV(&f); + + if (i < maxi2) + { + f.y_buf = NULL; + f.y_offs = 0; + f.y_num = 0; + f.uv_buf = UV + i; + f.uv_offs = offs2 + i; + f.uv_num = maxi2 - i < chunk_n ? maxi2 - i : chunk_n; + khwl_displayYUV(&f); + } + + } + +#ifdef WIN32 + khwl_osd_update(); +#endif + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + fclose(jpegfile); + + fflush(stdout); + + jpeg_dealloc(); + + if (param_rot != NULL) + *param_rot = rot; + + return TRUE; +} diff --git a/src/gui/jpeg.h b/src/gui/jpeg.h new file mode 100644 index 0000000..d3639d9 --- /dev/null +++ b/src/gui/jpeg.h @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - JPEG file display header file + * \file jpeg.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_JPEG_H +#define SP_JPEG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/// Initialize (allocate buffers) +BOOL jpeg_init(); + +/// Deinitialize (release buffers) +BOOL jpeg_deinit(); + +/// Display JPEG file +/// rotation is auto-detected and returned, if Exif data is present. +BOOL jpeg_show (char *filename, int hscale = 0, int vscale = 0, int offsx = 0, int offsy = 0, int *rot = NULL); + + +#ifdef __cplusplus +} +#endif + +#endif // of SP_JPEG_H diff --git a/src/gui/rect.cpp b/src/gui/rect.cpp new file mode 100644 index 0000000..0ba69a5 --- /dev/null +++ b/src/gui/rect.cpp @@ -0,0 +1,417 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - rectangle (incl. rounded) class impl. + * \file rect.cpp + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include + + +//////////////////////////////////////////////////////// + +// some inline helper functions for painting the 'context': + +static inline void Scanline(Context *context, int x1, int x2, int y, int bkcolor) +{ + if (x2 >= x1) + memset(context->data + y * context->pitch + x1, bkcolor, x2 - x1 + 1); +} + +static inline void SmallPoint1(Context *context, int x, int y, int color, int) +{ + *(context->data + y * context->pitch + x) = (char)color; +} + +// right-bottom +static inline void BigPoint1(Context *context, int x, int y, int color, int width) +{ + for (int i = 0; i <= width; i++) + Scanline(context, x, x + width, y++, color); +} + +// right-top +static inline void BigPoint2(Context *context, int x, int y, int color, int width) +{ + for (int i = 0; i <= width; i++) + Scanline(context, x, x + width, y--, color); +} + +// left-bottom +static inline void BigPoint3(Context *context, int x, int y, int color, int width) +{ + for (int i = 0; i <= width; i++) + Scanline(context, x - width, x, y++, color); +} + +// left-top +static inline void BigPoint4(Context *context, int x, int y, int color, int width) +{ + for (int i = 0; i <= width; i++) + Scanline(context, x - width, x, y--, color); +} + +static inline void Rect(Context *context, int x1, int y1, int x2, int y2, int bkcolor) +{ + if (x2 >= x1) + { + for (int i = y1; i <= y2; i++) + Scanline(context, x1, x2, i, bkcolor); + } +} + +///////////////////////////////////////////////////////////////////////// + +// modified painting function for clipped case: + +static inline void ClippedScanline(Context *context, int x1, int x2, int y, int bkcolor, + int cx1, int cy1, int cx2, int cy2) +{ + if (y >= cy1 && y <= cy2) + { + x1 = MAX(x1, cx1); + x2 = MIN(x2, cx2); + if (x2 >= x1) + memset(context->data + y * context->pitch + x1, bkcolor, x2 - x1 + 1); + } +} + +static inline void ClippedSmallPoint1(Context *context, int x, int y, int color, int, + int cx1, int cy1, int cx2, int cy2) +{ + if (x >= cx1 && y >= cy1 && x <= cx2 && y <= cy2) + *(context->data + y * context->pitch + x) = (char)color; +} + +// right-bottom +static inline void ClippedBigPoint1(Context *context, int x, int y, int color, int width, + int cx1, int cy1, int cx2, int cy2) +{ + for (int i = 0; i <= width; i++) + ClippedScanline(context, x, x + width, y++, color, cx1, cy1, cx2, cy2); +} + +// right-top +static inline void ClippedBigPoint2(Context *context, int x, int y, int color, int width, + int cx1, int cy1, int cx2, int cy2) +{ + for (int i = 0; i <= width; i++) + ClippedScanline(context, x, x + width, y--, color, cx1, cy1, cx2, cy2); +} + +// left-bottom +static inline void ClippedBigPoint3(Context *context, int x, int y, int color, int width, + int cx1, int cy1, int cx2, int cy2) +{ + for (int i = 0; i <= width; i++) + ClippedScanline(context, x - width, x, y++, color, cx1, cy1, cx2, cy2); +} + +// left-top +static inline void ClippedBigPoint4(Context *context, int x, int y, int color, int width, + int cx1, int cy1, int cx2, int cy2) +{ + for (int i = 0; i <= width; i++) + ClippedScanline(context, x - width, x, y--, color, cx1, cy1, cx2, cy2); +} + +////////////////////////////////////////////////////////////// + +/// Paints filled circle slices for rounded rect. +static inline void DrawRounds(Context *context, int center_x1, int center_y1, int center_x2, int center_y2, + int radius, int linewidth, int color, int bkcolor) +{ + int x; + int y = radius; + // circle decision variable + int d = 3 - (radius << 1); + // treat the line width as the additive to the scan coordinates + linewidth--; + + // draw filled part (generate scan sections of the circle) + if (bkcolor >= 0) + { + for (x = 0; x <= y; x++) + { + // draw the y-dependent scans + if (bkcolor >= 0) + { + Scanline(context, center_x1 - y, center_x1, center_y2 + x, bkcolor); + Scanline(context, center_x2, center_x2 + y, center_y2 + x, bkcolor); + if (x >= 0) + { + Scanline(context, center_x1 - y, center_x1, center_y1 - x, bkcolor); + Scanline(context, center_x2, center_x2 + y, center_y1 - x, bkcolor); + } + } + + // iterate the differential circle drawing code + if (d < 0) + { + d += (x << 2) + 6; + } + else + { + d += ((x - y) << 2) + 10; + + // draw the x-dependent scans - done not so frequently + if (x != y && bkcolor >= 0) + { + Scanline(context, center_x1 - x, center_x1, center_y1 - y, bkcolor); + Scanline(context, center_x2, center_x2 + x, center_y1 - y, bkcolor); + + Scanline(context, center_x1 - x, center_x1, center_y2 + y, bkcolor); + Scanline(context, center_x2, center_x2 + x, center_y2 + y, bkcolor); + } + + y--; + } + } + // restore values + y = radius; + d = 3 - (radius << 1); + } + + // draw border frame + if (color >= 0) + { + for (x = 0; x <= y; x++) // Generate scan sections of the circle + { + +#define CIRCLE_POINTS(size, dir1, dir2, dir3, dir4) \ + size##Point##dir1(context, center_x1 - x, center_y1 - y, color, linewidth); \ + size##Point##dir1(context, center_x1 - y, center_y1 - x, color, linewidth); \ + size##Point##dir2(context, center_x1 - x, center_y2 + y, color, linewidth); \ + size##Point##dir2(context, center_x1 - y, center_y2 + x, color, linewidth); \ + size##Point##dir3(context, center_x2 + x, center_y1 - y, color, linewidth); \ + size##Point##dir3(context, center_x2 + y, center_y1 - x, color, linewidth); \ + size##Point##dir4(context, center_x2 + x, center_y2 + y, color, linewidth); \ + size##Point##dir4(context, center_x2 + y, center_y2 + x, color, linewidth); + + if (linewidth < 1) + { + CIRCLE_POINTS(Small,1,1,1,1); + } else + { + CIRCLE_POINTS(Big,1,2,3,4); + } + + // Iterate the differential circle drawing code + if (d < 0) + d += (x << 2) + 6; + else + { + d += ((x - y) << 2) + 10; + y--; + } + } + } +} + +/// Paints clipped filled circle slices for rounded rect. +static inline void DrawClippedRounds(Context *context, int center_x1, int center_y1, int center_x2, int center_y2, + int radius, int linewidth, int color, int bkcolor, + int x1, int y1, int x2, int y2) +{ + int x; + int y = radius; + + // circle decision variable + int d = 3 - (radius << 1); + // treat the line width as the additive to the scan coordinates + linewidth--; + + // draw filled part (generate scan sections of the circle) + if (bkcolor >= 0) + { + for (x = 0; x <= y; x++) + { + // draw the y-dependent scans + if (bkcolor >= 0) + { + ClippedScanline(context, center_x1 - y, center_x1, center_y2 + x, bkcolor, x1, y1, x2, y2); + ClippedScanline(context, center_x2, center_x2 + y, center_y2 + x, bkcolor, x1, y1, x2, y2); + if (x >= 0) + { + ClippedScanline(context, center_x1 - y, center_x1, center_y1 - x, bkcolor, x1, y1, x2, y2); + ClippedScanline(context, center_x2, center_x2 + y, center_y1 - x, bkcolor, x1, y1, x2, y2); + } + } + + // iterate the differential circle drawing code + if (d < 0) + { + d += (x << 2) + 6; + } + else + { + d += ((x - y) << 2) + 10; + + // draw the x-dependent scans - done not so frequently + if (x != y && bkcolor >= 0) + { + ClippedScanline(context, center_x1 - x, center_x1, center_y1 - y, bkcolor, x1, y1, x2, y2); + ClippedScanline(context, center_x2, center_x2 + x, center_y1 - y, bkcolor, x1, y1, x2, y2); + + ClippedScanline(context, center_x1 - x, center_x1, center_y2 + y, bkcolor, x1, y1, x2, y2); + ClippedScanline(context, center_x2, center_x2 + x, center_y2 + y, bkcolor, x1, y1, x2, y2); + } + + y--; + } + } + // restore values + y = radius; + d = 3 - (radius << 1); + } + + // draw border frame + if (color >= 0) + { + for (x = 0; x <= y; x++) // Generate scan sections of the circle + { + +#define CLIPPED_CIRCLE_POINTS(size, dir1, dir2, dir3, dir4) \ + Clipped##size##Point##dir1(context, center_x1 - x, center_y1 - y, color, linewidth, x1, y1, x2, y2); \ + Clipped##size##Point##dir1(context, center_x1 - y, center_y1 - x, color, linewidth, x1, y1, x2, y2); \ + Clipped##size##Point##dir2(context, center_x1 - x, center_y2 + y, color, linewidth, x1, y1, x2, y2); \ + Clipped##size##Point##dir2(context, center_x1 - y, center_y2 + x, color, linewidth, x1, y1, x2, y2); \ + Clipped##size##Point##dir3(context, center_x2 + x, center_y1 - y, color, linewidth, x1, y1, x2, y2); \ + Clipped##size##Point##dir3(context, center_x2 + y, center_y1 - x, color, linewidth, x1, y1, x2, y2); \ + Clipped##size##Point##dir4(context, center_x2 + x, center_y2 + y, color, linewidth, x1, y1, x2, y2); \ + Clipped##size##Point##dir4(context, center_x2 + y, center_y2 + x, color, linewidth, x1, y1, x2, y2); + + if (linewidth < 1) + { + CLIPPED_CIRCLE_POINTS(Small,1,1,1,1); + } else + { + CLIPPED_CIRCLE_POINTS(Big,1,2,3,4); + } + + // Iterate the differential circle drawing code + if (d < 0) + d += (x << 2) + 6; + else + { + d += ((x - y) << 2) + 10; + y--; + } + } + } +} + +///////////////////////////////////////////////////////////////////////// + +Rectangle::Rectangle() +{ + round = 0; + linewidth = 1; + + color = gui.GetColor(); + bkcolor = gui.GetBkColor(); +} + +void Rectangle::SetLineWidth(int lw) +{ + linewidth = lw; + dirty = true; +} + +void Rectangle::SetRound(int r) +{ + round = r; + dirty = true; +} + +void Rectangle::SetColor(int c) +{ + if (c > 255) + c = -1; + color = c; + dirty = true; +} +void Rectangle::SetBkColor(int bc) +{ + if (bc > 255) + bc = -1; + bkcolor = bc; + dirty = true; +} + +bool Rectangle::Update(Context *context, int x1, int y1, int x2, int y2) +{ + if (context == NULL) + return false; + // fix some values for invalid rects + int lw = color >= 0 ? MIN(linewidth, MIN(width, height) / 2) : 0; + int clr = lw > 0 ? color : -1; + int rnd = MIN(round, lw <= 4 ? MIN(width, height) / 2 : MIN(width, height) / 2 - lw); + + // draw rounded parts + if (rnd > 1) + { + if (x1 == 0 && y1 == 0 && x2 == width - 1 && y2 == height - 1) + DrawRounds(context, rnd, rnd, width - 1 - rnd, + height - 1 - rnd, rnd, lw, clr, bkcolor); + else + DrawClippedRounds(context, rnd, rnd, width - 1 - rnd, + height - 1 - rnd, rnd, lw, clr, bkcolor, + x1, y1, x2, y2); + + // draw upper and lower filled rect. parts + if (bkcolor >= 0) + { + Rect(context, MAX(rnd, x1), MAX(lw, y1), + MIN(width - 1 - rnd, x2), MIN(rnd - 1, y2), bkcolor); + Rect(context, MAX(rnd, x1), MAX(height - rnd, y1), + MIN(width - 1 - rnd, x2), MIN(height - 1 - lw, y2), bkcolor); + } + } + + // draw top-left borders + if (clr >= 0) + { + Rect(context, MAX(rnd, x1), MAX(0, y1), + MIN(width - 1 - rnd, x2), MIN(lw - 1, y2), clr); + Rect(context, MAX(0, x1), MAX(MAX(lw, rnd), y1), + MIN(lw - 1, x2), MIN(height - 1 - MAX(lw, rnd), y2), clr); + } + + // draw main filled rect + if (bkcolor >= 0) + Rect(context, MAX(lw, x1), MAX(MAX(lw, rnd), y1), + MIN(width - 1 - lw, x2), MIN(height - 1 - MAX(lw, rnd), y2), bkcolor); + + // draw bottom-right borders + if (clr >= 0) + { + Rect(context, MAX(width - lw, x1), MAX(MAX(lw, rnd), y1), + MIN(width - 1, x2), MIN(height - 1 - MAX(lw, rnd), y2), clr); + Rect(context, MAX(rnd, x1), MAX(height - lw, y1), + MIN(width - 1 - rnd, x2), MIN(height - 1, y2), clr); + } + + return true; +} diff --git a/src/gui/rect.h b/src/gui/rect.h new file mode 100644 index 0000000..b80752a --- /dev/null +++ b/src/gui/rect.h @@ -0,0 +1,52 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - rectangle (incl. rounded) class header file + * \file rect.h + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_RECT_H +#define SP_RECT_H + +#include + +/// Rectangle (incl. rounded) window class +class Rectangle : public Window +{ +public: + /// ctor + Rectangle(); + /// dtor + virtual ~Rectangle() {} + + /// Update part of rect in LOCAL coords + virtual bool Update(Context *context, int x1, int y1, int x2, int y2); + + void SetLineWidth(int); + void SetRound(int); + void SetColor(int); + void SetBkColor(int); + +public: + int round, linewidth; + int color, bkcolor; +}; + +#endif // of SP_RECT_H diff --git a/src/gui/res.cpp b/src/gui/res.cpp new file mode 100644 index 0000000..efd1690 --- /dev/null +++ b/src/gui/res.cpp @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - abstract resource class impl. + * \file res.cpp + * \author bombur + * \version 0.1 + * \date 14.10.2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#define _BSD_SOURCE // needed for strdup() +#include + +#include +#include + +void Resource::SetName(char *n) +{ + SPSafeFree(name); + if (n == NULL) + { + name = NULL; + namehash = 0; + return; + } + name = SPstrdup(n); + constname = false; + namehash = SPStringHashFunc(name, resource_num_hash); +} + +void Resource::SetConstName(const char *n) +{ + SPSafeFree(name); + constname = true; + if (n == NULL) + { + name = NULL; + namehash = 0; + return; + } + name = (char *)n; + namehash = SPStringHashFunc(name, resource_num_hash); +} + diff --git a/src/gui/res.h b/src/gui/res.h new file mode 100644 index 0000000..eb25b24 --- /dev/null +++ b/src/gui/res.h @@ -0,0 +1,93 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - abstract resource class header file + * \file res.h + * \author bombur + * \version 0.1 + * \date 14.10.2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_RES_H +#define SP_RES_H + + +const int resource_num_hash = 347; + +/// Loadable resource +class Resource +{ +public: + /// ctor + Resource() + { + prev = NULL; + next = NULL; + + name = NULL; + namehash = 0; + + index = -1; + temporary = true; + constname = true; + } + + /// dtor + virtual ~Resource() + { + if (!constname) + SPSafeFree(name); + } + + /// compare + template + bool operator == (const T & r) + { + if (name == NULL || r.name == NULL) + return false; + return strcmp(name, r.name) == 0; + } + + inline operator DWORD () const + { + return namehash; + } + + const Resource * const GetItem() const + { + return this; + } + + /// Set variable name & calc. hash + void SetName(char *n); + /// Set constant name & calc. hash + /// Use this for const.strings to avoid strdup(). + void SetConstName(const char *n); + +public: + bool temporary, constname; + char *name; + DWORD namehash; + + int index; + + // linked list support + Resource *prev, *next; +}; + + +#endif // of SP_RES_H diff --git a/src/gui/text.cpp b/src/gui/text.cpp new file mode 100644 index 0000000..f974637 --- /dev/null +++ b/src/gui/text.cpp @@ -0,0 +1,305 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - text object class impl. + * \file rect.cpp + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include +#include + + +static BYTE row_buf[720]; + +///////////////////////////////////////////////////////////////////////// + +#define TEXT_OUTLINE_IF(rdd, c, wdd, bc) { if (*(rdd) != c) *(wdd) = bc; } +#define TEXT_OUTLINE(wdd, bc) { *(wdd) = bc; } + +Text::Text() +{ + font = NULL; + style = TEXT_STYLE_NORMAL; + color = gui.GetColor(); + bkcolor = gui.GetBkColor(); + text_align = TEXT_ALIGN_LEFT; + transparent = true; +} + +bool Text::Update(Context *context, int x1, int y1, int x2, int y2) +{ + if (context == NULL || font == NULL) + return false; + + if (font->unloaded) + { + if (!font->Load()) + return false; + } + + BYTE *d, *pd, *nd, *rd; + int clrs[2]; + BYTE clrs2; + if (style == TEXT_STYLE_OUTLINE) + { + if (x1 > 0) + x1--; + if (y1 > 0) + y1--; + x2--; + y2--; + d = context->data + (y1 + 1) * context->pitch + (x1 + 1); + + pd = d - context->pitch; + nd = d + context->pitch; + rd = row_buf; + + clrs[0] = -1; + clrs2 = (BYTE)bkcolor; + } + else + { + d = context->data + y1 * context->pitch + x1; + + clrs[0] = bkcolor; + clrs2 = '\0'; + } + clrs[1] = color; + + for (int iy = y1; iy <= y2; iy++) + { + int row = iy / font->height; + if (row < 0 || row >= rows.GetN()) + continue; + int offy = iy % font->height; + int ix, w = 0, cw = 0, ich = -1; + BYTE ch = 0; + ULONGLONG *s = NULL; + int row_offs, xx1 = x1; + if (text_align == TEXT_ALIGN_LEFT) + row_offs = 0; + else if (text_align == TEXT_ALIGN_CENTER) + { + row_offs = MAX(((x2 - x1 + 1) - rows[row].width) / 2, 0); + if (clrs[0] >= 0) + memset(d, clrs[0], row_offs); + xx1 = MAX(x1 - row_offs, 0); + } + else + { + row_offs = MAX(((x2 - x1 + 1) - rows[row].width), 0); + if (clrs[0] >= 0) + memset(d, clrs[0], row_offs); + xx1 = MAX(x1 - row_offs, 0); + } + int xx2 = x2 - row_offs; + BYTE *dd, *pdd, *ndd, *rdd; + BYTE prev_cc, prev_rdd; + dd = d + row_offs; + if (style == TEXT_STYLE_OUTLINE) + { + pdd = pd + row_offs; + ndd = nd + row_offs; + rdd = rd + row_offs; + prev_cc = 0; + prev_rdd = 0; + } + for (ix = 0; ix <= xx2; ix++) + { + if (ix >= w) + { +onemore: + ch = text[rows[row].off + (++ich)]; + if (ch == '\0' || ch == '\n') + break; + cw = font->widths[ch]; + if (cw < 1) + goto onemore; + w += cw; + s = font->data[ch]; + } + + if (ix >= xx1) + { + int c; + if (style == TEXT_STYLE_UNDERLINE && offy == font->baseline) + c = clrs[1]; + else + c = clrs[((s[offy] >> (cw - w + ix)) & 1)]; + if (c >= 0) + { + BYTE cc = (BYTE)c; + *dd = cc; + if (clrs2 > 0) // outline + { + if (prev_rdd != cc) + TEXT_OUTLINE(pdd-1, clrs2); + TEXT_OUTLINE_IF(rdd, cc, pdd, clrs2); + TEXT_OUTLINE_IF(rdd+1, cc, pdd+1, clrs2); + + TEXT_OUTLINE(ndd-1, clrs2); + TEXT_OUTLINE(ndd, clrs2); + TEXT_OUTLINE(ndd+1, clrs2); + + if (prev_cc != cc) + TEXT_OUTLINE(dd-1, clrs2); + TEXT_OUTLINE(dd+1, clrs2); + prev_cc = cc; + prev_rdd = *rdd; + *rdd = cc; + } + } + dd++; + if (clrs2 > 0) + { + if (c < 0) + { + prev_cc = 0; + prev_rdd = *rdd; + *rdd = 0; + } + rdd++; + pdd++; + ndd++; + } + } + } + if (ix < xx1) + ix = xx1; + if (clrs[0] >= 0 && ix < xx2) + memset(dd, clrs[0], xx2 - ix + 1); + + d += context->pitch; + if (clrs2 > 0) + { + pd += context->pitch; + nd += context->pitch; + } + } + + return true; +} + +bool Text::SetFont(char *fname) +{ + font = guifonts->GetFont(fname); + if (font == NULL) + return false; + return UpdateFormat(); +} + +bool Text::SetText(const SPString & txt) +{ + text = txt; + return UpdateFormat(); +} + +bool Text::SetStyle(TEXT_STYLE st) +{ + style = st; + return UpdateFormat(); +} + +void Text::SetTextAlign(TEXT_ALIGN ta) +{ + text_align = ta; + dirty = true; +} + +void Text::SetColor(int c) +{ + if (c >= 0 && c < 256) + { + color = c; + dirty = true; + } +} + +void Text::SetBkColor(int bc) +{ + if (bc > 255) + bc = -1; + bkcolor = bc; + dirty = true; +} + +bool Text::UpdateFormat() +{ + int new_width = 0; + int new_height = 0; + rows.Clear(); + + if (font != NULL) + { + if (font->unloaded) + { + if (!font->Load()) + return false; + } + + int rowidx = -1; + for (int i = 0; i < text.GetLength(); i++) + { + if (rowidx < 0) + { + TextRow r; + r.off = i; + r.len = 0; + r.width = 0; + rowidx = rows.Add(r); + } + if (text[i] == '\n') + { + if (rows[rowidx].width > new_width) + new_width = rows[rowidx].width; + new_height += font->height; + rowidx = -1; + continue; + } + rows[rowidx].width += font->widths[(BYTE)text[i]]; + rows[rowidx].len++; + } + if (rowidx >= 0) + { + if (rows[rowidx].width > new_width) + new_width = rows[rowidx].width; + new_height += font->height; + } + } + memset(row_buf, 0, MIN(new_width, 720)); + + if (style == TEXT_STYLE_OUTLINE) + { + new_width += 2; + new_height += 2; + } + + SetWidth(new_width); + SetHeight(new_height); + auto_width = new_width; + auto_height = new_height; + + dirty = true; + return true; +} diff --git a/src/gui/text.h b/src/gui/text.h new file mode 100644 index 0000000..65893c1 --- /dev/null +++ b/src/gui/text.h @@ -0,0 +1,92 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - text object class header file + * \file gui/text.h + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_TEXT_H +#define SP_TEXT_H + +#include +#include + +enum TEXT_STYLE +{ + TEXT_STYLE_NORMAL = 0, + TEXT_STYLE_UNDERLINE, + TEXT_STYLE_OUTLINE, +}; + +enum TEXT_ALIGN +{ + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_CENTER, + TEXT_ALIGN_RIGHT +}; + +class TextRow +{ +public: + /// row text offset + int off; + /// row text length + int len; + /// row width, pixels + int width; +}; + +/// Text object window class +class Text : public Window +{ +public: + /// ctor + Text(); + /// dtor + virtual ~Text() {} + + /// Update part of text in LOCAL coords + virtual bool Update(Context *context, int x1, int y1, int x2, int y2); + + bool SetText(const SPString & txt); + bool SetFont(char *fname); + bool SetStyle(TEXT_STYLE); + void SetColor(int); + void SetBkColor(int); + void SetTextAlign(TEXT_ALIGN); + +public: + /// text + SPString text; + /// current font + Font *font; + /// formatted rows data + SPList rows; + + TEXT_STYLE style; + int color, bkcolor; + TEXT_ALIGN text_align; + +private: + // Update text dims for new font/text + bool UpdateFormat(); +}; + +#endif // of SP_TEXT_H diff --git a/src/gui/window.cpp b/src/gui/window.cpp new file mode 100644 index 0000000..cc0ac8c --- /dev/null +++ b/src/gui/window.cpp @@ -0,0 +1,733 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - abstract window class impl. + * \file window.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +WindowManager gui; + + +//////////////////////////////////////////////////////////// + +Window::Window() +{ + x = 0; + y = 0; + width = 0; + height = 0; + auto_width = auto_height = 0; + + old_x = old_y = old_width = old_height = 0; + + dirty = false; + visible = true; + wasvisible = false; + transparent = false; + removing = false; + + group = NULL; + + halign = gui.halign; + valign = gui.valign; + + timer = 0; + timerobj = NULL; + + prev = next = NULL; +} + +bool Window::Update(int) +{ + return false; +} + +void Window::SetX(int newx) +{ + if (halign == WINDOW_ALIGN_RIGHT) + { + x = newx - width; + } + else if (halign == WINDOW_ALIGN_CENTER) + { + x = newx - width/2; + } + else + x = newx; + dirty = true; +} + +int Window::GetX() +{ + if (halign == WINDOW_ALIGN_RIGHT) + { + return x + width; + } + else if (halign == WINDOW_ALIGN_CENTER) + { + return x + width/2; + } + return x; +} + +void Window::SetY(int newy) +{ + if (valign == WINDOW_ALIGN_BOTTOM) + { + y = newy - height; + } + else if (valign == WINDOW_ALIGN_CENTER) + { + y = newy - height/2; + } + else + y = newy; + dirty = true; +} + +int Window::GetY() +{ + if (valign == WINDOW_ALIGN_BOTTOM) + { + return y + height; + } + else if (valign == WINDOW_ALIGN_CENTER) + { + return y + height/2; + } + return y; +} + +void Window::SetWidth(int newwidth) +{ + if (newwidth <= 0) // use auto-width + newwidth = auto_width; + + if (halign == WINDOW_ALIGN_RIGHT) + { + x = x + width - newwidth; + } + else if (halign == WINDOW_ALIGN_CENTER) + { + x = x + width/2 - newwidth/2; + } + + width = newwidth; + dirty = true; +} + +int Window::GetWidth() +{ + return width; +} + +void Window::SetHeight(int newheight) +{ + if (newheight < 0) // use auto-width + newheight = auto_height; + if (valign == WINDOW_ALIGN_BOTTOM) + { + y = y + height - newheight; + } + else if (valign == WINDOW_ALIGN_CENTER) + { + y = y + height/2 - newheight/2; + } + height = newheight; + dirty = true; +} + +int Window::GetHeight() +{ + return height; +} + +void Window::SetVisible(bool newv) +{ + visible = newv; + dirty = true; +} + +void Window::SetHAlign(WINDOW_ALIGN newha) +{ + int user_x = GetX(); + halign = newha; + SetX(user_x); + dirty = true; +} + +void Window::SetVAlign(WINDOW_ALIGN newva) +{ + int user_y = GetY(); + valign = newva; + SetY(user_y); + dirty = true; +} + +//////////////////////////////////////////////////////////// + +WindowManager::WindowManager() +{ + halign = WINDOW_ALIGN_LEFT; + valign = WINDOW_ALIGN_TOP; + + update_enabled = true; + display_switched = true; + + osd_fullscreen = false; +} + +WindowManager::~WindowManager() +{ + DeInitialize(); +} + +bool WindowManager::Initialize() +{ + if (!jpeg_init()) + return false; + + // init OSD + KHWL_OSDSTRUCT osd = { 0 }; + khwl_osd_switch(&osd, FALSE/*TRUE*/); + + // bpp is 8, i guess? + if (osd.bpp != 8) + return false; + + data = (BYTE *)osd.addr + 8 + 1024; + pal = (BYTE *)osd.addr + 8; + width = osd.width; + height = osd.height; + + int offsx = 40, offsy = 30; + left = offsx; + top = offsx; + right = width - 1 - offsy; + bottom = height - 1 - offsy; + + // set default 'b/w' pal + BYTE bw_colors[1024] = { 0, 0, 0, 0, 255, 255, 255, 255, + /////////// ------------ this is for test only! + 255, 55, 5, 255 }; + SetPalette(bw_colors, 0, 256); + def_color = 1; + def_bkcolor = 0; + + tr_color = 0; + w_color = 1; + + tvout = (WINDOW_TVOUT)settings_get(SETTING_TVOUT); + tvstandard = (WINDOW_TVSTANDARD)settings_get(SETTING_TVSTANDARD); + + Clear(); + + guiimg = new ImageManager(); + guifonts = new FontManager(); + + return true; +} + +bool WindowManager::DeInitialize() +{ + SPSafeDelete(guiimg); + SPSafeDelete(guifonts); + removed_windows.Delete(); + windows.Delete(); + jpeg_deinit(); + return true; +} + +//////////////////////////////////////////////////// + +bool WindowManager::IsOsdFullscreen() +{ + return osd_fullscreen; +} + +void WindowManager::SetOsdFullscreen(bool is) +{ + osd_fullscreen = is; + khwl_osd_setfullscreen(osd_fullscreen); +} + +int WindowManager::GetColor() +{ + return def_color; +} + +int WindowManager::GetBkColor() +{ + return def_bkcolor; +} + +int WindowManager::GetTransparentColor() +{ + return tr_color; +} + +int WindowManager::GetWhiteColor() +{ + return w_color; +} + +WINDOW_ALIGN WindowManager::GetHAlign() +{ + return halign; +} + +WINDOW_ALIGN WindowManager::GetVAlign() +{ + return valign; +} + +//////////////////////////////////////////////////// + +bool WindowManager::SetColor(int c) +{ + if (c >= 0 && c < 256) + { + def_color = c; + return true; + } + return false; +} + +bool WindowManager::SetBkColor(int c) +{ + if (c < 256) + { + def_bkcolor = c; + return true; + } + return false; +} + +bool WindowManager::SetTransparentColor(int c) +{ + if (c >= 0 && c < 256) + { + tr_color = c; + return true; + } + return false; +} + +void WindowManager::SetHAlign(WINDOW_ALIGN a) +{ + halign = a; +} + +void WindowManager::SetVAlign(WINDOW_ALIGN a) +{ + valign = a; +} + +//////////////////////////////////////////////////// + +bool WindowManager::SetPalette(BYTE *argb, int offset, int num_colors) +{ + // check if current tr_color is valid + if (tr_color >= offset && tr_color < offset + num_colors) + { + if (*(pal + (tr_color - offset) * 4) != 0) + tr_color = -1; + } + BYTE *p = pal + offset * 4; + int min_a = 255, max_a = 128, max_sum = 0; + for (int i = 0; i < num_colors; i++) + { + BYTE Y, U, V; + khwl_vgargbtotvyuv(argb[1], argb[2], argb[3], &Y, &U, &V); + *p++ = argb[0]; + *p++ = Y; + *p++ = U; + *p++ = V; + if (tr_color < 0 && argb[0] < min_a) + { + tr_color = i; + min_a = argb[0]; + } + int s = argb[1] + argb[2] + argb[3]; + if (argb[0] >= max_a && s > max_sum) + { + max_a = argb[0]; + max_sum = s; + w_color = i; + } + argb += 4; + } + + return true; +} + +bool WindowManager::LoadPalette(const SPString & fname) +{ + FILE *fp = fopen(fname, "rb"); + if (fp == NULL) + { + msg_error("Cannot load palette from %s.\n", *fname); + return false; + } + fseek(fp, 0, SEEK_END); + int siz = ftell(fp); + rewind(fp); + + if (siz < 256 * 3) + { + msg_error("Palette error: file %s is truncated.\n", *fname); + fclose(fp); + return false; + } + + int maxsiz = 256 * 4 + 24; + BYTE *pal = new BYTE [maxsiz]; + fread(pal, Min(siz, maxsiz), 1, fp); + fclose(fp); + + if (siz == 256*3 || siz == 256*3+4) + { + BYTE *p = pal + 256*4; + for (int i = 255; i >= 0; i--) + { + *--p = pal[i * 3 + 2]; + *--p = pal[i * 3 + 1]; + *--p = pal[i * 3]; + *--p = 0xff; + } + } + else if (pal[0] == 'R' && pal[1] == 'I' && pal[2] == 'F' && pal[3] == 'F') + { + BYTE *p = pal; + int i, numc = (pal[17] << 8) | pal[16]; + for (i = 6; i < numc+6; i++) + { + *p++ = 0xff;// pal[i * 4 + 3]; + *p++ = pal[i * 4 + 0]; + *p++ = pal[i * 4 + 1]; + *p++ = pal[i * 4 + 2]; + } + for (i = numc; i < 256; i++) + { + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + } + } + + SetPalette(pal, 0, 256); + + delete [] pal; + + return true; +} + +BYTE *WindowManager::GetPaletteEntry(int index) +{ + if (pal == NULL || index < 0 || index > 255) + return NULL; + return pal + index * 4; +} + +bool WindowManager::SetBackground(char *fname, int hscale, int vscale, int offsx, int offsy, int *rotate) +{ + if (fname == NULL || fname[0] == '\0') + { + msg("Clearing background.\n"); + khwl_display_clear(); + khwl_set_window_source(-1, -1); + return true; + } + msg("Setting background to %s\n", fname); + //khwl_setvideomode(KHWL_VIDEOMODE_NORMAL, TRUE); + if (!jpeg_show(fname, hscale, vscale, offsx, offsy, rotate)) + { + msg_error("Cannot show JPEG '%s'.\n", fname); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////// + +bool WindowManager::AddWindow(Window *w) +{ + if (w == NULL) + return false; + if (w == console) + windows.Add(w); + else + windows.InsertBefore(console, w); +#if 0 +printf("Windows = %d\n", windows.GetNum()); +#endif + return true; +} + +bool WindowManager::RemoveWindow(Window *w) +{ + if (w == NULL) + return false; + if (w->removing) + return true; + w->removing = true; + windows.Remove(w); + removed_windows.Add(w); + return true; +} + +bool WindowManager::ShowWindow(Window *w, bool ison) +{ + if (w == NULL) + return false; + if (ison != w->visible) + { + w->SetVisible(ison); + } + return true; +} + +void WindowManager::UpdateEnable(bool ison) +{ + update_enabled = ison; +} + +bool WindowManager::IsUpdateEnabled() +{ + return update_enabled; +} + +bool WindowManager::SetTv(WINDOW_TVOUT tvo, WINDOW_TVSTANDARD tvs) +{ + if (tvo != WINDOW_TVOUT_UNKNOWN) + tvout = tvo; + if (tvs != WINDOW_TVSTANDARD_UNKNOWN) + tvstandard = tvs; + return SwitchDisplay(true); +} + +WINDOW_TVOUT WindowManager::GetTvOut() +{ + return tvout; +} + +WINDOW_TVSTANDARD WindowManager::GetTvStandard() +{ + return tvstandard; +} + +bool WindowManager::SwitchDisplay(bool ison) +{ + static const KHWL_TV_OUTPUT_FORMAT_TYPE khwl_tvout[] = { evTvOutputFormat_COMPOSITE, + evTvOutputFormat_COMPONENT_YUV, + evTvOutputFormat_COMPONENT_RGB_SCART }; + static const KHWL_TV_STANDARD_TYPE khwl_standard[] = + { + evTvStandard_NTSC, evTvStandard_PAL, + evTvStandard_480P, evTvStandard_576P, evTvStandard_720P, evTvStandard_1080I, + }; + + static int old_out = -1, old_standard = -1, old_tvtype = -1; + + display_switched = ison; + + if (display_switched) + { + int tvtype = settings_get(SETTING_TVTYPE); + if (tvout != old_out || tvstandard != old_standard || tvtype != old_tvtype) + { + khwl_setwide((tvtype == 2 || tvtype == 3) ? TRUE : FALSE); + khwl_setdisplay(khwl_tvout[tvout], khwl_standard[tvstandard]); + old_out = tvout; + old_standard = tvstandard; + old_tvtype = tvtype; + } + } + else + { + khwl_setdisplay(evTvOutputFormat_OUTPUT_OFF, khwl_standard[tvstandard]); + old_out = -1; old_standard = -1; + } + + return true; +} + +bool WindowManager::IsDisplaySwitchedOn() +{ + return display_switched; +} + +bool WindowManager::Update() +{ + if (!update_enabled) + return true; + + bool need_update = false; + // clean-up after deleted windows too + Window *win = removed_windows.GetFirst(); + while (win != NULL) + { + win->visible = false; + if (UpdateForWindow(win)) + need_update = true; + + Window *next = win->next; + removed_windows.Delete(win); + win = next; + } + + win = windows.GetFirst(); + while (win != NULL) + { + if (win->dirty && (win->visible || win->wasvisible)) + { + if (UpdateForWindow(win)) + need_update = true; + + win->old_x = win->x; + win->old_y = win->y; + win->old_width = win->width; + win->old_height = win->height; + win->dirty = false; + win->wasvisible = win->visible; + } + win = win->next; + } + if (need_update) + return khwl_osd_update() == TRUE; + return true; +} + +bool WindowManager::UpdateForWindow(Window *win) +{ + static Context c; + bool ret = false; + int upd_x1, upd_y1, upd_x2, upd_y2; + if (win != NULL) + { + upd_x1 = Min(win->old_x, win->x); + if (upd_x1 < 0) upd_x1 = 0; + + upd_y1 = Min(win->old_y, win->y); + if (upd_y1 < 0) upd_y1 = 0; + + upd_x2 = Max(win->old_x + win->old_width, win->x + win->width); + if (upd_x2 >= width) upd_x2 = width - 1; + + upd_y2 = Max(win->old_y + win->old_height, win->y + win->height); + if (upd_y2 >= height) upd_y2 = height - 1; + } else + { + upd_x1 = 0; + upd_y1 = 0; + upd_x2 = width - 1; + upd_y2 = height - 1; + } + + // clear background if window was moved/sized or transparent/hidden + if (win == NULL || win->x != win->old_x || win->y != win->old_y + || win->width != win->old_width || win->height != win->old_height + || win->transparent || !win->visible) + { + if (Clear(false, upd_x1, upd_y1, upd_x2, upd_y2)) + ret = true; + } + + Window *winj = windows.GetFirst(); + while (winj != NULL) + { + if (winj->visible) + { + c.data = data + winj->y * width + winj->x; + c.pitch = width; + c.width = winj->width; + c.height = winj->height; + // apply update region + int lupd_x1 = Max(upd_x1, winj->x); + int lupd_y1 = Max(upd_y1, winj->y); + int lupd_x2 = Min(upd_x2, winj->x + winj->width - 1); + int lupd_y2 = Min(upd_y2, winj->y + winj->height - 1); + if (lupd_x1 <= lupd_x2 && lupd_y1 <= lupd_y2) + { + lupd_x1 -= winj->x; + lupd_y1 -= winj->y; + lupd_x2 -= winj->x; + lupd_y2 -= winj->y; + if (winj->Update(&c, lupd_x1, lupd_y1, lupd_x2, lupd_y2)) + ret = true; + } + } + winj = winj->next; + } + return ret; +} + +bool WindowManager::TextOut(int x, int y, char *str, int nx) +{ + Context c; + c.data = data + y * width + x; + c.pitch = width; + c.width = width; + c.height = height; + return console->TextOut(&c, str, nx); +} + +bool WindowManager::Clear(bool updatenow, int x1, int y1, int x2, int y2) +{ + Context c; + c.data = data; + c.pitch = width; + c.width = width; + c.height = height; + if (x1 < 0) x1 = 0; + if (y1 < 0) y1 = 0; + if (x2 < 0 || x2 >= width) x2 = width - 1; + if (y2 < 0 || y2 >= height) y2 = height - 1; + + if (x2 < x1 || y2 < y1) + return false; + + BYTE *d = c.data + y1 * c.pitch + x1; + int len = (x2 - x1 + 1) * sizeof(BYTE); + for (int iy = y1; iy <= y2; iy++) + { + memset(d, tr_color, len); + d += c.pitch; + } + return updatenow ? (khwl_osd_update() == TRUE) : true; +} diff --git a/src/gui/window.h b/src/gui/window.h new file mode 100644 index 0000000..98d0b14 --- /dev/null +++ b/src/gui/window.h @@ -0,0 +1,248 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - abstract window class header file + * \file window.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_WINDOW_H +#define SP_WINDOW_H + +/// Drawing context +class Context +{ +public: + /// 8-bit color data + BYTE *data; + /// data pitch + int pitch; + /// context dims + int width, height; +}; + +////////////////////////////////////////////////////////////////// + +enum WINDOW_ALIGN +{ + WINDOW_ALIGN_TOP = 0, + WINDOW_ALIGN_LEFT = 0, + WINDOW_ALIGN_CENTER = 1, + WINDOW_ALIGN_RIGHT = 2, + WINDOW_ALIGN_BOTTOM = 2 +}; + +enum WINDOW_TVSTANDARD +{ + WINDOW_TVSTANDARD_UNKNOWN = -1, + WINDOW_TVSTANDARD_NTSC = 0, + WINDOW_TVSTANDARD_PAL, + WINDOW_TVSTANDARD_480P, + WINDOW_TVSTANDARD_576P, + WINDOW_TVSTANDARD_720P, + WINDOW_TVSTANDARD_1080I, +}; + +enum WINDOW_TVOUT +{ + WINDOW_TVOUT_UNKNOWN = -1, + WINDOW_TVOUT_COMPOSITE = 0, + WINDOW_TVOUT_YPBPR, + WINDOW_TVOUT_RGB, +}; + +class ScriptTimerObject; + +/// Abstract window class +class Window +{ +public: + /// ctor + Window(); + /// dtor + virtual ~Window() + { + SPSafeDelete(group); + } + + /// Update object's state for current time (in milliseconds) + virtual bool Update(int curtime); + + /// Update part of window in LOCAL coords + virtual bool Update(Context *context, int x1, int y1, int x2, int y2) = 0; + + /// Set window center using halign + void SetX(int); + /// Set window center using valign + void SetY(int); + /// Set window width using halign + void SetWidth(int); + /// Set window height using valign + void SetHeight(int); + + void SetHAlign(WINDOW_ALIGN); + void SetVAlign(WINDOW_ALIGN); + + /// Get window center using halign + int GetX(); + /// Get window center using valign + int GetY(); + int GetWidth(); + int GetHeight(); + + void SetVisible(bool); + +public: + /// window coords + int x, y; + /// window size + int width, height; + + WINDOW_ALIGN halign, valign; + /// window is visible? + bool visible, wasvisible; + /// set this to update window + bool dirty; + /// set if window is being removed + bool removing; + /// if window is transparent + bool transparent; + + /// saved coords & dims + int old_x, old_y, old_width, old_height, auto_width, auto_height; + + SPString *group; + + int timer; + /// update queue object (used by script) + ScriptTimerObject *timerobj; + + Window *prev, *next; +}; + +/// Window manager +class WindowManager +{ +public: + /// ctor + WindowManager(); + /// dtor + ~WindowManager(); + + /// initialize + bool Initialize(); + + /// deinitialize + bool DeInitialize(); + + /// Turn display on/off + bool SwitchDisplay(bool ison); + bool IsDisplaySwitchedOn(); + bool SetTv(WINDOW_TVOUT = WINDOW_TVOUT_UNKNOWN, WINDOW_TVSTANDARD = WINDOW_TVSTANDARD_UNKNOWN); + WINDOW_TVOUT GetTvOut(); + WINDOW_TVSTANDARD GetTvStandard(); + + /// Add window to the list + bool AddWindow(Window *); + + /// Remove window from the list + bool RemoveWindow(Window *); + + /// Show/Hide window + bool ShowWindow(Window *, bool); + + /// Update windows if needed + bool Update(); + + /// Enable/disable windows update + void UpdateEnable(bool ison); + bool IsUpdateEnabled(); + + /// Clear screen + bool Clear(bool updatenow = true, int x1 = 0, int y1 = 0, int x2 = -1, int y2 = -1); + + //////////////////////////////////////////// + bool TextOut(int x, int y, char *str, int nx = 0); + + //////////////////////////////////////////// + int GetColor(); + int GetBkColor(); + int GetTransparentColor(); + int GetWhiteColor(); + WINDOW_ALIGN GetHAlign(); + WINDOW_ALIGN GetVAlign(); + + bool IsOsdFullscreen(); + void SetOsdFullscreen(bool); + + bool SetColor(int); + bool SetBkColor(int); + bool SetTransparentColor(int); + void SetHAlign(WINDOW_ALIGN); + void SetVAlign(WINDOW_ALIGN); + + bool LoadPalette(const SPString & fname); + bool SetPalette(BYTE *argb, int offset, int num_colors); + + /// in ARGB form + BYTE *GetPaletteEntry(int index); + + bool SetBackground(char *fname, int hscale = 100, int vscale = 100, int offsx = 0, int offsy = 0, int *rotate = NULL); + +public: + /// Use these freely + int left, top, right, bottom; + WINDOW_ALIGN halign, valign; + +protected: + /// windows list + SPDLinkedListAbstract windows; + SPDLinkedListAbstract removed_windows; + +private: + BYTE *data; + BYTE *pal; + /// won't be changed + int width, height; + + // current def.object color & background color + int def_color, def_bkcolor; + // current transparent color + int tr_color; + // current white color + int w_color; + + bool update_enabled; + bool display_switched; + + bool osd_fullscreen; + + /// Update screen area for given window (or entire screen if NULL). + /// (Not thread-safe!) + bool UpdateForWindow(Window *win); + + /// Current values. See SETTING_TVOUT and SETTING_TVSTANDARD. + WINDOW_TVOUT tvout; + WINDOW_TVSTANDARD tvstandard; +}; + +/// User interface manager +extern WindowManager gui; + +#endif // of SP_WINDOW_H diff --git a/src/info/player_info.cpp b/src/info/player_info.cpp new file mode 100644 index 0000000..e1edb2f --- /dev/null +++ b/src/info/player_info.cpp @@ -0,0 +1,290 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - File info source file. + * \file player_info.cpp + * \author bombur + * \version 0.1 + * \date 22.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "player_info.h" + +#ifdef PLAYER_INFO_EMBED +#include +#include "script.h" +#endif + +#include + +extern "C" +{ +#include +#include +#include +} + +#if 0 +int strcasecmp (char *dst, char *src) +{ + int f, l; + do + { + f = tolower((unsigned char)(*(dst++))); + l = tolower((unsigned char)(*(src++))); + } while (f != 0 && (f == l)); + return(f - l); +} +#endif + +/////////////////////////////////////////////////////// + +#define NetWordRotate(w) w = (WORD)((((w) & 0x00ffU) << 8) | (((w) & 0xff00U) >> 8)) +#define NetDwordRotate(dw) dw = ((DWORD)( \ + (((DWORD)(dw) & (DWORD)0x000000ffUL) << 24) | \ + (((DWORD)(dw) & (DWORD)0x0000ff00UL) << 8) | \ + (((DWORD)(dw) & (DWORD)0x00ff0000UL) >> 8) | \ + (((DWORD)(dw) & (DWORD)0xff000000UL) >> 24) )); + +#ifdef WIN32 +#pragma pack(1) +#endif + +typedef struct JfifMarkerSize +{ + WORD marker; + WORD size; + +} ATTRIBUTE_PACKED JfifMarkerSize; + +typedef struct JfifFrameMarker +{ + BYTE precision; + WORD height; + WORD width; + BYTE numc; + +} ATTRIBUTE_PACKED JfifFrameSize; + +#ifdef WIN32 +#pragma pack() +#endif + +BOOL player_get_jpginfo(const char *fname) +{ +#ifdef WIN32 + if (fname[0] == '/') fname++; +#endif + + FILE *fp = fopen(fname, "rb"); + if (fp == NULL) + { +#ifndef PLAYER_INFO_EMBED + printf("Errr\n"); +#endif + return FALSE; + } + + WORD soi; + fread(&soi, sizeof(soi), 1, fp); + JfifMarkerSize marker; + + int width = -1, height = -1; + int numc = -1; + + if (soi == (WORD)0xd8ff) + { + for (;;) + { + if (fread(&marker, sizeof(marker), 1, fp) != 1) + break; + // corrupted file... give it a chance... + if ((marker.marker & 0xff) != 0xff) + { + fseek(fp, -1, SEEK_CUR); + continue; + } + // SOF + if ((marker.marker & 0xf0ff) == 0xc0ff + && marker.marker != 0xc4ff && marker.marker != 0xccff) + { + JfifFrameMarker frame; + if (fread(&frame, sizeof(frame), 1, fp) == 1) + { + NetWordRotate(frame.width); + NetWordRotate(frame.height); + width = frame.width; + height = frame.height; + numc = frame.numc; + } + break; + } + NetWordRotate(marker.size); + if (marker.size < 2) + break; + if (marker.size > 2) + fseek(fp, marker.size - 2, SEEK_CUR); + } + } + bool wasany = false; + if (width >= 0 && height >= 0) + { +#ifdef PLAYER_INFO_EMBED + script_framesize_callback(width, height); +#else + printf("Dims\n%d\n%d\n", width, height); +#endif + wasany = true; + } + if (numc == 1 || numc == 3) + { +#ifdef PLAYER_INFO_EMBED + script_colorspace_callback(numc); +#else + printf("Clrs\n%d\n", numc); +#endif + wasany = true; + } + if (!wasany) + { +#ifdef PLAYER_INFO_EMBED + printf("None\n"); +#endif + } + fclose(fp); + + return TRUE; +} + +BOOL player_get_id3(const char *fname, const char *charset) +{ + bool wasany = false; + PLAYER_INFO_CHARSET info_charset = PLAYER_INFO_CHARSET_LATIN1; + if (strcasecmp(charset, "cp1251") == 0) + info_charset = PLAYER_INFO_CHARSET_CP1251; + +#ifdef WIN32 + if (fname[0] == '/') fname++; +#endif + struct id3_file *id3 = id3_file_open(fname, ID3_FILE_MODE_READONLY); + if (id3 == NULL) + { +#ifndef PLAYER_INFO_EMBED + printf("Errr\n"); +#endif + return FALSE; + } + struct id3_tag *id3tag = id3_file_tag(id3); + if (id3tag != NULL) + { + static char const *frms[] = { ID3_FRAME_TITLE, ID3_FRAME_ARTIST }; + for (int i = 0; i < 2; i++) + { + struct id3_frame *id3frame = id3_tag_findframe(id3tag, frms[i], 0); + if (id3frame != NULL) + { + union id3_field field = id3frame->fields[1]; + id3_ucs4_t const *tmpstr = id3_field_getstrings(&field, 0); + if (tmpstr != NULL) + { + int slen = id3_ucs4_latin1size(tmpstr); + id3_latin1_t *str = new id3_latin1_t[slen + 1]; + if (str != NULL) + { + if (info_charset == PLAYER_INFO_CHARSET_CP1251) + id3_cp1251_encode(str, tmpstr); + else + id3_latin1_encode(str, tmpstr); + + if (slen > 250) + str[250] = '\0'; +#ifdef PLAYER_INFO_EMBED + if (i == 0) + script_name_callback((char *)str); + else if (i == 1) + script_artist_callback((char *)str); +#else + static char const *hdrs[] = { "Titl", "Atst" }; + printf("%s\n%s\n", hdrs[i], str); +#endif + SPSafeDeleteArray(str); + wasany = true; + } + } + } + } + } +#ifndef PLAYER_INFO_EMBED + if (!wasany) + printf("None\n"); +#endif + if (id3 != NULL) + { + id3_file_close(id3); + id3 = NULL; + } + + return FALSE; +} + +BOOL player_getinfo(const char *fname, const char *charset) +{ + const char *ext = strrchr(fname, '.'); + if (ext != NULL) + { + if (strcasecmp(ext, ".jpg") == 0 || strcasecmp(ext, ".jpeg") == 0) + { + return player_get_jpginfo(fname); + } + else if (strcasecmp(ext, ".mp3") == 0 || strcasecmp(ext, ".wav") == 0 || strcasecmp(ext, ".mp2") == 0 || strcasecmp(ext, ".mp1") == 0 || strcasecmp(ext, ".mpa") == 0 || strcasecmp(ext, ".mus") == 0) + { + return player_get_id3(fname, charset); + } + } + return FALSE; +} + + +#ifndef PLAYER_INFO_EMBED + +int main(int argc, char *argv[]) +{ + if (argc < 3) + { + printf("Use: fileinfo.bin fname charset.\n"); + return 1; + } + + player_getinfo(argv[1], argv[2]); + + fflush(stdout); + return 0; +} + +#endif diff --git a/src/info/player_info.h b/src/info/player_info.h new file mode 100644 index 0000000..a49fbd6 --- /dev/null +++ b/src/info/player_info.h @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - file info header file + * \file player_info.h + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_PLAYER_INFO_H +#define SP_PLAYER_INFO_H + +enum PLAYER_INFO_CHARSET +{ + PLAYER_INFO_CHARSET_LATIN1 = 0, + PLAYER_INFO_CHARSET_CP1251 = 1, +}; + +BOOL player_getinfo(const char *fname, const char *charset); + +BOOL player_get_id3(const char *fname, const char *charset); +BOOL player_get_jpginfo(const char *fname); + +#endif // of SP_PLAYER_INFO_H diff --git a/src/info/player_info.make b/src/info/player_info.make new file mode 100644 index 0000000..9fb8fd4 --- /dev/null +++ b/src/info/player_info.make @@ -0,0 +1,52 @@ +######################################################################### +# +# SigmaPlayer source project - player_info makefile +# \file player_info.make +# \author bombur +# \version 0.1 +# \date 15.2.2007 +# +########################################################################## + + +MAIN_SRC := info/player_info.cpp + +PREBUILD := cd contrib/libid3tag && make && cd ../.. + +EXTERNAL_STATIC_LINKS_WITH := \ + contrib/libid3tag/.libs/libid3tag.a \ + contrib/libid3tag/fakezlib/libz.a + +# contrib/memcpy.o \ +# contrib/memset.o \ + + +SPINCLUDE = libsp/ +JPEGINCLUDE = contrib/libjpeg/ +DVDINCLUDE = contrib/libdvdnav/src/ +DVDINCLUDE1 = contrib/libdvdnav/src/dvdread/ +DVDINCLUDE2 = contrib/libdvdnav/src/vm/ +DVDINCLUDE3 = contrib/libdvdcss/ +DVDINCLUDE4 = contrib/libdvdcss/src/ +ID3V2INCLUDE = contrib/libid3tag/ + +SPCFLAGS += -msoft-float -Iinfo -I$(SPINCLUDE) -I$(JPEGINCLUDE) -I$(DVDINCLUDE) -I$(DVDINCLUDE1) -I$(DVDINCLUDE2) -I$(DVDINCLUDE3) -I$(DVDINCLUDE4) -I$(ID3V2INCLUDE) -DDVDNAV_COMPILE=1 +#SPCFLAGS += -I$(SPINCLUDE) -I$(ID3V2INCLUDE) + +LOCAL_MAKEFILE := Makefile + +TARGET_TYPE := EXECUTABLE + +USE_STD_LIB := 1 + +COMPILKIND = release + +PREPROCESSORFLAGS += -D__STDC_LIMIT_MACROS + +MAKE_CLEAN = -rm -fr info/player_info.gdb && cd contrib/libid3tag && make clean && cd ../.. + +CROSS = arm-elf- +LDFLAGS = -elf2flt="-s262144" -s --static +EXEFLAGS = -msoft-float -lutil -lstdc++ + +include Makefile.inc diff --git a/src/init b/src/init new file mode 100644 index 0000000..05ab443 Binary files /dev/null and b/src/init differ diff --git a/src/init.cpp b/src/init.cpp new file mode 100644 index 0000000..9830a26 --- /dev/null +++ b/src/init.cpp @@ -0,0 +1,227 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - main source file + * \file init.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +//#define SHOW_CONSOLE_AT_STARTUP + + +#ifdef WIN32 +//#define SHOW_CONSOLE_AT_STARTUP +#endif + +bool is_sleeping = false, do_sleep = false, need_to_stop = false; +int steps = 0; + +void gui_update() +{ + script_update(true); + gui.Update(); +} + +int cycle(bool gfx_only) +{ + int but = fip_read_button(FALSE); + if (but != 0) + { + if (but == -1) // for win32 exit + return -1; + + if (but == FIP_KEY_POWER) + { + is_sleeping = !is_sleeping; + do_sleep = true; + if (is_sleeping) + { + if (!stop_all()) + need_to_stop = true; + } + } + + else if (!is_sleeping) + { + if (but == FIP_KEY_PN) + { + if (msg_get_output() == MSG_OUTPUT_SHOW) + { + msg_set_output(MSG_OUTPUT_FREEZE); + } + else if (msg_get_output() == MSG_OUTPUT_FREEZE) + { + msg_set_output(MSG_OUTPUT_HIDE); + } + else if (msg_get_output() == MSG_OUTPUT_HIDE) + { + msg_set_output(MSG_OUTPUT_SHOW); + } + } + // PBC shows sysinfo in console mode + else if (but == FIP_KEY_PBC) + { + if (msg_get_output() == MSG_OUTPUT_SHOW) + { +#if 0 + SPMemoryManager &memManager = SPMemoryManager::GetHandle(); + memManager.TEST_DUMP(); + + guiimg->DumpImages(); +#endif + msg_sysinfo(); + } + else + msg_shell(); + } + script_key_callback(but); + } + } + + if (do_sleep) + { + if (!need_to_stop || stop_all()) + { + msg("sleeping = %s\n", is_sleeping ? "true" : "false"); + player_turn_onoff(!is_sleeping); + + if (!is_sleeping) + { + disc_changed(CDROM_STATUS_UNKNOWN); + script_skiptime(); + } + need_to_stop = false; + do_sleep = false; + } + } + + if (!is_sleeping) + { + script_update(gfx_only); + + if (mmsl != NULL) + { + if (!mmsl->Run()) + { + if (!is_internal_playing()) + usleep(10000); + } + } + + if (!gui.Update()) + { + // win32 exit + return -1; + } + + if (!is_playing()) + { + if ((steps++) % 15 == 0) // every 750 ms + disc_changed(); + } + } else + usleep(50000); + + return 0; +} + +int main(int /*argc*/, char * /*argv*/[]) +{ + if (!fip_init(TRUE)) + exit(1); + + // needed for some drives which do not eject at startup + if (fip_read_button(FALSE) == FIP_KEY_FRONT_EJECT) + { + if (!cdrom_init()) + exit(4); + cdrom_eject(TRUE); // open tray + usleep(2000000); + } + + fip_write_string("LoAd"); + + if (!khwl_init(TRUE)) + exit(2); + + if (!settings_init()) + exit(3); + + if (!cdrom_init()) + exit(4); + + if (!gui.Initialize()) + exit(5); + + console = new Console(60, 20); + gui.AddWindow(console); + gui.SwitchDisplay(true); + + msg_init(); + +#ifdef SHOW_CONSOLE_AT_STARTUP + msg_set_output(MSG_OUTPUT_SHOW); + msg("Starting debug (see sp_log.txt)...\n"); +#endif + + if (msg_get_output() == MSG_OUTPUT_HIDE) + gui.ShowWindow(console, false); + + script_init(); + + disc_changed(); + +//debug_init(); + + for (;;) + { + if (cycle() < 0) + break; + } + + // probably we won't get here in firmware... + + SPSafeDelete(mmsl); + script_deinit(); + + cdrom_deinit(); + khwl_deinit(); + fip_deinit(); + + return 0; +} diff --git a/src/libsp/KISS/todo b/src/libsp/KISS/todo new file mode 100644 index 0000000..8571307 --- /dev/null +++ b/src/libsp/KISS/todo @@ -0,0 +1 @@ +Not ready yet. \ No newline at end of file diff --git a/src/libsp/MG35/arch-jasper/hardware.h b/src/libsp/MG35/arch-jasper/hardware.h new file mode 100644 index 0000000..c8cdec0 --- /dev/null +++ b/src/libsp/MG35/arch-jasper/hardware.h @@ -0,0 +1,798 @@ +/* + * linux/include/asm-arm/arch-jasper/hardware.h + * [bombur]: this is a part of uClinux (GPL) headers. + * for JASPER + * Created 12/12/2001 Fabrice Gautier + * Copyright 2001, Sigma Desings, Inc + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#define IO_ADDRESS(x) (x) + +// PLL input clock, typically 27 Mhz +#define JASPER_EXT_CLOCK 27000000 + +/* 0=TC0, 1=TC1, 2=TC2 */ + +//------------------------------------------------------ +// SYSTEM CONTROLLER 0x0050_0000 +//------------------------------------------------------ +#define JASPER_SYSCTRL_BASE 0x00500000 + +#define SYSCTRL_CHIP_ID 0x00000000 +#define SYSCTRL_REVISION_ID 0x00000008 +#define SYSCTRL_CPUCFG 0x0000000C +#define SYSCTRL_TESTSTAT 0x00000010 +#define SYSCTRL_ERRSTAT 0x00000014 +#define SYSCTRL_BADADDR 0x00000018 +#define SYSCTRL_RSTCTL 0x00000020 +#define SYSCTRL_CPUTIMESLOT 0x00000024 + +//------------------------------------------------------ +// TIMER 0 AND 1 0x0050_0100 +//-------------------------TIMER_----------------------- +#define JASPER_TIMER_BASE 0x00500100 + +#define TIMER_TMRSTAT 0x00000000 +#define TIMER_TMR0LOAD 0x00000010 +#define TIMER_TMR0VAL 0x00000014 +#define TIMER_TMR0CTL 0x00000018 +#define TIMER_TMR1LOAD 0x00000020 +#define TIMER_TMR1VAL 0x00000024 +#define TIMER_TMR1CTL 0x00000028 + +//------------------------------------------------------ +// INT CONTROLLER 0x0050_0200 +//------------------------------------------------------ +#define JASPER_INT_CONTROLLER_BASE 0x00500200 + +#define INT_IRQSTAT 0x00000000 +#define INT_FIQSTAT 0x00000004 +#define INT_INTTYPE 0x00000010 +#define INT_INTPOLL 0x00000020 +#define INT_INTEN 0x00000024 + +//------------------------------------------------------ +// MAC Registers 0x00500300 +//------------------------------------------------------ +#define JASPER_MAC_BASE 0x00500300 + +#define MAC_REFTIMER 0x00000000 +#define MAC_FLASH_CFG 0x00000014 +#define MAC_FLASH_ST 0x0000001c +#define MAC_SDRAMCTL 0x00000020 +#define MAC_SDRAMCFG 0x00000024 +#define MAC_SDRAMDATA 0x00000028 +#define MAC_SDRAMST 0x0000002c +#define MAC_ARBITERCTRL 0x00000090 +#define MAC_ARBITERSTATE 0x00000094 +#define MAC_WATCHDOG_CTRL 0x000000A0 +#define MAC_WATCHDOG_TMO0 0x000000A4 +#define MAC_WATCHDOG_TMO1 0x000000A8 +#define MAC_WATCHDOG_INT 0x000000Ac +#define MAC_TIMESLOTCNT 0x000000B0 + + +//------------------------------------------------------ +// UART REGISTERs +// UART0 0050_0500 +// UART1 0050_1300 +//------------------------------------------------------ +#define JASPER_UART0_BASE 0x00500500 +#define JASPER_UART1_BASE 0x00501300 +#define UART_NR 2 + +#define UART_RBR 0x00 +#define UART_TBR 0x04 +#define UART_IER 0x08 +#define UART_IIR 0x0C +#define UART_FCR 0x10 +#define UART_LCR 0x14 +#define UART_MCR 0x18 +#define UART_LSR 0x1C +#define UART_MSR 0x20 +#define UART_SCRATCH 0x24 +#define UART_CLKDIV 0x28 +#define UART_CLKSEL 0x2C + +//------------------------------------------------------ +// PIO0 block 0x0050_0600 +// PIO1 block 0x0050_0A00 +//------------------------------------------------------ +#define JASPER_PIO0_BASE 0x00500600 +#define JASPER_PIO1_BASE 0x00500A00 + +#define PIO_INT_STATUS 0x00000000 +#define PIO_DATA 0x00000004 +#define PIO_DIR 0x00000008 +#define PIO_POL 0x0000000C +#define PIO_INT_ENABLE 0x00000010 + + +//------------------------------------------------------ +// I2C MASTER REGISTERs 0X0050_0800 +//------------------------------------------------------ +#define JASPER_I2C_MASTER_BASE 0x00500800 + +#define I2C_MASTER_CONFIG 0x00 +#define I2C_MASTER_CLK_DIV 0x04 +#define I2C_MASTER_DEV_ADDR 0x08 +#define I2C_MASTER_ADR 0x0C +#define I2C_MASTER_DATAOUT 0x10 +#define I2C_MASTER_DATAIN 0x14 +#define I2C_MASTER_STATUS 0x18 +#define I2C_MASTER_STARTXFER 0x1C +#define I2C_MASTER_BYTE_COUNT 0x20 +#define I2C_MASTER_INTEN 0x24 +#define I2C_MASTER_INT 0x28 + + +//------------------------------------------------------ +// I2C SLAVE REGISTERs 0X0050_0900 +//------------------------------------------------------ +#define JASPER_I2C_SLAVE_BASE 0x00500900 + +#define I2C_SLAVE_ADDR 0x00 +#define I2C_SLAVE_DATAOUT 0x04 +#define I2C_SLAVE_DATAIN 0x08 +#define I2C_SLAVE_STATUS 0x0C +#define I2C_SLAVE_INTEN 0x10 +#define I2C_SLAVE_INT 0x14 +#define I2C_SLAVE_BUS_HOLD 0x18 + +//------------------------------------------------------ +// IDE_REGISTERs 0x0050_0B00 +//------------------------------------------------------ +#define JASPER_IDE_BASE 0x00500B00 + +#define JASPER_IDE_DMA_BASE 0x00500E00 + + // **** DMA CHANNEL REG **** +#define IDE_BMIC 0x00 // ( 8 BIT) BMIC IDE COMMAND REG +#define IDE_BMIS 0x04 // ( 8 BIT) BMIC IDE STATUS REG +#define IDE_BMIDTP 0x08 // (32 BIT) BUSMASTER IDE DESCRIPTOR TABLE POINTER REG +#define IDE_TIM 0x40 // (16 BIT) IDE TIMING Reg +#define IDE_SIDETIM 0x48 // ( 8 BIT) SLAVE IDE TIMING Reg +#define IDE_SRC 0x4C // (16 BIT) SLEW RATE CTRL Reg (45h-46h) +#define IDE_STATUS 0x50 // ( 8 BIT) IDESTATUS +#define IDE_UDMACTL 0x54 // ( 8 BIT) ULTRA DMA CONTORL Reg +#define IDE_UDMATIM 0x58 // (16 BIT) ULTRA DMA TIMING Reg (4A - 4B) +#define IDE_PRI_DEVICE_CONTROL 0xE6 // (16 BIT) Device 0: +#define IDE_PRI_DATA 0xF0 // (16 BIT) Device 0: +#define IDE_PRI_SECTOR_COUNT 0xF2 // (16 BIT) Device 0: +#define IDE_PRI_DEVICE_HEAD 0xF6 // (16 BIT) Device 0: +#define IDE_PRI_CMD 0xF7 // (16 BIT) Device 0: + + +//------------------------------------------------------ +// DVD-LOADER_REGISTERs 0x0050_0C00 +//------------------------------------------------------ +#define JASPER_DVD_BASE 0x00500C00 +#define DVD_AV_CTRL 0x00 // (16 BIT) AUDIO/VIDEO PART FROM HOST +#define DVD_AV_SEC_CNT 0x04 // +#define DVD_AV_BYTE_CNT 0x08 // +#define DVD_AV_INTMSK 0x0C // +#define DVD_AV_INT 0x10 // +#define DVD_FIFO_LIM 0x14 // +#define DVD_TIMOUT_LIM 0x18 // +#define DVD_AV_X2C 0x1C // +#define DVD_HOST_CTRL 0x20 // +#define DVD_HOST_SCLK 0x24 // +#define DVD_HOST_TXREG 0x28 // +#define DVD_HOST_RXREG 0x2C // + +//------------------------------------------------------ +// FIP REGISTERs 0x0050_0D00 +//------------------------------------------------------ + +#define JASPER_FIP_BASE 0x00500D00 + +#define FIP_COMMAND 0x00 +#define FIP_DISPLAY_DATA 0x04 +#define FIP_LED_DATA 0x08 +#define FIP_KEY_DATA1 0x0C +#define FIP_KEY_DATA2 0x10 +#define FIP_SWITCH_DATA 0x14 +#define FIP_CLK_DIV 0x20 +#define FIP_TRISTATE_MODE 0x24 + +//------------------------------------------------------ +// DVD-DMA REGISTERs 0x0050_0F00 +//------------------------------------------------------ +#define JASPER_DVD_DMA_BASE 0x00500F00 +#define DVD_DMACTL 0x00 // +#define DVD_DMAMSK 0x04 // +#define DVD_DMAINT 0x08 // +#define DVD_DMARAW 0x0C // +#define DVD_RXADDR 0x10 // +#define DVD_RXBYTES 0x14 // + +//------------------------------------------------------ +// RTC REGISTER 0x0050_1400 +//------------------------------------------------------ +#define JASPER_RTC_BASE 0x00501400 +#define RTC_CTRL 0x00000000 +#define RTC_LOAD1 0x00000004 +#define RTC_LOAD2 0x00000008 +#define RTC_ALARM 0x0000000C +#define RTC_INTEN 0x00000010 +#define RTC_INT0 0x00000014 +#define RTC_COUNT1 0x00000018 +#define RTC_COUNT2 0x0000001C + +//------------------------------------------------------ +// HOST/QUASAR SLAVE REGISTERS 0x0050_1500 +//------------------------------------------------------ +#define JASPER_HOST_SLAVE_QUASAR_BASE 0x00501500 + +#define HOST_SLAVE_WR_QUASAR_BYTE 0x00000000 +#define HOST_SLAVE_WR_QUASAR_1BYTE 0x00000000 +#define HOST_SLAVE_WR_QUASAR_2BYTE 0x00000004 +#define HOST_SLAVE_WR_QUASAR_3BYTE 0x00000008 +#define HOST_SLAVE_WR_QUASAR_4BYTE 0x0000000C + +#define HOST_SLAVE_RD_QUASAR_BYTE 0x00000000 +#define HOST_SLAVE_RD_QUASAR_1BYTE 0x00000000 +#define HOST_SLAVE_RD_QUASAR_2BYTE 0x00000004 +#define HOST_SLAVE_RD_QUASAR_3BYTE 0x00000008 +#define HOST_SLAVE_RD_QUASAR_4BYTE 0x0000000C + +//------------------------------------------------------ +// I2S REGISTERs 0x0050_1600 +//------------------------------------------------------ +#define JASPER_I2S_BASE 0x00501600 + +#define I2S_CTRL 0x0 +#define I2S_PROG_LEN 0x4 +#define I2S_STATUS 0x8 +#define I2S_FRAME_CNTR 0xC + +#define I2S_RESET 0x2 +#define I2S_ENABLE 0x1 +#define I2S_MASTER_MODE 0x4 +#define I2S_SCIN_DIV00 0x00 +#define I2S_SCIN_DIV01 0x08 +#define I2S_SCIN_DIV10 0x10 +#define I2S_SCIN_DIV11 0x18 + +//------------------------------------------------------ +// SPI/I2S_DMA REGISTERs 0x0050_1700 +//------------------------------------------------------ +#define JASPER_SPI_I2S_DMA_BASE 0x00501700 + +#define SPI_I2S_DMA_CTRL_REG 0x0 +#define SPI_I2S_DMA_BASE_ADD_REG 0x4 +#define SPI_I2S_DMA_SIZE_REG 0x8 +#define SPI_I2S_DMA_WR_PTR_REG 0xC +#define SPI_I2S_DMA_RD_PTR_REG 0x10 +#define SPI_I2S_DMA_TRSH_REG 0x14 +#define SPI_I2S_DMA_INT_EN_REG 0x18 +#define SPI_I2S_DMA_INT_REG 0x1C +#define SPI_I2S_DMA_INT_POLL_REG 0x20 +#define SPI_I2S_DMA_INTER_FIFO_REG 0x24 +#define SPI_I2S_DMA_CNT_REG 0x28 + +//------------------------------------------------------ +// SPI REGISTERs 0x0050_1800 +//------------------------------------------------------ +#define JASPER_SPI_BASE 0x00501800 + +#define SPI_CNTR 0x0 +#define SPI_REC_COUNTER 0x4 +#define SPI_INT_EN 0x8 +#define SPI_INT_STATUS 0xC +#define SPI_ERROR_CNT 0x10 + + +//------------------------------------------------------ +// QUASAR PM/DM AREA +//------------------------------------------------------ +#define JASPER_QUASAR_BASE 0x00600000 + +#define QUASAR_MAP_AREA 0x00600000 +#define QUASAR_PM_START 0x00600000 +#define QUASAR_PM_SIZE 0x00002000 +#define QUASAR_DM_START 0x00604000 +#define QUASAR_DM_SIZE 0x00002000 + +//------------------------------------------------------ +// QUASAR DRAM CONTROLLER +//------------------------------------------------------ + +#define QUASAR_DRAM_CFG 0x00007000 +#define QUASAR_DRAM_FIFOSIZE0 0x00007004 +#define QUASAR_DRAM_FIFOSIZE1 0x00007008 +#define QUASAR_DRAM_CASDELAY 0x0000700C +#define QUASAR_DRAM_PLLCONTROL 0x00007010 +#define QUASAR_DRAM_TK0 0x00007014 +#define QUASAR_DRAM_TK1 0x00007018 +#define QUASAR_DRAM_TK2 0x0000701C +#define QUASAR_DRAM_STARTUP0 0x00007020 +#define QUASAR_DRAM_STARTUP1 0x00007024 +#define QUASAR_DRAM_AC3_BASE 0x00007028 +#define QUASAR_DRAM_FIFOSIZE2 0x0000702C +#define QUASAR_DRAM_PORTMUX 0x00007030 + +//------------------------------------------------------ +// QUASAR <-> HOST INTERFACE ( DMA ENGINES ) +//------------------------------------------------------ + +#define QUASAR_H2Q_READ_ADDRESS_LO 0x00007F80 //0xFE0 +#define QUASAR_H2Q_READ_ADDRESS_HI 0x00007F84 //0xFE1 +#define QUASAR_H2Q_READ_CONTER 0x00007F88 //0xFE2 +#define QUASAR_H2Q_READ_MASTER_ENABLE 0x00007F8C //0xFE3 +#define QUASAR_H2Q_INT_MASK 0x00007F90 //0xFE4 +#define QUASAR_H2Q_INT 0x00007F94 //0xFE5 +#define QUASAR_H2Q_INT_STATUS 0x00007F98 //0xFE6 + +#define QUASAR_Q2H_WRITE_ADDRESS_LO 0x00007FA0 //0xFE8 +#define QUASAR_Q2H_WRITE_ADDRESS_HI 0x00007FA4 //0xFE9 +#define QUASAR_Q2H_WRITE_CONTER 0x00007FA8 //0xFEA +#define QUASAR_Q2H_WRITE_MASTER_ENABLE 0x00007FAC //0xFEB +#define QUASAR_Q2H_INT_MASK 0x00007FB0 //0xFEC +#define QUASAR_Q2H_INT 0x00007FB4 //0xFED +#define QUASAR_Q2H_INT_STATUS 0x00007FB8 //0xFEE + +#define QUASAR_OSD_SOURCE_ADDRESS_LO 0x00007980 //0xE60 +#define QUASAR_OSD_SOURCE_ADDRESS_HI 0x00007984 //0xE61 +#define QUASAR_OSD_SOURCE_COUNTER 0x00007988 //0xE62 +#define QUASAR_OSD_SOURCE_MUX_ENABLE 0x0000798C //0xE63 +#define QUASAR_OSD_INT_MASK 0x00007990 //0xE64 +#define QUASAR_OSD_INT 0x00007994 //0xE65 +#define QUASAR_OSD_INT_STATUS 0x00007998 //0xE66 + +//------------------------------------------------------ +// QUASAR Local Bus Controller (LBC) +//------------------------------------------------------ + +#define QUASAR_LBC_CONFIG0 0x00007900 //0x1E40 +#define QUASAR_LBC_CONFIG1 0x00007904 //0x1E41 +#define QUASAR_LBC_WRITE_FIFO0_ACCESS 0x00007908 //0x1E42 +#define QUASAR_LBC_WRITE_FIFO0_CNT 0x0000790C //0x1E43 +#define QUASAR_LBC_READ_FIFO0_ACCESS 0x00007910 //0x1E44 +#define QUASAR_LBC_READ_FIFO0_CNT 0x00007914 //0x1E45 +#define QUASAR_LBC_READ_FIFO1_ACCESS 0x00007918 //0x1E46 +#define QUASAR_LBC_READ_FIFO1_CNT 0x0000791C //0x1E47 +#define QUASAR_LBC_WRITE_ADDR 0x00007920 //0x1E48 +#define QUASAR_LBC_WRITE_DATA 0x00007924 //0x1E49 +#define QUASAR_LBC_READ_ADDR 0x00007928 //0x1E4a +#define QUASAR_LBC_READ_DATA 0x0000792C //0x1E4b +#define QUASAR_LBC_BURST_XFER_CTRL 0x00007930 //0x1E4c +#define QUASAR_LBC_STATUS 0x00007934 //0x1E4d +#define QUASAR_LBC_INTERRUPT 0x00007938 //0x1E4e +#define QUASAR_LBC_PGIO 0x0000793C //0x1E4f + +//------------------------------------------------------ +// PIO COMMAND DEFINITIONS +//------------------------------------------------------ +// IN/OUTPUT PIO direction +#define PIO_OUTPUT_BIT0 0x00010001 +#define PIO_OUTPUT_BIT1 0x00020002 +#define PIO_OUTPUT_BIT2 0x00040004 +#define PIO_OUTPUT_BIT3 0x00080008 +#define PIO_OUTPUT_BIT4 0x00100010 +#define PIO_OUTPUT_BIT5 0x00200020 +#define PIO_OUTPUT_BIT6 0x00400040 +#define PIO_OUTPUT_BIT7 0x00800080 +#define PIO_OUTOUT_ALL16BITS 0xFFFFFFFF +// Set DATA to the PIO OUTPUT pin +#define PIO_DATA_BIT0 0x00010001 +#define PIO_DATA_BIT1 0x00020002 +#define PIO_DATA_BIT2 0x00040004 +#define PIO_DATA_BIT3 0x00080008 +#define PIO_DATA_BIT4 0x00100010 +#define PIO_DATA_BIT5 0x00200020 +#define PIO_DATA_BIT6 0x00400040 +#define PIO_DATA_BIT7 0x00800080 + +#define PIO_EN_SET_BIT7 0x00800000 +#define PIO_EN_SET_BIT6 0x00400000 +#define PIO_EN_SET_BIT5 0x00200000 +#define PIO_EN_SET_BIT4 0x00100000 +#define PIO_EN_SET_BIT3 0x00080000 +#define PIO_EN_SET_BIT2 0x00040000 +#define PIO_EN_SET_BIT1 0x00020000 +#define PIO_EN_SET_BIT0 0x00010000 +#define PIO_EN_ALL16_BITS 0xFFFF0000 +#define PIO_EN_BITS15to8 0xFF000000 +#define PIO_EN_BITS7to0 0x00FF0000 + +//------------------------------------------------------ +// INT CTRL COMMAND DEFINITIONS +//------------------------------------------------------ +#define ENABLE_TIMER0_INT 0x00000001 +#define ENABLE_TIMER1_INT 0x00000002 +#define ENABLE_PIO0_INT 0x00000020 +#define ENABLE_PIO1_INT 0x00000040 + +#define GLOBAL_INT_ENABLE 0x80000000 + +#define MAX_INT 0x00800000 +#define Q2H_LOC_INT 0x00400000 +#define Q2H_RISC_INT 0x00200000 +#define SPI_INT 0x00100000 +#define SPI_I2S_DMA_INT 0x00080000 +#define I2S_INT 0x00040000 +#define RTC_INT 0x00020000 +#define Q2P_INT 0x00010000 +#define P2Q_DMA_INT 0x00008000 +#define OSD_DMA_INT 0x00004000 +#define FIP_INT 0x00002000 +#define IDE_DMA_INT 0x00001000 +#define IDE_INT 0x00000800 +#define DVD_DMA_INT 0x00000400 +#define DVD_INT 0x00000200 +#define I2CS_INT 0x00000100 +#define I2CM_INT 0x00000080 +#define PIO1_INT 0x00000040 +#define PIO0_INT 0x00000020 +#define UART1_INT 0x00000008 +#define UART0_INT 0x00000004 +#define WDTIMER_INT 0x00000002 +#define TIMER1_INT 0x00000002 +#define TIMER0_INT 0x00000001 + +#define JASPER_SC_VALID_INT 0x007FFFEF + +//------------------------------------------------------ +// INT CTRL COMMAND DEFINITIONS II for J_IRQCTRL.c +//------------------------------------------------------ +#define ENABLE_INT_GLOBAL 0x80000000 //INT_ENABLE command + +#define ENABLE_INT_TIMER0 0x80000001 //INT_ENABLE command +#define ENABLE_INT_WDTIMER 0x80000002 //INT_ENABLE command +#define ENABLE_INT_UART_1 0x80000004 //INT_ENABLE command +#define ENABLE_INT_UART_2 0x80000008 //INT_ENABLE command + +#define ENABLE_INT_PIO 0x80000020 //INT_ENABLE command +#define ENABLE_INT_PIO1 0x80000040 //INT_ENABLE command +#define ENABLE_INT_I2C_MASTER 0x80000080 //INT_ENABLE command + +#define ENABLE_INT_I2C_SLAVE 0x80000100 //INT_ENABLE command +#define ENABLE_INT_DVD 0x80000200 //INT_ENABLE command +#define ENABLE_INT_DVD_DMA 0x80000400 //INT_ENABLE command +#define ENABLE_INT_IDE 0x80000800 //INT_ENABLE command + +#define ENABLE_INT_IDE_DMA 0x80001000 //INT_ENABLE command +#define ENABLE_INT_FIP 0x80002000 //INT_ENABLE command +#define ENABLE_INT_OSD_DMA 0x80004000 //INT_ENABLE command +#define ENABLE_INT_H2Q_DMA 0x80008000 //INT_ENABLE command + +#define ENABLE_INT_Q2H_DMA 0x80010000 //INT_ENABLE command +#define ENABLE_INT_RTC 0x80020000 //INT_ENABLE command +#define ENABLE_INT_I2S 0x80040000 //INT_ENABLE command +#define ENABLE_INT_I2S_DMA 0x80080000 //INT_ENABLE command + +#define ENABLE_INT_SPI 0x80100000 //INT_ENABLE command +#define ENABLE_INT_Q2H_RISC 0x80200000 //INT_ENABLE command +#define ENABLE_INT_Q2H_LOC 0x80400000 //INT_ENABLE command + +#define DISABLE_INT_GLOBAL 0x7FFFFFFF //INT_ENABLE command +#define DISABLE_INT_UART_1 0xFFFFFFFB //INT_ENABLE command +#define DISABLE_INT_UART_2 0xFFFFFFF7 //INT_ENABLE command +#define DISABLE_INT_ALL 0x10000000 //INT_ENABLE command + +//------------------------------------------------------ +//SYSTEM CTRL COMMAND DEFINITIONS +//------------------------------------------------------ +#define SYSCTRL_CMD_RESET_TIMER 0x00000001 // Bit 0 +#define SYSCTRL_CMD_RESET_INTCTRL 0x00000002 // Bit 1 +#define SYSCTRL_CMD_RESET_UART0 0x00000004 // Bit 2 +#define SYSCTRL_CMD_RESET_UART1 0x00000008 // Bit 3 +#define SYSCTRL_CMD_RESET_MAC 0x00000010 // Bit 4 +#define SYSCTRL_CMD_RESET_PIO0 0x00000020 // Bit 5 +#define SYSCTRL_CMD_RESET_PIO1 0x00000040 // Bit 6 +#define SYSCTRL_CMD_RESET_I2CM 0x00000080 // Bit 7 + +#define SYSCTRL_CMD_RESET_I2CS 0x00000100 // Bit 8 +#define SYSCTRL_CMD_RESET_DVD 0x00000200 // Bit 9 +#define SYSCTRL_CMD_RESET_DVD_DMA 0x00000400 // Bit10 +#define SYSCTRL_CMD_RESET_IDE 0x00000800 // Bit11 +#define SYSCTRL_CMD_RESET_IDE_DMA 0x00001000 // Bit12 +#define SYSCTRL_CMD_RESET_FIP 0x00002000 // Bit13 +#define SYSCTRL_CMD_RESET_OSD_DMA 0x00004000 // Bit14 +#define SYSCTRL_CMD_RESET_H2Q_DMA 0x00008000 // Bit15 + +#define SYSCTRL_CMD_RESET_Q2H_DMA 0x00010000 // Bit16 +#define SYSCTRL_CMD_RESET_RTC 0x00020000 // Bit17 +#define SYSCTRL_CMD_RESET_I2S 0x00040000 // Bit18 +#define SYSCTRL_CMD_RESET_I2S_DMA 0x00080000 // Bit19 +#define SYSCTRL_CMD_RESET_SPI 0x00100000 // Bit20 +#define SYSCTRL_CMD_RESET_SLAVE 0x00200000 // Bit21 +#define SYSCTRL_CMD_RESET_3 0x00400000 // Bit22 +#define SYSCTRL_CMD_RESET_4 0x00800000 // Bit23 + +#define SYSCTRL_CMD_RESET_5 0x01000000 // Bit24 +#define SYSCTRL_CMD_RESET_6 0x02000000 +#define SYSCTRL_CMD_RESET_7 0x03000000 +#define SYSCTRL_CMD_RESET_8 0x04000000 +#define SYSCTRL_CMD_RESET_10 0x10000000 +#define SYSCTRL_CMD_RESET_11 0x20000000 +#define SYSCTRL_CMD_RESET_Q4 0x40000000 // Bit30 +#define SYSCTRL_CMD_RESET_ALL 0x80000000 // Bit31 + +#define FORCE_REMAP 0x1 +#define CPU_ACCESS_240_CLOCKS 0xF // 240 closck +#define CPU_TIMEOUT_15_CLOCK 0xF // 15 clocks +#define CPU_TIMESLOT_ENABLE 0x100 // Enable TIMESLOT mechanism + + +//------------------------------------------------------ +// MAC COMMAND DEFINITIONS +//------------------------------------------------------ +#define SDRAMCLK_EN 0x1 +#define SDRAMINI_SET 0x2 +//#define TIME_SLOT_4DW 0x0 +//#define TIME_SLOT_8DW 0x1 +//#define TIME_SLOT_16DW 0x2 +//#define TIME_SLOT_32DW 0x3 +#define TIME_SLOT_HIGH_ARBITRATION 0x10000 +#define TIME_SLOT_SLOW_ARBITRATION 0x000 + + + +//------------------------------------------------------ +// TIMER COMMAND DEFINITIONS +//------------------------------------------------------ +#define TIMER02IRQ 0xFFFFFFFE +#define TIMER02FIQ 0x00000001 +#define TIMER12IRQ 0xFFFFFFFD +#define TIMER12FIQ 0x00000002 +#define TIMER0_START 0x00000010 +#define TIMER1_START 0x00000020 +#define TIMER0_INT_CLR 0x00000001 +#define TIMER1_INT_CLR 0x00000002 + +#define TIMER_FREE_RUN_MODE 0x00000000 +#define TIMER_PERIODIC_MODE 0x00000010 +#define TIMER_RUN_OUT_MODE 0x00000020 +#define TIMER_COUNT_ENABLE 0x00000080 + +#define TIMER_NO_PRESCALE 0x0 +#define TIMER_PRESCALE_4 0x1 +#define TIMER_PRESCALE_8 0x2 +#define TIMER_PRESCALE_16 0x3 +#define TIMER_PRESCALE_32 0x4 +#define TIMER_PRESCALE_64 0x5 +#define TIMER_PRESCALE_128 0x6 +#define TIMER_PRESCALE_256 0x7 +#define TIMER_PRESCALE_512 0x8 +#define TIMER_PRESCALE_1024 0x9 +#define TIMER_PRESCALE_2048 0xA +#define TIMER_PRESCALE_4096 0xB +#define TIMER_PRESCALE_8192 0xC +#define TIMER_PRESCALE_16384 0xD +#define TIMER_PRESCALE_32768 0xE +#define TIMER_PRESCALE_65536 0xF + + +//------------------------------------------------------ +// SPI COMMAND DEFINITIONS +//------------------------------------------------------ +#define SPI_ENABLE 0x1 +#define SPI_RESET 0x2 +#define SPI_RESET_ERR_CNTR 0x4 +#define SPI_DISABLE_ERR_CHECK 0x8 +#define SPI_STATUS_MASK 0x000070 + +#define SPI_PKT_DONE 0x1 +#define SPI_SIZE_ERR 0x2 +#define SPI_SYNC_ERR 0x4 +#define SPI_HW_ERR 0x8 + +//------------------------------------------------------ +// SPI/I2S-DMA COMMAND DEFINITIONS +//------------------------------------------------------ +#define SPI_I2S_DMA_RESET 0x2 +#define SPI_I2S_DMA_EN 0x1 +#define SPI_I2S_INT_BUF_FULL 0x1 +#define SPI_I2S_INT_BUF_14 0x2 +#define SPI_I2S_INT_BUF_12 0x4 +#define SPI_I2S_INT_BUF_34 0x8 +#define SPI_I2S_CIR_EN 0x8 /* Enable circular buffer */ +#define SPI_I2S_MUX_SPI_SELECT 0x10 +#define SPI_I2S_FLASH_INTER_FIFO 0x4 + +//------------------------------------------------------ +// FIP COMMAND DEFINITIONS +//------------------------------------------------------ +#define FIP_CMD_DISP_MODE_08DIGITS_20SEGMENTS 0x00 +#define FIP_CMD_DISP_MODE_09DIGITS_19SEGMENTS 0x08 +#define FIP_CMD_DISP_MODE_10DIGITS_18SEGMENTS 0x09 +#define FIP_CMD_DISP_MODE_11DIGITS_17SEGMENTS 0x0a +#define FIP_CMD_DISP_MODE_12DIGITS_16SEGMENTS 0x0b +#define FIP_CMD_DISP_MODE_13DIGITS_15SEGMENTS 0x0c +#define FIP_CMD_DISP_MODE_14DIGITS_14SEGMENTS 0x0d +#define FIP_CMD_DISP_MODE_15DIGITS_13SEGMENTS 0x0e +#define FIP_CMD_DISP_MODE_16DIGITS_12SEGMENTS 0x0f + + +#define FIP_CMD_DATA_SET_RW_MODE_WRITE_DISPLAY 0x40 +#define FIP_CMD_DATA_SET_RW_MODE_WRITE_LED_PORT 0x41 +#define FIP_CMD_DATA_SET_RW_MODE_READ_KEYS 0x42 +#define FIP_CMD_DATA_SET_RW_MODE_READ_SWITCHES 0x43 +#define FIP_CMD_DATA_SET_ADR_MODE_INCREMENT_ADR 0x40 +#define FIP_CMD_DATA_SET_ADR_MODE_FIXED_ADR 0x44 +#define FIP_CMD_DATA_SET_OP_MODE_NORMAL_OPERATION 0x40 +#define FIP_CMD_DATA_SET_OP_MODE_TEST_MODE 0x48 + +#define FIP_CMD_ADR_SETTING 0xC0 + +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_1_16 0x80 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_2_16 0x81 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_4_16 0x82 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_10_16 0x83 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_11_16 0x84 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_12_16 0x85 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_13_16 0x86 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_14_16 0x87 +#define FIP_CMD_DISP_CTRL_TURN_DISPLAY_OFF_MASK 0x87 +#define FIP_CMD_DISP_CTRL_TURN_DISPLAY_ON 0x88 + +//--------------------------------------------------------------------------------------------- +// I/O Macro definitions +//--------------------------------------------------------------------------------------------- +#define PRINT_STATUS *( (volatile unsigned int * )SimStatusAddress) +#define VERILOG_STOP *( (volatile unsigned int * )SIMULATION_CONTROL) = SIMULATION_CMD_STOP_WITH_ERROR + +//--------------------------------------------------------------------------------------------- +// QuickTurn Macro definitions +//--------------------------------------------------------------------------------------------- +#define WRITE_LED_DISPLAY PIO_0_DATA_REG +#define WRITE_HEX_DISPLAY PIO_1_DATA_REG + +//--------------------------------------------------------------------------------------------- +// PIO Macro definitions +//--------------------------------------------------------------------------------------------- +#define PIO_0_INT_STATUS_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_INT_STATUS) ) +#define PIO_0_DATA_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_DATA) ) +#define PIO_0_DIR_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_DIR) ) +#define PIO_0_POL_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_POL) ) +#define PIO_0_INT_ENABLE_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_INT_ENABLE) ) + +#define PIO_1_INT_STATUS_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_INT_STATUS) ) +#define PIO_1_DATA_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_DATA) ) +#define PIO_1_DIR_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_DIR) ) +#define PIO_1_POL_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_POL) ) +#define PIO_1_INT_ENABLE_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_INT_ENABLE) ) + +//--------------------------------------------------------------------------------------------- +// SPI_I2S_DMA Macro definitions +//--------------------------------------------------------------------------------------------- +#define SPI_I2S_DMA_REG_CTRL ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_CTRL_REG) ) +#define SPI_I2S_DMA_REG_BASE_ADD ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_BASE_ADD_REG) ) +#define SPI_I2S_DMA_REG_SIZE ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_SIZE_REG) ) +#define SPI_I2S_DMA_REG_WR_PTR ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_WR_PTR_REG) ) +#define SPI_I2S_DMA_REG_RD_PTR ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_RD_PTR_REG) ) +#define SPI_I2S_DMA_REG_TRSH ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_TRSH_REG) ) +#define SPI_I2S_DMA_REG_INT_EN ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INT_EN_REG) ) +#define SPI_I2S_DMA_REG_INT ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INT_REG) ) +#define SPI_I2S_DMA_REG_INT_POLL ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INT_POLL_REG) ) +#define SPI_I2S_DMA_REG_INTER_FIFO ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INTER_FIFO_REG) ) +#define SPI_I2S_DMA_REG_CNT ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_CNT_REG) ) + +//--------------------------------------------------------------------------------------------- +// Memory Access Controller (MAC) Macro definitions +//--------------------------------------------------------------------------------------------- +#define MAC_REFTIMER_REG ( (volatile unsigned int * ) (MAC_base + MAC_REFTIMER) ) +#define MAC_FLASHCFG_REG ( (volatile unsigned int * ) (MAC_base + MAC_FLASH_CFG) ) +#define MAC_SDRAMCTL_REG ( (volatile unsigned int * ) (MAC_base + MAC_SDRAMCTL) ) +#define MAC_SDRAMCFG_REG ( (volatile unsigned int * ) (MAC_base + MAC_SDRAMCFG) ) +#define MAC_SDRAMDATA_REG ( (volatile unsigned int * ) (MAC_base + MAC_SDRAMDATA) ) + +//--------------------------------------------------------------------------------------------- +// Interrupt Controller Macro definitions +//--------------------------------------------------------------------------------------------- +#define INT_IRQSTAT_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_IRQSTAT) ) +#define INT_FIQSTAT_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_FIQSTAT) ) +#define INT_TYPE_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_INTTYPE) ) +#define INT_POLL_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_INTPOLL) ) +#define INT_ENABLE_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_INTEN) ) + +//--------------------------------------------------------------------------------------------- +// SPI Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define SPI_CNTR_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_CNTR) ) +#define SPI_REC_COUNTER_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_REC_COUNTER) ) +#define SPI_INT_EN_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_INT_EN) ) +#define SPI_INT_STATUS_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_INT_STATUS) ) +#define SPI_ERROR_CNT_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_ERROR_CNT) ) + +//--------------------------------------------------------------------------------------------- +// I2S Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define I2S_CTRL_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_CTRL) ) +#define I2S_PROG_LEN_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_PROG_LEN) ) +#define I2S_STATUS_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_STATUS) ) +#define I2S_FRAME_CNTR_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_FRAME_CNTR) ) + +//--------------------------------------------------------------------------------------------- +// RTC Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define RTC_CTRL_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_CTRL) ) +#define RTC_LOAD1_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_LOAD1) ) +#define RTC_LOAD2_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_LOAD2) ) +#define RTC_ALARM_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_ALARM) ) +#define RTC_INTEN_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_INTEN) ) +#define RTC_INT_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_INT0) ) +#define RTC_COUNT1_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_COUNT1) ) +#define RTC_COUNT2_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_COUNT2) ) + +//--------------------------------------------------------------------------------------------- +// Timer Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define TIMER_TMRSTAT_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMRSTAT) ) +#define TIMER0_LOAD_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR0LOAD) ) +#define TIMER0_VAL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR0VAL) ) +#define TIMER0_CNTL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR0CTL) ) + +#define TIMER1_LOAD_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR1LOAD) ) +#define TIMER1_VAL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR1VAL) ) +#define TIMER1_CNTL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR1CTL) ) + +//--------------------------------------------------------------------------------------------- +// Interrupt Registers Macro definitions +//--------------------------------------------------------------------------------------------- +/* XXX - defined twice - see above INT_xxx_REG +#define INTERRUPT_IRQSTAT_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_IRQSTAT) ) +#define INTERRUPT_FIQSTAT_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_FIQSTAT) ) +#define INTERRUPT_INTTYPE_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_INTTYPE) ) +#define INTERRUPT_POLL_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_INTPOLL) ) +#define INTERRUPT_ENABLE_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_INTEN) ) +*/ + +//--------------------------------------------------------------------------------------------- +// System Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define SYS_CHIPID_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_CHIP_ID) ) +#define SYS_REVID_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_REVISION_ID) ) +#define SYS_CPU_CFG_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_CPUCFG) ) +#define SYS_TESTSTAT_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_TESTSTAT) ) +#define SYS_RESET_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_RSTCTL) ) +#define SYS_TIMESLOT_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_CPUTIMESLOT) ) + +//--------------------------------------------------------------------------------------------- +// FIP Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define FIP_COMMAND_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_COMMAND) ) +#define FIP_DISPLAY_DATA_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_DISPLAY_DATA) ) +#define FIP_LED_DATA_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_LED_DATA) ) +#define FIP_KEY_DATA1_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_KEY_DATA1) ) +#define FIP_KEY_DATA2_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_KEY_DATA2) ) +#define FIP_SWITCH_DATA_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_SWITCH_DATA) ) +#define FIP_CLK_DIV_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_CLK_DIV) ) +#define FIP_TRISTATE_MODE_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_TRISTATE_MODE) ) + +#ifndef __ASSEMBLY__ +#include + +#define HARD_RESET_NOW() outl(JASPER_SYSCTRL_BASE + SYSCTRL_RSTCTL,1) + +static inline unsigned long __get_clock(unsigned int unit) +{ + unsigned int clock; +#ifndef CONFIG_QUICKTURN_HACKS + unsigned int pll_reg; + unsigned int pll_mult, pll_div, pll_D; + + pll_reg = inl(JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + pll_mult = (pll_reg & 0xFF) >> 2; + pll_div = (pll_reg >> 8 ) & 0x3; + pll_D = (pll_reg & 0x2); + + clock = ((JASPER_EXT_CLOCK / unit) * (pll_mult+2))/(pll_div + 2); + if(pll_D) + clock = clock / 2; +#else +#warning ***** QUICKTURN HACK ***** Kernel think CPU clock is 4 Mhz + clock = 4000000 / unit; +#endif + return clock; +} +#endif + +#endif /* _ASM_ARCH_HARDWARE_H */ + + diff --git a/src/libsp/MG35/sp_cdrom.cpp b/src/libsp/MG35/sp_cdrom.cpp new file mode 100644 index 0000000..7cbf44f --- /dev/null +++ b/src/libsp/MG35/sp_cdrom.cpp @@ -0,0 +1,651 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CDROM driver's functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_cdrom.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __USE_LARGEFILE64 +#define __USE_LARGEFILE64 +#endif + +#include + +#include +#include + +#include "sp_misc.h" +#include "sp_msg.h" +#include "sp_cdrom.h" + +/// CD-ROM fs mount flag +static BOOL cdrom_cd_mounted = FALSE, cdrom_hdd_mounted = FALSE, cdrom_cd_inserted = FALSE; +static BOOL cdrom_cd = FALSE, cdrom_hdd = FALSE, cdrom_hdd_root = FALSE; +/// CD-ROM fs mount language +static char *def_cdrom_language = "iso8859-1"; +static char *cdrom_language = NULL; +static char cdrom_last_letter = 'c'; +static CDROM_STATUS cdrom_hdd_status = CDROM_STATUS_HAS_ISO; + +/// Internal function used by cdrom_getstatus() +static int cdrom_getmediumtype(); + +#if 0 +static void cdrom_count_tracks(); +#endif + +/// OS-specific path to CD-ROM. Used by cdrom_getdevicepath() +static const char *curdvdpath = "/dev/cdroms/cdrom0"; + +/// CD-ROM device handle +int cdrom_handle = -1; +int cdrom_hdd_handle[2] = { -1, -1 }; + +/// Used by cdrom_getmediumtype(). +/// Taken from linux/cdrom.h (kernel mode) + +struct mode_page_header +{ + WORD mode_data_length; + BYTE medium_type; + BYTE reserved1; + BYTE reserved2; + BYTE reserved3; + WORD desc_length; +}; + + +/// Used by cdrom_getmediumtype(). +/// Taken from drivers/ide/ide-cd.h (uClinux source) +struct atapi_capabilities_page +{ + struct mode_page_header header; + BYTE caps[20]; +}; + + +BOOL cdrom_init() +{ + cdrom_deinit(); + + cdrom_language = SPstrdup(def_cdrom_language); + cdrom_hdd_mounted = FALSE; + cdrom_cd_mounted = FALSE; + cdrom_cd_inserted = FALSE; + + // try CD-ROM + cdrom_handle = open("/dev/cdroms/cdrom0", O_NONBLOCK); + if (cdrom_handle >= 0) + { + cdrom_cd = TRUE; + printf("cdrom: CD-ROM Detected!\n"); + } + // try HDD + for (int i = 0; i < 2; i++) + { + char hdd_name[40]; + sprintf(hdd_name, "/dev/discs/disc%d/disc", i); + cdrom_hdd_handle[i] = open(hdd_name, O_NONBLOCK); + if (cdrom_hdd_handle[i] >= 0) + { + cdrom_hdd = TRUE; + printf("cdrom: HDD-%d Detected!\n", i+1); + } + } + + return (cdrom_handle != -1 || cdrom_hdd_handle[0] != -1 || cdrom_hdd_handle[1] != -1); +} + +BOOL cdrom_switch(BOOL on) +{ + if (cdrom_hdd) + { + BYTE args1[4], args2[4]; + int r1, r2 = 0; + + for (int i = 0; i < 2; i++) + { + if (on) + { + static const BYTE on_args1[4] = { WIN_SETIDLE1, 0, 0, 0 }; + static const BYTE on_args2[4] = { WIN_SETIDLE2, 0, 0, 0 }; + + memcpy(args1, on_args1, 4); + memcpy(args2, on_args2, 4); + } else + { + static const BYTE off_args1[4] = { WIN_STANDBYNOW1, 0, 0, 0 }; + static const BYTE off_args2[4] = { WIN_STANDBYNOW2, 0, 0, 0 }; + + memcpy(args1, off_args1, 4); + memcpy(args2, off_args2, 4); + } + + if (cdrom_hdd_handle[i] == -1) + continue; + r1 = ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &args1); + if (r1 != 0) + r2 = ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &args2); + + printf("HDD-%d: Switch %s (result=%d,%d)\n", i+1, (on ? "On" : "Off"), r1, r2); + + // now check the results... + BYTE cp_args1[4] = { WIN_CHECKPOWERMODE1, 0, 0, 0 }; + BYTE cp_args2[4] = { WIN_CHECKPOWERMODE2, 0, 0, 0 }; + const char *state; + if (ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &cp_args1) && ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &cp_args2)) + { + if (errno != EIO || cp_args1[0] != 0 || cp_args1[1] != 0) + state = "Unknown"; + else + state = "Sleeping"; + } else + { + if (cp_args1[2] == 255 || cp_args2[2] == 255) + state = "Active/Idle"; + else + state = "Standby"; + } + msg("HDD-%d: Drive state is: %s\n", i+1, state); + } + } + if (cdrom_cd) + { + if (on) + ioctl(cdrom_handle, CDROMSTART); + else + ioctl(cdrom_handle, CDROMSTOP); + + printf("CD: Switch %s\n", (on ? "On" : "Off")); + } + return TRUE; +} + +BOOL cdrom_deinit() +{ + if (cdrom_handle != -1) + close (cdrom_handle); + if (cdrom_hdd_handle[0] != -1) + close (cdrom_hdd_handle[0]); + if (cdrom_hdd_handle[1] != -1) + close (cdrom_hdd_handle[1]); + cdrom_handle = -1; + cdrom_hdd_handle[0] = cdrom_hdd_handle[1] = -1; + SPSafeFree(cdrom_language); + return TRUE; +} + +int cdrom_eject(BOOL open) +{ + if (cdrom_cd) + { + struct timeval tv; + struct timezone tz; + int start_time, stop_time; + + cdrom_generic_command cmd; + struct request_sense sense; + + cdrom_umount(); + + // [bombur]: I wish it was true... :-( + //return ioctl(cdrom_handle, CDROMEJECT, 0); + + // [bombur]: this is the exact code used in original init! + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; + cmd.cmd[4] = 0; // unlock + cmd.buffer = NULL; + cmd.buflen = 0; + cmd.sense = &sense; + cmd.data_direction = CGC_DATA_READ; + ioctl(cdrom_handle, CDROM_SEND_PACKET, &cmd); + + gettimeofday(&tv, &tz); + start_time = tv.tv_sec * 1000 + (tv.tv_usec / 1000); + + cmd.cmd[0] = GPCMD_START_STOP_UNIT; + cmd.cmd[1] = 1; + cmd.cmd[4] = open ? 2 : 3; + if (ioctl(cdrom_handle, CDROM_SEND_PACKET, &cmd)) + return -1; + + do + { + gui_update(); + usleep(10000); + gettimeofday(&tv, &tz); + stop_time = tv.tv_sec * 1000 + (tv.tv_usec / 1000); + } while (stop_time - start_time < 2000); // less than 2 seconds passed - wait! + + return 0; + } + else if (cdrom_hdd) + { + // emulate 'ejecting' HDD - to enable 'Setup' mode possibility + cdrom_hdd_status = open ? CDROM_STATUS_TRAYOPEN : CDROM_STATUS_HAS_ISO; + return 0; + } + + return -1; +} + +int cdrom_mount(char *language, BOOL cd_only) +{ + int ret = 0; + char iocharset[1024]; + if (language == NULL) + language = cdrom_language; + + BOOL lang_changed = strcasecmp(cdrom_language, language) != 0; + if (cdrom_cd && cdrom_cd_inserted) + { + if (!cdrom_cd_mounted || lang_changed) + { + int rmnt = ((cdrom_cd_mounted && lang_changed) ? MS_REMOUNT : 0); + sprintf(iocharset, "iocharset=%s", language); + ret = mount("/dev/cdroms/cdrom0", "/cdrom", "iso9660", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + msg("CD: mount with %s(%d) = %d\n", iocharset, rmnt, ret < 0 ? -errno : ret); + if (ret >= 0) + { + cdrom_cd_mounted = TRUE; + } + } +// cdrom_count_tracks(); + } + + if (cdrom_hdd && !cd_only) + { + if (!cdrom_hdd_mounted || lang_changed) + { + char tmpdir[256], tmpmnt[256]; + char dirname[40]; + char *mntname = "/hdd/"; + char mnt_char = 'c'; + struct dirent *entry; + //int rmnt = ((cdrom_hdd_mounted && lang_changed) ? MS_REMOUNT : 0); + int rmnt = 0; + for (int i = 0; i < 2; i++) + { + if (cdrom_hdd_handle[i] < 0) + continue; + sprintf(dirname, "/dev/discs/disc%d", i); + DIR *dir = opendir(dirname); + printf("Mounting HDD-%d...\n", i+1); + while ((entry = readdir(dir)) != NULL) + { + if (memcmp(entry->d_name, "part", 4) == 0) + { + sprintf(tmpdir, "%s/%s", dirname, entry->d_name); + sprintf(tmpmnt, "%s%c", mntname, mnt_char); + + if (lang_changed) + umount(tmpmnt); + + printf("* Mounting %s AS FAT: ", tmpdir);fflush(stdout); + sprintf(iocharset, "iocharset=%s", language); + ret = mount(tmpdir, tmpmnt, "vfat", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + if (ret < 0) + { + printf("NO. Mounting AS NTFS: ");fflush(stdout); + sprintf(iocharset, "nls=%s", language); + ret = mount(tmpdir, tmpmnt, "ntfs", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + } + printf(ret < 0 ? "FAILED\n" : "OK\n");fflush(stdout); + if (ret >= 0) + { + mnt_char++; + cdrom_hdd_mounted = TRUE; + } + } + } + cdrom_last_letter = mnt_char - 1; + closedir(dir); + + msg("HDD-%d: mount with %s(%d) = %d\n", i+1, iocharset, rmnt, ret < 0 ? -errno : ret); + } + } + } + + if (lang_changed) + { + SPSafeFree(cdrom_language); + cdrom_language = SPstrdup(language); + } + + return ret; +} + +int cdrom_umount() +{ + msg("CD-ROM: umount.\n"); + if (cdrom_cd) + { + cdrom_cd_mounted = FALSE; + return umount("/cdrom"); + } + return FALSE; +} + +BOOL cdrom_ismounted() +{ + return cdrom_cd ? cdrom_cd_mounted : cdrom_hdd_mounted; +} + +static CDROM_STATUS cdrom_detect_dvd() +{ + char dvdpath2[1024]; + + cdrom_cd_inserted = TRUE; + + cdrom_mount(NULL, TRUE); + + DIR *dir = opendir("/cdrom"); + struct dirent *entry; + struct stat statbuf; + while ((entry = readdir(dir)) != NULL) + { + if (strcasecmp(entry->d_name, "VIDEO_TS") == 0) + { + sprintf(dvdpath2, "/cdrom/%s", entry->d_name); + if (stat(dvdpath2, &statbuf) >= 0) + { + if (S_ISDIR(statbuf.st_mode)) + { + closedir(dir); + cdrom_umount(); + return CDROM_STATUS_HAS_DVD; + } + } + } + } + closedir(dir); + + cdrom_umount(); + return CDROM_STATUS_HAS_ISO; +} + +CDROM_STATUS cdrom_getstatus() +{ + static int old_medium = -1; + static CDROM_STATUS old_status = CDROM_STATUS_UNKNOWN; + + if (!cdrom_cd && cdrom_hdd) + return cdrom_hdd_status; + + if (cdrom_handle != -1) + { + int medium = cdrom_getmediumtype(), auxtype; + + if (medium != old_medium) + msg("Drive: medium type = %d.\n", medium); + + switch (medium) + { + case 112: + old_status = cdrom_hdd ? cdrom_hdd_status : CDROM_STATUS_NODISC; + cdrom_cd_inserted = FALSE; + old_medium = medium; + return old_status; + case 113: + old_status = CDROM_STATUS_TRAYOPEN; + cdrom_cd_inserted = FALSE; + old_medium = medium; + return old_status; + case 1: + case 4: + case 5: + case 8: + case 0x11: + case 0x14: + case 0x15: + case 0x18: + case 0x21: + case 0x24: + case 0x25: + case 0x28: + // [bombur]: mixed discs are not always recognized by mediumtype + auxtype = ioctl(cdrom_handle, CDROM_DISC_STATUS, CDSL_CURRENT); + old_status = (auxtype == CDS_MIXED) ? CDROM_STATUS_HAS_MIXED : CDROM_STATUS_HAS_ISO; + old_medium = medium; + cdrom_cd_inserted = TRUE; + return old_status; + case 2: + case 6: + case 0x12: + case 0x16: + case 0x22: + case 0x26: + old_medium = medium; + old_status = CDROM_STATUS_HAS_AUDIO; + cdrom_cd_inserted = TRUE; + return old_status; + case 3: + case 7: + case 0x13: + case 0x17: + case 0x23: + case 0x27: + old_medium = medium; + old_status = CDROM_STATUS_HAS_MIXED; + cdrom_cd_inserted = TRUE; + return old_status; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + if (old_medium < 0x40 || old_medium > 0x48 || old_status == CDROM_STATUS_UNKNOWN) + old_status = cdrom_detect_dvd(); + old_medium = medium; + return old_status; + case 0: + old_medium = medium; + break; + default: + if (medium != old_medium) + msg("Drive: Unknown medium type = %d.\n", medium); + old_medium = medium; + break; + } + } + return CDROM_STATUS_UNKNOWN; +} + +BOOL cdrom_isready() +{ + // ready or not, we failed + if (cdrom_handle == -1) + return TRUE; + if (cdrom_hdd && !cdrom_cd) + return TRUE; + + int drive = ioctl(cdrom_handle, CDROM_DRIVE_STATUS, CDSL_CURRENT); + int disc = ioctl(cdrom_handle, CDROM_DISC_STATUS, CDSL_CURRENT); + +// msg("CD-ROM: drive.status = %d disc.status = %d.\n", drive, disc); +// gui_update(); + + if (/*drive == CDS_TRAY_OPEN || */drive == CDS_DRIVE_NOT_READY || + /*disc == CDS_TRAY_OPEN || */disc == CDS_DRIVE_NOT_READY) + return FALSE; + return TRUE; +} + +/// Internal function used by cdrom_getstatus() +/// [bombur]: this was die hard! +int cdrom_getmediumtype() +{ + cdrom_generic_command cmd; + struct request_sense sense; + struct atapi_capabilities_page caps; + + if (cdrom_handle != -1) + { + memset(&cmd, 0, sizeof(cmd)); + cmd.buffer = (BYTE *)∩︀ + cmd.buflen = sizeof(caps); + cmd.cmd[0] = GPCMD_MODE_SENSE_10; + cmd.cmd[2] = GPMODE_CAPABILITIES_PAGE; + cmd.cmd[8] = cmd.buflen & 0xff; + cmd.sense = &sense; + cmd.data_direction = CGC_DATA_READ; + ioctl(cdrom_handle, CDROM_SEND_PACKET, &cmd); + + return caps.header.medium_type; + } + return 0; +} + +const char *cdrom_getdevicepath(const char *src_path) +{ + if (src_path != NULL) + return src_path; + return curdvdpath; +} + +int cdrom_stat(const char *path, struct stat64 *s) +{ + return stat64(path, s); +} + +DIR *cdrom_opendir(const char *path) +{ + cdrom_hdd_root = FALSE; + if (cdrom_hdd) + { + if (strcasecmp(path, "/hdd/") == 0) + cdrom_hdd_root = TRUE; + } + return opendir(path); +} + +struct dirent *cdrom_readdir(DIR *dir) +{ + struct dirent *d = readdir(dir); + // fast mount-check (exclude unmounted folders) + if (cdrom_hdd_root && d->d_name[0] > cdrom_last_letter && d->d_name[1] == '\0') + return NULL; + return d; +} + +int cdrom_closedir(DIR *dir) +{ + return closedir(dir); +} + +int cdrom_open(const char *fname, int flags) +{ + return open(fname, flags); +} + +char *cdrom_getrealpath(const char *path) +{ + static char tmpp[4096]; +msg("CD-ROM: GET_REAL_PATH (%s) = %d %d %d\n", path, cdrom_hdd, cdrom_cd, cdrom_cd_inserted); + if (memcmp(path, "/", 2) == 0) + { + if (cdrom_hdd && cdrom_cd && cdrom_cd_inserted) + return (char *)path; + else if (cdrom_hdd) + strcpy(tmpp, "/hdd"); + else + strcpy(tmpp, "/cdrom"); + strcat(tmpp, path); + return tmpp; + } + return (char *)path; +} + + +#if 0 +void cdrom_count_tracks() +{ + struct cdrom_tochdr header; + struct cdrom_tocentry entry; + int ret, i; +/* + tracks->data=0; + tracks->audio=0; + tracks->cdi=0; + tracks->xa=0; + tracks->error=0; +*/ + /* Grab the TOC header so we can see how many tracks there are */ + if ((ret = ioctl(cdrom_handle, CDROMREADTOCHDR, &header))) + { + if (ret == -ENOMEDIUM) + msg("cdrom_count_tracks: CDS_NO_DISC!"); + else + msg("cdrom_count_tracks: CDS_NO_INFO!"); + return; + } + /* check what type of tracks are on this disc */ + entry.cdte_format = CDROM_MSF; + msg("Starting %d-%d:\n", header.cdth_trk0, header.cdth_trk1); + for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) + { + entry.cdte_track = i; + if (ioctl(cdrom_handle, CDROMREADTOCENTRY, &entry)) + { + msg("track %2d: CDS_NO_INFO\n"); + continue; + } + /* + if (entry.cdte_ctrl & CDROM_DATA_TRACK) + { + if (entry.cdte_format == 0x10) + tracks->cdi++; + else if (entry.cdte_format == 0x20) + tracks->xa++; + else + tracks->data++; + } else + tracks->audio++; + */ + msg("track %2d: fmt=0x%x, ctrl=0x%x\n", i, entry.cdte_format, entry.cdte_ctrl); + } + /* + cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", + header.cdth_trk1, tracks->audio, tracks->data, + tracks->cdi, tracks->xa); + */ + usleep(1000000); +} +#endif diff --git a/src/libsp/MG35/sp_eeprom.cpp b/src/libsp/MG35/sp_eeprom.cpp new file mode 100644 index 0000000..1502220 --- /dev/null +++ b/src/libsp/MG35/sp_eeprom.cpp @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - EEPROM interface functions source file + * For Technosonic-compatible players ('MP') + * \file sp_eeprom.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" +#include "sp_eeprom.h" + +BOOL eeprom_set_value(DWORD addr, DWORD val, int size) +{ + KHWL_ADDR_DATA data; + /// \warning: not usual byte order used! + for (int i = 0; i < size; i++) + { + data.Addr = addr + i; + data.Data = (val >> (i * 8)) & 0xff; + khwl_setproperty(KHWL_EEPROM_SET, eEepromAccess, sizeof(data), &data); + } + return TRUE; +} + +DWORD eeprom_get_value(DWORD addr, int size) +{ + KHWL_ADDR_DATA data; + DWORD val = 0; + /// \warning: not usual byte order used! + for (int i = 0; i < size; i++) + { + data.Addr = addr + i; + data.Data = 0; + khwl_getproperty(KHWL_EEPROM_SET, eEepromAccess, sizeof(data), &data); + val |= (data.Data & 0xff) << (i * 8); + } + return val; +} + diff --git a/src/libsp/MG35/sp_fip.cpp b/src/libsp/MG35/sp_fip.cpp new file mode 100644 index 0000000..44f82f4 --- /dev/null +++ b/src/libsp/MG35/sp_fip.cpp @@ -0,0 +1,261 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP interface functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_fip.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_fip.h" +#include "sp_fip_ioctl.h" + +#if defined(SP_PLAYER_TECHNOSONIC) + #include "sp_fip_codes-technosonic.h" +#elif defined(SP_PLAYER_DREAMX108) + #include "sp_fip_codes-dreamx108.h" +#endif + +/// Characters supported by LED +static unsigned char char_table[] = " -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-\1"; +/// Current LEF data storage +static unsigned char fipram[12]; +/// Binary definitions for LED data +static unsigned char led_table[] = +{ + 0x00,0x10,0xEE,0x48,0xD6,0xDA,0x78,0xBA,0xBE,0xC8,0xFE,0xFA,0xFC,0xFE,0xA6,0xEE, + 0xB6,0xB4,0xBE,0x7C,0x48,0x4A,0x7C,0x26,0xEC,0xEC,0xEE,0xF4,0xEE,0xFC,0xBA,0xC8, + 0x6E,0x6E,0x6E,0x6C,0x78,0x82,0x02,0x1E,0x3E,0x16,0x5E,0xF6,0xB4,0xFA,0x3C,0x08, + 0x0A,0x2C,0x26,0x1C,0x1C,0x1E,0xF4,0xF8,0x14,0xBA,0x36,0x0E,0x0E,0x0E,0x0C,0x78, + 0x12,0x10,0x00 +}; + +static unsigned char led_special[] = +{ + 0x01, 0x07, 0x01, 0x06, 0x03, 0x07, 0x02, 0x07, 0x05, 0x07, 0x04, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x05, 0x07, 0x04, 0x07, 0x03, 0x07, 0x02, 0x07, 0x01, 0x07, 0x00, 0x09, 0x07, 0x09, 0x06, + 0x09, 0x05, 0x09, 0x04, 0x09, 0x03, 0x09, 0x02, 0x09, 0x01, 0x09, 0x00, 0x08, 0x07, 0x08, 0x06, + 0x08, 0x05, 0x08, 0x04, 0x08, 0x03, 0x08, 0x02 +}; + +/// Button codes translation look-up table +static BYTE *button_LUT = NULL; +static DWORD butcode = 0; +static int fip_panel_num_codes = 0; + +/// FIP device handle +int fip_handle = -1; + +void fip_create_table(BYTE *lut) +{ + memset(lut, 0xff, 65536); + + DWORD *codes[2]; + codes[0] = fip_panel_codes; + codes[1] = fip_remote_codes; + + fip_panel_num_codes = 0; + for (int i = 0; i < 2; i++) + { + int j; + for (j = 0; codes[i][j] != 0xffffffff; j++) + { + lut[codes[i][j] & 0xffff] = j; + } + if (i == 0) + fip_panel_num_codes = j; + } +} + +BOOL fip_init(BOOL applymodule) +{ + fip_deinit(); + + if (applymodule == FALSE || module_apply("/drivers/fipmodule.o")) // insert + { + fip_handle = open("/dev/fip", O_NONBLOCK, 0); + if (fip_handle != -1) + { + fip_clear(); + + button_LUT = (BYTE *)SPmalloc(65536); + if (button_LUT == NULL) + return FALSE; + + fip_create_table(button_LUT); + + return TRUE; + } + } + + return FALSE; +} + +BOOL fip_deinit() +{ + if (fip_handle == -1) + return FALSE; + close(fip_handle); + fip_handle = -1; + + if (button_LUT != NULL) + { + SPfree(button_LUT); + button_LUT = NULL; + } + + return TRUE; +} + +BOOL fip_clear() +{ + int i; + + if (fip_handle == -1) + return FALSE; + // clear FIP + for (i = 0; i < 10; i++) + { + fipram[i] = 0; +// ioctl(fip_handle, FIP_DISPLAY_SYMBOL, i << 16); + } + return TRUE; +} + +BOOL fip_write_char(int ch, int pos) +{ + int lr; + unsigned char old_fip1, old_fip2 = 0; + + if (pos < 1 || pos - 1 > 6 || fip_handle == -1) + return FALSE; + ch &= 255; + for (lr = 0; lr < 66; lr++) + { + if (char_table[lr] == (BYTE)ch) + break; + } + // saving + old_fip1 = fipram[pos-1]; + + // clear + if (pos == 2) + { + old_fip2 = fipram[pos-2]; + + fipram[pos-1] &= 192; + fipram[pos-2] &= 127; + } else + fipram[pos-1] &= 128; + // set + if (pos == 2) + { + fipram[pos-1] |= led_table[lr] >> 2; + fipram[pos-2] |= (led_table[lr] << 6) & ~127; + } else + fipram[pos-1] |= led_table[lr] >> 1; + // write to device +// if (old_fip1 != fipram[pos-1]) +// ioctl(fip_handle, FIP_DISPLAY_SYMBOL, fipram[pos-1] | ((pos-1) << 16)); +// if (pos == 2 && old_fip2 != fipram[pos-2]) +// ioctl(fip_handle, FIP_DISPLAY_SYMBOL, fipram[pos-2] | ((pos-2) << 16)); + return TRUE; +} + +BOOL fip_write_string(const char *str) +{ + int i, len; + if (str == NULL || fip_handle == -1) + return FALSE; + len = strlen(str); + if (len > 7) + len = 7; + for (i = 0; i < 7; i++) + fip_write_char(i < len ? str[len - i - 1] : ' ', i + 1); + return TRUE; +} + +BOOL fip_write_special_char(int pos, int shift, BOOL onoff) +{ + BYTE ch = fipram[pos]; + if (onoff) + fipram[pos] = ch | (1 << shift); + else + fipram[pos] = ch & ~(1 << shift); + if (fipram[pos] == ch) + return TRUE; +// ioctl(fip_handle, FIP_DISPLAY_SYMBOL, fipram[pos] | (pos << 16)); + return TRUE; +} + +BOOL fip_write_special(int id, BOOL onoff) +{ + if (id < 0 || id > 27) + return FALSE; + return fip_write_special_char(led_special[id*2], led_special[id*2+1], onoff); +} + +BOOL fip_get_special(int id) +{ + if (id < 0 || id > 27) + return FALSE; + int pos = led_special[id*2]; + int shift = led_special[id*2+1]; + return (fipram[pos] >> shift) & 1; +} + +int fip_read_button(BOOL blocked) +{ + if (fip_handle == -1 || button_LUT == NULL) + return 0; + ioctl(fip_handle, FIP_BUTTON_READ, &butcode); + if (butcode == 0) + return FIP_KEY_NONE; + +#if 0 + BYTE bc = button_LUT[butcode & 0xffff]; +#ifdef SP_PLAYER_DREAMX108 + // special case - front panel STOP button + if (butcode == 0x00080000) + return FIP_KEY_FRONT_STOP; + // special case - front panel PREV button + if (butcode == 0x00010000) + return FIP_KEY_FRONT_SKIP_PREV; +#endif + + if (bc == 0xff) + return FIP_KEY_NONE; + if (bc < fip_panel_num_codes) + { + if (butcode == fip_panel_codes[bc]) + return (unsigned int)bc + fip_code_offset[0]; + } + if (butcode == fip_remote_codes[bc]) + return (unsigned int)bc + fip_code_offset[1]; +#endif + return FIP_KEY_NONE; +} diff --git a/src/libsp/MG35/sp_fip_codes-dreamx108.h b/src/libsp/MG35/sp_fip_codes-dreamx108.h new file mode 100644 index 0000000..9f7ab06 --- /dev/null +++ b/src/libsp/MG35/sp_fip_codes-dreamx108.h @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP button internal codes header. + * For DreamX-108 player + * \file sp_fip_codes-dreamx108.h + * \author bombur + * \version 0.2 + * \date 21.01.2009 4.05.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_CODES_H +#define SP_FIP_CODES_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Button codes definitions: + +static DWORD fip_code_offset[2] = { FIP_KEY_FRONT_EJECT, FIP_KEY_POWER }; + +/// 1) definitions for the buttons on the front panel: +static DWORD fip_panel_codes[] = +{ + 0x00001000, // FIP_KEY_FRONT_EJECT, + 0x80000080, // FIP_KEY_FRONT_PLAY, + 0x00080000, // FIP_KEY_FRONT_STOP, + 0x08000008, // FIP_KEY_FRONT_PAUSE, + 0x00010000, // FIP_KEY_FRONT_SKIP_PREV, + 0x00004000, // FIP_KEY_FRONT_SKIP_NEXT, + 0x10000010, // FIP_KEY_FRONT_REWIND, + 0x01000001, // FIP_KEY_FRONT_FORWARD, + + 0xffffffff +}; + +/// 2) definitions for the keys on the remote control: +static DWORD fip_remote_codes[] = +{ + 0x00FBF00F, // FIP_KEY_POWER, + 0x00FBB847, // FIP_KEY_EJECT, + + 0x00FBCA35, // FIP_KEY_ONE, + 0x00FBD02F, // FIP_KEY_TWO, + 0x00FB7887, // FIP_KEY_THREE, + 0x00FBC03F, // FIP_KEY_FOUR, + 0x00FB8A75, // FIP_KEY_FIVE, + 0x00FB20DF, // FIP_KEY_SIX, + 0x00FB2AD5, // FIP_KEY_SEVEN, + 0x00FB807F, // FIP_KEY_EIGHT, + 0x00FBD827, // FIP_KEY_NINE, + 0x00FB708F, // FIP_KEY_ZERO, + + 0x00FB6897, // FIP_KEY_CANCEL, + 0x00FBE21D, // FIP_KEY_SEARCH, + 0x00FBA05F, // FIP_KEY_ENTER, + + 0x00FB827D, // FIP_KEY_OSD, + 0x00FBA25D, // FIP_KEY_SUBTITLE, + 0x00FBB24D, // FIP_KEY_SETUP, + 0x00FBD22D, // FIP_KEY_RETURN, + 0x00FBF807, // FIP_KEY_TITLE, + 0x00000800, // FIP_KEY_PN, + 0x00FB42BD, // FIP_KEY_MENU, + 0x00FB28D7, // FIP_KEY_AB, + 0x00FB8877, // FIP_KEY_REPEAT, + + 0x00FB30CF, // FIP_KEY_UP, + 0x00FBF20D, // FIP_KEY_DOWN, + 0x00FB9867, // FIP_KEY_LEFT, + 0x00FB32CD, // FIP_KEY_RIGHT, + + 0x00FBC23D, // FIP_KEY_VOLUME_DOWN, + 0x00FB22DD, // FIP_KEY_VOLUME_UP, + 0x00FB629D, // FIP_KEY_PAUSE, + + 0x00FB926D, // FIP_KEY_REWIND, + 0x00FB6A95, // FIP_KEY_FORWARD, + 0x00FB38C7, // FIP_KEY_SKIP_PREV, + 0x00FB609F, // FIP_KEY_SKIP_NEXT, + + 0x00FBA857, // FIP_KEY_PLAY, + 0x00FBB04F, // FIP_KEY_STOP, + + 0x00FBE817, // FIP_KEY_SLOW, + 0x00FB728D, // FIP_KEY_AUDIO, + 0x00FBAA55, // FIP_KEY_VMODE, + 0x00FB906F, // FIP_KEY_MUTE, + 0x00FBC837, // FIP_KEY_ZOOM, + 0x00FFBABA, // FIP_KEY_PROGRAM, + 0x00FF728D, // FIP_KEY_PBC, + 0x00FB4AB5, // FIP_KEY_ANGLE, + + 0xffffffff +}; + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_CODES_H diff --git a/src/libsp/MG35/sp_fip_codes-technosonic.h b/src/libsp/MG35/sp_fip_codes-technosonic.h new file mode 100644 index 0000000..85a49b2 --- /dev/null +++ b/src/libsp/MG35/sp_fip_codes-technosonic.h @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP button internal codes header. + * For Technosonic-compatible players ('MP') + * \file sp_fip_codes-technosonic.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_CODES_H +#define SP_FIP_CODES_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Button codes definitions: + +static DWORD fip_code_offset[2] = { FIP_KEY_FRONT_EJECT, FIP_KEY_POWER }; + +/// 1) definitions for the buttons on the front panel: +static DWORD fip_panel_codes[] = +{ + 0x08000008, // FIP_KEY_FRONT_EJECT, + 0x00000080, // FIP_KEY_FRONT_PLAY, + 0x40000040, // FIP_KEY_FRONT_STOP, + 0x04000004, // FIP_KEY_FRONT_PAUSE, + 0x02000002, // FIP_KEY_FRONT_SKIP_PREV, + 0x20000020, // FIP_KEY_FRONT_SKIP_NEXT, + 0x10000010, // FIP_KEY_FRONT_REWIND, + 0x01000001, // FIP_KEY_FRONT_FORWARD, + + 0xffffffff +}; + +/// 2) definitions for the keys on the remote control: +static DWORD fip_remote_codes[] = +{ + 0x00FF30CF, // FIP_KEY_POWER, + 0x00FFB04F, // FIP_KEY_EJECT, + + 0x00FF00FF, // FIP_KEY_ONE, + 0x00FF807F, // FIP_KEY_TWO, + 0x00FF40BF, // FIP_KEY_THREE, + 0x00FFC03F, // FIP_KEY_FOUR, + 0x00FF20DF, // FIP_KEY_FIVE, + 0x00FFA05F, // FIP_KEY_SIX, + 0x00FF609F, // FIP_KEY_SEVEN, + 0x00FFE01F, // FIP_KEY_EIGHT, + 0x00FF10EF, // FIP_KEY_NINE, + 0x00FF906F, // FIP_KEY_ZERO, + + 0x00FF50AF, // FIP_KEY_CANCEL, + 0x00FFD02F, // FIP_KEY_SEARCH, + 0x00FF708F, // FIP_KEY_ENTER, + + 0x00FF7887, // FIP_KEY_OSD, + 0x00FFF807, // FIP_KEY_SUBTITLE, + 0x00FF38C7, // FIP_KEY_SETUP, + 0x00FFB847, // FIP_KEY_RETURN, + 0x00FF28D7, // FIP_KEY_TITLE, + 0x00FFA857, // FIP_KEY_PN, + 0x00FF6897, // FIP_KEY_MENU, + 0x00FFE817, // FIP_KEY_AB, + 0x00FF18E7, // FIP_KEY_REPEAT, + + 0x00FF08F7, // FIP_KEY_UP, + 0x00FF8877, // FIP_KEY_DOWN, + 0x00FF48B7, // FIP_KEY_LEFT, + 0x00FFC837, // FIP_KEY_RIGHT, + + 0x00FFD827, // FIP_KEY_VOLUME_DOWN, + 0x00FF58A7, // FIP_KEY_VOLUME_UP, + 0x00FF9867, // FIP_KEY_PAUSE, + + 0x00FF02FD, // FIP_KEY_REWIND, + 0x00FF827D, // FIP_KEY_FORWARD, + 0x00FF42BD, // FIP_KEY_SKIP_PREV, + 0x00FFC23D, // FIP_KEY_SKIP_NEXT, + + 0x00FF22DD, // FIP_KEY_PLAY, + 0x00FFA25D, // FIP_KEY_STOP, + + 0x00FF12ED, // FIP_KEY_SLOW, + 0x00FF926D, // FIP_KEY_AUDIO, + 0x00FF52AD, // FIP_KEY_VMODE, + 0x00FFD22D, // FIP_KEY_MUTE, + 0x00FF32CD, // FIP_KEY_ZOOM, + 0x00FFB24D, // FIP_KEY_PROGRAM, + 0x00FF728D, // FIP_KEY_PBC, + 0x00FFF20D, // FIP_KEY_ANGLE, + + 0xffffffff +}; + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_CODES_H diff --git a/src/libsp/MG35/sp_fip_ioctl.h b/src/libsp/MG35/sp_fip_ioctl.h new file mode 100644 index 0000000..8e460e2 --- /dev/null +++ b/src/libsp/MG35/sp_fip_ioctl.h @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Internal FIP IOCTL codes. + * For Technosonic-compatible players ('MP') + * \file sp_fip_ioctl.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_IOCTL_H +#define SP_FIP_IOCTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Driver I/O defines: + + +/// Controls the display. +/// Used for setting the pulse width and turning the display on and off. +/// The flags you wish to set on the display where flags is one of the +/// FIP_PULSE_ defines. +#define FIP_DISPLAY_CONTROL 0x45000f + +/// Description: Displays the symbol on the display. +/// Sets given symbol data at given position: (data | (pos << 16)). +#define FIP_DISPLAY_SYMBOL 0x45000f + +/// Reads a button code (like getchar()). Can be blocked or not. +/// The button code is returned. +#define FIP_BUTTON_READ 0x450001 + +// #define FIP_??? 0x450004 + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_IOCTL_H diff --git a/src/libsp/MG35/sp_flash.cpp b/src/libsp/MG35/sp_flash.cpp new file mode 100644 index 0000000..c6569eb --- /dev/null +++ b/src/libsp/MG35/sp_flash.cpp @@ -0,0 +1,174 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FLASH-ROM interface functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_flash.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include +#include + +#include "sp_misc.h" +#include "sp_fip.h" +#include "sp_flash.h" + + +static int file_handle, mtd_handle; +static DWORD file_read_cnt, num_read, num_written; +static int flen; +static void *buf = NULL; + +/* +void flash_output_progress(int cnt, int total) +{ + char buf[10]; + cnt = cnt * 100 / total; + sprintf(buf, "%u", cnt); + fip_write_string(buf); +} +*/ + +int flash_end() +{ + if (buf != NULL) + SPSafeFree(buf); + close(file_handle); + close(mtd_handle); + return 0; +} + + +int flash_file(char *fname, DWORD address) +{ + if (buf != NULL) + { + flash_end(); + } + int addr = address; + DWORD length = 0x400000 - addr; + struct erase_info_user eiu; + int mtdpos; + + file_handle = open(fname, O_RDONLY); + if (file_handle == -1) + return -1; + flen = lseek(file_handle, 0, SEEK_END); + if (flen < (int)length) + length = flen; + lseek(file_handle, 0, SEEK_SET); + + mtd_handle = open("/dev/mtd/0", O_RDWR); + if (mtd_handle == -1) + { + mtd_handle = file_handle; + goto err0; + } + mtdpos = lseek(mtd_handle, addr, SEEK_SET); + if (mtdpos == -1) + goto err; + + buf = SPmalloc(0x1000); + if (buf == NULL) + goto err; + + if (addr < 0x4000) + { + length += addr; + addr = 0; + } else if (addr < 0x8000) + { + length += (DWORD)addr % 0x2000; + addr &= ~0x1fff; + } else if (addr < 0x10000) + { + length += (DWORD)addr - 0x8000; + addr = 0x8000; + } else + { + length += (DWORD)addr & 0xffff; + addr = (DWORD)addr / 0x10000 * 0x10000; + } + + if (addr + (int)length <= 0x4000) + { + length = 0x4000; + } else if (addr + (int)length <= 0x8000) + { + length = ((length - 1) / 0x2000) * 0x2000 + 0x1fff; + length = length - 1; + } else if (addr + (int)length <= 0x10000) + { + length = 0x10000 - addr; + } else + { + length = ((((DWORD)(addr+length)-1) / 0x10000+1 ) * 0x10000) -1; + length = length + 1 - (DWORD)addr; + } + + // erase FLASH memory + eiu.start = addr; + eiu.length = length; + if (ioctl(mtd_handle, MEMERASE, &eiu) != 0) + goto err; + + file_read_cnt = 0; + return 0; + +err: + if (buf != NULL) + SPfree(buf); + close(file_handle); +err0: + close(mtd_handle); + return -1; +} + +int flash_cycle() +{ + if (buf == NULL) + { + return -1; + } + num_read = read(file_handle, buf, 0x1000); + if (num_read <= 0) + { + flash_end(); + return 100; + } + num_written = write(mtd_handle, buf, num_read); + if (num_read != num_written) + goto err; + file_read_cnt += num_read; + + if ((int)file_read_cnt != flen) + goto err; + + return file_read_cnt * 100 / flen; +err: + flash_end(); + return -1; +} + diff --git a/src/libsp/MG35/sp_i2c.cpp b/src/libsp/MG35/sp_i2c.cpp new file mode 100644 index 0000000..30bad99 --- /dev/null +++ b/src/libsp/MG35/sp_i2c.cpp @@ -0,0 +1,93 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - I2C data transfer functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_i2c.cpp + * \author bombur + * \version 0.1 + * \date 1.02.2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_io.h" +#include "sp_i2c.h" + +#include "arch-jasper/hardware.h" + + +BOOL i2c_data_in(BYTE addr, BYTE idx, BYTE *data, int num) +{ + outl(375, JASPER_I2C_MASTER_BASE+I2C_MASTER_CLK_DIV); + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + for (int i = 0; i < num; i++) + { + outl(250, JASPER_I2C_MASTER_BASE+I2C_MASTER_CONFIG); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_BYTE_COUNT); + outl(addr/2, JASPER_I2C_MASTER_BASE+I2C_MASTER_DEV_ADDR); + outl(idx++, JASPER_I2C_MASTER_BASE+I2C_MASTER_DATAOUT); + outl(4, JASPER_I2C_MASTER_BASE+I2C_MASTER_STARTXFER); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 2) == 0) + ; + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + outl(250, JASPER_I2C_MASTER_BASE+I2C_MASTER_CONFIG); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_BYTE_COUNT); + outl(addr/2, JASPER_I2C_MASTER_BASE+I2C_MASTER_DEV_ADDR); + outl(1, JASPER_I2C_MASTER_BASE+I2C_MASTER_STARTXFER); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 4) == 0) + ; + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + *data++ = inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_DATAIN); + } + return TRUE; +} + +BOOL i2c_data_out(BYTE addr, BYTE idx, BYTE *data, int num) +{ + outl(248, JASPER_I2C_MASTER_BASE+I2C_MASTER_CONFIG); + outl(375, JASPER_I2C_MASTER_BASE+I2C_MASTER_CLK_DIV); + outl(addr/2, JASPER_I2C_MASTER_BASE+I2C_MASTER_DEV_ADDR); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + for (int i = 0; i < num; i++) + { + outl(idx++, JASPER_I2C_MASTER_BASE+I2C_MASTER_ADR); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_BYTE_COUNT); + outl(*data++, JASPER_I2C_MASTER_BASE+I2C_MASTER_DATAOUT); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_STARTXFER); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 2) == 0) + ; + } + return TRUE; +} + diff --git a/src/libsp/MG35/sp_khwl.cpp b/src/libsp/MG35/sp_khwl.cpp new file mode 100644 index 0000000..458dcf8 --- /dev/null +++ b/src/libsp/MG35/sp_khwl.cpp @@ -0,0 +1,351 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - KHWL interface functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_khwl.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" +#include "sp_khwl_ioctl.h" +#include "sp_mpeg.h" +#include "sp_fip.h" +#include "sp_io.h" +#include "sp_i2c.h" + +#include "arch-jasper/hardware.h" + + +/// Muxed media packets +MpegPlayStruct *MPEG_PLAY_STRUCT = (MpegPlayStruct *)(0x17c0000 + 0x3fc00 + 768); +/// Video packets +MpegPlayStruct *MPEG_VIDEO_STRUCT = (MpegPlayStruct *)(0x2000000 - 0x800000 - 232); +/// Audio packets +MpegPlayStruct *MPEG_AUDIO_STRUCT = (MpegPlayStruct *)(0x2000000 - 0x800000 - 208); +/// Subpicture packets +MpegPlayStruct *MPEG_SPU_STRUCT = (MpegPlayStruct *)(0x2000000 - 0x800000 - 184); + +/// Buffers storage +BYTE *BUF_BASE = (BYTE *)0x01680000; +//BYTE *BUF_BASE = (BYTE *)0x016c0000; + + +/// KHWL module handle +int khwl_handle = -1; + +/// OSD properties used +KHWL_OSDSTRUCT osd = { NULL }; + +/// insmod flag +static BOOL module_applied = FALSE; + +/// If digital TV (HDTV) is installed. +static BOOL digital_tv = FALSE; + +int FRAME_WIDTH = 720; +int FRAME_HEIGHT = 480; + + +BOOL khwl_init(BOOL applymodule) +{ + khwl_inityuv(); + khwl_deinit(); + + if (module_applied == TRUE || applymodule == FALSE || module_apply("/drivers/khwl.o")) // insert + { + module_applied = TRUE; + + khwl_handle = open("/dev/realmagichwl0", 0, 0); + if (khwl_handle != -1) + { + //khwl_reset(); + + if (!khwl_restoreparams()) + return FALSE; + + return TRUE; + } + } + return FALSE; +} + +BOOL khwl_restoreparams() +{ + int val = 0; + khwl_setproperty(KHWL_VIDEO_SET, evMacrovisionFlags, sizeof(int), &val); + + int flickerval = 15; // flicker = max + khwl_setproperty(KHWL_DECODER_SET, edecOsdFlicker, sizeof(int), &flickerval); + + KHWL_WINDOW wnd, osdwnd; + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(wnd), &wnd); + khwl_setproperty(KHWL_VIDEO_SET, evDestinationWindow, sizeof(wnd), &wnd); + + osdwnd = wnd; + // fix rather strange OSD scaling bug... + osdwnd.h = 30 * wnd.h / 31; + khwl_setproperty(KHWL_OSD_SET, eOsdDestinationWindow, sizeof(osdwnd), &osdwnd); + + val = 0; + khwl_setproperty(KHWL_VIDEO_SET, evForcedProgressiveAlways, sizeof(int), &val); + + KHWL_YUV_WRITE_PARAMS_TYPE yuvparams; + yuvparams.wWidth = wnd.w; + yuvparams.wHeight = wnd.h; + yuvparams.YUVFormat = KHWL_YUV_420_UNPACKED; + + khwl_setproperty(KHWL_VIDEO_SET, evYUVWriteParams, sizeof(yuvparams), &yuvparams); + + // do some HDTV-specific checks... + digital_tv = FALSE; + if ((inl(JASPER_QUASAR_BASE + QUASAR_DRAM_STARTUP1) & 0x2000) != 0) + { + BYTE data[4]; + // test for HDTV 1080I + i2c_data_in(112, 0, data, 4); + if (data[0] == 1 && data[1] == 0 && data[2] == 8 && data[3] == 0) + digital_tv = TRUE; + } + + return TRUE; +} + +BOOL khwl_deinit() +{ + if (khwl_handle == -1) + return FALSE; + close(khwl_handle); + khwl_handle = -1; + return TRUE; +} + +BOOL khwl_reset() +{ + if (khwl_handle == -1) + return FALSE; + return ioctl(khwl_handle, KHWL_HARDRESET, 0); +} + +int khwl_osd_switch(KHWL_OSDSTRUCT *_osd, BOOL autoupd) +{ + KHWL_WINDOW wnd; + int ret; + if (khwl_handle == -1) + return FALSE; + osd.flags = autoupd ? 1 : 0; + ret = ioctl(khwl_handle, KHWL_OSDFB_SWITCH, &osd); + + if (_osd != NULL) + { + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(wnd), &wnd); + khwl_setproperty(KHWL_OSD_SET, eOsdDestinationWindow, sizeof(wnd), &wnd); + *_osd = osd; + } + return ret; +} + +void khwl_get_osd_size(int *width, int *height) +{ + *width = 640;//osd.width; + *height = 480;//osd.height; +} + + +BOOL khwl_osd_update() +{ + ioctl(khwl_handle, KHWL_OSDFB_UPDATE, 0); + return TRUE; +} + +int khwl_osd_setalpha(int alpha) +{ + return ioctl(khwl_handle, KHWL_OSDFB_ALPHA, &alpha); +} + +void khwl_osd_setpalette(BYTE *pal, int entry, BYTE r, BYTE g, BYTE b, BYTE a) +{ + // assert(entry >= 0 && entry < 256); + BYTE y, u, v; + entry <<= 2; + khwl_vgargbtotvyuv(r, g, b, &y, &u, &v); + pal[entry++] = a; // alpha + pal[entry++] = y; + pal[entry++] = u; + pal[entry] = v; +} + +int khwl_displayYUV(KHWL_YUV_FRAME *f) +{ + int ret = ioctl(khwl_handle, KHWL_DISPLAY_YUV, f); + return ret; +} + +int khwl_setproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value) +{ + KHWL_PROPERTY p; + p.pset = pset; + p.id = id; + p.size = size; + p.v = value; + return ioctl(khwl_handle, KHWL_SETPROP, &p); +} + +int khwl_getproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value) +{ + KHWL_PROPERTY p; + p.pset = pset; + p.id = id; + p.size = size; + p.v = value; + return ioctl(khwl_handle, KHWL_GETPROP, &p); +} + +int khwl_audioswitch(BOOL ison) +{ + int val = ison ? 1 : 0; + return ioctl(khwl_handle, KHWL_AUDIOSWITCH, &val); +} + +int *khwl_get_samplerates() +{ + static int rates[2][12] = + { + // chip rev.A + { 16000, 22050, 24000, 32000, 44100, 48000, -1 }, + // chip rev.B supports more samplerates + { 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, -1 }, + }; + return rates[inl(SYS_REVID_REG) & 1]; +} + +int khwl_play(int mode) +{ + return ioctl(khwl_handle, KHWL_PLAY, &mode); +} + +int khwl_stop() +{ + return ioctl(khwl_handle, KHWL_STOP, 0); +} + +int khwl_pause() +{ + return ioctl(khwl_handle, KHWL_PAUSE, 0); +} + +BOOL khwl_blockirq(BOOL block) +{ + unsigned irqstat; + irqstat = inl(JASPER_INT_CONTROLLER_BASE + INT_INTEN); + if (block) + irqstat &= ~Q2H_RISC_INT; + else + irqstat |= Q2H_RISC_INT; + outl(irqstat, JASPER_INT_CONTROLLER_BASE + INT_INTEN); + return TRUE; +} + +BOOL khwl_happeningwait(DWORD *mask) +{ + KHWL_WAITABLE w; + w.mask = *mask; + w.timeout_microsecond = 400000; + ioctl(khwl_handle, KHWL_WAIT, &w); + *mask = w.mask; + return TRUE; +} + +BOOL khwl_poll(WORD mask, DWORD timeout) +{ + pollfd pfd; + pfd.events = mask; + pfd.fd = khwl_handle; + return poll(&pfd, 1, timeout) >= 0; +} + +BOOL khwl_ideswitch(BOOL ison) +{ + KHWL_ADDR_DATA data; + // switch IDE? + data.Addr = 4; + data.Data = ison ? 1 : 0; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + return TRUE; +} + +int khwl_getfrequency() +{ + int temp = inl(JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + + int div = (temp >> 8) & 0xff; + int mul = (temp >> 2) & 63; + + int freq = (27 * (mul + 2)) / ((div + 2) * 2); + return freq; +} + +BOOL khwl_setfrequency(int freq) +{ + if (freq < 100 || freq > 202) + return FALSE; + + int temp = inl(JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + temp = temp & 0xF000; + int div = (temp >> 8) & 0xff; + //int mul = (temp >> 2) & 63; + + int mul = (freq * ((10 * div+20)*20) / 270 - 20 /* + 5 */) / 10; + if (mul < 0 || mul > 63) + return FALSE; + + temp = temp | 0x02; + temp = temp | (div << 8); + temp = temp | (mul << 2); + + outl(temp & 0x7FFF, JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + return TRUE; +} + +char *khwl_gethw() +{ + static char hw[256]; +/* + char b[128]; + b[0] = '\0'; + khwl_getproperty(KHWL_BOARDINFO_SET, ebiBoardNameString, 256, b); + + DWORD v_ebiDeviceId, v_ebiSubId, v_ebiBoardVersion, v_ebiHwLibVersion, v_ebiUcodeVersion; + khwl_getproperty(KHWL_BOARDINFO_SET, ebiDeviceId, sizeof(DWORD), &v_ebiDeviceId); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiSubId, sizeof(DWORD), &v_ebiSubId); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiBoardVersion, sizeof(DWORD), &v_ebiBoardVersion); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiHwLibVersion, sizeof(DWORD), &v_ebiHwLibVersion); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiUcodeVersion , sizeof(DWORD), &v_ebiUcodeVersion); +*/ + sprintf(hw, "%X.%c", inl(SYS_CHIPID_REG), inl(SYS_REVID_REG) + 'A'); + + return hw; +} diff --git a/src/libsp/MG35/sp_khwl_ioctl.h b/src/libsp/MG35/sp_khwl_ioctl.h new file mode 100644 index 0000000..b5b44e1 --- /dev/null +++ b/src/libsp/MG35/sp_khwl_ioctl.h @@ -0,0 +1,65 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Internal KHWL driver's IOCTL codes. + * For Technosonic-compatible players ('MP') + * \file sp_khwl_ioctl.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_KHWL_IOCTL_H +#define SP_KHWL_IOCTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Driver I/O defines: + +#define KHWL_IO_BASE 0x3cc +#define KHWL_IO_PLAYER 0x3d0 +#define KHWL_IO_PROP 0x3d4 +#define KHWL_IO_OSD 0x3e1 +#define KHWL_IO_DISPLAY 0x3e6 + + +#define KHWL_HARDRESET KHWL_IO_BASE+3 + +#define KHWL_PLAY KHWL_IO_PLAYER +#define KHWL_STOP KHWL_IO_PLAYER+1 +#define KHWL_PAUSE KHWL_IO_PLAYER+2 +#define KHWL_AUDIOSWITCH KHWL_IO_PLAYER+3 + +#define KHWL_WAIT KHWL_IO_PROP+1 +#define KHWL_SETPROP KHWL_IO_PROP+2 +#define KHWL_GETPROP KHWL_IO_PROP+3 + +#define KHWL_OSDFB_SWITCH KHWL_IO_OSD +#define KHWL_OSDFB_UPDATE KHWL_IO_OSD+1 +#define KHWL_OSDFB_ALPHA KHWL_IO_OSD+2 // general alpha apply + +#define KHWL_DISPLAY_CLEAR KHWL_IO_DISPLAY +#define KHWL_DISPLAY_YUV KHWL_IO_DISPLAY+1 + +#ifdef __cplusplus +} +#endif + +#endif // of SP_HWL_IOCTL_H diff --git a/src/libsp/MG35/sp_module.cpp b/src/libsp/MG35/sp_module.cpp new file mode 100644 index 0000000..c18db37 --- /dev/null +++ b/src/libsp/MG35/sp_module.cpp @@ -0,0 +1,198 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Module system support source file. + * For Technosonic-compatible players ('MP') + * \file sp_module.cpp + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +extern "C" +{ + +// portions of code from uClibc... +#ifdef COMPILE_MODULE + +void (*__app_fini)(void) = NULL; + +extern int main(int argc, char **argv, char **envp); + + +void __attribute__ ((__noreturn__)) +__uClibc_start_main(int argc, char **argv, char **envp, + void (*app_init)(void), void (*app_fini)(void)) +{ + /* Arrange for the application's dtors to run before we exit. */ + __app_fini = app_fini; + + /* Run all the application's ctors now. */ + if (app_init!=NULL) { + app_init(); + } + + exit(main(argc, argv, envp)); +} + +void exit(int rv) +{ + if (__app_fini != NULL) + (__app_fini)(); + + _exit(rv); +} + +void module_wait() +{ + kill(getpid(), SIGSTOP); +} + +/* Copy SRC to DEST. */ +char *strcpy (char *dest, const char *src) +{ + char c; + char *s = (char *) (src); + const int off = (dest) - s - 1; + + do + { + c = *s++; + s[off] = c; + } + while (c != '\0'); + + return dest; +} + +void abort(void) +{ + struct sigaction act; + sigset_t sset; + + (void) fflush (NULL); + + if ((sigemptyset (&sset) == 0) && (sigaddset (&sset, SIGABRT) == 0)) { + (void) sigprocmask (SIG_UNBLOCK, &sset, (sigset_t *) NULL); + } + + raise(SIGABRT); + + memset (&act, '\0', sizeof (struct sigaction)); + act.sa_handler = SIG_DFL; + sigfillset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGABRT, &act, NULL); + + raise (SIGABRT); + + _exit (127); +} + +int atexit(void (*) (void)) +{ + // empty + return 0; +} + + +#undef LOAD_ARGS_1 +#define LOAD_ARGS_1(a1) \ + _a1 = (int) (a1); +#undef ASM_ARGS_1 +#define ASM_ARGS_1 , "r" (_a1) +#ifndef SYS_ify +# define SYS_ify(syscall_name) (__NR_##syscall_name) +#endif + +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ unsigned int _sys_result; \ + { \ + register int _a1 asm ("a1"); \ + LOAD_ARGS_##nr (args) \ + asm volatile ("swi %1 @ syscall " #name \ + : "=r" (_a1) \ + : "i" (SYS_ify(name)) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) + + +void _exit(int status) +{ + INLINE_SYSCALL(exit, 1, status); +} + + +#else ///////////////////// server side + +int module_binary_load(char *fname, char *arg) +{ + char *args[3]; + args[0] = fname; + args[1] = arg; + args[2] = NULL; + + return exec_file(args[0], (const char **)args); +} + +int module_binary_unload(int pid) +{ + // kill it by force + kill(pid, SIGKILL); + int pstat; + waitpid(pid, &pstat, 0); + return 0; +} + +void module_copy_func(void *from, void *to) +{ + #define JMP_OPCODE_SIZE 2 + DWORD diff = (((DWORD)from)/4 - (((DWORD)to)/4 + JMP_OPCODE_SIZE)); + *((DWORD *)to) = 0xEA000000 | (diff & 0xFFFFFF); +} + +void module_clear_func(void *func) +{ + *((DWORD *)func) = 0; +} + + +#endif + +} diff --git a/src/libsp/MG35/sp_module_crt0.S b/src/libsp/MG35/sp_module_crt0.S new file mode 100644 index 0000000..7478630 --- /dev/null +++ b/src/libsp/MG35/sp_module_crt0.S @@ -0,0 +1,125 @@ +/* When we enter this piece of code, the program stack looks like this: + argc argument counter (integer) + argv[0] program name (pointer) + argv[1...N] program args (pointers) + argv[argc-1] end of args (integer) + NULL + env[0...N] environment variables (pointers) + NULL + + For uClinux it looks like this: + + argc argument counter (integer) + argv char *argv[] + envp char *envp[] + argv[0] program name (pointer) + argv[1...N] program args (pointers) + argv[argc-1] end of args (integer) + NULL + env[0...N] environment variables (pointers) + NULL + + When we are done here, we want + a1=argc + a2=argv[0] + a3=argv[argc+1] + +ARM register quick reference: + + Name Number ARM Procedure Calling Standard Role + + a1 r0 argument 1 / integer result / scratch register / argc + a2 r1 argument 2 / scratch register / argv + a3 r2 argument 3 / scratch register / envp + a4 r3 argument 4 / scratch register + v1 r4 register variable + v2 r5 register variable + v3 r6 register variable + v4 r7 register variable + v5 r8 register variable + sb/v6 r9 static base / register variable + sl/v7 r10 stack limit / stack chunk handle / reg. variable + fp r11 frame pointer + ip r12 scratch register / new-sb in inter-link-unit calls + sp r13 lower end of current stack frame + lr r14 link address / scratch register + pc r15 program counter +*/ + +#include + +.text + .global _start + .type _start,%function +#if ! defined __UCLIBC_CTOR_DTOR__ + .type __uClibc_main,%function +#else + .weak _init + .weak _fini + .type __uClibc_start_main,%function +#endif +/* Stick in a dummy reference to main(), so that if an application + * is linking when the main() function is in a static library (.a) + * we can be sure that main() actually gets linked in */ + .type main,%function + + +.text +_start: + /* clear the frame pointer */ + mov fp, #0 + +#ifdef __UCLIBC_HAS_MMU__ + /* Load register r0 (argc) from the stack to its final resting place */ + ldr r0, [sp], #4 + + /* Copy argv pointer into r1 -- which its final resting place */ + mov r1, sp + + /* Skip to the end of argv and put a pointer to whatever + we find there (hopefully the environment) in r2 */ + add r2, r1, r0, lsl #2 + add r2, r2, #4 + +#else + /* + * uClinux stacks look a little different from normal + * MMU-full Linux stacks (for no good reason) + */ + /* pull argc, argv and envp off the stack */ + ldr r0,[sp, #0] + ldr r1,[sp, #4] + ldr r2,[sp, #8] +#endif + +#if defined __UCLIBC_CTOR_DTOR__ + /* Store the address of _init in r3 as an argument to main() */ + ldr r3, =_init + + /* Push _fini onto the stack as the final argument to main() */ + ldr r4, =_fini + stmfd sp!, {r4} + + /* Ok, now run uClibc's main() -- shouldn't return */ + bl __uClibc_start_main +#else + bl __uClibc_main +#endif + + /* Crash if somehow `exit' returns anyways. */ + bl abort + +/* We need this stuff to make gdb behave itself, otherwise + gdb will chokes with SIGILL when trying to debug apps. +*/ + .section ".note.ABI-tag", "a" + .align 4 + .long 1f - 0f + .long 3f - 2f + .long 1 +0: .asciz "GNU" +1: .align 4 +2: .long 0 + .long 2,0,0 +3: .align 4 + diff --git a/src/libsp/MP/arch-jasper/hardware.h b/src/libsp/MP/arch-jasper/hardware.h new file mode 100644 index 0000000..c8cdec0 --- /dev/null +++ b/src/libsp/MP/arch-jasper/hardware.h @@ -0,0 +1,798 @@ +/* + * linux/include/asm-arm/arch-jasper/hardware.h + * [bombur]: this is a part of uClinux (GPL) headers. + * for JASPER + * Created 12/12/2001 Fabrice Gautier + * Copyright 2001, Sigma Desings, Inc + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#define IO_ADDRESS(x) (x) + +// PLL input clock, typically 27 Mhz +#define JASPER_EXT_CLOCK 27000000 + +/* 0=TC0, 1=TC1, 2=TC2 */ + +//------------------------------------------------------ +// SYSTEM CONTROLLER 0x0050_0000 +//------------------------------------------------------ +#define JASPER_SYSCTRL_BASE 0x00500000 + +#define SYSCTRL_CHIP_ID 0x00000000 +#define SYSCTRL_REVISION_ID 0x00000008 +#define SYSCTRL_CPUCFG 0x0000000C +#define SYSCTRL_TESTSTAT 0x00000010 +#define SYSCTRL_ERRSTAT 0x00000014 +#define SYSCTRL_BADADDR 0x00000018 +#define SYSCTRL_RSTCTL 0x00000020 +#define SYSCTRL_CPUTIMESLOT 0x00000024 + +//------------------------------------------------------ +// TIMER 0 AND 1 0x0050_0100 +//-------------------------TIMER_----------------------- +#define JASPER_TIMER_BASE 0x00500100 + +#define TIMER_TMRSTAT 0x00000000 +#define TIMER_TMR0LOAD 0x00000010 +#define TIMER_TMR0VAL 0x00000014 +#define TIMER_TMR0CTL 0x00000018 +#define TIMER_TMR1LOAD 0x00000020 +#define TIMER_TMR1VAL 0x00000024 +#define TIMER_TMR1CTL 0x00000028 + +//------------------------------------------------------ +// INT CONTROLLER 0x0050_0200 +//------------------------------------------------------ +#define JASPER_INT_CONTROLLER_BASE 0x00500200 + +#define INT_IRQSTAT 0x00000000 +#define INT_FIQSTAT 0x00000004 +#define INT_INTTYPE 0x00000010 +#define INT_INTPOLL 0x00000020 +#define INT_INTEN 0x00000024 + +//------------------------------------------------------ +// MAC Registers 0x00500300 +//------------------------------------------------------ +#define JASPER_MAC_BASE 0x00500300 + +#define MAC_REFTIMER 0x00000000 +#define MAC_FLASH_CFG 0x00000014 +#define MAC_FLASH_ST 0x0000001c +#define MAC_SDRAMCTL 0x00000020 +#define MAC_SDRAMCFG 0x00000024 +#define MAC_SDRAMDATA 0x00000028 +#define MAC_SDRAMST 0x0000002c +#define MAC_ARBITERCTRL 0x00000090 +#define MAC_ARBITERSTATE 0x00000094 +#define MAC_WATCHDOG_CTRL 0x000000A0 +#define MAC_WATCHDOG_TMO0 0x000000A4 +#define MAC_WATCHDOG_TMO1 0x000000A8 +#define MAC_WATCHDOG_INT 0x000000Ac +#define MAC_TIMESLOTCNT 0x000000B0 + + +//------------------------------------------------------ +// UART REGISTERs +// UART0 0050_0500 +// UART1 0050_1300 +//------------------------------------------------------ +#define JASPER_UART0_BASE 0x00500500 +#define JASPER_UART1_BASE 0x00501300 +#define UART_NR 2 + +#define UART_RBR 0x00 +#define UART_TBR 0x04 +#define UART_IER 0x08 +#define UART_IIR 0x0C +#define UART_FCR 0x10 +#define UART_LCR 0x14 +#define UART_MCR 0x18 +#define UART_LSR 0x1C +#define UART_MSR 0x20 +#define UART_SCRATCH 0x24 +#define UART_CLKDIV 0x28 +#define UART_CLKSEL 0x2C + +//------------------------------------------------------ +// PIO0 block 0x0050_0600 +// PIO1 block 0x0050_0A00 +//------------------------------------------------------ +#define JASPER_PIO0_BASE 0x00500600 +#define JASPER_PIO1_BASE 0x00500A00 + +#define PIO_INT_STATUS 0x00000000 +#define PIO_DATA 0x00000004 +#define PIO_DIR 0x00000008 +#define PIO_POL 0x0000000C +#define PIO_INT_ENABLE 0x00000010 + + +//------------------------------------------------------ +// I2C MASTER REGISTERs 0X0050_0800 +//------------------------------------------------------ +#define JASPER_I2C_MASTER_BASE 0x00500800 + +#define I2C_MASTER_CONFIG 0x00 +#define I2C_MASTER_CLK_DIV 0x04 +#define I2C_MASTER_DEV_ADDR 0x08 +#define I2C_MASTER_ADR 0x0C +#define I2C_MASTER_DATAOUT 0x10 +#define I2C_MASTER_DATAIN 0x14 +#define I2C_MASTER_STATUS 0x18 +#define I2C_MASTER_STARTXFER 0x1C +#define I2C_MASTER_BYTE_COUNT 0x20 +#define I2C_MASTER_INTEN 0x24 +#define I2C_MASTER_INT 0x28 + + +//------------------------------------------------------ +// I2C SLAVE REGISTERs 0X0050_0900 +//------------------------------------------------------ +#define JASPER_I2C_SLAVE_BASE 0x00500900 + +#define I2C_SLAVE_ADDR 0x00 +#define I2C_SLAVE_DATAOUT 0x04 +#define I2C_SLAVE_DATAIN 0x08 +#define I2C_SLAVE_STATUS 0x0C +#define I2C_SLAVE_INTEN 0x10 +#define I2C_SLAVE_INT 0x14 +#define I2C_SLAVE_BUS_HOLD 0x18 + +//------------------------------------------------------ +// IDE_REGISTERs 0x0050_0B00 +//------------------------------------------------------ +#define JASPER_IDE_BASE 0x00500B00 + +#define JASPER_IDE_DMA_BASE 0x00500E00 + + // **** DMA CHANNEL REG **** +#define IDE_BMIC 0x00 // ( 8 BIT) BMIC IDE COMMAND REG +#define IDE_BMIS 0x04 // ( 8 BIT) BMIC IDE STATUS REG +#define IDE_BMIDTP 0x08 // (32 BIT) BUSMASTER IDE DESCRIPTOR TABLE POINTER REG +#define IDE_TIM 0x40 // (16 BIT) IDE TIMING Reg +#define IDE_SIDETIM 0x48 // ( 8 BIT) SLAVE IDE TIMING Reg +#define IDE_SRC 0x4C // (16 BIT) SLEW RATE CTRL Reg (45h-46h) +#define IDE_STATUS 0x50 // ( 8 BIT) IDESTATUS +#define IDE_UDMACTL 0x54 // ( 8 BIT) ULTRA DMA CONTORL Reg +#define IDE_UDMATIM 0x58 // (16 BIT) ULTRA DMA TIMING Reg (4A - 4B) +#define IDE_PRI_DEVICE_CONTROL 0xE6 // (16 BIT) Device 0: +#define IDE_PRI_DATA 0xF0 // (16 BIT) Device 0: +#define IDE_PRI_SECTOR_COUNT 0xF2 // (16 BIT) Device 0: +#define IDE_PRI_DEVICE_HEAD 0xF6 // (16 BIT) Device 0: +#define IDE_PRI_CMD 0xF7 // (16 BIT) Device 0: + + +//------------------------------------------------------ +// DVD-LOADER_REGISTERs 0x0050_0C00 +//------------------------------------------------------ +#define JASPER_DVD_BASE 0x00500C00 +#define DVD_AV_CTRL 0x00 // (16 BIT) AUDIO/VIDEO PART FROM HOST +#define DVD_AV_SEC_CNT 0x04 // +#define DVD_AV_BYTE_CNT 0x08 // +#define DVD_AV_INTMSK 0x0C // +#define DVD_AV_INT 0x10 // +#define DVD_FIFO_LIM 0x14 // +#define DVD_TIMOUT_LIM 0x18 // +#define DVD_AV_X2C 0x1C // +#define DVD_HOST_CTRL 0x20 // +#define DVD_HOST_SCLK 0x24 // +#define DVD_HOST_TXREG 0x28 // +#define DVD_HOST_RXREG 0x2C // + +//------------------------------------------------------ +// FIP REGISTERs 0x0050_0D00 +//------------------------------------------------------ + +#define JASPER_FIP_BASE 0x00500D00 + +#define FIP_COMMAND 0x00 +#define FIP_DISPLAY_DATA 0x04 +#define FIP_LED_DATA 0x08 +#define FIP_KEY_DATA1 0x0C +#define FIP_KEY_DATA2 0x10 +#define FIP_SWITCH_DATA 0x14 +#define FIP_CLK_DIV 0x20 +#define FIP_TRISTATE_MODE 0x24 + +//------------------------------------------------------ +// DVD-DMA REGISTERs 0x0050_0F00 +//------------------------------------------------------ +#define JASPER_DVD_DMA_BASE 0x00500F00 +#define DVD_DMACTL 0x00 // +#define DVD_DMAMSK 0x04 // +#define DVD_DMAINT 0x08 // +#define DVD_DMARAW 0x0C // +#define DVD_RXADDR 0x10 // +#define DVD_RXBYTES 0x14 // + +//------------------------------------------------------ +// RTC REGISTER 0x0050_1400 +//------------------------------------------------------ +#define JASPER_RTC_BASE 0x00501400 +#define RTC_CTRL 0x00000000 +#define RTC_LOAD1 0x00000004 +#define RTC_LOAD2 0x00000008 +#define RTC_ALARM 0x0000000C +#define RTC_INTEN 0x00000010 +#define RTC_INT0 0x00000014 +#define RTC_COUNT1 0x00000018 +#define RTC_COUNT2 0x0000001C + +//------------------------------------------------------ +// HOST/QUASAR SLAVE REGISTERS 0x0050_1500 +//------------------------------------------------------ +#define JASPER_HOST_SLAVE_QUASAR_BASE 0x00501500 + +#define HOST_SLAVE_WR_QUASAR_BYTE 0x00000000 +#define HOST_SLAVE_WR_QUASAR_1BYTE 0x00000000 +#define HOST_SLAVE_WR_QUASAR_2BYTE 0x00000004 +#define HOST_SLAVE_WR_QUASAR_3BYTE 0x00000008 +#define HOST_SLAVE_WR_QUASAR_4BYTE 0x0000000C + +#define HOST_SLAVE_RD_QUASAR_BYTE 0x00000000 +#define HOST_SLAVE_RD_QUASAR_1BYTE 0x00000000 +#define HOST_SLAVE_RD_QUASAR_2BYTE 0x00000004 +#define HOST_SLAVE_RD_QUASAR_3BYTE 0x00000008 +#define HOST_SLAVE_RD_QUASAR_4BYTE 0x0000000C + +//------------------------------------------------------ +// I2S REGISTERs 0x0050_1600 +//------------------------------------------------------ +#define JASPER_I2S_BASE 0x00501600 + +#define I2S_CTRL 0x0 +#define I2S_PROG_LEN 0x4 +#define I2S_STATUS 0x8 +#define I2S_FRAME_CNTR 0xC + +#define I2S_RESET 0x2 +#define I2S_ENABLE 0x1 +#define I2S_MASTER_MODE 0x4 +#define I2S_SCIN_DIV00 0x00 +#define I2S_SCIN_DIV01 0x08 +#define I2S_SCIN_DIV10 0x10 +#define I2S_SCIN_DIV11 0x18 + +//------------------------------------------------------ +// SPI/I2S_DMA REGISTERs 0x0050_1700 +//------------------------------------------------------ +#define JASPER_SPI_I2S_DMA_BASE 0x00501700 + +#define SPI_I2S_DMA_CTRL_REG 0x0 +#define SPI_I2S_DMA_BASE_ADD_REG 0x4 +#define SPI_I2S_DMA_SIZE_REG 0x8 +#define SPI_I2S_DMA_WR_PTR_REG 0xC +#define SPI_I2S_DMA_RD_PTR_REG 0x10 +#define SPI_I2S_DMA_TRSH_REG 0x14 +#define SPI_I2S_DMA_INT_EN_REG 0x18 +#define SPI_I2S_DMA_INT_REG 0x1C +#define SPI_I2S_DMA_INT_POLL_REG 0x20 +#define SPI_I2S_DMA_INTER_FIFO_REG 0x24 +#define SPI_I2S_DMA_CNT_REG 0x28 + +//------------------------------------------------------ +// SPI REGISTERs 0x0050_1800 +//------------------------------------------------------ +#define JASPER_SPI_BASE 0x00501800 + +#define SPI_CNTR 0x0 +#define SPI_REC_COUNTER 0x4 +#define SPI_INT_EN 0x8 +#define SPI_INT_STATUS 0xC +#define SPI_ERROR_CNT 0x10 + + +//------------------------------------------------------ +// QUASAR PM/DM AREA +//------------------------------------------------------ +#define JASPER_QUASAR_BASE 0x00600000 + +#define QUASAR_MAP_AREA 0x00600000 +#define QUASAR_PM_START 0x00600000 +#define QUASAR_PM_SIZE 0x00002000 +#define QUASAR_DM_START 0x00604000 +#define QUASAR_DM_SIZE 0x00002000 + +//------------------------------------------------------ +// QUASAR DRAM CONTROLLER +//------------------------------------------------------ + +#define QUASAR_DRAM_CFG 0x00007000 +#define QUASAR_DRAM_FIFOSIZE0 0x00007004 +#define QUASAR_DRAM_FIFOSIZE1 0x00007008 +#define QUASAR_DRAM_CASDELAY 0x0000700C +#define QUASAR_DRAM_PLLCONTROL 0x00007010 +#define QUASAR_DRAM_TK0 0x00007014 +#define QUASAR_DRAM_TK1 0x00007018 +#define QUASAR_DRAM_TK2 0x0000701C +#define QUASAR_DRAM_STARTUP0 0x00007020 +#define QUASAR_DRAM_STARTUP1 0x00007024 +#define QUASAR_DRAM_AC3_BASE 0x00007028 +#define QUASAR_DRAM_FIFOSIZE2 0x0000702C +#define QUASAR_DRAM_PORTMUX 0x00007030 + +//------------------------------------------------------ +// QUASAR <-> HOST INTERFACE ( DMA ENGINES ) +//------------------------------------------------------ + +#define QUASAR_H2Q_READ_ADDRESS_LO 0x00007F80 //0xFE0 +#define QUASAR_H2Q_READ_ADDRESS_HI 0x00007F84 //0xFE1 +#define QUASAR_H2Q_READ_CONTER 0x00007F88 //0xFE2 +#define QUASAR_H2Q_READ_MASTER_ENABLE 0x00007F8C //0xFE3 +#define QUASAR_H2Q_INT_MASK 0x00007F90 //0xFE4 +#define QUASAR_H2Q_INT 0x00007F94 //0xFE5 +#define QUASAR_H2Q_INT_STATUS 0x00007F98 //0xFE6 + +#define QUASAR_Q2H_WRITE_ADDRESS_LO 0x00007FA0 //0xFE8 +#define QUASAR_Q2H_WRITE_ADDRESS_HI 0x00007FA4 //0xFE9 +#define QUASAR_Q2H_WRITE_CONTER 0x00007FA8 //0xFEA +#define QUASAR_Q2H_WRITE_MASTER_ENABLE 0x00007FAC //0xFEB +#define QUASAR_Q2H_INT_MASK 0x00007FB0 //0xFEC +#define QUASAR_Q2H_INT 0x00007FB4 //0xFED +#define QUASAR_Q2H_INT_STATUS 0x00007FB8 //0xFEE + +#define QUASAR_OSD_SOURCE_ADDRESS_LO 0x00007980 //0xE60 +#define QUASAR_OSD_SOURCE_ADDRESS_HI 0x00007984 //0xE61 +#define QUASAR_OSD_SOURCE_COUNTER 0x00007988 //0xE62 +#define QUASAR_OSD_SOURCE_MUX_ENABLE 0x0000798C //0xE63 +#define QUASAR_OSD_INT_MASK 0x00007990 //0xE64 +#define QUASAR_OSD_INT 0x00007994 //0xE65 +#define QUASAR_OSD_INT_STATUS 0x00007998 //0xE66 + +//------------------------------------------------------ +// QUASAR Local Bus Controller (LBC) +//------------------------------------------------------ + +#define QUASAR_LBC_CONFIG0 0x00007900 //0x1E40 +#define QUASAR_LBC_CONFIG1 0x00007904 //0x1E41 +#define QUASAR_LBC_WRITE_FIFO0_ACCESS 0x00007908 //0x1E42 +#define QUASAR_LBC_WRITE_FIFO0_CNT 0x0000790C //0x1E43 +#define QUASAR_LBC_READ_FIFO0_ACCESS 0x00007910 //0x1E44 +#define QUASAR_LBC_READ_FIFO0_CNT 0x00007914 //0x1E45 +#define QUASAR_LBC_READ_FIFO1_ACCESS 0x00007918 //0x1E46 +#define QUASAR_LBC_READ_FIFO1_CNT 0x0000791C //0x1E47 +#define QUASAR_LBC_WRITE_ADDR 0x00007920 //0x1E48 +#define QUASAR_LBC_WRITE_DATA 0x00007924 //0x1E49 +#define QUASAR_LBC_READ_ADDR 0x00007928 //0x1E4a +#define QUASAR_LBC_READ_DATA 0x0000792C //0x1E4b +#define QUASAR_LBC_BURST_XFER_CTRL 0x00007930 //0x1E4c +#define QUASAR_LBC_STATUS 0x00007934 //0x1E4d +#define QUASAR_LBC_INTERRUPT 0x00007938 //0x1E4e +#define QUASAR_LBC_PGIO 0x0000793C //0x1E4f + +//------------------------------------------------------ +// PIO COMMAND DEFINITIONS +//------------------------------------------------------ +// IN/OUTPUT PIO direction +#define PIO_OUTPUT_BIT0 0x00010001 +#define PIO_OUTPUT_BIT1 0x00020002 +#define PIO_OUTPUT_BIT2 0x00040004 +#define PIO_OUTPUT_BIT3 0x00080008 +#define PIO_OUTPUT_BIT4 0x00100010 +#define PIO_OUTPUT_BIT5 0x00200020 +#define PIO_OUTPUT_BIT6 0x00400040 +#define PIO_OUTPUT_BIT7 0x00800080 +#define PIO_OUTOUT_ALL16BITS 0xFFFFFFFF +// Set DATA to the PIO OUTPUT pin +#define PIO_DATA_BIT0 0x00010001 +#define PIO_DATA_BIT1 0x00020002 +#define PIO_DATA_BIT2 0x00040004 +#define PIO_DATA_BIT3 0x00080008 +#define PIO_DATA_BIT4 0x00100010 +#define PIO_DATA_BIT5 0x00200020 +#define PIO_DATA_BIT6 0x00400040 +#define PIO_DATA_BIT7 0x00800080 + +#define PIO_EN_SET_BIT7 0x00800000 +#define PIO_EN_SET_BIT6 0x00400000 +#define PIO_EN_SET_BIT5 0x00200000 +#define PIO_EN_SET_BIT4 0x00100000 +#define PIO_EN_SET_BIT3 0x00080000 +#define PIO_EN_SET_BIT2 0x00040000 +#define PIO_EN_SET_BIT1 0x00020000 +#define PIO_EN_SET_BIT0 0x00010000 +#define PIO_EN_ALL16_BITS 0xFFFF0000 +#define PIO_EN_BITS15to8 0xFF000000 +#define PIO_EN_BITS7to0 0x00FF0000 + +//------------------------------------------------------ +// INT CTRL COMMAND DEFINITIONS +//------------------------------------------------------ +#define ENABLE_TIMER0_INT 0x00000001 +#define ENABLE_TIMER1_INT 0x00000002 +#define ENABLE_PIO0_INT 0x00000020 +#define ENABLE_PIO1_INT 0x00000040 + +#define GLOBAL_INT_ENABLE 0x80000000 + +#define MAX_INT 0x00800000 +#define Q2H_LOC_INT 0x00400000 +#define Q2H_RISC_INT 0x00200000 +#define SPI_INT 0x00100000 +#define SPI_I2S_DMA_INT 0x00080000 +#define I2S_INT 0x00040000 +#define RTC_INT 0x00020000 +#define Q2P_INT 0x00010000 +#define P2Q_DMA_INT 0x00008000 +#define OSD_DMA_INT 0x00004000 +#define FIP_INT 0x00002000 +#define IDE_DMA_INT 0x00001000 +#define IDE_INT 0x00000800 +#define DVD_DMA_INT 0x00000400 +#define DVD_INT 0x00000200 +#define I2CS_INT 0x00000100 +#define I2CM_INT 0x00000080 +#define PIO1_INT 0x00000040 +#define PIO0_INT 0x00000020 +#define UART1_INT 0x00000008 +#define UART0_INT 0x00000004 +#define WDTIMER_INT 0x00000002 +#define TIMER1_INT 0x00000002 +#define TIMER0_INT 0x00000001 + +#define JASPER_SC_VALID_INT 0x007FFFEF + +//------------------------------------------------------ +// INT CTRL COMMAND DEFINITIONS II for J_IRQCTRL.c +//------------------------------------------------------ +#define ENABLE_INT_GLOBAL 0x80000000 //INT_ENABLE command + +#define ENABLE_INT_TIMER0 0x80000001 //INT_ENABLE command +#define ENABLE_INT_WDTIMER 0x80000002 //INT_ENABLE command +#define ENABLE_INT_UART_1 0x80000004 //INT_ENABLE command +#define ENABLE_INT_UART_2 0x80000008 //INT_ENABLE command + +#define ENABLE_INT_PIO 0x80000020 //INT_ENABLE command +#define ENABLE_INT_PIO1 0x80000040 //INT_ENABLE command +#define ENABLE_INT_I2C_MASTER 0x80000080 //INT_ENABLE command + +#define ENABLE_INT_I2C_SLAVE 0x80000100 //INT_ENABLE command +#define ENABLE_INT_DVD 0x80000200 //INT_ENABLE command +#define ENABLE_INT_DVD_DMA 0x80000400 //INT_ENABLE command +#define ENABLE_INT_IDE 0x80000800 //INT_ENABLE command + +#define ENABLE_INT_IDE_DMA 0x80001000 //INT_ENABLE command +#define ENABLE_INT_FIP 0x80002000 //INT_ENABLE command +#define ENABLE_INT_OSD_DMA 0x80004000 //INT_ENABLE command +#define ENABLE_INT_H2Q_DMA 0x80008000 //INT_ENABLE command + +#define ENABLE_INT_Q2H_DMA 0x80010000 //INT_ENABLE command +#define ENABLE_INT_RTC 0x80020000 //INT_ENABLE command +#define ENABLE_INT_I2S 0x80040000 //INT_ENABLE command +#define ENABLE_INT_I2S_DMA 0x80080000 //INT_ENABLE command + +#define ENABLE_INT_SPI 0x80100000 //INT_ENABLE command +#define ENABLE_INT_Q2H_RISC 0x80200000 //INT_ENABLE command +#define ENABLE_INT_Q2H_LOC 0x80400000 //INT_ENABLE command + +#define DISABLE_INT_GLOBAL 0x7FFFFFFF //INT_ENABLE command +#define DISABLE_INT_UART_1 0xFFFFFFFB //INT_ENABLE command +#define DISABLE_INT_UART_2 0xFFFFFFF7 //INT_ENABLE command +#define DISABLE_INT_ALL 0x10000000 //INT_ENABLE command + +//------------------------------------------------------ +//SYSTEM CTRL COMMAND DEFINITIONS +//------------------------------------------------------ +#define SYSCTRL_CMD_RESET_TIMER 0x00000001 // Bit 0 +#define SYSCTRL_CMD_RESET_INTCTRL 0x00000002 // Bit 1 +#define SYSCTRL_CMD_RESET_UART0 0x00000004 // Bit 2 +#define SYSCTRL_CMD_RESET_UART1 0x00000008 // Bit 3 +#define SYSCTRL_CMD_RESET_MAC 0x00000010 // Bit 4 +#define SYSCTRL_CMD_RESET_PIO0 0x00000020 // Bit 5 +#define SYSCTRL_CMD_RESET_PIO1 0x00000040 // Bit 6 +#define SYSCTRL_CMD_RESET_I2CM 0x00000080 // Bit 7 + +#define SYSCTRL_CMD_RESET_I2CS 0x00000100 // Bit 8 +#define SYSCTRL_CMD_RESET_DVD 0x00000200 // Bit 9 +#define SYSCTRL_CMD_RESET_DVD_DMA 0x00000400 // Bit10 +#define SYSCTRL_CMD_RESET_IDE 0x00000800 // Bit11 +#define SYSCTRL_CMD_RESET_IDE_DMA 0x00001000 // Bit12 +#define SYSCTRL_CMD_RESET_FIP 0x00002000 // Bit13 +#define SYSCTRL_CMD_RESET_OSD_DMA 0x00004000 // Bit14 +#define SYSCTRL_CMD_RESET_H2Q_DMA 0x00008000 // Bit15 + +#define SYSCTRL_CMD_RESET_Q2H_DMA 0x00010000 // Bit16 +#define SYSCTRL_CMD_RESET_RTC 0x00020000 // Bit17 +#define SYSCTRL_CMD_RESET_I2S 0x00040000 // Bit18 +#define SYSCTRL_CMD_RESET_I2S_DMA 0x00080000 // Bit19 +#define SYSCTRL_CMD_RESET_SPI 0x00100000 // Bit20 +#define SYSCTRL_CMD_RESET_SLAVE 0x00200000 // Bit21 +#define SYSCTRL_CMD_RESET_3 0x00400000 // Bit22 +#define SYSCTRL_CMD_RESET_4 0x00800000 // Bit23 + +#define SYSCTRL_CMD_RESET_5 0x01000000 // Bit24 +#define SYSCTRL_CMD_RESET_6 0x02000000 +#define SYSCTRL_CMD_RESET_7 0x03000000 +#define SYSCTRL_CMD_RESET_8 0x04000000 +#define SYSCTRL_CMD_RESET_10 0x10000000 +#define SYSCTRL_CMD_RESET_11 0x20000000 +#define SYSCTRL_CMD_RESET_Q4 0x40000000 // Bit30 +#define SYSCTRL_CMD_RESET_ALL 0x80000000 // Bit31 + +#define FORCE_REMAP 0x1 +#define CPU_ACCESS_240_CLOCKS 0xF // 240 closck +#define CPU_TIMEOUT_15_CLOCK 0xF // 15 clocks +#define CPU_TIMESLOT_ENABLE 0x100 // Enable TIMESLOT mechanism + + +//------------------------------------------------------ +// MAC COMMAND DEFINITIONS +//------------------------------------------------------ +#define SDRAMCLK_EN 0x1 +#define SDRAMINI_SET 0x2 +//#define TIME_SLOT_4DW 0x0 +//#define TIME_SLOT_8DW 0x1 +//#define TIME_SLOT_16DW 0x2 +//#define TIME_SLOT_32DW 0x3 +#define TIME_SLOT_HIGH_ARBITRATION 0x10000 +#define TIME_SLOT_SLOW_ARBITRATION 0x000 + + + +//------------------------------------------------------ +// TIMER COMMAND DEFINITIONS +//------------------------------------------------------ +#define TIMER02IRQ 0xFFFFFFFE +#define TIMER02FIQ 0x00000001 +#define TIMER12IRQ 0xFFFFFFFD +#define TIMER12FIQ 0x00000002 +#define TIMER0_START 0x00000010 +#define TIMER1_START 0x00000020 +#define TIMER0_INT_CLR 0x00000001 +#define TIMER1_INT_CLR 0x00000002 + +#define TIMER_FREE_RUN_MODE 0x00000000 +#define TIMER_PERIODIC_MODE 0x00000010 +#define TIMER_RUN_OUT_MODE 0x00000020 +#define TIMER_COUNT_ENABLE 0x00000080 + +#define TIMER_NO_PRESCALE 0x0 +#define TIMER_PRESCALE_4 0x1 +#define TIMER_PRESCALE_8 0x2 +#define TIMER_PRESCALE_16 0x3 +#define TIMER_PRESCALE_32 0x4 +#define TIMER_PRESCALE_64 0x5 +#define TIMER_PRESCALE_128 0x6 +#define TIMER_PRESCALE_256 0x7 +#define TIMER_PRESCALE_512 0x8 +#define TIMER_PRESCALE_1024 0x9 +#define TIMER_PRESCALE_2048 0xA +#define TIMER_PRESCALE_4096 0xB +#define TIMER_PRESCALE_8192 0xC +#define TIMER_PRESCALE_16384 0xD +#define TIMER_PRESCALE_32768 0xE +#define TIMER_PRESCALE_65536 0xF + + +//------------------------------------------------------ +// SPI COMMAND DEFINITIONS +//------------------------------------------------------ +#define SPI_ENABLE 0x1 +#define SPI_RESET 0x2 +#define SPI_RESET_ERR_CNTR 0x4 +#define SPI_DISABLE_ERR_CHECK 0x8 +#define SPI_STATUS_MASK 0x000070 + +#define SPI_PKT_DONE 0x1 +#define SPI_SIZE_ERR 0x2 +#define SPI_SYNC_ERR 0x4 +#define SPI_HW_ERR 0x8 + +//------------------------------------------------------ +// SPI/I2S-DMA COMMAND DEFINITIONS +//------------------------------------------------------ +#define SPI_I2S_DMA_RESET 0x2 +#define SPI_I2S_DMA_EN 0x1 +#define SPI_I2S_INT_BUF_FULL 0x1 +#define SPI_I2S_INT_BUF_14 0x2 +#define SPI_I2S_INT_BUF_12 0x4 +#define SPI_I2S_INT_BUF_34 0x8 +#define SPI_I2S_CIR_EN 0x8 /* Enable circular buffer */ +#define SPI_I2S_MUX_SPI_SELECT 0x10 +#define SPI_I2S_FLASH_INTER_FIFO 0x4 + +//------------------------------------------------------ +// FIP COMMAND DEFINITIONS +//------------------------------------------------------ +#define FIP_CMD_DISP_MODE_08DIGITS_20SEGMENTS 0x00 +#define FIP_CMD_DISP_MODE_09DIGITS_19SEGMENTS 0x08 +#define FIP_CMD_DISP_MODE_10DIGITS_18SEGMENTS 0x09 +#define FIP_CMD_DISP_MODE_11DIGITS_17SEGMENTS 0x0a +#define FIP_CMD_DISP_MODE_12DIGITS_16SEGMENTS 0x0b +#define FIP_CMD_DISP_MODE_13DIGITS_15SEGMENTS 0x0c +#define FIP_CMD_DISP_MODE_14DIGITS_14SEGMENTS 0x0d +#define FIP_CMD_DISP_MODE_15DIGITS_13SEGMENTS 0x0e +#define FIP_CMD_DISP_MODE_16DIGITS_12SEGMENTS 0x0f + + +#define FIP_CMD_DATA_SET_RW_MODE_WRITE_DISPLAY 0x40 +#define FIP_CMD_DATA_SET_RW_MODE_WRITE_LED_PORT 0x41 +#define FIP_CMD_DATA_SET_RW_MODE_READ_KEYS 0x42 +#define FIP_CMD_DATA_SET_RW_MODE_READ_SWITCHES 0x43 +#define FIP_CMD_DATA_SET_ADR_MODE_INCREMENT_ADR 0x40 +#define FIP_CMD_DATA_SET_ADR_MODE_FIXED_ADR 0x44 +#define FIP_CMD_DATA_SET_OP_MODE_NORMAL_OPERATION 0x40 +#define FIP_CMD_DATA_SET_OP_MODE_TEST_MODE 0x48 + +#define FIP_CMD_ADR_SETTING 0xC0 + +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_1_16 0x80 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_2_16 0x81 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_4_16 0x82 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_10_16 0x83 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_11_16 0x84 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_12_16 0x85 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_13_16 0x86 +#define FIP_CMD_DISP_CTRL_PULSE_WIDTH_14_16 0x87 +#define FIP_CMD_DISP_CTRL_TURN_DISPLAY_OFF_MASK 0x87 +#define FIP_CMD_DISP_CTRL_TURN_DISPLAY_ON 0x88 + +//--------------------------------------------------------------------------------------------- +// I/O Macro definitions +//--------------------------------------------------------------------------------------------- +#define PRINT_STATUS *( (volatile unsigned int * )SimStatusAddress) +#define VERILOG_STOP *( (volatile unsigned int * )SIMULATION_CONTROL) = SIMULATION_CMD_STOP_WITH_ERROR + +//--------------------------------------------------------------------------------------------- +// QuickTurn Macro definitions +//--------------------------------------------------------------------------------------------- +#define WRITE_LED_DISPLAY PIO_0_DATA_REG +#define WRITE_HEX_DISPLAY PIO_1_DATA_REG + +//--------------------------------------------------------------------------------------------- +// PIO Macro definitions +//--------------------------------------------------------------------------------------------- +#define PIO_0_INT_STATUS_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_INT_STATUS) ) +#define PIO_0_DATA_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_DATA) ) +#define PIO_0_DIR_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_DIR) ) +#define PIO_0_POL_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_POL) ) +#define PIO_0_INT_ENABLE_REG ( (volatile unsigned int * ) (JASPER_PIO0_BASE + PIO_INT_ENABLE) ) + +#define PIO_1_INT_STATUS_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_INT_STATUS) ) +#define PIO_1_DATA_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_DATA) ) +#define PIO_1_DIR_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_DIR) ) +#define PIO_1_POL_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_POL) ) +#define PIO_1_INT_ENABLE_REG ( (volatile unsigned int * ) (JASPER_PIO1_BASE + PIO_INT_ENABLE) ) + +//--------------------------------------------------------------------------------------------- +// SPI_I2S_DMA Macro definitions +//--------------------------------------------------------------------------------------------- +#define SPI_I2S_DMA_REG_CTRL ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_CTRL_REG) ) +#define SPI_I2S_DMA_REG_BASE_ADD ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_BASE_ADD_REG) ) +#define SPI_I2S_DMA_REG_SIZE ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_SIZE_REG) ) +#define SPI_I2S_DMA_REG_WR_PTR ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_WR_PTR_REG) ) +#define SPI_I2S_DMA_REG_RD_PTR ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_RD_PTR_REG) ) +#define SPI_I2S_DMA_REG_TRSH ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_TRSH_REG) ) +#define SPI_I2S_DMA_REG_INT_EN ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INT_EN_REG) ) +#define SPI_I2S_DMA_REG_INT ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INT_REG) ) +#define SPI_I2S_DMA_REG_INT_POLL ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INT_POLL_REG) ) +#define SPI_I2S_DMA_REG_INTER_FIFO ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_INTER_FIFO_REG) ) +#define SPI_I2S_DMA_REG_CNT ( (volatile unsigned int * ) (SPI_I2S_DMA_BASE + SPI_I2S_DMA_CNT_REG) ) + +//--------------------------------------------------------------------------------------------- +// Memory Access Controller (MAC) Macro definitions +//--------------------------------------------------------------------------------------------- +#define MAC_REFTIMER_REG ( (volatile unsigned int * ) (MAC_base + MAC_REFTIMER) ) +#define MAC_FLASHCFG_REG ( (volatile unsigned int * ) (MAC_base + MAC_FLASH_CFG) ) +#define MAC_SDRAMCTL_REG ( (volatile unsigned int * ) (MAC_base + MAC_SDRAMCTL) ) +#define MAC_SDRAMCFG_REG ( (volatile unsigned int * ) (MAC_base + MAC_SDRAMCFG) ) +#define MAC_SDRAMDATA_REG ( (volatile unsigned int * ) (MAC_base + MAC_SDRAMDATA) ) + +//--------------------------------------------------------------------------------------------- +// Interrupt Controller Macro definitions +//--------------------------------------------------------------------------------------------- +#define INT_IRQSTAT_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_IRQSTAT) ) +#define INT_FIQSTAT_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_FIQSTAT) ) +#define INT_TYPE_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_INTTYPE) ) +#define INT_POLL_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_INTPOLL) ) +#define INT_ENABLE_REG ( (volatile unsigned int * ) (JASPER_INT_CONTROLLER_BASE + INT_INTEN) ) + +//--------------------------------------------------------------------------------------------- +// SPI Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define SPI_CNTR_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_CNTR) ) +#define SPI_REC_COUNTER_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_REC_COUNTER) ) +#define SPI_INT_EN_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_INT_EN) ) +#define SPI_INT_STATUS_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_INT_STATUS) ) +#define SPI_ERROR_CNT_REG ( (volatile unsigned int * ) (JASPER_SPI_BASE + SPI_ERROR_CNT) ) + +//--------------------------------------------------------------------------------------------- +// I2S Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define I2S_CTRL_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_CTRL) ) +#define I2S_PROG_LEN_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_PROG_LEN) ) +#define I2S_STATUS_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_STATUS) ) +#define I2S_FRAME_CNTR_REG ( (volatile unsigned int * ) (JASPER_I2S_BASE + I2S_FRAME_CNTR) ) + +//--------------------------------------------------------------------------------------------- +// RTC Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define RTC_CTRL_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_CTRL) ) +#define RTC_LOAD1_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_LOAD1) ) +#define RTC_LOAD2_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_LOAD2) ) +#define RTC_ALARM_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_ALARM) ) +#define RTC_INTEN_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_INTEN) ) +#define RTC_INT_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_INT0) ) +#define RTC_COUNT1_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_COUNT1) ) +#define RTC_COUNT2_REG ( (volatile unsigned int * ) (JASPER_RTC_BASE + RTC_COUNT2) ) + +//--------------------------------------------------------------------------------------------- +// Timer Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define TIMER_TMRSTAT_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMRSTAT) ) +#define TIMER0_LOAD_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR0LOAD) ) +#define TIMER0_VAL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR0VAL) ) +#define TIMER0_CNTL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR0CTL) ) + +#define TIMER1_LOAD_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR1LOAD) ) +#define TIMER1_VAL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR1VAL) ) +#define TIMER1_CNTL_REG ( (volatile unsigned int * ) (JASPER_TIMER_BASE + TIMER_TMR1CTL) ) + +//--------------------------------------------------------------------------------------------- +// Interrupt Registers Macro definitions +//--------------------------------------------------------------------------------------------- +/* XXX - defined twice - see above INT_xxx_REG +#define INTERRUPT_IRQSTAT_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_IRQSTAT) ) +#define INTERRUPT_FIQSTAT_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_FIQSTAT) ) +#define INTERRUPT_INTTYPE_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_INTTYPE) ) +#define INTERRUPT_POLL_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_INTPOLL) ) +#define INTERRUPT_ENABLE_REG ( (volatile unsigned int * ) (INT_CONTROLLER_BASE + INT_INTEN) ) +*/ + +//--------------------------------------------------------------------------------------------- +// System Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define SYS_CHIPID_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_CHIP_ID) ) +#define SYS_REVID_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_REVISION_ID) ) +#define SYS_CPU_CFG_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_CPUCFG) ) +#define SYS_TESTSTAT_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_TESTSTAT) ) +#define SYS_RESET_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_RSTCTL) ) +#define SYS_TIMESLOT_REG ( (volatile unsigned int * ) (JASPER_SYSCTRL_BASE + SYSCTRL_CPUTIMESLOT) ) + +//--------------------------------------------------------------------------------------------- +// FIP Registers Macro definitions +//--------------------------------------------------------------------------------------------- +#define FIP_COMMAND_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_COMMAND) ) +#define FIP_DISPLAY_DATA_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_DISPLAY_DATA) ) +#define FIP_LED_DATA_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_LED_DATA) ) +#define FIP_KEY_DATA1_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_KEY_DATA1) ) +#define FIP_KEY_DATA2_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_KEY_DATA2) ) +#define FIP_SWITCH_DATA_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_SWITCH_DATA) ) +#define FIP_CLK_DIV_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_CLK_DIV) ) +#define FIP_TRISTATE_MODE_REG ( (volatile unsigned int * ) (JASPER_FIP_BASE + FIP_TRISTATE_MODE) ) + +#ifndef __ASSEMBLY__ +#include + +#define HARD_RESET_NOW() outl(JASPER_SYSCTRL_BASE + SYSCTRL_RSTCTL,1) + +static inline unsigned long __get_clock(unsigned int unit) +{ + unsigned int clock; +#ifndef CONFIG_QUICKTURN_HACKS + unsigned int pll_reg; + unsigned int pll_mult, pll_div, pll_D; + + pll_reg = inl(JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + pll_mult = (pll_reg & 0xFF) >> 2; + pll_div = (pll_reg >> 8 ) & 0x3; + pll_D = (pll_reg & 0x2); + + clock = ((JASPER_EXT_CLOCK / unit) * (pll_mult+2))/(pll_div + 2); + if(pll_D) + clock = clock / 2; +#else +#warning ***** QUICKTURN HACK ***** Kernel think CPU clock is 4 Mhz + clock = 4000000 / unit; +#endif + return clock; +} +#endif + +#endif /* _ASM_ARCH_HARDWARE_H */ + + diff --git a/src/libsp/MP/sp_cdrom.cpp b/src/libsp/MP/sp_cdrom.cpp new file mode 100644 index 0000000..a02ced6 --- /dev/null +++ b/src/libsp/MP/sp_cdrom.cpp @@ -0,0 +1,670 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CDROM driver's functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_cdrom.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + + + +//#define USE_UCLINUX_26 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __USE_LARGEFILE64 +#define __USE_LARGEFILE64 +#endif + +#include + +#include +#include + +#include "sp_misc.h" +#include "sp_msg.h" +#include "sp_cdrom.h" + +/// CD-ROM fs mount flag +static BOOL cdrom_cd_mounted = FALSE, cdrom_hdd_mounted = FALSE, cdrom_cd_inserted = FALSE; +static BOOL cdrom_cd = FALSE, cdrom_hdd = FALSE, cdrom_hdd_root = FALSE; +static int cdrom_mount_tries = 0; +/// CD-ROM fs mount language +static const char *def_cdrom_language = "iso8859-1"; +static char *cdrom_language = NULL; +static char cdrom_last_letter = 'c'; +static CDROM_STATUS cdrom_hdd_status = CDROM_STATUS_HAS_ISO; + +/// Internal function used by cdrom_getstatus() +static int cdrom_getmediumtype(); + +#if 0 +static void cdrom_count_tracks(); +#endif + +/// OS-specific path to CD-ROM. Used by cdrom_getdevicepath() +static const char *curdvdpath = "/dev/cdroms/cdrom0"; + +/// CD-ROM device handle +int cdrom_handle = -1; +int cdrom_hdd_handle[2] = { -1, -1 }; + +/// Used by cdrom_getmediumtype(). +/// Taken from linux/cdrom.h (kernel mode) + +#ifndef USE_UCLINUX_26 +struct mode_page_header +{ + WORD mode_data_length; + BYTE medium_type; + BYTE reserved1; + BYTE reserved2; + BYTE reserved3; + WORD desc_length; +}; +#endif + + +/// Used by cdrom_getmediumtype(). +/// Taken from drivers/ide/ide-cd.h (uClinux source) +struct atapi_capabilities_page +{ + struct mode_page_header header; + BYTE caps[20]; +}; + + +BOOL cdrom_init() +{ + cdrom_deinit(); + + cdrom_language = SPstrdup(def_cdrom_language); + cdrom_hdd_mounted = FALSE; + cdrom_cd_mounted = FALSE; + cdrom_mount_tries = 0; + cdrom_cd_inserted = FALSE; + + // try CD-ROM + cdrom_handle = open("/dev/cdroms/cdrom0", O_NONBLOCK); + if (cdrom_handle >= 0) + { + cdrom_cd = TRUE; + printf("cdrom: CD-ROM Detected!\n"); + } + // try HDD + for (int i = 0; i < 2; i++) + { + char hdd_name[40]; + sprintf(hdd_name, "/dev/discs/disc%d/disc", i); + cdrom_hdd_handle[i] = open(hdd_name, O_NONBLOCK); + if (cdrom_hdd_handle[i] >= 0) + { + cdrom_hdd = TRUE; + printf("cdrom: HDD-%d Detected!\n", i+1); + } + } + + return (cdrom_handle != -1 || cdrom_hdd_handle[0] != -1 || cdrom_hdd_handle[1] != -1); +} + +BOOL cdrom_switch(BOOL on) +{ + if (cdrom_hdd) + { + BYTE args1[4], args2[4]; + int r1, r2 = 0; + + for (int i = 0; i < 2; i++) + { + if (on) + { + static const BYTE on_args1[4] = { WIN_SETIDLE1, 0, 0, 0 }; + static const BYTE on_args2[4] = { WIN_SETIDLE2, 0, 0, 0 }; + + memcpy(args1, on_args1, 4); + memcpy(args2, on_args2, 4); + } else + { + static const BYTE off_args1[4] = { WIN_STANDBYNOW1, 0, 0, 0 }; + static const BYTE off_args2[4] = { WIN_STANDBYNOW2, 0, 0, 0 }; + + memcpy(args1, off_args1, 4); + memcpy(args2, off_args2, 4); + } + + if (cdrom_hdd_handle[i] == -1) + continue; + r1 = ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &args1); + if (r1 != 0) + r2 = ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &args2); + + printf("HDD-%d: Switch %s (result=%d,%d)\n", i+1, (on ? "On" : "Off"), r1, r2); + + // now check the results... + BYTE cp_args1[4] = { WIN_CHECKPOWERMODE1, 0, 0, 0 }; + BYTE cp_args2[4] = { WIN_CHECKPOWERMODE2, 0, 0, 0 }; + const char *state; + if (ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &cp_args1) && ioctl(cdrom_hdd_handle[i], HDIO_DRIVE_CMD, &cp_args2)) + { + if (errno != EIO || cp_args1[0] != 0 || cp_args1[1] != 0) + state = "Unknown"; + else + state = "Sleeping"; + } else + { + if (cp_args1[2] == 255 || cp_args2[2] == 255) + state = "Active/Idle"; + else + state = "Standby"; + } + msg("HDD-%d: Drive state is: %s\n", i+1, state); + } + } + if (cdrom_cd) + { + if (on) + ioctl(cdrom_handle, CDROMSTART); + else + ioctl(cdrom_handle, CDROMSTOP); + + printf("CD: Switch %s\n", (on ? "On" : "Off")); + } + return TRUE; +} + +BOOL cdrom_deinit() +{ + if (cdrom_handle != -1) + close (cdrom_handle); + if (cdrom_hdd_handle[0] != -1) + close (cdrom_hdd_handle[0]); + if (cdrom_hdd_handle[1] != -1) + close (cdrom_hdd_handle[1]); + cdrom_handle = -1; + cdrom_hdd_handle[0] = cdrom_hdd_handle[1] = -1; + SPSafeFree(cdrom_language); + return TRUE; +} + +int cdrom_eject(BOOL open) +{ + if (cdrom_cd) + { + struct timeval tv; + struct timezone tz; + int start_time, stop_time; + + cdrom_generic_command cmd; + struct request_sense sense; + + cdrom_umount(); + + // [bombur]: I wish it was true... :-( + //return ioctl(cdrom_handle, CDROMEJECT, 0); + + // [bombur]: this is the exact code used in original init! + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; + cmd.cmd[4] = 0; // unlock + cmd.buffer = NULL; + cmd.buflen = 0; + cmd.sense = &sense; + cmd.data_direction = CGC_DATA_READ; + ioctl(cdrom_handle, CDROM_SEND_PACKET, &cmd); + + gettimeofday(&tv, &tz); + start_time = tv.tv_sec * 1000 + (tv.tv_usec / 1000); + + cmd.cmd[0] = GPCMD_START_STOP_UNIT; + cmd.cmd[1] = 1; + cmd.cmd[4] = open ? 2 : 3; + if (ioctl(cdrom_handle, CDROM_SEND_PACKET, &cmd)) + return -1; + + do + { + gui_update(); + usleep(10000); + gettimeofday(&tv, &tz); + stop_time = tv.tv_sec * 1000 + (tv.tv_usec / 1000); + } while (stop_time - start_time < 2000); // less than 2 seconds passed - wait! + + return 0; + } + else if (cdrom_hdd) + { + // emulate 'ejecting' HDD - to enable 'Setup' mode possibility + cdrom_hdd_status = open ? CDROM_STATUS_TRAYOPEN : CDROM_STATUS_HAS_ISO; + return 0; + } + + return -1; +} + +int cdrom_mount(char *language, BOOL cd_only) +{ + int ret = 0; + char iocharset[1024]; + if (language == NULL) + language = cdrom_language; + + BOOL lang_changed = strcasecmp(cdrom_language, language) != 0; + if (cdrom_cd && cdrom_cd_inserted) + { + if ((!cdrom_cd_mounted && cdrom_mount_tries < 1) || lang_changed) + { + int rmnt = ((cdrom_cd_mounted && lang_changed) ? MS_REMOUNT : 0); + sprintf(iocharset, "iocharset=%s", language); + ret = mount("/dev/cdroms/cdrom0", "/cdrom", "iso9660", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + msg("CD: mount ISO with %s(%d) = %d\n", iocharset, rmnt, ret < 0 ? -errno : ret); + if (ret < 0) + { + ret = mount("/dev/cdroms/cdrom0", "/cdrom", "udf", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + msg("CD: mount UDF with %s(%d) = %d\n", iocharset, rmnt, ret < 0 ? -errno : ret); + cdrom_mount_tries++; + } + if (ret >= 0) + { + cdrom_cd_mounted = TRUE; + cdrom_mount_tries = 0; + } + } +// cdrom_count_tracks(); + } + + if (cdrom_hdd && !cd_only) + { + if (!cdrom_hdd_mounted || lang_changed) + { + char tmpdir[256], tmpmnt[256]; + char dirname[40]; + const char *mntname = "/hdd/"; + char mnt_char = 'c'; + struct dirent *entry; + //int rmnt = ((cdrom_hdd_mounted && lang_changed) ? MS_REMOUNT : 0); + int rmnt = 0; + for (int i = 0; i < 2; i++) + { + if (cdrom_hdd_handle[i] < 0) + continue; + sprintf(dirname, "/dev/discs/disc%d", i); + DIR *dir = opendir(dirname); + printf("Mounting HDD-%d...\n", i+1); + while ((entry = readdir(dir)) != NULL) + { + if (memcmp(entry->d_name, "part", 4) == 0) + { + sprintf(tmpdir, "%s/%s", dirname, entry->d_name); + sprintf(tmpmnt, "%s%c", mntname, mnt_char); + + if (lang_changed) + umount(tmpmnt); + + printf("* Mounting %s AS FAT: ", tmpdir);fflush(stdout); + sprintf(iocharset, "iocharset=%s", language); + ret = mount(tmpdir, tmpmnt, "vfat", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + if (ret < 0) + { + printf("NO. Mounting AS NTFS: ");fflush(stdout); + sprintf(iocharset, "nls=%s", language); + ret = mount(tmpdir, tmpmnt, "ntfs", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + } + printf(ret < 0 ? "FAILED\n" : "OK\n");fflush(stdout); + if (ret >= 0) + { + mnt_char++; + cdrom_hdd_mounted = TRUE; + } + } + } + cdrom_last_letter = mnt_char - 1; + closedir(dir); + + msg("HDD-%d: mount with %s(%d) = %d\n", i+1, iocharset, rmnt, ret < 0 ? -errno : ret); + } + } + } + + if (lang_changed) + { + SPSafeFree(cdrom_language); + cdrom_language = SPstrdup(language); + } + + return ret; +} + +int cdrom_umount() +{ + msg("CD-ROM: umount.\n"); + if (cdrom_cd) + { + cdrom_cd_mounted = FALSE; + cdrom_mount_tries = 0; + return umount("/cdrom"); + } + return FALSE; +} + +BOOL cdrom_ismounted() +{ + return cdrom_cd ? cdrom_cd_mounted : cdrom_hdd_mounted; +} + +static CDROM_STATUS cdrom_detect_dvd() +{ + char dvdpath2[1024]; + + cdrom_cd_inserted = TRUE; + + cdrom_mount(NULL, TRUE); + + DIR *dir = opendir("/cdrom"); + struct dirent *entry; + struct stat statbuf; + while ((entry = readdir(dir)) != NULL) + { + if (strcasecmp(entry->d_name, "VIDEO_TS") == 0) + { + sprintf(dvdpath2, "/cdrom/%s", entry->d_name); + if (stat(dvdpath2, &statbuf) >= 0) + { + if (S_ISDIR(statbuf.st_mode)) + { + closedir(dir); + cdrom_umount(); + return CDROM_STATUS_HAS_DVD; + } + } + } + } + closedir(dir); + + cdrom_umount(); + return CDROM_STATUS_HAS_ISO; +} + +CDROM_STATUS cdrom_getstatus(BOOL *force_update) +{ + static int old_medium = -1; + static CDROM_STATUS old_status = CDROM_STATUS_UNKNOWN; + + if (!cdrom_cd && cdrom_hdd) + return cdrom_hdd_status; + + if (cdrom_handle != -1) + { + int medium = cdrom_getmediumtype(), auxtype; + + if (medium != old_medium) + { + *force_update = TRUE; + msg("Drive: medium type = %d.\n", medium); + } + + switch (medium) + { + case 112: + old_status = cdrom_hdd ? cdrom_hdd_status : CDROM_STATUS_NODISC; + cdrom_cd_inserted = FALSE; + cdrom_mount_tries = 0; + old_medium = medium; + return old_status; + case 113: + old_status = CDROM_STATUS_TRAYOPEN; + cdrom_cd_inserted = FALSE; + cdrom_mount_tries = 0; + old_medium = medium; + return old_status; + case 1: + case 4: + case 5: + case 8: + case 0x11: + case 0x14: + case 0x15: + case 0x18: + case 0x21: + case 0x24: + case 0x25: + case 0x28: + // [bombur]: mixed discs are not always recognized by mediumtype + auxtype = ioctl(cdrom_handle, CDROM_DISC_STATUS, CDSL_CURRENT); + old_status = (auxtype == CDS_MIXED) ? CDROM_STATUS_HAS_MIXED : CDROM_STATUS_HAS_ISO; + old_medium = medium; + cdrom_cd_inserted = TRUE; + return old_status; + case 2: + case 6: + case 0x12: + case 0x16: + case 0x22: + case 0x26: + old_medium = medium; + old_status = cdrom_hdd ? CDROM_STATUS_HAS_MIXED : CDROM_STATUS_HAS_AUDIO; + cdrom_cd_inserted = TRUE; + return old_status; + case 3: + case 7: + case 0x13: + case 0x17: + case 0x23: + case 0x27: + old_medium = medium; + old_status = CDROM_STATUS_HAS_MIXED; + cdrom_cd_inserted = TRUE; + return old_status; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + if (old_medium < 0x40 || old_medium > 0x48 || old_status == CDROM_STATUS_UNKNOWN) + old_status = cdrom_detect_dvd(); + old_medium = medium; + return old_status; + case 0: + old_medium = medium; + break; + default: + if (medium != old_medium) + msg("Drive: Unknown medium type = %d.\n", medium); + old_medium = medium; + break; + } + } + return CDROM_STATUS_UNKNOWN; +} + +BOOL cdrom_isready() +{ + // ready or not, we failed + if (cdrom_handle == -1) + return TRUE; + if (cdrom_hdd && !cdrom_cd) + return TRUE; + + int drive = ioctl(cdrom_handle, CDROM_DRIVE_STATUS, CDSL_CURRENT); + int disc = ioctl(cdrom_handle, CDROM_DISC_STATUS, CDSL_CURRENT); + +// msg("CD-ROM: drive.status = %d disc.status = %d.\n", drive, disc); +// gui_update(); + + if (/*drive == CDS_TRAY_OPEN || */drive == CDS_DRIVE_NOT_READY || + /*disc == CDS_TRAY_OPEN || */disc == CDS_DRIVE_NOT_READY) + return FALSE; + return TRUE; +} + +/// Internal function used by cdrom_getstatus() +/// [bombur]: this was die hard! +int cdrom_getmediumtype() +{ + cdrom_generic_command cmd; + struct request_sense sense; + struct atapi_capabilities_page caps; + + if (cdrom_handle != -1) + { + memset(&cmd, 0, sizeof(cmd)); + cmd.buffer = (BYTE *)∩︀ + cmd.buflen = sizeof(caps); + cmd.cmd[0] = GPCMD_MODE_SENSE_10; + cmd.cmd[2] = GPMODE_CAPABILITIES_PAGE; + cmd.cmd[8] = cmd.buflen & 0xff; + cmd.sense = &sense; + cmd.data_direction = CGC_DATA_READ; + ioctl(cdrom_handle, CDROM_SEND_PACKET, &cmd); + + return caps.header.medium_type; + } + return 0; +} + +const char *cdrom_getdevicepath(const char *src_path) +{ + if (src_path != NULL) + return src_path; + return curdvdpath; +} + +int cdrom_stat(const char *path, struct stat64 *s) +{ + return stat64(path, s); +} + +DIR *cdrom_opendir(const char *path) +{ + cdrom_hdd_root = FALSE; + if (cdrom_hdd) + { + if (strcasecmp(path, "/hdd/") == 0) + cdrom_hdd_root = TRUE; + } + return opendir(path); +} + +struct dirent *cdrom_readdir(DIR *dir) +{ + struct dirent *d = readdir(dir); + // fast mount-check (exclude unmounted folders) + if (cdrom_hdd_root && d->d_name[0] > cdrom_last_letter && d->d_name[1] == '\0') + return NULL; + return d; +} + +int cdrom_closedir(DIR *dir) +{ + return closedir(dir); +} + +int cdrom_open(const char *fname, int flags) +{ + return open(fname, flags | O_LARGEFILE); +} + +char *cdrom_getrealpath(const char *path) +{ + static char tmpp[4096]; +msg("CD-ROM: GET_REAL_PATH (%s) = %d %d %d\n", path, cdrom_hdd, cdrom_cd, cdrom_cd_inserted); + if (memcmp(path, "/", 2) == 0) + { + if (cdrom_hdd && cdrom_cd && cdrom_cd_inserted) + return (char *)path; + else if (cdrom_hdd) + strcpy(tmpp, "/hdd"); + else + strcpy(tmpp, "/cdrom"); + strcat(tmpp, path); + return tmpp; + } + return (char *)path; +} + + +#if 0 +void cdrom_count_tracks() +{ + struct cdrom_tochdr header; + struct cdrom_tocentry entry; + int ret, i; +/* + tracks->data=0; + tracks->audio=0; + tracks->cdi=0; + tracks->xa=0; + tracks->error=0; +*/ + /* Grab the TOC header so we can see how many tracks there are */ + if ((ret = ioctl(cdrom_handle, CDROMREADTOCHDR, &header))) + { + if (ret == -ENOMEDIUM) + msg("cdrom_count_tracks: CDS_NO_DISC!"); + else + msg("cdrom_count_tracks: CDS_NO_INFO!"); + return; + } + /* check what type of tracks are on this disc */ + entry.cdte_format = CDROM_MSF; + msg("Starting %d-%d:\n", header.cdth_trk0, header.cdth_trk1); + for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) + { + entry.cdte_track = i; + if (ioctl(cdrom_handle, CDROMREADTOCENTRY, &entry)) + { + msg("track %2d: CDS_NO_INFO\n"); + continue; + } + /* + if (entry.cdte_ctrl & CDROM_DATA_TRACK) + { + if (entry.cdte_format == 0x10) + tracks->cdi++; + else if (entry.cdte_format == 0x20) + tracks->xa++; + else + tracks->data++; + } else + tracks->audio++; + */ + msg("track %2d: fmt=0x%x, ctrl=0x%x\n", i, entry.cdte_format, entry.cdte_ctrl); + } + /* + cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", + header.cdth_trk1, tracks->audio, tracks->data, + tracks->cdi, tracks->xa); + */ + usleep(1000000); +} +#endif diff --git a/src/libsp/MP/sp_eeprom.cpp b/src/libsp/MP/sp_eeprom.cpp new file mode 100644 index 0000000..1502220 --- /dev/null +++ b/src/libsp/MP/sp_eeprom.cpp @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - EEPROM interface functions source file + * For Technosonic-compatible players ('MP') + * \file sp_eeprom.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" +#include "sp_eeprom.h" + +BOOL eeprom_set_value(DWORD addr, DWORD val, int size) +{ + KHWL_ADDR_DATA data; + /// \warning: not usual byte order used! + for (int i = 0; i < size; i++) + { + data.Addr = addr + i; + data.Data = (val >> (i * 8)) & 0xff; + khwl_setproperty(KHWL_EEPROM_SET, eEepromAccess, sizeof(data), &data); + } + return TRUE; +} + +DWORD eeprom_get_value(DWORD addr, int size) +{ + KHWL_ADDR_DATA data; + DWORD val = 0; + /// \warning: not usual byte order used! + for (int i = 0; i < size; i++) + { + data.Addr = addr + i; + data.Data = 0; + khwl_getproperty(KHWL_EEPROM_SET, eEepromAccess, sizeof(data), &data); + val |= (data.Data & 0xff) << (i * 8); + } + return val; +} + diff --git a/src/libsp/MP/sp_fip.cpp b/src/libsp/MP/sp_fip.cpp new file mode 100644 index 0000000..0e1503b --- /dev/null +++ b/src/libsp/MP/sp_fip.cpp @@ -0,0 +1,261 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP interface functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_fip.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_fip.h" +#include "sp_fip_ioctl.h" + +#if defined(SP_PLAYER_TECHNOSONIC) + #include "sp_fip_codes-technosonic.h" +#elif defined(SP_PLAYER_DREAMX108) + #include "sp_fip_codes-dreamx108.h" +#elif defined(SP_PLAYER_MECOTEK) + #include "sp_fip_codes-mecotek.h" +#endif + +/// Characters supported by LED +static unsigned char char_table[] = " -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-\1"; +/// Current LEF data storage +static unsigned char fipram[12]; +/// Binary definitions for LED data +static unsigned char led_table[] = +{ + 0x00,0x10,0xEE,0x48,0xD6,0xDA,0x78,0xBA,0xBE,0xC8,0xFE,0xFA,0xFC,0xFE,0xA6,0xEE, + 0xB6,0xB4,0xBE,0x7C,0x48,0x4A,0x7C,0x26,0xEC,0xEC,0xEE,0xF4,0xEE,0xFC,0xBA,0xC8, + 0x6E,0x6E,0x6E,0x6C,0x78,0x82,0x02,0x1E,0x3E,0x16,0x5E,0xF6,0xB4,0xFA,0x3C,0x08, + 0x0A,0x2C,0x26,0x1C,0x1C,0x1E,0xF4,0xF8,0x14,0xBA,0x36,0x0E,0x0E,0x0E,0x0C,0x78, + 0x12,0x10,0x00 +}; + +static unsigned char led_special[] = +{ + 0x01, 0x07, 0x01, 0x06, 0x03, 0x07, 0x02, 0x07, 0x05, 0x07, 0x04, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x05, 0x07, 0x04, 0x07, 0x03, 0x07, 0x02, 0x07, 0x01, 0x07, 0x00, 0x09, 0x07, 0x09, 0x06, + 0x09, 0x05, 0x09, 0x04, 0x09, 0x03, 0x09, 0x02, 0x09, 0x01, 0x09, 0x00, 0x08, 0x07, 0x08, 0x06, + 0x08, 0x05, 0x08, 0x04, 0x08, 0x03, 0x08, 0x02 +}; + +/// Button codes translation look-up table +static BYTE *button_LUT = NULL; +static DWORD butcode = 0; +static int fip_panel_num_codes = 0; + +/// FIP device handle +int fip_handle = -1; + +void fip_create_table(BYTE *lut) +{ + memset(lut, 0xff, 65536); + + DWORD *codes[2]; + codes[0] = fip_panel_codes; + codes[1] = fip_remote_codes; + + fip_panel_num_codes = 0; + for (int i = 0; i < 2; i++) + { + int j; + for (j = 0; codes[i][j] != 0xffffffff; j++) + { + lut[codes[i][j] & 0xffff] = j; + } + if (i == 0) + fip_panel_num_codes = j; + } +} + +BOOL fip_init(BOOL applymodule) +{ + fip_deinit(); + + if (applymodule == FALSE || module_apply("/drivers/fipmodule.o")) // insert + { + fip_handle = open("/dev/fip", O_NONBLOCK, 0); + if (fip_handle != -1) + { + fip_clear(); + + button_LUT = (BYTE *)SPmalloc(65536); + if (button_LUT == NULL) + return FALSE; + + fip_create_table(button_LUT); + + return TRUE; + } + } + + return FALSE; +} + +BOOL fip_deinit() +{ + if (fip_handle == -1) + return FALSE; + close(fip_handle); + fip_handle = -1; + + if (button_LUT != NULL) + { + SPfree(button_LUT); + button_LUT = NULL; + } + + return TRUE; +} + +BOOL fip_clear() +{ + int i; + + if (fip_handle == -1) + return FALSE; + // clear FIP + for (i = 0; i < 10; i++) + { + fipram[i] = 0; + ioctl(fip_handle, FIP_DISPLAY_SYMBOL, i << 16); + } + return TRUE; +} + +BOOL fip_write_char(int ch, int pos) +{ + int lr; + unsigned char old_fip1, old_fip2 = 0; + + if (pos < 1 || pos - 1 > 6 || fip_handle == -1) + return FALSE; + ch &= 255; + for (lr = 0; lr < 66; lr++) + { + if (char_table[lr] == (BYTE)ch) + break; + } + // saving + old_fip1 = fipram[pos-1]; + + // clear + if (pos == 2) + { + old_fip2 = fipram[pos-2]; + + fipram[pos-1] &= 192; + fipram[pos-2] &= 127; + } else + fipram[pos-1] &= 128; + // set + if (pos == 2) + { + fipram[pos-1] |= led_table[lr] >> 2; + fipram[pos-2] |= (led_table[lr] << 6) & ~127; + } else + fipram[pos-1] |= led_table[lr] >> 1; + // write to device + if (old_fip1 != fipram[pos-1]) + ioctl(fip_handle, FIP_DISPLAY_SYMBOL, fipram[pos-1] | ((pos-1) << 16)); + if (pos == 2 && old_fip2 != fipram[pos-2]) + ioctl(fip_handle, FIP_DISPLAY_SYMBOL, fipram[pos-2] | ((pos-2) << 16)); + return TRUE; +} + +BOOL fip_write_string(const char *str) +{ + int i, len; + if (str == NULL || fip_handle == -1) + return FALSE; + len = strlen(str); + if (len > 7) + len = 7; + for (i = 0; i < 7; i++) + fip_write_char(i < len ? str[len - i - 1] : ' ', i + 1); + return TRUE; +} + +BOOL fip_write_special_char(int pos, int shift, BOOL onoff) +{ + BYTE ch = fipram[pos]; + if (onoff) + fipram[pos] = ch | (1 << shift); + else + fipram[pos] = ch & ~(1 << shift); + if (fipram[pos] == ch) + return TRUE; + ioctl(fip_handle, FIP_DISPLAY_SYMBOL, fipram[pos] | (pos << 16)); + return TRUE; +} + +BOOL fip_write_special(int id, BOOL onoff) +{ + if (id < 0 || id > 27) + return FALSE; + return fip_write_special_char(led_special[id*2], led_special[id*2+1], onoff); +} + +BOOL fip_get_special(int id) +{ + if (id < 0 || id > 27) + return FALSE; + int pos = led_special[id*2]; + int shift = led_special[id*2+1]; + return (fipram[pos] >> shift) & 1; +} + +int fip_read_button(BOOL blocked) +{ + if (fip_handle == -1 || button_LUT == NULL) + return 0; + butcode = ioctl(fip_handle, FIP_BUTTON_READ, blocked); + if (butcode == 0) + return FIP_KEY_NONE; + + BYTE bc = button_LUT[butcode & 0xffff]; +#ifdef SP_PLAYER_DREAMX108 + // special case - front panel STOP button + if (butcode == 0x00080000) + return FIP_KEY_FRONT_STOP; + // special case - front panel PREV button + if (butcode == 0x00010000) + return FIP_KEY_FRONT_SKIP_PREV; +#endif + + if (bc == 0xff) + return FIP_KEY_NONE; + if (bc < fip_panel_num_codes) + { + if (butcode == fip_panel_codes[bc]) + return (unsigned int)bc + fip_code_offset[0]; + } + if (butcode == fip_remote_codes[bc]) + return (unsigned int)bc + fip_code_offset[1]; + return FIP_KEY_NONE; +} diff --git a/src/libsp/MP/sp_fip_codes-dreamx108.h b/src/libsp/MP/sp_fip_codes-dreamx108.h new file mode 100644 index 0000000..9f7ab06 --- /dev/null +++ b/src/libsp/MP/sp_fip_codes-dreamx108.h @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP button internal codes header. + * For DreamX-108 player + * \file sp_fip_codes-dreamx108.h + * \author bombur + * \version 0.2 + * \date 21.01.2009 4.05.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_CODES_H +#define SP_FIP_CODES_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Button codes definitions: + +static DWORD fip_code_offset[2] = { FIP_KEY_FRONT_EJECT, FIP_KEY_POWER }; + +/// 1) definitions for the buttons on the front panel: +static DWORD fip_panel_codes[] = +{ + 0x00001000, // FIP_KEY_FRONT_EJECT, + 0x80000080, // FIP_KEY_FRONT_PLAY, + 0x00080000, // FIP_KEY_FRONT_STOP, + 0x08000008, // FIP_KEY_FRONT_PAUSE, + 0x00010000, // FIP_KEY_FRONT_SKIP_PREV, + 0x00004000, // FIP_KEY_FRONT_SKIP_NEXT, + 0x10000010, // FIP_KEY_FRONT_REWIND, + 0x01000001, // FIP_KEY_FRONT_FORWARD, + + 0xffffffff +}; + +/// 2) definitions for the keys on the remote control: +static DWORD fip_remote_codes[] = +{ + 0x00FBF00F, // FIP_KEY_POWER, + 0x00FBB847, // FIP_KEY_EJECT, + + 0x00FBCA35, // FIP_KEY_ONE, + 0x00FBD02F, // FIP_KEY_TWO, + 0x00FB7887, // FIP_KEY_THREE, + 0x00FBC03F, // FIP_KEY_FOUR, + 0x00FB8A75, // FIP_KEY_FIVE, + 0x00FB20DF, // FIP_KEY_SIX, + 0x00FB2AD5, // FIP_KEY_SEVEN, + 0x00FB807F, // FIP_KEY_EIGHT, + 0x00FBD827, // FIP_KEY_NINE, + 0x00FB708F, // FIP_KEY_ZERO, + + 0x00FB6897, // FIP_KEY_CANCEL, + 0x00FBE21D, // FIP_KEY_SEARCH, + 0x00FBA05F, // FIP_KEY_ENTER, + + 0x00FB827D, // FIP_KEY_OSD, + 0x00FBA25D, // FIP_KEY_SUBTITLE, + 0x00FBB24D, // FIP_KEY_SETUP, + 0x00FBD22D, // FIP_KEY_RETURN, + 0x00FBF807, // FIP_KEY_TITLE, + 0x00000800, // FIP_KEY_PN, + 0x00FB42BD, // FIP_KEY_MENU, + 0x00FB28D7, // FIP_KEY_AB, + 0x00FB8877, // FIP_KEY_REPEAT, + + 0x00FB30CF, // FIP_KEY_UP, + 0x00FBF20D, // FIP_KEY_DOWN, + 0x00FB9867, // FIP_KEY_LEFT, + 0x00FB32CD, // FIP_KEY_RIGHT, + + 0x00FBC23D, // FIP_KEY_VOLUME_DOWN, + 0x00FB22DD, // FIP_KEY_VOLUME_UP, + 0x00FB629D, // FIP_KEY_PAUSE, + + 0x00FB926D, // FIP_KEY_REWIND, + 0x00FB6A95, // FIP_KEY_FORWARD, + 0x00FB38C7, // FIP_KEY_SKIP_PREV, + 0x00FB609F, // FIP_KEY_SKIP_NEXT, + + 0x00FBA857, // FIP_KEY_PLAY, + 0x00FBB04F, // FIP_KEY_STOP, + + 0x00FBE817, // FIP_KEY_SLOW, + 0x00FB728D, // FIP_KEY_AUDIO, + 0x00FBAA55, // FIP_KEY_VMODE, + 0x00FB906F, // FIP_KEY_MUTE, + 0x00FBC837, // FIP_KEY_ZOOM, + 0x00FFBABA, // FIP_KEY_PROGRAM, + 0x00FF728D, // FIP_KEY_PBC, + 0x00FB4AB5, // FIP_KEY_ANGLE, + + 0xffffffff +}; + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_CODES_H diff --git a/src/libsp/MP/sp_fip_codes-mecotek.h b/src/libsp/MP/sp_fip_codes-mecotek.h new file mode 100644 index 0000000..108ff2e --- /dev/null +++ b/src/libsp/MP/sp_fip_codes-mecotek.h @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP button internal codes header. + * For Mecotek MK-X4000 player + * \file sp_fip_codes-mecotek.h + * \author bombur + * \version 0.1 + * \date 18.02.2010 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_CODES_H +#define SP_FIP_CODES_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Button codes definitions: + +static DWORD fip_code_offset[2] = { FIP_KEY_FRONT_EJECT, FIP_KEY_POWER }; + +/// 1) definitions for the buttons on the front panel: +static DWORD fip_panel_codes[] = +{ + 0x08000008, // FIP_KEY_FRONT_EJECT, + 0x80000080, // FIP_KEY_FRONT_PLAY, + 0x04000004, // FIP_KEY_FRONT_STOP, + 0x40000040, // FIP_KEY_FRONT_PAUSE, + 0x10000010, // FIP_KEY_FRONT_SKIP_PREV, + 0x20000020, // FIP_KEY_FRONT_SKIP_NEXT, + 0x02003333, // FIP_KEY_FRONT_REWIND, // --------------- + 0x02005555, // FIP_KEY_FRONT_FORWARD, // --------------- + + 0xffffffff +}; + +/// 2) definitions for the keys on the remote control: +static DWORD fip_remote_codes[] = +{ + 0x00FBF00F, // FIP_KEY_POWER, + 0x00FBB847, // FIP_KEY_EJECT, + + 0x00FBCA35, // FIP_KEY_ONE, + 0x00FBD02F, // FIP_KEY_TWO, + 0x00FB7887, // FIP_KEY_THREE, + 0x00FBC03F, // FIP_KEY_FOUR, + 0x00FB8A75, // FIP_KEY_FIVE, + 0x00FB20DF, // FIP_KEY_SIX, + 0x00FB2AD5, // FIP_KEY_SEVEN, + 0x00FB807F, // FIP_KEY_EIGHT, + 0x00FBD827, // FIP_KEY_NINE, + 0x00FB708F, // FIP_KEY_ZERO, + + 0x00FB6897, // FIP_KEY_CANCEL, + 0x00FBE21D, // FIP_KEY_SEARCH, + 0x00FBA05F, // FIP_KEY_ENTER, + + 0x00FB827D, // FIP_KEY_OSD, + 0x00FBA25D, // FIP_KEY_SUBTITLE, + 0x00FBB24D, // FIP_KEY_SETUP, + 0x00FBD22D, // FIP_KEY_RETURN, + 0x00FBF807, // FIP_KEY_TITLE, + 0x02000002, // FIP_KEY_PN, + 0x00FB42BD, // FIP_KEY_MENU, + 0x00FB28D7, // FIP_KEY_AB, + 0x00FB8877, // FIP_KEY_REPEAT, + + 0x00FB30CF, // FIP_KEY_UP, + 0x00FBF20D, // FIP_KEY_DOWN, + 0x00FB9867, // FIP_KEY_LEFT, + 0x00FB32CD, // FIP_KEY_RIGHT, + + 0x00FBC23D, // FIP_KEY_VOLUME_DOWN, + 0x00FB22DD, // FIP_KEY_VOLUME_UP, + 0x00FB629D, // FIP_KEY_PAUSE, + + 0x00FB926D, // FIP_KEY_REWIND, + 0x00FB6A95, // FIP_KEY_FORWARD, + 0x00FB38C7, // FIP_KEY_SKIP_PREV, + 0x00FB609F, // FIP_KEY_SKIP_NEXT, + + 0x00FBA857, // FIP_KEY_PLAY, + 0x00FBB04F, // FIP_KEY_STOP, + + 0x00FBE817, // FIP_KEY_SLOW, + 0x00FB728D, // FIP_KEY_AUDIO, + 0x00FBAA55, // FIP_KEY_VMODE, + 0x00FB906F, // FIP_KEY_MUTE, + 0x00FBC837, // FIP_KEY_ZOOM, + 0x00FFBABA, // FIP_KEY_PROGRAM, // -------- + 0x00FFE0E0, // FIP_KEY_PBC, // -------- + 0x00FB4AB5, // FIP_KEY_ANGLE, + + 0xffffffff +}; + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_CODES_H diff --git a/src/libsp/MP/sp_fip_codes-technosonic.h b/src/libsp/MP/sp_fip_codes-technosonic.h new file mode 100644 index 0000000..85a49b2 --- /dev/null +++ b/src/libsp/MP/sp_fip_codes-technosonic.h @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP button internal codes header. + * For Technosonic-compatible players ('MP') + * \file sp_fip_codes-technosonic.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_CODES_H +#define SP_FIP_CODES_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Button codes definitions: + +static DWORD fip_code_offset[2] = { FIP_KEY_FRONT_EJECT, FIP_KEY_POWER }; + +/// 1) definitions for the buttons on the front panel: +static DWORD fip_panel_codes[] = +{ + 0x08000008, // FIP_KEY_FRONT_EJECT, + 0x00000080, // FIP_KEY_FRONT_PLAY, + 0x40000040, // FIP_KEY_FRONT_STOP, + 0x04000004, // FIP_KEY_FRONT_PAUSE, + 0x02000002, // FIP_KEY_FRONT_SKIP_PREV, + 0x20000020, // FIP_KEY_FRONT_SKIP_NEXT, + 0x10000010, // FIP_KEY_FRONT_REWIND, + 0x01000001, // FIP_KEY_FRONT_FORWARD, + + 0xffffffff +}; + +/// 2) definitions for the keys on the remote control: +static DWORD fip_remote_codes[] = +{ + 0x00FF30CF, // FIP_KEY_POWER, + 0x00FFB04F, // FIP_KEY_EJECT, + + 0x00FF00FF, // FIP_KEY_ONE, + 0x00FF807F, // FIP_KEY_TWO, + 0x00FF40BF, // FIP_KEY_THREE, + 0x00FFC03F, // FIP_KEY_FOUR, + 0x00FF20DF, // FIP_KEY_FIVE, + 0x00FFA05F, // FIP_KEY_SIX, + 0x00FF609F, // FIP_KEY_SEVEN, + 0x00FFE01F, // FIP_KEY_EIGHT, + 0x00FF10EF, // FIP_KEY_NINE, + 0x00FF906F, // FIP_KEY_ZERO, + + 0x00FF50AF, // FIP_KEY_CANCEL, + 0x00FFD02F, // FIP_KEY_SEARCH, + 0x00FF708F, // FIP_KEY_ENTER, + + 0x00FF7887, // FIP_KEY_OSD, + 0x00FFF807, // FIP_KEY_SUBTITLE, + 0x00FF38C7, // FIP_KEY_SETUP, + 0x00FFB847, // FIP_KEY_RETURN, + 0x00FF28D7, // FIP_KEY_TITLE, + 0x00FFA857, // FIP_KEY_PN, + 0x00FF6897, // FIP_KEY_MENU, + 0x00FFE817, // FIP_KEY_AB, + 0x00FF18E7, // FIP_KEY_REPEAT, + + 0x00FF08F7, // FIP_KEY_UP, + 0x00FF8877, // FIP_KEY_DOWN, + 0x00FF48B7, // FIP_KEY_LEFT, + 0x00FFC837, // FIP_KEY_RIGHT, + + 0x00FFD827, // FIP_KEY_VOLUME_DOWN, + 0x00FF58A7, // FIP_KEY_VOLUME_UP, + 0x00FF9867, // FIP_KEY_PAUSE, + + 0x00FF02FD, // FIP_KEY_REWIND, + 0x00FF827D, // FIP_KEY_FORWARD, + 0x00FF42BD, // FIP_KEY_SKIP_PREV, + 0x00FFC23D, // FIP_KEY_SKIP_NEXT, + + 0x00FF22DD, // FIP_KEY_PLAY, + 0x00FFA25D, // FIP_KEY_STOP, + + 0x00FF12ED, // FIP_KEY_SLOW, + 0x00FF926D, // FIP_KEY_AUDIO, + 0x00FF52AD, // FIP_KEY_VMODE, + 0x00FFD22D, // FIP_KEY_MUTE, + 0x00FF32CD, // FIP_KEY_ZOOM, + 0x00FFB24D, // FIP_KEY_PROGRAM, + 0x00FF728D, // FIP_KEY_PBC, + 0x00FFF20D, // FIP_KEY_ANGLE, + + 0xffffffff +}; + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_CODES_H diff --git a/src/libsp/MP/sp_fip_ioctl.h b/src/libsp/MP/sp_fip_ioctl.h new file mode 100644 index 0000000..72becce --- /dev/null +++ b/src/libsp/MP/sp_fip_ioctl.h @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Internal FIP IOCTL codes. + * For Technosonic-compatible players ('MP') + * \file sp_fip_ioctl.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_IOCTL_H +#define SP_FIP_IOCTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Driver I/O defines: + + +/// Repeats current button press. +/// The button to be received is set to be received twice. +/// This will destroy unread queued up presses. +#define FIP_BUTTON_REPEAT 0x450000 + +/// Controls the display. +/// Used for setting the pulse width and turning the display on and off. +/// The flags you wish to set on the display where flags is one of the +/// FIP_PULSE_ defines. +#define FIP_DISPLAY_CONTROL 0x450001 + +/// Description: Displays the symbol on the display. +/// Sets given symbol data at given position: (data | (pos << 16)). +#define FIP_DISPLAY_SYMBOL 0x450002 + +/// Reads a button code (like getchar()). Can be blocked or not. +/// The button code is returned. +#define FIP_BUTTON_READ 0x450003 + +// #define FIP_??? 0x450004 + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_IOCTL_H diff --git a/src/libsp/MP/sp_i2c.cpp b/src/libsp/MP/sp_i2c.cpp new file mode 100644 index 0000000..30bad99 --- /dev/null +++ b/src/libsp/MP/sp_i2c.cpp @@ -0,0 +1,93 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - I2C data transfer functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_i2c.cpp + * \author bombur + * \version 0.1 + * \date 1.02.2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_io.h" +#include "sp_i2c.h" + +#include "arch-jasper/hardware.h" + + +BOOL i2c_data_in(BYTE addr, BYTE idx, BYTE *data, int num) +{ + outl(375, JASPER_I2C_MASTER_BASE+I2C_MASTER_CLK_DIV); + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + for (int i = 0; i < num; i++) + { + outl(250, JASPER_I2C_MASTER_BASE+I2C_MASTER_CONFIG); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_BYTE_COUNT); + outl(addr/2, JASPER_I2C_MASTER_BASE+I2C_MASTER_DEV_ADDR); + outl(idx++, JASPER_I2C_MASTER_BASE+I2C_MASTER_DATAOUT); + outl(4, JASPER_I2C_MASTER_BASE+I2C_MASTER_STARTXFER); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 2) == 0) + ; + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + outl(250, JASPER_I2C_MASTER_BASE+I2C_MASTER_CONFIG); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_BYTE_COUNT); + outl(addr/2, JASPER_I2C_MASTER_BASE+I2C_MASTER_DEV_ADDR); + outl(1, JASPER_I2C_MASTER_BASE+I2C_MASTER_STARTXFER); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 4) == 0) + ; + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + *data++ = inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_DATAIN); + } + return TRUE; +} + +BOOL i2c_data_out(BYTE addr, BYTE idx, BYTE *data, int num) +{ + outl(248, JASPER_I2C_MASTER_BASE+I2C_MASTER_CONFIG); + outl(375, JASPER_I2C_MASTER_BASE+I2C_MASTER_CLK_DIV); + outl(addr/2, JASPER_I2C_MASTER_BASE+I2C_MASTER_DEV_ADDR); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 1) == 0) + ; + + for (int i = 0; i < num; i++) + { + outl(idx++, JASPER_I2C_MASTER_BASE+I2C_MASTER_ADR); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_BYTE_COUNT); + outl(*data++, JASPER_I2C_MASTER_BASE+I2C_MASTER_DATAOUT); + outl(0, JASPER_I2C_MASTER_BASE+I2C_MASTER_STARTXFER); + + while ((inl(JASPER_I2C_MASTER_BASE+I2C_MASTER_STATUS) & 2) == 0) + ; + } + return TRUE; +} + diff --git a/src/libsp/MP/sp_khwl.cpp b/src/libsp/MP/sp_khwl.cpp new file mode 100644 index 0000000..dd0c862 --- /dev/null +++ b/src/libsp/MP/sp_khwl.cpp @@ -0,0 +1,360 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - KHWL interface functions source file. + * For Technosonic-compatible players ('MP') + * \file sp_khwl.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" +#include "sp_khwl_ioctl.h" +#include "sp_mpeg.h" +#include "sp_fip.h" +#include "sp_io.h" +#include "sp_i2c.h" + +#include "arch-jasper/hardware.h" + + +/// Muxed media packets +MpegPlayStruct *MPEG_PLAY_STRUCT = (MpegPlayStruct *)(0x17c0000 + 0x3fc00 + 768); +/// Video packets +MpegPlayStruct *MPEG_VIDEO_STRUCT = (MpegPlayStruct *)(0x2000000 - 0x800000 - 232); +/// Audio packets +MpegPlayStruct *MPEG_AUDIO_STRUCT = (MpegPlayStruct *)(0x2000000 - 0x800000 - 208); +/// Subpicture packets +MpegPlayStruct *MPEG_SPU_STRUCT = (MpegPlayStruct *)(0x2000000 - 0x800000 - 184); + +/// Buffers storage +BYTE *BUF_BASE = (BYTE *)0x01680000; +//BYTE *BUF_BASE = (BYTE *)0x016c0000; + + +/// KHWL module handle +int khwl_handle = -1; + +/// OSD properties used +KHWL_OSDSTRUCT osd = { NULL }; + +/// insmod flag +static BOOL module_applied = FALSE; + +/// If digital TV (HDTV) is installed. +static BOOL digital_tv = FALSE; + +int FRAME_WIDTH = 720; +int FRAME_HEIGHT = 480; + + +BOOL khwl_init(BOOL applymodule) +{ + khwl_inityuv(); + khwl_deinit(); + + if (module_applied == TRUE || applymodule == FALSE || module_apply("/drivers/khwl.o")) // insert + { + module_applied = TRUE; + + khwl_handle = open("/dev/realmagichwl0", 0, 0); + if (khwl_handle != -1) + { + //khwl_reset(); + + if (!khwl_restoreparams()) + return FALSE; + + return TRUE; + } + } + return FALSE; +} + +BOOL khwl_restoreparams() +{ + int val = 0; + khwl_setproperty(KHWL_VIDEO_SET, evMacrovisionFlags, sizeof(int), &val); + + int flickerval = 15; // flicker = max + khwl_setproperty(KHWL_DECODER_SET, edecOsdFlicker, sizeof(int), &flickerval); + + KHWL_WINDOW wnd, osdwnd; + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(wnd), &wnd); + khwl_setproperty(KHWL_VIDEO_SET, evDestinationWindow, sizeof(wnd), &wnd); + + osdwnd = wnd; + osdwnd.h = 30 * wnd.h / 31; + khwl_setproperty(KHWL_OSD_SET, eOsdDestinationWindow, sizeof(osdwnd), &osdwnd); + + val = 0; + khwl_setproperty(KHWL_VIDEO_SET, evForcedProgressiveAlways, sizeof(int), &val); + + KHWL_YUV_WRITE_PARAMS_TYPE yuvparams; + yuvparams.wWidth = wnd.w; + yuvparams.wHeight = wnd.h; + yuvparams.YUVFormat = KHWL_YUV_420_UNPACKED; + + khwl_setproperty(KHWL_VIDEO_SET, evYUVWriteParams, sizeof(yuvparams), &yuvparams); + + // do some HDTV-specific checks... + digital_tv = FALSE; + if ((inl(JASPER_QUASAR_BASE + QUASAR_DRAM_STARTUP1) & 0x2000) != 0) + { + BYTE data[4]; + // test for HDTV 1080I + i2c_data_in(112, 0, data, 4); + if (data[0] == 1 && data[1] == 0 && data[2] == 8 && data[3] == 0) + digital_tv = TRUE; + } + + return TRUE; +} + +BOOL khwl_deinit() +{ + if (khwl_handle == -1) + return FALSE; + close(khwl_handle); + khwl_handle = -1; + return TRUE; +} + +BOOL khwl_reset() +{ + if (khwl_handle == -1) + return FALSE; + return ioctl(khwl_handle, KHWL_HARDRESET, 0); +} + +int khwl_osd_switch(KHWL_OSDSTRUCT *_osd, BOOL autoupd) +{ + KHWL_WINDOW wnd; + int ret; + if (khwl_handle == -1) + return FALSE; + osd.flags = autoupd ? 1 : 0; + ret = ioctl(khwl_handle, KHWL_OSDFB_SWITCH, &osd); + + if (_osd != NULL) + { + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(wnd), &wnd); + khwl_setproperty(KHWL_OSD_SET, eOsdDestinationWindow, sizeof(wnd), &wnd); + *_osd = osd; + } + return ret; +} + +void khwl_get_osd_size(int *width, int *height) +{ + *width = 640;//osd.width; + *height = 480;//osd.height; +} + + +BOOL khwl_osd_update() +{ + ioctl(khwl_handle, KHWL_OSDFB_UPDATE, 0); + return TRUE; +} + +int khwl_osd_setalpha(int alpha) +{ + return ioctl(khwl_handle, KHWL_OSDFB_ALPHA, &alpha); +} + +void khwl_osd_setpalette(BYTE *pal, int entry, BYTE r, BYTE g, BYTE b, BYTE a) +{ + // assert(entry >= 0 && entry < 256); + BYTE y, u, v; + entry <<= 2; + khwl_vgargbtotvyuv(r, g, b, &y, &u, &v); + pal[entry++] = a; // alpha + pal[entry++] = y; + pal[entry++] = u; + pal[entry] = v; +} + +void khwl_osd_setfullscreen(BOOL is) +{ + KHWL_WINDOW wnd, osdwnd; + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(wnd), &wnd); + osdwnd = wnd; + if (!is) + osdwnd.h = 30 * wnd.h / 31; + khwl_setproperty(KHWL_OSD_SET, eOsdDestinationWindow, sizeof(osdwnd), &osdwnd); +} + +int khwl_displayYUV(KHWL_YUV_FRAME *f) +{ + int ret = ioctl(khwl_handle, KHWL_DISPLAY_YUV, f); + return ret; +} + +int khwl_setproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value) +{ + KHWL_PROPERTY p; + p.pset = pset; + p.id = id; + p.size = size; + p.v = value; + return ioctl(khwl_handle, KHWL_SETPROP, &p); +} + +int khwl_getproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value) +{ + KHWL_PROPERTY p; + p.pset = pset; + p.id = id; + p.size = size; + p.v = value; + return ioctl(khwl_handle, KHWL_GETPROP, &p); +} + +int khwl_audioswitch(BOOL ison) +{ + int val = ison ? 1 : 0; + return ioctl(khwl_handle, KHWL_AUDIOSWITCH, &val); +} + +int *khwl_get_samplerates() +{ + static int rates[2][12] = + { + // chip rev.A + { 16000, 22050, 24000, 32000, 44100, 48000, -1 }, + // chip rev.B supports more samplerates + { 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, -1 }, + }; + return rates[inl(SYS_REVID_REG) & 1]; +} + +int khwl_play(int mode) +{ + return ioctl(khwl_handle, KHWL_PLAY, &mode); +} + +int khwl_stop() +{ + return ioctl(khwl_handle, KHWL_STOP, 0); +} + +int khwl_pause() +{ + return ioctl(khwl_handle, KHWL_PAUSE, 0); +} + +BOOL khwl_blockirq(BOOL block) +{ + unsigned irqstat; + irqstat = inl(JASPER_INT_CONTROLLER_BASE + INT_INTEN); + if (block) + irqstat &= ~Q2H_RISC_INT; + else + irqstat |= Q2H_RISC_INT; + outl(irqstat, JASPER_INT_CONTROLLER_BASE + INT_INTEN); + return TRUE; +} + +BOOL khwl_happeningwait(DWORD *mask) +{ + KHWL_WAITABLE w; + w.mask = *mask; + w.timeout_microsecond = 400000; + ioctl(khwl_handle, KHWL_WAIT, &w); + *mask = w.mask; + return TRUE; +} + +BOOL khwl_poll(WORD mask, DWORD timeout) +{ + pollfd pfd; + pfd.events = mask; + pfd.fd = khwl_handle; + return poll(&pfd, 1, timeout) >= 0; +} + +BOOL khwl_ideswitch(BOOL ison) +{ + KHWL_ADDR_DATA data; + // switch IDE? + data.Addr = 4; + data.Data = ison ? 1 : 0; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + return TRUE; +} + +int khwl_getfrequency() +{ + int temp = inl(JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + + int div = (temp >> 8) & 0xff; + int mul = (temp >> 2) & 63; + + int freq = (27 * (mul + 2)) / ((div + 2) * 2); + return freq; +} + +BOOL khwl_setfrequency(int freq) +{ + if (freq < 100 || freq > 202) + return FALSE; + + int temp = inl(JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + temp = temp & 0xF000; + int div = (temp >> 8) & 0xff; + //int mul = (temp >> 2) & 63; + + int mul = (freq * ((10 * div+20)*20) / 270 - 20 /* + 5 */) / 10; + if (mul < 0 || mul > 63) + return FALSE; + + temp = temp | 0x02; + temp = temp | (div << 8); + temp = temp | (mul << 2); + + outl(temp & 0x7FFF, JASPER_QUASAR_BASE + QUASAR_DRAM_PLLCONTROL); + return TRUE; +} + +char *khwl_gethw() +{ + static char hw[256]; +/* + char b[128]; + b[0] = '\0'; + khwl_getproperty(KHWL_BOARDINFO_SET, ebiBoardNameString, 256, b); + + DWORD v_ebiDeviceId, v_ebiSubId, v_ebiBoardVersion, v_ebiHwLibVersion, v_ebiUcodeVersion; + khwl_getproperty(KHWL_BOARDINFO_SET, ebiDeviceId, sizeof(DWORD), &v_ebiDeviceId); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiSubId, sizeof(DWORD), &v_ebiSubId); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiBoardVersion, sizeof(DWORD), &v_ebiBoardVersion); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiHwLibVersion, sizeof(DWORD), &v_ebiHwLibVersion); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiUcodeVersion , sizeof(DWORD), &v_ebiUcodeVersion); +*/ + sprintf(hw, "%X.%c", inl(SYS_CHIPID_REG), inl(SYS_REVID_REG) + 'A'); + + return hw; +} diff --git a/src/libsp/MP/sp_khwl_ioctl.h b/src/libsp/MP/sp_khwl_ioctl.h new file mode 100644 index 0000000..3822c5d --- /dev/null +++ b/src/libsp/MP/sp_khwl_ioctl.h @@ -0,0 +1,65 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Internal KHWL driver's IOCTL codes. + * For Technosonic-compatible players ('MP') + * \file sp_khwl_ioctl.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_KHWL_IOCTL_H +#define SP_KHWL_IOCTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Driver I/O defines: + +#define KHWL_IO_BASE 0x3cc +#define KHWL_IO_PLAYER 0x3d0 +#define KHWL_IO_PROP 0x3d4 +#define KHWL_IO_OSD 0x3e0 +#define KHWL_IO_DISPLAY 0x3e3 + + +#define KHWL_HARDRESET KHWL_IO_BASE+3 + +#define KHWL_PLAY KHWL_IO_PLAYER +#define KHWL_STOP KHWL_IO_PLAYER+1 +#define KHWL_PAUSE KHWL_IO_PLAYER+2 +#define KHWL_AUDIOSWITCH KHWL_IO_PLAYER+3 + +#define KHWL_WAIT KHWL_IO_PROP+1 +#define KHWL_SETPROP KHWL_IO_PROP+2 +#define KHWL_GETPROP KHWL_IO_PROP+3 + +#define KHWL_OSDFB_SWITCH KHWL_IO_OSD +#define KHWL_OSDFB_UPDATE KHWL_IO_OSD+1 +#define KHWL_OSDFB_ALPHA KHWL_IO_OSD+2 // general alpha apply + +#define KHWL_DISPLAY_CLEAR KHWL_IO_DISPLAY +#define KHWL_DISPLAY_YUV KHWL_IO_DISPLAY+1 + +#ifdef __cplusplus +} +#endif + +#endif // of SP_HWL_IOCTL_H diff --git a/src/libsp/MP/sp_module.cpp b/src/libsp/MP/sp_module.cpp new file mode 100644 index 0000000..c18db37 --- /dev/null +++ b/src/libsp/MP/sp_module.cpp @@ -0,0 +1,198 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Module system support source file. + * For Technosonic-compatible players ('MP') + * \file sp_module.cpp + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +extern "C" +{ + +// portions of code from uClibc... +#ifdef COMPILE_MODULE + +void (*__app_fini)(void) = NULL; + +extern int main(int argc, char **argv, char **envp); + + +void __attribute__ ((__noreturn__)) +__uClibc_start_main(int argc, char **argv, char **envp, + void (*app_init)(void), void (*app_fini)(void)) +{ + /* Arrange for the application's dtors to run before we exit. */ + __app_fini = app_fini; + + /* Run all the application's ctors now. */ + if (app_init!=NULL) { + app_init(); + } + + exit(main(argc, argv, envp)); +} + +void exit(int rv) +{ + if (__app_fini != NULL) + (__app_fini)(); + + _exit(rv); +} + +void module_wait() +{ + kill(getpid(), SIGSTOP); +} + +/* Copy SRC to DEST. */ +char *strcpy (char *dest, const char *src) +{ + char c; + char *s = (char *) (src); + const int off = (dest) - s - 1; + + do + { + c = *s++; + s[off] = c; + } + while (c != '\0'); + + return dest; +} + +void abort(void) +{ + struct sigaction act; + sigset_t sset; + + (void) fflush (NULL); + + if ((sigemptyset (&sset) == 0) && (sigaddset (&sset, SIGABRT) == 0)) { + (void) sigprocmask (SIG_UNBLOCK, &sset, (sigset_t *) NULL); + } + + raise(SIGABRT); + + memset (&act, '\0', sizeof (struct sigaction)); + act.sa_handler = SIG_DFL; + sigfillset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGABRT, &act, NULL); + + raise (SIGABRT); + + _exit (127); +} + +int atexit(void (*) (void)) +{ + // empty + return 0; +} + + +#undef LOAD_ARGS_1 +#define LOAD_ARGS_1(a1) \ + _a1 = (int) (a1); +#undef ASM_ARGS_1 +#define ASM_ARGS_1 , "r" (_a1) +#ifndef SYS_ify +# define SYS_ify(syscall_name) (__NR_##syscall_name) +#endif + +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ unsigned int _sys_result; \ + { \ + register int _a1 asm ("a1"); \ + LOAD_ARGS_##nr (args) \ + asm volatile ("swi %1 @ syscall " #name \ + : "=r" (_a1) \ + : "i" (SYS_ify(name)) ASM_ARGS_##nr \ + : "memory"); \ + _sys_result = _a1; \ + } \ + (int) _sys_result; }) + + +void _exit(int status) +{ + INLINE_SYSCALL(exit, 1, status); +} + + +#else ///////////////////// server side + +int module_binary_load(char *fname, char *arg) +{ + char *args[3]; + args[0] = fname; + args[1] = arg; + args[2] = NULL; + + return exec_file(args[0], (const char **)args); +} + +int module_binary_unload(int pid) +{ + // kill it by force + kill(pid, SIGKILL); + int pstat; + waitpid(pid, &pstat, 0); + return 0; +} + +void module_copy_func(void *from, void *to) +{ + #define JMP_OPCODE_SIZE 2 + DWORD diff = (((DWORD)from)/4 - (((DWORD)to)/4 + JMP_OPCODE_SIZE)); + *((DWORD *)to) = 0xEA000000 | (diff & 0xFFFFFF); +} + +void module_clear_func(void *func) +{ + *((DWORD *)func) = 0; +} + + +#endif + +} diff --git a/src/libsp/MP/sp_module_crt0.S b/src/libsp/MP/sp_module_crt0.S new file mode 100644 index 0000000..7478630 --- /dev/null +++ b/src/libsp/MP/sp_module_crt0.S @@ -0,0 +1,125 @@ +/* When we enter this piece of code, the program stack looks like this: + argc argument counter (integer) + argv[0] program name (pointer) + argv[1...N] program args (pointers) + argv[argc-1] end of args (integer) + NULL + env[0...N] environment variables (pointers) + NULL + + For uClinux it looks like this: + + argc argument counter (integer) + argv char *argv[] + envp char *envp[] + argv[0] program name (pointer) + argv[1...N] program args (pointers) + argv[argc-1] end of args (integer) + NULL + env[0...N] environment variables (pointers) + NULL + + When we are done here, we want + a1=argc + a2=argv[0] + a3=argv[argc+1] + +ARM register quick reference: + + Name Number ARM Procedure Calling Standard Role + + a1 r0 argument 1 / integer result / scratch register / argc + a2 r1 argument 2 / scratch register / argv + a3 r2 argument 3 / scratch register / envp + a4 r3 argument 4 / scratch register + v1 r4 register variable + v2 r5 register variable + v3 r6 register variable + v4 r7 register variable + v5 r8 register variable + sb/v6 r9 static base / register variable + sl/v7 r10 stack limit / stack chunk handle / reg. variable + fp r11 frame pointer + ip r12 scratch register / new-sb in inter-link-unit calls + sp r13 lower end of current stack frame + lr r14 link address / scratch register + pc r15 program counter +*/ + +#include + +.text + .global _start + .type _start,%function +#if ! defined __UCLIBC_CTOR_DTOR__ + .type __uClibc_main,%function +#else + .weak _init + .weak _fini + .type __uClibc_start_main,%function +#endif +/* Stick in a dummy reference to main(), so that if an application + * is linking when the main() function is in a static library (.a) + * we can be sure that main() actually gets linked in */ + .type main,%function + + +.text +_start: + /* clear the frame pointer */ + mov fp, #0 + +#ifdef __UCLIBC_HAS_MMU__ + /* Load register r0 (argc) from the stack to its final resting place */ + ldr r0, [sp], #4 + + /* Copy argv pointer into r1 -- which its final resting place */ + mov r1, sp + + /* Skip to the end of argv and put a pointer to whatever + we find there (hopefully the environment) in r2 */ + add r2, r1, r0, lsl #2 + add r2, r2, #4 + +#else + /* + * uClinux stacks look a little different from normal + * MMU-full Linux stacks (for no good reason) + */ + /* pull argc, argv and envp off the stack */ + ldr r0,[sp, #0] + ldr r1,[sp, #4] + ldr r2,[sp, #8] +#endif + +#if defined __UCLIBC_CTOR_DTOR__ + /* Store the address of _init in r3 as an argument to main() */ + ldr r3, =_init + + /* Push _fini onto the stack as the final argument to main() */ + ldr r4, =_fini + stmfd sp!, {r4} + + /* Ok, now run uClibc's main() -- shouldn't return */ + bl __uClibc_start_main +#else + bl __uClibc_main +#endif + + /* Crash if somehow `exit' returns anyways. */ + bl abort + +/* We need this stuff to make gdb behave itself, otherwise + gdb will chokes with SIGILL when trying to debug apps. +*/ + .section ".note.ABI-tag", "a" + .align 4 + .long 1f - 0f + .long 3f - 2f + .long 1 +0: .asciz "GNU" +1: .align 4 +2: .long 0 + .long 2,0,0 +3: .align 4 + diff --git a/src/libsp/containers/clist.h b/src/libsp/containers/clist.h new file mode 100644 index 0000000..21f4c41 --- /dev/null +++ b/src/libsp/containers/clist.h @@ -0,0 +1,494 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib linear classic (new-based) dynamic list template prototype + * \file libsp/containers/clist.h + * \author bombur + * \version x.xx + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_CLIST_H +#define SP_CLIST_H + +const int SP_CLIST_BUFFER_SIZE = 2; +#define GROW(num) (9 * num / 8) + +/// Dynamic classic linear list template ('vector') +/// Does all needed classes handling correctly (but a little bit slower)! +/// \warning: Only single-threaded version!!! +/// \warning: List resizing is slower than SPList version! +/// \warning: Copying lists is SLOW 'cause copy ctors are called for items. +template +class SPClassicList +{ +public: + + /// comparison function prototype (see Sort()) + typedef int (*SPClassicListCompareFunc)(T *e1, T *e2); + + /// Ctor. Creates empty list + SPClassicList () + { + l = new T [SP_CLIST_BUFFER_SIZE]; + //SPCHECKMSG(l != NULL, "Memory error"); + lastnum = num = 0; + } + + /// Ctor. Creates list with n elements. + SPClassicList (int n) + { + lastnum = num = n; + l = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + } + + /// Copy ctor. + SPClassicList (const SPClassicList & list) + { + lastnum = num = list.num; + l = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + //SPCHECKMSG(l != NULL, "Memory error"); + if (num > 0) + { + for (int i = 0; i < num; i++) + { + l[i] = list.l[i]; // call elements' copy ctors + } + } + } + + SPClassicList & operator = (const SPClassicList & list) + { + lastnum = num = list.num; + delete [] l; + l = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + //SPCHECKMSG(l != NULL, "Memory error"); + if (num > 0) + { + for (int i = 0; i < num; i++) + { + l[i] = list.l[i]; // call elements' copy ctors + } + } + return (*this); + } + + /// Dtor. Destroys only the list, not the elements. + ~SPClassicList () + { + SPSafeDeleteArray(l); + lastnum = num = 0; + } + + /// Reserve memory for N items + BOOL Reserve(int n) + { + lastnum = n + 1; + + T *newl = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + for (int i = 0; i < num; i++) + { + newl[i] = l[i]; // call elements' copy ctors + } + delete [] l; + l = newl; + + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + return TRUE; + } + + /// Add item to the end of the list + int Add (const T & item) + { + if (num + 1 >= lastnum + SP_CLIST_BUFFER_SIZE) // need to expand buffer + { + lastnum = GROW(num) + 1; + + T *newl = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + for (int i = 0; i < num; i++) + { + newl[i] = l[i]; // call elements' copy ctors + } + delete [] l; + l = newl; + + if (l == NULL) + { + SPERRMES("Memory error"); + return -1; + } + } + l[num] = item; + return num++; + } + + /// Add one list to the end of another list. + /// Returns the last element added. + int Add (const SPClassicList & list) + { + int ret = -1; + for (int i = 0; i < list.GetN(); i++) + ret = Add (list[i]); + return ret; + } + + /// Add unique item to the list, and return the existing or new index. + int Merge (const T & item) + { + int g = Get (item); + if (g == -1) + return Add (item); + return g; + } + + /// Merge lists (avoid item duplicates) + int Merge (const SPClassicList & list) + { + int ret = -1; + for (int i = 0; i < list.GetN(); i++) + { + T item = list[i]; + if (Get (item) == -1) + ret = Add (item); + } + return ret; + } + + /// Insert the 'item' element to the 'where' position in the list + bool Insert (T item, int where) + { + int n = num; + if (where < 0) + return FALSE; + if (where > (int)num) + n = where; + + if (n + 1 >= lastnum + SP_CLIST_BUFFER_SIZE) // need to expand buffer + { + lastnum = n + 1; + + T *newl = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + for (int i = 0; i < num; i++) + { + newl[i] = l[i]; // call elements' copy ctors + } + delete [] l; + l = newl; + + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + + register int i; + for (i = num; i > where; i--) + l[i] = l[i - 1]; + + l[where] = item; + num = n + 1; + return TRUE; + } + + /// Replace item with new one; expand list if needed. + bool Put (T item, int where) + { + if (where < 0) + return FALSE; + if (where >= (int)num) + { + num = where + 1; + if (num >= lastnum + SP_CLIST_BUFFER_SIZE) // need to expand buffer + { + lastnum = num; + + T *newl = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + for (int i = 0; i < num; i++) + { + newl[i] = l[i]; // call elements' copy ctors + } + delete [] l; + l = newl; + + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + } + l[where] = item; + return TRUE; + } + + /// Find item's index number + int Get (const T & item, int idx1 = 0, int idx2 = -1) + { + if (idx1 < 0) + return -1; + if (idx2 < 0) idx2 = num - 1; + for (int i = idx1; i <= idx2; i++) + if (l[i] == item) + return i; + return -1; + } + + /// Remove the item from the list + bool Remove (int n) + { + if (n < 0 || n >= (int)num) + return FALSE; + for (int i = n; i < num - 1; i++) + l[i] = l[i + 1]; + if (num >= 1) + { + if (num - 1 < lastnum) // need to shrink buffer + { + T *newl = new T [lastnum]; + for (int i = 0; i < num-1; i++) + { + newl[i] = l[i]; // call elements' copy ctors + } + delete [] l; + l = newl; + + if (lastnum > SP_CLIST_BUFFER_SIZE) + lastnum -= SP_CLIST_BUFFER_SIZE; + else + lastnum = 0; + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + num--; + return TRUE; + } + return FALSE; + } + + /// Remove item from the list (search used) + bool Remove (const T & item) + { + int i; + while ((i = Get (item)) != -1) + { + if (!Remove (i)) + return FALSE; + } + return TRUE; + } + + /// Remove elements from 'this' list found in the 'list'. + /// Returns the number of elements removed. + int Remove (const SPClassicList & list) + { + int numdel = 0; + for (int i = 0; i < list.GetN(); i++) + { + int ret = Get (list[i]); + if (ret != -1) + { + Remove (ret); + numdel++; + } + } + return numdel; + } + + /// Remove all items from the list + bool Clear () + { + delete [] l; + l = new T [SP_CLIST_BUFFER_SIZE]; + if (l == NULL) + return FALSE; + lastnum = num = 0; + return TRUE; + } + + /// Moves item in the list (delete + insert) + bool Move (int from, int to) + { + if (from < 0 || from >= (int)num) + return FALSE; + T item = l[from]; + if (Remove (from) == FALSE) + return FALSE; + if (Insert (item, to) == FALSE) + return FALSE; + return TRUE; + } + + /// Delete all objects themself and clear the list + bool DeleteObjects () + { + for (int i = 0; i < num; i++) + SPSafeDelete(l[i]); + return Clear (); + } + + /// The main item access operator + FORCEINLINE T & operator [] (int n) const + { + return l[n]; + } + + /// List concatenation and assign + SPClassicList & operator += (const SPClassicList & list) + { + Add (list); + return *this; + } + + /// Boolean 'and' operation - returns elements present in both of the lists + SPClassicList & operator &= (const SPClassicList & list) + { + for (int i = 0; i < num; i++) + { + if (list.Get(l[i]) == -1) + this->Delete (i); + } + return *this; + } + + /// Boolean 'or' operation - returns unique elements present in any of the lists + SPClassicList & operator |= (const SPClassicList & list) + { + Merge(list); + return *this; + } + + /// Add one list to another and return the sum. + SPClassicList operator + (const SPClassicList & list) + { + SPClassicList r(*this); + r.Add(list); + return r; + } + + /// Return the elements of the first list not present in the second. + SPClassicList operator - (const SPClassicList & list) + { + SPClassicList r; + for (int i = 0; i < num; i++) + { + if (list.Get(l[i]) == -1) + r.Add (l[i]); + } + return r; + } + + /// Sort list using user-defined comparison function + void Sort (SPClassicListCompareFunc compare) + { + qsort((void *)l, num, sizeof(T), + (int (/*__cdecl*/ *)(const void *, const void *))compare); + } + + /// Get items number (count) + FORCEINLINE const int & GetN () const + { + return num; + } + + /// Set items count (reallocate the memory but don't change the data) + BOOL SetN(int n) + { + int oldnum = num; + num = (int)n; + if ((num >= lastnum + SP_CLIST_BUFFER_SIZE) || // need to expand buffer + (num <= lastnum - SP_CLIST_BUFFER_SIZE)) // need to shrink buffer + { + lastnum = num; + T *newl = new T [lastnum + SP_CLIST_BUFFER_SIZE]; + for (int i = 0; i < (n < oldnum ? n : oldnum); i++) + { + newl[i] = l[i]; // call elements' copy ctors + } + delete [] l; + l = newl; + + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + return TRUE; + } + + // Set items count and clear them + BOOL SetClearN(int n) + { + if (!SetN(n)) + return FALSE; + memset(l, 0, n * sizeof(T)); + return TRUE; + } + + /// This is 'hack' method used by fast-loading operations + T *GetData() const + { + return l; + } + + /// List concatenation operator + template friend SPClassicList operator + (const SPClassicList &, const SPClassicList &); + /// Boolean 'or' operation - returns unique elements present in any of the lists + template friend SPClassicList operator | (const SPClassicList &, const SPClassicList &); + /// Boolean 'and' operation - returns elements present in both of the lists + template friend SPClassicList operator & (const SPClassicList &, const SPClassicList &); + +protected: + /// Dynamic array, contains all data + T *l; + /// Number of stored items. Use GetN() for retrieving + int num; + int lastnum; /// used for buffered memory reallocs +}; + +/// List concatenation operator +template inline SPClassicList operator + (const SPClassicList &a, const SPClassicList &b) +{ + return (SPClassicList (a) += (b)); +} + +/// Boolean 'or' operation - returns unique elements present in any of the lists +template inline SPClassicList operator | (const SPClassicList &a, const SPClassicList &b) +{ + return (SPClassicList(a) |= b); +} + +/// Boolean 'and' operation - returns elements present in both of the lists +template inline SPClassicList operator & (const SPClassicList &a, const SPClassicList &b) +{ + return (SPClassicList(a) &= b); +} + +/// string list +typedef SPClassicList SP_CLIST_STR; +/// dword values list +typedef SPClassicList SP_CLIST_DWORD; + +#endif // of SP_CLIST_H diff --git a/src/libsp/containers/dllist.h b/src/libsp/containers/dllist.h new file mode 100644 index 0000000..29c9ecf --- /dev/null +++ b/src/libsp/containers/dllist.h @@ -0,0 +1,695 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib double-linked dynamic list template prototype + * \file libsp/containers/dllist.h + * \author bombur + * \version x.xx + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_DLLIST_H +#define SP_DLLIST_H + +/// Double-linked list abstract container. Assumes that 'T' has 'next' and 'prev' fields. +/// For ordinary item classes, use SPDLinkedList instead. +/// \warning Only single-threaded version!!! +/// \warning Check the params! Must be (elem1 < elem2) and (from < to) ! +template +class SPDLinkedListAbstract +{ +protected: + /// the first and last elements + T *first, *last; + /// size for the stacks. + /// >0 means first deleting (FIFO), <0 means last one (FILO). + int size; + int num; /// real number of elements (for optimization only) + +public: + /// ctor + SPDLinkedListAbstract() + { + first = last = NULL; + num = size = 0; + } + + /// copy ctor + SPDLinkedListAbstract(const SPDLinkedListAbstract & dllist) + { + first = dllist.first; + last = dllist.last; + size = dllist.size; + num = dllist.num; + } + + /// copy ctor + SPDLinkedListAbstract(T *elem1, T *elem2 = NULL) + { + first = elem1; + if (elem2 != NULL) + last = elem2; + else + last = elem1; + size = 0; + num = GetNum(); + } + + /// dtor + ~SPDLinkedListAbstract() + { + ///Delete(); + } + + /// Get the first element of the list + T *GetFirst() + { + return first; + } + + /// Get the last element of the list + T *GetLast() + { + return last; + } + + /// Get(Find) the element by it's pointer + T *Get(/*const */BaseT *t) + { + T *cur = first; + for (int i = 0; cur != NULL; i++) + { + if (*cur == *t) + return cur; + cur = cur->next; + } + return NULL; + } + + /// Get the element with the given offset from the current + T *Get(T *from, int offset) + { + T *cur = from; + if (offset > 0) + { + for (int i = 0; i < offset && cur != NULL; i++) + { + cur = (T *)cur->next; + } + } else + { + for (int i = 0; i > offset && cur != NULL; i--) + { + cur = (T *)cur->prev; + } + } + return cur; + } + + /// Get the next element of the list + T *GetNext(T *from, int offset = 1) + { + if (from != NULL) + { + if (offset < 0) + offset = -offset; + if (offset == 1) + return (T *)from->next; + return Get(from, offset); + } + return NULL; + } + + /// Get the previous element of the list + T *GetPrev(T *from, int offset = 1) + { + if (from != NULL) + { + if (offset > 0) + offset = -offset; + if (offset == -1) + return from->prev; + return Get(from, offset); + } + return NULL; + } + + /// The numbered item access operator + T *operator [] (int n) + { + if (first == NULL || last == NULL) + return NULL; + T *cur = first; + for (int i = 0; i < n; i++) + { + if (cur->next == NULL) + break; + cur = cur->next; + } + return cur; + } + + /// Get the number of given elements (distance). NULLs = all list + /// ! If the order is reversed, the number is negative ! + int GetNum(T *from = NULL, T *to = NULL) + { + if (from == NULL) + from = first; + if (to == NULL) + to = last; + int n = 0; + BOOL found = FALSE; + if (from == first && to == last) + return num; + if (to != first && from != last) + { + for (T *cur = from; cur != NULL; n++) + { + if (cur == to) + { + n++; + found = TRUE; + break; + } + cur = (T *)cur->next; + } + } else + { + if (from == first || to == last) + return 1; + if (from == last && to == first) + return -num; + return 0; + } + + if (!found) + { + n = 0; + for (T *cur = to; cur != NULL; n--) + { + if (cur == from) + { + n--; + found = TRUE; + break; + } + cur = (T *)cur->prev; + } + } + //SPASSERT(found); + return n; + } + + /// Set the maximum list size + BOOL SetSize(int s) + { + size = s; + if (s == 0) + return TRUE; + int n = (int)num; + if (n > abs(size)) + { + if (size > 0) + Delete(first, n - size); + else + Delete(last, -n - size); + } + return TRUE; + } + + /// Insert the element range to the list after the 'from' element + BOOL InsertAfter(T *from, T *elem1, T *elem2 = NULL) + { + int addn = 1; + if (elem2 == NULL) + elem2 = elem1; + else + addn = (int)GetNum(elem1, elem2); + if (first == NULL || last == NULL) + { + first = elem1; + last = elem2; + num = addn; + return TRUE; + } + if (from == NULL || elem1 == NULL) + return FALSE; + + if (size != 0) + { + int n = num; + if (n + addn > Abs(size)) + { + if (size > 0) + Delete(first, n + addn - size - 1); + else + Delete(last, -n - addn - size - 1); + } + } + num += addn; + + if (from->next != NULL) + { + from->next->prev = elem1; + elem2->next = from->next; + } else + { + elem2->next = NULL; + last = elem2; + } + from->next = elem1; + elem1->prev = from; + return TRUE; + } + + /// Insert the elements in the list after the 'from' element + BOOL InsertAfter(T *from, const SPDLinkedListAbstract & ll) + { + return InsertAfter(from, ll.first, ll.last); + } + + /// Insert the element range to the list before the 'from' element + BOOL InsertBefore(T *from, T *elem1, T *elem2 = NULL) + { + int addn = 1; + if (elem2 == NULL) + elem2 = elem1; + else + addn = GetNum(elem1, elem2); + if (first == NULL || last == NULL) + { + first = elem1; + last = elem2; + num = addn; + return TRUE; + } + if (from == NULL || elem1 == NULL) + return FALSE; + + if (size != 0) + { + int n = num; + if (n + addn > Abs(size)) + { + if (size > 0) + Delete(first, n + addn - Abs(size)); + else + Delete(last, Abs(size) - n - addn); + } + } else + num += addn; + + if (from->prev != NULL) + { + from->prev->next = elem1; + elem1->prev = from->prev; + } else + { + elem1->prev = NULL; + first = elem1; + } + from->prev = elem2; + elem2->next = from; + return TRUE; + } + + /// Insert the elements in the list before the 'from' element + BOOL InsertBefore(T *from, const SPDLinkedListAbstract & ll) + { + return InsertBefore(from, ll.first, ll.last); + } + + /// Add the elements to the list + BOOL Add(T *elem1, T *elem2 = NULL) + { + return InsertAfter(last, elem1, elem2); + } + + /// Allocate and add element to the list (stack push) + BOOL Push(const BaseT & elem) + { + T *e = new T(elem); + return Add(e); + } + + /// Retreive the last element and remove it from the list (stack pop) + T & Pop() + { + T *e = GetLast(); + BaseT & t = e->item; + e->item = NULL; + Delete(e); + return t; + } + + + /// Remove the elements range from the list + BOOL Remove(T *from, T *to = NULL) + { + int remn = 1; + if (from == NULL) + { + if (to != NULL) + from = to; + else + return FALSE; + } + if (to == NULL) + to = from; + else + remn = GetNum(from, to); + + if (from == first) + first = (T *)to->next; + if (to == last) + last = (T *)from->prev; + if (from->prev != NULL) + from->prev->next = to->next; + if (to->next != NULL) + to->next->prev = from->prev; + from->prev = NULL; + to->next = NULL; + num -= remn; + return TRUE; + } + + /// Remove and delete the elements in the range + BOOL Delete(T *from = NULL, T *to = NULL) + { + if (from == NULL) + { + if(to != NULL) + { + from = to; + to = NULL; + } else // delete entire list + { + from = first; + to = last; + } + } + if (first == NULL || last == NULL) + return TRUE; + + if (Remove(from, to) == FALSE) + return FALSE; + + T *cur = from; + while (cur != NULL) + { + T *next = (T *)cur->next; + /////////// + if (cur != NULL) + delete cur; + /////////// + if (cur == to) + break; + cur = next; + } + + return TRUE; + } + + /// Remove and delete 'n' elements starting from the current + BOOL Delete(T *from, int n) + { + T *to = Get(from, n); + return Delete(from, to); + } + + /// Detach the elements range from the list and put them to the new one. + SPDLinkedListAbstract *Detach(T *from, T *to = NULL) + { + if (Remove(from, to) == FALSE) + return NULL; + SPDLinkedListAbstract *ll = new SPDLinkedListAbstract; + ll->size = size; + ll->start = from; + if (to != NULL) + ll->end = to; + else + ll->end = from; + return ll; + } + + /// Move elements in the list to the right or left (sign of 'offset') + BOOL Move(int offset, T *elem1, T *elem2 = NULL) + { + if (offset == 0) + return TRUE; + if (elem2 == NULL) + elem2 = elem1; + if (offset > 0) + { + T *to = Get(elem2, offset); + Remove(elem1, elem2); + if (to == NULL) + return InsertAfter(last, elem1, elem2); + return InsertAfter(to, elem1, elem2); + } + T *to = Get(elem1, offset); + Remove(elem1, elem2); + if (to == NULL) + return InsertBefore(first, elem1, elem2); + return InsertBefore(to, elem1, elem2); + } + + /// Move elements in the list to the specified place (instead of 'to') + /// \todo: optimise and check it!!! + BOOL Move(T *to, T *elem1, T *elem2 = NULL) + { + Remove(elem1, elem2); + if (to == NULL) + return InsertBefore(first, elem1, elem2); + if (to == last) + return InsertAfter(to, elem1, elem2); + if (GetNum(elem1, to) > 0) + return InsertAfter(to, elem1, elem2); + return InsertBefore(to, elem1, elem2); + } + + /// Swaps two elements, the order isn't important (elem1<>elem2) + BOOL Swap(T *elem1, T *elem2) + { + if (elem1 == NULL || elem2 == NULL) + return FALSE; + + BOOL closeto1 = (elem1->next == elem2); + BOOL closeto2 = (elem2->next == elem1); + + if (elem1->prev != NULL && !closeto2) + elem1->prev->next = elem2; + if (elem1->next != NULL && !closeto1) + elem1->next->prev = elem2; + if (elem2->prev != NULL && !closeto1) + elem2->prev->next = elem1; + if (elem2->next != NULL && !closeto2) + elem2->next->prev = elem1; + + if (elem1 == first) + first = elem2; + else if (elem2 == first) + first = elem1; + if (elem1 == last) + last = elem2; + else if (elem2 == last) + last = elem1; + + T *tmp = elem1->prev; + if (closeto1) + elem1->prev = elem2; + else + elem1->prev = elem2->prev; + if (closeto2) + elem2->prev = elem1; + else + elem2->prev = tmp; + + tmp = elem2->next; + if (closeto1) + elem2->next = elem1; + else + elem2->next = elem1->next; + if (closeto2) + elem1->next = elem2; + else + elem1->next = tmp; + return TRUE; + } + + /// Check if everything is ok with the list (integrity check) + BOOL Check() + { + if (first == NULL && last == NULL) // empty list + return TRUE; + T *cur = first; + int cnum = 1; + while (true) + { + if (cur->next != NULL) + { + cnum++; + if (cur->next == cur) // no cyclic chains + return FALSE; + if (cur->next->prev != cur) // breaked chain + return FALSE; + } else + break; + cur = cur->next; + } + if (cur != last) // invalid 'last' chain marker + return FALSE; + if (cnum != num) // invalid number of elements + return FALSE; + if (size != 0 && cnum > size) // number of elements exceeded + return FALSE; + return TRUE; + } + + /// Check if the element belongs to the list + BOOL IsInList(T *elem) + { + if (elem == NULL) + return FALSE; + T *cur = first; + while (cur != NULL) + { + if (cur == elem) + return TRUE; + cur = cur->next; + } + return FALSE; + } + + /*/// Check if the element belongs to the list + BOOL IsInList(const T & elem) + { + if (elem == NULL) + return FALSE; + T *cur = first; + while (cur != NULL) + { + if (cur == elem) + return TRUE; + cur = cur->next; + } + return FALSE; + }*/ + + /// Check if the list is empty + BOOL IsEmpty() + { + if (first == NULL && last == NULL) + { + //if (num != 0) + // SPASSERT("DLList damaged!"); + return TRUE; + } + return FALSE; + } +}; + +//////////////////////////////////////////////////////////////////////////// + +/// Double-Linked list element. Used as wrapper for ordinary data types. +/// \warning only single-threaded version!!! +template +class DLElement +{ +public: + + T item; + DLElement *next, *prev; + + /// ctor + DLElement() + { + next = prev = NULL; + } + /// ctor + DLElement(const T & t) + { + item = t; + next = prev = NULL; + } + + /// copy ctor + DLElement(const DLElement & e) + { + item = e.item; + next = e.next; + prev = e.prev; + } + + /// dtor + virtual ~DLElement() + { +// delete item; + } + + /// ref-counted copy from another DLElement + const DLElement & operator=(const DLElement & e) + { + item = e.item; + next = e.next; + prev = e.prev; + return *this; + } + + /// ref-counted copy from 'T' object + const DLElement & operator=(const T & src) + { + item = src; + next = NULL; + prev = NULL; + return *this; + } + + /// compare + bool operator == (const T & t) + { + return item == t; + } + + /// 'T' conversion operator + operator const T & ( ) const + { + return item; + } + + const T & GetItem() const + { + return item; + } + + void SetItem(const T & t) + { + item = t; + } + +}; + + +/// Double-linked list manager. Use it for any item classes/types. +/// \warning Only single-threaded version!!! +/// \warning Check the params! Must be (elem1 < elem2) and (from < to) ! +template +class SPDLinkedList : public SPDLinkedListAbstract, T > +{ +}; + +#endif // of SP_DLLIST_H diff --git a/src/libsp/containers/hashlist.h b/src/libsp/containers/hashlist.h new file mode 100644 index 0000000..bab3453 --- /dev/null +++ b/src/libsp/containers/hashlist.h @@ -0,0 +1,336 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib hash list (search) template prototype + * \file libsp/containers/hashlist.h + * \author bombur + * \version x.xx + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_HASHLIST_H +#define SP_HASHLIST_H + +#include + +/// Hash-table list (search-optimised) template. +/// Use SetN() first, then Add() or Merge() to add elements; +/// Get() searches for elements, and GetN() returns the actual number stored. +/// \warning only single-threaded version!!! +template +class SPHashListAbstract : public SPClassicList > +{ +public: + /////////////////////////////////////////////////////////////// + /// Hash function - declare it in derived class. + /// The return value should be in the range of [0..num-1] + /// DO NOT USE THIS IMPL. ON POINTERS!!! + virtual DWORD HashFunc(const BaseT & item) + { + return (DWORD)item % ((this->num > 0) ? this->num : 1); + } + + /// Comparison function - declare it in derived class + /// DO NOT USE THIS IMPL. ON POINTERS!!! + virtual BOOL Compare(const BaseT & item1, const BaseT & item2) + { + return ((T &)item1 == (T &)item2); + } + /////////////////////////////////////////////////////////////// + + /// Ctor. Creates list with N hash-size + SPHashListAbstract (int N = 1) : SPClassicList >() + { + this->SetN(N); + } + + /// Copy ctor. + SPHashListAbstract (const SPHashListAbstract & list) + : SPClassicList >(list) + { + } + + /// Dtor. Destroys only the list, not the elements. + virtual ~SPHashListAbstract () + { + DeleteObjects(); + } + + /// Add item to the list + /// Do not pass temporary variables!!! + BOOL Add (BaseT *item) + { + if (this->num == 0) + return FALSE; + DWORD f = HashFunc(*item); + return this->l[f].Add((T *)item); + } + + /// Add item to the list ONLY IF UNIQUE, and return the existing or new one. + /// Do not pass temporary variables!!! + + BaseT *Merge (const BaseT & item) + { + DWORD f = HashFunc((BaseT)item); + T *cur = this->l[f].GetFirst(); + while (cur != NULL) + { + if (Compare((BaseT)cur->GetItem(), (BaseT)item)) + return (BaseT *)&cur->GetItem(); + cur = cur->next; + } + if (this->l[f].Add((T *)item) == FALSE) + return NULL; + return &(BaseT)item; + } + + /// Find item (return pointer to existing item or NULL) + BaseT *Get (const BaseT & item) + { + DWORD f = HashFunc(item); + T *cur = this->l[f].GetFirst(); + while (cur != NULL) + { + if (Compare(*((BaseT *)cur->GetItem()), item)) + return (BaseT *)cur->GetItem(); + cur = (T *)cur->next; + } + return NULL; + } + + /// Find the first item of the hash-list + /// \WARNING: Works only with pointer items! + BaseT *GetFirst() + { + if (this->num == 0) + return NULL; + for (int f = 0; f < this->num; f++) + { + if (this->l[f].GetFirst() != NULL) + return (BaseT *)(this->l[f].GetFirst()->GetItem()); + } + return NULL; + } + + /// Find the next item of the specified one (or the first, if called with 'NULL') + /// \WARNING: Works only with pointer items! + BaseT *GetNext(const BaseT & item) + { + int f = HashFunc(item); + T *cur = this->l[f].GetFirst(); + while (cur != NULL) + { + if (Compare(*((BaseT *)cur->GetItem()), item)) + { + if (cur->next == NULL) // get from the next row + { + while (++f < this->num) + { + if (this->l[f].GetFirst() != NULL) + return (BaseT *)(this->l[f].GetFirst()->GetItem()); + } + return NULL; + } else + return (BaseT *)(cur->next->GetItem()); + } + cur = (T *)cur->next; + } + return NULL; // not in this list + } + + /// Get all items as a linear list + SPList GetList() + { + SPList list; + for (int f = 0; f < this->num; f++) + { + T *cur = this->l[f].GetFirst(); + while (cur != NULL) + { + list.Add(cur->GetItem()); + cur = cur->next; + } + } + return list; + } + + /// Remove item from the list (but don't delete the item itself!) + BOOL Remove (const BaseT & item) + { + DWORD f = HashFunc(item); + T *cur = this->l[f].GetFirst(); + while (cur != NULL) + { + if (Compare(*((BaseT *)cur->GetItem()), item)) + return this->l[f].Remove(cur); + cur = cur->next; + } + return FALSE; + } + + /// Delete item from the list (but don't delete the item itself!) + BOOL Delete (const BaseT & item) + { + DWORD f = HashFunc(item); + T *cur = this->l[f].GetFirst(); + while (cur != NULL) + { + if (Compare(*((BaseT *)cur->GetItem()), item)) + return this->l[f].Delete(cur); + cur = cur->next; + } + return FALSE; + } + + /// Remove all items from the list + BOOL Clear () + { + for (int i = 0; i < this->num; i++) + { + this->l[i].Remove(this->l[i].GetFirst(), this->l[i].GetLast()); + } + return TRUE; + } + + /// Delete all objects ourself and clear the list + BOOL DeleteObjects () + { + for (int i = 0; i < this->num; i++) + { + if (this->l[i].Delete() == FALSE) + return FALSE; + } + return TRUE; + } + + /// Get items number (count) + inline int GetN () + { + int n = 0; + for (int i = 0; i < this->num; i++) + n += this->l[i].GetN(); + return n; + } + +}; + + +/// Hash list for 'normal' elements, with built-in dllist-element class +template +class SPHashList : public SPHashListAbstract, T> +{ +public: + /// ctor + SPHashList (int N = 1) : SPHashListAbstract, T> (N) {} + /// Add item to the list + BOOL Add (const T & item) + { + if (this->num == 0) + return FALSE; + DWORD f = HashFunc(item); + DLElement *elem = new DLElement(item); + return this->l[f].Add(elem); + } + + /// Add item to the list ONLY IF UNIQUE, and return the existing or new one. + T *Merge (const T & item) + { + DWORD f = HashFunc(item); + DLElement *cur = this->l[f].GetFirst(); + while (cur != NULL) + { + if (Compare(*cur, item)) + return &cur->item; + cur = cur->next; + } + DLElement *elem = new DLElement(item); + if (this->l[f].Add(elem) == FALSE) + return NULL; + return &(elem->item); + } +}; + +/// Integer hash table implementation. +/// \warning For testing purposes only. +class SPIntHashList : public SPHashList +{ +public: + /// ctor + SPIntHashList() + { + } + + /// dtor + virtual ~SPIntHashList() + { + } + +}; + +// calculate djb2 (Bernstein) string hash +inline DWORD SPStringHashFunc(char * const & item, int /*num*/) +{ + char *s = item; + DWORD hash = 5381; + int c; + if (s != NULL && s[0] != '\0') + { + while ((c = *s++) != '\0') + hash = ((hash << 5) + hash) + c; // = hash * 33 + c; + } + return hash; +/* + DWORD hash = 0; + char *it = (char *)item; + for (int i = 0; *it; i++) + hash += ((DWORD)*it++) ^ (i % num); + return hash; +*/ +} + +/// String hash table implementation. +/// \warning For testing purposes only. +class SPStringHashList : public SPHashList +{ +public: + /// ctor + SPStringHashList() + { + } + + /// dtor + virtual ~SPStringHashList() + { + } + + /// Hash function - declare it in derived class. + /// The return value should be in the range of [0..num-1] + virtual DWORD HashFunc(char * const & item) // \todo Get better function + { + if (item == NULL) + return 0; + return SPStringHashFunc(item, num) % num; + } + + /// Comparison function - declare it in derived class + virtual BOOL Compare(char * const & item1, char* const & item2) + { + return strcmp(item1, item2) == 0; + } +}; + +#endif // of SP_HASHLIST_H diff --git a/src/libsp/containers/list.h b/src/libsp/containers/list.h new file mode 100644 index 0000000..072f0e7 --- /dev/null +++ b/src/libsp/containers/list.h @@ -0,0 +1,459 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib linear dynamic list template prototype + * \file libsp/containers/list.h + * \author bombur + * \version x.x + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_LIST_H +#define SP_LIST_H + +const int SP_LIST_BUFFER_SIZE = 2; + +#define GROW(num) (9 * num / 8) + +/// Dynamic linear list template ('vector') +/// \warning: Only single-threaded version!!! +/// \warning: Don't use SPList, where Object uses ctors for initialization. +/// Ctors will not be called! Use SPList or SPClassicList instead! +/// \warning: Copying lists is SLOW 'cause copy ctors are called for items. +template +class SPList +{ +public: + + /// comparison function prototype (see Sort()) + typedef int (*SPListCompareFunc)(T *e1, T *e2); + + /// Ctor. Creates empty list + SPList () + { + l = (T *)SPmalloc (sizeof(T) * SP_LIST_BUFFER_SIZE); + //SPCHECKMSG(l != NULL, "Memory error"); + lastnum = num = 0; + } + + /// Ctor. Creates list with n elements. + SPList (int n) + { + lastnum = num = n; + l = (T *)SPmalloc ((lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + } + + /// Copy ctor. + SPList (const SPList & list) + { + lastnum = num = list.num; + l = (T *)SPmalloc ((lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + //SPCHECKMSG(l != NULL, "Memory error"); + if (num > 0) + { + for (int i = 0; i < num; i++) + { + l[i] = list.l[i]; // call elements' copy ctors + } + } + } + + SPList & operator = (const SPList & list) + { + lastnum = num = list.num; + SPSafeFree(l); + l = (T *)SPmalloc ((lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + //SPCHECKMSG(l != NULL, "Memory error"); + if (num > 0) + { + for (int i = 0; i < num; i++) + { + l[i] = list.l[i]; // call elements' copy ctors + } + } + return (*this); + } + + /// Dtor. Destroys only the list, not the elements. + ~SPList () + { + SPSafeFree(l); + lastnum = num = 0; + } + + /// Reserve memory for N items + BOOL Reserve(int num) + { + if (lastnum <= num) + { + lastnum = num + 1; + l = (T *)SPrealloc ((void *)l, (lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + return TRUE; + } + return FALSE; + } + + /// Add item to the end of the list + int Add (T item) + { + if (num + 1 >= lastnum + SP_LIST_BUFFER_SIZE) // need to expand buffer + { + lastnum = GROW(num) + 1; + l = (T *)SPrealloc ((void *)l, (lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + if (l == NULL) + { + SPERRMES("Memory error"); + return -1; + } + } + l[num] = item; + return num++; + } + + /// Add one list to the end of another list. + /// Returns the last element added. + int Add (const SPList & list) + { + int ret = -1; + for (int i = 0; i < list.GetN(); i++) + ret = Add (list[i]); + return ret; + } + + /// Add unique item to the list, and return the existing or new index. + int Merge (T item) + { + int g = Get (item); + if (g == -1) + return Add (item); + return g; + } + + /// Merge lists (avoid item duplicates) + int Merge (const SPList & list) + { + int ret = -1; + for (int i = 0; i < list.GetN(); i++) + { + T item = list[i]; + if (Get (item) == -1) + ret = Add (item); + } + return ret; + } + + /// Insert the 'item' element to the 'where' position in the list + bool Insert (T item, int where) + { + int n = num; + if (where < 0) + return FALSE; + if (where > (int)num) + n = where; + + if (n + 1 >= lastnum + SP_LIST_BUFFER_SIZE) // need to expand buffer + { + lastnum = n + 1; + l = (T *)SPrealloc ((void *)l, (lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + + register int i; + for (i = num; i > where; i--) + l[i] = l[i - 1]; + + l[where] = item; + num = n + 1; + return TRUE; + } + + /// Replace item with new one; expand list if needed. + bool Put (T item, int where) + { + if (where < 0) + return FALSE; + if (where >= (int)num) + { + num = where + 1; + if (num >= lastnum + SP_LIST_BUFFER_SIZE) // need to expand buffer + { + lastnum = num; + l = (T *)SPrealloc ((void *)l, (lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + } + l[where] = item; + return TRUE; + } + + /// Find item's index number + int Get (const T & item, int idx1 = 0, int idx2 = -1) + { + if (idx1 < 0) + return -1; + if (idx2 < 0) idx2 = num - 1; + for (int i = idx1; i <= idx2; i++) + if (l[i] == item) + return i; + return -1; + } + + /// Remove the item from the list + bool Remove (int n) + { + if (n < 0 || n >= (int)num) + return FALSE; + for (int i = n; i < num - 1; i++) + l[i] = l[i + 1]; + if (num >= 1) + { + if (num - 1 < lastnum) // need to shrink buffer + { + l = (T *)SPrealloc ((void *)l, lastnum * sizeof(T)); + if (lastnum > SP_LIST_BUFFER_SIZE) + lastnum -= SP_LIST_BUFFER_SIZE; + else + lastnum = 0; + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + num--; + return TRUE; + } + return FALSE; + } + + /// Remove item from the list (search used) + bool Remove (const T & item) + { + int i; + while ((i = Get (item)) != -1) + { + if (!Remove (i)) + return FALSE; + } + return TRUE; + } + + /// Remove elements from 'this' list found in the 'list'. + /// Returns the number of elements removed. + int Remove (const SPList & list) + { + int numdel = 0; + for (int i = 0; i < list.GetN(); i++) + { + int ret = Get (list[i]); + if (ret != -1) + { + Remove (ret); + numdel++; + } + } + return numdel; + } + + /// Remove all items from the list + bool Clear () + { + if (lastnum > 1) + l = (T *)SPrealloc ((void *)l, sizeof(T) * SP_LIST_BUFFER_SIZE); + if (l == NULL) + return FALSE; + lastnum = num = 0; + return TRUE; + } + + /// Moves item in the list (delete + insert) + bool Move (int from, int to) + { + if (from < 0 || from >= (int)num) + return FALSE; + T item = l[from]; + if (Remove (from) == FALSE) + return FALSE; + if (Insert (item, to) == FALSE) + return FALSE; + return TRUE; + } + + /// Delete all objects themself and clear the list + bool DeleteObjects () + { + for (int i = 0; i < num; i++) + SPSafeDelete(l[i]); + return Clear (); + } + + /// The main item access operator + FORCEINLINE T & operator [] (int n) const + { + return l[n]; + } + + /// List concatenation and assign + SPList & operator += (const SPList & list) + { + Add (list); + return *this; + } + + /// Boolean 'and' operation - returns elements present in both of the lists + SPList & operator &= (const SPList & list) + { + for (int i = 0; i < num; i++) + { + if (list.Get(l[i]) == -1) + this->Delete (i); + } + return *this; + } + + /// Boolean 'or' operation - returns unique elements present in any of the lists + SPList & operator |= (const SPList & list) + { + Merge(list); + return *this; + } + + /// Add one list to another and return the sum. + SPList operator + (const SPList & list) + { + SPList r(*this); + r.Add(list); + return r; + } + + /// Return the elements of the first list not present in the second. + SPList operator - (const SPList & list) + { + SPList r; + for (int i = 0; i < num; i++) + { + if (list.Get(l[i]) == -1) + r.Add (l[i]); + } + return r; + } + + /// Sort list using user-defined comparison function + void Sort (SPListCompareFunc compare) + { + qsort((void *)l, num, sizeof(T), + (int (/*__cdecl*/ *)(const void *, const void *))compare); + } + + /// Sort list range using user-defined comparison function + void Sort (SPListCompareFunc compare, int idx1, int idx2) + { + qsort((void *)(l + idx1), idx2 - idx1 + 1, sizeof(T), + (int (/*__cdecl*/ *)(const void *, const void *))compare); + } + + /// Get items number (count) + FORCEINLINE const int & GetN () const + { + return num; + } + + /// Set items count (reallocate the memory but don't change the data) + BOOL SetN(int n) + { + num = n; + if ((num >= lastnum + SP_LIST_BUFFER_SIZE) || // need to expand buffer + (num <= lastnum - SP_LIST_BUFFER_SIZE)) // need to shrink buffer + { + lastnum = num; + l = (T *)SPrealloc ((void *)l, (lastnum + SP_LIST_BUFFER_SIZE) * sizeof(T)); + if (l == NULL) + { + SPERRMES("Memory error"); + return FALSE; + } + } + return TRUE; + } + + // Set items count and clear them + BOOL SetClearN(int n) + { + if (!SetN(n)) + return FALSE; + memset(l, 0, n * sizeof(T)); + return TRUE; + } + + /// This is 'hack' method used by fast-loading operations + T *GetData() const + { + return l; + } + + /// List concatenation operator + template friend SPList operator + (const SPList &, const SPList &); + /// Boolean 'or' operation - returns unique elements present in any of the lists + template friend SPList operator | (const SPList &, const SPList &); + /// Boolean 'and' operation - returns elements present in both of the lists + template friend SPList operator & (const SPList &, const SPList &); + +protected: + /// Dynamic array, contains all data + T *l; + /// Number of stored items. Use GetN() for retrieving + int num; + int lastnum; /// used for bufferized memory reallocs +}; + +/// List concatenation operator +template inline SPList operator + (const SPList &a, const SPList &b) +{ + return (SPList (a) += (b)); +} + +/// Boolean 'or' operation - returns unique elements present in any of the lists +template inline SPList operator | (const SPList &a, const SPList &b) +{ + return (SPList(a) |= b); +} + +/// Boolean 'and' operation - returns elements present in both of the lists +template inline SPList operator & (const SPList &a, const SPList &b) +{ + return (SPList(a) &= b); +} + +/// string list +typedef SPList SP_LIST_STR; +/// dword values list +typedef SPList SP_LIST_DWORD; + +#endif // of SP_LIST_H diff --git a/src/libsp/containers/membin.cpp b/src/libsp/containers/membin.cpp new file mode 100644 index 0000000..96bdae4 --- /dev/null +++ b/src/libsp/containers/membin.cpp @@ -0,0 +1,322 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib small memory bin implementation + * \file libsp/containers/membin.cpp + * \author bombur + * \version 1.0 + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + + +// bin size, in bytes (incl. all headers) +const int binsize = 65536; +// end of list +const WORD EOL = (WORD)0xffff; + +#define IS_FREE(hdr) ((hdr->binidx & 0x8000) == 0) +#define MARK_FREE(hdr) { hdr->binidx &= 0x7fff; } +#define MARK_BUSY(hdr) { hdr->binidx |= 0x8000; } +#define BINIDX(hdr) (hdr->binidx & 0x7fff) + +#define GET_HDR(data) ((BinHeader *)((char *)data - sizeof(BinHeader))) +#define GET_PTR(hdr) ((char *)hdr + sizeof(BinHeader)) + + +#ifdef WIN32 +#pragma pack(1) +#endif +typedef struct BinHeader +{ +public: + // bin index; high bit of binidx is 'busy' flag + WORD binidx; + + // real data size, in bytes + WORD size; + + // offset to prev. BinHeader, in WORDs + WORD prev; + + // offset to next BinHeader, in WORDs + WORD next; + +} ATTRIBUTE_PACKED BinHeader; +#ifdef WIN32 +#pragma pack() +#endif + + +/// Memory bin +class MemBin +{ +public: + /// ctor + MemBin() + { + bin = NULL; + last = EOL; + } + + // a little hack! + MemBin & operator = (MemBin & mb) + { + bin = mb.bin; + mb.bin = NULL; + last = mb.last; + return *this; + } + + /// Allocate + BOOL Alloc(WORD idx) + { + bin = (WORD *)SPmalloc(binsize * sizeof(char)); + if (bin != NULL) + { + BinHeader *hdr = (BinHeader *)bin; + hdr->binidx = idx; + hdr->size = (binsize - sizeof(BinHeader)); + hdr->prev = hdr->next = EOL; + + last = 0; + return TRUE; + } else + { + last = EOL; + return FALSE; + } + } + + ~MemBin() + { + SPSafeFree(bin); + } + + // find a free chunk of 'size' bytes + BinHeader *Find(int size) + { + // the real size is greater + WORD s = (WORD)(size + sizeof(BinHeader)); + BinHeader *hdr = (BinHeader *)(bin + last); + if (IS_FREE(hdr) && hdr->size >= s) + return hdr; + WORD cur = 0; + while (cur != EOL) + { + BinHeader *hdr = (BinHeader *)(bin + cur); + if (IS_FREE(hdr) && hdr->size >= s) + return hdr; + cur = hdr->next; + } + return NULL; + } + + BOOL Occupy(BinHeader *hdr, WORD size) + { + if (hdr->size > size + 1 + sizeof(BinHeader)) + { + BinHeader *nexthdr = (BinHeader *)((char *)hdr + sizeof(BinHeader) + size); + BinHeader *oldnexthdr = hdr->next == EOL ? NULL : (BinHeader *)(bin + hdr->next); + hdr->next = (WORD)((WORD *)nexthdr - bin); + if (oldnexthdr != NULL) + { + oldnexthdr->prev = hdr->next; + nexthdr->next = (WORD)((WORD *)oldnexthdr - bin); + } else + { + nexthdr->next = EOL; + last = hdr->next; + } + nexthdr->binidx = hdr->binidx; + nexthdr->prev = (WORD)((WORD *)hdr - bin); + nexthdr->size = (WORD)(hdr->size - size - sizeof(BinHeader)); + hdr->size = size; + } + MARK_BUSY(hdr); + return TRUE; + } + + BOOL Free(BinHeader *hdr) + { + BinHeader *prev = hdr->prev != EOL ? (BinHeader *)(bin + hdr->prev) : NULL; + BinHeader *next = hdr->next != EOL ? (BinHeader *)(bin + hdr->next) : NULL; + // combine with left chunk if it's free + + if (prev != NULL && IS_FREE(prev)) + { + prev->size = (WORD)(prev->size + hdr->size + sizeof(BinHeader)); + prev->next = hdr->next; + if (next != NULL) + { + // add right chunk if it's also free + if (IS_FREE(next)) + { + BinHeader *nextnext = next->next != EOL ? (BinHeader *)(bin + next->next) : NULL; + if (nextnext != NULL) + nextnext->prev = hdr->prev; + else + last = hdr->prev; + prev->next = next->next; + prev->size = (WORD)(prev->size + next->size + sizeof(BinHeader)); + } else + next->prev = hdr->prev; + } + return TRUE; + } + + MARK_FREE(hdr); + + // add right chunk if it's also free + if (next != NULL && IS_FREE(next)) + { + hdr->size = (WORD)(hdr->size + next->size + sizeof(BinHeader)); + hdr->next = next->next; + BinHeader *nextnext = next->next != EOL ? (BinHeader *)(bin + next->next) : NULL; + if (nextnext != NULL) + nextnext->prev = next->prev; + else + last = next->prev; + } + + return TRUE; + } + +public: + WORD *bin; + // offset to the last BinHeader, in WORDs + WORD last; +}; + +SPClassicList bins; +static int curbin = -1; + +void *membin_alloc(void *data, size_t size) +{ + // huge block + if (size > binsize - sizeof(BinHeader)) + { + BinHeader *hdr = (BinHeader *)SPmalloc(size + sizeof(BinHeader)); + if (hdr != NULL) + { + hdr->binidx = EOL; + hdr->size = 0; // special 'huge' external chunk + hdr->prev = hdr->next = EOL; + } + return GET_PTR(hdr); + } + + // size should be positive and DWORD-aligned + WORD siz = (size > 0) ? (WORD)((size + 3) & ~3) : (WORD)4; + + BinHeader *oldhdr = NULL; + if (data != NULL) // first, see what we have... + { + oldhdr = GET_HDR(data); + // we don't resize free blocks + if (!IS_FREE(oldhdr) && BINIDX(oldhdr) < bins.GetN()) + { + // no shrinking, sorry... + if (siz <= oldhdr->size) + return data; + } else + oldhdr = NULL; + } + + // first in the current bin + BinHeader *freehdr = NULL; + if (curbin != -1) + { + freehdr = bins[curbin].Find(siz); + } + if (freehdr == NULL) + { + // we don't use reverse order because last 'curbin' was at the end already... + for (curbin = 0; curbin < bins.GetN(); curbin++) + { + freehdr = bins[curbin].Find(siz); + if (freehdr != NULL) + break; + } + } + // no free space left, so allocate a new bin + if (freehdr == NULL) + { + curbin = -1; + // already too many bins - we failed... + if (bins.GetN() > 32767) + return NULL; + + membin_next(); + freehdr = bins[curbin].Find(siz); + } + // absolute failure... + if (freehdr == NULL || curbin < 0) + return NULL; + + // now we have a new hdr, so split & mark + bins[curbin].Occupy(freehdr, siz); + + // return to user + void *ptr = GET_PTR(freehdr); + + if (oldhdr != NULL) + { + // copy old data after "resize" + memcpy(ptr, data, oldhdr->size); + // free old data + bins[BINIDX(oldhdr)].Free(oldhdr); + } + + return ptr; +} + +void membin_free(void *data) +{ + if (data == NULL) + return; + + BinHeader *hdr = GET_HDR(data); + // if huge block + if (hdr->binidx == EOL && hdr->size == 0 && hdr->prev == 0 && hdr->next == 0) + { + SPfree(hdr); + return; + } + + if (IS_FREE(hdr)) // it's already free + return; + // a valid bin + if (BINIDX(hdr) < bins.GetN()) + { + // mark hdr as free block + bins[BINIDX(hdr)].Free(hdr); + } +} + +void membin_next() +{ + curbin = bins.GetN(); + if (curbin >= 10) + return; + bins.SetN(curbin + 1); + bins[curbin].Alloc((WORD)curbin); +} diff --git a/src/libsp/containers/membin.h b/src/libsp/containers/membin.h new file mode 100644 index 0000000..bb1a7ec --- /dev/null +++ b/src/libsp/containers/membin.h @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib small memory bin header + * \file libsp/containers/membin.h + * \author bombur + * \version 1.0 + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MEMORY_BIN_H +#define SP_MEMORY_BIN_H + +/* +/////////////////////////////////////////////////////////////////////// + Used for small memory (<64k) chunks to decrease memory fragmentation. + All mem.blocks are WORD-aligned. + Warning! No bounds-check/mem.leak/debug control! +/////////////////////////////////////////////////////////////////////// +*/ + +/// Allocate or reallocate small memory chunk +void *membin_alloc(void *, size_t); + +/// Free small memory chunk +void membin_free(void *); + +/// Use next memory bit for new allocs (faster?) +void membin_next(); + +#endif // of SP_MEMORY_BIN_H diff --git a/src/libsp/containers/salist.h b/src/libsp/containers/salist.h new file mode 100644 index 0000000..ca9b9ed --- /dev/null +++ b/src/libsp/containers/salist.h @@ -0,0 +1,259 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib self-allocated double-linked list template prototype + * \file libsp/containers/salist.h + * \author bombur + * \version x.x + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_SALIST_H +#define SP_SALIST_H + +enum SALIST_ITEM_TYPE +{ + SALIST_FREE = 0, + SALIST_USED = 1, +}; + +/// Self-allocated dynamic double-linked list template +/// with fast insertion/deletion of items. +/// STORES ITEMS OF DIFFERENT TYPES IN THE SAME POINTER LIST! +/// Used to store constantly created/deleted objects of several different types/sizes +/// WITHOUT frequent memory allocs/frees & memory fragmentation. +/// \Parameters: 'T' type must be a base class of 'U'! +/// 'num_slots' is the estimated number of stored items of the same type/size. +/// \warning: Only single-threaded version!!! +template +class SPSAList : public SPList +{ +protected: + /// internal item linkage class + class ListPrevNext + { + public: + ListPrevNext() + { + prev[SALIST_FREE] = next[SALIST_FREE] = -1; + prev[SALIST_USED] = next[SALIST_USED] = -1; + } + + int prev[2], next[2]; + }; + + /// Corresponds to the group of items of the same type/size. + struct ListAllocType + { + // all these are relative indexes (0..num_slots-1) + SPClassicList dllist; + int first[2], last[2]; + int size; // sizeof(element) + int num[2]; // number of elements + // these are abs. indexes + int begin, end; + }; + + /// Does double-linked item insertion/deletion + /// 'idx' is relative to the start of alloc: [0..num_slots]! + inline bool MoveFreeUsed(int alloc_idx, int idx, int from, int to) + { + int &from_prev = allocs[alloc_idx].dllist[idx].prev[from]; + int &from_next = allocs[alloc_idx].dllist[idx].next[from]; + // 1. remove + if (allocs[alloc_idx].first[from] == idx) + allocs[alloc_idx].first[from] = from_next; + if (allocs[alloc_idx].last[from] == idx) + allocs[alloc_idx].last[from] = from_prev; + if (from_prev >= 0) + allocs[alloc_idx].dllist[from_prev].next[from] = from_next; + if (from_next >= 0) + allocs[alloc_idx].dllist[from_next].prev[from] = from_prev; + // detach item + from_prev = from_next = -1; + + // 2. insert + int &to_prev = allocs[alloc_idx].dllist[idx].prev[to]; + int &to_next = allocs[alloc_idx].dllist[idx].next[to]; + // if the list is empty... + if (allocs[alloc_idx].first[to] < 0 || allocs[alloc_idx].last[to] < 0) + { + allocs[alloc_idx].first[to] = allocs[alloc_idx].last[to] = idx; + to_prev = -1; + to_next = -1; + allocs[alloc_idx].num[from]--; + allocs[alloc_idx].num[to]++; // = 1 + return true; + } + // additional check if item was already freed/used + if (to_prev < 0 && to_next < 0) + { + // add 'idx' after the last one + allocs[alloc_idx].dllist[allocs[alloc_idx].last[to]].next[to] = idx; + to_prev = allocs[alloc_idx].last[to]; + to_next = -1; + allocs[alloc_idx].last[to] = idx; + + allocs[alloc_idx].num[from]--; + allocs[alloc_idx].num[to]++; + return true; + } + return false; + } + + +public: + /// Ctor. Creates empty list + SPSAList() : SPList() + { + } + + ~SPSAList() + { + for (int i = 0; i < allocs.GetN(); i++) + { + //delete [] l[allocs[i].begin]; + SPfree(this->l[allocs[i].begin]); + } + } + + /// Allocates and returns a new item via parameter. + /// Item index (abs.) is returned to free the item afterwards. + template + int Allocate(U **newobj) + { + int i, alloc_idx = -1; + ListAllocType at; + // \todo: Optimize more! Use LUTs or hash... + for (i = 0; i < allocs.GetN(); i++) + { + if (sizeof(U) == allocs[i].size) + { + if (allocs[i].first[SALIST_FREE] >= 0) // at least 1 free item left + { + alloc_idx = i; + break; + } + } + } + if (alloc_idx == -1) // allocate new... + { + //U *arr = new U [num_slots]; + U *arr = (U *)SPmalloc(sizeof(U) * num_slots); + at.size = sizeof(U); + at.begin = SPList::GetN(); + at.end = at.begin + num_slots - 1; + SetN(at.begin + num_slots); + + int abs_cur = at.begin; + int cur_first = 0; + at.num[SALIST_USED] = 1; + at.num[SALIST_FREE] = num_slots - 1; + at.first[SALIST_USED] = at.last[SALIST_USED] = cur_first; + at.first[SALIST_FREE] = ++cur_first; + at.dllist.SetN(num_slots); + this->l[abs_cur++] = (T *)(arr); + for (i = 1; i < num_slots - 1; i++) + { + this->l[abs_cur++] = (T *)(arr + i); + at.dllist[i + 1].prev[SALIST_FREE] = cur_first; + at.dllist[i].next[SALIST_FREE] = ++cur_first; + } + this->l[abs_cur] = (T *)(arr + i); + at.last[SALIST_FREE] = cur_first; + allocs.Add(at); + if (newobj != NULL) + { + *newobj = arr; + new (*newobj) U(); + } + return at.begin + at.first[SALIST_USED]; + } + // find free item... + int idx = allocs[alloc_idx].first[SALIST_FREE]; + // mark one of free items as used and return it + MoveFreeUsed(alloc_idx, idx, SALIST_FREE, SALIST_USED); + idx += allocs[alloc_idx].begin; + if (newobj != NULL) + { + *newobj = (U *)this->l[idx]; + new (*newobj) U(); + } + return idx; + } + + /// Free used item. + bool Free(int idx) + { + if (idx < 0 || idx >= SPList::GetN()) + return false; + this->l[idx]->~T(); + int alloc_idx = idx / num_slots; + if (alloc_idx >= allocs.GetN()) + return false; + return MoveFreeUsed(alloc_idx, idx % num_slots, SALIST_USED, SALIST_FREE); + } + + /// Get the FIRST allocated element stored in the list. + /// Initialize 'cur_idx' to the value returned from Allocate(). + T *GetFirst(int *idx) const + { + *idx = -1; + return GetNext(idx); + } + + /// Get the NEXT allocated element stored in the list. + /// Set 'idx' to -1 for the first element or just pass the current value to advance. + T *GetNext(int *idx) const + { + int alloc_idx; + if (*idx >= 0) + { + alloc_idx = *idx / num_slots; + if (alloc_idx >= allocs.GetN()) + return NULL; + *idx = allocs[alloc_idx].dllist[*idx % num_slots].next[SALIST_USED]; + } else + alloc_idx = -1; + // search for the first item of the next group + while (*idx < 0) + { + alloc_idx++; + if (alloc_idx >= allocs.GetN()) + return NULL; + *idx = allocs[alloc_idx].first[SALIST_USED]; + } + *idx += allocs[alloc_idx].begin; + return this->l[*idx]; + } + + /// Get total number of free or used items. Used for stats. + int GetN(SALIST_ITEM_TYPE type) + { + int num = 0; + for (int i = 0; i < allocs.GetN(); i++) + num += allocs[i].num[type]; + return num; + } + +protected: + + SPClassicList allocs; +}; + + +#endif // of SP_SALIST_H diff --git a/src/libsp/containers/string.cpp b/src/libsp/containers/string.cpp new file mode 100644 index 0000000..ff0e0bf --- /dev/null +++ b/src/libsp/containers/string.cpp @@ -0,0 +1,290 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib string implementation + * \file libsp/containers/string.cpp + * \author bombur et al. + * \version x.xx + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//#define USE_MEMBIN + +#ifndef USE_MEMBIN +#define membin_alloc(s, n) SPrealloc(s, n) +#define membin_free(s) SPfree(s) +#else +#include +#endif + +#ifdef _MSC_VER + +#pragma warning(disable : 4706) + +#else + +char * strlwr(char *string) +{ + char *str = string; + if (str == NULL) + return NULL; + + while (*str != 0) + { + *str = tolower(*str); + str++; + } + + return string; +} + +char * strupr (char * string) +{ + char *str = string; + if (str == NULL) + return NULL; + + while (*str != 0) + { + *str = toupper(*str); + str++; + } + + return string; +} + +char * strrev (char * string) +{ + char *start = string; + char *left = string; + + while (*string++) + ; + string -= 2; + + while (left < string) + { + char ch = *left; + *left++ = *string; + *string-- = ch; + } + + return (start); +} + +char * strdup (char * string) +{ + char *memory; + if (!string) + return(NULL); + if ((memory = (char *)SPmalloc(strlen(string) + 1)) != NULL) + return strcpy(memory, string); + return NULL; +} + +int strcasecmp (char *dst, char *src) +{ + int f, l; + do + { + f = tolower((unsigned char)(*(dst++))); + l = tolower((unsigned char)(*(src++))); + } while (f != 0 && (f == l)); + return(f - l); +} + +#endif + +SPString::~SPString () +{ + if (str != NULL) + membin_free(str); + str = NULL; +} + +void SPString::Printf (const char *string, ...) +{ + va_list l; + va_start(l, string); + char *tmp = (char *)SPalloca (4096); // in stack + vsprintf(tmp, string, l); + Insert(GetLength()+1, tmp); + va_end(l); +} + +void SPString::Strftime (const char *string, time_t tim) +{ + struct tm *tmtim = localtime(&tim); + char *tmp = (char *)SPalloca (4096); // in stack + strftime(tmp, 4096, string, tmtim); + Insert(GetLength()+1, tmp); +} + +void SPString::Realloc() +{ + str = (char *)membin_alloc(str, (max + 1) * sizeof(char)); +} + +// Compare helpers +bool operator== (const SPString & s1, const SPString & s2) +{ + return s1.Compare(*s2) == 0; +} +bool operator== (const SPString & s1, const char *s2) +{ + if (s2 == NULL) + { + return (s1.str == NULL); + } + return s1.Compare(s2) == 0; +} +bool operator== (const char *s1, const SPString & s2) +{ + return s2.Compare(s1) == 0; +} + +bool operator!= (const SPString & s1, const SPString & s2) +{ + return s1.Compare(*s2) != 0; +} +bool operator!= (const SPString & s1, const char *s2) +{ + if (s2 == NULL) + return s1.str != NULL; + return s1.Compare(s2) != 0; +} +bool operator!= (const char *s1, const SPString & s2) +{ + return s2.Compare(s1) != 0; +} + +bool operator< (const SPString & s1, const SPString & s2) +{ + return s1.Compare(*s2) < 0; +} +bool operator< (const SPString & s1, const char *s2) +{ + return s1.Compare(s2) < 0; +} +bool operator< (const char *s1, const SPString & s2) +{ + return s2.Compare(s1) > 0; +} + +bool operator> (const SPString & s1, const SPString & s2) +{ + return s1.Compare(*s2) > 0; +} +bool operator> (const SPString & s1, const char *s2) +{ + return s1.Compare(s2) > 0; +} +bool operator> (const char *s1, const SPString & s2) +{ + return s2.Compare(s1) < 0; +} + +bool operator<= (const SPString & s1, const SPString & s2) +{ + return s1.Compare(*s2) <= 0; +} +bool operator<= (const SPString & s1, const char *s2) +{ + return s1.Compare(s2) <= 0; +} +bool operator<= (const char *s1, const SPString & s2) +{ + return s2.Compare(s1) >= 0; +} + +bool operator>= (const SPString & s1, const SPString & s2) +{ + return s1.Compare(*s2) >= 0; +} +bool operator>= (const SPString & s1, const char *s2) +{ + return s1.Compare(s2) >= 0; +} +bool operator>= (const char *s1, const SPString & s2) +{ + return s2.Compare(s1) <= 0; +} + + +////////////////////////////////////////////////////////// + +static void similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max) +{ + char *end1 = (char *)txt1 + len1; + char *end2 = (char *)txt2 + len2; + int l; + + *max = 0; + for (char *p = (char *)txt1; p < end1; p++) + { + for (char *q = (char *)txt2; q < end2; q++) + { + for (l = 0; p + l < end1 && q + l < end2 && p[l] == q[l]; l++) + ; + if (l > *max) + { + *max = l; + *pos1 = p - txt1; + *pos2 = q - txt2; + } + } + } +} + +static int similar_char(const char *txt1, int len1, const char *txt2, int len2) +{ + int sum; + int pos1, pos2, max; + + similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max); + if ((sum = max)) + { + if (pos1 && pos2) + { + sum += similar_char(txt1, pos1, txt2, pos2); + } + if (pos1 + max < len1 && pos2 + max < len2) + { + sum += similar_char(txt1 + pos1 + max, len1 - pos1 - max, txt2 + pos2 + max, len2 - pos2 - max); + } + } + return sum; +} + +int SPString::Similar(const SPString & s2) +{ + if (len == 0 || s2.len == 0) + return 0; + int num = similar_char(str, len, s2.str, s2.len); + return num * 200 / (len + s2.len); +} diff --git a/src/libsp/containers/string.h b/src/libsp/containers/string.h new file mode 100644 index 0000000..e699536 --- /dev/null +++ b/src/libsp/containers/string.h @@ -0,0 +1,816 @@ +////////////////////////////////////////////////////////////////////////// +/** + * support lib string header + * \file libsp/containers/string.h + * \author bombur et al. + * \version x.xx + * \date xx.xx.xxxx + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_STRING_H +#define SP_STRING_H + +#include +#include +#include +#include + +#define GROW(num) (9 * num / 8) + +#ifdef _MSC_VER +#pragma warning (disable : 4239) +#endif + +/// String manipulation class +class SPString +{ +public: + /// empty ctor + SPString () + { + str = NULL; + len = 0; + max = 0; + } + + /// dtor + ~SPString (); + + /// copy ctor + SPString (const SPString & src) + { + str = NULL; + len = 0; + max = 0; + + if (src.len > 0) + { + Add(src.len); + if (src.str != NULL) + strcpy(str, src.str); + } + // don't copy mbstr + } + + /// from a single character + SPString (char ch, int repeat = 1) + { + str = NULL; + len = 0; + max = 0; + + if (repeat < 0) + repeat = 0; + Add(repeat); + int i; + for (i = 0; i < repeat; i++) + str[i] = ch; + str[i] = '\0'; + } + + /// from a string (converts to char) + SPString (char *src) + { + str = NULL; + len = 0; + max = 0; + + if (src != NULL) + { + Add(strlen(src)); + strcpy(str, src); + } + } + + /// from a string (converts to char) + SPString (const char *src) + { + str = NULL; + len = 0; + max = 0; + + if (src != NULL) + { + Add(strlen(src)); + strcpy(str, src); + } + } + + /// subset of characters from an string (converts to char) + SPString (char *pitch, int inLen) + { + str = NULL; + len = 0; + max = 0; + + if (pitch != NULL && inLen > 0) + { + Add(inLen); + int i; + for(i = 0; i < len; i++) + str[i] = pitch[i]; + str[i] = '\0'; + } + } + + // Attributes & Operations + + /// get data length + int GetLength () const + { + return len; + } + + /// TRUE if zero length + BOOL IsEmpty () const + { + return !len; + } + + /// clear contents to empty + void Empty () + { + len = 0; + } + + /// cleans addition memory allocated + void Shrink () + { + max = len; + Realloc(); + } + + /// return single character at zero-based index + char GetAt (int index) const + { + if (index < 0 || index > len) + return *str; + return *(str + index); + } + + /// return single character at zero-based index + char & operator [] (int index) const + { + if (index < 0 || index > len) + return *str; + return *(str + index); + } + + /// set a single character at zero-based index + void SetAt (int index, char ch) + { + if (index < 0 || index >= len) + *(str + index) = ch; + } + + /// return pointer to const string (will be freed in dtor) + const char* operator * () const + { + return len ? str : ""; + } + + /// return pointer to const string (will be freed in dtor) + operator char* () const + { + return len ? str : (char *)""; + } + + // overloaded assignment + + /// ref-counted copy from another SPString + const SPString & operator = (const SPString & src) + { + if (this != &src) + { + len = max = src.len; + Realloc(); + if (len > 0) + { + strcpy(str, src.str); + } + } + return *this; + } + + /// set string content to single character + const SPString & operator = (char ch) + { + len = max = 1; + Realloc(); + *str = ch; + str[1] = '\0'; + return *this; + } + + /// copy string content from string + const SPString & operator = (const char *src) + { + if (str != src) + { + for (len = 0; *(src + len) != '\0'; len++) + ; + max = len; + Realloc(); + if (len != 0) + strcpy(str, src); + } + return *this; + } + + // string concatenation + + /// concatenate a character after converting it to char + const SPString & operator += (const char *src) + { + if (max != 0) + { + int index = len; + Add(strlen(src)); + strcpy(str + index, src); + } + else if (*src != '\0') + { + Add(strlen(src)); + strcpy(str, src); + } + return *this; + + } + + /// concatenate from another SPString + const SPString & operator += (const SPString & src) + { + return operator+=(*src); + } + + friend SPString operator + (const SPString & string1, const SPString & string2) + { + return SPString(string1) += string2; + } + + friend SPString operator + (const SPString & string, const char *str) + { + return SPString(string) += str; + } + + friend SPString operator + (const char *str, const SPString & string) + { + return SPString((char*)str) += string; + } + + // string comparison + + /// straight character comparison + int Compare (const SPString & string) const + { + if (len == 0) + { + if (string.str == NULL || string.len < 1) + return 0; + return string.str[0] == '\0' ? 0 : 1; + } + else if (string.len == 0 || string.str == NULL) + return -1; + return strcmp(str, string.str); + } + + /// compare ignoring case + int CompareNoCase (const SPString & string) const + { + if (len == 0) + { + if (string.str == NULL || string.len < 1) + return 0; + return string.str[0] == '\0' ? 0 : 1; + } + else if (string.len == 0 || string.str == NULL) + return -1; + return strcasecmp(str, string.str); + } + + // simple sub-string extraction + + /// return count characters starting at zero-based first + SPString Mid (int first, int count) const + { + if (first < 0) + first = 0; + if (first >= len) + return SPString(); + if (first + count > len) + count = len - first; + return SPString(str + first, count); + } + + /// return all characters starting at zero-based first + SPString Mid (int first) const + { + if (first < 0) + first = 0; + if (first >= len) + return SPString(); + return SPString(str + first); + } + + /// return first count characters in string + SPString Left (int count) const + { + if (count > len) + return SPString(str, len); + return SPString(str, count); + } + + /// return nCount characters from end of string + SPString Right (int count) const + { + if (count > len) + return SPString(); + return SPString(str + len - count, count); + } + + // upper/lower/reverse conversion +#ifdef _MSC_VER + /// NLS aware conversion to uppercase + void MakeUpper () + { + if (str == NULL) + return; + _strupr(str); + } + + /// NLS aware conversion to lowercase + void MakeLower () + { + if (str == NULL) + return; + _strlwr(str); + } + + /// reverse string right-to-left + void MakeReverse () + { + if (str == NULL) + return; + _strrev(str); + } +#endif + // trimming anything (either side) + + /// remove continuous occurrences of target starting from right + void TrimLeft (char target = ' ') + { + if (str == NULL) + return; + int i; + for (i = 0; i < len && str[i] == target; i++) + ; + if (i != 0) + { + memmove(str, str + i, (len - i + 1) * sizeof(char)); + len -= i; + } + } + + /// remove continuous occurrences of target starting from left + void TrimRight (char target = ' ') + { + if (str == NULL) + return; + int i; + for (i = len - 1; i > 0 && str[i] == target; i--) + ; + len = i + 1; + str[len] = '\0'; + } + + /// remove continuous occurrences of one of charSet starting from right + void TrimLeft (const char *charSet) + { + if (str == NULL) + return; + int i; + for (i = 0; i < len; i++) + { + bool found = false; + for (int j = 0; charSet[j] != '\0'; j++) + { + if (str[i] == charSet[j]) + { + found = true; + break; + } + } + if (!found) + break; + } + + if (i != 0) + { + memmove(str, str + i, (len - i + 1) * sizeof(char)); + len -= i; + } + } + + /// remove continuous occurrences of one of charSet starting from left + void TrimRight (const char *charSet) + { + if (str == NULL) + return; + int i; + for (i = len - 1; i; i--) + { + bool found = false; + for (int j = 0; charSet[j]; j++) + { + if (str[i] == charSet[j]) + { + found = true; + break; + } + } + if (!found) + break; + } + len = i + 1; + str[len] = '\0'; + } + + void TrimLines(int numlines) + { + if (str == NULL) + return; + int j = 0; + for (int i = 0; str[j] && i < numlines; i++) + { + for(; j < len && str[j] != '\n'; j++) + ; + if (str[j] == '\n') + j++; + } + len = j; + str[len] = '\0'; + } + + // advanced manipulation + + /// replace occurrences of oldS with newS + int Replace (char oldS, char newS) + { + if (str == NULL) + return 0; + int ret = 0; + for (int i = 0; i < len; i++) + { + if (str[i] == oldS) + { + str[i] = newS; + ret++; + } + } + return ret; + } + + /// replace occurrences of substring oldString with newString; + /// empty newString removes instances of oldString + int Replace (const char *oldString, const char *newString) + { + if (str == NULL) + return 0; + int last = 0; + int ret = 0; + int oldLen = strlen(oldString); + int newLen = strlen(newString); + + while (last < len && (last = Find(oldString, last)) != -1) + { + Delete(last, oldLen); + Insert(last, newString); + ret++; + last += newLen; + } + return ret; + } + + /// insert substring at zero-based index; concatenates + /// if index is past end of string + /// add to existing string + int Insert (int index, const char *string) + { + if (index < 0) + index = 0; + + int stringLen = strlen(string); + if (len == 0) + { + Add(stringLen); + strcpy(str, string); + return index; + } + + if (index >= len) + index = len; + + int l = len - index + 1; + + Add(stringLen); + + memmove(str + index + stringLen, str + index, l * sizeof(char)); + memmove(str + index, string, stringLen * sizeof(char)); + + return index; + } + + /// delete count characters starting at zero-based index + int Delete (int index, int count = 1) + { + if (index >= len || index < 0) + return -1; + if (index + count > len) + { + len = index; + return count; + } + memmove(str + index, str + index + count, (len - index - count + 1) * sizeof(char)); + len -= count; + return count; + } + + // searching + + /// find character starting at left, -1 if not found + int Find (char ch) const + { + for (int i = 0; i < len; i++) + { + if (str[i] == ch) + return i; + } + return -1; + } + + /// find character starting at right + int ReverseFind (char ch) const + { + for(int i = len - 1; i >= 0; i--) + { + if (str[i] == ch) + return i; + } + return -1; + } + + /// find character starting at zero-based index and going right + int Find (char ch, int start) const + { + for (int i = start; i < len; i++) + { + if (str[i] == ch) + return i; + } + return -1; + } + + /// find first instance of any character in passed string + int FindOneOf (const char *charSet) const + { + int charSetLen = strlen(charSet); + for (int i = 0; i= 0; i--) + { + for (int j = 0; j < charSetLen; j++) + { + if (str[i] == charSet[j]) + return i; + } + } + return -1; + } + + /// reverse find the first character not contained in passed string + int ReverseFindNoneOf (const char *charSet, int start = -1) const + { + int charSetLen = strlen(charSet); + if (start == -1) + start = len - 1; + for (int i = start; i >= 0; i--) + { + bool notfound = true; + for (int j = 0; j < charSetLen; j++) + { + if (str[i] == charSet[j]) + { + notfound = false; + break; + } + } + if (notfound) + return i; + } + return -1; + } + + /// find first instance of substring starting at zero-based index + int Find (const char *string, int start = 0) const + { + if (start < 0 || start >= len || string == NULL) + return -1; + + char *ret = strstr(str + start, string); + return ret ? ret - str : -1; + } + + /// find first instance of substring starting at zero-based index + int FindNoCase (const char *string, int start = 0) const + { + if (start < 0 || start >= len || string == NULL) + return -1; + + char *cp = str + start; + char *s1, *s2; + + if (!*string) + return start; + + while (*cp) + { + s1 = cp; + s2 = (char *) string; + + while (*s1 && *s2 && !(tolower(*s1) - tolower(*s2))) + s1++, s2++; + if (!*s2) + return cp - str; + cp++; + } + return -1; + } + + /// calculate djb2 (Bernstein) string hash + DWORD Hash() const + { + const char *s = str; + DWORD hash = 5381; + int c; + if (len > 0) + { + while ((c = *s++) != '\0') + hash = ((hash << 5) + hash) + c; // = hash * 33 + c; + } + return hash; + } + + // simple formatting + + /// printf-like formatting using passed string + void Printf (const char *string, ...); + void Strftime (const char *string, time_t tim); + + /// Set string from integer + void FromInteger(int i) + { + if (max < 12) + { + max = 12; + Realloc(); + } + char *s = str; + if (i < 0) + { + *(s++) = '-'; + i = -i; + } + char *b = s; + do + { + *s++ = (char)((i % 10) + '0'); + i /= 10; + } while (i > 0); + len = s - str; + *s-- = '\0'; + do + { + char temp = *s; + *s = *b; + *b = temp; + --s; + ++b; + } while (b < s); + } + + /// Calculate the similarity between two strings, in percents. [algorithm (c) Oliver, 1993] + /// \Warning! Recursive! + int Similar(const SPString & s2); + + +protected: + char *str; /// pointer to ref counted string data + int len; /// length in chars + int max; /// max length in chars + + /// reallocates memory + void Realloc(); + + /// adds count symbols, returns index of new first symbol + int Add(int count) + { + if (count < 0 || len < 0 || max < len) + return -1; + + int index = len; + if ((len += count) >= max) + { + // allocate more memory + max = GROW(len) + 8; + Realloc(); + } + return index; + } + +protected: + friend bool operator == (const SPString &, const char *); + friend bool operator != (const SPString &, const char *); +}; + +/* +static int SPListStringsCompare(SPString *e1, SPString *e2) +{ + return e1->Compare(*e2); +} + +static int SPListStringsCompareNoCase(SPString *e1, SPString *e2) +{ + return e1->CompareNoCase(*e2); +} +*/ + +// Compare helpers +bool operator== (const SPString & s1, const SPString & s2); +bool operator== (const SPString & s1, const char *s2); +bool operator== (const char *s1, const SPString & s2); +bool operator!= (const SPString & s1, const SPString & s2); +bool operator!= (const SPString & s1, const char *s2); +bool operator!= (const char *s1, const SPString & s2); +bool operator< (const SPString & s1, const SPString & s2); +bool operator< (const SPString & s1, const char *s2); +bool operator< (const char *s1, const SPString & s2); +bool operator> (const SPString & s1, const SPString & s2); +bool operator> (const SPString & s1, const char *s2); +bool operator> (const char *s1, const SPString & s2); +bool operator<= (const SPString & s1, const SPString & s2); +bool operator<= (const SPString & s1, const char *s2); +bool operator<= (const char *s1, const SPString & s2); +bool operator>= (const SPString & s1, const SPString & s2); +bool operator>= (const SPString & s1, const char *s2); +bool operator>= (const char *s1, const SPString & s2); + +#endif // of SP_STRING_H diff --git a/src/libsp/sp_bswap.h b/src/libsp/sp_bswap.h new file mode 100644 index 0000000..2b62817 --- /dev/null +++ b/src/libsp/sp_bswap.h @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - optimized byte-swap header file + * \file sp_bswap.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_BSWAP_H +#define SP_BSWAP_H + + +#ifdef SP_ARM + +#define BSWAP(d) \ + asm volatile ("eor r3, %0, %0, ROR #16\n" \ + "bic r3, r3, #0xff0000\n" \ + "mov %0, %0, ROR #8\n" \ + "eor %0, %0, r3, LSR #8\n" \ + : "=r" (d) : "0" (d) : "r3"); + +#else + +#define BSWAP(d) \ + ((d) = (((d) & 0xff) << 24) | (((d) & 0xff00) << 8) | \ + (((d) >> 8) & 0xff00) | (((d) >> 24) & 0xff)) + +#endif + +#define BWSWAP(w) (((w) >> 8) | (((w) & 0xff) << 8)) + +#endif // of SP_BSWAP_H diff --git a/src/libsp/sp_cdrom.h b/src/libsp/sp_cdrom.h new file mode 100644 index 0000000..54abd6c --- /dev/null +++ b/src/libsp/sp_cdrom.h @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CDROM driver's interface header. + * \file sp_cdrom.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_CDROM_H +#define SP_CDROM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Enums: + +typedef enum +{ + CDROM_STATUS_CURRENT = -1, + + CDROM_STATUS_UNKNOWN = 0, + CDROM_STATUS_NODISC, + CDROM_STATUS_TRAYOPEN, + + CDROM_STATUS_HASDISC, + + CDROM_STATUS_HAS_ISO = CDROM_STATUS_HASDISC | (1 << 4), + CDROM_STATUS_HAS_DVD = CDROM_STATUS_HASDISC | (2 << 4), + CDROM_STATUS_HAS_AUDIO = CDROM_STATUS_HASDISC | (3 << 4), + CDROM_STATUS_HAS_MIXED = CDROM_STATUS_HASDISC | (4 << 4), + +} CDROM_STATUS; + +//////////////////////////////////// +/// Functions: + +/// Init (open) CDROM driver +BOOL cdrom_init(); + +/// Release CDROM driver +BOOL cdrom_deinit(); + +/// Get device path (set src_path to NULL to get root device path) +const char *cdrom_getdevicepath(const char *src_path); + +/// Eject CD-ROM +int cdrom_eject(BOOL open); + +/// Mount or remount CD-ROM (if language changed) +int cdrom_mount(char *language, BOOL cd_only); +/// Unmount CD-ROM +int cdrom_umount(); +/// Return TRUE if CD-ROM is mounted +BOOL cdrom_ismounted(); + +/// Get CDROM status +CDROM_STATUS cdrom_getstatus(BOOL *force_update); + +/// Return TRUE if CDROM is ready (use additional checks) +BOOL cdrom_isready(); + +/// Switch CDROM on/off +BOOL cdrom_switch(BOOL on); + +int cdrom_stat(const char *, struct stat64 *); + +DIR *cdrom_opendir(const char *); +struct dirent *cdrom_readdir(DIR *); +int cdrom_closedir(DIR *); + +int cdrom_open(const char *fname, int flags); + +char *cdrom_getrealpath(const char *); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_CDROM_H diff --git a/src/libsp/sp_eeprom.h b/src/libsp/sp_eeprom.h new file mode 100644 index 0000000..ec6d06b --- /dev/null +++ b/src/libsp/sp_eeprom.h @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - EEPROM interface header. + * \file sp_eeprom.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_EEPROM_H +#define SP_EEPROM_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Functions: + +/// Sets EEPROM value at given address. +BOOL eeprom_set_value(DWORD addr, DWORD val, int size = 4); + +/// Gets EEPROM value from given address. +DWORD eeprom_get_value(DWORD addr, int size = 4); + + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_EEPROM_H diff --git a/src/libsp/sp_fip.h b/src/libsp/sp_fip.h new file mode 100644 index 0000000..d2531bc --- /dev/null +++ b/src/libsp/sp_fip.h @@ -0,0 +1,170 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP (front panel & remote) driver's header. + * \file sp_fip.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FIP_H +#define SP_FIP_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Functions: + +/// Loads driver module and opens it. +BOOL fip_init(BOOL applymodule); + +/// Closes driver handle and unloads module +BOOL fip_deinit(); + +/// Clears the FIP display. +BOOL fip_clear(); + +/// Writes character to FIP display at given position. +BOOL fip_write_char(int ch, int pos); + +/// Writes right-aligned string to display (up to 7 symbols) +BOOL fip_write_string(const char *str); + +/// Writes special display indicators (see FIP_SPECIAL_*) +BOOL fip_write_special(int id, BOOL onoff); + +BOOL fip_get_special(int id); + +/// Gets pressed button code (see FIP_KEY_*) if available or waits for it +int fip_read_button(BOOL blocked = TRUE); + +//////////////////////////////////// +/// Button codes definitions: +enum +{ + /// 1) definitions for the buttons on the front panel: + FIP_KEY_NONE = 0, + FIP_KEY_FRONT_EJECT, + FIP_KEY_FRONT_PLAY, + FIP_KEY_FRONT_STOP, + FIP_KEY_FRONT_PAUSE, + FIP_KEY_FRONT_SKIP_PREV, + FIP_KEY_FRONT_SKIP_NEXT, + FIP_KEY_FRONT_REWIND, + FIP_KEY_FRONT_FORWARD, + + /// 2) definitions for the keys on the remote control: + FIP_KEY_POWER, + FIP_KEY_EJECT, + + FIP_KEY_ONE, + FIP_KEY_TWO, + FIP_KEY_THREE, + FIP_KEY_FOUR, + FIP_KEY_FIVE, + FIP_KEY_SIX, + FIP_KEY_SEVEN, + FIP_KEY_EIGHT, + FIP_KEY_NINE, + FIP_KEY_ZERO, + + FIP_KEY_CANCEL, + FIP_KEY_SEARCH, + FIP_KEY_ENTER, + + FIP_KEY_OSD, + FIP_KEY_SUBTITLE, + FIP_KEY_SETUP, + FIP_KEY_RETURN, + FIP_KEY_TITLE, + FIP_KEY_PN, + FIP_KEY_MENU, + FIP_KEY_AB, + FIP_KEY_REPEAT, + + FIP_KEY_UP, + FIP_KEY_DOWN, + FIP_KEY_LEFT, + FIP_KEY_RIGHT, + + FIP_KEY_VOLUME_DOWN, + FIP_KEY_VOLUME_UP, + FIP_KEY_PAUSE, + + FIP_KEY_REWIND, + FIP_KEY_FORWARD, + FIP_KEY_SKIP_PREV, + FIP_KEY_SKIP_NEXT, + + FIP_KEY_PLAY, + FIP_KEY_STOP, + + FIP_KEY_SLOW, + FIP_KEY_AUDIO, + FIP_KEY_VMODE, + FIP_KEY_MUTE, + FIP_KEY_ZOOM, + FIP_KEY_PROGRAM, + FIP_KEY_PBC, + FIP_KEY_ANGLE, +}; + +enum +{ + FIP_SPECIAL_PBC = 0, + FIP_SPECIAL_MP3 = 1, + FIP_SPECIAL_CAMERA = 2, + FIP_SPECIAL_COLON1 = 3, + FIP_SPECIAL_DOLBY = 4, + FIP_SPECIAL_COLON2 = 5, + FIP_SPECIAL_DTS = 6, + + FIP_SPECIAL_S = 7, + FIP_SPECIAL_V = 8, + FIP_SPECIAL_CD = 9, + + FIP_SPECIAL_PLAY = 10, + FIP_SPECIAL_PAUSE = 11, + FIP_SPECIAL_ALL = 12, + FIP_SPECIAL_REPEAT = 13, + + FIP_SPECIAL_DVD = 14, + + FIP_SPECIAL_CIRCLE_1 = 15, + FIP_SPECIAL_CIRCLE_2, + FIP_SPECIAL_CIRCLE_3, + FIP_SPECIAL_CIRCLE_4, + FIP_SPECIAL_CIRCLE_5, + FIP_SPECIAL_CIRCLE_6, + FIP_SPECIAL_CIRCLE_7, + FIP_SPECIAL_CIRCLE_8, + FIP_SPECIAL_CIRCLE_9, + FIP_SPECIAL_CIRCLE_10, + FIP_SPECIAL_CIRCLE_11, + FIP_SPECIAL_CIRCLE_12, +}; + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FIP_H diff --git a/src/libsp/sp_flash.cpp b/src/libsp/sp_flash.cpp new file mode 100644 index 0000000..6a9bfa6 --- /dev/null +++ b/src/libsp/sp_flash.cpp @@ -0,0 +1,276 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FLASH-ROM interface functions source file. + * \file sp_flash.cpp + * \author bombur + * \version 0.2 + * \date 30.03.2010 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include +#include + +#include "sp_misc.h" +#include "sp_fip.h" +#include "sp_cdrom.h" +#include "sp_flash.h" +#include "sp_msg.h" + +static int file_handle = -1, mtd_handle = -1; +static DWORD file_read_cnt, num_read = 0, num_written; +static DWORD flen; +static void *buf = NULL; +static BYTE *curbuf = NULL; +static BYTE *cur_addr, *cur_a; + +static struct region_info_user riu[16]; +static int reg_cnt = 0; + +static char fwver[16]; + +int flash_end() +{ + if (buf != NULL) + SPSafeFree(buf); + if (file_handle >= 0) + { + close(file_handle); + file_handle = -1; + } + if (mtd_handle >= 0) + { + close(mtd_handle); + mtd_handle = -1; + } + return 0; +} + + +int flash_file(char *fname, DWORD address) +{ + flash_end(); + + int mtdpos; + int err = 0; + + file_handle = cdrom_open(fname, O_RDONLY | O_BINARY); + if (file_handle == -1) + return -1; + flen = lseek(file_handle, 0, SEEK_END); + lseek(file_handle, 0, SEEK_SET); + +#ifdef WIN32 + char *mtdpath = "mtd0"; + mtd_handle = open(mtdpath, O_RDWR | O_BINARY | O_CREAT | O_TRUNC); + chmod(mtdpath, 0777); + static BYTE mtdbuf[2*1024*1024]; + cur_addr = mtdbuf; +#else + mtd_handle = open("/dev/mtd/0", O_RDWR); + cur_addr = (BYTE *)address; +#endif + + if (mtd_handle == -1) + { + err = -2; + goto err; + } + + mtdpos = lseek(mtd_handle, address, SEEK_SET); + if (mtdpos == -1) + { + err = -3; + goto err; + } + + buf = SPmalloc(0x10000); + if (buf == NULL) + { + err = -4; + goto err; + } + + file_read_cnt = 0; + num_read = 0; + + // gather info + struct mtd_info_user miu; + if (ioctl(mtd_handle, MEMGETINFO, &miu) == 0) + { + msg("Flash: MTD size=%d erase_size=%d\n", miu.size, miu.erasesize); + } + if (ioctl(mtd_handle, MEMGETREGIONCOUNT, ®_cnt) == 0) + { + msg("Flash: %d erase regions:\n", reg_cnt); + if (reg_cnt > 16) + reg_cnt = 16; + for (int i = 0; i < reg_cnt; i++) + { + riu[i].regionindex = i; + if (ioctl(mtd_handle, MEMGETREGIONINFO, &riu[i]) == 0) + { + msg(" [%d] %08x %08x num=%d\n", i, riu[i].offset, riu[i].erasesize, riu[i].numblocks); + } + } + } + + num_read = read(file_handle, buf, 32); + if (num_read < 32 || memcmp(buf, "-rom1fs-", 8) != 0) + { + msg("Flash: Wrong firmware file type or file error.\n"); + err = -5; + goto err; + } + + lseek(file_handle, 0, SEEK_SET); + num_read = 0; + strncpy(fwver, (char *)buf + 16, 16); + + // test size + if (flen > address + miu.size) + { + msg("Flash: Firmware size (%d) exceeds flash size (%d) for given offset (%d)\n", flen, miu.size, address); + err = -6; + goto err; + } + + msg("Flash: Found '%s'. Starting flash...\n", fwver); + + return 0; + +err: + flash_end(); + + return err; +} + +int flash_cycle() +{ + if (buf == NULL || file_handle < 0 || mtd_handle < 0) + return -1; + + if (num_read == 0) + { + // find corresponding erase zone + int len = 0; +#ifdef WIN32 + len = 0x1000; +#else + for (int i = 0; i < reg_cnt; i++) + { + if ((DWORD)cur_addr >= riu[i].offset && (DWORD)cur_addr < riu[i].offset + riu[i].erasesize * riu[i].numblocks) + { + len = riu[i].erasesize; + break; + } + } +#endif + if (len == 0) + { + msg("Flash: Cannot find erase region for address %08x", (DWORD)cur_addr); + return -1; + } + num_read = read(file_handle, buf, len); + curbuf = (BYTE *)buf; + if (num_read <= 0) + { + flash_end(); + return 100; + } + + // test + if (memcmp(cur_addr, buf, num_read) != 0) + { + // erase FLASH memory + struct erase_info_user eiu; + eiu.start = (DWORD)cur_addr; + eiu.length = len; + ioctl(mtd_handle, MEMUNLOCK, &eiu); + + if (ioctl(mtd_handle, MEMERASE, &eiu) != 0) + { + msg("Flash: MEMERASE ERR(%x, %x)\n", eiu.start, eiu.length); + goto err; + } + + lseek(mtd_handle, (DWORD)cur_addr, SEEK_SET); + + cur_a = cur_addr; + cur_addr += len; + } + else + { + cur_addr += len; + file_read_cnt += num_read; + + num_read = 0; + } + } + + if (num_read > 0) + { + int len = Min(0x1000, (int)num_read); + num_written = write(mtd_handle, curbuf, len); + if (num_written != (DWORD)len) + { + msg("Flash: write ERR(%x, %x)\n", file_read_cnt, num_written); + goto err; + } +#ifndef WIN32 + if (memcmp(cur_a, curbuf, len) != 0) + { + msg("Flash: Verify error @ %08x...\n", cur_a); + return -2; + } +#endif + cur_a += len; + curbuf += len; + num_read -= len; + file_read_cnt += len; + } + + if (file_read_cnt > flen) + file_read_cnt = flen; + + return file_read_cnt * 100 / flen; +err: + flash_end(); + return -1; +} + +DWORD flash_get_memory_size() +{ +#ifdef WIN32 + return 1*1024*1024; +#else + int mtd_handle = open("/dev/mtd/0", O_RDWR); + if (mtd_handle == -1) + return 0; + struct mtd_info_user miu; + int size = 0; + if (ioctl(mtd_handle, MEMGETINFO, &miu) == 0) + size = miu.size; + close(mtd_handle); + return size; +#endif +} diff --git a/src/libsp/sp_flash.h b/src/libsp/sp_flash.h new file mode 100644 index 0000000..7883cd3 --- /dev/null +++ b/src/libsp/sp_flash.h @@ -0,0 +1,51 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FLASH interface header. + * \file sp_flash.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_FLASH_H +#define SP_FLASH_H + + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////// +/// Functions: + +/// Starts file upload to FLASH-ROM address. +/// uClinux kernel compiled with 'CONFIG_MTD=y' (and 'CONFIG_MTD_CHAR=y') is required. +int flash_file(char *fname, DWORD address); + +/// Call this in cycle to upload the file. Progress is returned, in per cents. +/// When upload is finished, 100 is returned. +int flash_cycle(); + +DWORD flash_get_memory_size(); + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_FLASH_H diff --git a/src/libsp/sp_i2c.h b/src/libsp/sp_i2c.h new file mode 100644 index 0000000..103b384 --- /dev/null +++ b/src/libsp/sp_i2c.h @@ -0,0 +1,42 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - I2C data transfer functions header file. + * \file sp_i2c.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_I2C_H +#define SP_I2C_H + +#ifdef __cplusplus +extern "C" { +#endif + +/// Reads data from the I2C bus +BOOL i2c_data_in(BYTE addr, BYTE idx, BYTE *data, int num); + +/// Writes data to the I2C bus +BOOL i2c_data_out(BYTE addr, BYTE idx, BYTE *data, int num); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_I2C_H diff --git a/src/libsp/sp_io.h b/src/libsp/sp_io.h new file mode 100644 index 0000000..d0ec4bc --- /dev/null +++ b/src/libsp/sp_io.h @@ -0,0 +1,55 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Port IO header. Stripped from + * \file sp_io.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_IO_H +#define SP_IO_H +#ifndef __ASM_ARM_IO_H + +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getw(a) (*(volatile unsigned short *)(a)) +#define __arch_getl(a) (*(volatile unsigned int *)(a)) + + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +#define __raw_writeb(v,a) __arch_putb(v,a) +#define __raw_writew(v,a) __arch_putw(v,a) +#define __raw_writel(v,a) __arch_putl(v,a) + +#define __raw_readb(a) __arch_getb(a) +#define __raw_readw(a) __arch_getw(a) +#define __raw_readl(a) __arch_getl(a) + +#define outb(v,p) __raw_writeb(v,p) +#define outw(v,p) __raw_writew(v,p) +#define outl(v,p) __raw_writel(v,p) + +#define inb(p) __raw_readb(p) +#define inw(p) __raw_readw(p) +#define inl(p) __raw_readl(p) + +#endif +#endif // of SP_IO_H diff --git a/src/libsp/sp_khwl.h b/src/libsp/sp_khwl.h new file mode 100644 index 0000000..bfb67df --- /dev/null +++ b/src/libsp/sp_khwl.h @@ -0,0 +1,190 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - KHWL driver's header. + * \file sp_khwl.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_KHWL_H +#define SP_KHWL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sp_khwl_prop.h" +#include "sp_video.h" + + +// This trick transforms [0..255] range into [0..65535] range (instead of about 0..255*256) +#define RANGE8TO16(x) (((x) << 8) | (x)) + +/// Play modes +enum KHWL_PLAY_MODE_TYPE +{ + KHWL_PLAY_MODE_NORMAL = 0, + KHWL_PLAY_MODE_STEP = 1, + KHWL_PLAY_MODE_IFRAME = 2, + KHWL_PLAY_MODE_REV = 5, + KHWL_PLAY_MODE_IFRAME_REV = 6, +}; + +//////////////////////////////////// +/// Structures: + +/// OSD setup struct +typedef struct _KHWL_OSDSTRUCT +{ + void *addr; + int width; + int height; + int bpp; + int flags; + +} KHWL_OSDSTRUCT; + +/// Window coords and size +typedef struct _KHWL_WINDOW +{ + int x, y; + int w, h; + +} KHWL_WINDOW; + + +/// YUV frame +typedef struct +{ + void *y_buf; + void *uv_buf; + int y_offs, uv_offs; + int y_num, uv_num; + +} KHWL_YUV_FRAME; + +/// Address-data pair (used for EEPROM and PIO) +typedef struct +{ + DWORD Addr; + DWORD Data; + +} KHWL_ADDR_DATA; + +/// Used for hapeningwait() +typedef struct +{ + DWORD timeout_microsecond; + DWORD mask; + +} KHWL_WAITABLE; + +extern KHWL_OSDSTRUCT osd; + +//////////////////////////////////// +/// Functions: + +/// Loads driver module and opens it. +BOOL khwl_init(BOOL applymodule); + +/// Closes driver handle and unloads module +BOOL khwl_deinit(); + +/// Resets the driver +BOOL khwl_reset(); + +/// OSD switch (enable). Fills given structure with params. +int khwl_osd_switch(KHWL_OSDSTRUCT *osd, BOOL autoupd); + +/// Update OSD. Returns FALSE when user pressed 'exit' for Win32. +BOOL khwl_osd_update(); + +/// Set general alpha for OSD (0-65535) +int khwl_osd_setalpha(int alpha); + +void khwl_get_osd_size(int *width, int *height); + +void khwl_osd_setfullscreen(BOOL is); + +/// Set OSD palette entry +void khwl_osd_setpalette(BYTE *pal, int entry, BYTE r, BYTE g, BYTE b, BYTE a); + +/// Set KHWL property +int khwl_setproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value); +/// Get KHWL property +int khwl_getproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value); + + +/// Initialize color conversion tables +void khwl_inityuv(); +/// RGB -> YUV +void khwl_vgargbtotvyuv(BYTE R, BYTE G, BYTE B, BYTE *y, BYTE *u, BYTE *v); +/// YUV -> RGB +void khwl_tvyuvtovgargb(BYTE y, BYTE u, BYTE v, BYTE *R, BYTE *G, BYTE *B); +/// JPEG YUV -> RGB +void khwl_jpegyuvtorgb(BYTE y, BYTE u, BYTE v, BYTE *R, BYTE *G, BYTE *B); + +/// Display YUV buffer +int khwl_displayYUV(KHWL_YUV_FRAME *f); + +/// Audio switch +int khwl_audioswitch(BOOL ison); + +/// Get supported audio sample rates list (the last is -1). +int *khwl_get_samplerates(); + +/// Decoder play (mode = 0, 2, 6 ?) +int khwl_play(int mode); + +/// Decoder stop +int khwl_stop(); + +/// Decoder pause +int khwl_pause(); + +/// Restore params +BOOL khwl_restoreparams(); + +/// Block/Unblock irq for data change +BOOL khwl_blockirq(BOOL block); + +/// Wait to process media packets +BOOL khwl_happeningwait(DWORD *mask); + +/// Poll khwl device +BOOL khwl_poll(WORD mask, DWORD timeout); + +/// IDE turn on/off +BOOL khwl_ideswitch(BOOL ison); + +/// Get CPU frequency +int khwl_getfrequency(); + +/// Set CPU frequency (100 <= freq <= 202) +/// Caution! Use this in predicaments only! +BOOL khwl_setfrequency(int freq); + +/// Get hardware string +char *khwl_gethw(); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_KHWL_H diff --git a/src/libsp/sp_khwl_colors.cpp b/src/libsp/sp_khwl_colors.cpp new file mode 100644 index 0000000..7484e07 --- /dev/null +++ b/src/libsp/sp_khwl_colors.cpp @@ -0,0 +1,278 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - color space support functions source file + * \file sp_khwl_colors.c + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" + + + +#define USE_NEW_YUV +//#define USE_GAMMA + + +#define START 0 +#define END 65536 +#define PRECISION 20 + +#define SCALEBITS_INT 8 +#define FIX_INT(x) ((WORD) ((x) * (1L<> SCALEBITS_INT) + Y_ADD_INT) +#define RGB2U(r,g,b) (((- U_R_INT * r - U_G_INT * g + U_B_INT * b) >> (SCALEBITS_INT + 2)) + U_ADD_INT) +#define RGB2V(r,g,b) (((V_R_INT * r - V_G_INT * g - V_B_INT * b) >> (SCALEBITS_INT + 2)) + V_ADD_INT) + + +// yuv -> rgb constants +#define RGB_Y_INT 1.164 + +#define B_U_INT 2.018 +#define G_U_INT 0.391 + +#define G_V_INT 0.813 +#define R_V_INT 1.596 + +#define RGB555(R,G,B) ((clip[R] << 7) & 0x7c00) | ((clip[G] << 2) & 0x03e0) | ((clip[B] >> 3) & 0x001f) +#define RGB565(R,G,B) ((clip[R] << 8) & 0xf800) | ((clip[G] << 3) & 0x07e0) | ((clip[B] >> 3) & 0x001f) + +// yuv -> rgb lookup tables +static DWORD RGB_Y_tab[256]; +static DWORD B_U_tab[256]; +static DWORD G_U_tab[256]; +static DWORD G_V_tab[256]; +static DWORD R_V_tab[256]; + +//smart clipping table +static BYTE clip_tab[2048]; +static BYTE *clip = NULL; + +void khwl_inityuv() +{ + DWORD i; + + for (i = 0; i < 512; i++) + clip_tab[i] = 0; + for (i = 512; i < 512+256; i++) + clip_tab[i] = (BYTE)(i - 512); + for (i = 512+256; i < 2048; i++) + clip_tab[i] = 255; + + clip = clip_tab + 512; + + for (i = 0; i < 256; i++) + { + RGB_Y_tab[i] = FIX_INT(RGB_Y_INT) * (i - Y_ADD_INT); + B_U_tab[i] = FIX_INT(B_U_INT) * (i - U_ADD_INT); + G_U_tab[i] = FIX_INT(G_U_INT) * (i - U_ADD_INT); + G_V_tab[i] = FIX_INT(G_V_INT) * (i - V_ADD_INT); + R_V_tab[i] = FIX_INT(R_V_INT) * (i - V_ADD_INT); + } +} + +void new_rgbtoyuv(BYTE R, BYTE G, BYTE B, BYTE *y, BYTE *u, BYTE *v) +{ + *y = (BYTE)RGB2Y(R,G,B); + *u = (BYTE)RGB2U(R,G,B); + *v = (BYTE)RGB2V(R,G,B); +} + +void new_yuvtorgb(BYTE y, BYTE u, BYTE v, BYTE *R, BYTE *G, BYTE *B) +{ + int rgb_y = RGB_Y_tab[y]; + int b_u = B_U_tab[u]; + int g_uv = G_U_tab[u] + G_V_tab[v]; + int r_v = R_V_tab[v]; + + register int r = (rgb_y + r_v) >> SCALEBITS_INT; + register int g = (rgb_y - g_uv) >> SCALEBITS_INT; + register int b = (rgb_y + b_u) >> SCALEBITS_INT; + *R = clip[r]; + *G = clip[g]; + *B = clip[b]; +} + +#ifdef USE_GAMMA + +static DWORD powertwodottwotable[PRECISION + 1] = +{ + 0, 89, 413, 1008, 1899, 3104, 4636, 6507, 8729, 11312, 14263, 17590, + 21301, 25403, 29901, 34802, 40112, 45835, 51977, 58542, 65536 +}; + +static DWORD invertofpowertwodottwotable[PRECISION + 1]= +{ + 0, 16792, 23010, 27667, 31533, 34899, 37914, 40666, 43211, 45587, 47824, + 49941, 51956, 53881, 55727, 57502, 59214, 60869, 62471, 64025, 65536 +}; + +// computes y/65536=f(x/65536) with 0<=x,y<65536 with f=^2.2 or ^(1/2.2) given as a DWORD table (have to code the 65536 case) +static WORD compute_f(DWORD beg, DWORD end, DWORD prec, DWORD *table, WORD x) +{ + long a,b,fa,fb,entry; + + entry = (x - beg) * prec / (end - beg); + + if ((entry < 0) || (entry >= 20)) + { + printf("memory corrupted x=%hd beg=%ld end=%ld prec=%ld\n", x, beg, end, prec); + return 0; + } + + a = entry * (end - beg) / prec + beg; + b = (entry + 1) * (end - beg) / prec + beg; + fa = table[entry]; + fb = table[entry + 1]; + return (WORD)(fa + (fb - fa) * (x - a) / (b - a)); +} +#endif + + +// see video demystified page 43 + +static void internal_rgbtoyuv(WORD R, WORD G, WORD B, WORD *y, WORD *u,WORD *v) +{ + long yraw, uraw, vraw; + + yraw = ( 257*R +504*G + 98*B)/1000 + RANGE8TO16(16); + uraw = (-148*R -291*G +439*B)/1000 + RANGE8TO16(128); + vraw = ( 439*R -368*G - 71*B)/1000 + RANGE8TO16(128); + + *y = (WORD)MAX(MIN(yraw, RANGE8TO16(235)), RANGE8TO16(16)); + *u = (WORD)MAX(MIN(uraw, RANGE8TO16(240)), RANGE8TO16(16)); + *v = (WORD)MAX(MIN(vraw, RANGE8TO16(240)), RANGE8TO16(16)); +} + +/* +static void internal_yuvtorgb(WORD y, WORD u, WORD v, WORD *R, WORD *G, WORD *B) +{ + long Rraw, Graw, Braw; + long ym = y - RANGE8TO16(16), um = u - RANGE8TO16(128), vm = v - RANGE8TO16(128); + + Rraw = (1164 * ym + 1596 * vm)/1000; + Graw = (1164 * ym + 392 * um - 813 * vm)/1000; + Braw = (1164 * ym + 2017 * um )/1000; + + *R = (WORD)MAX(0, MIN(Rraw, RANGE8TO16(255))); + *G = (WORD)MAX(0, MIN(Graw, RANGE8TO16(255))); + *B = (WORD)MAX(0, MIN(Braw, RANGE8TO16(255))); +} +*/ + +void khwl_vgargbtotvyuv(BYTE R, BYTE G, BYTE B, BYTE *y, BYTE *u, BYTE *v) +{ +//#ifdef USE_NEW_YUV +// new_rgbtoyuv(R, G, B, y, u, v); +//#else +#ifdef USE_GAMMA + WORD Rc = compute_f(START, END, PRECISION, powertwodottwotable, (WORD)RANGE8TO16(R)); + WORD Gc = compute_f(START, END, PRECISION, powertwodottwotable, (WORD)RANGE8TO16(G)); + WORD Bc = compute_f(START, END, PRECISION, powertwodottwotable, (WORD)RANGE8TO16(B)); +#else + WORD Rc = (WORD)RANGE8TO16(R); + WORD Gc = (WORD)RANGE8TO16(G); + WORD Bc = (WORD)RANGE8TO16(B); +#endif + WORD wy, wu, wv; + internal_rgbtoyuv(Rc, Gc, Bc, &wy, &wu, &wv); + *y = (BYTE)(wy >> 8); + *u = (BYTE)(wu >> 8); + *v = (BYTE)(wv >> 8); +//#endif +} + +void khwl_tvyuvtovgargb(BYTE y, BYTE u, BYTE v, BYTE *R, BYTE *G, BYTE *B) +{ +#ifdef USE_NEW_YUV + new_yuvtorgb(y, u, v, R, G, B); +#else + WORD Ruc, Guc, Buc; + internal_yuvtorgb((WORD)RANGE8TO16(y), (WORD)RANGE8TO16(u), (WORD)RANGE8TO16(v), &Ruc, &Guc, &Buc); +#ifdef USE_GAMMA + *R = (BYTE)(compute_f(START, END, PRECISION, invertofpowertwodottwotable, Ruc) >> 8); + *G = (BYTE)(compute_f(START, END, PRECISION, invertofpowertwodottwotable, Guc) >> 8); + *B = (BYTE)(compute_f(START, END, PRECISION, invertofpowertwodottwotable, Buc) >> 8); +#else + *R = (BYTE)(Ruc >> 8); + *G = (BYTE)(Guc >> 8); + *B = (BYTE)(Buc >> 8); +#endif +#endif +} + + +void khwl_jpegyuvtorgb(BYTE y, BYTE u, BYTE v, BYTE *R, BYTE *G, BYTE *B) +{ + long Rraw, Graw, Braw; + long ym = RANGE8TO16(y), um = RANGE8TO16(u) - RANGE8TO16(128); + long vm = RANGE8TO16(v) - RANGE8TO16(128); + + Rraw = (1000 * ym + 1000*vm)/1000; + Graw = (1000 * ym - 509 * um - 194 * vm)/1000; + Braw = (1000 * ym + 1000*um )/1000; + + Rraw = (WORD)MAX(0, MIN(Rraw, RANGE8TO16(255))); + Graw = (WORD)MAX(0, MIN(Graw, RANGE8TO16(255))); + Braw = (WORD)MAX(0, MIN(Braw, RANGE8TO16(255))); + *R = (BYTE)(Rraw >> 8); + *G = (BYTE)(Graw >> 8); + *B = (BYTE)(Braw >> 8); +} + + +/* + float y = (float)ybuf[i] / 255.0f; + float u = (float)uvbuf[ui*2+1] / 255.0f -0.5f; + float v = (float)uvbuf[ui*2] / 255.0f -0.5f; + + b = (y + u) * 255.0f; + if (b < 0) b = 0; + if (b > 255)b = 255; + + g = (y - 0.509 * u - 0.194*v) * 255.0f; + if (g < 0)g = 0; + if (g > 255)g = 255; + + r = (y + v) * 255.0f; + if (r < 0) r = 0; + if (r > 255)r = 255; + + backbuf[vi] = (b << 16) | (g << 8) | r; +*/ diff --git a/src/libsp/sp_khwl_prop.h b/src/libsp/sp_khwl_prop.h new file mode 100644 index 0000000..db15fe8 --- /dev/null +++ b/src/libsp/sp_khwl_prop.h @@ -0,0 +1,393 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - KHWL driver's properties. + * \file sp_khwl_prop.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_KHWL_PROP_H +#define SP_KHWL_PROP_H + +#ifdef __cplusplus +extern "C" { +#endif + +// property sets +typedef enum +{ + KHWL_COMMON_SET = 1, + KHWL_EEPROM_SET = 5, // eeprom + KHWL_BOARDINFO_SET = 6, // general properties + KHWL_VIDEO_SET = 7, // video properties + KHWL_AUDIO_SET = 8, // audio properties + KHWL_TIME_SET = 9, // time properties + KHWL_SUBPICTURE_SET = 10, // subpicture properties + KHWL_DVI_TRANSMITTER_SET = 13, // DVI transmitter + KHWL_DECODER_SET = 14, // Mpeg decoder + KHWL_OSD_SET = 17, // OSD properties + +} KHWL_PROPERTY_SET; + +// struct used to set property +typedef struct _KHWL_PROPERTY +{ + KHWL_PROPERTY_SET pset; + int id; + int size; + void *v; + +} KHWL_PROPERTY; + +//////////////////////////////////////////////////// + +// ----------------- KHWL_COMMON_SET (1) common +typedef enum +{ + eDoAudioLater = 15, + +} KHWL_COMMON; + +// ----------------- KHWL_EEPROM_SET (5) eeprom +typedef enum +{ + eEepromAccess = 0, + +} KHWL_EEPROM_SET_PROP; + +// ----------------- KHWL_BOARDINFO_SET (6) general properties +typedef enum +{ + ebiBoardVersion = 2, + ebiAPMState = 3, + ebiPIOAccess = 4, + ebiCommand = 7, + +} KHWL_BOARDINFO_SET_PROP; + +// ----------------- KHWL_VIDEO_SET (7) video properties +typedef enum +{ + evOutputDevice = 1, + evTvOutputFormat = 2, + evTvStandard = 3, + evBrightness = 4, + evContrast = 5, + evSaturation = 6, + evInAspectRatio = 7, + evInStandard = 8, + evOutDisplayOption = 9, + evSourceWindow = 10, + evZoomedWindow = 11, + evMaxDisplayWindow = 12, + evDestinationWindow = 13, + evValidWindow = 14, + evCustomHdtvParams = 15, + evSpeed = 16, + evScartAspectRatio = 23, + evYUVWriteParams = 25, + evDigOvOnlyParams = 28, + evVOBUReverseSpeed = 31, + evForcedProgressiveAlways = 34, + evMacrovisionFlags = 37, + evForcePanScanDefaultSize = 56, + +} KHWL_VIDEO_SET_PROP; + +// ----------------- KHWL_AUDIO_SET (8) audio properties +typedef enum +{ + eaVolumeRight = 5, + eaVolumeLeft = 6, + eAudioFormat = 7, + eAudioSampleRate = 8, + eAudioNumberOfChannels = 9, + eAudioNumberOfBitsPerSample = 10, + eAudioDigitalOutput = 13, + +} KHWL_AUDIO_SET_PROP; + +// ----------------- KHWL_TIME_SET (9) time properties +typedef enum +{ + etimSystemTimeClock = 2, + etimVOPTimeIncrRes = 5, + etimVideoCTSTimeScale = 6, + etimAudioCTSTimeScale = 7, + etimVideoFrameDisplayedTime = 8, + +} KHWL_TIME_SET_PROP; + +// ----------------- KHWL_SUBPICTURE_SET (10) subpicture properties +typedef enum +{ + eSubpictureCmd = 0, + eSubpictureUpdatePalette = 1, + eSubpictureUpdateButton = 2, +} KHWL_SUBPICTURE_SET_PROP; + +// ----------------- KHWL_DVI_TRANSMITTER_SET (13) DVI transmitter +typedef enum +{ + edtAccessRegister = 0, + edtOutputEnable = 1, + +} KHWL_DVI_TRANSMITTER_SET_PROP; + +// ----------------- KHWL_DECODER_SET (14) Mpeg decoder +typedef enum +{ + edecVideoStd = 2, + edecOsdFlicker = 3, + edecForceFixedVOPRate = 5, + edecCSSChlg = 7, // get challenge + edecCSSKey1 = 8, // set key + edecCSSChlg2 = 9, // set challenge + edecCSSKey2 = 10, // get key + edecCSSDiscKey = 11, // set + edecCSSTitleKey = 12, // set + +} KHWL_DECODER_SET_PROP; + +// ----------------- KHWL_OSD_SET (17) OSD properties +typedef enum +{ + eOsdCommand = 0, + eOsdDestinationWindow = 2, + +} KHWL_OSD_SET_PROP; + + +//////////////////////////////////////////////////////// + +/// Aux. structures + +/// Time clock type +typedef struct +{ + DWORD timeres; // 90000 + ULONGLONG pts; + +} KHWL_TIME_TYPE; + +/// Board command +typedef enum +{ + ebiCommand_HardwareReset = 1, + ebiCommand_VideoHwBlackFrame = 2, + +} KHWL_BOARD_COMMAND_TYPE; + +/// Audio format type +typedef enum +{ + eAudioFormat_MPEG1 = 1, // mpeg1 layer 1 + eAudioFormat_MPEG2 = 2, // mpeg1 layer 2 ? + eAudioFormat_AC3 = 3, // ac3 + eAudioFormat_PCM = 4, // lpcm + eAudioFormat_DTS = 5, // dts + eAudioFormat_DVD_AUDIO = 6, // dvd audio + eAudioFormat_REVERSE_PCM = 7, // rpcm + eAudioFormat_AAC = 8, // aac + eAudioFormat_MPEG1_LAYER3 = 9, // mpeg1 layer 3 + eAudioFormat_MPEG2_LAYER1 = 10, // mpeg2 layer 1 + eAudioFormat_MPEG2_LAYER2 = 11, // mpeg2 layer 2 + eAudioFormat_MPEG2_LAYER3 = 12, // mpeg2 layer 3 + + eAudioFormat_UNKNOWN = 0, + +} KHWL_AUDIO_FORMAT_TYPE; + +/// Digital audio output type +typedef enum +{ + eAudioDigitalOutput_Pcm = 0, + eAudioDigitalOutput_Compressed = 1, + +} KHWL_AUDIO_DIGITAL_OUTPUT_TYPE; + +/// Output video device +typedef enum +{ + evOutputDevice_VGA = 0, + evOutputDevice_TV = 1, + evOutputDevice_HDTV = 0x20, + evOutputDevice_DigOvOnly = 0x21, + evOutputDevice_HdtvSubd = 0x400, + +} KHWL_OUTPUT_DEVICE_TYPE; + +/// TV standard used +typedef enum +{ + evTvStandard_NTSC = 0, + evTvStandard_PAL = 2, + evTvStandard_PAL60 = 8, + evTvStandard_PALM = 10, + + // HD/Progressive formats + + evTvStandard_480P = 11, + evTvStandard_576P = 12, + evTvStandard_720P = 13, + evTvStandard_1080I = 14, + + evTvStandard_720P50 = 255, + +} KHWL_TV_STANDARD_TYPE; + +/// TV Output (cable) format used +typedef enum +{ + evTvOutputFormat_NONE = -1, + evTvOutputFormat_COMPOSITE = 0, + evTvOutputFormat_OUTPUT_OFF = 0x40, + evTvOutputFormat_COMPONENT_YUV = 0x80, + evTvOutputFormat_COMPONENT_RGB = 0xc0, + evTvOutputFormat_COMPONENT_RGB_SCART = 0x200, + + evTvOutputFormat_DVI = 0x1000, + +} KHWL_TV_OUTPUT_FORMAT_TYPE; + +/// TV Aspect ratio used +typedef enum +{ + evInAspectRatio_none = 0, + evInAspectRatio_4x3 = 2, + evInAspectRatio_16x9 = 3, + +} KHWL_IN_ASPECT_RATIO_TYPE; + +/// Out display ratio used +typedef enum +{ + evOutDisplayOption_Normal = 0, + evOutDisplayOption_16x9to4x3_PanScan = 1, + evOutDisplayOption_16x9to4x3_LetterBox = 2, + evOutDisplayOption_4x3to16x9_HorzCenter = 3, + evOutDisplayOption_4x3to16x9_VertCenter = 4, + +} KHWL_OUT_DISPLAY_OPTION_TYPE; + +/// OSD switch +typedef enum +{ + eOsdOn = 0, + eOsdOff = 1, + eOsdFlush = 2, + +} KHWL_OSD_COMMAND_TYPE; + + +/// YUV buffer format +typedef enum +{ + KHWL_YUV_420_UNPACKED = 0, + KHWL_YUV_422_UNPACKED, + +} KHWL_YUV_DATA_FORMAT_TYPE; + +/// YUV setup +typedef struct +{ + WORD wWidth; // Picture width in pixels + WORD wHeight; // Picture height in lines + KHWL_YUV_DATA_FORMAT_TYPE YUVFormat; + +} KHWL_YUV_WRITE_PARAMS_TYPE; + +// DigOV params +typedef struct +{ + DWORD HFreq; + DWORD VFreq; + DWORD VideoWidth; + DWORD VideoHeight; + + DWORD HSyncTotal; + DWORD PreHSync; + DWORD HSyncActive; + DWORD PostHSync; + + DWORD VSyncTotal; + DWORD PreVSync; + DWORD VSyncActive; + DWORD PostVSync; + + DWORD PixelFreq; + DWORD Interlaced; + + BYTE HSyncPolarity; + BYTE VSyncPolarity; + + BYTE BitsPerClock; + KHWL_TV_STANDARD_TYPE TvHdtvStandard; + BYTE Ccir; + BYTE InvertField; + BYTE SyncEnable; + BYTE Vip20; + DWORD SyncGen; +} KHWL_DIG_OV_PARAMS; + + +/// SPU commands (bitfields) +typedef enum +{ + KHWL_SPU_ENABLE = 0x2, + KHWL_SPU_BUTTONS_ENABLE = 0x100, + +} KHWL_SPU_COMMAND_TYPE; + +/// SPU palette entry type +typedef struct +{ + BYTE yuvX; + BYTE yuvY; + BYTE yuvCr; + BYTE yuvCb; + +} KHWL_SPU_PALETTE_ENTRY; + +/// SPU button type +typedef struct +{ + int left; + int top; + int right; + int bottom; + int color; + int contrast; + +} KHWL_SPU_BUTTON_TYPE; + +/// Fixed VOP rate type +typedef struct +{ + DWORD force; // command for set, status for get + DWORD time_incr; + DWORD incr_res; + +} KHWL_FIXED_VOP_RATE_TYPE; + +#ifdef __cplusplus +} +#endif + +#endif // of SP_KHWL_PROP_H diff --git a/src/libsp/sp_memory.h b/src/libsp/sp_memory.h new file mode 100644 index 0000000..7da9097 --- /dev/null +++ b/src/libsp/sp_memory.h @@ -0,0 +1,267 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer support lib memory debugging routines + * \file sp_memory.h + * \author Storm + * \version 0.1 + * \date 14.07.2002 (23.08.2001) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MEMORY_H +#define SP_MEMORY_H + +// The memory remains... (c) M. +#ifdef SP_MEMDEBUG + +#ifndef __cplusplus +#error Include with SP_MEMDEBUG for C++ files only! +#endif + +#include +#include + +/// allocation types +enum +{ + SP_ALLOC_UNKNOWN = 0, + SP_ALLOC_NEW, + SP_ALLOC_NEW_ARRAY, + SP_ALLOC_MALLOC, + SP_ALLOC_CALLOC, + SP_ALLOC_REALLOC, + SP_ALLOC_STRDUP, + SP_ALLOC_DELETE, + SP_ALLOC_DELETE_ARRAY, + SP_ALLOC_FREE +}; + +/// internal stats +struct SPMemoryStats +{ + DWORD totalReportedMemory; + DWORD totalActualMemory; + DWORD peakReportedMemory; + DWORD peakActualMemory; + DWORD accumulatedReportedMemory; + DWORD accumulatedActualMemory; + DWORD accumulatedAllocUnitCount; + DWORD totalAllocUnitCount; + DWORD peakAllocUnitCount; +}; + +/// internal memory manager's struct +struct SPAllocUnit +{ + DWORD actualSize; + DWORD reqSize; + void *actualAddress; + void *reportedAddress; + char sourceFile[40]; + DWORD sourceLine; + DWORD allocationType; + DWORD allocationNumber; + SPAllocUnit *next; + SPAllocUnit *prev; +}; + +const DWORD SP_MM_HASHSIZE = 4096; +const DWORD SP_MM_HASHSIZEM = SP_MM_HASHSIZE - 1; +static const char* SP_MM_LOGFILENAME = "sp_mem.log"; +static const char* SP_MMDUMP_LOGFILENAME = "sp_mem_dump.log"; +static char *allocTypes[] = {"unknown", "new", "new[]", "malloc", + "calloc", "realloc", "strdup", "delete", + "delete[]", "free"}; + +////////////////////////////////////////////////////////////////////////// +/// Memory allocator/tracer +class SPMemoryManager +{ +public: + /// Functions + + /// dtor. we use it to let us know when we're in static deinit. + /// and log all leaks info + ~SPMemoryManager() {LeakReport();} + + /// singleton-related function + static SPMemoryManager& GetHandle() {return *mm;} + + /// basic mem functions + void *Alloc(const char *file, const DWORD line, const DWORD reqSize, + const DWORD allocType); + void *Realloc(const char *file, const DWORD line, const DWORD reqSize, + void* reqAddress, const DWORD reallocType); + void Dealloc(const char *file, const DWORD line, + const DWORD deallocType, void* reqAddress); + char *Strdup(const char *file, const DWORD line, const char *source); + + /// final leak report + void LeakReport(); + /// dump all current allocations + void DumpAllocs(FILE *fp); + void DumpLastAlloc(FILE *fp); + + /// print memory usage statistics + void LogStats(); + /// set file and line number + void SetOwner(const char *file, const DWORD line); + +//!!!!!!!!!!!!!!!! + void TEST_DUMP(); +//!!!!!!!!!!!!!!!! + + // friends + friend void *operator new(size_t reqSize); + friend void *operator new[](size_t reqSize); + friend void operator delete(void *reqAddress); + friend void operator delete[](void *reqAddress); + +protected: + friend int _crt_init(); + friend int _crt_deinit(); + + static SPMemoryManager *mm; // singleton + +private: + /// Variables + char *srcFile; /// source file of call + DWORD srcLine; /// line number in scrFile + + SPAllocUnit *units; /// allocation units array + SPAllocUnit **unitsBuffer; /// list linked to hash + SPAllocUnit *hashTable[SP_MM_HASHSIZE]; /// hash for fast unit search + SPMemoryStats memStats; /// memory stats + + DWORD currentAllocated; /// currently allocated bytes + DWORD unitsBufferSize; /// number of allocated units + DWORD borderSize; /// size of safe border + + DWORD prefixPattern; /// beginning pattern + DWORD postfixPattern; /// ending pattern + DWORD unusedPattern; /// clean memory pattern + DWORD releasedPattern; /// deleted memory pattern + + /// Functions + + /// ctor. cleans logfile + SPMemoryManager(); + + /// create logfile + void BeginLog(); + /// preserve globals + void ClearGlobals(); + /// handle out-of-memory case + void OutOfMemory(); + + /// misc. functions + + /// fill allocated memory with specified pattern + void FillWithPattern(SPAllocUnit *u, DWORD pattern, + DWORD originalSize = 0); + /// internal: search unit in hash + SPAllocUnit *FindAllocUnit(void *reqAddress); + /// returnsname of src file + char *GetSourceName(char *sourceFile); + /// scan memory chunk for unused bytes (based on patterns) + DWORD CalculateUnused(SPAllocUnit *u); + /// validate integrity of memory allocation unit + BOOL ValidateUnit(SPAllocUnit *u); + /// helper function that logs into SP_MM_LOGFILENAME + void Log(char *message, ...); + /// dump unit + void DumpUnit(SPAllocUnit *u); +}; + +// Operators' redefinition +void *operator new(size_t reqSize); +void *operator new[](size_t reqSize); +void operator delete(void *reqAddress); +void operator delete[](void *reqAddress); + +#ifndef __PLACEMENT_NEW_INLINE +#define __PLACEMENT_NEW_INLINE +inline void *__cdecl operator new(size_t, void *_P) + {return (_P); } +#if _MSC_VER >= 1200 +inline void __cdecl operator delete(void *, void *) + {return; } +#endif +#endif + +// Macros +#define new (SPMemoryManager::GetHandle().SetOwner (__FILE__, __LINE__), false) ? NULL : new +#define delete (SPMemoryManager::GetHandle().SetOwner (__FILE__, __LINE__), false) ? NULL : delete +#define SPmalloc(sz) SPMemoryManager::GetHandle().Alloc(__FILE__, __LINE__, sz, SP_ALLOC_MALLOC) +#define SPcalloc(sz) SPMemoryManager::GetHandle().Alloc(__FILE__, __LINE__, sz, SP_ALLOC_CALLOC) +#define SPrealloc(ptr,sz) SPMemoryManager::GetHandle().Realloc(__FILE__, __LINE__, sz, ptr, SP_ALLOC_REALLOC) +#define SPfree(ptr) SPMemoryManager::GetHandle().Dealloc(__FILE__, __LINE__, SP_ALLOC_FREE, ptr) +#define SPstrdup(str) SPMemoryManager::GetHandle().Strdup(__FILE__, __LINE__, str) +#define SPLogMemStats() SPMemoryManager::GetHandle().LogStats(); + +#ifdef TEST_UCLIBC +#ifdef __cplusplus +extern "C" +{ +#endif +void *SPmalloc (size_t __size); +void *SPcalloc (size_t __nmemb); +void *SPrealloc (void *__ptr, size_t __size); +void SPfree (void *__ptr); +char *SPstrdup (const char *__s); +#ifdef __cplusplus +} +#endif +#endif + +#else // SP_MEMDEBUG + +#include + +// just use RTL-fuctions +#define SPmalloc(s) malloc(s) +#define SPcalloc(s) calloc(s, 1) +#define SPrealloc(d, s) realloc(d, s) +#define SPfree(d) free(d) +#define SPstrdup(p) strdup(p) +#define SPLogMemStats() + +#ifdef __cplusplus +#ifndef __PLACEMENT_NEW_INLINE +#define __PLACEMENT_NEW_INLINE +inline void * operator new(size_t, void *_P) + {return (_P); } +#ifdef _MSC_VER +#if _MSC_VER >= 1200 +inline void operator delete(void *, void *) + {return; } +#endif +#endif +#endif +#endif + + +#endif // SP_MEMDEBUG + +// Safe deallocation macros +#define SPSafeFree(ptr) {if (ptr) SPfree(ptr); (ptr) = NULL;} +#define SPSafeDelete(ptr) {if (ptr) delete ptr; (ptr) = NULL;} +#define SPSafeDeleteArray(ptr) {if (ptr) delete [] ptr; (ptr) = NULL;} +// Stack allocation macro +#define SPalloca(ptr) alloca(ptr) + +#endif // SP_MEMORY_H diff --git a/src/libsp/sp_misc.cpp b/src/libsp/sp_misc.cpp new file mode 100644 index 0000000..abf81bb --- /dev/null +++ b/src/libsp/sp_misc.cpp @@ -0,0 +1,95 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - misc. functions source file + * \file sp_misc.cpp + * \author bombur + * \version 0.2 + * \date 10.10.2006 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include "sp_misc.h" + +BOOL module_apply(const char *modname) +{ + static const char *envps[] = { "HOME=/", "TERM=linux", NULL }; + static const char *args1[] = { "busybox", "insmod", NULL, NULL }; + static const char *args2[] = { "minimod", NULL, NULL }; + + args1[2] = modname; + args2[1] = modname; + + int pid = vfork(); + if (pid == 0) + { + if (errno = 0, !(execve ("/bin/busybox", (char * const *)args1, (char * const *)envps)+1)) + if (errno = 0, !(execve ("/bin/minimod.bin", (char * const *)args2, (char * const *)envps)+1)) + _exit(1); + _exit(0); // for safety + } + + int pstatus; + waitpid(pid, &pstatus, 0); + return WIFSIGNALED(pstatus) == 0; +} + +int exec_file(const char *binname, const char **pargs) +{ + static char *envps[] = { NULL }; + static char *args[] = { NULL, NULL }; + static char **ar = NULL; + if (pargs == NULL) + ar = args; + else + ar = (char **)pargs; + if (binname[0] != '/') + ar[0] = (char *)binname; + else + ar[0] = (char *)binname + 1; + + //msg("EXECVE %s\n", binname); + //for (int i = 0; ar[i]; i++) + // msg(" ARG%d = %s\n", i, ar[i]); + + int pid = vfork(); + if (pid == 0) + { + if (errno = 0, !(execve (binname, ar, envps)+1)) + _exit(1); + } + return pid; +} + +// patch for old UCLIBC +#ifdef __UCLIBC_HAS_THREADS__ +extern "C" +{ +pid_t __libc_fork(void) +{ + errno = ENOSYS; + return -1; +} +} +#endif diff --git a/src/libsp/sp_misc.h b/src/libsp/sp_misc.h new file mode 100644 index 0000000..ba3f658 --- /dev/null +++ b/src/libsp/sp_misc.h @@ -0,0 +1,200 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - misc. functions header file + * \file sp_misc.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MISC_H +#define SP_MISC_H + +// some typedefs +#ifndef BOOL +typedef int BOOL; +#endif + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +#ifdef WIN32 +typedef __int64 LONGLONG; +typedef unsigned __int64 ULONGLONG; +#define INT64(d) d##i64 +#define PRINTF_64d "%I64d" +#define SP_INLINE __inline +#define FORCEINLINE __forceinline +#pragma warning(disable: 4710) +#pragma warning(disable: 4996) +#else + +typedef long long LONGLONG; +typedef unsigned long long ULONGLONG; +#define INT64(d) d##LL +#define PRINTF_64d "%lld" +#ifndef __GNUC__ +#define SP_INLINE __inline +#elif __GNUC__ < 3 +#define SP_INLINE inline +#define FORCEINLINE inline +#else +//#define FORCEINLINE inline __attribute__ ((always_inline)) +#define SP_INLINE inline +#define FORCEINLINE inline +#endif +#endif + +#if defined(__GNUC__) +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#define ATTRIBUTE_PACKED __attribute__ ((packed)) +#endif +#endif +#ifdef WIN32 +#define ATTRIBUTE_PACKED +#endif + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + + +#ifndef MIN +#define MIN(a, b) (((a) <= (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) >= (b)) ? (a) : (b)) +#endif + +#ifndef SP_MEMDEBUG_OFF +#ifdef __cplusplus +#ifdef WIN32 +#define SP_MEMDEBUG 1 +#endif +#endif +#endif + +#define SPERRMES(err) + +#include + +#include + +#ifndef __USE_LARGEFILE64 +#define __USE_LARGEFILE64 +#define __LARGE64_FILES +#endif +#include + +#define PAD_EVEN(x) (((x)+1) & ~1) + +#ifdef __cplusplus + +#ifdef _MSC_VER +#pragma warning (disable : 4505) +#pragma warning (disable : 4514) +#endif + +template inline T Max(T a, T b) +{ + return (a >= b) ? a : b; +} +template inline T Min(T a, T b) +{ + return (a <= b) ? a : b; +} +template inline T Abs(T a) +{ + return (a >= (T)0) ? a : (T)-a; +} +template inline void Swap(T& a, T& b) +{ + const T Temp = a; + a = b; + b = Temp; +} + +// 'F' -> 15 +inline int hex2char(int h) +{ + if (h >= '0' && h <= '9') + return h - '0'; + if (h >= 'A' && h <= 'F') + return h - 'A' + 10; + if (h >= 'a' && h <= 'f') + return h - 'a' + 10; + return 0; +} + +#define SafeGetWord(ptr) ((WORD)(((WORD)ptr[1] << 8) | ((WORD)ptr[0]))) +#define SafeGetDword(ptr) ((DWORD)(((DWORD)ptr[3] << 24) | ((DWORD)ptr[2] << 16) | ((DWORD)ptr[1] << 8) | ((DWORD)ptr[0]))) + +#include +#include +#include +#include +#include +#include + +#else +#define Abs abs +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/// Inserts or deletes module to the linux kenrel. +/// Used for external firmware drivers. +BOOL module_apply(const char *modname); + +/// Calls binary file in a separate child process. +/// Used for external programs and players. +/// Returns child pid. +int exec_file(const char *binname, const char **args); + +/// Call GUI update +void gui_update(void); + +#ifdef __cplusplus +} +#endif + + +#endif // of SP_MISC_H diff --git a/src/libsp/sp_module.h b/src/libsp/sp_module.h new file mode 100644 index 0000000..9bfdd19 --- /dev/null +++ b/src/libsp/sp_module.h @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - modules support functions header file + * \file sp_module.h + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_SYSMODULE_H +#define SP_SYSMODULE_H + +#ifdef WIN32 +#define MODULE_FUNC(f) unsigned __int64 f +#else +#define MODULE_FUNC(f) unsigned long f __attribute__ ((__section__ (".text"))) +//#define MODULE_FUNC(f) unsigned long f +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + +/// Load module binary (process ID is returned). +int module_binary_load(char *fname, char *arg); + +/// Unload module binary from memory. +int module_binary_unload(int pid); + +/// Freeze module process +void module_wait(); + +/// Write 'from' address to the 'to' memory location +void module_copy_func(void *from, void *to); + +/// Set function location to NULL +void module_clear_func(void *func); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_SYSMODULE_H diff --git a/src/libsp/sp_mpeg.cpp b/src/libsp/sp_mpeg.cpp new file mode 100644 index 0000000..876de1d --- /dev/null +++ b/src/libsp/sp_mpeg.cpp @@ -0,0 +1,2396 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MPEG player source file. + * \file sp_mpeg.cpp + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +///////////////////////////////////// +//#define MPEG_DEBUG +//#define MPEG_BUF_DEBUG +///////////////////////////////////// + +#ifndef MPEG_DEBUG +static void empty_msg(const char *,...) +{ +} +#define MSG empty_msg +#else +#define MSG msg +#endif + + +#include "settings.h" + +int MPEG_NUM_BUFS[3] = { 8, 0, 0 }; +int MPEG_BUF_SIZE[3] = { 32768, 0, 0 }; +int MPEG_PACKET_LENGTH = 2048; +int MPEG_NUM_PACKETS = 512; + +static MpegPacket *packets = NULL; +static int cur_num_packets = 0; + +static int cur_bufidx[3] = { 7, -1, -1 }; +static BYTE *bufbase[3][256]; +static BYTE bufidx[3][256/*MPEG_NUM_BUFS*/] = { { 0 }, { 0 }, { 0 } }; +static bool buf_created[3] = { false, false, false }; + +static MPEG_VIDEO_FORMAT mpeg_fmt = MPEG_1; + +static int mpeg_rate = 0, mpeg_rate_sum = 0, mpeg_rate_pos = 0, mpeg_nr = 0; +static int old_mpglayer = -1; +const int num_rates = 40; +static int mpeg_rates[num_rates]; + +static int mpeg_width = 0, mpeg_height = 0, mpeg_fps = 0, mpeg_aspect = 0; +static int mpeg_video_muxrate = 0; +static int mpeg_old_width = 0, mpeg_old_height = 0, mpeg_old_fps = 0, mpeg_old_aspect = 0; + +static int mpeg_zoom_hscale = 0, mpeg_zoom_vscale = 0, mpeg_zoom_offsetx = 0, mpeg_zoom_offsety = 0; + +static KHWL_AUDIO_FORMAT_TYPE mpeg_audio_format = eAudioFormat_UNKNOWN; +static int mpeg_audio_numchans = 0, mpeg_audio_bits = 0, mpeg_sample_rate = 0; +static int mpeg_resample_rate = 0; + +static LONGLONG mpeg_wait_last_pts = 0; +static int mpeg_wait_last_depth = 0; +static int mpeg_wait_count_still = 0, mpeg_wait_cnt = 0; +static bool mpeg_show_empty_stack_depth = true; + +int ac3_total_frame_size = 0, ac3_next_total_frame_size = 0; + +/// Use this to support 8-bit PCM +const int mpeg_min_audio_bits = 16; + +static bool mpeg_allow_mpa_parsing = false; +static bool mpeg_show_mpa_parsing = true; + +static bool mpeg_is_mpeg1 = false; +static bool mpeg_format_changed = false, mpeg_audio_format_set = false; + +static LONGLONG delta_pts = 0; +static LONGLONG last_video_pts = 0; +static LONGLONG mpeg_vop_rate = 24000, mpeg_vop_scale = 1000; + +static bool firstchunk = true; +static bool firstdisplayed = false; +static bool use_scr = true; + +static bool mpeg_audioonly = false; +static int mpeg_curaudstream = 0; +static int mpeg_curspustream = 0; +static int mpeg_numaudstream = 0; +static int mpeg_numspustream = 0; +static MPEG_SPEED_TYPE mpeg_speed = MPEG_SPEED_STOP; +static bool mpeg_needrestoreaudio = false; + +static int mpeg_srate = 0; +static KHWL_AUDIO_FORMAT_TYPE mpeg_aformat = eAudioFormat_UNKNOWN; +static int mpeg_nchannels = 2; +static int mpeg_nbitspersample = 24; + +static WORD ac3_frame_sizes[38][3]; + +static BYTE mpeg_seq_start_packet[256]; +static BYTE mpeg_gop_packet[8] = { 0, 0, 1, 0xb8, 0, 8, 0, 0x40 }; +static int mpeg_seq_start_packet_len = 0; +static bool mpeg_need_seq_start_packet = false; +static bool mpeg_was_seq_header = false, mpeg_was_picture = false; +static bool mpeg_parse_video = false; + +static const BYTE picture_start_code = 0x00; +static const BYTE pack_start_code = 0xBA; +static const BYTE system_header_start_code = 0xBB; +static const BYTE sequence_header_start_code = 0xB3; +static const BYTE packet_start_padding_code = 0xBE; +static const BYTE packet_start_pci_dsi_code = 0xBF; +static const BYTE packet_start_video_code1 = 0xE0; +static const BYTE packet_start_video_code2 = 0xE2; // 0xEF +static const BYTE packet_start_audio1_code1 = 0xC0; +static const BYTE packet_start_audio1_code2 = 0xCF; +static const BYTE packet_start_audio2_code1 = 0xD0; +static const BYTE packet_start_audio2_code2 = 0xDF; +static const BYTE packet_start_private1_code = 0xBD; + +static const int MPEG_WRAP_THRESHOLD = 120000; // value taken from xine + +static const WORD ac3_bitrates[19] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, + 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 }; +static const BYTE ac3_channels[8] = { 2, 1, 2, 3, 3, 4, 4, 5 }; +static const WORD ac3_freqs[3] = { 48000, 44100, 32000 }; + +// in frames per msec. +static const int mpeg_fps_table[16] = { 0, 23976, 24000, 25000, + 29970, 30000, 50000, 59940, 60000, + 15000, 5000, 10000, 12000, 15000, 0, 0, }; +#if 0 +static const char *mpeg_fps_strings[16] = { "none", "3/2 pulldown", "film", "PAL", "NTSC", + "drop-frame NTSC", "double-rate PAL", + "double-rate NTSC", "double-rate d.f. NTSC", + "Xing", "Economy-libmpeg3", "Economy-libmpeg3", + "Economy-libmpeg3", "Economy-libmpeg3", "Unknown", "Unknown", }; +#endif + +bool mpeg_novideo = FALSE; +int mpeg_scr = 0; +bool tell_about_encryption = true; + +int fip_audio_format = -1; + +///////////////////////////////////////////////////// +typedef struct MpegPacketFIFO +{ + MpegPacket *packet; + MpegPacketFIFO *next; +} MpegPacketFIFO; + +static const int feed_stack_num = 16; +static MpegPacketFIFO feed_stack[feed_stack_num]; // FIFO +static MpegPacketFIFO *feed_stack_in = feed_stack; // points to the last being added +static MpegPacketFIFO *feed_stack_out = NULL; // points to the first being removed + +///////////////////////////////////////////////////// + +BOOL mpeg_init(MPEG_VIDEO_FORMAT fmt, BOOL audio_only, BOOL mpa_parsing, BOOL need_seq_start_packet) +{ + mpeg_audioonly = audio_only == TRUE; + mpeg_allow_mpa_parsing = mpa_parsing == TRUE; + mpeg_show_mpa_parsing = true; + mpeg_need_seq_start_packet = need_seq_start_packet == TRUE; + + mpeg_setaudiostream(0); + mpeg_setspustream(0); + mpeg_numaudstream = 0; + mpeg_numspustream = 0; + + delta_pts = 0; + last_video_pts = 0; + + mpeg_vop_rate = 24000; + mpeg_vop_scale = 1000; + + khwl_stop(); + + mpeg_fmt = fmt; + + int var = fmt == MPEG_1 || fmt == MPEG_2 ? 0 : (fmt == MPEG_4 ? 1 : 0); //256; + khwl_setproperty(KHWL_DECODER_SET, edecVideoStd, sizeof(int), &var); // mpeg4 + + var = 0; //256; + khwl_setproperty(KHWL_VIDEO_SET, evVOBUReverseSpeed, sizeof(int), &var); // normal speed + + var = 0; //256; + khwl_setproperty(KHWL_VIDEO_SET, evSpeed, sizeof(int), &var); // normal speed + + firstchunk = true; + firstdisplayed = false; + use_scr = true; + + mpeg_reset(); + + mpeg_setpts(0); + + mpeg_rate = 0; + mpeg_rate_sum = 0; + mpeg_rate_pos = 0; + mpeg_nr = 0; + old_mpglayer = -1; + memset(mpeg_rates, 0, num_rates * sizeof(int)); + + mpeg_is_mpeg1 = false; + mpeg_format_changed = false; + mpeg_audio_format_set = false; + fip_audio_format = -1; + + mpeg_srate = 0; + mpeg_aformat = eAudioFormat_UNKNOWN; + mpeg_nchannels = 2; + mpeg_nbitspersample = 24; + + mpeg_needrestoreaudio = true; + mpeg_audio_format = eAudioFormat_UNKNOWN; + mpeg_sample_rate = 0; + mpeg_audio_numchans = 0; mpeg_audio_bits = 0; + mpeg_resample_rate = 0; + + if (!audio_only) + { + KHWL_WINDOW wnd; + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(wnd), &wnd); + //wnd.w = 720; + //wnd.h = 576; + //mpeg_setframesize(wnd.w, wnd.h); + MSG("MPEG: Default frame window: %dx%d\n", wnd.w, wnd.h); + + mpeg_width = 0; mpeg_height = 0; mpeg_fps = 0; mpeg_aspect = 0; + mpeg_video_muxrate = 0; + mpeg_old_width = 0; mpeg_old_height = 0; mpeg_old_fps = 0; mpeg_old_aspect = 0; + + mpeg_zoom_reset(); + } + + for(int i = 0; i < 38; i++) + { + int br = ac3_bitrates[i >> 1]; + ac3_frame_sizes[i][0] = (WORD)(2*br); + ac3_frame_sizes[i][1] = (WORD)((320*br / 147) + (i & 1)); + ac3_frame_sizes[i][2] = (WORD)(3*br); + } + + tell_about_encryption = true; + + for (int k = 0; k < 3; k++) + { + for (int j = 0; j < 256; j++) + bufbase[k][j] = NULL; + } + + mpeg_wait_last_pts = 0; + mpeg_wait_last_depth = 0; + mpeg_wait_count_still = 0; + mpeg_wait_cnt = 0; + mpeg_show_empty_stack_depth = true; + mpeg_seq_start_packet_len = 0; + mpeg_was_seq_header = false; + mpeg_was_picture = false; + + mpeg_parse_video = false; + + for (int j = 0; j < feed_stack_num; j++) + { + feed_stack[j].next = &feed_stack[(j + 1) % feed_stack_num]; + } + feed_stack_in = feed_stack; + feed_stack_out = NULL; + + return TRUE; +} + +BOOL mpeg_deinit() +{ + khwl_stop(); + + if (!mpeg_audioonly) + { + mpeg_zoom_reset(); + khwl_display_clear(); + } + + for (int k = 0; k < 3; k++) + { + if (buf_created[k]) + { + for (int j = 0; j < 256; j++) + SPSafeFree(bufbase[k][j]); + } + } + + if (packets != NULL) + { + SPfree(packets); + packets = NULL; + } + mpeg_speed = MPEG_SPEED_STOP; + return TRUE; +} + +BOOL mpeg_reset() +{ + mpeg_init_packets(); + + cur_bufidx[0] = cur_bufidx[1] = -1; + MPEG_NUM_BUFS[0] = MPEG_NUM_BUFS[1] = 0; + MPEG_BUF_SIZE[0] = MPEG_BUF_SIZE[1] = 0; + + for (int k = 0; k < 3; k++) + { + for (int j = 0; j < 256; j++) + bufbase[k][j] = NULL; + buf_created[k] = false; + } + + mpeg_feed_init(packets, MPEG_NUM_PACKETS); + + return TRUE; +} + +BOOL mpeg_setbuffer_array(MPEG_BUFFER which, BYTE **base, int num_bufs, int buf_size) +{ + MPEG_NUM_BUFS[which] = num_bufs; + MPEG_BUF_SIZE[which] = buf_size; + + for (int i = 0; i < num_bufs; i++) + { + bufbase[which][i] = base[i]; + } + cur_bufidx[which] = num_bufs - 1; + + khwl_blockirq(TRUE); + memset(bufidx[which], 0, MPEG_NUM_BUFS[which]); + khwl_blockirq(FALSE); + + return TRUE; +} + +BOOL mpeg_setbuffer(MPEG_BUFFER which, BYTE *base, int num_bufs, int buf_size) +{ + MPEG_NUM_BUFS[which] = num_bufs; + MPEG_BUF_SIZE[which] = buf_size; + + BYTE *b = base; + for (int i = 0; i < num_bufs; i++) + { + bufbase[which][i] = b; + b += MPEG_BUF_SIZE[which]; + } + cur_bufidx[which] = num_bufs - 1; + + khwl_blockirq(TRUE); + memset(bufidx[which], 0, MPEG_NUM_BUFS[which]); + khwl_blockirq(FALSE); + + return TRUE; +} + + +int mpeg_getbufsize(MPEG_BUFFER which) +{ + return MPEG_BUF_SIZE[which]; +} + +BYTE *mpeg_getbufbase() +{ + return BUF_BASE; +} + +//////////////////////////////////////////////////////// + +BOOL mpeg_setspeed(MPEG_SPEED_TYPE speed) +{ + int val = 256; + + // some currently forbidden combinations: +#if 0 + // 1) no fwd/rev in paused mode + if (((speed & MPEG_SPEED_FWD_MASK) == MPEG_SPEED_FWD_MASK + || (speed & MPEG_SPEED_REV_MASK) == MPEG_SPEED_REV_MASK) + && (mpeg_speed == MPEG_SPEED_PAUSE || mpeg_speed == MPEG_SPEED_STEP)) + return FALSE; +#endif + // 2) slow fwd only at play + if (((speed & MPEG_SPEED_SLOW_FWD_MASK) == MPEG_SPEED_SLOW_FWD_MASK) + && (mpeg_speed != MPEG_SPEED_NORMAL + && (speed & MPEG_SPEED_SLOW_FWD_MASK) != MPEG_SPEED_SLOW_FWD_MASK)) + return FALSE; + // 3) slow rev only at play + if (((speed & MPEG_SPEED_SLOW_REV_MASK) == MPEG_SPEED_SLOW_REV_MASK) + && (mpeg_speed != MPEG_SPEED_NORMAL + && (speed & MPEG_SPEED_SLOW_REV_MASK) != MPEG_SPEED_SLOW_REV_MASK)) + return FALSE; + // 4) pause/step only from play or slow + if ((speed == MPEG_SPEED_PAUSE || speed == MPEG_SPEED_STEP) + && (mpeg_speed != MPEG_SPEED_NORMAL && mpeg_speed != MPEG_SPEED_PAUSE + && ((mpeg_speed & MPEG_SPEED_SLOW_FWD_MASK) != MPEG_SPEED_SLOW_FWD_MASK) + && ((mpeg_speed & MPEG_SPEED_SLOW_REV_MASK) != MPEG_SPEED_SLOW_REV_MASK) + && mpeg_speed != MPEG_SPEED_STEP && !firstchunk)) + return FALSE; + + if (speed == MPEG_SPEED_NORMAL) + { + if (mpeg_speed == MPEG_SPEED_PAUSE || mpeg_speed == MPEG_SPEED_STEP) + { + mpeg_play(); + } + else if ((mpeg_speed & MPEG_SPEED_SLOW_FWD_MASK) == MPEG_SPEED_SLOW_FWD_MASK + || (mpeg_speed & MPEG_SPEED_SLOW_REV_MASK) == MPEG_SPEED_SLOW_REV_MASK) + { + khwl_pause(); + khwl_audioswitch(TRUE); + //mpeg_needrestoreaudio = true; + + val = 256; + khwl_setproperty(KHWL_VIDEO_SET, evSpeed, sizeof(int), &val); + khwl_play(KHWL_PLAY_MODE_NORMAL); + firstchunk = false; + firstdisplayed = true; + } + else // fast fwd/rev + { + ULONGLONG pts; + pts = mpeg_getpts(); + khwl_stop(); + val = 256; + khwl_setproperty(KHWL_VIDEO_SET, evSpeed, sizeof(int), &val); + khwl_setproperty(KHWL_VIDEO_SET, evVOBUReverseSpeed, sizeof(int), &val); + + //khwl_play(KHWL_PLAY_MODE_NORMAL); + //firstchunk = false; + + mpeg_start(); + mpeg_setpts(pts); + } + mpeg_speed = speed; + return TRUE; + } + + if (speed == MPEG_SPEED_PAUSE || speed == MPEG_SPEED_STEP) + { + if (mpeg_speed != MPEG_SPEED_NORMAL + && mpeg_speed != MPEG_SPEED_PAUSE && mpeg_speed != MPEG_SPEED_STEP) + { + ULONGLONG pts; + pts = mpeg_getpts(); + khwl_stop(); + val = 256; + khwl_setproperty(KHWL_VIDEO_SET, evSpeed, sizeof(int), &val); + khwl_setproperty(KHWL_VIDEO_SET, evVOBUReverseSpeed, sizeof(int), &val); + khwl_play(KHWL_PLAY_MODE_NORMAL); + mpeg_setpts(pts); + } + if (speed == MPEG_SPEED_PAUSE) + khwl_pause(); + else + { + khwl_play(KHWL_PLAY_MODE_STEP); + firstchunk = false; + firstdisplayed = true; + } + mpeg_speed = speed; + return TRUE; + } + + // TODO: add FIFO sync... +// if (firstchunk) +// return FALSE; + + + switch (speed) + { + case MPEG_SPEED_REV_4X: + case MPEG_SPEED_FWD_4X: val = 0x400; break; + case MPEG_SPEED_REV_8X: + case MPEG_SPEED_FWD_8X: val = 0x800; break; + case MPEG_SPEED_REV_16X: + case MPEG_SPEED_FWD_16X: val = 0x1000; break; + case MPEG_SPEED_REV_32X: + case MPEG_SPEED_FWD_32X: val = 0x2000; break; + case MPEG_SPEED_REV_48X: + case MPEG_SPEED_FWD_48X: val = 0x3000; break; + + case MPEG_SPEED_SLOW_REV_2X: + case MPEG_SPEED_SLOW_FWD_2X: val = 0x80; break; + case MPEG_SPEED_SLOW_REV_4X: + case MPEG_SPEED_SLOW_FWD_4X: val = 0x40; break; + case MPEG_SPEED_SLOW_REV_8X: + case MPEG_SPEED_SLOW_FWD_8X: val = 0x20; break; + default: + val = 0; + } + + int old_mpeg_speed = mpeg_speed; + mpeg_speed = speed; + + if ((speed & MPEG_SPEED_FWD_MASK) == MPEG_SPEED_FWD_MASK) + { + if ((speed & MPEG_SPEED_SLOW_FWD_MASK) == MPEG_SPEED_SLOW_FWD_MASK) + { + if ((old_mpeg_speed & MPEG_SPEED_SLOW_FWD_MASK) == MPEG_SPEED_SLOW_FWD_MASK + || old_mpeg_speed == MPEG_SPEED_NORMAL) + khwl_pause(); + else + khwl_stop(); + khwl_audioswitch(FALSE); + } + else + khwl_stop(); + khwl_setproperty(KHWL_VIDEO_SET, evSpeed, sizeof(int), &val); + mpeg_play(); + } + else if ((speed & MPEG_SPEED_REV_MASK) == MPEG_SPEED_REV_MASK) + { + if ((speed & MPEG_SPEED_SLOW_REV_MASK) == MPEG_SPEED_SLOW_REV_MASK) + { + if ((old_mpeg_speed & MPEG_SPEED_SLOW_REV_MASK) == MPEG_SPEED_SLOW_REV_MASK + || old_mpeg_speed == MPEG_SPEED_NORMAL) + khwl_pause(); + else + khwl_stop(); + khwl_audioswitch(FALSE); + } + else + khwl_stop(); + khwl_setproperty(KHWL_VIDEO_SET, evVOBUReverseSpeed, sizeof(int), &val); + mpeg_play(); + //mpeg_setpts(pts); + } + + return TRUE; +} + +BOOL mpeg_setframesize(int width, int height, bool noaspect) +{ + if (width <= 0 || height <= 0) + return FALSE; + + mpeg_width = width; + mpeg_height = height; + + khwl_display_clear(); + khwl_set_window_zoom(noaspect ? KHWL_ZOOMMODE_ASPECT : KHWL_ZOOMMODE_DVD); + khwl_set_window(-1, -1, width, height, 100, 100, 0, 0); + + return TRUE; +} + +BOOL mpeg_getframesize(int *width, int *height) +{ + *width = mpeg_width; + *height = mpeg_height; + return TRUE; +} + +int mpeg_get_fps() +{ + return mpeg_fps; +} + +int mpeg_getaspect() +{ + return mpeg_aspect; +} + +void mpeg_start() +{ + firstchunk = true; + MSG("MPEG: MPEG_START\n"); +} + +BOOL mpeg_is_playing() +{ + return !firstchunk; +} + +BOOL mpeg_is_displayed() +{ + return firstdisplayed; +} + +MPEG_VIDEO_FORMAT mpeg_get_video_format() +{ + // MPEG1/2 is detected. + if (mpeg_is_mpeg1) + return MPEG_1; + return mpeg_fmt; +} + +BOOL mpeg_feed(MPEG_FEED_TYPE type) +{ + static MpegPlayStruct *ps[] = { MPEG_VIDEO_STRUCT, MPEG_AUDIO_STRUCT, MPEG_SPU_STRUCT }; + + MpegPlayStruct *feed = ps[type]; + MpegPlayStruct *from = MPEG_PLAY_STRUCT; + MpegPacket *fromin = from->in; + if (fromin == NULL) + return FALSE; + + if (fromin->pts < 0) + fromin->pts = 0; + // save video pts for wrap detection and waiting... + if (fromin->type == 0) + { + if (fromin->flags == 2) + last_video_pts = fromin->pts; + else if (fromin->flags == 0x80) + last_video_pts = INT64(90000) * fromin->pts / mpeg_vop_rate; + + } + +#if 0 +#ifdef WIN32 + if (fromin->type == 0) { + static int siz = 0; + FILE *fp; + fp = fopen("out.m1v", "ab"); + fwrite(fromin->pData, fromin->size, 1, fp); + fclose(fp); + siz += fromin->size; + } + if (fromin->type == 1) { + FILE *fp; + fp = fopen("out.mpa", "ab"); + fwrite(fromin->pData, fromin->size, 1, fp); + fclose(fp); + } +#endif +#endif + + khwl_blockirq(TRUE); + + // advance to the next packet + from->in = from->in->next; + + // one packet will be removed from 'play' FIFO + from->num--; + from->in_cnt++; + // one packet will be added to 'feed' FIFO + feed->num++; + feed->out_cnt++; + + if (fromin->next == NULL) + from->out = NULL; + if (feed->out == NULL) // all data was processed + feed->in = fromin; + else // otherwise - add it to the queue + feed->out->next = fromin; + feed->out = fromin; + + fromin->next = NULL; + + khwl_blockirq(FALSE); + + return TRUE; +} + +BOOL mpeg_feed_push() +{ + MpegPlayStruct *from = MPEG_PLAY_STRUCT; + MpegPacket *fromin = from->in; + + if (fromin == NULL) + return FALSE; + + // check if stack is full + if (feed_stack_in == feed_stack_out) + return FALSE; + + if (feed_stack_out == NULL) + feed_stack_out = feed_stack_in; + + feed_stack_in->packet = fromin; + + feed_stack_in = feed_stack_in->next; + + if (fromin->pts < 0) + fromin->pts = 0; + + khwl_blockirq(TRUE); + + // advance to the next packet + from->in = from->in->next; + + // one packet will be removed from 'play' FIFO + from->num--; + from->in_cnt++; + + if (fromin->next == NULL) + from->out = NULL; + + fromin->next = NULL; + + khwl_blockirq(FALSE); + return TRUE; +} + +BOOL mpeg_feed_pop() +{ + static MpegPlayStruct *ps[] = { MPEG_VIDEO_STRUCT, MPEG_AUDIO_STRUCT, MPEG_SPU_STRUCT }; + + if (feed_stack_out == NULL) + return FALSE; + + MpegPacket *fromin = feed_stack_out->packet; + MpegPlayStruct *feed = ps[fromin->type]; + + feed_stack_out = (feed_stack_out->next != feed_stack_in) ? feed_stack_out->next : NULL; + + // save video pts for wrap detection and waiting... + if (fromin->type == 0) + { + if (fromin->flags == 2) + last_video_pts = fromin->pts; + else if (fromin->flags == 0x80) + last_video_pts = INT64(90000) * fromin->pts / mpeg_vop_rate; + } + + khwl_blockirq(TRUE); + + // one packet will be added to 'feed' FIFO + feed->num++; + feed->out_cnt++; + + if (feed->out == NULL) // all data was processed + feed->in = fromin; + else // otherwise - add it to the queue + feed->out->next = fromin; + feed->out = fromin; + + khwl_blockirq(FALSE); + return TRUE; +} + +BOOL mpeg_feed_isempty() +{ + return (feed_stack_out == NULL) ? TRUE : FALSE; +} + +BOOL mpeg_feed_reset() +{ + while (mpeg_feed_pop()) + ; + feed_stack_in = feed_stack; + feed_stack_out = NULL; + return TRUE; +} + +BOOL mpeg_correct_pts() +{ + MpegPacketFIFO *first = feed_stack_out; + if (first == NULL) + return FALSE; + LONGLONG *p_pts = &first->packet->pts, pts = *p_pts; + + MpegPacketFIFO *cur = first; + while (cur) + { + cur = cur->next; + if (cur == feed_stack_in) + break; + //cur->packet->pts = pts; + BYTE *b = cur->packet->pData; + if (b[0] == 0 && b[1] == 0 && b[2] == 1 && b[3] == 0xb6) + pts += mpeg_vop_scale; + } + *p_pts = pts; + return TRUE; +} + +BOOL mpeg_feed_init(MpegPacket *start, int num) +{ + MPEG_PLAY_STRUCT->in = start; + + khwl_blockirq(TRUE); + + for (int i = 0; i < num-1; i++) + start[i].next = &start[i+1]; + start[num-1].next = NULL; + + MPEG_PLAY_STRUCT->out = &start[num-1]; + + MPEG_PLAY_STRUCT->out_cnt = 0; + MPEG_PLAY_STRUCT->in_cnt = 0; + MPEG_PLAY_STRUCT->num = num; + MPEG_PLAY_STRUCT->reserved = 0; + + MPEG_AUDIO_STRUCT->out_cnt = 0; + MPEG_AUDIO_STRUCT->in_cnt = 0; + MPEG_AUDIO_STRUCT->num = 0; + MPEG_AUDIO_STRUCT->reserved = 0; + MPEG_AUDIO_STRUCT->in = NULL; + MPEG_AUDIO_STRUCT->out = NULL; + + MPEG_VIDEO_STRUCT->out_cnt = 0; + MPEG_VIDEO_STRUCT->in_cnt = 0; + MPEG_VIDEO_STRUCT->num = 0; + MPEG_VIDEO_STRUCT->reserved = 0; + MPEG_VIDEO_STRUCT->in = NULL; + MPEG_VIDEO_STRUCT->out = NULL; + + MPEG_SPU_STRUCT->out_cnt = 0; + MPEG_SPU_STRUCT->in_cnt = 0; + MPEG_SPU_STRUCT->num = 0; + MPEG_SPU_STRUCT->reserved = 0; + MPEG_SPU_STRUCT->in = NULL; + MPEG_SPU_STRUCT->out = NULL; + + khwl_blockirq(FALSE); + + return TRUE; +} + +void mpeg_stop() +{ + mpeg_feed_reset(); + khwl_stop(); + mpeg_speed = MPEG_SPEED_STOP; + +} + +void mpeg_play() +{ + if (mpeg_speed == MPEG_SPEED_NORMAL || + mpeg_speed == MPEG_SPEED_PAUSE || mpeg_speed == MPEG_SPEED_STEP || + mpeg_speed == MPEG_SPEED_STOP) + { + mpeg_speed = MPEG_SPEED_NORMAL; + int val = 256; + khwl_setproperty(KHWL_VIDEO_SET, evSpeed, sizeof(int), &val); + khwl_setproperty(KHWL_VIDEO_SET, evVOBUReverseSpeed, sizeof(int), &val); + khwl_play(KHWL_PLAY_MODE_NORMAL); + MSG("MPEG: KHWL_PLAY NORMAL\n"); + } + if ((mpeg_speed & MPEG_SPEED_FWD_MASK) == MPEG_SPEED_FWD_MASK) + { + if ((mpeg_speed & MPEG_SPEED_SLOW_FWD_MASK) == MPEG_SPEED_SLOW_FWD_MASK) + { + khwl_play(KHWL_PLAY_MODE_NORMAL); + MSG("MPEG: KHWL_PLAY NORMAL\n"); + } else + { + khwl_play(KHWL_PLAY_MODE_IFRAME); + MSG("MPEG: KHWL_PLAY IFRAME\n"); + } + } + else if ((mpeg_speed & MPEG_SPEED_REV_MASK) == MPEG_SPEED_REV_MASK) + { + if ((mpeg_speed & MPEG_SPEED_SLOW_REV_MASK) == MPEG_SPEED_SLOW_REV_MASK) + { + /// \TODO: It seems that mode doesn't work... + khwl_play(KHWL_PLAY_MODE_REV); + MSG("MPEG: KHWL_PLAY REV\n"); + } else + { + khwl_play(KHWL_PLAY_MODE_IFRAME_REV); + MSG("MPEG: KHWL_PLAY IFRAME REV\n"); + } + } + + firstchunk = false; + firstdisplayed = true; + + mpeg_wait_last_pts = 0; + mpeg_wait_last_depth = 0; + mpeg_wait_count_still = 0; + mpeg_wait_cnt = 0; + mpeg_show_empty_stack_depth = true; +} + +void mpeg_play_normal() +{ + int val = 256; + khwl_setproperty(KHWL_VIDEO_SET, evSpeed, sizeof(int), &val); + khwl_play(KHWL_PLAY_MODE_NORMAL); + MSG("MPEG: Play NORMAL\n"); + firstchunk = false; + firstdisplayed = true; +} + +BOOL mpeg_init_packets() +{ + if (packets != NULL && cur_num_packets != MPEG_NUM_PACKETS) + { + SPfree(packets); + packets = NULL; + } + if (packets == NULL) + { + packets = (MpegPacket *)SPmalloc(MPEG_NUM_PACKETS * sizeof(MpegPacket)); + if (packets == NULL) + return FALSE; + } + cur_num_packets = MPEG_NUM_PACKETS; + + khwl_blockirq(TRUE); + for (int i = 0; i < MPEG_NUM_PACKETS; i++) + { + memset(packets + i, 0, sizeof(MpegPacket)); + } + khwl_blockirq(FALSE); + return TRUE; +} + +int mpeg_feed_getstackdepth() +{ + if (mpeg_speed == MPEG_SPEED_STOP) + return 0; + if (firstchunk || mpeg_speed != MPEG_SPEED_NORMAL) + return MPEG_NUM_PACKETS; + return MPEG_NUM_PACKETS - MPEG_PLAY_STRUCT->num; +} + +int mpeg_wait(BOOL onetime) +{ + //khwl_stop(); + if (!onetime) + mpeg_play_normal(); // be sure we play +#if 0 + LONGLONG last_msecs = last_video_pts; + do + { + if (mpeg_feed_getstackdepth() == 0) + return 1; + if (!mpeg_audioonly) + { + LONGLONG msecs = (LONGLONG)mpeg_getpts(); + LONGLONG diff = last_msecs - msecs; + if (diff > 9000) // 100 ms + usleep(MIN((int)(1000 * diff / 90), 10000)); + else + return 1; + } + } while (!onetime); +#endif + + do + { + int depth = mpeg_feed_getstackdepth(); + if (depth == 0) + { + if (mpeg_show_empty_stack_depth) + { + msg("MPEG: * stack depth=0\n"); + mpeg_show_empty_stack_depth = false; + } + //return 1; + } + if (!mpeg_audioonly) + { + KHWL_TIME_TYPE displ; + displ.pts = 0; + displ.timeres = 90000; + khwl_getproperty(KHWL_TIME_SET, etimVideoFrameDisplayedTime, sizeof(displ), &displ); + if (Abs((LONGLONG)displ.pts - mpeg_wait_last_pts) < 9000) + { + //msg("*** dpts = %d\n", (int)displ.pts); + mpeg_wait_count_still++; + } + else + mpeg_wait_count_still = 0; + mpeg_wait_last_pts = displ.pts; + } else + { + if (depth == mpeg_wait_last_depth) + { + //msg("*** depth=%d\n", depth); + mpeg_wait_count_still++; + } + else + mpeg_wait_count_still = 0; + mpeg_wait_last_depth = depth; + } + usleep(100000); + mpeg_wait_cnt++; + if (mpeg_wait_count_still > 15) + { + mpeg_wait_last_pts = 0; + mpeg_wait_last_depth = 0; + mpeg_wait_count_still = 0; + mpeg_wait_cnt = 0; + //mpeg_show_empty_stack_depth = true; + return 1; + } + } while (!onetime); + + return 0; +} + +MpegPacket *mpeg_feed_getlast() +{ + MpegPlayStruct *from = MPEG_PLAY_STRUCT; + + // if playing and buffer is empty... +#ifndef WIN32 +/* + static int empty_cnt = 0; + if (from->num == MPEG_NUM_PACKETS && !mpeg_audioonly && mpeg_fmt == MPEG_2 && !firstchunk && mpeg_speed == MPEG_SPEED_NORMAL) + { + if (++empty_cnt > 0) + { + empty_cnt = 0; + khwl_pause(); + mpeg_start(); + msg("MPEG: Buffer is empty. Resync...\n"); + } + } else + empty_cnt = 0; +*/ +#endif + return from->in; +} + +BYTE *mpeg_getcurbuf(MPEG_BUFFER which) +{ + return bufbase[which][cur_bufidx[which]]; +} + +int mpeg_getpacketlength() +{ + return MPEG_PACKET_LENGTH; +} + +void mpeg_setpts(ULONGLONG estpts) +{ + KHWL_TIME_TYPE stc; + stc.pts = estpts; + stc.timeres = 90000; + khwl_setproperty(KHWL_TIME_SET, etimSystemTimeClock, sizeof(stc), &stc); + last_video_pts = estpts; +} + +ULONGLONG mpeg_getpts() +{ + KHWL_TIME_TYPE stc; + stc.pts = 0; + stc.timeres = 90000; + khwl_getproperty(KHWL_TIME_SET, etimSystemTimeClock, sizeof(stc), &stc); + return stc.pts; +} + +void mpeg_setaudiostream(int id) +{ + mpeg_curaudstream = id; +} + +int mpeg_getaudiostream() +{ + return mpeg_curaudstream; +} + +int mpeg_getaudiostreamsnum() +{ + return mpeg_numaudstream; +} + +void mpeg_setspustream(int id) +{ + mpeg_curspustream = id; +} + +int mpeg_getspustream() +{ + return mpeg_curspustream; +} + +int mpeg_getspustreamsnum() +{ + return mpeg_numspustream; +} + +void mpeg_resetstreams() +{ + mpeg_numaudstream = 0; + mpeg_numspustream = 0; +} + +int mpeg_find_free_blocks(const MPEG_BUFFER which) +{ + const int num_tries = 1; + static int buffull = false; + + int badcnt; + for (badcnt = 0; badcnt < num_tries; badcnt++) + { + cur_bufidx[which] = MPEG_NUM_BUFS[which] - 1; + + khwl_blockirq(TRUE); + while (cur_bufidx[which] >= 0) + { + if (bufidx[which][cur_bufidx[which]] == 0) + break; + cur_bufidx[which]--; + } + khwl_blockirq(FALSE); + + // when paused, just fill the buffer and wait... + // (full buffer is absolutely normal in this mode) + if (mpeg_speed == MPEG_SPEED_PAUSE || + mpeg_speed == MPEG_SPEED_STEP) + break; + + if (firstchunk) + { + if ((MPEG_NUM_BUFS[which] <= 16 && cur_bufidx[which] <= 3) + || (cur_bufidx[which] <= MPEG_NUM_BUFS[which]/2)) + { + mpeg_play(); + usleep(100); + } + } + + // wait for khwl to process packets + // (we need to free the first buffers) + if (cur_bufidx[which] >= 0) + { + buffull = false; + break; + } + + if (!buffull) + { +#ifdef MPEG_BUF_DEBUG + msg("MPEG: .\n"); +#endif + buffull = true; + } + + usleep(50); + //DWORD mask = 0xffffffff; + //khwl_happeningwait(&mask); + } + + if (cur_bufidx[which] < 0) // very bad, but still let's try again later... + { + cur_bufidx[which] = MPEG_NUM_BUFS[which]-1; // no matter which... + return 0; + } + + return 1; +} + +void mpeg_setbufidx(MPEG_BUFFER which, MpegPacket *packet) +{ + khwl_blockirq(TRUE); + bufidx[which][cur_bufidx[which]]++; + khwl_blockirq(FALSE); + + // set bufidx + if (packet != NULL) + packet->bufidx = bufidx[which] + cur_bufidx[which]; +} + +void mpeg_release_packet(MPEG_BUFFER which, MpegPacket *packet) +{ + khwl_blockirq(TRUE); + if (bufidx[which][cur_bufidx[which]] > 0) + bufidx[which][cur_bufidx[which]]--; + khwl_blockirq(FALSE); + + // set bufidx + if (packet != NULL) + packet->bufidx = NULL; +} + +//////////////////////////////////////////////////////////////////////////////////// +// parser + +START_CODE_TYPES mpeg_findpacket(BYTE * &buf, BYTE *base, int &startCounter) +{ + static const BYTE startCode[3] = { 0x00, 0x00, 0x01 }; + + // mini DFA + for (;;) + { + BYTE *bbuf = buf; + if (!mpeg_incParsingBufIndex(buf, base, 1)) + return START_CODE_END; + register BYTE b = *bbuf; + if (startCounter == sizeof(startCode)) + { + switch (b) + { + case pack_start_code: + return START_CODE_PACK; + case system_header_start_code: + return START_CODE_SYSTEM; + case packet_start_pci_dsi_code: + return START_CODE_PCI; + case packet_start_private1_code: + return START_CODE_PRIVATE1; + case packet_start_padding_code: + return START_CODE_PADDING; + case sequence_header_start_code: + buf -= 4; // leave this header to video parser + return START_CODE_MPEG_VIDEO_ELEMENTARY; + } + if (b >= packet_start_video_code1 && b <= packet_start_video_code2) + return START_CODE_MPEG_VIDEO; + if (b >= packet_start_audio1_code1 && b <= packet_start_audio1_code2) + return START_CODE_MPEG_AUDIO1; +#if 0 + if (b >= packet_start_audio2_code1 && b <= packet_start_audio2_code2) + return START_CODE_MPEG_AUDIO2; +#endif + startCounter = 0; + } else + { + if (b == startCode[startCounter]) + startCounter++; + else if (startCounter != 2 || b != 0) // remove this code? + startCounter = 0; + } + } + + // we won't get here + return START_CODE_UNKNOWN; +} + +inline ULONGLONG mpeg_extractTimingStampfromPESheader(BYTE * &buf) +{ + BYTE *tmp = buf; + return ((((tmp[4] >> 1) & 0x7F) + + ((tmp[3] << 7) & 0x7F80) + + ((tmp[2] << 14) & 0x3F8000) + + ((tmp[1] << 22) & 0x3FC00000) + + ((tmp[0] << 29) & INT64(0x1C0000000))) & INT64(0x1FFFFFFFF)); +} + +LONGLONG mpeg_parse_program_stream_pack_header(BYTE * &buf, BYTE * /*base*/) +{ + LONGLONG scr = 0; + mpeg_is_mpeg1 = (buf[0] & 0x40) == 0; + int mux_rate = 0; + if (mpeg_is_mpeg1) + { + scr = (buf[0] & 0x02) << 30; + scr |= (buf[1] & 0xFF) << 22; + scr |= (buf[2] & 0xFE) << 14; + scr |= (buf[3] & 0xFF) << 7; + scr |= (buf[4] & 0xFE) >> 1; + + mux_rate = (buf[5] & 0x7F) << 15; + mux_rate |= (buf[6] & 0x7F) << 7; + mux_rate |= (buf[7] & 0xFE) >> 1; + } else + { + scr = (buf[0] & 0x38) << 27; + scr |= (buf[0] & 0x03) << 28; + scr |= buf[1] << 20; + scr |= (buf[2] & 0xF8) << 12; + scr |= (buf[2] & 0x03) << 13; + scr |= buf[3] << 5; + scr |= (buf[4] & 0xF8) >> 3; +/* + mux_rate = (buf[6] & 0x7f) << 15; + mux_rate |= (buf[7] << 7); + mux_rate |= (buf[8] & 0xfe) >> 1; +*/ + mux_rate = (buf[6]) << 14; + mux_rate |= (buf[7]) << 6; + mux_rate |= (buf[8] & 0xfc) >> 2; + } + + mpeg_rate_sum += mux_rate; + if (mpeg_nr >= num_rates) + { + mpeg_rate_sum -= mpeg_rates[mpeg_rate_pos]; + mpeg_rate = mpeg_rate_sum / num_rates; // here just for optimisation + } + else + { + mpeg_nr++; + mpeg_rate = mpeg_rate_sum / mpeg_nr; + } + mpeg_rates[mpeg_rate_pos] = mux_rate; + + mpeg_rate_pos = (mpeg_rate_pos + 1) % num_rates; + + buf += 8; + return scr; +} + +int mpeg_getrate(BOOL now) +{ + if (now) + { + // at least get video mux.rate + if (mpeg_rate == 0) + return mpeg_video_muxrate * 50; + } + else if (mpeg_nr < num_rates) + return 0; + return mpeg_rate * 50; +} + +////////////////////////////////////////////////////////// + +int mpeg_setaudioparams(MpegAudioPacketInfo *paudio) +{ + if (paudio == NULL) + return -1; + + KHWL_AUDIO_FORMAT_TYPE audioformat = paudio->type; + int numberofchannels, numberofbitspersample, samplerate; + + if (audioformat == eAudioFormat_PCM) + { + samplerate = paudio->samplerate; + numberofchannels = paudio->numberofchannels; + numberofbitspersample = paudio->numberofbitspersample; + } + else if (audioformat == eAudioFormat_MPEG1) + { + samplerate = paudio->samplerate; + numberofchannels = paudio->numberofchannels; + numberofbitspersample = 16; + } + else + { + samplerate = 48000; + numberofchannels = mpeg_nchannels; + numberofbitspersample = mpeg_nbitspersample; + } + + if (samplerate != mpeg_srate || audioformat != mpeg_aformat || + numberofchannels != mpeg_nchannels || + numberofbitspersample != mpeg_nbitspersample || mpeg_needrestoreaudio) + { + if (paudio->fromstream) + mpeg_needrestoreaudio = false; + msg("MPEG: setaudio(format=%d, rate=%d, nc=%d, nbs=%d)\n", audioformat, + samplerate, numberofchannels, numberofbitspersample); + + khwl_audioswitch(FALSE); + mpeg_audio_format = audioformat; + mpeg_sample_rate = samplerate; + mpeg_audio_numchans = numberofchannels; + mpeg_audio_bits = numberofbitspersample; + mpeg_resample_rate = 0; + int newsrate = mpeg_set_sample_rate(samplerate); + if (newsrate != samplerate || mpeg_audio_bits < mpeg_min_audio_bits) + { + if (audioformat == eAudioFormat_PCM && newsrate > 0) + { + mpeg_resample_rate = newsrate; + numberofbitspersample = mpeg_min_audio_bits; + msg("MPEG: Audio PCM resampling from %d/%d to %d/%d.\n", + samplerate, mpeg_audio_bits, + mpeg_resample_rate, mpeg_min_audio_bits); + } else + { + msg_error("MPEG: Samplerate %d not supported by decoder.\n", samplerate); + return -1; + } + } + int var; + if (audioformat == eAudioFormat_PCM) + var = eAudioDigitalOutput_Pcm; + else if (audioformat == eAudioFormat_DTS) + var = eAudioDigitalOutput_Compressed; + else + var = settings_get(SETTING_AUDIOOUT) == 1 ? eAudioDigitalOutput_Compressed : eAudioDigitalOutput_Pcm; + khwl_setproperty(KHWL_AUDIO_SET, eAudioDigitalOutput, sizeof(DWORD), &var); + if (audioformat == eAudioFormat_PCM) + { + khwl_setproperty(KHWL_AUDIO_SET, eAudioNumberOfChannels, sizeof(DWORD), &numberofchannels); + khwl_setproperty(KHWL_AUDIO_SET, eAudioNumberOfBitsPerSample, sizeof(DWORD), &numberofbitspersample); + } + khwl_setproperty(KHWL_AUDIO_SET, eAudioFormat, sizeof(KHWL_AUDIO_FORMAT_TYPE), &audioformat); + khwl_audioswitch(TRUE); + + mpeg_srate = samplerate; + mpeg_aformat = audioformat; + mpeg_nchannels = numberofchannels; + mpeg_nbitspersample = numberofbitspersample; + + mpeg_format_changed = true; + mpeg_audio_format_set = true; + } + + if (paudio->fromstream && audioformat != fip_audio_format) + { + if (audioformat == eAudioFormat_AC3) + { + fip_write_special(FIP_SPECIAL_DOLBY, 1); + fip_write_special(FIP_SPECIAL_DTS, 0); + } + else if (audioformat == eAudioFormat_DTS) + { + fip_write_special(FIP_SPECIAL_DTS, 1); + fip_write_special(FIP_SPECIAL_DOLBY, 0); + } + else + { + fip_write_special(FIP_SPECIAL_DOLBY, 0); + fip_write_special(FIP_SPECIAL_DTS, 0); + } + fip_audio_format = audioformat; + } + + //is_audio_set = TRUE; + return 0; +} + +MpegAudioPacketInfo mpeg_getaudioparams() +{ + MpegAudioPacketInfo apinfo; + apinfo.type = mpeg_audio_format; + apinfo.samplerate = mpeg_sample_rate; + apinfo.numberofchannels = mpeg_audio_numchans; + apinfo.numberofbitspersample = mpeg_audio_bits; + apinfo.fromstream = TRUE; + return apinfo; +} + +int mpeg_set_sample_rate(int samplerate) +{ + int i, *r = khwl_get_samplerates(); + for (i = 0; r[i] > 0; i++) + { + if (r[i] == samplerate) + { + goto found; + } + } + // find 2x upsample rates + for (i = 0; r[i] > 0; i++) + { + if (r[i] == samplerate * 2) + { + samplerate *= 2; + goto found; + } + } + // find 1/2 downsample rates + for (i = 0; r[i] > 0; i++) + { + if (r[i] == samplerate / 2) + { + samplerate /= 2; + goto found; + } + } + // find closest downsample freq. + for (i = 1; r[i] > 0; i++) + { + if (r[i] > samplerate) + { + samplerate = r[i - 1]; + goto found; + } + } +/* + // find closest upsample freq. + for (--i; i > 0; i--) + { + if (r[i - 1] < samplerate) + { + samplerate = r[i]; + goto found; + } + } +*/ + return -1; + +found: + msg("MPEG: * Samplerate = %d.\n", samplerate); + khwl_setproperty(KHWL_AUDIO_SET, eAudioSampleRate, sizeof(DWORD), &samplerate); + return samplerate; +} + +void mpeg_PCM_to_LPCM(BYTE *buf, int len) +{ + if (mpeg_audio_bits == 16) + { + register int i; + if (((DWORD)buf & 3) == 0) // DWORD-aligned version + { + register DWORD *dw = (DWORD *)buf; + int ds = len / 4; + for (i = ds - 1; i >= 0; i--, dw++) + { + *dw = ((*dw & 0x00ff00ff) << 8) | ((*dw & 0xff00ff00) >> 8); + } + + if (len & 3) + { + register WORD *w = (WORD *)dw; + *w = (WORD)(((*w & 0xff) << 8) | (*w >> 8)); + } + } + else if (((DWORD)buf & 1) == 0) // WORD-aligned version + { + register WORD *w = (WORD *)buf; + int ws = len / 2; + for (i = ws - 1; i >= 0; i--, w++) + { + *w = (WORD)(((*w & 0xff) << 8) | (*w >> 8)); + } + } + else + { + register BYTE tmp; + for (i = len - 1; i >= 0; i -= 2, buf += 2) + { + tmp = buf[0]; + buf[0] = buf[1]; + buf[1] = tmp; + } + } + } +} + +BOOL mpeg_is_resample_needed() +{ + return mpeg_resample_rate != 0; +} + +int mpeg_PCM_resample_to_LPCM(BYTE *buf, int len, BYTE *out, int *olen) +{ + if (mpeg_resample_rate == 0 || mpeg_sample_rate == 0) + return -1; + int inlen, outlen; + // 8->16 bits + if (mpeg_audio_bits == 8 && mpeg_audio_bits < mpeg_min_audio_bits) + { + outlen = *olen / 2; + inlen = outlen * mpeg_sample_rate / mpeg_resample_rate; + if (len < inlen) + { + inlen = len; + outlen = len * mpeg_resample_rate / mpeg_sample_rate; + } + + const int FRAC_SHIFT = 10, FRAC_MUL = 1 << FRAC_SHIFT; + int ind = mpeg_sample_rate > mpeg_resample_rate ? + mpeg_sample_rate * FRAC_MUL / mpeg_resample_rate : FRAC_MUL; + int outd = mpeg_resample_rate > mpeg_sample_rate ? + mpeg_resample_rate * FRAC_MUL / mpeg_sample_rate : FRAC_MUL; + register int inpos = 0, outpos = 0, oldoutpos = 0; + for (int i = mpeg_resample_rate > mpeg_sample_rate ? inlen - 1 : outlen - 1; i >= 0; i--) + { + // input contains non-aligned WORDs + register BYTE *b = buf + (inpos >> FRAC_SHIFT); + register WORD *o = (WORD *)out + (outpos >> FRAC_SHIFT); + inpos += ind; + outpos += outd; + WORD w = (WORD)(*b - 0x80); // little-endian -> big-endian + for (int j = (outpos - oldoutpos) >> FRAC_SHIFT; j > 0; j--) + *o++ = w; + oldoutpos = outpos; + } + + *olen = outlen * 2; + } + else if (mpeg_audio_bits == 8) + { + outlen = *olen; + inlen = outlen * mpeg_sample_rate / mpeg_resample_rate; + if (len < inlen) + { + inlen = len; + outlen = len * mpeg_resample_rate / mpeg_sample_rate; + } + + const int FRAC_SHIFT = 10, FRAC_MUL = 1 << FRAC_SHIFT; + int ind = mpeg_sample_rate > mpeg_resample_rate ? + mpeg_sample_rate * FRAC_MUL / mpeg_resample_rate : FRAC_MUL; + int outd = mpeg_resample_rate > mpeg_sample_rate ? + mpeg_resample_rate * FRAC_MUL / mpeg_sample_rate : FRAC_MUL; + register int inpos = 0, outpos = 0, oldoutpos = 0; + for (int i = mpeg_resample_rate > mpeg_sample_rate ? inlen - 1 : outlen - 1; i >= 0; i--) + { + register BYTE *b = buf + (inpos >> FRAC_SHIFT); + register BYTE *o = out + (outpos >> FRAC_SHIFT); + inpos += ind; + outpos += outd; + for (int j = (outpos - oldoutpos) >> FRAC_SHIFT; j > 0; j--) + *o++ = *b; + oldoutpos = outpos; + } + + *olen = outlen; + } + else if (mpeg_audio_bits == 16) + { + outlen = *olen / 2; + inlen = outlen * mpeg_sample_rate / mpeg_resample_rate; + len /= 2; + if (len < inlen) + { + inlen = len; + outlen = len * mpeg_resample_rate / mpeg_sample_rate; + } + + const int FRAC_SHIFT = 10, FRAC_MUL = 1 << FRAC_SHIFT; + int ind = mpeg_sample_rate > mpeg_resample_rate ? + mpeg_sample_rate * FRAC_MUL / mpeg_resample_rate : FRAC_MUL; + int outd = mpeg_resample_rate > mpeg_sample_rate ? + mpeg_resample_rate * FRAC_MUL / mpeg_sample_rate : FRAC_MUL; + register int inpos = 0, outpos = 0, oldoutpos = 0; + for (int i = mpeg_resample_rate > mpeg_sample_rate ? inlen - 1 : outlen - 1; i >= 0; i--) + { + // input contains non-aligned WORDs + register BYTE *b = buf + (inpos >> FRAC_SHIFT) * 2; + register WORD *o = (WORD *)out + (outpos >> FRAC_SHIFT); + inpos += ind; + outpos += outd; + WORD w = (WORD)((*b << 8) | b[1]); // little-endian -> big-endian + for (int j = (outpos - oldoutpos) >> FRAC_SHIFT; j > 0; j--) + *o++ = w; + oldoutpos = outpos; + } + + *olen = outlen * 2; + inlen *= 2; + } + else + return -1; + + return inlen; +} + +WORD mpeg_calc_crc16(BYTE *buf, DWORD bitsize) +{ + DWORD n; + WORD tmpchar, crcmask, tmpi; + crcmask = tmpchar = 0; + WORD crc = 0xffff; // start with inverted value of 0 + + // start with byte 2 of header + for (n = 16; n < bitsize; n++) + { + if (n < 32 || n >= 48) // skip the 2 bytes of the crc itself + { + if (n%8 == 0) + { + crcmask = 1 << 8; + tmpchar = buf[n/8]; + } + crcmask >>= 1; + tmpi = (WORD)(crc & 0x8000); + crc <<= 1; + + if (!tmpi ^ !(tmpchar & crcmask)) + crc ^= 0x8005; + } + } + crc &= 0xffff; // invert the result + return crc; +} + +int mpeg_extractpacket(BYTE * &buf, BYTE *base, MpegPacket *packet, START_CODE_TYPES type, BOOL parse_video) +{ + BYTE *startbuf = buf; + if (packet != NULL) + { + WORD pes_packet_length = 0; + BYTE pes_header_data_length = 0; + BYTE pes_header_data_length0 = 3; + BYTE pts_dts_flags = 0; + BYTE pes_extension_flag = 0; + BOOL encrypted = FALSE; + BOOL need_skip = FALSE; + + if (type == START_CODE_MPEG_VIDEO_ELEMENTARY) + { + pes_packet_length = (WORD)(MPEG_PACKET_LENGTH + 3); + } else + { + pes_packet_length = (WORD)(((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF)); + + if (mpeg_is_mpeg1) + { + if (!mpeg_incParsingBufIndex(buf, base, 2)) + return -1; + //pes_header_data_length = 1; + pes_header_data_length = 1; + pes_header_data_length0 = 0; + if (mpeg_eofBuf(buf, base)) + return -1; + // stuffing + while ((*buf & 0x80) == 0x80) + { + if (!mpeg_incParsingBufIndex(buf, base, 1)) + return -1; + pes_header_data_length0++; + } + if (mpeg_eofBuf(buf, base)) + return -1; + // STD_buffer_scale, STD_buffer_size + if ((*buf & 0xc0) == 0x40) + { + if (!mpeg_incParsingBufIndex(buf, base, 2)) + return -1; + pes_header_data_length0 += 2; + } + if (mpeg_eofBuf(buf, base)) + return -1; + if ((*buf & 0xe0) == 0x20) + { + pes_header_data_length += 4; + if (*buf & 0x10) + pes_header_data_length += 5; + pts_dts_flags = 2; + } + // mpeg-2 pes + else if ((*buf & 0xc0) == 0x80) + { + pts_dts_flags = (BYTE)(((*buf) >> 6) & 0x3); + pes_extension_flag = (BYTE)((*buf++) & 0x1); + pes_header_data_length = (BYTE)(pes_header_data_length + (*buf++)); + } + + // don't use SCR for MPEG-1 (or VCD) stream. + // \TODO: Is it correct? + use_scr = false; + + } else + { + encrypted = (buf[2] & 0x30) != 0; + if (!mpeg_incParsingBufIndex(buf, base, 3)) + return -1; + pes_header_data_length0 = 3; + pts_dts_flags = (BYTE)(((*buf) >> 6) & 0x3); + pes_extension_flag = (BYTE)((*buf++) & 0x1); + pes_header_data_length = *buf++; + if (mpeg_eofBuf(buf, base)) + return -1; + } + switch(pts_dts_flags) + { + case 0x3: + // no dts info for audio packets, but pts is good + case 0x1: + // ??? + case 0x2: + // base timestamp is set by caller + packet->pts += mpeg_extractTimingStampfromPESheader(buf); + packet->flags = 2; + break; + default: + // no timing info + packet->pts = 0; + break; + } + buf += pes_header_data_length; + if (mpeg_eofBuf(buf, base)) + return -1; + } + + if (!use_scr) + packet->scr = 0; + + int pack_length = 0; + MpegAudioPacketInfo plaudioinfo; + bool forbid_setaudio = false; + + switch (type) + { + case START_CODE_MPEG_VIDEO: + case START_CODE_MPEG_VIDEO_ELEMENTARY: + { + mpeg_was_seq_header = false; + mpeg_was_picture = false; + packet->type = 0; + // find frame width & height + BYTE *b = buf; + // header + if (b[0] == 0 && b[1] == 0 && b[2] == 1 && b[3] == 0xb3) + { + int wh = (b[4] << 16) | (b[5] << 8) | b[6]; + mpeg_width = ((wh >> 12) + 15) & ~15; + mpeg_height = ((wh & 0xfff) + 15) & ~15; + mpeg_fps = mpeg_fps_table[b[7] & 0xf]; + + mpeg_aspect = (b[7] >> 4) & 0xf; /* 1 = 1:1, 2 = 4:3, 3 = 16:9 */ + + mpeg_was_seq_header = true; + + if (mpeg_is_mpeg1) + mpeg_video_muxrate = (b[8] << 10) | (b[9] << 2) | (b[10] >> 6); + else + mpeg_video_muxrate = (b[8] << 10) | (b[9] << 2) | (b[10] >> 6); + if (mpeg_video_muxrate == 0x3FFFF) + mpeg_video_muxrate = 0; + + if (mpeg_width != mpeg_old_width || mpeg_height != mpeg_old_height || mpeg_fps != mpeg_old_fps + || mpeg_aspect != mpeg_old_aspect) + { + //mpeg_setframesize(mpeg_width, mpeg_height); + mpeg_old_width = mpeg_width; + mpeg_old_height = mpeg_height; + mpeg_old_fps = mpeg_fps; + mpeg_old_aspect = mpeg_aspect; + } + + b += 4; + b += 7; + if (mpeg_eofBuf(b, base)) + { + buf = b; + return -1; + } + if (b[0] & 2) + b += 64; + if (b[0] & 1) + b += 64; + b += 1; + if (mpeg_eofBuf(b, base)) + { + buf = b; + return -1; + } + if (mpeg_need_seq_start_packet /*&& b - buf >= 12*/) + { + /* + mpeg_seq_start_packet_len = b - buf; + memcpy(mpeg_seq_start_packet, buf, mpeg_seq_start_packet_len); + mpeg_need_seq_start_packet = false; + */ + + if (mpeg_is_mpeg1) + { + mpeg_seq_start_packet_len = 12; + memcpy(mpeg_seq_start_packet, buf, mpeg_seq_start_packet_len); + mpeg_seq_start_packet[8] |= 3; + mpeg_seq_start_packet[9] |= 0xff; + mpeg_seq_start_packet[10] |= 0xff; + mpeg_seq_start_packet[11] &= ~3; + } else + mpeg_seq_start_packet_len = 0; + + memcpy(mpeg_seq_start_packet + mpeg_seq_start_packet_len, mpeg_gop_packet, sizeof(mpeg_gop_packet)); + mpeg_seq_start_packet_len += sizeof(mpeg_gop_packet); + mpeg_need_seq_start_packet = false; + } + + } +#if 1 + else if (parse_video && !mpeg_is_mpeg1) + { + int psize = pes_packet_length - pes_header_data_length - pes_header_data_length0 - pack_length; + for (BYTE *endb = buf + psize; b < endb; b++) + { + if (b[0] == 0 && b[1] == 0 && b[2] == 1 && b[3] == 0) + { + // test picture type + int pic_type = (b[5] >> 3) & 3; + if (pic_type == 1) + { + mpeg_was_picture = true; + pes_packet_length -= (WORD)(b - buf); + buf = b; + break; + } + } + } + } +#endif +#if 0 + while (mpeg_parse_video) + { + // extension + if (b[0] == 0 && b[1] == 0 && b[2] == 1 && b[3] == 0xb5) + { + b += 4; + switch (b[0] & 0xf0) + { + case 0x10: /* sequence extension */ + b += 6; break; + case 0x20: /* sequence display extension */ + b += 1 + 1 + 1 + 1 + 4; break; + case 0x30: /* quant matrix extension */ + { + if (b[0] & 8) + b += 64; + if (b[0] & 4) + b += 64; + break; + } + case 0x70: /* picture display extension for Pan & Scan */ + b += 4; break; + + case 0x80: /* picture coding extension */ + b += 5; break; + } + continue; + } + // GOP + if (b[0] == 0 && b[1] == 0 && b[2] == 1 && b[3] == 0xb8) + { + b += 8; + bool gop_start = true; + } + break; + } +#endif + } + break; + case START_CODE_MPEG_AUDIO1: // MPEG-1 L1, L2, L2.5 + case START_CODE_MPEG_AUDIO2: + { + // this is not good, but it works... + int substreamid = *(startbuf - 1); + packet->type = 1; + mpeg_numaudstream = MAX(mpeg_numaudstream, (substreamid & 0x07)+1); + + if ((substreamid & 0x1f) != mpeg_curaudstream) // skip + { + need_skip = TRUE; + break; + } + + packet->nframeheaders = 0xffff; + packet->firstaccessunitpointer = 0; + forbid_setaudio = true; + +#if 0 + if (type == START_CODE_MPEG_AUDIO2) + { + WORD nfh = ((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF); + packet->nframeheaders = 0xffff; + packet->firstaccessunitpointer = 0; + pack_length = nfh + 6; // ??? + buf += nfh + 6; + } else + pack_length = 1; +#endif + + DWORD header = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + if (mpeg_allow_mpa_parsing && (header & 0xffe00000) == 0xffe00000) + { + plaudioinfo.samplerate = 48000; + plaudioinfo.numberofchannels = 2; + + DWORD mpglayer = 4 - ((header >> 17) & 0x3); + bool has_CRC = ((header >> 16) & 0x1) == 0; + DWORD sample_rate_index = (header >> 10) & 3; + DWORD bitrate_index = (header >> 12) & 0xf; + DWORD emphasis = header & 3; + DWORD mode = (header >> 6) & 3; + DWORD modeext = (header >> 4) & 3; + //msg("MPEG: *FFE* layer=%d, old=%d\n", mpglayer, old_mpglayer); + if (has_CRC && mpglayer == 1) + { + int bound = mode == 1 ? 4 + modeext * 4 : 32; + int pbits = 4* ((mode == 3 ? 1 : 2) * bound + (32 - bound)); + pbits += 4*8 + 16; + //int crcsize = (pbits + 7) / 8; + WORD wCRC16 = mpeg_calc_crc16(buf, pbits); + // read out crc from frame (it follows frame header) + WORD fileCRC = (WORD)((buf[4] << 8) | buf[5]); + has_CRC = wCRC16 != fileCRC; + } + else if (!mpeg_audio_format_set) // give it a chance + has_CRC = false; + + // layer change currently not supported in MPEG-1/2 container... + if ((int)mpglayer == old_mpglayer || old_mpglayer == -1) + { + // mpeg1l3 currently not supported in MPEG-1/2 container... + if (!has_CRC && sample_rate_index < 3 && mpglayer < 3 && bitrate_index < 15 && emphasis != 2) + { + DWORD version_idx = 0; + if (mpglayer == 2) // mpeg1 L2 extensions... + { + if (((header >> 19) & 0x1) == 0) // lsf + version_idx++; + if (((header >> 20) & 0x1) == 0) // mpeg25 + version_idx++; + } + + + const DWORD mpa_freq_tab[] = { 44100, 48000, 32000 }; + plaudioinfo.samplerate = mpa_freq_tab[sample_rate_index] >> version_idx/*(lsf + mpeg25)*/; + plaudioinfo.numberofchannels = (mode == 3/*mono*/) ? 1 : 2; + old_mpglayer = mpglayer; + forbid_setaudio = false; + + if (mpeg_sample_rate != plaudioinfo.samplerate || + mpeg_audio_numchans != plaudioinfo.numberofchannels || + mpeg_show_mpa_parsing) + { + msg("MPEG: * Audio stream format detected: %d kHz %s\n", plaudioinfo.samplerate, + plaudioinfo.numberofchannels == 1 ? "mono" : "stereo"); + mpeg_show_mpa_parsing = false; + } + } + } + } else + if (mpeg_needrestoreaudio) + { + plaudioinfo.samplerate = 48000; + plaudioinfo.numberofchannels = 2; + forbid_setaudio = false; + } + + plaudioinfo.type = eAudioFormat_MPEG1; + break; + } + case START_CODE_PRIVATE1: // DVD private + { + int substreamid = *buf++; + pack_length = 1; + if ((substreamid & 0xE0) == 0x20) // DVD SPU substream + { + int spu_id = (substreamid & 0x1f); + mpeg_numspustream = MAX(mpeg_numspustream, spu_id+1); + packet->type = 2; + + if (spu_id != mpeg_curspustream && mpeg_curspustream != -2) + { + need_skip = TRUE; + break; + } + } + else if (substreamid == 0x70 && (packet->nframeheaders & 0xFC) == 0x00) // SVCD OGT spu... + { + int spu_id = *buf++; + mpeg_numspustream = MAX(mpeg_numspustream, spu_id+1); + packet->type = 2; + + if (spu_id != mpeg_curspustream) + { + need_skip = TRUE; + break; + } + } + else if ((substreamid & 0xFC) == 0x00) // CVD spu... + { + int spu_id = (substreamid & 0x03); + mpeg_numspustream = MAX(mpeg_numspustream, spu_id+1); + packet->type = 2; + + if (spu_id != mpeg_curspustream) + { + need_skip = TRUE; + break; + } + } + else if ((substreamid & 0xF0) == 0x80) // AC3/DTS + { + BYTE nframeheaders = *buf; + packet->nframeheaders = 0; + packet->firstaccessunitpointer = (WORD)(((buf[1] & 0xFF) << 8) + (buf[2] & 0xFF)); + buf += 3; + pack_length += 3; + + mpeg_numaudstream = MAX(mpeg_numaudstream, (substreamid & 0x07)+1); + packet->type = 1; + + if ((substreamid & 0x07) != mpeg_curaudstream) // skip + { + need_skip = TRUE; + break; + } + + if ((substreamid & 0xF8) == 0x88) + { + plaudioinfo.type = eAudioFormat_DTS; + packet->nframeheaders = nframeheaders; + } + else + plaudioinfo.type = eAudioFormat_AC3; + } + else if ((substreamid & 0xf0) == 0xa0) // MPEG-2 lpcm + { + int track = substreamid & 0x07; + + mpeg_numaudstream = MAX(mpeg_numaudstream, track+1); + packet->type = 1; + + if (track != mpeg_curaudstream) // skip + { + buf += 6; + pack_length += 6; + need_skip = TRUE; + break; + } + + packet->nframeheaders = 0xffff;//buf[0]; + packet->firstaccessunitpointer = (WORD)(((buf[1] & 0xFF) << 8) + (buf[2] & 0xFF)); + const DWORD lpcm_freq_tab[] = { 48000, 96000, 44100, 32000 }; + plaudioinfo.samplerate = lpcm_freq_tab[(buf[4] >> 4) & 0x3]; + plaudioinfo.numberofchannels = (buf[4] & 0x7) + 1; + switch ((buf[4] >> 6) & 3) + { + case 1: + plaudioinfo.numberofbitspersample = 20; + break; + case 2: + plaudioinfo.numberofbitspersample = 24; + break; + case 3: + plaudioinfo.numberofbitspersample = 32; + break; + default: // = 0 + plaudioinfo.numberofbitspersample = 16; + } + plaudioinfo.dynrange = buf[5]; + buf += 6; + + pack_length += 6; + plaudioinfo.type = eAudioFormat_PCM; + } + break; + } + default: + ; + } + + packet->pData = buf; + packet->size = pes_packet_length - pes_header_data_length - pes_header_data_length0 - pack_length; + + if (need_skip) + return 0; + + if (encrypted) + { + packet->encryptedinfo = 0x8000 | (105 - pes_header_data_length - pack_length); + if (tell_about_encryption) + { + MSG("MPEG: !!CSS-encrypted!!\n"); + tell_about_encryption = false; + } + } + + mpeg_format_changed = false; + if (packet->type == 1 && !forbid_setaudio) // audio + { + plaudioinfo.fromstream = 1; + mpeg_setaudioparams(&plaudioinfo); + } + + return 1; + } + return -1; +} + +int mpeg_parse_ac3_header(BYTE *buf, int len, int *bitrate, int *sample_rate, int *channels, int *lfe, int *framesize) +{ + if (len < 7) + return -1; + // check sync.word + if (buf[0] != 0xb || buf[1] != 0x77) + return -1; + + int bsid = (buf[5] >> 3) & 0x1f; + + // if E-AC-3, not AC-3 + if (bsid > 10) + return -2; + + int fscod = (buf[4] >> 6) & 3; + if (fscod == 3) + return -3; + + int frmsizecod = buf[4] & 0x3f; + if (frmsizecod > 37) + return -4; + + int frame_size = ac3_frame_sizes[frmsizecod][fscod] * 2; + ac3_total_frame_size = ac3_next_total_frame_size; + ac3_next_total_frame_size += frame_size; + + if (framesize != NULL) + *framesize = frame_size; +/* + msg("frame = %d, bps = %d\n", frame_size, + (ac3_bitrates[frmsizecod >> 1] * 1000) >> halfratecod); +*/ + + // fill in extended info + if (bitrate != NULL) + { + int halfratecod = MAX(bsid, 8) - 8; + + *bitrate = (ac3_bitrates[frmsizecod >> 1] * 1000) >> halfratecod; + if (sample_rate != NULL) + *sample_rate = ac3_freqs[fscod] >> halfratecod; + int acmod = (buf[6] >> 5) & 7; + if (channels != NULL) + *channels = ac3_channels[acmod]; + if (lfe != NULL) + { + int lfe_offs = 4; + if ((acmod & 1) && acmod != 1) + lfe_offs -= 2; + if (acmod & 4) + lfe_offs -= 2; + if (acmod == 2) + lfe_offs -= 2; + + *lfe = (buf[6] >> lfe_offs) & 1; + } + } + + return 0; +} + +BOOL mpeg_audio_format_changed() +{ + return mpeg_format_changed; +} + +LONGLONG mpeg_detect_and_fix_pts_wrap(MpegPacket *packet) +{ + LONGLONG diff = last_video_pts - packet->pts; + LONGLONG scr = packet->scr & (~SPTM_SCR_FLAG); + if (use_scr && Abs(packet->pts - scr) > MPEG_WRAP_THRESHOLD) + { + packet->scr = 0; + use_scr = false; + } + if (last_video_pts != 0 && (int)diff > MPEG_WRAP_THRESHOLD) + { + // fix packet data + packet->pts += diff; + packet->scr = (scr + diff) | SPTM_SCR_FLAG; + + return diff; + } + + return 0; +} + +BOOL mpeg_needs_seq_start_header(MpegPacket **cur_packet) +{ + if (mpeg_was_seq_header) + return TRUE; +#if 1 + // for MPEG2 we can only wait for native seq.headers + if (!mpeg_is_mpeg1 && !mpeg_was_picture) + return FALSE; +#endif + + if (mpeg_seq_start_packet_len < 1) + return FALSE; + + // first, save current packet + MpegPacket tmp_packet; + memcpy((BYTE *)&tmp_packet + 4, (BYTE *)*cur_packet + 4, sizeof(MpegPacket) - 4); + + MpegPacket *packet = NULL; + packet = mpeg_feed_getlast(); + if (packet == NULL) // well, it won't really help + return FALSE; + + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + //packet->type = 0; + //packet->flags = 0; + //packet->bufidx = 0; + packet->pData = mpeg_seq_start_packet; + packet->size = mpeg_seq_start_packet_len; + mpeg_feed(MPEG_FEED_VIDEO); + + *cur_packet = mpeg_feed_getlast(); + if (*cur_packet == NULL) // well, it won't really help + return FALSE; + memcpy((BYTE *)*cur_packet + 4, (BYTE *)&tmp_packet + 4, sizeof(MpegPacket) - 4); + + return TRUE; +} + +void mpeg_set_scale_rate(DWORD *scale, DWORD *rate) +{ + if (*scale < 1) + *scale = 1; + if (*rate < 1) + *rate = 1; + + if (*scale < 1000) + { + int d = 1000 / *scale; + *scale *= d; + *rate *= d; + } + if (*rate >= 64000) + { + *rate = (int)(((LONGLONG)*rate * 1000) / *scale); + *scale = 1000; + } + if (*scale == 1000 && *rate == 23975) + { + *rate = 24000; + *scale = 1001; + } + if (*scale == 1000 && *rate == 23976) + { + *rate = 24000; + *scale = 1001; + } + if (*scale == 1000) + { + if (*rate >= 29992 && *rate <= 30007) + { + if (*rate != 30000) + { + *rate = 30000; + *scale = 1001; + } + } + } + + khwl_setproperty(KHWL_TIME_SET, etimVOPTimeIncrRes, sizeof(int), rate); + khwl_setproperty(KHWL_TIME_SET, etimVideoCTSTimeScale, sizeof(int), rate); + khwl_setproperty(KHWL_TIME_SET, etimAudioCTSTimeScale, sizeof(int), rate); + + KHWL_FIXED_VOP_RATE_TYPE voprate; + voprate.force = 1; + voprate.time_incr = *scale; + voprate.incr_res = *rate; + mpeg_vop_rate = *rate; + mpeg_vop_scale = *scale; + khwl_setproperty(KHWL_DECODER_SET, edecForceFixedVOPRate, sizeof(voprate), &voprate); + + mpeg_fps = (int)(INT64(1000) * mpeg_vop_rate / mpeg_vop_scale); +} + +void mpeg_zoom_scroll() +{ + const int zoom_delta = 25; + const int scroll_delta = 15; + + MSG("MPEG: zoom_scroll(%d,%d %d,%d)\n", mpeg_zoom_hscale, mpeg_zoom_vscale, mpeg_zoom_offsetx, mpeg_zoom_offsety); + + khwl_set_window(mpeg_width, mpeg_height, mpeg_width, mpeg_height, + 100 + zoom_delta*mpeg_zoom_hscale, 100 + zoom_delta*mpeg_zoom_vscale, + mpeg_zoom_offsetx*scroll_delta, mpeg_zoom_offsety*scroll_delta); +} + +BOOL mpeg_zoom_hor(int scale) +{ + mpeg_zoom_hscale = scale; + mpeg_zoom_scroll(); + return TRUE; +} + +BOOL mpeg_zoom_ver(int scale) +{ + mpeg_zoom_vscale = scale; + mpeg_zoom_scroll(); + return TRUE; +} + +BOOL mpeg_scroll(int offsetx, int offsety) +{ + mpeg_zoom_offsetx = offsetx; + mpeg_zoom_offsety = offsety; + mpeg_zoom_scroll(); + return TRUE; +} + +BOOL mpeg_zoom_reset() +{ + if (mpeg_zoom_hscale != 0 || mpeg_zoom_vscale != 0 || mpeg_zoom_offsetx != 0 || mpeg_zoom_offsety != 0) + { + mpeg_zoom_hscale = 0; + mpeg_zoom_vscale = 0; + mpeg_zoom_offsetx = 0; + mpeg_zoom_offsety = 0; + mpeg_zoom_scroll(); + return TRUE; + } + return FALSE; +} diff --git a/src/libsp/sp_mpeg.h b/src/libsp/sp_mpeg.h new file mode 100644 index 0000000..d5eb435 --- /dev/null +++ b/src/libsp/sp_mpeg.h @@ -0,0 +1,456 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MPEG support header file + * \file sp_mpeg.h + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MPEG_H +#define SP_MPEG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPTM_SCR_FLAG INT64(0x8000000000000000) + +#define FOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | \ + ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | \ + ((DWORD)(BYTE)(ch3) << 24)) + +static inline ULONGLONG GET_ULONGLONG(BYTE *b) +{ + ULONGLONG r = (b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24)); + ULONGLONG s = (b[4] | (b[5]<<8) | (b[6]<<16) | (b[7]<<24)); + return ((s << 32) & INT64(0xffffffff00000000U)) | (r & INT64(0xffffffff)); +} + + +static inline DWORD GET_DWORD(BYTE *b) +{ + return (b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24)); +} + +static inline DWORD GET_SYNCSAFE_DWORD(BYTE *b) +{ + return ((b[0] & 0x7f) << 21) | ((b[1] & 0x7f) << 14) + | ((b[2] & 0x7f) << 7) | (b[3] & 0x7f); +} + +static inline WORD GET_WORD(BYTE *b) +{ + return (WORD)(b[0] | (b[1] << 8)); +} + +#ifdef WIN32 +#pragma pack(1) +#endif + +/// MPEG Write packet (not 100% accurate info) +typedef struct MpegPacket_s MpegPacket; +struct MpegPacket_s +{ + MpegPacket *next; + int type; + DWORD flags; + + DWORD reserved[3]; // indexes, counters - not used (i guess) + + BYTE *pData; + DWORD size; + LONGLONG pts; + LONGLONG dts; // not used ? + DWORD encryptedinfo; + WORD nframeheaders; + WORD firstaccessunitpointer; + BYTE *bufidx; + DWORD AudioType; + + LONGLONG scr; + LONGLONG vobu_sptm; +} ATTRIBUTE_PACKED; + +#ifdef WIN32 +#pragma pack() +#endif + +typedef struct +{ + MpegPacket *in; + MpegPacket *out; + int num; + int out_cnt; + int in_cnt; + DWORD reserved; +} MpegPlayStruct; + +typedef struct +{ + KHWL_AUDIO_FORMAT_TYPE type; + int dynrange; + int samplerate; + int numberofchannels; + int numberofbitspersample; + + BOOL fromstream; +} MpegAudioPacketInfo; + +typedef struct +{ + void *payload; + DWORD payload_size; + ULONGLONG pts; +} MpegSpuPacketTnfo; + +extern int MPEG_PACKET_LENGTH; // = 2048 for standard MPEG1/2 +extern int MPEG_NUM_PACKETS; // = 512 (DVD, VCD) or 2048 (others) + +/// Data pointers used by player code +extern MpegPlayStruct *MPEG_PLAY_STRUCT; +extern MpegPlayStruct *MPEG_VIDEO_STRUCT; +extern MpegPlayStruct *MPEG_AUDIO_STRUCT; +extern MpegPlayStruct *MPEG_SPU_STRUCT; + +/// Packet feed types +typedef enum +{ + MPEG_FEED_VIDEO = 0, + MPEG_FEED_AUDIO, + MPEG_FEED_SPU, +} MPEG_FEED_TYPE; + +/// Default buffers storage (use it in mpeg_setbuffer()) +extern BYTE *BUF_BASE; + +/// Source media types +typedef enum +{ + MEDIA_TYPE_UNKNOWN, + MEDIA_TYPE_DVD = 1, + MEDIA_TYPE_VCD = 2, + MEDIA_TYPE_MPEG = 3, + MEDIA_TYPE_AUDIO = 4, + MEDIA_TYPE_VIDEO = 5, + MEDIA_TYPE_CDDA = 6, + //... +} MEDIA_TYPES; + +/// Packet types +typedef enum +{ + START_CODE_UNKNOWN = 0xff, + START_CODE_END = 0xfe, + + START_CODE_PACK = 0, + START_CODE_SYSTEM, + START_CODE_PCI, + START_CODE_PADDING, + START_CODE_MPEG_VIDEO, + START_CODE_MPEG_VIDEO_ELEMENTARY, + START_CODE_MPEG_AUDIO1, + START_CODE_MPEG_AUDIO2, + START_CODE_PRIVATE1, +} START_CODE_TYPES; + +/// Playing speed +typedef enum +{ + MPEG_SPEED_STOP = 0, + MPEG_SPEED_NORMAL = 1, // play/resume + MPEG_SPEED_PAUSE = 2, + MPEG_SPEED_STEP = 3, + + /////////////////////////////////////////////////////// + /// masks: + MPEG_SPEED_FWD_MASK = 0x100, + MPEG_SPEED_REV_MASK = 0x200, + MPEG_SPEED_FAST_FWD_MASK = MPEG_SPEED_FWD_MASK | 0x10, + MPEG_SPEED_FAST_REV_MASK = MPEG_SPEED_REV_MASK | 0x20, + MPEG_SPEED_SLOW_FWD_MASK = MPEG_SPEED_FWD_MASK | 0x40, + MPEG_SPEED_SLOW_REV_MASK = MPEG_SPEED_REV_MASK | 0x80, + /////////////////////////////////////////////////////// + + MPEG_SPEED_FWD_4X = MPEG_SPEED_FAST_FWD_MASK | 1, + MPEG_SPEED_FWD_8X = MPEG_SPEED_FAST_FWD_MASK | 2, + MPEG_SPEED_FWD_16X = MPEG_SPEED_FAST_FWD_MASK | 3, + MPEG_SPEED_FWD_32X = MPEG_SPEED_FAST_FWD_MASK | 4, + MPEG_SPEED_FWD_48X = MPEG_SPEED_FAST_FWD_MASK | 5, + MPEG_SPEED_FWD_MAX = MPEG_SPEED_FAST_FWD_MASK | 6, + + MPEG_SPEED_REV_4X = MPEG_SPEED_FAST_REV_MASK | 1, + MPEG_SPEED_REV_8X = MPEG_SPEED_FAST_REV_MASK | 2, + MPEG_SPEED_REV_16X = MPEG_SPEED_FAST_REV_MASK | 3, + MPEG_SPEED_REV_32X = MPEG_SPEED_FAST_REV_MASK | 4, + MPEG_SPEED_REV_48X = MPEG_SPEED_FAST_REV_MASK | 5, + MPEG_SPEED_REV_MAX = MPEG_SPEED_FAST_REV_MASK | 6, + + MPEG_SPEED_SLOW_FWD_2X = MPEG_SPEED_SLOW_FWD_MASK | 1, // 1/2 + MPEG_SPEED_SLOW_FWD_4X = MPEG_SPEED_SLOW_FWD_MASK | 2, // 1/4 + MPEG_SPEED_SLOW_FWD_8X = MPEG_SPEED_SLOW_FWD_MASK | 3, // 1/8 + + MPEG_SPEED_SLOW_REV_2X = MPEG_SPEED_SLOW_REV_MASK | 1, // 1/2 + MPEG_SPEED_SLOW_REV_4X = MPEG_SPEED_SLOW_REV_MASK | 2, // 1/4 + MPEG_SPEED_SLOW_REV_8X = MPEG_SPEED_SLOW_REV_MASK | 3, // 1/8 + + MPEG_SPEED_UNKNOWN = 0xffffffff, + +} MPEG_SPEED_TYPE; + + +typedef enum +{ + MPEG_BUFFER_1 = 0, + MPEG_BUFFER_2 = 1, + MPEG_BUFFER_3 = 2, +} MPEG_BUFFER; + +typedef enum +{ + MPEG_UNKNOWN = 0, + MPEG_1 = 1, + MPEG_2 = 2, + MPEG_4 = 4, + +} MPEG_VIDEO_FORMAT; + +////////////////////////////////////////////////////// +/// Functions + +/// Initialize MPEG player. +/// If 'videobuf' is set, a separate videobuffer is created. +BOOL mpeg_init(MPEG_VIDEO_FORMAT fmt, BOOL audio_only, BOOL mpa_parsing, BOOL need_seq_start_packet); + +/// Set buffers from 1 big memory chunk +BOOL mpeg_setbuffer(MPEG_BUFFER which, BYTE *base, int num_bufs, int buf_size); +/// Set buffers from array +BOOL mpeg_setbuffer_array(MPEG_BUFFER which, BYTE **base, int num_bufs, int buf_size); + +/// Get main buffer base address +BYTE *mpeg_getbufbase(); + +/// Get buffer size +int mpeg_getbufsize(MPEG_BUFFER which); + +/// Deinitialize MPEG player +BOOL mpeg_deinit(); + +/// Change playing speed +BOOL mpeg_setspeed(MPEG_SPEED_TYPE speed); + +/// Get last frame dimensions +BOOL mpeg_getframesize(int *width, int *height); + +/// Get current frames-per-second, in x1000 format (25000 = 25 fps) +int mpeg_get_fps(); + +/// Get current aspect ratio (1 = 1:1, 2 = 4:3, 3 = 16:9) +int mpeg_getaspect(); + +/// Zoom window horizontally (scale = 0, 1, 2,... for zoom-out, and negative for zoom-in) +BOOL mpeg_zoom_hor(int scale); +/// Zoom window vertically (scale = 0, 1, 2,... for zoom-out, and negative for zoom-in) +BOOL mpeg_zoom_ver(int scale); + +/// Scroll window (offset = ..., -2, -1, 0, 1, 2,...) +/// <0 = window is shifted to the left +/// >0 = window is shifted to the right +BOOL mpeg_scroll(int offsetx, int offsety); + +/// Reset zoom&scroll to defaults +BOOL mpeg_zoom_reset(); + +/// Reset MPEG queues and data before next play +BOOL mpeg_reset(); + +/// Start playing, but wait for +void mpeg_start(); + +/// Feed given struct directly to khwl queue +BOOL mpeg_feed(MPEG_FEED_TYPE type); + +/// Cached feed version - push packet into the stack (up to 16 packets in stack) +BOOL mpeg_feed_push(); + +/// Pop stored packet from the FIFO stack into khwl queue +BOOL mpeg_feed_pop(); + +/// Return TRUE if feed stack is empty +BOOL mpeg_feed_isempty(); + +BOOL mpeg_feed_reset(); + +BOOL mpeg_correct_pts(); + +/// Init queue +BOOL mpeg_feed_init(MpegPacket *start, int num); + +/// Make sure we start playing +void mpeg_play(); + +/// Make sure we stopped playing +void mpeg_stop(); + +/// Start normal play (but don't change speed) - used for 'wait' func. +void mpeg_play_normal(); + +/// Return true if we are actually playing (not just buffering) +BOOL mpeg_is_playing(); + +/// Return true if any frame was displayed +BOOL mpeg_is_displayed(); + +/// Get video format. +MPEG_VIDEO_FORMAT mpeg_get_video_format(); + +/// Reset (clear) packets data +BOOL mpeg_init_packets(); + +/// Return how many packets are in processing +int mpeg_feed_getstackdepth(); + +/// Wait for all packets are processed by decoder. +BOOL mpeg_wait(BOOL onetime); + +/// Get Last packet ready to fill in +MpegPacket *mpeg_feed_getlast(); + +/// Return current buffer's pointer +BYTE *mpeg_getcurbuf(MPEG_BUFFER which); + +int mpeg_getpacketlength(); + +/// Set system PTS value +void mpeg_setpts(ULONGLONG estpts); + +/// Get system PTS value +ULONGLONG mpeg_getpts(); + +/// Get stream rate, in bytes per sec. (or 0 if not ready) +int mpeg_getrate(BOOL now); + +void mpeg_resetstreams(); + +/// Change audio stream +void mpeg_setaudiostream(int id); + +/// Get current audio stream +int mpeg_getaudiostream(); + +/// Get audio streams number +int mpeg_getaudiostreamsnum(); + +/// Change SPU stream +void mpeg_setspustream(int id); + +/// Get current SPU stream +int mpeg_getspustream(); + +/// Get SPU streams number +int mpeg_getspustreamsnum(); + +/// Set current buffer index to free chunk (or wait for it) +int mpeg_find_free_blocks(const MPEG_BUFFER which); + +/// Increase and set buffer index for packet +void mpeg_setbufidx(MPEG_BUFFER which, MpegPacket *packet); + +/// Decrease buffer index and release packet +void mpeg_release_packet(MPEG_BUFFER which, MpegPacket *packet); + +/// Check for the special 'sequence start' header (and send one for MPEG1) +BOOL mpeg_needs_seq_start_header(MpegPacket **cur_packet); + +// sorry, a packet parsing part is for CPP only +#ifdef __cplusplus + +/// Retrieve the next packet and determine its type +START_CODE_TYPES mpeg_findpacket(BYTE * &buf, BYTE *base, int &startCounter); + +/// Get PTS from packet header +ULONGLONG mpeg_extractTimingStampfromPESheader(BYTE * &buf); + +/// Get MPEG type and bitrate, and return SCR +LONGLONG mpeg_parse_program_stream_pack_header(BYTE * &buf, BYTE *base); + +/// Get Dolby AC-3 bitrate and audio params. +int mpeg_parse_ac3_header(BYTE *buf, int len, int *bitrate, int *sample_rate, int *channels, int *lfe, int *framesize); + +/// Set audio params to KHWL +int mpeg_setaudioparams(MpegAudioPacketInfo *paudio); + +/// Get current audio params copy +MpegAudioPacketInfo mpeg_getaudioparams(); + +/// Set audio sample rate and check if it's supported by decoder. +/// Return the closest available rate. +int mpeg_set_sample_rate(int samplerate); + +/// Returns if resampling needed for non-standard audio sample rates. +BOOL mpeg_is_resample_needed(); + +/// Returns TRUE if audio format changed from the parsed MPEG stream +BOOL mpeg_audio_format_changed(); + +/// Fill packet data from raw packet +int mpeg_extractpacket(BYTE * &buf, BYTE *base, MpegPacket *packet, START_CODE_TYPES type, BOOL parse_video); + +/// Detect & fix PTS wrap. Return fix PTS offset for new packets. +LONGLONG mpeg_detect_and_fix_pts_wrap(MpegPacket *packet); + +/// Set MPEG4 VOP rate and scale +void mpeg_set_scale_rate(DWORD *scale, DWORD *rate); + +/// Set video frame size +BOOL mpeg_setframesize(int width, int height, bool noaspect); + +/// Converts little-endian PCM to big-endian LPCM +void mpeg_PCM_to_LPCM(BYTE *buf, int len); + +/// Resample PCM audio and return bytes read. +/// Also converts little-endian PCM to big-endian. +int mpeg_PCM_resample_to_LPCM(BYTE *buf, int len, BYTE *out, int *outlen); + +/// Advance data pointer with bounds check +inline int mpeg_incParsingBufIndex(BYTE * &buf, BYTE *base, DWORD inc) +{ + if (buf + inc <= base + MPEG_PACKET_LENGTH) + { + buf += inc; + return TRUE; + } + return FALSE; +} + +inline bool mpeg_eofBuf(BYTE * buf, BYTE *base) +{ + return (buf >= base + MPEG_PACKET_LENGTH); +} + +WORD mpeg_calc_crc16(BYTE *buf, DWORD bitsize); + +#endif // of #ifdef __cplusplus + +#ifdef __cplusplus +} +#endif + +#endif // of SP_MPEG_H diff --git a/src/libsp/sp_msg.cpp b/src/libsp/sp_msg.cpp new file mode 100644 index 0000000..837511c --- /dev/null +++ b/src/libsp/sp_msg.cpp @@ -0,0 +1,177 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - debug messaging functions impl. + * \file sp_msg.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include +#include + +#ifndef SP_MSG_SIMPLE +#include +#include +#endif + +// 0 = off, 1 = on, 2 = ready_to_clear +MSG_OUTPUT msg_output = MSG_OUTPUT_HIDE; +int msg_filter = MSG_FILTER_ALL; + +static char msgbuf[4096]; + +void msg_set_filter(int f) +{ + msg_filter = f; +} + +int msg_get_filter() +{ + return msg_filter; +} + +void msg_init() +{ +#ifndef SP_MSG_SIMPLE +#ifdef WIN32 + FILE *fp = fopen("sp_log.txt", "wt"); + fclose(fp); +#endif +#endif +} + +void msg_set_output(MSG_OUTPUT o) +{ + if (o == MSG_OUTPUT_SHOW) + { + msg_output = o; +#ifndef SP_MSG_SIMPLE + gui.UpdateEnable(true); + gui.ShowWindow(console, true); +#endif + msg("DEBUG show...\n"); + } + else if (o == MSG_OUTPUT_HIDE) + { + msg_output = o; +#ifndef SP_MSG_SIMPLE + gui.ShowWindow(console, false); +#endif + } + else if (o == MSG_OUTPUT_FREEZE) + { + msg("DEBUG stop...\n"); + msg_output = o; + } +} + +MSG_OUTPUT msg_get_output() +{ + return msg_output; +} + +/////////////////////////////////////////////// + +static void msg_internal(const char *msgbuf) +{ + if (msg_output != MSG_OUTPUT_FREEZE) + { + printf(msgbuf);fflush(stdout); + } + +#ifndef SP_MSG_SIMPLE + if (console != NULL) + console->AddString(msgbuf); + +#ifdef WIN32 + FILE *fp = fopen("sp_log.txt", "at"); + if (fp) { fprintf(fp, msgbuf);fclose(fp); } +#endif +#endif +} + +void msg(const char *text, ...) +{ + if (msg_output != MSG_OUTPUT_FREEZE && (msg_filter & MSG_FILTER_DEBUG) == MSG_FILTER_DEBUG) + { + va_list args; + va_start(args, text); + vsnprintf(msgbuf, 4096, text, args); + va_end(args); + msg_internal(msgbuf); + } +} + +void msg_error(const char *text, ...) +{ + if (msg_output != MSG_OUTPUT_FREEZE && (msg_filter & MSG_FILTER_ERROR) == MSG_FILTER_ERROR) + { + va_list args; + va_start(args, text); + vsnprintf(msgbuf, 4096, text, args); + va_end(args); + msg_internal(msgbuf); + } +} + +void msg_critical(const char *text, ...) +{ + if (/*msg_output != MSG_OUTPUT_FREEZE && */ (msg_filter & MSG_FILTER_CRITICAL) == MSG_FILTER_CRITICAL) + { + va_list args; + va_start(args, text); + vsnprintf(msgbuf, 4096, text, args); + va_end(args); + msg_internal(msgbuf); + } +} + +void msg_sysinfo() +{ +#ifndef SP_MSG_SIMPLE + struct sysinfo si; + sysinfo(&si); + + msg("uptime : %d\n", si.uptime); + msg("totalram : %d\n", si.totalram); + msg("freeram : %d\n", si.freeram); + //msg("sharedram : %d\n", si.sharedram); + //msg("bufferram : %d\n", si.bufferram); + //msg("totalswap : %d\n", si.totalswap); + //msg("freeswap : %d\n", si.freeswap); + msg("procs : %d\n", si.procs); + //msg("totalhigh : %d\n", si.totalhigh); + //msg("freehigh : %d\n", si.freehigh); + //msg("mem_unit : %d\n", si.mem_unit); +#endif +} + +void msg_shell() +{ +#ifndef SP_MSG_SIMPLE + static const char *args[] = { "busybox", "sh", NULL }; + printf("Starting SHELL...\n"); + exec_file("/bin/busybox", args); +#endif +} diff --git a/src/libsp/sp_msg.h b/src/libsp/sp_msg.h new file mode 100644 index 0000000..5acb102 --- /dev/null +++ b/src/libsp/sp_msg.h @@ -0,0 +1,80 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - debug messaging functions header file + * \file sp_msg.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MSG_H +#define SP_MSG_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum MSG_OUTPUT +{ + MSG_OUTPUT_HIDE = 0, + MSG_OUTPUT_SHOW = 1, + MSG_OUTPUT_FREEZE = 2, +} MSG_OUTPUT; + +typedef enum MSG_FILTER +{ + MSG_FILTER_NONE = 0, + + MSG_FILTER_CRITICAL = 1, + MSG_FILTER_ERROR = 2, + MSG_FILTER_DEBUG = 4, + + MSG_FILTER_ALL = MSG_FILTER_CRITICAL | MSG_FILTER_ERROR | MSG_FILTER_DEBUG, +} MSG_FILTER; + +/// Initialize debug/messaging system +void msg_init(void); + +/// Set messages output type (show/hide/disable) +void msg_set_output(MSG_OUTPUT o); +/// Get messages output type +MSG_OUTPUT msg_get_output(void); + +/// Set messages filter (see MSG_FILTER bitfields) +void msg_set_filter(int); +/// Get messages filter +int msg_get_filter(void); + +/// Output debug message to the console. +void msg(const char *text, ...); +/// Output error message to the console. +void msg_error(const char *text, ...); +/// Output critical error message to the console. +void msg_critical(const char *text, ...); + +/// Output system information +void msg_sysinfo(void); + +/// Open TTY shell +void msg_shell(void); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_MSG_H diff --git a/src/libsp/sp_video.cpp b/src/libsp/sp_video.cpp new file mode 100644 index 0000000..a2995e7 --- /dev/null +++ b/src/libsp/sp_video.cpp @@ -0,0 +1,753 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - KHWL misc. video functions source file. + * \file sp_video.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include +#include +#include + +static KHWL_WINDOW dest_wnd; +static KHWL_VIDEOMODE cur_mode = KHWL_VIDEOMODE_NORMAL; +static int cur_aspect = evInAspectRatio_4x3; +static int cur_output = evOutDisplayOption_Normal; +static int frame_left = 0, frame_top = 0, frame_right = 719, frame_bottom = 479; + +static int khwl_wide = 0; + +int khwl_display_clear() +{ + //return ioctl(khwl_handle, KHWL_DISPLAY_CLEAR, 0); + int var = ebiCommand_VideoHwBlackFrame; + return khwl_setproperty(KHWL_BOARDINFO_SET, ebiCommand, sizeof(DWORD), &var); +} + +void khwl_set_max_osd_wnd(int width, int osd_width, int height, int osd_height) +{ + KHWL_WINDOW wnd; + wnd.x = (width * 35) / 720; + + int h = height; + if (h < 0) + h += 31; + wnd.y = h / 32; + + wnd.w = width * osd_width / 720; + + wnd.h = height * osd_height / 480; + + khwl_getproperty(KHWL_OSD_SET, eOsdDestinationWindow, sizeof(wnd), &wnd); + +} + +void khwl_switch_dvi(bool is_on) +{ + KHWL_ADDR_DATA data; + if (is_on) + { + data.Addr = 8; + data.Data = 55; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 9; + data.Data = 13; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 10; + data.Data = 240; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 12; + data.Data = 137; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 13; + data.Data = 0; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 14; + data.Data = 0; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 15; + data.Data = 0; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + } else + { + data.Addr = 8; + data.Data = 6; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 12; + data.Data = 10; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + data.Addr = 51; + data.Data = 1; + khwl_setproperty(KHWL_DVI_TRANSMITTER_SET, edtAccessRegister, sizeof(data), &data); + } +} + +void khwl_setwide(BOOL wide) +{ + khwl_wide = wide ? 1 : 0; +} + +int khwl_setdisplay(KHWL_TV_OUTPUT_FORMAT_TYPE mode, KHWL_TV_STANDARD_TYPE standard) +{ + static KHWL_TV_OUTPUT_FORMAT_TYPE old_mode = evTvOutputFormat_NONE; + static int old_device = evOutputDevice_TV; + static int old_standard = -1; + static BOOL old_wide = TRUE; + + static const KHWL_DIG_OV_PARAMS dig_params[10] = + { + // YUV-480P + { 31469, 5994, 720, 480, 858, 16, 62, 60, 525, 9, 6, 30, 0, 0, 0, 0, + 8, evTvStandard_480P, 0, 0, 1, 1, 0 }, + // YUV-576P + { 31250, 5004, 720, 576, 864, 20, 63, 60, 625, 5, 5, 39, 0, 0, 0, 0, + 8, evTvStandard_576P, 0, 0, 1, 1, 0 }, + // YUV-720P + { 45000, 6000, 1280, 720, 1650, 110, 40, 220, 750, 5, 5, 20, 0, 0, 1, 1, + 24, evTvStandard_720P, 0, 0, 1, 1, 0 }, + // YUV-720P-50 + { 37500, 5000, 1280, 720, 1650, 110, 40, 220, 750, 5, 5, 20, 0, 0, 1, 1, + 24, evTvStandard_720P, 0, 0, 1, 1, 0 }, + // YUV-1080I + { 33716, 5994, 1920, 1080, 2199, 88, 44, 148, 1125, 5, 10, 30, 0, 1, 0, 0, + 24, evTvStandard_1080I, 0, 0, 1, 1, 0 }, + + ///////////////////// + + // DVI-480P + { 31469, 5994, 720, 480, 858, 16, 62, 60, 525, 9, 6, 30, 0, 0, 0, 0, + 24, evTvStandard_480P, 0, 0, 1, 1, 0 }, + // DVI-576P + { 31250, 5004, 720, 576, 864, 20, 63, 60, 625, 5, 5, 39, 0, 0, 0, 0, + 24, evTvStandard_576P, 0, 0, 1, 1, 0 }, + // DVI-1080I + { 33716, 5994, 1920, 1080, 2199, 88, 44, 148, 1125, 5, 10, 30, 0, 1, 1, 1, + 24, evTvStandard_1080I, 0, 0, 1, 1, 0 }, + }; + + int use_dvi = false, use_hd = false; + bool is_on = mode != evTvOutputFormat_OUTPUT_OFF; + + int val; + if (is_on) + { + if (standard != old_standard) + { + KHWL_WINDOW valid_wnd; + const KHWL_DIG_OV_PARAMS *dig = NULL; + valid_wnd.x = valid_wnd.y = 0; + + // set params + switch (standard) + { + case evTvStandard_480P: + dig = &dig_params[0]; + break; + case evTvStandard_576P: + dig = &dig_params[1]; + break; + case evTvStandard_720P: + dig = &dig_params[2]; + break; + case evTvStandard_720P50: + dig = &dig_params[3]; + break; + case evTvStandard_1080I: + dig = &dig_params[4]; + break; + case evTvStandard_NTSC: + valid_wnd.w = 720; + valid_wnd.h = 480; + break; + default: + case evTvStandard_PAL: + valid_wnd.w = 720; + valid_wnd.h = 576; + break; + + // TODO: add HDTV modes... + } + + if (dig != NULL) + { + valid_wnd.w = dig->VideoWidth; + valid_wnd.h = dig->VideoHeight; + + khwl_setproperty(KHWL_VIDEO_SET, evDigOvOnlyParams, sizeof(KHWL_DIG_OV_PARAMS), (void *)dig); + + old_mode = evTvOutputFormat_NONE; + old_standard = -1; + standard = dig->TvHdtvStandard; + + if (mode == evTvOutputFormat_COMPONENT_YUV) + use_hd = true; + else if (mode == evTvOutputFormat_DVI) + use_dvi = true; + } else + { + val = standard; + khwl_setproperty(KHWL_VIDEO_SET, evTvStandard, sizeof(DWORD), &val); + if (old_standard != evTvStandard_NTSC && old_standard != evTvStandard_PAL) + old_mode = evTvOutputFormat_NONE; + old_standard = standard; + } + + khwl_setproperty(KHWL_VIDEO_SET, evValidWindow, sizeof(valid_wnd), &valid_wnd); + } + + if (mode != old_mode) + { + val = (mode == evTvOutputFormat_DVI) ? evTvOutputFormat_COMPONENT_RGB_SCART : mode; + khwl_setproperty(KHWL_VIDEO_SET, evTvOutputFormat, sizeof(DWORD), &val); + + val = use_dvi ? evOutputDevice_HDTV : (use_hd ? evOutputDevice_DigOvOnly : evOutputDevice_TV); + if (old_device != val) + { + khwl_setproperty(KHWL_VIDEO_SET, evOutputDevice, sizeof(DWORD), &val); + old_device = val; + } + + KHWL_ADDR_DATA data; + + // composite/component? + data.Addr = 3; + data.Data = (mode == evTvOutputFormat_COMPOSITE) ? 1 : 0; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + + // DVI + data.Addr = 5; + data.Data = use_dvi ? 0 : 1; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + + // RCA-output? + data.Addr = 6; + data.Data = (mode != evTvOutputFormat_COMPONENT_RGB_SCART) ? 1 : 0; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + + khwl_switch_dvi(use_hd || use_dvi); + } + + // Wide + if (khwl_wide != old_wide) + { + KHWL_ADDR_DATA data; + data.Addr = 7; + data.Data = khwl_wide ? 1 : 0; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + old_wide = khwl_wide; + } + + // init as normal/wide + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(dest_wnd), &dest_wnd); + + int osd_width, osd_height; + khwl_get_osd_size(&osd_width, &osd_height); + khwl_set_max_osd_wnd(dest_wnd.w, osd_width, dest_wnd.h, osd_height); + + khwl_restoreparams(); + + khwl_set_window(-1, -1, -1, -1, 100, 100, 0, 0); + + } else + { + if (mode != old_mode) + { + val = mode; + khwl_setproperty(KHWL_VIDEO_SET, evTvOutputFormat, sizeof(DWORD), &val); + } + + if (old_mode == evTvOutputFormat_DVI) + khwl_switch_dvi(false); + + KHWL_ADDR_DATA data; + /* + data.Addr = 5; + data.Data = 1; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + */ + + data.Addr = 6; + data.Data = 1; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(data), &data); + } + + old_mode = mode; + + return TRUE; +} + +void khwl_transform(KHWL_VIDEOMODE mode, int *x, int *y) +{ + switch (mode) + { + case KHWL_VIDEOMODE_PANSCAN: + *x = 4 * (*x) / 3; + break; + case KHWL_VIDEOMODE_LETTERBOX: + *y = 3 * (*y) / 4; + break; + case KHWL_VIDEOMODE_HCENTER: + *x = 3 * (*x) / 4; + break; + case KHWL_VIDEOMODE_VCENTER: + *y = 4 * (*y) / 3; + break; + default: + ; + } +} + +void khwl_inversetransform(KHWL_VIDEOMODE mode, int *x, int *y) +{ + switch (mode) + { + case KHWL_VIDEOMODE_PANSCAN: + *x = 3 * (*x) / 4; + break; + case KHWL_VIDEOMODE_LETTERBOX: + *y = 4 * (*y) / 3; + break; + case KHWL_VIDEOMODE_HCENTER: + *x = 4 * (*x) / 3; + break; + case KHWL_VIDEOMODE_VCENTER: + *y = 3 * (*y) / 4; + break; + default: + ; + } +} + +void khwl_getscreensize(int *width, int *height) +{ + KHWL_WINDOW wnd; + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(wnd), &wnd); + *width = wnd.w; + *height = wnd.h; +} + +void khwl_transformcoord(KHWL_VIDEOMODE mode, int *x, int *y, int /*width*/, int /*height*/) +{ + // correction for NTSC/PAL +/* + int sw, sh; + khwl_getscreensize(&sw, &sh); + if (width != 0) + *x = *x * sw / width; + if (height != 0) + *y = *y * sh / height; +*/ + // correction for aspect ratio + khwl_transform(mode, x, y); + // correction for black bands (letterbox & hcenter) + *x += dest_wnd.x; + *y += dest_wnd.y; +} + +void khwl_getdestwindow(KHWL_VIDEOMODE mode, KHWL_WINDOW *wnd) +{ + int screenWidth, screenHeight; + khwl_getscreensize(&screenWidth, &screenHeight); + + int displayWidth = screenWidth; + int displayHeight = screenHeight; + + khwl_transform(mode, &displayWidth, &displayHeight); + + wnd->x = (screenWidth - displayWidth) / 2; + wnd->y = (screenHeight - displayHeight) / 2; + wnd->w = displayWidth; + wnd->h = displayHeight; + + //khwl_setproperty(KHWL_VIDEO_SET, evDestinationWindow, sizeof(*wnd), wnd); +} + + +void khwl_setvideomode(KHWL_VIDEOMODE mode, BOOL set_hw) +{ + KHWL_IN_ASPECT_RATIO_TYPE aspect = evInAspectRatio_4x3; + KHWL_OUT_DISPLAY_OPTION_TYPE output = evOutDisplayOption_Normal; + int panscan = 0; + KHWL_ADDR_DATA pio7 = { 7, 0 }; + pio7.Data = 0; + + switch (mode) + { + case KHWL_VIDEOMODE_NONE: + aspect = evInAspectRatio_none; + output = evOutDisplayOption_Normal; + break; + case KHWL_VIDEOMODE_NORMAL: + aspect = evInAspectRatio_4x3; + output = evOutDisplayOption_Normal; + break; + case KHWL_VIDEOMODE_VCENTER: + aspect = evInAspectRatio_4x3; + output = evOutDisplayOption_4x3to16x9_VertCenter; + khwl_wide = 1; + break; + case KHWL_VIDEOMODE_HCENTER: + aspect = evInAspectRatio_4x3; + output = evOutDisplayOption_4x3to16x9_HorzCenter; + khwl_wide = 1; + break; + case KHWL_VIDEOMODE_WIDE: + aspect = evInAspectRatio_16x9; + output = evOutDisplayOption_Normal; + khwl_wide = 1; + break; + case KHWL_VIDEOMODE_PANSCAN: + aspect = evInAspectRatio_16x9; + output = evOutDisplayOption_16x9to4x3_PanScan; + panscan = 1; + break; + case KHWL_VIDEOMODE_LETTERBOX: + aspect = evInAspectRatio_16x9; + output = evOutDisplayOption_16x9to4x3_LetterBox; + break; + } + + if (set_hw && (mode != cur_mode || aspect != cur_aspect || output != cur_output)) + { + cur_mode = mode; + cur_aspect = aspect; + cur_output = output; + + khwl_set_window(-1, -1, -1, -1, 100, 100, 0, 0); +/* + //khwl_getdestwindow(mode, &dest_wnd); + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(dest_wnd), &dest_wnd); + + KHWL_IN_ASPECT_RATIO_TYPE a = (aspect == evInAspectRatio_none) ? evInAspectRatio_4x3 : aspect; + khwl_setproperty(KHWL_VIDEO_SET, evInAspectRatio, sizeof(a), &a); + + khwl_setproperty(KHWL_VIDEO_SET, evOutDisplayOption, sizeof(output), &output); + + khwl_setproperty(KHWL_VIDEO_SET, evDestinationWindow, sizeof(dest_wnd), &dest_wnd); + + khwl_setproperty(KHWL_VIDEO_SET, evForcePanScanDefaultSize, sizeof(panscan), &panscan); +*/ + pio7.Data = khwl_wide ? 1 : 0; + khwl_setproperty(KHWL_BOARDINFO_SET, ebiPIOAccess, sizeof(pio7), &pio7); + } + cur_mode = mode; + cur_aspect = aspect; + cur_output = output; +} + +static int old_sw = 720, old_sh = 480; +static KHWL_ZOOMMODE zoom_mode = KHWL_ZOOMMODE_YUV; + +void khwl_set_window_source(int src_width, int src_height) +{ + old_sw = src_width; + old_sh = src_height; +} + +void khwl_set_window_zoom(KHWL_ZOOMMODE zm) +{ + zoom_mode = zm; +} + +void khwl_set_window_frame(int fr_left, int fr_top, int fr_right, int fr_bottom) +{ + frame_left = MIN(MAX(fr_left, 0), 719) & 0x3ffe; + frame_top = MIN(MAX(fr_top, 0), 479) & 0x3ffe; + frame_right = MIN(MAX(fr_right, 0), 719); + frame_bottom = MIN(MAX(fr_bottom, 0), 479); + + if ((frame_right - frame_left + 1) & 1) + frame_right--; + if ((frame_bottom - frame_top + 1) & 1) + frame_bottom--; + + frame_right = MAX(frame_left, frame_right); + frame_bottom = MAX(frame_top, frame_bottom); +} + +void khwl_get_window_frame(int *fr_left, int *fr_top, int *fr_right, int *fr_bottom) +{ + *fr_left = frame_left; + *fr_top = frame_top; + *fr_right = frame_right; + *fr_bottom = frame_bottom; +} + +void khwl_apply_aspect(KHWL_WINDOW *dstwnd, int maxw, int maxh, int src_width, int src_height, int offsx, int offsy) +{ + int dstw = dstwnd->w; + int dsth = dstwnd->h; + + int which = -1; + + // process special DVD modes first + if (cur_output == evOutDisplayOption_4x3to16x9_VertCenter) + { + src_width = 4; + src_height = 3; + which = 3; + } + else if (cur_output == evOutDisplayOption_4x3to16x9_HorzCenter) + { + src_width = 4; + src_height = 3; + which = 2; + } + else if (cur_output == evOutDisplayOption_16x9to4x3_PanScan) + { + src_width = 16; + src_height = 9; + which = 0; + } + else if (cur_output == evOutDisplayOption_16x9to4x3_LetterBox) + { + src_width = 16; + src_height = 9; + which = 1; + } + else if (cur_aspect == evInAspectRatio_4x3) + { + if (3 * src_width < 4 * src_height) + which = 0; + else + which = 1; + } + else if (cur_aspect == evInAspectRatio_16x9) // Wide + { + if (9 * src_width < 16 * src_height) + which = 2; + else + which = 3; + } + + switch (which) + { + case 0: + dstw = 3 * dstw * src_width / (4 * src_height); + dsth = dsth; + break; + case 1: + dstw = dstw; + dsth = 4 * dsth * src_height / (3 * src_width); + break; + case 2: + dstw = 9 * dstw * src_width / (16 * src_height); + dsth = dsth; + break; + case 3: + dstw = dstw; + dsth = 16 * dsth * src_height / (9 * src_width); + break; + default: + ; + } + + dstwnd->x = (maxw - dstw)/2; + dstwnd->y = (maxh - dsth)/2; + + int x = Abs(dstwnd->x), y = Abs(dstwnd->y); + dstwnd->x += MAX(MIN(offsx, x), -x); + dstwnd->y += MAX(MIN(offsy, y), -y); + + dstwnd->w = dstw; + dstwnd->h = dsth; + +} + +void khwl_set_window(int src_width, int src_height, int frame_width, int frame_height, int hscale, int vscale, int offsx, int offsy) +{ + KHWL_WINDOW wnd, dstwnd; + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(dstwnd), &dstwnd); + + KHWL_WINDOW curdst, maxdst; + khwl_getproperty(KHWL_VIDEO_SET, evDestinationWindow, sizeof(curdst), &curdst); + khwl_getproperty(KHWL_VIDEO_SET, evMaxDisplayWindow, sizeof(maxdst), &maxdst); + + if (src_width < 0) + src_width = old_sw; + if (src_height < 0) + src_height = old_sh; + + int frame_x = 0, frame_y = 0; + if (frame_width > 0 && frame_height > 0) + { + wnd.x = 0; + wnd.y = 0; + wnd.w = frame_width; + wnd.h = frame_height; + khwl_setproperty(KHWL_VIDEO_SET, evZoomedWindow, sizeof(wnd), &wnd); + wnd.x = 0; + wnd.y = 0; + wnd.w = (frame_width + 15) & ~15; + wnd.h = (frame_height + 15) & ~15; + khwl_setproperty(KHWL_VIDEO_SET, evSourceWindow, sizeof(wnd), &wnd); + + KHWL_YUV_WRITE_PARAMS_TYPE yuvparams; + yuvparams.wWidth = (WORD)wnd.w; + yuvparams.wHeight = (WORD)wnd.h; + yuvparams.YUVFormat = KHWL_YUV_420_UNPACKED; + khwl_setproperty(KHWL_VIDEO_SET, evYUVWriteParams, sizeof(yuvparams), &yuvparams); + } else + { + khwl_getproperty(KHWL_VIDEO_SET, evSourceWindow, sizeof(wnd), &wnd); + frame_x = wnd.x; + frame_y = wnd.y; + frame_width = wnd.w; + frame_height = wnd.h; + } + + if (src_width < 0) + src_width = frame_width; + if (src_height < 0) + src_height = frame_height; + + int sw, sh, sx, sy; + + sx = src_width / 2; + sy = src_height / 2; + sw = src_width; + sh = src_height; + + if (hscale < 10) + hscale = 10; + if (hscale > 400) + hscale = 400; + if (vscale < 10) + vscale = 10; + if (vscale > 400) + vscale = 400; + +#if 0 + msg("* zmode=%d, hscale=%d, vscale=%d, src=(%dx%d).\n", zoom_mode, hscale, vscale, src_width, src_height); +#endif + + if (zoom_mode == KHWL_ZOOMMODE_YUV) + { + if (hscale < 100) + dstwnd.w = dstwnd.w * hscale / 100; + else + sw = src_width * 100 / hscale; + if (vscale < 100) + dstwnd.h = dstwnd.h * vscale / 100; + else + sh = src_height * 100 / vscale; + + khwl_apply_aspect(&dstwnd, maxdst.w, maxdst.h, src_width, src_height, 0, 0); + + wnd.x = sx - sw/2; + wnd.y = sy - sh/2; + wnd.w = sw; + wnd.h = sh; + wnd.x += MAX(MIN(offsx, wnd.x), -wnd.x); + wnd.y += MAX(MIN(offsy, wnd.y), -wnd.y); + wnd.x += (frame_width - src_width)/2; + wnd.y += (frame_height - src_height)/2; + khwl_setproperty(KHWL_VIDEO_SET, evZoomedWindow, sizeof(wnd), &wnd); + + khwl_setproperty(KHWL_VIDEO_SET, evDestinationWindow, sizeof(dstwnd), &dstwnd); + } + else if (zoom_mode == KHWL_ZOOMMODE_ASPECT || zoom_mode == KHWL_ZOOMMODE_DVD) + { +#if 0 + if (zoom_mode == KHWL_ZOOMMODE_DVD && vscale == 100 && hscale == 100) + khwl_setvideomode(cur_mode, TRUE); + else +#endif + { + if (hscale == vscale) // constrain proportions... + { + dstwnd.w = MAX(dstwnd.w * hscale / 100, 64); + dstwnd.h = dstwnd.h * dstwnd.w / maxdst.w; + } else + { + dstwnd.w = MAX(dstwnd.w * hscale / 100, 64); + dstwnd.h = MAX(dstwnd.h * vscale / 100, 64); + } + + // fix aspect ratio for anamorphic modes only + int old_asp = cur_aspect; + int old_out = cur_output; + if (zoom_mode == KHWL_ZOOMMODE_DVD && (cur_mode == KHWL_VIDEOMODE_NORMAL || cur_mode == KHWL_VIDEOMODE_WIDE)) + cur_aspect = evInAspectRatio_none; + + khwl_apply_aspect(&dstwnd, maxdst.w, maxdst.h, src_width, src_height, offsx, offsy); + + cur_aspect = evInAspectRatio_4x3; + khwl_setproperty(KHWL_VIDEO_SET, evInAspectRatio, sizeof(cur_aspect), &cur_aspect); + + cur_output = evOutDisplayOption_Normal; + khwl_setproperty(KHWL_VIDEO_SET, evOutDisplayOption, sizeof(cur_output), &cur_output); + + khwl_setproperty(KHWL_VIDEO_SET, evDestinationWindow, sizeof(dstwnd), &dstwnd); + + int panscan = 0; + khwl_setproperty(KHWL_VIDEO_SET, evForcePanScanDefaultSize, sizeof(panscan), &panscan); + + cur_aspect = old_asp; + cur_output = old_out; + + //cur_mode = KHWL_VIDEOMODE_NONE; + } + } +#if 0 + msg("zoom(%d,%d)=%d,%d %dx%d\n", hscale, vscale, wnd.x, wnd.y, wnd.w, wnd.h); + msg(" frm=%d,%d %dx%d, src=%dx%d,\n", frame_x, frame_y, frame_width, frame_height, src_width, src_height); + + msg("* olddst=%d,%d %dx%d\n", curdst.x, curdst.y, curdst.w, curdst.h); + msg("* maxdst=%d,%d %dx%d\n", maxdst.x, maxdst.y, maxdst.w, maxdst.h); + msg("* dst=%d,%d %dx%d\n", dstwnd.x, dstwnd.y, dstwnd.w, dstwnd.h); +#endif + old_sw = src_width; + old_sh = src_height; +} + +void khwl_set_display_settings(int brightness, int contrast, int saturation) +{ + if (brightness != -1) + { + brightness = MIN(MAX(brightness, 0), 1000); + khwl_setproperty(KHWL_VIDEO_SET, evBrightness, sizeof(brightness), &brightness); + } + if (contrast != -1) + { + contrast = MIN(MAX(contrast, 0), 1000); + khwl_setproperty(KHWL_VIDEO_SET, evContrast, sizeof(contrast), &contrast); + } + if (saturation != -1) + { + saturation = MIN(MAX(saturation, 0), 1000); + khwl_setproperty(KHWL_VIDEO_SET, evSaturation, sizeof(saturation), &saturation); + } +} + +void khwl_get_display_settings(int *brightness, int *contrast, int *saturation) +{ + if (brightness != NULL) + khwl_getproperty(KHWL_VIDEO_SET, evBrightness, sizeof(brightness), brightness); + if (contrast != NULL) + khwl_getproperty(KHWL_VIDEO_SET, evContrast, sizeof(contrast), contrast); + if (saturation != NULL) + khwl_getproperty(KHWL_VIDEO_SET, evSaturation, sizeof(saturation), saturation); +} diff --git a/src/libsp/sp_video.h b/src/libsp/sp_video.h new file mode 100644 index 0000000..86ed3f5 --- /dev/null +++ b/src/libsp/sp_video.h @@ -0,0 +1,96 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - KHWL video functions/enums properties. + * \file sp_video.h + * \author bombur + * \version 0.1 + * \date 14.09.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_SPVIDEO_H +#define SP_SPVIDEO_H + +#ifdef __cplusplus +extern "C" { +#endif + + +// Video mode +typedef enum +{ + KHWL_VIDEOMODE_NONE = 0, + + KHWL_VIDEOMODE_NORMAL = 1, // source = 4:3, display = 4:3, normal + KHWL_VIDEOMODE_VCENTER, // source = 4:3, display = 16:9, crop top/bottom + KHWL_VIDEOMODE_HCENTER, // source = 4:3, display = 16:9, black band on left/right + KHWL_VIDEOMODE_WIDE, // source = 16:9, display = 16:9, wide + KHWL_VIDEOMODE_PANSCAN, // source = 16:9, display = 4:3, panscan (crop left/right) + KHWL_VIDEOMODE_LETTERBOX, // source = 16:9, display = 4:3, letterbox (black band on top/bottom) + +} KHWL_VIDEOMODE; + +typedef enum +{ + KHWL_ZOOMMODE_YUV = 0, + KHWL_ZOOMMODE_DVD, + KHWL_ZOOMMODE_ASPECT, +} KHWL_ZOOMMODE; + +/// Set display output -1=turn off else = set tvoutput mode +/// and standard. +int khwl_setdisplay(KHWL_TV_OUTPUT_FORMAT_TYPE mode, KHWL_TV_STANDARD_TYPE standard); + +/// Clear YUV screen +int khwl_display_clear(); + +/// Set video mode (change aspect ratio) +/// Use frame width/height if set. +void khwl_setvideomode(KHWL_VIDEOMODE mode, BOOL set_hw); + +/// Transform coord (used for anamorphic modes and overlays) +void khwl_transformcoord(KHWL_VIDEOMODE mode, int *x, int *y, int width, int height); + +/// Get screen width +void khwl_getscreensize(int *width, int *height); + +void khwl_set_window(int src_width, int src_height, int frame_width, int frame_height, + int hscale, int vscale, int offsx, int offsy); + +void khwl_set_window_zoom(KHWL_ZOOMMODE); + +void khwl_set_window_source(int src_width, int src_height); + +/// Set Window Frame in OSD coordinates! +void khwl_set_window_frame(int fr_left, int fr_top, int fr_right, int fr_bottom); +/// Get Window Frame in OSD coordinates! +void khwl_get_window_frame(int *fr_left, int *fr_top, int *fr_right, int *fr_bottom); + +/// Set display settings (values 0..1000) +void khwl_set_display_settings(int brightness, int contrast, int saturation); + +/// Get display settings (values 0..1000) +void khwl_get_display_settings(int *brightness, int *contrast, int *saturation); + +/// Used for start-up procedure only... +void khwl_setwide(BOOL wide); + +#ifdef __cplusplus +} +#endif + +#endif // of SP_SPVIDEO_H diff --git a/src/libsp/win32/dirent.c b/src/libsp/win32/dirent.c new file mode 100644 index 0000000..f3b5c71 --- /dev/null +++ b/src/libsp/win32/dirent.c @@ -0,0 +1,57 @@ +#include +#include +#include "dirent.h" + +struct _finddata_t first; +int wasfirst = 0; + +DIR * opendir(const char *name) +{ + char tmp[4097], dir[4097]; + //int len; + DIR *ret; + wasfirst = 1; + /*strcpy(tmp, name); + len = strlen(tmp); + if (tmp[len-1] != '/' && tmp[len-1] != '\\') + strcat(tmp, "/");*/ + _getcwd(tmp, 1024); + if (name[0] == '/') + { + strcpy(dir, tmp); + strcat(dir, name); + name = dir; + } + _chdir(name); + ret = (DIR *)_findfirst("*.*", &first); + _chdir(tmp); + return ret; +} + +int closedir (DIR *d) +{ + _findclose((long)d); + return 0; +} + +struct _finddata_t *readdir(DIR *d) +{ + if (wasfirst == 1) + { + wasfirst = 0; + return &first; + } + if (_findnext((long)d, &first) != 0) + return NULL; + return &first; +} + +int readlink(char *path, char *buf, size_t size) +{ + path = path; + buf = buf; + size = size; + + return -1; +} + diff --git a/src/libsp/win32/fip.bmp b/src/libsp/win32/fip.bmp new file mode 100644 index 0000000..ab8a828 Binary files /dev/null and b/src/libsp/win32/fip.bmp differ diff --git a/src/libsp/win32/include/alloca.h b/src/libsp/win32/include/alloca.h new file mode 100644 index 0000000..60e0279 --- /dev/null +++ b/src/libsp/win32/include/alloca.h @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/src/libsp/win32/include/byteswap.h b/src/libsp/win32/include/byteswap.h new file mode 100644 index 0000000..c0ac97c --- /dev/null +++ b/src/libsp/win32/include/byteswap.h @@ -0,0 +1,105 @@ +/* Macros to swap the order of bytes in integer values. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +//#if !defined _BYTESWAP_H && !defined _NETINET_IN_H +//# error "Never use directly; include instead." +//#endif + +/* Swap bytes in 16 bit value. */ +#define __bswap_constant_16(x) \ + ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) + +#if defined __GNUC__ && __GNUC__ >= 2 +# define __bswap_16(x) \ + (__extension__ \ + ({ register unsigned short int __v; \ + if (__builtin_constant_p (x)) \ + __v = __bswap_constant_16 (x); \ + else \ + __asm__ __volatile__ ("rorw $8, %w0" \ + : "=r" (__v) \ + : "0" ((unsigned short int) (x)) \ + : "cc"); \ + __v; })) +#else +/* This is better than nothing. */ +# define __bswap_16(x) __bswap_constant_16 (x) +#endif + + +/* Swap bytes in 32 bit value. */ +#define __bswap_constant_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#if defined __GNUC__ && __GNUC__ >= 2 +/* To swap the bytes in a word the i486 processors and up provide the + `bswap' opcode. On i386 we have to use three instructions. */ +# if !defined __i486__ && !defined __pentium__ && !defined __pentiumpro__ +# define __bswap_32(x) \ + (__extension__ \ + ({ register unsigned int __v; \ + if (__builtin_constant_p (x)) \ + __v = __bswap_constant_32 (x); \ + else \ + __asm__ __volatile__ ("rorw $8, %w0;" \ + "rorl $16, %0;" \ + "rorw $8, %w0" \ + : "=r" (__v) \ + : "0" ((unsigned int) (x)) \ + : "cc"); \ + __v; })) +# else +# define __bswap_32(x) \ + (__extension__ \ + ({ register unsigned int __v; \ + if (__builtin_constant_p (x)) \ + __v = __bswap_constant_32 (x); \ + else \ + __asm__ __volatile__ ("bswap %0" \ + : "=r" (__v) \ + : "0" ((unsigned int) (x))); \ + __v; })) +# endif +#else +# define __bswap_32(x) __bswap_constant_32 (x) +#endif + + +#if defined __GNUC__ && __GNUC__ >= 2 +/* Swap bytes in 64 bit value. */ +# define __bswap_64(x) \ + (__extension__ \ + ({ union { __extension__ unsigned long long int __ll; \ + unsigned long int __l[2]; } __w, __r; \ + __w.__ll = (x); \ + __r.__l[0] = __bswap_32 (__w.__l[1]); \ + __r.__l[1] = __bswap_32 (__w.__l[0]); \ + __r.__ll; })) +#endif + +// [bombur]: hey, win32 can do this also! +#ifdef WIN32 + /* Swap bytes in 64 bit value. */ +# define __bswap_64(x) \ + ((__int64)__bswap_constant_32(x >> 32)) | (((__int64)__bswap_constant_32(x & 0xffffffff) << 32)) +#endif + + +#include "win32-stuff.h" \ No newline at end of file diff --git a/src/libsp/win32/include/dirent.h b/src/libsp/win32/include/dirent.h new file mode 100644 index 0000000..4ac3506 --- /dev/null +++ b/src/libsp/win32/include/dirent.h @@ -0,0 +1,59 @@ +#include +#include + +#ifndef __DIRENT_H__ +#define __DIRENT_H__ + +#define DIR int +#define PATH_MAX 4096 + +#define d_name name +#define dirent _finddata_t + +#define S_IROTH _S_IREAD +#define S_IRGRP 0 +#define S_IRWXU 0 +#define S_IRUSR 0 // 0000400 +#define S_IWUSR 0 // 0000200 +#define S_IXUSR 0 // 0000100 +#define S_IRWXG 0 // 0000070 +#define S_IWGRP 0 // 0000020 +#define S_IXGRP 0 // 0000010 +#define S_IRWXO 0 // 0000007 +#define S_IWOTH 0 // 0000002 +#define S_IXOTH 0 // 0000001 + +#define S_IFBLK 0060000 + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define lstat stat +#define stat64 _stati64 + +#define STAT_INODE(X) (X.st_size * X.st_mtime * X.st_ctime) + +typedef int mode_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +DIR * opendir(const char *name); +int closedir (DIR *); + +struct _finddata_t *readdir(DIR *); + +int readlink(char *path, char *buf, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // of __DIRENT_H__ \ No newline at end of file diff --git a/src/libsp/win32/include/endian.h b/src/libsp/win32/include/endian.h new file mode 100644 index 0000000..6e3f608 --- /dev/null +++ b/src/libsp/win32/include/endian.h @@ -0,0 +1,4 @@ +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN + diff --git a/src/libsp/win32/include/inttypes.h b/src/libsp/win32/include/inttypes.h new file mode 100644 index 0000000..78e5503 --- /dev/null +++ b/src/libsp/win32/include/inttypes.h @@ -0,0 +1,43 @@ +#ifndef _INTTYPES_H +#define _INTTYPES_H 1 + +#ifndef __int8_t_defined +# define __int8_t_defined +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef __int64 int64_t; +#endif + +/* Unsigned. */ +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +#ifndef __uint32_t_defined +typedef unsigned int uint32_t; +# define __uint32_t_defined +#endif +typedef unsigned __int64 uint64_t; + +#ifndef _UINTPTR_T_DEFINED +typedef unsigned long int uintptr_t; +#endif + +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types. */ +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +# define INT64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types. */ +# define UINT8_MAX (255) +# define UINT16_MAX (65535) +# define UINT32_MAX (4294967295U) +# define UINT64_MAX (__UINT64_C(18446744073709551615)) + +#endif /* inttypes.h */ + +#include "win32-stuff.h" \ No newline at end of file diff --git a/src/libsp/win32/include/linux/cdrom.h b/src/libsp/win32/include/linux/cdrom.h new file mode 100644 index 0000000..4d17615 --- /dev/null +++ b/src/libsp/win32/include/linux/cdrom.h @@ -0,0 +1,178 @@ + +#define _WINSOCKAPI_ +#include +#include +#define NOTIMEVAL + +#define CDROMPAUSE 0x5301 /* Pause Audio Operation */ +#define CDROMRESUME 0x5302 /* Resume paused Audio Operation */ +#define CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */ +#define CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index + (struct cdrom_ti) */ +#define CDROMREADTOCHDR 0x5305 /* Read TOC header + (struct cdrom_tochdr) */ +#define CDROMREADTOCENTRY 0x5306 /* Read TOC entry + (struct cdrom_tocentry) */ +#define CDROMSTOP 0x5307 /* Stop the cdrom drive */ +#define CDROMSTART 0x5308 /* Start the cdrom drive */ +#define CDROMEJECT 0x5309 /* Ejects the cdrom media */ +#define CDROMVOLCTRL 0x530a /* Control output volume + (struct cdrom_volctrl) */ +#define CDROMSUBCHNL 0x530b /* Read subchannel data + (struct cdrom_subchnl) */ +#define CDROMREADMODE2 0x530c /* Read CDROM mode 2 data (2336 Bytes) + (struct cdrom_read) */ +#define CDROMREADMODE1 0x530d /* Read CDROM mode 1 data (2048 Bytes) + (struct cdrom_read) */ +#define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ +#define CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */ +#define CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session + address of multi session disks + (struct cdrom_multisession) */ +#define CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code" + if available (struct cdrom_mcn) */ +#define CDROM_GET_UPC CDROM_GET_MCN /* This one is depricated, + but here anyway for compatability */ +#define CDROMRESET 0x5312 /* hard-reset the drive */ +#define CDROMVOLREAD 0x5313 /* Get the drive's volume setting + (struct cdrom_volctrl) */ +#define CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes) + + + + +/* Address in MSF format */ +struct cdrom_msf0 +{ + BYTE minute; + BYTE second; + BYTE frame; +}; + +/* Address in either MSF or logical format */ +union cdrom_addr +{ + struct cdrom_msf0 msf; + int lba; +}; + +/* This struct is used by the CDROMPLAYMSF ioctl */ +struct cdrom_msf +{ + BYTE cdmsf_min0; /* start minute */ + BYTE cdmsf_sec0; /* start second */ + BYTE cdmsf_frame0; /* start frame */ + BYTE cdmsf_min1; /* end minute */ + BYTE cdmsf_sec1; /* end second */ + BYTE cdmsf_frame1; /* end frame */ +}; + +/* This struct is used by the CDROMPLAYTRKIND ioctl */ +struct cdrom_ti +{ + BYTE cdti_trk0; /* start track */ + BYTE cdti_ind0; /* start index */ + BYTE cdti_trk1; /* end track */ + BYTE cdti_ind1; /* end index */ +}; + +/* This struct is used by the CDROMREADTOCHDR ioctl */ +struct cdrom_tochdr +{ + BYTE cdth_trk0; /* start track */ + BYTE cdth_trk1; /* end track */ +}; + +/* This struct is used by the CDROMVOLCTRL and CDROMVOLREAD ioctls */ +struct cdrom_volctrl +{ + BYTE channel0; + BYTE channel1; + BYTE channel2; + BYTE channel3; +}; + +/* This struct is used by the CDROMSUBCHNL ioctl */ +struct cdrom_subchnl +{ + BYTE cdsc_format; + BYTE cdsc_audiostatus; + BYTE cdsc_adr: 4; + BYTE cdsc_ctrl: 4; + BYTE cdsc_trk; + BYTE cdsc_ind; + union cdrom_addr cdsc_absaddr; + union cdrom_addr cdsc_reladdr; +}; + + +/* This struct is used by the CDROMREADTOCENTRY ioctl */ +struct cdrom_tocentry +{ + BYTE cdte_track; + BYTE cdte_adr :4; + BYTE cdte_ctrl :4; + BYTE cdte_format; + union cdrom_addr cdte_addr; + BYTE cdte_datamode; +}; + +/* This struct is used by the CDROMREADMODE1, and CDROMREADMODE2 ioctls */ +struct cdrom_read +{ + int cdread_lba; + char *cdread_bufaddr; + int cdread_buflen; +}; + +/* This struct is used by the CDROMREADAUDIO ioctl */ +struct cdrom_read_audio +{ + union cdrom_addr addr; /* frame address */ + BYTE addr_format; /* CDROM_LBA or CDROM_MSF */ + int nframes; /* number of 2352-byte-frames to read at once */ + BYTE *buf; /* frame buffer (size: nframes*2352 bytes) */ +}; + + +#define CD_MINS 74 /* max. minutes per CD, not really a limit */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_SYNC_SIZE 12 /* 12 sync bytes per raw data frame */ +#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ +#define CD_CHUNK_SIZE 24 /* lowest-level "data bytes piece" */ +#define CD_NUM_OF_CHUNKS 98 /* chunks per frame */ +#define CD_FRAMESIZE_SUB 96 /* subchannel data "frame" size */ +#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ +#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ +#define CD_EDC_SIZE 4 /* bytes EDC per most raw data frame types */ +#define CD_ZERO_SIZE 8 /* bytes zero per yellow book mode 1 frame */ +#define CD_ECC_SIZE 276 /* bytes ECC per most raw data frame types */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */ +#define CD_FRAMESIZE_RAWER 2646 /* The maximum possible returned bytes */ +/* most drives don't deliver everything: */ +#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ +#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ + +#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ +#define CD_XA_TAIL (CD_EDC_SIZE+CD_ECC_SIZE) /* "after data" part of raw XA frame */ +#define CD_XA_SYNC_HEAD (CD_SYNC_SIZE+CD_XA_HEAD) /* sync bytes + header of XA frame */ + +/* CD-ROM address types (cdrom_tocentry.cdte_format) */ +#define CDROM_LBA 0x01 /* "logical block": first frame is #0 */ +#define CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */ + +/* bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl) */ +#define CDROM_DATA_TRACK 0x04 + +/* The leadout track is always 0xAA, regardless of # of tracks on disc */ +#define CDROM_LEADOUT 0xAA + +/* audio states (from SCSI-2, but seen with other drives, too) */ +#define CDROM_AUDIO_INVALID 0x00 /* audio status not supported */ +#define CDROM_AUDIO_PLAY 0x11 /* audio play operation in progress */ +#define CDROM_AUDIO_PAUSED 0x12 /* audio play operation paused */ +#define CDROM_AUDIO_COMPLETED 0x13 /* audio play successfully completed */ +#define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */ +#define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */ diff --git a/src/libsp/win32/include/linux/mtd/mtd.h b/src/libsp/win32/include/linux/mtd/mtd.h new file mode 100644 index 0000000..f730238 --- /dev/null +++ b/src/libsp/win32/include/linux/mtd/mtd.h @@ -0,0 +1,41 @@ + +/* [bombur]: this is a fake! */ + +#ifndef __MTD_MTD_H__ +#define __MTD_MTD_H__ + +struct erase_info_user { + unsigned long start; + unsigned long length; +}; + +struct mtd_info_user { + unsigned char type; + unsigned long flags; + unsigned long size; // Total size of the MTD + unsigned long erasesize; + unsigned long oobblock; // Size of OOB blocks (e.g. 512) + unsigned long oobsize; // Amount of OOB data per block (e.g. 16) + unsigned long ecctype; + unsigned long eccsize; +}; + +struct region_info_user { + unsigned long offset; /* At which this region starts, from the beginning of the MTD */ + unsigned long erasesize; /* For this region */ + unsigned long numblocks; /* Number of blocks in this region */ + unsigned long regionindex; +}; + + +#define MEMGETINFO 1 +#define MEMERASE 2 +#define MEMWRITEOOB 3 +#define MEMREADOOB 4 +#define MEMLOCK 5 +#define MEMUNLOCK 6 +#define MEMGETREGIONCOUNT 7 +#define MEMGETREGIONINFO 8 + + +#endif /* __MTD_MTD_H__ */ diff --git a/src/libsp/win32/include/mntent.h b/src/libsp/win32/include/mntent.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/pty.h b/src/libsp/win32/include/pty.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/pwd.h b/src/libsp/win32/include/pwd.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sched.h b/src/libsp/win32/include/sched.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/stdint.h b/src/libsp/win32/include/stdint.h new file mode 100644 index 0000000..917d353 --- /dev/null +++ b/src/libsp/win32/include/stdint.h @@ -0,0 +1,2 @@ + +#include diff --git a/src/libsp/win32/include/strings.h b/src/libsp/win32/include/strings.h new file mode 100644 index 0000000..78caf5b --- /dev/null +++ b/src/libsp/win32/include/strings.h @@ -0,0 +1,3 @@ +#ifndef strcasecmp +#define strcasecmp _stricmp +#endif \ No newline at end of file diff --git a/src/libsp/win32/include/sys/io.h b/src/libsp/win32/include/sys/io.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/ioctl.h b/src/libsp/win32/include/sys/ioctl.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/mman.h b/src/libsp/win32/include/sys/mman.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/mount.h b/src/libsp/win32/include/sys/mount.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/param.h b/src/libsp/win32/include/sys/param.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/poll.h b/src/libsp/win32/include/sys/poll.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/socket.h b/src/libsp/win32/include/sys/socket.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/sysinfo.h b/src/libsp/win32/include/sys/sysinfo.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/time.h b/src/libsp/win32/include/sys/time.h new file mode 100644 index 0000000..4c15111 --- /dev/null +++ b/src/libsp/win32/include/sys/time.h @@ -0,0 +1,2 @@ +#include "../win32-stuff.h" + diff --git a/src/libsp/win32/include/sys/uio.h b/src/libsp/win32/include/sys/uio.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/un.h b/src/libsp/win32/include/sys/un.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/sys/wait.h b/src/libsp/win32/include/sys/wait.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/termios.h b/src/libsp/win32/include/termios.h new file mode 100644 index 0000000..e69de29 diff --git a/src/libsp/win32/include/unistd.h b/src/libsp/win32/include/unistd.h new file mode 100644 index 0000000..b1e97a0 --- /dev/null +++ b/src/libsp/win32/include/unistd.h @@ -0,0 +1,5 @@ +#include +#include + + +#include "win32-stuff.h" \ No newline at end of file diff --git a/src/libsp/win32/include/win32-stuff.h b/src/libsp/win32/include/win32-stuff.h new file mode 100644 index 0000000..073d60b --- /dev/null +++ b/src/libsp/win32/include/win32-stuff.h @@ -0,0 +1,424 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - win32-unix compatibility header. + * \file win32-stuff.h + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + + +#ifndef __WIN32_STUFF__ +#define __WIN32_STUFF__ + +#include +#include +#include + +/* Standard file descriptors. */ +#define STDIN_FILENO 0 /* Standard input. */ +#define STDOUT_FILENO 1 /* Standard output. */ +#define STDERR_FILENO 2 /* Standard error output. */ + +#define SIGKILL 9 +#define SIGALRM 14 +#define SIGCHLD 17 /* Child status has changed (POSIX). */ + +#define SA_NOCLDSTOP 1 /* Don't send SIGCHLD when children stop. */ +#define SA_NOCLDWAIT 2 /* Don't create zombie on child death. */ +#define SA_SIGINFO 4 /* Invoke signal-catching function with three arguments instead of one. */ + +#define WIFSIGNALED(status) 0 + +#define WNOHANG 1 /* Don't block waiting. */ +#define WUNTRACED 2 /* Report status of stopped children. */ + +#define ONLCR 0000004 +#define ECHO 0000010 + +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#define F_DUPFD 0 /* Duplicate file descriptor. */ +#define F_GETFD 1 /* Get file descriptor flags. */ +#define F_SETFD 2 /* Set file descriptor flags. */ +#define F_GETFL 3 /* Get file status flags. */ +#define F_SETFL 4 /* Set file status flags. */ + +#define O_NONBLOCK 04000 + +#define PROT_READ 0x1 /* Page can be read. */ +#define PROT_WRITE 0x2 /* Page can be written. */ +#define PROT_EXEC 0x4 /* Page can be executed. */ +#define PROT_NONE 0x0 /* Page can not be accessed. */ + +#define MAP_SHARED 0x01 /* Share changes. */ +#define MAP_PRIVATE 0x02 /* Changes are private. */ +#define MAP_ANONYMOUS 0x20 /* Don't use a file. */ +#define MAP_ANON MAP_ANONYMOUS + +typedef int __pid_t; +typedef int __uid_t; + +# ifndef __pid_t_defined +typedef __pid_t pid_t; +# define __pid_t_defined +# endif +# ifndef __uid_t_defined +typedef __uid_t uid_t; +# define __uid_t_defined +# endif + + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef long int __clock_t; + +// from inttypes.h +typedef __int64 ssize_t; + +extern int fcntl (int __fd, int __cmd, ...); +extern void usleep(unsigned int); +extern unsigned int sleep (unsigned int __seconds); +extern unsigned int alarm (unsigned int __seconds); +extern int kill (__pid_t __pid, int __sig); +extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options); +extern __pid_t vfork (void); + +extern void *mmap (void *__addr, int __len, int __prot, int __flags, int __fd, int __offset); +extern int munmap (void *__addr, int __len); + +#ifndef lseek64 +#define lseek64 _lseeki64 +#endif + +void *alloca (unsigned __size); + +extern int fsync(int); +extern int fchdir (int __fd); + +enum __itimer_which + { + /* Timers run in real time. */ + ITIMER_REAL = 0, +#define ITIMER_REAL ITIMER_REAL + /* Timers run only when the process is executing. */ + ITIMER_VIRTUAL = 1, +#define ITIMER_VIRTUAL ITIMER_VIRTUAL + /* Timers run when the process is executing and when + the system is executing on behalf of the process. */ + ITIMER_PROF = 2 +#define ITIMER_PROF ITIMER_PROF + }; + +typedef long suseconds_t; + +///////////////////////////////////////////////////// + +#define POLLIN 0x001 /* There is data to read. */ +#define POLLPRI 0x002 /* There is urgent data to read. */ +#define POLLOUT 0x004 /* Writing now will not block. */ + +struct pollfd +{ + int fd; /* File descriptor to poll. */ + short int events; /* Types of events poller cares about. */ + short int revents; /* Types of events that actually occurred. */ +}; + +typedef unsigned long int nfds_t; + +extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); + +#ifndef NOTIMEVAL + +struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* microseconds */ +}; + +struct itimerval + { + /* Value to put into `it_value' when the timer expires. */ + struct timeval it_interval; + /* Time to the next timer expiration. */ + struct timeval it_value; + }; + +struct timezone + { + int tz_minuteswest; /* Minutes west of GMT. */ + int tz_dsttime; /* Nonzero if DST is ever in effect. */ + }; + +#endif + +/* Set the timer WHICH to *NEW. If OLD is not NULL, + set *OLD to the old value of timer WHICH. + Returns 0 on success, -1 on errors. */ +extern int setitimer (enum __itimer_which __which, + const struct itimerval *__new, + struct itimerval *__old); + + +extern int gettimeofday (struct timeval *__tv, + struct timezone *__tz); + + +/////////////////////////////////////////////////////////////// + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 +struct termios + { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ + }; + +struct winsize + { + unsigned short int ws_row; + unsigned short int ws_col; + unsigned short int ws_xpixel; + unsigned short int ws_ypixel; + }; + +extern int openpty (int *__amaster, int *__aslave, char *__name, + struct termios *__termp, struct winsize *__winp); + +extern int tcgetattr (int __fd, struct termios *__termios_p); + +extern int tcsetattr (int __fd, int __optional_actions, + struct termios *__termios_p); + +/////////////////////////////////////////////////////////////// +typedef void (*__sighandler_t) (int); +# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) +typedef struct + { + unsigned long int __val[_SIGSET_NWORDS]; + } __sigset_t; + +typedef union sigval + { + int sival_int; + void *sival_ptr; + } sigval_t; + +#define __WORDSIZE 32 +# define __SI_MAX_SIZE 128 +# if __WORDSIZE == 64 +# define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 4) +# else +# define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 3) +# endif + +typedef struct siginfo + { + int si_signo; /* Signal number. */ + int si_errno; /* If non-zero, an errno value associated with + this signal, as defined in . */ + int si_code; /* Signal code. */ + + union + { + int _pad[__SI_PAD_SIZE]; + + /* kill(). */ + struct + { + __pid_t si_pid; /* Sending process ID. */ + __uid_t si_uid; /* Real user ID of sending process. */ + } _kill; + + /* POSIX.1b timers. */ + struct + { + unsigned int _timer1; + unsigned int _timer2; + } _timer; + + /* POSIX.1b signals. */ + struct + { + __pid_t si_pid; /* Sending process ID. */ + __uid_t si_uid; /* Real user ID of sending process. */ + sigval_t si_sigval; /* Signal value. */ + } _rt; + + /* SIGCHLD. */ + struct + { + __pid_t si_pid; /* Which child. */ + __uid_t si_uid; /* Real user ID of sending process. */ + int si_status; /* Exit value or signal. */ + __clock_t si_utime; + __clock_t si_stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ + struct + { + void *si_addr; /* Faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL. */ + struct + { + long int si_band; /* Band event for SIGPOLL. */ + int si_fd; + } _sigpoll; + } _sifields; + } siginfo_t; + +struct sigaction + { + /* Signal handler. */ + union + { + __sighandler_t sa_handler; + void (*sa_sigaction) (int, siginfo_t *, void *); + } __sigaction_handler; + # define sa_handler __sigaction_handler.sa_handler + # define sa_sigaction __sigaction_handler.sa_sigaction + + /* Additional set of signals to be blocked. */ + __sigset_t sa_mask; + + /* Special flags. */ + int sa_flags; + + /* Restore handler. */ + void (*sa_restorer) (void); + }; + +# define si_pid _sifields._kill.si_pid + +typedef jmp_buf sigjmp_buf; + +extern int sigaction (int __sig, struct sigaction *__act, struct sigaction *__oact); + +/////////////////////////////////////////////////////////////// + +struct sysinfo { + long uptime; /* Seconds since boot */ + unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ + unsigned long totalram; /* Total usable main memory size */ + unsigned long freeram; /* Available memory size */ + unsigned long sharedram; /* Amount of shared memory */ + unsigned long bufferram; /* Memory used by buffers */ + unsigned long totalswap; /* Total swap space size */ + unsigned long freeswap; /* swap space still available */ + unsigned short procs; /* Number of current processes */ + unsigned short pad; /* Padding needed for m68k */ + unsigned long totalhigh; /* Total high memory size */ + unsigned long freehigh; /* Available high memory size */ + unsigned int mem_unit; /* Memory unit size in bytes */ + char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ +}; + +extern int sysinfo (struct sysinfo *__info); + +/////////////////////////////////////////////////////////////// + +#ifndef _WINSOCKAPI_ + +#undef __NFDBITS +#define __NFDBITS (8 * sizeof(unsigned long)) + +#undef __FD_SETSIZE +#define __FD_SETSIZE 1024 + +#undef __FDSET_LONGS +#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS) + +typedef struct { + unsigned long fds_bits [__FDSET_LONGS]; +} fd_set; + +#undef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31))) + +#undef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31))) + +#undef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp))) + + +#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp) +#define FD_CLR(fd,fdsetp) __FD_CLR(fd,fdsetp) +#define FD_ISSET(fd,fdsetp) __FD_ISSET(fd,fdsetp) +#define FD_ZERO(fdsetp) __FD_ZERO(fdsetp) + + +int select (int __nfds, fd_set *__readfds, + fd_set *__writefds, fd_set *__exceptfds, + struct timeval *__timeout); + +extern int ioctl (int __fd, unsigned long int __request, ...); +extern int ftruncate(int fd, off_t length); + +#endif // of _WINSOCKAPI_ + +#ifndef strcasecmp +#define strcasecmp _stricmp +#endif +#ifndef strncasecmp +#define strncasecmp _strnicmp +#endif + +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +#define bswap_16(x) __bswap_16 (x) + +/* Return a value with all bytes in the 32 bit argument swapped. */ +#define bswap_32(x) __bswap_32 (x) + +/* Return a value with all bytes in the 64 bit argument swapped. */ +# define bswap_64(x) __bswap_64 (x) + +extern __int64 strtoll (const char *__nptr, char ** __endptr, int __base); +extern unsigned __int64 strtoull (const char * __nptr, char **__endptr, int __base); + +#ifdef __cplusplus +} +#endif + +#endif // of __WIN32_STUFF__ \ No newline at end of file diff --git a/src/libsp/win32/libsp.aps b/src/libsp/win32/libsp.aps new file mode 100644 index 0000000..939631e Binary files /dev/null and b/src/libsp/win32/libsp.aps differ diff --git a/src/libsp/win32/libsp.rc b/src/libsp/win32/libsp.rc new file mode 100644 index 0000000..27a6e55 --- /dev/null +++ b/src/libsp/win32/libsp.rc @@ -0,0 +1,161 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resrc1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resrc1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""resource.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_EJECT DIALOG 0, 0, 154, 63 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Drive ejected..." +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "&Use real device",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,10,12,65,10 + CONTROL "Emulate &ISO",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,10,22,60,10 + CONTROL "Emulate &HDD",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,10,32,60,10 + CONTROL "Emulate &DVD",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,10,42,70,10 + DEFPUSHBUTTON "Close",IDOK,95,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,95,24,50,14 + GROUPBOX "Choose medium type:",IDC_STATIC,5,2,80,58 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_FIP BITMAP "fip.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,4,1,0 + PRODUCTVERSION 1,4,1,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "www.sigmaplayer.com" + VALUE "CompanyName", "SigmaPlayer Team" + VALUE "FileDescription", "SigmaPlayer firmware emulator" + VALUE "FileVersion", "1, 4, 1, a" + VALUE "InternalName", "init" + VALUE "LegalCopyright", "Copyright © 2004-2010" + VALUE "OriginalFilename", "init.exe" + VALUE "ProductName", "SigmaPlayer emulator" + VALUE "ProductVersion", "1, 4, 1, a" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_EJECT, DIALOG + BEGIN + RIGHTMARGIN, 153 + BOTTOMMARGIN, 51 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/libsp/win32/manifest.xml b/src/libsp/win32/manifest.xml new file mode 100644 index 0000000..d7c922f --- /dev/null +++ b/src/libsp/win32/manifest.xml @@ -0,0 +1,23 @@ + + + +SigmaPlayer emulator + + + + + + diff --git a/src/libsp/win32/resource.h b/src/libsp/win32/resource.h new file mode 100644 index 0000000..eaec160 --- /dev/null +++ b/src/libsp/win32/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by libsp.rc +// +#define IDD_EJECT 1101 +#define IDB_FIP 102 +#define IDC_RADIO1 1000 +#define IDC_RADIO2 1001 +#define IDC_RADIO3 1002 +#define IDC_RADIO4 1003 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1004 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/libsp/win32/resrc1.h b/src/libsp/win32/resrc1.h new file mode 100644 index 0000000..d1e8a4d --- /dev/null +++ b/src/libsp/win32/resrc1.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by libsp.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/libsp/win32/sp_cdrom.cpp b/src/libsp/win32/sp_cdrom.cpp new file mode 100644 index 0000000..6771840 --- /dev/null +++ b/src/libsp/win32/sp_cdrom.cpp @@ -0,0 +1,536 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CDROM driver's functions source file (Win32) + * \file sp_cdrom.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include + +#pragma warning (disable : 4201) +#include +#pragma warning (default : 4201) + +#include +#include +#include +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_msg.h" +#include "sp_cdrom.h" + +#include "resource.h" + +int cdrom_handle = -1; + +int cdrom_last_letter = 'z'; + +static int dvd_letter = 0; +static BOOL cdrom_mounted = FALSE; + +/// CD-ROM fs mount language +static char *def_cdrom_language = "iso8859-1"; +static char *cdrom_language = NULL; + +static CDROM_STATUS cdrom_type = /*CDROM_STATUS_HAS_ISO; */CDROM_STATUS_NODISC; + +static int cdrom_getmediumtype(); + +static char dvdpath[3], dvdpath2[1024]; +static const char *curdvdpath = (const char *)dvdpath; + +static BOOL cdrom_cd_hdd = FALSE, cdrom_hdd = FALSE, cdrom_hdd_root = FALSE; +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +char *CDROMDIR = "cdrom"; +//char *CDROMDIR = dvdpath; +extern int khwl_handle; + +// taken from linux/cdrom.h (kernel mode) +struct mode_page_header +{ + WORD mode_data_length; + BYTE medium_type; + BYTE reserved1; + BYTE reserved2; + BYTE reserved3; + WORD desc_length; +}; + +struct atapi_capabilities_page +{ + struct mode_page_header header; + BYTE caps[20]; +}; + + +BOOL cdrom_init() +{ + cdrom_deinit(); + cdrom_language = SPstrdup(def_cdrom_language); + + char tmp[256]; + DWORD mask = GetLogicalDrives(); + for (char letter = 'A'; letter <= 'Z'; letter++) + { + if ((mask & (1 << (letter - 'A'))) != 0) + { + sprintf( tmp, "%c:\\", letter ); + if (GetDriveType(tmp) == DRIVE_CDROM) + { + dvd_letter = letter; + break; + } + } + } + + if (dvd_letter != 0) + { + dvdpath[0] = (char)dvd_letter; + dvdpath[1] = ':'; + dvdpath[2] = '\0'; + } else + curdvdpath = NULL; + + // fake for sure... + cdrom_handle = 1; + + return TRUE; +} + +BOOL cdrom_deinit() +{ + if (cdrom_handle == -1) + return FALSE; +// close (cdrom_handle); + cdrom_handle = -1; + SPSafeFree(cdrom_language); + return TRUE; +} + +BOOL cdrom_switch(BOOL ) +{ + return TRUE; +} + +const char *cdrom_getdevicepath(const char *src_path) +{ + if (src_path != NULL) + { + static char tmpp[2014]; + if (_strnicmp(src_path, "/cdrom", 6) == 0) // real device! + sprintf(tmpp, "%s%s", CDROMDIR, src_path + 6); + else if (_strnicmp(src_path, "/hdd", 4) == 0) // real device! + sprintf(tmpp, "%s%s", CDROMDIR, src_path + 4); + else + return curdvdpath; + return tmpp; + } + return curdvdpath; +} + +BOOL CALLBACK eject_dlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static int timer_id = 0; + ULONG wID, code; + switch (uMsg) + { + case WM_INITDIALOG: + CheckDlgButton(hwndDlg, IDC_RADIO1, BST_CHECKED); + timer_id = SetTimer(hwndDlg, NULL, 10, NULL); + return 0; + + case WM_CLOSE: + KillTimer(hwndDlg, timer_id); + EndDialog(hwndDlg, 0); + break; + case WM_COMMAND: + wID = LOWORD(wParam); + code = HIWORD(wParam); + switch(wID) + { + case IDOK: + if (IsDlgButtonChecked(hwndDlg, IDC_RADIO1) == BST_CHECKED) + EndDialog(hwndDlg, 0); + else if (IsDlgButtonChecked(hwndDlg, IDC_RADIO2) == BST_CHECKED) + EndDialog(hwndDlg, 1); + else if (IsDlgButtonChecked(hwndDlg, IDC_RADIO3) == BST_CHECKED) + EndDialog(hwndDlg, 2); + else if (IsDlgButtonChecked(hwndDlg, IDC_RADIO4) == BST_CHECKED) + EndDialog(hwndDlg, 3); + break; + case IDCANCEL: + EndDialog(hwndDlg, -1); + break; + } + break; + // bigfix: strange XP-style behaviour... + case WM_NCCALCSIZE: + break; + case WM_TIMER: + gui_update(); + break; + + default: + return DefWindowProc(hwndDlg, uMsg, wParam, lParam); + } + return 0; +} + +int cdrom_eject(BOOL open) +{ + if (open) + { + cdrom_handle = 1; + gui_update(); + cdrom_hdd = FALSE; + + int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_EJECT), + (HWND)khwl_handle, eject_dlg); + SetFocus((HWND)khwl_handle); + if (ret == -1) + cdrom_type = CDROM_STATUS_NODISC; + else if (ret == 0) // autodetect from real device + { + cdrom_type = CDROM_STATUS_NODISC; + cdrom_handle = 2; + + ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); + + if (dvd_letter != 0) + { + char tmp[256]; + sprintf(tmp, "\\\\.\\%c:", dvd_letter); + + HANDLE fd = CreateFile(tmp, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, NULL); + + if (fd == INVALID_HANDLE_VALUE) + fd = CreateFile(tmp, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, NULL); + if (fd != INVALID_HANDLE_VALUE) + { + struct MY_GET_MEDIA_TYPES + { + DWORD DeviceType; // FILE_DEVICE_XXX values + DWORD MediaInfoCount; + DEVICE_MEDIA_INFO MediaInfo[256]; + } mt; + int BytesReturned; + if (DeviceIoControl(fd, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, NULL, 0, + (LPVOID)&mt, (DWORD)sizeof(mt), (LPDWORD) &BytesReturned, NULL) != 0) + { + BOOL mounted = FALSE; + for (DWORD i = 0; i < mt.MediaInfoCount; i++) + { + if ((mt.DeviceType == FILE_DEVICE_DVD || mt.DeviceType == FILE_DEVICE_CD_ROM) && + (mt.MediaInfo[i].DeviceSpecific.DiskInfo.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED) + == MEDIA_CURRENTLY_MOUNTED) + { + mounted = TRUE; + break; + } + } + if (mounted) + { + MCI_OPEN_PARMS mciOpen; + MCI_STATUS_PARMS mciParams; + mciOpen.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO; + mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD)&mciOpen); + + mciParams.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)&mciParams); + int numtr = mciParams.dwReturn; + bool has_audio = false, has_data = false; + for (int i = 0; i < numtr; i++) + { + mciParams.dwItem = MCI_CDA_STATUS_TYPE_TRACK; + mciParams.dwTrack = i + 1; + mciSendCommand(mciOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&mciParams); + if (mciParams.dwReturn == MCI_CDA_TRACK_AUDIO) + has_audio = true; + else + has_data = true; + } + mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, 0, 0); + + curdvdpath = dvdpath; + CDROMDIR = dvdpath; + + DIR *dir = opendir(dvdpath); + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) + { + if (_stricmp(entry->name, "VIDEO_TS") == 0) + { + cdrom_type = CDROM_STATUS_HAS_DVD; + break; + } + } + closedir(dir); + // one more chance... + if (cdrom_type != CDROM_STATUS_HAS_DVD) + { + dir = opendir(dvdpath); + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) + { + sprintf(dvdpath2, "%s/%s", dvdpath, entry->name); + DIR *dir2 = opendir(dvdpath2); + struct dirent *entry2; + while ((entry2 = readdir(dir2)) != NULL) + { + if (_stricmp(entry2->name, "VIDEO_TS") == 0) + { + cdrom_type = CDROM_STATUS_HAS_DVD; + break; + } + } + closedir(dir2); + if (cdrom_type == CDROM_STATUS_HAS_DVD) + { + curdvdpath = dvdpath2; + break; + } + } + closedir(dir); + } + + if (cdrom_type != CDROM_STATUS_HAS_DVD) + { + if (has_audio && !has_data) + cdrom_type = CDROM_STATUS_HAS_AUDIO; + else if (has_audio && has_data) + cdrom_type = CDROM_STATUS_HAS_MIXED; + else + cdrom_type = CDROM_STATUS_HAS_ISO; + } + } + } else + { + //DWORD err = GetLastError(); + } + + + CloseHandle(fd); + } + } + ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); + } + else if (ret == 1) + { + cdrom_hdd = FALSE; + CDROMDIR = "cdrom"; + cdrom_type = CDROM_STATUS_HAS_ISO; + } + else if (ret == 2) + { + cdrom_hdd = TRUE; + CDROMDIR = "cdrom/hdd"; + cdrom_type = CDROM_STATUS_HAS_ISO; + } + else if (ret == 3) + { + cdrom_hdd = FALSE; + curdvdpath = "cdrom/dvd"; + cdrom_type = CDROM_STATUS_HAS_DVD; + } + } else + { + gui_update(); + } + + return -1; +} + + +int cdrom_mount(char *language, BOOL /*cd_only*/) +{ + int ret = 0; + char iocharset[1024]; + if (language == NULL) + language = cdrom_language; + + BOOL lang_changed = strcasecmp(cdrom_language, language) != 0; + if (!cdrom_mounted || lang_changed) + { + sprintf(iocharset, "iocharset=%s", language); + //int rmnt = ((cdrom_mounted && lang_changed) ? MS_REMOUNT : 0); + //ret = mount("/dev/cdroms/cdrom0", "/cdrom", "iso9660", MS_RDONLY | MS_NOSUID | MS_NODEV | rmnt, iocharset); + + msg("CD-ROM: mount with %s.\n", iocharset); + } + cdrom_mounted = TRUE; + + if (lang_changed) + { + SPSafeFree(cdrom_language); + cdrom_language = SPstrdup(language); + } + + return ret; +} + +int cdrom_umount() +{ + msg("CD-ROM: umount.\n"); + cdrom_mounted = FALSE; + //return umount("/cdrom"); + return 0; +} + +BOOL cdrom_ismounted() +{ + return cdrom_mounted; +} + + +CDROM_STATUS cdrom_getstatus(BOOL *) +{ + return cdrom_type; +} + +BOOL cdrom_isready() +{ + return TRUE; +} + +// [bombur]: this was die hard! +int cdrom_getmediumtype() +{ +/* + cdrom_generic_command cmd; + struct request_sense sense; + struct atapi_capabilities_page caps; + + if (cdrom_handle != -1) + { + memset(&cmd, 0, sizeof(cmd)); + cmd.buffer = (BYTE *)∩︀ + cmd.buflen = sizeof(caps); + cmd.cmd[0] = GPCMD_MODE_SENSE_10; + cmd.cmd[2] = GPMODE_CAPABILITIES_PAGE; + cmd.cmd[8] = cmd.buflen & 0xff; + cmd.sense = &sense; + cmd.data_direction = CGC_DATA_READ; + ioctl(cdrom_handle, CDROM_SEND_PACKET, &cmd); + + return caps.header.medium_type; + } +*/ + return 0; +} + +int cdrom_stat(const char *path, struct stat64 *s) +{ + if (_strnicmp(path, "/cdrom", 6) == 0) // real device! + { + char tmpp[2014]; + sprintf(tmpp, "%s%s", CDROMDIR, path + 6); + return _stati64(tmpp, s); + } + if (_strnicmp(path, "/hdd", 4) == 0) // real device! + { + char tmpp[2014]; + sprintf(tmpp, "%s%s", CDROMDIR, path + 4); + return _stati64(tmpp, s); + } + if (path[0] == '/') + { + path++; + } + return _stati64(path, s); +} + +DIR *cdrom_opendir(const char *path) +{ + cdrom_hdd_root = FALSE; + if (_strnicmp(path, "/cdrom", 6) == 0) // real device! + { + char tmpp[2014]; + sprintf(tmpp, "%s%s", CDROMDIR, path + 6); + return opendir(tmpp); + } + if (_strnicmp(path, "/hdd", 4) == 0) // real device! + { + char tmpp[2014]; + sprintf(tmpp, "%s%s", CDROMDIR, path + 4); + if (path[4] == '/' && path[5] == '\0') + cdrom_hdd_root = TRUE; + return opendir(tmpp); + } + return opendir(path); +} + +int cdrom_open(const char *fname, int flags) +{ + if (_strnicmp(fname, "/cdrom", 6) == 0) // real device! + { + char tmpp[2014]; + sprintf(tmpp, "%s%s", CDROMDIR, fname + 6); + return open(tmpp, flags | O_BINARY); + } + if (_strnicmp(fname, "/hdd", 4) == 0) // real device! + { + char tmpp[2014]; + sprintf(tmpp, "%s%s", CDROMDIR, fname + 4); + return open(tmpp, flags | O_BINARY); + } + return -1; +} + +char *cdrom_getrealpath(const char *path) +{ + static char tmpp[4096]; + if (memcmp(path, "/", 2) == 0) + { + if (cdrom_cd_hdd) + return (char *)path; + if (cdrom_hdd) + strcpy(tmpp, "/hdd"); + else + strcpy(tmpp, "/cdrom"); + strcat(tmpp, path); + return tmpp; + } + return (char *)path; +} + +struct dirent *cdrom_readdir(DIR *dir) +{ + struct dirent *d = readdir(dir); + if (d == NULL) + return NULL; + // fast mount-check (exclude unmounted folders) + if (cdrom_hdd_root && d->name[0] > cdrom_last_letter && d->name[1] == '\0') + return NULL; + return d; +} + +int cdrom_closedir(DIR *dir) +{ + return closedir(dir); +} \ No newline at end of file diff --git a/src/libsp/win32/sp_css.cpp b/src/libsp/win32/sp_css.cpp new file mode 100644 index 0000000..ec6a176 --- /dev/null +++ b/src/libsp/win32/sp_css.cpp @@ -0,0 +1,229 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CSS auth. functions source file (Win32) + * \file sp_css.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" +#include "sp_css.h" + +typedef unsigned char uint8_t; + +#include + +void CryptKey( int i_key_type, int i_variant, + unsigned char const *p_challenge, unsigned char *p_key ) +{ + /* Permutation table for challenge */ + unsigned char pp_perm_challenge[3][10] = + { { 1, 3, 0, 7, 5, 2, 9, 6, 4, 8 }, + { 6, 1, 9, 3, 8, 5, 7, 4, 0, 2 }, + { 4, 0, 3, 5, 7, 2, 8, 6, 1, 9 } }; + + /* Permutation table for variant table for key2 and buskey */ + unsigned char pp_perm_variant[2][32] = + { { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, + 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, + 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, + 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 }, + { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, + 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, + 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, + 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d } }; + + unsigned char p_variants[32] = + { 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73, + 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42, + 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B, + 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 }; + + /* The "secret" key */ + unsigned char p_secret[5] = { 0x55, 0xD6, 0xC4, 0xC5, 0x28 }; + + unsigned char p_bits[30], p_scratch[10], p_tmp1[5], p_tmp2[5]; + unsigned char i_lfsr0_o; /* 1 bit used */ + unsigned char i_lfsr1_o; /* 1 bit used */ + unsigned char i_css_variant, i_cse, i_index, i_combined, i_carry; + unsigned char i_val = 0; + unsigned long i_lfsr0, i_lfsr1; + int i_term = 0; + int i_bit; + int i; + + for (i = 9; i >= 0; --i) + p_scratch[i] = p_challenge[pp_perm_challenge[i_key_type][i]]; + + i_css_variant = (unsigned char)(( i_key_type == 0 ) ? i_variant : + pp_perm_variant[i_key_type-1][i_variant]); + + /* + * This encryption engine implements one of 32 variations + * one the same theme depending upon the choice in the + * variant parameter (0 - 31). + * + * The algorithm itself manipulates a 40 bit input into + * a 40 bit output. + * The parameter 'input' is 80 bits. It consists of + * the 40 bit input value that is to be encrypted followed + * by a 40 bit seed value for the pseudo random number + * generators. + */ + + /* Feed the secret into the input values such that + * we alter the seed to the LFSR's used above, then + * generate the bits to play with. + */ + for( i = 5 ; --i >= 0 ; ) + { + p_tmp1[i] = (unsigned char)(p_scratch[5 + i] ^ p_secret[i] ^ p_crypt_tab2[i]); + } + + /* + * We use two LFSR's (seeded from some of the input data bytes) to + * generate two streams of pseudo-random bits. These two bit streams + * are then combined by simply adding with carry to generate a final + * sequence of pseudo-random bits which is stored in the buffer that + * 'output' points to the end of - len is the size of this buffer. + * + * The first LFSR is of degree 25, and has a polynomial of: + * x^13 + x^5 + x^4 + x^1 + 1 + * + * The second LSFR is of degree 17, and has a (primitive) polynomial of: + * x^15 + x^1 + 1 + * + * I don't know if these polynomials are primitive modulo 2, and thus + * represent maximal-period LFSR's. + * + * + * Note that we take the output of each LFSR from the new shifted in + * bit, not the old shifted out bit. Thus for ease of use the LFSR's + * are implemented in bit reversed order. + * + */ + + /* In order to ensure that the LFSR works we need to ensure that the + * initial values are non-zero. Thus when we initialise them from + * the seed, we ensure that a bit is set. + */ + i_lfsr0 = ( p_tmp1[0] << 17 ) | ( p_tmp1[1] << 9 ) | + (( p_tmp1[2] & ~7 ) << 1 ) | 8 | ( p_tmp1[2] & 7 ); + i_lfsr1 = ( p_tmp1[3] << 9 ) | 0x100 | p_tmp1[4]; + + i_index = sizeof(p_bits); + i_carry = 0; + + do + { + for( i_bit = 0, i_val = 0 ; i_bit < 8 ; ++i_bit ) + { + + i_lfsr0_o = (unsigned char)(( ( i_lfsr0 >> 24 ) ^ ( i_lfsr0 >> 21 ) ^ + ( i_lfsr0 >> 20 ) ^ ( i_lfsr0 >> 12 ) ) & 1); + i_lfsr0 = ( i_lfsr0 << 1 ) | i_lfsr0_o; + + i_lfsr1_o = (unsigned char)(( ( i_lfsr1 >> 16 ) ^ ( i_lfsr1 >> 2 ) ) & 1); + i_lfsr1 = ( i_lfsr1 << 1 ) | i_lfsr1_o; + + i_combined = (unsigned char)(!i_lfsr1_o + i_carry + !i_lfsr0_o); + /* taking bit 1 */ + i_carry = (unsigned char)(( i_combined >> 1 ) & 1); + i_val |= ( i_combined & 1 ) << i_bit; + } + + p_bits[--i_index] = i_val; + } while( i_index > 0 ); + + /* This term is used throughout the following to + * select one of 32 different variations on the + * algorithm. + */ + i_cse = (unsigned char)(p_variants[i_css_variant] ^ p_crypt_tab2[i_css_variant]); + + /* Now the actual blocks doing the encryption. Each + * of these works on 40 bits at a time and are quite + * similar. + */ + i_index = 0; + for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_scratch[i] ) + { + i_index = (unsigned char)(p_bits[25 + i] ^ p_scratch[i]); + i_index = (unsigned char)(p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse); + + p_tmp1[i] = (unsigned char)(p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term); + } + p_tmp1[4] ^= p_tmp1[0]; + + for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] ) + { + i_index = (unsigned char)(p_bits[20 + i] ^ p_tmp1[i]); + i_index = (unsigned char)(p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse); + + p_tmp2[i] = (unsigned char)(p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term); + } + p_tmp2[4] ^= p_tmp2[0]; + + for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] ) + { + i_index = (unsigned char)(p_bits[15 + i] ^ p_tmp2[i]); + i_index = (unsigned char)(p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse); + i_index = (unsigned char)(p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term); + + p_tmp1[i] = (unsigned char)(p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index]); + } + p_tmp1[4] ^= p_tmp1[0]; + + for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] ) + { + i_index = (unsigned char)(p_bits[10 + i] ^ p_tmp1[i]); + i_index = (unsigned char)(p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse); + + i_index = (unsigned char)(p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term); + + p_tmp2[i] = (unsigned char)(p_crypt_tab0[i_index] ^ p_crypt_tab2[i_index]); + } + p_tmp2[4] ^= p_tmp2[0]; + + for( i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp2[i] ) + { + i_index = (unsigned char)(p_bits[5 + i] ^ p_tmp2[i]); + i_index = (unsigned char)(p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse); + + p_tmp1[i] = (unsigned char)(p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term); + } + p_tmp1[4] ^= p_tmp1[0]; + + for(i = 5, i_term = 0 ; --i >= 0 ; i_term = p_tmp1[i] ) + { + i_index = (unsigned char)(p_bits[i] ^ p_tmp1[i]); + i_index = (unsigned char)(p_crypt_tab1[i_index] ^ ~p_crypt_tab2[i_index] ^ i_cse); + + p_key[i] = (unsigned char)(p_crypt_tab2[i_index] ^ p_crypt_tab3[i_index] ^ i_term); + } + + return; +} diff --git a/src/libsp/win32/sp_css.h b/src/libsp/win32/sp_css.h new file mode 100644 index 0000000..ce559fd --- /dev/null +++ b/src/libsp/win32/sp_css.h @@ -0,0 +1,32 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - CSS auth. functions header (Win32) + * \file sp_css.h + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_CSS_WIN32 +#define SP_CSS_WIN32 + + +void CryptKey( int i_key_type, int i_variant, + unsigned char const *p_challenge, unsigned char *p_key ); + +#endif // of SP_CSS_WIN32 diff --git a/src/libsp/win32/sp_eeprom.cpp b/src/libsp/win32/sp_eeprom.cpp new file mode 100644 index 0000000..c04a881 --- /dev/null +++ b/src/libsp/win32/sp_eeprom.cpp @@ -0,0 +1,61 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - EEPROM interface functions source file + * For Technosonic-compatible players ('MP') + * \file sp_eeprom.cpp + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" +#include "sp_eeprom.h" + +BOOL eeprom_set_value(DWORD addr, DWORD val, int size) +{ + KHWL_ADDR_DATA data; + /// \warning: not usual byte order used! + for (int i = 0; i < size; i++) + { + data.Addr = addr + i; + data.Data = (val >> (i * 8)) & 0xff; + khwl_setproperty(KHWL_EEPROM_SET, eEepromAccess, sizeof(data), &data); + } + return TRUE; +} + +DWORD eeprom_get_value(DWORD addr, int size) +{ + KHWL_ADDR_DATA data; + DWORD val = 0; + /// \warning: not usual byte order used! + for (int i = 0; i < size; i++) + { + data.Addr = addr + i; + data.Data = 0; + khwl_getproperty(KHWL_EEPROM_SET, eEepromAccess, sizeof(data), &data); + val |= (data.Data & 0xff) << (i * 8); + } + return val; +} + diff --git a/src/libsp/win32/sp_fip.cpp b/src/libsp/win32/sp_fip.cpp new file mode 100644 index 0000000..c8613de --- /dev/null +++ b/src/libsp/win32/sp_fip.cpp @@ -0,0 +1,167 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - FIP interface functions source file (Win32) + * \file sp_fip.c + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_fip.h" + +static unsigned char char_table[] = " -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-\1"; +unsigned char fipram[12]; +static unsigned char led_table[] = +{ + 0x00,0x10,0xEE,0x48,0xD6,0xDA,0x78,0xBA,0xBE,0xC8,0xFE,0xFA,0xFC,0xFE,0xA6,0xEE, + 0xB6,0xB4,0xBE,0x7C,0x48,0x4A,0x7C,0x26,0xEC,0xEC,0xEE,0xF4,0xEE,0xFC,0xBA,0xC8, + 0x6E,0x6E,0x6E,0x6C,0x78,0x82,0x02,0x1E,0x3E,0x16,0x5E,0xF6,0xB4,0xFA,0x3C,0x08, + 0x0A,0x2C,0x26,0x1C,0x1C,0x1E,0xF4,0xF8,0x14,0xBA,0x36,0x0E,0x0E,0x0E,0x0C,0x78, + 0x12,0x10,0x00 +}; +static unsigned char led_special[] = +{ + 0x01, 0x07, 0x01, 0x06, 0x03, 0x07, 0x02, 0x07, 0x05, 0x07, 0x04, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x05, 0x07, 0x04, 0x07, 0x03, 0x07, 0x02, 0x07, 0x01, 0x07, 0x00, 0x09, 0x07, 0x09, 0x06, + 0x09, 0x05, 0x09, 0x04, 0x09, 0x03, 0x09, 0x02, 0x09, 0x01, 0x09, 0x00, 0x08, 0x07, 0x08, 0x06, + 0x08, 0x05, 0x08, 0x04, 0x08, 0x03, 0x08, 0x02 +}; + +int fip_handle = -1; + +int fip_lastkey = 0; + +#include "../MP/sp_fip_codes-technosonic.h" + +extern bool khwl_msgloop(); +extern int khwl_handle; + +BOOL fip_init(BOOL /*applymodule*/) +{ + fip_deinit(); + fip_handle = 1; + return TRUE; +} + +BOOL fip_deinit() +{ + if (fip_handle == -1) + return FALSE; + + fip_handle = -1; + return TRUE; +} + +BOOL fip_clear() +{ + int i; + + if (fip_handle == -1) + return FALSE; + // clear FIP + for (i = 0; i < 12; i++) + { + fipram[i] = 0; + } + return TRUE; +} + +BOOL fip_write_char(int ch, int pos) +{ + int lr; + + if (pos < 1 || pos - 1 > 6 || fip_handle == -1) + return FALSE; + ch &= 255; + for (lr = 0; lr < 66; lr++) + if (char_table[lr] == ch) + break; + + fipram[pos-1] &= 128; + fipram[pos-1] |= led_table[lr] >> 1; + + return TRUE; +} + +BOOL fip_write_special_char(int pos, int shift, BOOL onoff) +{ + BYTE ch = fipram[pos]; + if (onoff) + fipram[pos] = (unsigned char)(ch | (1 << shift)); + else + fipram[pos] = (unsigned char)(ch & ~(1 << shift)); + if (fipram[pos] == ch) + return TRUE; + + return TRUE; +} + +BOOL fip_write_special(int id, BOOL onoff) +{ + if (id < 0 || id > 27) + return FALSE; + fip_write_special_char(led_special[id*2], led_special[id*2+1], onoff); + InvalidateRect((HWND)khwl_handle, NULL, FALSE); + UpdateWindow((HWND)khwl_handle); + return TRUE; +} + +BOOL fip_get_special(int id) +{ + if (id < 0 || id > 27) + return FALSE; + int pos = led_special[id*2]; + int shift = led_special[id*2+1]; + return (fipram[pos] >> shift) & 1; +} + +BOOL fip_write_string(const char *str) +{ + int i, len; + if (str == NULL || fip_handle == -1) + return FALSE; + len = strlen(str); + if (len > 7) + len = 7; + for (i = 0; i < 7; i++) + fip_write_char(i < len ? str[len - i - 1] : ' ', i + 1); + + InvalidateRect((HWND)khwl_handle, NULL, FALSE); + UpdateWindow((HWND)khwl_handle); + + return TRUE; +} + +int fip_read_button(BOOL ) +{ + if (fip_handle == -1) + return 0; + + if (!khwl_msgloop()) + return -1; + + int ret = fip_lastkey; + fip_lastkey = 0; + return ret; +} diff --git a/src/libsp/win32/sp_i2c.cpp b/src/libsp/win32/sp_i2c.cpp new file mode 100644 index 0000000..11778ec --- /dev/null +++ b/src/libsp/win32/sp_i2c.cpp @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - I2C data transfer functions source file. + * Win32 version (stub). + * \file sp_i2c.cpp + * \author bombur + * \version 0.1 + * \date 1.02.2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include "sp_misc.h" +#include "sp_io.h" +#include "sp_i2c.h" + +BOOL i2c_data_in(BYTE addr, BYTE idx, BYTE *data, int num) +{ + return TRUE; +} + +BOOL i2c_data_out(BYTE addr, BYTE idx, BYTE *data, int num) +{ + return TRUE; +} + diff --git a/src/libsp/win32/sp_khwl.cpp b/src/libsp/win32/sp_khwl.cpp new file mode 100644 index 0000000..df741fe --- /dev/null +++ b/src/libsp/win32/sp_khwl.cpp @@ -0,0 +1,1350 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - KHWL interface functions source file (Win32) + * \file sp_khwl.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "sp_misc.h" +#include "sp_khwl.h" +#include "sp_mpeg.h" +#include "sp_fip.h" +#include "sp_css.h" + +#include "resource.h" + +//#define DUMP_VIDEO_FRAMES_ORDER +//#define DUMP_VIDEO +//#define DUMP_VIDEO_PACKET + +int khwl_handle = -1; + +static HANDLE khwl_parser = NULL; +static DWORD khwl_parser_id = (DWORD)-1; +static HANDLE khwl_parser_mutex = NULL; +static int khwl_rate = 24000, khwl_scale = 1000; + +static int khwl_audio_format = 0; +static int khwl_audio_sample_rate = 0, khwl_audio_bits = 0, khwl_audio_channels = 0; +static LONGLONG khwl_audio_pts_per_Mb = 0; + +// here we store the data +static MpegPlayStruct mpeg_playstruct_storage[4]; + +/// Muxed media packets +MpegPlayStruct *MPEG_PLAY_STRUCT = &mpeg_playstruct_storage[0]; +/// Video packets +MpegPlayStruct *MPEG_VIDEO_STRUCT = &mpeg_playstruct_storage[1]; +/// Audio packets +MpegPlayStruct *MPEG_AUDIO_STRUCT = &mpeg_playstruct_storage[2]; +/// Subpicture packets +MpegPlayStruct *MPEG_SPU_STRUCT = &mpeg_playstruct_storage[3]; + +BYTE *BUF_BASE = NULL; + +const int yoffset = 110; + +const int osd_width = 640, osd_height = 480; + +static char *wndtitle = "SigmaPlayer :: version " __DATE__ " " __TIME__ " :: "; + +static struct // BITMAPINFO with 16 colors +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +} bi; + +static HDC hMemDC = NULL; +static HBITMAP hSrcBitmap = NULL; +static HDC curDC = NULL; +static ULONGLONG khwl_pts = 0; + +static BYTE tmp_UV[720 * 576/2]; +static BYTE tmp_Y[720 * 576]; +static int yuv_width = 720, yuv_height = 480; +static BOOL yuv_dirty = FALSE; +static BYTE tv_mask[osd_width * osd_height]; +static int tv_brightness = 500, tv_contrast = 500, tv_saturation = 500; + +static bool step_mode = false, use_tvmask = false; + +static int fip_button = -1; + +static int freq_reg = ((1 << 8) | (34 << 2) | 0x02); + + +#ifdef DUMP_VIDEO_FRAMES_ORDER +#include "sp_msg.h" +#endif + + +void CALLBACK OSDUpdate( UINT /*uID*/, UINT /*uMsg*/, DWORD /*dwUser*/, + DWORD /*dw1*/, DWORD /*dw2*/ ) +{ + khwl_osd_update(); +} + +bool khwl_msgloop(); + +int khwl_nextfeedpacket(MpegPlayStruct *feed) +{ + MpegPlayStruct *from = MPEG_PLAY_STRUCT; + MpegPacket *feedin = feed->in; + if (feedin == NULL) + return FALSE; + + //!!!!!!!!!!!!!!!!!!!!!!!! +#ifdef DUMP_VIDEO_FRAMES_ORDER + if (feedin->type == 0) + { + char frms[] = " IPB"; + int frm_type = -1; + if (feedin->pData[0] == 0 && feedin->pData[1] == 0 && feedin->pData[2] == 1 && feedin->pData[3] == 0xb6) + frm_type = (int)(feedin->pData[4] >> 6); + msg("(%c) PTS = %d\n", frms[frm_type+1], feedin->pts); + } +#endif + +#ifdef DUMP_VIDEO + if (feedin->type == 0) + { + FILE *fp; + fp = fopen("out.m4v", "ab"); + fwrite(feedin->pData, feedin->size, 1, fp); + fclose(fp); + } +#endif +#ifdef DUMP_VIDEO_PACKET + if (feedin->type == 0) + { + static int p_idx = 0; + FILE *fp; + fp = fopen("out_packets.log", "ab"); + //fprintf(fp, "[%4d] flg=%2x siz=%6d pts=" PRINTF_64d "\n", p_idx++, feedin->flags, feedin->size, feedin->pts); + fprintf(fp, "[%4d] flg=%2x siz=%6d\n", p_idx++, feedin->flags, feedin->size); + fclose(fp); + } +#endif + + //!!!!!!!!!!!!!!!!!!!!!!!! + + if (feedin->flags == 2) + khwl_pts = feedin->pts; + else if (feedin->flags == 0x80) + { + khwl_pts = INT64(90000) * feedin->pts / khwl_rate; + } + else if (feedin->flags == 0 && feedin->type == 1) + { + khwl_pts += khwl_audio_pts_per_Mb * feedin->size / (1024*1024); + } + + feed->in = feed->in->next; + + feed->num--; + feed->in_cnt++; + from->num++; + from->out_cnt++; + + if (feedin->next == NULL) + feed->out = NULL; + if (from->out == NULL) + from->in = feedin; + else + from->out->next = feedin; + from->out = feedin; + feedin->next = NULL; + + ////// simulate budidx decrement + if (feedin->bufidx) + { + if (*(feedin->bufidx) > 0) + (*feedin->bufidx)--; + } + + return TRUE; +} + +void __stdcall khwl_parser_proc(void *) +{ + for (;;) + { + WaitForSingleObject(khwl_parser_mutex, INFINITE); + if (MPEG_VIDEO_STRUCT->in != NULL) + khwl_nextfeedpacket(MPEG_VIDEO_STRUCT); + if (MPEG_AUDIO_STRUCT->in != NULL) + khwl_nextfeedpacket(MPEG_AUDIO_STRUCT); + if (MPEG_SPU_STRUCT->in != NULL) + khwl_nextfeedpacket(MPEG_SPU_STRUCT); + + ReleaseMutex(khwl_parser_mutex); + + // simulate hard work... :-) + //Sleep(3); + + // well, it isn't a real step mode 'cause we don't wait for I-frames... + /* + if (step_mode) + { + khwl_pause(); + step_mode = false; + + } + */ + + + } +} + +extern int fip_lastkey; + +KHWL_OSDSTRUCT osd; + +static BOOL module_applied = FALSE; + +DWORD *backbuf = NULL; +DWORD *osdbuf = NULL; +BYTE *buf = NULL; +KHWL_WINDOW max_wnd, dest_wnd, zoomed_wnd, src_wnd, valid_wnd, osd_wnd; + +DWORD vol[2] = { 50, 50 }; +int audio_offset = 0; + +BYTE p_challenge[10]; +BYTE p_key1[5], p_key2[5], p_key_check[5]; +int css_variant = 0; + +void khwl_calc_audio_pts_rate() +{ + if (khwl_audio_format == eAudioFormat_PCM) + { + khwl_audio_pts_per_Mb = khwl_audio_sample_rate * khwl_audio_bits * khwl_audio_channels; + if (khwl_audio_pts_per_Mb != 0) + khwl_audio_pts_per_Mb = INT64(90000)*8*1024*1024 / khwl_audio_pts_per_Mb; + } +} + +int khwl_setproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value) +{ + int i; + DWORD val = *(DWORD *)value; + if (pset == KHWL_COMMON_SET && id == eDoAudioLater) + { + audio_offset = (int)val; + } + else if (pset == KHWL_BOARDINFO_SET && id == ebiCommand) + { + if (*(int *)value == ebiCommand_VideoHwBlackFrame) + { + memset(backbuf, 0, 720*480*4); + khwl_osd_update(); + } + } + else if (pset == KHWL_VIDEO_SET) + { + if (id == evDestinationWindow) + dest_wnd = *((KHWL_WINDOW *)value); + else if (id == evZoomedWindow) + zoomed_wnd = *((KHWL_WINDOW *)value); + else if (id == evSourceWindow) + src_wnd = *((KHWL_WINDOW *)value); + else if (id == evValidWindow) + valid_wnd = *((KHWL_WINDOW *)value); + else if (id == evYUVWriteParams) + { + KHWL_YUV_WRITE_PARAMS_TYPE *params = (KHWL_YUV_WRITE_PARAMS_TYPE *)value; + yuv_width = params->wWidth; + yuv_height = params->wHeight; + } + else if (id == evBrightness) + tv_brightness = val; + else if (id == evContrast) + tv_contrast = val; + else if (id == evSaturation) + tv_saturation = val; + } + else if (pset == KHWL_OSD_SET && id == eOsdDestinationWindow) + { + osd_wnd = *((KHWL_WINDOW *)value); + } + else if (pset == KHWL_TIME_SET) + { + if (id == etimSystemTimeClock) + { + KHWL_TIME_TYPE *t = (KHWL_TIME_TYPE *)value; + khwl_pts = t->pts; + } + else if (id == etimVideoCTSTimeScale) + { + khwl_rate = val; + } + } + else if (pset == KHWL_AUDIO_SET) + { + if (id == eaVolumeLeft) + vol[0] = val; + else if (id == eaVolumeRight) + vol[1] = val; + else if (id == eAudioFormat) + { + khwl_audio_format = val; + khwl_calc_audio_pts_rate(); + } + else if (id == eAudioSampleRate) + { + khwl_audio_sample_rate = val; + khwl_calc_audio_pts_rate(); + } + else if (id == eAudioNumberOfBitsPerSample) + { + khwl_audio_bits = val; + khwl_calc_audio_pts_rate(); + } + else if (id == eAudioNumberOfChannels) + { + khwl_audio_channels = val; + khwl_calc_audio_pts_rate(); + } + } + else if (pset == KHWL_EEPROM_SET && id == eEepromAccess) + { + KHWL_ADDR_DATA *data = (KHWL_ADDR_DATA *)value; + FILE *fp = fopen("settings.dat", "rb+"); + if (fp == NULL) + fp = fopen("settings.dat", "wb"); + if (fp != NULL) + { + fseek(fp, data->Addr, SEEK_SET); + BYTE d = (BYTE)data->Data; + fwrite(&d, sizeof(BYTE), 1, fp); + fclose(fp); + + } + } + else if (pset == KHWL_DECODER_SET) + { + if (id == edecCSSKey1) + { + for (i = 0 ; i < size; i++) + { + p_key1[i] = ((char *)value)[4-i]; + } + + for (i = 0 ; i < 32; ++i) + { + CryptKey(0, i, p_challenge, p_key_check); + + if (memcmp( p_key_check, p_key1, size) == 0) + { + css_variant = i; + break; + } + } + } + else if (id == edecCSSChlg2) + { + for( i = 0 ; i < size; ++i) + { + p_challenge[i] = ((char *)value)[9-i]; + } + + CryptKey(1, css_variant, p_challenge, p_key2); + } + else if (id == edecForceFixedVOPRate) + { + KHWL_FIXED_VOP_RATE_TYPE *params = (KHWL_FIXED_VOP_RATE_TYPE *)value; + khwl_scale = params->time_incr; + } + } + + return 0; +} + +int khwl_getproperty(KHWL_PROPERTY_SET pset, int id, int size, void *value) +{ + int i; + if (pset == KHWL_COMMON_SET && id == eDoAudioLater) + { + *(DWORD *)value = audio_offset; + } + else if (pset == KHWL_TIME_SET && id == etimSystemTimeClock) + ((KHWL_TIME_TYPE *)value)->pts = khwl_pts; + else if (pset == KHWL_VIDEO_SET) + { + if (id == evMaxDisplayWindow) + *((KHWL_WINDOW *)value) = max_wnd; + else if (id == evDestinationWindow) + *((KHWL_WINDOW *)value) = dest_wnd; + else if (id == evSourceWindow) + *((KHWL_WINDOW *)value) = src_wnd; + else if (id == evZoomedWindow) + *((KHWL_WINDOW *)value) = zoomed_wnd; + else if (id == evValidWindow) + *((KHWL_WINDOW *)value) = valid_wnd; + else if (id == evBrightness) + *(DWORD *)value = tv_brightness; + else if (id == evContrast) + *(DWORD *)value = tv_contrast; + else if (id == evSaturation) + *(DWORD *)value = tv_saturation; + } + else if (pset == KHWL_OSD_SET && id == eOsdDestinationWindow) + *((KHWL_WINDOW *)value) = osd_wnd; + else if (pset == KHWL_TIME_SET && id == etimVideoFrameDisplayedTime) + ((KHWL_TIME_TYPE *)value)->pts = khwl_pts; + else if (pset == KHWL_EEPROM_SET && id == eEepromAccess) + { + KHWL_ADDR_DATA *data = (KHWL_ADDR_DATA *)value; + FILE *fp = fopen("settings.dat", "rb"); + if (fp != NULL) + { + if (fseek(fp, data->Addr, SEEK_SET) == 0) + { + BYTE d; + fread(&d, sizeof(BYTE), 1, fp); + data->Data = d; + } + fclose(fp); + + } + } + else if (pset == KHWL_AUDIO_SET && id == eaVolumeLeft) + { + *(DWORD *)value = vol[0]; + } + else if (pset == KHWL_AUDIO_SET && id == eaVolumeRight) + { + *(DWORD *)value = vol[1]; + } + else if (pset == KHWL_DECODER_SET && id == edecCSSChlg) + { + for (i = 0 ; i < size; ++i ) + ((char *)value)[9-i] = p_challenge[i] = (BYTE)i; + } + else if (pset == KHWL_DECODER_SET && id == edecCSSKey2) + { + for (i = 0; i < size; ++i) + { + ((char *)value)[4-i] = p_key2[i]; + } + } + return 0; +} + +/////////////////////////////////////////////////////////// + +extern unsigned char fipram[8]; + +static HBITMAP hbm = 0; + +void UpdateYUV() +{ + if (yuv_dirty) + { + int maxoff = 720 * 480; + BYTE *ybuf = (BYTE *)((char *)tmp_Y); + BYTE *uvbuf = (BYTE *)((char *)tmp_UV); + + for (int i = 0; i < maxoff; i++) + { + BYTE r, g, b; + int o = i; + int ui = (o / yuv_width) / 4 * yuv_width + (o % yuv_width)/2; + int vi = (479 - MIN(o / yuv_width, 479)) * 720 + o % yuv_width; + + khwl_jpegyuvtorgb(ybuf[i], uvbuf[ui*2+1], uvbuf[ui*2], &r, &g, &b); + khwl_tvyuvtovgargb(ybuf[i], uvbuf[ui*2+1], uvbuf[ui*2], &r, &g, &b); + + if (vi >= 0 && vi < maxoff) + backbuf[vi] = (b << 16) | (g << 8) | r; + } + + yuv_dirty = FALSE; + } +} + +void UpdateFIP(HDC hDC) +{ + static HBRUSH hbrw[3] = { 0 }; + + if (hbrw[0] == 0) + { + LOGBRUSH lb; + lb.lbColor = RGB(49, 1, 15); + lb.lbStyle = BS_SOLID; + lb.lbHatch = 0; + hbrw[0] = CreateBrushIndirect(&lb); + } + if (hbrw[1] == 0) + { + LOGBRUSH lb; + lb.lbColor = RGB(178, 242, 249); + lb.lbStyle = BS_SOLID; + lb.lbHatch = 0; + hbrw[1] = CreateBrushIndirect(&lb); + } + if (hbrw[2] == 0) + { + LOGBRUSH lb; + lb.lbColor = RGB(255, 10, 0); + lb.lbStyle = BS_SOLID; + lb.lbHatch = 0; + hbrw[2] = CreateBrushIndirect(&lb); + } + + SelectObject(hMemDC, hbm); + BitBlt(hDC, 0, 0, 720, yoffset, hMemDC, 0, 0, SRCCOPY); + + RECT r; + + const int w = 2, h = 9, h2 = 5; + const int cx[] = { w, 0, w+h, w, 0, w+h, w }; + const int cy[] = { w+h+w+h, w+h+w, w+h+w, w+h, w, w, 0 }; + const int cw[] = { h, w, w, h, w, w, h }; + const int ch[] = { w, h, h, w, h, h, w }; + int i, posx = 500; + int posy = 11; + for (i = 0; i < 7; i++) + { + posx += (w + h + w + w); + if (i == 3 || i == 5) + posx += h; + for (int k = 0; k < 7; k++) + { + int bit = (fipram[6-i] >> k) & 1; + r.left = posx + cx[k]; + r.top = posy + cy[k]; + r.right = r.left + cw[k]; + r.bottom = r.top + ch[k]; + FillRect(hDC, &r, hbrw[!bit ? 0 : (i < 2 ? 2 : 1)] ); + } + } + posx = 500; + if (fip_get_special(FIP_SPECIAL_COLON1)) + { + r.left = posx + (w+h)*5+w+h2; + r.top = posy + (w+h/2); + r.right = r.left + w; + r.bottom = r.top + w; + FillRect(hDC, &r, hbrw[1] ); + r.top = posy + (w+h)+(w+h/2); + r.bottom = r.top + w; + FillRect(hDC, &r, hbrw[1] ); + } + if (fip_get_special(FIP_SPECIAL_COLON2)) + { + r.left = posx + (w+h)*9+w; + r.top = posy + (w+h/2); + r.right = r.left + w; + r.bottom = r.top + w; + FillRect(hDC, &r, hbrw[1] ); + r.top = posy + (w+h)+(w+h/2); + r.bottom = r.top + w; + FillRect(hDC, &r, hbrw[1] ); + } + if (fip_get_special(FIP_SPECIAL_PLAY)) + { + POINT p[3]; + const int r = 5; + const int off = 4; + p[0].x = posx + off; + p[0].y = posy + (w+h/2); + p[1].x = p[0].x - r; + p[1].y = p[0].y - r; + p[2].x = p[0].x - r; + p[2].y = p[0].y + r; + HBRUSH oldbr = (HBRUSH)SelectObject(hDC, hbrw[1]); + Polygon(hDC, p, 3); + SelectObject(hDC, oldbr); + } + if (fip_get_special(FIP_SPECIAL_PAUSE)) + { + const int d = 8; + const int off = 5; + r.left = posx + off; + r.top = posy + (w); + r.right = r.left + w; + r.bottom = r.top + d; + FillRect(hDC, &r, hbrw[2]); + r.left = posx + off + w*2; + r.right = r.left + w; + FillRect(hDC, &r, hbrw[2]); + } + + HBRUSH oldbr = (HBRUSH)SelectObject(hDC, hbrw[1]); + const int rad = 15, srad = 7; + const int off = 5; + int cposx = posx - rad - off; + int cposy = posy + rad; + const int cpie[12][4] = + { + { -66, 74, -30, 95 }, + { -95, 30, -74, 66 }, + { -97, -20, -97, 20 }, + { -74, -66, -95, -30 }, + { -30, -95, -66, -74 }, + { 20, -97, -20, -97 }, + { 66, -74, 30, -95 }, + { 95, -30, 74, -66 }, + { 97, 20, 97, -20 }, + { 74, 66, 95, 30 }, + { 30, 95, 66, 74 }, + { -20, 97, 20, 97 }, + + }; + for (i = FIP_SPECIAL_CIRCLE_1; i <= FIP_SPECIAL_CIRCLE_12; i++) + { + if (fip_get_special(i)) + { + POINT v1, v2; + POINT l1, l2; + int j = i - FIP_SPECIAL_CIRCLE_1; + v1.x = cpie[j][0]; + v1.y = cpie[j][1]; + v2.x = cpie[j][2]; + v2.y = cpie[j][3]; + l1.x = v1.x + cposx; + l1.y = v1.y + cposy; + l2.x = v2.x + cposx; + l2.y = v2.y + cposy; + Pie(hDC, cposx - rad, cposy - rad, cposx + rad, cposy + rad, l1.x, l1.y, l2.x, l2.y); + } + } + SelectObject(hDC, ::GetStockObject(BLACK_BRUSH)); + Ellipse(hDC, cposx - srad, cposy - srad, cposx + srad, cposy + srad); + SelectObject(hDC, oldbr); +} + +inline void FillHorzLine(BYTE *d, int x1, int x2, int y, BYTE color) +{ + d += y * osd_width + x1; + memset(d, color, x2 - x1 + 1); +} + +inline void FillVertLine(BYTE *d, int x, int y1, int y2, BYTE color) +{ + d += y1 * osd_width + x; + y2 -= y1; + for (int i = 0; i <= y2; i++) + { + *d = color; + d += osd_width; + } +} + +static void CreateTvMask() +{ + const int num_scan_lines = 13; + int i, scan_lines[2][num_scan_lines] = + { + { 45, 47, 48, 50, 52, 54, 57, 62, 68, 77, 92, 122, 212 }, + { 37, 39, 40, 42, 44, 46, 49, 54, 60, 69, 84, 114, 204 }, + }; + + memset(tv_mask, 0xff, osd_width * osd_height); + for (i = 0; i <= 23; i++) + { + memset(tv_mask + i * osd_width, 0, osd_width); + memset(tv_mask + (i + 456) * osd_width, 0, osd_width); + } + for (i = 0; i < osd_height; i++) + { + memset(tv_mask + i * osd_width, 0, 32); + memset(tv_mask + i * osd_width + 608, 0, 32); + } + for (i = 0; i < num_scan_lines; i++) + { + FillHorzLine(tv_mask, 0, scan_lines[0][i], 36 - i, 0); + FillHorzLine(tv_mask, 0, scan_lines[0][i], 443 + i, 0); + FillHorzLine(tv_mask, osd_width - scan_lines[0][i], osd_width - 1, 36 - i, 0); + FillHorzLine(tv_mask, osd_width - scan_lines[0][i], osd_width - 1, 443 + i, 0); + FillVertLine(tv_mask, 44 - i, 0, scan_lines[1][i], 0); + FillVertLine(tv_mask, 595 + i, 0, scan_lines[1][i], 0); + FillVertLine(tv_mask, 44 - i, osd_height - scan_lines[1][i], osd_height - 1, 0); + FillVertLine(tv_mask, 595 + i, osd_height - scan_lines[1][i], osd_height - 1, 0); + } +} + +void Generate_yuv2rgb_tables(void); +void new_rgbtoyuv(BYTE R, BYTE G, BYTE B, BYTE *y, BYTE *u, BYTE *v); +void new_yuvtorgb(BYTE y, BYTE u, BYTE v, BYTE *R, BYTE *G, BYTE *B); + + +LRESULT FAR PASCAL CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + break; + case WM_CLOSE: + PostQuitMessage(0); + break; + case WM_ERASEBKGND: + return 0; + case WM_PAINT: + { + if (buf != NULL) + { + PAINTSTRUCT ps; + BeginPaint((HWND)khwl_handle, &ps); + + HDC hDC = GetDC((HWND)khwl_handle); + HBITMAP hBitmap; + + if (hDC != curDC) + { + if (hMemDC != NULL) + DeleteDC(hMemDC); + hMemDC = CreateCompatibleDC(hDC); + if (hSrcBitmap != NULL) + DeleteObject(hSrcBitmap); + hSrcBitmap = CreateCompatibleBitmap(hDC, (WORD)720, 480); + curDC = hDC; + } + + int i; + RGBQUAD pal[256] = { 0 }; + for (i = 0; i < 256; i++) + { + khwl_tvyuvtovgargb(buf[8+i*4+1], buf[8+i*4+2], buf[8+i*4+3], + &pal[i].rgbRed, &pal[i].rgbGreen, &pal[i].rgbBlue); + } + + UpdateYUV(); + + BYTE *bb = buf + 8 + 1024 + 640*480, *b = bb; + BYTE *tvmm = tv_mask + 640*480, *tvm = tvmm; + DWORD *osd = osdbuf, *src = backbuf; + BYTE *ach = buf + 8; + + /// \TODO: use MMX/SSE for optimization... + for (i = 0; i < 480; i++) + { + bb -= 640; + tvmm -= 640; + for (int ix = 0; ix < 720; ix++) + { + register int dix = ix * 640 / 720; + b = bb + dix; + tvm = tvmm + dix; + int a = ach[*b << 2]; + if (*tvm || !use_tvmask) + { + if (a == 0) + *osd = *src; + else if (a == 0xff) + *osd = *(DWORD *)(pal + *b); + else + { + int y = (*src >> 16) & 0xff; + *osd = ((a * (pal[*b].rgbRed - y) / 255 + y) << 16); + y = (*src >> 8) & 0xff; + *osd |= ((a * (pal[*b].rgbGreen - y) / 255 + y) << 8); + y = (*src) & 0xff; + *osd |= ((a * (pal[*b].rgbBlue - y) / 255 + y)); + } + } else + *osd = 0; + osd++; + src++; + } + } + + SetDIBits(hDC, hSrcBitmap, 0, 480, osdbuf, (BITMAPINFO *)&bi, DIB_RGB_COLORS); + hBitmap = (HBITMAP)SelectObject(hMemDC, hSrcBitmap); + + BitBlt(hDC, 0, yoffset, 720, 480, hMemDC, 0, 0, SRCCOPY); + + //Rectangle(hDC, zoomed_wnd.x, zoomed_wnd.y+yoffset, zoomed_wnd.x + zoomed_wnd.w, zoomed_wnd.y+zoomed_wnd.h+yoffset); + + UpdateFIP(hDC); + + SelectObject(hMemDC, hBitmap); + ReleaseDC((HWND)khwl_handle, hDC); + + EndPaint((HWND)khwl_handle, &ps); + } + } + break; + case WM_KEYDOWN: + { + struct + { + int vk_key; + int fip_key; + } keytabl[] = + { + { VK_LEFT, FIP_KEY_LEFT }, + { VK_RIGHT, FIP_KEY_RIGHT }, + { VK_UP, FIP_KEY_UP }, + { VK_DOWN, FIP_KEY_DOWN }, + { VK_HOME, FIP_KEY_REWIND }, + { VK_END, FIP_KEY_FORWARD }, + { VK_PRIOR, FIP_KEY_SKIP_PREV }, + { VK_NEXT, FIP_KEY_SKIP_NEXT }, + { VK_ESCAPE, FIP_KEY_RETURN }, + { 13, FIP_KEY_ENTER }, + { VK_BACK, FIP_KEY_RETURN }, + + { VK_SPACE, FIP_KEY_PLAY }, + { VK_TAB, FIP_KEY_STOP }, + + { '1', FIP_KEY_ONE }, + { '2', FIP_KEY_TWO }, + { '3', FIP_KEY_THREE }, + { '4', FIP_KEY_FOUR }, + { '5', FIP_KEY_FIVE }, + { '6', FIP_KEY_SIX }, + { '7', FIP_KEY_SEVEN }, + { '8', FIP_KEY_EIGHT }, + { '9', FIP_KEY_NINE }, + { '0', FIP_KEY_ZERO }, + + { 'A', FIP_KEY_ANGLE }, + { 'B', FIP_KEY_AB }, + { 'C', FIP_KEY_CANCEL }, + { 'D', FIP_KEY_AUDIO }, + { 'E', FIP_KEY_TITLE }, + { 'I', FIP_KEY_PBC }, + { 'L', FIP_KEY_SLOW }, + { 'M', FIP_KEY_MENU }, + { 'N', FIP_KEY_PN }, + { 'O', FIP_KEY_PROGRAM }, + { 'P', FIP_KEY_PAUSE }, + { 'R', FIP_KEY_REPEAT }, + { 'S', FIP_KEY_SEARCH }, + { 'T', FIP_KEY_SUBTITLE }, + { 'U', FIP_KEY_MUTE }, + { 'V', FIP_KEY_VMODE }, + { 'Z', FIP_KEY_ZOOM }, + + { 187, FIP_KEY_VOLUME_UP }, + { 189, FIP_KEY_VOLUME_DOWN }, + + { VK_F1, FIP_KEY_POWER }, + { VK_F2, FIP_KEY_EJECT }, + { VK_F3, FIP_KEY_SETUP }, + { VK_F4, FIP_KEY_OSD }, + { -1, -1 } + }; + + if (wParam != 0) + { + for (int i = 0; keytabl[i].vk_key != -1; i++) + { + if ((int)wParam == keytabl[i].vk_key) + { + fip_lastkey = keytabl[i].fip_key; + break; + } + } + } + if (wParam == VK_F9) + { + use_tvmask = !use_tvmask; + InvalidateRect((HWND)khwl_handle, NULL, FALSE); + UpdateWindow((HWND)khwl_handle); + } + break; + } + case WM_KEYUP: + //fip_lastkey = 0; + break; + case WM_MOUSEMOVE: + { + int x = LOWORD(lParam); + int y = HIWORD(lParam); + static char buf[256]; + if (y >= yoffset) + { + sprintf(buf, "%s (%d, %d)", wndtitle, x, y-yoffset); + SetWindowText(hWnd, buf); + } + else + { + struct + { + int fip_key; + int x1, y1, x2, y2; + } keytabl[] = + { + { FIP_KEY_FRONT_EJECT, 418, 28, 445, 42 }, + { FIP_KEY_FRONT_PLAY, 421, 68, 439, 85 }, + { FIP_KEY_FRONT_STOP, 458, 68, 476, 85 }, + { FIP_KEY_FRONT_PAUSE, 497, 68, 515, 85 }, + { FIP_KEY_FRONT_SKIP_PREV, 579, 68, 597, 85 }, + { FIP_KEY_FRONT_SKIP_NEXT, 609, 68, 627, 85 }, + { FIP_KEY_FRONT_REWIND, 653, 68, 671, 85 }, + { FIP_KEY_FRONT_FORWARD, 683, 68, 701, 85 }, + { -1, -1, -1, -1, -1 } + }; + + fip_button = -1; + for (int i = 0; keytabl[i].fip_key != -1; i++) + { + if (x >= keytabl[i].x1 && x <= keytabl[i].x2 + && y >= keytabl[i].y1 && y <= keytabl[i].y2) + { + fip_button = keytabl[i].fip_key; + break; + } + } + + if (fip_button != -1) + SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(32649))); + else + SetCursor(::LoadCursor(NULL, IDC_ARROW)); + + SetWindowText(hWnd, wndtitle); + } + break; + } + case WM_LBUTTONDOWN: + { + if (fip_button != -1) + fip_lastkey = fip_button; + } + break; + default: + return(DefWindowProc(hWnd, uMsg, wParam, lParam)); + } + return((LRESULT)NULL); +} + +///////////////////////////////////////////// + +static BOOL init(void) +{ + //InitCommonControls(); + + WNDCLASS wc; + + wc.style = (UINT)NULL; + wc.lpfnWndProc = (WNDPROC)MainWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandle(NULL); + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName ="SPInitClass"; + return (RegisterClass(&wc) != 0); +} + +static void cwnd() +{ + HWND hWnd; + int w = 720,h = 480+yoffset; + int xcoord = GetSystemMetrics(SM_CXSCREEN)/2-w/2; + int ycoord = GetSystemMetrics(SM_CYSCREEN)/2-h/2; + hWnd = CreateWindow("SPInitClass", wndtitle, WS_OVERLAPPED|WS_SYSMENU, xcoord, ycoord, w, h, NULL, NULL, GetModuleHandle(NULL), NULL); + RECT dstrect; + GetClientRect(hWnd, &dstrect); + int dx = w*2 - (dstrect.right - dstrect.left); + int dy = h*2 - (dstrect.bottom - dstrect.top); + SetWindowPos(hWnd, HWND_TOP, GetSystemMetrics(SM_CXSCREEN) / 2 - dx / 2, + GetSystemMetrics(SM_CYSCREEN) / 2 - dy / 2, dx, dy, 0); + + khwl_handle = (int)hWnd; + ShowWindow(hWnd, SW_SHOW); + UpdateWindow(hWnd); +} + +BOOL khwl_init(BOOL /*applymodule*/) +{ + khwl_inityuv(); + + khwl_deinit(); + + init(); + cwnd(); + + buf = (BYTE *)SPmalloc(640*480 + 1024 + 8); + backbuf = (DWORD *)SPmalloc(720 * 480 * sizeof(DWORD)); + memset(backbuf, 0, 720*480*sizeof(DWORD)); + osdbuf = (DWORD *)SPmalloc(720 * 480 * sizeof(DWORD)); + + int bs = 1048576; + BUF_BASE = (BYTE *)VirtualAlloc((void *)0x016c0000/*0x01680000*/, bs, MEM_RESERVE, PAGE_READWRITE); + BUF_BASE = (BYTE *)VirtualAlloc(BUF_BASE, bs, MEM_COMMIT, PAGE_READWRITE); + if (BUF_BASE == NULL) + { + //int err = GetLastError(); + BUF_BASE = (BYTE *)VirtualAlloc(NULL, bs, MEM_COMMIT, PAGE_READWRITE); + } + if (BUF_BASE == NULL) + return FALSE; + + + khwl_parser_mutex = CreateMutex(NULL, FALSE, NULL); + khwl_parser = CreateThread (NULL, 16384, (LPTHREAD_START_ROUTINE)khwl_parser_proc, + (void *)0, CREATE_SUSPENDED, &khwl_parser_id); + + memset(&bi, 0, sizeof(bi)); + + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = 720; + bi.bmiHeader.biHeight = 480; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + + if (hbm == NULL) + { + hbm = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_FIP)); + + if (hbm == NULL) + { + int err = GetLastError(); + char tmp[25]; + sprintf(tmp, "Resources loading error = %d", err); + MessageBox((HWND)khwl_handle, tmp, "Error", MB_OK|MB_ICONEXCLAMATION); + return FALSE; + } + } + + max_wnd.x = 0; + max_wnd.y = 0; + max_wnd.w = 720; + max_wnd.h = 480; + + src_wnd = zoomed_wnd = valid_wnd = dest_wnd = max_wnd; + osd_wnd = max_wnd; + + CreateTvMask(); + + return TRUE; +} + +BOOL khwl_restoreparams() +{ + + return TRUE; +} + +BOOL khwl_deinit() +{ + if (khwl_handle == -1) + return FALSE; + + SPfree(buf); + SPfree(backbuf); + SPfree(osdbuf); + + CloseHandle(khwl_parser); + CloseHandle(khwl_parser_mutex); + + VirtualFree(BUF_BASE, 0, MEM_RELEASE); + BUF_BASE = NULL; + + DestroyWindow((HWND)khwl_handle); + khwl_handle = -1; + return TRUE; +} + +BOOL khwl_reset() +{ + if (khwl_handle == -1) + return FALSE; + + return 0; +} + +int khwl_osd_switch(KHWL_OSDSTRUCT *_osd, BOOL autoupd) +{ + static int TimerID = -1; + if (khwl_handle == -1) + return FALSE; + if (_osd->flags != 0 || autoupd) + { + if (TimerID != -1) + timeKillEvent(TimerID); + TimerID = timeSetEvent(1000, 1, OSDUpdate, 0, TIME_PERIODIC); + } + osd.addr = buf; + osd.bpp = 8; + osd.width = 640; + osd.height = 480; + *_osd = osd; + + + return 0; +} + +void khwl_get_osd_size(int *width, int *height) +{ + *width = 640;//osd.width; + *height = 480;//osd.height; +} + +bool khwl_msgloop() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) + { + if (GetMessage(&msg, NULL, 0, 0) == 0) + return false; + //if (TranslateAccelerator(hWnd, hAccel, &msg) == 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + return true; +} + +BOOL khwl_osd_update() +{ + InvalidateRect((HWND)khwl_handle, NULL, FALSE); + UpdateWindow((HWND)khwl_handle); + + return khwl_msgloop(); +} + +int khwl_osd_setalpha(int ) +{ + return 0; +} + +void khwl_osd_setpalette(BYTE *pal, int entry, BYTE r, BYTE g, BYTE b, BYTE a) +{ + // assert(entry >= 0 && entry < 256); + BYTE y, u, v; + entry <<= 2; + khwl_vgargbtotvyuv(r, g, b, &y, &u, &v); + pal[entry++] = a; // alpha + pal[entry++] = y; + pal[entry++] = u; + pal[entry] = v; +} + +void khwl_osd_setfullscreen(BOOL) +{ +} + +int *khwl_get_samplerates() +{ + static int rates[2][12] = + { + // chip rev.A + { 16000, 22050, 24000, 32000, 44100, 48000, -1 }, + // chip rev.B supports more samplerates + { 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, -1 }, + }; + return rates[0/*inl(SYS_REVID_REG) & 1*/]; +} + +#define MIN(a, b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a, b) (((a) >= (b)) ? (a) : (b)) + +int khwl_displayYUV(KHWL_YUV_FRAME *f) +{ + if (f->uv_buf != NULL) + { + memcpy(tmp_UV + f->uv_offs, f->uv_buf, f->uv_num); + yuv_dirty = TRUE; + } + if (f->y_buf != NULL) + { + memcpy(tmp_Y + f->y_offs, f->y_buf, f->y_num); + yuv_dirty = TRUE; + } + return 0; +} + +int khwl_audioswitch(BOOL /*ison*/) +{ + //int val = ison ? 1 : 0; + //return ioctl(khwl_handle, KHWL_AUDIOSWITCH, &val); + return TRUE; +} + +int khwl_play(int mode) +{ + if (mode == KHWL_PLAY_MODE_STEP) + { + if (!step_mode) + { + khwl_pause(); + step_mode = true; + } + return 0; + } + int last; + while ((last = ResumeThread(khwl_parser)) > 1) + ; + step_mode = false; + return 0; +} + +int khwl_pause() +{ + WaitForSingleObject(khwl_parser_mutex, INFINITE); + SuspendThread(khwl_parser); + ReleaseMutex(khwl_parser_mutex); + return 0; +} + +int khwl_stop() +{ + WaitForSingleObject(khwl_parser_mutex, INFINITE); + SuspendThread(khwl_parser); + + for (;;) + { + if (MPEG_VIDEO_STRUCT->in != NULL) + { + khwl_nextfeedpacket(MPEG_VIDEO_STRUCT); + continue; + } + if (MPEG_AUDIO_STRUCT->in != NULL) + { + khwl_nextfeedpacket(MPEG_AUDIO_STRUCT); + continue; + } + if (MPEG_SPU_STRUCT->in != NULL) + { + khwl_nextfeedpacket(MPEG_SPU_STRUCT); + continue; + } + break; + } + + + ReleaseMutex(khwl_parser_mutex); + + return 0; +} + +BOOL khwl_blockirq(BOOL block) +{ + if (block) + WaitForSingleObject(khwl_parser_mutex, INFINITE); + else + ReleaseMutex(khwl_parser_mutex); + + return TRUE; +} + +BOOL khwl_happeningwait(DWORD *) +{ + // do nothing + khwl_msgloop(); + Sleep(1); + return TRUE; +} + +BOOL khwl_poll(WORD , DWORD ) +{ + khwl_msgloop(); + Sleep(1); + return TRUE; +} + +BOOL khwl_ideswitch(BOOL ) +{ + return TRUE; +} + +int khwl_getfrequency() +{ + int temp = freq_reg; + + int div = (temp >> 8) & 0xff; + int mul = (temp >> 2) & 63; + + int freq = (27 * (mul + 2)) / ((div + 2) * 2); + return freq; +} + +BOOL khwl_setfrequency(int freq) +{ + if (freq < 100 || freq > 202) + return FALSE; + + int temp = freq_reg; + temp = temp & 0xF000; + int div = (temp >> 8) & 0xff; + //int mul = (temp >> 2) & 63; + + int mul = (freq * ((10 * div+20)*20) / 270 - 20 /* + 5 */) / 10; + if (mul < 0 || mul > 63) + return FALSE; + + temp = temp | 0x02; + temp = temp | (div << 8); + temp = temp | (mul << 2); + + freq_reg = temp & 0x7FFF; + return TRUE; +} + +char *khwl_gethw() +{ + static char hw[256]; +/* + char b[128]; + b[0] = '\0'; + khwl_getproperty(KHWL_BOARDINFO_SET, ebiBoardNameString, 256, b); + + DWORD v_ebiDeviceId, v_ebiSubId, v_ebiBoardVersion, v_ebiHwLibVersion, v_ebiUcodeVersion; + khwl_getproperty(KHWL_BOARDINFO_SET, ebiDeviceId, sizeof(DWORD), &v_ebiDeviceId); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiSubId, sizeof(DWORD), &v_ebiSubId); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiBoardVersion, sizeof(DWORD), &v_ebiBoardVersion); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiHwLibVersion, sizeof(DWORD), &v_ebiHwLibVersion); + khwl_getproperty(KHWL_BOARDINFO_SET, ebiUcodeVersion , sizeof(DWORD), &v_ebiUcodeVersion); +*/ + sprintf(hw, "%X.%c", 0x8500/*inl(SYS_CHIPID_REG)*/, 0/*inl(SYS_REVID_REG)*/ + 'A'); + + return hw; +} + +///////////////////////////////////////////////////////// + +extern int main(int argc, char *argv[]); + +int PASCAL WinMain (HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR lpszCmdLine, int /*nCmdShow*/) +{ + char *args[2] = { lpszCmdLine, NULL }; + + AllocConsole(); + + int hCrt = _open_osfhandle((long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); + FILE *hf = _fdopen( hCrt, "w" ); + //FILE *hf = fopen("sp.log", "w"); + *stdout = *hf; + int ret = setvbuf( stdout, NULL, _IONBF, 0 ); + + hCrt = _open_osfhandle((long) GetStdHandle(STD_ERROR_HANDLE), _O_TEXT); + hf = _fdopen( hCrt, "w" ); + *stderr = *hf; + ret = setvbuf( stderr, NULL, _IONBF, 0 ); + + return main(1, args); +} + diff --git a/src/libsp/win32/sp_memory.cpp b/src/libsp/win32/sp_memory.cpp new file mode 100644 index 0000000..267bbd2 --- /dev/null +++ b/src/libsp/win32/sp_memory.cpp @@ -0,0 +1,995 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer support lib memory debugging routines + * \file sp_memory.cpp + * \author ***** + * \version 0.1 + * \date 14.07.2002 (23.08.2001) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include + +//#define MEMDUMP +//#define TEST_UCLIBC + +// undefine our macros +#undef new +#undef delete + + +static bool special_case = false; + +////////////////////////////////////////////////////////////////////////// +// this is needed to ensure that mm starts first and ends last +int _crt_deinit() +{ +#ifdef SP_MEMDEBUG + special_case = true; + delete SPMemoryManager::mm; + special_case = false; +#endif + return 0; +} +int _crt_init() +{ + onexit(_crt_deinit); + +#ifdef SP_MEMDEBUG + special_case = true; + SPMemoryManager::mm = new SPMemoryManager(); + special_case = false; +#endif + + return 0; +} + +// this is VC-specific hack for calling before CRT +typedef int cb(void); +#pragma data_seg(".CRT$XIU") +static cb *autostart[] = { _crt_init }; +#pragma data_seg(".CRT$XPU") +static cb *autoexit[] = { _crt_deinit }; +#pragma data_seg() // reset data-segment + +#ifdef SP_MEMDEBUG + +#ifdef _DEBUG +#define SP_CRT_DEBUG +#endif + + +// global manager definition +SPMemoryManager *SPMemoryManager::mm = NULL; + +#ifdef SP_CRT_DEBUG +#define _NORMAL_BLOCK 1 +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +_CRTIMP void * __cdecl _malloc_dbg(size_t,int,const char *,int); +_CRTIMP void * __cdecl _realloc_dbg(void *,size_t,int,const char *,int); +_CRTIMP void __cdecl _free_dbg(void *,int); +#ifdef __cplusplus +} +#endif +#endif + +// Global new/new[] & delete/delete[] +////////////////////////////////////////////////////////////////////////// + +void *operator new(size_t reqSize) +{ + if (special_case) // used by mm itself + return calloc(reqSize, 1); + +#ifdef TEST_UCLIBC + return SPcalloc(reqSize); +#else + + SPMemoryManager &memManager = SPMemoryManager::GetHandle(); + + // zero allocation is valid (but strange...) + if(reqSize == 0) + { + reqSize = 1; + memManager.Log("Warning: Zero allocation in %s (%d)", memManager. + GetSourceName(memManager.srcFile), memManager.srcLine); + } + void *ptr = memManager.Alloc(memManager.srcFile, + memManager.srcLine, reqSize, SP_ALLOC_NEW); + + return ptr; +#endif +} + +// ----------------------------------------------------------------------- + +void *operator new[](size_t reqSize) +{ +#ifdef TEST_UCLIBC + return SPcalloc(reqSize); +#else + SPMemoryManager &memManager = SPMemoryManager::GetHandle(); + + // zero allocation is valid (but strange...) + if(reqSize == 0) + { + reqSize = 1; + memManager.Log("Warning: Zero allocation in %s (%d)", memManager. + GetSourceName(memManager.srcFile), memManager.srcLine); + } + void *ptr = memManager.Alloc(memManager.srcFile, + memManager.srcLine, reqSize, SP_ALLOC_NEW_ARRAY); + + return ptr; +#endif +} + +// ----------------------------------------------------------------------- + +void operator delete(void *reqAddress) +{ + if (special_case) // used by mm itself + { + free(reqAddress); + return; + } + +#ifdef TEST_UCLIBC + SPfree(reqAddress); +#else + + SPMemoryManager &memManager = SPMemoryManager::GetHandle(); + + // zero deallocation is valid (but strange...) + if (!reqAddress) + { + memManager.Log("Warning: Zero deallocation in %s (%d)", + memManager.GetSourceName(memManager.srcFile), + memManager.srcLine); + return; + } + + memManager.Dealloc(memManager.srcFile, memManager.srcLine, + SP_ALLOC_DELETE, reqAddress); +#endif +} + +// ----------------------------------------------------------------------- + +void operator delete[](void *reqAddress) +{ +#ifdef TEST_UCLIBC + SPfree(reqAddress); +#else + SPMemoryManager &memManager = SPMemoryManager::GetHandle(); + + // zero deallocation is valid (but strange...) + if (!reqAddress) + { + memManager.Log("Warning: Zero deallocation in %s (%d)", + memManager.GetSourceName(memManager.srcFile), + memManager.srcLine); + return; + } + memManager.Dealloc(memManager.srcFile, memManager.srcLine, + SP_ALLOC_DELETE_ARRAY, reqAddress); +#endif +} + +// SPMemoryManager member-functions +////////////////////////////////////////////////////////////////////////// + +SPMemoryManager::SPMemoryManager() : srcFile(NULL), srcLine(0), + prefixPattern(0xAAAAAAAA), postfixPattern(0xBBBBBBBB), + unusedPattern(0xCCCCCCCC), releasedPattern(0xDDDDDDDD), + currentAllocated(0), unitsBufferSize(0), borderSize(8), units(NULL), + unitsBuffer(NULL) +{ + memset(&memStats, 0, sizeof(memStats)); + BeginLog(); +} + +void* SPMemoryManager::Alloc(const char *file, const DWORD line, + const DWORD reqSize, const DWORD allocType) +{ + currentAllocated++; + if(!units) + { + // allocate 256 unit elements + units = (SPAllocUnit *)malloc(sizeof(SPAllocUnit) * 256); + if(units == NULL) + { + OutOfMemory(); + return NULL; + } + + memset(units, 0, sizeof(SPAllocUnit) * 256); + for(DWORD i = 0; i < 256 - 1; i++) + units[i].next = &units[i+1]; + SPAllocUnit **temp = (SPAllocUnit **)realloc(unitsBuffer, + (unitsBufferSize + 1) * sizeof(SPAllocUnit *)); + if(temp) + { + unitsBuffer = temp; + unitsBuffer[unitsBufferSize++] = units; + } + else + { + OutOfMemory(); + return NULL; + } + } + + SPAllocUnit *cur = units; + units = cur->next; + + // fill alloc unit + cur->reqSize = reqSize; + cur->actualSize = reqSize + borderSize * sizeof(DWORD) * 2; + cur->actualAddress = malloc(cur->actualSize); + if (cur->actualAddress == NULL) + { + OutOfMemory(); + return NULL; + } + cur->allocationType = allocType; + cur->reportedAddress = reinterpret_cast(cur->actualAddress) + + borderSize * sizeof(DWORD); + strncpy(cur->sourceFile, GetSourceName(const_cast(file)), + sizeof(cur->sourceFile) - 1); + cur->sourceLine = line; + cur->allocationNumber = currentAllocated; + + // insert unit into hash table + DWORD hashIndex = (reinterpret_cast(cur->reportedAddress) >> + 4) & SP_MM_HASHSIZEM; + if(hashTable[hashIndex]) + hashTable[hashIndex]->prev = cur; + cur->next = hashTable[hashIndex]; + cur->prev = NULL; + hashTable[hashIndex] = cur; + + // update stats + memStats.totalReportedMemory += cur->reqSize; + memStats.totalActualMemory += cur->actualSize; + memStats.totalAllocUnitCount++; + if(memStats.totalReportedMemory > memStats.peakReportedMemory) + memStats.peakReportedMemory = memStats.totalReportedMemory; + if(memStats.totalActualMemory > memStats.peakActualMemory) + memStats.peakActualMemory = memStats.totalActualMemory; + if(memStats.totalAllocUnitCount > memStats.peakAllocUnitCount) + memStats.peakAllocUnitCount = memStats.totalAllocUnitCount; + memStats.accumulatedReportedMemory += cur->reqSize; + memStats.accumulatedActualMemory += cur->actualSize; + memStats.accumulatedAllocUnitCount++; + + // prepare memory block + FillWithPattern(cur, unusedPattern); + + // calloc expects zero-filled memory + if(allocType == SP_ALLOC_CALLOC) + memset(cur->reportedAddress, 0, cur->reqSize); + + // preserve globals + ClearGlobals(); + +#ifdef MEMDUMP + FILE *fp = fopen(SP_MMDUMP_LOGFILENAME, "at"); + fprintf(fp, "+[%d] %s (%d):\t\t%d\t\t[%d]\n", currentAllocated, file, line, reqSize,memStats.totalReportedMemory); + fclose(fp); +#endif + + return cur->reportedAddress; +} + +// ----------------------------------------------------------------------- + +char* SPMemoryManager::Strdup(const char *file, const DWORD line, + const char *source) +{ + DWORD reqSize; + if(!source) + reqSize = 1; + else + reqSize = strlen(source) + 1; + DWORD allocType = SP_ALLOC_STRDUP; + + currentAllocated++; + if(!units) + { + // allocate 256 unit elements + units = (SPAllocUnit *)malloc(sizeof(SPAllocUnit) * 256); + if(units == NULL) + { + OutOfMemory(); + return NULL; + } + + memset(units, 0, sizeof(SPAllocUnit) * 256); + for(DWORD i = 0; i < 256 - 1; i++) + units[i].next = &units[i+1]; + SPAllocUnit **temp = (SPAllocUnit **)realloc(unitsBuffer, + (unitsBufferSize + 1) * sizeof(SPAllocUnit *)); + if (temp) + { + unitsBuffer = temp; + unitsBuffer[unitsBufferSize++] = units; + } + else + { + OutOfMemory(); + return NULL; + } + } + + SPAllocUnit *cur = units; + units = cur->next; + + // fill alloc unit + cur->reqSize = reqSize; + cur->actualSize = reqSize + borderSize * sizeof(DWORD) * 2; + cur->actualAddress = malloc(cur->actualSize); + if(!cur->actualAddress) + { + OutOfMemory(); + return NULL; + } + cur->allocationType = allocType; + cur->reportedAddress = reinterpret_cast(cur->actualAddress) + + borderSize * sizeof(DWORD); + strncpy(cur->sourceFile, GetSourceName(const_cast(file)), + sizeof(cur->sourceFile) - 1); + cur->sourceLine = line; + cur->allocationNumber = currentAllocated; + + // insert unit into hash table + DWORD hashIndex = (reinterpret_cast(cur->reportedAddress) >> + 4) & SP_MM_HASHSIZEM; + if(hashTable[hashIndex]) + hashTable[hashIndex]->prev = cur; + cur->next = hashTable[hashIndex]; + cur->prev = NULL; + hashTable[hashIndex] = cur; + + // update stats + memStats.totalReportedMemory += cur->reqSize; + memStats.totalActualMemory += cur->actualSize; + memStats.totalAllocUnitCount++; + if(memStats.totalReportedMemory > memStats.peakReportedMemory) + memStats.peakReportedMemory = memStats.totalReportedMemory; + if(memStats.totalActualMemory > memStats.peakActualMemory) + memStats.peakActualMemory = memStats.totalActualMemory; + if(memStats.totalAllocUnitCount > memStats.peakAllocUnitCount) + memStats.peakAllocUnitCount = memStats.totalAllocUnitCount; + memStats.accumulatedReportedMemory += cur->reqSize; + memStats.accumulatedActualMemory += cur->actualSize; + memStats.accumulatedAllocUnitCount++; + + // prepare memory block + FillWithPattern(cur, unusedPattern); + + // copy strdup string + if(source) + strcpy(static_cast(cur->reportedAddress), source); + + // preserve globals + ClearGlobals(); + +#ifdef MEMDUMP + FILE *fp = fopen(SP_MMDUMP_LOGFILENAME, "at"); + fprintf(fp, "+[%d] %s (%d):\t\t%d\t\t[%d]\n", currentAllocated, file, line, reqSize,memStats.totalReportedMemory); + fclose(fp); +#endif + + return static_cast(cur->reportedAddress); +} + +// ----------------------------------------------------------------------- + +void* SPMemoryManager::Realloc(const char *file, const DWORD line, + const DWORD reqSize, void* reqAddress, const DWORD reallocType) +{ + if(!reqAddress) + return Alloc(file, line, reqSize, reallocType); + + SPAllocUnit *u = FindAllocUnit(reqAddress); + if(u == NULL) + { + Log("Request to reallocate RAM that was never allocated in %s (%d)", + GetSourceName(const_cast(file)), line); + return NULL; + } + + currentAllocated++; + + ValidateUnit(u); + + if(!(u->allocationType == SP_ALLOC_MALLOC|| u->allocationType == + SP_ALLOC_CALLOC || u->allocationType == SP_ALLOC_REALLOC)) + Log("Allocation/deallocation mismatch in %s (%d)", + GetSourceName(const_cast(file)), line); + + DWORD originalSize = u->reqSize; + + // do the reallocation + void *oldReqAddress = reqAddress; + DWORD newActualSize = reqSize + borderSize * sizeof(DWORD) * 2; + void *newActualAddress = realloc(u->actualAddress, newActualSize); + if(!newActualAddress) + { + OutOfMemory(); + return NULL; + } + + memStats.totalReportedMemory -= u->reqSize; + memStats.totalActualMemory -= u->actualSize; + + u->actualSize = newActualSize; + u->actualAddress = newActualAddress; + u->reqSize = reqSize; + u->reportedAddress = reinterpret_cast(newActualAddress) + + borderSize * sizeof(DWORD); + u->allocationType = reallocType; + u->sourceLine = line; + u->allocationNumber = currentAllocated; + + strncpy(u->sourceFile, GetSourceName(const_cast(file)), + sizeof(u->sourceFile) - 1); + + DWORD hashIndex; + if(oldReqAddress != u->reportedAddress) + { + // remove this allocation unit from the hash table + { + hashIndex = (reinterpret_cast(oldReqAddress) >> 4) & + SP_MM_HASHSIZEM; + if(hashTable[hashIndex] == u) + hashTable[hashIndex] = hashTable[hashIndex]->next; + else + { + if(u->prev) u->prev->next = u->next; + if(u->next) u->next->prev = u->prev; + } + } + + // re-insert it back into the hash table + hashIndex = (reinterpret_cast(u->reportedAddress) >> 4) & + SP_MM_HASHSIZEM; + if(hashTable[hashIndex]) + hashTable[hashIndex]->prev = u; + u->next = hashTable[hashIndex]; + u->prev = NULL; + hashTable[hashIndex] = u; + } + + memStats.totalReportedMemory += u->reqSize; + memStats.totalActualMemory += u->actualSize; + if(memStats.totalReportedMemory > memStats.peakReportedMemory) + memStats.peakReportedMemory = memStats.totalReportedMemory; + if(memStats.totalActualMemory > memStats.peakActualMemory) + memStats.peakActualMemory = memStats.totalActualMemory; + DWORD deltaReportedSize = reqSize - originalSize; + if (deltaReportedSize > 0) + { + memStats.accumulatedReportedMemory += deltaReportedSize; + memStats.accumulatedActualMemory += deltaReportedSize; + } + // prepare the allocation + FillWithPattern(u, unusedPattern, originalSize); + + // preserve globals + ClearGlobals(); + +#ifdef MEMDUMP + FILE *fp = fopen(SP_MMDUMP_LOGFILENAME, "at"); + fprintf(fp, "*[%d] %s (%d):\t\t%d->%d\t\t[%d]\n", currentAllocated, file, line, originalSize, reqSize, memStats.totalReportedMemory); + fclose(fp); +#endif + + return u->reportedAddress; +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::Dealloc(const char *file, const DWORD line, + const DWORD deallocType, void* reqAddress) +{ + SPAllocUnit *u = FindAllocUnit(reqAddress); + if (u == NULL) + { + Log("Request to deallocate RAM that was never allocated in %s" + " (%d)", GetSourceName(const_cast(file)), line); + return; + } + + ValidateUnit(u); + + if(!((deallocType == SP_ALLOC_DELETE && u->allocationType == SP_ALLOC_NEW) || + (deallocType == SP_ALLOC_DELETE_ARRAY && u->allocationType == SP_ALLOC_NEW_ARRAY) || + (deallocType == SP_ALLOC_FREE && u->allocationType == SP_ALLOC_MALLOC) || + (deallocType == SP_ALLOC_FREE && u->allocationType == SP_ALLOC_CALLOC) || + (deallocType == SP_ALLOC_FREE && u->allocationType == SP_ALLOC_REALLOC) || + (deallocType == SP_ALLOC_FREE && u->allocationType == SP_ALLOC_STRDUP) || + (deallocType == SP_ALLOC_UNKNOWN))) + { + Log("Allocation/deallocation mismatch in %s (%d)", + GetSourceName(const_cast(file)), line); + } + + // unfortunately, code has no effect because of MS debug libs :( + FillWithPattern(u, releasedPattern); + + free(u->actualAddress); + + DWORD hashIndex = ((DWORD) u->reportedAddress >> 4) & SP_MM_HASHSIZEM; + if (hashTable[hashIndex] == u) + hashTable[hashIndex] = u->next; + else + { + if (u->prev) u->prev->next = u->next; + if (u->next) u->next->prev = u->prev; + } + + // remove this allocation from our stats + memStats.totalReportedMemory -= u->reqSize; + memStats.totalActualMemory -= u->actualSize; + memStats.totalAllocUnitCount--; + + memset(u, 0, sizeof(SPAllocUnit)); + u->next = units; + units = u; + + // preserve globals + ClearGlobals(); + +#ifdef MEMDUMP + FILE *fp = fopen(SP_MMDUMP_LOGFILENAME, "at"); + fprintf(fp, "-[%d] %s (%d):\t\t%d\t\t[%d]\n", currentAllocated, file, line, u->reqSize, memStats.totalReportedMemory); + fclose(fp); +#endif + +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::Log(char *message, ...) +{ + va_list l; + va_start(l, message); + + char *lasterr = (char *)malloc (1024); + vsprintf(lasterr, message, l); + + FILE *fp = fopen(SP_MM_LOGFILENAME, "at"); + vfprintf(fp, message, l); + fprintf(fp, "\n"); + fclose(fp); + + free(lasterr); +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::BeginLog() +{ + FILE *fp = fopen(SP_MM_LOGFILENAME, "wt"); + + fprintf(fp, "SigmaPlayer memory manager report\n"); + fprintf(fp, "--------------------------------------------------------" + "------------------------\n\n"); + fclose(fp); + +#ifdef MEMDUMP + fp = fopen(SP_MMDUMP_LOGFILENAME, "wt"); + fclose(fp); +#endif + +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::LeakReport() +{ + // log final stats + LogStats(); + + FILE *fp = fopen(SP_MM_LOGFILENAME, "at"); + if (!fp) return; + + static char timeString[25]; + memset(timeString, 0, sizeof(timeString)); + time_t t = time(NULL); + struct tm *tme = localtime(&t); + + fprintf(fp, "\n------------------------------------------------------" + "--------------------------\n"); + fprintf(fp, "Memory leak report for: %02d/%02d/%04d %02d:%02d:%02d\n" + , tme->tm_mon + 1, tme->tm_mday, tme->tm_year + 1900, + tme->tm_hour, tme->tm_min, tme->tm_sec); + fprintf(fp, "--------------------------------------------------------" + "------------------------\n\n"); + + if (memStats.totalAllocUnitCount) + fprintf(fp, "%d memory leak%s found:\n", memStats. + totalAllocUnitCount, memStats.totalAllocUnitCount == 1 ? "":"s"); + else + { + fprintf(fp, "No memory leaks found.\n"); + + // free our memory + if (unitsBuffer) + { + for (DWORD i = 0; i < unitsBufferSize; i++) + free(unitsBuffer[i]); + free(unitsBuffer); + unitsBuffer = 0; + unitsBufferSize = 0; + units = NULL; + } + } + fprintf(fp, "\n"); + + if(memStats.totalAllocUnitCount) + DumpAllocs(fp); + fclose(fp); +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::LogStats() +{ + FILE *fp = fopen(SP_MM_LOGFILENAME, "at"); + if (!fp) return; + + static char timeString[25]; + memset(timeString, 0, sizeof(timeString)); + time_t t = time(NULL); + struct tm *tme = localtime(&t); + + fprintf(fp, "\nMemory stats for: %02d/%02d/%04d %02d:%02d:%02d\n", + tme->tm_mon + 1, tme->tm_mday, tme->tm_year + 1900, tme->tm_hour, + tme->tm_min, tme->tm_sec); + fprintf(fp, "--------------------------------------------------------" + "------------------------\n\n"); + + fprintf(fp, "Total allocated memory : 0x%08X (%10u)\n", + memStats.totalActualMemory, memStats.totalActualMemory); + fprintf(fp, "Total reported memory : 0x%08X (%10u)\n", + memStats.totalReportedMemory, memStats.totalReportedMemory); + fprintf(fp, "Total allocation units : 0x%08X (%10u)\n\n", + memStats.totalAllocUnitCount, memStats.totalAllocUnitCount); + + fprintf(fp, "Peak allocated memory : 0x%08X (%10u)\n", + memStats.peakActualMemory, memStats.peakActualMemory); + fprintf(fp, "Peak reported memory : 0x%08X (%10u)\n", + memStats.peakReportedMemory, memStats.peakReportedMemory); + fprintf(fp, "Peak allocation units : 0x%08X (%10u)\n\n", + memStats.peakAllocUnitCount, memStats.peakAllocUnitCount); + + fprintf(fp, "Accum allocated memory : 0x%08X (%10u)\n", + memStats.accumulatedActualMemory, + memStats.accumulatedActualMemory); + fprintf(fp, "Accum reported memory : 0x%08X (%10u)\n", + memStats.accumulatedReportedMemory, + memStats.accumulatedReportedMemory); + fprintf(fp, "Accum allocation units : 0x%08X (%10u)\n", + memStats.accumulatedAllocUnitCount, + memStats.accumulatedAllocUnitCount); + + fclose(fp); +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::DumpAllocs(FILE *fp) +{ + fprintf(fp, "Alloc. Addr Size Addr Size " + " \n"); + fprintf(fp, "Number Reported Required Actual Actual Unus" + "ed Method Allocated by \n"); + fprintf(fp, "------ ---------- ---------- ---------- ---------- -----" + "----- -------- -----------------\n"); + + for (DWORD i = 0; i < 4096; i++) + { + SPAllocUnit *ptr = hashTable[i]; + while(ptr) + { + fprintf(fp, "%06d 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %-8s %s" + " (%d)\n", + ptr->allocationNumber, + reinterpret_cast(ptr->reportedAddress), + ptr->reqSize, + reinterpret_cast(ptr->actualAddress), + ptr->actualSize, + CalculateUnused(ptr), + allocTypes[ptr->allocationType], + GetSourceName(ptr->sourceFile), + ptr->sourceLine); + + ptr = ptr->next; + } + } +} + +void SPMemoryManager::DumpLastAlloc(FILE *fp) +{ + for (DWORD i = 0; i < 4096; i++) + { + SPAllocUnit *ptr = hashTable[i]; + while(ptr) + { + if (ptr->allocationNumber == currentAllocated) + { + fprintf(fp, "%06d 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %-8s %s" + " (%d)\n", + ptr->allocationNumber, + reinterpret_cast(ptr->reportedAddress), + ptr->reqSize, + reinterpret_cast(ptr->actualAddress), + ptr->actualSize, + CalculateUnused(ptr), + allocTypes[ptr->allocationType], + GetSourceName(ptr->sourceFile), + ptr->sourceLine); + return; + } + ptr = ptr->next; + } + } +} + +void SPMemoryManager::TEST_DUMP() +{ + static int j = -1; + static SPAllocUnit au[10000]; + + FILE *fp = fopen(SP_MM_LOGFILENAME, "at"); + if (!fp) return; + fprintf(fp, "\n\n ------- MEM.DIFFERENCE --------\n"); + + if (j < 0) + { + fprintf(fp, "STAGE 0\n\n"); + j = 0; + for (DWORD i = 0; i < 4096; i++) + { + SPAllocUnit *ptr = hashTable[i]; + while(ptr) + { + memcpy(&au[j++], ptr, sizeof(SPAllocUnit)); + ptr = ptr->next; + if (j > 10000) + { + exit(0); + } + } + } + } else + { + fprintf(fp, "STAGE 1\n\n"); + for (DWORD i = 0; i < 4096; i++) + { + SPAllocUnit *ptr = hashTable[i]; + while(ptr) + { + bool was = false; + for (int k = 0; k < j; k++) + { + if (au[k].allocationNumber == ptr->allocationNumber) + { + was = true; + au[k].next = (SPAllocUnit *)1; + break; + } + } + if (!was) + { + fprintf(fp, "%06d 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %-8s %s" + " (%d)\n", + ptr->allocationNumber, + reinterpret_cast(ptr->reportedAddress), + ptr->reqSize, + reinterpret_cast(ptr->actualAddress), + ptr->actualSize, + CalculateUnused(ptr), + allocTypes[ptr->allocationType], + GetSourceName(ptr->sourceFile), + ptr->sourceLine); + } + ptr = ptr->next; + } + } + + fprintf(fp, "\n-------------------------------------------\n\n"); + for (int k = 0; k < j; k++) + { + if ((DWORD)au[k].next != 1) + { + SPAllocUnit *ptr = &au[k]; + fprintf(fp, "%06d 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %-8s %s" + " (%d)\n", + ptr->allocationNumber, + reinterpret_cast(ptr->reportedAddress), + ptr->reqSize, + reinterpret_cast(ptr->actualAddress), + ptr->actualSize, + CalculateUnused(ptr), + allocTypes[ptr->allocationType], + GetSourceName(ptr->sourceFile), + ptr->sourceLine); + } + } + + j = -1; + } + fclose(fp); +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::SetOwner(const char *file, const DWORD line) +{ + srcFile = const_cast(file); + srcLine = line; +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::ClearGlobals() +{ + srcFile = ""; + srcLine = NULL; +} + +// ----------------------------------------------------------------------- + +char* SPMemoryManager::GetSourceName(char *sourceFile) +{ + char *ptr = strrchr(sourceFile, '\\'); + if(ptr) return ptr + 1; + return sourceFile; +} + +// ----------------------------------------------------------------------- + +SPAllocUnit* SPMemoryManager::FindAllocUnit(void *reqAddress) +{ + if(!reqAddress) + return NULL; + + DWORD hashIndex = ((DWORD)reqAddress >> 4) & SP_MM_HASHSIZEM; + SPAllocUnit *ptr = hashTable[hashIndex]; + while(ptr) + { + if(ptr->reportedAddress == reqAddress) + return ptr; + ptr = ptr->next; + } + return NULL; +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::FillWithPattern(SPAllocUnit *u, DWORD pattern, + DWORD originalSize) +{ + DWORD i; + DWORD *lptr = reinterpret_cast(reinterpret_cast + (u->reportedAddress) + originalSize); + int length = u->reqSize - originalSize; + if(length > 0) + { + for(i = 0; i<(static_cast(length) >> 2); i++, lptr++) + { + *lptr = pattern; + } + // fill the remainder + DWORD shiftCount = 0; + char *cptr = reinterpret_cast(lptr); + for(i = 0; i<(static_cast(length) & 0x3); i++, cptr++, + shiftCount += 8) + { + *cptr = (char)((pattern & (0xff << shiftCount)) >> shiftCount); + } + } + + // write in the prefix/postfix bytes + DWORD *pre = reinterpret_cast(u->actualAddress); + DWORD *post = reinterpret_cast(reinterpret_cast + (u->actualAddress) + u->actualSize - borderSize * sizeof(DWORD)); + for(i = 0; i < borderSize; i++, pre++, post++) + { + *pre = prefixPattern; + *post = postfixPattern; + } +} + +// ----------------------------------------------------------------------- + +DWORD SPMemoryManager::CalculateUnused(SPAllocUnit *u) +{ + const DWORD *ptr = (const DWORD *)u->reportedAddress; + DWORD count = 0; + for(DWORD i = 0; i < u->reqSize; i += sizeof(DWORD), ptr++) + if(*ptr == unusedPattern) count += sizeof(DWORD); + return count; +} + +// ----------------------------------------------------------------------- + +BOOL SPMemoryManager::ValidateUnit(SPAllocUnit *u) +{ + // make sure the borders are untouched + DWORD *pre = reinterpret_cast(u->actualAddress); + DWORD *post = reinterpret_cast(reinterpret_cast + (u->actualAddress) + u->actualSize - borderSize * sizeof(DWORD)); + BOOL errorFlag = false; + + for(DWORD i = 0; i < borderSize; i++, pre++, post++) + { + if (*pre != prefixPattern) + { + Log("A memory allocation unit was corrupt because of an underrun:"); + DumpUnit(u); + errorFlag = true; + } + + if (*post != postfixPattern) + { + Log("A memory allocation unit was corrupt because of an overrun:"); + DumpUnit(u); + errorFlag = true; + } + } + return !errorFlag; +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::DumpUnit(SPAllocUnit *u) +{ + Log("Address (reported): %010p", u->reportedAddress); + Log("Address (actual) : %010p", u->actualAddress); + Log("Size (required) : 0x%08X", u->reqSize); + Log("Size (actual) : 0x%08X", u->actualSize); + Log("Owner : %s(%d)", u->sourceFile, u->sourceLine); + Log("Allocation type : %s", allocTypes[u->allocationType]); + Log("Allocation number : %d", u->allocationNumber); +} + +// ----------------------------------------------------------------------- + +void SPMemoryManager::OutOfMemory() +{ + Log("Ran out of memory in %s (%d)!", + GetSourceName(srcFile), srcLine); + SPMemoryManager::GetHandle().LeakReport(); + abort(); +} + +// ----------------------------------------------------------------------- + +#endif // SP_MEMDEBUG \ No newline at end of file diff --git a/src/libsp/win32/sp_module.cpp b/src/libsp/win32/sp_module.cpp new file mode 100644 index 0000000..631bf19 --- /dev/null +++ b/src/libsp/win32/sp_module.cpp @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Module system support source file. + * For Win32. + * \file sp_module.cpp + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include + +extern "C" +{ + +// portions of code from uClibc... +#ifdef COMPILE_MODULE + +extern int main(int argc, char **argv, char **envp); + +__declspec( dllexport ) void ModuleLink(char *fname, char *arg) +{ + char *argv[2]; + argv[0] = fname; + argv[1] = arg; + main(2, argv, NULL); +} + +BOOL WINAPI DllMain(HINSTANCE , DWORD , LPVOID) +{ + return TRUE; +} + +void module_wait() +{ +} + +#else ///////////////////////////////////////////////////////////////////////// + +extern "C" +{ + typedef void (*ModuleLink_decl)(char *, char *); + ModuleLink_decl ModuleLink; +} + +int module_binary_load(char *fname, char *arg) +{ + char *fpath = (fname[0] == '/') ? fname + 1 : fname; + HMODULE h = LoadLibrary(fpath); + if (h == NULL) + { + DWORD err = GetLastError(); + printf("Module: Load error = %d.\n", err); + return -1; + } + + ModuleLink = (ModuleLink_decl)GetProcAddress(h, "ModuleLink"); + if (ModuleLink == NULL) + return -1; + ModuleLink(fname, arg); + + return (int)h; +} + +int module_binary_unload(int pid) +{ + HMODULE h = (HMODULE)pid; + return FreeLibrary(h) ? 0 : -1; +} + +void module_copy_func(void *from, void *to) +{ + #define JMP_OPCODE_SIZE 5 + ULONGLONG diff = (DWORD)from - (DWORD)to - JMP_OPCODE_SIZE; + *((ULONGLONG *)to) = 0xE9 | (diff << 8); +} + +void module_clear_func(void *func) +{ + *((ULONGLONG *)func) = 0; +} + +#endif +} \ No newline at end of file diff --git a/src/libsp/win32/win32-stuff.c b/src/libsp/win32/win32-stuff.c new file mode 100644 index 0000000..e3e266b --- /dev/null +++ b/src/libsp/win32/win32-stuff.c @@ -0,0 +1,247 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - win32 compatibility stuff... + * \file win32-stuff.c + * \author bombur + * \version 0.1 + * \date 4.05.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#undef _WINSOCKAPI_ +#include "win32-stuff.h" +#define _WINSOCKAPI_ // no timeval +#pragma warning (disable : 4115) +#include +#include +#pragma warning (default : 4115) +#include + +typedef void (*sigaction_type) (int, siginfo_t *, void *); + +static HANDLE sigathr = NULL; +static DWORD sigathr_id = 0; +static sigaction_type sa_siga = NULL; + + +DWORD WINAPI SigThreadProc(LPVOID lpParameter) +{ + // wait 10 sec and call sigaction + Sleep(10000); + if (sa_siga != NULL) + { + siginfo_t sigi; + memset(&sigi, 0, sizeof(sigi)); + sigi.si_pid = (int)lpParameter; + sa_siga(SIGCHLD, &sigi, 0); + } + return 0; +} + + +#undef _WINSOCKAPI_ + +#pragma comment(lib, "winmm.lib") + +#pragma warning (disable : 4100) +#pragma warning (disable : 4054) + +extern int fcntl (int __fd, int __cmd, ...) +{ + return 0; +} + +void usleep(unsigned int usecs) +{ + Sleep(usecs / 1000); +} + +unsigned int sleep (unsigned int __seconds) +{ + Sleep(__seconds); + return 0; +} + +unsigned int alarm (unsigned int seconds) +{ + struct itimerval old, new; + new.it_interval.tv_usec = 0; + new.it_interval.tv_sec = 0; + new.it_value.tv_usec = 0; + new.it_value.tv_sec = (long int) seconds; + if (setitimer (ITIMER_REAL, &new, &old) < 0) + return 0; + else + return (unsigned int)old.it_value.tv_sec; +} + +int kill (__pid_t __pid, int __sig) +{ + //if (__pid == 1) + { + TerminateThread(sigathr, 0); + sigathr = NULL; + } + return 0; +} +__pid_t vfork (void) +{ + int pid = 1; + // we currently won't allow more than 1 childs... + if (sigathr != NULL) + { + TerminateThread(sigathr, 0); + sigathr = NULL; + } + + sigathr = CreateThread(NULL, 0, SigThreadProc, (void *)pid, + 0, &sigathr_id); + return pid; +} + +__pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options) +{ + return 1; +} + +int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout) +{ + usleep(10000); + return 0; +} + +int openpty (int *__amaster, int *__aslave, char *__name, + struct termios *__termp, struct winsize *__winp) +{ + *__amaster = 0; + *__aslave = 0; + if (__name != NULL) + *__name = '\0'; + return 0; +} + +int tcgetattr (int __fd, struct termios *__termios_p) +{ + return 0; +} + +int tcsetattr (int __fd, int __optional_actions, + struct termios *__termios_p) +{ + return -1; +} + +int setitimer (enum __itimer_which __which, const struct itimerval *__new, struct itimerval *__old) +{ + return 0; +} + +int sigaction (int __sig, struct sigaction *__act, struct sigaction *__oact) +{ + if (__act != NULL) + { + sa_siga = __act->sa_sigaction; + } + return 0; +} + +int gettimeofday (struct timeval *__tv, struct timezone *__tz) +{ + DWORD ms = timeGetTime(); + __tv->tv_sec = ms / 1000; + __tv->tv_usec = (ms % 1000) * 1000; + return 0; +} + + +void *alloca (unsigned __size) +{ + return _alloca(__size); +} + +int fsync(int fd) +{ + return 0; +} + +int fchdir (int __fd) +{ + return 0; +} + +#ifndef _WINSOCKAPI_ + +int select (int __nfds, fd_set *__readfds, + fd_set *__writefds, fd_set *__exceptfds, + struct timeval *__timeout) +{ + return 0; +} + +#endif + +#if 0 +void *mmap (void *__addr, int __len, int __prot, + int __flags, int __fd, int __offset) +{ + return malloc(__len); +} + +int munmap (void *__addr, int __len) +{ + free(__addr); + return 0; +} +#endif + +int sysinfo (struct sysinfo *__info) +{ + if (__info != NULL) + { + MEMORYSTATUS mstat; + memset(__info, 0, sizeof(struct sysinfo)); + + GlobalMemoryStatus (&mstat); + + __info->uptime = clock(); + __info->totalram = mstat.dwTotalPhys; + __info->freeram = mstat.dwAvailPhys; + __info->procs = 1; + } + return 0; +} + +int ioctl (int __fd, unsigned long int __request, ...) +{ + return 0; +} + +int ftruncate(int fd, off_t length) +{ + return 0; +} + +__int64 strtoll (const char *__nptr, char ** __endptr, int __base) +{ + return (__int64)strtol(__nptr, __endptr, __base); +} + +unsigned __int64 strtoull (const char * __nptr, char **__endptr, int __base) +{ + return (unsigned __int64)strtoul(__nptr, __endptr, __base); +} diff --git a/src/media.cpp b/src/media.cpp new file mode 100644 index 0000000..7512f4b --- /dev/null +++ b/src/media.cpp @@ -0,0 +1,647 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - media access source file. Uses libdvdnav. + * \file media.cpp + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "player.h" +#include "dvd.h" +#include "audio.h" +#include "video.h" +#include "cdda.h" +#include "media.h" + + +static int cur_bufpos = 0, cur_bufleft = -1; +static int cur_chunkleft = -1; +static BYTE *cur_copybuf = NULL; +static MEDIA_TYPES media_type = MEDIA_TYPE_UNKNOWN; +// fip 'disc' index +static int fipdisc_i = 0; +static int update_counter = 0; +static int fd = -1; +static int numread = 0; +static LONGLONG file_pos = 0; + +#ifdef INTERNAL_VIDEO_PLAYER +static VIDEO_CHUNK_TYPE chtype = VIDEO_CHUNK_UNKNOWN; +#endif + +int media_open(const char *path, MEDIA_TYPES mtype) +{ + cur_bufleft = -1; + media_type = mtype; + numread = 0; + file_pos = 0; + if (mtype == MEDIA_TYPE_DVD) + { + MPEG_PACKET_LENGTH = 2048; + MPEG_NUM_PACKETS = 512; + + if (dvd_open(path) < 0) + return -1; + + } + else if (mtype == MEDIA_TYPE_CDDA) + { + MPEG_PACKET_LENGTH = 2352; + MPEG_NUM_PACKETS = 512; + + if (!cdda_open()) + { + msg_error("Media: Couldn't open CDDA: %s\n", path); + return -1; + } + + } +#ifdef INTERNAL_VIDEO_PLAYER + else if (mtype == MEDIA_TYPE_VIDEO) + { + MPEG_PACKET_LENGTH = 0; // use variable packet size + MPEG_NUM_PACKETS = 2048; + + if (!video_open(path)) + { + video_close(); + msg_error("Media: Couldn't open video: %s\n", path); + return -1; + } + } +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (mtype == MEDIA_TYPE_AUDIO) + { + MPEG_PACKET_LENGTH = 4096; + MPEG_NUM_PACKETS = 512; + + if (!audio_open(path)) + { + audio_close(); + msg_error("Media: Couldn't open audio: %s\n", path); + return -1; + } + } +#endif + + cur_bufpos = 0; + cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1); + cur_chunkleft = cur_bufleft; + cur_copybuf = NULL; + + fipdisc_i = 0; + fip_write_special(FIP_SPECIAL_CIRCLE_1 + fipdisc_i, 1); + + return 1; +} + +void set_media_type(MEDIA_TYPES mtype) +{ + media_type = mtype; +} + +inline int media_get_next_free(const MPEG_BUFFER which, MEDIA_EVENT *event, bool &update_fip) +{ + int ret = mpeg_find_free_blocks(which); + if (ret == 0) + { + // the buffer is not ready yet - wait... + *event = MEDIA_EVENT_NOP; + return 0; + } + cur_bufpos = 0; + cur_bufleft = mpeg_getbufsize(which); + cur_chunkleft = cur_bufleft; + + if (update_counter++ >= 8) + { + update_fip = true; + update_counter = 0; + } + return ret; +} + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//extern int num_packets; +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +int media_get_next_block(BYTE **buf, MEDIA_EVENT *event, int *len) +{ + if (cur_bufleft < 0) + { + cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1); + } + bool update_fip = false; + + *event = MEDIA_EVENT_OK; + + if (media_type == MEDIA_TYPE_DVD) + { + *len = MPEG_PACKET_LENGTH; + if (cur_bufleft < MPEG_PACKET_LENGTH) + { + if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0) + return 0; + } + BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1); + + BYTE *bb = tmpbuf + cur_bufpos; + int ret = dvd_get_next_block(&bb, (int *)event, len); + if (ret < 0) + return -1; + else if (ret) + media_accept_block(); + *buf = bb; + } +#ifdef INTERNAL_VIDEO_MPEG_PLAYER + else if (media_type == MEDIA_TYPE_MPEG) + { + *len = MPEG_PACKET_LENGTH; + if (cur_bufleft < MPEG_PACKET_LENGTH) + { + if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0) + return 0; + } + BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1); + + if (cur_bufpos == 0) + { + //numread = read(fd, tmpbuf, mpeg_getbufsize(MPEG_BUFFER_1)); + numread = video_read(tmpbuf, mpeg_getbufsize(MPEG_BUFFER_1)); + file_pos += numread; + if (update_counter++ >= 8) + { + update_fip = true; + update_counter = 0; + } + // sorry, we won't show the last few bytes... + numread &= ~(MPEG_PACKET_LENGTH - 1); + MPEG_PACKET_LENGTH = numread; + } + if (cur_bufpos + MPEG_PACKET_LENGTH > numread || numread < 1) + { + if (numread < 1 || video_eof()) + { + *buf = tmpbuf + cur_bufpos; + *event = MEDIA_EVENT_STOP; + return 1; + } + else + { + *event = MEDIA_EVENT_NOP; // retry? + return 0; + } + } + *buf = tmpbuf + cur_bufpos; + media_accept_block(); + } +#endif + else if (media_type == MEDIA_TYPE_CDDA) + { + *len = MPEG_PACKET_LENGTH; + if (cur_bufleft < MPEG_PACKET_LENGTH) + { + if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0) + return 0; + } + BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1); + + if (cur_bufpos == 0) + { + numread = cdda_read(tmpbuf, mpeg_getbufsize(MPEG_BUFFER_1) / MPEG_PACKET_LENGTH); + numread *= MPEG_PACKET_LENGTH; + if (update_counter++ >= 6) + { + update_fip = true; + update_counter = 0; + } + } + else if (cur_bufpos + MPEG_PACKET_LENGTH > numread) + { + if (cdda_feof()) + { + *event = MEDIA_EVENT_STOP; + } + else + { + *event = MEDIA_EVENT_NOP; // retry? + return 0; + } + } + *buf = tmpbuf + cur_bufpos; + media_accept_block(); + } +#ifdef INTERNAL_VIDEO_PLAYER + else if (media_type == MEDIA_TYPE_VIDEO) + { + if (cur_bufleft < 1) + { + if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0) + return 0; + cur_copybuf = NULL; + } + + BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1); +fragmented: + if (cur_bufleft < 16) + { + // read one more buffer + /* + numread = mpeg_getbufsize(MPEG_BUFFER_1) - cur_bufleft; + if (cur_copybuf == NULL) + cur_copybuf = tmpbuf + cur_bufpos; + int len = cur_bufleft; + if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0) + return 0; + tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1); + *buf = tmpbuf + cur_bufpos; + memcpy(tmpbuf, cur_copybuf, len); + cur_copybuf = NULL; + if ((numread = video_read(tmpbuf + len, numread)) == 0) + { + *event = MEDIA_EVENT_STOP; + return 1; + } + numread += len; + video_shiftpos(len); + */ + + if (media_skip_buffer(&tmpbuf) == 0) + return 0; + numread = mpeg_getbufsize(MPEG_BUFFER_1); + + } else + { + *buf = tmpbuf + cur_bufpos; + if (cur_bufpos == 0) + { + numread = mpeg_getbufsize(MPEG_BUFFER_1); + } + } + + for (;;) + { + chtype = video_getnext(tmpbuf + cur_bufpos, numread, &cur_bufpos, &cur_bufleft, &MPEG_PACKET_LENGTH); + if (chtype == VIDEO_CHUNK_FRAGMENT) + goto fragmented; + if (chtype != VIDEO_CHUNK_UNKNOWN) + break; + if (media_skip_buffer(&tmpbuf) == 0) + return 0; + numread = mpeg_getbufsize(MPEG_BUFFER_1); + } + *buf = tmpbuf + cur_bufpos; + + if (chtype == VIDEO_CHUNK_EOF) + { + *event = MEDIA_EVENT_STOP; + return 1; + } + if (chtype == VIDEO_CHUNK_RECOVERY) + { + if (cur_bufpos > 0) + media_skip_buffer(&tmpbuf); + return 0; + } + + else if (chtype == VIDEO_CHUNK_AUDIO) + *event = MEDIA_EVENT_AUDIO; + else if (chtype == VIDEO_CHUNK_VIDEO) + *event = MEDIA_EVENT_VIDEO; + else if (chtype == VIDEO_CHUNK_AUDIO_PARTIAL) + *event = MEDIA_EVENT_AUDIO_PARTIAL; + else if (chtype == VIDEO_CHUNK_VIDEO_PARTIAL) + *event = MEDIA_EVENT_VIDEO_PARTIAL; + if (update_counter++ >= 6) + { + update_fip = true; + update_counter = 0; + } + *len = MPEG_PACKET_LENGTH; + MPEG_PACKET_LENGTH = PAD_EVEN(MPEG_PACKET_LENGTH); + media_accept_block(); + + if ((*event & MEDIA_EVENT_PARTIAL) == 0) + { + cur_chunkleft = cur_bufleft; + } + } +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (media_type == MEDIA_TYPE_AUDIO) + { + if (cur_bufleft < 1) + { + if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0) + return 0; + } + + BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1); + *buf = tmpbuf + cur_bufpos; + if (cur_bufpos == 0) + { + numread = mpeg_getbufsize(MPEG_BUFFER_1); + if (audio_read(tmpbuf, &numread) == 0) + { + *event = MEDIA_EVENT_STOP; + return 1; + } + } + if (cur_bufpos + MPEG_PACKET_LENGTH > numread) + *len = MAX(numread - cur_bufpos, 0); + else + *len = MPEG_PACKET_LENGTH; + + *buf = tmpbuf + cur_bufpos; + + if (update_counter++ >= 6) + { + update_fip = true; + update_counter = 0; + } + media_accept_block(); + + } +#endif + + // update FIP + if (update_fip) + { + media_update_fip(); + } + + return 1; +} + +int media_update_fip() +{ + fip_write_special(FIP_SPECIAL_CIRCLE_1 + fipdisc_i, 0); + fipdisc_i++; + if (fipdisc_i >= 12) + fipdisc_i = 0; + fip_write_special(FIP_SPECIAL_CIRCLE_1 + fipdisc_i, 1); + return 0; +} + +int media_skip_buffer(BYTE **buf) +{ + int ret = mpeg_find_free_blocks(MPEG_BUFFER_1); + if (ret == 0) // sorry, out of buffers... + return 0; + cur_bufpos = 0; + cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1); + cur_chunkleft = cur_bufleft; + if (buf != NULL) + *buf = mpeg_getcurbuf(MPEG_BUFFER_1); + return 1; +} + +int media_seek_curleft() +{ +#ifdef INTERNAL_VIDEO_PLAYER + video_lseek(-cur_chunkleft, SEEK_CUR); + media_skip_buffer(NULL); +#endif + return 0; +} + +LONGLONG media_get_filepos() +{ + return file_pos; +} + +void media_set_filepos(LONGLONG fp) +{ + file_pos = fp; +} + +int media_read_block(BYTE **buf, MEDIA_EVENT *event, int *len) +{ +#ifdef INTERNAL_VIDEO_PLAYER + *event = MEDIA_EVENT_NOP; + if (media_type == MEDIA_TYPE_VIDEO) + { + if (len == NULL || *len == 0) + { + *buf = mpeg_getcurbuf(MPEG_BUFFER_1); + *event = MEDIA_EVENT_STOP; + return 1; + } + + bool update_fip = false; + MPEG_PACKET_LENGTH = PAD_EVEN(*len); + if (cur_bufleft < 16 || (MPEG_PACKET_LENGTH > cur_bufleft)) + { + if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0) + return 0; + } + BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1); + *buf = tmpbuf + cur_bufpos; + int numread = MIN(cur_bufleft, MPEG_PACKET_LENGTH); + if ((numread = video_read(*buf, numread)) == 0) + { + *event = MEDIA_EVENT_STOP; + return 1; + } + if (numread < *len) + { + *len = numread; + MPEG_PACKET_LENGTH = numread; + } + *event = MEDIA_EVENT_OK; + media_accept_block(); + media_update_fip(); + return 1; + } +#endif + return -1; +} + +int media_accept_block() +{ + cur_bufleft -= MPEG_PACKET_LENGTH; + cur_bufpos += MPEG_PACKET_LENGTH; + return 1; +} + +int media_free_block(BYTE *data) +{ + if (media_type == MEDIA_TYPE_DVD) + { + if (dvd_free_block(data) < 0) + return -1; + } + else if (media_type == MEDIA_TYPE_MPEG) + { + } + else if (media_type == MEDIA_TYPE_CDDA) + { + } + else if (media_type == MEDIA_TYPE_VIDEO) + { + } + else if (media_type == MEDIA_TYPE_AUDIO) + { + } + return 1; +} + +int media_close() +{ + if (media_type == MEDIA_TYPE_DVD) + { + if (dvd_close() < 0) + return -1; + } +#ifdef INTERNAL_VIDEO_MPEG_PLAYER + else if (media_type == MEDIA_TYPE_MPEG) + { + video_close(); + } +#endif + else if (media_type == MEDIA_TYPE_CDDA) + { + // we'll close when disc changes + //cdda_close(); + } +#ifdef INTERNAL_VIDEO_PLAYER + else if (media_type == MEDIA_TYPE_VIDEO) + { + video_close(); + } +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (media_type == MEDIA_TYPE_AUDIO) + { + audio_close(); + } +#endif + return 1; +} + +int media_seek(int blockid, int from) +{ + if (media_type == MEDIA_TYPE_DVD) + { + // not used + return -1; + } + else if (media_type == MEDIA_TYPE_MPEG) + { + if (lseek(fd, blockid * mpeg_getbufsize(MPEG_BUFFER_1), from) != 0) + return -1; + } + else if (media_type == MEDIA_TYPE_CDDA) + { + // TODO: + return -1; + } + else if (media_type == MEDIA_TYPE_VIDEO) + { + // TODO: + return -1; + } + else if (media_type == MEDIA_TYPE_AUDIO) + { + // TODO: + return -1; + } + return 1; +} + +int media_rewind() +{ + cur_bufpos = 0; + cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1); + cur_chunkleft = cur_bufleft; + + if (media_type == MEDIA_TYPE_DVD) + { + if (dvd_reset() < 0) + return -1; + } + else if (media_type == MEDIA_TYPE_MPEG) + { + lseek(fd, 0, SEEK_SET); + } + else if (media_type == MEDIA_TYPE_CDDA) + { + // TODO: + return -1; + } + else if (media_type == MEDIA_TYPE_VIDEO) + { + // TODO: + return -1; + } + else if (media_type == MEDIA_TYPE_AUDIO) + { + // TODO: + return -1; + } + return 1; +} + +const char *media_geterror() +{ + if (media_type == MEDIA_TYPE_DVD) + { + return dvd_error_string(); + } + else if (media_type == MEDIA_TYPE_MPEG) + { + static char tmp[15]; + sprintf(tmp, "%d", 0); + return tmp; + } + else if (media_type == MEDIA_TYPE_CDDA) + { + // TODO: + return ""; + } + else if (media_type == MEDIA_TYPE_VIDEO) + { + // TODO: + return ""; + } + else if (media_type == MEDIA_TYPE_AUDIO) + { + // TODO: + return ""; + } + return ""; + +} + diff --git a/src/media.h b/src/media.h new file mode 100644 index 0000000..b2f72dd --- /dev/null +++ b/src/media.h @@ -0,0 +1,87 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - input media header file + * \file media.h + * \author bombur + * \version 0.1 + * \date 12.10.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MEDIA_H +#define SP_MEDIA_H + + +#ifdef __cplusplus +extern "C" { +#endif + +int media_open(const char *dvdpath, MEDIA_TYPES mtype); +void set_media_type(MEDIA_TYPES mtype); + +typedef enum +{ + MEDIA_EVENT_OK = 0, + MEDIA_EVENT_NOP = 1, + MEDIA_EVENT_STOP = 8, + MEDIA_EVENT_PARTIAL = 0x10, + + MEDIA_EVENT_AUDIO = 0x1000, + MEDIA_EVENT_VIDEO = 0x1001, + MEDIA_EVENT_AUDIO_PARTIAL = MEDIA_EVENT_AUDIO | MEDIA_EVENT_PARTIAL, + MEDIA_EVENT_VIDEO_PARTIAL = MEDIA_EVENT_VIDEO | MEDIA_EVENT_PARTIAL, +} MEDIA_EVENT; + +int media_get_next_block(BYTE **buf, MEDIA_EVENT *event, int *len); + +// call this if we needed the block +int media_accept_block(); + +int media_free_block(BYTE *data); + +/// used by AVI. +/// \todo: UGLY! +int media_read_block(BYTE **buf, MEDIA_EVENT *event, int *len); +int media_seek_curleft(); + +// called by cache if cache-miss happens +int media_skip_buffer(BYTE **buf); + +int media_close(); + +int media_seek(int blockid, int from); + +int media_rewind(); + +// used by mpeg player to seek 'bad' files +LONGLONG media_get_filepos(); +void media_set_filepos(LONGLONG); + +const char *media_geterror(); + +#ifndef DVDNAV_H_INCLUDED +typedef struct dvdnav_s dvdnav_t; +#endif + +int media_update_fip(); + + +#ifdef __cplusplus +} +#endif + +#endif // of SP_MEDIA_H diff --git a/src/mmsl/mmsl-file.cpp b/src/mmsl/mmsl-file.cpp new file mode 100644 index 0000000..5f8c086 --- /dev/null +++ b/src/mmsl/mmsl-file.cpp @@ -0,0 +1,149 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MMSL file loader/saver impl. + * \file mmsl/mmsl-file.cpp + * \author bombur + * \version 0.1 + * \date 10.04.2010 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static DWORD crc_table[256]; +static BOOL crc_was_init = 0; + +static void mmso_init_crc() +{ + DWORD c, poly; + unsigned n; + static const BYTE p[] = { 0,1,2,4,5,7,8,10,11,12,16,22,23,26 }; + + poly = 0L; + for (n = 0; n < sizeof(p); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (DWORD)n; + for(int k = 0; k < 8; k++) + c= (c & 1) ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_was_init = 1; +} + +static DWORD mmso_crc(BYTE *str, int size) +{ + if (!crc_was_init) + mmso_init_crc(); + + DWORD crc32 = 0xffffffffL; + for(int i = 0; i < size;i++) + { + BYTE c = str[i]; + crc32 = crc_table[(crc32 & 0xff) ^ c] ^ (crc32 >> 8); + } + return (crc32 ^ 0xffffffffL); +} + + +BYTE *mmso_load(const char *fname, int *buflen) +{ + BYTE *buf = NULL; + FILE *fp = fopen(fname, "rb"); + if (fp != NULL) + { + fseek(fp, 0, SEEK_END); + *buflen = ftell(fp); + rewind(fp); + + MmslSerFileHeader hdr; + if (*buflen <= (int)sizeof(hdr)) + { + msg("Mmso: File %s is too small.\n", fname); + fclose(fp); + return NULL; + } + fread(&hdr, sizeof(hdr), 1, fp); + *buflen -= sizeof(hdr); + + if (memcmp(hdr.magic, "MMSO", 4) != 0 || hdr.ver > MMSO_VERSION) + { + msg("Mmso: Wrong file header or version (%d).\n", hdr.ver); + fclose(fp); + return NULL; + } + + buf = (BYTE *)SPmalloc(*buflen + 1); + if (buf != NULL) + fread(buf, *buflen, 1, fp); + + // now check crc + DWORD real_crc = mmso_crc(buf, *buflen); + if (real_crc != hdr.crc) + { + msg("Mmso: Wrong checksum!\n"); + fclose(fp); + SPSafeFree(buf); + return NULL; + } + + fclose(fp); + } + + return buf; +} + +BOOL mmso_save(const char *fname, BYTE *buf, int buflen) +{ + int prev_buflen; + BYTE *prev_buf = mmso_load(fname, &prev_buflen); + if (prev_buf != NULL) + { + BOOL is_the_same = (buflen == prev_buflen && memcmp(buf, prev_buf, buflen) == 0); + SPSafeFree(prev_buf); + if (is_the_same) + return TRUE; + } + + FILE *fp = fopen(fname, "wb"); + if (fp != NULL) + { + MmslSerFileHeader hdr; + memcpy(hdr.magic, "MMSO", 4); + hdr.ver = MMSO_VERSION; + hdr.crc = mmso_crc(buf, buflen); + fwrite(&hdr, sizeof(hdr), 1, fp); + + fwrite(buf, buflen, 1, fp); + fclose(fp); + } + + return TRUE; +} diff --git a/src/mmsl/mmsl-file.h b/src/mmsl/mmsl-file.h new file mode 100644 index 0000000..0a85fe7 --- /dev/null +++ b/src/mmsl/mmsl-file.h @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MMSL file manager header file + * \file mmsl/mmsl-file.h + * \author bombur + * \version 0.1 + * \date 10.04.2010 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MMSL_FILE_H +#define SP_MMSL_FILE_H + +#define MMSO_VERSION 100 + +#ifdef WIN32 +#pragma pack(1) +#endif + +typedef struct ATTRIBUTE_PACKED +{ + char magic[4]; + DWORD ver; + DWORD crc; +} MmslSerFileHeader; + +typedef struct ATTRIBUTE_PACKED +{ + int num_var; + int var_buf_size; + int num_class; + int num_event; + int num_assignedobj; + int num_expr; + int num_lut; + int num_clut; + int num_assignedvar; + int num_cond; + int num_token; +} MmslSerHeader; + +typedef struct ATTRIBUTE_PACKED +{ + short ID; + short idx_vars1, idx_vars2; +} MmslSerClass; + +typedef struct ATTRIBUTE_PACKED +{ + short idx_triggertokens1, idx_triggertokens2; + short idx_conditions1, idx_conditions2; + short idx_execute1, idx_execute2; +} MmslSerEvent; + +typedef struct ATTRIBUTE_PACKED +{ + short idx_assigned_vars1, idx_assigned_vars2; +} MmslSerAssignedObject; + +typedef struct ATTRIBUTE_PACKED +{ + short idx_tokens1, idx_tokens2; +} MmslSerExpression; + +#ifdef WIN32 +#pragma pack() +#endif + + +/// Load MMSO file into the buffer (with buffer's memory allocation) +BYTE *mmso_load(const char *fname, int *buflen); + +/// Save buffer into the MMSO file +BOOL mmso_save(const char *fname, BYTE *buf, int buflen); + + +#endif // of SP_MMSL_FILE_H diff --git a/src/mmsl/mmsl-parser.cpp b/src/mmsl/mmsl-parser.cpp new file mode 100644 index 0000000..b9689b5 --- /dev/null +++ b/src/mmsl/mmsl-parser.cpp @@ -0,0 +1,1320 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MMSL interpreter impl. + * \file mmsl/mmsl-parser.cpp + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + + + +#define USE_CONSTANTS_OPTIMISATION + + +const int num_spaces_in_tab = 4; + +MmslParser *mmsl_parser = NULL; + + +////////////////////////////// +// We combine multiple lists into one global list. +// There macros are wrappers for this list. + +#define IDXLIST_ADD(prefix, name, value) { if (prefix idx_##name##1 < 0) \ + prefix idx_##name##1 = prefix idx_##name##2 = mmsl_parser->name.Add(value); \ + else mmsl_parser->name.Insert(value, ++prefix idx_##name##2); } +#define IDXLIST_ADD_SHIFT(list,P, i, name, value) { if (list[i] P idx_##name##1 < 0) \ + list[i] P idx_##name##1 = list[i] P idx_##name##2 = mmsl_parser->name.Add(value); \ + else { mmsl_parser->name.Insert(value, ++list[i] P idx_##name##2); \ + for (int __i = 0; __i < list.GetN(); __i++) { \ + if (__i == i) continue; \ + if (list[__i] P idx_##name##1 >= list[i] P idx_##name##2) list[__i] P idx_##name##1++; \ + if (list[__i] P idx_##name##2 < 0) list[__i] P idx_##name##2 = list[__i] P idx_##name##1; \ + else if (list[__i] P idx_##name##2 >= list[i] P idx_##name##2) list[__i] P idx_##name##2++; \ + } } } +#define IDXLIST_MERGE_SHIFTPTR(list, i, name, value) { if (mmsl_parser->name.Get(value, list[i]->idx_##name##1, list[i]->idx_##name##2) == -1) { \ + IDXLIST_ADD_SHIFT(list,->,i,name,value); } } + +#define IDXLIST_PUT(prefix, name, value, idx) { mmsl_parser->name[prefix idx_##name##1 + idx] = value; } +#define IDXLIST_NUM(prefix, name) (prefix idx_##name##1 < 0 ? 0 : (prefix idx_##name##2 - prefix idx_##name##1 + 1)) + +/////////////////////////////////////////////////////////////////////////////// + +/// Output MMSL error message to the console. +void mmsl_error(const char *text, ...) +{ + va_list args; + va_start(args, text); + char *msgbuf = (char *)SPalloca(4096); + vsprintf(msgbuf, text, args); + va_end(args); + if (mmsl != NULL) + { + if (mmsl_parser->curfile != NULL && mmsl_parser->curfile->row > 0) + { + msg("Mmsl (%s:%d,%d): %s\n", *mmsl_parser->curfile->fname, mmsl_parser->curfile->row, mmsl_parser->curfile->col, msgbuf); + return; + } + } + msg("Mmsl: %s\n", msgbuf); +} + +const int max_varspace = 130016; + +MmslParser::MmslParser() +{ + varscache_used = 0; + varscache = new SPClassicList(4000); + + varspace = new char [max_varspace+256]; // 256 is for safety + maxvaridx = 0; + + pvars.l.Reserve(4600); + events.Reserve(900); + assigned_objs.Reserve(100); + lut.Reserve(1000); + clut.Reserve(100); + assigned_vars.Reserve(1400); + conditions.Reserve(1500); + tokens.Reserve(12000); + execute.Reserve(2200); + + parse_events_stack.Reserve(100); + parse_events_stack_idx = -1; + + token_stack.Reserve(256); + token_stack_idx = -1; + + last_data = NULL; + + curfile = NULL; + + was_overflow = false; +} + +MmslParser::~MmslParser() +{ + SPSafeDeleteArray(varspace); + + pvars.hash.Clear(); + for (int i = 0; i < pvars.l.GetN(); i++) + { + if (pvars.l[i]->temporary) + { + SPSafeDelete(pvars.l[i]); + } + else + pvars.l[i] = NULL; + } + + pclasses.hash.DeleteObjects(); + +#ifdef USE_CONSTANTS_OPTIMISATION + pconstsvars.hash.DeleteObjects(); +#endif + + SPSafeDelete(varscache); +} + +char *MmslParser::LockVariableName() +{ + // overflow + if (maxvaridx >= max_varspace) + { + msg_critical("Error! Variable space overflow.\n"); + return NULL; + } + return varspace + maxvaridx; +} + +void MmslParser::UnlockVariableName(int len) +{ + maxvaridx += len; +} + +MmslToken MmslParser::GetNextToken(char * &data) +{ + static bool was_newline = true, was_realnewline = true, was_semicolon = false; + static int last_indent = -1; + static char *last_newline = NULL; + static int num_spaces = 0, num_tabs = 0; + static MmslFile *curf = NULL; + static struct + { + MMSL_TOKEN_TYPE type; + const char *name; + } lexemes[] = + { + { MMSL_TOKEN_BREAK, "break" }, + { MMSL_TOKEN_DELETE, "delete" }, + { MMSL_TOKEN_INCLUDE, "include" }, + { MMSL_TOKEN_ON, "on" }, + { MMSL_TOKEN_ADD, "add" }, + { MMSL_TOKEN_UNDEFINED, NULL }, + }; + int lexeme_idx = -1, i = 0, j; + int ignore_sym = false; + bool hex_number = false; + + if (curfile != NULL && curfile != curf) + { + curf = curfile; + if (curfile->row == 0) + { + was_newline = true; + was_realnewline = true; + last_newline = NULL; + } else + { + was_newline = false; + was_realnewline = false; + last_newline = data; // wrong but who cares... + } + was_semicolon = false; + last_indent = -1; + num_spaces = 0; + num_tabs = 0; + } + + last_data = data; + + if (last_newline == NULL || was_realnewline) + { + last_newline = data; + AddRow(); + } + MmslToken token; + token.type = MMSL_TOKEN_UNDEFINED; + token.ival = 0; + + while (*data != '\0') + { +cont: + // comments + if (*data == '/') + { + if (data[1] == '/') + { + data+= 2; + while (*data != '\n' && *data != '\0') + data++; + continue; + } + else if (data[1] == '*') + { + data += 2; + while ((*data != '*' || data[1] != '/') && *data != '\0') + { + if (*data == '\n') + { + AddRow(); + last_newline = data + 1; + } + data++; + } + if (*data != '\0') + data += 2; + continue; + } + } + if (was_newline) + { + if (*data == ' ') + num_spaces++; + else if (*data == '\t') + num_tabs++; + else if (*data != '\r' && *data != '\n') + { + token.type = MMSL_TOKEN_INDENT; + token.ival = was_semicolon ? last_indent : num_tabs + num_spaces / num_spaces_in_tab; + last_indent = token.ival; + + was_semicolon = false; + was_newline = false; + was_realnewline = false; + return token; + } + } + switch (token.type) + { + case MMSL_TOKEN_UNDEFINED: + // IDs and built-in commands + if (isalpha(*data) || *data == '.') + { + SetCol(data - last_newline + 1, num_tabs); + token.sval = LockVariableName(); + if (token.sval == NULL) + { + token.type = MMSL_TOKEN_EOF; + return token; + } + token.sval[0] = (char)tolower(*data); + for (j = 0; lexemes[j].name != NULL; j++) + { + if (lexemes[j].name[0] == token.sval[0]) + { + lexeme_idx = j; + break; + } + } + token.type = MMSL_TOKEN_ID; + i = 1; + } + // numbers + else if (isdigit(*data)) + { + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_NUMBER; + hex_number = false; + token.ival = (int)(*data) - '0'; + } + // strings + else if (*data == '\"' || *data == '\'') + { + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_STRING; + token.sval = LockVariableName(); + if (token.sval == NULL) + { + token.type = MMSL_TOKEN_EOF; + return token; + } + i = 0; + char term = *data; + data++; + while (*data != term && *data != '\0' && *data != '\n') + { + if (*data == '\\') + { + int k = 0; + switch (data[1]) + { + case '\r': + case '\n': // line-continuation + data += 2; + if (*data == '\r' || *data == '\n') + data++; + break; + case '\"': + case '\'': + case '\\': + case '?': + data++; + token.sval[i++] = *data++; + break; + case 'a': + data += 2; + token.sval[i++] = '\a'; + break; + case 'b': + data += 2; + token.sval[i++] = '\b'; + break; + case 'f': + data += 2; + token.sval[i++] = '\f'; + break; + case 'n': + data += 2; + token.sval[i++] = '\n'; + break; + case 'r': + data += 2; + token.sval[i++] = '\r'; + break; + case 't': + data += 2; + token.sval[i++] = '\t'; + break; + case 'v': + data += 2; + token.sval[i++] = '\v'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + // octal + token.sval[i] = 0; + do + { + token.sval[i] = (char)(token.sval[i] * 8 + ((int)(*data) - '0')); + data++; + k++; + } while (k < 3 && *data >= '0' && *data <= '7'); + i++; + break; + case 'x': + // hex + data += 2; + token.sval[i] = 0; + while (k < 3 && ((*data >= '0' && *data <= '9') || + (*data >= 'a' && *data <= 'f') || + (*data >= 'A' && *data <= 'F'))) + { + token.sval[i] = (char)(token.sval[i] * 16 + hex2char(*data)); + data++; + k++; + } + i++; + break; + default: + token.sval[i++] = *data++; + } + continue; + } + token.sval[i++] = *data++; + } + if (*data == term) + data++; + token.sval[i] = '\0'; + UnlockVariableName(i); + return token; + } + // arithmetic operators + else switch (*data) + { + case '\\': + if (data[1] == '\n' || data[1] == '\r') + { + data += 2; + if (*data == '\r' || *data == '\n') + data++; + if (*data != '\0') + goto cont; + } + break; + case ';': + was_semicolon = true; + case '\n': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_EOL; + was_newline = true; + num_spaces = 0; + num_tabs = 0; + was_realnewline = (*data == '\n'); + if (was_realnewline) + was_semicolon = false; + data++; + return token; + case '(': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_LP; + data++; + return token; + case ')': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_RP; + data++; + return token; + case '+': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_PLUS; + data++; + return token; + case '-': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_MINUS; + data++; + return token; + case '*': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_MUL; + data++; + return token; + case '/': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_DIV; + data++; + return token; + case '%': + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_MOD; + data++; + return token; + case '!': + if (data[1] == '=') + { + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_NONEQU; + data += 2; + return token; + } + break; + case '&': + if (data[1] == '&') + { + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_ANDAND; + data += 2; + return token; + } + break; + case '|': + if (data[1] == '|') + { + SetCol(data - last_newline + 1, num_tabs); + token.type = MMSL_TOKEN_OROR; + data += 2; + return token; + } + break; + case '>': + SetCol(data - last_newline + 1, num_tabs); + data++; + if (*data == '=') + { + token.type = MMSL_TOKEN_GTEQU; + data++; + } else + token.type = MMSL_TOKEN_GT; + return token; + case '<': + SetCol(data - last_newline + 1, num_tabs); + data++; + if (*data == '=') + { + token.type = MMSL_TOKEN_LTEQU; + data++; + } else + token.type = MMSL_TOKEN_LT; + return token; + case '=': + SetCol(data - last_newline + 1, num_tabs); + data++; + if (*data == '=') + { + token.type = MMSL_TOKEN_EQUEQU; + data++; + } else + token.type = MMSL_TOKEN_EQU; + return token; + default: + if (!ignore_sym && *data != ' ' && *data != '\t' && *data != '\n' && *data != '\r') + { + mmsl_error("Ignoring unrecognized symbol."); + ignore_sym = true; + } + break; + } + break; + case MMSL_TOKEN_ID: + if (!isalnum(*data) && *data != '.' && *data != '_') + { + if (lexeme_idx >= 0 && lexemes[lexeme_idx].name[i] == '\0') + { + token.type = lexemes[lexeme_idx].type; + token.ival = 0; + } + else + token.sval[i] = '\0'; + UnlockVariableName(i); + + return token; + } + token.sval[i] = (char)tolower(*data); + // first, check built-in lexemes + if (lexeme_idx >= 0) + { + if (lexemes[lexeme_idx].name[i] != token.sval[i]) + lexeme_idx = -1; + } + i++; + break; + case MMSL_TOKEN_NUMBER: + if (*data == 'x') + { + hex_number = true; + break; + } + else if (hex_number && ((*data >= '0' && *data <= '9') || + (*data >= 'A' && *data <= 'F') || + (*data >= 'a' && *data <= 'f'))) + { + token.ival = token.ival * 16 + hex2char((int)(*data)); + } + else if (!isdigit(*data)) + { + return token; + } + else + token.ival = token.ival * 10 + ((int)(*data) - '0'); + break; + default: + ; + } + data++; + } + if (token.type == MMSL_TOKEN_UNDEFINED) + token.type = MMSL_TOKEN_EOF; + return token; +} + +void MmslParser::AddRow() +{ + if (curfile != NULL) + curfile->row++; + SetCol(1, 0); +} + +void MmslParser::SetCol(int col, int num_tabs) +{ + if (curfile != NULL) + { + curfile->col = col + num_tabs * (num_spaces_in_tab - 1); + } +} + +void MmslParser::UndoToken(char * &data) +{ + if (last_data != NULL) + data = last_data; +} + +int MmslToken::GetPriority(MMSL_TOKEN_TYPE type) +{ + switch(type) + { + case MMSL_TOKEN_LP: + return 1; + case MMSL_TOKEN_EQU: + return 2; + case MMSL_TOKEN_ANDAND: + case MMSL_TOKEN_OROR: + return 3; + case MMSL_TOKEN_EQUEQU: + case MMSL_TOKEN_NONEQU: + return 4; + case MMSL_TOKEN_GT: + case MMSL_TOKEN_GTEQU: + case MMSL_TOKEN_LT: + case MMSL_TOKEN_LTEQU: + return 5; + case MMSL_TOKEN_PLUS: + case MMSL_TOKEN_MINUS: + return 6; + case MMSL_TOKEN_MUL: + case MMSL_TOKEN_DIV: + case MMSL_TOKEN_MOD: + return 7; + case MMSL_TOKEN_UNARY: + return 8; + default: + return 0; + } +} + +MMSL_OPERATOR_TYPE MmslToken::GetOperator(MMSL_TOKEN_TYPE type) +{ + MMSL_OPERATOR_TYPE op = (MMSL_OPERATOR_TYPE)(MMSL_OPERATOR_LP + type - MMSL_TOKEN_LP); + if (op <= MMSL_OPERATOR_UNKNOWN1 || op >= MMSL_OPERATOR_UNKNOWN2) + return MMSL_OPERATOR_UNKNOWN1; + return op; +} + +/////////////////////////////////////////////////////////////////////// + +BOOL MmslParser::ParseFile(const char *fname, int start_indent) +{ + int i; + if (fname == NULL) + return FALSE; + FILE *fp = fopen(fname, "rb"); + if (fp == NULL) + { + char *newfname = new char [4096]; + sprintf(newfname, "mmsl/%s", fname); + fp = fopen(newfname, "rb"); + if (fp == NULL) + { + mmsl_error("Cannot include file '%s'.", newfname); + delete [] newfname; + return FALSE; + } + delete [] newfname; + } + + MmslFile fil; + fil.fname = SPString(fname); + files.Add(fil); + curfile = &files[files.GetN() - 1]; + + fseek(fp, 0, SEEK_END); + int size = ftell(fp); + rewind(fp); + char *buf = (char *)SPmalloc(size + 1); + fread(buf, size, 1, fp); + for (i = 0; i < size; i++) + { + if (buf[i] == '\0') + buf[i] = ' '; + } + buf[size] = '\0'; + fclose(fp); + + char *b = buf; + int cur_event; + + if (events.GetN() < 1) + { + MmslEvent event; + IDXLIST_ADD(event.trigger., tokens, MMSL_CONST_TRUE); + cur_event = events.Add(event); + parse_events_stack_idx = -1; + parse_events_stack.Put(cur_event, ++parse_events_stack_idx); + + } + + int cur_indent = start_indent; + cur_event = FindParentEvent(cur_indent); + + for (;;) + { + MmslToken token = GetNextToken(b); + + if (token.type == MMSL_TOKEN_EOL) + continue; + + // include MMSL file + if (token.type == MMSL_TOKEN_INCLUDE) + { + MmslToken tfname = GetNextToken(b); + if (tfname.type != MMSL_TOKEN_STRING) + mmsl_error("Cannot include file - string expected."); + else + { + if (strcasecmp(tfname.sval, fname) == 0) + { + mmsl_error("This file is already included."); + } else + { + ParseFile(tfname.sval, cur_indent); + } + } + } + + // debug_print_token(token); + + if (token.type == MMSL_TOKEN_INDENT) + { + cur_indent = token.ival + start_indent; + cur_event = FindParentEvent(cur_indent); + } + + if (token.type == MMSL_TOKEN_ON) + { + MmslEvent event; + event.indent = cur_indent; + ParseExpression(b, event.trigger, events.GetN()); + if (IDXLIST_NUM(event.trigger., tokens) < 1) + { + mmsl_error("No condition set for event."); + } + // do not add root condition (it's always true) + for (int i = 1; i <= parse_events_stack_idx; i++) + IDXLIST_ADD(event., conditions, parse_events_stack[i]); + cur_event = events.Add(event); + parse_events_stack.Put(cur_event, ++parse_events_stack_idx); + } + + else if (token.type == MMSL_TOKEN_ADD) + { + MmslExpression e; + IDXLIST_ADD(e., tokens, MMSL_OPERATOR_ADD); + + token = GetNextToken(b); + if (token.type != MMSL_TOKEN_ID) + mmsl_error("'Object Type' identifier expected for 'add' operator."); + else + { + MmslParserClass *cls = pclasses.Get(token.sval); + if (cls == NULL) + mmsl_error("Wrong object type specified for 'add' operator."); + else + { + IDXLIST_ADD(e., tokens, cls->index); + + token = GetNextToken(b); + if (token.type != MMSL_TOKEN_ID) + mmsl_error("'Object Type' identifier expected for 'add' operator."); + else + { + SPString nam(token.sval); + MmslAssignedObject an; + // now register variables + for (int i = 0; i < pvars.l.GetN(); i++) + { + if (pvars.l[i]->obj_id == cls->ID) + { + if (pvars.l[i]->name && pvars.l[i]->name[0] == '.') // only abstact vars like ".anyvar" + { + int idx = RegisterVariable(nam + pvars.l[i]->name); + // copy var data + *pvars.l[idx] = *pvars.l[i]; + IDXLIST_ADD(an., assigned_vars, idx); + } + } + } + int an_idx = assigned_objs.Add(an); + IDXLIST_ADD(e., tokens, an_idx); + IDXLIST_ADD_SHIFT(events,., cur_event, execute, e); + } + } + } + } + else if (token.type == MMSL_TOKEN_DELETE) + { + MmslExpression e; + IDXLIST_ADD(e., tokens, MMSL_OPERATOR_DELETE); + ParseExpression(b, e, -2); + if (IDXLIST_NUM(e., tokens) < 1) + { + mmsl_error("No condition set for delete."); + } else + { + IDXLIST_ADD_SHIFT(events,.,cur_event, execute, e); + } + } + else if (token.type == MMSL_TOKEN_ID) + { + UndoToken(b); + MmslExpression e; + ParseExpression(b, e, -1); + IDXLIST_ADD_SHIFT(events,., cur_event, execute, e); + } + + if (token.type == MMSL_TOKEN_EOF) + break; + } + + files.Remove(files.GetN() - 1); + curfile = files.GetN() > 0 ? &files[files.GetN() - 1] : NULL; + + SPfree(buf); + return TRUE; +} + +int MmslParser::FindParentEvent(int indent) +{ + if (indent == 0) + { + parse_events_stack_idx = 0; + return 0; + } + for ( ; parse_events_stack_idx >= 0; parse_events_stack_idx--) + { + int idx = parse_events_stack[parse_events_stack_idx]; + if (idx >= 0 && idx < events.GetN() && events[idx].indent < indent) + return idx; + } + return 0; +} + +void MmslParser::ParseExpression(char * &b, MmslExpression &expr, int event_idx) +{ + int num_par = 0; + bool was_op = false, was_id = false; + token_stack_idx = -1; + +#ifdef MMSL_DEBUG + if (curfile != NULL) + expr.pos = *curfile; +#endif + + for (;;) + { + MmslToken token = GetNextToken(b); + if (token.type == MMSL_TOKEN_EOL || token.type == MMSL_TOKEN_EOF) + break; + if (token.type == MMSL_TOKEN_ID) + { + int idx = RegisterVariable(token.sval); + if (event_idx >= 0) + { + IDXLIST_MERGE_SHIFTPTR(pvars.l, idx, lut, event_idx); + } + IDXLIST_ADD(expr., tokens, idx); + was_op = false; + was_id = true; + } + else if (token.type == MMSL_TOKEN_NUMBER) + { + int idx = RegisterConstant(token.ival); + IDXLIST_ADD(expr., tokens, idx); + was_op = false; + was_id = true; + } + else if (token.type == MMSL_TOKEN_STRING) + { + int idx = RegisterConstant(token.sval); + IDXLIST_ADD(expr., tokens, idx); + was_op = false; + was_id = true; + } + else if (token.type == MMSL_TOKEN_LP) + { + token_stack.Put(MMSL_TOKEN_LP, ++token_stack_idx); + num_par++; + was_op = false; + } + else if (token.type == MMSL_TOKEN_RP) + { + if (was_op) + mmsl_error("Syntax error."); + MMSL_TOKEN_TYPE tok; + while (token_stack_idx >= 0 && (tok = token_stack[token_stack_idx--]) != MMSL_TOKEN_LP && num_par > 0) + { + IDXLIST_ADD(expr., tokens, MmslToken::GetOperator(tok)); + } + num_par--; + was_op = false; + } + else // operator? + { + MMSL_OPERATOR_TYPE op = token.GetOperator(token.type); + if (op != MMSL_OPERATOR_UNKNOWN1) + { + MMSL_TOKEN_TYPE type = token.type; + // fix '==' typos for conditional expression + if (op == MMSL_OPERATOR_EQU && event_idx != -1) + { + op = MMSL_OPERATOR_EQUEQU; + type = MMSL_TOKEN_EQUEQU; + } + + // process unary +/- operators + int cur_pri = MmslToken::GetPriority(type); + if (!was_id && (op == MMSL_OPERATOR_PLUS || op == MMSL_OPERATOR_MINUS)) + { + int idx = RegisterConstant(0); + IDXLIST_ADD(expr., tokens, idx); + cur_pri = MmslToken::GetPriority(MMSL_TOKEN_UNARY); + } + was_op = true; + was_id = false; + + for ( ; token_stack_idx >= 0 + && cur_pri <= MmslToken::GetPriority(token_stack[token_stack_idx]); + token_stack_idx--) + { + IDXLIST_ADD(expr., tokens, MmslToken::GetOperator(token_stack[token_stack_idx])); + } + if (token_stack_idx < 0 || cur_pri > MmslToken::GetPriority(token_stack[token_stack_idx])) + token_stack.Put(type, ++token_stack_idx); + } else + { + mmsl_error("Unknown token in expression."); + } + } + } + // flush operators + for ( ; token_stack_idx >= 0; token_stack_idx--) + { + IDXLIST_ADD(expr., tokens, MmslToken::GetOperator(token_stack[token_stack_idx])); + } +} + +MmslParserVariable *MmslParser::GetNewVariable() +{ + if (varscache_used < varscache->GetN()) + { + MmslParserVariable *var = &(*varscache)[varscache_used++]; + var->temporary = false; + return var; + } + return new MmslParserVariable(); +} + +int MmslParser::RegisterVariable(const char *name, int ID) +{ + if (name == NULL || ID < 0) + return -1; + MmslParserVariable *var = GetNewVariable(); + var->ID = ID; + var->SetConstName(name); + var->type = MMSL_VARIABLE_INTEGER; + return RegisterVariable(var); +} + +int MmslParser::RegisterObject(const char *name, int ID) +{ + if (name == NULL || ID < 0) + return -1; + MmslParserClass *cls = new MmslParserClass(); + cls->ID = ID; + cls->SetConstName(name); + return RegisterObjectClass(cls); +} + +int MmslParser::RegisterObjectVariable(int obj_ID, const char *var_name, int var_ID) +{ + if (obj_ID < 0 || var_name == NULL || var_ID < 0) + return -1; + MmslParserVariable *cvar = pvars.Get((char *)var_name); + if (cvar == NULL) + { + cvar = GetNewVariable(); + if (cvar == NULL) + return -1; + cvar->type = MMSL_VARIABLE_OBJECTVAR; + cvar->SetConstName(var_name); + // init pclasses LUT + for (int i = 0; i < pclasses.l.GetN(); i++) + IDXLIST_ADD(cvar->, clut, -1); + RegisterVariable(cvar); + } + + for (int i = 0; i < pclasses.l.GetN(); i++) + { + if (pclasses.l[i]->ID == obj_ID) + { + MmslParserVariable *var = GetNewVariable(); + if (var == NULL) + return -1; + var->ID = var_ID; + var->obj_id = obj_ID; + var->obj = NULL; // will be assigned dynamically for a real variable + var->type = MMSL_VARIABLE_INTEGER; + var->SetConstName(var_name); + + var->index = RegisterVariable(var); + + // write class index + IDXLIST_PUT(cvar->, clut, var->index, i); + + return var->index; + } + } + + return -1; +} + +int MmslParser::RegisterVariable(char *name) +{ + MmslParserVariable *var = pvars.Get(name); + if (var != NULL) + return var->index; + var = GetNewVariable(); + var->SetName(name); + var->type = MMSL_VARIABLE_INTEGER; + return RegisterVariable(var); +} + +int MmslParser::RegisterConstant(char *strval) +{ + SPString *s = new_SPString(strval); +#ifdef USE_CONSTANTS_OPTIMISATION + MmslParserHashVariable tmphash(s); + MmslParserHashVariable *ret = pconstsvars.hash.Get(tmphash); + if (ret) + { + delete_SPString(s); + return ret->var->index; + } +#endif + // add hash search? + MmslParserVariable *var = GetNewVariable(); + var->type = MMSL_VARIABLE_CONST_STRING; + var->sval = s; +#ifdef USE_CONSTANTS_OPTIMISATION + MmslParserHashVariable *newphv = new MmslParserHashVariable(var); + pconstsvars.hash.Add(newphv); +#endif + return RegisterVariable(var); +} + +int MmslParser::RegisterConstant(int val) +{ +#ifdef USE_CONSTANTS_OPTIMISATION + // use raw search + for (int i = 0; i < pconstivars.GetN(); i++) + { + if (pconstivars[i]->ival == val) + return pconstivars[i]->index; + } +#endif + // add hash search? + MmslParserVariable *var = GetNewVariable(); + var->type = MMSL_VARIABLE_CONST_INTEGER; + var->ival = val; +#ifdef USE_CONSTANTS_OPTIMISATION + pconstivars.Add(var); +#endif + return RegisterVariable(var); + +} + +int MmslParser::RegisterVariable(MmslParserVariable *var) +{ + if (var == NULL) + return -1; + pvars.hash.Add(var); + var->index = pvars.l.Add(var); +/* + if (var->ID >= 0) + { + MmslID *vid = new MmslID; + vid->ID = var->ID; + vid->index = var->index; + idvars.Add(vid); + } +*/ + return var->index; +} + +int MmslParser::RegisterObjectClass(MmslParserClass *obj) +{ + pclasses.hash.Add(obj); + obj->index = pclasses.l.Add(obj); + return obj->index; +} + +///////////////////////////////////////////////////////////////////// + +BYTE *MmslParser::Save(int *buflen) +{ + const int max_buf_size = 512*1024; // 512 Kb + BYTE *buf0 = (BYTE *)SPmalloc(max_buf_size); + BYTE *buf = buf0; + int i; + + was_overflow = false; + + MmslSerHeader *hdr = (MmslSerHeader *)buf; + buf += sizeof(MmslSerHeader); + + BYTE *varbuf = (BYTE *)buf; + buf += (hdr->var_buf_size = CalcSerVarSize()); + hdr->num_var = pvars.l.GetN(); + + MmslSerClass *serclass = (MmslSerClass *)buf; + buf += sizeof(MmslSerClass) * (hdr->num_class = pclasses.l.GetN()); + MmslSerEvent *serevent = (MmslSerEvent *)buf; + buf += sizeof(MmslSerEvent) * (hdr->num_event = events.GetN()); + MmslSerAssignedObject *serassignedobj = (MmslSerAssignedObject *)buf; + buf += sizeof(MmslSerAssignedObject) * (hdr->num_assignedobj = assigned_objs.GetN()); + MmslSerExpression *serexpr = (MmslSerExpression *)buf; + buf += sizeof(MmslSerExpression) * (hdr->num_expr = execute.GetN()); + + short *serlut = (short *)buf; + buf += sizeof(short) * (hdr->num_lut = lut.GetN()); + short *serclut = (short *)buf; + buf += sizeof(short) * (hdr->num_clut = clut.GetN()); + short *serassignedvars = (short *)buf; + buf += sizeof(short) * (hdr->num_assignedvar = assigned_vars.GetN()); + short *sercond = (short *)buf; + buf += sizeof(short) * (hdr->num_cond = conditions.GetN()); + short *sertoken = (short *)buf; + buf += sizeof(short) * (hdr->num_token = tokens.GetN()); + + int str_len = 0; + for (i = 0; i < pvars.l.GetN(); i++) + { + if (pvars.l[i]->sval) + str_len += pvars.l[i]->sval->GetLength() + 1; + } + + char *str_buf = (char *)buf; + buf += str_len; + + int buf_size = (int)(buf - buf0); + // at this moment, the buffer is not filled yet, so let's check its size + if (buf_size > max_buf_size) + { + msg("Mmsl: Max. buffer size exceeded.\n"); + SPfree(buf0); + return NULL; + } + + char *curstr = str_buf; + + for (i = 0; i < pvars.l.GetN(); i++) + { + *varbuf++ = (BYTE)pvars.l[i]->type; // type contains variable bit-fields also (see CalcSerVarSize()) + if (pvars.l[i]->type & MMSL_VARIABLE_HAS_ID) + WriteShort(varbuf, pvars.l[i]->ID); + if (pvars.l[i]->type & MMSL_VARIABLE_HAS_LUT) + { + WriteShort(varbuf, pvars.l[i]->idx_lut1); + WriteShort(varbuf, pvars.l[i]->idx_lut2); + } + if (pvars.l[i]->type & MMSL_VARIABLE_HAS_CLUT) + { + WriteChar(varbuf, pvars.l[i]->idx_clut1); + WriteChar(varbuf, pvars.l[i]->idx_clut2); + } + if (pvars.l[i]->type & MMSL_VARIABLE_HAS_OBJID) + WriteChar(varbuf, pvars.l[i]->obj_id); + + pvars.l[i]->type = (MMSL_VARIABLE_TYPE)(pvars.l[i]->type & MMSL_VARIABLE_MASK); + + // raw integer or strings index + if (pvars.l[i]->type == MMSL_VARIABLE_CONST_STRING) + { + if (pvars.l[i]->sval) + { + WriteInt(varbuf, (int)(curstr - str_buf)); + int l = pvars.l[i]->sval->GetLength() + 1; + memcpy(curstr, *pvars.l[i]->sval, l); + curstr += l; + } else + WriteInt(varbuf, -1); + } + else + WriteInt(varbuf, pvars.l[i]->ival); + } + + for (i = 0; i < pclasses.l.GetN(); i++) + { + serclass[i].ID = GetShort(pclasses.l[i]->ID); + serclass[i].idx_vars1 = GetShort(pclasses.l[i]->idx_vars1); + serclass[i].idx_vars2 = GetShort(pclasses.l[i]->idx_vars2); + } + + for (i = 0; i < events.GetN(); i++) + { + serevent[i].idx_triggertokens1 = GetShort(events[i].trigger.idx_tokens1); + serevent[i].idx_triggertokens2 = GetShort(events[i].trigger.idx_tokens2); + serevent[i].idx_conditions1 = GetShort(events[i].idx_conditions1); + serevent[i].idx_conditions2 = GetShort(events[i].idx_conditions2); + serevent[i].idx_execute1 = GetShort(events[i].idx_execute1); + serevent[i].idx_execute2 = GetShort(events[i].idx_execute2); + } + + for (i = 0; i < assigned_objs.GetN(); i++) + { + serassignedobj[i].idx_assigned_vars1 = GetShort(assigned_objs[i].idx_assigned_vars1); + serassignedobj[i].idx_assigned_vars2 = GetShort(assigned_objs[i].idx_assigned_vars2); + } + + for (i = 0; i < execute.GetN(); i++) + { + serexpr[i].idx_tokens1 = GetShort(execute[i].idx_tokens1); + serexpr[i].idx_tokens2 = GetShort(execute[i].idx_tokens2); + } + + //memcpy(serlut, lut.GetData(), sizeof(serlut[0]) * lut.GetN()); + for (i = 0; i < lut.GetN(); i++) + serlut[i] = GetShort(lut[i]); + //memcpy(serclut, clut.GetData(), sizeof(serclut[0]) * clut.GetN()); + for (i = 0; i < clut.GetN(); i++) + serclut[i] = GetShort(clut[i]); + //memcpy(serassignedvars, assigned_vars.GetData(), sizeof(serassignedvars[0]) * assigned_vars.GetN()); + for (i = 0; i < assigned_vars.GetN(); i++) + serassignedvars[i] = GetShort(assigned_vars[i]); + //memcpy(sercond, conditions.GetData(), sizeof(sercond[0]) * conditions.GetN()); + for (i = 0; i < conditions.GetN(); i++) + sercond[i] = GetShort(conditions[i]); + //memcpy(sertoken, tokens.GetData(), sizeof(sertoken[0]) * tokens.GetN()); + for (i = 0; i < tokens.GetN(); i++) + sertoken[i] = GetShort(tokens[i]); + + if (was_overflow) + { + msg("MmslParser: Serialization overflow! Not saved!\n"); + SPfree(buf0); + return NULL; + } + + *buflen = buf_size; + return buf0; +} + +short MmslParser::GetShort(int v) +{ + short b = (short)v; + if (v != (int)b) + was_overflow = true; + return b; +} + +void MmslParser::WriteChar(BYTE* &buf, int v) +{ + if (v != (int)((char)v)) + was_overflow = true; + *buf++ = (BYTE)((char)v); +} + +void MmslParser::WriteShort(BYTE* &buf, int v) +{ + *buf++ = (BYTE)((char)(v & 0xff)); + *buf++ = (BYTE)((char)(v >> 8)); +} + +void MmslParser::WriteInt(BYTE* &buf, int v) +{ + DWORD d = *((DWORD *)&v); + *buf++ = (BYTE)d; + *buf++ = (BYTE)(d >>= 8); + *buf++ = (BYTE)(d >>= 8); + *buf++ = (BYTE)(d >>= 8); +} + +int MmslParser::CalcSerVarSize() +{ + int ser_var_size = 0; + for (int i = 0; i < pvars.l.GetN(); i++) + { + ser_var_size += 5; // pvars.l[i]->type + ival/sval_idx + + pvars.l[i]->type = (MMSL_VARIABLE_TYPE)(pvars.l[i]->type & MMSL_VARIABLE_MASK); + + if (pvars.l[i]->ID >= 0) + { + ser_var_size += 2; + pvars.l[i]->type = (MMSL_VARIABLE_TYPE)(pvars.l[i]->type | MMSL_VARIABLE_HAS_ID); + } + if (pvars.l[i]->idx_lut1 >= 0 || pvars.l[i]->idx_lut2 >= 0) + { + ser_var_size += 4; + pvars.l[i]->type = (MMSL_VARIABLE_TYPE)(pvars.l[i]->type | MMSL_VARIABLE_HAS_LUT); + } + if (pvars.l[i]->idx_clut1 >= 0 || pvars.l[i]->idx_clut2 >= 0) + { + ser_var_size += 2; + pvars.l[i]->type = (MMSL_VARIABLE_TYPE)(pvars.l[i]->type | MMSL_VARIABLE_HAS_CLUT); + } + if (pvars.l[i]->obj_id >= 0) + { + ser_var_size ++; + pvars.l[i]->type = (MMSL_VARIABLE_TYPE)(pvars.l[i]->type | MMSL_VARIABLE_HAS_OBJID); + } + } + return PAD_EVEN(ser_var_size); +} diff --git a/src/mmsl/mmsl-parser.h b/src/mmsl/mmsl-parser.h new file mode 100644 index 0000000..ba4fa18 --- /dev/null +++ b/src/mmsl/mmsl-parser.h @@ -0,0 +1,264 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MMSL interpreter header file + * \file mmsl/mmsl-parser.h + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MMSL_PARSER_H +#define SP_MMSL_PARSER_H + +#include +#include + +//////////////////////////////////////////////////////////////////// + +template +class HashList +{ +public: + /// ctor + HashList() + { + hash.SetN(n); + } + + /// Not thread-safe! + T *Get(char *name) + { + static T tmp; + tmp.SetConstName(name); + T *ret = hash.Get(tmp); + tmp.name = NULL; + return ret; + } + +public: + SPHashListAbstract hash; + SPList l; +}; + +class MmslToken +{ +public: + MMSL_TOKEN_TYPE type; + union + { + int ival; + char *sval; + }; + + static int GetPriority(MMSL_TOKEN_TYPE type); + static MMSL_OPERATOR_TYPE GetOperator(MMSL_TOKEN_TYPE type); +}; + +/// Built-in or user-defined variable (also object var.) +class MmslParserVariable : public Resource, public MmslVariable +{ +public: + /// ctor + MmslParserVariable() {} + + /// dtor + ~MmslParserVariable() {} + + MmslParserVariable (const MmslParserVariable & v) : MmslVariable(v) + { + } + + MmslParserVariable & operator = (const MmslParserVariable & v) + { + MmslVariable::operator =(v); + + return (*this); + } + +public: +}; + +/// Registered object class (for 'add [object] [name]' command) +class MmslParserClass : public Resource, public MmslClass +{ +public: + MmslParserClass() + { + add_callback = 0; + delete_callback = 0; + param = NULL; + } + + /// dtor + ~MmslParserClass() + { + } + +public: + MmslObjectCallback add_callback, delete_callback; + void *param; + +}; + + +const int parservar_num_hash = 57; + +/// Used for const-strings search optimisation +class MmslParserHashVariable +{ +public: + MmslParserHashVariable(SPString *str) + { + prev = next = NULL; + var = NULL; + sval = str; + const char *ss = **str; + hash = SPStringHashFunc((char * const &)ss, parservar_num_hash); + } + + MmslParserHashVariable(MmslParserVariable *v) + { + prev = next = NULL; + var = v; + sval = v->sval; + hash = v->sval ? SPStringHashFunc(*v->sval, parservar_num_hash) : 0; + } + + /// compare + template + bool operator == (const T & phv) + { + if (sval == NULL || phv.sval == NULL) + return false; + return var->sval->Compare(*phv.sval) == 0; + } + + inline operator DWORD () const + { + return hash; + } + + const MmslParserHashVariable * const GetItem() const + { + return this; + } + + MmslParserHashVariable *prev, *next; + +public: + MmslParserVariable *var; + SPString *sval; + DWORD hash; +}; + + +//////////////////////////////////////////////////////////////// + +/// MMSL Parser/Interpreter singleton class +class MmslParser : public Mmsl +{ +public: + /// ctor + MmslParser(); + /// dtor + ~MmslParser(); + + /// Register predefined external variable (names must be string constants). + int RegisterVariable(const char *name, int ID); + + /// Register dynamic object type - to create/delete it from script + /// (names must be string constants). + int RegisterObject(const char *name, int ID); + + /// Register object variables + /// (names must be string constants). + int RegisterObjectVariable(int obj_ID, const char *var_name, int var_ID); + + /// Read and process MMSL file + BOOL ParseFile(const char *fname, int start_indent = 0); + + /// Serialization: Save all created data into the buffer + BYTE *Save(int *buflen); + +public: + HashList pvars; + + /// registered object pclasses + HashList pclasses; + + SPList pconstivars; + HashList pconstsvars; + +protected: + friend class MmslParserVariable; + friend void mmsl_error(const char *, ...); + + SPList parse_events_stack; + int parse_events_stack_idx; + + SPList token_stack; + int token_stack_idx; + + MmslToken GetNextToken(char * &data); + void UndoToken(char * &data); + + char *varspace; + int maxvaridx; + char *last_data; + + SPClassicList *varscache; + int varscache_used; + + /// Parsing file info stack (fname, row, col) for nested includes + SPClassicList files; + MmslFile *curfile; + + /// Return a new variable pointer + char *LockVariableName(); + /// Close variable pointer + void UnlockVariableName(int len); + + int FindParentEvent(int indent); + void ParseExpression(char * &b, MmslExpression &expr, int event_idx); + + void AddRow(); + void SetCol(int col, int numtabs); + + int RegisterObjectClass(MmslParserClass *obj); + int RegisterVariable(char *name); + int RegisterConstant(char *val); + int RegisterConstant(int val); + int RegisterVariable(MmslParserVariable *var); + + MmslParserVariable *GetNewVariable(); + + ////////////////////////////// + inline short GetShort(int v); + inline void WriteChar(BYTE* &buf, int v); + inline void WriteShort(BYTE* &buf, int v); + inline void WriteInt(BYTE* &buf, int v); + + int CalcSerVarSize(); + +private: + bool was_overflow; +}; + +extern MmslParser *mmsl_parser; + +#endif // of SP_MMSL_PARSER_H diff --git a/src/mmsl/mmsl.cpp b/src/mmsl/mmsl.cpp new file mode 100644 index 0000000..96236a2 --- /dev/null +++ b/src/mmsl/mmsl.cpp @@ -0,0 +1,1105 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MMSL interpreter impl. + * \file mmsl/mmsl.cpp + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +const int num_spaces_in_tab = 4; + +#ifdef WIN32 +//#define MMSL_DEBUG +#endif + +//#define MMSL_DUMP + +Mmsl *mmsl = NULL; + +////////////////////////////// +// We combine multiple lists into one global list. +// There macros are wrappers for this list. + +#define IDXLIST_NUM(prefix, name) (prefix idx_##name##1 < 0 ? 0 : (prefix idx_##name##2 - prefix idx_##name##1 + 1)) +#define IDXLIST_LAST(i, prefix, name) (prefix idx_##name##1 < 0 ? false : (i == prefix idx_##name##2)) +#define IDXLIST_FOR(i, prefix, name) for (i = prefix idx_##name##1; i >= 0 && i <= prefix idx_##name##2; i++) +#define IDXLIST_FOR_OFFS(i, prefix, name, start) for (i = prefix idx_##name##1 + start; i >= 0 && i <= prefix idx_##name##2; i++) +#define IDXLIST(prefix, name, idx) (mmsl->name[prefix idx_##name##1 + idx]) +#define IDXLISTABS(prefix, name, idx) (mmsl->name[idx]) + +/////////////////////////////////////////////////////////////////////////////// + +/// Output MMSL error message to the console. +void mmsl_run_error(const char *text, ...) +{ + va_list args; + va_start(args, text); + char *msgbuf = (char *)SPalloca(4096); + vsprintf(msgbuf, text, args); + va_end(args); + msg("Mmsl: %s\n", msgbuf); +} + +const int max_varspace = 86016; + +Mmsl::Mmsl() +{ + cur_counter = 0; + need_to_run_events = false; + + objects.SetN(mmsl_num_hash); +} + +Mmsl::~Mmsl() +{ + objects.DeleteObjects(); +} + +int Mmsl::BindVariable(int ID, MmslVariableCallback Get, MmslVariableCallback Set, void *param) +{ + if (ID < 0 || Get == NULL || Set == NULL) + return -1; + MmslVariable *var = GetVariable(ID); + if (var) + { + var->get_callback = Get; + var->set_callback = Set; + var->param = param; + var->type = MMSL_VARIABLE_INTEGER; + return 0; + } + return -1; +} + +int Mmsl::BindObject(int ID, MmslObjectCallback Add, MmslObjectCallback Delete, void *param) +{ + if (ID < 0 || Add == NULL || Delete == NULL) + return -1; + MmslClass *cls = GetClass(ID); + if (cls) + { + cls->add_callback = Add; + cls->delete_callback = Delete; + cls->param = param; + return 0; + } + return -1; +} + +int Mmsl::BindObjectVariable(int obj_ID, int var_ID, + MmslVariableCallback Get, MmslVariableCallback Set, void *param) +{ + int i; + bool was_any = false; + if (obj_ID < 0 || var_ID < 0 || Get == NULL || Set == NULL) + return -1; + for (i = 0; i < vars.GetN(); i++) + { + MmslVariable &var = vars[i]; + + if (var.obj_id == obj_ID && var.type != MMSL_VARIABLE_OBJECTVAR) + { + var.get_callback = Get; + var.set_callback = Set; + var.param = param; + var.obj = NULL; // will be assigned dynamically for a real variable + var.type = MMSL_VARIABLE_INTEGER; + was_any = true; + } + } + return was_any ? 0 : -1; +} + + +/////////////////////////////////////////////////////////////////////// + +MmslVariable::MmslVariable() +{ + type = MMSL_VARIABLE_CONST_INTEGER; + ival = 0; + sval = NULL; + get_callback = NULL; + set_callback = NULL; + param = NULL; + + obj_id = -1; + obj = NULL; + + idx_lut1 = idx_lut2 = -1; + idx_clut1 = idx_clut2 = -1; + + ref = NULL; + + ID = -1; +} + +void MmslVariable::Set(int value) +{ + // cannot change constants + if (type == MMSL_VARIABLE_CONST_INTEGER || type == MMSL_VARIABLE_CONST_STRING) + return; + + if (type == MMSL_VARIABLE_STRING || type == MMSL_VARIABLE_RET_STRING) + delete_SPString(sval); + type = MMSL_VARIABLE_INTEGER; + ival = value; + //Update(false); +} + +void MmslVariable::Set(const SPString & value) +{ + // cannot change constants + if (type == MMSL_VARIABLE_CONST_INTEGER || type == MMSL_VARIABLE_CONST_STRING) + return; + + if (type == MMSL_VARIABLE_STRING || type == MMSL_VARIABLE_RET_STRING) + { + *sval = value; + } else + { + sval = new_SPString(value); + } + type = MMSL_VARIABLE_STRING; + ival = 0; + //Update(false); +} + +void MmslVariable::Set(const MmslVariable & from) +{ + // cannot change constants + if (type == MMSL_VARIABLE_CONST_INTEGER || type == MMSL_VARIABLE_CONST_STRING) + return; + // cannot set from 'objectvars' + if (type == MMSL_VARIABLE_OBJECTVAR || from.type == MMSL_VARIABLE_OBJECTVAR) + return; + + if ((from.type & MMSL_VARIABLECLASS_STRING) == MMSL_VARIABLECLASS_STRING) + { + if (type == MMSL_VARIABLE_STRING || type == MMSL_VARIABLE_RET_STRING) + { + if (sval != NULL) + { + if (from.sval == NULL) + *sval = ""; + else + *sval = *from.sval; + } + else + sval = (from.sval == NULL) ? new_SPString() : new_SPString(*from.sval); + } else + sval = (from.sval == NULL) ? new_SPString() : new_SPString(*from.sval); + ival = 0; + type = (from.type == MMSL_VARIABLE_RET_STRING) ? MMSL_VARIABLE_RET_STRING : MMSL_VARIABLE_STRING; + } + else if ((from.type & MMSL_VARIABLECLASS_INTEGER) == MMSL_VARIABLECLASS_INTEGER) + { + if (type == MMSL_VARIABLE_STRING || type == MMSL_VARIABLE_RET_STRING) + delete_SPString(sval); + + ival = from.ival; + sval = NULL; + type = MMSL_VARIABLE_INTEGER; + } + + // pass new value for registered vars + if (ref == NULL) + { + if (ID >= 0 && set_callback != NULL) + set_callback(ID, this, param, obj_id, &obj); + Update(false); + } +} + +void MmslVariable::Update(bool immediate_trigger) +{ + if (mmsl == NULL) + return; + if (type == MMSL_VARIABLE_OBJECTVAR) + return; + + // UpdateTriggers() + int i, num_e = mmsl->events.GetN(); + for (i = idx_lut1; i >= 0 && i <= idx_lut2; i++) + { + int event_idx = mmsl->lut[i]; + if (event_idx < 0 || event_idx >= num_e) + continue; + + mmsl->Evaluate(mmsl->events[event_idx].trigger); + } + + for (i = idx_lut1; i >= 0 && i <= idx_lut2; i++) + { + mmsl->TriggerEvent(mmsl->lut[i], immediate_trigger); + } +} + +int MmslVariable::GetInteger() +{ + if ((type & MMSL_VARIABLECLASS_INTEGER) == MMSL_VARIABLECLASS_INTEGER) + return ival; + if ((type & MMSL_VARIABLECLASS_STRING) == MMSL_VARIABLECLASS_STRING) + { + if (sval != NULL) + return atol(*sval); + } + return 0; +} + +SPString &MmslVariable::GetString() +{ + if ((type & MMSL_VARIABLECLASS_STRING) == MMSL_VARIABLECLASS_STRING) + return *sval; + static SPString str; + str.FromInteger(ival); + return str; +} + +//////////////////////////////////////////////////// + +MmslObject::~MmslObject() +{ + // call 'on_delete' + if (class_idx >= 0 && class_idx < mmsl->classes.GetN()) + { + MmslClass *cls = &mmsl->classes[class_idx]; + if (cls->delete_callback != NULL) + cls->delete_callback(cls->ID, &obj, cls->param); + } +} + +//////////////////////////////////////////////////// + +MmslVariable *Mmsl::GetVariable(int ID) +{ + if (ID >= 0 && ID < idvars.GetN()) + { + return &vars[idvars[ID]]; + } + return NULL; +} + +MmslClass *Mmsl::GetClass(int ID) +{ + if (ID >= 0 && ID < idclasses.GetN()) + { + return &classes[idclasses[ID]]; + } + return NULL; +} + +BOOL Mmsl::UpdateVariable(int ID) +{ + MmslVariable *ret = GetVariable(ID); + if (ret != NULL) + { + ret->Update(false); + return TRUE; + } + return FALSE; +} + +BOOL Mmsl::UpdateObjectVariable(MMSL_OBJECT obj, int ID) +{ + MmslObject tmp, *ret; + tmp.obj = obj; + ret = objects.Get(tmp); + if (ret != NULL && ret->assigned_obj != NULL && ret->class_idx >= 0 && ret->class_idx < classes.GetN()) + { + MmslClass &c = classes[ret->class_idx]; + if (ID >= 0 && ID < IDXLIST_NUM(c., idobjvars)) + { + int vi = IDXLIST(c., idobjvars, ID); + if (vi >= 0 && vi < IDXLIST_NUM(ret->assigned_obj->, assigned_vars)) + { + int vidx = IDXLIST(ret->assigned_obj->, assigned_vars, vi); + if (vidx >= 0 && vidx < vars.GetN()) + { + vars[vidx].Update(false); + return TRUE; + } + } + } + } + return FALSE; +} + +void Mmsl::TriggerEvent(int event_idx, bool immediate_trigger) +{ + if (event_idx < 0 || event_idx >= events.GetN()) + return; + int i; + MmslEvent &e = events[event_idx]; + + // we don't care if there's nothing to execute... + if (IDXLIST_NUM(e., execute) < 1) + return; + + // check additional conditions + IDXLIST_FOR(i, e., conditions) + { + int idx = IDXLISTABS(e., conditions, i); + if (idx < 0 || idx >= events.GetN()) + continue; + +#ifdef MMSL_DEBUG + if (events[idx].trigger.value >= 0) + { + int oldval = events[idx].trigger.value; + + Evaluate(events[idx].trigger); + if (events[idx].trigger.value != oldval) + { + //MmslFile *oldcurfile = curfile; + //curfile = &events[idx].trigger.pos; + + mmsl_run_error("Trigger expression mismatch for event %d!", idx); + + //curfile = oldcurfile; + + events[idx].trigger.value = -1; + } + } +#endif + if (events[idx].trigger.value == 0 || (events[idx].trigger.value < 0 && !Evaluate(events[idx].trigger))) + return; + } + + // check trigger condition + if (e.trigger.value == 1 || (e.trigger.value < 0 && Evaluate(e.trigger))) + { + if (!immediate_trigger && e.counter >= cur_counter) + { + need_to_run_events = true; + e.counter = cur_counter + 1; + return; + } + e.counter = cur_counter; + IDXLIST_FOR(i, e., execute) + { + Evaluate(IDXLISTABS(e., execute, i)); + } + if (e.counter <= cur_counter) + e.counter = 0; + } +} + +bool Mmsl::Evaluate(MmslExpression &e) +{ + e.value = 0; + if (IDXLIST_NUM(e., tokens) < 1) + return false; + if (IDXLIST(e., tokens, 0) == MMSL_CONST_TRUE) + { + e.value = 1; + return true; + } + if (IDXLIST(e., tokens, 0) == MMSL_OPERATOR_ADD) + { + // tokens[1] = type (index into classes) + if (IDXLIST(e., tokens, 1) < 0 || IDXLIST(e., tokens, 1) > classes.GetN()) + return false; + // tokens[2] = name (index into assigned_objs) + if (IDXLIST(e., tokens, 2) < 0 || IDXLIST(e., tokens, 2) > assigned_objs.GetN()) + return false; + MmslAssignedObject *an = &assigned_objs[IDXLIST(e., tokens, 2)]; + if (an == NULL) + return false; + // remove old object reference + if (an->obj != NULL) + an->obj->assigned_obj = NULL; + int index = IDXLIST(e., tokens, 1); + MmslClass *cls = &classes[index]; + if (cls == NULL || cls->add_callback == NULL) + return false; + MMSL_OBJECT obj = NULL; + cls->add_callback(cls->ID, &obj, cls->param); + MmslObject *newobj = new MmslObject(); + if (newobj == NULL) + return false; + newobj->class_idx = index; + newobj->obj = obj; + // set new object reference + newobj->assigned_obj = an; + an->obj = newobj; + int i; + IDXLIST_FOR(i, an->, assigned_vars) + { + int vi = IDXLISTABS(an->, assigned_vars, i); + if (vi >= 0 && vi < vars.GetN()) + { + vars[vi].obj = obj; + } + } + objects.Add(newobj); + return true; + } + if (IDXLIST(e., tokens, 0) == MMSL_OPERATOR_DELETE) + { + MmslObject *cur = objects.GetFirst(), *next = NULL; + bool was_del = false; + while (cur != NULL) + { + next = objects.GetNext(*cur); + if (EvaluateMath(e, 1, cur, true)) + { + // unset object variables + if (cur->assigned_obj != NULL) + { + cur->assigned_obj->obj = NULL; + int i; + IDXLIST_FOR(i, cur->assigned_obj->, assigned_vars) + { + int vi = IDXLISTABS(cur->assigned_obj->, assigned_vars, i); + if (vi > 0 && vi < vars.GetN()) + { + vars[vi].obj = NULL; + } + } + } + objects.Delete(*cur); + was_del = true; + } + cur = next; + } + return was_del; + } + e.value = EvaluateMath(e, 0, NULL) != 0 ? 1 : 0; + return e.value != 0; +} + + +int Mmsl::EvaluateMath(const MmslExpression & e, int start, MmslObject *obj, bool del) +{ + //msg("----------------- EVAL %d %d\n", e.pos.row, e.pos.col); + + const int max_vars_in_stack = 64; + /// this is a bit dirty way, because ctor is not called, but it's ok + MmslVariable *var_stack = (MmslVariable *)SPalloca(max_vars_in_stack * sizeof(MmslVariable)); + if (var_stack == NULL) + { + mmsl_run_error("Cannot allocate variable stack."); + return 0; + } + int i, var_stack_idx = -1; + + // for correct error/debug report + bool was_err = false; +#ifdef MMSL_DEBUG + //curfile = (MmslFile *)&e.pos; +#endif + + IDXLIST_FOR_OFFS(i, e., tokens, start) + { + int tokens_i = IDXLISTABS(e., tokens, i); + if (tokens_i > MMSL_OPERATOR_UNKNOWN1 && tokens_i < MMSL_OPERATOR_UNKNOWN2) // operator + { + if (var_stack_idx < 1) + { + mmsl_run_error("Cannot evaluate expression (operands expected)."); + was_err = true; + break; + } + MMSL_OPERATOR_TYPE op = (MMSL_OPERATOR_TYPE)tokens_i; + MmslVariable *ret = Calc(op, var_stack[var_stack_idx - 1].ref, + var_stack[var_stack_idx].ref, IDXLIST_LAST(i, e., tokens)); + if (ret == NULL) + { + was_err = true; + break; + } + + // clean-up top-stack var + if (var_stack[var_stack_idx].type == MMSL_VARIABLE_STRING + || var_stack[var_stack_idx].type == MMSL_VARIABLE_RET_STRING) + delete_SPString(var_stack[var_stack_idx].sval); + var_stack[--var_stack_idx].Set(*ret); + var_stack[var_stack_idx].ref = &var_stack[var_stack_idx]; + } else + { + if (tokens_i >= 0 && tokens_i < vars.GetN()) + { + MmslVariable *v = &vars[tokens_i]; + // evaluate abstract object variable using given object idx + if (v->type == MMSL_VARIABLE_OBJECTVAR && obj != NULL) + { + if (obj->class_idx < 0 || obj->class_idx >= IDXLIST_NUM(v->, clut)) + { + mmsl_run_error("Cannot find object variable."); + was_err = true; + break; + } + + int vidx = IDXLIST(v->, clut, obj->class_idx); + if (vidx < 0 || vidx >= vars.GetN()) + { + // for delete condition it's normal situation + if (del) + return 0; + mmsl_run_error("Cannot find object variable."); + was_err = true; + break; + } + //v = &IDXLIST(classes[obj->class_idx]., vars, vidx); + v = &vars[vidx]; + } + // get current value of the variable or object's variable + // TODO: l-values are also queried - it's no good... + if (v->type == MMSL_VARIABLE_INTEGER || v->type == MMSL_VARIABLE_STRING || + v->type == MMSL_VARIABLE_OBJECT_INTEGER || v->type == MMSL_VARIABLE_OBJECT_STRING) + { + if (v->get_callback != NULL) + v->get_callback(v->ID, v, v->param, v->obj_id, obj != NULL ? &obj->obj : &v->obj); + } + if (var_stack_idx >= max_vars_in_stack) + { + mmsl_run_error("Too long expression, stack overflow."); + return 0; + } + ++var_stack_idx; + var_stack[var_stack_idx].type = MMSL_VARIABLE_INTEGER; + var_stack[var_stack_idx].ref = v; + var_stack[var_stack_idx].ID = -1; + } + } + } + + // stack vars clean-up + for (i = 0; i <= var_stack_idx; i++) + { + if (var_stack[i].type == MMSL_VARIABLE_STRING || + var_stack[i].type == MMSL_VARIABLE_RET_STRING) + delete_SPString(var_stack[i].sval); + } + +#ifdef MMSL_DEBUG + //curfile = NULL; +#endif + + if (was_err) + return 0; + if (var_stack_idx >= 0) + { + return var_stack[var_stack_idx].ival; + } + return 0; +} + +MmslVariable *Mmsl::Calc(MMSL_OPERATOR_TYPE op, MmslVariable *arg1, MmslVariable *arg2, bool last_op) +{ + static MmslVariable ret; + + // ret is static so we need to clean-up + delete_SPString(ret.sval); + ret.ival = 0; + + if (arg1 == NULL || arg2 == NULL) + { + mmsl_run_error("Wrong arithm. arguments."); + return NULL; + } + + int d; + switch (op) + { + /////////////////////////////////////////////////// + // arithmetic: + + case MMSL_OPERATOR_MINUS: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() - arg2->GetInteger(); + break; + case MMSL_OPERATOR_MUL: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() * arg2->GetInteger(); + break; + case MMSL_OPERATOR_DIV: + ret.type = MMSL_VARIABLE_INTEGER; + d = arg2->GetInteger(); + if (d == 0) + { + mmsl_run_error("Division by zero."); + break; + } + ret.ival = arg1->GetInteger() / d; + break; + case MMSL_OPERATOR_MOD: + ret.type = MMSL_VARIABLE_INTEGER; + d = arg2->GetInteger(); + if (d == 0) + { + mmsl_run_error("Modulus Division by zero."); + break; + } + ret.ival = arg1->GetInteger() % d; + break; + + /////////////////////////////////////////////////// + // comparison: + + case MMSL_OPERATOR_GT: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() > arg2->GetInteger(); + break; + case MMSL_OPERATOR_LT: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() < arg2->GetInteger(); + break; + case MMSL_OPERATOR_GTEQU: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() >= arg2->GetInteger(); + break; + case MMSL_OPERATOR_LTEQU: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() <= arg2->GetInteger(); + break; + case MMSL_OPERATOR_OROR: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() || arg2->GetInteger(); + break; + case MMSL_OPERATOR_ANDAND: + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() && arg2->GetInteger(); + break; + + /////////////////////////////////////////////////// + // special: + case MMSL_OPERATOR_PLUS: + if (arg1->type == MMSL_VARIABLE_CONST_INTEGER || arg2->type == MMSL_VARIABLE_CONST_INTEGER) + { + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() + arg2->GetInteger(); + } + else if (arg1->type == MMSL_VARIABLE_CONST_STRING || arg2->type == MMSL_VARIABLE_CONST_STRING + || arg1->type == MMSL_VARIABLE_RET_STRING || arg2->type == MMSL_VARIABLE_RET_STRING) + { + ret.type = MMSL_VARIABLE_RET_STRING; + ret.sval = new_SPString(arg1->GetString()); + *ret.sval += arg2->GetString(); + } + else if (arg1->type == MMSL_VARIABLE_INTEGER || arg2->type == MMSL_VARIABLE_INTEGER) + { + ret.type = MMSL_VARIABLE_INTEGER; + ret.ival = arg1->GetInteger() + arg2->GetInteger(); + } + else + { + ret.type = MMSL_VARIABLE_RET_STRING; + ret.sval = new_SPString(arg1->GetString()); + *ret.sval += arg2->GetString(); + } + break; + + case MMSL_OPERATOR_EQUEQU: + ret.type = MMSL_VARIABLE_INTEGER; + if (arg1->type == MMSL_VARIABLE_CONST_INTEGER || arg2->type == MMSL_VARIABLE_CONST_INTEGER) + ret.ival = arg1->GetInteger() == arg2->GetInteger(); + else if (arg1->type == MMSL_VARIABLE_CONST_STRING || arg2->type == MMSL_VARIABLE_CONST_STRING) + ret.ival = arg1->GetString().CompareNoCase(arg2->GetString()) == 0; + else if (arg1->type == MMSL_VARIABLE_INTEGER || arg2->type == MMSL_VARIABLE_INTEGER) + ret.ival = arg1->GetInteger() == arg2->GetInteger(); + else + ret.ival = arg1->GetString().CompareNoCase(arg2->GetString()) == 0; + break; + + case MMSL_OPERATOR_NONEQU: + ret.type = MMSL_VARIABLE_INTEGER; + if (arg1->type == MMSL_VARIABLE_CONST_INTEGER || arg2->type == MMSL_VARIABLE_CONST_INTEGER) + ret.ival = arg1->GetInteger() != arg2->GetInteger(); + else if (arg1->type == MMSL_VARIABLE_CONST_STRING || arg2->type == MMSL_VARIABLE_CONST_STRING) + ret.ival = arg1->GetString().CompareNoCase(arg2->GetString()) != 0; + else if (arg1->type == MMSL_VARIABLE_INTEGER || arg2->type == MMSL_VARIABLE_INTEGER) + ret.ival = arg1->GetInteger() != arg2->GetInteger(); + else + ret.ival = arg1->GetString().CompareNoCase(arg2->GetString()) != 0; + break; + + case MMSL_OPERATOR_EQU: + { + arg1->Set(*arg2); + // we're not in conditional, and not need the result + if (!last_op) + ret.Set(*arg2); + } + break; + default: + break; + } + + return &ret; +} + +BOOL Mmsl::Run() +{ + bool more_events = false; + + cur_counter++; + + if (cur_counter == 1) // startup + { + TriggerEvent(0, false); + } + + if (need_to_run_events) + { + need_to_run_events = false; + for (int i = 1; i < events.GetN(); i++) + { + if (events[i].counter >= cur_counter) + { + events[i].counter = 0; + if (IDXLIST_NUM(events[i]., execute) > 0) + { + TriggerEvent(i, false); + more_events = true; + } + } + } + } + return more_events; +} + +////////////////////////////////////////////////// + +BOOL Mmsl::Load(BYTE *buf, int buflen) +{ + /// \WARNING: This code is unprotected from corrupted data! + + int i; + BYTE *buf0 = buf; + MmslSerHeader *hdr = (MmslSerHeader *)buf; + buf += sizeof(MmslSerHeader); + vars.SetN(hdr->num_var); + classes.SetN(hdr->num_class); + events.SetN(hdr->num_event); + assigned_objs.SetN(hdr->num_assignedobj); + execute.SetN(hdr->num_expr); + lut.SetN(hdr->num_lut); + clut.SetN(hdr->num_clut); + assigned_vars.SetN(hdr->num_assignedvar); + conditions.SetN(hdr->num_cond); + tokens.SetN(hdr->num_token); + + BYTE *serbuf0 = (BYTE *)buf; + buf += hdr->var_buf_size; + MmslSerClass *serclass = (MmslSerClass *)buf; + buf += sizeof(MmslSerClass) * classes.GetN(); + MmslSerEvent *serevent = (MmslSerEvent *)buf; + buf += sizeof(MmslSerEvent) * events.GetN(); + MmslSerAssignedObject *serassignedobj = (MmslSerAssignedObject *)buf; + buf += sizeof(MmslSerAssignedObject) * assigned_objs.GetN(); + MmslSerExpression *serexpr = (MmslSerExpression *)buf; + buf += sizeof(MmslSerExpression) * execute.GetN(); + short *serlut = (short *)buf; + buf += sizeof(short) * lut.GetN(); + short *serclut = (short *)buf; + buf += sizeof(short) * clut.GetN(); + short *serassignedvars = (short *)buf; + buf += sizeof(short) * assigned_vars.GetN(); + short *sercond = (short *)buf; + buf += sizeof(short) * conditions.GetN(); + short *sertoken = (short *)buf; + buf += sizeof(short) * tokens.GetN(); + char *str_buf = (char *)buf; + + if (buflen < (int)(buf - buf0)) + { + msg("Mmsl: It seems that MMSO buffer is damaged!\n"); + } + + BYTE *serbuf = serbuf0; + for (i = 0; i < vars.GetN(); i++) + { + vars[i].type = (MMSL_VARIABLE_TYPE)ReadChar(serbuf); + + if (vars[i].type & MMSL_VARIABLE_HAS_ID) + vars[i].ID = ReadShort(serbuf); + if (vars[i].type & MMSL_VARIABLE_HAS_LUT) + { + vars[i].idx_lut1 = ReadShort(serbuf); + vars[i].idx_lut2 = ReadShort(serbuf); + } + if (vars[i].type & MMSL_VARIABLE_HAS_CLUT) + { + vars[i].idx_clut1 = ReadChar(serbuf); + vars[i].idx_clut2 = ReadChar(serbuf); + } + if (vars[i].type & MMSL_VARIABLE_HAS_OBJID) + vars[i].obj_id = ReadChar(serbuf); + + vars[i].type = (MMSL_VARIABLE_TYPE)(vars[i].type & MMSL_VARIABLE_MASK); + + int val = ReadInt(serbuf); + if (vars[i].type == MMSL_VARIABLE_CONST_STRING) + { + vars[i].ival = 0; + vars[i].sval = (val >= 0) ? new_SPString(str_buf + val) : new_SPString(); + } else + { + vars[i].ival = val; + vars[i].sval = NULL; + } + } + + if (PAD_EVEN(serbuf - serbuf0) != hdr->var_buf_size) + { + msg("Mmsl: It seems that MMSO var.buffer is damaged!\n"); + } + + int max_ID = 0; + for (i = 0; i < vars.GetN(); i++) + { + if (vars[i].ID > max_ID) + max_ID = vars[i].ID; + } + idvars.SetN(max_ID + 1); + for (i = 0; i <= max_ID; i++) + idvars[i] = -1; + + SPList num_idobjvars; + int max_num_idobjvars = 0; + num_idobjvars.SetN(classes.GetN()); + for (i = 0; i < classes.GetN(); i++) + num_idobjvars[i] = 0; + for (i = 0; i < vars.GetN(); i++) + { + if (vars[i].obj_id >= 0 && vars[i].obj_id < num_idobjvars.GetN()) + { + num_idobjvars[vars[i].obj_id]++; + if (max_num_idobjvars < vars[i].ID + 1) + max_num_idobjvars = vars[i].ID + 1; + } + if (vars[i].ID >= 0 && vars[i].obj_id < 0) + idvars[vars[i].ID] = i; + } + + max_ID = 0; + for (i = 0; i < classes.GetN(); i++) + { + if (serclass[i].ID > max_ID) + max_ID = serclass[i].ID; + } + idclasses.SetN(max_ID + 1); + for (i = 0; i <= max_ID; i++) + idclasses[i] = -1; + + idobjvars.SetN(max_num_idobjvars * classes.GetN()); + for (i = 0; i < idobjvars.GetN(); i++) + idobjvars[i] = -1; + + for (i = 0; i < classes.GetN(); i++) + { + classes[i].ID = serclass[i].ID; + classes[i].idx_vars1 = serclass[i].idx_vars1; + classes[i].idx_vars2 = serclass[i].idx_vars2; + + if (classes[i].ID >= 0) + idclasses[classes[i].ID] = i; + + classes[i].idx_idobjvars1 = i * max_num_idobjvars; + classes[i].idx_idobjvars2 = (i + 1) * max_num_idobjvars - 1; + + int local_idx = 0; + for (int j = 0; j < vars.GetN(); j++) + { + if (vars[j].obj_id == classes[i].ID) + { + int k = classes[i].idx_idobjvars1 + vars[j].ID; + if (idobjvars[k] == -1) + idobjvars[k] = local_idx++; + } + } + } + + for (i = 0; i < events.GetN(); i++) + { + events[i].trigger.idx_tokens1 = serevent[i].idx_triggertokens1; + events[i].trigger.idx_tokens2 = serevent[i].idx_triggertokens2; + events[i].idx_conditions1 = serevent[i].idx_conditions1; + events[i].idx_conditions2 = serevent[i].idx_conditions2; + events[i].idx_execute1 = serevent[i].idx_execute1; + events[i].idx_execute2 = serevent[i].idx_execute2; + } + + for (i = 0; i < assigned_objs.GetN(); i++) + { + assigned_objs[i].idx_assigned_vars1 = serassignedobj[i].idx_assigned_vars1; + assigned_objs[i].idx_assigned_vars2 = serassignedobj[i].idx_assigned_vars2; + } + + for (i = 0; i < execute.GetN(); i++) + { + execute[i].idx_tokens1 = serexpr[i].idx_tokens1; + execute[i].idx_tokens2 = serexpr[i].idx_tokens2; + } + + for (i = 0; i < lut.GetN(); i++) + lut[i] = serlut[i]; + for (i = 0; i < clut.GetN(); i++) + clut[i] = serclut[i]; + for (i = 0; i < assigned_vars.GetN(); i++) + assigned_vars[i] = serassignedvars[i]; + for (i = 0; i < conditions.GetN(); i++) + conditions[i] = sercond[i]; + for (i = 0; i < tokens.GetN(); i++) + tokens[i] = sertoken[i]; + + msg("Mmsl Loaded: %d vars, %d cls, %d evnts, %d exec, %d asno, %d asnv\n", + vars.GetN(), classes.GetN(), events.GetN(), execute.GetN(), assigned_objs.GetN(), assigned_vars.GetN()); + msg(" %d conds, %d tokens, %d lut, %d clut\n", + conditions.GetN(), tokens.GetN(), lut.GetN(), clut.GetN()); + msg(" %d idv, %d ido, %d idc\n", + idvars.GetN(), idobjvars.GetN(), idclasses.GetN()); + + return TRUE; +} + +int Mmsl::ReadChar(BYTE* &buf) +{ + return (int)(*buf++); +} + +int Mmsl::ReadShort(BYTE* &buf) +{ + int v = (buf[1] << 8) | buf[0]; + buf += 2; + return v; +} + +int Mmsl::ReadInt(BYTE* &buf) +{ + int v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + buf += 4; + return v; +} + +#ifdef MMSL_DUMP + +void Mmsl::Dump() +{ + int i; + for (i = 0; i < vars.GetN(); i++) + { + msg("V[%d] %d %d, %d \"%s\" %d %d %d %d, %d, %c %c\n", + i, vars[i].type, vars[i].ID, vars[i].ival, (vars[i].sval ? **vars[i].sval : ""), + vars[i].idx_lut1, vars[i].idx_lut2, vars[i].idx_clut1, vars[i].idx_clut2, + vars[i].obj_id, + (vars[i].get_callback ? 'G' : '.'), (vars[i].set_callback ? 'S' : '.')); + } + + msg("\n\n-----------------------------------\n\n"); + + for (i = 0; i < classes.GetN(); i++) + { + msg("C[%d] %d, %d %d %d %d, %c %c\n", + i, classes[i].ID, + classes[i].idx_idobjvars1, classes[i].idx_idobjvars2, classes[i].idx_vars1, classes[i].idx_vars2, + classes[i].add_callback ? 'A' : '.', classes[i].delete_callback ? 'S' : '.'); + + } + + msg("\n\n-----------------------------------\n\n"); + + for (i = 0; i < events.GetN(); i++) + { + msg("E[%d] %d %d, %d %d, %d %d\n", + i, events[i].trigger.idx_tokens1, events[i].trigger.idx_tokens2, + events[i].idx_conditions1, events[i].idx_conditions2, + events[i].idx_execute1, events[i].idx_execute2); + } + + msg("\n\n-----------------------------------\n\n"); + + for (i = 0; i < execute.GetN(); i++) + { + msg("X[%d] %d %d\n", + i, execute[i].idx_tokens1, execute[i].idx_tokens2); + } + + msg("\n\n-----------------------------------\n\n"); + + for (i = 0; i < assigned_objs.GetN(); i++) + { + msg("A[%d] %d %d\n", + i, assigned_objs[i].idx_assigned_vars1, assigned_objs[i].idx_assigned_vars2); + } + + DumpIntList("AV", assigned_vars); + DumpIntList("CO", conditions); + DumpIntList("TO", tokens); + DumpIntList("LU", lut); + DumpIntList("CL", clut); + DumpIntList("IV", idvars); + DumpIntList("IO", idobjvars); + DumpIntList("IC", idclasses); + +} + +template +void Mmsl::DumpIntList(const char *n, const L &list) +{ + int i; + msg("\n\n-----------------------------------\n\n"); + for (i = 0; i < list.GetN() / 16 * 16; i+=16) + { + msg("%s[%d] %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d\n", n, i, + list[i+0], list[i+1], list[i+2], list[i+3], list[i+4], list[i+5], list[i+6], list[i+7], + list[i+8], list[i+9], list[i+10], list[i+11], list[i+12], list[i+13], list[i+14], list[i+15]); + } + for (; i < list.GetN(); i++) + { + msg("%s[%d] %d\n", n, i, list[i]); + } +} + +#endif + +////////////////////////////////////////////////// + +SPString *new_SPString() +{ + return new SPString(); +} + +SPString *new_SPString(const SPString & s) +{ + return new SPString(s); +} + +void delete_SPString(SPString * & s) +{ + SPSafeDelete(s); + s = NULL; +} diff --git a/src/mmsl/mmsl.h b/src/mmsl/mmsl.h new file mode 100644 index 0000000..8429ef7 --- /dev/null +++ b/src/mmsl/mmsl.h @@ -0,0 +1,537 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MMSL interpreter header file + * \file mmsl/mmsl.h + * \author bombur + * \version 0.1 + * \date 4.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MMSL_H +#define SP_MMSL_H + + +#define MMSL_VERSION "0.94" + +#ifdef WIN32 +//#define MMSL_DEBUG +#endif + +class MmslVariable; + +typedef void* MMSL_OBJECT; +typedef int MMSL_EXPR_TOKEN; + +typedef void (*MmslObjectCallback)(int obj_id, MMSL_OBJECT *obj, void *param); +typedef void (*MmslVariableCallback)(int var_id, MmslVariable *var, void *param, int obj_id, MMSL_OBJECT *obj); + +SPString *new_SPString(); +SPString *new_SPString(const SPString &); +void delete_SPString(SPString * &); + +const int mmsl_num_hash = 347; + +enum MMSL_VARIABLE_CLASS +{ + MMSL_VARIABLECLASS_INTEGER = 0x4, + MMSL_VARIABLECLASS_STRING = 0x8, +}; + + +enum MMSL_VARIABLE_TYPE +{ + MMSL_VARIABLE_INTEGER = MMSL_VARIABLECLASS_INTEGER, + MMSL_VARIABLE_CONST_INTEGER = MMSL_VARIABLECLASS_INTEGER | 1, + MMSL_VARIABLE_OBJECT_INTEGER = MMSL_VARIABLECLASS_INTEGER | 2, + + MMSL_VARIABLE_STRING = MMSL_VARIABLECLASS_STRING, + MMSL_VARIABLE_CONST_STRING = MMSL_VARIABLECLASS_STRING | 1, + MMSL_VARIABLE_RET_STRING = MMSL_VARIABLECLASS_STRING | 2, + MMSL_VARIABLE_OBJECT_STRING = MMSL_VARIABLECLASS_STRING | 3, + + MMSL_VARIABLE_OBJECTVAR, // '.varname' + + // these used only for serialization + MMSL_VARIABLE_HAS_ID = 0x10, + MMSL_VARIABLE_HAS_LUT = 0x20, + MMSL_VARIABLE_HAS_CLUT = 0x40, + MMSL_VARIABLE_HAS_OBJID = 0x80, + + MMSL_VARIABLE_MASK = ~(MMSL_VARIABLE_HAS_ID | MMSL_VARIABLE_HAS_LUT | MMSL_VARIABLE_HAS_CLUT | MMSL_VARIABLE_HAS_OBJID), +}; + +enum MMSL_OPERATOR_TYPE +{ + MMSL_OPERATOR_UNKNOWN1 = -100, + + MMSL_OPERATOR_LP, // ( + MMSL_OPERATOR_RP, // ) + MMSL_OPERATOR_PLUS, // + + MMSL_OPERATOR_MINUS, // - + MMSL_OPERATOR_MUL, // * + MMSL_OPERATOR_DIV, // / + MMSL_OPERATOR_MOD, // % + MMSL_OPERATOR_NONEQU, // != + MMSL_OPERATOR_GT, // > + MMSL_OPERATOR_LT, // < + MMSL_OPERATOR_GTEQU, // >= + MMSL_OPERATOR_LTEQU, // <= + MMSL_OPERATOR_EQUEQU, // == + MMSL_OPERATOR_OROR, // || + MMSL_OPERATOR_ANDAND, // && + MMSL_OPERATOR_EQU, // = + + MMSL_OPERATOR_UNKNOWN2, + + // 'add object' operator + // arg1 = index into classes + // arg2 = index into 'assigned_objects' + MMSL_OPERATOR_ADD, + + // 'delete objects' operator + // following arguments = deletion condition + MMSL_OPERATOR_DELETE, + + // special operator (no args) - returns true. + // used for 'default' event condition + MMSL_CONST_TRUE, +}; + +// lexemes for tokens are case-insensitive! +enum MMSL_TOKEN_TYPE +{ + MMSL_TOKEN_UNDEFINED = 0, + + MMSL_TOKEN_ID, // [a-z][a-z0-9]+ + MMSL_TOKEN_NUMBER, // [0-9]+ + MMSL_TOKEN_STRING, // ['"][^"']*["'] + + MMSL_TOKEN_ADD, // "add" + MMSL_TOKEN_BREAK, // "break" + MMSL_TOKEN_DELETE, // "delete" + MMSL_TOKEN_INCLUDE, // "include" + MMSL_TOKEN_ON, // "on" + + // operators + MMSL_TOKEN_LP, // ( + MMSL_TOKEN_RP, // ) + MMSL_TOKEN_PLUS, // + + MMSL_TOKEN_MINUS, // - + MMSL_TOKEN_MUL, // * + MMSL_TOKEN_DIV, // / + MMSL_TOKEN_MOD, // % + MMSL_TOKEN_NONEQU, // != + MMSL_TOKEN_GT, // > + MMSL_TOKEN_LT, // < + MMSL_TOKEN_GTEQU, // >= + MMSL_TOKEN_LTEQU, // <= + MMSL_TOKEN_EQUEQU, // == + MMSL_TOKEN_OROR, // || + MMSL_TOKEN_ANDAND, // && + MMSL_TOKEN_EQU, // = + + + MMSL_TOKEN_OPERATOR_MAX, + + // special tokens + + MMSL_TOKEN_INDENT, // indent at the start of a line + MMSL_TOKEN_EOL, // end of line [\r\n] + MMSL_TOKEN_EOF, // end of file + // comments are skipped: + // \/\/[^\n]* c++ comments + // \/\*(.*?)\*\/ c-like comments + + // fake 'unary operator' token definition - for correct priorities + MMSL_TOKEN_UNARY, +}; + + + +//////////////////////////////////////////////////////////////////// + +/// Built-in or user-defined variable (also object var.) +class MmslVariable +{ +public: + /// ctor + MmslVariable(); + + /// dtor + ~MmslVariable() + { + delete_SPString(sval); + //SPSafeDelete(lut); + //SPSafeDelete(clut); + } + + void Set(int value); + void Set(const SPString & value); + void Set(const MmslVariable & from); + + int GetInteger(); + /// not thread-safe + SPString &GetString(); + + void Update(bool immediate_trigger); + + MmslVariable (const MmslVariable & v) + { + type = v.type; + ival = v.ival; + sval = v.sval != NULL ? new_SPString(*v.sval) : NULL; + ID = v.ID; + } + + MmslVariable & operator = (const MmslVariable & v) + { + type = v.type; + ival = v.ival; + sval = v.sval != NULL ? new_SPString(*v.sval) : NULL; + get_callback = v.get_callback; + set_callback = v.set_callback; + param = v.param; + obj = v.obj; + obj_id = v.obj_id; + ID = v.ID; + //idx_lut1 = idx_lut2 = -1; + //idx_clut1 = idx_clut2 = -1; + + return (*this); + } + +public: + /// set for tmp vars - references to the real ones + MmslVariable *ref; + + MMSL_VARIABLE_TYPE type; + + int ID; + + int ival; + SPString *sval; + + /// 1) lut='event_deps' - A list of dependent event indexes. + /// If variable changes, they should be revised. + //SPClassicList lut; + int idx_lut1, idx_lut2; + /// 2) lut='class_var_idx' for MMSL_VARIABLE_OBJECTVAR + /// lut[class_idx] = class_var_idx (MmslClass::vars) + /// or -1 if variable not used in class + //SPClassicList clut; + int idx_clut1, idx_clut2; + + /// object ID (for object vars only) + int obj_id; + /// object pointer + MMSL_OBJECT obj; + + /// For 'system' pre-set variables + MmslVariableCallback get_callback, set_callback; + void *param; +}; + +/// Registered object class (for 'add [object] [name]' command) +class MmslClass +{ +public: + MmslClass() + { + add_callback = 0; + delete_callback = 0; + param = NULL; + ID = -1; + + idx_vars1 = idx_vars2 = -1; + idx_idobjvars1 = idx_idobjvars2 = -1; + } + + /// dtor + ~MmslClass() + { + } + +public: + MmslObjectCallback add_callback, delete_callback; + void *param; + + int ID; + + // idobjvars[classes[i].idx_idobjvars1 + var_ID] = vars_idx + int idx_idobjvars1, idx_idobjvars2; // listed by ID + + /// Abstract Variables (like ".var") + int idx_vars1, idx_vars2; +}; + +/// Saved file position (for error reports) +class MmslFile +{ +public: + /// ctor + MmslFile() + { + row = col = 0; + } + + /// dtor + ~MmslFile() {} + +public: + SPString fname; + int row, col; +}; + +/// Expression storage +class MmslExpression +{ +public: + /// ctor + MmslExpression() + { + idx_tokens1 = idx_tokens2 = -1; + value = -1; + } + + // Tokens are in PPN order. + // Operators ADD and DELETE come first. + // Contains variable/constant indexes or operators (< 0). + + //SPList tokens; + int idx_tokens1, idx_tokens2; + + /// Last calculated value + int value; + +#ifdef MMSL_DEBUG + /// expression location (for error/debug) + MmslFile pos; +#endif +}; + +/// Conditional 'on' block +class MmslEvent +{ +public: + /// ctor + MmslEvent() + { + counter = 0; + indent = 0; + idx_conditions1 = idx_conditions2 = -1; + idx_execute1 = idx_execute2 = -1; + } + +public: + /// Iteration counter + int counter; + + /// event statement indent (used to align sub-statements) + int indent; + + /// This one triggers event + MmslExpression trigger; + + /// These conditions (indexes stored) must be true to trigger this event + /// triggers of the parent events) + /// Pointers to the trigger conditions of other events + //SPClassicList conditions; + int idx_conditions1, idx_conditions2; + + /// We need to execute these if event triggered + //SPClassicList execute; + int idx_execute1, idx_execute2; +}; + +class MmslObject; + +/// An object with assigned name (i.e. used in 'add obj name' operator). +/// Used to re-assign objects (MmslObject) to names. +/// Created each time 'add obj' operator encounted. +class MmslAssignedObject +{ +public: + /// ctor + MmslAssignedObject() + { + obj = NULL; + idx_assigned_vars1 = idx_assigned_vars2 = -1; + } + +public: + /// Link to the object + MmslObject *obj; + + /// Indexes of created object variables + /// Created from MmslClass::vars, the same size! + /// Used to access object variables via 'Update' mechanism + // SPList vars; + int idx_assigned_vars1, idx_assigned_vars2; +}; + +/// Dynamically created object +class MmslObject +{ +public: + MmslObject() + { + class_idx = -1; + obj = NULL; + assigned_obj = NULL; + prev = next = NULL; + } + + /// dtor + ~MmslObject(); + +public: + friend class MmslAssignedObject; + + int class_idx; + MMSL_OBJECT obj; + + /// Set if a name exists + MmslAssignedObject *assigned_obj; + +public: + const MmslObject * const GetItem() const + { + return this; + } + + template + bool operator == (const T & o) + { + return obj == o.obj; + } + + inline operator DWORD () const + { + return (DWORD)obj; + } + + + // linked list support + MmslObject *prev, *next; +}; + +//////////////////////////////////////////////////////////////// + +/// MMSL Interpreter singleton class +class Mmsl +{ +public: + /// ctor + Mmsl(); + /// dtor + ~Mmsl(); + + // user land: + + /// Serialization: Save all created data into the buffer + BOOL Load(BYTE *buf, int buflen); + + /// Bind callbacks to the predefined external variable. + int BindVariable(int ID, MmslVariableCallback Get = NULL, MmslVariableCallback Set = NULL, + void *param = NULL); + + /// Bind callbacks to the dynamic object type - to create/delete it from script + int BindObject(int ID, MmslObjectCallback Add, MmslObjectCallback Delete, void *param); + + /// Bind callbacks to the object variables + int BindObjectVariable(int obj_ID, int var_ID, MmslVariableCallback Get, MmslVariableCallback Set, + void *param); + + /// Run script - call this from your program loop every time + BOOL Run(); + + /// Call this to trigger script events when one of variables changed + BOOL UpdateVariable(int ID); + + /// Call this to trigger script events when one of object variables changed + BOOL UpdateObjectVariable(MMSL_OBJECT obj, int ID); + + MmslVariable *GetVariable(int ID); + MmslClass *GetClass(int ID); + + void Dump(); + +public: + /// Created objects + SPHashListAbstract objects; + + /// registered/created variables + SPClassicList vars; + + /// registered object classes + SPClassicList classes; + + /// Events list (contains ALL events). Also used for triggering events. + SPClassicList events; + + /// name-assigned objects (linked to objects) + SPClassicList assigned_objs; + + /// Expressions + SPClassicList execute; + + // internal lists for events/variables/assigned_objs: + SPList lut; + SPList clut; // clut[var_offs + class_idx] = var_idx + SPList assigned_vars; + SPList conditions; + SPList tokens; + + /// LUT for update-vars mechanism + SPList idvars; + /// LUT for update-objectvars mechanism + SPList idobjvars; + /// LUT for classes + SPList idclasses; + +protected: + friend class MmslVariable; + friend void mmsl_run_error(const char *, ...); + + /// Current execution pass counter + int cur_counter; + bool need_to_run_events; + + void SetVariable(int var_idx, bool immediate_trigger); + + void TriggerEvent(int event_idx, bool immediate_trigger); + + bool Evaluate(MmslExpression &e); + + /// Not thread-safe! + int EvaluateMath(const MmslExpression & e, int start, MmslObject *obj, bool del = false); + /// Not thread-safe! + MmslVariable *Calc(MMSL_OPERATOR_TYPE op, MmslVariable *arg1, MmslVariable *arg2, bool last_op); + +private: + inline int ReadChar(BYTE* &buf); + inline int ReadShort(BYTE* &buf); + inline int ReadInt(BYTE* &buf); + + template + void DumpIntList(const char *n, const L &list); +}; + +extern Mmsl *mmsl; + +#endif // of SP_MMSL_H diff --git a/src/module-dvd.cpp b/src/module-dvd.cpp new file mode 100644 index 0000000..6f22c18 --- /dev/null +++ b/src/module-dvd.cpp @@ -0,0 +1,130 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - DVD module interface impl. + * \file module-dvd.cpp + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifdef COMPILE_MODULE + #define MODULE_SERVER +#endif + +#ifdef MODULE_SERVER + #include + #include + #include + + #include +#endif + +#include +#include + +extern "C" { + +MODULE_DECL_START() + + MODULE_DECL(dvd_open), + MODULE_DECL(dvd_get_next_block), + MODULE_DECL(dvd_free_block), + MODULE_DECL(dvd_close), + MODULE_DECL(dvd_reset), + MODULE_DECL(dvd_error_string), + MODULE_DECL(dvd_do_command), + MODULE_DECL(dvd_stop), + MODULE_DECL(dvd_getnumtitles), + MODULE_DECL(dvd_play), + MODULE_DECL(dvd_setdeflang_spu), + MODULE_DECL(dvd_setdeflang_audio), + MODULE_DECL(dvd_setdeflang_menu), + MODULE_DECL(dvd_button_play), + MODULE_DECL(dvd_getnumchapters), + MODULE_DECL(dvd_get_cur), + MODULE_DECL(dvd_seek_titlepart), + MODULE_DECL(dvd_seek), + MODULE_DECL(dvd_getdebug), + MODULE_DECL(dvd_ismenu), + MODULE_DECL(dvd_getangle), + MODULE_DECL(dvd_getspeed), + MODULE_DECL(dvd_get_saved), + MODULE_DECL(dvd_setdebug), + MODULE_DECL(dvd_get_total_time), + MODULE_DECL(dvd_get_chapter_for_time), + MODULE_DECL(dvd_button_subtitle), + MODULE_DECL(dvd_button_audio), + MODULE_DECL(dvd_button_menu), + MODULE_DECL(dvd_button_angle), + MODULE_DECL(dvd_setspeed), + MODULE_DECL(dvd_player_loop), + +MODULE_DECL_END(); + + +MODULE_FUNC_TABLE dvd_funcs[] = +{ + MODULE_ENTRY(dvd_open), + MODULE_ENTRY(dvd_get_next_block), + MODULE_ENTRY(dvd_free_block), + MODULE_ENTRY(dvd_close), + MODULE_ENTRY(dvd_reset), + MODULE_ENTRY(dvd_error_string), + MODULE_ENTRY(dvd_do_command), + MODULE_ENTRY(dvd_stop), + MODULE_ENTRY(dvd_getnumtitles), + MODULE_ENTRY(dvd_play), + MODULE_ENTRY(dvd_setdeflang_spu), + MODULE_ENTRY(dvd_setdeflang_audio), + MODULE_ENTRY(dvd_setdeflang_menu), + MODULE_ENTRY(dvd_button_play), + MODULE_ENTRY(dvd_getnumchapters), + MODULE_ENTRY(dvd_get_cur), + MODULE_ENTRY(dvd_seek_titlepart), + MODULE_ENTRY(dvd_seek), + MODULE_ENTRY(dvd_getdebug), + MODULE_ENTRY(dvd_ismenu), + MODULE_ENTRY(dvd_getangle), + MODULE_ENTRY(dvd_getspeed), + MODULE_ENTRY(dvd_get_saved), + MODULE_ENTRY(dvd_setdebug), + MODULE_ENTRY(dvd_get_total_time), + MODULE_ENTRY(dvd_get_chapter_for_time), + MODULE_ENTRY(dvd_button_subtitle), + MODULE_ENTRY(dvd_button_audio), + MODULE_ENTRY(dvd_button_menu), + MODULE_ENTRY(dvd_button_angle), + MODULE_ENTRY(dvd_setspeed), + MODULE_ENTRY(dvd_player_loop), + + MODULE_ENTRY_END(), +}; + +MODULE_DESC module_dvd_desc = +{ + "dvd", // name + "dvd", // class + "DVD Player module", // desc. + 100, // version = 1.00 + 140, // min. init ver = 1.40 + + { 0 }, +}; + +// end of extern "C" +} diff --git a/src/module-init.cpp b/src/module-init.cpp new file mode 100644 index 0000000..9b01294 --- /dev/null +++ b/src/module-init.cpp @@ -0,0 +1,377 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Main program module interface impl. + * \file module-init.cpp + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +// For main program, use "if NOT defined"! +#ifndef COMPILE_MODULE + #define MODULE_SERVER +#endif + +#ifdef MODULE_SERVER + #define __USE_LARGEFILE64 + #define __LARGE64_FILES + #define _LARGEFILE64_SOURCE + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + +extern "C" { extern int __sigjmp_save (sigjmp_buf env, int savemask); }; +#endif + +#include +#include + + +extern "C" { + +MODULE_DECL_START() + + MODULE_DECL(script_error_callback), + MODULE_DECL(script_player_saved_callback), + MODULE_DECL(script_video_info_callback), + MODULE_DECL(script_zoom_scroll_reset_callback), + MODULE_DECL(script_speed_callback), + MODULE_DECL(script_time_callback), + MODULE_DECL(script_dvd_chapter_callback), + MODULE_DECL(script_dvd_title_callback), + MODULE_DECL(script_dvd_menu_callback), + MODULE_DECL(script_totaltime_callback), + MODULE_DECL(script_audio_lang_callback), + MODULE_DECL(script_audio_stream_callback), + MODULE_DECL(script_audio_info_callback), + MODULE_DECL(script_spu_lang_callback), + MODULE_DECL(script_spu_stream_callback), + MODULE_DECL(script_framerate_callback), + MODULE_DECL(script_framesize_callback), + MODULE_DECL(script_update_variable), + + MODULE_DECL(mpeg_init), + MODULE_DECL(mpeg_deinit), + MODULE_DECL(mpeg_getaudiostream), + MODULE_DECL(mpeg_getspustream), + MODULE_DECL(mpeg_zoom_hor), + MODULE_DECL(mpeg_zoom_ver), + MODULE_DECL(mpeg_scroll), + MODULE_DECL(mpeg_getbufbase), + MODULE_DECL(mpeg_setaudioparams), + MODULE_DECL(mpeg_getpacketlength), + MODULE_DECL(mpeg_setbuffer), + MODULE_DECL(mpeg_getframesize), + MODULE_DECL(mpeg_setspeed), + MODULE_DECL(mpeg_zoom_reset), + MODULE_DECL(mpeg_is_displayed), + MODULE_DECL(mpeg_parse_ac3_header), + MODULE_DECL(mpeg_getaudioparams), + MODULE_DECL(mpeg_wait), + MODULE_DECL(mpeg_getrate), + MODULE_DECL(mpeg_is_playing), + MODULE_DECL(mpeg_get_video_format), + MODULE_DECL(mpeg_setpts), + MODULE_DECL(mpeg_resetstreams), + MODULE_DECL(mpeg_setaudiostream), + MODULE_DECL(mpeg_start), + MODULE_DECL(mpeg_play), + MODULE_DECL(mpeg_feed), + MODULE_DECL(mpeg_setbufidx), + MODULE_DECL(mpeg_setspustream), + MODULE_DECL(mpeg_get_fps), + MODULE_DECL(mpeg_audio_format_changed), + MODULE_DECL(mpeg_extractpacket), + MODULE_DECL(mpeg_feed_getlast), + MODULE_DECL(mpeg_parse_program_stream_pack_header), + MODULE_DECL(mpeg_findpacket), + + MODULE_DECL(khwl_display_clear), + MODULE_DECL(khwl_stop), + MODULE_DECL(khwl_setvideomode), + MODULE_DECL(khwl_setproperty), + MODULE_DECL(khwl_getproperty), + MODULE_DECL(khwl_transformcoord), + MODULE_DECL(khwl_set_window_zoom), + + MODULE_DECL(fip_write_string), + MODULE_DECL(fip_write_special), + MODULE_DECL(fip_clear), + + MODULE_DECL(msg_error), + MODULE_DECL(msg), + + MODULE_DECL(settings_get), + MODULE_DECL(settings_set), + + MODULE_DECL(media_open), + MODULE_DECL(media_close), + MODULE_DECL(media_free_block), + MODULE_DECL(media_geterror), + MODULE_DECL(media_get_next_block), + MODULE_DECL(media_skip_buffer), + + MODULE_DECL(usleep), + MODULE_DECL(gettimeofday), + MODULE_DECL(closedir), + MODULE_DECL(readdir), + MODULE_DECL(opendir), + +#ifndef WIN32 + MODULE_DECL(__errno_location), + MODULE_DECL(__sigjmp_save), + MODULE_DECL(atoi), + MODULE_DECL(calloc), + MODULE_DECL(chdir), + MODULE_DECL(clock), + MODULE_DECL(close), + MODULE_DECL(fclose), + MODULE_DECL(ferror), + MODULE_DECL(fgets), + MODULE_DECL(fopen64), + MODULE_DECL(fprintf), + MODULE_DECL(fread), + MODULE_DECL(free), + MODULE_DECL(fstat64), + MODULE_DECL(getcwd), + MODULE_DECL(getenv), + MODULE_DECL(getmntent), + MODULE_DECL(getpwuid), + MODULE_DECL(getuid), + MODULE_DECL(ioctl), + MODULE_DECL(localtime), + MODULE_DECL(lseek64), + MODULE_DECL(malloc), + MODULE_DECL(memset), + MODULE_DECL(open64), + MODULE_DECL(rand), + MODULE_DECL(read), + MODULE_DECL(readdir64), + MODULE_DECL(readv), + MODULE_DECL(realloc), + MODULE_DECL(snprintf), + MODULE_DECL(sprintf), + MODULE_DECL(srand), + MODULE_DECL(stat64), + MODULE_DECL(strcasecmp), + MODULE_DECL(strcat), + MODULE_DECL(strdup), + MODULE_DECL(strerror), + MODULE_DECL(strftime), + MODULE_DECL(strncasecmp), + MODULE_DECL(strncat), + MODULE_DECL(strncmp), + MODULE_DECL(strncpy), + MODULE_DECL(strtok), + MODULE_DECL(strtol), + MODULE_DECL(tolower), + MODULE_DECL(toupper), + MODULE_DECL(vsprintf), + + MODULE_DECL(fflush), + MODULE_DECL(sigemptyset), + MODULE_DECL(sigaddset), + MODULE_DECL(sigprocmask), + MODULE_DECL(sigfillset), + MODULE_DECL(sigaction), + MODULE_DECL(raise), + + MODULE_DECL(getpid), + MODULE_DECL(kill), +#endif + +MODULE_DECL_END(); + + +MODULE_FUNC_TABLE init_funcs[] = +{ + MODULE_ENTRY(script_error_callback), + MODULE_ENTRY(script_player_saved_callback), + MODULE_ENTRY(script_video_info_callback), + MODULE_ENTRY(script_zoom_scroll_reset_callback), + MODULE_ENTRY(script_speed_callback), + MODULE_ENTRY(script_time_callback), + MODULE_ENTRY(script_dvd_chapter_callback), + MODULE_ENTRY(script_dvd_title_callback), + MODULE_ENTRY(script_dvd_menu_callback), + MODULE_ENTRY(script_totaltime_callback), + MODULE_ENTRY(script_audio_lang_callback), + MODULE_ENTRY(script_audio_stream_callback), + MODULE_ENTRY(script_audio_info_callback), + MODULE_ENTRY(script_spu_lang_callback), + MODULE_ENTRY(script_spu_stream_callback), + MODULE_ENTRY(script_framerate_callback), + MODULE_ENTRY(script_framesize_callback), + MODULE_ENTRY(script_update_variable), + + MODULE_ENTRY(mpeg_init), + MODULE_ENTRY(mpeg_deinit), + MODULE_ENTRY(mpeg_getaudiostream), + MODULE_ENTRY(mpeg_getspustream), + MODULE_ENTRY(mpeg_zoom_hor), + MODULE_ENTRY(mpeg_zoom_ver), + MODULE_ENTRY(mpeg_scroll), + MODULE_ENTRY(mpeg_getbufbase), + MODULE_ENTRY(mpeg_setaudioparams), + MODULE_ENTRY(mpeg_getpacketlength), + MODULE_ENTRY(mpeg_setbuffer), + MODULE_ENTRY(mpeg_getframesize), + MODULE_ENTRY(mpeg_setspeed), + MODULE_ENTRY(mpeg_zoom_reset), + MODULE_ENTRY(mpeg_is_displayed), + MODULE_ENTRY(mpeg_parse_ac3_header), + MODULE_ENTRY(mpeg_getaudioparams), + MODULE_ENTRY(mpeg_wait), + MODULE_ENTRY(mpeg_getrate), + MODULE_ENTRY(mpeg_is_playing), + MODULE_ENTRY(mpeg_get_video_format), + MODULE_ENTRY(mpeg_setpts), + MODULE_ENTRY(mpeg_resetstreams), + MODULE_ENTRY(mpeg_setaudiostream), + MODULE_ENTRY(mpeg_start), + MODULE_ENTRY(mpeg_play), + MODULE_ENTRY(mpeg_feed), + MODULE_ENTRY(mpeg_setbufidx), + MODULE_ENTRY(mpeg_setspustream), + MODULE_ENTRY(mpeg_get_fps), + MODULE_ENTRY(mpeg_audio_format_changed), + MODULE_ENTRY(mpeg_extractpacket), + MODULE_ENTRY(mpeg_feed_getlast), + MODULE_ENTRY(mpeg_parse_program_stream_pack_header), + MODULE_ENTRY(mpeg_findpacket), + + MODULE_ENTRY(khwl_display_clear), + MODULE_ENTRY(khwl_stop), + MODULE_ENTRY(khwl_setvideomode), + MODULE_ENTRY(khwl_setproperty), + MODULE_ENTRY(khwl_getproperty), + MODULE_ENTRY(khwl_transformcoord), + MODULE_ENTRY(khwl_set_window_zoom), + + MODULE_ENTRY(fip_write_string), + MODULE_ENTRY(fip_write_special), + MODULE_ENTRY(fip_clear), + + MODULE_ENTRY(msg_error), + MODULE_ENTRY(msg), + + MODULE_ENTRY(settings_get), + MODULE_ENTRY(settings_set), + + MODULE_ENTRY(media_open), + MODULE_ENTRY(media_close), + MODULE_ENTRY(media_free_block), + MODULE_ENTRY(media_geterror), + MODULE_ENTRY(media_get_next_block), + MODULE_ENTRY(media_skip_buffer), + + MODULE_ENTRY(usleep), + MODULE_ENTRY(gettimeofday), + MODULE_ENTRY(closedir), + MODULE_ENTRY(readdir), + MODULE_ENTRY(opendir), + +#ifndef WIN32 + MODULE_ENTRY(__errno_location), + MODULE_ENTRY(__sigjmp_save), + MODULE_ENTRY(atoi), + MODULE_ENTRY(calloc), + MODULE_ENTRY(chdir), + MODULE_ENTRY(clock), + MODULE_ENTRY(close), + MODULE_ENTRY(fclose), + MODULE_ENTRY(ferror), + MODULE_ENTRY(fgets), + MODULE_ENTRY(fopen64), + MODULE_ENTRY(fprintf), + MODULE_ENTRY(fread), + MODULE_ENTRY(free), + MODULE_ENTRY(fstat64), + MODULE_ENTRY(getcwd), + MODULE_ENTRY(getenv), + MODULE_ENTRY(getmntent), + MODULE_ENTRY(getpwuid), + MODULE_ENTRY(getuid), + MODULE_ENTRY(ioctl), + MODULE_ENTRY(localtime), + MODULE_ENTRY(lseek64), + MODULE_ENTRY(malloc), + MODULE_ENTRY(memset), + MODULE_ENTRY(open64), + MODULE_ENTRY(rand), + MODULE_ENTRY(read), + MODULE_ENTRY(readdir64), + MODULE_ENTRY(readv), + MODULE_ENTRY(realloc), + MODULE_ENTRY(snprintf), + MODULE_ENTRY(sprintf), + MODULE_ENTRY(srand), + MODULE_ENTRY(stat64), + MODULE_ENTRY(strcasecmp), + MODULE_ENTRY(strcat), + MODULE_ENTRY(strdup), + MODULE_ENTRY(strerror), + MODULE_ENTRY(strftime), + MODULE_ENTRY(strncasecmp), + MODULE_ENTRY(strncat), + MODULE_ENTRY(strncmp), + MODULE_ENTRY(strncpy), + MODULE_ENTRY(strtok), + MODULE_ENTRY(strtol), + MODULE_ENTRY(tolower), + MODULE_ENTRY(toupper), + MODULE_ENTRY(vsprintf), + + MODULE_ENTRY(fflush), + MODULE_ENTRY(sigemptyset), + MODULE_ENTRY(sigaddset), + MODULE_ENTRY(sigprocmask), + MODULE_ENTRY(sigfillset), + MODULE_ENTRY(sigaction), + MODULE_ENTRY(raise), + + MODULE_ENTRY(getpid), + MODULE_ENTRY(kill), +#endif + + MODULE_ENTRY_END(), +}; + +} diff --git a/src/module.cpp b/src/module.cpp new file mode 100644 index 0000000..5031904 --- /dev/null +++ b/src/module.cpp @@ -0,0 +1,292 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - module system impl. + * \file module.cpp + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifdef COMPILE_MODULE + +#include + +extern "C" { + +typedef int (*MODULE_INIT_PROC)(MODULE_DESC *desc, MODULE_FUNC_TABLE *client, MODULE_FUNC_TABLE *server); + +MODULE_INIT_PROC module_init; + +MODULE_INIT_PROC module_getproc(char *str) +{ + if (str == 0) + return 0; + + // str - decimal pointer + unsigned long proc = 0; + for (char *s = str; *s != '\0'; s++) + { + if (*s < '0' || *s > '9') + return 0; + proc *= 10; + proc += (*s - '0'); + } + + return (MODULE_INIT_PROC)proc; +} + +void module_start(char *interface_ptr_str, MODULE_DESC *desc, MODULE_FUNC_TABLE *client, MODULE_FUNC_TABLE *server) +{ + module_init = module_getproc(interface_ptr_str); + if (module_init != 0) + { + if (module_init(desc, client, server) < 0) + return; + } +} + +// end of extern "C" +}; + +#else // server side + +#include +#include +#include + +#include +#include +#include + +#include +#include + +extern "C" { + +const int MAX_NUM_MODULES = 32; +typedef struct MODULE_STRUCT +{ + volatile BOOL loaded; + SPString name; + DWORD hash; + MODULE_DESC *desc; + int pid; + MODULE_FUNC_TABLE *client_table; +} MODULE_STRUCT; + +MODULE_STRUCT modules[MAX_NUM_MODULES]; +int num_modules = 0; +static volatile bool was_module_error = false; + +///////////////////////////// +extern MODULE_FUNC_TABLE dvd_funcs[]; +extern MODULE_FUNC_TABLE init_funcs[]; +///////////////////////////// + +int module_find(const SPString & name) +{ + // find module + DWORD hash = name.Hash(); + int mod_idx = -1; + for (int i = 0; i < num_modules; i++) + { + if (modules[i].hash == hash) + { + if (modules[i].name.CompareNoCase(name) == 0) + { + mod_idx = i; + break; + } + } + } + return mod_idx; +} + +int module_copy_table(MODULE_FUNC_TABLE *from, MODULE_FUNC_TABLE *to) +{ + for (int i = 0; to[i].addr != NULL; i++) + { + int id = to[i].id; + bool found = false; + for (int j = 0; from[j].addr != NULL; j++) + { + if (from[j].id == id) + { + found = true; + module_copy_func(from[j].addr, to[i].addr); + break; + } + } + if (!found) + { + msg("Module: Cannot find function entry, ID=%d!\n", id); + return -1; + } + } + return 0; +} + +/// Called from module! +int module_init(MODULE_DESC *desc, MODULE_FUNC_TABLE *client, MODULE_FUNC_TABLE *server) +{ + was_module_error = false; + if (desc == NULL || client == NULL || server == NULL) + { + was_module_error = true; + return -1; + } + + msg("Module: Starting '%s'...\n", desc->name); + if (desc->init_ver > SP_VERSION) + { + msg("Module: Required version mismatch (%d.%d > %d.%d)!\n", desc->init_ver / 100, desc->init_ver % 100, + SP_VERSION / 100, SP_VERSION % 100); + was_module_error = true; + return -1; + } + int mod_idx = module_find(desc->name); + if (mod_idx < 0) + { + msg("Module: Unknown module loaded - '%s'!\n", desc->name); + was_module_error = true; + return -1; + } + modules[mod_idx].desc = desc; + + // copy dvd tables + MODULE_FUNC_TABLE *client_table = NULL; + + if (strcasecmp(desc->class_name, "dvd") == 0) + client_table = dvd_funcs; + if (client_table == NULL) + { + msg("Module: Cannot find client table for module '%s'.\n", desc->name); + was_module_error = true; + return -1; + } + if (module_copy_table(client, client_table) < 0) + { + was_module_error = true; + return -1; + } + if (module_copy_table(init_funcs, server) < 0) + { + was_module_error = true; + return -1; + } + + modules[mod_idx].client_table = client_table; + modules[mod_idx].loaded = TRUE; + + msg("Module: '%s' Started.\n", desc->name); + + return 0; +} + + +int module_load(const SPString & name) +{ + int mod_idx = module_find(name); + if (mod_idx < 0) // add new module + { + if (num_modules >= MAX_NUM_MODULES) + { + msg("Module: Max. modules number limit exceeded!\n"); + return -1; + } + mod_idx = num_modules++; + modules[mod_idx].name = name; + modules[mod_idx].hash = name.Hash(); + modules[mod_idx].loaded = FALSE; + modules[mod_idx].desc = NULL; + modules[mod_idx].client_table = NULL; + } else + { + if (modules[mod_idx].loaded) // it's already loaded! + return 0; + } + + char fname[128], arg[32]; + sprintf(fname, "/modules/%s.bin", (char *)name); + sprintf(arg, "%lu", (DWORD)module_init); + + msg("Module: Loading '%s'...\n", (char *)name); + + was_module_error = false; + int pid = module_binary_load(fname, arg); + if (pid <= 0) + { + msg("Module: Cannot load module '%s'!\n", (char *)name); + return -1; + } + + modules[mod_idx].pid = pid; + + // now we'll wait for process to settle: + for (int tries = 0; tries < 1000; tries++) + { + if (modules[mod_idx].loaded) + break; + if (was_module_error) + { + msg("Module: Error was detected during module_init()!\n"); + break; + } + usleep(100); + } + if (!modules[mod_idx].loaded) + { + msg("Module: Cannot init module '%s'.\n", (char *)name); + module_unload(name); + return -1; + } + + msg("Module: '%s' Loaded!\n", (char *)name); + return 0; +} + +int module_unload(const SPString & name) +{ + int mod_idx = module_find(name); + if (mod_idx < 0) + return -1; + if (!modules[mod_idx].loaded) + { + msg("Module: Unload - Module '%s' is not loaded!\n", (char *)name); + return -1; + } + if (module_binary_unload(modules[mod_idx].pid) >= 0) + { + if (modules[mod_idx].client_table != NULL) + { + MODULE_FUNC_TABLE *tbl = modules[mod_idx].client_table; + for (int i = 0; tbl[i].addr != NULL; i++) + { + module_clear_func(modules[mod_idx].client_table); + } + } + modules[mod_idx].pid = -1; + modules[mod_idx].loaded = FALSE; + } + return 0; +} + +// end of extern "C" +}; + +#endif diff --git a/src/module.h b/src/module.h new file mode 100644 index 0000000..0f66ad4 --- /dev/null +++ b/src/module.h @@ -0,0 +1,76 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - module system header file + * \file module.h + * \author bombur + * \version 0.1 + * \date 10.12.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MODULE_H +#define SP_MODULE_H + +typedef struct MODULE_FUNC_TABLE +{ + int id; + void *addr; +} MODULE_FUNC_TABLE; + +#define MODULE_DECL_START() enum { +#define MODULE_DECL_END() }; + +#ifdef MODULE_SERVER +#define MODULE_DECL(f) modid_##f +#else +#define MODULE_DECL(f) modid_##f }; MODULE_FUNC(f); enum { modid_##f##_continue = modid_##f + +#endif + +#define MODULE_ENTRY(f) { modid_##f, ((void *)&f) } +#define MODULE_ENTRY_END() { -1, 0 } + +typedef struct MODULE_DESC +{ + const char *name; /// module name + const char *class_name; /// module class name + const char *desc; /// module description + int ver; /// module version (100 = 1.00) + int init_ver; /// minimal init (module sys.) version (100 = 1.00) + + int reserved[16]; + +} MODULE_DESC; + +#ifdef COMPILE_MODULE +extern "C" +{ +void module_start(char *interface_ptr_str, MODULE_DESC *desc, MODULE_FUNC_TABLE *client, MODULE_FUNC_TABLE *server); +} +#else + +#include +extern "C" +{ +int module_load(const SPString & name); +int module_unload(const SPString & name); +} +#endif + + + +#endif // of SP_MODULE_H diff --git a/src/mpg.cpp b/src/mpg.cpp new file mode 100644 index 0000000..be8973d --- /dev/null +++ b/src/mpg.cpp @@ -0,0 +1,739 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MPEG1/MPEG2/VOB files player source file. + * \file mpg.cpp + * \author bombur + * \version 0.2 + * \date 02.07.2010 07.05.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "script.h" +#include "player.h" +#include "media.h" +#include "settings.h" + +#ifdef INTERNAL_VIDEO_PLAYER + +#define VIDEO_INTERNAL + +#include "audio.h" +#include "video.h" +#include "mpg.h" + +#define MSG if (video_msg) msg + +static const int seek_delta_pts = 60 * 90000; // 1 min. + +VideoMpg::VideoMpg() +{ + type = VIDEO_CONTAINER_MPEG; + new_frame_size = true; + cur_rate = 0; + + scan_for_length = true; + seek_start = true; + start_time_pts = -1; + end_time_pts = -1; + totaltime_pts = 0; + pts_base = 0; + wait_for_new_pts = false; + set_pts = true; + + elementary_stream = false; + is_cdxa = false; + + packet_left = 0; + saved_sct = START_CODE_UNKNOWN; + saved_length = -1; + saved_start_counter = 0; + saved_feed = true; + + //tmp_packet_header_buf_active = false; + //tmp_packet_header_buf_size = 0; + packet_header_incomplete = false; + + was_pack = false; + + mpeg_format = -1; + mpeg_aspect = -1; + + old_pts = 0; + video_pts = 0; + + is_totaltime_from_rate = false; + +} + +VideoMpg::~VideoMpg() +{ +} + +//////////////////////////////////////////////// + +BOOL VideoMpg::Parse() +{ + // Read first 4 bytes and check that this is an MPEG file + BYTE data[16]; + if (video_read(data, 12) != 12) + { + msg_error("Mpg: Read error.\n"); + return FALSE; + } + if (strncasecmp((char *)data, "RIFF", 4) == 0 && strncasecmp((char *)data+8, "AVI ", 4) == 0) + { + msg_error("Mpg: Avi file found in MPEG container.\n"); + return FALSE; + } + if (strncasecmp((char *)data, "RIFF", 4) == 0 && strncasecmp((char *)data+8, "CDXA", 4) == 0) + { + msg("Mpg: CDXA format detected.\n"); + is_cdxa = true; + } + video_lseek(0, SEEK_END); + filesize = video_lseek(0L, SEEK_CUR); + seek_filesize = filesize; + +//msg("! seek_filesize = %d\n", (int)seek_filesize); + + video_lseek(0, SEEK_SET); + + video_fmt = RIFF_VIDEO_MPEG12; + video_fmt_str.Printf("MPEG-1/2"); + + //MPEG_PACKET_LENGTH = 2048; + MPEG_PACKET_LENGTH = 32768; + MPEG_NUM_PACKETS = 512; + set_media_type(MEDIA_TYPE_MPEG); + + return TRUE; +} + +BOOL VideoMpg::GetTimeLength() +{ + LONGLONG pos = video_lseek(-32768, SEEK_END); + int ret = mpeg_find_free_blocks(MPEG_BUFFER_1); + // we cannot wait + if (ret < 1) + return FALSE; + BYTE *base = mpeg_getcurbuf(MPEG_BUFFER_1); + if (base == NULL) + return FALSE; + int len = (int)video_read(base, (int)(filesize - pos)); + if (len < 1) + return FALSE; + + // now parse the stream + MPEG_PACKET_LENGTH = len; + start_time_pts = -1; + end_time_pts = -1; + totaltime_pts = 0; + seek_start = false; + scan_for_length = true; + fps = 30; // not correct, but it works + ProcessChunk(base, len); + MPEG_PACKET_LENGTH = 32768; + + video_lseek(0, SEEK_SET); + seek_start = true; + scan_for_length = true; + + return TRUE; +} + +////////////////////////////////////////////////////////////////// + +VIDEO_CHUNK_TYPE VideoMpg::GetNext(BYTE *, int , int *, int *, int *) +{ + return VIDEO_CHUNK_UNKNOWN; +} + +int VideoMpg::ProcessChunk(BYTE *buf, int ) +{ + START_CODE_TYPES sct; + BYTE *base = buf, *lastbuf = base; + + for (; ;) + { + if (packet_left > 0 || (elementary_stream && saved_sct != START_CODE_UNKNOWN)) + sct = saved_sct; + else + { + sct = mpeg_findpacket(buf, base, saved_start_counter); + if (sct == START_CODE_END) + { + return 1; + } + saved_start_counter = 0; + } + bool datapacket = false; + switch (sct) + { + case START_CODE_PACK: + { + int left = MPEG_PACKET_LENGTH - (buf - base); + if (packet_left > 0) + { + memcpy(tmp_packet_header_buf + packet_left, buf, 8 - packet_left); + BYTE *b = tmp_packet_header_buf; + scr = mpeg_parse_program_stream_pack_header(b, tmp_packet_header_buf); + buf += 8; + packet_left = 0; + } + else if (left < 8) + { + memcpy(tmp_packet_header_buf, buf, left); + packet_left = left; + saved_sct = sct; + return 1; + } + else + scr = mpeg_parse_program_stream_pack_header(buf, base); + scr += pts_base; + if (scr < 0) + scr = 0; + if (scr > 0 && scan_for_length) + { + //scan_for_length = false; + if (seek_start) + { + if (start_time_pts < 0) + { + start_time_pts = scr; + UpdateTotalTime(); + } + } + else + { + if (scr > end_time_pts && (end_time_pts < 0 || scr < end_time_pts + 120000)) + end_time_pts = scr; + // early exit + //return 1; + } + } + // this is needed for 'khwl' + scr |= SPTM_SCR_FLAG; + was_pack = true; + lastbuf = buf; + } + break; + case START_CODE_SYSTEM: + case START_CODE_PCI: + case START_CODE_PADDING: + { + int len; + int left = MPEG_PACKET_LENGTH - (buf - base); + if (left < 1) + return 1; + if (packet_left > 0) + { + // if we read only 1 byte of packet length + if (saved_length >= 0) + { + // one byte was already read + len = ((saved_length << 8) | buf[0]) + 1; + } else + len = packet_left; + packet_left = 0; + saved_length = -1; + } + else + { + if (left < 2) // cannot get length + { + saved_length = buf[0]; + packet_left = 1; + saved_sct = sct; + return 1; + } + len = ((buf[0] << 8) | buf[1]) + 2; + } + + if (len > left) // length is greater than packet size + { + packet_left = len - left; + saved_length = -1; + len = left; + saved_sct = sct; + return 1; + } + // it's safe now + buf += len; + lastbuf = buf; + break; + } + case START_CODE_MPEG_VIDEO_ELEMENTARY: + elementary_stream = true; + saved_sct = sct; + case START_CODE_MPEG_VIDEO: + case START_CODE_MPEG_AUDIO1: + case START_CODE_MPEG_AUDIO2: + case START_CODE_PRIVATE1: + datapacket = true; + break; + default:; + } + + if (datapacket) + { + if (scan_for_length) + { + LONGLONG pts = 0; + if (!seek_start) + { + if (sct == START_CODE_MPEG_VIDEO && was_pack) + { + MpegPacket tmppacket; + tmppacket.flags = 0; + tmppacket.pts = 0; + if (mpeg_extractpacket(buf, base, &tmppacket, sct, FALSE) >= 0) + { + if (tmppacket.flags == 2 && tmppacket.pts > 0) + pts = tmppacket.pts; + } + buf += tmppacket.size; + lastbuf = buf; + } + } +#if 0 + if (sct == START_CODE_MPEG_VIDEO || sct == START_CODE_MPEG_VIDEO_ELEMENTARY) + { + BYTE *last = base + MIN(buflen, MPEG_PACKET_LENGTH); + for(BYTE *b = buf; b < last; b++) + { + if (b[0] == 0 && b[1] == 0 && b[2] == 1 && b[3] == 0xb8) // GOP + { + // xhhhhhmm mmmmxsss sssfffff fxxxxxxx + int hours = (b[4] >> 2) & 63; + int mins = ((b[4] & 3) << 4) | (b[5] >> 4); + int secs = ((b[5] & 7) << 3) | (b[6] >> 5); + int frames = ((b[6] << 1) & 63) | (b[7] >> 7); + pts = ((LONGLONG)(hours * 3600) + (LONGLONG)(mins * 60) + (LONGLONG)secs) * + INT64(90000) + (LONGLONG)frames * INT64(90000) / fps; + break; + } + } + // we don't need packets if we scan at the end of file + if (pts == 0 && !seek_start) + return 1; + } +#endif + if (seek_start) + { + if (pts > 0) + { + scan_for_length = false; + start_time_pts = pts; + UpdateTotalTime(); + } + } + else + { + if (pts > 0 && pts > end_time_pts) + { + end_time_pts = pts; + scan_for_length = false; + return 1; + } + if (elementary_stream) + return 1; + continue; + } + } + + // audio or video + MpegPacket *packet = NULL; + packet = mpeg_feed_getlast(); + if (packet == NULL) // well, it won't really help + return 0; + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + packet->pts = pts_base; + + //!!!!!!!!!!!!!!!!!!! + packet->scr = scr; + + bool feed = true; + + if (packet_header_incomplete) // we haven't read the header last time + { + packet_left = 0; + packet_header_incomplete = false; + } + + if (packet_left > 0) + { + packet->type = saved_packet->type; + packet->pData = buf; + packet->size = packet_left; + packet->pts = saved_packet->pts; + packet->nframeheaders = saved_packet->nframeheaders; + packet->firstaccessunitpointer = saved_packet->firstaccessunitpointer; + packet->scr = 0; + feed = saved_feed; + packet_left = 0; + } else + { + BYTE *lb = buf; + int ret = mpeg_extractpacket(buf, base, packet, sct, wait_for_new_pts); + if (ret < 0) // if not enough data in the packet + { + LONGLONG off = -(base + MPEG_PACKET_LENGTH - lb); + video_lseek(off, SEEK_CUR); + saved_sct = sct; + packet_left = 1; // the value doesn't really matter + packet_header_incomplete = true; + return 1; + } + if (ret == 0) + feed = false; + } + + int left = MPEG_PACKET_LENGTH - (buf - base); + bool need_return = false; + if ((int)packet->size > left) // length is greater than packet size + { + packet_left = packet->size - left; + packet->size = left; + saved_sct = sct; + saved_packet = packet; + saved_feed = feed; + need_return = true; + } + + if (new_frame_size) + { + int w, h; + mpeg_getframesize(&w, &h); + if (w != 0 && h != 0) + { + script_framesize_callback(w, h); + new_frame_size = false; + } + + int aspect = mpeg_getaspect(); + if (mpeg_aspect != aspect) + { + mpeg_aspect = aspect; + + int tvtype = settings_get(SETTING_TVTYPE); + KHWL_VIDEOMODE vmode = KHWL_VIDEOMODE_NORMAL; + if (aspect == 2) // 4:3 + { + if (tvtype == 0 || tvtype == 1) + vmode = KHWL_VIDEOMODE_NORMAL; + else + vmode = (tvtype == 2) ? KHWL_VIDEOMODE_HCENTER : KHWL_VIDEOMODE_VCENTER; + } + else if (aspect == 3) // 16:9 + { + if (tvtype == 2 || tvtype == 3) + vmode = KHWL_VIDEOMODE_WIDE; + else + vmode = (tvtype == 0) ? KHWL_VIDEOMODE_LETTERBOX : KHWL_VIDEOMODE_PANSCAN; + } + msg("MPEG: set vmode = %d (%d)\n", vmode, aspect); + + khwl_display_clear(); + khwl_set_window_zoom(KHWL_ZOOMMODE_DVD); + khwl_setvideomode(vmode, TRUE); + } + + int cur_fps = mpeg_get_fps(); + if (cur_fps > 0) + { + fps = cur_fps; + script_framerate_callback(fps); + } + + int cur_fmt = mpeg_get_video_format(); + if (cur_fmt != mpeg_format) + { + if (!elementary_stream) + { + video_fmt_str.Empty(); + video_fmt_str.Printf("MPEG-%d", cur_fmt == MPEG_1 ? 1 : 2); + script_video_info_callback(video_fmt_str); + MSG("Video: * Video format %s detected!\n", *video_fmt_str); + mpeg_format = cur_fmt; + } + } + } + + if (packet->flags == 2 && feed) + { + if (wait_for_new_pts) + { + if (packet->type == 0) + { + if (mpeg_needs_seq_start_header(&packet)) + wait_for_new_pts = false; + else + feed = false; + } + else + feed = false; + } + if (packet->type == 0) + { + pts_base += mpeg_detect_and_fix_pts_wrap(packet); + if (set_pts) + { + mpeg_setpts(packet->pts); + set_pts = false; + } + video_pts = packet->pts; + } else + { + int cur_numaudio_streams = mpeg_getaudiostreamsnum(); + if (cur_numaudio_streams != num_tracks) + { + num_tracks = cur_numaudio_streams; + } + } + + if (displ_pts_base == 0) + { + if (packet->type == 0) + { + displ_pts_base = -MAX(packet->pts - 45000, 0); + /* + pts_base = -MAX(packet->pts - 45000, 0); + packet->pts += pts_base; + scr = packet->scr = ((packet->scr & (~SPTM_SCR_FLAG)) + pts_base) | SPTM_SCR_FLAG; + */ + } + } + int rate = mpeg_getrate(elementary_stream); + if (rate != cur_rate) + { + // calc. total time + if (rate > 0) + { + UpdateTotalTime(); + cur_rate = rate; + } + } + old_pts = packet->pts; + } else + { + if (wait_for_new_pts) + feed = false; + packet->pts = old_pts; + } +#if 0 +{ +static int num_packets = 0; + +static LONGLONG last_pts = 0; +if (feed) +{ +if (packet->type == 1) +msg("[%d] a - %d ---%d: %8d\t\t%d\t\t[%d]\t%d\n", num_packets, packet->size, packet->flags, (int)packet->pts, (int)(packet->scr & 0xfffffff), (int)(packet->pts - last_pts), pts_base); +else if (packet->type == 0) +msg("[%d] v - %d ---%d: %8d\t\t%d\t\t[%d]\t%d\n", num_packets, packet->size, packet->flags, (int)packet->pts, (int)(packet->scr & 0xfffffff), (int)(packet->pts - last_pts), pts_base); +last_pts = packet->pts; +} +/* +extern void player_printpacket(MpegPacket *packet); +player_printpacket(packet); +*/ +num_packets++; +} +//!!!!!!!!!!!!!!!!!!!!! +/* +if (msg_get_output() == MSG_OUTPUT_SHOW && packet->type != 0) +feed = false; +if (msg_get_output() == MSG_OUTPUT_FREEZE && packet->type != 0 && packet->type != 1) +feed = false; +*/ +//!!!!!!!!!!!!!!!!!!!!! +#endif + + //packet->vobu_sptm = (vobu_sptm + pts_base) | SPTM_SCR_FLAG; + // increase bufidx + if (packet->size >= 1 && feed) + { + mpeg_setbufidx(MPEG_BUFFER_1, packet); + mpeg_feed((MPEG_FEED_TYPE)packet->type); + //num_packets++; + } + buf += packet->size; + lastbuf = buf; + + if (need_return) + return 1; + } + } + return 1; +} + +void VideoMpg::UpdateTotalTime() +{ + LONGLONG new_totaltime = 0; + if (start_time_pts >= 0 && end_time_pts >= 0 && end_time_pts > start_time_pts) + { + new_totaltime = (end_time_pts - start_time_pts); + seek_filesize = filesize; + is_totaltime_from_rate = false; +//msg("! new_tt = %d (s=%d e=%d)\n", (int)new_totaltime, (int)start_time_pts, (int)end_time_pts); + } + else + { + LONGLONG rate = (LONGLONG)mpeg_getrate(elementary_stream); + if (rate > 0) + { + new_totaltime = INT64(90000) * filesize / rate; + seek_filesize = filesize; + is_totaltime_from_rate = true; +//msg("! new_tt = %d (r=%d fs=%d)\n", (int)new_totaltime, (int)rate, (int)filesize); + } + } + // if we're unable to deremine total time + if (video_pts + displ_pts_base > new_totaltime) + { + new_totaltime = video_pts + displ_pts_base; + seek_filesize = media_get_filepos(); + is_totaltime_from_rate = false; +//msg("! video_pts (%d) > new_totaltime (%d)\n", (int)video_pts, (int)new_totaltime); +//msg("! seek_filesize = %d\n", (int)seek_filesize); + } + if (new_totaltime > 0) + { + if (new_totaltime > totaltime_pts || (is_totaltime_from_rate && Abs(new_totaltime - totaltime_pts) > 90000)) + { + script_totaltime_callback((int)(new_totaltime / 90000)); + totaltime_pts = new_totaltime; + } + } +} + +int VideoMpg::GetNextIndexes() +{ + return -1; +} + +int VideoMpg::GetNextKeyFrame() +{ + return -1; +} + +int VideoMpg::GetKeyFrame(LONGLONG time) +{ + // undo some Video actions for MPEGs: + skip_fwd = false; + skip_rev = false; + skip_cnt = 0; + searching = false; + packet_left = 0; + + packet_header_incomplete = false; + + old_pts = 0; + wait_for_new_pts = true; + set_pts = true; + was_pack = false; + + saved_sct = START_CODE_UNKNOWN; + saved_length = -1; + saved_start_counter = 0; + saved_feed = true; + + mpeg_stop(); + mpeg_setspeed(MPEG_SPEED_NORMAL); + media_skip_buffer(NULL); + mpeg_setpts(0); + mpeg_start(); + + if (totaltime_pts < 1 || filesize < 1) + { + msg("MPEG: Cannot seek! Total time or size unknown.\n"); + return -1; + } + + LONGLONG curtime = saved_pts; + LONGLONG vpts = video_pts + displ_pts_base; + if (curtime < 0) + curtime = 0; + if (curtime > vpts) + curtime = vpts; + if (curtime < vpts - 10*90000) + curtime = vpts; + LONGLONG pts = 0; + + if (time == VIDEO_KEY_FRAME_NEXT) + { + pts = curtime + seek_delta_pts; + } + else if (time == VIDEO_KEY_FRAME_PREV) + { + pts = curtime - seek_delta_pts; + } + else + { + pts = time * 90000; + } + + LONGLONG filepos = (seek_filesize * pts / totaltime_pts) & (~(/*MPEG_PACKET_LENGTH*/512 - 1)); + if (filepos < 0) + filepos = 0; + // a special correction fix for VBR MPEGs + if (time == VIDEO_KEY_FRAME_NEXT || time == VIDEO_KEY_FRAME_PREV) + { + LONGLONG rate = (LONGLONG)mpeg_getrate(elementary_stream); + if (rate > 0) + { + LONGLONG avg_rate = INT64(90000) * seek_filesize / totaltime_pts; + LONGLONG thr = 100 * Abs(rate - avg_rate) / avg_rate; + if (thr < 10) + { + LONGLONG delta_pos = filepos - media_get_filepos(); + LONGLONG delta_time = INT64(90000) * delta_pos / rate; + LONGLONG d = Abs(delta_time) - seek_delta_pts; + d = seek_delta_pts * rate / INT64(90000); + if (time == VIDEO_KEY_FRAME_PREV) + d = -d; + filepos = media_get_filepos() + d; + msg("MPEG: * Bitrate-correcting (" PRINTF_64d ", r=" PRINTF_64d ")!\n", d, rate); + } + } + } + msg("(saved=%d fsize=%d)\n", (int)saved_pts, (int)seek_filesize); + msg("MPEG: Seek to " PRINTF_64d " (filepos=" PRINTF_64d "/" PRINTF_64d ")\n", pts, filepos, filesize); + LONGLONG ret = video_lseek(filepos, SEEK_SET); + if (ret != filepos) + msg("MPEG: Seek ERROR! Pos = " PRINTF_64d "\n", ret); + if (ret < 0) + { + msg("MPEG: Cannot seek! File error %d.\n", -errno); + return -1; + } + return 1; +} + +#endif diff --git a/src/mpg.h b/src/mpg.h new file mode 100644 index 0000000..577c43d --- /dev/null +++ b/src/mpg.h @@ -0,0 +1,90 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - MPEG1/MPEG2/VOB files player header file + * \file mpg.h + * \author bombur + * \version 0.1 + * \date 07.05.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_MPG_H +#define SP_MPG_H + +#include "video.h" + +#ifdef VIDEO_INTERNAL + +/// MPEG container player class +class VideoMpg : public Video +{ +public: + /// ctor + VideoMpg(); + + /// dtor + virtual ~VideoMpg(); + +public: + virtual BOOL Parse(); + virtual VIDEO_CHUNK_TYPE GetNext(BYTE *buf, int buflen, int *pos, int *left, int *len); + /// Returns 0 if found, -1 if failed, 1 for EOF. + virtual int GetNextIndexes(); + /// Find next key-frame in raw mode + virtual int GetNextKeyFrame(); + + virtual int GetKeyFrame(LONGLONG time); + virtual void UpdateTotalTime(); + + /// Called from video.cpp + int ProcessChunk(BYTE *buf, int buflen); + + BOOL GetTimeLength(); + +private: + int mpeg_format, mpeg_aspect; + bool new_frame_size; + bool elementary_stream, is_cdxa; + bool wait_for_new_pts, set_pts; + bool is_totaltime_from_rate; + int cur_rate; + LONGLONG filesize, seek_filesize; + LONGLONG video_pts; + + bool scan_for_length, seek_start, was_pack; + LONGLONG start_time_pts, end_time_pts; + LONGLONG totaltime_pts, pts_base; + int fps; + + int packet_left; + START_CODE_TYPES saved_sct; + int saved_length; + int saved_start_counter; + bool saved_feed; + MpegPacket *saved_packet; + + BYTE tmp_packet_header_buf[128]; + bool packet_header_incomplete; + + LONGLONG old_pts; +}; + +#endif + +/////////////////////////////////////////////////////////////// + +#endif // of SP_MPG_H diff --git a/src/player.cpp b/src/player.cpp new file mode 100644 index 0000000..d01579a --- /dev/null +++ b/src/player.cpp @@ -0,0 +1,931 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - File player source file. + * \file player.cpp + * \author bombur + * \version 0.1 + * \date 22.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "player.h" + +#ifdef WIN32 +#include "info/player_info.h" +#endif + +#ifdef EXTERNAL_PLAYER +#define MSG if (player_msg) msg +static BOOL player_msg = TRUE; +#endif + +#ifdef FILEPLAYER_DEBUG + +//#define FILEPLAYER_DEBUG +//#define DEBUG_MSG msg +#define DEBUG_MSG printf + + +static int player_debug_num_packets = 0; +//extern "C" +//{ +void player_printpacket(MpegPacket *packet) +{ + DEBUG_MSG("[%d] t=%d fl=%ld\n", player_debug_num_packets++, packet->type, packet->flags); + DEBUG_MSG("SIZE=%ld\n", packet->size); + if (packet->pData != NULL) + { + int s = (packet->size + 7) / 8; + for (int i = 0; i < s; i += 8) + { + DEBUG_MSG("DATA: %02x %02x %02x %02x %02x %02x %02x %02x\n", + packet->pData[i+0], packet->pData[i+1], packet->pData[i+2], packet->pData[i+3], + packet->pData[i+4], packet->pData[i+5], packet->pData[i+6], packet->pData[i+7]); + } + } + DEBUG_MSG("pts=%u+%u dts=%u scr=%u+%u vobu=%u+%u\n", + (unsigned)(packet->pts >> 32), (unsigned)packet->pts, + (unsigned)packet->dts, + (unsigned)(packet->scr >> 32), (unsigned)packet->scr, + (unsigned)(packet->vobu_sptm >> 32), (unsigned)packet->vobu_sptm); + DEBUG_MSG("ei=%d nfh=%d faup=%d at=%d r=%d,%d,%d\n", + (int)packet->encryptedinfo, (int)packet->nframeheaders, (int)packet->firstaccessunitpointer, + (int)packet->AudioType, + (int)packet->reserved[0], (int)packet->reserved[1], (int)packet->reserved[2]); + DEBUG_MSG("\n\n"); + fflush(stdout); +} + +/* +void player_feed(MpegPlayStruct *feed) +{ + MpegPlayStruct *from = MPEG_PLAY_STRUCT; + if (from->in != NULL) + player_printpacket(from->in); + mpeg_feed(feed); +} +//} +int player_nextfeedpacket(MpegPlayStruct *feed) +{ + MpegPlayStruct *from = MPEG_PLAY_STRUCT; + MpegPacket *feedin = feed->in; + if (feedin == NULL) + return FALSE; + + player_printpacket(feedin); + + feed->in = feed->in->next; + + feed->num--; + feed->in_cnt++; + from->num++; + from->out_cnt++; + + if (feedin->next == NULL) + feed->out = NULL; + if (from->out == NULL) + from->in = feedin; + else + from->out->next = feedin; + from->out = feedin; + feedin->next = NULL; + + ////// simulate budidx decrement + if (feedin->bufidx) + { + if (*(feedin->bufidx) > 0) + (*feedin->bufidx)--; + } + + return TRUE; +} + +void player_debug_packets() +{ + for (;;) + { + //khwl_blockirq(TRUE); + while (MPEG_VIDEO_STRUCT->in != NULL) + { + player_nextfeedpacket(MPEG_VIDEO_STRUCT); + } + while (MPEG_AUDIO_STRUCT->in != NULL) + { + player_nextfeedpacket(MPEG_AUDIO_STRUCT); + } + while (MPEG_SPU_STRUCT->in != NULL) + { + player_nextfeedpacket(MPEG_SPU_STRUCT); + } + //khwl_blockirq(FALSE); + usleep(1000); + } +} +*/ +#endif + +/////////////////////////////////////////////////// + +class PlayerTerm +{ +public: + /// ctor + PlayerTerm() + { + master_handle = -1; + slave_handle = -1; + old_stdin = -1; + old_stdout = -1; + pts_id = -1; + } + + /// Create and open terminal + int Open(); + /// Close terminal + void Close(); + + /// Return true if terminal is opened + bool IsOpened(); + + /// Set terminal to current stdin/stdout + void Set(); + + /// Restore default stdin/stdout + void Restore(); + + /// Read data from the terminal (non-blocked). + /// Returns number of bytes read. + int Read(char *data, int max_data_size); + + /// Write zero-terminated string to the terminal. + void Write(const char *str); + +public: + int master_handle, slave_handle; + int old_stdin, old_stdout; + int pts_id; +}; + + +int PlayerTerm::Open() +{ + if (slave_handle >= 0) + Restore(); + if (master_handle >= 0) + Close(); + + char pts_str[10]; + pts_id = openpty (&master_handle, &slave_handle, pts_str, NULL, NULL); + if (pts_id == -1) + { + msg_error("Player: Cannot open pty.\n"); + return -1; + } + + struct termios tattr; + if (tcgetattr (master_handle, &tattr) == -1) + { + msg_error("Player: pty getattr failed.\n"); + return -1; + } + tattr.c_oflag &= ~ONLCR; + tattr.c_lflag &= ~ECHO; + tcsetattr(master_handle, TCSANOW, &tattr); + + int flgs = fcntl(master_handle, F_GETFL, 0); + fcntl(master_handle, F_SETFL, flgs | O_NONBLOCK); + + msg("Player: * pty #%d (%s) opened.\n", pts_id, pts_str); + + return 0; +} + +void PlayerTerm::Close() +{ + if (master_handle >= 0) + { + close(master_handle); + master_handle = -1; + + msg("Player: * pty #%d closed.\n", pts_id); + pts_id = -1; + } +} + +void PlayerTerm::Set() +{ + old_stdin = dup(STDIN_FILENO); + old_stdout = dup(STDOUT_FILENO); + close(STDIN_FILENO); + close(STDOUT_FILENO); + + dup2(slave_handle, STDIN_FILENO); + dup2(slave_handle, STDOUT_FILENO); +} + +void PlayerTerm::Restore() +{ + dup2(old_stdin, STDIN_FILENO); + dup2(old_stdout, STDOUT_FILENO); + close(old_stdin); + close(old_stdout); + close(slave_handle); + old_stdin = -1; + old_stdout = -1; + slave_handle = -1; +} + +bool PlayerTerm::IsOpened() +{ + return master_handle >= 0; +} + +void PlayerTerm::Write(const char *str) +{ + if (master_handle >= 0) + write(master_handle, str, strlen(str) + 1); +} + +int PlayerTerm::Read(char *data, int max_data_size) +{ + struct pollfd pfd; + pfd.fd = master_handle; + pfd.events = POLLIN; + pfd.revents = 0; + if (poll(&pfd, 1, 100) <= 0) + return 0; + if (pfd.revents & POLLIN) + { + return read(master_handle, data, max_data_size); + } + return 0; +} + +///////////////////////////////////////////////////// + +static PlayerTerm id3term; +static void player_parseid3(char *data, int data_size); +static void stopid3(); + +enum PLAYER_READID3 +{ + PLAYER_READID3_NONE = 0, + PLAYER_READID3_TITLE, + PLAYER_READID3_ARTIST, + PLAYER_READID3_WIDTH, + PLAYER_READID3_HEIGHT, + PLAYER_READID3_CLRS, +}; + +static PLAYER_READID3 player_reading_id3 = PLAYER_READID3_NONE; +const int id3_max_data_size = 256; +static char id3_data[id3_max_data_size + 1]; +static int id3id = -1; + +inline void to_enter(char* &data, int &data_size) +{ + char *end = strchr(data, '\n'); + if (end != NULL) + { + *end = '\0'; + data_size -= (end - data + 1); + data = end + 1; + } else + data_size = 0; +} + +// called when child player process ends +static void player_sig_handler(int sig, siginfo_t *info, void *) +{ + if (sig != SIGCHLD) + return; + msg("Player: * SIG handler (%d)!\n", info->si_pid); + int pstat; + waitpid(info->si_pid, &pstat, 0); +#ifdef EXTERNAL_PLAYER + if (info->si_pid == playerid) + stopfile(); +#endif + if (info->si_pid == id3id) + stopid3(); +} + +void set_sig(void (*siga) (int, siginfo_t *, void *)) +{ + struct sigaction sig; + memset(&sig, 0, sizeof(sig)); + if (siga != NULL) + sig.sa_flags = SA_SIGINFO; + sig.sa_sigaction = siga; + sigaction(SIGCHLD, &sig, NULL); +} + +///////////////////////////////////////////////////////////////////// + +#ifdef EXTERNAL_PLAYER + +static PlayerTerm pterm; +const int player_max_data_size = 1024; +static char player_data[player_max_data_size + 1]; +static char player_type[10]; +static char vmodebuf[10]; +static bool player_paused = false; + +enum PLAYER_READINFO +{ + PLAYER_READINFO_NONE = 0, + PLAYER_READINFO_TIME = 1, + PLAYER_READINFO_TITLE, + PLAYER_READINFO_ARTIST, + PLAYER_READINFO_VIDEOINFO, + PLAYER_READINFO_AUDIOINFO, +}; +static PLAYER_READINFO player_reading_info = PLAYER_READINFO_NONE; + +static int playerid = -1; +static BOOL playing = FALSE, video = FALSE, mpegplayer = FALSE; +static int mpegplayer_info_cnt = 0; + +static int playfile(const char *filename, const char *type, int vmode); +static BOOL player_command(const char *command); +static void stopfile(); +static void stopid3(); +static void player_parseinfo(char *data, int data_size); +static void set_sig(void (*siga) (int, siginfo_t *, void *)); + +int playfile(const char *filename, const char *type, int vmode) +{ + char *args1[] = { "/bin/fileplayer.bin", (char *)type, (char *)filename, (char *)vmodebuf, NULL }; + char *args2[] = { "/bin/mpegplayer.bin", (char *)filename, (char *)vmodebuf, NULL }; + char **args = (char **)args1; + video = FALSE; + mpegplayer = FALSE; + mpegplayer_info_cnt = 0; + sprintf(vmodebuf, "%d", vmode); + if (type != NULL) + { + if ((type[0] == 'M' && type[1] == 'P' && type[2] == 'G') || + (type[0] == 'M' && type[1] == 'P' && type[2] == 'E' && type[3] == 'G') || + (type[0] == 'V' && type[1] == 'O' && type[2] == 'B') || + (type[0] == 'D' && type[1] == 'A' && type[2] == 'T') + ) + { + args = (char **)args2; + video = TRUE; + mpegplayer = TRUE; + } + else + { + if ((type[0] == 'A' && type[1] == 'V' && type[2] == 'I')) + video = TRUE; + } + } + + if (playerid != -1) + player_stop(); + + pterm.Open(); + set_sig(player_sig_handler); + pterm.Set(); + playerid = exec_file(args[0], (const char **)args); + pterm.Restore(); + + MSG("Player: * Started (%d)...\n", playerid); + playing = TRUE; + + return 0; +} + +void stopfile() +{ + if (playerid < 0) + return; + + fip_clear(); + + // we'll have to wait for the next player_loop() + playerid = -1; + playing = FALSE; + video = FALSE; + mpegplayer = FALSE; + + MSG("Player: * Stopped.\n"); +} + +BOOL player_command(const char *command) +{ + if (playerid < 0 || command == NULL) + return FALSE; + MSG("Player: *COMMAND = %s\n", command); + pterm.Write(command); + return TRUE; +} + +/////////////////////////////////////////////////////////// + +int player_play(char *filepath) +{ +#ifdef FILEPLAYER_DEBUG + player_debug_num_packets = 0; + /* + DWORD *ptr = (DWORD *)0x167FFE0; + *(ptr) = (DWORD)&player_printpacket; + */ +#endif + + if (filepath == NULL) // resume playing + { + player_command("P\n"); + return 0; + } + + // start player + char *ext = strrchr(filepath, '.'); + if (ext != NULL) + { + ext = ext + 1; + strncpy(player_type, ext, 10); + strupr(player_type); + + int vmode = 0; + // TODO: set real vmode + player_paused = false; + return playfile(filepath, player_type, vmode); + } + // unknown file type... + return -1; +} + +int player_info_loop() +{ +#ifdef FILEPLAYER_DEBUG +// player_debug_packets(); +#endif + + if (pterm.IsOpened()) + { + int player_data_size = pterm.Read(player_data, player_max_data_size); + //strcpy(player_data, "Info\n00:00:24\nN/A\nN/A\nN/A\nN/A\n"); + //int player_data_size = strlen(player_data); + + // parse data from player: + if (player_data_size > 0) + { + player_data[player_data_size] = '\0'; + //MSG("data[%d]: %s\n", player_data_size, player_data); + if (!mpegplayer || mpegplayer_info_cnt++ < 10) + player_parseinfo(player_data, player_data_size); + } + } + // playing stopped, so clean-up + if (playerid < 0) + { + if (pterm.IsOpened()) + { + pterm.Close(); + player_reading_info = PLAYER_READINFO_NONE; + } + return 1; + } + return 0; +} + +void player_parseinfo(char *data, int data_size) +{ + while (data_size > 0) + { + if (player_reading_info == PLAYER_READINFO_TIME) + { + if (data_size > 7) + { + int timelen = 0; + if (isdigit(data[0])) + { + timelen = ((data[0] - '0') * 10 + (data[1] - '0')) * 3600; + timelen += ((data[3] - '0') * 10 + (data[4] - '0')) * 60; + timelen += ((data[6] - '0') * 10 + (data[7] - '0')); + } + script_totaltime_callback(timelen); + MSG("* TOTAL TIME: %d secs\n", timelen); + data += 8; + data_size -= 8; + player_reading_info = PLAYER_READINFO_TITLE; + to_enter(data, data_size); + continue; + } + data++; + data_size--; + } + else if (player_reading_info == PLAYER_READINFO_TITLE) + { + char *titl = data; + to_enter(data, data_size); + MSG("* TITLE: %s.\n", titl); + player_reading_info = PLAYER_READINFO_ARTIST; + continue; + } + else if (player_reading_info == PLAYER_READINFO_ARTIST) + { + char *artist = data; + to_enter(data, data_size); + MSG("* ARTIST: %s.\n", artist); + player_reading_info = PLAYER_READINFO_AUDIOINFO; + continue; + } + else if (player_reading_info == PLAYER_READINFO_AUDIOINFO) + { + char *ai = data; + to_enter(data, data_size); + script_audio_info_callback(ai); + MSG("* AUDIO: %s.\n", ai); + player_reading_info = PLAYER_READINFO_VIDEOINFO; + continue; + } + else if (player_reading_info == PLAYER_READINFO_VIDEOINFO) + { + char *vi = data; + to_enter(data, data_size); + script_video_info_callback(vi); + MSG("* VIDEO: %s.\n", vi); + player_reading_info = PLAYER_READINFO_NONE; + continue; + } + else + { + DWORD cmd = SafeGetDword(data); + if (cmd == 0x656d6954 && data_size >= 7) // "Time" + { + if (data[4] <= 99 && data[5] <= 59 && data[6] <= 59) + { + int tim = data[4] * 3600 + data[5] * 60 + data[6]; + script_time_callback(tim); + MSG("PLAYER TIME = %d\n", tim); + } + data += 7; + data_size -= 7; + player_reading_info = PLAYER_READINFO_NONE; + } + else if (cmd == 0x6f666e49 && data_size > 4 + && data[4] == '\n') // "Info" + { + player_reading_info = PLAYER_READINFO_TIME; + data += 5; + data_size -= 5; + } + else if (cmd == 0x79616c50 && data_size >= 4) // "Play" + { + data += 4; + data_size -= 4; + player_reading_info = PLAYER_READINFO_NONE; + player_paused = false; + } + else if (cmd == 0x74696157 && data_size >= 4) // "Wait" + { + data += 4; + data_size -= 4; + script_error_callback(SCRIPT_ERROR_WAIT); + player_reading_info = PLAYER_READINFO_NONE; + } + else if (cmd == 0x41646142 && data_size >= 4) // "BadA" + { + data += 4; + data_size -= 4; + script_error_callback(SCRIPT_ERROR_BAD_AUDIO); + player_reading_info = PLAYER_READINFO_NONE; + } + else if (cmd == 0x43646142 && data_size >= 4) // "BadC" + { + data += 4; + data_size -= 4; + script_error_callback(SCRIPT_ERROR_BAD_CODEC); + player_reading_info = PLAYER_READINFO_NONE; + } + else + { + data++; + data_size--; + player_reading_info = PLAYER_READINFO_NONE; + } + } + } +} + +BOOL player_pause() +{ + player_paused = !player_paused; + player_command("P\n"); + return TRUE; +} + +BOOL player_stop() +{ + int pstat; + if (playerid < 0) + return FALSE; + + MSG("Player: * Stopping...\n"); + + // first, we ask player to stop... + player_command("X\n"); + + // sleep and wait for signals... + sleep(1); + usleep(200000); + + // if it's still alive... + if (waitpid(playerid, &pstat, WNOHANG) == 0) + { + MSG("Player: * Stopping by force (%d)!\n", playerid); +khwl_stop(); + // kill it by force + kill(playerid, SIGKILL); + int pstat; + waitpid(playerid, &pstat, 0); +khwl_stop(); + // clear video garbage + if (video) + khwl_restoreparams(); + } + + stopfile(); + + return TRUE; +} + +BOOL player_seek(int seconds) +{ + if (player_paused) + { + player_command("P\n"); + player_paused = false; + } + + char seekcmd[10]; + sprintf(seekcmd, "s%06d\n", seconds); + player_command(seekcmd); + + return TRUE; +} + +BOOL player_zoom_hor(int /*scale*/) +{ + //player_command("zw15\n"); + //zl15 + //zr15 + //zu15 + //zd15 + //zw15 + //zw-15 + //zh15 + //zh-15 + //zF + //zR reset zoom + //zC center scroll + return FALSE; +} + +BOOL player_zoom_ver(int /*scale*/) +{ + return FALSE; +} + +BOOL player_scroll(int /*offx*/, int /*offy*/) +{ + return FALSE; +} + +int player_forward() +{ + player_command("t1\n"); + if (video && !mpegplayer) + return 1; + return 0; +} + +int player_rewind() +{ + player_command("t2\n"); + if (video && !mpegplayer) + return 1; + return 0; +} + +#endif + +////////////////////////////////////////////////////////////////////// +// INFO + +void stopid3() +{ + if (id3id < 0) + return; + + id3id = -1; + msg("Player: * ID3 Stopped.\n"); +} + + +int player_id3_loop() +{ + if (id3term.IsOpened()) + { + int id3_data_size = id3term.Read(id3_data, id3_max_data_size); + //strcpy(id3_data, "Titl\nTitle\nAuth\nArtist\n"); + //strcpy(id3_data, "Dims\n1000\n500\nClrs\n3\n"); + //int id3_data_size = strlen(id3_data); + + // parse data from fileinfo: + if (id3_data_size > 0) + { + id3_data[id3_data_size] = '\0'; + //MSG("ID3DATA (%d): [%s]\n", id3_data_size, id3_data); + player_parseid3(id3_data, id3_data_size); + + } + } + + // id3 info process stopped, so clean-up + if (id3id < 0) + { + if (id3term.IsOpened()) + { + id3term.Close(); + player_reading_id3 = PLAYER_READID3_NONE; + } + return 1; + } + + return 0; +} + +void player_parseid3(char *data, int data_size) +{ + static int width = 0; + while (data_size > 0) + { + if (player_reading_id3 == PLAYER_READID3_TITLE) + { + char *titl = data; + to_enter(data, data_size); + script_name_callback(titl); + player_reading_id3 = PLAYER_READID3_NONE; + continue; + } + else if (player_reading_id3 == PLAYER_READID3_ARTIST) + { + char *auth = data; + to_enter(data, data_size); + script_artist_callback(auth); + player_reading_id3 = PLAYER_READID3_NONE; + continue; + } + else if (player_reading_id3 == PLAYER_READID3_WIDTH) + { + char *w = data; + to_enter(data, data_size); + width = atoi(w); + player_reading_id3 = PLAYER_READID3_HEIGHT; + continue; + } + else if (player_reading_id3 == PLAYER_READID3_HEIGHT) + { + char *height = data; + to_enter(data, data_size); + script_framesize_callback(width, atoi(height)); + player_reading_id3 = PLAYER_READID3_NONE; + continue; + } + else if (player_reading_id3 == PLAYER_READID3_CLRS) + { + char *clrs = data; + to_enter(data, data_size); + script_colorspace_callback(atoi(clrs)); + player_reading_id3 = PLAYER_READID3_NONE; + continue; + } + else + { + DWORD cmd = SafeGetDword(data); + if (cmd == 0x6c746954 && data_size >= 5) // "Titl" + { + data += 5; + data_size -= 5; + player_reading_id3 = PLAYER_READID3_TITLE; + continue; + } + else if (cmd == 0x74737441 && data_size >= 5) // "Atst" + { + data += 5; + data_size -= 5; + player_reading_id3 = PLAYER_READID3_ARTIST; + continue; + } + else if (cmd == 0x736d6944 && data_size >= 5) // "Dims" + { + data += 5; + data_size -= 5; + width = 0; + player_reading_id3 = PLAYER_READID3_WIDTH; + continue; + } + else if (cmd == 0x73726c43 && data_size >= 5) // "Clrs" + { + data += 5; + data_size -= 5; + player_reading_id3 = PLAYER_READID3_CLRS; + continue; + } + else if (cmd == 0x72727245 && data_size >= 5) // "Errr" + { + data += 5; + data_size -= 5; + script_name_callback(""); + script_artist_callback(""); + //script_error_callback(); + player_reading_id3 = PLAYER_READID3_NONE; + continue; + } + else if (cmd == 0x656e6f4e && data_size >= 5) // "None" + { + data += 5; + data_size -= 5; + script_name_callback(""); + script_artist_callback(""); + player_reading_id3 = PLAYER_READID3_NONE; + continue; + } + else + data_size = 0; + } + } +} + + + +void player_startinfo(const char *fname, const char *charset) +{ +#ifdef PLAYER_INFO_EMBED + player_getinfo(fname, charset); +#else + const char *args[] = { "/bin/fileinfo.bin", fname, charset, NULL }; + + if (id3id >= 0) + { + kill(id3id, SIGKILL); + int pstat; + waitpid(id3id, &pstat, 0); + id3id = -1; + } + + id3term.Open(); + set_sig(player_sig_handler); + id3term.Set(); + id3id = exec_file(args[0], (const char **)args); + id3term.Restore(); +#endif +} + +#ifdef EXTERNAL_PLAYER +void player_setdebug(BOOL ison) +{ + player_msg = ison == TRUE; +} + +BOOL player_getdebug() +{ + return player_msg; +} +#endif diff --git a/src/player.h b/src/player.h new file mode 100644 index 0000000..5f64177 --- /dev/null +++ b/src/player.h @@ -0,0 +1,67 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - file player header file + * \file player.h + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_PLAYER_H +#define SP_PLAYER_H + +// use this for our audio/video players +#define INTERNAL_VIDEO_PLAYER +#define INTERNAL_VIDEO_MPEG_PLAYER +#define INTERNAL_AUDIO_PLAYER + +//#define EXTERNAL_PLAYER + +int player_mem_init(); +int player_mem_deinit(); + +/// Play file +int player_play(char *filepath = NULL); + +/// Advance playing +int player_info_loop(); +int player_id3_loop(); + +/// Pause playing +BOOL player_pause(); + +/// Stop playing +BOOL player_stop(); + +/// Seek to given time and play +BOOL player_seek(int seconds); + +BOOL player_zoom_hor(int scale); +BOOL player_zoom_ver(int scale); +BOOL player_scroll(int offx, int offy); + +int player_forward(); +int player_rewind(); + +/// Start get_info from media file using external program. +void player_startinfo(const char *fname, const char *charset); + +void player_setdebug(BOOL ison); +BOOL player_getdebug(); + +#endif // of SP_PLAYER_H diff --git a/src/script-dummyobjs.inc.cpp b/src/script-dummyobjs.inc.cpp new file mode 100644 index 0000000..72d7f51 --- /dev/null +++ b/src/script-dummyobjs.inc.cpp @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +#include + +#include + +// dummy declarations (for utilities etc.): +void on_image_create(int obj_id, MMSL_OBJECT *obj, void *param) { } +void on_image_delete(int obj_id, MMSL_OBJECT *obj, void *param) { } + +void on_text_create(int obj_id, MMSL_OBJECT *obj, void *param) { } +void on_text_delete(int obj_id, MMSL_OBJECT *obj, void *param) { } + +void on_rect_create(int obj_id, MMSL_OBJECT *obj, void *param) { } +void on_rect_delete(int obj_id, MMSL_OBJECT *obj, void *param) { } + +#include + +#include + +// dummy declarations (for utilities etc.): +void on_image_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_image_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_text_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_text_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_rect_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_rect_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + diff --git a/src/script-dummyvars.inc.cpp b/src/script-dummyvars.inc.cpp new file mode 100644 index 0000000..0ee8805 --- /dev/null +++ b/src/script-dummyvars.inc.cpp @@ -0,0 +1,34 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +#include + +#include + +// dummy declarations (for utilities etc.): +void on_kernel_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_kernel_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_screen_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_screen_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_pad_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_pad_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_drive_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_drive_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_explorer_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_explorer_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_player_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_player_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_settings_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_settings_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + +void on_flash_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } +void on_flash_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL) { } + diff --git a/src/script-explorer.cpp b/src/script-explorer.cpp new file mode 100644 index 0000000..9b3e83a --- /dev/null +++ b/src/script-explorer.cpp @@ -0,0 +1,1190 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - file explorer wrapper impl. + * \file script-explorer.cpp + * \author bombur + * \version 0.1 + * \date 12.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +static const StringPair items_sort_pairs[] = +{ + { "none", ITEMS_SORT_NONE }, + { "normal", ITEMS_SORT_NORMAL }, + { "inverse", ITEMS_SORT_INVERSE }, + { "random", ITEMS_SORT_RANDOM }, + { NULL, -1 }, +}; + +static const StringPair item_type_pairs[] = +{ + { "", ITEMS_SORT_NONE }, + { "file", ITEM_TYPE_FILE }, + { "track", ITEM_TYPE_TRACK }, + { "folder", ITEM_TYPE_FOLDER }, + { "up", ITEM_TYPE_UP }, + { "dvd", ITEM_TYPE_DVD }, + { NULL, -1 }, +}; + +// used for items hash +Item *tmpit = NULL; + +static int ItemsListCompareFuncNormal(Item **i1, Item **i2) +{ + return (*i1)->name.CompareNoCase((*i2)->name); +} +static int ItemsListCompareFuncReverse(Item **i1, Item **i2) +{ + return -(*i1)->name.CompareNoCase((*i2)->name); +} + + +//////////////////////////////////////////////////////////////////////// + +void ItemsList::Update() +{ + if (cur >= 0 && cur < items.GetN()) + { + // get extension + int eidx = items[cur]->name.ReverseFind('.'); + if (eidx < 0) + eidx = items[cur]->name.GetLength(); + fname = items[cur]->name.Left(eidx); + if (fname.FindNoCase("/cdrom/") == 0) + fname = fname.Mid(7); + if (fname.FindNoCase("/hdd/") == 0) + fname = fname.Mid(5); + if (fname.FindNoCase("/") == 0) + fname = fname.Mid(1); + ext = items[cur]->name.Mid(eidx); + if (itemhash != NULL) // playlist + path = items[cur]->name; + else + path = folder + items[cur]->name; + type = items[cur]->type; + filetime = items[cur]->datetime; + mask_index = items[cur]->mask_index; + filesize = MAX(items[cur]->size, 0); + + params->lastitem = items[cur]; + + if (params->curtarget != NULL && params->curtarget->itemhash != NULL) + { + tmpit->SetName(path); + copied = (params->curtarget->itemhash->Get(*tmpit) != NULL); + } + } else + { + if (cur < 0) + cur = -1; + if (cur > items.GetN()) + cur = items.GetN(); + fname = ""; + ext = ""; + path = ""; + type = ITEM_TYPE_NONE; + copied = FALSE; + filetime = 0; + filesize = 0; + mask_index = 0; + + params->lastitem = NULL; + } + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_POSITION); + + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_PATH); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FILENAME); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_EXTENSION); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_TYPE); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COPIED); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FILETIME); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_MASKINDEX); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FILESIZE); +} + +bool mask_compare(char *str, const SPString & msk) +{ + // empty mask - not allowed! + if (msk[0] == '\0') + return false; + + // process multiple masks + char *comma = strchr(msk, ','); + int mlen = msk.GetLength(); + if (comma != NULL) + { + // if one of other masks match + if (mask_compare(str, SPString(comma + 1))) + return true; + mlen = comma - *msk; + } + + int end = 0, omaski = 0; + int len = strlen(str); + int ml; + for (int i = 0; i < len && omaski <= mlen; omaski++) + { + const char *m = *msk + omaski; + for (int j = omaski; j < mlen && *m != '*'; j++) + m++; + if (*m == '*') + ml = m - msk - omaski; + else + ml = mlen - omaski + 1; + BOOL fl0 = false; + for (; i <= end; i++) + { + const char *tmp1 = str + i; + const char *tmp2 = *msk + omaski; + BOOL fl = true; + for (int j = 0; (j < ml); j++, tmp1++, tmp2++) + { + if (tolower(*tmp1) != tolower(*tmp2 == ',' ? 0 : *tmp2) && *tmp2 != '?') + { + fl = false; + break; + } + } + if (fl) + { + omaski += ml; + i += ml; + end = len; + fl0 = true; + break; + } + } + if (!fl0) + return false; + } + return true; +} + +static void items_sub_sort(int idx1, int idx2) +{ + if (idx1 == idx2) + return; + if (params->sort == ITEMS_SORT_NORMAL) + { + params->curitem->items.Sort(ItemsListCompareFuncNormal, idx1, idx2); + } + else if (params->sort == ITEMS_SORT_INVERSE) + { + params->curitem->items.Sort(ItemsListCompareFuncReverse, idx1, idx2); + } + else if (params->sort == ITEMS_SORT_RANDOM) + { + int n = idx2 - idx1 + 1; + for (int k = idx1; k <= idx2; k++) + { + int j; + // find random swap pos + do + { + j = (rand() % n) + idx1; + } while (j == k); + + // swap + Item *tmp = params->curitem->items[j]; + params->curitem->items[j] = params->curitem->items[k]; + params->curitem->items[k] = tmp; + } + } +} + +static void items_list_sort() +{ + params->lastitem = NULL; + if (params->curitem != NULL && params->sort != ITEMS_SORT_NONE) + { + int k, idx1 = 0, idx2 = 0, maxidx = 0; + // save current index + bool need_new_idx = params->curitem->cur >= 0 && params->curitem->cur < params->curitem->items.GetN(); + if (need_new_idx) + { + params->curitem->items[params->curitem->cur]->oldidx = params->curitem->cur; + } + + for (k = 0; k < ITEM_TYPE_MAX && params->filter[k] != ITEM_TYPE_NONE; k++) + { + //idx1 = params->curitem->add4types[k]; + idx2 = (k < ITEM_TYPE_MAX && params->filter[k] != ITEM_TYPE_NONE) + ? params->curitem->add4types[k]-1 : params->curitem->items.GetN() - 1; + if (idx2 + 1 > maxidx) + maxidx = idx2 + 1; + if (idx2 < idx1) + continue; + items_sub_sort(idx1, idx2); + idx1 = idx2 + 1; + } + if (maxidx < params->curitem->items.GetN()) + items_sub_sort(maxidx, params->curitem->items.GetN() - 1); + + if (need_new_idx) + { + int cur = params->curitem->cur; + params->curitem->cur = 0; + for (k = 0; k < params->curitem->items.GetN(); k++) + { + if (params->curitem->items[k]->oldidx == cur) + { + params->curitem->items[k]->oldidx = -1; + params->curitem->cur = k; + break; + } + } + params->curitem->Update(); + } + } +} + +void explorer_get_folder_name(SPString &folder) +{ + // skip the 'up' folder + if (folder == ".." || folder.GetLength() < 1) + return; + folder.Replace('\\', '/'); + if (folder.Find("/") != 0) + folder = "/" + folder; + if (folder.ReverseFind('/') != folder.GetLength() - 1) + folder = folder + "/"; +} + +void script_explorer_reset() +{ + if (params != NULL) + { + params->lists.DeleteObjects(); + params->playlists.DeleteObjects(); + params->curtarget = NULL; + params->curitem = NULL; + params->lastitem = NULL; + params->folder = ""; + + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER); + } +} + +void on_explorer_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_EXPLORER_CHARSET: + var->Set(params->iso_lang); + break; + case SCRIPT_VAR_EXPLORER_FOLDER: + { + SPString f = params->folder; + if (f.ReverseFind('/') == f.GetLength() - 1) + f = f.Left(f.GetLength() - 1); + var->Set(f); + } + break; + case SCRIPT_VAR_EXPLORER_DRIVE_LETTER: + { + SPString f; + if (params->folder.FindNoCase("/hdd/") == 0) + { + f = params->folder.Mid(5); + if (f != "") + { + static const char led_drive_table[] = { 'A', 'b', 'C', 'd', 'E', 'F', 'G', 'H', + 'I', 'J', 'k', 'L', 'm', 'N', 'O', 'P', 'q', 'r', 'S', 't', 'U', 'v' }; + char ch = (char)toupper(f[0]); + if (ch > 'A' && ch < sizeof(led_drive_table) + 'A') + ch = led_drive_table[ch - 'A']; + f = SPString(ch, 1); + var->Set(f); + break; + } + } + var->Set(f); + } + break; + case SCRIPT_VAR_EXPLORER_TARGET: + { + SPString f = params->target; + if (f.ReverseFind('/') == f.GetLength() - 1) + f = f.Left(f.GetLength() - 1); + var->Set(f); + } + break; + case SCRIPT_VAR_EXPLORER_FILTER: + { + const char *flt[] = { "", "file", "track", "folder", "up", "dvd" }; + SPString filter; + for (int i = 0; i < ITEM_TYPE_MAX; i++) + { + if (params->filter[i] != ITEM_TYPE_NONE) + { + if (filter != "") + filter += ","; + filter += flt[params->filter[i]]; + } + } + + var->Set(filter); + } + break; + case SCRIPT_VAR_EXPLORER_MASK1: + case SCRIPT_VAR_EXPLORER_MASK2: + case SCRIPT_VAR_EXPLORER_MASK3: + case SCRIPT_VAR_EXPLORER_MASK4: + case SCRIPT_VAR_EXPLORER_MASK5: + var->Set(params->mask[var_id - SCRIPT_VAR_EXPLORER_MASK1]); + break; + case SCRIPT_VAR_EXPLORER_PATH: + var->Set(params->curitem != NULL ? params->curitem->path : SPString()); + break; + case SCRIPT_VAR_EXPLORER_FILENAME: + var->Set(params->curitem != NULL ? params->curitem->fname : SPString()); + break; + case SCRIPT_VAR_EXPLORER_EXTENSION: + var->Set(params->curitem != NULL ? params->curitem->ext : SPString()); + break; + case SCRIPT_VAR_EXPLORER_TYPE: + { + int typ = params->curitem != NULL ? params->curitem->type : -1; + StringPair::Set(var, item_type_pairs, typ); + } + break; + case SCRIPT_VAR_EXPLORER_FILESIZE: + { + if (params->curitem == NULL) + var->Set(0); + else + { + int fsize = (params->curitem->filesize < 0x7fffffff) ? + (int)params->curitem->filesize : -(int)(params->curitem->filesize/1024); + var->Set(fsize); + } + } + break; + case SCRIPT_VAR_EXPLORER_FILETIME: + { + static SPString ft; + ft = ""; + if (params->curitem->filetime != 0) + ft.Strftime("%d.%m.%Y %H:%M", params->curitem->filetime); + var->Set(ft); + } + break; + case SCRIPT_VAR_EXPLORER_MASKINDEX: + var->Set(params->curitem != NULL ? params->curitem->mask_index : 0); + break; + case SCRIPT_VAR_EXPLORER_COUNT: + var->Set(params->curitem != NULL ? params->curitem->items.GetN() : 0); + break; + case SCRIPT_VAR_EXPLORER_SORT: + StringPair::Set(var, items_sort_pairs, params->sort); + break; + case SCRIPT_VAR_EXPLORER_POSITION: + var->Set(params->curitem != NULL ? params->curitem->cur : -1); + break; + case SCRIPT_VAR_EXPLORER_COMMAND: + case SCRIPT_VAR_EXPLORER_FIND: + var->Set(""); + break; + case SCRIPT_VAR_EXPLORER_COPIED: + var->Set(params->curitem != NULL ? params->curitem->copied : 0); + break; + } +} + +void on_explorer_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_EXPLORER_CHARSET: + params->iso_lang = var->GetString(); + params->iso_lang_changed = true; + params->list_changed = true; + break; + case SCRIPT_VAR_EXPLORER_FOLDER: + { + params->folder = var->GetString(); + if (params->folder.FindNoCase("/cdrom/") == 0 || params->folder.FindNoCase("/hdd/") == 0 || + params->folder.FindNoCase("/") == 0) + params->list_changed = true; + explorer_get_folder_name(params->folder); + } + break; + case SCRIPT_VAR_EXPLORER_TARGET: + { + params->target = var->GetString(); + explorer_get_folder_name(params->target); + params->curtarget = NULL; + for (int i = 0; i < params->playlists.GetN(); i++) + { + if (params->target.FindNoCase(params->playlists[i]->folder) == 0) + { + params->curtarget = params->playlists[i]; + break; + } + } + } + break; + case SCRIPT_VAR_EXPLORER_FILTER: + { + SPString filter = var->GetString(); + int i; + for (i = 0; i < ITEM_TYPE_MAX; i++) + { + if (filter.FindNoCase("up") == 0) + params->filter[i] = ITEM_TYPE_UP; + else if (filter.FindNoCase("folder") == 0) + params->filter[i] = ITEM_TYPE_FOLDER; + else if (filter.FindNoCase("file") == 0) + params->filter[i] = ITEM_TYPE_FILE; + else if (filter.FindNoCase("track") == 0) + params->filter[i] = ITEM_TYPE_TRACK; + else if (filter.FindNoCase("dvd") == 0) + params->filter[i] = ITEM_TYPE_DVD; + else + break; + int nxt = filter.Find(','); + if (nxt < 0) + filter = ""; + filter = filter.Mid(nxt + 1); + } + for (; i < ITEM_TYPE_MAX; i++) + params->filter[i] = ITEM_TYPE_NONE; + params->list_changed = true; + } + break; + case SCRIPT_VAR_EXPLORER_MASK1: + case SCRIPT_VAR_EXPLORER_MASK2: + case SCRIPT_VAR_EXPLORER_MASK3: + case SCRIPT_VAR_EXPLORER_MASK4: + case SCRIPT_VAR_EXPLORER_MASK5: + { + SPString m = var->GetString(); + + // for easy mask concatenation + m.TrimLeft(); + m.TrimRight(); + if (m.GetLength() > 0 && m[(int)m.GetLength() - 1] != ',') + m += SPString(","); + params->mask[var_id - SCRIPT_VAR_EXPLORER_MASK1] = m; + + params->allmask = SPString(); + for (int i = 0; i < num_file_masks; i++) + params->allmask += params->mask[i]; + + params->list_changed = true; + } + break; + case SCRIPT_VAR_EXPLORER_SORT: + params->sort = (ITEMS_SORT)StringPair::Get(var, items_sort_pairs, ITEMS_SORT_NONE); + items_list_sort(); + params->list_changed = true; + break; + case SCRIPT_VAR_EXPLORER_POSITION: + if (params->curitem != NULL && params->curitem->items.GetN() > 0) + { + params->curitem->cur = var->GetInteger(); + params->curitem->Update(); + } + break; + case SCRIPT_VAR_EXPLORER_COMMAND: + { + // our generated random indexes aren't valid any more... + if (params->curitem != NULL) + { + if (params->list_changed) + { + SPSafeDeleteArray(params->curitem->random_idx); + SPSafeDeleteArray(params->curitem->random_ridx); + params->curitem->cur_random_pos = -1; + params->list_changed = false; + } + } + + SPString cmd = var->GetString(); + if (cmd.CompareNoCase("update") == 0) + { + int i; + params->curitem = NULL; + + msg("Explorer: Update!\n"); + + if (params->folder == "..") + { + if (params->lists.GetN() > 1) + { + int idx = params->lists.GetN() - 1; + SPSafeDelete(params->lists[idx]); + params->lists.Remove(idx); + + // if we don't need update + if (params->lists[idx - 1]->allmask.CompareNoCase(params->allmask) != 0) + { + params->folder = params->lists[idx - 1]->folder; + } else + { + params->curitem = params->lists[idx - 1]; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + params->curitem->Update(); + params->folder = params->curitem->folder; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER); + break; + } + } else + { + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + params->folder = ""; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER); + break; + } + } + + // translate virtual path + SPString oldfolder = params->folder; + params->folder = cdrom_getrealpath(params->folder); + if (params->folder != oldfolder) + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER); + + if (params->folder.FindNoCase("/cdrom/") == 0 || params->folder.FindNoCase("/hdd/") == 0) + { + int from_which = -1; + for (i = params->lists.GetN() - 1; i >= 0; i--) + { + if (params->folder.FindNoCase(params->lists[i]->folder) == 0) + { + // exactly the same! + if (params->folder.CompareNoCase(params->lists[i]->folder) == 0) + { +#if 0 + params->curitem = params->lists[i]; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + params->curitem->Update(); + params->folder = params->curitem->folder; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_FOLDER); + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_DRIVE_LETTER); + break; +#endif + from_which = i - 1; + } + else + from_which = i; + break; + } + } + // delete sub-lists + for (i = params->lists.GetN() - 1; i > from_which; i--) + { + SPSafeDelete(params->lists[i]); + params->lists.Remove(i); + } + } + + // detect source type + if (params->folder.FindNoCase("/cdrom/") == 0 || params->folder.FindNoCase("/hdd/") == 0 || + params->folder == "/") + { + params->curitem = new ItemsList(); + + // read items + explorer_get_folder_name(params->folder); + params->curitem->folder = params->folder; + params->curitem->allmask = params->allmask; + for (i = 0; i < num_file_masks; i++) + params->curitem->mask[i] = params->mask[i]; + + srand((unsigned int)time(NULL)); + + // first, add audio tracks (for root folder only!) + char tmp[10]; + if (params->folder.CompareNoCase("/cdrom/") == 0) + { + Cdda *cdda = cdda_open(); + if (cdda != NULL) + { + for (i = 0; i < cdda->tracks.GetN(); i++) + { + Item *it = new Item(); + it->parent = params->curitem; + sprintf(tmp, "%02d.cda", i + 1); + // we don't need hash for '/cdrom' lists + if (params->curitem->itemhash == NULL) + { + it->name = tmp; + it->namehash = 0; + } else + it->SetName(tmp); + it->datetime = 0; + it->mask_index = 0; + it->size = 0; + it->type = ITEM_TYPE_TRACK; + bool was = false, filterset = false; + for (int ins = 0; ins < ITEM_TYPE_MAX; ins++) + { + if (params->filter[ins] != ITEM_TYPE_NONE) + filterset = true; + if (params->filter[ins] == ITEM_TYPE_TRACK) + { + params->curitem->items.Insert(it, params->curitem->add4types[ins]); + was = true; + } + if (was) + params->curitem->add4types[ins]++; + } + if (!filterset) + params->curitem->items.Add(it); + else if (!was) + delete it; + } + } + } + + //if (has_data) + { + if (!cdrom_ismounted() || params->iso_lang_changed) + { + cdrom_mount(params->iso_lang, FALSE); + params->iso_lang_changed = false; + } + + // determine DVD folder + bool is_dvd = false; + int p = params->folder.FindNoCase("VIDEO_TS/"); + if (p >= 0 && p == params->folder.GetLength() - 9) + { + is_dvd = true; + } + + bool root_folder = (params->folder == "/"); + + DIR *dir = cdrom_opendir(params->folder); + static char path[4097]; + strcpy(path, params->folder); + int path_add = strlen(path); + if (path_add < 4000) + while (dir != NULL) + { + struct dirent *d = cdrom_readdir(dir); + if (d == NULL) + break; + if (d->d_name[0] == '.' && d->d_name[1] == '\0') + continue; + struct stat64 statbuf; + + strcpy(path + path_add, d->d_name); + int mask_index = 0; + if (cdrom_stat(path, &statbuf) < 0) + { + msg("Cannot stat %s\n", path); + statbuf.st_mode = 0; + } + ITEM_TYPE ittype; + if (!root_folder && d->d_name[0] == '.' && d->d_name[1] == '.' && d->d_name[2] == '\0') + { + if (params->lists.GetN() == 0) + continue; + ittype = ITEM_TYPE_UP; + } + else if (S_ISDIR(statbuf.st_mode)) + { + if (d->d_name[0] == '.') // hidden + continue; + + // don't show other root folders except mounted ones. + if (root_folder) + { + if (strcasecmp(d->d_name, "cdrom") != 0 && + strcasecmp(d->d_name, "hdd") != 0) + continue; + } + ittype = ITEM_TYPE_FOLDER; + } + else + { + if (is_dvd && (strcasecmp(d->d_name, "VIDEO_TS.IFO") == 0 || + strcasecmp(d->d_name, "VIDEO_TS.BUP") == 0)) + { + ittype = ITEM_TYPE_DVD; + is_dvd = false; + } else + { + ittype = ITEM_TYPE_FILE; + BOOL found = FALSE; + for (int mi = 0; mi < num_file_masks; mi++) + { + if (mask_compare(d->d_name, params->mask[mi])) + { + found = TRUE; + mask_index = mi + 1; + break; + } + } + if (!found) + continue; + } + } + Item *it = new Item(); + it->parent = params->curitem; + // we don't need hash for '/cdrom' lists + if (params->curitem->itemhash == NULL) + { + it->name = d->d_name; + it->namehash = 0; + } else + it->SetName(d->d_name); + it->datetime = statbuf.st_mtime; + it->size = ittype == ITEM_TYPE_FILE ? statbuf.st_size : 0; + it->type = ittype; + it->mask_index = mask_index; + bool was = false, filterset = false; + for (int ins = 0; ins < ITEM_TYPE_MAX; ins++) + { + if (params->filter[ins] != ITEM_TYPE_NONE) + filterset = true; + if (params->filter[ins] == ittype) + { + params->curitem->items.Insert(it, params->curitem->add4types[ins]); + was = true; + } + if (was) + { + params->curitem->add4types[ins]++; + } + } + if (!filterset) + params->curitem->items.Add(it); + else if (!was) + delete it; + + // script_update(); + } + cdrom_closedir(dir); + } + + if (params->sort != ITEMS_SORT_NONE) + items_list_sort(); + + params->lists.Add(params->curitem); + } + else if (params->folder.FindNoCase("/dvd/") == 0) + { + } + else // other playlists + { + for (i = 0; i < params->playlists.GetN(); i++) + { + if (params->folder.FindNoCase(params->playlists[i]->folder) == 0) + { + params->curitem = params->playlists[i]; + // If we need to apply a new mask to playlist, + // we use actual list in itemhash to create filtered items list. + if (params->curitem->allmask.CompareNoCase(params->allmask) != 0 + && params->curitem->itemhash != NULL) + { + params->curitem->items.Clear(); + Item *cur = params->curitem->itemhash->GetFirst(); + while (cur != NULL) + { + if (mask_compare(cur->name, params->allmask)) + params->curitem->items.Add(cur); + cur = params->curitem->itemhash->GetNext(*cur); + } + params->curitem->allmask = params->allmask; + for (int mi = 0; mi < num_file_masks; mi++) + params->curitem->mask[mi] = params->mask[mi]; + // we must apply sorting because hash list is unordered. + ITEMS_SORT oldsort = params->sort; + if (params->sort == ITEMS_SORT_NONE) + params->sort = ITEMS_SORT_NORMAL; + items_list_sort(); + params->sort = oldsort; + } + break; + } + } + } + + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + + if (params->curitem != NULL) + { + Item *lastit = params->lastitem; + params->curitem->cur = 0; + params->curitem->Update(); + if (lastit != NULL) + params->lastitem = lastit; + } + } + else if (cmd.CompareNoCase("first") == 0) + { + if (params->curitem != NULL && params->curitem->items.GetN() > 0) + { + params->curitem->cur = 0; + params->curitem->Update(); + } + } + else if (cmd.CompareNoCase("last") == 0) + { + if (params->curitem != NULL && params->curitem->items.GetN() > 0) + { + params->curitem->cur = params->curitem->items.GetN() - 1; + params->curitem->Update(); + } + } + else if (cmd.CompareNoCase("next") == 0) + { + if (params->curitem != NULL && params->curitem->items.GetN() > 0 && params->curitem->cur < params->curitem->items.GetN()) + { + params->curitem->cur++; + params->curitem->Update(); + } + } + else if (cmd.CompareNoCase("prev") == 0) + { + if (params->curitem != NULL && params->curitem->items.GetN() > 0 && params->curitem->cur >= 0) + { + params->curitem->cur--; + params->curitem->Update(); + } + } + else if (cmd.CompareNoCase("randomize") == 0) + { + if (params->curitem != NULL && params->curitem->items.GetN() > 0) + { + int k, n = params->curitem->items.GetN(); + SPSafeDeleteArray(params->curitem->random_idx); + SPSafeDeleteArray(params->curitem->random_ridx); + params->curitem->random_idx = new int [n]; + params->curitem->random_ridx = new int [n]; + for (k = 0; k < n; k++) + params->curitem->random_idx[k] = k; + if (n > 1) + for (k = 0; k < n; k++) + { + int j; // find random swap pos + do + { + j = (rand() % n); + } while (j == k); + // swap + int tmp = params->curitem->random_idx[j]; + params->curitem->random_idx[j] = params->curitem->random_idx[k]; + params->curitem->random_idx[k] = tmp; + } + for (k = 0; k < n; k++) + params->curitem->random_ridx[params->curitem->random_idx[k]] = k; + params->curitem->cur_random_pos = 0; + params->curitem->cur = params->curitem->random_idx[params->curitem->cur_random_pos]; + params->curitem->Update(); + } + } + else if (cmd.CompareNoCase("nextrandom") == 0 || cmd.CompareNoCase("prevrandom") == 0) + { + if (params->curitem != NULL && params->curitem->items.GetN() > 0) + { + if (params->curitem->random_idx != NULL && params->curitem->random_ridx != NULL) + { + if (params->curitem->cur >= 0 && params->curitem->cur < params->curitem->items.GetN()) + params->curitem->cur_random_pos = params->curitem->random_ridx[params->curitem->cur]; + + if (cmd.CompareNoCase("nextrandom") == 0) + params->curitem->cur_random_pos++; + else + params->curitem->cur_random_pos--; + + if (params->curitem->cur_random_pos < 0 || params->curitem->cur_random_pos >= params->curitem->items.GetN()) + { + params->curitem->cur = -1; + params->curitem->cur_random_pos = -1; + } else + { + params->curitem->cur = params->curitem->random_idx[params->curitem->cur_random_pos]; + } + params->curitem->Update(); + } + } + + } + else if (cmd.CompareNoCase("remove") == 0) + { + if (params->curitem != NULL && params->curitem->items.GetN() > 0 && + params->curitem->cur >= 0 && params->curitem->cur < params->curitem->items.GetN()) + { + if (params->curitem->itemhash != NULL) + params->curitem->itemhash->Remove(*params->curitem->items[params->curitem->cur]); + SPSafeDelete(params->curitem->items[params->curitem->cur]); + params->curitem->items.Remove(params->curitem->cur); + if (params->curitem->cur == params->curitem->items.GetN() - 1) + params->curitem->cur--; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + params->curitem->Update(); + } + } + else if (cmd.CompareNoCase("removeall") == 0) + { + if (params->curitem != NULL) + { + if (params->curitem->itemhash != NULL) + params->curitem->itemhash->Clear(); + params->curitem->items.DeleteObjects(); + params->curitem->cur = -1; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + params->curitem->Update(); + } + } + else if (cmd.CompareNoCase("copy") == 0 || cmd.CompareNoCase("copyall") == 0) + { + // first, find existing play-list + explorer_get_folder_name(params->target); + + int i; + ItemsList *pl = NULL; + for (i = params->playlists.GetN() - 1; i >= 0; i--) + { + // exactly the same! + if (params->target.CompareNoCase(params->playlists[i]->folder) == 0) + { + pl = params->playlists[i]; + break; + } + } + if (pl == NULL) // create a new play-list + { + pl = new ItemsList(); + if (pl == NULL) + break; + pl->allmask = params->allmask; + for (int mi = 0; mi < num_file_masks; mi++) + pl->mask[mi] = params->mask[mi]; + pl->folder = params->target; + + pl->itemhash = new SPHashListAbstract(items_num_hash); + + params->playlists.Add(pl); + } + params->curtarget = pl; + if (params->curitem == NULL || pl == params->curitem) + { + msg_error("Cannot copy items from current source.\n"); + break; + } + bool copyall = cmd.CompareNoCase("copyall") == 0; + + if (!copyall) + { + if (params->curitem->cur < 0 || params->curitem->cur >= params->curitem->items.GetN()) + { + msg_error("Cannot copy current item.\n"); + break; + } + i = params->curitem->cur; + } else + i = 0; + for (; i < params->curitem->items.GetN(); i++) + { + Item *srcit = params->curitem->items[i]; + if (srcit != NULL && (srcit->type == ITEM_TYPE_FILE || srcit->type == ITEM_TYPE_TRACK)) + { + // check if item already exists + Item *item = NULL; + static SPString nam; + nam = params->folder + srcit->name; + if (pl->itemhash != NULL) + { + tmpit->SetName(nam); + item = pl->itemhash->Get(*tmpit); + } + // not in the playlist yet. + if (item == NULL) + { + item = new Item(); + item->SetName(nam); + item->type = srcit->type; + item->datetime = srcit->datetime; + item->mask_index = srcit->mask_index; + item->size = srcit->size; + item->parent = srcit->parent; // inherit parent + pl->itemhash->Add(item); + + srcit->playlist = pl; + srcit->playlist_idx = pl->items.Add(item); + if (i == params->curitem->cur) + params->curitem->Update(); + } + } + if (!copyall) + break; + } + } + else if (cmd.CompareNoCase("targetremove") == 0 || cmd.CompareNoCase("targetremoveall") == 0) + { + // first, find existing play-list + explorer_get_folder_name(params->target); + + ItemsList *pl = NULL; + for (int i = params->playlists.GetN() - 1; i >= 0; i--) + { + // exactly the same! + if (params->target.CompareNoCase(params->playlists[i]->folder) == 0) + { + pl = params->playlists[i]; + break; + } + } + if (pl == NULL) // create a new play-list + { + msg_error("Cannot find target playlist.\n"); + break; + } + params->curtarget = pl; + if (params->curitem == NULL) + { + msg_error("Cannot use items from current source for removing.\n"); + break; + } + + bool removed = false; + if (cmd.CompareNoCase("targetremoveall") == 0) + { + pl->itemhash->Clear(); + pl->items.DeleteObjects(); + removed = true; + } else + { + + if (params->curitem->cur < 0 || params->curitem->cur >= params->curitem->items.GetN()) + { + msg_error("Cannot remove current item from target playlist.\n"); + break; + } + Item *srcit = params->curitem->items[params->curitem->cur]; + if (srcit != NULL) + { + // check if item already exists + Item *item = NULL; + SPString nam = params->folder + srcit->name; + if (pl->itemhash != NULL) + { + tmpit->SetName(nam); + item = pl->itemhash->Get(*tmpit); + } + // not in the playlist yet. + if (item == NULL) + { + msg_error("Cannot find current item in the target playlist.\n"); + break; + } + pl->itemhash->Remove(*item); + // find item in the linear list + for (int i = 0; i < pl->items.GetN(); i++) + { + if (pl->items[i] == item) + { + SPSafeDelete(pl->items[i]); + pl->items.Remove(i); + removed = true; + break; + } + } + } + } + + if (removed) + { + if (params->curitem == pl) + { + if (params->curitem->cur == params->curitem->items.GetN() - 1) + params->curitem->cur--; + mmsl->UpdateVariable(SCRIPT_VAR_EXPLORER_COUNT); + } + params->curitem->Update(); + } + } + } + break; + case SCRIPT_VAR_EXPLORER_FIND: + { + SPString fpath = var->GetString(); + if (params->curitem != NULL && params->curitem->items.GetN() > 0) + { + // first, a little optimization for current items in playlist + if (params->lastitem != NULL && params->lastitem->parent != NULL + && fpath.CompareNoCase(params->lastitem->parent->folder + params->lastitem->name) == 0 + && params->lastitem->playlist == params->curitem + && params->lastitem->playlist_idx >= 0 + && params->lastitem->playlist_idx < params->curitem->items.GetN()) + { + params->curitem->cur = params->lastitem->playlist_idx; + } + else + { + params->curitem->cur = -1; + for (int i = 0; i < params->curitem->items.GetN(); i++) + { + Item *ci = params->curitem->items[i]; + if (fpath.CompareNoCase(params->curitem->folder + ci->name) == 0) + { + params->curitem->cur = i; + break; + } + } + } + params->curitem->Update(); + } + } + break; + } + +} + diff --git a/src/script-internal.h b/src/script-internal.h new file mode 100644 index 0000000..3450658 --- /dev/null +++ b/src/script-internal.h @@ -0,0 +1,510 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - script wrapper header file + * \file script-internal.h + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_SCRIPT_INTERNAL_H +#define SP_SCRIPT_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "script-vars.h" +#include "script-objs.h" + +enum SCRIPT_ERRORS +{ + SCRIPT_ERRORS_ALL = 0, + SCRIPT_ERRORS_GENERAL, + SCRIPT_ERRORS_CRITICAL, + SCRIPT_ERRORS_NONE, +}; + +enum PLAYER_REPEAT +{ + PLAYER_REPEAT_NONE = 0, + PLAYER_REPEAT_SELECTION, + PLAYER_REPEAT_TRACK, + PLAYER_REPEAT_ALL, + PLAYER_REPEAT_RANDOM, +}; + +enum ITEMS_SORT +{ + ITEMS_SORT_NONE = 0, + ITEMS_SORT_NORMAL, + ITEMS_SORT_INVERSE, + ITEMS_SORT_RANDOM, +}; + +enum ITEM_TYPE +{ + ITEM_TYPE_NONE = 0, + ITEM_TYPE_FILE, + ITEM_TYPE_TRACK, + ITEM_TYPE_FOLDER, + ITEM_TYPE_UP, + ITEM_TYPE_DVD, + + ITEM_TYPE_MAX, +}; + +enum PLAYER_TYPE +{ + PLAYER_TYPE_UNKNOWN = 0, + PLAYER_TYPE_DVD, + PLAYER_TYPE_AUDIOCD, + PLAYER_TYPE_VIDEO, + PLAYER_TYPE_AUDIO, + PLAYER_TYPE_FILE, + PLAYER_TYPE_FOLDER, +}; + +enum PLAYER_COLOR_SPACE +{ + PLAYER_COLOR_SPACE_UNKNOWN = 0, + PLAYER_COLOR_SPACE_GRAYSCALE = 1, + PLAYER_COLOR_SPACE_YCRCB = 3, +}; + +const int num_file_masks = 5; + +/////////////////////////////////////////// + +class StringPair +{ +public: + const char *str; + int value; + + static int Get(MmslVariable *var, const StringPair *arr, int def) + { + SPString str = var->GetString(); + for (int i = 0; arr[i].str != NULL; i++) + { + if (str.CompareNoCase(arr[i].str) == 0) + return arr[i].value; + } + return def; + } + + static bool Set(MmslVariable *var, const StringPair *arr, int value) + { + for (int i = 0; arr[i].str != NULL; i++) + { + if (arr[i].value == value) + { + var->Set(arr[i].str); + return true; + } + } + return false; + } +}; + +const int items_num_hash = 117; + +class ItemsList; + +/// List item +class Item +{ +public: + /// ctor + Item() + { + type = ITEM_TYPE_NONE; + mask_index = 0; + oldidx = -1; + parent = NULL; + + playlist = NULL; + playlist_idx = -1; + + datetime = 0; + size = 0; + + prev = NULL; + next = NULL; + + namehash = 0; + } + +public: + /// filename (file.ext) or item name + SPString name; + /// item type + ITEM_TYPE type; + /// mask index + int mask_index; + + time_t datetime; + LONGLONG size; + + // used to search new index after sorting + int oldidx; + + // parent list index (primary only, not for play-lists) + ItemsList *parent; + + /// last playlist the item was added to (if multiple) + ItemsList *playlist; + int playlist_idx; + +public: + // hash-related stuff... + Item *prev, *next; + DWORD namehash; + + /// compare + template + bool operator == (const T & r) + { + if (name == NULL || r.name == NULL) + return false; + return name.CompareNoCase(r.name) == 0; + } + + inline operator DWORD () const + { + return namehash; + } + + const Item * const GetItem() const + { + return this; + } + + /// Set variable name & calc. hash + void SetName(const SPString & n) + { + name = n; + namehash = SPStringHashFunc(name, items_num_hash); + } + +}; + +class ItemsList +{ +public: + /// ctor + ItemsList() + { + cur = -1; + copied = FALSE; + filesize = 0; + filetime = 0; + mask_index = 0; + + for (int i = 0; i < ITEM_TYPE_MAX; i++) + add4types[i] = 0; + + itemhash = NULL; + + random_idx = NULL; + random_ridx = NULL; + cur_random_pos = -1; + } + + /// dtor + ~ItemsList() + { + // don't delete itemhash items! + if (itemhash != NULL) + { + itemhash->DeleteObjects(); + delete itemhash; + items.Clear(); + } + else + items.DeleteObjects(); + SPSafeDeleteArray(random_idx); + SPSafeDeleteArray(random_ridx); + } + + void Update(); + +public: + SPList items; + // "/folder1/folder2/" + SPString folder; + SPString allmask, mask[num_file_masks]; + int cur; + + // some cached current data: + SPString path, fname, ext; + ITEM_TYPE type; + BOOL copied; + LONGLONG filesize; + time_t filetime; + int mask_index; + + int add4types[ITEM_TYPE_MAX]; + + SPHashListAbstract *itemhash; + + // random indexes + int *random_idx; + // reversed random indexes + int *random_ridx; + // random index + int cur_random_pos; +}; + +class ItemInfo +{ +public: + /// ctor + ItemInfo() + { + cur_time = 0; + length = 0; + + cur_title = cur_chapter = 0; + real_cur_title = real_cur_chapter = 0; + real_cur_time = 0; + cur_changed = false; + cur_time_changed = false; + num_titles = num_chapters = 0; + width = height = 0; + frame_rate = 0; + clrs = PLAYER_COLOR_SPACE_UNKNOWN; + + dvd_menu_lang = "en"; + dvd_audio_lang = "en"; + spu_lang = "en"; + + audio_stream = spu_stream = 0; + + subtitle_charset = SUBTITLE_CHARSET_DEFAULT; + subtitle_wrap = 35; + } + +public: + SPString name; + SPString artist; + SPString audio_info; + SPString video_info; + + SPString subtitle; + SUBTITLE_CHARSET subtitle_charset; + int subtitle_wrap; + + int cur_time; + int length; + + int cur_title, cur_chapter; + int real_cur_title, real_cur_chapter, real_cur_time; + bool cur_changed, cur_time_changed; + int num_titles, num_chapters; + + int width, height; + int frame_rate; + // color space + PLAYER_COLOR_SPACE clrs; + + SPString dvd_menu_lang; + SPString dvd_audio_lang; + SPString spu_lang; // for dvd and video subtitles + int audio_stream; + int spu_stream; // for dvd and video subtitles +}; + +/// Current script parameters +class ScriptParams +{ +public: + /// ctor + ScriptParams() + { + errors = SCRIPT_ERRORS_ALL; + status = CDROM_STATUS_UNKNOWN; + require_next_status = CDROM_STATUS_UNKNOWN; + saved_iso_status = CDROM_STATUS_UNKNOWN; + key = 0; + + dvdplaying = FALSE; + cddaplaying = FALSE; + fileplaying = FALSE; + videoplaying = FALSE; + audioplaying = FALSE; + waitinfo = FALSE; + wasejected = FALSE; + + need_to_toggle_tray = FALSE; + + // screen: + pal_idx = 0; + hscale = 100; vscale = 100; rotate = 0; + hscroll = 0; vscroll = 0; + backleft = backtop = 0; backright = 719; backbottom = 479; + bigbackleft = bigbacktop = 0; bigbackright = 719; bigbackbottom = 479; + bigback_width = 0; bigback_height = 0; + need_setwindow = false; + + // explorer: + curitem = NULL; + curtarget = NULL; + lastitem = NULL; + iso_lang = "iso8859-1"; + iso_lang_changed = true; + filter[0] = ITEM_TYPE_UP; + filter[1] = ITEM_TYPE_FOLDER; + filter[2] = ITEM_TYPE_TRACK; + filter[3] = ITEM_TYPE_DVD; + filter[4] = ITEM_TYPE_FILE; + filter[5] = ITEM_TYPE_NONE; + sort = ITEMS_SORT_NONE; + mask[0] = "*.*"; + for (int i = 1; i < num_file_masks; i++) + mask[i] = ""; + allmask = mask[0]; + list_changed = false; + + // player: + player_type = PLAYER_TYPE_UNKNOWN; + player_do_command = false; + player_debug = false; + player_repeat = PLAYER_REPEAT_NONE; + speed = MPEG_SPEED_STOP; + + // flash: + flash_address = -1; + flash_progress = -1; + flash_p = -1; + + // timer support + curtime = old_curtime = start_sec = 0; + } + + /// dtor + ~ScriptParams() + { + lists.DeleteObjects(); + playlists.DeleteObjects(); + timed_objs.Delete(); + } + +public: + SCRIPT_ERRORS errors; + + SPString back, bigback; + SPString pal; + SPString font; + int pal_idx; + + SPString fw_ver, mmsl_ver; + + CDROM_STATUS status; + CDROM_STATUS require_next_status; + CDROM_STATUS saved_iso_status; + BOOL need_to_toggle_tray; + + int key; + SPString keystr; + + int hscale, vscale, hscroll, vscroll, rotate; + int backleft, backtop, backright, backbottom; + int bigbackleft, bigbacktop, bigbackright, bigbackbottom; + int bigback_width, bigback_height; + bool need_setwindow; + + BOOL dvdplaying, fileplaying, videoplaying, audioplaying, cddaplaying, waitinfo; + bool wasejected; + + // explorer + + SPString iso_lang; + bool iso_lang_changed; + + SPString folder, allmask, mask[num_file_masks]; + SPString target; + ITEM_TYPE filter[ITEM_TYPE_MAX]; + ITEMS_SORT sort; + + SPList lists; + SPList playlists; + ItemsList *curitem; + ItemsList *curtarget; + Item *lastitem; + bool list_changed; + + // player + + SPString player_command; + bool player_do_command; + + PLAYER_TYPE player_type; + SPString player_source, player_folder; + PLAYER_REPEAT player_repeat; + ItemInfo info; + SPString player_error; + bool player_debug; + // used for external players + MPEG_SPEED_TYPE speed; + + // flash: + SPString flash_file; + int flash_address; + int flash_progress, flash_p; + + /// timer support + SPDLinkedListAbstract timed_objs; + int curtime, old_curtime, start_sec; +}; + +extern ScriptParams *params; +extern Item *tmpit; + +void script_explorer_reset(); + +extern bool player_dvd_command(const SPString & command); +extern bool player_file_command(const SPString & command); +extern bool player_video_command(const SPString & command); +extern bool player_audio_command(const SPString & command); +extern bool player_cdda_command(const SPString & command); + +extern void player_do_command(); + +#endif // of SP_SCRIPT_INTERNAL_H diff --git a/src/script-objects.cpp b/src/script-objects.cpp new file mode 100644 index 0000000..3d0629e --- /dev/null +++ b/src/script-objects.cpp @@ -0,0 +1,534 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - script objects wrapper impl. + * \file script-objects.cpp + * \author bombur + * \version 0.1 + * \date 12.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include + +void on_image_create(int obj_id, MMSL_OBJECT *obj, void *) +{ + if (obj_id == SCRIPT_OBJECT_IMAGE) + { + Image *img = new Image(); + img->timerobj = NULL; + gui.AddWindow(img); + *obj = (MMSL_OBJECT)img; + } +} + +void on_image_delete(int obj_id, MMSL_OBJECT *obj, void *) +{ + if (obj_id == SCRIPT_OBJECT_IMAGE) + { + Image *img = (Image *)*obj; + if (img->timerobj != NULL) + { + img->timerobj->obj = NULL; + params->timed_objs.Delete(img->timerobj); + img->timerobj = NULL; + } + if (img->updateobj != NULL) + { + img->updateobj->obj = NULL; + params->timed_objs.Delete(img->updateobj); + img->updateobj = NULL; + } + gui.RemoveWindow(img); + *obj = NULL; + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_text_create(int obj_id, MMSL_OBJECT *obj, void *) +{ + if (obj_id == SCRIPT_OBJECT_TEXT) + { + Text *txt = new Text(); + txt->SetFont(params->font); + gui.AddWindow(txt); + *obj = (MMSL_OBJECT)txt; + } +} + +void on_text_delete(int obj_id, MMSL_OBJECT *obj, void *) +{ + if (obj_id == SCRIPT_OBJECT_TEXT) + { + Text *txt = (Text *)*obj; + if (txt->timerobj != NULL) + { + txt->timerobj->obj = NULL; + if (params != NULL) + params->timed_objs.Delete(txt->timerobj); + txt->timerobj = NULL; + } + gui.RemoveWindow(txt); + *obj = NULL; + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_rect_create(int obj_id, MMSL_OBJECT *obj, void *) +{ + if (obj_id == SCRIPT_OBJECT_RECT) + { + Rectangle *rect = new Rectangle(); + gui.AddWindow(rect); + *obj = (MMSL_OBJECT)rect; + } +} + +void on_rect_delete(int obj_id, MMSL_OBJECT *obj, void *) +{ + if (obj_id == SCRIPT_OBJECT_RECT) + { + Rectangle *rect = (Rectangle *)*obj; + if (rect->timerobj != NULL) + { + rect->timerobj->obj = NULL; + params->timed_objs.Delete(rect->timerobj); + rect->timerobj = NULL; + } + gui.RemoveWindow(rect); + *obj = NULL; + } +} + +//////////////////////////////////////////////////////////////////////// +/// common vars for all dynamic objects +void on_common_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *obj) +{ + if (obj == NULL) + return; + Window *win = (Window *)*obj; + if (win == NULL || var == NULL) + return; + switch (var_id) + { + case SCRIPT_OBJECT_VAR_IMAGE_TYPE: + var->Set("image"); + break; + case SCRIPT_OBJECT_VAR_TEXT_TYPE: + var->Set("text"); + break; + case SCRIPT_OBJECT_VAR_RECT_TYPE: + var->Set("rect"); + break; + case SCRIPT_OBJECT_VAR_IMAGE_GROUP: + case SCRIPT_OBJECT_VAR_TEXT_GROUP: + case SCRIPT_OBJECT_VAR_RECT_GROUP: + var->Set(win->group != NULL ? *win->group : SPString()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_X: + case SCRIPT_OBJECT_VAR_TEXT_X: + case SCRIPT_OBJECT_VAR_RECT_X: + var->Set(win->GetX()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_Y: + case SCRIPT_OBJECT_VAR_TEXT_Y: + case SCRIPT_OBJECT_VAR_RECT_Y: + var->Set(win->GetY()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_VISIBLE: + case SCRIPT_OBJECT_VAR_TEXT_VISIBLE: + case SCRIPT_OBJECT_VAR_RECT_VISIBLE: + var->Set(win->visible); + break; + case SCRIPT_OBJECT_VAR_IMAGE_WIDTH: + case SCRIPT_OBJECT_VAR_TEXT_WIDTH: + case SCRIPT_OBJECT_VAR_RECT_WIDTH: + var->Set(win->GetWidth()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_HEIGHT: + case SCRIPT_OBJECT_VAR_TEXT_HEIGHT: + case SCRIPT_OBJECT_VAR_RECT_HEIGHT: + var->Set(win->GetHeight()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_HALIGN: + case SCRIPT_OBJECT_VAR_TEXT_HALIGN: + case SCRIPT_OBJECT_VAR_RECT_HALIGN: + { + const char *ha[] = { "left", "center", "right" }; + var->Set(ha[win->halign]); + } + break; + case SCRIPT_OBJECT_VAR_IMAGE_VALIGN: + case SCRIPT_OBJECT_VAR_TEXT_VALIGN: + case SCRIPT_OBJECT_VAR_RECT_VALIGN: + { + const char *va[] = { "top", "center", "bottom" }; + var->Set(va[win->valign]); + } + break; + case SCRIPT_OBJECT_VAR_IMAGE_TIMER: + case SCRIPT_OBJECT_VAR_TEXT_TIMER: + case SCRIPT_OBJECT_VAR_RECT_TIMER: + var->Set(win->timer > 0 ? win->timer - params->curtime : win->timer); + break; + } +} + +void on_common_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *obj) +{ + if (obj == NULL) + return; + Window *win = (Window *)*obj; + if (win == NULL || var == NULL) + return; + switch (var_id) + { + case SCRIPT_OBJECT_VAR_IMAGE_GROUP: + case SCRIPT_OBJECT_VAR_TEXT_GROUP: + case SCRIPT_OBJECT_VAR_RECT_GROUP: + SPSafeDelete(win->group); + win->group = new SPString(var->GetString()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_X: + case SCRIPT_OBJECT_VAR_TEXT_X: + case SCRIPT_OBJECT_VAR_RECT_X: + win->SetX(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_Y: + case SCRIPT_OBJECT_VAR_TEXT_Y: + case SCRIPT_OBJECT_VAR_RECT_Y: + win->SetY(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_VISIBLE: + case SCRIPT_OBJECT_VAR_TEXT_VISIBLE: + case SCRIPT_OBJECT_VAR_RECT_VISIBLE: + win->SetVisible(var->GetInteger() != 0); + break; + case SCRIPT_OBJECT_VAR_IMAGE_WIDTH: + case SCRIPT_OBJECT_VAR_TEXT_WIDTH: + case SCRIPT_OBJECT_VAR_RECT_WIDTH: + win->SetWidth(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_HEIGHT: + case SCRIPT_OBJECT_VAR_TEXT_HEIGHT: + case SCRIPT_OBJECT_VAR_RECT_HEIGHT: + win->SetHeight(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_IMAGE_HALIGN: + case SCRIPT_OBJECT_VAR_TEXT_HALIGN: + case SCRIPT_OBJECT_VAR_RECT_HALIGN: + { + SPString str = var->GetString(); + if (str.CompareNoCase("center") == 0) + win->SetHAlign(WINDOW_ALIGN_CENTER); + else if (str.CompareNoCase("right") == 0) + win->SetHAlign(WINDOW_ALIGN_RIGHT); + else + win->SetHAlign(WINDOW_ALIGN_LEFT); + } + break; + case SCRIPT_OBJECT_VAR_IMAGE_VALIGN: + case SCRIPT_OBJECT_VAR_TEXT_VALIGN: + case SCRIPT_OBJECT_VAR_RECT_VALIGN: + { + SPString str = var->GetString(); + if (str.CompareNoCase("center") == 0) + win->SetVAlign(WINDOW_ALIGN_CENTER); + else if (str.CompareNoCase("bottom") == 0) + win->SetVAlign(WINDOW_ALIGN_BOTTOM); + else + win->SetVAlign(WINDOW_ALIGN_TOP); + } + break; + case SCRIPT_OBJECT_VAR_IMAGE_TIMER: + case SCRIPT_OBJECT_VAR_TEXT_TIMER: + case SCRIPT_OBJECT_VAR_RECT_TIMER: + { + int delta = var->GetInteger(); + if (delta > 0) + { + ScriptTimerObject *to = new ScriptTimerObject(); + to->type = SCRIPT_OBJECT_TIMER; + to->obj = win; + to->var_ID = var_id; + win->timer = params->curtime + delta; + if (win->timerobj != NULL) + params->timed_objs.Delete(win->timerobj); + win->timerobj = to; + params->timed_objs.Add(to); + } else + win->timer = delta; + } + break; + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_image_get(int var_id, MmslVariable *var, void *param, int obj_id, MMSL_OBJECT *obj) +{ + if (var == NULL || obj_id != SCRIPT_OBJECT_IMAGE || obj == NULL) + return; + + Image *img = (Image *)*obj; + if (img == NULL) + return; + + on_common_get(var_id, var, param, obj_id, obj); + + switch (var_id) + { + case SCRIPT_OBJECT_VAR_IMAGE_SRC: + var->Set(img->img != NULL ? img->img->name : 0); + break; + case SCRIPT_OBJECT_VAR_IMAGE_HFLIP: + var->Set(img->flipx); + break; + case SCRIPT_OBJECT_VAR_IMAGE_VFLIP: + var->Set(img->flipy); + break; + } +} + +void on_image_set(int var_id, MmslVariable *var, void *param, int obj_id, MMSL_OBJECT *obj) +{ + if (var == NULL || obj_id != SCRIPT_OBJECT_IMAGE || obj == NULL) + return; + + Image *img = (Image *)*obj; + if (img == NULL) + return; + + on_common_set(var_id, var, param, obj_id, obj); + + switch (var_id) + { + case SCRIPT_OBJECT_VAR_IMAGE_SRC: + { + img->SetSource(var->GetString()); + // add to update queue + ScriptTimerObject *to = img->updateobj; + if (img->img != NULL && img->img->num_frames > 1) + { + if (to == NULL) + { + to = new ScriptTimerObject(); + to->obj = img; + to->var_ID = var_id; + to->type = SCRIPT_OBJECT_UPDATE; + img->updateobj = to; + params->timed_objs.Add(to); + } + } + else if (to != NULL) + { + params->timed_objs.Delete(to); + img->updateobj = NULL; + } + mmsl->UpdateObjectVariable(img, SCRIPT_OBJECT_VAR_IMAGE_WIDTH); + mmsl->UpdateObjectVariable(img, SCRIPT_OBJECT_VAR_IMAGE_HEIGHT); + } + break; + case SCRIPT_OBJECT_VAR_IMAGE_HFLIP: + img->SetFlipX(var->GetInteger() != 0); + break; + case SCRIPT_OBJECT_VAR_IMAGE_VFLIP: + img->SetFlipY(var->GetInteger() != 0); + break; + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_text_get(int var_id, MmslVariable *var, void *param, int obj_id, MMSL_OBJECT *obj) +{ + if (var == NULL || obj_id != SCRIPT_OBJECT_TEXT || obj == NULL) + return; + + Text *text = (Text *)*obj; + if (text == NULL) + return; + + on_common_get(var_id, var, param, obj_id, obj); + + switch (var_id) + { + case SCRIPT_OBJECT_VAR_TEXT_COLOR: + var->Set(text->color); + break; + case SCRIPT_OBJECT_VAR_TEXT_BACKCOLOR: + var->Set(text->color); + break; + case SCRIPT_OBJECT_VAR_TEXT_FONT: + var->Set(text->font != NULL ? text->font->name : ""); + break; + case SCRIPT_OBJECT_VAR_TEXT_VALUE: + var->Set(text->text); + break; + case SCRIPT_OBJECT_VAR_TEXT_COUNT: + var->Set(text->text.GetLength()); + break; + case SCRIPT_OBJECT_VAR_TEXT_TEXTALIGN: + { + const char *ta[] = { "left", "center", "right" }; + var->Set(ta[text->text_align]); + } + break; + case SCRIPT_OBJECT_VAR_TEXT_DELETE: + var->Set(0); + break; + case SCRIPT_OBJECT_VAR_TEXT_STYLE: + { + const char *sty[] = { "", "underline", "outline" }; + var->Set(sty[text->style]); + } + break; + } +} + +void on_text_set(int var_id, MmslVariable *var, void *param, int obj_id, MMSL_OBJECT *obj) +{ + if (var == NULL || obj_id != SCRIPT_OBJECT_TEXT || obj == NULL) + return; + + Text *text = (Text *)*obj; + if (text == NULL) + return; + + on_common_set(var_id, var, param, obj_id, obj); + + switch (var_id) + { + case SCRIPT_OBJECT_VAR_TEXT_COLOR: + text->SetColor(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_TEXT_BACKCOLOR: + text->SetBkColor(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_TEXT_FONT: + text->SetFont(var->GetString()); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_WIDTH); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_HEIGHT); + break; + case SCRIPT_OBJECT_VAR_TEXT_VALUE: + text->SetText(var->GetString()); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_WIDTH); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_HEIGHT); + break; + case SCRIPT_OBJECT_VAR_TEXT_COUNT: + text->SetText(text->text.Left(var->GetInteger())); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_WIDTH); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_HEIGHT); + break; + case SCRIPT_OBJECT_VAR_TEXT_DELETE: + text->SetText(text->text.Mid(var->GetInteger())); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_WIDTH); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_HEIGHT); + break; + case SCRIPT_OBJECT_VAR_TEXT_STYLE: + { + SPString str = var->GetString(); + if (str.CompareNoCase("underline") == 0) + text->SetStyle(TEXT_STYLE_UNDERLINE); + else if (str.CompareNoCase("outline") == 0) + text->SetStyle(TEXT_STYLE_OUTLINE); + else + text->SetStyle(TEXT_STYLE_NORMAL); + } + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_WIDTH); + mmsl->UpdateObjectVariable(text, SCRIPT_OBJECT_VAR_TEXT_HEIGHT); + break; + case SCRIPT_OBJECT_VAR_TEXT_TEXTALIGN: + { + SPString str = var->GetString(); + if (str.CompareNoCase("center") == 0) + text->SetTextAlign(TEXT_ALIGN_CENTER); + else if (str.CompareNoCase("right") == 0) + text->SetTextAlign(TEXT_ALIGN_RIGHT); + else + text->SetTextAlign(TEXT_ALIGN_LEFT); + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_rect_get(int var_id, MmslVariable *var, void *param, int obj_id, MMSL_OBJECT *obj) +{ + if (var == NULL || obj_id != SCRIPT_OBJECT_RECT || obj == NULL) + return; + + Rectangle *rect = (Rectangle *)*obj; + if (rect == NULL) + return; + + on_common_get(var_id, var, param, obj_id, obj); + + switch (var_id) + { + case SCRIPT_OBJECT_VAR_RECT_COLOR: + var->Set(rect->color); + break; + case SCRIPT_OBJECT_VAR_RECT_BACKCOLOR: + var->Set(rect->bkcolor); + break; + case SCRIPT_OBJECT_VAR_RECT_LINEWIDTH: + var->Set(rect->linewidth); + break; + case SCRIPT_OBJECT_VAR_RECT_ROUND: + var->Set(rect->round); + break; + } +} + +void on_rect_set(int var_id, MmslVariable *var, void *param, int obj_id, MMSL_OBJECT *obj) +{ + if (var == NULL || obj_id != SCRIPT_OBJECT_RECT || obj == NULL) + return; + + Rectangle *rect = (Rectangle *)*obj; + if (rect == NULL) + return; + + on_common_set(var_id, var, param, obj_id, obj); + + switch (var_id) + { + case SCRIPT_OBJECT_VAR_RECT_COLOR: + rect->SetColor(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_RECT_BACKCOLOR: + rect->SetBkColor(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_RECT_LINEWIDTH: + rect->SetLineWidth(var->GetInteger()); + break; + case SCRIPT_OBJECT_VAR_RECT_ROUND: + rect->SetRound(var->GetInteger()); + break; + } +} + diff --git a/src/script-objs.h b/src/script-objs.h new file mode 100644 index 0000000..267ae90 --- /dev/null +++ b/src/script-objs.h @@ -0,0 +1,84 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +// callbacks: +void on_image_create(int obj_id, MMSL_OBJECT *obj, void *param); +void on_image_delete(int obj_id, MMSL_OBJECT *obj, void *param); + +void on_text_create(int obj_id, MMSL_OBJECT *obj, void *param); +void on_text_delete(int obj_id, MMSL_OBJECT *obj, void *param); + +void on_rect_create(int obj_id, MMSL_OBJECT *obj, void *param); +void on_rect_delete(int obj_id, MMSL_OBJECT *obj, void *param); + + +enum +{ + SCRIPT_OBJECT_IMAGE, + SCRIPT_OBJECT_TEXT, + SCRIPT_OBJECT_RECT, +}; + +void on_image_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_image_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_text_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_text_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_rect_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_rect_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + + +enum SCRIPT_OBJECT_VARS +{ + SCRIPT_OBJECT_VAR_IMAGE_TYPE, + SCRIPT_OBJECT_VAR_IMAGE_GROUP, + SCRIPT_OBJECT_VAR_IMAGE_SRC, + SCRIPT_OBJECT_VAR_IMAGE_X, + SCRIPT_OBJECT_VAR_IMAGE_Y, + SCRIPT_OBJECT_VAR_IMAGE_VISIBLE, + SCRIPT_OBJECT_VAR_IMAGE_WIDTH, + SCRIPT_OBJECT_VAR_IMAGE_HEIGHT, + SCRIPT_OBJECT_VAR_IMAGE_HFLIP, + SCRIPT_OBJECT_VAR_IMAGE_VFLIP, + SCRIPT_OBJECT_VAR_IMAGE_HALIGN, + SCRIPT_OBJECT_VAR_IMAGE_VALIGN, + SCRIPT_OBJECT_VAR_IMAGE_TIMER, + + SCRIPT_OBJECT_VAR_TEXT_TYPE, + SCRIPT_OBJECT_VAR_TEXT_GROUP, + SCRIPT_OBJECT_VAR_TEXT_X, + SCRIPT_OBJECT_VAR_TEXT_Y, + SCRIPT_OBJECT_VAR_TEXT_VISIBLE, + SCRIPT_OBJECT_VAR_TEXT_WIDTH, + SCRIPT_OBJECT_VAR_TEXT_HEIGHT, + SCRIPT_OBJECT_VAR_TEXT_HALIGN, + SCRIPT_OBJECT_VAR_TEXT_VALIGN, + SCRIPT_OBJECT_VAR_TEXT_COLOR, + SCRIPT_OBJECT_VAR_TEXT_BACKCOLOR, + SCRIPT_OBJECT_VAR_TEXT_VALUE, + SCRIPT_OBJECT_VAR_TEXT_COUNT, + SCRIPT_OBJECT_VAR_TEXT_DELETE, + SCRIPT_OBJECT_VAR_TEXT_FONT, + SCRIPT_OBJECT_VAR_TEXT_TEXTALIGN, + SCRIPT_OBJECT_VAR_TEXT_STYLE, + SCRIPT_OBJECT_VAR_TEXT_TIMER, + + SCRIPT_OBJECT_VAR_RECT_TYPE, + SCRIPT_OBJECT_VAR_RECT_GROUP, + SCRIPT_OBJECT_VAR_RECT_X, + SCRIPT_OBJECT_VAR_RECT_Y, + SCRIPT_OBJECT_VAR_RECT_VISIBLE, + SCRIPT_OBJECT_VAR_RECT_WIDTH, + SCRIPT_OBJECT_VAR_RECT_HEIGHT, + SCRIPT_OBJECT_VAR_RECT_LINEWIDTH, + SCRIPT_OBJECT_VAR_RECT_COLOR, + SCRIPT_OBJECT_VAR_RECT_BACKCOLOR, + SCRIPT_OBJECT_VAR_RECT_HALIGN, + SCRIPT_OBJECT_VAR_RECT_VALIGN, + SCRIPT_OBJECT_VAR_RECT_ROUND, + SCRIPT_OBJECT_VAR_RECT_TIMER, +}; + diff --git a/src/script-objs.inc.c b/src/script-objs.inc.c new file mode 100644 index 0000000..364d6ec --- /dev/null +++ b/src/script-objs.inc.c @@ -0,0 +1,74 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +static const struct SCRIPT_OBJECT +{ + MmslObjectCallback Create, Delete; + int ID; +} script_objects[] = +{ + { on_image_create, on_image_delete, SCRIPT_OBJECT_IMAGE }, + { on_text_create, on_text_delete, SCRIPT_OBJECT_TEXT }, + { on_rect_create, on_rect_delete, SCRIPT_OBJECT_RECT }, + { NULL, NULL, -1 } +}; + +static const struct SCRIPT_OBJECT_VAR +{ + MmslVariableCallback Get, Set; + int obj_ID; + int ID; +} script_object_vars[] = +{ + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_TYPE }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_GROUP }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_SRC }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_X }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_Y }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_VISIBLE }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_WIDTH }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_HEIGHT }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_HFLIP }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_VFLIP }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_HALIGN }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_VALIGN }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_TIMER }, + + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_TYPE }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_GROUP }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_X }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_Y }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_VISIBLE }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_WIDTH }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_HEIGHT }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_HALIGN }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_VALIGN }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_COLOR }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_BACKCOLOR }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_VALUE }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_COUNT }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_DELETE }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_FONT }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_TEXTALIGN }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_STYLE }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_TIMER }, + + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_TYPE }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_GROUP }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_X }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_Y }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_VISIBLE }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_WIDTH }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_HEIGHT }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_LINEWIDTH }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_COLOR }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_BACKCOLOR }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_HALIGN }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_VALIGN }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_ROUND }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_TIMER }, + { NULL, NULL, -1, -1, } +}; + diff --git a/src/script-player.cpp b/src/script-player.cpp new file mode 100644 index 0000000..1a1e110 --- /dev/null +++ b/src/script-player.cpp @@ -0,0 +1,1375 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - media player wrapper impl. + * \file script-player.cpp + * \author bombur + * \version 0.1 + * \date 12.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +static const StringPair player_repeat_pairs[] = +{ + { "none", PLAYER_REPEAT_NONE }, + { "selection", PLAYER_REPEAT_SELECTION }, + { "track", PLAYER_REPEAT_TRACK }, + { "all", PLAYER_REPEAT_ALL }, + { "random", PLAYER_REPEAT_RANDOM }, + { NULL, -1 }, +}; + +static const StringPair player_menu_pairs[] = +{ + { "0", DVD_MENU_ESCAPE }, + { "1", DVD_MENU_ROOT }, + { "escape", DVD_MENU_ESCAPE }, + { "title", DVD_MENU_TITLE }, + { "root", DVD_MENU_ROOT }, + { "subtitle", DVD_MENU_SUBTITLE }, + { "audio", DVD_MENU_AUDIO }, + { "angle", DVD_MENU_ANGLE }, + { "chapters", DVD_MENU_CHAPTERS }, + { NULL, -1 }, +}; + +static const StringPair player_clrs_pairs[] = +{ + { "", PLAYER_COLOR_SPACE_UNKNOWN }, + { "YCrCb", PLAYER_COLOR_SPACE_YCRCB }, + { "Grayscale", PLAYER_COLOR_SPACE_GRAYSCALE }, + { NULL, -1 }, +}; + +static const StringPair player_charset_pairs[] = +{ + { "", SUBTITLE_CHARSET_DEFAULT }, + { "cp1251", SUBTITLE_CHARSET_CP1251 }, + { "iso8859-1", SUBTITLE_CHARSET_ISO8859_1 }, + { "iso8859-2", SUBTITLE_CHARSET_ISO8859_2 }, + { "koi8-r", SUBTITLE_CHARSET_KOI8R }, + { NULL, -1 }, +}; + +static const StringPair player_speed_pairs[] = +{ + { "0", MPEG_SPEED_PAUSE, }, + { "4", MPEG_SPEED_FWD_4X, }, + { "8", MPEG_SPEED_FWD_8X, }, + { "16", MPEG_SPEED_FWD_16X, }, + { "32", MPEG_SPEED_FWD_32X, }, + { "48", MPEG_SPEED_FWD_48X, }, + { "100", MPEG_SPEED_FWD_MAX, }, + { "-4", MPEG_SPEED_REV_4X, }, + { "-8", MPEG_SPEED_REV_8X, }, + { "-16", MPEG_SPEED_REV_16X, }, + { "-32", MPEG_SPEED_REV_32X, }, + { "-48", MPEG_SPEED_REV_48X, }, + { "-100", MPEG_SPEED_REV_MAX, }, + { "1/2", MPEG_SPEED_SLOW_FWD_2X, }, + { "1/4", MPEG_SPEED_SLOW_FWD_4X, }, + { "1/8", MPEG_SPEED_SLOW_FWD_8X, }, + { "-1/2", MPEG_SPEED_SLOW_REV_2X, }, + { "-1/4", MPEG_SPEED_SLOW_REV_4X, }, + { "-1/8", MPEG_SPEED_SLOW_REV_8X, }, + { NULL, -1 }, +}; + +//////////////////////////////////////////////// + +int get_volume() +{ + DWORD lvol = 0, rvol = 0; + khwl_getproperty(KHWL_AUDIO_SET, eaVolumeLeft, sizeof(lvol), &lvol); + khwl_getproperty(KHWL_AUDIO_SET, eaVolumeRight, sizeof(rvol), &rvol); + return MAX(lvol, rvol); +} + +int get_balance() +{ + DWORD lvol = 0, rvol = 0; + khwl_getproperty(KHWL_AUDIO_SET, eaVolumeLeft, sizeof(lvol), &lvol); + khwl_getproperty(KHWL_AUDIO_SET, eaVolumeRight, sizeof(rvol), &rvol); + int volume = MAX(lvol, rvol); + if (volume == 0) + return 0; + int balance = 100 * MIN(lvol, rvol) / volume - 100; + return (lvol < rvol) ? balance : -balance; +} + +int get_audio_offset() +{ + int audio_offs; + //khwl_getproperty(KHWL_COMMON_SET, eDoAudioLater, sizeof(audio_offs), &audio_offs); + audio_offs = (int)(video_get_audio_offset() / INT64(90)); + return audio_offs; +} + + +void set_volume(int vol) +{ + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + int balance = get_balance(); + int lvol = balance <= 0 ? vol : (100-vol) * balance / 100; + int rvol = balance >= 0 ? vol : (vol-100) * balance / 100; + khwl_setproperty(KHWL_AUDIO_SET, eaVolumeLeft, sizeof(lvol), &lvol); + khwl_setproperty(KHWL_AUDIO_SET, eaVolumeRight, sizeof(rvol), &rvol); + msg("Volume set to (%d,%d).\n", lvol, rvol); +} + +void set_balance(int balance) +{ + if (balance < -100) + balance = -100; + if (balance > 100) + balance = 100; + int vol = get_volume(); + int lvol = balance <= 0 ? vol : (100-vol) * balance / 100; + int rvol = balance >= 0 ? vol : (vol-100) * balance / 100; + khwl_setproperty(KHWL_AUDIO_SET, eaVolumeLeft, sizeof(lvol), &lvol); + khwl_setproperty(KHWL_AUDIO_SET, eaVolumeRight, sizeof(rvol), &rvol); + msg("Volume set to (%d,%d).\n", lvol, rvol); +} + +void set_audio_offset(int audio_offs) +{ + if (audio_offs < -5000) + audio_offs = -5000; + if (audio_offs > 5000) + audio_offs = 5000; + audio_offs *= 90; + //khwl_setproperty(KHWL_COMMON_SET, eDoAudioLater, sizeof(audio_offs), &audio_offs); + video_set_audio_offset(audio_offs); + msg("Audio offset set to %d PTS.\n", audio_offs); +} + +/////////////////////////////////////////////////////////// + +bool player_dvd_command(const SPString & command) +{ + if (command.CompareNoCase("play") == 0) + { + params->player_error = ""; + + if (module_load("dvd") < 0) + return false; + + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ERROR); + + gui_update(); + + if (params->player_source.FindNoCase("/dvd") == 0 && + params->status != CDROM_STATUS_HAS_DVD) + { + module_unload("dvd"); + return false; + } + + if (params->dvdplaying) + { + // if user changed time + if (params->info.cur_time_changed) + { + params->info.cur_time_changed = false; + dvd_seek(params->info.cur_time); + return true; + } + // if user changed title or chapter: + if (params->info.cur_changed) + { + params->info.cur_changed = false; + if (!dvd_seek_titlepart(params->info.cur_title, params->info.cur_chapter)) + { + dvd_get_cur(¶ms->info.cur_title, ¶ms->info.cur_chapter); + params->info.num_chapters = dvd_getnumchapters(params->info.cur_title); + } + return true; + } + + // restore normal play + dvd_button_play(); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + // first time - start DVD... + dvd_setdeflang_menu(params->info.dvd_menu_lang); + dvd_setdeflang_audio(params->info.dvd_audio_lang); + dvd_setdeflang_spu(params->info.spu_lang); + + const char *source; + bool play_from_drive = true; + if (params->player_source.FindNoCase("/dvd") != 0 && + params->player_source.FindNoCase("/cdrom/video_ts/") != 0) + { + source = cdrom_getdevicepath(*params->player_folder); + play_from_drive = false; + } else + source = cdrom_getdevicepath(NULL); + int ret = dvd_play(source, play_from_drive); + if (ret < 0) + { + // Failure - try DVD disc as ISO... + params->require_next_status = CDROM_STATUS_HAS_ISO; + return true; + } + + // all went OK! + params->dvdplaying = TRUE; + params->info.num_titles = dvd_getnumtitles(); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("stop") == 0) + { + if (params->dvdplaying) + { + dvd_stop(); + params->dvdplaying = FALSE; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + module_unload("dvd"); + return true; + } + } + else if (command.CompareNoCase("cancel") == 0) + { + if (params->dvdplaying) + { + params->info.cur_chapter = params->info.real_cur_chapter; + params->info.cur_title = params->info.real_cur_title; + params->info.cur_time = params->info.real_cur_time; + params->info.cur_changed = false; + params->info.cur_time_changed = false; + return true; + } + } + else if (params->dvdplaying) + { + return dvd_do_command(command); + } + return false; +} + +#ifdef EXTERNAL_PLAYER +bool player_file_command(const SPString & command) +{ + if (command.CompareNoCase("play") == 0) + { + params->player_error = ""; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ERROR); + gui_update(); + + if (params->status != CDROM_STATUS_HAS_ISO && params->status != CDROM_STATUS_HAS_MIXED) + return false; + if (params->fileplaying) + { + // if user changed time + if (params->info.cur_time_changed) + { + params->info.cur_time_changed = false; + player_seek(params->info.cur_time); + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + + // restore normal play + params->speed = MPEG_SPEED_NORMAL; + player_play(); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + params->fileplaying = FALSE; + if (player_play(params->player_source) >= 0) + { + // all went OK! + params->fileplaying = TRUE; + params->speed = MPEG_SPEED_NORMAL; + } + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("info") == 0) + { + params->waitinfo = TRUE; + player_startinfo(params->player_source, params->iso_lang); + } + else if (command.CompareNoCase("stop") == 0) + { + if (params->fileplaying) + { + player_stop(); + params->fileplaying = FALSE; + params->speed = MPEG_SPEED_STOP; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + return true; + } + } + else if (command.CompareNoCase("pause") == 0) + { + if (params->fileplaying) + { + player_pause(); + params->speed = MPEG_SPEED_PAUSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("forward") == 0) + { + if (params->fileplaying) + { + if (player_forward() == 1) + { + params->speed = MPEG_SPEED_FWD_4X; + } else + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("rewind") == 0) + { + if (params->fileplaying) + { + if (player_rewind() == 1) + { + params->speed = MPEG_SPEED_REV_4X; + } else + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + return false; +} +#endif + +#ifdef INTERNAL_VIDEO_PLAYER +bool player_video_command(const SPString & command) +{ + if (command.CompareNoCase("play") == 0) + { + params->player_error = ""; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ERROR); + gui_update(); + + if (params->status != CDROM_STATUS_HAS_ISO && params->status != CDROM_STATUS_HAS_MIXED) + return false; + if (params->videoplaying) + { + // if user changed time + if (params->info.cur_time_changed) + { + params->info.cur_time_changed = false; + video_seek(params->info.cur_time); + //return true; + } + + // restore normal play + params->speed = MPEG_SPEED_NORMAL; + video_play(); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + params->videoplaying = FALSE; + if (video_play(params->player_source) >= 0) + { + // all went OK! + params->videoplaying = TRUE; + params->speed = MPEG_SPEED_NORMAL; + } + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("stop") == 0) + { + if (params->videoplaying) + { + if (video_stop()) + { + params->videoplaying = FALSE; + params->speed = MPEG_SPEED_STOP; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + return true; + } + return false; + } + } + else if (command.CompareNoCase("pause") == 0) + { + if (params->videoplaying) + { + video_pause(); + params->speed = MPEG_SPEED_PAUSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("forward") == 0 || command.CompareNoCase("rewind") == 0) + { + if (params->videoplaying) + { + bool fwd = command.CompareNoCase("forward") == 0; + if (params->speed == MPEG_SPEED_FWD_4X) + params->speed = fwd ? MPEG_SPEED_FWD_MAX : MPEG_SPEED_REV_4X; + else if (params->speed == MPEG_SPEED_REV_4X) + params->speed = fwd ? MPEG_SPEED_FWD_4X : MPEG_SPEED_REV_MAX; + else if (params->speed == MPEG_SPEED_FWD_MAX) + params->speed = fwd ? MPEG_SPEED_FWD_MAX : MPEG_SPEED_FWD_4X; + else if (params->speed == MPEG_SPEED_REV_MAX) + params->speed = fwd ? MPEG_SPEED_REV_4X : MPEG_SPEED_REV_MAX; + else if (params->speed == MPEG_SPEED_NORMAL) + params->speed = fwd ? MPEG_SPEED_FWD_4X : MPEG_SPEED_REV_4X; + + if (params->speed & MPEG_SPEED_FWD_MASK) + { + if (video_forward(params->speed == MPEG_SPEED_FWD_MAX) != 1) + params->speed = MPEG_SPEED_NORMAL; + } else + { + if (video_rewind(params->speed == MPEG_SPEED_REV_MAX) != 1) + params->speed = MPEG_SPEED_NORMAL; + } + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("audio") == 0) + { + if (params->videoplaying) + { + video_set_audio_track(-1); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_LANGUAGE_AUDIO); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_AUDIO_STREAM); + return true; + } + } + else if (command.CompareNoCase("subtitle") == 0) + { + if (params->videoplaying) + { + if (!subtitle_next()) + script_error_callback(SCRIPT_ERROR_INVALID); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_LANGUAGE_SUBTITLE); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SUBTITLE_STREAM); + return true; + } else + script_error_callback(SCRIPT_ERROR_INVALID); + return true; + } + else if (command.CompareNoCase("angle") == 0) + { + script_error_callback(SCRIPT_ERROR_INVALID); + return true; + } + return false; +} +#endif + +#ifdef INTERNAL_AUDIO_PLAYER +bool player_audio_command(const SPString & command) +{ + if (command.CompareNoCase("play") == 0) + { + params->player_error = ""; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ERROR); + gui_update(); + + if (params->status != CDROM_STATUS_HAS_ISO && params->status != CDROM_STATUS_HAS_MIXED) + return false; + if (params->audioplaying) + { + // if user changed time + if (params->info.cur_time_changed) + { + params->info.cur_time_changed = false; + audio_seek(params->info.cur_time, SEEK_SET); + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + + // restore normal play + params->speed = MPEG_SPEED_NORMAL; + audio_play(); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + params->audioplaying = FALSE; + if (audio_play(params->player_source, params->player_type == PLAYER_TYPE_FOLDER) >= 0) + { + // all went OK! + params->audioplaying = TRUE; + params->speed = MPEG_SPEED_NORMAL; + } + params->player_type = PLAYER_TYPE_AUDIO; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("info") == 0) + { + params->waitinfo = TRUE; + if (params->player_type != PLAYER_TYPE_FOLDER) + player_startinfo(params->player_source, params->iso_lang); + } + else if (command.CompareNoCase("stop") == 0) + { + if (params->audioplaying) + { + audio_delete_filelist(); + audio_stop(); + params->audioplaying = FALSE; + params->speed = MPEG_SPEED_STOP; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + return true; + } + } + else if (command.CompareNoCase("next") == 0) + { + if (params->audioplaying) + { + if (audio_stop()) + { + audio_delete_filelist(); + + params->audioplaying = FALSE; + params->speed = MPEG_SPEED_STOP; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + } + return true; + } + } + else if (command.CompareNoCase("prev") == 0) + { + if (params->audioplaying) + { + if (audio_stop(FALSE)) // 'prev' + { + audio_delete_filelist(); + + params->audioplaying = FALSE; + params->speed = MPEG_SPEED_STOP; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + } + return true; + } + } + else if (command.CompareNoCase("pause") == 0) + { + if (params->audioplaying) + { + audio_pause(); + params->speed = MPEG_SPEED_PAUSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("forward") == 0) + { + if (params->audioplaying) + { + if (audio_forward() == 1) + { + params->speed = MPEG_SPEED_FWD_4X; + } else + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("rewind") == 0) + { + if (params->audioplaying) + { + if (audio_rewind() == 1) + { + params->speed = MPEG_SPEED_REV_4X; + } else + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + return false; +} +#endif + +bool player_cdda_command(const SPString & command) +{ + if (command.CompareNoCase("play") == 0) + { + params->player_error = ""; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ERROR); + gui_update(); + + if (params->status != CDROM_STATUS_HAS_AUDIO && params->status != CDROM_STATUS_HAS_MIXED) + return false; + if (params->cddaplaying) + { + // if user changed time + if (params->info.cur_time_changed) + { + params->info.cur_time_changed = false; + cdda_seek(params->info.cur_time); + //return true; + } + + // restore normal play + params->speed = MPEG_SPEED_NORMAL; + cdda_play(NULL); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + params->cddaplaying = FALSE; + if (cdda_play(params->player_source) >= 0) + { + // all went OK! + params->cddaplaying = TRUE; + params->speed = MPEG_SPEED_NORMAL; + } + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + else if (command.CompareNoCase("info") == 0) + { + params->info.length = cdda_get_length(params->player_source); + params->info.num_titles = cdda_get_numtracks(); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_LENGTH); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_NUM_TITLES); + } + else if (command.CompareNoCase("stop") == 0) + { + if (params->cddaplaying) + { + cdda_stop(); + params->cddaplaying = FALSE; + params->speed = MPEG_SPEED_STOP; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + return true; + } + } + else if (command.CompareNoCase("pause") == 0) + { + if (params->cddaplaying) + { + cdda_pause(); + params->speed = MPEG_SPEED_PAUSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("forward") == 0) + { + if (params->cddaplaying) + { + cdda_forward(); + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + else if (command.CompareNoCase("rewind") == 0) + { + if (params->cddaplaying) + { + cdda_rewind(); + params->speed = MPEG_SPEED_NORMAL; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + return true; + } + } + return false; +} + + +bool is_internal_playing() +{ + return params->dvdplaying == TRUE || params->cddaplaying == TRUE + || params->videoplaying == TRUE || params->audioplaying == TRUE; +} + +bool is_playing() +{ + return params->dvdplaying == TRUE || params->fileplaying == TRUE + || params->videoplaying == TRUE || params->audioplaying == TRUE + || params->cddaplaying == TRUE; +} + +void player_update_source(char *filepath) +{ + params->player_source = filepath; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SOURCE); +} + +void player_do_command() +{ + SPString & cmd = params->player_command; + + if (params->player_type == PLAYER_TYPE_DVD) + { + player_dvd_command(cmd); + } +#ifdef EXTERNAL_PLAYER + else if (params->player_type == PLAYER_TYPE_FILE) + { + if (!cdrom_ismounted()) + cdrom_mount(params->iso_lang, FALSE); + player_file_command(cmd); + } +#else + else if (params->player_type == PLAYER_TYPE_FILE) + { + if (cmd.CompareNoCase("info") == 0) + { + params->waitinfo = TRUE; + player_startinfo(params->player_source, params->iso_lang); + } + } +#endif +#ifdef INTERNAL_VIDEO_PLAYER + else if (params->player_type == PLAYER_TYPE_VIDEO) + { + if (!cdrom_ismounted()) + cdrom_mount(params->iso_lang, FALSE); + player_video_command(cmd); + } +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (params->player_type == PLAYER_TYPE_AUDIO || + params->player_type == PLAYER_TYPE_FOLDER) + { + if (!cdrom_ismounted()) + cdrom_mount(params->iso_lang, FALSE); + player_audio_command(cmd); + } +#endif + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + { + player_cdda_command(cmd); + } + else + { + // undo playing + if (cmd == "play") + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + } +} + + +//////////////////////////////////////////////////////////////////////// + +void on_player_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_PLAYER_SOURCE: + var->Set(params->player_source); + break; + case SCRIPT_VAR_PLAYER_COMMAND: + case SCRIPT_VAR_PLAYER_SELECT: + var->Set(""); + break; + case SCRIPT_VAR_PLAYER_PLAYING: + { + if (params->player_type == PLAYER_TYPE_DVD) + var->Set(params->dvdplaying); + else if (params->player_type == PLAYER_TYPE_FILE) + var->Set(params->fileplaying); + else if (params->player_type == PLAYER_TYPE_VIDEO) + var->Set(params->videoplaying); + else if (params->player_type == PLAYER_TYPE_AUDIO) + var->Set(params->audioplaying); + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + var->Set(params->cddaplaying); + else + var->Set(0); + } + break; + case SCRIPT_VAR_PLAYER_SAVED: + if (params->player_type == PLAYER_TYPE_DVD) + { + if (module_load("dvd") < 0) + { + var->Set(0); + return; + } + var->Set(dvd_get_saved() ? 1 : 0); + } + else + var->Set(0); + break; + case SCRIPT_VAR_PLAYER_REPEAT: + StringPair::Set(var, player_repeat_pairs, params->player_repeat); + break; + case SCRIPT_VAR_PLAYER_SPEED: + { + MPEG_SPEED_TYPE speed = MPEG_SPEED_STOP; + if (params->player_type == PLAYER_TYPE_DVD) + { + if (!params->dvdplaying) + speed = MPEG_SPEED_STOP; + else + speed = dvd_getspeed(); + } + else if (params->player_type == PLAYER_TYPE_FILE) + speed = params->speed; + else if (params->player_type == PLAYER_TYPE_VIDEO) + speed = params->speed; + else if (params->player_type == PLAYER_TYPE_AUDIO) + speed = params->speed; + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + speed = params->speed; + switch (speed) + { + case MPEG_SPEED_NORMAL: + var->Set(1); break; + case MPEG_SPEED_PAUSE: + case MPEG_SPEED_STEP: + case MPEG_SPEED_STOP: + var->Set(0); break; + case MPEG_SPEED_FWD_4X: + var->Set(4); break; + case MPEG_SPEED_FWD_8X: + var->Set(8); break; + case MPEG_SPEED_FWD_16X: + var->Set(16); break; + case MPEG_SPEED_FWD_32X: + var->Set(32); break; + case MPEG_SPEED_FWD_48X: + var->Set(48); break; + case MPEG_SPEED_FWD_MAX: + var->Set(100); break; + case MPEG_SPEED_REV_4X: + var->Set(-4); break; + case MPEG_SPEED_REV_8X: + var->Set(-8); break; + case MPEG_SPEED_REV_16X: + var->Set(-16); break; + case MPEG_SPEED_REV_32X: + var->Set(-32); break; + case MPEG_SPEED_REV_48X: + var->Set(-48); break; + case MPEG_SPEED_REV_MAX: + var->Set(-100); break; + case MPEG_SPEED_SLOW_FWD_2X: + var->Set("1/2"); break; + case MPEG_SPEED_SLOW_FWD_4X: + var->Set("1/4"); break; + case MPEG_SPEED_SLOW_FWD_8X: + var->Set("1/8"); break; + case MPEG_SPEED_SLOW_REV_2X: + var->Set("-1/2"); break; + case MPEG_SPEED_SLOW_REV_4X: + var->Set("-1/4"); break; + case MPEG_SPEED_SLOW_REV_8X: + var->Set("-1/8"); break; + default: + var->Set(0); break; + } + } + break; + case SCRIPT_VAR_PLAYER_ANGLE: + if (params->player_type == PLAYER_TYPE_DVD) + var->Set(dvd_getangle()); + else + var->Set(0); + break; + case SCRIPT_VAR_PLAYER_MENU: + if (params->player_type == PLAYER_TYPE_DVD) + { + if (module_load("dvd") < 0) + { + var->Set(0); + return; + } + var->Set(dvd_ismenu() ? 1 : 0); + } + else + var->Set(0); + break; + case SCRIPT_VAR_PLAYER_LANGUAGE_MENU: + if (params->player_type == PLAYER_TYPE_DVD) + var->Set(params->info.dvd_menu_lang); + else + var->Set(""); + break; + case SCRIPT_VAR_PLAYER_LANGUAGE_AUDIO: + if (params->player_type == PLAYER_TYPE_DVD) + var->Set(params->info.dvd_audio_lang); + else + var->Set(""); + break; + case SCRIPT_VAR_PLAYER_LANGUAGE_SUBTITLE: + if (params->player_type == PLAYER_TYPE_DVD || params->player_type == PLAYER_TYPE_VIDEO) + var->Set(params->info.spu_lang); + else + var->Set(""); + break; + case SCRIPT_VAR_PLAYER_SUBTITLE: + if (params->player_type == PLAYER_TYPE_VIDEO) + var->Set(params->info.subtitle); + else + var->Set(""); + break; + case SCRIPT_VAR_PLAYER_SUBTITLE_CHARSET: + StringPair::Set(var, player_charset_pairs, params->info.subtitle_charset); + break; + case SCRIPT_VAR_PLAYER_SUBTITLE_WRAP: + var->Set(params->info.subtitle_wrap); + break; + case SCRIPT_VAR_PLAYER_VOLUME: + var->Set(get_volume()); + break; + case SCRIPT_VAR_PLAYER_BALANCE: + var->Set(get_balance()); + break; + case SCRIPT_VAR_PLAYER_AUDIO_OFFSET: + var->Set(get_audio_offset()); + break; + case SCRIPT_VAR_PLAYER_TIME: + var->Set(params->info.cur_time); + break; + case SCRIPT_VAR_PLAYER_TITLE: + var->Set(params->info.cur_title); + break; + case SCRIPT_VAR_PLAYER_CHAPTER: + var->Set(params->info.cur_chapter); + break; + case SCRIPT_VAR_PLAYER_NUM_TITLES: + var->Set(params->info.num_titles); + break; + case SCRIPT_VAR_PLAYER_NUM_CHAPTERS: + var->Set(params->info.num_chapters); + break; + case SCRIPT_VAR_PLAYER_NAME: + var->Set(params->info.name); + break; + case SCRIPT_VAR_PLAYER_ARTIST: + var->Set(params->info.artist); + break; + case SCRIPT_VAR_PLAYER_AUDIO_INFO: + var->Set(params->info.audio_info); + break; + case SCRIPT_VAR_PLAYER_VIDEO_INFO: + var->Set(params->info.video_info); + break; + case SCRIPT_VAR_PLAYER_AUDIO_STREAM: + var->Set(params->info.audio_stream); + break; + case SCRIPT_VAR_PLAYER_SUBTITLE_STREAM: + var->Set(params->info.spu_stream); + break; + case SCRIPT_VAR_PLAYER_LENGTH: + var->Set(params->info.length); + break; + case SCRIPT_VAR_PLAYER_WIDTH: + var->Set(params->info.width); + break; + case SCRIPT_VAR_PLAYER_HEIGHT: + var->Set(params->info.height); + break; + case SCRIPT_VAR_PLAYER_FRAME_RATE: + var->Set(params->info.frame_rate); + break; + case SCRIPT_VAR_PLAYER_COLOR_SPACE: + StringPair::Set(var, player_clrs_pairs, params->info.clrs); + break; + case SCRIPT_VAR_PLAYER_DEBUG: + if (params->player_type == PLAYER_TYPE_DVD) + var->Set(dvd_getdebug()); +#ifdef EXTERNAL_PLAYER + else if (params->player_type == PLAYER_TYPE_FILE) + var->Set(player_getdebug()); +#endif +#ifdef INTERNAL_VIDEO_PLAYER + else if (params->player_type == PLAYER_TYPE_VIDEO) + var->Set(video_getdebug()); +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (params->player_type == PLAYER_TYPE_AUDIO) + var->Set(audio_getdebug()); +#endif + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + var->Set(cdda_getdebug()); + else + var->Set(0); + break; + case SCRIPT_VAR_PLAYER_ERROR: + var->Set(params->player_error); + break; + } +} + +void on_player_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + + params->player_error = ""; + + switch (var_id) + { + case SCRIPT_VAR_PLAYER_SOURCE: + { + params->player_source = var->GetString(); + params->player_source.Replace('\\', '/'); + if (params->player_source.Find('/') != 0) + params->player_source = "/" + params->player_source; + params->player_folder = params->player_source; + int rf = params->player_folder.ReverseFind('/'); + if (rf > 0) + params->player_folder = params->player_folder.Left(rf); + // detect media type + params->player_type = PLAYER_TYPE_UNKNOWN; + if (params->player_source.FindNoCase("/dvd") == 0) + { + params->player_type = PLAYER_TYPE_DVD; + } + else if (params->player_source.FindNoCase("/cdrom") == 0 || + params->player_source.FindNoCase("/hdd") == 0) + { + // test for folder + struct stat64 statbuf; + if (cdrom_stat(params->player_source, &statbuf) >= 0 + && S_ISDIR(statbuf.st_mode)) + { + params->player_type = PLAYER_TYPE_FOLDER; + } + else if (params->player_source.FindNoCase(".cda") > 0) + params->player_type = PLAYER_TYPE_AUDIOCD; + else if (params->player_source.FindNoCase(".ifo") > 0 || + params->player_source.FindNoCase(".bup") > 0) + params->player_type = PLAYER_TYPE_DVD; +#ifdef INTERNAL_VIDEO_PLAYER + else if (params->player_source.FindNoCase(".avi") > 0 + || params->player_source.FindNoCase(".divx") > 0 + || params->player_source.FindNoCase(".mp4") > 0 + || params->player_source.FindNoCase(".3gp") > 0 + || params->player_source.FindNoCase(".mov") > 0 +#ifdef INTERNAL_VIDEO_MPEG_PLAYER + || params->player_source.FindNoCase(".mpg") > 0 + || params->player_source.FindNoCase(".m1v") > 0 + || params->player_source.FindNoCase(".m2v") > 0 + || params->player_source.FindNoCase(".mpeg") > 0 + || params->player_source.FindNoCase(".vob") > 0 + || params->player_source.FindNoCase(".dat") > 0 +#endif + ) + params->player_type = PLAYER_TYPE_VIDEO; +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (params->player_source.FindNoCase(".mp3") > 0 + || params->player_source.FindNoCase(".mp2") > 0 + || params->player_source.FindNoCase(".mp1") > 0 + || params->player_source.FindNoCase(".mpa") > 0 + || params->player_source.FindNoCase(".ac3") > 0 + || params->player_source.FindNoCase(".wav") > 0 + || params->player_source.FindNoCase(".ogg") > 0) + params->player_type = PLAYER_TYPE_AUDIO; +#endif + else + params->player_type = PLAYER_TYPE_FILE; + } + + params->info.name = ""; + params->info.artist = ""; + params->info.width = 0; + params->info.height = 0; + params->info.frame_rate = 0; + params->info.clrs = PLAYER_COLOR_SPACE_UNKNOWN; + params->info.length = 0; + + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_NAME); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ARTIST); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_WIDTH); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_HEIGHT); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_FRAME_RATE); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_COLOR_SPACE); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_LENGTH); + + } + break; + case SCRIPT_VAR_PLAYER_COMMAND: + params->player_command = var->GetString(); + //if (params->player_type == PLAYER_TYPE_DVD || params->player_command.CompareNoCase("stop") == 0) + player_do_command(); + /*else + params->player_do_command = true; + */ + break; + case SCRIPT_VAR_PLAYER_PLAYING: + { + switch (var->GetInteger()) + { + case 0: + if (params->player_type == PLAYER_TYPE_DVD) + player_dvd_command("stop"); +#ifdef EXTERNAL_PLAYER + else if (params->player_type == PLAYER_TYPE_FILE) + player_file_command("stop"); +#endif +#ifdef INTERNAL_VIDEO_PLAYER + else if (params->player_type == PLAYER_TYPE_VIDEO) + player_video_command("stop"); +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (params->player_type == PLAYER_TYPE_AUDIO) + player_audio_command("stop"); +#endif + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + player_cdda_command("stop"); + break; + case 1: + if (params->player_type == PLAYER_TYPE_DVD) + player_dvd_command("play"); +#ifdef EXTERNAL_PLAYER + else if (params->player_type == PLAYER_TYPE_FILE) + player_file_command("play"); +#endif +#ifdef INTERNAL_VIDEO_PLAYER + else if (params->player_type == PLAYER_TYPE_VIDEO) + player_video_command("play"); +#endif +#ifdef INTERNAL_AUDIO_PLAYER + else if (params->player_type == PLAYER_TYPE_AUDIO) + player_audio_command("play"); +#endif + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + player_cdda_command("play"); + break; + default: + ; + } + } + break; + case SCRIPT_VAR_PLAYER_SELECT: + break; + case SCRIPT_VAR_PLAYER_REPEAT: + params->player_repeat = (PLAYER_REPEAT)StringPair::Get(var, player_repeat_pairs, PLAYER_REPEAT_NONE); + break; + case SCRIPT_VAR_PLAYER_SPEED: + if (params->player_type == PLAYER_TYPE_DVD) + { + MPEG_SPEED_TYPE speed = (MPEG_SPEED_TYPE)StringPair::Get(var, player_speed_pairs, MPEG_SPEED_NORMAL); + dvd_setspeed(speed); + } + break; + case SCRIPT_VAR_PLAYER_ANGLE: + if (params->player_type == PLAYER_TYPE_DVD) + { + dvd_button_angle(var->GetInteger()); + } + break; + case SCRIPT_VAR_PLAYER_MENU: + if (params->player_type == PLAYER_TYPE_DVD) + { + DVD_MENU_TYPE menu = (DVD_MENU_TYPE)StringPair::Get(var, player_menu_pairs, DVD_MENU_DEFAULT); + dvd_button_menu(menu); + } + break; + case SCRIPT_VAR_PLAYER_LANGUAGE_MENU: + params->info.dvd_menu_lang = var->GetString(); + break; + case SCRIPT_VAR_PLAYER_LANGUAGE_AUDIO: + if (params->player_type == PLAYER_TYPE_DVD) + { + params->info.dvd_audio_lang = var->GetString(); + if (params->dvdplaying) + dvd_button_audio(params->info.dvd_audio_lang); + } + break; + case SCRIPT_VAR_PLAYER_LANGUAGE_SUBTITLE: + if (params->player_type == PLAYER_TYPE_DVD) // only for DVDs + { + params->info.spu_lang = var->GetString(); + if (params->dvdplaying) + dvd_button_subtitle(params->info.spu_lang); + } + break; + case SCRIPT_VAR_PLAYER_SUBTITLE_CHARSET: + params->info.subtitle_charset = (SUBTITLE_CHARSET)StringPair::Get(var, player_charset_pairs, SUBTITLE_CHARSET_DEFAULT); + break; + case SCRIPT_VAR_PLAYER_SUBTITLE_WRAP: + params->info.subtitle_wrap = MAX(0, var->GetInteger()); + break; + case SCRIPT_VAR_PLAYER_VOLUME: + set_volume(var->GetInteger()); + break; + case SCRIPT_VAR_PLAYER_BALANCE: + set_balance(var->GetInteger()); + break; + case SCRIPT_VAR_PLAYER_AUDIO_OFFSET: + set_audio_offset(var->GetInteger()); + break; + case SCRIPT_VAR_PLAYER_TIME: + if (params->player_type == PLAYER_TYPE_DVD) + { + params->info.cur_time = var->GetInteger(); + params->info.cur_time_changed = true; + dvd_get_chapter_for_time(params->info.cur_title, params->info.cur_time, + ¶ms->info.cur_chapter); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_CHAPTER); + } + else if (params->player_type == PLAYER_TYPE_FILE) + { + params->info.cur_time = var->GetInteger(); + params->info.cur_time_changed = true; + } + else if (params->player_type == PLAYER_TYPE_VIDEO) + { + params->info.cur_time = var->GetInteger(); + params->info.cur_time_changed = true; + } + else if (params->player_type == PLAYER_TYPE_AUDIO) + { + params->info.cur_time = var->GetInteger(); + params->info.cur_time_changed = true; + } + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + { + params->info.cur_time = var->GetInteger(); + params->info.cur_time_changed = true; + } + break; + case SCRIPT_VAR_PLAYER_CHAPTER: + if (params->player_type == PLAYER_TYPE_DVD) + { + int ch = var->GetInteger(); + if (ch > 0) + { + msg("Player chapter set to %d.\n", ch); + params->info.cur_chapter = ch; + params->info.cur_changed = true; + dvd_get_total_time(params->info.cur_title, params->info.cur_chapter, + ¶ms->info.cur_time); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_TIME); + } + } + break; + case SCRIPT_VAR_PLAYER_TITLE: + if (params->player_type == PLAYER_TYPE_DVD) + { + int titl = var->GetInteger(); + if (titl > 0) + { + msg("Player title set to %d.\n", titl); + params->info.cur_title = titl; + params->info.cur_chapter = 1; + params->info.cur_changed = true; + params->info.num_chapters = dvd_getnumchapters(params->info.cur_title); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_NUM_CHAPTERS); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_CHAPTER); + dvd_get_total_time(params->info.cur_title, params->info.cur_chapter, + ¶ms->info.cur_time); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_TIME); + } + } + break; + case SCRIPT_VAR_PLAYER_DEBUG: + if (params->player_type == PLAYER_TYPE_DVD) + { + dvd_setdebug(var->GetInteger()); + } +#ifdef EXTERNAL_PLAYER + else if (params->player_type == PLAYER_TYPE_FILE) + { + player_setdebug(var->GetInteger()); + } +#endif + else if (params->player_type == PLAYER_TYPE_VIDEO) + { +#ifdef INTERNAL_VIDEO_PLAYER + video_setdebug(var->GetInteger()); +#endif + } + else if (params->player_type == PLAYER_TYPE_AUDIO) + { +#ifdef INTERNAL_AUDIO_PLAYER + audio_setdebug(var->GetInteger()); +#endif + } + else if (params->player_type == PLAYER_TYPE_AUDIOCD) + { + cdda_setdebug(var->GetInteger()); + } + break; + } +} diff --git a/src/script-pobjs.inc.c b/src/script-pobjs.inc.c new file mode 100644 index 0000000..f064988 --- /dev/null +++ b/src/script-pobjs.inc.c @@ -0,0 +1,76 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +static const struct SCRIPT_OBJECT +{ + MmslObjectCallback Create, Delete; + int ID; + const char *name; +} script_objects[] = +{ + { on_image_create, on_image_delete, SCRIPT_OBJECT_IMAGE, "image" }, + { on_text_create, on_text_delete, SCRIPT_OBJECT_TEXT, "text" }, + { on_rect_create, on_rect_delete, SCRIPT_OBJECT_RECT, "rect" }, + { NULL, NULL, -1, NULL } +}; + +static const struct SCRIPT_OBJECT_VAR +{ + MmslVariableCallback Get, Set; + int obj_ID; + int ID; + const char *name; +} script_object_vars[] = +{ + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_TYPE, ".type" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_GROUP, ".group" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_SRC, ".src" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_X, ".x" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_Y, ".y" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_VISIBLE, ".visible" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_WIDTH, ".width" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_HEIGHT, ".height" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_HFLIP, ".hflip" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_VFLIP, ".vflip" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_HALIGN, ".halign" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_VALIGN, ".valign" }, + { on_image_get, on_image_set, SCRIPT_OBJECT_IMAGE, SCRIPT_OBJECT_VAR_IMAGE_TIMER, ".timer" }, + + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_TYPE, ".type" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_GROUP, ".group" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_X, ".x" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_Y, ".y" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_VISIBLE, ".visible" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_WIDTH, ".width" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_HEIGHT, ".height" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_HALIGN, ".halign" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_VALIGN, ".valign" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_COLOR, ".color" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_BACKCOLOR, ".backcolor" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_VALUE, ".value" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_COUNT, ".count" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_DELETE, ".delete" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_FONT, ".font" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_TEXTALIGN, ".textalign" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_STYLE, ".style" }, + { on_text_get, on_text_set, SCRIPT_OBJECT_TEXT, SCRIPT_OBJECT_VAR_TEXT_TIMER, ".timer" }, + + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_TYPE, ".type" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_GROUP, ".group" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_X, ".x" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_Y, ".y" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_VISIBLE, ".visible" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_WIDTH, ".width" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_HEIGHT, ".height" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_LINEWIDTH, ".linewidth" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_COLOR, ".color" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_BACKCOLOR, ".backcolor" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_HALIGN, ".halign" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_VALIGN, ".valign" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_ROUND, ".round" }, + { on_rect_get, on_rect_set, SCRIPT_OBJECT_RECT, SCRIPT_OBJECT_VAR_RECT_TIMER, ".timer" }, + { NULL, NULL, -1, -1, NULL } +}; + diff --git a/src/script-pvars.inc.c b/src/script-pvars.inc.c new file mode 100644 index 0000000..cf45a93 --- /dev/null +++ b/src/script-pvars.inc.c @@ -0,0 +1,168 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +static const struct SCRIPT_VAR +{ + MmslVariableCallback Get, Set; + int ID; + const char *name; +} script_vars[] = +{ + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_POWER, "kernel.power" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FREQUENCY, "kernel.frequency" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_CHIP, "kernel.chip" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FREE_MEMORY, "kernel.free_memory" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FLASH_MEMORY, "kernel.flash_memory" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_PRINT, "kernel.print" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FIRMWARE_VERSION, "kernel.firmware_version" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_MMSL_VERSION, "kernel.mmsl_version" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_MMSL_ERRORS, "kernel.mmsl_errors" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_RUN, "kernel.run" }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_RANDOM, "kernel.random" }, + + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_SWITCH, "screen.switch" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_UPDATE, "screen.update" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TVSTANDARD, "screen.tvstandard" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TVOUT, "screen.tvout" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_LEFT, "screen.left" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TOP, "screen.top" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_RIGHT, "screen.right" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BOTTOM, "screen.bottom" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALETTE, "screen.palette" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALIDX, "screen.palidx" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALALPHA, "screen.palalpha" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALCOLOR, "screen.palcolor" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_FONT, "screen.font" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_COLOR, "screen.color" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACKCOLOR, "screen.backcolor" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TRCOLOR, "screen.trcolor" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_HALIGN, "screen.halign" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_VALIGN, "screen.valign" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK, "screen.back" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_LEFT, "screen.back_left" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_TOP, "screen.back_top" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_RIGHT, "screen.back_right" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_BOTTOM, "screen.back_bottom" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PRELOAD, "screen.preload" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_HZOOM, "screen.hzoom" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_VZOOM, "screen.vzoom" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_HSCROLL, "screen.hscroll" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_VSCROLL, "screen.vscroll" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_ROTATE, "screen.rotate" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BRIGHTNESS, "screen.brightness" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_CONTRAST, "screen.contrast" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_SATURATION, "screen.saturation" }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_FULLSCREEN, "screen.fullscreen" }, + + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_KEY, "pad.key" }, + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_DISPLAY, "pad.display" }, + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_SET, "pad.set" }, + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_CLEAR, "pad.clear" }, + + { on_drive_get, on_drive_set, SCRIPT_VAR_DRIVE_MEDIATYPE, "drive.mediatype" }, + { on_drive_get, on_drive_set, SCRIPT_VAR_DRIVE_TRAY, "drive.tray" }, + + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_CHARSET, "explorer.charset" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FOLDER, "explorer.folder" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_TARGET, "explorer.target" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILTER, "explorer.filter" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK1, "explorer.mask1" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK2, "explorer.mask2" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK3, "explorer.mask3" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK4, "explorer.mask4" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK5, "explorer.mask5" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_PATH, "explorer.path" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILENAME, "explorer.filename" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_EXTENSION, "explorer.extension" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_DRIVE_LETTER, "explorer.drive_letter" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_TYPE, "explorer.type" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASKINDEX, "explorer.maskindex" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILESIZE, "explorer.filesize" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILETIME, "explorer.filetime" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_COUNT, "explorer.count" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_SORT, "explorer.sort" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_POSITION, "explorer.position" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_COMMAND, "explorer.command" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FIND, "explorer.find" }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_COPIED, "explorer.copied" }, + + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SOURCE, "player.source" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_PLAYING, "player.playing" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SAVED, "player.saved" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_COMMAND, "player.command" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SELECT, "player.select" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_REPEAT, "player.repeat" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SPEED, "player.speed" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_MENU, "player.menu" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LANGUAGE_MENU, "player.language_menu" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LANGUAGE_AUDIO, "player.language_audio" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LANGUAGE_SUBTITLE, "player.language_subtitle" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE_CHARSET, "player.subtitle_charset" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE_WRAP, "player.subtitle_wrap" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE, "player.subtitle" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_ANGLE, "player.angle" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_VOLUME, "player.volume" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_BALANCE, "player.balance" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_AUDIO_OFFSET, "player.audio_offset" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_TIME, "player.time" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_TITLE, "player.title" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_CHAPTER, "player.chapter" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_NAME, "player.name" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_ARTIST, "player.artist" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_AUDIO_INFO, "player.audio_info" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_VIDEO_INFO, "player.video_info" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_AUDIO_STREAM, "player.audio_stream" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE_STREAM, "player.subtitle_stream" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LENGTH, "player.length" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_NUM_TITLES, "player.num_titles" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_NUM_CHAPTERS, "player.num_chapters" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_WIDTH, "player.width" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_HEIGHT, "player.height" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_FRAME_RATE, "player.frame_rate" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_COLOR_SPACE, "player.color_space" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_DEBUG, "player.debug" }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_ERROR, "player.error" }, + + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_COMMAND, "settings.command" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_AUDIOOUT, "settings.audioout" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_TVTYPE, "settings.tvtype" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_TVSTANDARD, "settings.tvstandard" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_TVOUT, "settings.tvout" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVI, "settings.dvi" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_HQ_JPEG, "settings.hq_jpeg" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_HDD_SPEED, "settings.hdd_speed" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_PARENTAL, "settings.dvd_parental" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_MV, "settings.dvd_mv" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_LANG_MENU, "settings.dvd_lang_menu" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_LANG_AUDIO, "settings.dvd_lang_audio" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_LANG_SPU, "settings.dvd_lang_spu" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_VOLUME, "settings.volume" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_BALANCE, "settings.balance" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_BRIGHTNESS, "settings.brightness" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_CONTRAST, "settings.contrast" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_SATURATION, "settings.saturation" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER1, "settings.user1" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER2, "settings.user2" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER3, "settings.user3" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER4, "settings.user4" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER5, "settings.user5" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER6, "settings.user6" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER7, "settings.user7" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER8, "settings.user8" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER9, "settings.user9" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER10, "settings.user10" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER11, "settings.user11" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER12, "settings.user12" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER13, "settings.user13" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER14, "settings.user14" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER15, "settings.user15" }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER16, "settings.user16" }, + + { on_flash_get, on_flash_set, SCRIPT_VAR_FLASH_FILE, "flash.file" }, + { on_flash_get, on_flash_set, SCRIPT_VAR_FLASH_ADDRESS, "flash.address" }, + { on_flash_get, on_flash_set, SCRIPT_VAR_FLASH_PROGRESS, "flash.progress" }, + { NULL, NULL, -1, NULL } +}; + diff --git a/src/script-vars.h b/src/script-vars.h new file mode 100644 index 0000000..b36512e --- /dev/null +++ b/src/script-vars.h @@ -0,0 +1,187 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +void on_kernel_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_kernel_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_screen_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_screen_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_pad_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_pad_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_drive_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_drive_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_explorer_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_explorer_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_player_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_player_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_settings_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_settings_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + +void on_flash_get(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); +void on_flash_set(int var_id, MmslVariable *var, void *param, int obj_id = -1, MMSL_OBJECT *obj = NULL); + + +enum SCRIPT_VARS +{ + SCRIPT_VAR_KERNEL_POWER, + SCRIPT_VAR_KERNEL_FREQUENCY, + SCRIPT_VAR_KERNEL_CHIP, + SCRIPT_VAR_KERNEL_FREE_MEMORY, + SCRIPT_VAR_KERNEL_FLASH_MEMORY, + SCRIPT_VAR_KERNEL_PRINT, + SCRIPT_VAR_KERNEL_FIRMWARE_VERSION, + SCRIPT_VAR_KERNEL_MMSL_VERSION, + SCRIPT_VAR_KERNEL_MMSL_ERRORS, + SCRIPT_VAR_KERNEL_RUN, + SCRIPT_VAR_KERNEL_RANDOM, + + SCRIPT_VAR_SCREEN_SWITCH, + SCRIPT_VAR_SCREEN_UPDATE, + SCRIPT_VAR_SCREEN_TVSTANDARD, + SCRIPT_VAR_SCREEN_TVOUT, + SCRIPT_VAR_SCREEN_LEFT, + SCRIPT_VAR_SCREEN_TOP, + SCRIPT_VAR_SCREEN_RIGHT, + SCRIPT_VAR_SCREEN_BOTTOM, + SCRIPT_VAR_SCREEN_PALETTE, + SCRIPT_VAR_SCREEN_PALIDX, + SCRIPT_VAR_SCREEN_PALALPHA, + SCRIPT_VAR_SCREEN_PALCOLOR, + SCRIPT_VAR_SCREEN_FONT, + SCRIPT_VAR_SCREEN_COLOR, + SCRIPT_VAR_SCREEN_BACKCOLOR, + SCRIPT_VAR_SCREEN_TRCOLOR, + SCRIPT_VAR_SCREEN_HALIGN, + SCRIPT_VAR_SCREEN_VALIGN, + SCRIPT_VAR_SCREEN_BACK, + SCRIPT_VAR_SCREEN_BACK_LEFT, + SCRIPT_VAR_SCREEN_BACK_TOP, + SCRIPT_VAR_SCREEN_BACK_RIGHT, + SCRIPT_VAR_SCREEN_BACK_BOTTOM, + SCRIPT_VAR_SCREEN_PRELOAD, + SCRIPT_VAR_SCREEN_HZOOM, + SCRIPT_VAR_SCREEN_VZOOM, + SCRIPT_VAR_SCREEN_HSCROLL, + SCRIPT_VAR_SCREEN_VSCROLL, + SCRIPT_VAR_SCREEN_ROTATE, + SCRIPT_VAR_SCREEN_BRIGHTNESS, + SCRIPT_VAR_SCREEN_CONTRAST, + SCRIPT_VAR_SCREEN_SATURATION, + SCRIPT_VAR_SCREEN_FULLSCREEN, + + SCRIPT_VAR_PAD_KEY, + SCRIPT_VAR_PAD_DISPLAY, + SCRIPT_VAR_PAD_SET, + SCRIPT_VAR_PAD_CLEAR, + + SCRIPT_VAR_DRIVE_MEDIATYPE, + SCRIPT_VAR_DRIVE_TRAY, + + SCRIPT_VAR_EXPLORER_CHARSET, + SCRIPT_VAR_EXPLORER_FOLDER, + SCRIPT_VAR_EXPLORER_TARGET, + SCRIPT_VAR_EXPLORER_FILTER, + SCRIPT_VAR_EXPLORER_MASK1, + SCRIPT_VAR_EXPLORER_MASK2, + SCRIPT_VAR_EXPLORER_MASK3, + SCRIPT_VAR_EXPLORER_MASK4, + SCRIPT_VAR_EXPLORER_MASK5, + SCRIPT_VAR_EXPLORER_PATH, + SCRIPT_VAR_EXPLORER_FILENAME, + SCRIPT_VAR_EXPLORER_EXTENSION, + SCRIPT_VAR_EXPLORER_DRIVE_LETTER, + SCRIPT_VAR_EXPLORER_TYPE, + SCRIPT_VAR_EXPLORER_MASKINDEX, + SCRIPT_VAR_EXPLORER_FILESIZE, + SCRIPT_VAR_EXPLORER_FILETIME, + SCRIPT_VAR_EXPLORER_COUNT, + SCRIPT_VAR_EXPLORER_SORT, + SCRIPT_VAR_EXPLORER_POSITION, + SCRIPT_VAR_EXPLORER_COMMAND, + SCRIPT_VAR_EXPLORER_FIND, + SCRIPT_VAR_EXPLORER_COPIED, + + SCRIPT_VAR_PLAYER_SOURCE, + SCRIPT_VAR_PLAYER_PLAYING, + SCRIPT_VAR_PLAYER_SAVED, + SCRIPT_VAR_PLAYER_COMMAND, + SCRIPT_VAR_PLAYER_SELECT, + SCRIPT_VAR_PLAYER_REPEAT, + SCRIPT_VAR_PLAYER_SPEED, + SCRIPT_VAR_PLAYER_MENU, + SCRIPT_VAR_PLAYER_LANGUAGE_MENU, + SCRIPT_VAR_PLAYER_LANGUAGE_AUDIO, + SCRIPT_VAR_PLAYER_LANGUAGE_SUBTITLE, + SCRIPT_VAR_PLAYER_SUBTITLE_CHARSET, + SCRIPT_VAR_PLAYER_SUBTITLE_WRAP, + SCRIPT_VAR_PLAYER_SUBTITLE, + SCRIPT_VAR_PLAYER_ANGLE, + SCRIPT_VAR_PLAYER_VOLUME, + SCRIPT_VAR_PLAYER_BALANCE, + SCRIPT_VAR_PLAYER_AUDIO_OFFSET, + SCRIPT_VAR_PLAYER_TIME, + SCRIPT_VAR_PLAYER_TITLE, + SCRIPT_VAR_PLAYER_CHAPTER, + SCRIPT_VAR_PLAYER_NAME, + SCRIPT_VAR_PLAYER_ARTIST, + SCRIPT_VAR_PLAYER_AUDIO_INFO, + SCRIPT_VAR_PLAYER_VIDEO_INFO, + SCRIPT_VAR_PLAYER_AUDIO_STREAM, + SCRIPT_VAR_PLAYER_SUBTITLE_STREAM, + SCRIPT_VAR_PLAYER_LENGTH, + SCRIPT_VAR_PLAYER_NUM_TITLES, + SCRIPT_VAR_PLAYER_NUM_CHAPTERS, + SCRIPT_VAR_PLAYER_WIDTH, + SCRIPT_VAR_PLAYER_HEIGHT, + SCRIPT_VAR_PLAYER_FRAME_RATE, + SCRIPT_VAR_PLAYER_COLOR_SPACE, + SCRIPT_VAR_PLAYER_DEBUG, + SCRIPT_VAR_PLAYER_ERROR, + + SCRIPT_VAR_SETTINGS_COMMAND, + SCRIPT_VAR_SETTINGS_AUDIOOUT, + SCRIPT_VAR_SETTINGS_TVTYPE, + SCRIPT_VAR_SETTINGS_TVSTANDARD, + SCRIPT_VAR_SETTINGS_TVOUT, + SCRIPT_VAR_SETTINGS_DVI, + SCRIPT_VAR_SETTINGS_HQ_JPEG, + SCRIPT_VAR_SETTINGS_HDD_SPEED, + SCRIPT_VAR_SETTINGS_DVD_PARENTAL, + SCRIPT_VAR_SETTINGS_DVD_MV, + SCRIPT_VAR_SETTINGS_DVD_LANG_MENU, + SCRIPT_VAR_SETTINGS_DVD_LANG_AUDIO, + SCRIPT_VAR_SETTINGS_DVD_LANG_SPU, + SCRIPT_VAR_SETTINGS_VOLUME, + SCRIPT_VAR_SETTINGS_BALANCE, + SCRIPT_VAR_SETTINGS_BRIGHTNESS, + SCRIPT_VAR_SETTINGS_CONTRAST, + SCRIPT_VAR_SETTINGS_SATURATION, + SCRIPT_VAR_SETTINGS_USER1, + SCRIPT_VAR_SETTINGS_USER2, + SCRIPT_VAR_SETTINGS_USER3, + SCRIPT_VAR_SETTINGS_USER4, + SCRIPT_VAR_SETTINGS_USER5, + SCRIPT_VAR_SETTINGS_USER6, + SCRIPT_VAR_SETTINGS_USER7, + SCRIPT_VAR_SETTINGS_USER8, + SCRIPT_VAR_SETTINGS_USER9, + SCRIPT_VAR_SETTINGS_USER10, + SCRIPT_VAR_SETTINGS_USER11, + SCRIPT_VAR_SETTINGS_USER12, + SCRIPT_VAR_SETTINGS_USER13, + SCRIPT_VAR_SETTINGS_USER14, + SCRIPT_VAR_SETTINGS_USER15, + SCRIPT_VAR_SETTINGS_USER16, + + SCRIPT_VAR_FLASH_FILE, + SCRIPT_VAR_FLASH_ADDRESS, + SCRIPT_VAR_FLASH_PROGRESS, +}; + diff --git a/src/script-vars.inc.c b/src/script-vars.inc.c new file mode 100644 index 0000000..77b5bce --- /dev/null +++ b/src/script-vars.inc.c @@ -0,0 +1,167 @@ +////////////////////////////////////////////////////// +// SigmaPlayer Project. +// File auto-generated from MMSL language reference. +////////////////////////////////////////////////////// + +static const struct SCRIPT_VAR +{ + MmslVariableCallback Get, Set; + int ID; +} script_vars[] = +{ + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_POWER }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FREQUENCY }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_CHIP }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FREE_MEMORY }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FLASH_MEMORY }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_PRINT }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_FIRMWARE_VERSION }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_MMSL_VERSION }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_MMSL_ERRORS }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_RUN }, + { on_kernel_get, on_kernel_set, SCRIPT_VAR_KERNEL_RANDOM }, + + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_SWITCH }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_UPDATE }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TVSTANDARD }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TVOUT }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_LEFT }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TOP }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_RIGHT }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BOTTOM }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALETTE }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALIDX }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALALPHA }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PALCOLOR }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_FONT }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_COLOR }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACKCOLOR }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_TRCOLOR }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_HALIGN }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_VALIGN }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_LEFT }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_TOP }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_RIGHT }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BACK_BOTTOM }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_PRELOAD }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_HZOOM }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_VZOOM }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_HSCROLL }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_VSCROLL }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_ROTATE }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_BRIGHTNESS }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_CONTRAST }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_SATURATION }, + { on_screen_get, on_screen_set, SCRIPT_VAR_SCREEN_FULLSCREEN }, + + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_KEY }, + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_DISPLAY }, + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_SET }, + { on_pad_get, on_pad_set, SCRIPT_VAR_PAD_CLEAR }, + + { on_drive_get, on_drive_set, SCRIPT_VAR_DRIVE_MEDIATYPE }, + { on_drive_get, on_drive_set, SCRIPT_VAR_DRIVE_TRAY }, + + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_CHARSET }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FOLDER }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_TARGET }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILTER }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK1 }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK2 }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK3 }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK4 }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASK5 }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_PATH }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILENAME }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_EXTENSION }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_DRIVE_LETTER }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_TYPE }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_MASKINDEX }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILESIZE }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FILETIME }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_COUNT }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_SORT }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_POSITION }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_COMMAND }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_FIND }, + { on_explorer_get, on_explorer_set, SCRIPT_VAR_EXPLORER_COPIED }, + + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SOURCE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_PLAYING }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SAVED }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_COMMAND }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SELECT }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_REPEAT }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SPEED }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_MENU }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LANGUAGE_MENU }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LANGUAGE_AUDIO }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LANGUAGE_SUBTITLE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE_CHARSET }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE_WRAP }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_ANGLE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_VOLUME }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_BALANCE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_AUDIO_OFFSET }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_TIME }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_TITLE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_CHAPTER }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_NAME }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_ARTIST }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_AUDIO_INFO }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_VIDEO_INFO }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_AUDIO_STREAM }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_SUBTITLE_STREAM }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_LENGTH }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_NUM_TITLES }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_NUM_CHAPTERS }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_WIDTH }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_HEIGHT }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_FRAME_RATE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_COLOR_SPACE }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_DEBUG }, + { on_player_get, on_player_set, SCRIPT_VAR_PLAYER_ERROR }, + + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_COMMAND }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_AUDIOOUT }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_TVTYPE }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_TVSTANDARD }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_TVOUT }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVI }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_HQ_JPEG }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_HDD_SPEED }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_PARENTAL }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_MV }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_LANG_MENU }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_LANG_AUDIO }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_DVD_LANG_SPU }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_VOLUME }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_BALANCE }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_BRIGHTNESS }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_CONTRAST }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_SATURATION }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER1 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER2 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER3 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER4 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER5 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER6 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER7 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER8 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER9 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER10 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER11 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER12 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER13 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER14 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER15 }, + { on_settings_get, on_settings_set, SCRIPT_VAR_SETTINGS_USER16 }, + + { on_flash_get, on_flash_set, SCRIPT_VAR_FLASH_FILE }, + { on_flash_get, on_flash_set, SCRIPT_VAR_FLASH_ADDRESS }, + { on_flash_get, on_flash_set, SCRIPT_VAR_FLASH_PROGRESS }, + { NULL, NULL, -1, } +}; + diff --git a/src/script.cpp b/src/script.cpp new file mode 100644 index 0000000..615fbbe --- /dev/null +++ b/src/script.cpp @@ -0,0 +1,1998 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - script wrapper impl. + * \file script.cpp + * \author bombur + * \version 0.1 + * \date 12.10.2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#ifdef WIN32 +#define USE_MMSL_PARSER +#endif + + +#ifdef USE_MMSL_PARSER +#include +#endif + +#include +#include +#include + +ScriptParams *params = NULL; + +#include + +#ifdef USE_MMSL_PARSER +#include +#include +#else +#include +#include +#endif + +////////////////////////////////////////////////// + +static const StringPair tvtype_pairs[] = +{ + { "letterbox", 0 }, + { "panscan", 1 }, + { "wide", 2 }, + { "vcenter", 3 }, + { NULL, -1 }, +}; + +static const StringPair tvstandard_pairs[] = +{ + { "ntsc", 0 }, + { "pal", 1 }, + { "480p", 2 }, + { "576p", 3 }, + { "720p", 4 }, + { "1080i", 5 }, + { NULL, -1 }, +}; + +static const StringPair tvout_pairs[] = +{ + { "composite", 0 }, + { "ypbpr", 1 }, + { "rgb", 2 }, + { NULL, -1 }, +}; + +static const StringPair audioout_pairs[] = +{ + { "analog", 0 }, + { "digital", 1 }, + { NULL, -1 }, +}; + +static const StringPair hddspeed_pairs[] = +{ + { "fastest", 0 }, + { "limited", 1 }, + { "slow", 2 }, + { NULL, -1 }, +}; + +static const StringPair button_pairs[] = +{ + { "", FIP_KEY_NONE }, + { "power", FIP_KEY_POWER }, + { "eject", FIP_KEY_EJECT }, + { "one", FIP_KEY_ONE }, + { "two",FIP_KEY_TWO }, + { "three",FIP_KEY_THREE }, + { "four",FIP_KEY_FOUR }, + { "five",FIP_KEY_FIVE }, + { "six",FIP_KEY_SIX }, + { "seven",FIP_KEY_SEVEN }, + { "eight",FIP_KEY_EIGHT }, + { "nine",FIP_KEY_NINE }, + { "zero",FIP_KEY_ZERO }, + { "cancel",FIP_KEY_CANCEL }, + { "search",FIP_KEY_SEARCH }, + { "enter",FIP_KEY_ENTER }, + { "osd",FIP_KEY_OSD }, + { "subtitle",FIP_KEY_SUBTITLE }, + { "setup",FIP_KEY_SETUP }, + { "return",FIP_KEY_RETURN }, + { "title",FIP_KEY_TITLE }, + { "pn",FIP_KEY_PN }, + { "menu",FIP_KEY_MENU }, + { "ab",FIP_KEY_AB }, + { "repeat",FIP_KEY_REPEAT }, + { "up",FIP_KEY_UP }, + { "down",FIP_KEY_DOWN }, + { "left",FIP_KEY_LEFT }, + { "right",FIP_KEY_RIGHT }, + { "volume_down",FIP_KEY_VOLUME_DOWN }, + { "volume_up",FIP_KEY_VOLUME_UP }, + { "pause",FIP_KEY_PAUSE }, + { "rewind",FIP_KEY_REWIND }, + { "forward",FIP_KEY_FORWARD }, + { "prev",FIP_KEY_SKIP_PREV }, + { "next",FIP_KEY_SKIP_NEXT }, + { "play",FIP_KEY_PLAY }, + { "stop",FIP_KEY_STOP }, + { "slow",FIP_KEY_SLOW }, + { "audio",FIP_KEY_AUDIO }, + { "vmode",FIP_KEY_VMODE }, + { "mute",FIP_KEY_MUTE }, + { "zoom",FIP_KEY_ZOOM }, + { "program",FIP_KEY_PROGRAM }, + { "pbc",FIP_KEY_PBC }, + { "angle",FIP_KEY_ANGLE }, + + { "eject", FIP_KEY_FRONT_EJECT }, + { "pause",FIP_KEY_FRONT_PAUSE }, + { "rewind",FIP_KEY_FRONT_REWIND }, + { "forward",FIP_KEY_FRONT_FORWARD }, + { "prev",FIP_KEY_FRONT_SKIP_PREV }, + { "next",FIP_KEY_FRONT_SKIP_NEXT }, + { "play",FIP_KEY_FRONT_PLAY }, + { "stop",FIP_KEY_FRONT_STOP }, + { NULL, -1 }, +}; + +static const StringPair front_button_pairs2[] = +{ + { "", FIP_KEY_NONE }, + { "front_eject", FIP_KEY_FRONT_EJECT }, + { "front_pause",FIP_KEY_FRONT_PAUSE }, + { "front_rewind",FIP_KEY_FRONT_REWIND }, + { "front_forward",FIP_KEY_FRONT_FORWARD }, + { "front_prev",FIP_KEY_FRONT_SKIP_PREV }, + { "front_next",FIP_KEY_FRONT_SKIP_NEXT }, + { "front_play",FIP_KEY_FRONT_PLAY }, + { "front_stop",FIP_KEY_FRONT_STOP }, + { NULL, -1 }, +}; + +static const StringPair pad_special_pairs[] = +{ + { "play", FIP_SPECIAL_PLAY, }, + { "pause", FIP_SPECIAL_PAUSE, }, + { "mp3", FIP_SPECIAL_MP3, }, + { "dvd", FIP_SPECIAL_DVD, }, + { "s", FIP_SPECIAL_S, }, + { "v", FIP_SPECIAL_V, }, + { "cd", FIP_SPECIAL_CD, }, + { "dolby", FIP_SPECIAL_DOLBY, }, + { "dts", FIP_SPECIAL_DTS, }, + { "play_all", FIP_SPECIAL_ALL, }, + { "play_repeat", FIP_SPECIAL_REPEAT, }, + { "pbc", FIP_SPECIAL_PBC, }, + { "camera", FIP_SPECIAL_CAMERA, }, + { "colon1", FIP_SPECIAL_COLON1, }, + { "colon2", FIP_SPECIAL_COLON2, }, + { NULL, -1 }, +}; + +static const StringPair mediatype_pairs[] = +{ + { "none", CDROM_STATUS_NODISC }, + { "none", CDROM_STATUS_TRAYOPEN }, + { "dvd", CDROM_STATUS_HAS_DVD }, + { "iso", CDROM_STATUS_HAS_ISO }, + { "audio", CDROM_STATUS_HAS_AUDIO }, + { "mixed", CDROM_STATUS_HAS_MIXED }, + { NULL, -1 }, +}; + +static int GetScreenAdjustmentSetting(int idx) +{ + SETTING_SET which = SETTING_BRIGHTNESS_CONTRAST_SATURATION_PAL; + if (gui.GetTvStandard() == WINDOW_TVSTANDARD_NTSC) + which = SETTING_BRIGHTNESS_CONTRAST_SATURATION_NTSC; + DWORD v = (settings_get(which) >> (idx * 10)) & 1023; + return v; +} + +static void SetScreenAdjustmentSetting(int idx, int v) +{ + if (v < 0) v = 0; + if (v > 1000) v = 1000; + SETTING_SET which = SETTING_BRIGHTNESS_CONTRAST_SATURATION_PAL; + if (gui.GetTvStandard() == WINDOW_TVSTANDARD_NTSC) + which = SETTING_BRIGHTNESS_CONTRAST_SATURATION_NTSC; + DWORD d = settings_get(which) & ~(1023 << (idx * 10)); + settings_set(which, d | ((v & 1023) << (idx * 10))); +} + +////////////////////////////////////////////////// + +int script_init() +{ + int i; + int buflen; + BYTE *buf = NULL; + + params = new ScriptParams(); + tmpit = new Item(); + + const char *mmso_filename = "mmsl/startup.mmso"; + +#ifdef USE_MMSL_PARSER + mmsl_parser = new MmslParser(); + + for (i = 0; script_vars[i].name != NULL; i++) + { + mmsl_parser->RegisterVariable(script_vars[i].name, script_vars[i].ID); + } + + for (i = 0; script_objects[i].name != NULL; i++) + { + mmsl_parser->RegisterObject(script_objects[i].name, script_objects[i].ID); + } + + for (i = 0; script_object_vars[i].name != NULL; i++) + { + mmsl_parser->RegisterObjectVariable(script_object_vars[i].obj_ID, + script_object_vars[i].name, script_object_vars[i].ID); + } + if (!mmsl_parser->ParseFile("startup.mmsl")) + { + msg_error("Cannot open/parse script file!\n"); + } + buf = mmsl_parser->Save(&buflen); + + SPSafeDelete(mmsl_parser); + + if (buf != NULL) + { + mmso_save(mmso_filename, buf, buflen); + SPSafeFree(buf); + } +#endif + + mmsl = new Mmsl(); + msg("Loading MMSO '%s'\n", mmso_filename); + buf = mmso_load(mmso_filename, &buflen); + + if (buf != NULL) + { + if (!mmsl->Load(buf, buflen)) + { + msg("Cannot init main script!\n"); + } + SPSafeFree(buf); + + for (i = 0; script_vars[i].ID >= 0; i++) + { + if (mmsl->BindVariable(script_vars[i].ID, script_vars[i].Get, script_vars[i].Set) < 0) + msg("Script: Cannot bind variable #%d\n", script_vars[i].ID); + } + + for (i = 0; script_objects[i].ID >= 0; i++) + { + if (mmsl->BindObject(script_objects[i].ID, script_objects[i].Create, script_objects[i].Delete, NULL) < 0) + msg("Script: Cannot bind object #%d\n", script_objects[i].ID); + } + + for (i = 0; script_object_vars[i].ID >= 0; i++) + { + if (mmsl->BindObjectVariable(script_object_vars[i].obj_ID, script_object_vars[i].ID, script_object_vars[i].Get, + script_object_vars[i].Set, NULL) < 0) + msg("Script: Cannot bind object's #%d variable #%d\n", + script_object_vars[i].obj_ID, script_object_vars[i].ID); + } + } else + { + msg("Cannot load the main MMSO script!\n"); + } + + msg("Mmsl: Starting...\n"); + + //mmsl->Dump(); + + SPSafeFree(buf); + + struct timeval tv; + gettimeofday(&tv, NULL); + params->start_sec = (int)tv.tv_sec; + params->curtime = params->old_curtime = tv.tv_usec / 1000; + + params->fw_ver.Printf("%s-%d.%d (" __DATE__ ")", SP_NAME, SP_VERSION / 100, SP_VERSION % 100); + params->mmsl_ver = MMSL_VERSION; + + return 0; +} + +int script_deinit() +{ + stop_all(); + cdda_close(); + + SPSafeDelete(params); + SPSafeDelete(tmpit); + + return 0; +} + +int script_update(bool gfx_only) +{ + if (!params) + return 0; + + struct timeval tv; + gettimeofday(&tv, NULL); + + params->curtime = (int)((tv.tv_sec - params->start_sec) * 1000 + tv.tv_usec / 1000); + + // check if we need to call elapsed timers: +restart: + ScriptTimerObject *cur = params->timed_objs.GetFirst(); + while (cur != NULL) + { + // check timer value + Window *win = (Window *)cur->obj; + if (win != NULL) + { + // check if object timer elapsed + if (!gfx_only && cur->type == SCRIPT_OBJECT_TIMER) + { + if (win->timer > 0 && win->timer < params->curtime) + { + win->timer = 0; + mmsl->UpdateObjectVariable(win, cur->var_ID); + if (win->timerobj == NULL || win->timer != 0) + goto restart; + } + } + // some objects may require updates + else if (cur->type == SCRIPT_OBJECT_UPDATE) + { + win->Update(params->curtime); + } + } + cur = cur->next; + } + + if (gfx_only) + return 0; + + // update other stuff + + if (params->need_to_toggle_tray) + { + if (toggle_tray()) + params->need_to_toggle_tray = FALSE; + } + + if (params->flash_progress >= 0 && params->flash_progress < 100) + { + params->flash_p = flash_cycle(); + if (params->flash_p != params->flash_progress || params->flash_p < 0) + { + params->flash_progress = params->flash_p; + + msg("FLASH %d%%\n", params->flash_progress); + if (params->flash_progress == 100) + { + msg("FLASH OK!\n"); + } + mmsl->UpdateVariable(SCRIPT_VAR_FLASH_PROGRESS); + } + + // do nothing more + return 0; + } + + if (params->player_do_command) + { + params->player_do_command = false; + player_do_command(); + } + + if (params->dvdplaying) + { + if (dvd_player_loop() == 1) + { + dvd_stop(); + params->dvdplaying = FALSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + module_unload("dvd"); + } + } +#ifdef EXTERNAL_PLAYER + if (params->fileplaying) + { + if (player_info_loop() == 1) + { + player_stop(); + params->fileplaying = FALSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + } +#endif +#ifdef INTERNAL_VIDEO_PLAYER + if (params->videoplaying) + { + if (video_loop() == 1) + { + video_stop(); + params->videoplaying = FALSE; + params->speed = MPEG_SPEED_STOP; + if (mmsl != NULL) + { + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + } + } +#endif +#ifdef INTERNAL_AUDIO_PLAYER + if (params->audioplaying) + { + if (audio_loop() == 1) + { + audio_delete_filelist(); + audio_stop(); + params->audioplaying = FALSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + } +#endif + if (params->cddaplaying) + { + if (cdda_player_loop() == 1) + { + cdda_stop(); + params->cddaplaying = FALSE; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_PLAYING); + } + } + + if (params->waitinfo) + { + if (player_id3_loop() == 1) + { + params->waitinfo = FALSE; + } + } + + return 0; +} + +int script_get_time(struct timeval *tv) +{ + if (tv == NULL) + return params->curtime; + else + return (int)((tv->tv_sec - params->start_sec) * 1000 + tv->tv_usec / 1000 - params->curtime); +} + +void script_skiptime() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + int next_time = script_get_time(&tv); + params->start_sec += next_time / 1000; +} + +bool script_update_variable(int ID) +{ + return mmsl->UpdateVariable(ID) != 0; +} + +/////////////////////////////////////////////////////// + +void script_drive_callback(CDROM_STATUS status) +{ + bool status_changed = (status != params->status); + if ((status == CDROM_STATUS_TRAYOPEN && params->status != CDROM_STATUS_TRAYOPEN) || + (params->status == CDROM_STATUS_TRAYOPEN && status != CDROM_STATUS_TRAYOPEN) || + (params->status == CDROM_STATUS_UNKNOWN && status != CDROM_STATUS_UNKNOWN)) + { + params->status = status; +#if 1 + msg("* DRIVE.TRAY = %d\n", params->status); +#endif + mmsl->UpdateVariable(SCRIPT_VAR_DRIVE_TRAY); + } + if (status_changed) + { + params->status = status; +#if 1 + msg("* DRIVE.MEDIATYPE = %d\n", params->status); +#endif + mmsl->UpdateVariable(SCRIPT_VAR_DRIVE_MEDIATYPE); + } +} + +void script_set_key(int key) +{ + params->key = key; + + for (int i = 0; button_pairs[i].str != NULL; i++) + { + if (button_pairs[i].value == key) + { + params->keystr = button_pairs[i].str; + break; + } + } +} + +void script_key_callback(int key) +{ + if (params->flash_progress < 0) + { + msg("****** button %s ******\n", get_button_string(key)); + + script_set_key(key); + mmsl->UpdateVariable(SCRIPT_VAR_PAD_KEY); + } +} + +void script_time_callback(int secs) +{ + params->info.cur_time = secs; + params->info.real_cur_time = secs; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_TIME); +} + +void script_totaltime_callback(int secs) +{ + params->info.length = secs; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_LENGTH); +} + +void script_dvd_menu_callback(bool ) +{ + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_MENU); +} + +void script_speed_callback(int speed) +{ + if (speed >= 0) + params->speed = (MPEG_SPEED_TYPE)speed; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SPEED); +} + +void script_dvd_chapter_callback(int chapter) +{ + params->info.real_cur_chapter = params->info.cur_chapter = chapter; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_CHAPTER); +} + +void script_dvd_title_callback(int title, int numchapters) +{ + params->info.real_cur_title = params->info.cur_title = title; + params->info.num_chapters = numchapters; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_TITLE); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_NUM_CHAPTERS); +} + +void script_player_saved_callback() +{ + if (mmsl != NULL) + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SAVED); +} + +void script_cdda_track_callback(int track) +{ + params->info.real_cur_title = params->info.cur_title = track; + params->info.num_chapters = 0; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_TITLE); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_NUM_CHAPTERS); +} + +void script_name_callback(const SPString & n) +{ + params->info.name = n; + msg("Title: %s\n", *params->info.name); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_NAME); +} + +void script_artist_callback(const SPString & a) +{ + params->info.artist = a; + msg("Artist: %s\n", *params->info.artist); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ARTIST); +} + +void script_audio_info_callback(const SPString & ai) +{ + params->info.audio_info = ai; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_AUDIO_INFO); +} + +void script_video_info_callback(const SPString & vi) +{ + params->info.video_info = vi; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_VIDEO_INFO); +} + +void script_player_subtitle_callback(const char *s) +{ + params->info.subtitle = s; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_SUBTITLE); +} + +void script_error_callback(SCRIPT_ERROR_CODE err) +{ + switch (err) + { + case SCRIPT_ERROR_INVALID: + params->player_error = "invalid"; + break; + case SCRIPT_ERROR_BAD_AUDIO: + params->player_error = "badaudio"; + break; + case SCRIPT_ERROR_BAD_CODEC: + params->player_error = "badvideo"; + break; + case SCRIPT_ERROR_QPEL: + params->player_error = "qpel"; + break; + case SCRIPT_ERROR_GMC: + params->player_error = "gmc"; + break; + case SCRIPT_ERROR_WAIT: + params->player_error = "wait"; + break; + case SCRIPT_ERROR_CORRUPTED: + params->player_error = "corrupted"; + break; + default: + return; + } + + if (params->player_type == PLAYER_TYPE_DVD) + { + if (dvd_getdebug()) + msg("DVD Warning!: %s!\n", *params->player_error); + } +#ifdef EXTERNAL_PLAYER + else if (params->player_type == PLAYER_TYPE_FILE) + { + if (player_getdebug()) + msg("Player Warning!: %s!\n", *params->player_error); + } +#endif + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_ERROR); +} + +void script_framesize_callback(int width, int height) +{ + if ((params->player_type == PLAYER_TYPE_DVD && dvd_getdebug()) +#ifdef EXTERNAL_PLAYER + || (params->player_type == PLAYER_TYPE_FILE && player_getdebug()) +#endif + ) + { + msg("* FRAME = %dx%d\n", width, height); + } + params->info.width = width; + params->info.height = height; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_WIDTH); + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_HEIGHT); +} + +void script_framerate_callback(int frame_rate) +{ + if ((params->player_type == PLAYER_TYPE_DVD && dvd_getdebug()) +#ifdef EXTERNAL_PLAYER + || (params->player_type == PLAYER_TYPE_FILE && player_getdebug()) +#endif + ) + { + msg("* FRAME_RATE = %d\n", frame_rate); + } + params->info.frame_rate = frame_rate; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_FRAME_RATE); +} + +void script_zoom_scroll_reset_callback() +{ + params->hscale = 0; + params->vscale = 0; + params->hscroll = 0; + params->vscroll = 0; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_HZOOM); + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_VZOOM); + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_HSCROLL); + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_VSCROLL); +} + +void script_colorspace_callback(int clrs) +{ + if ((params->player_type == PLAYER_TYPE_DVD && dvd_getdebug()) +#ifdef EXTERNAL_PLAYER + || (params->player_type == PLAYER_TYPE_FILE && player_getdebug()) +#endif + ) + { + msg("* COLORSPACE = %d\n", clrs); + } + params->info.clrs = (PLAYER_COLOR_SPACE)clrs; + mmsl->UpdateVariable(SCRIPT_VAR_PLAYER_COLOR_SPACE); +} + +void script_audio_lang_callback(const char *lang) +{ + params->info.dvd_audio_lang = lang; +} + +void script_spu_lang_callback(const char *lang) +{ + params->info.spu_lang = lang; +} + +void script_audio_stream_callback(int stream) +{ + params->info.audio_stream = stream; +} + +void script_spu_stream_callback(int stream) +{ + params->info.spu_stream = stream; +} + +///////////////////////////////////////////////////// + +bool stop_all() +{ + if (params->dvdplaying) + player_dvd_command("stop"); +#ifdef EXTERNAL_PLAYER + if (params->fileplaying) + player_file_command("stop"); +#endif +#ifdef INTERNAL_VIDEO_PLAYER + if (params->videoplaying) + { + return player_video_command("stop"); + } +#endif +#ifdef INTERNAL_AUDIO_PLAYER + if (params->audioplaying) + player_audio_command("stop"); +#endif + if (params->cddaplaying) + player_cdda_command("stop"); + return true; +} + + +bool toggle_tray() +{ + static int in_toggle = 0; + if (in_toggle) + return false; + + in_toggle = 1; + gui.Update(); + + BOOL force_update = FALSE; + CDROM_STATUS status = cdrom_getstatus(&force_update); + bool eject = (status != CDROM_STATUS_TRAYOPEN); + + if (eject) + { + if (!stop_all()) + { + params->need_to_toggle_tray = TRUE; + return false; + } + + // media is being changed - so close CDDA data + cdda_close(); + + // clear all cached lists and playlists + script_explorer_reset(); + + status = CDROM_STATUS_TRAYOPEN; + params->require_next_status = CDROM_STATUS_UNKNOWN; + } + + if (force_update) + params->status = CDROM_STATUS_UNKNOWN; + + script_drive_callback(status); + + msg("* toggle_tray: eject = %d (%d)!!!\n", eject, params->status); + cdrom_eject(eject); + + params->wasejected = TRUE; // to restore fip + in_toggle = 0; + return true; +} + +void disc_changed(CDROM_STATUS st) +{ + if (st != CDROM_STATUS_CURRENT) + params->status = st; + if (is_playing()) + return; + BOOL force_update = FALSE; + CDROM_STATUS status = cdrom_getstatus(&force_update); + + if ((status & CDROM_STATUS_HASDISC) == CDROM_STATUS_HASDISC + && params->require_next_status != CDROM_STATUS_UNKNOWN) + status = params->require_next_status; + + if (params->status != status || force_update) + { + if (status == CDROM_STATUS_NODISC || status == CDROM_STATUS_TRAYOPEN) + params->require_next_status = CDROM_STATUS_UNKNOWN; + if (force_update) + params->status = CDROM_STATUS_UNKNOWN; + params->wasejected = FALSE; + script_drive_callback(status); + } +} + +///////////////////////////////////////////////////////// + +void player_halt() +{ + for (;;) + { + khwl_osd_update(); + } +} + +bool player_turn_onoff(bool on) +{ + // we cannot combine instructions because of different order + if (!on) // OFF + { + // close CD-ROM tray and prepare for shutdown + BOOL force_status = FALSE; + CDROM_STATUS status = cdrom_getstatus(&force_status); + if (status == CDROM_STATUS_TRAYOPEN || !cdrom_isready()) + { + fip_clear(); + fip_write_string("CLOSE"); + cdrom_eject(false); + for (int tries = 0; tries < 80; tries++) + { + //msg("try=%d [status=%d]\n", tries, status); + //gui_update(); + + usleep(250000); + if (cdrom_isready()) + { + status = cdrom_getstatus(&force_status); + if (status != CDROM_STATUS_TRAYOPEN && status != CDROM_STATUS_UNKNOWN) + break; + } + } + // if we stop CDROM before it detects a disc, we won't start it again... + // I don't know a reliable way to check if we can stop - so wait 3 secs... + //status = cdrom_getstatus(); + //if (status != CDROM_STATUS_TRAYOPEN && status != CDROM_STATUS_NODISC) + // usleep(3500000); + } + + params->status = CDROM_STATUS_NODISC; + mmsl->UpdateVariable(SCRIPT_VAR_DRIVE_TRAY); + mmsl->UpdateVariable(SCRIPT_VAR_DRIVE_MEDIATYPE); + + gui.Clear(); + khwl_display_clear(); + fip_clear(); + + gui.SwitchDisplay(false); + khwl_osd_update(); + + cdrom_switch(FALSE); + khwl_ideswitch(FALSE); + } + else // ON + { + fip_write_string("LoAd"); + khwl_ideswitch(TRUE); + + usleep(1000000); + + gui.SwitchDisplay(true); + + usleep(1000000); + + khwl_set_window_frame(params->bigbackleft, params->bigbacktop, params->bigbackright, params->bigbackbottom); + gui.SetBackground(params->bigback); + + usleep(1000000); + + cdrom_switch(TRUE); + } + return true; +} + +bool script_next_vmode() +{ + int vout_max = settings_getmax(SETTING_TVOUT); + int vstd_max = 1;//settings_getmax(SETTING_TVSTANDARD); + int vout = gui.GetTvOut(); + int vstd = gui.GetTvStandard(); + if (vstd >= WINDOW_TVSTANDARD_480P) + { + vout = 0; + vstd = 0; + } + else if (++vout > vout_max) + { + vout = 0; + if (++vstd > vstd_max) + { + vstd = WINDOW_TVSTANDARD_480P; + vout = WINDOW_TVOUT_YPBPR; + } + } + + gui.SetTv((WINDOW_TVOUT)vout, (WINDOW_TVSTANDARD)vstd); + if (!params->dvdplaying && !params->videoplaying) + { + khwl_setvideomode(KHWL_VIDEOMODE_NONE, TRUE); + khwl_set_window_frame(params->bigbackleft, params->bigbacktop, params->bigbackright, params->bigbackbottom); + gui.SetBackground(params->bigback); + } + const char *vstds[] = { "NTSC", "PAL", "480P", "576P", "720P", "1080I" }; + const char *vouts[] = { "C/S-Video", "C/YPbPr", "C/RGB" }; + msg("VMODE set = %s %s\n", vstds[vstd], vouts[vout]); + + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_TVSTANDARD); + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_TVOUT); + return true; +} + +//////////////////////////////////////////////////////////////////////// + +void on_kernel_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + switch (var_id) + { + case SCRIPT_VAR_KERNEL_POWER: + var->Set(1); + break; + case SCRIPT_VAR_KERNEL_PRINT: + var->Set(""); + break; + case SCRIPT_VAR_KERNEL_FIRMWARE_VERSION: + var->Set(params->fw_ver); + break; + case SCRIPT_VAR_KERNEL_MMSL_VERSION: + var->Set(params->mmsl_ver); + break; + case SCRIPT_VAR_KERNEL_MMSL_ERRORS: + { + const char *errs[] = { "all", "general", "critical", "none" }; + var->Set(errs[params->errors]); + } + break; + case SCRIPT_VAR_KERNEL_RUN: + var->Set(""); + break; + case SCRIPT_VAR_KERNEL_RANDOM: + var->Set(rand() % 32768); + break; + case SCRIPT_VAR_KERNEL_FREQUENCY: + var->Set(khwl_getfrequency()); + break; + case SCRIPT_VAR_KERNEL_CHIP: + var->Set(khwl_gethw()); + break; + case SCRIPT_VAR_KERNEL_FREE_MEMORY: + { + struct sysinfo si; + sysinfo(&si); + var->Set(si.freeram); + } + break; + case SCRIPT_VAR_KERNEL_FLASH_MEMORY: + { + var->Set(flash_get_memory_size()); + } + break; + } +} + +void on_kernel_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + switch (var_id) + { + case SCRIPT_VAR_KERNEL_POWER: + if (var->GetInteger() == 2) + player_halt(); + else + { + extern bool is_sleeping, do_sleep, need_to_stop; + is_sleeping = var->GetInteger() == 0; + do_sleep = 1; + if (is_sleeping) + { + if (!stop_all()) + need_to_stop = true; + } + //player_turn_onoff(var->GetInteger() != 0); + } + break; + case SCRIPT_VAR_KERNEL_PRINT: + msg("User: %s\n", *var->GetString()); + break; + case SCRIPT_VAR_KERNEL_MMSL_ERRORS: + { + SPString str = var->GetString(); + if (str.CompareNoCase("none") == 0) + { + params->errors = SCRIPT_ERRORS_NONE; + msg_set_filter(MSG_FILTER_NONE); + } + else if (str.CompareNoCase("general") == 0) + { + params->errors = SCRIPT_ERRORS_GENERAL; + msg_set_filter(MSG_FILTER_ERROR); + } + else if (str.CompareNoCase("critical") == 0) + { + params->errors = SCRIPT_ERRORS_CRITICAL; + msg_set_filter(MSG_FILTER_CRITICAL); + } + else + { + params->errors = SCRIPT_ERRORS_ALL; + msg_set_filter(MSG_FILTER_ALL); + } + } + break; + case SCRIPT_VAR_KERNEL_RUN: + { + SPString str = var->GetString(); + str.TrimLeft(); + str.TrimRight(); + char *args[20]; + args[0] = &str[0]; + bool in_quotes = false; + int curarg = 0; + for (int i = 0; i < str.GetLength(); i++) + { + if (str[i] == '\"') + { + in_quotes = !in_quotes; + } + if (str[i] == ' ' && !in_quotes) + { + str[i] = '\0'; + args[++curarg] = &str[i + 1]; + if (curarg >= 20) + break; + } + } + args[++curarg] = NULL; + if (vfork() == 0) + { + exec_file(args[0], (const char **)args); + } + } + break; + case SCRIPT_VAR_KERNEL_FREQUENCY: + khwl_setfrequency(var->GetInteger()); + break; + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_screen_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_SCREEN_SWITCH: + var->Set(gui.IsDisplaySwitchedOn()); + break; + case SCRIPT_VAR_SCREEN_UPDATE: + var->Set(gui.IsUpdateEnabled()); + break; + case SCRIPT_VAR_SCREEN_TVSTANDARD: + StringPair::Set(var, tvstandard_pairs, gui.GetTvStandard()); + break; + case SCRIPT_VAR_SCREEN_TVOUT: + StringPair::Set(var, tvout_pairs, gui.GetTvOut()); + break; + case SCRIPT_VAR_SCREEN_FULLSCREEN: + var->Set(gui.IsOsdFullscreen()); + break; + case SCRIPT_VAR_SCREEN_LEFT: + var->Set(gui.left); + break; + case SCRIPT_VAR_SCREEN_TOP: + var->Set(gui.top); + break; + case SCRIPT_VAR_SCREEN_RIGHT: + var->Set(gui.right); + break; + case SCRIPT_VAR_SCREEN_BOTTOM: + var->Set(gui.bottom); + break; + case SCRIPT_VAR_SCREEN_PALETTE: + var->Set(params->pal); + break; + case SCRIPT_VAR_SCREEN_PALIDX: + var->Set(params->pal_idx); + break; + case SCRIPT_VAR_SCREEN_PALALPHA: + { + BYTE *p = gui.GetPaletteEntry(params->pal_idx); + var->Set((p != NULL) ? p[0] : 0); + } + break; + case SCRIPT_VAR_SCREEN_PALCOLOR: + { + BYTE *p = gui.GetPaletteEntry(params->pal_idx); + BYTE r, g, b; + khwl_tvyuvtovgargb(p[1], p[2], p[3], &r, &g, &b); + var->Set((p != NULL) ? ((r << 16) | (g << 8) | b) : 0); + } + break; + case SCRIPT_VAR_SCREEN_FONT: + var->Set(params->font); + break; + case SCRIPT_VAR_SCREEN_COLOR: + var->Set(gui.GetColor()); + break; + case SCRIPT_VAR_SCREEN_BACKCOLOR: + var->Set(gui.GetBkColor()); + break; + case SCRIPT_VAR_SCREEN_TRCOLOR: + var->Set(gui.GetTransparentColor()); + break; + case SCRIPT_VAR_SCREEN_HALIGN: + { + const char *ha[] = { "left", "center", "right" }; + var->Set(ha[gui.GetHAlign()]); + } + break; + case SCRIPT_VAR_SCREEN_VALIGN: + { + const char *ha[] = { "top", "center", "bottom" }; + var->Set(ha[gui.GetVAlign()]); + } + break; + case SCRIPT_VAR_SCREEN_BACK: + var->Set(params->back); + break; + case SCRIPT_VAR_SCREEN_BACK_LEFT: + var->Set(params->backleft); + break; + case SCRIPT_VAR_SCREEN_BACK_TOP: + var->Set(params->backtop); + break; + case SCRIPT_VAR_SCREEN_BACK_RIGHT: + var->Set(params->backright); + break; + case SCRIPT_VAR_SCREEN_BACK_BOTTOM: + var->Set(params->backbottom); + break; + case SCRIPT_VAR_SCREEN_PRELOAD: + var->Set(""); + break; + case SCRIPT_VAR_SCREEN_HZOOM: + var->Set(params->hscale); + break; + case SCRIPT_VAR_SCREEN_VZOOM: + var->Set(params->vscale); + break; + case SCRIPT_VAR_SCREEN_ROTATE: + var->Set(params->rotate * 90); + break; + case SCRIPT_VAR_SCREEN_HSCROLL: + var->Set(params->hscroll); + break; + case SCRIPT_VAR_SCREEN_VSCROLL: + var->Set(params->vscroll); + break; + case SCRIPT_VAR_SCREEN_BRIGHTNESS: + { + int val; + khwl_get_display_settings(&val, NULL, NULL); + var->Set(val); + } + break; + case SCRIPT_VAR_SCREEN_CONTRAST: + { + int val; + khwl_get_display_settings(NULL, &val, NULL); + var->Set(val); + } + break; + case SCRIPT_VAR_SCREEN_SATURATION: + { + int val; + khwl_get_display_settings(NULL, NULL, &val); + var->Set(val); + } + break; + } +} + +void on_screen_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_SCREEN_SWITCH: + if (var->GetString().CompareNoCase("next") == 0) + script_next_vmode(); + else + { + bool onoff = var->GetInteger() != 0; + gui.SwitchDisplay(onoff); + if (onoff) + { + khwl_set_window_frame(params->bigbackleft, params->bigbacktop, params->bigbackright, params->bigbackbottom); + gui.SetBackground(params->bigback); + } + } + break; + case SCRIPT_VAR_SCREEN_UPDATE: + { + bool upd = false; + if (var->GetString().CompareNoCase("now") == 0) + { + upd = true; + gui.Update(); + } + else + { + upd = var->GetInteger() != 0; + gui.UpdateEnable(upd); + } + if (upd && params->need_setwindow) + { + khwl_set_window(-1, -1, -1, -1, params->hscale, params->vscale, params->hscroll, params->vscroll); + params->need_setwindow = false; + } + } + break; + case SCRIPT_VAR_SCREEN_TVSTANDARD: + gui.SetTv(WINDOW_TVOUT_UNKNOWN, (WINDOW_TVSTANDARD)StringPair::Get(var, tvstandard_pairs, -1)); + khwl_set_window_frame(params->bigbackleft, params->bigbacktop, params->bigbackright, params->bigbackbottom); + gui.SetBackground(params->bigback); + break; + case SCRIPT_VAR_SCREEN_TVOUT: + gui.SetTv((WINDOW_TVOUT)StringPair::Get(var, tvout_pairs, -1), WINDOW_TVSTANDARD_UNKNOWN); + khwl_set_window_frame(params->bigbackleft, params->bigbacktop, params->bigbackright, params->bigbackbottom); + gui.SetBackground(params->bigback); + break; + case SCRIPT_VAR_SCREEN_FULLSCREEN: + gui.SetOsdFullscreen(var->GetInteger() != 0); + break; + case SCRIPT_VAR_SCREEN_PALETTE: + { + SPString pal = var->GetString(); + if (gui.LoadPalette(pal)) + { + params->pal = pal; + console->UpdateFont(); + } + } + break; + case SCRIPT_VAR_SCREEN_PALIDX: + params->pal_idx = var->GetInteger(); + break; + case SCRIPT_VAR_SCREEN_PALALPHA: + { + BYTE *p = gui.GetPaletteEntry(params->pal_idx); + if (p != NULL) + p[0] = (BYTE)var->GetInteger(); + } + break; + case SCRIPT_VAR_SCREEN_PALCOLOR: + { + BYTE *p = gui.GetPaletteEntry(params->pal_idx); + if (p != NULL) + { + SPString str = var->GetString(); + str.TrimLeft(); + BYTE r, g, b; + if (str.GetLength() >= 7 && str[0] == '#') + { + r = (BYTE)(hex2char(str[1]) * 16 + hex2char(str[2])); + g = (BYTE)(hex2char(str[3]) * 16 + hex2char(str[4])); + b = (BYTE)(hex2char(str[5]) * 16 + hex2char(str[6])); + } else + { + int c24 = var->GetInteger(); + r = (BYTE)((c24 >> 16) & 0xff); + g = (BYTE)((c24 >> 8) & 0xff); + b = (BYTE)((c24) & 0xff); + } + khwl_vgargbtotvyuv(r, g, b, p + 1, p + 2, p + 3); + } + } + break; + case SCRIPT_VAR_SCREEN_FONT: + params->font = var->GetString(); + break; + case SCRIPT_VAR_SCREEN_COLOR: + gui.SetColor(var->GetInteger()); + break; + case SCRIPT_VAR_SCREEN_BACKCOLOR: + gui.SetBkColor(var->GetInteger()); + break; + case SCRIPT_VAR_SCREEN_TRCOLOR: + gui.SetTransparentColor(var->GetInteger()); + console->UpdateFont(); + break; + case SCRIPT_VAR_SCREEN_HALIGN: + { + SPString str = var->GetString(); + if (str.CompareNoCase("center") == 0) + gui.SetHAlign(WINDOW_ALIGN_CENTER); + else if (str.CompareNoCase("right") == 0) + gui.SetHAlign(WINDOW_ALIGN_RIGHT); + else + gui.SetHAlign(WINDOW_ALIGN_LEFT); + } + break; + case SCRIPT_VAR_SCREEN_VALIGN: + { + SPString str = var->GetString(); + if (str.CompareNoCase("center") == 0) + gui.SetHAlign(WINDOW_ALIGN_CENTER); + else if (str.CompareNoCase("right") == 0) + gui.SetHAlign(WINDOW_ALIGN_RIGHT); + else + gui.SetHAlign(WINDOW_ALIGN_LEFT); + } + break; + case SCRIPT_VAR_SCREEN_BACK: + { + SPString back = var->GetString(); + if (back.CompareNoCase(params->back) != 0) + { + params->back = back; + params->hscale = 100; + params->vscale = 100; + params->hscroll = 0; + params->vscroll = 0; + params->rotate = -1; + + int bw = params->backright - params->backleft + 1; + int bh = params->backbottom - params->backtop + 1; + if (bw >= params->bigback_width || bh >= params->bigback_height || back.GetLength() == 0) + { + params->bigback_width = bw; + params->bigback_height = bh; + params->bigback = params->back; + params->bigbackleft = params->backleft; + params->bigbacktop = params->backtop; + params->bigbackright = params->backright; + params->bigbackbottom = params->backbottom; + } + + khwl_set_window_frame(params->backleft, params->backtop, params->backright, params->backbottom); + + int old_rotate = params->rotate; + if (!gui.SetBackground(params->back, params->hscale, params->vscale, + params->hscroll, params->vscroll, ¶ms->rotate)) + { + params->back = ""; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK); + if (params->rotate != old_rotate) + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_ROTATE); + } + + params->need_setwindow = false; + } + } + break; + case SCRIPT_VAR_SCREEN_BACK_LEFT: + params->backleft = var->GetInteger(); + if (params->backleft < 0) + { + params->backleft = 0; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_LEFT); + } + if (params->backleft > 719) + { + params->backleft = 719; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_LEFT); + } + break; + case SCRIPT_VAR_SCREEN_BACK_TOP: + params->backtop = var->GetInteger(); + if (params->backtop < 0) + { + params->backtop = 0; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_TOP); + } + if (params->backtop > 479) + { + params->backtop = 479; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_TOP); + } + break; + case SCRIPT_VAR_SCREEN_BACK_RIGHT: + params->backright = var->GetInteger(); + if (params->backright < 0) + { + params->backright = 0; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_RIGHT); + } + if (params->backright > 719) + { + params->backright = 719; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_RIGHT); + } + break; + case SCRIPT_VAR_SCREEN_BACK_BOTTOM: + params->backbottom = var->GetInteger(); + if (params->backbottom < 0) + { + params->backbottom = 0; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_BOTTOM); + } + if (params->backbottom > 479) + { + params->backbottom = 479; + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_BACK_BOTTOM); + } + break; + case SCRIPT_VAR_SCREEN_PRELOAD: + { + SPString fname = var->GetString(); + if (fname == "") + { + guiimg->ClearImageData(); +#if 0 // !!!!!!!!!!!!!!!!!!! + guifonts->ClearFontData(); +#endif + } + else + { + if (fname.FindNoCase(".fon") > 0 || fname.FindNoCase(".fnt") > 0) + guifonts->GetFont(fname); + else if (fname.FindNoCase(".gif") > 0) + guiimg->GetImageData(fname); + } + } + break; + case SCRIPT_VAR_SCREEN_HZOOM: + { + SPString z = var->GetString(); + if (z.CompareNoCase("in") == 0) + params->hscale += 5; + else if (z.CompareNoCase("out") == 0) + params->hscale -= 5; + else + params->hscale = var->GetInteger(); + if (params->hscale < 25) + params->hscale = 25; + if (params->hscale > 400) + params->hscale = 400; + params->hscroll = 0; + params->vscroll = 0; + if (gui.IsUpdateEnabled()) + { + khwl_set_window(-1, -1, -1, -1, params->hscale, params->vscale, params->hscroll, params->vscroll); + params->need_setwindow = false; + } + else + params->need_setwindow = true; + } + break; + case SCRIPT_VAR_SCREEN_VZOOM: + { + SPString z = var->GetString(); + if (z.CompareNoCase("in") == 0) + params->vscale += 5; + else if (z.CompareNoCase("out") == 0) + params->vscale -= 5; + else + params->vscale = var->GetInteger(); + if (params->vscale < 25) + params->vscale = 25; + if (params->vscale > 400) + params->vscale = 400; + params->hscroll = 0; + params->vscroll = 0; + if (gui.IsUpdateEnabled()) + { + khwl_set_window(-1, -1, -1, -1, params->hscale, params->vscale, params->hscroll, params->vscroll); + params->need_setwindow = false; + } + else + params->need_setwindow = true; + } + break; + case SCRIPT_VAR_SCREEN_ROTATE: + { + if (var->GetString().CompareNoCase("auto") == 0) + params->rotate = -1; + else + { + params->rotate = var->GetInteger() / 90; + if (params->rotate < 0) + params->rotate = (-params->rotate/4+1)*4+params->rotate; + params->rotate %= 4; + } + params->hscroll = 0; + params->vscroll = 0; + int old_rotate = params->rotate; + gui.SetBackground(params->back, params->hscale, params->vscale, params->hscroll, params->vscroll, ¶ms->rotate); + if (params->rotate != old_rotate) + mmsl->UpdateVariable(SCRIPT_VAR_SCREEN_ROTATE); + } + break; + case SCRIPT_VAR_SCREEN_HSCROLL: + params->hscroll = var->GetInteger(); + if (gui.IsUpdateEnabled()) + { + khwl_set_window(-1, -1, -1, -1, params->hscale, params->vscale, params->hscroll, params->vscroll); + params->need_setwindow = false; + } + else + params->need_setwindow = true; + break; + case SCRIPT_VAR_SCREEN_VSCROLL: + params->vscroll = var->GetInteger(); + if (gui.IsUpdateEnabled()) + { + khwl_set_window(-1, -1, -1, -1, params->hscale, params->vscale, params->hscroll, params->vscroll); + params->need_setwindow = false; + } + else + params->need_setwindow = true; + break; + case SCRIPT_VAR_SCREEN_BRIGHTNESS: + khwl_set_display_settings(var->GetInteger(), -1, -1); + break; + case SCRIPT_VAR_SCREEN_CONTRAST: + khwl_set_display_settings(-1, var->GetInteger(), -1); + break; + case SCRIPT_VAR_SCREEN_SATURATION: + khwl_set_display_settings(-1, -1, var->GetInteger()); + break; + } +} + +//////////////////////////////////////////////////////////////////////// + + +const char *get_button_string(int but) +{ + static const StringPair *pairs[2] = { front_button_pairs2, button_pairs }; + for (int t = 0; t < 2; t++) + { + for (int i = 0; pairs[t][i].str != NULL; i++) + { + if (pairs[t][i].value == but) + return pairs[t][i].str; + } + } + return "?"; +} + +void on_pad_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_PAD_KEY: + var->Set(params->keystr); + break; + case SCRIPT_VAR_PAD_DISPLAY: + case SCRIPT_VAR_PAD_CLEAR: + case SCRIPT_VAR_PAD_SET: + var->Set(""); + break; + } +} + +void on_pad_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_PAD_DISPLAY: + fip_write_string(var->GetString()); + break; + case SCRIPT_VAR_PAD_SET: + fip_write_special(StringPair::Get(var, pad_special_pairs, -1), TRUE); + break; + case SCRIPT_VAR_PAD_KEY: + script_set_key(StringPair::Get(var, button_pairs, 0)); + break; + case SCRIPT_VAR_PAD_CLEAR: + { + SPString str = var->GetString(); + if (str.CompareNoCase("all") == 0) + fip_clear(); + else + fip_write_special(StringPair::Get(var, pad_special_pairs, -1), FALSE); + } + break; + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_drive_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_DRIVE_MEDIATYPE: + StringPair::Set(var, mediatype_pairs, params->status); + break; + case SCRIPT_VAR_DRIVE_TRAY: + if (params->status == CDROM_STATUS_NODISC || + (params->status & CDROM_STATUS_HASDISC) == CDROM_STATUS_HASDISC) + var->Set("close"); + else + var->Set("open"); + break; + } +} + +void on_drive_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_DRIVE_TRAY: + { + BOOL force_status = FALSE; + CDROM_STATUS status = cdrom_getstatus(&force_status); + SPString str = var->GetString(); + if (str.CompareNoCase("toggle") == 0 || + (str.CompareNoCase("open") == 0 && status != CDROM_STATUS_TRAYOPEN) || + (str.CompareNoCase("close") == 0 && status == CDROM_STATUS_TRAYOPEN) + ) + { + toggle_tray(); + } + } + break; + case SCRIPT_VAR_DRIVE_MEDIATYPE: + { + SPString str = var->GetString(); + if (params->status == CDROM_STATUS_HAS_DVD && str.CompareNoCase("iso") == 0) + { + params->require_next_status = (params->saved_iso_status != CDROM_STATUS_UNKNOWN) ? + params->saved_iso_status : CDROM_STATUS_HAS_ISO; + disc_changed(CDROM_STATUS_CURRENT); + } + else if ((params->status == CDROM_STATUS_HAS_ISO || params->status == CDROM_STATUS_HAS_MIXED) && str.CompareNoCase("dvd") == 0) + { + params->saved_iso_status = params->status; + params->require_next_status = CDROM_STATUS_HAS_DVD; + disc_changed(CDROM_STATUS_CURRENT); + } + else + { + params->saved_iso_status = params->status; + params->require_next_status = CDROM_STATUS_UNKNOWN; + disc_changed(CDROM_STATUS_UNKNOWN); + } + } + break; + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_settings_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_SETTINGS_COMMAND: + var->Set(""); + break; + case SCRIPT_VAR_SETTINGS_AUDIOOUT: + StringPair::Set(var, audioout_pairs, settings_get(SETTING_AUDIOOUT)); + break; + case SCRIPT_VAR_SETTINGS_TVTYPE: + StringPair::Set(var, tvtype_pairs, settings_get(SETTING_TVTYPE)); + break; + case SCRIPT_VAR_SETTINGS_TVSTANDARD: + StringPair::Set(var, tvstandard_pairs, settings_get(SETTING_TVSTANDARD)); + break; + case SCRIPT_VAR_SETTINGS_TVOUT: + StringPair::Set(var, tvout_pairs, settings_get(SETTING_TVOUT)); + break; + case SCRIPT_VAR_SETTINGS_DVI: + var->Set(settings_get(SETTING_DVI)); + break; + case SCRIPT_VAR_SETTINGS_HQ_JPEG: + var->Set(settings_get(SETTING_HQ_JPEG)); + break; + case SCRIPT_VAR_SETTINGS_HDD_SPEED: + StringPair::Set(var, hddspeed_pairs, settings_get(SETTING_HDD_SPEED)); + break; + case SCRIPT_VAR_SETTINGS_DVD_PARENTAL: + var->Set(settings_get(SETTING_DVD_PARENTAL)); + break; + case SCRIPT_VAR_SETTINGS_DVD_MV: + var->Set(settings_get(SETTING_DVD_MV)); + break; + case SCRIPT_VAR_SETTINGS_DVD_LANG_MENU: + case SCRIPT_VAR_SETTINGS_DVD_LANG_AUDIO: + case SCRIPT_VAR_SETTINGS_DVD_LANG_SPU: + { + char str[3] = { 0 }; + SETTING_SET sset = SETTING_VERSION; + switch (var_id) + { + case SCRIPT_VAR_SETTINGS_DVD_LANG_MENU: + sset = SETTING_DVD_LANG_MENU; + break; + case SCRIPT_VAR_SETTINGS_DVD_LANG_AUDIO: + sset = SETTING_DVD_LANG_AUDIO; + break; + default: + sset = SETTING_DVD_LANG_SPU; + } + int v = settings_get(sset); + if (v > 0) + { + str[0] = (char)((v >> 8) & 0xff); + str[1] = (char)((v) & 0xff); + var->Set(str); + } else + var->Set(""); + } + break; + case SCRIPT_VAR_SETTINGS_VOLUME: + var->Set(settings_get(SETTING_VOLUME)); + break; + case SCRIPT_VAR_SETTINGS_BALANCE: + var->Set(settings_get(SETTING_BALANCE) - 100); + break; + case SCRIPT_VAR_SETTINGS_BRIGHTNESS: + var->Set(GetScreenAdjustmentSetting(0)); + break; + case SCRIPT_VAR_SETTINGS_CONTRAST: + var->Set(GetScreenAdjustmentSetting(1)); + break; + case SCRIPT_VAR_SETTINGS_SATURATION: + var->Set(GetScreenAdjustmentSetting(2)); + break; + case SCRIPT_VAR_SETTINGS_USER1: + case SCRIPT_VAR_SETTINGS_USER2: + case SCRIPT_VAR_SETTINGS_USER3: + case SCRIPT_VAR_SETTINGS_USER4: + case SCRIPT_VAR_SETTINGS_USER5: + case SCRIPT_VAR_SETTINGS_USER6: + case SCRIPT_VAR_SETTINGS_USER7: + case SCRIPT_VAR_SETTINGS_USER8: + case SCRIPT_VAR_SETTINGS_USER9: + case SCRIPT_VAR_SETTINGS_USER10: + case SCRIPT_VAR_SETTINGS_USER11: + case SCRIPT_VAR_SETTINGS_USER12: + case SCRIPT_VAR_SETTINGS_USER13: + case SCRIPT_VAR_SETTINGS_USER14: + case SCRIPT_VAR_SETTINGS_USER15: + case SCRIPT_VAR_SETTINGS_USER16: + { + SETTING_SET idx = (SETTING_SET)(SETTING_GUI_0 + var_id - SCRIPT_VAR_SETTINGS_USER1); + var->Set(settings_get(idx)); + } + break; + } +} + +void on_settings_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_SETTINGS_COMMAND: + { + SPString cmd = var->GetString(); + if (cmd.CompareNoCase("defaults") == 0) + { + settings_init(true); + for (int i = SCRIPT_VAR_SETTINGS_AUDIOOUT; i <= SCRIPT_VAR_SETTINGS_USER16; i++) + mmsl->UpdateVariable(i); + } + } + break; + case SCRIPT_VAR_SETTINGS_AUDIOOUT: + settings_set(SETTING_AUDIOOUT, StringPair::Get(var, audioout_pairs, 0)); + break; + case SCRIPT_VAR_SETTINGS_TVTYPE: + settings_set(SETTING_TVTYPE, StringPair::Get(var, tvtype_pairs, 0)); + break; + case SCRIPT_VAR_SETTINGS_TVSTANDARD: + settings_set(SETTING_TVSTANDARD, StringPair::Get(var, tvstandard_pairs, 1)); + break; + case SCRIPT_VAR_SETTINGS_TVOUT: + settings_set(SETTING_TVOUT, StringPair::Get(var, tvout_pairs, 0)); + break; + case SCRIPT_VAR_SETTINGS_DVI: + settings_set(SETTING_DVI, var->GetInteger()); + break; + case SCRIPT_VAR_SETTINGS_HQ_JPEG: + { + int val = var->GetInteger(); + val %= 2; + settings_set(SETTING_HQ_JPEG, val); + } + break; + case SCRIPT_VAR_SETTINGS_HDD_SPEED: + if (var->GetString().CompareNoCase("next") == 0) + { + int val = settings_get(SETTING_HDD_SPEED); + val = (val + 1) % (settings_getmax(SETTING_HDD_SPEED) + 1); + settings_set(SETTING_HDD_SPEED, val); + break; + } + settings_set(SETTING_HDD_SPEED, StringPair::Get(var, hddspeed_pairs, 0)); + break; + case SCRIPT_VAR_SETTINGS_DVD_PARENTAL: + settings_set(SETTING_DVD_PARENTAL, var->GetInteger()); + break; + case SCRIPT_VAR_SETTINGS_DVD_MV: + settings_set(SETTING_DVD_MV, var->GetInteger()); + break; + case SCRIPT_VAR_SETTINGS_DVD_LANG_MENU: + case SCRIPT_VAR_SETTINGS_DVD_LANG_AUDIO: + case SCRIPT_VAR_SETTINGS_DVD_LANG_SPU: + { + SETTING_SET sset = SETTING_VERSION; + switch (var_id) + { + case SCRIPT_VAR_SETTINGS_DVD_LANG_MENU: + sset = SETTING_DVD_LANG_MENU; + break; + case SCRIPT_VAR_SETTINGS_DVD_LANG_AUDIO: + sset = SETTING_DVD_LANG_AUDIO; + break; + default: + sset = SETTING_DVD_LANG_SPU; + } + SPString lang = var->GetString(); + if (isalpha(lang[0]) && isalpha(lang[1])) + { + settings_set(sset, (lang[0] << 8) | lang[1]); + } + } + break; + case SCRIPT_VAR_SETTINGS_VOLUME: + settings_set(SETTING_VOLUME, var->GetInteger()); + break; + case SCRIPT_VAR_SETTINGS_BALANCE: + settings_set(SETTING_BALANCE, var->GetInteger() + 100); + break; + case SCRIPT_VAR_SETTINGS_BRIGHTNESS: + SetScreenAdjustmentSetting(0, var->GetInteger()); + break; + case SCRIPT_VAR_SETTINGS_CONTRAST: + SetScreenAdjustmentSetting(1, var->GetInteger()); + break; + case SCRIPT_VAR_SETTINGS_SATURATION: + SetScreenAdjustmentSetting(2, var->GetInteger()); + break; + case SCRIPT_VAR_SETTINGS_USER1: + case SCRIPT_VAR_SETTINGS_USER2: + case SCRIPT_VAR_SETTINGS_USER3: + case SCRIPT_VAR_SETTINGS_USER4: + case SCRIPT_VAR_SETTINGS_USER5: + case SCRIPT_VAR_SETTINGS_USER6: + case SCRIPT_VAR_SETTINGS_USER7: + case SCRIPT_VAR_SETTINGS_USER8: + case SCRIPT_VAR_SETTINGS_USER9: + case SCRIPT_VAR_SETTINGS_USER10: + case SCRIPT_VAR_SETTINGS_USER11: + case SCRIPT_VAR_SETTINGS_USER12: + case SCRIPT_VAR_SETTINGS_USER13: + case SCRIPT_VAR_SETTINGS_USER14: + case SCRIPT_VAR_SETTINGS_USER15: + case SCRIPT_VAR_SETTINGS_USER16: + { + SETTING_SET idx = (SETTING_SET)(SETTING_GUI_0 + var_id - SCRIPT_VAR_SETTINGS_USER1); + settings_set(idx, var->GetInteger()); + } + break; + + } +} + +//////////////////////////////////////////////////////////////////////// + +void on_flash_get(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_FLASH_FILE: + var->Set(params->flash_file); + break; + case SCRIPT_VAR_FLASH_ADDRESS: + var->Set(params->flash_address < 0 ? 0 : params->flash_address); + break; + case SCRIPT_VAR_FLASH_PROGRESS: + var->Set(params->flash_progress); + break; + } +} + +void on_flash_set(int var_id, MmslVariable *var, void *, int , MMSL_OBJECT *) +{ + if (var == NULL) + return; + switch (var_id) + { + case SCRIPT_VAR_FLASH_FILE: + params->flash_file = var->GetString(); + break; + case SCRIPT_VAR_FLASH_ADDRESS: + params->flash_address = var->GetInteger(); + break; + } + + if (var_id == SCRIPT_VAR_FLASH_FILE || var_id == SCRIPT_VAR_FLASH_ADDRESS) + { + if (params->flash_file != "" && params->flash_address <= 0) + { + params->flash_address = get_firmware_address(); + } + if (params->flash_file != "" && params->flash_address > 0) + { + params->flash_progress = -1; + params->flash_p = -1; + msg("FLASH %s at 0x%x...\n", *params->flash_file, params->flash_address); + + stop_all(); + cdda_close(); + + int ret = flash_file(params->flash_file, params->flash_address); + if (ret < 0) + { + msg_error("Cannot flash file %s at address 0x%x (err=%d).\n", *params->flash_file, + params->flash_address, ret); + mmsl->UpdateVariable(SCRIPT_VAR_FLASH_PROGRESS); + } + else + params->flash_progress = 0; + } + + } +} + diff --git a/src/script.h b/src/script.h new file mode 100644 index 0000000..e5744ed --- /dev/null +++ b/src/script.h @@ -0,0 +1,147 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - script wrapper header file + * \file script.h + * \author bombur + * \version 0.1 + * \date 2.08.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_SCRIPT_H +#define SP_SCRIPT_H + +#include + +//////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +extern "C" { +#endif + +enum SCRIPT_ERROR_CODE +{ + SCRIPT_ERROR_INVALID = 0, + SCRIPT_ERROR_BAD_AUDIO, + SCRIPT_ERROR_BAD_CODEC, + SCRIPT_ERROR_QPEL, + SCRIPT_ERROR_GMC, + SCRIPT_ERROR_WAIT, + SCRIPT_ERROR_CORRUPTED, +}; + +/// General program cycle +int cycle(bool gfx_only = false); + +/// Initialize script variables & objects +int script_init(); + +/// Deinit script defs. +int script_deinit(); + +/// Update script data (call triggers if something changed) +int script_update(bool gfx_only = false); + +/// Get the current time elapsed since script was started, in milliseconds. +int get_curtime(); + +/// Skip timer for all time elapsed since the last call of script_update(). Used for sleeping. +void script_skiptime(); + +bool script_update_variable(int ID); + +/// 'ison' is the next status +bool player_turn_onoff(bool on); +void player_halt(); + +bool script_next_vmode(); + +void script_key_callback(int key); +void script_drive_callback(CDROM_STATUS); + +void script_time_callback(int secs); +void script_totaltime_callback(int secs); + +void script_error_callback(SCRIPT_ERROR_CODE); + +void script_name_callback(const SPString &); +void script_artist_callback(const SPString &); +void script_audio_info_callback(const SPString &); +void script_video_info_callback(const SPString &); +void script_framesize_callback(int width, int height); +void script_framerate_callback(int frame_rate); +void script_zoom_scroll_reset_callback(); +void script_colorspace_callback(int clrs); +void script_speed_callback(int speed = -1); +void script_player_saved_callback(); + +void script_player_subtitle_callback(const char *); + +void script_dvd_menu_callback(bool ismenu); +void script_dvd_chapter_callback(int chapter); +void script_dvd_title_callback(int title, int numchapters); +void script_cdda_track_callback(int track); +void script_audio_lang_callback(const char *lang); +void script_spu_lang_callback(const char *lang); +void script_audio_stream_callback(int stream); +void script_spu_stream_callback(int stream); + +const char *get_button_string(int); +bool stop_all(); +bool toggle_tray(); +bool start_iso(); +bool start_dvd(); +bool stop_dvd(); +void disc_changed(CDROM_STATUS = CDROM_STATUS_CURRENT); +bool is_internal_playing(); +bool is_playing(); + +/// Get current time (if tv == NULL) or delta-time, in msec. +int script_get_time(struct timeval *tv); + +void player_update_source(char *filepath); + +//////////////////////////////////////////////////// + +enum SCRIPT_TIMER_OBJECT_TYPE +{ + SCRIPT_OBJECT_UPDATE = 0, + SCRIPT_OBJECT_TIMER, +}; + +class ScriptTimerObject +{ +public: + /// ctor + ScriptTimerObject() + { + prev = next = NULL; + } + +public: + MMSL_OBJECT obj; + int var_ID; + SCRIPT_TIMER_OBJECT_TYPE type; + + ScriptTimerObject *prev, *next; +}; + + +#ifdef __cplusplus +} +#endif + +#endif // of SP_SCRIPT_H diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..8422483 --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,231 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - settings setting/getting source file + * \file settings.cpp + * \author bombur + * \version 0.1 + * \date 4.07.2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "settings.h" + +const DWORD cur_version = (DWORD)(SP_VERSION_MASK | 0x0D); + +static int num_settings = 0; +static bool was_reset = false; + +static struct +{ + DWORD size; + DWORD def; + DWORD max; + DWORD value; + int addr; +} settings[max_settings] = +{ + { 4, cur_version, 0xFFFFFFFF }, // SETTING_VERSION + + { 1, 0, 1, }, // SETTING_AUDIOOUT + + { 1, 0, 3, }, // SETTING_HDTV + + { 4, 0, 255, }, // SETTING_DVI + + { 1, 1, 5, }, // SETTING_TVSTANDARD // 1 = "PAL" + { 1, 0, 2, }, // SETTING_TVOUT // 0 = "C/S-Video" + + { 1, 0, 3, }, // SETTING_TVTYPE, // 0 = 4:3 letterbox + + { 1, 0, 1, }, // SETTING_HQ_JPEG, + + { 1, 0, 8, }, // SETTING_DVD_PARENTAL, + { 1, 1, 1, }, // SETTING_DVD_MV, + + { 2, 0x656e, 0xffff, }, // SETTING_DVD_LANG_MENU 'en', + + { 2, 0x656e, 0xffff, }, // SETTING_DVD_LANG_AUDIO 'en', + + { 2, 0x656e, 0xffff, }, // SETTING_DVD_LANG_SPU 'en', + + { 1, 80, 100, }, // SETTING_VOLUME, + + { 1, 100, 200, }, // SETTING_BALANCE, + + + { 4, (500<<20)|(500<<10)|500, (1000<<20)|(1000<<10)|1000, }, // SETTING_BRIGHTNESS_CONTRAST_SATURATION_PAL, + { 4, (500<<20)|(500<<10)|500, (1000<<20)|(1000<<10)|1000, }, // SETTING_BRIGHTNESS_CONTRAST_SATURATION_NTSC, + { 4, (500<<20)|(500<<10)|500, (1000<<20)|(1000<<10)|1000, }, // SETTING_BRIGHTNESS_CONTRAST_SATURATION_OTHER, + + { 4, 0, 0xffffffff, }, // SETTING_GUI_0, + { 4, 0, 0xffffffff, }, // SETTING_GUI_1, + { 4, 0, 0xffffffff, }, // SETTING_GUI_2, + { 4, 0, 0xffffffff, }, // SETTING_GUI_3, + { 4, 0, 0xffffffff, }, // SETTING_GUI_4, + { 4, 0, 0xffffffff, }, // SETTING_GUI_5, + { 4, 0, 0xffffffff, }, // SETTING_GUI_6, + { 4, 0, 0xffffffff, }, // SETTING_GUI_7, + { 4, 0, 0xffffffff, }, // SETTING_GUI_8, + { 4, 0, 0xffffffff, }, // SETTING_GUI_9, + { 4, 0, 0xffffffff, }, // SETTING_GUI_10, + { 4, 0, 0xffffffff, }, // SETTING_GUI_11, + { 4, 0, 0xffffffff, }, // SETTING_GUI_12, + { 4, 0, 0xffffffff, }, // SETTING_GUI_13, + { 4, 0, 0xffffffff, }, // SETTING_GUI_14, + { 4, 0, 0xffffffff, }, // SETTING_GUI_15, + + { 4, 0, 0xffffffff, }, // SETTING_DVD_ID1, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_POS1, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA11, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA12, + + { 4, 0, 0xffffffff, }, // SETTING_DVD_ID2, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_POS2, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA21, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA22, + + { 4, 0, 0xffffffff, }, // SETTING_DVD_ID3, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_POS3, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA31, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA32, + + { 4, 0, 0xffffffff, }, // SETTING_DVD_ID4, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_POS4, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA41, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA42, + + { 4, 0, 0xffffffff, }, // SETTING_DVD_ID5, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_POS5, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA51, + { 4, 0xffffffff, 0xffffffff, }, // SETTING_DVD_DATA52, + + { 1, 0, 2, }, // SETTING_HDD_SPEED, + + { 0 }, +}; + +int settings_get_eeprom(int id) +{ + return eeprom_get_value(settings[id].addr, settings[id].size); +} + +BOOL settings_init(bool set_defaults) +{ + settings[0].addr = 0; + int i; + for (i = 1; i < max_settings; i++) + { + if (settings[i].size == 0) + { + num_settings = i; + break; + } + settings[i].addr = settings[i-1].addr + settings[i-1].size; + } + + DWORD stored_version = settings_get_eeprom(SETTING_VERSION); + + bool reset = (stored_version & 0xffffff00) != (cur_version & 0xffffff00); + if ((stored_version & 0xff) < (cur_version & 0xff) || set_defaults) + { + was_reset = true; + reset = true; + } + + for (i = 0; i < num_settings; i++) + { + if (reset) + settings_set((SETTING_SET)i, settings[i].def); + else + { + DWORD from_eeprom = settings_get_eeprom(i); + if (from_eeprom <= settings[i].max) + settings[i].value = from_eeprom; + else + settings_set((SETTING_SET)i, settings[i].def); + } + } + return TRUE; +} + +BOOL settings_set(SETTING_SET id, int val, bool no_eeprom) +{ + if (id < num_settings && (DWORD)val <= settings[id].max) + { + settings[id].value = val; + if (!no_eeprom) + { + eeprom_set_value(settings[id].addr, val, settings[id].size); + msg("Settings: %d = %d\n", id, val); + } + return TRUE; + } + return FALSE; +} + +int settings_get(SETTING_SET id) +{ + return id < num_settings ? settings[id].value : 0; +} + +int settings_getmax(SETTING_SET id) +{ + return id < num_settings ? settings[id].max : 0; +} + +DWORD get_firmware_address() +{ + DWORD addr = 0; + msg("Flash: Detecting firmware address...\n"); + // find ROMFS address +#ifdef WIN32 + addr = 0x6000; +#else + for (int i = 0x6000; i <= 0x10000; i += 0x1000) + { + BYTE *data = (BYTE *)i; + if (memcmp(data, "-rom1fs-", 8) == 0) + { + addr = (DWORD)i; + break; + } + } +#endif + + if (addr == 0) + { + msg("Flash: Cannot find ROMFS address!\n"); + return 0; + } + msg("Flash: ROMFS found @ 0x%08x\n", addr); + + return addr; +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..a7dcf73 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,143 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - user settings header file + * \file settings.h + * \author bombur + * \version 0.1 + * \date 12.01.2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_SETTINGS_H +#define SP_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "version.h" + +/// This is version identification mask +const DWORD SP_VERSION_MASK = 0xCFDA9900; + +const int max_settings = 64; + +/// Settings IDs (no more than max_settings) +typedef enum +{ + SETTING_VERSION = 0, // not used normally + + SETTING_AUDIOOUT, // 0 = analog, 1 = digital + + SETTING_HDTV, // 0 = off, 1 = 480p, 2 = 720p, 3 = 1080i + + SETTING_DVI, // !RESERVED! 0 = off, X = number read from cfg file?? + + SETTING_TVSTANDARD, // 0 = "NTSC", 1 = "PAL", 2 = "480P", 3 = "576P", 4 = "720P", 5 = "1080I" + + SETTING_TVOUT, // 0 = "C/S-Video", 1 = "C/YPbPr", 2 = "C/RGB" + + SETTING_TVTYPE, // 0 = 4:3 letterbox, 1 = 4:3 panscan, 2 = 16:9, 3 = 16:9 panscan + + SETTING_HQ_JPEG, // 0 = off, 1 = on + + SETTING_DVD_PARENTAL, + SETTING_DVD_MV, + + SETTING_DVD_LANG_MENU, + + SETTING_DVD_LANG_AUDIO, + + SETTING_DVD_LANG_SPU, + + SETTING_VOLUME, + + SETTING_BALANCE, + + SETTING_BRIGHTNESS_CONTRAST_SATURATION_PAL, + SETTING_BRIGHTNESS_CONTRAST_SATURATION_NTSC, + SETTING_BRIGHTNESS_CONTRAST_SATURATION_OTHER, + + SETTING_GUI_0, + SETTING_GUI_1, + SETTING_GUI_2, + SETTING_GUI_3, + SETTING_GUI_4, + SETTING_GUI_5, + SETTING_GUI_6, + SETTING_GUI_7, + SETTING_GUI_8, + SETTING_GUI_9, + SETTING_GUI_10, + SETTING_GUI_11, + SETTING_GUI_12, + SETTING_GUI_13, + SETTING_GUI_14, + SETTING_GUI_15, + + SETTING_DVD_ID1, // most recent + SETTING_DVD_POS1, + SETTING_DVD_DATA11, + SETTING_DVD_DATA12, + SETTING_DVD_ID2, + SETTING_DVD_POS2, + SETTING_DVD_DATA21, + SETTING_DVD_DATA22, + SETTING_DVD_ID3, + SETTING_DVD_POS3, + SETTING_DVD_DATA31, + SETTING_DVD_DATA32, + SETTING_DVD_ID4, + SETTING_DVD_POS4, + SETTING_DVD_DATA41, + SETTING_DVD_DATA42, + SETTING_DVD_ID5, + SETTING_DVD_POS5, + SETTING_DVD_DATA51, + SETTING_DVD_DATA52, + + SETTING_HDD_SPEED, + + +} SETTING_SET; + +/////////////////////////////////////////////////// + +/// Initialize settings (and read EEPROM) +BOOL settings_init(bool set_defaults = false); + +/// Store settings value (and write EEPROM if allowed) +BOOL settings_set(SETTING_SET id, int val, bool no_eeprom = false); + +/// Get stored settings value from cache +int settings_get(SETTING_SET id); + +/// Get max. allowed value for given settings ID +int settings_getmax(SETTING_SET id); + +/////////////////////////////////////////////////// +/// Special functions + +DWORD get_firmware_address(); + +// not yet + +#ifdef __cplusplus +} +#endif + +#endif // of SP_SETTINGS_H diff --git a/src/subtitle.cpp b/src/subtitle.cpp new file mode 100644 index 0000000..a137e8a --- /dev/null +++ b/src/subtitle.cpp @@ -0,0 +1,1416 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Subtitles for video player source file. + * \file subtitle.cpp + * \author bombur + * \version 0.1 + * \date 01.10.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "script.h" +#include "script-internal.h" +#include "subtitle.h" + + +static const int max_allowed_playlist_subs = 2; + +static Subtitles *sub = NULL; + +static const SubtitleFormat sub_formats[] = +{ + { /* 0 */ + "SubRip", + { SUB(SUB_TOKEN_SKIP_DIGITS), "\n", SUB(SUB_TOKEN_HOUR1), ":", SUB(SUB_TOKEN_MIN1), ":", SUB(SUB_TOKEN_SEC1), SUB(SUB_TOKEN_OPTIONAL_NEXT), ",", SUB(SUB_TOKEN_OPTIONAL_NEXT), SUB(SUB_TOKEN_MSEC1), " --> ", + SUB(SUB_TOKEN_HOUR2), ":", SUB(SUB_TOKEN_MIN2), ":", SUB(SUB_TOKEN_SEC2), SUB(SUB_TOKEN_OPTIONAL_NEXT), ",", SUB(SUB_TOKEN_OPTIONAL_NEXT), SUB(SUB_TOKEN_MSEC2), + NULL + }, + "\n\n" + }, + { /* 1 */ + "SubViewer 1.0", + { "[", SUB(SUB_TOKEN_HOUR1), ":", SUB(SUB_TOKEN_MIN1), ":", SUB(SUB_TOKEN_SEC1), "]\n", + NULL + }, + "\n" + }, + { /* 2 */ + "SubViewer 2.0", + { SUB(SUB_TOKEN_HOUR1), ":", SUB(SUB_TOKEN_MIN1), ":", SUB(SUB_TOKEN_SEC1), ".", SUB(SUB_TOKEN_DSEC1), ",", + SUB(SUB_TOKEN_HOUR2), ":", SUB(SUB_TOKEN_MIN2), ":", SUB(SUB_TOKEN_SEC2), ".", SUB(SUB_TOKEN_DSEC2), "\n", + NULL + }, + "\n\n" + }, + { /* 3 */ + "DVDSubtitle", + { "{T ", SUB(SUB_TOKEN_HOUR1), ":", SUB(SUB_TOKEN_MIN1), ":", SUB(SUB_TOKEN_SEC1), ":", SUB(SUB_TOKEN_DSEC1), "\n", + NULL + }, + "\n}\n" + }, + { /* 4 */ + "DVD Architect", + { SUB(SUB_TOKEN_SKIP_DIGITS_4), "\t", SUB(SUB_TOKEN_HOUR1), ":", SUB(SUB_TOKEN_MIN1), ":", SUB(SUB_TOKEN_SEC1), ":", SUB(SUB_TOKEN_DSEC1), "\t", + SUB(SUB_TOKEN_HOUR2), ":", SUB(SUB_TOKEN_MIN2), ":", SUB(SUB_TOKEN_SEC2), ":", SUB(SUB_TOKEN_DSEC2), "\t", + NULL + }, + "\n\n" + }, + { /* 5 */ + "MicroDVD", + { "{", SUB(SUB_TOKEN_FRAMES1), "}{", SUB(SUB_TOKEN_FRAMES2), "}", + NULL + }, + "\n" + }, + { /* 6 */ + "MPSub", + { SUB(SUB_TOKEN_DELTA_SECS1), SUB(SUB_TOKEN_OPTIONAL_NEXT), ".", SUB(SUB_TOKEN_OPTIONAL_NEXT), SUB(SUB_TOKEN_DELTA_MSECS1), " ", + SUB(SUB_TOKEN_DELTA_SECS2), SUB(SUB_TOKEN_OPTIONAL_NEXT), ".", SUB(SUB_TOKEN_OPTIONAL_NEXT), SUB(SUB_TOKEN_DELTA_MSECS2), "\n", + NULL + }, + "\n\n" + }, + { /* 7 */ + "TMPlayer", + { SUB(SUB_TOKEN_HOUR1), ":", SUB(SUB_TOKEN_MIN1), ":", SUB(SUB_TOKEN_SEC1), ",", SUB(SUB_TOKEN_LINE_NUMBER), "=", + NULL + }, + "\n" + }, + { /* 8 */ + "SubSonic", + { "1 ", SUB(SUB_TOKEN_SEC1_256), ".", SUB(SUB_TOKEN_DSEC1_256), SUB(SUB_TOKEN_OPTIONAL_NEXT_2), " \\ ~:\\", + NULL + }, + "\n" + }, + { /* 9 */ + "SubStation Alpha", + { SUB(SUB_TOKEN_SKIP_TO_NEXT), ",", SUB(SUB_TOKEN_HOUR1_1), ":", SUB(SUB_TOKEN_MIN1), ":", SUB(SUB_TOKEN_SEC1), ".", SUB(SUB_TOKEN_DSEC1), ",", + SUB(SUB_TOKEN_HOUR2_1), ":", SUB(SUB_TOKEN_MIN2), ":", SUB(SUB_TOKEN_SEC2), ".", SUB(SUB_TOKEN_DSEC2), ",", + SUB(SUB_TOKEN_SKIP_TO_NEXT), ",", SUB(SUB_TOKEN_SKIP_TO_NEXT), ",", SUB(SUB_TOKEN_SKIP_TO_NEXT), ",", + SUB(SUB_TOKEN_SKIP_TO_NEXT), ",", SUB(SUB_TOKEN_SKIP_TO_NEXT), ",", SUB(SUB_TOKEN_SKIP_TO_NEXT), ",", + NULL + }, + "\n" + }, + { + NULL, + { NULL }, + NULL + } +}; + +///////////////////////////////////////////////////////////////////// + +BOOL SubtitleData::Alloc(int add_size) +{ + if (add_size > 0 && ptr != NULL) + { + ptr = (char *)SPrealloc((void *)ptr, max_string_length + add_size); + left += add_size; + } + else + ptr = cur = (char *)SPmalloc(max_string_length); + if (ptr == NULL) + return FALSE; + cur[0] = '\0'; + return TRUE; +} + +///////////////////////////////////////////////////////////////////// + +Subtitles::Subtitles() +{ + Reset(); + + saved_left[0] = saved_left[1] = 0; + + max_line_letters_cnt = 35; + + cur_sub = -1; +} + +Subtitles::~Subtitles() +{ + data.DeleteObjects(); + subs.DeleteObjects(); +} + +void Subtitles::Reset() +{ + fd = -1; + cur_method = -1; + buf_idx = 0; + buf_cnt[0] = buf_cnt[1] = 0; + buf_read_left[0] = buf_read_left[1] = 0; + buf_read_cnt = 1; + + is_start_of_file = true; + is_utf8 = false; is_utf16 = false; is_utf16be = false; +} + +void Subtitles::InitTranslationTable(SUBTITLE_CHARSET charset) +{ + static const BYTE koi_win[][2] = + { + { 0xe1, 0xc0 }, { 0xe2, 0xc1 }, { 0xf7, 0xc2 }, { 0xe7, 0xc3 }, + { 0xe4, 0xc4 }, { 0xe5, 0xc5 }, { 0xf6, 0xc6 }, { 0xfa, 0xc7 }, + { 0xe9, 0xc8 }, { 0xea, 0xc9 }, { 0xeb, 0xca }, { 0xec, 0xcb }, + { 0xed, 0xcc }, { 0xee, 0xcd }, { 0xef, 0xce }, { 0xf0, 0xcf }, + { 0xf2, 0xd0 }, { 0xf3, 0xd1 }, { 0xf4, 0xd2 }, { 0xf5, 0xd3 }, + { 0xe6, 0xd4 }, { 0xe8, 0xd5 }, { 0xe3, 0xd6 }, { 0xfe, 0xd7 }, + { 0xfb, 0xd8 }, { 0xfd, 0xd9 }, { 0xff, 0xda }, { 0xf9, 0xdb }, + { 0xf8, 0xdc }, { 0xfc, 0xdd }, { 0xe0, 0xde }, { 0xf1, 0xdf }, + { 0xc1, 0xe0 }, { 0xc2, 0xe1 }, { 0xd7, 0xe2 }, { 0xc7, 0xe3 }, + { 0xc4, 0xe4 }, { 0xc5, 0xe5 }, { 0xd6, 0xe6 }, { 0xda, 0xe7 }, + { 0xc9, 0xe8 }, { 0xca, 0xe9 }, { 0xcb, 0xea }, { 0xcc, 0xeb }, + { 0xcd, 0xec }, { 0xce, 0xed }, { 0xcf, 0xee }, { 0xd0, 0xef }, + { 0xd2, 0xf0 }, { 0xd3, 0xf1 }, { 0xd4, 0xf2 }, { 0xd5, 0xf3 }, + { 0xc6, 0xf4 }, { 0xc8, 0xf5 }, { 0xc3, 0xf6 }, { 0xde, 0xf7 }, + { 0xdb, 0xf8 }, { 0xdd, 0xf9 }, { 0xdf, 0xfa }, { 0xd9, 0xfb }, + { 0xd8, 0xfc }, { 0xdc, 0xfd }, { 0xc0, 0xfe }, { 0xd1, 0xff }, + { 0xb3, 0xa8 }, { 0xa3, 0xb8 }, { 0, 0 }, + }; + + for (int i = 0; i < 256; i++) + charset_translation_table[i] = (BYTE)i; + + if (charset == SUBTITLE_CHARSET_KOI8R) // KOI8 to CP1251 + { + for (int i = 0; koi_win[i][0] != '\0'; i++) + charset_translation_table[koi_win[i][0]] = koi_win[i][1]; + } +} + +void Subtitles::FillUTFTable(SUBTITLE_CHARSET charset) +{ + const static WORD utf_win1251[128] = + { + 0x0402,0x0403,0x201A,0x0453,0x201E,0x2026,0x2020,0x2021,0x20AC,0x2030,0x0409,0x2039,0x040A,0x040C,0x040B,0x040F, + 0x0452,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014,0x0000,0x2122,0x0459,0x203A,0x045A,0x045C,0x045B,0x045F, + 0x00A0,0x040E,0x045E,0x0408,0x00A4,0x0490,0x00A6,0x00A7,0x0401,0x00A9,0x0404,0x00AB,0x00AC,0x00AD,0x00AE,0x0407, + 0x00B0,0x00B1,0x0406,0x0456,0x0491,0x00B5,0x00B6,0x00B7,0x0451,0x2116,0x0454,0x00BB,0x0458,0x0405,0x0455,0x0457, + 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,0x041E,0x041F, + 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,0x042E,0x042F, + 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D,0x043E,0x043F, + 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,0x044E,0x044F, + }; + + const static WORD utf_iso8859_2[128] = + { + 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F, + 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F, + 0x00A0,0x0104,0x02D8,0x0141,0x00A4,0x013D,0x015A,0x00A7,0x00A8,0x0160,0x015E,0x0164,0x0179,0x00AD,0x017D,0x017B, + 0x00B0,0x0105,0x02DB,0x0142,0x00B4,0x013E,0x015B,0x02C7,0x00B8,0x0161,0x015F,0x0165,0x017A,0x02DD,0x017E,0x017C, + 0x0154,0x00C1,0x00C2,0x0102,0x00C4,0x0139,0x0106,0x00C7,0x010C,0x00C9,0x0118,0x00CB,0x011A,0x00CD,0x00CE,0x010E, + 0x0110,0x0143,0x0147,0x00D3,0x00D4,0x0150,0x00D6,0x00D7,0x0158,0x016E,0x00DA,0x0170,0x00DC,0x00DD,0x0162,0x00DF, + 0x0155,0x00E1,0x00E2,0x0103,0x00E4,0x013A,0x0107,0x00E7,0x010D,0x00E9,0x0119,0x00EB,0x011B,0x00ED,0x00EE,0x010F, + 0x0111,0x0144,0x0148,0x00F3,0x00F4,0x0151,0x00F6,0x00F7,0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9, + }; + + DWORD i; + for (i = 0; i < 127; i++) + utf16_to_ansi_table[i] = (BYTE)i; + for (i = 127; i < sizeof(utf16_to_ansi_table); i++) + utf16_to_ansi_table[i] = ' '; + if (charset == SUBTITLE_CHARSET_ISO8859_1) + { + for (i = 127; i < 256; i++) + utf16_to_ansi_table[i] = (BYTE)i; + } + else if (charset == SUBTITLE_CHARSET_ISO8859_2) + { + for (i = 0; i < 128; i++) + { + int j = Min((size_t)utf_iso8859_2[i], sizeof(utf16_to_ansi_table)); + if (j > 0) + utf16_to_ansi_table[j] = (BYTE)(i + 128); + } + } + else + { + for (i = 0; i < 128; i++) + { + int j = Min((size_t)utf_win1251[i], sizeof(utf16_to_ansi_table)); + if (j > 0) + utf16_to_ansi_table[j] = (BYTE)(i + 128); + } + } + + if (is_utf8 || is_utf16) + { + for (i = 0; i < 256; i++) + charset_translation_table[i] = (BYTE)i; + } +} + +int Subtitles::AddString(BYTE *str, int &length, bool attach) +{ + int l = length + 1; + if (l > max_string_length) + return -1; + + int n = data.GetN(); + SubtitleData *d = data[n - 1]; + if (n == 0 || d->left < l) + { + if (!attach || n == 0 || !d->Alloc(l)) + { + d = new SubtitleData(); + if (!d->Alloc(0)) + return -1; + if (data.Add(d) < 0) + return -1; + n = data.GetN(); + } + } + + char last_ds; + if (attach && d->cur > d->ptr) + { + *(d->cur - 1) = last_ds = '\n'; + } + else + last_ds = 0; + + // replace all newlines now: + char *dst = d->cur; + int i = 0; + int line_letters_cnt = 0, last_space_cnt = 0; + for (BYTE *s = str; i < length; i++, s++) + { + char ds; + if (*s == '|') + ds = '\n'; + else if (*s == '\\' && s[1] == 'N') + { + ds = '\n'; + s++; + i++; + } + else if (*s == '[' && s[1] == 'b' && s[2] == 'r' && s[3] == ']') + { + ds = '\n'; + s += 3; + i += 3; + } + else + { + ds = charset_translation_table[(BYTE)*s]; + if (ds == ' ') + last_space_cnt = line_letters_cnt; + } + if (line_letters_cnt == 0) + { + if (ds == ' ' || ds == '\n' || ds == '%') + { + continue; + } + } + else if (line_letters_cnt > max_line_letters_cnt) + { + if (last_space_cnt > 0) + { + int delta = line_letters_cnt - last_space_cnt; + s -= delta; + i -= delta; + dst -= delta; + line_letters_cnt = last_space_cnt; + last_space_cnt = 0; + ds = '\n'; + } + } + if (ds == '\n') + { + line_letters_cnt = 0; + if (last_ds == '\n') + { + continue; + } + } + else + line_letters_cnt++; + *dst++ = last_ds = ds; + } + + if (last_ds == '\n' || last_ds == '%') + { + dst--; + } + *dst = '\0'; + int pos = d->cur - d->ptr; + length = dst - d->cur + 1; + d->cur += length; + d->len += length; + d->left -= length; + length--; + return pos; +} + +BOOL Subtitles::Scan(BYTE *&buf, int &left, int line_num, int method, SubtitleFields fields[2]) +{ + memset(fields, 0xff, sizeof(SubtitleFields) * 2); + fields[1].is_set = false; + + SUB_CUR_MODE cur_mode = SUB_CUR_MODE_NORMAL; + SUB_CUR_FORMAT cur_format = SUB_CUR_FORMAT_STRING; + SUB_CUR_FIELD cur_field = SUB_CUR_FIELD_NONE; + int cur_num_digits = 0; + + int field_idx = 0; + const SubtitleFormat &fmt = sub_formats[method]; + for (int i = 0; fmt.start[i] != NULL; i++) + { + const char *str = fmt.start[i]; + if ((int)str < 0x1000) + { + cur_field = SUB_CUR_FIELD_NONE; + + if (str == SUB(SUB_TOKEN_SKIP_TO_NEXT)) + { + cur_mode = SUB_CUR_MODE_SEARCH_NEXT; + continue; + } + else if (str == SUB(SUB_TOKEN_OPTIONAL_NEXT)) + { + cur_mode = SUB_CUR_MODE_OPTIONAL; + continue; + } + else if (str == SUB(SUB_TOKEN_OPTIONAL_NEXT_2)) + { + if (line_num > 0) + cur_mode = SUB_CUR_MODE_OPTIONAL; + continue; + } + if (str >= SUB(SUB_TOKEN_SKIP_DIGITS) && str <= SUB(SUB_TOKEN_SKIP_DIGITS_4)) + { + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = str - SUB(SUB_TOKEN_SKIP_DIGITS); + } + + field_idx = ((int)str > 0x100) ? 1 : 0; + switch ((int)str & 0xff) + { + case SUB_TOKEN_HOUR1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 2; + cur_field = SUB_CUR_FIELD_HOUR; + break; + case SUB_TOKEN_HOUR1_1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 1; + cur_field = SUB_CUR_FIELD_HOUR; + break; + case SUB_TOKEN_MIN1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 2; + cur_field = SUB_CUR_FIELD_MIN; + break; + case SUB_TOKEN_SEC1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 2; + cur_field = SUB_CUR_FIELD_SEC; + break; + case SUB_TOKEN_DSEC1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 2; + cur_field = SUB_CUR_FIELD_MSEC; + break; + case SUB_TOKEN_MSEC1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 3; + cur_field = SUB_CUR_FIELD_MSEC; + break; + case SUB_TOKEN_SEC1_256: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 0; + cur_field = SUB_CUR_FIELD_SEC256; + break; + case SUB_TOKEN_DSEC1_256: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 2; + cur_field = SUB_CUR_FIELD_MSEC256; + break; + case SUB_TOKEN_DELTA_SECS1: + cur_format = SUB_CUR_FORMAT_DIGITS_SIGN; + cur_num_digits = 0; + cur_field = SUB_CUR_FIELD_DELTA_SEC; + break; + case SUB_TOKEN_DELTA_MSECS1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 0; + cur_field = SUB_CUR_FIELD_DELTA_MSEC; + break; + case SUB_TOKEN_FRAMES1: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 0; + cur_field = SUB_CUR_FIELD_FRAMES; + break; + case SUB_TOKEN_LINE_NUMBER: + cur_format = SUB_CUR_FORMAT_DIGITS; + cur_num_digits = 1; + cur_field = SUB_CUR_FIELD_LINE_NUMBER; + break; + } + + } else + { + cur_format = SUB_CUR_FORMAT_STRING; + cur_field = SUB_CUR_FIELD_NONE; + } + + int value = 0, sign = 1; + while (left > 0) + { + int num_read = 0; + SavePos(1, buf, left); + switch (cur_format) + { + case SUB_CUR_FORMAT_STRING: + { + const char *ss = str; + for (; *ss != '\0'; buf++, left--, num_read++) + { + if (left < 1) + { + if ((buf = ReadMore(&left)) == NULL) + { + num_read = 0; + return FALSE; + } + } + if (*buf == '\r') + continue; + if (*buf != *ss) + { + num_read = 0; + if (!LoadPos(1, buf, left)) + return FALSE; + break; + } + ss++; + } + } + break; + case SUB_CUR_FORMAT_DIGITS_SIGN: + if (*buf == '-') + { + num_read++; + buf++; + left--; + sign = -1; + if (left < 1) + { + if ((buf = ReadMore(&left)) == NULL) + { + num_read = 0; + return FALSE; + } + } + } + case SUB_CUR_FORMAT_DIGITS: + value = 0; + while (left > 0) + { + int max_num_read = cur_num_digits == 0 ? left : cur_num_digits; + for ( ; num_read < max_num_read && left > 0 && isdigit(*buf); num_read++, buf++, left--) + { + value = value * 10 + (*buf - '0'); + } + //if ((cur_num_digits > 0 && num_read == cur_num_digits) || (cur_num_digits == 0 && num_read > 0)) + if (left > 0) + break; + if ((buf = ReadMore(&left)) == NULL) + return FALSE; + } + if (cur_num_digits > 0 && num_read != cur_num_digits) + { + num_read = 0; + value = 0; + } + break; + } + + if (num_read > 0) + { + value *= sign; + + switch (cur_field) + { + case SUB_CUR_FIELD_HOUR: + fields[field_idx].hour = value; + break; + case SUB_CUR_FIELD_MIN: + fields[field_idx].min = value; + break; + case SUB_CUR_FIELD_SEC: + fields[field_idx].sec = value; + break; + case SUB_CUR_FIELD_SEC256: + fields[field_idx].sec256 = value; + break; + case SUB_CUR_FIELD_MSEC: + fields[field_idx].msec = (num_read == 2) ? value * 10 : value; + break; + case SUB_CUR_FIELD_MSEC256: + fields[field_idx].msec256 = (num_read == 2) ? value * 10 : value; + break; + case SUB_CUR_FIELD_DELTA_SEC: + fields[field_idx].delta_sec = value - 1; + break; + case SUB_CUR_FIELD_DELTA_MSEC: + fields[field_idx].delta_msec = ((num_read == 1) ? value * 100 : value * 10) - 1; + break; + case SUB_CUR_FIELD_FRAMES: + fields[field_idx].frames = value; + break; + case SUB_CUR_FIELD_LINE_NUMBER: + fields[field_idx].line_number = value; + break; + case SUB_CUR_FIELD_NONE: + break; + } + if (cur_field != SUB_CUR_FIELD_NONE) + fields[field_idx].is_set = true; + + cur_mode = SUB_CUR_MODE_NORMAL; + } + else if (cur_mode == SUB_CUR_MODE_SEARCH_NEXT) + { + // skip only at current line + buf++; + left--; + if (left < 1) + { + if ((buf = ReadMore(&left)) == NULL) + return FALSE; + } + if (*buf == '\n' || left < 1) + return FALSE; + continue; + } + else if (cur_mode == SUB_CUR_MODE_OPTIONAL) + { + LoadPos(1, buf, left); + cur_mode = SUB_CUR_MODE_NORMAL; + break; + } + else + { + // failure - didn't match the template + return FALSE; + } + + cur_mode = SUB_CUR_MODE_NORMAL; + break; + } + if (left < 1) + { + buf = sub->ReadMore(&left); + if (buf == NULL) + return FALSE; + } + } + return TRUE; +} + +void Subtitles::ConvertUTF16(BYTE *buf, int *left) +{ + int l = *left; + BYTE *wb = buf; + BYTE *rb = wb; + for (; l > 0; l-=2, wb++, rb+=2) + { + WORD u = rb[0] | (rb[1] << 8); + + *wb = (u < sizeof(utf16_to_ansi_table)) ? utf16_to_ansi_table[u] : ' '; + } + + *left = wb - buf; +} + +void Subtitles::ConvertUTF16BE(BYTE *buf, int *left) +{ + int l = *left; + BYTE *wb = buf; + BYTE *rb = wb; + for (; l > 0; l-=2, wb++, rb+=2) + { + WORD u = rb[1] | (rb[0] << 8); + + *wb = (u < sizeof(utf16_to_ansi_table)) ? utf16_to_ansi_table[u] : ' '; + } + + *left = wb - buf; +} + +int Subtitles::ConvertUTF8(BYTE *buf, int *left) +{ + int l = *left - 6; + int d = 1; + BYTE *wb = buf; + BYTE *rb = wb; + + for (; l > 0; wb++, rb += d, l -= d) + { + WORD u = 0xffff; + d = 1; + if ((rb[0] & 0x80) == 0x00) + u = rb[0]; + else if ((rb[0] & 0xe0) == 0xc0 && (rb[1] & 0xc0) == 0x80) + { + u = ((rb[0] & 0x1fL) << 6) | ((rb[1] & 0x3fL) << 0); + if (u >= 0x00000080L) + d = 2; + } + else if ((rb[0] & 0xf0) == 0xe0 && (rb[1] & 0xc0) == 0x80 && (rb[2] & 0xc0) == 0x80) + { + u = ((rb[0] & 0x0fL) << 12) | ((rb[1] & 0x3fL) << 6) | ((rb[2] & 0x3fL) << 0); + if (u >= 0x00000800L) + d = 3; + } + else if ((rb[0] & 0xf8) == 0xf0 && (rb[1] & 0xc0) == 0x80 && (rb[2] & 0xc0) == 0x80 && + (rb[3] & 0xc0) == 0x80) + { + u = ((rb[0] & 0x07L) << 18) | ((rb[1] & 0x3fL) << 12) | + ((rb[2] & 0x3fL) << 6) | ((rb[3] & 0x3fL) << 0); + if (u >= 0x00010000L) + d = 4; + } + else if ((rb[0] & 0xfc) == 0xf8 && (rb[1] & 0xc0) == 0x80 && (rb[2] & 0xc0) == 0x80 && + (rb[3] & 0xc0) == 0x80 && (rb[4] & 0xc0) == 0x80) + { + u = ((rb[0] & 0x03L) << 24) | ((rb[1] & 0x3fL) << 18) | + ((rb[2] & 0x3fL) << 12) | ((rb[3] & 0x3fL) << 6) | ((rb[4] & 0x3fL) << 0); + if (u >= 0x00200000L) + d = 5; + } + else if ((rb[0] & 0xfe) == 0xfc && (rb[1] & 0xc0) == 0x80 && (rb[2] & 0xc0) == 0x80 && + (rb[3] & 0xc0) == 0x80 && (rb[4] & 0xc0) == 0x80 && (rb[5] & 0xc0) == 0x80) + { + u = ((rb[0] & 0x01L) << 30) | ((rb[1] & 0x3fL) << 24) | ((rb[2] & 0x3fL) << 18) | + ((rb[3] & 0x3fL) << 12) | ((rb[4] & 0x3fL) << 6) | ((rb[5] & 0x3fL) << 0); + if (u >= 0x04000000L) + d = 6; + } + + *wb = (u < sizeof(utf16_to_ansi_table)) ? utf16_to_ansi_table[u] : ' '; + } + + *left = wb - buf; + + return rb - buf; +} + +BYTE *Subtitles::ReadMore(int *left, bool force_read) +{ + // we don't want to read more data if subtitle format is unknown + if (cur_method < 0 && !force_read) + return NULL; + int new_bufidx = (++buf_idx) & 1; + BYTE *b = buf[new_bufidx]; + if (buf_read_cnt <= buf_cnt[new_bufidx]) + { + *left = buf_read_left[new_bufidx]; + } else + { + int left0 = read(fd, b, read_buf_length); + if (is_start_of_file) + { + if (b[0] == 0xff && b[1] == 0xfe) + { + sub->is_utf16 = true; + msg("Subtitle: UTF-16 Detected!\n"); + FillUTFTable(params->info.subtitle_charset); + b += 2; + left0 -= 2; + } + if (b[0] == 0xfe && b[1] == 0xff) + { + sub->is_utf16be = true; + msg("Subtitle: UTF-16BE Detected!\n"); + FillUTFTable(params->info.subtitle_charset); + b += 2; + left0 -= 2; + } + else if (b[0] == 0xef && b[1] == 0xbb && b[2] == 0xbf) + { + sub->is_utf8 = true; + msg("Subtitle: UTF-8 Detected!\n"); + FillUTFTable(params->info.subtitle_charset); + b += 3; + left0 -= 3; + } + is_start_of_file = false; + } + *left = left0; + + // UTF8/16 conversion + if (sub->is_utf16) + { + ConvertUTF16(b, left); + } + if (sub->is_utf16be) + { + ConvertUTF16BE(b, left); + } + else if (sub->is_utf8) + { + left0 -= ConvertUTF8(b, left); + lseek(fd, -left0, SEEK_CUR); + } + + buf_read_cnt++; + } + if (*left < 1) + { + if (*left < 0) + { + msg("Subtitle: cannot read file!\n"); + } + return NULL; + } + buf_read_left[new_bufidx] = *left; + buf_cnt[new_bufidx] = buf_read_cnt; + buf_idx = new_bufidx; + return b; +} + +void Subtitles::SavePos(int saveidx, BYTE *buf, int left) +{ + saved_bufidx[saveidx] = buf_idx; + saved_buf[saveidx] = buf; + saved_left[saveidx] = left; + saved_bufcnt[saveidx] = buf_cnt[buf_idx]; +} + +BOOL Subtitles::LoadPos(int saveidx, BYTE *&buf, int &left) +{ + if (buf_cnt[saved_bufidx[saveidx]] != saved_bufcnt[saveidx] || saved_buf[saveidx] == NULL) + return FALSE; + buf_idx = saved_bufidx[saveidx]; + buf = saved_buf[saveidx]; + left = saved_left[saveidx]; + return TRUE; +} + +/////////////////////////////////////////////////////////////// + +void Subtitle::Add(BYTE *str, int str_length, SubtitleFields result[2]) +{ + if (str_length > 0) + sub->AddString(str, str_length, false); + + SubtitleRecord rec; + rec.string_length = (WORD)str_length; + rec.delta_time = GetTime(result[0]); + records.Add(rec); + + if (result[1].is_set) + { + SubtitleRecord rec; + rec.string_length = 0; + rec.delta_time = GetTime(result[1]); + records.Add(rec); + } +} + +short Subtitle::GetTime(const SubtitleFields & f) +{ + int new_time = cur_time; + if (f.frames >= 0) + { + new_time = (int)(INT64(100000) * (LONGLONG)f.frames / fps); + } + else + { + if (f.sec256 >= 0 && f.msec256 >= 0) + { + new_time = f.sec256 * 100 + f.msec256 / 10; + if (new_time < last_256 || new_time > last_256 + 25600) + last_256_add += 25600; + last_256 = new_time; + new_time += last_256_add; + } + if (f.delta_sec != -1) + { + new_time += (f.delta_sec + 1) * 100; + } + if (f.delta_msec != -1) + { + new_time += (f.delta_msec + 1) / 10; + } + + if (f.sec >= 0) + { + new_time = f.hour * 360000 + f.min * 6000 + f.sec * 100 + f.msec / 10; + } + } + int delta = new_time - cur_time; + cur_time = new_time; + return (short)delta; +} + + +///////////////////////////////////////////////////////////////////// + +int SimilarityCompare(SPString *str1, SPString *str2) +{ + // this is a little bit slow + SPString s[2]; + s[0] = *str1; + s[1] = *str2; + for (int i = 0; i < 2; i++) + { + int name_pos = s[i].ReverseFind('/'); + if (name_pos > 0) + s[i] = s[i].Mid(name_pos + 1); + name_pos = s[i].ReverseFind('.'); + if (name_pos >= 0) + s[i] = s[i].Left(name_pos); + } + + return sub->vid_file.Similar(s[1]) - sub->vid_file.Similar(s[0]); +} + +BOOL read_subtitles(char *video_fname) +{ + static const char *subt_ext[] = { ".sub", ".srt", ".ssa", ".txt", NULL }; + int i; + SPSafeDelete(sub); + sub = new Subtitles; + + if (params == NULL) + return FALSE; + + fip_write_string("LoAd"); + + sub->InitTranslationTable(params->info.subtitle_charset); + sub->max_line_letters_cnt = params->info.subtitle_wrap; + + // now add subtitle files + for (i = 0; i < params->playlists.GetN(); i++) + { + if (params->playlists[i] == NULL) + continue; + SPList &il = params->playlists[i]->items; + + for (int j = 0; j < il.GetN(); j++) + { + SPString &name = il[j]->name; + // check extensions + bool found = false; + for (int k = 0; subt_ext[k] != NULL; k++) + { + if (name.FindNoCase(subt_ext[k]) == name.GetLength() - 4) + { + found = true; + break; + } + } + if (found) + { + if (sub->subs.GetN() < max_allowed_playlist_subs) + { + add_subtitle_file(name); + // enable first user-selected subtitle file by default + if (sub->subs.GetN() > 0) + sub->cur_sub = 0; + } + + // now remove item from the playlist + if (params->playlists[i]->itemhash != NULL) + params->playlists[i]->itemhash->Remove(*il[j]); + SPSafeDelete(il[j]); + il.Remove(j); + j--; + } + } + } + +//!!!!!!!!!!!!!!!!!!!! +//add_subtitle_file("/cdrom/SUB/MicroDVD.sub"); +//add_subtitle_file("/cdrom/SUB/MPSub.sub"); +//add_subtitle_file("/cdrom/SUB/DVDSubtitle.sub"); +//add_subtitle_file("/cdrom/SUB/SubViewer 1.0.sub"); +//add_subtitle_file("/cdrom/SUB/SubSonic.sub"); +//add_subtitle_file("/cdrom/SUB/SubRip.srt"); + +//add_subtitle_file("/cdrom/SUB/LOTR/DVD Architect.sub"); +//add_subtitle_file("/cdrom/SUB/LOTR/DVDSubtitle.sub"); +//add_subtitle_file("/cdrom/SUB/LOTR/MicroDVD.sub"); +//add_subtitle_file("/cdrom/SUB/LOTR/MPSub.sub"); +//add_subtitle_file("/cdrom/SUB/LOTR/SubRip.srt"); +//add_subtitle_file("/cdrom/SUB/LOTR/SubSonic.sub"); +//add_subtitle_file("/cdrom/SUB/LOTR/SubStation Alpha.ssa"); +//add_subtitle_file("/cdrom/SUB/LOTR/SubViewer1.sub"); +//add_subtitle_file("/cdrom/SUB/LOTR/SubViewer2.sub"); +//add_subtitle_file("/cdrom/SUB/LOTR/TMPlayer.sub"); +//add_subtitle_file("/cdrom/Scary_movie_RUS_2000.srt"); + + // try adding curdir subtitle, if there's only one (and it wasn't added) + if (sub->subs.GetN() == 0) + { + SPClassicList files; + DIR *dir = cdrom_opendir(params->folder); + SPString name, path = params->folder; + if (path.ReverseFind('/') != path.GetLength() - 1) + path += "/"; + while (dir != NULL) + { + struct dirent *d = cdrom_readdir(dir); + if (d == NULL) + break; + if ((d->d_name[0] == '.' && d->d_name[1] == '\0') || + (d->d_name[0] == '.' && d->d_name[1] == '.' && d->d_name[2] == '\0')) + continue; + struct stat64 statbuf; + name = path + d->d_name; + if (cdrom_stat(*name, &statbuf) < 0) + { + msg("Subtitle: Cannot stat %s\n", *name); + statbuf.st_mode = 0; + //continue; + } + if (S_ISDIR(statbuf.st_mode)) + continue; + + // is it subtitle file? + bool found = false; + for (int k = 0; subt_ext[k] != NULL; k++) + { + if (name.FindNoCase(subt_ext[k]) == name.GetLength() - 4) + { + found = true; + break; + } + } + if (found) + { + found = false; + for (int i = 0; i < sub->subs.GetN(); i++) + { + if (sub->subs[i]->fname.CompareNoCase(name) == 0) + { + found = true; + break; + } + } + if (!found) + files.Add(name); + } + } + cdrom_closedir(dir); + + sub->vid_file = video_fname; + int name_pos = sub->vid_file.ReverseFind('/'); + if (name_pos > 0) + sub->vid_file = sub->vid_file.Mid(name_pos + 1); + name_pos = sub->vid_file.ReverseFind('.'); + if (name_pos >= 0) + sub->vid_file = sub->vid_file.Left(name_pos); + + // now sort and cut the list + files.Sort(SimilarityCompare); + for (int i = 0; i < files.GetN() && sub->subs.GetN() < max_allowed_playlist_subs; i++) + { + add_subtitle_file(files[i]); + } + } + + return TRUE; +} + +BOOL delete_subtitles() +{ + SPSafeDelete(sub); + return TRUE; +} + +BOOL add_subtitle_file(char *fname) +{ + if (sub == NULL) + return FALSE; + + msg("Subtitle: Reading %s...\n", fname); + + sub->Reset(); + + sub->fd = cdrom_open(fname, O_RDONLY); + if (sub->fd < 0) + { + msg("Subtitle: cannot open file %s\n", fname); + return FALSE; + } + + int line_num = 0; + Subtitle *news = NULL; + + sub->cur_method = -1; + bool detected = false; + + BYTE str_buf[4096]; + + for (;;) + { + int left = 0; + BYTE *buf = sub->ReadMore(&left, !detected); + if (buf == NULL) + break; + + while (left > 0) + { + int method = MAX(sub->cur_method, 0); + SubtitleFields result[2]; + bool found = false; + do + { + sub->SavePos(0, buf, left); + if (sub->Scan(buf, left, line_num, method, result)) + { + found = true; + break; + } + // try again + if (sub->cur_method < 0) + { + if (!sub->LoadPos(0, buf, left)) + { + close(sub->fd); + return FALSE; + } + } + method++; + } while (sub->cur_method < 0 && sub_formats[method].name != NULL); + // skip or need more data? + if (!found) + { + do + { + while (left > 0 && *buf != '\n') + { + buf++; + left--; + } + } while (left < 1 && (buf = sub->ReadMore(&left)) != NULL); + do + { + while (left > 0 && (*buf == '\n' || *buf == '\r')) + { + buf++; + left--; + } + } while (left < 1 && (buf = sub->ReadMore(&left)) != NULL); + continue; + } + + sub->cur_method = method; + + // add subtitle to the list + if (!detected) + { + news = new Subtitle(); + news->fname = fname; + news->name = fname; + int name_pos = news->name.ReverseFind('/'); + if (name_pos > 0) + news->name = news->name.Mid(name_pos + 1); + name_pos = news->name.ReverseFind('.'); + if (name_pos >= 0) + news->name = news->name.Left(name_pos); + news->name = news->name.Left(10); + + if (sub->data.GetN() > 0) + { + news->data_idx = sub->data.GetN() - 1; + SubtitleData *d = sub->data[news->data_idx]; + news->data_start_pos = d->cur - d->ptr; + } else + { + news->data_idx = 0; + news->data_start_pos = 0; + } + news->cur_data_idx = news->data_idx; + news->cur_data_pos = news->data_start_pos; + sub->subs.Add(news); + detected = true; + + msg("Subtitle: * %s format detected!\n", sub_formats[sub->cur_method].name); + } + + // now read the string + BYTE *str = str_buf; + const char *end = sub_formats[method].end; + int str_length = 0; + found = false; + + while (left > 0 && str_length < 4096) + { + found = true; + sub->SavePos(1, buf, left); + const char *e = end; + do + { + for (; *e != '\0' && left > 0; buf++, left--) + { + if (*buf == '\r') + continue; + if (*buf != *e) + { + found = false; + break; + } + e++; + } + } while (left < 1 && (buf = sub->ReadMore(&left)) != NULL); + if (buf == NULL) + break; + if (found) + break; + sub->LoadPos(1, buf, left); + if (*buf != '\r') + { + *str++ = *buf; + str_length++; + } + + buf++; + left--; + + if (left < 1) + { + if ((buf = sub->ReadMore(&left)) == NULL) + { + close(sub->fd); + return FALSE; + } + } + } + + + if (news->fps == 0 && result[0].frames > 0) + { + char buf[128]; + int l = MIN(str_length, 100); + strncpy(buf, (const char *)str_buf, l); + buf[l] = '\0'; + int f1 = 0, f2 = 0; + sscanf(buf, "%d.%d", &f1, &f2); + news->fps = f1 * 1000 + f2; + continue; + } + + if (result[0].line_number > 1) + { + // attach to previous string + if (str_length > 0) + { + sub->AddString(str_buf, str_length, true); + SubtitleRecord &rec = news->records[news->records.GetN() - 1]; + rec.string_length = (WORD)(rec.string_length + str_length + 1); + } + } else + { + news->Add(str_buf, str_length, result); + line_num = (line_num + 1) & 1; + } + } + + // if didn't guess, no need to read more... + if (sub->cur_method < 0) + { + msg("Subtitle: Error! Unknown subtitle file format.\n"); + close(sub->fd); + return FALSE; + } + } + + news->is_ready = true; + if (news->records.GetN() > 0) + { + news->cur_pts = news->records[0].delta_time * 900; + news->cur_record = 0; + } + + close(sub->fd); + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#if 0 +{ +int sub_idx = 0; +if (sub->subs.GetN() > sub_idx && sub->subs[sub_idx]->is_ready) +{ + int pi = sub->subs[sub_idx]->data_idx, pp = sub->subs[sub_idx]->data_start_pos, t = 0; + for (int z = 0; z < sub->subs[sub_idx]->records.GetN(); z++) + { + int l = sub->subs[sub_idx]->records[z].string_length; + char *s; + t += sub->subs[sub_idx]->records[z].delta_time; + if (l > 0) + { + s = sub->data[pi]->ptr + pp; + pp += l + 1; + } + else + s = ""; + if (sub->data.GetN() > 0) + if (pp >= sub->data[pi]->len) + { + if (pi < sub->data.GetN() - 1) + pi++; + pp = 0; + } + } +} +} +#endif + return TRUE; +} + +BOOL show_subtitles(LONGLONG pts) +{ + if (sub == NULL || sub->cur_sub < 0 || pts < 0) + return FALSE; + + Subtitle *cur = sub->subs[sub->cur_sub]; + + const char *s = NULL; + if (pts > cur->cur_pts) + { + for (int z = cur->cur_record; z < cur->records.GetN(); z++) + { + SubtitleRecord &r = cur->records[z]; + LONGLONG d_pts = (LONGLONG)((int)r.delta_time * 900); + + if (z != cur->cur_record) + { + cur->cur_pts += d_pts; + cur->cur_record = z; + if (pts < cur->cur_pts) + break; + } + + cur->cur_last_pts = cur->cur_pts; + cur->cur_last_record = z; + int l = cur->records[cur->cur_record].string_length; + if (l > 0 && sub->data.GetN() > 0) + { + s = sub->data[cur->cur_data_idx]->ptr + cur->cur_data_pos; + cur->cur_data_pos += l + 1; + if (cur->cur_data_pos >= sub->data[cur->cur_data_idx]->len) + { + if (cur->cur_data_idx < sub->data.GetN() - 1) + cur->cur_data_idx++; + cur->cur_data_pos = 0; + } + } + else + s = ""; + } + } + else if (pts < cur->cur_last_pts && cur->cur_last_record > 0) + { + int z; + for (z = cur->cur_last_record; z >= 0; z--) + { + SubtitleRecord &r = cur->records[z]; + LONGLONG d_pts = (LONGLONG)((int)r.delta_time * 900); + + cur->cur_pts = cur->cur_last_pts; + cur->cur_record = cur->cur_last_record; + cur->cur_last_record--; + cur->cur_last_pts -= d_pts; + + int l = cur->records[z].string_length; + if (l > 0 && sub->data.GetN() > 0) + { + cur->cur_data_pos -= l + 1; + if (cur->cur_data_pos < 0) + { + if (cur->cur_data_idx > 0) + { + cur->cur_data_idx--; + cur->cur_data_pos = sub->data[cur->cur_data_idx]->len - (l + 1); + } else + cur->cur_data_pos = 0; + } + } + + if (pts > cur->cur_last_pts) + break; + } + if (z < 0 || cur->cur_last_pts == 0) + { + cur->cur_last_pts = 0; + cur->cur_last_record = -1; + if (cur->records.GetN() > 0) + { + cur->cur_pts = cur->records[0].delta_time * 900; + cur->cur_record = 0; + } + } + // don't show subtitles in reverse mode + s = ""; + } + + if (s != NULL) + { + int t = (int)(pts / 900); + msg("[%02d:%02d:%02d.%02d] %s\n\n", t/360000, (t % 360000) / 6000, (t % 6000) / 100, (t % 100), s); + script_player_subtitle_callback(s); + return TRUE; + } + return FALSE; +} + +BOOL subtitle_next() +{ + if (sub == NULL || sub->subs.GetN() < 1 || params == NULL) + return FALSE; + if (++sub->cur_sub >= sub->subs.GetN()) + sub->cur_sub = -1; + params->info.spu_stream = sub->cur_sub + 1; + if (sub->cur_sub >= 0) + { + params->info.spu_lang = sub->subs[sub->cur_sub]->name; + msg("Subtitle: * Set to '%s'.\n", *params->info.spu_lang); + } + else + { + params->info.spu_lang = SPString(); + msg("Subtitle: * Disabled.\n"); + } + + script_player_subtitle_callback(""); + return TRUE; +} diff --git a/src/subtitle.h b/src/subtitle.h new file mode 100644 index 0000000..8ca3f71 --- /dev/null +++ b/src/subtitle.h @@ -0,0 +1,280 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Subtitles for video player header file + * \file subtitle.h + * \author bombur + * \version 0.1 + * \date 01.10.2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_SUBTITLE_H +#define SP_SUBTITLE_H + +/// 1 Subtitle record +typedef struct SubtitleRecord +{ + short delta_time; // in 1/100 secs + WORD string_length; // string length (not including '\0') +} SubtitleRecord; + +typedef struct SubtitleFormat +{ + const char *name; + const char *start[32]; + const char *end; +} SubtitleFormat; + +typedef struct SubtitleFields +{ + int hour; + int min; + int sec; + int msec; + int sec256; + int msec256; + int delta_sec; + int delta_msec; + int frames; + int line_number; + bool is_set; +} SubtitleFields; + +#define SUB_TOKEN_HOUR1 0x1 +#define SUB_TOKEN_HOUR2 0x101 +#define SUB_TOKEN_HOUR1_1 0x2 +#define SUB_TOKEN_HOUR2_1 0x102 + +#define SUB_TOKEN_MIN1 0x3 +#define SUB_TOKEN_MIN2 0x103 + +#define SUB_TOKEN_SEC1 0x4 +#define SUB_TOKEN_SEC2 0x104 + +#define SUB_TOKEN_DSEC1 0x5 +#define SUB_TOKEN_DSEC2 0x105 + +#define SUB_TOKEN_MSEC1 0x6 +#define SUB_TOKEN_MSEC2 0x106 + +#define SUB_TOKEN_SEC1_256 0x7 +#define SUB_TOKEN_DSEC1_256 0x8 + +#define SUB_TOKEN_DELTA_SECS1 0x9 +#define SUB_TOKEN_DELTA_SECS2 0x109 + +#define SUB_TOKEN_DELTA_MSECS1 0xa +#define SUB_TOKEN_DELTA_MSECS2 0x10a + +#define SUB_TOKEN_FRAMES1 0xb +#define SUB_TOKEN_FRAMES2 0x10b + +#define SUB_TOKEN_LINE_NUMBER 0xc + +// special +#define SUB_TOKEN_SKIP_DIGITS 0x20 +#define SUB_TOKEN_SKIP_DIGITS_4 0x24 +#define SUB_TOKEN_SKIP_TO_NEXT 0x30 +#define SUB_TOKEN_OPTIONAL_NEXT 0x40 +#define SUB_TOKEN_OPTIONAL_NEXT_2 0x41 + +#define SUB(s) (const char *)s + +enum SUB_CUR_FORMAT +{ + SUB_CUR_FORMAT_STRING = 0, + SUB_CUR_FORMAT_DIGITS, + SUB_CUR_FORMAT_DIGITS_SIGN, +}; + +enum SUB_CUR_MODE +{ + SUB_CUR_MODE_NORMAL = 0, + SUB_CUR_MODE_SEARCH_NEXT, + SUB_CUR_MODE_OPTIONAL, +}; + +enum SUB_CUR_FIELD +{ + SUB_CUR_FIELD_NONE = 0, + SUB_CUR_FIELD_HOUR, + SUB_CUR_FIELD_MIN, + SUB_CUR_FIELD_SEC, + SUB_CUR_FIELD_SEC256, + SUB_CUR_FIELD_MSEC, + SUB_CUR_FIELD_MSEC256, + SUB_CUR_FIELD_DELTA_SEC, + SUB_CUR_FIELD_DELTA_MSEC, + SUB_CUR_FIELD_FRAMES, + SUB_CUR_FIELD_LINE_NUMBER, +}; + +enum SUBTITLE_CHARSET +{ + SUBTITLE_CHARSET_DEFAULT, + SUBTITLE_CHARSET_ISO8859_1, + SUBTITLE_CHARSET_ISO8859_2, + SUBTITLE_CHARSET_CP1251, + SUBTITLE_CHARSET_KOI8R, +}; + +const int max_string_length = 8192; +const int read_buf_length = 4096; + +/////////////////////////////////////////////////////////// + +class Subtitle +{ +public: + /// ctor + Subtitle() + { + is_ready = false; + data_idx = 0; + data_start_pos = 0; + fps = 0; + cur_time = 0; + last_256 = 0; + last_256_add = 0; + + cur_record = 0; + cur_last_record = -1; + cur_pts = cur_last_pts = 0; + cur_data_idx = 0; + cur_data_pos = 0; + } + + void Add(BYTE *str, int str_length, SubtitleFields result[2]); + + /// Get time, in 1/100s of second. + short GetTime(const SubtitleFields & f); + +public: + SPList records; + bool is_ready; + + int data_idx, data_start_pos; + LONGLONG fps; + SPString fname, name; + + int cur_time; + int last_256, last_256_add; + + // the _next_ record we're waiting for + int cur_record, cur_data_idx, cur_data_pos; + int cur_last_record; + LONGLONG cur_pts, cur_last_pts; +}; + + +class SubtitleData +{ +public: + /// ctor + SubtitleData() + { + ptr = NULL; + cur = NULL; + len = 0; + left = max_string_length; + } + /// dtor + ~SubtitleData() + { + SPSafeFree(ptr); + } + + BOOL Alloc(int add_size); + +public: + char *ptr, *cur; + int len, left; +}; + +class Subtitles +{ +public: + /// ctor + Subtitles(); + /// dtor + ~Subtitles(); + + /// Reset subtitle parser. + void Reset(); + + void InitTranslationTable(SUBTITLE_CHARSET charset); + + /// Read more data to the buffer + BYTE *ReadMore(int *left, bool force_read = false); + + /// Add string and return offset + int AddString(BYTE *, int &length, bool attach); + + int Scan(BYTE *&buf, int &left, int line_num, int method, SubtitleFields fields[2]); + + void SavePos(int saveidx, BYTE *buf, int left); + BOOL LoadPos(int saveidx, BYTE *&buf, int &left); + +public: + SPList subs; + SPList data; + + /// Current video file being played. + SPString vid_file; + + int max_line_letters_cnt; + + BYTE buf[2][read_buf_length]; + int buf_idx; + int buf_cnt[2]; // used to identify buffers (check for changes and avoid double reading) + int buf_read_left[2]; + int buf_read_cnt; + int fd; + + int cur_method; + + int cur_sub; + + int saved_bufidx[2], saved_left[2]; + int saved_bufcnt[2]; + BYTE *saved_buf[2]; + + BYTE charset_translation_table[256]; + BYTE utf16_to_ansi_table[2048]; + + bool is_start_of_file; + bool is_utf8, is_utf16, is_utf16be; + +protected: + + int ConvertUTF8(BYTE *buf, int *left); // returns number of bytes read + void ConvertUTF16(BYTE *buf, int *left); + void ConvertUTF16BE(BYTE *buf, int *left); + void FillUTFTable(SUBTITLE_CHARSET charset); +}; + +BOOL read_subtitles(char *video_fname); + +BOOL delete_subtitles(); + +BOOL add_subtitle_file(char *fname); + +BOOL show_subtitles(LONGLONG pts); + +BOOL subtitle_next(); + +#endif // of SP_SUBTITLE_H diff --git a/src/version-DX.h b/src/version-DX.h new file mode 100644 index 0000000..e84d349 --- /dev/null +++ b/src/version-DX.h @@ -0,0 +1,5 @@ + + +const char * const SP_NAME = "SP-DX"; + +const int SP_VERSION = 151; diff --git a/src/version-MP.h b/src/version-MP.h new file mode 100644 index 0000000..8bd03af --- /dev/null +++ b/src/version-MP.h @@ -0,0 +1,4 @@ + +const char * const SP_NAME = "SP-MP"; + +const int SP_VERSION = 151; diff --git a/src/version-MT.h b/src/version-MT.h new file mode 100644 index 0000000..4bdcafe --- /dev/null +++ b/src/version-MT.h @@ -0,0 +1,4 @@ + +const char * const SP_NAME = "SP-MT"; + +const int SP_VERSION = 151; diff --git a/src/version-WIN.h b/src/version-WIN.h new file mode 100644 index 0000000..e9617fe --- /dev/null +++ b/src/version-WIN.h @@ -0,0 +1,4 @@ + +const char * const SP_NAME = "SP-WIN"; + +const int SP_VERSION = 151; diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..4d8c75f --- /dev/null +++ b/src/version.h @@ -0,0 +1,22 @@ +#ifndef SP_VERSION_H +#define SP_VERSION_H + + +#ifdef SP_PLAYER_TECHNOSONIC + #include "version-MP.h" +#endif + +#ifdef SP_PLAYER_DREAMX108 + #include "version-DX.h" +#endif + +#ifdef SP_PLAYER_MECOTEK + #include "version-MT.h" +#endif + +#ifdef WIN32 + #include "version-WIN.h" +#endif + + +#endif // of SP_VERSION_H diff --git a/src/video.cpp b/src/video.cpp new file mode 100644 index 0000000..2238594 --- /dev/null +++ b/src/video.cpp @@ -0,0 +1,2125 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Video player source file. + * \file video.cpp + * \author bombur + * \version 0.1 + * \date 07.03.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef INTERNAL_VIDEO_PLAYER + +#define RESYNC_TIMEOUT INT64(120000) + +#define NEW_SYNC +#define USE_RESYNCS_CONTROL + +//#define SKIP_AUDIO + +#define VIDEO_INTERNAL +#include +#include +#include +#include +#include +#include + +int num_packets = 0; +static int info_cnt = 0; +bool video_msg = true; +#define MSG if (video_msg) msg + +static int max_info_cnt = 32; +static const int DIVX3_BUF_MARGIN = 128; + + +//#define VIDEO_PACKET_DEBUG +//#define VIDEO_USE_MMAP + +#define DUMP_FRAME msg +//#define DUMP_FRAME gui_update();msg + +static Video *video = NULL; + +BYTE *VideoAlloc(int size) +{ +#ifdef VIDEO_USE_MMAP + return (BYTE *)mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); +#else + return (BYTE *)SPmalloc(size); +#endif +} + +void VideoFree(BYTE *&buf, int /*size*/) +{ + if (buf != NULL) + { +#ifdef VIDEO_USE_MMAP + munmap(buf, size); +#else + SPfree(buf); +#endif + buf = NULL; + } + +} + +//////////////////////////////////////// +// some helper functions for MPEG stream parsing + +static void video_bits_init(BYTE *buf, int len); +static int video_skip_bits(int num_bits); +static DWORD video_get_bits(int num_bits); +static int video_log2(DWORD v); + + +Video::Video() +{ + int i; + type = VIDEO_CONTAINER_UNKNOWN; + + playing = false; + stopping = false; + is_eof = false; + event = MEDIA_EVENT_OK; + scale = 1000; + rate = 24000; + scr = 0; + saved_pts = 0; + displ_pts_base = 0; + video_fmt = RIFF_VIDEO_UNKNOWN; + audio_fmt = RIFF_AUDIO_UNKNOWN; + chunktype = VIDEO_CHUNK_UNKNOWN; + chunkleft = 0; + look4chunk = false; + test_for_qpel_gmc = true; + wait_for_resync = false; + + for (i = 0; i < 16; i++) + { + mux_buf[i] = NULL; + allocated_mux_buf[i] = NULL; + allocated_mux_buf_size[i] = 0; + divx_buf[i] = NULL; + divx_base[i] = NULL; + } + mux_numbufs = 12; + mux_bufsize = 32768; + allocated_numbufs = 0; + no_partial = false; + + fd = -1; + + width = height = 0; + fps = 0; + qpel_flag = false; + gmc_flag = false; + video_frames = 0; + fourcc[0] = '\0'; + + cur_track = 0; + first_track = 0; + num_tracks = 0; + cur_audio_bits = 0; + + for (i = 0; i < VIDEO_MAX_AUDIO_TRACKS; i++) + { + track[i].wfe = NULL; + } + + min_delta_pts = 2000; + max_delta_pts = 8000; + minus_delta_pts = 0; + saved_video_pts = 0; + video_pos_base = 0; + abs_video_pos = 0; + ResetAvgPts(); + + total_frames = 0; + audio_total_bytes = 0; + audio_delta = SPTM_SCR_FLAG; + audio_pts_offset = 0; + + video_pos = 0; + last_key_pos = -min_delta_keyframes - 1; + cur_key_pos = 0; + + cur_key_idx = 0; + last_good_key_idx = -1; + last_key_idx = -1; + + frame_pos = 0; + last_frame_pos = 0; + + max_rev_incr = def_max_rev_incr; + + searching = false; + skip_fwd = false; + skip_rev = false; + skip_wait = false; + skip_waiting = false; + last_keyframe_time = 0; + delayed_skip = 0; + cancel_skip = false; + audio_halfrate = false; + skip_cnt = 0; + + cur_offs = 0; + + video_packet_len = 0; + old_video_packet_len = 0; + + good_delta_stc = 90000; + + in_divx_packet = false; + need_to_stop = false; +} + +Video::~Video() +{ + int i; + for (i = VIDEO_MAX_AUDIO_TRACKS - 1; i >= 0; i--) + SPSafeFree(track[i].wfe); + for (i = 15; i >= 0; i--) + { + //SPSafeFree(divx_base[i]); + VideoFree(divx_base[i], (video->mux_bufsize + DIVX3_BUF_MARGIN * 2 + 8)); + } + for (i = allocated_numbufs - 1; i >= 0; i--) + { + //SPSafeFree(mux_buf[i]); + VideoFree(allocated_mux_buf[i], allocated_mux_buf_size[i]); + } +} + +VideoKeyFrame *Video::GetIndex(int idx) +{ + int y = idx / num_key_frames_block; + if (y >= indexes.GetN()) + return NULL; + int x = idx % num_key_frames_block; + if (x >= indexes[y].GetN()) + return NULL; + return &indexes[y][x]; +} + +int Video::GetKeyFrame(LONGLONG time) +{ + int idx1 = 0, idx2 = last_key_idx; + static LONGLONG stime; + + bool need_to_restore_pos = false; + + if (time == VIDEO_KEY_FRAME_CONTINUE) + time = stime; + else + stime = time; + + switch (time) + { + case VIDEO_KEY_FRAME_NEXT: + msg("Video: SEARCH NEXT!\n"); + idx1 = idx2 = cur_key_idx + 1; + skip_cnt++; + break; + case VIDEO_KEY_FRAME_PREV: + msg("Video: SEARCH PREV!\n"); + idx1 = idx2 = cur_key_idx - 1; + skip_cnt++; + break; + default: + { + msg("Video: SEARCH TIME = %d !\n", (int)time); + VideoKeyFrame *curidx = GetIndex(cur_key_idx); + if (curidx != NULL) + { + if (time < curidx->i * scale / rate) + { + idx1 = 0; idx2 = cur_key_idx - 1; + } else + { + idx1 = cur_key_idx; idx2 = last_key_idx; + } + } + } + break; + } + + // now we have idx range, so use dichotomy + int ret = 0; + while (idx1 <= idx2) + { + VideoKeyFrame *lastidx = GetIndex(last_key_idx); + if (lastidx != NULL) + { + LONGLONG last_time = lastidx->i * scale / rate; + if (time > last_time) + { + idx1 = last_key_idx + 1; + ret = GetNextIndexes(); + need_to_restore_pos = true; + idx2 = MAX(last_key_idx, idx1); + if (ret < 0) + break; + continue; + } + } + // if we need to extend index more... + if (idx2 > last_key_idx) + { + int k; + for (k = 0; k < max_rev_incr; k++) + { + ret = GetNextIndexes(); + need_to_restore_pos = true; + if (ret != 0) + break; + } + max_rev_incr += def_max_rev_incr; + if (ret < 0 && k == 0) + break; + ret = 0; + continue; + } + if (idx1 == idx2) + break; + // ok, now all range is inside buf + int newidx = (idx1 + idx2) / 2; + VideoKeyFrame *median = GetIndex(newidx); + if (median == NULL) + break; + if (time <= median->i * scale / rate) + { + idx2 = newidx; + } else + { + idx1 = newidx + 1; + } + } + +msg("[%d] ret=%d idx1=%d idx2=%d\n", cur_key_idx, ret, idx1, idx2); + + if (ret >= 0 && idx1 == idx2) + { + if (idx1 < 0) + { + video->cancel_skip = true; + return 0; + } + VideoKeyFrame *idx = GetIndex(idx1); + if (idx != NULL) + { + abs_video_pos = idx->i; + last_chunk_len = video_packet_len = idx->len; + cur_key_offs = last_chunk_offs = video_offs = idx->offs; + video_lseek(video_offs, SEEK_SET); + MSG("AVI: I-FRAME #%d @ (" PRINTF_64d ",%d)\n", abs_video_pos, idx->offs, idx->len); + if (time != VIDEO_KEY_FRAME_NEXT && time != VIDEO_KEY_FRAME_PREV) + cur_key_idx = 0; + last_good_key_idx = idx1; + scr = INT64(90000) * abs_video_pos * scale / rate; + info_cnt = max_info_cnt + 1; + return 1; + } + } + + // we failed to search in index + if (ret < 0 && time == VIDEO_KEY_FRAME_NEXT) + { + if (need_to_restore_pos) + { + if (last_chunk_len < 1) + return -1; + video_lseek(last_chunk_offs + 8 + PAD_EVEN(last_chunk_len), SEEK_SET); + } + return GetNextKeyFrame(); + } + + return -1; +} + +void Video::UpdateTotalTime() +{ + // do nothing, normally total play time cannot change +} + +int Video::SetCurrentIndex(int i, int len, LONGLONG offs) +{ + int cur_index_x, cur_index_y; + if (i >= last_key_pos + min_delta_keyframes) + { + if (AddIndex(i, len, offs) < 0) + return -1; + } + if (cur_key_idx > 0) + { + int cki = cur_key_idx - 1; + cur_index_x = cki % num_key_frames_block; + for (cur_index_y = cki / num_key_frames_block; cur_index_y >= 0; cur_index_y--, cur_index_x = indexes[cur_index_y].GetN() - 1) + { + for (; cur_index_x >= 0; cur_index_x--, cki--) + { + if (indexes[cur_index_y][cur_index_x].i < i) + { + goto next; + } + cur_key_idx = cki; + } + } + } + +next: + // find new index positions... + cur_index_x = cur_key_idx % num_key_frames_block; + for (cur_index_y = cur_key_idx / num_key_frames_block; cur_index_y < indexes.GetN(); cur_index_y++, cur_index_x = 0) + { + for (; cur_index_x < indexes[cur_index_y].GetN(); cur_index_x++, cur_key_idx++) + { + if (indexes[cur_index_y][cur_index_x].i >= i) + { + return 0; + } + } + } + return 0; +} + +int Video::AddIndex(int i, int len, LONGLONG offs) +{ + static VideoKeyFrame kf; + +//msg("*** %d %d %I64d\n", i, len, offs); + + if (indexes.GetN() < 1 || indexes[indexes.GetN() - 1].GetN() >= num_key_frames_block) + { + indexes.SetN(indexes.GetN() + 1); + indexes[indexes.GetN() - 1].Reserve(num_key_frames_block); + } + int y = indexes.GetN() - 1; + + kf.i = i; + kf.len = len; + kf.offs = offs; + int x = indexes[y].Add(kf); + if (x < 0) + return -1; + + last_key_pos = i; + last_key_idx = y * num_key_frames_block + x; + return 0; +} + +void Video::ResetAvgPts() +{ + for (int i = 0; i < saved_delta_pts_num; i++) + saved_delta_pts[i] = 0; + saved_delta_pts_idx = 0; + avg_delta_pts = 0; + +} + +LONGLONG Video::FixAudioPts(LONGLONG pts) +{ + static int num_corrections = 0; + LONGLONG delta = avg_delta_pts / saved_delta_pts_num; + if (delta > max_delta_pts + min_delta_pts) + { + minus_delta_pts = delta - min_delta_pts; + if (num_corrections++ < 10) + msg("AVI: Audio far ahead video (%d). Correction = %d.\n", (int)delta, (int)minus_delta_pts); + // reset avg + ResetAvgPts(); + } + + pts -= minus_delta_pts; + + avg_delta_pts -= saved_delta_pts[saved_delta_pts_idx]; + saved_delta_pts[saved_delta_pts_idx++] = pts - saved_video_pts; + avg_delta_pts += pts - saved_video_pts; + saved_delta_pts_idx %= saved_delta_pts_num; + + + + return pts; +} + +//////////////////////////////////////////////// + +int video_play(char *filepath) +{ + if (filepath == NULL) + { + if (video != NULL) + { + if (video->skip_fwd || video->skip_rev || video->searching) + video->cancel_skip = true; + else + { + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_REPEAT, 0); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + mpeg_setspeed(MPEG_SPEED_NORMAL); + } + } + return 0; + } + + if (strncasecmp(filepath, "/cdrom/", 7) != 0 && strncasecmp(filepath, "/hdd/", 5) != 0) + return -1; + + int ret = media_open(filepath, MEDIA_TYPE_VIDEO); + if (ret < 0) + { + msg_error("Video: media open FAILED.\n"); + video_stop(); + return ret; + } + MSG("Video: Start...\n"); + + num_packets = 0; + + video_detect_formats(); + + if (video->video_fmt == RIFF_VIDEO_UNKNOWN) + { + msg_error("Video: Video codec not supported.\n"); + script_error_callback(SCRIPT_ERROR_BAD_CODEC); + video_stop(); + return -1; + } + + video->scr = 0; + + if (video->video_fmt == RIFF_VIDEO_MPEG12) + { + max_info_cnt = 1; + + mpeg_init(MPEG_2, FALSE, TRUE, TRUE); + video->mux_numbufs = 16; + video->mux_bufsize = 32768; + mpeg_setbuffer(MPEG_BUFFER_1, BUF_BASE, video->mux_numbufs, video->mux_bufsize); + + ((VideoMpg *)video)->GetTimeLength(); + } else + { + max_info_cnt = 16; + + //video->UpdateTotalTime(); + int totaltime = video->rate != 0 ? (int)((LONGLONG)video->video_frames * video->scale / video->rate) : 0; + script_totaltime_callback(totaltime); + + video->indexes.Reserve(1024); + + mpeg_init(MPEG_4, FALSE, TRUE, FALSE); + + mpeg_set_scale_rate((DWORD *)&video->scale, (DWORD *)&video->rate); + video->good_delta_stc = RESYNC_TIMEOUT * video->scale / video->rate; + + int tvtype = settings_get(SETTING_TVTYPE); + KHWL_VIDEOMODE vmode = KHWL_VIDEOMODE_NORMAL; + if (tvtype == 2 || tvtype == 3) + vmode = KHWL_VIDEOMODE_WIDE; + //khwl_setvideomode(KHWL_VIDEOMODE_NORMAL, TRUE); + khwl_setvideomode(vmode, FALSE); + + mpeg_setframesize(video->width, video->height, true); + + if (video->video_fmt == RIFF_VIDEO_DIV3) + { + video->mux_numbufs = 2; + video->mux_bufsize = 200960; + } + + bool all_allocated = false; + int max_allocs[4]; +#if 0 + max_allocs[0] = 1; + max_allocs[1] = 2; + max_allocs[2] = video->mux_numbufs; + max_allocs[3] = 0; +#endif + max_allocs[0] = video->mux_numbufs; + max_allocs[1] = 0; + + for (int num_tries = 0; max_allocs[num_tries] != 0; num_tries++) + { + all_allocated = true; + int i = 0; + for (int num_allocs = 0; num_allocs < max_allocs[num_tries]; num_allocs++) + { + int nb = video->mux_numbufs / max_allocs[num_tries]; + int bsize = video->mux_bufsize * nb + 8; + BYTE *buf = VideoAlloc(bsize); + if (buf == NULL) + { + all_allocated = false; + break; + } + video->allocated_mux_buf_size[video->allocated_numbufs] = bsize; + video->allocated_mux_buf[video->allocated_numbufs] = buf; + video->allocated_numbufs++; + + for (int j = 0; j < nb; j++, i++) + { + video->mux_buf[i] = buf; + buf += video->mux_bufsize; + } + } + if (all_allocated) + break; + } + if (!all_allocated) + { + msg_error("Video: Cannot allocate mux buffers.\n"); + video_stop(); + return -1; + } + mpeg_setbuffer_array(MPEG_BUFFER_1, video->mux_buf, video->mux_numbufs, video->mux_bufsize); + } + + if (video->video_fmt == RIFF_VIDEO_DIV3) + { + khwl_display_clear(); + script_error_callback(SCRIPT_ERROR_WAIT); + gui_update(); + + if (divx_transcode_preinit() < 0) + { + msg_error("Video: Cannot pre-init DivX3 transcoder.\n"); + video_stop(); + return -1; + } + + if (divx_transcode_init(video->width, video->height, video->rate) < 0) + { + msg_error("Video: Cannot init DivX3 transcoder.\n"); + video_stop(); + return -1; + } + + for (int i = 0; i < video->mux_numbufs; i++) + { + video->divx_base[i] = VideoAlloc(video->mux_bufsize + DIVX3_BUF_MARGIN * 2 + 8); + if (video->divx_base[i] == NULL) + { + msg_error("Video: Cannot allocate DivX3 transcoding buffer [%d].\n", i); + video_stop(); + return -1; + } + video->divx_buf[i] = video->divx_base[i] + DIVX3_BUF_MARGIN; + } + + mpeg_setbuffer_array(MPEG_BUFFER_3, video->divx_buf, video->mux_numbufs, video->mux_bufsize); + video->divx_cur_bufpos = 0; + video->divx_cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_3); + + video->no_partial = true; + + //script_error_callback(SCRIPT_ERROR_NONE); + } + media_skip_buffer(NULL); + + // if we need a separate decompression for audio... + if (video->video_fmt != RIFF_VIDEO_MPEG12) + { + if (video->audio_fmt != RIFF_AUDIO_UNKNOWN && video->audio_fmt != RIFF_AUDIO_NONE) + { + video->audio_halfrate = (video->video_fmt == RIFF_VIDEO_DIV3); + if (!audio_init(video->audio_fmt, video->audio_halfrate)) + { + msg_error("Video: Cannot init audio decompressor.\n"); + script_error_callback(SCRIPT_ERROR_BAD_AUDIO); + } + } else + script_audio_info_callback(""); + + if (video->first_track >= 0) + { + if (video_set_audio_track(video->first_track) < 0) + { + msg_error("Video: Cannot init audio.\n"); + script_error_callback(SCRIPT_ERROR_BAD_AUDIO); + } + } else + MSG("Video: * No audio tracks...\n"); + + audio_set_ac3_getinfo(false); + } else + script_audio_info_callback(""); + + // read & parse subtitle files + read_subtitles(filepath); + + // write dvd-specific FIP stuff... + const char *digits = " 00000"; + fip_write_string(digits); + fip_write_special(FIP_SPECIAL_COLON1, 1); + fip_write_special(FIP_SPECIAL_COLON2, 1); + + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_REPEAT, 0); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + + script_time_callback(0); + + script_video_info_callback(video->video_fmt_str); + if (video->video_fmt != RIFF_VIDEO_MPEG12) + { + script_framesize_callback(video->width, video->height); + script_framerate_callback(mpeg_get_fps()); + } + + video->playing = true; + video->searching = false; + video->stopping = false; + video->skip_fwd = false; + video->skip_rev = false; + video->skip_wait = false; + video->skip_waiting = false; + + video->in_divx_packet = false; + video->need_to_stop = false; + + info_cnt = 0; + mpeg_start(); + + return 0; +} + +bool video_search_fourcc(DWORD fourcc, const DWORD *values) +{ + for (int i = 0; values[i] != 0xffffffff; i++) + { + if (fourcc == values[i]) + return true; + } + return false; +} + +void video_detect_formats() +{ + static const DWORD mpeg12[] = { + FOURCC('M','P','E','G'), FOURCC('m','p','e','g'), + FOURCC('P','I','M','1'), FOURCC('p','i','m','1'), + FOURCC('M','P','G','2'), FOURCC('m','p','g','2'), + 0xffffffff + }; + static const DWORD div3[] = { + FOURCC('D','I','V','3'), FOURCC('d','i','v','3'), + FOURCC('D','I','V','4'), FOURCC('d','i','v','4'), + FOURCC('D','I','V','5'), FOURCC('d','i','v','5'), + FOURCC('D','I','V','6'), FOURCC('d','i','v','6'), + FOURCC('M','P','4','3'), FOURCC('m','p','4','3'), + FOURCC('A','P','4','1'), FOURCC('a','p','4','1'), + FOURCC('M','P','G','3'), FOURCC('m','p','g','3'), + FOURCC('C','O','L','0'), FOURCC('c','o','l','0'), + FOURCC('C','O','L','1'), FOURCC('c','o','l','1'), + FOURCC('N','A','V','I'), FOURCC('S','A','N','3'), + 0xffffffff + }; + static const DWORD mpeg4[] = { + FOURCC('D','I','V','X'), FOURCC('d','i','v','x'), + FOURCC('D','i','v','x'), FOURCC('D','i','v','X'), + FOURCC('D','X','5','0'), FOURCC('d','x','5','0'), + FOURCC('M','P','4','S'), FOURCC('m','p','4','s'), + FOURCC('M','P','4','V'), FOURCC('m','p','4','v'), + FOURCC('M','4','S','2'), FOURCC('m','4','s','2'), + FOURCC('F','M','P','4'), FOURCC('f','m','p','4'), + FOURCC('X','V','I','D'), FOURCC('x','v','i','d'), + FOURCC('3','I','V','0'), FOURCC('3','I','V','1'), + FOURCC('3','I','V','2'), FOURCC('3','I','V','D'), + FOURCC('3','I','V','X'), FOURCC('3','V','I','D'), + FOURCC('A','T','M','4'), FOURCC('B','L','Z','0'), + FOURCC('F','V','F','W'), FOURCC('H','D','X','4'), + FOURCC('D','M','4','V'), FOURCC('M','P','G','4'), + FOURCC('M','4','C','C'), FOURCC('m','4','c','c'), + FOURCC('P','V','M','M'), FOURCC('R','M','P','4'), + FOURCC('S','E','D','G'), FOURCC('N','D','I','G'), + FOURCC('W','V','1','F'), FOURCC('X','V','I','X'), + 0xffffffff + + }; + + DWORD v4cc = FOURCC(video->fourcc[0], video->fourcc[1], video->fourcc[2], video->fourcc[3]); + + if (video_search_fourcc(v4cc, mpeg12)) + { + video->video_fmt = RIFF_VIDEO_MPEG12; + video->video_fmt_str.Printf("MPEG-1/2 ('%s')", video->fourcc); + } + else if (video_search_fourcc(v4cc, div3)) + { + video->video_fmt = RIFF_VIDEO_DIV3; + video->video_fmt_str.Printf("DivX3 ('%s')", video->fourcc); + } + else if (video_search_fourcc(v4cc, mpeg4)) + { + video->video_fmt = RIFF_VIDEO_MPEG4; + video->video_fmt_str.Printf("MPEG-4 ('%s')", video->fourcc); + } + MSG("Video: * Video format %s detected!\n", *video->video_fmt_str); + + if (video->video_fmt != RIFF_VIDEO_MPEG12) + { + if (video->cur_track < 0 || video->track[video->cur_track].wfe == NULL) + { + video->audio_fmt = RIFF_AUDIO_NONE; + video->audio_fmt_str = (char *)"None"; + MSG("Video: * Audio track not found.\n"); + } + else + { + video->audio_fmt = audio_get_audio_format(video->track[video->cur_track].wfe->w_format_tag); + video->audio_fmt_str = audio_get_audio_format_string(video->audio_fmt); + MSG("Video: * Audio format %s detected.\n", *video->audio_fmt_str); + } + } +} + +void video_update_info() +{ + if (video == NULL) + return; + static int old_secs = 0; + KHWL_TIME_TYPE displ; + displ.pts = 0; + displ.timeres = 90000; + if (video->skip_fwd || video->skip_rev || video->searching) + displ.pts = video->scr; + else if (mpeg_is_displayed()) + { + khwl_getproperty(KHWL_TIME_SET, etimVideoFrameDisplayedTime, sizeof(displ), &displ); + displ.pts += INT64(90000) * video->video_pos_base * video->scale / video->rate; + displ.pts += video->displ_pts_base; + } + + if ((LONGLONG)displ.pts != video->saved_pts) + { + if ((LONGLONG)displ.pts >= 0) + { + video->saved_pts = displ.pts; + + if (!video->skip_fwd && !video->skip_rev && !video->searching) + show_subtitles(displ.pts); + + char fip_out[10]; + int secs = (int)(displ.pts / 90000); + if (secs < 0) + secs = 0; + if (secs >= 10*3600) + secs = 10*3600-1; + if (secs != old_secs) + { + script_time_callback(secs); + // check if total time changed + video->UpdateTotalTime(); + + fip_out[0] = ' '; + fip_out[1] = ' '; + fip_out[2] = (char)((secs/3600) + '0'); + int secs3600 = secs%3600; + fip_out[3] = (char)(((secs3600/60)/10) + '0'); + fip_out[4] = (char)(((secs3600/60)%10) + '0'); + fip_out[5] = (char)(((secs3600%60)/10) + '0'); + fip_out[6] = (char)(((secs3600%60)%10) + '0'); + fip_out[7] = '\0'; + fip_write_string(fip_out); + + old_secs = secs; + } + } + } +} + +int video_read_input(BYTE * &buf, int &len, bool wait) +{ + int ret = 0; + + // don't read more blocks if we just need more output + if (video->skip_fwd || video->skip_rev || video->audio_fmt == RIFF_AUDIO_UNKNOWN + || video->audio_fmt == RIFF_AUDIO_NONE + // don't read more blocks if audio is not ready + || (video->audio_fmt != RIFF_AUDIO_UNKNOWN + && video->audio_fmt != RIFF_AUDIO_NONE && audio_ready())) + { + do + { + int skiphdr = 0; + if (video->skip_fwd || video->skip_rev) + { + if (video->event != MEDIA_EVENT_VIDEO_PARTIAL && video->event != MEDIA_EVENT_NOP) + { + video->chunkleft = 0; + video->old_video_packet_len = video->video_packet_len; + video->video_packet_len = 0; + + ret = video->GetKeyFrame(video->skip_fwd ? VIDEO_KEY_FRAME_NEXT : VIDEO_KEY_FRAME_PREV); + if (ret == 0) // wait... + { + if (wait) + { + if (cycle() < 0) + return -1; + continue; + } + return 0; + } + skiphdr = 8; + video->chunkleft = video->video_packet_len + skiphdr; + if (ret < 1) + { + ret = 1; + video->event = MEDIA_EVENT_STOP; + } + } + } + if (video->skip_fwd || video->skip_rev) + { + if (video->event != MEDIA_EVENT_STOP) + { + len = video->chunkleft; + video->event = MEDIA_EVENT_NOP; + ret = media_read_block(&buf, &video->event, &len); + if (video->event == MEDIA_EVENT_OK) + { + video->chunkleft -= len; + video->event = (video->chunkleft > 0) ? MEDIA_EVENT_VIDEO_PARTIAL : MEDIA_EVENT_VIDEO; + len -= skiphdr; + buf += skiphdr; + } + } + } + if (!video->skip_fwd && !video->skip_rev) // normal play + { + video->event = MEDIA_EVENT_OK; + len = 0; + buf = NULL; + + ret = media_get_next_block(&buf, &video->event, &len); + } + if (ret > 0 && buf == NULL) + { + msg_error("Video: Not initialized. STOP!\n"); + return -1; + } + if (ret == -1) + { + msg_error("Video: Error getting next block!\n"); + return -1; + } + else if (ret == 0) // wait... + { + if (wait) + { + if (cycle() < 0) + return -1; + continue; + } + return 0; + } + break; + } while (wait); + + if (video->event == MEDIA_EVENT_STOP) + { + MSG("Video: STOP Event triggered!\n"); + if (!video->skip_fwd && !video->skip_rev) + mpeg_play_normal(); + video->stopping = true; + return 0; + } + + if (video->video_fmt == RIFF_VIDEO_DIV3) + { + if (video->event == MEDIA_EVENT_VIDEO || video->event == MEDIA_EVENT_VIDEO_PARTIAL) + { + mpeg_setbufidx(MPEG_BUFFER_1, NULL); + +//msg("[%d] DECODE len=%d <%02x %02x %02x %02x %02x %02x %02x %02x> (buf=%08x)\n", num_packets, (video->event == MEDIA_EVENT_VIDEO ? len + 8 : len), +// buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf); +//gui_update(); + + bitstream_decode_buf_init(0, buf, video->event == MEDIA_EVENT_VIDEO ? len + 8 : len, true); + } + } + } + + return 1; +} + +int video_more_output(bool wait) +{ + if (video->divx_cur_bufleft < 24/*16*/) + { + do + { + if (video->need_to_stop) + return -1; + if (mpeg_find_free_blocks(MPEG_BUFFER_3) == 0) + { + if (wait) + { + if (cycle() < 0) + return -1; + continue; + } + return 0; // wait... + } + break; + } while (wait); + if (video == NULL) + return -1; + video->divx_cur_bufpos = 0; + video->divx_cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_3); + } + BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_3); + BYTE *buf = tmpbuf + video->divx_cur_bufpos; + int len = video->divx_cur_bufleft - 8; + +//msg("[%d] ENCODE len=%d (buf=%08x)\n", num_packets, len, buf); +//gui_update(); + + bitstream_encode_buf_init(buf, len); + + return 1; +} + +int video_send_video_packet(MPEG_BUFFER which, BYTE *buf, int len, bool start_of_packet) +{ + while (len > 0) + { + MpegPacket *packet = NULL; + packet = mpeg_feed_getlast(); + if (packet == NULL) // well, it won't really help + return 0; + memset((BYTE *)packet + 4, 0, sizeof(MpegPacket) - 4); + + BYTE *base = buf; + int curlen = len; + + // find next VOP start + if (video->video_fmt == RIFF_VIDEO_MPEG4) + { + for (; len >= 0 && (base == buf || *buf != 0 || buf[1] != 0 || buf[2] != 1 || buf[3] != 0xb6); len--) + { + if (video->test_for_qpel_gmc) + { + if (buf[0] == 0 && buf[1] == 0 && buf[2] == 1 && (buf[3] >= 0x20 && buf[3] <= 0x2F)) + { + video_decode_vol_header(buf + 4, len - 4); + if (video->gmc_flag) + { + msg("Video: Error! Cannot play MPEG-4 with GMC.\n"); + script_error_callback(SCRIPT_ERROR_GMC); + return -1; + } + else if (video->qpel_flag) + { + msg("Video: Error! Cannot play MPEG-4 with QPEL.\n"); + script_error_callback(SCRIPT_ERROR_QPEL); + return -1; + } + video->test_for_qpel_gmc = false; + } + } + buf++; + } + + if (len > 0) + curlen -= len; + } else + len = -1; + + VIDEO_FRAME_TYPE frm_type = VIDEO_FRAME_NONE; + packet->type = 0; + packet->pData = base; + packet->size = curlen; + if (base[0] == 0 && base[1] == 0 && base[2] == 1 && base[3] == 0xb6) + { + frm_type = (VIDEO_FRAME_TYPE)(base[4] >> 6); + // add I-frames to the index (but ignore too frequent I-frames) + if (frm_type == VIDEO_FRAME_I) + { + video->SetCurrentIndex(video->abs_video_pos, + video->video_packet_len, video->video_offs); + video->cur_key_offs = video->video_offs; + video->cur_key_pos = video->abs_video_pos; + video->last_frame_pos = video->frame_pos; + } else + { + // wrong index - skip it + if (video->skip_fwd || video->skip_rev) + { + video->cur_key_idx = video->last_good_key_idx; + break; + } + } + if (frm_type == VIDEO_FRAME_I || frm_type == VIDEO_FRAME_P) + { + if (video->skip_fwd || video->skip_rev) + { + if (video->skip_rev) + { + // \TODO: it'd be better to patch 'time_incr' header bits... + mpeg_setpts(0); + } + packet->pts = 0; + packet->flags = 0; + packet->scr = 0 | SPTM_SCR_FLAG; + } else + { + packet->pts = (LONGLONG)video->video_pos * video->scale; + packet->scr = packet->pts | SPTM_SCR_FLAG; + packet->pts += video->scale * 10; + packet->flags = 0x80; + + video->saved_video_pts = packet->pts; + +#if 0 +msg("v: %d\n", packet->pts); +#endif + +#ifdef USE_RESYNCS_CONTROL + if (mpeg_is_playing()) + { + LONGLONG stc = mpeg_getpts(); + LONGLONG good_scr = INT64(90000) * packet->pts / video->rate; + + //msg("%d %d\n", (int)stc, (int)good_scr); + if (stc > good_scr + video->good_delta_stc) + { + khwl_pause(); + mpeg_start(); + msg("Video: Resync...\n"); + video->wait_for_resync = false; + } + } +#endif + } + } + + } + +#if 0 +msg("PACKET [%d] len=%d (buf=%08x)\n", num_packets, packet->size, packet->pData); +if (packet->size > 0) +{ +BYTE *buf = packet->pData; +int len = packet->size; +DUMP_FRAME("%02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], + buf[len-8], buf[len-7], buf[len-6], buf[len-5], buf[len-4], buf[len-3], buf[len-2], buf[len-1]); +} +#endif + +#if 0 +{ +FILE *fp; +fp = fopen("out.m4v", "ab"); +//fwrite("00dc\0\0\0\0", 8, 1, fp); +fwrite(packet->pData, packet->size, 1, fp); +fclose(fp); +} +#endif +#if 0 +msg("[%d]\t\tsize=%d\t\tpts=%d\n", packet->type, packet->size, (int)packet->pts); +#endif + + // increase bufidx + mpeg_setbufidx(which, packet); + num_packets++; + + // frame order analysis +#ifdef NEW_SYNC + if (frm_type == VIDEO_FRAME_I) + { + mpeg_correct_pts(); + while (mpeg_feed_pop()) + ; + mpeg_feed(MPEG_FEED_VIDEO); + } + else if (frm_type == VIDEO_FRAME_P) + { + if (!mpeg_feed_isempty()) + { + mpeg_correct_pts(); + while (mpeg_feed_pop()) + ; + } + mpeg_feed_push(); + } + else + { + if (!mpeg_feed_isempty()) + mpeg_feed_push(); + else + mpeg_feed(MPEG_FEED_VIDEO); + } +#else + mpeg_feed(MPEG_FEED_VIDEO); +#endif + } + return 1; +} + +void video_decode_vol_header(BYTE *buf, int len) +{ + if (video == NULL) + return; + video->qpel_flag = false; + video->gmc_flag = false; + + video_bits_init(buf, len); + video_skip_bits(1); + video_skip_bits(8); + int vo_ver_id; + if (video_get_bits(1)) + { + vo_ver_id = video_get_bits(4); + video_skip_bits(3); + } else + vo_ver_id = 1; + + int aspect_ratio_info = video_get_bits(4); + if (aspect_ratio_info == 15) // extended + video_skip_bits(16); + + if (video_get_bits(1)) // vol control parameters + { + video_skip_bits(3); + if (video_get_bits(1)) // vbv parameters + { + video_skip_bits(16); + video_skip_bits(16); + video_skip_bits(16); + video_skip_bits(15); + video_skip_bits(16); + } + } + + int vol_shape = video_get_bits(2); + if(vol_shape == 3 && vo_ver_id != 1) // gray shape + video_skip_bits(4); + + // marker + video_skip_bits(1); + + int time_base_den = video_get_bits(16); + + // marker + video_skip_bits(1); + + if (video_get_bits(1)) // fixed_vop_rate + { + int time_increment_bits = video_log2(time_base_den - 1) + 1; + if (time_increment_bits < 1) + time_increment_bits = 1; + + video_skip_bits(time_increment_bits); + } + + if (vol_shape != 2) // not bin-only shape + { + if (vol_shape == 0) // rect shape + { + video_skip_bits(1); + /*int width = */video_get_bits(13); + video_skip_bits(1); + /*int height = */video_get_bits(13); + video_skip_bits(1); + } + + /*int progressive_frame = 1 - */video_get_bits(1); + video_skip_bits(1); + int vol_sprite_usage = video_get_bits(vo_ver_id == 1 ? 1 : 2); + if (vol_sprite_usage == 2) + video->gmc_flag = true; + if (vol_sprite_usage == 1 || vol_sprite_usage == 2) // static or GMC + { + if (vol_sprite_usage == 1) + { + video_skip_bits(14); + video_skip_bits(14); + video_skip_bits(14); + video_skip_bits(14); + } + video_skip_bits(9); + if (vol_sprite_usage == 1) + video_skip_bits(1); + } + if (video_get_bits(1) == 1) + video_skip_bits(8); + + if (video_get_bits(1)) // vol_quant_type + { + int i; + if (video_get_bits(1)) + { + for (i = 0; i < 64; i++) + { + if (video_get_bits(8) == 0) + break; + } + } + + if (video_get_bits(1)) + { + for (i = 0; i < 64; i++) + { + if (video_get_bits(8) == 0) + break; + } + } + } + + if (vo_ver_id != 1) + video->qpel_flag = video_get_bits(1) != 0; + } +} + +int divx3_callback(BITSTREAM_MODE mode, BYTE *outbuf, int outlen) +{ + if (mode != BITSTREAM_MODE_OUTPUT) + { + mpeg_release_packet(MPEG_BUFFER_1, NULL); + } + + if (outlen != 0) + { + int ll = (outlen + 7) & (~7); + video->divx_cur_bufleft -= ll; + video->divx_cur_bufpos += ll; + if (video_send_video_packet(MPEG_BUFFER_3, outbuf, outlen, false) < 0) + return -1; + } + + if (mode == BITSTREAM_MODE_INPUT) + { + BYTE *inbuf; + int inlen; + if (video_read_input(inbuf, inlen, true) < 0) + return -1; + } + + if (mode == BITSTREAM_MODE_OUTPUT) + { + if (video_more_output(true) < 0) + return -1; + } + + return 0; +} + +extern int frame_number; + +/// Advance playing +int video_loop() +{ + static BYTE *buf = NULL; + static int len = 0; + int ret; + + // for video transcoding + +#if 0 +again: +#endif + + if (video == NULL) + return 1; + + if (video->need_to_stop) + video_stop(); + + if (video == NULL) + return 1; + + if (video->stopping) + { + if (video->skip_fwd || video->skip_rev || video->searching) + { + video_stop(); + return 1; + } + if (mpeg_wait(TRUE) == 1) + { + video_stop(); + return 1; + } + } + + if (video->delayed_skip != 0 && !video->in_divx_packet) + { + if (!video->skip_fwd && !video->skip_rev) + media_seek_curleft(); + if (video->delayed_skip == 1) + video->skip_fwd = true; + else if (video->delayed_skip == 2) + video->skip_rev = true; + video->delayed_skip = 0; + } + + if (video->searching && !video->cancel_skip) + { + int ret = video->GetKeyFrame(VIDEO_KEY_FRAME_CONTINUE); + if (ret > 0) + video->cancel_skip = true; + } + + if (video->cancel_skip && (video->skip_fwd || video->skip_rev || video->searching) && !video->in_divx_packet) + { + video_lseek(video->video_offs, SEEK_SET); + video->video_pos_base = video->abs_video_pos;// = video->last_key_pos - 1; + video->video_pos = 0; + video->audio_total_bytes = -1; + video->audio_pos = 0; + video->frame_pos = video->last_frame_pos - 1; + + fip_write_special(FIP_SPECIAL_PLAY, 1); + fip_write_special(FIP_SPECIAL_REPEAT, 0); + fip_write_special(FIP_SPECIAL_PAUSE, 0); + + if (video->skip_waiting) + mpeg_release_packet(MPEG_BUFFER_1, NULL); + + mpeg_setspeed(MPEG_SPEED_NORMAL); + mpeg_set_scale_rate((DWORD *)&video->scale, (DWORD *)&video->rate); + // we'll correct display pts later... + mpeg_setpts(0); + + script_speed_callback(MPEG_SPEED_NORMAL); + + video->skip_fwd = false; + video->skip_rev = false; + video->skip_wait = false; + video->skip_waiting = false; + video->searching = false; + video->cancel_skip = false; + video->chunkleft = 0; + video->max_rev_incr = def_max_rev_incr; + + media_skip_buffer(NULL); + + if (video->audio_fmt != RIFF_AUDIO_UNKNOWN && video->audio_fmt != RIFF_AUDIO_NONE) + audio_reset(); + + info_cnt = 0; + } + + if (!video->stopping && !video->searching && !video->in_divx_packet) + { + if (!video->skip_waiting) + { + ret = video_read_input(buf, len, false); + if (ret == 0) + return 0; + if (ret < 0) + { + return 1; + } + } + + if (video->skip_wait) + { + int cur_time = script_get_time(NULL); + int delta = 300; + if (cur_time < video->last_keyframe_time + delta) + { + video->skip_waiting = true; + return 0; + } + video->last_keyframe_time = cur_time; + } + + if (video->video_fmt == RIFF_VIDEO_MPEG12) + { + if (((VideoMpg *)video)->ProcessChunk(buf, len) == 0) + return 0; + } + + else if (video->event == MEDIA_EVENT_VIDEO || video->event == MEDIA_EVENT_VIDEO_PARTIAL) + { + if (video->video_fmt == RIFF_VIDEO_DIV3) + { + video->in_divx_packet = true; + ret = video_more_output(false); + if (ret == 0) + { + video->in_divx_packet = false; + return 0; + } + if (ret < 0) + { + video->event = MEDIA_EVENT_NOP; + } +#if 0 +FILE *fp; +fp = fopen("out.m4v", "ab"); +fwrite("00dc", 4, 1, fp); +fwrite("\0\0\0\0", 4, 1, fp); +int fffpos = ftell(fp); +fclose(fp); +#endif + + // ok, now transcode + if (divx_transcode(divx3_callback /*, len */) < 0) + // skip this frame + { + if (video == NULL) + { + return 1; + } + video->event = MEDIA_EVENT_NOP; + mpeg_release_packet(MPEG_BUFFER_1, NULL); + } + +//msg("-- %d done\n", frame_number); +//gui_update(); + +#if 0 +fp = fopen("out.m4v", "rb+"); +fseek(fp, 0, SEEK_END); +int fffpos2 = ftell(fp); +fseek(fp, fffpos - 4, SEEK_SET); +int fff = fffpos2 - fffpos; +fwrite(&fff, 4, 1, fp); +fseek(fp, fffpos2, SEEK_SET); +if ((fffpos2 - fffpos) & 1) +{ + fputc(0, fp); +} +fclose(fp); +#endif + video->in_divx_packet = false; + video->skip_waiting = false; + } + else + { + if (video_send_video_packet(MPEG_BUFFER_1, buf, len, video->event == MEDIA_EVENT_VIDEO) < 0) + return 1; + video->skip_waiting = false; + } + + } + else if (video->event == MEDIA_EVENT_AUDIO || video->event == MEDIA_EVENT_AUDIO_PARTIAL) + { +#ifndef SKIP_AUDIO + if (video->audio_fmt != RIFF_AUDIO_UNKNOWN && video->audio_fmt != RIFF_AUDIO_NONE) + { + // send multiple frames (packets) in one chunk + BYTE *b = buf; + for (;;) + { + MpegPacket *packet = NULL; + packet = mpeg_feed_getlast(); + if (packet == NULL) // well, it won't really help + return 0; + + int numread = audio_parse_packet(packet, b, len); + if (numread == 0) + break; + len -= numread; + b += numread; + + // audio syncronisation... + int bps = audio_get_output_bps(); + if (bps > 0) + { + if (video->audio_total_bytes < 0) + { + video->audio_total_bytes = (video->saved_video_pts + video->audio_delta - video->scale * 10 - video->audio_pts_offset) * bps / video->rate; + } + + packet->pts = ((LONGLONG)video->audio_total_bytes * video->rate / bps) + video->audio_pts_offset; + packet->scr = packet->pts | SPTM_SCR_FLAG; + packet->pts += video->scale * 10; + + packet->flags = 0x80; + +#if 0 + msg("a: %d\t[%d]\n", (int)packet->pts, (int)(packet->pts - video->saved_video_pts)); +#endif + + if (video->audio_delta == (LONGLONG)SPTM_SCR_FLAG && video->saved_video_pts > 0) + video->audio_delta = packet->pts - video->saved_video_pts; + + } else + { + packet->pts = packet->scr = 0; + packet->flags = 0; +#if 0 + msg("a: %d\n", (int)packet->pts); +#endif + } + + if (video->audio_total_bytes >= 0) + video->audio_total_bytes += packet->size; + + mpeg_feed(MPEG_FEED_AUDIO); + num_packets++; + } + } +#endif + } + } + + if (info_cnt++ > max_info_cnt) + { + info_cnt = 0; + video_update_info(); + } + +#if 0 + if (!video->in_divx_packet) + goto again; +#endif + + return 0; +} + +/// Pause playing +BOOL video_pause() +{ + fip_write_special(FIP_SPECIAL_PLAY, 0); + fip_write_special(FIP_SPECIAL_REPEAT, 0); + fip_write_special(FIP_SPECIAL_PAUSE, 1); + + mpeg_setspeed(MPEG_SPEED_PAUSE); + + return TRUE; +} + +/// Stop playing +BOOL video_stop() +{ + if (video != NULL) + { + if (video->in_divx_packet) + { + video->need_to_stop = true; + return FALSE; + } + + delete_subtitles(); + + mpeg_deinit(); + khwl_setvideomode(KHWL_VIDEOMODE_NONE, TRUE); + if (video->playing) + { + video->playing = false; + } + video->stopping = false; + + media_close(); + } + return TRUE; +} + +void video_setdebug(BOOL ison) +{ + video_msg = ison == TRUE; +} +BOOL video_getdebug() +{ + return video_msg; +} + +/////////////////////////////////////////// + +BOOL video_open(const char *filepath) +{ + if (video != NULL) + video_close(); + int fd = cdrom_open(filepath, O_RDONLY); + if (fd < 0) + { + msg_error("Video: Cannot open file %s.\n", filepath); + return FALSE; + } + + // detect container type + SPString fname = filepath; + video = NULL; + if (fname.FindNoCase(".avi") >= 0 || fname.FindNoCase(".divx") >= 0) + { + video = new VideoAvi(); + } + else if (fname.FindNoCase(".mpg") >= 0 || fname.FindNoCase(".mpeg") >= 0 || fname.FindNoCase(".vob") >= 0 + || fname.FindNoCase(".dat") >= 0) + { + video = new VideoMpg(); + } + else if (fname.FindNoCase(".mp4") >= 0 || fname.FindNoCase(".3gp") >= 0 || fname.FindNoCase(".mov") >= 0) + { + //video = new VideoQt(); + msg_error("Video: MP4 container currently not supported.\n"); + close(fd); + return FALSE; + } + + for (int i = 0; i < 2; i++) + { + if (video == NULL) + { + // try to auto-detect video type + BYTE hdr[16]; + lseek64(fd, 0, SEEK_SET); + if (read(fd, hdr, 12) != 12) + { + msg_error("Video: Cannot read file header.\n"); + return FALSE; + } + lseek64(fd, 0, SEEK_SET); + if (strncmp((char *)hdr, "RIFF", 4) == 0 && strncmp((char *)hdr+8, "AVI ", 4) == 0) + { + video = new VideoAvi(); + } + else if ((hdr[0] == 0 && hdr[1] == 0 && hdr[2] == 1 && (hdr[3] == 0xba || hdr[3] == 0xb3)) + || (strncmp((char *)hdr, "RIFF", 4) == 0 && strncmp((char *)hdr+8, "CDXA", 4) == 0)) + { + video = new VideoMpg(); + } + else + { + msg_error("Video: Unknown media file type.\n"); + close(fd); + return FALSE; + } + i++; + } + // try to parse... + if (video != NULL) + { + video->fd = fd; + + if (video->Parse()) + { + video->look4chunk = false; + return TRUE; + } + SPSafeDelete(video); + } + } + close(fd); + return FALSE; +} + +BOOL video_close() +{ + if (video != NULL) + { + if (video->video_fmt == RIFF_VIDEO_DIV3) + { + divx_transcode_deinit(); + divx_transcode_predeinit(); + } + + if (video->audio_fmt != RIFF_AUDIO_UNKNOWN && video->audio_fmt != RIFF_AUDIO_NONE) + audio_deinit(); + + close(video->fd); + SPSafeDelete(video); + return TRUE; + } + return FALSE; +} + +VIDEO_CHUNK_TYPE video_getnext(BYTE *buf, int buflen, int *pos, int *left, int *len) +{ + if (video != NULL) + return video->GetNext(buf, buflen, pos, left, len); + return VIDEO_CHUNK_UNKNOWN; +} + +int video_read(BYTE *buf, int len) +{ + if (video == NULL || buf == NULL || len < 1) + return 0; + int n = 0, newlen = 0; + video->cur_offs = lseek64(video->fd, 0, SEEK_CUR); + while (newlen < len) + { + n = read (video->fd, buf + newlen, len - newlen); + if (n == 0) + { + video->is_eof = true; + break; + } + if (n < 0) + { + if (errno == EINTR) + continue; + else + break; + } + newlen += n; + } + + return newlen; +} + +bool video_eof() +{ + return video == NULL || video->is_eof; +} + +void video_shiftpos(int offs) +{ + video->cur_offs -= offs; +} + +LONGLONG video_lseek(LONGLONG off, int where) +{ + LONGLONG fp = lseek64(video->fd, off, where); + media_set_filepos(fp); + return fp; +} + +int video_set_audio_track(int track) +{ + if (track == -1) + { + track = video->cur_track + 1; + if (track >= video->num_tracks) + track = video->first_track; + } + if (track < video->first_track || track >= video->num_tracks) + { + script_audio_stream_callback(-1); + return -1; + } + + if (video->video_fmt == RIFF_VIDEO_MPEG12) + { + msg("MPEG: Set audio stream #%d.\n", track); + mpeg_setaudiostream(track); + video->cur_track = track; + script_audio_stream_callback(video->cur_track + 1); + return 0; + } + + if (video->audio_fmt == RIFF_AUDIO_UNKNOWN || video->audio_fmt == RIFF_AUDIO_NONE) + return -1; + + if (video->track[track].wfe == NULL) + { + msg("Video: Cannot change audio tracks of unknown format.\n"); + script_error_callback(SCRIPT_ERROR_INVALID); + return -1; + } + + RIFF_AUDIO_FORMAT newfmt = audio_get_audio_format(video->track[track].wfe->w_format_tag); + if (newfmt == RIFF_AUDIO_UNKNOWN || newfmt == RIFF_AUDIO_NONE) + { + msg_error("Video: Audio format not supported.\n"); + script_error_callback(SCRIPT_ERROR_BAD_AUDIO); + return -1; + } + if (newfmt != video->audio_fmt) + { + audio_deinit(); + khwl_stop(); + video->audio_fmt = newfmt; + video->audio_halfrate = (video->video_fmt == RIFF_VIDEO_DIV3); + if (!audio_init(video->audio_fmt, video->audio_halfrate)) + { + msg_error("Video: Cannot init audio decompressor.\n"); + script_error_callback(SCRIPT_ERROR_BAD_AUDIO); + } + + video_play_from_last_keyframe(); + } + + MSG("Video: Setting audio params.\n"); + if (audio_setaudioparams(video->audio_fmt, video->track[track].wfe, + video->audio_halfrate ? 2 : 1) < 0) + { + msg_error("Video: Audio format %d not supported!\n", video->audio_fmt); + video->cur_track = -1; + return -1; + } + + audio_reset(); + + if (track != video->cur_track) + { + video->cur_track = track; + video->audio_total_bytes = -1; + } + video->cur_audio_bits = video->track[video->cur_track].wfe->w_bits_per_sample; + + script_audio_stream_callback(video->cur_track + 1); + + return 0; +} + +///////////////////////////////////////////////////////////// + +BOOL video_seek(int seconds) +{ + if (video == NULL) + return FALSE; + + if (seconds > 10 * 60) + { + script_error_callback(SCRIPT_ERROR_WAIT); + script_player_subtitle_callback(""); + gui_update(); + } + + int ret = video->GetKeyFrame(seconds); + if (ret < 0) + { + script_error_callback(SCRIPT_ERROR_INVALID); + return FALSE; + } + + if (video->video_fmt != RIFF_VIDEO_MPEG12) + { + mpeg_stop(); + if (ret > 0) + { + video->cancel_skip = true; + } + + video->event = MEDIA_EVENT_OK; + video->searching = true; + } + + info_cnt = 0; + + return TRUE; +} + +int video_forward(BOOL fast) +{ + if (video->video_fmt == RIFF_VIDEO_MPEG12) + { + if (video->GetKeyFrame(VIDEO_KEY_FRAME_NEXT) < 0) + return -1; + info_cnt = 0; + return 0; + } + + fip_write_special(FIP_SPECIAL_PLAY, 0); + fip_write_special(FIP_SPECIAL_REPEAT, 1); + mpeg_setspeed(MPEG_SPEED_FAST_FWD_MASK); + mpeg_setpts(0); + script_player_subtitle_callback(""); + + // skip the rest of current chunk + if (!video->in_divx_packet) + { + if (!video->skip_fwd && !video->skip_rev) + media_seek_curleft(); + } + if (video->skip_waiting) + mpeg_release_packet(MPEG_BUFFER_1, NULL); + + video->event = MEDIA_EVENT_OK; + video->searching = false; + video->skip_rev = false; + video->skip_fwd = true; + video->skip_waiting = false; + video->skip_wait = !fast; + video->max_rev_incr = def_max_rev_incr; + video->skip_cnt = 0; + video->last_keyframe_time = script_get_time(NULL); + info_cnt = 0; + + if (video->in_divx_packet) + { + video->delayed_skip = 1; + video->skip_fwd = false; + } + + return 1; +} +int video_rewind(BOOL fast) +{ + if (video->video_fmt == RIFF_VIDEO_MPEG12) + { + if (video->GetKeyFrame(VIDEO_KEY_FRAME_PREV) < 0) + return -1; + info_cnt = 0; + return 0; + } + + fip_write_special(FIP_SPECIAL_PLAY, 0); + fip_write_special(FIP_SPECIAL_REPEAT, 1); + mpeg_setspeed(MPEG_SPEED_FAST_REV_MASK); + mpeg_setpts(0); + script_player_subtitle_callback(""); + + // skip the rest of current chunk + if (!video->in_divx_packet) + { + if (!video->skip_fwd && !video->skip_rev) + media_seek_curleft(); + } + if (video->skip_waiting) + mpeg_release_packet(MPEG_BUFFER_1, NULL); + + video->event = MEDIA_EVENT_OK; + video->searching = false; + video->skip_fwd = false; + video->skip_rev = true; + video->skip_waiting = false; + video->skip_wait = !fast; + video->skip_cnt = 0; + video->last_keyframe_time = script_get_time(NULL); + info_cnt = 0; + + if (video->in_divx_packet) + { + video->delayed_skip = 2; + video->skip_rev = false; + } + + return 1; +} + +void video_set_audio_offset(LONGLONG offset) +{ + if (video != NULL) + { + if (video->video_fmt != RIFF_VIDEO_MPEG12) + video->audio_pts_offset = offset * (LONGLONG)video->rate / INT64(90000); + } +} + +LONGLONG video_get_audio_offset() +{ + if (video != NULL) + { + if (video->video_fmt != RIFF_VIDEO_MPEG12) + return INT64(90000) * video->audio_pts_offset / video->rate; + } + return 0; +} + +int video_play_from_last_keyframe() +{ + // skip the rest of current chunk + if (!video->in_divx_packet) + { + if (!video->skip_fwd && !video->skip_rev) + media_seek_curleft(); + } + + video_lseek(video->cur_key_offs, SEEK_SET); + video->abs_video_pos = video->cur_key_pos; + video->video_pos_base = video->abs_video_pos;// = video->last_key_pos - 1; + video->video_pos = 0; + video->audio_total_bytes = video->audio_delta; + video->audio_pts_offset = 0; + video->audio_pos = 0; + video->frame_pos = video->last_frame_pos - 1; + + video->chunkleft = 0; + video->max_rev_incr = def_max_rev_incr; + + media_skip_buffer(NULL); + + info_cnt = 0; + + mpeg_setspeed(MPEG_SPEED_NORMAL); + mpeg_set_scale_rate((DWORD *)&video->scale, (DWORD *)&video->rate); + // we'll correct display pts later... + mpeg_setpts(0); + + return 0; +} + +//////////////////////////////////////////////////////////////// + +static DWORD v_dec_v = 0; +static int v_bitidx = 0, v_left = 0; + +static void video_bits_init(BYTE *buf, int len) +{ + bitstream_decode_buf_init(1, buf, len, true); + bitstream_decode_start(1, v_dec_v, v_bitidx, v_left); +} + +static DWORD video_get_bits(int num_bits) +{ + DWORD ret; + bitstream_get_bits(ret, 1, v_dec_v, v_bitidx, v_left, num_bits); + return ret; +} + +static int video_skip_bits(int num_bits) +{ + bitstream_skip_bits(1, v_dec_v, v_bitidx, v_left, num_bits); + return 0; +} + +static const BYTE video_log2_tab[256] = +{ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, +}; + +int video_log2(DWORD v) +{ + int n = 0; + if (v & 0xffff0000) + { + v >>= 16; + n += 16; + } + if (v & 0xff00) + { + v >>= 8; + n += 8; + } + + n += video_log2_tab[v]; + + return n; +} + + +#endif diff --git a/src/video.h b/src/video.h new file mode 100644 index 0000000..3455f17 --- /dev/null +++ b/src/video.h @@ -0,0 +1,260 @@ +////////////////////////////////////////////////////////////////////////// +/** + * SigmaPlayer source project - Video player header file + * \file video.h + * \author bombur + * \version 0.1 + * \date 07.03.2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + */ +////////////////////////////////////////////////////////////////////////// + +#ifndef SP_VIDEO_H +#define SP_VIDEO_H + +typedef enum +{ + VIDEO_CONTAINER_UNKNOWN = 0, + + VIDEO_CONTAINER_AVI = 1, + VIDEO_CONTAINER_MPEG = 2, + VIDEO_CONTAINER_QT = 3, + +} VIDEO_CONTAINER_TYPE; + +typedef enum +{ + VIDEO_CHUNK_UNKNOWN = 0, + VIDEO_CHUNK_VIDEO = 1, + VIDEO_CHUNK_AUDIO = 2, + VIDEO_CHUNK_VIDEO_PARTIAL = 3, + VIDEO_CHUNK_AUDIO_PARTIAL = 4, + VIDEO_CHUNK_SUBT = 5, + + VIDEO_CHUNK_FRAGMENT = 6, // if chunk header is split + VIDEO_CHUNK_HEADER = 7, // MPEG header w/o audio/video data + + VIDEO_CHUNK_RECOVERY = 8, + + VIDEO_CHUNK_EOF = 100, +} VIDEO_CHUNK_TYPE; + +typedef enum +{ + RIFF_VIDEO_UNKNOWN = -1, + RIFF_VIDEO_MPEG12 = 0, + RIFF_VIDEO_MPEG4 = 1, + RIFF_VIDEO_DIV3 = 2, + +} RIFF_VIDEO_FORMAT; + +typedef enum +{ + VIDEO_FRAME_NONE = -1, + VIDEO_FRAME_I = 0, + VIDEO_FRAME_P, + VIDEO_FRAME_B, +} VIDEO_FRAME_TYPE; + +#ifdef VIDEO_INTERNAL + +#include "divx.h" + +extern bool video_msg; + +typedef struct VideoKeyFrame +{ + int i; + int len; + LONGLONG offs; +} VideoKeyFrame; + +static const int num_key_frames_block = 32768 / sizeof(VideoKeyFrame); +static const int min_delta_keyframes = 10; +static const int def_max_rev_incr = 10; +static const int saved_delta_pts_num = 25; + +#define VIDEO_MAX_AUDIO_TRACKS 8 + +#define VIDEO_KEY_FRAME_NEXT INT64(-0x7ffffffffffffff0) +#define VIDEO_KEY_FRAME_PREV INT64(-0x7ffffffffffffff1) +#define VIDEO_KEY_FRAME_CONTINUE INT64(-0x7ffffffffffffff2) + +/// Generic base video player class +class Video +{ +public: + /// ctor + Video(); + + /// dtor + virtual ~Video(); + + virtual BOOL Parse() = 0; + virtual VIDEO_CHUNK_TYPE GetNext(BYTE *buf, int buflen, int *pos, int *left, int *len) = 0; + + /// Returns 0 if found, -1 if failed, 1 for EOF. + virtual int GetNextIndexes() = 0; + /// Find next key-frame in raw mode + virtual int GetNextKeyFrame() = 0; + + virtual int GetKeyFrame(LONGLONG time); + virtual void UpdateTotalTime(); + + int SetCurrentIndex(int i, int len, LONGLONG offs); + int AddIndex(int i, int len, LONGLONG offs); + + /// Fix audio packet PTS if audio is far ahead video + LONGLONG FixAudioPts(LONGLONG pts); + +public: + VIDEO_CONTAINER_TYPE type; + + bool playing, stopping, is_eof; + MEDIA_EVENT event; + int scale, rate; + LONGLONG scr; + LONGLONG good_delta_stc; + LONGLONG saved_pts, displ_pts_base; + bool wait_for_resync; + + RIFF_VIDEO_FORMAT video_fmt; + RIFF_AUDIO_FORMAT audio_fmt; + SPString video_fmt_str, audio_fmt_str; + + VIDEO_CHUNK_TYPE chunktype; + int chunkleft; + int video_packet_len, old_video_packet_len; + bool look4chunk; + bool test_for_qpel_gmc; + BYTE chunkheader[8]; + + BYTE *mux_buf[16], *allocated_mux_buf[16]; + int mux_numbufs, mux_bufsize; + int allocated_numbufs; + int allocated_mux_buf_size[16]; + bool no_partial; + + BYTE *divx_buf[16], *divx_base[16]; + int divx_cur_bufpos, divx_cur_bufleft; + bool in_divx_packet; + bool need_to_stop; + // for divx3 optimizations + bool audio_halfrate; + + //// file container reader - common vars: + int fd; + + int width, height; + float fps; + int video_frames; + bool qpel_flag, gmc_flag; + char fourcc[5]; + + RiffAudioTrack track[VIDEO_MAX_AUDIO_TRACKS]; + int cur_track, first_track, num_tracks; + int cur_audio_bits; + + int total_frames; + LONGLONG audio_delta, audio_total_bytes, audio_pts_offset; // needed for PTS calcs. + int num_idx; + + SPClassicList > indexes; + + int abs_video_pos, video_pos_base, video_pos, last_key_pos, cur_key_pos; + int audio_pos; + int cur_key_idx, last_good_key_idx, last_key_idx; + int frame_pos, last_frame_pos; + int max_rev_incr; + + bool skip_fwd, skip_rev, searching, skip_wait, skip_waiting; + int delayed_skip; // used to set skip_fwd/rev if not ready immediately + int last_keyframe_time; + int skip_cnt; + bool cancel_skip; + + LONGLONG cur_offs, video_offs, cur_key_offs; + + // for raw-mode seeking + LONGLONG last_chunk_offs; + int last_chunk_len; + + LONGLONG saved_video_pts; + +private: + /// Get given key-frame index + VideoKeyFrame *GetIndex(int idx); + + void ResetAvgPts(); + + LONGLONG saved_delta_pts[saved_delta_pts_num]; + LONGLONG avg_delta_pts, min_delta_pts, max_delta_pts, minus_delta_pts; + int saved_delta_pts_idx; +}; + +LONGLONG video_lseek(LONGLONG off, int where); +int video_read(BYTE *buf, int len); + + +#endif + +/// Play Video file +int video_play(char *filepath = NULL); + +/// Advance playing +int video_loop(); + +/// Pause playing +BOOL video_pause(); + +/// Stop playing +BOOL video_stop(); + +/// Seek to given time and play +BOOL video_seek(int seconds); + +int video_forward(BOOL fast); +int video_rewind(BOOL fast); + +void video_set_audio_offset(LONGLONG offset); +LONGLONG video_get_audio_offset(); + +void video_setdebug(BOOL ison); +BOOL video_getdebug(); + +/// Set audio track (if -1 then cycle through all) +int video_set_audio_track(int track); + +bool video_search_fourcc(DWORD fourcc, const DWORD *values); + +//////////////////////////////// +BOOL video_open(const char *filepath); +BOOL video_close(); + +LONGLONG video_lseek(LONGLONG off, int where); +int video_read(BYTE *buf, int len); +bool video_eof(); + +VIDEO_CHUNK_TYPE video_getnext(BYTE *buf, int buflen, int *pos, int *left, int *len); +void video_shiftpos(int offs); +void video_detect_formats(); +void video_update_info(); + +int video_play_from_last_keyframe(); + +void video_decode_vol_header(BYTE *buf, int len); + +#endif // of SP_VIDEO_H diff --git a/win32/dvd.dsp b/win32/dvd.dsp new file mode 100644 index 0000000..aee8929 --- /dev/null +++ b/win32/dvd.dsp @@ -0,0 +1,123 @@ +# Microsoft Developer Studio Project File - Name="dvd" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=dvd - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dvd.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dvd.mak" CFG="dvd - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dvd - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "dvd - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dvd - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release/dvd" +# PROP BASE Intermediate_Dir "Release/dvd" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release/dvd" +# PROP Intermediate_Dir "Release/dvd" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../src/libsp/win32/include" /I "../src" /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/msvc" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DVDCSS_USE_EXTERNAL_CSS" /YX /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "dvd - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug/dvd" +# PROP BASE Intermediate_Dir "Debug/dvd" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug/dvd" +# PROP Intermediate_Dir "Debug/dvd" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../src/libsp/win32/include" /I "../src" /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/msvc" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "DVDCSS_USE_EXTERNAL_CSS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "dvd - Win32 Release" +# Name "dvd - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\dvd\dvd.cpp +# ADD CPP /I "../src/contrib/libdvdnav/src/vm" /D "DVDNAV_COMPILE" +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\dvd_player.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\dvd_css.c +# ADD CPP /I "../src/contrib/libdvdcss/src" /I "../src/contrib/libdvdcss/win32" +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\dvd_misc.c +# ADD CPP /I "../src/contrib/libdvdnav/src/vm" /D "HAVE_CONFIG_H" /D "DVDNAV_COMPILE" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\src\dvd.h +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\dvd-internal.h +# End Source File +# Begin Source File + +SOURCE=..\src\dvd_misc.h +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/dvd.vcproj b/win32/dvd.vcproj new file mode 100644 index 0000000..28b70aa --- /dev/null +++ b/win32/dvd.vcproj @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/dvd_mod.dsp b/win32/dvd_mod.dsp new file mode 100644 index 0000000..dfa326e --- /dev/null +++ b/win32/dvd_mod.dsp @@ -0,0 +1,186 @@ +# Microsoft Developer Studio Project File - Name="dvd_mod" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=dvd_mod - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dvd_mod.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dvd_mod.mak" CFG="dvd_mod - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dvd_mod - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "dvd_mod - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dvd_mod - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release/dvd_mod" +# PROP BASE Intermediate_Dir "Release/dvd_mod" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release/dvd_mod" +# PROP Intermediate_Dir "Release/dvd_mod" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DVD_MOD_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../src/libsp/win32/include" /I "../src" /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/msvc" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DVD_MOD_EXPORTS" /D "DVDCSS_USE_EXTERNAL_CSS" /D "SP_MEMDEBUG_OFF" /D "COMPILE_MODULE" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /dll /machine:I386 /out:"../modules/dvd.bin" +# SUBTRACT LINK32 /nodefaultlib + +!ELSEIF "$(CFG)" == "dvd_mod - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug/dvd_mod" +# PROP BASE Intermediate_Dir "Debug/dvd_mod" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug/dvd_mod" +# PROP Intermediate_Dir "Debug/dvd_mod" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DVD_MOD_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../src/libsp/win32/include" /I "../src" /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/msvc" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DVD_MOD_EXPORTS" /D "DVDCSS_USE_EXTERNAL_CSS" /D "SP_MEMDEBUG_OFF" /D "COMPILE_MODULE" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /dll /incremental:no /debug /machine:I386 /out:"../modules/dvd.bin" /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "dvd_mod - Win32 Release" +# Name "dvd_mod - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\dvd\dvd.cpp +# ADD CPP /I "../src/contrib/libdvdnav/src/vm" /D "DVDNAV_COMPILE" +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\dvd_css.c +# ADD CPP /I "../src/contrib/libdvdcss/src" /I "../src/contrib/libdvdcss/win32" +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\dvd_misc.c +# ADD CPP /I "../src/contrib/libdvdnav/src/vm" /D "HAVE_CONFIG_H" /D "DVDNAV_COMPILE" +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\dvd_player.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\dvd\main.cpp +# End Source File +# Begin Source File + +SOURCE="..\src\module-dvd.cpp" + +!IF "$(CFG)" == "dvd_mod - Win32 Release" + +!ELSEIF "$(CFG)" == "dvd_mod - Win32 Debug" + +# ADD CPP /Gm- +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\src\module-init.cpp" + +!IF "$(CFG)" == "dvd_mod - Win32 Release" + +!ELSEIF "$(CFG)" == "dvd_mod - Win32 Debug" + +# ADD CPP /Gm- +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\src\module.cpp + +!IF "$(CFG)" == "dvd_mod - Win32 Release" + +!ELSEIF "$(CFG)" == "dvd_mod - Win32 Debug" + +# ADD CPP /Gm- +# SUBTRACT CPP /YX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_module.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\string.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\src\dvd\dvd-internal.h" +# End Source File +# Begin Source File + +SOURCE=..\src\dvd.h +# End Source File +# Begin Source File + +SOURCE=..\src\dvd_misc.h +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/dvd_mod.vcproj b/win32/dvd_mod.vcproj new file mode 100644 index 0000000..aae97bc --- /dev/null +++ b/win32/dvd_mod.vcproj @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/dvdcss.dsp b/win32/dvdcss.dsp new file mode 100644 index 0000000..03886f0 --- /dev/null +++ b/win32/dvdcss.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="dvdcss" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=dvdcss - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dvdcss.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dvdcss.mak" CFG="dvdcss - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dvdcss - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "dvdcss - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dvdcss - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../src/contrib/libdvdcss/win32" /I "../src/libsp/win32/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /Fo"Debug/libdvdcss/" /Fd"Debug/libdvdcss/" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "dvdcss - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../src/contrib/libdvdcss/win32" /I "../src/libsp/win32/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /Fo"Debug/libdvdcss/" /Fd"Debug/libdvdcss/" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "dvdcss - Win32 Release" +# Name "dvdcss - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\css.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\device.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\error.c" + +!IF "$(CFG)" == "dvdcss - Win32 Release" + +# PROP Intermediate_Dir "Release/error" + +!ELSEIF "$(CFG)" == "dvdcss - Win32 Debug" + +# PROP Intermediate_Dir "Debug/error" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\ioctl.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\libdvdcss.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\bsdi_dvd.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\common.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\css.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\csstables.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\device.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\ioctl.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdcss\src\libdvdcss.h" +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/dvdcss.vcproj b/win32/dvdcss.vcproj new file mode 100644 index 0000000..572bf91 --- /dev/null +++ b/win32/dvdcss.vcproj @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/dvdnav.dsp b/win32/dvdnav.dsp new file mode 100644 index 0000000..45d6548 --- /dev/null +++ b/win32/dvdnav.dsp @@ -0,0 +1,248 @@ +# Microsoft Developer Studio Project File - Name="dvdnav" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=dvdnav - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dvdnav.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dvdnav.mak" CFG="dvdnav - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dvdnav - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "dvdnav - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dvdnav - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/src/vm" /I "../src/libsp/win32/include" /I "../src/contrib/libdvdcss/src" /I "../src/contrib/libdvdnav/msvc" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /D "DVDNAV_COMPILE" /YX /Fo"Release/libdvdnav/" /Fd"Release/libdvdnav/" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "dvdnav - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/src/vm" /I "../src/libsp/win32/include" /I "../src/contrib/libdvdcss/src" /I "../src/contrib/libdvdnav/msvc" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /D "DVDNAV_COMPILE" /YX /Fo"Debug/libdvdnav/" /Fd"Debug/libdvdnav/" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "dvdnav - Win32 Release" +# Name "dvdnav - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\vm\decoder.c +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\dvd_input.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\dvd_reader.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\dvd_udf.c" +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\dvdnav.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\highlight.c +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\ifo_print.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\ifo_read.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\md5.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\nav_print.c" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\nav_read.c" +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\navigation.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\read_cache.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\remap.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\searching.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\settings.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\vm\vm.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\vm\vmcmd.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\bswap.h" +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\vm\decoder.h +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\dvd_input.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\dvd_reader.h" +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\dvd_types.h +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\dvd_udf.h" +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\dvdnav.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\dvdnav_events.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\dvdnav_internal.h +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\dvdread_internal.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\ifo_print.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\ifo_read.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\ifo_types.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\md5.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\nav_print.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\nav_read.h" +# End Source File +# Begin Source File + +SOURCE="..\src\contrib\libdvdnav\src\dvdread\nav_types.h" +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\read_cache.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\remap.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\vm\vm.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libdvdnav\src\vm\vmcmd.h +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/dvdnav.vcproj b/win32/dvdnav.vcproj new file mode 100644 index 0000000..269a4f1 --- /dev/null +++ b/win32/dvdnav.vcproj @@ -0,0 +1,664 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/gui.dsp b/win32/gui.dsp new file mode 100644 index 0000000..570ca73 --- /dev/null +++ b/win32/gui.dsp @@ -0,0 +1,173 @@ +# Microsoft Developer Studio Project File - Name="gui" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=gui - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gui.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gui.mak" CFG="gui - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gui - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "gui - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gui - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release/gui" +# PROP BASE Intermediate_Dir "Release/gui" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release/gui" +# PROP Intermediate_Dir "Release/gui" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W4 /GX /O2 /I "../src/libsp/win32/include" /I "../src" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "gui - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug/gui" +# PROP BASE Intermediate_Dir "Debug/gui" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug/gui" +# PROP Intermediate_Dir "Debug/gui" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /GX /ZI /Od /I "../src/libsp/win32/include" /I "../src" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "gui - Win32 Release" +# Name "gui - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\gui\console.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\font.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\giflib.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\image.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\jpeg.cpp +# ADD CPP /I "../src/contrib/libjpeg" +# End Source File +# Begin Source File + +SOURCE=..\src\gui\mmsl.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\rect.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\res.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\text.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\gui\window.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\src\gui\console.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\font.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\giflib.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\image.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\jpeg.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\mmsl.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\rect.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\res.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\text.h +# End Source File +# Begin Source File + +SOURCE=..\src\gui\window.h +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/gui.vcproj b/win32/gui.vcproj new file mode 100644 index 0000000..ea4196d --- /dev/null +++ b/win32/gui.vcproj @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/init.dsp b/win32/init.dsp new file mode 100644 index 0000000..e10631b --- /dev/null +++ b/win32/init.dsp @@ -0,0 +1,254 @@ +# Microsoft Developer Studio Project File - Name="init" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=init - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "init.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "init.mak" CFG="init - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "init - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "init - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "init - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W4 /GX /O2 /I "../src/libsp/win32/include" /I "../src" /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/msvc" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "DVDCSS_USE_EXTERNAL_CSS" /YX /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:yes /machine:I386 /out:"../init.exe" +# SUBTRACT LINK32 /debug + +!ELSEIF "$(CFG)" == "init - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /GX /ZI /Od /I "../src/libsp/win32/include" /I "../src" /I "../src/contrib/libdvdnav/src" /I "../src/contrib/libdvdnav/src/dvdread" /I "../src/contrib/libdvdnav/msvc" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "DVDCSS_USE_EXTERNAL_CSS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../init.exe" /pdbtype:sept /fixed:no +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "init - Win32 Release" +# Name "init - Win32 Debug" +# Begin Group "Source files" + +# PROP Default_Filter "*.cpp;*.c" +# Begin Source File + +SOURCE=..\src\audio.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\avi.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\bitstream.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\cdda.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\divx.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\init.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\media.cpp +# ADD CPP /D "DVDNAV_COMPILE" +# End Source File +# Begin Source File + +SOURCE="..\src\module-dvd.cpp" +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE="..\src\module-init.cpp" +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=..\src\module.cpp +# SUBTRACT CPP /YX +# End Source File +# Begin Source File + +SOURCE=..\src\mpg.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\player.cpp +# ADD CPP /D "PLAYER_INFO_EMBED" +# End Source File +# Begin Source File + +SOURCE=..\src\info\player_info.cpp +# ADD CPP /D "PLAYER_INFO_EMBED" +# End Source File +# Begin Source File + +SOURCE="..\src\script-explorer.cpp" +# End Source File +# Begin Source File + +SOURCE="..\src\script-objects.cpp" +# End Source File +# Begin Source File + +SOURCE="..\src\script-player.cpp" +# End Source File +# Begin Source File + +SOURCE=..\src\script.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\settings.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\subtitle.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\video.cpp +# End Source File +# End Group +# Begin Group "Header files" + +# PROP Default_Filter "*.h" +# Begin Source File + +SOURCE=..\src\audio.h +# End Source File +# Begin Source File + +SOURCE=..\src\avi.h +# End Source File +# Begin Source File + +SOURCE=..\src\bitstream.h +# End Source File +# Begin Source File + +SOURCE=..\src\cdda.h +# End Source File +# Begin Source File + +SOURCE="..\src\divx-tables.h" +# End Source File +# Begin Source File + +SOURCE=..\src\divx.h +# End Source File +# Begin Source File + +SOURCE=..\src\module.h +# End Source File +# Begin Source File + +SOURCE=..\src\mpg.h +# End Source File +# Begin Source File + +SOURCE=..\src\player.h +# End Source File +# Begin Source File + +SOURCE=..\src\info\player_info.h +# End Source File +# Begin Source File + +SOURCE="..\src\script-internal.h" +# End Source File +# Begin Source File + +SOURCE=..\src\script.h +# End Source File +# Begin Source File + +SOURCE=..\src\settings.h +# End Source File +# Begin Source File + +SOURCE=..\src\subtitle.h +# End Source File +# Begin Source File + +SOURCE=..\src\video.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\src\libsp\win32\fip.bmp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\libsp.rc +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\manifest.xml +# End Source File +# End Target +# End Project diff --git a/win32/init.dsw b/win32/init.dsw new file mode 100644 index 0000000..f8f388b --- /dev/null +++ b/win32/init.dsw @@ -0,0 +1,167 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "dvd"=.\dvd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name dvdnav + End Project Dependency +}}} + +############################################################################### + +Project: "dvd_mod"=.\dvd_mod.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name dvdnav + End Project Dependency +}}} + +############################################################################### + +Project: "dvdcss"=.\dvdcss.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "dvdnav"=.\dvdnav.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name dvdcss + End Project Dependency +}}} + +############################################################################### + +Project: "gui"=.\gui.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "init"=.\init.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libsp + End Project Dependency + Begin Project Dependency + Project_Dep_Name gui + End Project Dependency + Begin Project Dependency + Project_Dep_Name libjpeg + End Project Dependency + Begin Project Dependency + Project_Dep_Name libpng + End Project Dependency + Begin Project Dependency + Project_Dep_Name mw + End Project Dependency + Begin Project Dependency + Project_Dep_Name libid3tag + End Project Dependency + Begin Project Dependency + Project_Dep_Name libmad + End Project Dependency +}}} + +############################################################################### + +Project: "libid3tag"=.\libid3tag.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libjpeg"=.\libjpeg.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libmad"=.\libmad.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libsp"=.\libsp.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/win32/init.sln b/win32/init.sln new file mode 100644 index 0000000..b45e3f4 --- /dev/null +++ b/win32/init.sln @@ -0,0 +1,90 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dvd", "dvd.vcproj", "{9FC94E1B-F135-43E1-AB9D-5D56B8BD3F66}" + ProjectSection(ProjectDependencies) = postProject + {115F0E05-BB93-46B1-93A8-BE1B2B4DED93} = {115F0E05-BB93-46B1-93A8-BE1B2B4DED93} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dvd_mod", "dvd_mod.vcproj", "{B4DE03D5-6195-4D50-A162-8CA9341A5445}" + ProjectSection(ProjectDependencies) = postProject + {115F0E05-BB93-46B1-93A8-BE1B2B4DED93} = {115F0E05-BB93-46B1-93A8-BE1B2B4DED93} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dvdcss", "dvdcss.vcproj", "{37D2DD79-B8A3-45F2-82AA-9DD5E1CB2221}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dvdnav", "dvdnav.vcproj", "{115F0E05-BB93-46B1-93A8-BE1B2B4DED93}" + ProjectSection(ProjectDependencies) = postProject + {37D2DD79-B8A3-45F2-82AA-9DD5E1CB2221} = {37D2DD79-B8A3-45F2-82AA-9DD5E1CB2221} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gui", "gui.vcproj", "{357B6DE6-0C68-42E7-B70A-4106CEF47D1A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "init", "init.vcproj", "{DDFB60D8-953D-440F-B6F1-7483A172E1F9}" + ProjectSection(ProjectDependencies) = postProject + {5140CBBF-B016-4381-A38E-C23055D328EC} = {5140CBBF-B016-4381-A38E-C23055D328EC} + {357B6DE6-0C68-42E7-B70A-4106CEF47D1A} = {357B6DE6-0C68-42E7-B70A-4106CEF47D1A} + {5F05E39D-9409-48F4-B739-9ADBE945F637} = {5F05E39D-9409-48F4-B739-9ADBE945F637} + {3BE1FF59-65FA-4A91-996F-3579E44C7C5D} = {3BE1FF59-65FA-4A91-996F-3579E44C7C5D} + {8D244847-BD35-4CC3-BBBA-C877E383E3CF} = {8D244847-BD35-4CC3-BBBA-C877E383E3CF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libid3tag", "libid3tag.vcproj", "{3BE1FF59-65FA-4A91-996F-3579E44C7C5D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "libjpeg.vcproj", "{5F05E39D-9409-48F4-B739-9ADBE945F637}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmad", "libmad.vcproj", "{8D244847-BD35-4CC3-BBBA-C877E383E3CF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsp", "libsp.vcproj", "{5140CBBF-B016-4381-A38E-C23055D328EC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9FC94E1B-F135-43E1-AB9D-5D56B8BD3F66}.Debug|Win32.ActiveCfg = Debug|Win32 + {9FC94E1B-F135-43E1-AB9D-5D56B8BD3F66}.Debug|Win32.Build.0 = Debug|Win32 + {9FC94E1B-F135-43E1-AB9D-5D56B8BD3F66}.Release|Win32.ActiveCfg = Release|Win32 + {9FC94E1B-F135-43E1-AB9D-5D56B8BD3F66}.Release|Win32.Build.0 = Release|Win32 + {B4DE03D5-6195-4D50-A162-8CA9341A5445}.Debug|Win32.ActiveCfg = Debug|Win32 + {B4DE03D5-6195-4D50-A162-8CA9341A5445}.Debug|Win32.Build.0 = Debug|Win32 + {B4DE03D5-6195-4D50-A162-8CA9341A5445}.Release|Win32.ActiveCfg = Release|Win32 + {B4DE03D5-6195-4D50-A162-8CA9341A5445}.Release|Win32.Build.0 = Release|Win32 + {37D2DD79-B8A3-45F2-82AA-9DD5E1CB2221}.Debug|Win32.ActiveCfg = Debug|Win32 + {37D2DD79-B8A3-45F2-82AA-9DD5E1CB2221}.Debug|Win32.Build.0 = Debug|Win32 + {37D2DD79-B8A3-45F2-82AA-9DD5E1CB2221}.Release|Win32.ActiveCfg = Release|Win32 + {37D2DD79-B8A3-45F2-82AA-9DD5E1CB2221}.Release|Win32.Build.0 = Release|Win32 + {115F0E05-BB93-46B1-93A8-BE1B2B4DED93}.Debug|Win32.ActiveCfg = Debug|Win32 + {115F0E05-BB93-46B1-93A8-BE1B2B4DED93}.Debug|Win32.Build.0 = Debug|Win32 + {115F0E05-BB93-46B1-93A8-BE1B2B4DED93}.Release|Win32.ActiveCfg = Release|Win32 + {115F0E05-BB93-46B1-93A8-BE1B2B4DED93}.Release|Win32.Build.0 = Release|Win32 + {357B6DE6-0C68-42E7-B70A-4106CEF47D1A}.Debug|Win32.ActiveCfg = Debug|Win32 + {357B6DE6-0C68-42E7-B70A-4106CEF47D1A}.Debug|Win32.Build.0 = Debug|Win32 + {357B6DE6-0C68-42E7-B70A-4106CEF47D1A}.Release|Win32.ActiveCfg = Release|Win32 + {357B6DE6-0C68-42E7-B70A-4106CEF47D1A}.Release|Win32.Build.0 = Release|Win32 + {DDFB60D8-953D-440F-B6F1-7483A172E1F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {DDFB60D8-953D-440F-B6F1-7483A172E1F9}.Debug|Win32.Build.0 = Debug|Win32 + {DDFB60D8-953D-440F-B6F1-7483A172E1F9}.Release|Win32.ActiveCfg = Release|Win32 + {DDFB60D8-953D-440F-B6F1-7483A172E1F9}.Release|Win32.Build.0 = Release|Win32 + {3BE1FF59-65FA-4A91-996F-3579E44C7C5D}.Debug|Win32.ActiveCfg = Debug|Win32 + {3BE1FF59-65FA-4A91-996F-3579E44C7C5D}.Debug|Win32.Build.0 = Debug|Win32 + {3BE1FF59-65FA-4A91-996F-3579E44C7C5D}.Release|Win32.ActiveCfg = Release|Win32 + {3BE1FF59-65FA-4A91-996F-3579E44C7C5D}.Release|Win32.Build.0 = Release|Win32 + {5F05E39D-9409-48F4-B739-9ADBE945F637}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F05E39D-9409-48F4-B739-9ADBE945F637}.Debug|Win32.Build.0 = Debug|Win32 + {5F05E39D-9409-48F4-B739-9ADBE945F637}.Release|Win32.ActiveCfg = Release|Win32 + {5F05E39D-9409-48F4-B739-9ADBE945F637}.Release|Win32.Build.0 = Release|Win32 + {8D244847-BD35-4CC3-BBBA-C877E383E3CF}.Debug|Win32.ActiveCfg = Debug|Win32 + {8D244847-BD35-4CC3-BBBA-C877E383E3CF}.Debug|Win32.Build.0 = Debug|Win32 + {8D244847-BD35-4CC3-BBBA-C877E383E3CF}.Release|Win32.ActiveCfg = Release|Win32 + {8D244847-BD35-4CC3-BBBA-C877E383E3CF}.Release|Win32.Build.0 = Release|Win32 + {5140CBBF-B016-4381-A38E-C23055D328EC}.Debug|Win32.ActiveCfg = Debug|Win32 + {5140CBBF-B016-4381-A38E-C23055D328EC}.Debug|Win32.Build.0 = Debug|Win32 + {5140CBBF-B016-4381-A38E-C23055D328EC}.Release|Win32.ActiveCfg = Release|Win32 + {5140CBBF-B016-4381-A38E-C23055D328EC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win32/init.vcproj b/win32/init.vcproj new file mode 100644 index 0000000..d556f28 --- /dev/null +++ b/win32/init.vcproj @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/libid3tag.dsp b/win32/libid3tag.dsp new file mode 100644 index 0000000..c2bba71 --- /dev/null +++ b/win32/libid3tag.dsp @@ -0,0 +1,266 @@ +# Microsoft Developer Studio Project File - Name="libid3tag" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libid3tag - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libid3tag.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libid3tag.mak" CFG="libid3tag - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libid3tag - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libid3tag - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libid3tag - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\src\libsp\win32\include" /I "..\src\contrib\libid3tag\fakezlib" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /Fo"Release/libid3tag/" /Fd"Release/libid3tag/" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libid3tag - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\src\libsp\win32\include" /I "..\src\contrib\libid3tag\fakezlib" /D "_LIB" /D "HAVE_CONFIG_H" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "DEBUG" /Fo"Debug/libid3tag/" /Fd"Debug/libid3tag/" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libid3tag - Win32 Release" +# Name "libid3tag - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "c" +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\compat.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\cp1251.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\crc.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\debug.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\field.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\file.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\frame.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\frametype.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\genre.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\latin1.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\parse.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\render.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\tag.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\ucs4.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\utf16.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\utf8.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\util.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\version.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\fakezlib\zlib.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\compat.h +# End Source File +# Begin Source File + +SOURCE=.\config.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\cp1251.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\crc.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\debug.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\field.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\file.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\frame.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\frametype.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\genre.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\global.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\id3tag.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\latin1.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\parse.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\render.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\tag.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\ucs4.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\utf16.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\utf8.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\util.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\version.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\fakezlib\zlib.h +# End Source File +# End Group +# Begin Group "Data Files" + +# PROP Default_Filter "dat" +# Begin Source File + +SOURCE=..\src\contrib\libid3tag\genre.dat +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/libid3tag.vcproj b/win32/libid3tag.vcproj new file mode 100644 index 0000000..b80957e --- /dev/null +++ b/win32/libid3tag.vcproj @@ -0,0 +1,697 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/libjpeg.dsp b/win32/libjpeg.dsp new file mode 100644 index 0000000..4b87993 --- /dev/null +++ b/win32/libjpeg.dsp @@ -0,0 +1,244 @@ +# Microsoft Developer Studio Project File - Name="libjpeg" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libjpeg - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libjpeg.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libjpeg.mak" CFG="libjpeg - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libjpeg - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libjpeg - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libjpeg - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /Fo"Release/libjpeg/" /Fd"Release/libjpeg/" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libjpeg - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /Fo"Debug/libjpeg/" /Fd"Debug/libjpeg/" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libjpeg - Win32 Release" +# Name "libjpeg - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jcomapi.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdapimin.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdapistd.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdatadst.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdatasrc.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdcoefct.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdcolor.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jddctmgr.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdhuff.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdinput.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdmainct.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdmarker.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdmaster.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdmerge.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdphuff.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdpostct.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdsample.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdtrans.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jerror.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jidctflt.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jidctfst.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jidctint.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jidctred.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jmemansi.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jmemmgr.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jquant1.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jquant2.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jutils.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jconfig.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdct.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jdhuff.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jerror.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jinclude.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jmemsys.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jmorecfg.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jpegint.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jpeglib.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libjpeg\jversion.h +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/libjpeg.vcproj b/win32/libjpeg.vcproj new file mode 100644 index 0000000..1f117b8 --- /dev/null +++ b/win32/libjpeg.vcproj @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/libmad.dsp b/win32/libmad.dsp new file mode 100644 index 0000000..4b49168 --- /dev/null +++ b/win32/libmad.dsp @@ -0,0 +1,213 @@ +# Microsoft Developer Studio Project File - Name="libmad" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libmad - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libmad.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libmad.mak" CFG="libmad - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libmad - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libmad - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libmad - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /GX /O2 /I "..\src\contrib\libmad\msvc++" /I "..\src\libsp\win32\include" /D "NDEBUG" /D "FPM_INTEL" /D "WIN32" /D "_MBCS" /D "_LIB" /D "HAVE_CONFIG_H" /D "ASO_ZEROCHECK" /Fo"Release/libmad/" /Fd"Release/libmad/" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libmad - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /Gm /GX /ZI /Od /I "..\src\contrib\libmad\msvc++" /I "..\src\libsp\win32\include" /D "FPM_DEFAULT" /D "_LIB" /D "HAVE_CONFIG_H" /D "ASO_ZEROCHECK" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "DEBUG" /Fo"Debug/libmad/" /Fd"Debug/libmad/" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libmad - Win32 Release" +# Name "libmad - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "c" +# Begin Source File + +SOURCE=..\src\contrib\libmad\bit.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\decoder.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\fixed.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\frame.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\huffman.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\layer12.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\layer3.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\stream.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\synth.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\timer.c +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\version.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=..\src\contrib\libmad\bit.h +# End Source File +# Begin Source File + +SOURCE=.\src\contrib\libmad\config.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\decoder.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\fixed.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\frame.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\global.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\huffman.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\layer12.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\layer3.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\stream.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\synth.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\timer.h +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\version.h +# End Source File +# End Group +# Begin Group "Data Files" + +# PROP Default_Filter "dat" +# Begin Source File + +SOURCE=..\src\contrib\libmad\D.dat +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\imdct_s.dat +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\qc_table.dat +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\rq_table.dat +# End Source File +# Begin Source File + +SOURCE=..\src\contrib\libmad\sf_table.dat +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/libmad.vcproj b/win32/libmad.vcproj new file mode 100644 index 0000000..7d83c95 --- /dev/null +++ b/win32/libmad.vcproj @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/libsp.dsp b/win32/libsp.dsp new file mode 100644 index 0000000..3e6bba0 --- /dev/null +++ b/win32/libsp.dsp @@ -0,0 +1,256 @@ +# Microsoft Developer Studio Project File - Name="libsp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libsp - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libsp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libsp.mak" CFG="libsp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libsp - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libsp - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libsp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W4 /GX /O2 /I "../src/libsp" /I "../src/libsp/win32/include" /I "../src" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /Fo"Release/libsp/" /Fd"Release/libsp/" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libsp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /GX /ZI /Od /I "../src/libsp" /I "../src/libsp/win32/include" /I "../src" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /Fo"Debug/libsp/" /Fd"Debug/libsp/" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libsp - Win32 Release" +# Name "libsp - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\libsp\win32\dirent.c +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\membin.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_cdrom.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_css.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_eeprom.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_fip.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_flash.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_khwl.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_khwl_colors.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_memory.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_misc.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_module.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_mpeg.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_msg.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_video.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\string.cpp +# End Source File +# Begin Source File + +SOURCE="..\src\libsp\win32\win32-stuff.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\src\libsp\containers\clist.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\dirent.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\dllist.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\hashlist.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\list.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\membin.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\resource.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\slist.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_bswap.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_cdrom.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\win32\sp_css.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_eeprom.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_fip.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_flash.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_io.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_khwl.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_memory.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_misc.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_module.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_mpeg.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_msg.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\sp_video.h +# End Source File +# Begin Source File + +SOURCE=..\src\libsp\containers\string.h +# End Source File +# Begin Source File + +SOURCE="..\src\libsp\win32\win32-stuff.h" +# End Source File +# End Group +# End Target +# End Project diff --git a/win32/libsp.vcproj b/win32/libsp.vcproj new file mode 100644 index 0000000..b95dd4e --- /dev/null +++ b/win32/libsp.vcproj @@ -0,0 +1,636 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +