Hatred's Log Place

DON'T PANIC!

Jan 23, 2013 - 1 minute read - Comments -

AsciiDoc и PlantUML

AsciiDoc - язык разметки и утилита для генерации, из этой самой разметки, документов самых разных форматов: Unix man pages, HTML, PDF, OpenOffice и т.п. (список поддерживаемых форматов можно расширить модулями). При этом текст разметки напоминает некоторые WiKi (типа той же DokuWiki) и остаётся читабельным даже без компиляции в какой либо выходной формат. Часто используется для приготовления документации к продуктам.

PlantUML - тоже язык разметки, и тоже текстовый, для генерации различных UML диаграмм.

Резонный вопрос: как бы их скрестить. Помогает модульность AsciiDoc, в частности фильтры. В скором времени находим уже готовое решение: http://code.google.com/p/asciidoc-plantuml/

Устанавливается просто: 1. скачиваем файл plantuml.zip 2. натравливаем на него команду:bashasciidoc --filter install plantuml.zip

Либо, для пользователей ArchLinux, ипользуем пакет из AUR: https://aur.archlinux.org/packages/asciidoc-plantuml

После чего, в тело документа можно вставлять такие блоки:

[plantuml]
------
User -> (Start)
User --> (Use the application) : Polish label-Zażółć gęślą jaźń

:Main Admin: ---> (Use the application) : This is<br/>nyet another<br/>nlabel
------

И оно заменится картинкой с диаграммой.

Под катом снимок экрана редактора asciidoc-gui с предпросмотром диаграммы.

Jan 16, 2013 - 2 minute read - Comments - programming c++

Простой враппер для встроенных типов в C++

В C/C++ определение переменной не есть её инициализация. Верно для фундаментальных (или встроенных) типов. Для пользовательских типов всегда (если не указано ничего иного) вызывается конструктор по умолчанию, в котором можно принять необходимые меры по инициализации.

Враппер помогает решать задачи инициализации переменной при её объявлении, а так же при использовании в контейнерах типа std::map или std::multimap, когда нужно проверить переменную для ключа, которого ещё нет (при обращении через operator[] создастся новое значение, для которого вызовется конструктор по умолчанию).

Код:

/**
 * Can be used for built-in types only (like int, char, long and so on)
 */
template <typename T, T initialValue = 0>
struct BuiltInTypeWrapper
{
    BuiltInTypeWrapper()
        : value(initialValue)
    {}
    BuiltInTypeWrapper(T v)
        : value(v)
    {}

    bool isValid() const
    {
        return (value != initialValue);
    }

    void reset()
    {
        value = initialValue;
    }

    operator T&()
    {
        return value;
    }

    operator T const&() const
    {
        return value;
    }

    BuiltInTypeWrapper& operator=(T v)
    {
        value = v;
        return *this;
    }

    T value;
};

Для временных меток в FFMPEG можно использовать так:

/**
 * Simple wrapper for time stamp values
 */
typedef BuiltInTypeWrapper<int64_t, AV_NOPTS_VALUE> TsWrapper;

т.е. при объявлении переменной типа TsWrapper она автоматом станет инициализирована в AV_NOPTS_VALUE.

А просто для int так:

typedef BuiltInTypeWrapper<int> Integer;

При этом при объявлении переменной типа будет она будет инициализирована в 0.

За счёт определения оператора приведения типа и перегруженному оператору присваивания использование обёрнутого значения мало отличается от необёрнутого:

typedef BuiltInTypeWrapper<int64_t, AV_NOPTS_VALUE> TsWrapper;
...

void foo(int64_t &v)
{
    clog << v << endl;
}

...

TsWrapper wrappedValue;
int64_t   value = 255;

wrappedValue = value;      // 1
if (wrappedValue == value) // 2
...

foo(wrappedValue)          // 3
wrappedValue++;            // 4, аналогично для префиксной формы
wrappedValue--;            // 5, аналогично для префиксной формы
wrappedValue += 5;         // 6
wrappedValue -= 5;         // 7  

