영상 재생 API

미디어 플레이어 API는 oasis::ui 네임스페이스 범주에서 호출됩니다.

미디어 플레이어는 MediaObserver로 유도된 사용자 정의 observer 객체를 통하여 진행 상황이나 재생중 발생하는 오류 등의 이벤트를 받을 수 있습니다.

헤더 파일

OasisPlayer.h

함수

PlayerRef createPlayer ( int32_t display_id , key_value_map_t & parameters )
OasisPlayer.h
Player 객체를 생성합니다.
매개변수
display_id  영상이 보여질 Dispaly ID를 지정합니다. "0" 값을 지정합니다.
parameters  Player 생성에 필요한 key-value map을 지정합니다.
리턴값
성공하면 Player 객체를 리턴하고, 실패하면 nullptr를 리턴합니다.

Player 생성에 필요한 key-value map은 아래와 같습니다.

기본값
필수
설명
snd-path
createAudioDevice에서 설정한 오디오 장치 경로입니다. 지정하지 않으면 소리가 출력되지 않습니다.
rotation
0
 
영상 회전 각도를 지정합니다. 0, 90, 270, 180 값중 하나를 지정합니다. 일괄적으로 회전을 지정할 경우 사용되며, channel<N>-rotation 키값으로 개별 영상 트랙의 회전 각도를 지정할 수 있습니다.
channel-count
재생 파일의 영상 트랙 개수입니다.
primary-channel
주 채널 번호를 지정합니다. 시작번호는 1입니다.

각 영상 트랙에 대한 key-value map 값은 각 키값 앞에 prefix로 channel<N>- 이 붙습니다. <N>은 1부터 시작하여 1씩 증가합니다.

기본값
필수
설명
channel<N>-track-id
재생 파일 영상의 트랙 순번입니다. AVI 파일의 경우, 0번 부터 시작되며, MP4 파일의 경우, 1번 부터 시작됩니다. 어느 경우든 순차적으로 영상 트랙이 지정됩니다.
channel<N>-visible
1
 
"1" 값이면 재생시 영상이 보이고, "0" 값이면 영상을 숨깁니다.
channel<N>-rotation
0
 
영상 회전 각도를 지정합니다. 0, 90, 270, 180 중 한 값을 지정합니다.
channel<N>-x
영상 화면의 좌측상단 x 좌표입니다. 디스플레이 영역에서 벗어나면 짤려서 보입니다.
channel<N>-y
영상 화면의 좌측상단 y 좌표입니다. 디스플레이 영역에서 벗어나면 짤려서 보입니다.
channel<N>-width
영상 화면의 너비입니다. 디스플레이 영역에서 벗어나면 짤려서 보입니다.
channel<N>-height
영상 화면의 높이입니다. 디스플레이 영역에서 벗어나면 짤려서 보입니다.
channel<N>-zorder
0
 
영상이 보이는 순서입니다. 높을 값일 수록 위에서 보입니다.
channel<N>-enable-adas
0
 
재생 시 ADAS를 적용할지 지정합니다. "1" 이면 ADAS를 적용합니다.
channel<N>-adas-inference-model-names
 
ADAS에 적용될 추론 모델이름 목록을 지정합니다. 목록은 콤마(,)로 분리된 문자열입니다. 추론 모델이 추론 엔진에 없을 경우, ADAS는 적용되지 않습니다.
channel<N>-render-enable-recording
0
 
재생 중 화면에 보여지는 영상을 녹화할지 지정합니다. "1" 이면 channel<N>-render-recording-path에 지정된 경로에 녹화 영상을 저장합니다.
channel<N>-render-recording-path
 
channel<N>-render-enable-recording가 "1"일 경우, 녹화 영상이 저장될 경로입니다. 녹화 파일 확장자는 mp4만 지원합니다. mp4가 아닐 경우, 녹화하지 않습니다.
int32_t destroyPlayer ( const PlayerRef & player )
OasisPlayer.h
Player를 해제합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerStart ( const PlayerRef & player , const char * filepath , const std::shared_ptr<MediaObserver> & observer , void * user_data )
OasisPlayer.h
재생을 시작합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
filepath  AVI 파일이나 MP4 파일 경로입니다.
observer  재생시 발생한 이벤트를 받을 MediaObserver에서 유도된 사용자 정의 observer 객체입니다.
user_data  observer의 user_data 매개변수로 전달된 사용자 정의 데이터입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerStop ( const PlayerRef & player )
OasisPlayer.h
재생을 중지합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerResume ( const PlayerRef & player )
OasisPlayer.h
재생을 재시작합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerPause ( const PlayerRef & player )
OasisPlayer.h
재생을 일시 멈춥니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerSeek ( const PlayerRef & player , int64_t timestampUs )
OasisPlayer.h
재생 시 특정 위치로 이동합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
timestampUs  특정 위치의 timestamp 입니다. 마이크로초 단위입니다.
리턴값
  • 0: 성공
  • -1: 실패
int64_t playerGetDuraitonUs ( const PlayerRef & player )
OasisPlayer.h
총 재생 시간를 리턴합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
총 재생 시간 입니다. 마이크로초 단위입니다.
int64_t playerGetCurrentTimestampUs ( const PlayerRef & player )
OasisPlayer.h
현재 재생 timestmap를 리턴합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
현재 재생 timestamp 입니다. 마이크로초 단위입니다.
bool playerIsRunning ( const PlayerRef & player )
OasisPlayer.h
미디어플레이어가 동작 상태인지 확인합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
  • true: 동작 중입니다.
  • false: 중지 상태입니다.
bool playerIsPlaying ( const PlayerRef & player )
OasisPlayer.h
미디어플레이가 재생 중인지 확인합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
  • true: 재생 중입니다.
  • false: 재생 멈춤 상태입니다.
bool playerIsPaused ( const PlayerRef & player )
OasisPlayer.h
미디어플레이어가 현재 멈춤 상태인지 확인합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
리턴값
  • true: 재생 멈춤 상태니다.
  • false: 재생 멈춤 상태가 아닙니다. 재생 중입니다.
int32_t playerGetVideoTracks ( const PlayerRef & player , std::vector<MediaTrackInfo> & video_tracks )
OasisPlayer.h
영상 트랙 목록을 리턴합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
video_tracks  OUT 트랙 정보 목록입니다.
리턴값
트랙 개수를 리턴합니다. 영상 트랙이 없으면 0을 리턴합니다. 오류가 발생하면 -1을 리턴합니다.

MediaTrackInfo 정의는 아래 구조체 부분을 참고합니다.

MediaSourceRef playerGetVideoTrackSource ( const PlayerRef & player , int32_t track_id )
OasisPlayer.h
영상 트랙의 MediaSource를 리턴합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다. AVI는 0번부터, MP4는 1번부터 순차적으로 증가합니다.
리턴값
영상 트랙이 있을 경우, MediaSource 객체를 리턴하고, 없을 경우 nullptr을 리턴합니다.
int32_t playerAlign ( const PlayerRef & player , int32_t track_id , PositionType horz_position , PositionType vert_position )
OasisPlayer.h
영상 트랙이 보여질 위치를 변경합니다. 크기는 그대로 유지됩니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
horz_position  수평 위치를 지정합니다. left, center, right 중 하나 값을 지정합니다.
vert_position  수직 위치를 지정합니다. top, vcenter, bottom 중 하나 값을 지정합니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerSetPos ( const PlayerRef & player , int32_t track_id , int32_t x , int32_t y )
OasisPlayer.h
영상 트랙의 위치를 변경합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
x  영상 트랙의 x좌표입니다.
y  영상 트랙의 y좌표입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerSetSize ( const PlayerRef & player , int32_t track_id , int32_t width , int32_t height )
OasisPlayer.h
영상 트랙의 크기를 지정합니다. Display 크기를 벗어날 경우, 짤려서 보여집니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
width  영상 트랙의 가로 크기입니다.
height  영상 트랙의 세로 크기입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerSetRect ( const PlayerRef & player , int32_t track_id , int32_t left , int32_t top , int32_t width , int32_t height )
OasisPlayer.h
영상 트랙의 위치와 크기를 지정합니다. Display 크기를 벗어날 경우, 짤려서 보여집니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
left  영상 트랙의 x좌표입니다.
top  영상 트랙의 y좌표입니다.
width  영상 트랙의 가로 크기입니다.
height  영상 트랙의 세로 크기입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerSetZOrder ( const PlayerRef & player , int32_t track_id , int32_t zorder )
OasisPlayer.h
영상 트랙이 보여질 순서를 지정합니다. 값이 큰 영상이 앞에 보여집니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
zorder  영상 트랙의 순서입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerSetVisible ( const PlayerRef & player , int32_t track_id , bool show )
OasisPlayer.h
영상이 보여질 지를 지정합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
show  true이면 영상이 보여지고, false이면 영상을 보여지지 않습니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerIsVisible ( const PlayerRef & player , int32_t track_id )
OasisPlayer.h
영상 트랙이 현재 보여지는지 확인합니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
리턴값
  • true: 지정한 영상 트랙이 보이는 상태입니다.
  • false: 지정한 영상 트랙이 보이지 않는 상태입니다.
