1

Тема: Возврат к воспроизведению после выполнения обработки по расписанию

Добрый день!

Есть следующая задача. На четырех телевизорах в баре отображается меню в виде статичной картинки jpg. На каждом телевизоре своя картинка. Возникла потребность раз в полчаса крутить на всех четырех экранах 30-секундный ролик. Пока один, но боюсь в будущем их будет около 10 и каждые полчаса нужно будет крутить новый по кругу. По аналогии с DLNA-будильником сделал обработку, запускаю ее раз в полчаса:

var
  MediaItem: THmsScriptMediaItem;
begin
  MediaItem := HmsFindMediaFolder(mfVideoCollectionsItemID, 'Test');
  if (MediaItem <> nil) and MediaItem.HasChildItems then
    HmsPlayToGroup(MediaItem.ChildItems[0], 'GroupNoOne')  
end.

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

2

Re: Возврат к воспроизведению после выполнения обработки по расписанию

Можно сделать следующим образом.

Допустим, в HMS у нас есть папка с нашими видео.
Также у нас есть в разделе "Фото" папка с фотографиями. Например, в разделе Альбомы создадим папку "Showroom" со значением поля "Файл" -Showroom.

В папке фотографий, добавляем ссылки на фотографии, которые будут высвечиваться на устройствах как заставки. В каждой такой ссылке на фото в поле "Комментарий" указываем MAC-адрес устройства, на котором данная картинка будет отображаться.

В папке видео добавляем ссылки на видео файлы, которые будут по очереди воспроизводится.

Теперь нужно создать две обработки.
Одну как у вас - она будет по расписанию запускать видео (например, каждые 30 мин).
Вторая обработка будет запускать воспроизведение фото на устройства.

Вот пример первой обработки:

+ Запуск видео по-расписанию
var
  MediaFolder: THmsScriptMediaItem; nCounter: Integer;
begin
  MediaItem := HmsFindMediaFolder(mfVideoCollectionsItemID, 'Test');
  if (MediaFolder <> nil) and MediaFolder.HasChildItems then begin
    nCounter := MediaFolder[mpiTrack];                                     // Получаем значение счётчика очерёдности
    HmsPlayToGroup(MediaFolder.ChildItems[nCounter], 'GroupNoOne', false); // Запуск воспроизведения очередного видео из папки
    nCounter := nCounter + 1;                                              // Увеличиваем счётчик
    if nCounter >= MediaFolder.ChildCount then nCounter := 0;              // Если значение счётчика больше количества видео - сбрасываем счётчик
    MediaFolder[mpiTrack] := nCounter;                                     // Запоминаем значение счётчика в свойствах папки
  end;
end.

Пример второй обработки:

+ Запуск отображения заставок
var
  MediaFolder, MediaItem, VideoFolder: THmsScriptMediaItem; n: Integer;
begin
  // Находим папку с видео, после которых будет запускаться заставка
  VideoFolder := HmsFindMediaFolder(mfVideoCollectionsItemID, 'Test');
  
  // Находим папку с фото, которые будут отображаться на разных устройствах
  MediaFolder := HmsFindMediaFolder(mfImageAlbumsItemID, '-Showroom');
  
  // Проверяем, есть ли папка с фото и точно ли произошёл запуск этого скрипта
  // после остановки наших видео (проверяем, является ли родительский элемент
  // текущего элемента той папкой, которая содержит наши видео)
  if (MediaFolder <> nil) and MediaFolder.HasChildItems and (CurrentMediaItem.ItemParent = VideoFolder) then begin
  
    // В цикле обходим все картинки и запускаем их на показ устройствам
    // по MAC-адресу, указанному в комментариях к картинке
    for n := 0 to MediaFolder.ChildCount - 1 do begin
      MediaItem := MediaFolder.ChildItems[n];
      HmsPlayToDevice(MediaItem, MediaItem[mpiComment], false)
    end;
    
  end;
  
end.

И вторую обработку "Запуск отображения заставок" выставляем в настройках, в разделе "События" в событии "После завершения воспроизведения медиа-ресурса".

