/*
 * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All rights reserved.
 *
 */

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <termio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include "mfw_gplay_core.h"
#include "playlist.h"
#include <string.h>

#include <signal.h>
#include <unistd.h>
#include <errno.h>
#define PRINT printf

typedef enum{
    FSL_PLAYER_REPEAT_NONE = 0,
    FSL_PLAYER_REPEAT_PLAYLIST = 1,
    FSL_PLAYER_REPEAT_CURRENT = 2,
    FSL_PLAYER_REPEAT_NUMBER = 3
} repeat_mode;

typedef struct{
    fsl_player_s32 repeat;
    fsl_player_s32 start;
    void * pl;
    PlayItem * current;

    fsl_player_u32  info_interval_in_sec;
    fsl_player_bool quiet;
    fsl_player_bool handle_buffering;
    fsl_player_bool handle_redirect;

} options;


options oopt = {0};
options * opt=&oopt;
static fsl_player_bool gbexit_display_thread = FSL_PLAYER_FALSE;
static fsl_player_bool gbexit_msg_thread = FSL_PLAYER_FALSE;
static fsl_player_bool gbdisplay = FSL_PLAYER_TRUE;
static fsl_player_bool gbexit_main = FSL_PLAYER_FALSE;
fsl_player* g_pplayer;


void alarm_signal(int signum)
{
    //printf("%s(): Time out: signum=%d\n", __FUNCTION__, signum);
}

fsl_player_ret_val player_exit(fsl_player_handle handle)
{
    fsl_player* pplayer = NULL;
    pplayer = (fsl_player*)handle;
    struct sigaction act;

    pplayer->klass->stop(pplayer);
    pplayer->klass->exit_message_loop(pplayer); // flush all messages left in the message queue.
    pplayer->klass->send_message_exit(pplayer); // send a exit message.
    gbexit_main = FSL_PLAYER_TRUE;
    gbexit_msg_thread = FSL_PLAYER_TRUE;
    //_close_nolock(STDIN_FILENO); // no use for linux, but effective for win32

    // Register alarm handler for alarm
    act.sa_handler = &alarm_signal;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGALRM, &act, NULL);
    // Set timer for 1 seconds
    alarm(1);

    printf("%s(): No more multimedia files, exit.\n", __FUNCTION__);

    return FSL_PLAYER_SUCCESS;
}

fsl_player_ret_val playlist_next(fsl_player_handle handle, options* opt)
{
    fsl_player* pplayer = NULL;
    pplayer = (fsl_player*)handle;
    fsl_player_drm_format drm_format;
    PlayItem * current = opt->current;
    PlayItem * next = getNextItem(current);

    switch( opt->repeat )
    {
        case FSL_PLAYER_REPEAT_NONE:
        {
            if( next )
            {
                opt->current = next;
                printf("%s\n", opt->current->name);
                pplayer->klass->stop(pplayer);
                pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
                pplayer->klass->play(pplayer);
            }
            else
            {
                //gcore_register_callback(gcore, NULL, NULL,0);
                // if not repeated mode or no next item, exit.
                //printf("%s(): No more multimedia files, exit.\n", __FUNCTION__);
                //player_exit(pplayer);
            }
            break;
        }
        case FSL_PLAYER_REPEAT_PLAYLIST:
        {
            if( next )
            {
                opt->current = next;
                printf("%s\n", opt->current->name);
                pplayer->klass->stop(pplayer);
                pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
                pplayer->klass->play(pplayer);
            }
            else
            {
                next = getFirstItem(opt->pl);
                opt->current = next;
                pplayer->klass->stop(pplayer);
                pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
                pplayer->klass->play(pplayer);
            }
            break;
        }
        case FSL_PLAYER_REPEAT_CURRENT:
        {
            pplayer->klass->stop(pplayer);
            //pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
            pplayer->klass->play(pplayer);
            break;
        }
        default:
        {
            break;
        }
    }
    return FSL_PLAYER_SUCCESS;
}

