Многофункциональный мультимедийный компьютер: Часть 3. Cкрипты и масштабирование изображений
Отображение нужных изображений нужным образомЛьюин Эдвардс рассказывает об истории создания системы X,
ее архитектуре, а также о том, почему все это необходимо знать при
разработке графической системы встраиваемого устройства. Вводится
простой скриптовый язык для управления мультимедийным устройством.
В предыдущей статье
рассказывалось о настройке мультимедийного устройства на базе PowerPC®
и отображении файлов в формате JPEG. Из этой статьи вы узнаете как
добавить функцию масштабирования изображений и, что более важно,
поддержку скриптового языка; я частично опишу теорию разработки
мультимедийных устройств и возникающие при этом сложности. Кроме того,
я подробно расскажу о некоторых вещах, о которых умолчал ранее.
В прошлый раз мы начали с описания устройства фреймбуфера в Linux® и
увидели, как подключить его к вашему приложению. Потом мы хитрым
образом запустили наше приложение в X, и я пообещал объяснить как
работает это решение.
Я применил систему X при решении задачи в прошлой статье по двум причинам:
- По-видимому,
в драйвере фреймбуфера видеокарты ATI Mach64 (в моей второй
экспериментальной системе) есть какая-то ошибка. Обойти эту ошибку
можно, запустив X-сервер, который корректно инициализирует видеочип. - Некоторые
приложения, которые мы будем обсуждать позднее, наиболее просто могут
быть реализованы, используя сторонние программы, которым необходима
среда X. В конечном итоге приложение будет работать быстрее и
устойчивее, если все время будет запущен X-сервер и оконный менеджер,
даже несмотря на то, что большую часть времени мы не будем ими
пользоваться.
Итак, что же
такое X? Эта система известна под названиями XWindows, X Window System,
X11 или просто X. Она представляет собой в высшей степени
платформонезависимую графическую среду. Система X11 была спроектирована
с упором на разделение подсистемы отображения («сервер») и программ,
которым требуется вывод на экран («клиенты»).
|
Протокол
X как таковой описывает лишь механизм отображения на экране
определенных блоков пикселов. Чтобы организовать эти блоки пикселов в
единую графическую среду, в которой есть переключатели, флажки, окна с
заголовками, виджеты изменения размера окна и т. п., требуется
отдельная программа — оконный менеджер. Оконный менеджер отвечает за
представление окон на экране и взаимодействие пользователя с этими
окнами, а также обеспечивает единообразие интерфейса в различных
приложениях.
Инструментальные средства для X
Программировать
X напрямую мучительно неудобно, поэтому большая часть программ
взаимодействует с инструментальными средствами (toolkits), которые
отвечают за работу с сервером на низком уровне. Кстати, в былые времена
из-за этого получалась полная путаница в интерфейсах: на двух разных
компьютерах с X-сервером интерфейсы и методы работы с ними могли
значительно отличаться из-за разнообразия оконных менеджеров и
инструментальных средств. В последние годы ситуация улучшается, в
основном, из-за роста популярности некоторых рабочих сред, таких как
GNOME и KDE.
Система X кажется довольно странной.
В основе архитектуры X лежит предположение, что ваша программа и
графический интерфейс находятся на разных концах сетевого подключения.
Таким образом реализуется раздельная, но ужасно неэффективная в
современных системах схема. Сейчас и графический код, и код приложения
выполняются в одном физическом адресном пространстве на одном и том же
компьютере. В результате, путем различных ухищрений можно быстро
передавать данные между приложением и графическим оборудованием. Для
этого используются различные методы, начиная от простых общих участков
памяти до сложных многослойных API доступа к оборудованию, например,
Direct Rendering Interface (интерфейс прямой отрисовки) в XFree86 (см.
раздел Ресурсы).
Обратите
внимание, что протокол X не описывает никакой другой мультимедийной
функциональности, например, ввод-вывод звука. Этим занимается отдельная
программа — звуковой сервер. В данном примере мы обойдемся без него,
так как знаем, что приложение будет работать на том же самом
компьютере, который будет воспроизводить звук.
Если
рассматривать подробности реализации X на конкретной платформе
(например, в версии, включенной в дистрибутив Yellow Dog), все
оказывается даже сложнее: существует множество возможных способов
взаимодействия вашего приложения с X и взаимодействия X с
оборудованием. Например, можно запустить X поверх драйвера фреймбуфера
в ядре так, что X никогда не будет обращаться к регистрам управления
видео, а для записи в видеопамять будет использовать ioctl фреймбуфера.
Другой крайний случай — запуск «родного» X-сервера,
который самостоятельно инициализирует графическое оборудование. У
каждого способа есть свои преимущества и недостатки; я рассмотрю их
подробнее в следующей статье, когда мы поговорим о поддержке
воспроизведения видео.
Вся эта информация пока
приводится только для того, чтобы вы приняли ее к сведению. В примере
программы не будет использоваться API X-сервера; как уже говорилось
выше, система X напрямую использоваться не будет -- она запускается
только потому, что некоторые программы зависят от нее. Поэтому пока
закончим обсуждение X.
|
Когда
кто-то говорит: «Мне нужен язык программирования, в котором достаточно
только сказать, что мне нужно сделать», — дайте ему леденец. -- Алан Перлис (Alan Perlis)
Итак,
каким должен быть скриптовый язык? Мы говорим о программе, которая
потенциально может быть выпущена на рынок, поэтому нужно тщательно
продумать пользовательский интерфейс и скриптовую систему. В области
цифровых фоторамок уже придумано немало, хотя по большей части
результат получался не очень хороший (я авторитетно заявляю это, потому
что участвовал в разработке нескольких видов выпускаемых фоторамок и
еще нескольких прототипов, работаю над подобными устройствами уже около
пяти лет и имел возможность протестировать множество устройств
конкурентов). Начнем с общих направлений пользовательских интерфейсов
подобных продуктов.
Мультимедийные устройства можно разделить на три большие группы:
- «Глупые»
устройства (с различными возможностями) -- работают только со
специальными носителями, на которых содержится информация по работе с
ними или используется интуитивно понятный среднестатистическому
потребителю интерфейс. Хороший пример — DVD-проигрыватель: проигрывает
готовые диски и в большинстве своих функций аналогичен
видеомагнитофону. Хотя, разумеется, вы можете и самостоятельно
создавать собственные DVD-диски, это не предусмотрено в самом
устройстве, а его пользовательский интерфейс, соответственно, очень
прост. - Малые "умные" устройства хранят
файлы, записанные пользователем, но не предоставляют гибкости вариантов
по воспроизведению этих файлов. Обычно такие устройства имеют
ограниченную возможность отображения информации и узкий диапазон
вариантов воспроизведения, которые задаются через собственный
пользовательский интерфейс. Хороший пример — MP3-плеер или карманный
видеопроигрыватель. Такие устройства зачастую можно подключать к
компьютеру и пользоваться как расширенным пользовательским интерфейсом. - Серьезные
«умные» устройства обычно с большим количеством места под
пользовательские файлы. Как правило, сравнимы с обычным компьютером по
своим возможностям обработки контента и могут иметь сложный интерфейс,
позволяющий пользователю задавать большое число параметров
воспроизведения.
Такое
разделение выглядит чересчур категоричным, но если вы поищете примеры,
то поймете, что за несколькими исключениями самые успешные
потребительские устройства попадают в одну из этих групп. Если вы
интересуетесь новинками электроники, то наверняка вспомните устройства,
которые безуспешно пытались совмещать в себе свойства двух групп сразу.
Наиболее распространенная ошибка разработчиков
(причем не только мультимедийных устройств) — попытка наделить
устройство из второй группы функциями устройства третьей группы.
Конечно, всегда можно сделать так, чтобы какая-то сложная функция
выполнялась запутанными комбинациями нажатий кнопок, но пользователь
всегда будет раздражен при работе с таким интерфейсом. Плеер iPod от
Apple — отличный пример того, как благодаря решению отказаться от
сложного функционала в компактном устройстве получилось элегантное,
простое и коммерчески успешное решение. На iPod, как на КПК, вполне
можно было бы запустить операционную систему со сложнейшими
приложениями, но тогда им было бы намного сложнее пользоваться, чем
иерархическим древовидным меню, в пользу которого сделала выбор
компания Apple.
И наоборот, бывают устройства
третьей группы, имеющие множество функций и обширные системные ресурсы,
но настройка большинства этих функций недоступна пользователю. Вызывает
раздражение то, что устройство вполне способно иметь пользовательский
интерфейс, дающий доступ ко всем его возможностям, но производитель
решил сделать работу с этим устройством возможной только при
использовании внешнего дополнения — обычно собственной программы
редактирования контента, устанавливаемой на ПК. Нередко это делается
исключительно из коммерческих целей. Например, некоторые цифровые
фоторамки требуют подключения к Интернет, а управлять ими можно только
через веб-сайт. Таким образом в фоторамку помимо пользовательских
изображений всегда загружалась свежая реклама. Пользователю от этого не
было никакой пользы, а такое устройство лишь вызывало раздражение.
Учитывая
все вышесказанное, рассмотрим цели, которыми необходимо
руководствоваться при разработке скриптового языка многофункционального
устройства третьей группы:
- Формат
файлов должен обеспечивать простое считывание, декодирование,
повтороное кодирование из памяти и запись на носитель информации. - Язык
должен быть расширяемым и универсальным; возможно, при воспроизведении
некоторых типов файлов потребуются особые, пока неизвестные параметры. - Должен поддерживаться легкий и быстрый последовательный поиск, а также поиск с произвольной выборкой.
- В идеале, редактировать скрипты можно при помощи какого-либо привычного приложения без особых знаний программирования.
К
сожалению, лучший способ реализовать поиск с произвольной выборкой —
использовать двоичный файл с фиксированной длиной записи (такой метод я
применил в при разработке первого поколения цифровых фоторамок).
Проблема заключается в том, что хотя двоичные файлы легко считываются в
память и в них легко осуществляется случайный поиск (сдвиг в файле
рассчитывается просто: номер записи × размер записи), такие файлы
невозможно редактировать без специального ПО, а расширение формата
поддержкой новых параметров требует немалой работы. Раньше я решал
проблему так: пользователь писал в текстовом редакторе скрипт,
компилирующийся во временный двоичный файл, в котором осуществляется
поиск. Такое сложное решение было выбрано потому, что скрипты могли
быть произвольно большими.
В данном случае будем
считать, что скрипт всегда достаточно мал, чтобы целиком поместиться в
оперативную память. В файле html.c вы увидите, что функция загрузки
скрипта просто определяет размер файла, выделяет под него память и
загружает файл в память целиком. Кроме того, функция загрузки также
удаляет управляющие символы, чтобы облегчить синтаксический анализ
скрипта «на лету».
Кстати, в этой версии все еще
останется ограничение в 16384 изображения, введенное в предыдущей
версии приложения; я просто изменил способ наполнения структуры из
16384 элементов.
В устройстве применяется
подмножество языка HTML и простой HTML-парсер. Такой выбор был сделан
для того, чтобы файл скрипта можно было создать в WYSIWYG-режиме в
любом HTML-редакторе, например, в Openoffice.org.
Приложение,
которое вы сейчас скомпилируете, просто загружает файл /web/script.html
и пытается воспроизвести его. Реализованный мною парсер ищет в этом
файле тег <IMG> по очень простому алгоритму:
- Найти открывающую угловую скобку.
- Ждать символов "img" (без учета регистра и пробелов).
- Ждать символов "src" (без учета регистра).
- Ждать кавычки.
- Взять текст от этой кавычки до следующей в качестве имени файла.
- Пути к изображениям находить относительно каталога /web.
Заметьте,
что синтаксис тега IMG поддерживает любое количество параметров для
каждого изображения. В HTML определены некоторые такие параметры,
например,
WIDTH= и HEIGHT= указывают браузеру, что
изображение должно отображаться с соответствующей шириной и высотой. В
слайд-шоу также можно добавить практически любые необходимые метаданные
при помощи собственных тегов.
Допустим, у вас есть два изображения: PIC001.JPG и PIC002.JPG, тогда файл слайд-шоу будет выглядеть так:
Листинг 1. Пример сценария слайдшоу
| <HTML> <BODY> <IMG SRC="PIC001.JPG"><BR> <IMG SRC="PIC002.JPG"><BR> </BODY> </HTML> |
Теги HTML, BODY, и BR нужны только для отображении файла в обычном веб-браузере, а наша программа будет работать и без них.
Кроме
того, в этой версии программы я добавил еще одну функцию, важную для
цифровых фотоальбомов — масштабирование изображений. Алгоритм
масштабирования — простая система прореживания. Его код немного сложен
для чтения, так как для быстроты применяется целочисленная арифметика;
такие алгоритмы мне всегда легче объяснять математически.
Возьмем одну строку изображения шириной m пикселов, которое нужно масштабировать до размера экрана — n пикселов. Существует указатель-источник s,
с адресом крайнего левого пиксела исходной строки, а также указатель-приемник d
с адресом крайнего левого пиксела в получаемой строке. Разумеется,
каждый пиксел в получаемой строке должен быть отрисован только один
раз, поэтому цикл будет повторяться n раз и каждый раз d будет увеличиваться. К указателю-источнику при каждом повторении цикла прибавляется m/n.
В целочисленной арифметике это сделать непросто; проще использовать
числа с плавающей запятой, но такой код работает медленнее.
Теперь
у вас есть более управляемая программа показа слайд-шоу. В следующей
статье мы добавим в нее поддержку фильмов. Кроме того, мы внимательнее
изучим наши непростые отношения с X и расширим формат файла скриптов.