+ открыть спойлер

https://hms.lostcut.net/misc.php?action=pun_attachment&amp;item=1416

Эта обработка будет запускаться всегда, когда будет окончено воспроизведение показа видео или фото или чего бы то нибыло. Поэтому в этой обработке мы проверяем, откуда сработал скрипт и является ли текущий элемент воспроизведения нашим видео из нашей папки. Если да, то обрабатываем - запускаем цикл воспроизведения наших фото на конкретных устройствах, MAC-адреса которых прописаны в комментариях к фото.

Осталось выставить расписание запуска обработки, запускающей видео на группу устройств и будет происходить следующее:
1) Запустится видео из папки в соответствии с счётчиком, счётчик увеличится;
2) По окончании воспроизведения видео запустится обработка запуска воспроизведения заставок на устройствах;
3) Заставка будет отображаться пока не случится событие по расписанию и не запустится цикл с пункта 1).

Как то вот так.

Для кучи, прилагаю свои тестовые обработки. Правда я сделал папку с видео как папку в разделе "Подкасты" и там воспроизводятся ссылки с видео ресурса, а не локальные видео-файлы. Но, думаю, под себя всё сделать не составит труда.
Showroom_Photos - это папка раздела "Фото" в папке "Альбомы" со списком фотографий (заставок).
Showroom_Videos - это папка подкаста с видео ссылками, видео которых будет запускаться по-расписанию.

Прикреплённые файлы сообщения

showroom_event.png 57.55 kb, скачивалось 84 раза, начиная с 2016.11.05

Showroom_Photos.zip 984 b, скачивалось 135 раз, начиная с 2016.11.05

Showroom_Videos.zip 2.91 kb, скачивалось 137 раз, начиная с 2016.11.05

Обработка Showroom - запуск отображения заставки.cfg 4.03 kb, скачивалось 179 раз, начиная с 2016.11.05

Обработка Showroom - запуск следующего видео-ролика.cfg 2.87 kb, скачивалось 282 раза, начиная с 2016.11.05

Sony Bravia KDL-32CX523

3

Re: Возврат к воспроизведению после выполнения обработки по расписанию

Большое человеческое спасибо за помощь!

Есть только одна проблема. Через 1-2 секунды после начала воспроизведения видео оно прерывается и на экран выводится картинка. Я так полагаю, что у меня некорректно отрабатывает вот эта строчка второго скрипта:

if (MediaFolder <> nil) and MediaFolder.HasChildItems and (CurrentMediaItem.ItemParent = VideoFolder) then begin

Как вы писали:

Эта обработка будет запускаться всегда, когда будет окончено воспроизведение показа видео или фото или чего бы то нибыло. Поэтому в этой обработке мы проверяем, откуда сработал скрипт и является ли текущий элемент воспроизведения нашим видео из нашей папки. Если да, то обрабатываем - запускаем цикл воспроизведения наших фото на конкретных устройствах, MAC-адреса которых прописаны в комментариях к фото.

Т.е. я так думаю, что сразу после запуска видео срабатывает триггер на событие "После завершения воспроизведения медиа-ресурса" (показ картинки),  выполняется обработка и срабатывает указанное выше условие. Соответственно тут же запускается показ картинок, а видео прерывается. Посмотреть текущее значение CurrentMediaItem.ItemParent я не могу, в редакторе по F8 этого значения не увидишь.
У Вас я так понимаю все корректно отработало. Почему у меня проблема - не могу понять. Делал все в точности по инструкции, видео лежит в коллекции Test, фото в альбоме -Showroom.
На всякий прилагаю обработки. Версия сервера - 2.20.

Прикреплённые файлы сообщения

Script1_mod.cfg 2.84 kb, скачивалось 262 раза, начиная с 2016.11.06

Script2_mod.cfg 4.02 kb, скачивалось 253 раза, начиная с 2016.11.06

4

Re: Возврат к воспроизведению после выполнения обработки по расписанию

Да, именно поэтому там и нужно это проверять, ибо событие срабатывает и после отображения картинки. Сам этот цикл вечного запуска на телеке наблюдал, пока проверку не сделал.

