🌐 한국어

    영상 재생 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&lt;N>-render-recording-path에 지정된 경로에 녹화 영상을 저장합니다.
    channel<N>-render-recording-path
     
    channel&lt;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: 실패

    구조체#

    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["denoise-enabled"]="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["denoise-enabled"]="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;
    }