
Для начала я сделал fork этого репозитория и начал читать документы и howto. Сразу простроить проект у меня не получилось, были конфликты с установленным у меня mac ports, пришлось снести. Потом пришлось сделать up-merge для extras/tools/ragel/aapl компоненты, после этого все собралось по инструкции .
Дальше первое, что мне бросилось в глаза — это возможно добавлять в VLC — плагины (это такие модули, которые позволяют делать пост-обработку декодированных виде фреймов). Ну что-ж, я подумал, что этого будет достаточно для преобразования стерео изображения.
Отступление: исходный файл, который мне хотелось проиграть, имел в каждом видео фрейме 2 ракурса (слева картинка для левого глаза, справа — для правого) в общем, довольно стандартный формат для стерео-фильма.
Обработка сводилась к тому, что я формировал выходной видео буфер линия за линией из левого и правого полукадра соответственно. Ожидалось, что левый глаз будет видеть нечетные строчки, правый — четные.
Реализовать этот фильтр было просто (прочитал инструкцию взял за основу один из существующих). Но, конечно же, к успеху это не привело. На экране картинка выглядела полосатой, но линии не были синхронизированы с пикселями экрана, поэтому эффекта 3D в очках не наблюдалось.
Отступление: Хочу пояснить, как работает 3D режим на пассивных 3D мониторах. Я не специалист в этой технологии, поэтому буду описывать как дилетант.
В мониторах типа моего используется технология FPR (Film-type Patterned Retarder) для разделения ракурсов видео потока. Я ее представляю себе так, как будь то каждая линия пикселей на мониторе закрыта поляризационным фильтром, условно можно представить, что нечетные линии закрыты фильтром с вертикальной поляризацией, а четные с горизонтально, такие же фильтры стоят в очках, в результате один глаз видит только нечетные линии, второй четные.
Поняв это, я понял, что мне нужно делать пост-обработку непосредственно в рендере, чтоб я мог гарантировать попиксельно расположение выходного видео фрейма.
Посмотрел как реализован рендер в VLC для Mac. Оказалось все довольно просто. Каждый декодированный видео фрейм загружается в виде текстуры, которая в последствие отображается на экране средствами open GL. Преобразование графического формата из YUV в RBG происходит непосредственно в пиксельном шейдере. Это сразу натолкнуло меня на мысль — что нужно сделать. Поскольку известно, что пиксельный шейдер как раз формирует цвет для каждого пикселя экрана, мне остается только поправить этот шейдер, чтоб он при формирование цвета брал данные из нужной части текстуры, для четных и нечетных линий.
Вот пример кода (написано схематично, рабочий пример можно посмотреть тут ):
void main(void) {
vec4 x,y,z,result;
vec4 tc = TexCoord0;
+ float d = mod((floor(height*(tc.y+1.0))),2.0); //odd or even, height - is new uniform to get viewport height
+ if(d>0.1) tc.x += 0.5; //shift texture
x = texture2D(Texture0, tc.st);
y = texture2D(Texture1, tc.st);
z = texture2D(Texture2, tc.st);
result = x * Coefficient[0] + Coefficient[3]; //Coefficient - const coefficients for convert YUV to RGB
result = (y * Coefficient[1]) + result;
result = (z * Coefficient[2]) + result;
+ if(TexCoord0.x > 0.5) result = vec4(0,0,0,1); //cut off right side
gl_FragColor = result;
};
Если сравнивать с исходным кодом, то я добавил только строчки помеченные +.
После этого я уже получил правильное стерео изображение в левой части экрана.
В дальнейшем осталось только поправить размер картинки, и отрезать правую часть, и все — стерео-плеер готов.
Всем кому интересно — можно посмотреть код на github.
Фактически, чтоб получить стерео-плеер из VLC в общей сумме пришлось написать около 30 строк кода, это меня сильно поразило, и явилось причиной написания этой статьи.
PS: Уже потом, когда моя версия была сделана, я нашел отличный opensource стерео-плеер — sview.ru, на MacOS работает неплохо.