Так, погодите. У меня это дело срабатывало после запуска отображения картинки, потом опять запускалось отображение картинки...
А у вас видео не до конца проигралось, а уже сработал скрипт окончания воспроизведения??

По-идее, скрипт №2 должен сработать только по окончании видео ролика.
А у вас он через 1-2 секунды после начала.. Хм. А ролики локально расположены? У них в программе время (длительность) правильно выставлена?

Какое-то из устройств посылает HMS, что он проиграл файл. Проверить настройки устройств, все ли поддерживают UPnP-события. Там в "UPnP, DLNA" в самом низу есть галочка "Обработка запроса окончания транскодированного файла", может её убрать, а то он как передал файл телеку, так и сформировал событие "окончания"...
Но, это всё догадки и предположения.

По F8 да, переменная CurrentMediaItem не будет установлена. Я добавлял в код такие строки:

  HmsLogMessage(1, "CurrentMediaItem[mpiTitle   ]: "+CurrentMediaItem[mpiTitle   ]);
  HmsLogMessage(1, "CurrentMediaItem[mpiFilePath]: "+CurrentMediaItem[mpiFilePath]);
  HmsLogMessage(1, "CurrentMediaItem.ItemParent[mpiTitle   ]: "+CurrentMediaItem.ItemParent[mpiTitle   ]);
  HmsLogMessage(1, "CurrentMediaItem.ItemParent[mpiFilePath]: "+CurrentMediaItem.ItemParent[mpiFilePath]);

Чтобы при срабатывании скрипта в лог программы вываливались сообщения и там смотрел.

Если так и не выяснится причина срабатывания этого события раньше времени, то можно в крайнем случае, применить грязный хак: проверять в скрипте №2 сколько времени прошло с момента запуска скрипта №1.
Типа того:

+ Скрипт №1
var
  MediaFolder: THmsScriptMediaItem; nCounter: Integer;
begin
  //MediaFolder := HmsFindMediaFolder(mfVideoPodcastsFolderItemID, '-Showroom');
  MediaFolder := HmsFindMediaFolder(mfVideoCollectionsItemID, 'Test');
  if (MediaFolder <> nil) and MediaFolder.HasChildItems then begin
    nCounter := MediaFolder[mpiTrack];                                     // Получаем значение счётчика очерёдности
    HmsPlayToGroup(MediaFolder.ChildItems[nCounter], 'GroupNoOne', false); // Запуск воспроизведения очередного видео из папки
    nCounter := nCounter + 1;                                              // Увеличиваем счётчик
    if nCounter >= MediaFolder.ChildCount then nCounter := 0;              // Если значение счётчика больше количества видео - начинаем сначала
    MediaFolder[mpiTrack    ] := nCounter;                                 // Запоминаем значение счётчика в свойствах папки
    MediaFolder[mpiTimeStart] := DateTimeToTimeStamp1970(Now, false);      // Запоминаем TimeStamp старта показа видео
  end;
end.
+ В скрипте №2
  // Находим папку с видео, после которых будет запускаться заставка
  VideoFolder := HmsFindMediaFolder(mfVideoCollectionsItemID, 'Test');
  //VideoFolder := HmsFindMediaFolder(mfVideoPodcastsFolderItemID, '-Showroom');
  
  if VideoFolder<> nil then begin
    n := DateTimeToTimeStamp1970(Now, false) - StrToIntDef(VideoFolder[mpiTimeStart], 0);
    if n < 30 then Exit; // Если прошло менее 30 сек - выходим, не срабатываем.
  end;
  ...

Т.е. если прошло менее 30 сек, скрипт №2 не будет срабатывать.
Но тут нужно чтобы он сработал после 30 секунд. Нужно проверить, может быть он после 30 секунд и не сработает - устройства уже послали событие "конец показа".

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

Поэтому, думаю, код запуска заставок должен срабатывать не по событию, всё-таки, а по таймеру после срабатывания группового запуска видео.
Это можно сделать в одном скрипте.

