В 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
Почти всегда программа (особенно маленькие и без инсталлятора) для 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
Правило: при использовании boost::bind
будьте предельно осторожны при передаче аргументов
в виде boost::shared_ptr
(как и других типов умных указателей): по умолчанию используется
семантика копирования, поэтому в полученном функторе будет храниться копия вашего указателя с
увеличенным счётчиком ссылок. Данный факт, вкупе с использованием совместно с boost::thread
,
может стать иточником утечки ресурсов.
Ниже более детально.
Название страшное. На самом деле просто приведу, на заметку, команды которыми можно подготовить фотографию, что бы она была выполнена в монохромной палитре (1bpp - один бит на пиксель). Это удобно для реализации идеи приведённой в статье на хабре:
http://habrahabr.ru/post/157465/
Просто вариант с “газетным подходом” мне не совсем понравился, решил попробовать другое.
Итак, понадобится только
ImageMagick или
GraphicsMagick
В основном в части вкладок (в народе - “табов”).
Задачи две:
- Сделать так, что бы не отображался скролинг вкладок, а сами вкладки уменьшались до минимума аля Opera
- Уменьшить их высоту
Поиск дал ссылки на следующие материалы:
-
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;
}
Для начала, охранные классы, это не что иное как различные *_lock
классы, реализующие идиому
RAII, захватывающие мутекс в конструкторе (lock()
) и освобождающие его в деструкторе (unlock()
) -
паттерн “блокировка в области видимости”. Не смог придумать более корректного перевода.
Охранных классов в Boost много, легко можно в них запутаться. Но знать про них необходимо, так как почти вся библиотека
boost::thread спроектирована с ориентацией на их использование.
В терминах FFMPEG time-base, это параметр, используя который можно перевести PTS (Presentation Timestamp) закодированного пакета (AVPacke
t) или раскодированного фрейма (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.
Что получается:
- после открытия входного файла Stream1 имеет time-base InStreamTimeBase, а Coder1 имеет time-base InCoderTimeBase.
- после настройки выходного формата, и записи заголовка мы имеем: Stream2 с OutStreamTimeBase и Codec2 с OutCoderTimeBase.
av_read_fream()
возвращает пакеты с pts/dts в масштабе InStreamTimeBase.
- после декодирования видео-фрагментов, мы получаем фрейм с pts в масштабе InCoderTimeBase
- если возникает необходимость копировать pts/dts пакеты в pts фрейма необходимо сделать масштабирование: frame.pts = av_rescale_q(packet.pts/dts, InStreamTimeBase, InCoderTimeBase);
- перед кодировкой фрейма при помощи Coder1 нужно смаштабировать его pts: frame.pts = av_rescale_q(frame.pts, InCoderTimeBase, OutCoderTimeBase);
- перед записью получившегося пакета, нужно смаштабировать его pts/dts: packet.pts/dts = av_rescale_q(packet.pts/dts, OutCoderTimeBase, OutStreamTimeBase);
- записать пакет.
Масштабирования нужно делать только если значение временной метки не равно AV_NOPTS_VALUE.
За сим всё.
Валидных ссылок всё меньше и меньше, поэтому сохранил у себя:
http://htrd.su/~hatred/digma/e600_fw27_05_2011.zip
Прошивка не официальная.
Как я уже
писал, вяло пилю модифицированную версию плагина CMakeProjectManager для Qt Creator’а. Там же указаны причины, вынудившие меня на это. Но разговор, не про это, а про то, что с момента прошлого поста было сделано.
Итак:
- Для каждого профиля сборки сохраняются введённые параметры для CMake, так что, выбрав в следующий раз “Run CMake” не нужно вспоминать, с какими параметрами вы его запускали и легче управлять профилями сборки. Вкупе с последней фичей из апстрима: сохранения глобальной истории параметров для CMake, получается достаточно мощный механизм.
- Используя вышеприведённую информацию, появилась возможность при модификации дерева исходников (добавление, удаление, переименование) в фоновом режиме запускать обновление CBP файла и дерева сборки, что особо актуально при использовании глоббинга.
- По сравнению с первым вариантом, получилось значительно сократить расходование памяти при использовании плагина, особенно когда в дереве проекта много вспомогательных модулей, временного 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++ враппере для FFMPEG, а так же получения набора параметров и
именованных констант, которые они могут принимать.
Основные идеи данного паттерна изложены по этой ссылке:
http://sourcemaking.com/design_patterns/iterator, а возможные реализации на C++ здесь:
Сведения эти - общетеоретические. Более практическое описание с разделением итераторов на типы
приведено на cplusplus.com:
http://www.cplusplus.com/reference/std/iterator/, в частности вводятся
понятие следующих типов итераторов (а так же наглядная таблица, по которой можно понять какие методы
и операторы должны определяться в классе-итераторе):
А что бы несколько привести итераторы к одному виду, существует класс в стандартной библиотеке,
называется ~std::iterator~, почитать можно здесь:
http://www.cplusplus.com/reference/std/iterator/iterator/, там же приведён простой пример итератора.
В след за
выкладываю свои конфиги для 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
Пожелания по унификации приветствуются.
Ditaa - DIagrams Through Ascii Art - “компилятор” для ASCII диаграмм, на выходе создаёт достаточно приятные для глаза диаграммки:
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
Выложил свои конфиги для
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
Расшифровка значений переменной errno
на различных платформах:
http://www.ioplex.com/~miallen/errcmp.html
Копия на этом сервере:
http://htrd.su/data/errno_codes/errcmp.html
Работая над программой столкнулся с проблемой в части функционала сокетов, пока искал в интернетах возможный пути решения проблемы, натолкнулся на интересное руководство:
Beej’s Guide to Network Programming. Using Internet Sockets
Руководство доступно в в различных форматах (по ссылке выше можно найти подходящие), вот самые удобные, на мой взгляд:
Руководство переведено на несколько языков, но русского среди них нет, так что если кому не терпится - переводите, будет, по крайней мере, от меня, большое спасибо и пару-тройку бутылочек пива, если окажетесь в зоне досягаемости :)
Стоит отметить, что помимо всяких Linux/Unix есть информация и про Windows, в частности будет полезно при разработке кроссплатформенных сетевых приложений.
Ещё, среди кучи ссылок, в тексте обнаружилась такая полезная:
UNIX Socket FAQ - тоже кладезь знаний.
В дополнение, книжка “Linux Socket Programming by Example”, можно купить на Амазоне:
http://www.amazon.com/Linux-Socket-Programming-Example-Warren/dp/0789722410 или: