Вторник, 19.03.2024, 12:26
Вы вошли как
Приветствую Вас ГостьRSS
Меню
Категории раздела
Компиляция [2]
Инструкции по компиляции пакетов под плеер
Модификация прошивки [5]
Инструкции по модификации прошивки
Облако тегов
HDD playon!hd playonhd btpd 100 peers video 200 peers optware прошивка Realtek mipsel wifi rtorrent Firmware web Woxter i-Cube 750 ruTorrent Mede8er lighttpd digest Samba workgroup peers Port podware Compilation gcc Native hostname bmp bmp2rt felics rt2bmp ipkg ipkg-cl libexif libsigc++ Screen vsftpd transmission htop MC Nano rdate datasheet RTD1073
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа

Главная » Статьи » Продвинутые мануалы » Модификация прошивки

Некоторые размышления о кодированной графике
Upd 07.04.2011 Статья обновлена, выложены новые версии программ
Статья получилась очень "заумная". Но тем не менее - публикую, надеясь на то, что кому то она пригодится.

Многие в курсе, что в прошивке есть картинки, которые нельзя просмотреть и отредактировать обычными средствами. Кроме того, если эти картинки скопировать в другое место, плеер откажется их показывать. Порывшись в интернете, и почитав информацию по этому вопросу, я совершил небольшой промах. Поверив на слово заявлениям достаточно уважаемых спецов в этой области, дал обещание написать конвертер для этих файлов. Но не тут то было... Потратил больше недели. А неделя возни с ерундовым алгоритмом - для меня это много ;)

Начну по порядку.
Итак, в прошивке для любого плеера есть файлы с расширением bmp, которые вовсе такими не являются. Позволю себе высказать свои предположения, откуда они появились и для чего нужны.
Ежу понятно, что появление этих файлов растет из здоровой конкуренции между производителями. Прогу для кодирования файлов дает сам Realtek с составе СДК, и ее можно найти в инете (bmp2felics). Кстати, под моей Fedora 11 она не запустилась. А вот проги для декодирования я нигде не нашел.

Тут предвижу вполне законный вопрос: "А зачем нужны эти кодированные файлы, если плеер прекрасно жрет обычные bmp в формате 16bit R5G6B5?". Мой ответ такой: эти кодированные файлы гораздо быстрее прорисовываются плеером (видимо, за счет аппаратной поддержки).

Исходя из вышесказанного, я счел нужным заняться изучением этого формата.

Ну-с, приступим-с...

Подопытным кроликом я выбрал файл FILE_MANAGER_1.bmp, но не посмотрел, от какой прошивки и от какого плеера. В принципе, это неважно, т.к. формат этих файлов одинаковый, но если кому то будет интересно покопать вместе со мной, я его залил
Вполне естественно, что этот файл не открылся ни в одном графическом редакторе, и даже специальные программы не смогли определить его тип. Впрочем, я этого и ожидал. Поэтому открыл его в программе, которая может открыть абсолютно все - в HEX-редакторе. И увидел следующее:


Тем, кто когда нибудь открывал bmp подобным образом, сразу станет понятно, что битмапом тут и не пахнет. Хотя бы потому, что сигнатура bmp-файла другая. Обычно это BM, хотя встречаются и другие (в OS/2 - BA, CI, CP, IC, PT). Тут же мы видим символы RT, что очень смахивает на RealTek.
Немного пошевелив мозгами и покопавшись в исходниках (от самого первого СДК), а так же в коде функции DG_GetBmpHeader, предлагаю Вашему вниманию свои выводы:

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

Байты 4..7 представляют собой некоторую константу, из которой вычисляется количество бит и байт на пиксель. В данном случае это поле имеет значение 4. Следует читать байты в обратном направлении (т.е. 00 00 00 04). В коде предусмотрена возможность и отличного от 4 значения. На языке С это можно написать так:
Code
BitsPerPixel = x[4..7] == 4 ? 0x10 : 0x20 // 16 или 32 бита на пиксель
BytesPerPixel = x[4..7] == 4 ? 2 : 4 // 2 или 4 байта на пиксель
Pitch = Width * ( x[4..7] == 4 ? 2 : 4 ) // кол-во байт на одну строку

Следующие 2 байта (8..9) - это ширина (Width) изображения. 0x0087 = 135 пикселей. Аналогично байты 0xA..B - высота (Height). 0x7C = 124 пикселя.

В байтах 0xC..D и 0xE..F предыдущие значения повторяются. Для них в коде прошивки предусмотрены два лишних поля, названные как ori_width и ori_height. ИМХО, они особого значения не имеют, так как при разборе обычного bmp-заголовка в них копируются значения полей Width и Height.