В общем и целом практически повторяет поведение оригинального типа.

Кто какие нюансы видит?

PS тестировалось на gcc 4.7.2

Dec 17, 2012 - 1 minute read - Comments - programming c++

MinGW32: как избавиться от зависимостей в виде libgcc_*.dll и libstdc++-*.dll?

Почти всегда программа (особенно маленькие и без инсталлятора) для win распространяется в виде законченного бандла со всеми DLL и прочим потребством. Проблема, что программа, скомпилированная примерно так: i486-mingw32-g++ -o foo.exe foo.cpp

как минимум требует двух DLL: libgcc_*.dll и libstdc++-*.dll, что бы избавится от них можно использовать опции -static-libgcc и -static-libstdc++: i486-mingw32-g++ -static-libgcc -static-libstdc++ -o foo.exe foo.cpp

Dec 13, 2012 - 4 minute read - Comments - programming c++

Boost shared_ptr, bind и thread

Правило: при использовании boost::bind будьте предельно осторожны при передаче аргументов в виде boost::shared_ptr (как и других типов умных указателей): по умолчанию используется семантика копирования, поэтому в полученном функторе будет храниться копия вашего указателя с увеличенным счётчиком ссылок. Данный факт, вкупе с использованием совместно с boost::thread, может стать иточником утечки ресурсов.

Ниже более детально.

Dec 13, 2012 - 2 minute read - Comments -

Подготовка фотографии для перевода на фольгу

Название страшное. На самом деле просто приведу, на заметку, команды которыми можно подготовить фотографию, что бы она была выполнена в монохромной палитре (1bpp - один бит на пиксель). Это удобно для реализации идеи приведённой в статье на хабре: http://habrahabr.ru/post/157465/

Просто вариант с “газетным подходом” мне не совсем понравился, решил попробовать другое.

Итак, понадобится только ImageMagick или GraphicsMagick

Dec 10, 2012 - 2 minute read - Comments -

Немного тюнинга Firefox

В основном в части вкладок (в народе - “табов”).

Задачи две: 1. Сделать так, что бы не отображался скролинг вкладок, а сами вкладки уменьшались до минимума аля Opera 2. Уменьшить их высоту

