Сообщения cdslow
Transmission patch
Я сделал патч для transmission-2.94, который добавляет к анонсам поле «ip=» и дополнительный заголовок «X-Forwarded-For» с адресом шлюза. Это всё нужно для удобной работы через прокси.
Патч: https://yadi.sk/d/4e2Vp7Xh3XqTmD
Исходники transmission лежат на github, а я там не зарегистрирован, и регистрироваться особого желания нет.
Если есть желающие отправить им пул-реквест - милости прошу.
Установить переменную окружения для всех графических приложений в Fedora
Обновил я у себя Fedora, и испортились у меня после этого шрифты. Поискал в Интернете в чём дело и выяснил, что во Freetype поменялся алгоритм BCI по умолчанию, и вернуть всё обратно можно установив переменную окружения FREETYPE_PROPERTIES
со значением truetype:interpreter-version=35
.
Хорошо, создаю файл /etc/profile.d/fonts.sh
, пишу в нём:
export FREETYPE_PROPERTIES='truetype:interpreter-version=35'
Перезапускаю сеанс — ура, старые шрифты вернулись, глазкам полегчало.
Но. Запускаю с рабочего стола документ LibreOffice, и опаньки, снова кривые шрифты.
Начинаю разбираться в чём дело. Документ с рабочего стола запускается через systemd dbus activation
, а оно на profile.d плевать хотело. Ладно, создаю файл /etc/systemd/system.conf.d/env.conf
, пишу в нём:
[Manager]
DefaultEnvironment='FREETYPE_PROPERTIES=truetype:interpreter-version=35'
Перезагружаю систему — да, теперь шрифты нормальные и в LibreOffice.
Внимание вопрос: есть в Fedora какое-то одно место, где можно прописать переменную окружения для всех графических (или вообще всех) приложений, не повторяя одно и то же несколько раз?
Новая версия программы для слайдшоу c эффектами переходов — sleid0r 0.3
Что повесить на пробел — паузу или листание?
Решил я добавить в свою программу для слайдшоу (sleid0r) управляющие клавиши для листания вперёд/назад и для установки паузы. И теперь в раздумьях — какую из этих функций повесить на клавишу пробел?
С одной стороны, во многих программах пробел используется для перехода вперёд, с другой, во многих видеоплеерах он используется как клавиша паузы.
А какое поведение вы интуитивно ожидаете от пробела при показе слайдшоу?
PgcDemux для Linux
Я собрал консольную версию PgcDemux. Может, кому-нибудь пригодится.
Исходники: http://cdslow.org.ru/files/cpgcdemux/cpgcdemux-0.1.tar.gz
Пакеты: http://download.opensuse.org/repositories/home:/cdslow:/cpgcdemux/
[vala][srt2tmx] Покритикуйте код
Осваиваю vala. Без практической задачи мне программировать не интересно, поэтому реализовал то, в чём у меня сейчас была потребность.
Программа читает два набора .srt файлов на двух языках, и на основе сопоставления временных меток создаёт файл памяти перевода (translation memory) в формате tmx.
Программа работает, своё дело сделала, но мне интересно, что можно было написать проще/эффективнее/понятнее (например, мне не нравится, как организован двумерный динамический массив для имён файлов).
Много кода:
struct TextEvent
{
double begin;
double end;
string text;
}
struct TextPair
{
string orig;
string trans;
}
struct StringArray
{
string[] sa;
}
int main(string[] args)
{
string[] lang_codes={}; /* Languages */
StringArray[] lang_data={}; /* Source file names */
string out_file=null; /* Output file name */
int file_i=0; /* Source file number */
/* Process command line arguments */
for(int i=1; i < args.length; ++i)
{
if(args[i].has_prefix("-"))
{
/* It's an option */
string opt=args[i].substring(1);
if("o" == opt)
{
/* Output file name */
++i;
if(i < args.length)
out_file=args[i];
}
else if(2 == opt.length)
{
/* Language code */
lang_codes+=opt.up();
file_i=0;
}
else
{
/* Some shit */
stderr.printf("Invalid option: %s\n", args[i]);
return 1;
}
}
else
{
/* It's a file name */
if(0 == lang_codes.length)
{
/* Language code must go first */
stderr.printf("Language undefined!\n");
return 1;
}
if(lang_data.length <= file_i)
{
/* Allocate new set of files */
lang_data.resize(file_i + 1);
lang_data[file_i].sa={};
}
if(lang_data[file_i].sa.length < lang_codes.length)
/* Allocate space for file name */
lang_data[file_i].sa.resize(lang_codes.length);
/* Store file name */
lang_data[file_i].sa[lang_codes.length-1]=args[i];
++file_i;
}
}
/* Print source file names */
for(int lang_i=0; lang_i < lang_codes.length; ++lang_i)
{
stdout.printf("%s files:\n", lang_codes[lang_i]);
foreach(var ld in lang_data)
{
if(null == ld.sa[lang_i])
{
stderr.printf("File lists mismatch!\n");
return 1;
}
stdout.printf(" %s\n", ld.sa[lang_i]);
}
}
if(lang_codes.length != 2)
{
stderr.printf("There must be 2 input languages!\n");
return 1;
}
if(null == out_file)
{
stderr.printf("Missing output file name!\n");
return 1;
}
TextPair[] pairs={}; /* Translations */
/* Process file sets */
foreach(var ld in lang_data)
{
if(null == ld.sa[0] || null == ld.sa[1])
{
stderr.printf("File lists mismatch!\n");
return 1;
}
stdout.printf("Processing:\n %s\n %s\n", ld.sa[0], ld.sa[1]);
try
{
/* Read, parse and match */
match_events(ref pairs, ld.sa);
}
catch(FileError e)
{
stderr.printf("%s\n", e.message);
return 1;
}
}
/* Write XML */
stdout.printf("Writing: %s\n", out_file);
write_pairs(out_file, pairs, lang_codes);
return 0;
}
/* Process file set */
void match_events(ref TextPair[] pairs, string[] file_set) throws FileError
{
TextEvent[] orig, trans; /* Parsed srt data */
int i_trans=0, i_orig=0; /* String numbers */
double o_begin, o_end, o_mid; /* Original time interval */
double t_begin, t_end, t_mid; /* Translated time interval */
/* Read and parse files */
orig=parse_srt(file_set[0]);
trans=parse_srt(file_set[1]);
/* Process text events */
while(i_orig < orig.length && i_trans < trans.length)
{
/* Calculate original time interval */
o_begin=orig[i_orig].begin;
o_end=orig[i_orig].end;
o_mid=(o_begin + o_end) / 2.0;
/* Calculate transalted time interval */
t_begin=trans[i_trans].begin;
t_end=trans[i_trans].end;
t_mid=(t_begin + t_end) / 2.0;
/* Test for interval match */
if(t_mid > o_begin && t_mid < o_end || o_mid > t_begin && o_mid < t_end)
{
/* Store matched text */
push_pair(ref pairs, orig[i_orig].text, trans[i_trans].text);
++i_trans;
++i_orig;
/* Concatenate overlapping events */
do
{
while(i_trans < trans.length)
{
t_mid=(trans[i_trans].begin + trans[i_trans].end) / 2.0;
if(t_mid < o_begin || t_mid > o_end)
break;
pairs[pairs.length-1].trans+=" " + trans[i_trans].text;
t_end=trans[i_trans].end;
++i_trans;
}
while(i_orig < orig.length)
{
o_mid=(orig[i_orig].begin + orig[i_orig].end) / 2.0;
if(o_mid < t_begin || o_mid > t_end)
break;
pairs[pairs.length-1].orig+=" " + orig[i_orig].text;
o_end=orig[i_orig].end;
++i_orig;
}
}
while(t_mid > o_begin && t_mid < o_end && i_trans < trans.length);
}
else
{
/* No matching event */
if(o_mid < t_mid)
{
/* Skip original */
/*push_pair(ref pairs, orig[i_orig].text, "");*/
++i_orig;
}
else
{
/* Skip translated */
/*push_pair(ref pairs, "", trans[i_trans].text);*/
++i_trans;
}
}
}
}
/* Append text pair to array */
void push_pair(ref TextPair[] pairs, string t1, string t2)
{
pairs.resize(pairs.length+1);
pairs[pairs.length-1].orig=t1;
pairs[pairs.length-1].trans=t2;
}
/* Read and parse srt file */
TextEvent[] parse_srt(string file_name) throws FileError
{
TextEvent[] parsed={};
string file_text;
/* Read file */
FileUtils.get_contents(file_name, out file_text, null);
/* Parse text */
foreach(var srt_group in file_text.replace("\r", "").split("\n\n"))
{
var srt_part=srt_group.strip().split("\n", 3);
if(srt_part.length<3)
break;
var time_text=srt_part[1].split("-->", 2);
parsed.resize(parsed.length+1);
parsed[parsed.length-1].begin=parse_time_value(time_text[0]);
parsed[parsed.length-1].end=parse_time_value(time_text[1]);
parsed[parsed.length-1].text=srt_part[2].replace("\n", " ");
}
return parsed;
}
/* Convert srt time to double */
double parse_time_value(string time_text)
{
double time_value;
var time_parts=time_text.strip().replace(",", ".").split(":", 3);
time_value=double.parse(time_parts[2]);
time_value+=double.parse(time_parts[1])*60.0;
time_value+=double.parse(time_parts[0])*3600.0;
return time_value;
}
/* Write XML file */
void write_pairs(string file_name, TextPair[] pairs, string[] lang_codes)
{
var xml=new Xml.TextWriter.filename(file_name);
xml.set_indent(true);
xml.start_document();
xml.start_element("tmx");
xml.write_attribute("version", "1.4");
xml.write_attribute("xmlns", "http://www.localization.org/tmx14");
xml.start_element("header");
xml.write_attribute("creationtool", "srt2tmx");
xml.write_attribute("creationtoolversion", "0.1");
xml.write_attribute("datatype", "PlainText");
xml.write_attribute("segtype", "sentence");
xml.write_attribute("adminlang", "en-us");
xml.write_attribute("srclang", lang_codes[0]);
xml.write_attribute("o-tmf", "srt2tmx");
xml.end_element();
xml.start_element("body");
foreach(var p in pairs)
{
xml.start_element("tu");
xml.start_element("tuv");
xml.write_attribute("xml:lang", lang_codes[0]);
xml.write_element("seg", p.orig);
xml.end_element();
xml.start_element("tuv");
xml.write_attribute("xml:lang", lang_codes[1]);
xml.write_element("seg", p.trans);
xml.end_element();
xml.end_element();
}
xml.end_element();
xml.end_element();
xml.end_document();
xml.flush();
}
Видеофильтры
Придумал я несколько алгоритмов для фильтрации видео. И начал я их реализовывать для программы transcode. Но transcode скоропостижно скончалась. Тогда я решил переписать их под mencoder. Но API у mencoder мало того, что запутанный, так как завязан на mplayer с его оптимизациями, так ещё и не позволяет свободно манипулировать удалением/добавлением/перестановкой кадров. В общем, написал я собственный вариант API для видеофильтрации. И реализовал фильтры на нём.
Основная идея в том, что вся внутренняя обработка ведётся строго в одном формате цветности - yuv444 и фильтры могут буферизировать у себя любое количество кадров и выдавать их в любой последовательности.
Исходный код: video3x-0.1.tar.gz
Исполняемые файлы для Linux: video3x-0.1-linux.tar.gz
Исполняемые файлы для Windows: video3x-0.1-windows.zip
Опции командной строки (по английски): video3x-0.1-help.txt
Лицензия - LGPL 3+.
[ffmpeg] Замена ключа -s на -video_size в ffplay
API в ffmpeg ломают постоянно, к этому все давно привыкли.
А теперь сломали командную строку очень оригинальным образом. Итак, в fedora-16 ffplay не проигрывает raw-видео с ключём -s для указания размера кадра, вместо него теперь нужно использовать ключ -video_size. Всё бы ничего, только про этот ключ в справке ffplay ни слова.
Собственно вопрос: как в скрипте определить, какой ключ использовать для проигрывания raw-видео?
Может быть, кто-нибудь знает, с какой именно версии ffplay изменился ключ, чтобы сделать проверку по версии?
[C] Выбор структуры данных для видеофильтров
Пишу фреймворк для фильтрации видео. Не могу окончательно решить, какую структуру данных использовать для хранения обрабатываемых кадров.
Вариант 1:
typedef struct image_s
{
int w;
int h;
int sz_yy;
int sz_buf;
uint8_t *buf;
uint8_t *yy;
uint8_t *cb;
uint8_t *cr;
} image_t;
Вариант 2:
typedef struct pixel_s
{
uint8_t yy;
uint8_t cb;
uint8_t cr;
} pixel_t;
typedef struct image_s
{
int w;
int h;
int px_count;
int px_sz;
pixel_t *px;
} image_t;
Первый вариант удобнее импортировать/экспортировать из планарных форматов (yv12, yuv420p) и обрабатывать покомпонентными фильтрами.
Второй вариант удобнее обрабатывать попиксельными фильтрами, и использовать при этом код типа такого:
out->px[xy]=in->px[xy];
out->yy[xy]=in->yy[xy];
out->cb[xy]=in->cb[xy];
out->cr[xy]=in->cr[xy];
Есть какие-нибудь аргументы, чтобы остановиться на одном из вариантов?