Hatred's Log Place

DON'T PANIC!

Mar 28, 2013 - 1 minute read - programming c++

Qt Creator: "the debugger could not load the debugging helper library" на Windows XP

Решение подсказывают тут и тут. Если коротко: нужен GDB скомпилированный с поддержкой Python и Qt Creator на это расчитывает. По первой ссылке его рекомендуют брать в QtSDK, но качать его сильно накладно. Недолгое гугление привело на эту ссылку: http://origin.releases.qt-project.org/gdb/windows-xp/.

Устанавливатся просто: скачиваем, распаковываем, в настройках китов в Qt Creator (Tool -> Options… -> Build & Run -> Kits) выбираем новый отладчик (для MinGW) и живём.

PS другие версии: http://origin.releases.qt-project.org/gdb/ PPS более корректные ссылки: http://builds.qt-project.org/job/gdb-windowsxp/ и http://builds.qt-project.org/job/gdb-windows/

Mar 28, 2013 - 1 minute read - programming c++

Scott Meyers. Effective C++ in an Embedded Environment

This PDF document contains the presentation materials from Scott Meyers’ two-day training course Effective C++ in an Embedded Environment. It provides an in-depth examination of how C++ can be applied in embedded systems, including costs of language features, ROMing, ISRs, memory management, safety-critical and real-time considerations, and more.

Формат: презентация в PDF, чётко и по делу.

Для желающих получить без оплаты: effectcppemb.pdf

Mar 25, 2013 - 1 minute read -

С переездом!

Переехал на новый хостинг, вроде всё основное запустил. Заодно обновился и обновил плагин googleplusoneng.

Теперь проблем со скоростью (100Мбит) и доступностью (всё же сервер в серверной :)) должно быть поменьше.

Mar 5, 2013 - 1 minute read -

Google Drive и прокси с доменной авторизацией

Google Drive [речь про Windows] может работать только с прямым подключением к интернету или через прокси, настроенный в IE и без авторизации.

Что бы решить сабжевую проблему:

Пересказывая… Ставим cntlm прокси, идём в “C:
Program Files
Cntlm”, редактируем cntlm.ini, указываем логин и домен. При этом не спешим вводить свой пароль открытым текстом, вместо того вызываем cntml.exe следующим образом: cntlm.exe -H

вводим пароль, и копируем один из вариантов хеша в конфиг.

После всего этого делаем команду: net start cntml

и сервис у нас запущен.

В настройках прокси IE указываем:

  • хост: localhost
  • порт: 3128

Пробуем зайти на куда нибудь и радуемся жизни. Если на этот момент Google Drive уже поставлен и запущен, он сразу сможет подрубиться и начать свою работу.

UPD: Под Linux нужно попробовать: https://aur.archlinux.org/packages/insync/

Jan 23, 2013 - 2 minute read -

ArchLinux, systemd, run-level 3, startx, udisks и монтирование

Столкнулся с ситуацией: после перехода к systemd и его logind внезапно отказались монтироваться флешки средствами udisks и udisks2. При этом на соседнем компьютере всё нормально. Разница при этом между ними только одна: на одном иксы запускаются через kdm, на другом - startx. Вот там, где используется startx монтирование и не работает.

В ходе разбора наткнулся на эпичный тред, где поттеринг пытается убедить, что нужно апдейтить startx: https://bugzilla.redhat.com/show_bug.cgi?id=820675

Но оставим этого человека альтернативной ориентации и вернёмся к нашим баранам. А бараны такие: заставить без костылей или минимум оных монтировать накопители средствами udisks/udisks2 на машине, где используется startx.

Для начала выясняем, а в чём собственно соль проблемы. Выясняется, что когда мы запускаем иксы, они захватывают отдельный терминал и переключают пользователя на него, тем самым мы как бы переключаемся из сессии, созданной при логине в консоли, и она становится неактивной. Новой сессии для иксов при этом не создаётся. В результате этого в выводе команды loginctl show-session $XDG_SESSION_ID

видим такие строчки: Active=no

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

Проблема метода очевидна: ближайшее обновление и нам нужно мержить, или менять снова. Не гут.

Второй метод, запустить иксы на том же терминале, на котором мы залогинились. К примеру, мы зашли с первой консоли, команда tty выдаёт следующее: /dev/tty1

тогда, что бы запустить иксы на этой консоли нам нужно выполнить следующую команду: startx – vt1

И видим, что в выводе loginctl Active стал yes. Viva!

В таком варианте есть свой плюс: если заблокировать экран, допустим, с помощью xscreensaver, то мы не сможем переключиться на первую текстовую консоль и, нажав Ctrl-C, убить иксы и получить доступ к залогиненому аккаунту. Здесь же кроется и минус: подвисшую сессию оперативно не убьёшь, особенно, если она отказывается реагировать на Ctrl-Alt-BS. Плюс как-то не классически.

Как последний штрих, добавляем в ~/.bashrc следующее:

stx()
{
	local vt=$(fgconsole)
	startx -- vt$vt
}
alias startx='stx'

и продолжать пользоваться просто командой startx.

Здесь же кроется забавный баг: теперь, если случайно нажать startx в окне терминала в запущенных иксах, поверх них запустится их вторая копия и переключиться между ними не получится ни при каких обстоятельствах. Так что будьте осторожны и бдительны.

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

Материалы которые помогли мне разобраться:

Jan 23, 2013 - 1 minute read -

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. натравливаем на него команду:
    asciidoc --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 - 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 - 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 - programming c++

Boost shared_ptr, bind и thread

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

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

Dec 13, 2012 - 2 minute read -

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

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

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

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

Dec 10, 2012 - 2 minute read -

Немного тюнинга 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; } К сожалению, полностью от скролинга это не позволяет избавится.

    UPD: другой источник предлагает более элегантное решение: https://www.reddit.com/r/FirefoxCSS/comments/70cvby/fully_disable_tab_overflow/. Я его немного адаптировал, что бы исключить прилепленный вкладки:```css .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 - programming c++

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

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

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

Nov 23, 2012 - 4 minute read -

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. записать пакет.

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

За сим всё.