fsl_player_ret_val playlist_previous(fsl_player_handle handle, options* opt)
{
    fsl_player* pplayer = NULL;
    pplayer = (fsl_player*)handle;
    fsl_player_drm_format drm_format;
    PlayItem * current = opt->current;
    PlayItem * next = getPrevItem(current);

    if(next)
    {
        opt->current = next;
        printf("%s\n", opt->current->name);
        pplayer->klass->stop(pplayer);
        pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
        pplayer->klass->play(pplayer);
    }
    switch( opt->repeat )
    {
        case FSL_PLAYER_REPEAT_NONE:
        {
            if( next )
            {
                opt->current = next;
                printf("%s\n", opt->current->name);
                pplayer->klass->stop(pplayer);
                pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
                pplayer->klass->play(pplayer);
            }
            else
            {
                //gcore_register_callback(gcore, NULL, NULL,0);
                // if not repeated mode or no next item, exit.
                //printf("%s(): No more multimedia files, exit.\n", __FUNCTION__);
                //player_exit(pplayer);
            }
            break;
        }
        case FSL_PLAYER_REPEAT_PLAYLIST:
        {
            if( next )
            {
                opt->current = next;
                printf("%s\n", opt->current->name);
                pplayer->klass->stop(pplayer);
                pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
                pplayer->klass->play(pplayer);
            }
            else
            {
                next = getLastItem(opt->pl);
                opt->current = next;
                pplayer->klass->stop(pplayer);
                pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
                pplayer->klass->play(pplayer);
            }
            break;
        }
        case FSL_PLAYER_REPEAT_CURRENT:
        {
            pplayer->klass->stop(pplayer);
            //pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
            pplayer->klass->play(pplayer);
            break;
        }
        default:
        {
            break;
        }
    }
    return FSL_PLAYER_SUCCESS;
}

fsl_player_s32 parse_options(fsl_player_config* pconfig, options * opt, fsl_player_s32 argc, fsl_player_s8* argv[])
{
    fsl_player_s32 ret = -1;
    fsl_player_s32 i;
    fsl_player_s32 parseindex = 0;

    opt->pl = createPlayList(NULL);
    if (opt->pl==NULL){
        printf("Can not create Playlist!!\n");
        goto err;
    }



    for (i=1;i<argc;i++){
        if (strlen(argv[i])) {
            if (argv[i][0]=='-'){
                if ((strcmp(argv[i], "-h")==0)||(strcmp(argv[i], "--help")==0)){
                    printf("Usage of command line player:\n");
                    printf("    %s file_list\n", argv[0]);
                    ret = 1;
                    goto err;
                }

                if ((strcmp(argv[i], "--playbin")==0)){
                    pconfig->playbin_version = 1;
                    continue;
                }

                if (strcmp(argv[i], "--quiet")==0){
                    opt->info_interval_in_sec = 0;
                    parseindex=0;
                    continue;
                }

                if ((strcmp(argv[i], "-r")==0)||(strcmp(argv[i], "--repeat")==0)){
                    opt->repeat = FSL_PLAYER_REPEAT_PLAYLIST;
                    parseindex=0;
                    continue;
                }

                if ((strcmp(argv[i], "-p")==0)||(strcmp(argv[i], "--playback")==0)){
                    opt->start=1;
                    parseindex=0;
                    continue;
                }
                if ((strcmp(argv[i], "--video-sink")==0)){
                    parseindex = 1;
                    continue;
                }

                if ((strcmp(argv[i], "--video-sink")==0)){
                    parseindex = 1;
                    continue;
                }


                if ((strcmp(argv[i], "--info-interval")==0)){
                    parseindex = 2;
                    continue;
                }

                if ((strcmp(argv[i], "--handle-buffering")==0)){
                    parseindex = 0;
                    opt->handle_buffering = 1;
                    pconfig->features &= (~GPLAYCORE_FEATURE_AUTO_BUFFERING);
                    continue;
                }


                if ((strcmp(argv[i], "--handle-redirect")==0)){
                    parseindex = 0;
                    opt->handle_redirect= 1;
                    pconfig->features &= (~ GPLAYCORE_FEATURE_AUTO_REDIRECT_URI);
                    continue;
                }


                parseindex=0;
                continue;
            }else{

                switch (parseindex){
                    case 1:
                        pconfig->video_sink_name= argv[i];
                    break;
                    case 2:
                        opt->info_interval_in_sec = atoi(argv[i]);
                    break;
                    default:
                        addItemAtTail(opt->pl, argv[i],0);
                    break;
                }
                parseindex=0;
                continue;
            }
        }

    }

    opt->current=getFirstItem(opt->pl);
    if (opt->current==NULL){
        printf("NO File specified!!\n");
        goto err;
    }

    ret = 0;
    return ret;

err:
    if (opt->pl){
        destroyPlayList(opt->pl);
        opt->pl=NULL;
    }
    return ret;
}