+ Скрипт запуска видео и заставок
Const VideosDuration = 30; // Длительность видео по-умолчанию (через сколько секунд будут включены заставки)

///////////////////////////////////////////////////////////////////////////////
// Отображение заставок (фото) на устройствах (вызывается таймером "Timer4GroupNoOne")
Procedure ShowPictures();
Var
  MediaFolder, MediaItem: THmsScriptMediaItem; n: Integer;
Begin
  HmsExecuteByTimer("Timer4GroupNoOne", "", 0); // Сброс таймера
  //HmsLogMessage(1, "Сработала функция отображения заставок");
  
  // Находим папку с фото, которые будут отображаться на разных устройствах
  MediaFolder := HmsFindMediaFolder(mfImageAlbumsItemID, '-Showroom');
  
  if (MediaFolder <> nil) and MediaFolder.HasChildItems then begin
    // В цикле обходим все картинки и запускаем их на показ устройствам
    // по MAC-адресу, указанному в комментариях к картинке
    for n := 0 to MediaFolder.ChildCount - 1 do begin
      MediaItem := MediaFolder.ChildItems[n];
      HmsPlayToDevice(MediaItem, MediaItem[mpiComment], false)
    end;
    
  end;
  
End;

///////////////////////////////////////////////////////////////////////////////
//                     Г Л А В Н А Я   П Р О Ц Е Д У Р А                     //
Var
  MediaFolder, MediaItem: THmsScriptMediaItem; nCounter, nTime: Integer;
Begin
  // Находим папку с видео, которые мы будем запускать
  //MediaFolder := HmsFindMediaFolder(mfVideoPodcastsFolderItemID, '-Showroom');
  MediaFolder := HmsFindMediaFolder(mfVideoCollectionsItemID, 'Test');
  if (MediaFolder <> nil) and MediaFolder.HasChildItems then Begin
    nCounter  := MediaFolder[mpiTrack];                           // Получаем значение счётчика очерёдности
    MediaItem := MediaFolder.ChildItems[nCounter];                // Получаем элемент очередного видео
    HmsPlayToGroup(MediaItem, 'GroupNoOne', false);               // Запуск воспроизведения очередного видео из папки
    nCounter := nCounter + 1;                                     // Увеличиваем счётчик
    if nCounter >= MediaFolder.ChildCount then nCounter := 0;     // Если значение счётчика больше количества видео - начинаем сначала
    MediaFolder[mpiTrack] := nCounter;                            // Запоминаем значение счётчика в свойствах папки
    nTime := HmsTimeConvert(MediaItem[mpiTimeLength]);            // Получаем длительность видео в секундах
    if nTime = 0 then nTime := VideosDuration;                    // Если длительности видео нет, то по-умолчанию 30 сек
    HmsExecuteByTimer("Timer4GroupNoOne", "ShowPictures", nTime); // Запускаем таймер, который через n секунд вызовет функцию "ShowPictures"
  End;
End.

При таком случае скрипт нужен только один и не нужно выставлять скрипт на событие "После завершения воспроизведения медиа-ресурса" (очистить то поле).
А для этого скрипта просто настроить запуск по-расписанию.

При экспериментах с функцией HmsExecuteByTimer осторожней! При срабатывании данной функции, делается слепок данного скрипта и вызываемая функция хранится где-то в памяти, пока не будет сброшен таймер вызовом этой функции с ИД таймера и пустыми параметрами. Это значит, что просто отредактировав код вызываемой функции (например, там забыли вызвать сброс таймера), это никак не повлияет на периодический вызов функции и она всё также будет вызываться пока не будет исполнена новая команда вызова HmsExecuteByTimer с данным идентификатором.

Sony Bravia KDL-32CX523

5

Re: Возврат к воспроизведению после выполнения обработки по расписанию

Только сегодня добрался до этой задачи. Проверил, второй вариант отрабатывает замечательно. Единственное, что заставки могут по таймингу не совпадать. Но это решается клонированием скрипта и запуском каждого скрипта по своему расписанию.

Еще раз огромное спасибо за помощь!