Поиск дал ссылки на следующие материалы: * Quick Tip: Disable Firefox Tab Scrolling - расказывает как при помощи about:config добиться эффекта отсутствия скрола для множества табов, там же даётся ссылка на расширение Tab Mix Plus, при помощи которого можно сделать это же, а так же много другое (к примеру, назначить различные стили для незагруженных страниц, или страниц, содержимое которых изменилось со времени последнего просмотра). От себя замечу: лучше поставить опцию browser.tabs.tabMinWidth в 0, т.к. через дополнение не получается поставить значение меньше 16. Опции может и не быть в списке, тогда нужно её создать, тип указывать: integer. В некоторых источниках это же рекомендуют сделать с параметром browser.tabs.tabClipWidth. В некоторых версиях FireFox и это не поможет, тогда следует попробовать такой CSS-код в вашем userChrome.css (источник на Reddit: How to shrink tab width?):```css .tabbrowser-tab[fadein]:not([pinned]) { min-width: 0px !important; max-width: 250px !important; }

.tabbrowser-tab:not([pinned]) {
    min-width: initial !important;
}
.tab-content {
    overflow: hidden !important;
}
```Это решение позволяет избавиться от перекрытия контента табов.
  * В Firefox Quantum появилась возможность в Menu -> Customize... в нижней строчке в меню Density выбрать вариант Сompact, который решает проблему. Если интересно решение с CSS - смотрите историю этой страницы.
  * [Creating more screen space in Firefox](http://wiki.eeeuser.com/howto:shrinkfirefox) - статья на eeeuser.org которая описывает, как получить больше полезного пространства в Firefox на устройствах с небольшим размером экрана (типа Asus EeePC).
  * [r/FirefoxCSS](https://www.reddit.com/r/FirefoxCSS/) - много трюков с `userChrome.css`

И на последок, мой `userChrome.css`:
```css
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");

/*
 * Setup minimal Tab width
 * Ref: https://www.reddit.com/r/FirefoxCSS/comments/70cvby/fully_disable_tab_overflow/
 */
.tabbrowser-tab:not([pinned]) {
    min-width: initial !important;
}
.tab-content {
    overflow: hidden !important;
}

Dec 10, 2012 - 3 minute read - Comments - programming c++

Охранные классы в boost::thread

Для начала, охранные классы, это не что иное как различные *_lock классы, реализующие идиому RAII, захватывающие мутекс в конструкторе (lock()) и освобождающие его в деструкторе (unlock()) - паттерн “блокировка в области видимости”. Не смог придумать более корректного перевода.

Охранных классов в Boost много, легко можно в них запутаться. Но знать про них необходимо, так как почти вся библиотека boost::thread спроектирована с ориентацией на их использование.

Nov 23, 2012 - 4 minute read - Comments -

FFMPEG: немного про time-base и PTS

В терминах FFMPEG time-base, это параметр, используя который можно перевести PTS (Presentation Timestamp) закодированного пакета (AVPacket) или раскодированного фрейма (AVFrame) в реальное время, выраженное в секундах (это же верно для DTS закодированного пакета). Представляет собой рациональное число типа AVRational.

А вот теперь интересности, связанные с ним.

Общие сведения

Внутри библиотек libavformat и libavcodec, входящих в состав FFMPEG time-base может храниться в двух контекстах: * контекст потока (AVStream) * и контекст кодека (AVCodecContext)

При этом временные метки (далее я буду говорить только про PTS, если потребуется сказать про DTS - отдельно обращу внимание) могут храниться у AVFrame (поле pts) и AVPacket (аналогично, поле pts) тип всех временных меток (включая поле dts у AVPacket) - int64_t.

Отсюда возникает резонный вопрос: как соотносить time-base и временные метки.

Короткий ответ: * time-base AVStream является основной для временных меток AVPacket * time-base AVCodecContext является основой для временных меток AVFrame

Далее рассмотрим, когда и как мы должны устанавливать руками, а что и когда установится само.

Чтение и раскодирования файла

После того как создан и открыт AVFormatContext, прочитана информация о потоках картина получается такой: * поле time_base каждого потока (AVStream) заполнено самой библиотекой, изменять вручную его крайне не желательно, даже не могу представить, какие последствия может принести данная операция. * поле time_base созданных декодеров для каждого типа потока (AVCodecContext) так же заполняется библиотекой и изменять его не желательно

Логично было бы предположить, что временные метки для потока и его декодировщика должны быть одинаковы, но это не так. Как следствие временные метки пакета и раскодированного фрейма нельзя сравнивать напрямую. И если вы хотите установить, после раскодировки, PTS фрейма, это нужно делать при помощи функции av_rescale_q(...), примерно так:

frame.pts = av_rescale_q(packet.pts, packetTimeBase, frameTimeBase);

Ясно, что frameTimeBase берётся из AVCodecContext, а packetTimeBase из AVStream.

Стоит отметить так же то, что у некоторых пакетов поле pts имеет значение AV_NOPTS_VALUE, тогда как поле dts имеет корректное значение, тогда его и стоит брать для присваивания значению PTS фрейма. Суть такого поведения для меня не ясна.

Так же стоит отметить для для звуковых семплов, после раскодировки значение PTS фрейма будет AV_NOPTS_VALUE и НИ В КОЕМ СЛУЧАЕ НЕ МЕНЯЙТЕ ЕГО НА ЧТО-ТО ЛИБО ДРУГОЕ, это приведёт в смятение микшер, как следствие, звука в результирующем файле вы не услышите. И снова, суть такого поведения для меня не ясна.

Кодировка и запись (микширование потоков)

При кодировании и микшировании мы сами добавляем потоки в выходной формат. При этом time-base мы должны задавать только для кодировщика (AVCodecContext) и делать это обязательно.

Поле time-base у потока (AVStream) можно устанавливать, а можно и нет, всё равно, после вызова avformat_write_header(...) оно будет сброшено и установлено в необходимое значение подходящее для данного типа контейнера. При этом, значение time-base из AVCodecContext будет использоваться как подсказка, если контейнер не определяет требований к значению time-base.

Соответственно, важно: даже при записи вы не можете гарантировать, что значения time-base в AVStream и в AVCodecContext будут эквивалентны. Кроме того, вы не можете опираться на значение time-base внутри AVStream пока не будет вызвана avformat__write_header(...). Как следствие, при копировании временной метки из фрейма в пакет нужно использовать av_rescale_q(...)

Особо хочу отметить, что если вы делаете масштабирование поля pts пакета, не забудьте сделать то же для поля dts, иначе получите интересные артефакты при воспроизведении.

Для аудио-фреймов и аудио пакетов поля pts и dts всегда будут AV_NOPTS_VALUE и никаких преобразований делать не нужно.

Случай транскодирования

Пусть мы имеем входной файл формата Format1 с одним видео потоком Stream1, закодированный кодеком Codec1, нам нужно его перекодировать в файл формата Format2, так же с одним видео потоком Stream2, закодированным кодеком Codec2.

Что получается: 1. после открытия входного файла Stream1 имеет time-base InStreamTimeBase, а Coder1 имеет time-base InCoderTimeBase. 2. после настройки выходного формата, и записи заголовка мы имеем: Stream2 с OutStreamTimeBase и Codec2 с OutCoderTimeBase. 3. av_read_fream() возвращает пакеты с pts/dts в масштабе InStreamTimeBase. 4. после декодирования видео-фрагментов, мы получаем фрейм с pts в масштабе InCoderTimeBase 5. если возникает необходимость копировать pts/dts пакеты в pts фрейма необходимо сделать масштабирование: frame.pts = av_rescale_q(packet.pts/dts, InStreamTimeBase, InCoderTimeBase); 6. перед кодировкой фрейма при помощи Coder1 нужно смаштабировать его pts: frame.pts = av_rescale_q(frame.pts, InCoderTimeBase, OutCoderTimeBase); 7. перед записью получившегося пакета, нужно смаштабировать его pts/dts: packet.pts/dts = av_rescale_q(packet.pts/dts, OutCoderTimeBase, OutStreamTimeBase); 8. записать пакет. 9.

Масштабирования нужно делать только если значение временной метки не равно AV_NOPTS_VALUE.

За сим всё.

Oct 17, 2012 - 2 minute read - Comments - projects programming

CMakeProjectManager2 - последние изменения

Как я уже писал, вяло пилю модифицированную версию плагина CMakeProjectManager для Qt Creator’а. Там же указаны причины, вынудившие меня на это. Но разговор, не про это, а про то, что с момента прошлого поста было сделано.

Итак: 1. Для каждого профиля сборки сохраняются введённые параметры для CMake, так что, выбрав в следующий раз “Run CMake” не нужно вспоминать, с какими параметрами вы его запускали и легче управлять профилями сборки. Вкупе с последней фичей из апстрима: сохранения глобальной истории параметров для CMake, получается достаточно мощный механизм. 2. Используя вышеприведённую информацию, появилась возможность при модификации дерева исходников (добавление, удаление, переименование) в фоновом режиме запускать обновление CBP файла и дерева сборки, что особо актуально при использовании глоббинга. 3. По сравнению с первым вариантом, получилось значительно сократить расходование памяти при использовании плагина, особенно когда в дереве проекта много вспомогательных модулей, временного C/C++ кода.

Кодовая база периодически синхронизируется с GIT версией Qt Creator. Если кто-то будет делать клоны для стабильных релизов, просьба отписываться с информацией об оных.

HINT:

Так как, при добавлении, удалении или переименовывании файла, не осуществляется модификация CMakeLists.txt, то нужно вносить изменения самому, либо использовать globbing:cmake# UTILS file(GLOB_RECURSE UTIL_SOURCES "../util/*.cpp") file(GLOB_RECURSE UTIL_HEADERS "../util/*.h" "../util/*.hpp") На полноценный парсер пока времени нет (хотя уже адоптирован на чистый C++/Qt оный из KDevelop), к тому же, в списке рассылки Qt Creator проскакивала новость, что одна команда разрабатывает полноценный плагин (тыц). Зная это, не хочется делать бесполезную работу, при том, что текущий функционал уже вполне удовлетворяет.

Oct 8, 2012 - 1 minute read - Comments - programming c++

Паттерн Iterator

Полезно, когда нужно перебирать последовательно какие-то данные, мне, в частности, потребовалось для перебора кодеков и форматов во C++ враппере для FFMPEG, а так же получения набора параметров и именованных констант, которые они могут принимать.

Основные идеи данного паттерна изложены по этой ссылке: http://sourcemaking.com/design_patterns/iterator, а возможные реализации на C++ здесь: * С применением методов для перемещения итератора, разыменования оного: http://sourcemaking.com/design_patterns/iterator/cpp/1 * С использованием операторов для перемещения итератора, разыменования оного: http://sourcemaking.com/design_patterns/iterator/cpp/2

Сведения эти - общетеоретические. Более практическое описание с разделением итераторов на типы приведено на cplusplus.com: http://www.cplusplus.com/reference/std/iterator/, в частности вводятся понятие следующих типов итераторов (а так же наглядная таблица, по которой можно понять какие методы и операторы должны определяться в классе-итераторе): * Input - перемещается только вперёд, доступно только чтение значения (пример: поток stdin): http://www.cplusplus.com/reference/std/iterator/InputIterator/ * Output - перемещение только вперёд, доступна только запись значений (пример: поток stdout): http://www.cplusplus.com/reference/std/iterator/OutputIterator/ * Forward - объёдиняет свойства Input и Output итераторов: http://www.cplusplus.com/reference/std/iterator/ForwardIterator/ * Bidirectional - расширяет Forward итератор для перемещения назад: http://www.cplusplus.com/reference/std/iterator/BidirectionalIterator/ * Random Access - итератор с возможностью свободного перемещения назад/вперёд на произвольное количество позиций (пример: простой массив): http://www.cplusplus.com/reference/std/iterator/RandomAccessIterator/

А что бы несколько привести итераторы к одному виду, существует класс в стандартной библиотеке, называется ~std::iterator~, почитать можно здесь: http://www.cplusplus.com/reference/std/iterator/iterator/, там же приведён простой пример итератора.

Oct 4, 2012 - 1 minute read - Comments -

Emacs configs

В след за [](/blog/2012/09/10/luakit_configs/) выкладываю свои конфиги для Emacs: https://gitlab.com/hatred-configs/emacs((Репозитории для клонирования: https://gitlab.com/hatred-configs/emacs.git, git@gitlab.com:hatred-configs/emacs.git))

На данный момент они не совсем самодостаточны: нужно некоторые пакеты устанавливать самостоятельно, так что запуск emacs --debug-init в первое время в помощь. Все недостающие пакеты есть в AUR для ArchLinux.

Кроме того, некоторые расширения тянутся из git, и они подключены как субмодули, поэтому после клонирования репозитория нужно будет выполнить следующие команды: git submodule init git submodule update

Пожелания по унификации приветствуются.

Sep 17, 2012 - 2 minute read - Comments -

Emacs Org mode + ditaa + Artist mode

Ditaa - DIagrams Through Ascii Art - “компилятор” для ASCII диаграмм, на выходе создаёт достаточно приятные для глаза диаграммки: * Официальный сайт: http://ditaa.sourceforge.net/ * Demo: http://ditaa.org/ditaa/ - сервис, можно посмотреть на возможности программки и посоздавать свои * Дополнения: http://ditaa-addons.sourceforge.net/

Ditaa дружит с org-babel в Emacs org-mode, так что можно создавать диаграммы прямо в режиме заметки в Org mode.

Для начала, нужно добавить в .emacs (или .emacs.d/init.el) следующее:

;; 
;; Org Babel 
;; 
(require 'ob-tangle) 
(setq org-ditaa-jar-path "/usr/share/emacs/site-lisp/org_contrib/scripts/ditaa.jar") 
;(setq org-plantuml-jar-path "~/java/plantuml.jar") 


(defun bh/display-inline-images () 
(condition-case nil 
(org-display-inline-images) 
(error nil))) 
(add-hook 'org-babel-after-execute-hook 'bh/display-inline-images 'append) 

; Make babel results blocks lowercase 
(setq org-babel-results-keyword "results") 

(org-babel-do-load-languages 
(quote org-babel-load-languages) 
(quote ((emacs-lisp . t) 
(dot . t) 
(ditaa . t) 
(R . t) 
(python . t) 
(ruby . t) 
(gnuplot . t) 
(clojure . t) 
(sh . t) 
(ledger . t) 
(org . t) 
(plantuml . t) 
(latex . t)))) 


; Do not prompt to confirm evaluation 
; This may be dangerous - make sure you understand the consequences 
; of setting this -- see the docstring for details 
(setq org-confirm-babel-evaluate nil) 

С моей версией emacs-org-mode из AUR ditaa уже идёт комплекте. Если нет, скачайте с домашнего сайта и укажите путь до него.

само рисование осуществляется в блоке кода:

#+begin_src ditaa :file out.png 
... 
... 
... 
#+end_src 

Теперь небольшой хинт. Есть в штатной поставке emacs 24 такой минорный режим, как artist-mode - позволяет рисовать в ASCII, его-то можно использовать для рисования диаграмм, далее вспоминаем про такую штуку как narrowing (ну хоть убейте - не знаю как перевести, а если кратко: то можно выделить блок текста, так, что бы все изменения были только с ним, а остальные части документа вообще бы никак не могли быть доступны для изменения). Посему:

Шаг 1: жмем сколько нужно ‘RET’ (в народе - Enter) в блоке #+begin_src/#+end_src - выделяем себе пространство для дальнейшего манёвра

Шаг 2: выделяем весь этот блок и жмем ‘C-x n n’ (если включен CUA mode, то вместе ‘C-x’ нужно нажимать или ‘C-x C-x’ или ’S-C-x’, я использую второе) - тем самым мы перейдём к редактированию только этого блока

Шаг 3: выключаем artist-mode: M-x artist-mode

Шаг 4: рисуем диаграмму

Шаг 5: выключаем artist-mode: M-x artist-mode

Шаг 6: убираем выделение региона: ‘C-x n w’

Шаг 7: Жмем ‘C-c C-c’ находясь внутри блоке #+begin_src/#+end_src - запустится ditta и картинка покажется ниже блока кода.

Для себя, включение и выключение Artist mode я повесил на клавиатурную комбинацию ‘C-x a’, а выбор инструмента рисования в режиме Artist mode на C-s (инкрементный поиск тут не нужен)

И на последок, скрин-каст про artist mode: http://www.cinsk.org/emacs/emacs-artist.html

Sep 10, 2012 - 1 minute read - Comments -

Luakit configs

Выложил свои конфиги для Luakit на Gitorious: https://www.gitorious.org/hatred-configs/luakit

Помимо небольших кастомизаций под себя: * цвета закладок * сохранение сессии по w, а открытие окна по wi * включено отображение полосы прокрутки

сделана подсистема URI Rewrite и в globals.lua показано, как можно её использовать: * globals –> uri_rewrite_enable [true/false] — включить или выключить URI Rewrite * список uri_rewrites позволяет указать, что и как заменять, в конфиге показано как там заполнять, чуть ниже показано как делать “синонимы” для доменов, что бы, к примеру, для сайта с и без www. в начеле, делать одинаковые замены. * горячая клавиша Shift-F5 - перечитать текущую страницу, используя URI Rewrite

Посмотреть изменения относительно оригинальных конфигов: git diff master hatred