void print_help(fsl_player_handle handle)
{
    fsl_player_s8* str_version = NULL;
    fsl_player* pplayer = (fsl_player*)handle;
    pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_VERSION, (void*)(&str_version));
    PRINT("\n%s\n", (str_version?str_version:"FSL_PLAYER_UNKNOWN_VERSION"));
    PRINT("\t[h]display the operation Help\n");
	PRINT("\t[p]Play\n");
    PRINT("\t[s]Stop\n");
	PRINT("\t[e]Seek\n");
    PRINT("\t[a]Pause when playing, play when paused\n");

    PRINT("\t[v]Volume\n");
    PRINT("\t[m]Switch to mute or not\n");
    PRINT("\t[>]Play next file\n");
    PRINT("\t[<]Play previous file\n");
    PRINT("\t[r]Switch to repeated mode or not\n");
//    PRINT("\t[n]Get the current video snapshot while playing\n");
//    PRINT("\t[o]Set video output mode(LCD,NTSC,PAL,LCD&NTSC,LCD&PAL)\n");
//    PRINT("\t[d]Select the audio track\n");
//    PRINT("\t[b]Select the subtitle\n");
    PRINT("\t[f]Set full screen or not\n");
    PRINT("\t[z]resize the width and height\n");
    PRINT("\t[t]Rotate\n");

//    PRINT("\t[c]playing direction and speed control\n");
    PRINT("\t[i]Display the metadata\n");
    PRINT("\t[x]eXit\n");
}

void print_metadata(fsl_player_handle handle)
{
    fsl_player* pplayer = (fsl_player*)handle;
    fsl_player_u64 duration=0;
    fsl_player_metadata metadata;
    pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_METADATA, (void*)(&metadata));
    pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_DURATION, (void*)(&duration));

    PRINT("\nMetadata of File: %s\n", metadata.currentfilename);
    PRINT("\tTitle: %s\n", metadata.title);
    PRINT("\tAritist: %s\n", metadata.artist);
    PRINT("\tAlbum: %s\n", metadata.album);
    PRINT("\tYear: %s\n", metadata.year);
    PRINT("\tGenre: %s\n", metadata.genre);
    PRINT("\tDuration: %d seconds\n", (fsl_player_s32)(duration/1000000000));
    PRINT("Video:\n");
    PRINT("\tWidth: %d\n", metadata.width);
    PRINT("\tHeight: %d\n", metadata.height);
    PRINT("\tFrame Rate: %d\n", metadata.framerate);
    PRINT("\tBitrate: %d\n", metadata.videobitrate);
    PRINT("\tCodec: %s\n", metadata.videocodec);
    PRINT("Audio:\n");
    PRINT("\tChannels: %d\n", metadata.channels);
    PRINT("\tSample Rate: %d\n", metadata.samplerate);
    PRINT("\tBitrate: %d\n", metadata.audiobitrate);
    PRINT("\tCodec: %s\n", metadata.audiocodec);
    return;
}

