Перейти к тексту

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Вся введенная информация защищена.

  • Закрыть [x]

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

Вся введенная информация защищена.

  • Закрыть [x]

Многофункциональный мультимедийный компьютер: Часть 2. Показ изображений

Графическая подсистема, система X против фреймбуфера, а также волшебное решение

Льюин Эдвардс, разработчик, независимый писатель
Льюин Эдвардс (Lewin A.R.W. Edwards) работает в компании, входящей в список 50 крупнейших компаний мира. Он занимается разработкой беспроводных устройств охраны и пожарной безопасности. До этого он в течение пяти лет разрабатывал сетевые устройства на базе архитектур x86, ARM и PA-RISC в компании Digi-Frame Inc. Обладает обширным опытом в программном обеспечении по шифрованию и безопасности; автор двух книг о разработке встраиваемых устройств. С ним можно связаться по адресу sysadm@zws.com.

Описание:  В этой статье рассказывается о том, как эффективно напрямую использовать фреймбуфер для отображения JPEG-изображений, и обсуждается выбор между использованием сервера X Window и прямым доступом к фреймбуферу.

Больше статей из этой серии

Дата:  15.07.2008
Уровень сложности:  простой
Активность:  1759 просмотров
Комментарии:  


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

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

Требования к программе просмотра изображения

Начинаем разработку программы. Обычному устройству просмотра изображений требуются как минимум три функции:

  1. Отображение цветных растровых изображений на экране.
  2. Вывод списка графических файлов на жестком диске или подключенном внешнем носителе (во многих коммерческих устройствах для хранения данных используется внутренняя или внешняя флэш-память).
  3. Декодирование графических файлов.

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

Поддержка графики оборудованием

Начнем с поддержки графики. Оборудование Mac mini и программное обеспечение, установленные по инструкциям предыдущей статьи, дают вам несколько способов управления изображением на экране на уровне пикселов. Стандартный подход — запустить X-сервер, который у вас уже должен быть установлен, если вы в точности следовали инструкциям из предыдущей статьи. Позднее мы рассмотрим применение X, но пока будем считать этот вариант слишком сложным — не то чтобы ужасно сложным, но все же есть смысл рассмотреть сначала более простые пути.

Вместо системы X намного проще использовать напрямую драйвер фреймбуфера в ядре. Это дает удобный прямой доступ к видеопамяти. Ядро инициализирует дисплей в полноадресуемом режиме (APA); вам нужно только запросить у драйвера характеристики дисплея и внести адрес фреймбуфера в адресное пространство вашего процесса.

Наиболее часто приводятся следующие недостатки фреймбуфера:

  • Значительная зависимость от устройства: приложение должно уметь преобразовывать данные из любого цветового представления в формат устройства фреймбуфера. Драйвер фреймбуфера может лишь сообщить требуемый формат данных, но не может за вас выполнить их преобразование.
  • Более низкая производительность: большинство современных видеоплат обладают такими возможностями, как 3D-ускорение, аппаратная заливка, аппаратная отрисовка линий и т. д., которые не используются при работе с фреймбуфером. Если существует драйвер для X Window, то, как правило, он поддерживает все такие функции ускорения, и приложения автоматически пользуются их преимуществами. Однако во многих встраиваемых платформах аппаратное ускорение отсутствует, поэтому X в таких случаях только снижает производительность.
  • Сложности для разработчика: из предыдущего пункта следует, что разработчику приложения придется писать либо портировать код работы с палитрой и отрисовки графических примитивов — шрифтов, многоугольников, и т. п.

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

Второй пункт также зачастую не касается встраиваемых устройств. Основная причина, по которой я хочу рассказать вам о работе с фреймбуфером прежде, чем погрузиться в мир готового кода графических интерфейсов, заключается в том, что фреймбуфер — это, образно говоря, «наименьший общий знаменатель», и большинство встраиваемых Linux-устройств с графическим интерфейсом работают именно с фреймбуфером (даже если они используют X-сервер — довольно часто встречаются гибридные интерфейсы, о которых я тоже расскажу в этом цикле статей).

Доступ к фреймбуферу

Доступ к фреймбуферу чаще всего получают через устройства /dev/fb* (в большинстве случаев — /dev/fb0). Переключение режимов может осуществляться через интерфейс ioctl, либо из командной строки при помощи утилиты fbset. Для нее, в свою очередь, требуется конфигурационный файл /etc/fb.modes, где указываются частоты и глубина цвета для различных видеорежимов.

