Перехват и обработка декодированных кадров¶
Описание¶
При включенном транскодинге существует возможность перехватывать декодированные кадры опубликованного потока в формате YUV и изменять их содержимое попиксельно на стороне сервера. Кадр, в который были внесены изменения, будет закодирован и отправлен в выходной поток транскодера.
Реализация перехватчика¶
Для перехвата декодированных кадров необходимо разработать класс на языке Java, реализующий интерфейс IDecodedFrameInterceptor
. Функция этого класса frameDecoded()
будет получать декодированные кадры в формате YUV, например
TestInterceptor.java
// Package name should be strictly defined as com.flashphoner.frameInterceptor
package com.flashphoner.frameInterceptor;
// Import decoded frame interceptor interface
import com.flashphoner.sdk.media.IDecodedFrameInterceptor;
// Import YUV frame description
import com.flashphoner.sdk.media.YUVFrame;
/**
* Custom decoded frames interceptor implementation example
* The example daws a cross over the picture
*/
public class TestInterceptor implements IDecodedFrameInterceptor {
// Constants to parse pixel
private final int Y = 0;
private final int U = 1;
private final int V = 2;
// Dark colored pixel
private final byte[] DarkPixel = new byte []{42, -128, -128};
/**
* Function to handle decoded frame
* @param streamName - stream name
* @param frame - decoded YUV frame
*/
@Override
public void frameDecoded(String streamName, YUVFrame frame) {
// Get frame height
int frameHeight = frame.getHeight();
// Get frame width
int frameWidth = frame.getWidth();
// Declare cross lines padding
int PADDING = 4;
// Define frame center
int frameCenterX = frameWidth / 2;
int frameCenterY = frameHeight / 2;
// Define vertical line bounds
int leftBound = frameCenterX - PADDING;
int rightBound = frameCenterX + PADDING;
// Define horizontal line bounds
int topBound = frameCenterY - PADDING;
int bottomBound = frameCenterY + PADDING;
// Walk through the frame pixels and draw a cross
for (int x = 0; x < frameWidth; x++) {
for (int y = 0; y < frameHeight; y++) {
if (validateCoord(x, leftBound, rightBound) || validateCoord(y, topBound, bottomBound)) {
// Read the pixel
byte[] pixel = frame.readPixel(x, y);
// Modify the pixel
pixel[Y] = DarkPixel[Y];
pixel[U] = DarkPixel[U];
pixel[V] = DarkPixel[V];
// Write the pixel back
frame.writePixel(x, y, pixel);
}
}
}
}
/**
* Helper function to validate pixel drawing
* @param coord - pixel coordinate
* @param low - low coordinate bound
* @param high - high coordinate bound
* @return true if coordinate is valid
*/
private boolean validateCoord(int coord, int low, int high) {
return (coord > low && coord < high);
}
}
Затем следует скомпилировать класс в байт-код. Для этого создаем дерево каталогов, соответствующее названию пакета написанного класса
и выполняем команду
javac -cp /usr/local/FlashphonerWebCallServer/lib/wcs-core.jar ./com/flashphoner/frameInterceptor/TestInterceptor.java
Теперь упакуем скомпилированный код в jar-файл
и скопируем его в каталог, где размещены библиотеки WCS сервера
Для того, чтобы использовать разработанный класс, необходимо указать имя его пакета в настройке в файле flashphoner.properties
и перезапустить WCS.
Отдельный каталог для собственных Java библиотек¶
Начиная со сборки 5.2.1512, Java библиотеки (jar файлы) должны помещаться в каталог /usr/local/FlashphonerWebCallServer/lib/custom
Этот каталог сохраняется при дальнейших обновлениях сервера к более новым сборкам. Таким образом, нет необходимости снова копировать jar файлы после установки обновления.
Тестирование¶
-
Опубликуйте поток в примере Two Way Streaming
https://test1.flashphoner.com:8444/client2/examples/demo/streaming/two_way_streaming/two_way_streaming.html
,
гдеtest1.flashphoner.com
- адрес WCS сервера
-
Проиграйте поток в примере Player с указанием разрешения, чтобы включился транскодинг, например
https://test1.flashphoner.com:8444/client2/examples/demo/streaming/player/player.html?resolution=320x240
,
гдеtest1.flashphoner.com
- адрес WCS сервера
На изображении будут видны измененные пиксели.
Управление перехватчиками по REST API¶
В сборке 5.2.2055 добавлена возможность управления перехватчиками декодированных кадров по REST API
REST-запрос должен быть HTTP/HTTPS POST запросом в таком виде:
- HTTP:
http://streaming.flashphoner.com:8081/rest-api/video_interceptor/set
- HTTPS:
https://streaming.flashphoner.com:8444/rest-api/video_interceptor/set
Здесь:
streaming.flashphoner.com
- адрес WCS-сервера8081
- стандартный REST / HTTP порт WCS-сервера8444
- стандартный HTTPS портrest-api
- обязательный префикс/video_interceptor/set
- используемый REST-вызов
REST методы и статусы ответа¶
/video_interceptor/set¶
Назначить потоку обработчик декодированных фреймов. Обработчик начнет работать, как только поток начнет декодироваться, например, будет добавлен в микшер. На один поток может быть назначен один обработчик
Request example¶
POST /rest-api/video_interceptor/set HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"streamName":"stream1",
"className":"com.flashphoner.frameInterceptor.TestInterceptor"
}
Response example¶
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
500 | Internal server error |
/video_interceptor/find_all¶
Найти все назначенные обработчики
Request example¶
POST /rest-api/video_interceptor/find_all HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"streamName":"stream1",
"className":"com.flashphoner.frameInterceptor.TestInterceptor"
}
Response example¶
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
[
{
"hashcode":21982654,
"className":"com.flashphoner.frameInterceptor.TestInterceptor",
"processedFrames":169,
"streamName":"stream1",
"status":"PROCESSING"
}
]
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
/video_interceptor/remove¶
Удалить обработчик с указанного потока
Request example¶
POST /rest-api/video_interceptor/remove HTTP/1.1
Host: localhost:8081
Content-Type: application/json
{
"streamName":"stream1"
}
Response example¶
Return codes¶
Code | Reason |
---|---|
200 | OK |
404 | Not found |
Параметры¶
Параметр | Описание | Пример |
---|---|---|
streamName | Имя опубликованного потока | "streamName":"stream1" |
className | Имя класса перехватчика | "className":"com.flashphoner.frameInterceptor.TestInterceptor" |
hashcode | Идентификатор объекта перехватчика | "hashcode":21982654 |
status | Текущий статус перехватчика | "status":"PROCESSING" |
processedFrames | Количество обработанных кадров | "processedFrames":169 |
Перехватчик может находиться в одном из следующих состояний:
WAITING
- перехватчик ожидает, когда поток начнет декодироватьсяPROCESSING
- перехватчик получает декодированные кадры и обрабатывает ихUNSUPPORTED
- перехват не поддерживается (например, для потоков, декодированных на GPU)