fsl_player_s32 display_thread_fun(fsl_player_handle handle)
{
    fsl_player* pplayer = (fsl_player*)handle;
    fsl_player_s8 str_player_state[FSL_PLAYER_STATUS_NUMBER][20] = {"Stopped  ", "Paused   ", "Playing  ", "FF ", "SF ", "FB"};
    fsl_player_s8 str_repeated_mode[FSL_PLAYER_REPEAT_NUMBER][20] = {"", "(List Repeated)", "(Current Repeated)"};
    while(1)
    {
        if( FSL_PLAYER_TRUE == gbexit_display_thread )
        {
            return 0;
        }
        if( FSL_PLAYER_TRUE == gbdisplay )
        {
            fsl_player_s8 str_player_state_rate[16];
            fsl_player_s8 str_volume[16];
            fsl_player_s8* prepeated_mode = &(str_repeated_mode[opt->repeat][0]);
            fsl_player_u64 hour, minute, second;
            fsl_player_u64 hour_d, minute_d, second_d;
            fsl_player_u64 duration=0;
            fsl_player_u64 elapsed=0;
            fsl_player_state player_state = FSL_PLAYER_STATUS_STOPPED;
            double playback_rate = 0.0;
            fsl_player_bool bmute = 0;
            double volume = 0.0;
            fsl_player_u32 total_frames = 0;
            pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_DURATION, (void*)(&duration));
            pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_ELAPSED, (void*)(&elapsed));
            pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_PLAYER_STATE, (void*)(&player_state));
            pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_PLAYBACK_RATE, (void*)(&playback_rate));
            pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_MUTE, (void*)(&bmute));
            pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_VOLUME, (void*)(&volume));
            pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_TOTAL_FRAMES, (void*)(&total_frames));

            hour = (elapsed/ (fsl_player_u64)3600000000000);
            minute = (elapsed / (fsl_player_u64)60000000000) - (hour * 60);
            second = (elapsed / 1000000000) - (hour * 3600) - (minute * 60);
            hour_d = (duration/ (fsl_player_u64)3600000000000);
            minute_d = (duration / (fsl_player_u64)60000000000) - (hour_d * 60);
            second_d = (duration / 1000000000) - (hour_d * 3600) - (minute_d * 60);
            switch( player_state )
            {
                case FSL_PLAYER_STATUS_STOPPED:
                    sprintf(str_player_state_rate, "%s", str_player_state[player_state]);
                    break;
                case FSL_PLAYER_STATUS_PAUSED:
                    sprintf(str_player_state_rate, "%s", str_player_state[player_state]);
                    break;
                case FSL_PLAYER_STATUS_PLAYING:
                    sprintf(str_player_state_rate, "%s", str_player_state[player_state]);
                    break;
                case FSL_PLAYER_STATUS_FASTFORWARD:
                    sprintf(str_player_state_rate, "%s(%1.1fX)", str_player_state[player_state], playback_rate);
                    break;
                case FSL_PLAYER_STATUS_SLOWFORWARD:
                    sprintf(str_player_state_rate, "%s(%1.1fX)", str_player_state[player_state], playback_rate);
                    break;
                case FSL_PLAYER_STATUS_FASTBACKWARD:
                    sprintf(str_player_state_rate, "%s(%1.1fX)", str_player_state[player_state], playback_rate);
                    break;
                default:
                    break;
            }
            if( bmute )
            {
                sprintf(str_volume, "%s", "MUTE  ");
            }
            else
            {
                sprintf(str_volume, "Vol=%02d", (fsl_player_s32)(volume));
            }
            /* Get the real fps value */
            if ((hour*3600+minute*60+second) > 0 )
                printf("\r[%s%s][%s][%02d:%02d:%02d/%02d:%02d:%02d][fps:%.0f]",
                           str_player_state_rate/*str_player_state[player_state]*/,prepeated_mode/*(brepeated?"(Repeated)":"")*/, str_volume,
                           (fsl_player_s32)hour, (fsl_player_s32)minute, (fsl_player_s32)second,
                           (fsl_player_s32)hour_d, (fsl_player_s32)minute_d, (fsl_player_s32)second_d,
                           (float)(total_frames/(hour*3600+minute*60+second)));
            else
                printf("\r[%s%s][%s][%02d:%02d:%02d/%02d:%02d:%02d][fps:%.0f]",
                           str_player_state_rate/*str_player_state[player_state]*/,prepeated_mode/*(brepeated?"(Repeated)":"")*/, str_volume,
                           (fsl_player_s32)hour, (fsl_player_s32)minute, (fsl_player_s32)second,
                           (fsl_player_s32)hour_d, (fsl_player_s32)minute_d, (fsl_player_s32)second_d,
                           0);

            fflush (stdout);
        }
		FSL_PLAYER_SLEEP(opt->info_interval_in_sec*1000);
    }
    return 0;
}

