Титр собственного изготовления

Здесь обсуждаются любые продукты компании СофтЛаб-НСК для телевизионного вещания (Форвард Т, Форвард ТС, Форвард Голкипер, Форвард Рефери, Форвард Офис, Форвард Инжест)

Модераторы: ElenVR, Людмила, PR

Ответить
kasa
Сообщения: 90
Зарегистрирован: 04 сен 2008 01:50
Откуда: Красноярск

Титр собственного изготовления

Сообщение kasa »

Здравствуйте!

Есть задача: выводить на FD300 собственную динамическую графику.
В смысле, есть приложение, которое умеет рисовать 32х битные "битмапы" на Matrox CG2000. Нужно, чтобы то же самое начало рисоваться на FD300.
И эта графика должна включаться/выключаться по командам из расписания OnAir.
Подскажите, как можно данную задачу реализовать?

Напрашивается вариант разработки собственного титровального объекта для FDTitleDesigner на подобии часов или логотипа, но в SDK такой фишки не нашел.
Может, плохо искал?
Даниленко Сергей
Сообщения: 7093
Зарегистрирован: 26 фев 2004 09:53
Откуда: Techsupport SoftLab-NSK

Сообщение Даниленко Сергей »

1)SDK по созданию собственного титровального элемента, который бы виделся в FDTitleDesigner у нас нет. Может быть в дальнейшем появится, но сроки сказать пока невозможно.

2)Вашу задачу можно решить через низкоуровневое титровальное SDK. Оно позволяет показывать последовательность изображений, которые могут генерироваться внешним приложением. Отрисовка в этом случае производится в FIFO (кольцевой буфер) из которого происходит показ на экран с помощью платы FD300. Соответствующий раздел SDK называется SLTitleSDK.

3)Управление показом можно делать с помощью, например, SLMessageServer путем отправки сообщений внешнему приложению. Опыт, насколько мы помним по общению в форуме, в этом вопросе у вас есть.

Есть еще вариант - наш старый интерфейс, который позволяет посылать из расписания программы OnAir оконные команды Windows во внешние приложения. Он описан в нашем SDK в разделе Other. Документ называется OnAirExternalTaskMsg.doc
kasa
Сообщения: 90
Зарегистрирован: 04 сен 2008 01:50
Откуда: Красноярск

Сообщение kasa »

Даниленко Сергей писал(а): 2)Вашу задачу можно решить через низкоуровневое титровальное SDK. Оно позволяет показывать последовательность изображений, которые могут генерироваться внешним приложением. Отрисовка в этом случае производится в FIFO (кольцевой буфер) из которого происходит показ на экран с помощью платы FD300. Соответствующий раздел SDK называется SLTitleSDK.
Спасибо, я так и думал, но была слабая надежда :)

Еще пару вопросов тогда:
какого размера буфер (в экранах?)?
что будет происходить при пересечении регионов моей программы с регионами OnAir (тировальных объектов)?
Даниленко Сергей
Сообщения: 7093
Зарегистрирован: 26 фев 2004 09:53
Откуда: Techsupport SoftLab-NSK

Сообщение Даниленко Сергей »

какого размера буфер (в экранах?)?
Во-первых, есть размер картинки (т.е. не обязательно ваш титр должен быть полноэкранным). Во-вторых, есть глубина FIFO, т.е. сколько таких последовательных картинок вы используете.
Оба параметра задаете вы сами.
что будет происходить при пересечении регионов моей программы с регионами OnAir (тировальных объектов)?
В нашей титровальной системе есть понятие Z-кординаты. Каждый титровальный элемент имеет свою Z-координату и не может быть элементов с одной Z-координатой. Другими словами в каждом титровальном слое может находиться только один титровальный элемент. Этим обеспечивается однозначное расположение титров на экране по "глубине" (кто над кем рисуется).
При работе через SDK вы указываете Z-координату для своих титров. Так что при пересечении титров разного типа кто-то кого-то будет перекрывать в зависимости как вы укажите Z-координату.
kasa
Сообщения: 90
Зарегистрирован: 04 сен 2008 01:50
Откуда: Красноярск