Можно указать видеорежим, используемый при запуске PowerPC®-системы, добавив соответствующий параметр ядра в файл настроек yaboot. Если вы привыкли работать на системах x86, то вам будет приятно узнать, что загрузчик yaboot практически идентичен загрузчику LILO в плане настройки и использования; по умолчанию файл настроек расположен в /etc/yaboot.conf, и когда вы внесете в него изменения, вы можете применить их, запустив утилиту ybin. Чтобы явно задать конкретный видеорежим на этапе загрузки, просто добавьте параметр append="video=ВИДЕОРЕЖИМ" в конец команды yaboot, запускающей ядро, и запустите ybin, чтобы применить сделанные изменения (дальше будет подробнее рассказано о редактировании этих параметров). Например, файл yaboot.conf для Mac mini может выглядеть следующим образом:


Листинг 1. Пример файла yaboot.conf
                
boot=/dev/hda6
init-message="Нажмите TAB для получения списка вариантов или подождите..."
partition=8
timeout=30
install=/usr/lib/yaboot/yaboot
magicboot=/usr/lib/yaboot/ofboot
delay=10
enablecdboot

image=/boot/vmlinux-2.6.10-1.ydl.1
label=linux
read-only
initrd=/boot/initrd-2.6.10-1.ydl.1.img
root=/dev/hda8
append="video=radeonfb:1024x768-16"

(Если вы настраиваете iMac, то нужно указать видеодрайвер atyfb, так как в этом компьютере используется старый видеочип Mach64. Для задания корректных частот на iMac следует указывать видеорежим следующим образом: atyfb:vmode:17,cmode:16 — см. ниже).

Параметры в строке "video=" можно указывать в двух форматах: либо video=driver:hresxyres-depth (где hres — физическое разрешение по горизонтали, yres — разрешение по вертикали и depth — код глубины цвета), либо video=driver:vmode:V,cmode:C (где V — номер видеорежима, а C - код глубины цвета). Обратите внимание, что коды vmode не несут какой-либо смысловой нагрузки, а просто обозначают номер режима из устаревшей спецификации Apple на содержимое PRAM. Эти коды перечислены в ядре Linux в файле drivers/video/macmodes.h.

Ко всему вышесказанному следует добавить, что, изменяя загрузочные видеопараметры, можно столкнуться с загадочными проблемами. Некоторые виды оборудования в компьютерах Mac (в данном случае я говорю об упомянутой в прошлой статье резервной системе на основе iMac, см. Ресурсы) упорно отказываются принимать другие видеопараметры. Такое поведение, с одной стороны, частично объясняется различными странными ограничениями встроенных мониторов моноблоков Apple, а с другой — неизвестными проблемами в коде расчета фазовой синхронизации в ядре.

Кстати, если Linux не сможет найти подходящий видеорежим на вашем компьютере, вы можете использовать параметр "video=ofonly" (ofonly означает «только режим Open Firmware»). Это похоже на режимы VESA BIOS в компьютерах на базе процессоров Intel®.

Если вы хотите оставить загрузочные видеопараметры такими, как они были определены автоматически, то изменять видеорежим можно по своему усмотрению командой fbset. Сначала добавьте следующие строки в файл /etc/fb.modes:


Листинг 2. Определение режимов фреймбуфера
                
mode "1024x768-universal"
geometry 1024 768 1024 768 16
timings 12735 160 32 28 1 96 3
hsync high
vsync high
endmode

Сохранив этот файл, вы сможете переключаться в режим 1024x768 с 16-битной глубиной цвета с помощью команды fbset 1024x768-universal. Кстати, если вам интересно, почему я взял такие параметры, то причина в том, что и встроенный монитор в iMac, и ЖК-монитор, который я подключаю к Mac mini, с трудом работают с нестандартными частотами синхронизации. Видеорежимы, определенные в ядре по умолчанию, в частности, не работали на iMac; оба компьютера запускались только в режиме 1024x768 с 8-битным цветом. Поэтому при помощи команды fbset (без аргументов) я узнал параметры этого режима, изменил глубину цвета на 16 бит на пиксел и тем самым получил неплохой видеорежим, работающий на обоих компьютерах.

Далее предполагается, что компьютер уже переведен в совместимый видеорежим (16 бит на пиксел), при этом разрешение не имеет значения. Чтобы компьютер автоматически переходил в нужный видеорежим при загрузке, добавьте следующие строки в файл /etc/rc.d/rc.local сразу перед строкой "touch...":

fbset 1024x768-universal setterm -blank 0

Вторая строка просто отключает автоматическую очистку экрана. Без этой строки через пять минут бездействия с экрана автоматически будет исчезать вся информация.


Вывод на экран