fsl_player_s32 msg_thread_fun(fsl_player_handle handle)
{
    fsl_player* pplayer = (fsl_player*)handle;
    fsl_player_ui_msg * msg;

    while(1)
    {
        if( FSL_PLAYER_TRUE == gbexit_msg_thread )
        {
            return 0;
        }

        msg = NULL;
        if( FSL_PLAYER_SUCCESS == pplayer->klass->wait_message( handle, &msg, FSL_PLAYER_FOREVER) )
        {
            switch( msg->msg_id )
            {
                case FSL_PLAYER_UI_MSG_EOS:
                {
                    printf("FSL_PLAYER_UI_MSG_EOS\n");
                    pplayer->klass->stop(handle);
                    // Wait until eos message has been processed completely. Fix the bug of play/stop hang problem.
                    pplayer->klass->post_eos_semaphore(handle);
                    //printf("\nmsg_thread_fun:=======================================================\n");
                    if( (FSL_PLAYER_REPEAT_NONE==opt->repeat) && (NULL==getNextItem(opt->current)) )
                    {
                        player_exit(handle);
                    }
                    else
                    {
                        playlist_next(handle, opt);
                    }
                    fsl_player_ui_msg_free(msg);
                    break;
                }
                case FSL_PLAYER_UI_MSG_EXIT:
                {
                    printf("FSL_PLAYER_UI_MSG_EXIT\n");
                    fsl_player_ui_msg_free(msg);
                    return 0;
                }
                case FSL_PLAYER_UI_MSG_INTERNAL_ERROR:
                {
                    printf("FSL_PLAYER_UI_MSG_INTERNAL_ERROR: internal error message received.\n");
                    fsl_player_ui_msg_free(msg);
                    player_exit(handle);
                    return 0;
                }
                case FSL_PLAYER_UI_MSG_BUFFERING:
                {
                    fsl_player_ui_msg_body_buffering * pbody = (fsl_player_ui_msg_body_buffering *)(msg->msg_body);

                    if (opt->handle_buffering){
                        if (pbody->percent==0){
                            pplayer->klass->pause(pplayer);
                        }else if (pbody->percent>=100){
                            pplayer->klass->pause(pplayer);

                        }
                    }
                    fsl_player_ui_msg_free(msg);
                    break;
                 }
                default:
                {
                    fsl_player_ui_msg_free(msg);
                    break;
                }
            }


        }
    }

    return 0;
}

static struct termio term_backup;
static void kb_set_raw_term (fsl_player_s32 fd)
{
#if 0 // for convinience of test team.
    struct termio s;

    (void) ioctl (fd, TCGETA, &s);
    term_backup = s;

    s.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
    s.c_oflag |= (OPOST | ONLCR | TAB3);
    s.c_oflag &= ~(OCRNL | ONOCR | ONLRET);
    s.c_cc[VMIN] = 1;
    s.c_cc[VTIME] = 0;
    (void) ioctl (fd, TCSETAW, &s);
#endif
}

static void kb_restore_term (fsl_player_s32 fd)
{
#if 0 // for convinience of test team.
    struct termio s;
    s = term_backup;
    (void) ioctl (fd, TCSETAW, &s);
#endif
}