Сообщение kasa »

Здравствуйте!

Что-то не очень получается у меня реализовать задуманное. А конкретно, ну удается добиться плавного перемещения бегущей строки. Она, во-первых, движется с некой "дрожью", а во-вторых, периодически двигается с "подрывами". Полагаю, что я неверно понял примеры из SDK. Прошу помочь разобраться в этом.

Есть вот такой вот тестовый код основного цикла отрисовки:

Код: Выделить всё

		while (true) {
			THROW_FAILED(region->GetShotBuff(sizeRequired, sizeRequired, &buff, &size, 40),
				_T("Не удалось получить FIFO буфер для кадра!"));

			DrawImage1(WIDTH, HEIGHT, buff);

			// confirm valid image data
			CTitleShotInfo shotInfo;
			shotInfo.DataType = TitleShotDataType_RGBA;
			shotInfo.ShotNumber = frame;
			shotInfo.dx = WIDTH;
			shotInfo.dy = HEIGHT;
			THROW_FAILED(region->ConfirmShotSize(0, sizeRequired, &shotInfo),
				_T("Буфер не прошел валидацию!"));

			// Activate and run region
			THROW_FAILED(region->SetActive(TRUE, TRUE, 0),
				_T("Не удалось активировать регион!"));

			if (_kbhit() && _getch() == KEY_ESC)
				break;

			//color += 8;
			frame++;
			Sleep(40);
		}
Отрисовка в DrawImage1 - простое копированеи памяти, занимает очень мало времени. Sleep(40) установлено просто из соображений 25 FPS. Однако, если уменьшить это значение, то region->GetShotBuff перестает возвращать корректный буфер (не успевает?), хотя размер FIFO гораздо больше размера одного кадра (4000000 против 185000).

Код: Выделить всё

const long WIDTH = 720;
const long HEIGHT = 64;
...
		// create COM-object for application alive checking
		CComPtr<IUnknown> holder;
		THROW_FAILED&#40;holder.CoCreateInstance&#40;CLSID_SLResourceHolder&#41;,
			_T&#40;"Не удалось создать экземпляр SLResourceHolder!"&#41;&#41;;

		CComPtr<IUnknown> unk;
		CComPtr<ISLTitleRegion> region;
		THROW_FAILED&#40;surface->CreateTitleRectRegion&#40;holder, 4000000, 4000000, &unk&#41;,
			_T&#40;"Не удалось создать регион!"&#41;&#41;;
Думаю, что я не уловил какой-то принципиальный момент в механизме отрисовки. Растолкуйте, пожалуйста!

Спасибо.
Игорь Таранцев
Сообщения: 493
Зарегистрирован: 04 янв 2004 12:45
Откуда: СофтЛаб-НСК

Сообщение Игорь Таранцев »

Есть два замечания по коду:
движется с некой "дрожью"
В телевидении используется чересстрочная развертка, когда четные и нечетные строки одного кадра (одного изображения в нашем случае) показываются в разное время (сдвинуты друг относительно друга на 20 мс). В нашем SDK у интерфейса ISLTitleTarget есть метод GetTargetParams(), который возвращает размеры экрана, частоту кадров и сдвиг во времени верхнего и нижнего поля (от начала кадра). Если порядок полей UpperFieldFirst, то в поле m_LowerFieldTimerShift будет стоять величина 0,020. Если порядок полей LowerFieldFirst, то в поле m_UpperFieldTimerShift будет стоять величина 0,020.
В вашем коде необходимо копировать разные данные в четные и нечетные строки (в верхнее и нижнее поле).
периодически двигается с "подрывами"
Здесь надо обяснить, как работает титровальное фифо.
Ваше приложение заполняет фифо, а титровальное ядро "вытаскивает" из фифо кадры и показывает их на плате с частотой кадров платы FD300. Ваше приложение должно стараться держать фифо максимально заполненным. То есть проверять, что в фифо есть свободное место и если место есть, то генерировать очередной кадр (два поля). А если места нет, то тогда выполнять Sleep(40).
Соответственно, в вашем коде надо поправить проверку заполненности фифо:

