Skip to end of metadata
Go to start of metadata

Описание

При включенном транскодинге существует возможность перехватывать декодированные кадры опубликованного потока в формате 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 draws 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);
     }
}

Затем следует скомпилировать класс в байт-код. Для этого создаем дерево каталогов, соответствующее названию пакета написанного класса

mkdir -p com/flashphoner/frameInterceptor

и выполняем команду

javac -cp /usr/local/FlashphonerWebCallServer/lib/wcs-core.jar ./com/flashphoner/frameInterceptor/TestInterceptor.java

Теперь упакуем скомпилированный код в jar-файл

jar -cf testlayout.jar ./com/flashphoner/frameInterceptor/TestInterceptor.class

и скопируем его в каталог, где размещены библиотеки WCS сервера

cp testinterceptor.jar /usr/local/FlashphonerWebCallServer/lib

Для того, чтобы использовать разработанный класс, необходимо указать имя его пакета в настройке в файле flashphoner.properties

decoded_frame_interceptor=com.flashphoner.frameInterceptor.TestInterceptor

и перезапустить WCS.

Отдельный каталог для собственных Java библиотек

Начиная со сборки 5.2.1512, Java библиотеки (jar файлы) должны помещаться в каталог /usr/local/FlashphonerWebCallServer/lib/custom 

cp testlayout.jar /usr/local/FlashphonerWebCallServer/lib/custom

Этот каталог сохраняется при дальнейших обновлениях сервера к более новым сборкам. Таким образом, нет необходимости снова копировать jar файлы после установки обновления.

Тестирование

1. Опубликуйте поток в примере Two Way Streaming https://test1.flashphoner.com:8444/client2/examples/demo/streaming/two_way_streaming/two_way_streaming.html, где test1.flashphoner.com - адрес WCS сервера

2. Проиграйте поток в примере 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

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json

Return codes

Code

Reason

200OK
404Not found
500Internal 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

200OK
404Not 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

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json

Return codes

Code

Reason

200OK
404Not found

Параметры

Параметр

Описание

Пример

streamNameИмя опубликованного потока"streamName":"stream1" 
classNameИмя класса перехватчика"className":"com.flashphoner.frameInterceptor.TestInterceptor" 
hashcodeИдентификатор объекта перехватчика"hashcode":21982654 
statusТекущий статус перехватчика"status":"PROCESSING" 
processedFramesКоличество обработанных кадров"processedFrames":169 

Перехватчик может находиться в одном из следующих состояний:

  • WAITING - перехватчик ожидает, когда поток начнет декодироваться
  • PROCESSING - перехватчик получает декодированные кадры и обрабатывает их
  • UNSUPPORTED - перехват не поддерживается (например, для потоков, декодированных на GPU)


  • No labels