int32_t playerSetRotation ( const PlayerRef & player , int32_t track_id , int32_t rotation )
OasisPlayer.h
영상 트랙을 회전하여 보여줍니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
rotation  영상 트랙의 회전 각도입니다. 0, 90, 180, 270 중 하나 값을 지정합니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t playerSetZoom ( const PlayerRef & player , int32_t track_id , int32_t x , int32_t y , int32_t width , int32_t height )
OasisPlayer.h
영상 트랙을 확대 또는 축소하여 보여줍니다.
매개변수
player  createPlayer로 생성한 Player 객체입니다.
track_id  영상 트랙 ID입니다.
x  확대할 영역의 x좌표입니다.
y  확대할 영역의 y좌표입니다.
width  확대할 영역의 가로 크기입니다.
height  확대할 영역의 세로 크기입니다.
리턴값
  • 0: 성공
  • -1: 실패

구조체

struct MediaTrackInfo
Oasis.h
타입
이름
설명
int32_t
id
영상 트랙 ID입니다.
int32_t
width
영상 트랙의 가로 크기입니다.
int32_t
height
영상 트랙의 세로 크기입니다.

예제

아래는 녹화 파일의 영상 트랙 하나를 재생하는 미디어 플레이어 예입니다.

Oasis를 초기화 합니다.

#define OFFS_QUEUE_SIZE_KBYTES  (40*1024)
#define OFFS_CACHE_SIZE_KBYTES  (1024)
#define MEDIA_CACHE_SIZE_KBYTES (40*1024)


oasis::key_value_map_t parameters;

parameters["offs-qsize-max"] = std::to_string(OFFS_QUEUE_SIZE_KBYTES);
parameters["offs-overwrite-if-exist"] = "1";
parameters["offs-cache-size"] = std::to_string(OFFS_CACHE_SIZE_KBYTES);
parameters["media-cache-size"] = std::to_string(MEDIA_CACHE_SIZE_KBYTES);

if(oasis::initialize(parameters) < 0) {
    DLOG(DLOG_ERROR, "Oasis init failed\n");
    return -1;
}

오디오 출력(sink) 장치를 초기화 합니다.

    parameters.clear();

#if 0
#define SND_PATH "default"
#else
#define SND_PATH "hw:0,0"
#endif

parameters["types"]="sink";
parameters["path"]=SND_PATH;
parameters["always-on"]="0";
parameters["aec-disabled"]="1";
parameters["snd-input-channels"]="2";
parameters["snd-input-sample-size"]="16";
parameters["snd-input-sampling-duration-msec"]="40";
parameters["snd-input-sampling-rate"]="48000";

createAudioDevice(parameters);

디스프레이 장치를 초기화 합니다.

parameters.clear();

parameters["memory-type"] = "ion"; //cma
parameters["screen-width"] = "480";
parameters["screen-height"] = "320";