Код: Выделить всё

HRESULT hres = region->GetShotBuff&#40;sizeRequired, sizeRequired, &buff, &size, 40&#41;;
if&#40; hres==S_OK &#41; &#123;
  DrawImage&#40;&#41;;
  ... // остальной код, как он и был
&#125; else if&#40; hres==S_FALSE &#41; &#123;
  // нет свободного места в фифо - надо подождать, когда оно появится
  Sleep&#40;40&#41;;
&#125; else &#123; // какая-то ошибка - ломаемся
  THROW_FAILED&#40;...&#41;
&#125;
Игорь Таранцев
Сообщения: 493
Зарегистрирован: 04 янв 2004 12:45
Откуда: СофтЛаб-НСК

Сообщение Игорь Таранцев »

И еще одно мелкое замечание - вызывать SetActive() на каждом кадре не рекомендуется. Лучше вызвать один раз.
kasa
Сообщения: 90
Зарегистрирован: 04 сен 2008 01:50
Откуда: Красноярск

Сообщение kasa »

Игорь Таранцев писал(а): В вашем коде необходимо копировать разные данные в четные и нечетные строки (в верхнее и нижнее поле).
То есть фифо фрейм содержит сразу оба полукадра? Мне просто не совсем ясен механизм возникновения дрожи. Даже если я помещаю в один фифо фрейм не сдвинутые поля, то это может лишь замедлить строку в два раза, но не должно вызывать дрожь.
Игорь Таранцев писал(а): И еще одно мелкое замечание - вызывать SetActive() на каждом кадре не рекомендуется. Лучше вызвать один раз.
Один раз в рамках создания/инициализации региона?
Игорь Таранцев
Сообщения: 493
Зарегистрирован: 04 янв 2004 12:45
Откуда: СофтЛаб-НСК

Сообщение Игорь Таранцев »

То есть фифо фрейм содержит сразу оба полукадра?
Да, именно так.
Мне просто не совсем ясен механизм возникновения дрожи. Даже если я помещаю в один фифо фрейм не сдвинутые поля, то это может лишь замедлить строку в два раза, но не должно вызывать дрожь.
Дрожь возникает из-за свойств человеческого зрения. Пусть картинка в каждом кадре смещается на 2 пиксела влево. Тогда при показе первого поля картинка смещается на 2 пиксела влево, а при показе второго поля - остается на месте.
Рассмотрим поведение глаза. Глаз старается отслеживать положение картинки в пространстве. Когда в одном поле картинка сместилась на 2 пиксела влево, то глаз ожидает увидеть ее в следующем поле еще на 2 пиксела влево. В следующем поле он ее на находит в ожидаемом месте, но находит чуть сзади и решает, что картинка поехала назад. В следующем поле глаз опять не находит картинку в ожидаеом месте (сзади), а видит, что картинка в очередной раз дернулась, но уже вперед. И так далее. Глаз видит всякий раз картинку в "новом" месте, а не там, где она должна быть при непрерывном равномерном движении.

Про вызов SetActive().
Досаточно вызывать SetActive() один раз при смене состояния региона - один раз после создания региона при старте показа и один раз при переходе в состояние остановки. Если регион много раз меняет состояние - показывается/останавливается, то и метод SetActive() нужно вызывать много раз.
kasa
Сообщения: 90
Зарегистрирован: 04 сен 2008 01:50
Откуда: Красноярск

Сообщение kasa »

Игорь Таранцев писал(а): Рассмотрим поведение глаза.
Отличное пояснение, спасибо большое! "Даже я понял" (С) :)
Скролл работает как нужно...