Над смыслом следующих 3-х групп по 4 байта я думал довольно долго, пока не сложил их вместе. В результате получилось:
0xC70 (3184) + 0xFB0 (4016) + 0xDC0 (3520) = 0x29E0 (10720)
Если учесть, что длина файла составляет 0x2A00 (10752), разница между этими цифрами составляет 32 байта. Иными словами, 0x20 (32) - это длина заголовка, за которым следуют 3 блока с данными.

Последние 4 байта заголовка зарезервированы для Альфа-канала и в данном случае не используются.

Все вышесказанное нарисую в виде структуры:

Code
C  
typedef struct {
  BYTE magic[4];
  DWORD bpp;
  WORD Width;
  WORD Height;
  WORD ori_width;
  WORD ori_height;
  DWORD R_len;
  DWORD G_len;
  DWORD B_len;
  DWORD Reserved;
} RTHEADER;
   
Pascal  
  RTHeader = packed record
  magic: array [0..3] of Byte;
  bpp: Cardinal;
  Width: Word;
  Height: Word;
  ori_width: Word;
  ori_height: Word;
  R_len: Cardinal;
  G_len: Cardinal;
  B_len: Cardinal;
  Reserved: Cardinal;
  end;

Почему я дал название полям с длиной блоков с индексами цветов? Три блока - три цвета. А еще, если учесть, что в структуре R5G6B5 зеленый цвет занимает места больше остальных, становится понятным, почему размер второго блока больше других.
Для наглядности нарисую пару картинок.
Формат хранения R5G6B5 выглядит так:
1-й байт | 2-байт
RRRRRGGG | GGGBBBBB | и т.д.

В нашем случае, одинаковые цвета сгруппировали, примерно так:

1-й байт | 2-байт   | 3-байт ..
000RRRRR | 000RRRRR | 000RRRRR ....
--------   --------   --------
  |          |          цвет 3-го пикселя
  |          цвет 2-го пикселя
  цвет 1-го пикселя

То же самое для синего цвета. А зеленый сгруппирован по 6 бит.

Однако, если поле bpp равно 7, формат становится другим. В этих файлах для каждого цвета используется 8 бит на пиксель + дополнительные 8 бит для канала яркости (т.н. Альфа-канал). Вот графическое представление формата A8R8G8B8:
1-й байт | 2-й байт | 3-й байт | 4-й байт
AAAAAAAA | RRRRRRRR GGGGGGGG | BBBBBBBB | и т.д.

И еще очень важно: картинка считывается, начиная с нижней строки. Это вполне закономерно, т.к. плеер имеет точку начала координат в нижнем левом углу.

Но вот засада... Чтобы сохранить красный цвет в такой картинке, нужно:
135(ширина) * 124(высота) * 8(бит/пиксель) = 133920 бит или 16740 байт. А длина блока всего 3184 байта. Налицо сжатие более чем в 5 раз. Для сохранения синего цвета нужен такой же объем, но размер пакета другой...
Чем запакованы потоки? Как видно из названия проги от реалтека - это  FELICS (Fast Efficient & Lossless Image Compression System). Правда, и тут была очередная засада - авторы "слегка" изменили алгоритм.

И есть еще одна подсказка. В блоке данных тоже есть заголовок (8 байт). Но в нем всего одна цифра (выделено на рис. зеленым цветом). Это - длина закодированного потока в битах, причем порядок чтения байт обратный. Это значение чуть меньше длины данных в блоке за счет округления размера блока в большую сторону (кратно 4). Иными словами, кодированный поток битов начинается с 9-го байта в блоке.

Попробую объяснить работу этого алгоритма. Основной принцип: каждый следующий пиксель кодируется относительно значений двух ближайших соседей, которые уже побывали в обработке. Это очень хорошо продемонстрировано на рисунке ниже.


Исключением в данном методе являются 2 первых пикселя, для которых еще не существует 2-х обработанных соседей. Поэтому значение первого пикселя записывается в поток целиком, а для значений обоих соседей второго используется значение первого.
После этого значения соседей сравниваются между собой и записываются в переменные H и L (соответственно, большее и меньшее). Несложно догадаться, что в некоторых случаях они будут равны. Затем проверяется, попадает ли значение текущего пикселя P в диапазон между H и L включительно. Если да, в поток записывается бит IN_RANGE, в противном случае OUT_RANGE. Для кодирования внутридиапазонного значения используется модифицированный Adjusted binary код, а внедиапазонного - код Голомба-Рэйза.

Код Голомба-Рэйза
Первым делом в поток записывается бит, определяющий, где находится значение P относительно диапазона, выше или ниже. Соответственно ABOVE_RANGE или UNDER_RANGE. Следующим шагом вычисляется delta по одной из формул: 
delta = P - H - 1 или delta = L - P - 1
После этого в поток записываются несколько единиц, количество которых является результатом целочисленного деления delta на 4, 0 в качестве разделителя, и 2 бита остатка от деления.