void eos_callback(void *data)
{
    fsl_player_bool brepeated = FSL_PLAYER_FALSE;
    fsl_player_handle player_handle = (fsl_player_handle)data;
    fsl_player* pplayer = (fsl_player*)player_handle;

    if( NULL == data )
    {
        return;
    }

    pplayer->klass->stop(pplayer);
    switch( opt->repeat )
    {
        case FSL_PLAYER_REPEAT_NONE:
        {
            break;
        }
        case FSL_PLAYER_REPEAT_PLAYLIST:
        {
            playlist_next(pplayer, opt);
            break;
        }
        case FSL_PLAYER_REPEAT_CURRENT:
        {
            pplayer->klass->play(pplayer);
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}
static void signal_handler(int sig)
{
    printf(" Aborted by signal Interrupt...\n");
    if(g_pplayer != NULL)
        player_exit(g_pplayer);
	exit(0);
}

int main(int argc,char *argv[])
{
    fsl_player_s8 sCommand[128];
    fsl_player_s8 uri_buffer[500];
    fsl_player_thread_t display_thread;
    fsl_player_thread_t msg_thread;
    fsl_player_ret_val ret_val = FSL_PLAYER_SUCCESS;
    fsl_player_handle player_handle = NULL;
    fsl_player* pplayer = NULL;
    fsl_player_drm_format drm_format;
    fsl_player_config config;
    fsl_player_s32 ret;
    fsl_player_s32 volume = 1;

    if( argc < 2 ) {
        printf("Usage of command line player:\n");
        printf("    %s file_list\n", argv[0]);
        goto bail;
    }

    // Default playbin.
    memset(&config, 0, sizeof(fsl_player_config));
    config.playbin_version = 2;
    config.api_version = GPLAYCORE_API_VERSION;
    config.features = (GPLAYCORE_FEATURE_AUTO_BUFFERING|GPLAYCORE_FEATURE_AUTO_REDIRECT_URI);
    opt->info_interval_in_sec = 1;

    ret = parse_options(&config, opt, argc, argv);
    if( ret )
    {
        return -1;
    }

    fsl_player_element_property property[1];

    property[0].type = ELEMENT_TYPE_PLAYBIN;
    property[0].property_type = ELEMENT_PROPERTY_TYPE_INT;
    property[0].property_name = "flags";
    property[0].value_int = 87; /* default+native_video */
    property[0].next = NULL;
    config.ele_properties = property;

    if ((config.playbin_version==1)&&(config.video_sink_name==NULL)){
        config.video_sink_name = "autovideosink";
    }

    player_handle = fsl_player_init(&config);
    if( NULL == player_handle )
    {
        PRINT("Failed: player_handle == NULL returned by fsl_player_init().\n");
        goto bail;
    }

    pplayer = (fsl_player*)player_handle;
    g_pplayer = pplayer;

    if (opt->info_interval_in_sec){
        FSL_PLAYER_CREATE_THREAD( &display_thread, display_thread_fun, player_handle );
    }
    FSL_PLAYER_CREATE_THREAD( &msg_thread, msg_thread_fun, player_handle );

    // Play the multimedia file directory after starting command line player.
    pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
    pplayer->klass->play(pplayer);

    // Print the help menu to let user know the operation.
    print_help(player_handle);

    kb_set_raw_term(STDIN_FILENO);

    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGABRT, signal_handler);

    while( FSL_PLAYER_FALSE == gbexit_main )
    {
        sCommand[0] = ' ';
        errno = 0;
        scanf("%s", sCommand);
        //read(STDIN_FILENO, sCommand, 1);
        if( EINTR == errno )
        {
            //printf("Timed out: EINTR == %d", errno);
        }
        switch( sCommand[0] )
        {
            case 'h': // display the operation Help.
                print_help(player_handle);
                break;

            case 'p': // Play.
                //fsl_player_set_media_location(player_handle, filename2uri(uri_buffer,argv[1]), &drm_format);
                pplayer->klass->set_media_location(pplayer, opt->current->name, &drm_format);
                pplayer->klass->play(pplayer);
                break;

            case 's': // Stop.
                pplayer->klass->stop(pplayer);
                break;

            case 'a': // pAuse when playing, play when paused.
                pplayer->klass->pause(pplayer);
                break;

            case 'e': // sEek.
            {
            #if 0
                fsl_player_u32 seek_point_sec = 0;
                fsl_player_u64 duration_ns = 0;
                fsl_player_u32 duration_sec = 0;
                pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_DURATION, (void*)(&duration_ns));
                duration_sec = duration_ns / 1000000000;
                PRINT("Set seek point between [0,%u] seconds:", duration_sec);
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%s",sCommand);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                seek_point_sec = atoi(sCommand);
                if( seek_point_sec<0 || seek_point_sec>duration_sec  )
                {
                    printf("Invalid seek point!\n");
                    break;
                }
                pplayer->klass->seek(pplayer, seek_point_sec*1000);
                break;
            #else
                fsl_player_u32 seek_point_sec = 0;
                fsl_player_u64 duration_ns = 0;
                fsl_player_u32 duration_sec = 0;
                fsl_player_u32 seek_portion = 0;
                fsl_player_u32 seek_mode = 0;
                pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_DURATION, (void*)(&duration_ns));
                duration_sec = duration_ns / 1000000000;
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                PRINT("Select seek mode[Fast seek:0,Accurate seek:1]:");
                scanf("%s",sCommand);
                seek_mode = atoi(sCommand);
                PRINT("Seek to percentage[0:100]:");
                scanf("%s",sCommand);
                seek_portion = atoi(sCommand);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                if( seek_mode<0 || seek_mode>1  )
                {
                    printf("Invalid seek mode!\n");
                    break;
                }
                if( seek_portion<0 || seek_portion>100  )
                {
                    printf("Invalid seek point!\n");
                    break;
                }
                seek_point_sec = (fsl_player_u32)(seek_portion * duration_sec / 100);
                pplayer->klass->seek(pplayer, seek_point_sec*1000);
                break;
            #endif
            }

            case 'v': // Volume
            {
                double volume;
                PRINT("Set volume[0,10]:");
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%lf",&volume);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                if( (int)volume<0 || (int)volume>10  )
                {
                    printf("Invalid volume!\n");
                    break;
                }
                pplayer->klass->set_volume(pplayer, ((int)volume));
                break;
            }

            case '+': // Volume + 1
            {
                volume = volume + 1;
                if( volume > 10  )
                {
                    volume = 10;
                }
                pplayer->klass->set_volume(pplayer, ((int)volume));
                break;
            }

            case '-': // Volume - 1
            {
                volume = volume - 1;
                if( volume < 0  )
                {
                    volume = 0;
                }
                pplayer->klass->set_volume(pplayer, ((int)volume));
                break;
            }

            case 'm': // Switch to mute or not
                pplayer->klass->mute(pplayer);
                break;

            case '>': // Play next file
                printf("next\n");
                playlist_next(pplayer, opt);
                break;

            case '<': // Play previous file
                printf("previous\n");
                playlist_previous(pplayer, opt);
                break;

            case 'r': // Switch to repeated mode or not
            {
                fsl_player_s32 repeated_mode;
                PRINT("input repeated mode[0 for no repeated,1 for play list repeated,2 for current file repeated]:");
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%d",&repeated_mode);
                if( repeated_mode<0 || repeated_mode>2  )
                {
                    printf("Invalid repeated mode!\n");
                }
                else
                {
                    opt->repeat = repeated_mode;
                }
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                //pplayer->klass->repeat(pplayer);
                break;
            }
#if 1
            case 'n': // Get the current video snapshot while playing
                //pplayer->klass->snapshot(pplayer);
                break;

            case 'o': // Set video output mode(LCD,NTSC,PAL,LCD&NTSC,LCD&PAL)
            {
                fsl_player_s32 mode = 0;
                PRINT("Set video output mode(LCD:0,NTSC:1,PAL:2,LCD&NTSC:3,LCD&PAL:4):");
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%d",&mode);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                if( mode < 0 || mode >4 )
                {
                    printf("Invalid video output mode!\n");
                    break;
                }
                pplayer->klass->set_video_output(pplayer, mode);
                break;
            }

            case 'd': // Select the audio track
            {
                #if 1
                fsl_player_s32 audio_track_no = 0;
                fsl_player_s32 total_audio_no = 0;
                pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_TOTAL_AUDIO_NO, (void*)(&total_audio_no));
                PRINT("input audio track number[0,%d]:",total_audio_no-1);
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%d",&audio_track_no);
                if( audio_track_no < 0 || audio_track_no > total_audio_no-1 )
                {
                    printf("Invalid audio track!\n");
                }
                else
                {
                    pplayer->klass->select_audio_track(pplayer, audio_track_no);
                }
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                #endif
                break;
            }

            case 'b': // Select the subtitle
            {
                #if 1
                fsl_player_s32 subtitle_no = 0;
                fsl_player_s32 total_subtitle_no = 0;
                pplayer->klass->get_property(pplayer, FSL_PLAYER_PROPERTY_TOTAL_SUBTITLE_NO, (void*)(&total_subtitle_no));
                PRINT("input subtitle number[0,%d]:",total_subtitle_no-1);
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%d",&subtitle_no);
                if( subtitle_no < 0 || subtitle_no > total_subtitle_no-1 )
                {
                    printf("Invalid audio track!\n");
                }
                else
                {
                    pplayer->klass->select_subtitle(pplayer, subtitle_no);
                }
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                #endif
                break;
            }
#endif
            case 'f': // Set full screen or not
                pplayer->klass->full_screen(pplayer);
                break;

            case 'y': // Set display screen mode
            {
                fsl_player_s32 display_screen_mode = 0;
                PRINT("Input screen mode[Normal:0,FullScreen:1,Zoom:2]:");
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%d",&display_screen_mode);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                if( display_screen_mode < 0 || display_screen_mode > 2 )
                {
                    printf("Invalid display screen mode!\n");
                    break;
                }
                pplayer->klass->display_screen_mode(pplayer, display_screen_mode);
                break;
            }

            case 'z': // resize the width and height
            {
            #if 0
                fsl_player_display_parameter display_parameter;
                fsl_player_s32 width = 720;
                fsl_player_s32 height = 576;
                static fsl_player_s32 resize_index = 0;
                static float width_height_table[] = {0.25, 0.5, 0.75, 1, 2, 3, 4};
                static fsl_player_s32 offset_x_y_table[] = {600, 500, 400, 300, 200, 100, 0};
                if ((++resize_index)==6)
                    resize_index = 0;
                display_parameter.offsetx = 0;//offset_x_y_table[resize_index];
                display_parameter.offsety = 0;//offset_x_y_table[resize_index];
                display_parameter.disp_width = width_height_table[resize_index]*width;
                display_parameter.disp_height = width_height_table[resize_index]*height;
                pplayer->klass->resize(pplayer, display_parameter);
                break;
            #else
                fsl_player_display_parameter display_parameter;
                fsl_player_s8 sCommand_x[128];
                fsl_player_s8 sCommand_y[128];
                fsl_player_s8 sCommand_width[128];
                fsl_player_s8 sCommand_height[128];
                PRINT("Input [x,y,width,height]:");
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%s %s %s %s",sCommand_x,sCommand_y,sCommand_width,sCommand_height);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                display_parameter.offsetx = atoi(sCommand_x);//offset_x_y_table[resize_index];
                display_parameter.offsety = atoi(sCommand_y);//offset_x_y_table[resize_index];
                display_parameter.disp_width = atoi(sCommand_width);
                display_parameter.disp_height = atoi(sCommand_height);
                if( display_parameter.offsetx < 0 || display_parameter.offsety < 0
                    || display_parameter.disp_width <= 0 || display_parameter.disp_height <= 0 )
                {
                    printf("Invalid resize parameters!\n");
                    break;
                }
                pplayer->klass->resize(pplayer, display_parameter);
                break;
            #endif
            }

            case 't': // Rotate 90 degree every time
            {
                fsl_player_rotation rotate_value;
                PRINT("Set rotation(0,0),(4,-90),(3,180),(7,90):");
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%s",sCommand);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                rotate_value = (fsl_player_rotation)atoi(sCommand);
                if( (fsl_player_s32)rotate_value<0 || (fsl_player_s32)rotate_value>=(fsl_player_s32)FSL_PLAYER_ROTATION_NUMBER  )
                {
                    printf("Invalid rotation value=%d, rotation value should be between [0, %d]!\n", rotate_value, FSL_PLAYER_ROTATION_NUMBER-1);
                    break;
                }
                pplayer->klass->rotate(player_handle, rotate_value);
                break;
            }

            case 'c': // playing direction and speed Control.
            {
                double playback_rate;
                PRINT("Set playing speed[-8,-4,-2,0.125,0.25,0.5,1,2,4,8]:");
                kb_restore_term(STDIN_FILENO);
                gbdisplay = FSL_PLAYER_FALSE;
                scanf("%lf",&playback_rate);
                gbdisplay = FSL_PLAYER_TRUE;
                kb_set_raw_term(STDIN_FILENO);
                pplayer->klass->set_playback_rate(pplayer, playback_rate);
                break;
            }

            case 'i': // Display Metadata Information
            {
                print_metadata(player_handle);
                break;
            }

            case 'x': // eXit
            {
                //pplayer->klass->stop(pplayer);
                //pplayer->klass->exit_message_loop(pplayer); // flush all messages left in the message queue.
                //pplayer->klass->send_message_exit(pplayer); // send a exit message.
                //gbexit_main = FSL_PLAYER_TRUE;
                player_exit(pplayer);
                break;
            }

            case '*': // Sleep 5 seconds
            {
                FSL_PLAYER_SLEEP(5000);
                break;
            }

            case '#': // Sleep 10 seconds
            {
                FSL_PLAYER_SLEEP(10000);
                break;
            }

            default:
                //printf("Default: Nothing has been done!\n");
                break;
        }
    }
    kb_restore_term (STDIN_FILENO);

    gbexit_display_thread = FSL_PLAYER_TRUE;
    if (opt->info_interval_in_sec){
        FSL_PLAYER_THREAD_JOIN(display_thread);
    }
    FSL_PLAYER_THREAD_JOIN(msg_thread);

    fsl_player_deinit(player_handle);

bail:
    destroyPlayList(opt->pl);

    return 0;
}