Еще небольшой вопрос. Как думаете, полноэкранный титр будет без "провалов" работать, если допустить, что мой код отрисовки будет успевать в 40 мсек?
Игорь Таранцев
Сообщения: 493
Зарегистрирован: 04 янв 2004 12:45
Откуда: СофтЛаб-НСК

Сообщение Игорь Таранцев »

Если Ваш код отрисовки успевает генерировать картинку меньше, чем за 40мс (например, за 35мс), то "провалов" точно не будет.
Особенно, если сначала заполнить фифо "до конца", а только затем стартовать (активировать) регион.
kasa
Сообщения: 90
Зарегистрирован: 04 сен 2008 01:50
Откуда: Красноярск

Сообщение kasa »

Игорь Таранцев писал(а): Особенно, если сначала заполнить фифо "до конца", а только затем стартовать (активировать) регион.
Не могли бы вы уточнить? То есть лучше забить весь ФИФО кадрами и только потом вызывать SetActive, а дальше уже по мере освобождения блоков (в фифо) добавлять кадры? Если так, то как мне узнать, что фифо забит под завязку? Вероятно, можно вызывать GetShotBuff несколько раз подряд без соотв. вызовов ConfirmShotSize, до тех пор, пока GetShotBuff не вернет S_FALSE, а уже потом для всех полученных буферов вызвать ConfirmShotSize, так?
Или я неверно понял мысль?
Игорь Таранцев
Сообщения: 493
Зарегистрирован: 04 янв 2004 12:45
Откуда: СофтЛаб-НСК

Сообщение Игорь Таранцев »

Надо вызывать GetShotBuff, формировать кадр и вызывать ConfirmShotSize много раз подряд, пока метод GetShotBuff возвращает S_OK. Как только метод GetShotBuff вернул S_FALSE, значит фифо полное и пора вызывать SetActive.
Игорь Таранцев
Сообщения: 493
Зарегистрирован: 04 янв 2004 12:45
Откуда: СофтЛаб-НСК

Сообщение Игорь Таранцев »

А во время воспроизведения можно узнать заполненность фифо, сравнивая текущее время в фифо (номер кадра, который сейчас показывается) и номер последнего добавленного кадра.
Текущее время возвращает метод GetParameters (интерфейс ISLTitleRegion) - параметр CurrShot струткуры CRegionInfo.
Ну а последений номер Вы знаете сами - то, что Вы указали первым параметром при вызове метода ConfirmShotSize. Кстати, надеюсь Вы увеличиваете этот параметр от кадра к кадру? Очень важно, чтобы для каждого кадра указывался его настоящий номер - именно в это время титровальное ядро пытается показать этот кадр. Если у всех кадров стоит один и тот же номер (например, номер 0), то титровальное ядро будет пропускать все кадры, кроме самого последнего, только-что добавленного в фифо. Поскольку операционная система работает не строго равномерно, то в итоге некоторые кадры будут пропускаться и анимация будет показываться с подрывами.
kasa
Сообщения: 90
Зарегистрирован: 04 сен 2008 01:50
Откуда: Красноярск

Сообщение kasa »

Подниму старую тему, пожалуй...

Здравствуйте!

Такая ситуация: запускаю свой софт, который работает с титровалкой через SDK, а картинки на экране нету. Хотя на соседнем сервере есть. :)

Судя по логам моего софта, не производится вычитывание FIFO буфера. Как только мой софт его заполняет под завязку, GetShotBuff начинает возвращать S_FALSE бесконечно долго.
Насколько я помню, раньше такого не наблюдалось. Правда, тесты проводились на другом сервере с другой версией Forward.

Отсюда два вопроса:
1. Зависит ли функциональность, предоставляемая SDK, от версии Forward? Не работает нормально на версии 5.0.2, хотя вся инициализация проходит успешно. На версии 5.2.0 все работает и картинка есть.
2. Мы опять какую-нибудь "птичку" забыли установить в конфиге?

Спасибо.
Ответить