Теперь, когда видеорежим настроен (ну... почти настроен — в конце статьи вы поймете, что я имею в виду), давайте посмотрим, что нужно сделать, чтобы выводить на экран данные. Все, что нужно — выяснить, где находится видеопамять и каков ее формат. Эту информацию можно получить парой ioctl-вызовов, которые возвратят видимую область, глубину цвета, виртуальный размер экрана и другие сведения. См. файл graphics.c в архиве с исходным кодом, ссылка на который приведена в конце этой статьи. Вкратце, шаги следующие:

  1. Открыть устройство фреймбуфера — /dev/fb0.
  2. Получить информацию о "фиксированном" и "изменяющемся" экранах (fb_fix_screeninfo и fb_var_screeninfo), включая физические и виртуальные размеры, глубину цвета, физический адрес видеопамяти.
  3. Вызвать mmap(2), чтобы добавить память фреймбуфера в адресное пространство данного процесса.
  4. Выделить достаточное количество основной памяти для закадрового буфера («черновика»).
  5. Отключить курсор текстового режима.

Что касается последнего пункта, то если вы заглянете в конец функции GR_InitGraphics, вы увидите следующую уловку:


Листинг 3. Инициализация фреймбуфера
                
// Отключаем курсор
handle = open(FB_TTY, O_RDWR);
if (0 < handle) {
	write(handle, "\033[?1c", 5);
	close(handle);
}

Если вы где-либо в системе не предусмотрите такой код (примечание: вы можете просто использовать команду типа echo -e '\033[?1c' в загрузочных файлах), то поверх вашего изображения будет мигать курсор.

Я назвал этот код «уловкой» потому, что он основан на том неочевидном факте, что используемое вами устройство фреймбуфера (fb0) связано с устройством консоли tty0, а это не всегда так (и кстати, ничто не мешает запустить эту программу из другого виртуального терминала!). Однако в нашем случае это допущение всегда будет верным, потому что наш проект является встраиваемым устройством, где вы можете управлять загрузкой программы и средой ее выполнения.

Что касается файлов graphics.c и graphics.h, обратите внимание, что я определил единицу измерения для пикселов как typedef PIXEL и, помимо этого, определил макрос RGB2PIX, преобразующий RGB-триаду 8:8:8 в «родной» формат экранной памяти (в данном случае — 16-битное беззнаковое целое типа unsigned short). Этим предоставляется базовый уровень абстракции от устройства на уровне компиляции, что будет полезно при портировании кода на другую платформу.


Поиск файлов

Графическая подсистема теперь работает и встает задача поиска файлов на жестком диске. Этот функционал обеспечивается кодом в файле filescan.c, в первую очередь, функцией FL_Scan(). Эта функция ищет поддерживаемые типы файлов в каталоге /web и добавляет их в плоский массив динамически выделяемых структур. На данный момент каждая такая структура содержит только имя файла, но далее вы добавите к каждому изображению атрибуты, задаваемые пользователем (длительность показа и т. д.). Обратите внимание, что я написал отдельную функцию, которая определяет возможность воспроизведения файла с заданным именем на основе его расширения (без учета регистра символов) и назначает этому файлу один из перечисленных типов. Сейчас это может показаться излишним, но пригодится впоследствии, когда будет введена поддержка других типов медиафайлов.

Основной цикл программы следующий:

  • Запустить функцию FL_Scan() для поиска изображений. Если изображений не найдено, то подождать 10 секунд и повторить поиск.
  • Проиграть слайдшоу из всех найденных изображений; между изображениями делать паузу в 10 секунд.
  • Повторять бесконечно.

Теперь о декодировании JPEG. Для простоты я применил библиотеку JPEG, которая входит в состав Yellow Dog Linux. Библиотека основана на стандартном образце кода IJG JPEG 6b и проста в применении. Обычно не следует без изменений использовать эту библиотеку в профессиональной встраиваемой системе, так как она активно использует динамическое управление памятью (malloc/free). Тем не менее, поскольку наш проект не является профессиональной встраиваемой системой, я посчитал оправданным применение стандартной библиотеки (а также добавил собственную реализацию динамического выделения памяти).

На менее мощных компьютерах может потребоваться более внимательный подход к вопросам памяти. Мне приходилось работать над различными коммерческими цифровыми мультимедийными устройствами. Я использовал тот же самый код от Independent JPEG Group, но написал свою собственную небольшую подпрограмму управления памятью, которая выделяла память декомпрессора в отдельный пул, сбрасывающийся при каждом вызове кодека. Все это реализовывалось на довольно необычной системе со своей собственной закрытой ОС, которая работала на микроконтроллере архитектуры PA-RISC с 384 килобайтами памяти под все — стеки, буферы, глобальные переменные и т. д. В Mac mini ограничений намного меньше!