Adjusted binary код
Здесь немного посложнее. Базовыми понятиями здесь являются смещение значения текущего пикселя относительно минимального значения диапазона P - L, и сам диапазон delta = H - L. Кодирование значения производится методом определения положения P - L в диапазоне от 0 до delta по определенным правилам. Для примера приведу значения кодов для первых десяти значений delta + 1 (от 2 до 10), при P - L от 0 до 9.
  2  3  4  5  6  7  8  9  10 
0  11  10  111  110  101  100  1111  1110 
1  11  00  111  110  101  000  1111 
2    10  00  01  00  111  110  001  000 
3      01  10  01  00  111  010  001 
4        110  100  010  000  011  010 
5          101  011  001  100  011 
6            100  010  101  100 
7              011  110  101 
8                1110  1100 
9                  1101 
Как видно из таблицы, количество бит, необходимое для кодирования, впрямую зависит от значения delta + 1, а точнее не может превышать степень, в которую надо возвести число 2, чтобы полученное значение было больше или равно delta + 1. Назовем этот параметр range. Соответственно, если delta + 1 = 2^range, все значения кодов будут иметь длину range, а в противном случае - от range - 1 до range.

А как же распределяются коды по диапазону? В случае delta + 1 = 2^range все достаточно просто: числа идут по порядку от середины диапазона и затем продолжаюся с его начала. Для второго варианта придется вычислить еще пару значений. Количество кодов с длиной range - 1 можно вычислить по формуле: 
CountShortWord = 2^range - (delta + 1)
, а количество кодов с максимальной длиной: 
CountLongWord = (delta + 1) - CountShortWord. Короткие коды всегда располагаются в середине диапазона, и их значения начинаются с нуля и возрастают с каждым шагом на 1. Длинные слова располагаются симметрично по краям диапазона, начинаясь после последнего короткого и продолжаясь сверху. Минимальное значение длинного слова равно (значение последнего короткого + 1) * 2. А максимальное значение длинного слова всегда равно 2^range - 1

Для варианта IN_RANGE при delta + 1 = 1, значение текущего байта P не кодируется вообще, так оно равно минимальному значению.

И для тех, кто будет править графику. Нужно обязательно сохранять файл в формате BMP 16bit R5G6B5 или, если присутствует Альфа-канал - в формате BMP 32bit A8R8G8B8. Эти форматы поддерживают: фотошоп от 7-й версии и абсолютно бесплатный GIMP. Прозрачным (transparent) цветом обычно является абсолютно белый, но надо учитывать, что значение этого цвета может быть перепрограммировано в прошивке на другой.

На этом все. Осталось только сообщить значения констант:
IN_RANGE = 0
OUT_RANGE = 1
UNDER_RANGE = 0
ABOVE_RANGE = 1

Ну и для тех, кто дочитал до конца, маленький подарок.  Программы для декомпрессии и компрессии под винды. Обновлены 07.04.2011 до версии 0.2 Пользоваться ими очень просто: бросить программу в папку с картинками и запустить. Компрессор найдет все некодированные файлы, немного поколдует над ними и сложит в папку rfc. В свою очередь, декомпрессор ищет только закодированные файлы и складывает результат работы в папку rfd

PS. Для тех, кто боится вирусов, гарантирую - вирей и прочей нечисти там нет (я этим не занимаюсь). Для желающих собрать проги самостоятельно - обращайтесь в приват, дам ссылку на исходники.

Категория: Модификация прошивки | Добавил: Lossless (15.09.2010)
Просмотров: 11116 | Комментарии: 5 | Теги: felics, bmp, rt2bmp, bmp2rt | Рейтинг: 5.0/2
Всего комментариев: 5
5 nezbedboi  
0
hi lossless!
would you mind publishing the source code of your excellent rt2bmp and bmp2rt utility?
thanks in advance, nezbednik

4 msilko21  
0
А чем посмотреть катинки Лого в файле Загрузчика плеера bootloader.tar или подобном, идущем в составе прошивки? Ваши утилиты их не открывают и после смены расширения файла на bmp.

3 pnedkov  
0
Успел подменить картинки плеера EAGET M880,
Спасибо!

2 etix  
0
Огромное человеческое спасибо!
Сам ковыряюсь в прошивке Seagate FreeAgent Theater+, видел я эти хитрые bmp, да только матерился и не знал как побороть.
А тут случайно наткнулся на Ваши замечательные разработки. СУПЕР!
Спасибо еще раз и успехов во всех творческих начинаниях.

1 Lossless  
1
И еще чуток. Для варианта IN_RANGE при delta + 1 = 1, значение текущего байта P не кодируется вообще, так оно равно минимальному значению.

И для тех, кто будет править графику. Нужно обязательно сохранять файл в формате BMP 16bit R5G6B5. Этот формат поддерживают: фотошоп от 7-й версии и абсолютно бесплатный GIMP. Прозрачным (transparent) цветом обычно является абсолютно белый, но надо учитывать, что значение этого цвета может быть перепрограммировано в прошивке на другой.


Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]