display::setup(parameters);

GUI를 설정합니다. 여기 예에서는 터치를 사용하지 않습니다.

parameters.clear();

parameters["system-font-size"] = "10";
parameters["system-font-path"] = "/mnt/sd/consola.ttf";
parameters["display-rotation"] = "0";
parameters["enable-touch"] = "0";

err = ui::setup(parameters);
if (err < 0) {
    DLOG(DLOG_ERROR, "Oasis ui::setup failed\n");
    return -1;
}

미디어 플레이어를 초기화 합니다.

parameters.clear();

// 기본 스크린 객체를 얻고 너비와 높이를 미디어플레이어에 적용합니다.
ui::ScreenRef screen = ui::getDefaultScreen();

int32_t screen_width = ui::screenWidth(screen);
int32_t screen_height = ui::screenHeight(screen);


// MediaObserver 에서 유도된 사용자 정의 객체를 생성합니다.
std::shared_ptr<MyPlayingObserver> observer = std::make_shared<MyPlayingObserver>();

// 필요할 경우 rotation과 snd-path 도 지정합니다. 
// snd-path는 오디오 장치 생성시 지정한 장치 경로이어야 합니다.
parameters["rotation"] = std::to_string(rotation);
parameters["snd-path"] = SND_PATH;
parameters["channel-count"] = "1";
parameters["primary-channel"] = "1";

// track-id가 '0'고 실제 파일의 첫 트랙 ID가 '1'이어도 순차적으로 할당됩니다.
parameters["channel1-track-id"] = "0";
parameters["channel1-visible"] = "1";
parameters["channel1-rotation"] = std::to_string(rotation);
// 재생 화면을 전체 스크린으로 지정합니다.
parameters["channel1-x"] = "0";
parameters["channel1-y"] = "0";
parameters["channel1-width"] = std::to_string(screen_width);
parameters["channel1-height"] = std::to_string(screen_height);
parameters["channel1-zorder"] = "0";

ui::PlayerRef player = ui::createPlayer(0, parameters);
// setup the player object
observer->player_ = player;

화면을 구성합니다. 최상위 Window 객체에 Fixed 레이아웃 컨테이너를 이용하고, 재생화면은 전체화면으로 설정합니다.

ui::WindowRef player_panel = ui::createWindow("Player1");

ui::FixedRef fixed_layout = ui::createFixed();
ui::containerAdd(player_panel, fixed_layout);

ui::setFixedSize(player, screen_width, screen_height);
ui::fixedPut(fixed_layout, player, 0, 0);
ui::screenAdd(screen, player_panel);

ui::setVisible(player_panel, true);

재생을 시작합니다.

err = ui::playerStart(player, file_path, observer, nullptr);

// 트랙 정보를 얻습니다.
std::vector<MediaTrackInfo> tracks;
ui::playerGetVideoTracks(player, tracks);

재생 중 10초 앞으로 재생 위치를 변경하는 예입니다.

if (ui::playerIsPlaying(player) || ui::playerIsPaused(player)) {
    int64_t duration = ui::playerGetDuraitonUs(player);
    int64_t timestamp = ui::playerGetCurrentTimestampUs(player);
    timestamp += 10*1000000ll;
    if(timestamp > duration-10*1000000ll) {
        timestamp = duration-10*1000000ll;
    }
    if(timestamp < 0) {
        timestamp = 0ll;
    }
    err = ui::playerSeek(player, timestamp);
}

재생 중 화면 위치와 크기를 변경하는 예입니다.

ui::playerSetRect(player, track_id, 100, 100, 320, 240)

재생을 중지합니다.

ui::playerStop(player);

아래는 전체 코드입니다.

#include "OasisAPI.h"
#include "OasisLog.h"
#include "OasisMedia.h"
#include "OasisUI.h"
#include "OasisFS.h"
#include "OasisUtil.h"
#include "OasisDisplay.h"
#include "OasisInference.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

#include <signal.h>

#include <thread>
#include <mutex>
#include <memory>
#include <condition_variable>