Сведения о вызове декомпрессора JPEG содержатся в файле codecs.c. Не обойдется без некоторого количества возни — в основном, нужно создать точки возврата setjmp для всех ошибок, возникающих глубоко внутри библиотеки JPEG. Основные шаги хорошо задокументированы в примере программы на C, ссылку на которую вы найдете в разделе Ресурсы. Обратите внимание, что чтение одной строки за раз официально считается нежелательным из-за неэффективности. Суть JPEG-кодирования такова, что оригинальный файл декодируется блоками по 8 строк (точнее, блоками 8x8), поэтому при каждом вызове jpeg_read_scanlines следующая строка либо копируется из буфера предварительного декодирования, либо целиком считываются следующие восемь строк.

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


Запускаем

Теперь запишите пару JPEG-файлов в каталог /web и запустите программу ibmslides. Если все настроено корректно, то изображения будут отображаться одно за другим (без масштабирования и центрирования). Если вы подключитесь по FTP и запишете в каталог еще несколько изображений, то они появятся при следующем проходе слайдшоу. Все отлично... или нет? Нет! На iMac цвета отображаются абсолютно неправильно.

Тут целая история, полная отчаяния и анализа кода, но я лишь вкратце расскажу о моих экспериментах. В старых версиях iMac устройство фреймбуфера сообщает, что оно работает в стандартном режиме 5:6:5 с глубиной цвета 16 бит на пиксел. Но это совершенно не так — на самом деле оно работает в очень странном и нестандартном режиме. Старший бит каждого слова используется в каких-то необычных целях; пикселы, где этот бит установлен, показываются черными. Другие компоненты цвета тоже проявляют странное поведение: красный, зеленый и синий занимают правые биты, но интенсивность цвета не имеет линейной зависимости от того, что записывается в эти биты. Создается ощущение, что ЦАП в чипе Mach64 все еще работает в палитровом видеорежиме (с использованием CLUT), а не в режиме direct color (с непосредственным представлением цвета).

Если с первого раза у вас не получилось...

Что тогда делать? Можно засучить рукава и мужественно патчить ядро, а можно пойти более хитрым путем и инициализировать видеоподсистему как-то иначе. Мы будем делать это при помощи XFree86 — сервера оконной системы X11.

На самом деле я, честное слово, хотел и по другим причинам перейти от простого использования фреймбуфера к гибриду X + фреймбуфер, а сложности с цветами только ускорили этот переход.

Сейчас я просто покажу вам волшебное решение, не особенно объясняя его. В архиве с исходным кодом вы найдете графический файл blank.xbm. Это пустой файл растрового изображения, созданный при помощи утилиты bitmap(1), и с его помощью мы избавимся от экранного курсора.

Сначала откройте файл /etc/X11/XF86Config и внесите следующие изменения в раздел Screen:


Листинг 4. Файл XF86Config
                
Section "Screen"
        Identifier      "Screen0"
        Device          "Card0"
        Monitor         "Monitor0"
        DefaultDepth    16
        SubSection "Display"
                Depth           16
                Modes           "1024x768"
        EndSubSection
EndSection

Теперь скопируйте файл blank.xbm в каталог /etc (или любое другое удобное место) и выполните следующие команды (предполагается, что программа ibmslides находится в текущем каталоге):


Листинг 5. Запуск X
                
X & sleep 10 ; DISPLAY=:0 ; export DISPLAY ; twm & xsetroot -cursor
/etc/blank.xbm /etc/blank.xbm ; xset -dpms s off ; ./ibmslides

Вот и всё — идеальные изображения!

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


Загрузки

Раздел загрузок для данной статьи обновляется. Попытайтесь повторить загрузку позднее.


Ресурсы

Об авторе

Льюин Эдвардс (Lewin A.R.W. Edwards) работает в компании, входящей в список 50 крупнейших компаний мира. Он занимается разработкой беспроводных устройств охраны и пожарной безопасности. До этого он в течение пяти лет разрабатывал сетевые устройства на базе архитектур x86, ARM и PA-RISC в компании Digi-Frame Inc. Обладает обширным опытом в программном обеспечении по шифрованию и безопасности; автор двух книг о разработке встраиваемых устройств. С ним можно связаться по адресу sysadm@zws.com.

Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Спасибо. Эта запись была помечена для модератора.


Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Сообщение о нарушении не было отправлено. Попробуйте, пожалуйста, позже.


developerWorks: вход


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Выберите ваше отображаемое имя

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

(Должно содержать от 3 до 31 символа.)


Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Оценить эту статью

Комментарии

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=320612
ArticleTitle=Многофункциональный мультимедийный компьютер: Часть 2. Показ изображений
publish-date=07152008
author1-email=sysadm@zws.com
author1-email-cc=

Теги

Help
Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Используйте ползунок, чтобы отразить больше или меньше тегов.

КнопкаПопулярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere).

Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).

Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Кнопка Популярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere). Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).