using namespace oasis;

#define OFFS_QUEUE_SIZE_KBYTES  (40*1024)
#define OFFS_CACHE_SIZE_KBYTES  (1024)
#define OFFS_WRITE_ALIGNMENT_BYTES  8192
#define MEDIA_CACHE_SIZE_KBYTES (40*1024)


static bool continue_playing = true;
void cancel_handler(int signum)
{
    continue_playing = false;
}


class MyPlayingObserver : public MediaObserver {
public:
    virtual void onStarted(void *user_data, const char *file_path) {
        fprintf(stdout, "Playing started, file path \"%s\"\n", file_path);
    }

    virtual void onStopped(void *user_data, media_report_reason_t reason, void *details) {
        fprintf(stdout, "Playing stopped, reason: %d\n", reason);
        continue_playing = false;
    }

    virtual void onFileChanged(void *user_data, const char *new_file_path) {}

    virtual void onError(void *user_data, media_report_reason_t reason, void *details) {
        fprintf(stdout, "Playing error, reason: %d (%s)\n", reason, mediaReportReasonString(reason));
        continue_playing = false;
    }

    virtual void onInfo(void *user_data, MediaInfo *info) {
        int h, m, s, u;
        parseUsec(info->durationUs, h, m, s, u);
        int h1, m1, s1, u1;
        parseUsec(info->currentTimestampUs, h1, m1, s1, u1);

        fprintf(stdout, "\rPlaying duration %02d:%02d:%02d.%06d, current %02d:%02d:%02d.%06d            ", h, m, s, u, h1, m1, s1, u1);
        fflush(stdout);
    }

    virtual void onPaused(void *user_data, MediaInfo *info) {
        fprintf(stdout, "Paused duration %lld usec, current %lld usec\n", info->durationUs, info->currentTimestampUs);
    }

    virtual void onResumed(void *user_data, MediaInfo *info) {
        fprintf(stdout, "Resumed duration %lld usec, current %lld usec\n", info->durationUs, info->currentTimestampUs);
    }

    ui::PlayerRef player_;
};

static bool isFile(const char *path)
{
    struct stat path_stat;
    stat(path, &path_stat);
    return S_ISREG(path_stat.st_mode);
}


void printUsage(const char *pgname)
{
    fprintf(stderr, "USAGE: %s [-r <rotation. 90, 270>] <mp4 or avi file-path>\n", pgname);
}


int main(int argc, char *argv[])
{
    int32_t err;
    int c;
    int32_t rotation = 0;
    std::vector<MediaTrackInfo> tracks;
    bool is_playing = false;
    int32_t track_id = -1;

    opterr = 0;
    while ((c = getopt(argc, argv, "r:h")) != -1) {
        switch (c) {
        case 'r':
            if(optarg == nullptr) {
                fprintf(stderr, "error: bad option argument '%c'\n", optopt);
                return -1;
            }
            rotation = atoi(optarg);
            if(rotation != 0 && rotation != 90 /*&& rotation != 180*/ && rotation != 270) {
                fprintf(stderr, "bad rotation: %d\n", rotation);
                return -1;
            }
            break;
        case 'h':
        default:
            printUsage(argv[0]);
            return -1;
        }
    }

    if(argc-optind < 1) {
        fprintf(stderr, "error: invalid or insufficient arguments (%d, %d)\n", argc, optind);
        printUsage(argv[0]);
        return -1;
    }

    if (access(argv[optind], F_OK) != 0) {
        fprintf(stderr, "\"%s\" not found\n", argv[optind]);
        return -1;
    }

    std::string file_path = argv[optind];
    if(!isFile(dir_path.c_str())) {
        fprintf(stderr, "\"%s\" not type of file\n", argv[optind]);
        return -1;
    }

    signal(SIGINT, cancel_handler);

    oasis::key_value_map_t parameters;

    ////////////////////////////////////////////////////////////////////////////////////////////
    // init

    parameters["offs-qsize-max"] = std::to_string(OFFS_QUEUE_SIZE_KBYTES);
    parameters["offs-overwrite-if-exist"] = "1";
    parameters["offs-cache-size"] = std::to_string(OFFS_CACHE_SIZE_KBYTES);
    parameters["media-cache-size"] = std::to_string(MEDIA_CACHE_SIZE_KBYTES);

    if(oasis::initialize(parameters) < 0) {
        DLOG(DLOG_ERROR, "Oasis init failed\n");
        return -1;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // audio
    parameters.clear();
#if 0
    #define SND_PATH "default"
#else
    #define SND_PATH "hw:0,0"
#endif

    parameters["types"]="sink";
    parameters["path"]=SND_PATH;
    parameters["always-on"]="0";
    parameters["aec-disabled"]="1";
    parameters["snd-input-channels"]="2";
    parameters["snd-input-sample-size"]="16";
    parameters["snd-input-sampling-duration-msec"]="40";
    parameters["snd-input-sampling-rate"]="48000";

    createAudioDevice(parameters);

    ////////////////////////////////////////////////////////////////////////////////////////////
    // display setup
    parameters.clear();

    parameters["memory-type"] = "ion"; //cma
    parameters["screen-width"] = "480";
    parameters["screen-height"] = "320";

    display::setup(parameters);


    //////////////////////////////////////////////////////////////////////////////////////////
    // ui setup
    parameters.clear();

    parameters["system-font-size"] = "10";
    parameters["system-font-path"] = "/mnt/sd/consola.ttf";
    parameters["display-rotation"] = "0";
    parameters["enable-touch"] = "0";

    err = ui::setup(parameters);
    if (err < 0) {
        DLOG(DLOG_ERROR, "Oasis ui::setup failed\n");
        return -1;
    }

    ui::ScreenRef screen = ui::getDefaultScreen();
    //ASSERT(screen != nullptr);

    int32_t screen_width = ui::screenWidth(screen);
    int32_t screen_height = ui::screenHeight(screen);

    //////////////////////////////////////////////////////////////////////////////////////////

    parameters.clear();

    parameters["rotation"] = std::to_string(rotation);


    /////////////////////////////////////////////////////////////////////////
    //player_panel
    ui::WindowRef player_panel = ui::createWindow("Player1");
    //ASSERT(player_panel != nullptr);

    ui::FixedRef fixed_layout = ui::createFixed();
    ui::containerAdd(player_panel, fixed_layout);

    std::shared_ptr<MyPlayingObserver> observer = std::make_shared<MyPlayingObserver>();

    parameters["snd-path"] = SND_PATH;

    parameters["channel-count"] = "1";
    parameters["primary-channel"] = "1";

    parameters["channel1-track-id"] = "0";
    parameters["channel1-visible"] = "1";
    parameters["channel1-rotation"] = std::to_string(rotation);
    parameters["channel1-x"] = "0";
    parameters["channel1-y"] = "0";
    parameters["channel1-width"] = std::to_string(screen_width);
    parameters["channel1-height"] = std::to_string(screen_height);
    parameters["channel1-zorder"] = "0";

    ui::PlayerRef player = ui::createPlayer(0, parameters);
    //setup the player object
    observer->player_ = player;

    ui::setFixedSize(player, screen_width, screen_height);
    ui::fixedPut(fixed_layout, player, 0, 0);
    ui::screenAdd(screen, player_panel);

    ui::setVisible(player_panel, true);

    err = ui::playerStart(player, file_path.c_str(), observer, nullptr);

    if(err != 0) {
        fprintf(stderr, "\"%s\" failed to play!\n", file_path.c_str());
    } else {
        is_playing = true;
        ui::playerGetVideoTracks(player, tracks);
        if(tracks.size() > 0) {
            track_id = tracks[0].id;
        }
        fprintf(stdout, "video track count %d, 1st track id %d\n", tracks.size(), track_id);
    }

    do {
        usleep(100000);
    } while (continue_playing);

    if(is_playing) {
        ui::playerStop(player);
    }

    err = ui::cleanup();

    oasis::finalize();

    return 0;
}