0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

全志R128基础组件开发指南—RTOS多媒体解码

冬至子 来源:丨budboool 作者:丨budboool 2023-10-10 16:28 次阅读

RTOS 多媒体解码

介绍 FreeRTOS 下如何使用 rtplayer 的接口来开发播放器应用程序,方便播放器开发人员快速正确地开发,以及播放器测试人员如何根据该文档对 rtplayer 播放器进行验证测试。

RTPLAYER 状态图

这张状态转换图清晰地描述了 rtlayer 的各个状态,也列举了主要的方法的调用时序,每种方法只能在一些特定的状态下使用,否则会出错。另外,只有在 Prepared、Started、Paused、Play‑backCompleted 这四种状态下可以进行 seekTo() 操作,并且 seekTo() 之后,状态不变。

image-20230512165957929.png

Idle 状态

Idle 状态:当调用 player_init() 创建一个 rtplayer 或者调用了其 reset() 方法时,rtplayer 处于 idle状态。

Initialized 状态

这个状态比较简单,调用 setDateSource_url() 方法就进入 Initialized 状态,表示此时要播放的文件已经设置好了

Preparing 状态

调用 prepare() 函数还没返回或者是调用 prepareAsync() 并且还没收到 RTPLAYER_NOTIFY_PREPARED 这个回调消息的时候就处于 Preparing 状态

Prepared 状态

调用 prepare() 函数已经返回或者是调用 prepareAsync() 并且已经收到 RTPLAYER_NOTIFY_PREPARED 这个回调消息之后的状态就处于 Prepared 状态。在这个状态下说明所有的资源都已经就绪了,调用 start() 函数就可以播放了。

Started 状态

rtplayer 一旦 prepare 完成,就可以调用 start() 方法,这样 rtplayer 就处于 Started 状态,这表明 rtplayer 正在播放文件过程中。可以使用 XPlayerIsPlaying() 测试 rtplayer 是否处于了 Started 状态。如果播放完毕,而又设置了循环播放,则 rtplayer 仍然会处于 Started 状态。

Paused 状态

Started 状态下可以调用 pause_l() 方法暂停 rtplayer,从而进入 Paused 状态,rtplayer 暂停后再次调用 start() 则可以继续 TPlayer 的播放,转到 Started 状态。

Stopped 状态

Started 或者 Paused 状态下均可调用 stop() 停止 rtplayer,而处于 Stop 状态的 rtplayer 要想重新播放,需要通过 prepareAsync() 和 prepare() 回到先前的 Prepared 状态重新开始才可以。

PlaybackCompleted 状态

文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并且会通过 RTPLAYER_NOTIFY_PLAYBACK_COMPLETE 这个消息回调给应用。此时可以调用 start() 方法重新从头播放文件,也可以 stop() 停止 rtplayer,或者也可以 seekTo() 来重新定位播放位置。

Error 状态

由于某种原因 rtplayer 出现了错误,就会进入该状态,并且会通过 RTPLAYER_NOTIFY_MEDIA_ERROR 这个消息回调给应用。如果 rtplayer 进入了 Error 状态,可以通过调用 reset() 来恢复,使得 rtplayer 重新返回到 Idle 状态。

End 状态

通过 plater_deinit() 的方法可以进入 End 状态,只要 rtplayer 不再被使用,就应当尽快将其 destroy 掉。

rtplayer 层接口

创建一个 RTPLAYER

函数原型

uint32_t player_init(void)

参数

返回值:

  • 成功返回 rtplayer 的指针,失败返回 NULL

销毁一个 RTPLAYER

函数原型

void player_deinit(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针

返回值:

设置 RTPLAYER 的消息回调函数

函数原型

void registerCallback(void* handle, void* userData, player_callback_t fn)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针
  • userData: 回调消息处理对象
  • fn: 回调消息处理函数指针,需要由应用实现

返回值:

创建完 rtplayer 播放器之后,就要调用该函数设置回调消息处理函数。

设置播放文件的 URL

可以是本地文件也可以是网络

函数原型

status_t setDataSource_url(void* handle,void* userData, const char * url, int id)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针
  • userData: 回调消息处理对象
  • url: 需要播放的文件的 url
  • id: 回调时使用的播放索引, 为 0 即可

返回值:

  • 成功返回 0,失败返回‑1 或错误码

解析文件头部信息,获取元数据

函数原型

status_t prepare(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;

返回值:

  • 成功返回 0,失败返回‑1 或错误码

异步解析文件头部信息,获取元数据

函数原型

status_t prepareAsync(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;

返回值:

  • 成功返回 0,失败返回‑1

该函数是非阻塞函数,需要等到 RTPLAYER_NOTIFY_P‑ REPARED 消息回调之后才能调 start() 函数进行播放,而且 start() 函数不能在回调函数中调用

开始播放

函数原型

status_t start(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;

返回值:

  • 成功返回 0,失败返回‑1

暂停播放

函数原型

status_t pause_l(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;

返回值:

  • 成功返回 0,失败返回‑1

停止播放

函数原型

status_t stop(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针

返回值:

  • 成功返回 0,失败返回‑1

重置播放器

函数原型

status_t reset(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;

返回值:

  • 成功返回 0,失败返回‑1

在任何状态下都可以调用该函数,每次播放不同的音频之前,都需要调用该函数重置播放器,另外,一般收到 RTPLAYER_NOTIFY_MEDIA_ERROR 这个消息的时候,也需要通过调用该函数来重置播放器。但是不能在回调函数中调用该函数,否则会出现死锁

跳播

函数原型

status_t seekTo(void* handle, int sec)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针
  • sec: 跳播的位置,单位是:s

返回值:

  • 成功返回 0,失败返回‑1

获取当前播放的位置

函数原型

status_t getCurrentPosition(void* handle, int * sec)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;
  • sec: 存放当前播放的位置值,单位:s

返回值:

  • 成功返回 0,失败返回‑1

获取播放的文件总时长

函数原型

status_t getDuration(void* handle, int * sec)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;
  • sec: 存储文件总时长,单位:s

返回值:

  • 成功返回 0,失败返回‑1

需要在 prepared 状态之后才可以调用该函数

获取播放的文件信息

函数原型

MediaInfo* getMediaInfo(void* handle)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;

返回值:

  • 成功返回 0,失败返回‑1

需要在 prepared 状态之后才可以调用该函数

设置循环播放模式

函数原型

status_t setLooping(void* handle, int loop)

参数:

  • handle: 通过 player_init() 函数创建的 rtplayer 指针;
  • loop:1 表示单曲循环,0 表示不会单曲循环

返回值:

  • 成功返回 0,失败返回‑1

XPlayer 层播放接口

创建一个 XPLAYER

函数原型

XPlayer* XPlayerCreate()

参数:

返回值:

  • 成功: XPlayer 指针; 失败: NULL

设置 XPLAYER 的回调通知

函数原型

int XPlayerSetNotifyCallback(XPlayer* p, XPlayerNotifyCallback notifier, void* pUserData)

参数:

  • P:通过 XPlayerCreate 创建的 Xplayer 指针
  • notifier:回调通知
  • pUserData:应用程序传下来的自定义数据

返回值:

  • 成功:XPlayer 指针;失败:NULL

Xplayer 将接收来自下层的回调通知,进行相应的操作

创建指向音频播放设备管理模块的指针,用于播放音频

函数原型

SoundCtrl* RTSoundDeviceCreate(int card)

参数:

  • card:声卡序号0:default;1:sw:audio1;2:sw:audio2;3:sw:audio3;4:sw:audio4;5:sw:audio5

返回值:

  • 成功:音频播放设备管理模块的指针;失败:NULL

创建指向音频播放设备管理模块的指针,用于播放音频

函数原型

int XPlayerSetDataSourceUrl(XPlayer* p, const char* pUrl, void* httpService, const CdxKeyedVectorT* pHeaders)

参数:

  • pUrl:url 地址
  • httpService:服务器信息
  • pHeaders:头文件信息

返回值:

  • 返回值: 成功:0;失败:‑1 或线程响应设置数据源命令的返回值或线程响应 xplayer prepare 命令的返回值

调用说明: 发送 SetDataSource 命令,获取需要播放的音频数据内容

将 XPLAYER 置为准备状态, 解析头部信息,获取元数据

函数原型

int XPlayerPrepare(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 Xplayer 指针

返回值:

  • 成功:线程响应异步 Prepare 命令的返回值;失败:NULL

该函数是阻塞函数,调用完返回之后就进入了 Prepared 状态,此时可调 XPlayerStart() 函数进行播放

将 XPLAYER 置为异步准备状态

函数原型

int XPlayerPrepareAsync(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

  • 成功:线程响应异步 Prepare 命令的返回值;失败:NULL

网络播放源一般采用 PrepareAsync,而不是 Prepare 命令,PrepareAsync 命令的返回值为 0 时说明响应成功,播放器准备工作已经完成可以开始播放,为‑1 时说明响应失败

将 XPLAYER 置为启动状态

函数原型

int XPlayerStart(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

  • 成功:线程响应 start 命令的返回值;失败:NULL

Start 命令的返回值为 0 时说明响应成功,为‑1 时说明响应失败

将 XPLAYER 置为暂停状态

函数原型

int XPlayerPause(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

  • 成功:线程响应 pause 命令的返回值;失败:NULL

在 XPlayer 处于 start 状态时可调用此接口,Pause 命令的返回值为 0 时说明响应成功,为‑1 时说明响应失败

将 XPLAYER 置为停止状态

函数原型

int XPlayerStop(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

  • 成功:返回 0;失败:返回‑1

重置 XPLAYER

将相关变量复位,并销毁各模块,如音频解码模块、音频解码数据接收模块等

函数原型

int XPlayerReset(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

  • 成功:线程响应 Reset 命令的返回值;失败:NULL

Reset 命令的返回值为 0 时说明响应成功,为‑1 时说明响应失败

获取节目时长

函数原型

int XPlayerGetDuration(XPlayer* p, int *msec)

参数:

  • p:通过 XPlayerCreate 创建的 Xplayer 指针
  • msec:保存节目时长

返回值:

  • 成功:0;失败:‑1

在 XPlayer 处于 PREPARED、STARTED、PAUSED、STOPPED 或 COMPLETE 状态下才可调用此接口,否则操作无效

SEEK 到给定的时间点

函数原型

int XPlayerSeekTo(XPlayer* p, int nSeekTimeMs)

参数:

  • p:通过 XPlayerCreate 创建的 Xplayer 指针
  • nSeekTimeMs:跳转的时间点

返回值:

  • 成功:线程响应 Seek 命令的返回值;失败:NULL

如果跳转前播放处于暂停状态,则跳转后将保持在暂停状态

获取媒体文件的总时长

函数原型

int XPlayerGetDuration(XPlayer* p, int *msec)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针
  • msec:保存媒体文件的总时长

返回值:

  • 成功:0;失败:‑1

需要在 prepared 状态之后才可以调用该函数

获取当前的播放时间点(即播放位置)

在 XPlayer 处于 PREPARED、STARTED、PAUSED、STOPPED 或 COMPLETE 状态下才可调用此接口,否则操作无效,在 complete 状态下,可能会调用 prepare 方法并更改媒体信息,获取的播放时间以 ms 为单位

函数原型

int XPlayerGetCurrentPosition(XPlayer* p, int* msec)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针
  • msec:保存当前的播放时间

返回值:

  • 成功:0;失败:‑1

获取媒体信息

函数原型

MediaInfo* XPlayerGetMediaInfo(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

  • 成功返回 0,失败返回‑1。如果失败,则 mediaInfo 指针为 NULL

需要在 prepared 状态之后才可以调用该函数

设置循环播放模式

函数原型

int XPlayerSetLooping(XPlayer* p, int loop)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针
  • loop: 1: 表示单曲循环模式;0:表示不会循环

返回值:

查询是否正在播放

函数原型

int XPlayerIsPlaying(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

  • 1:正在播放;0:未播放

销毁一个 XPLAYER

函数原型

void XPlayerDestroy(XPlayer* p)

参数:

  • p:通过 XPlayerCreate 创建的 XPlayer 指针

返回值:

播放器开发示例

  1. player_init() 创建一个播放器

  2. registerCallback() 设置消息回调函数

  3. setDataSource_url() 设置 url

  4. prepare() 或 prepareAsync() 解析头部信息,获取元数据,并根据元数据的信息初始化对应的解码器

  5. start() 播放 (注: 如果是用 prepareAsync() 函数,则需要等到 RTPLAYER_NOTIFY_PREPARED 消息回调之后才可以调用 start() 函数进行播放)

  6. 如果需要跳播,则可以调用 seekTo() 函数

  7. 如果需要暂停,则调用 pause_l() 函数进行暂停

  8. 如果需要停止,则可以调用 stop() 或 reset() 函数进行停止 (注:建议用 reset() 函数进行停止,因为任何状态下都可以调用 reset() 函数)

  9. 如果需要播放下一个或其他的,则可以先调用 reset() 函数使播放器进入 idle 状态,然后再重复 (3)(4)(5) 的步骤

    include

    include

    include

    include

    include

    include

    include

    include

    include

    include

    include

    include

    include

    include "FreeRTOS_POSIX/utils.h"

    include "rtplayer.h"

    include "xplayer.h"

    define PAUSE_CMD 'P'

    define PING_CMD 'p'

    define STOP_CMD 'S'

    define SEEK_TO_CMD 's'

    define SEEK_TO_CMD2 'j'

    define BACKGROUND_CMD 'b'

    define SHOW_BUFFER_CMD 'B'

    define QUIT_CMD 'q'

    define LOOP_CMD 'l'

    define GET_DURATION_CMD 'G'

    define GET_POSITION_CMD 'g'

    define HELP_CMD 'h'

    define INFO_CMD 'i'

    define REPLAY_CMD 'r'

    define RETRY_CMD 256

    define USE_PREPARE_ASYNC 0

    define LOGD(msg, arg...) //printf("[PLAYER_DBG] <%s : %d> " msg "n", func , LINE , ##arg)

    define LOGI(msg, arg...) //printf("[PLAYER_INFO] <%s : %d> " msg "n", func , LINE , ##arg)

    define LOGW(msg, arg...) printf("[PLAYER_WRN] <%s : %d> " msg "n", func , LINE , ##arg)

    define LOGE(msg, arg...) printf("[PLAYER_ERR] <%s : %d> " msg "n", func , LINE , ##arg)

    typedef struct DemoPlayerContext
    {

    RTPlayer* mRTplayer;
    sem_t mPreparedSem;
    mqd_t mRTplayerMq;
    pthread_t mThreadId;
    char *pUrl;
    int mSeekable;
    char isPlayingFlag;
    char mError;
    int inputMode;
    int isSetLoop;
    char quitFlag;//no_shell_input mode quitFlag
    int testMode;
    MediaInfo* mMediaInfo;
    int SoundCard;
    

    }DemoPlayerContext;

    typedef struct DemoPlayerMsg
    {

    int msg;
    int data;
    

    }DemoPlayerMsg;

    define INVALID_MQD ( ( mqd_t ) -1 )

    define DEFAULT_MODE 0600

    static const char *pcRTplayerMqName = "/rtplayerMq";
    static volatile mqd_t mRTplayerMq = INVALID_MQD;
    static int mRTplayerUserInput = 0;
    static struct mq_attr xRTplayerMqAttr =

    {
        .mq_flags   =   0,
        .mq_maxmsg  =   3,
        .mq_msgsize =   sizeof(DemoPlayerMsg),
        .mq_curmsgs =   0
    };
    

    static void showHelp(){

    printf("n");
    printf("**************************n");
    printf("* This is a simple audio player, when it is started, you can input commands to telln");
    printf("* what you want it to do.n");
    printf("* Usage: n");
    printf("*   tplayer_demo /data/test.mp3  : this means play test.mp3n");
    printf("*   P  :this will Pause if in playing status,or Play in paused status n");
    printf("*   S  :this means Stop n");
    printf("*   s  :this means seek to 10s n");
    printf("*   B  :show buffer n");
    printf("*   b  :this means player will run in the background n");
    printf("*   q  :this means quit the player n");
    printf("*   l  :this means loop play n");
    printf("*   G :this means Get  duration n");
    printf("*   g :this means get  position n");
    printf("*   i :this means show media info n");
    printf("*   h :this means show the help information n");
    printf("*   r : replay the current audion");
    printf("**************************n");
    

    }
    static int rtplayer_clear_cmd(mqd_t mq){

    struct timespec cur, delay, abstime;
    clock_gettime( CLOCK_REALTIME, &cur );
    delay.tv_sec = 0;
    delay.tv_nsec = 5*1000*1000;
    UTILS_TimespecAdd(&cur, &delay, &abstime);
    DemoPlayerMsg msg;
    while(mq_timedreceive(mq, (char *)&msg, sizeof(msg), NULL, &abstime)!=-1);
    return 0;
    

    }
    static int rtplayer_send_cmd(mqd_t mq, int msg, int data){

    DemoPlayerMsg pmsg = {msg, data};
    struct timespec tsn, ts;
    clock_gettime(CLOCK_REALTIME, &tsn);
    UTILS_TimespecAddNanoseconds(&tsn, 20*1000*1000, &ts);
    int status = mq_timedsend(mq, (char *)&pmsg, sizeof(pmsg), 0, &ts);
    if(status)
        LOGE("send cmd %c,%d failed!", pmsg.msg, pmsg.data);
    return status;
    

    }

    static int rtplayer_send_cmd_force(mqd_t mq, int msg, int data){

    int try_times = 0;
    DemoPlayerMsg pmsg = {msg, data};
    struct timespec tsn, ts;
    int status;
    

    try_send:

    clock_gettime(CLOCK_REALTIME, &tsn);
    UTILS_TimespecAddNanoseconds(&tsn, 20*1000*1000, &ts);
    status = mq_timedsend(mq, (char *)&pmsg, sizeof(pmsg), 0, &ts);
    if(status){
        try_times++;
        if(try_times< 5){
            LOGE("send cmd %c,%d failed, retry...", pmsg.msg, pmsg.data);
            goto try_send;
        }
        else if(try_times< 10){
            DemoPlayerMsg tmp;
            LOGE("send cmd %c,%d failed, retry...", pmsg.msg, pmsg.data);
            clock_gettime(CLOCK_REALTIME, &tsn);
            UTILS_TimespecAddNanoseconds(&tsn, 20*1000*1000, &ts);
            status = mq_timedreceive(mq, (char *)&tmp, sizeof(tmp), NULL, &ts);
            if(status< 0){
                LOGE("mq_receive fail %d", status);
                goto fail_exit;
            }
            LOGW("drop: %c, %d", tmp.msg, tmp.data);
            goto try_send;
        }
        goto fail_exit;
    }
    return status;
    

    fail_exit:

    LOGE("send cmd %c,%d failed!n", pmsg.msg, pmsg.data);
    return status;
    

    }

    static void callbackFromRTplayer(void* userData,int msg, int id, int ext1, int ext2);
    static void* RTplayerThread(void* arg){

    DemoPlayerContext* demoPlayer = (DemoPlayerContext*)arg;
    char quitFlag = 0;
    
    if(demoPlayer- >inputMode)
    {
    while(1)
    {
         if(demoPlayer- >quitFlag)
         {
        if(demoPlayer- >mRTplayer != NULL)
        {
            printf("player finsh, quit the rtplayern");
            mRTplayerMq = INVALID_MQD;
    

    if USE_PREPARE_ASYNC

    sem_destroy(&demoPlayer- >mPreparedSem);
    

    endif

    player_deinit(demoPlayer- >mRTplayer);
            free(demoPlayer- >pUrl);
            free(demoPlayer);
        }
        break;
         }
        usleep(50*1000);
    }
    return NULL;
    
    }
    while(!quitFlag){
        int cRxed = 0;
        int data = 0;
        DemoPlayerMsg msg;
        ssize_t status;
        if(demoPlayer- >mRTplayerMq!=INVALID_MQD){
            usleep(50*1000);
            ssize_t status = mq_receive(demoPlayer- >mRTplayerMq, (char *)&msg, sizeof(msg), NULL);
            if(status<=-1){
                LOGE("mq_receive fail %d", status);
                usleep(1*1000*1000);
                continue;
            }
            printf("receive %c,%dn", msg.msg, msg.data);
            cRxed = msg.msg;
            data = msg.data;
        }
        else{
            cRxed = QUIT_CMD;
        }
        switch(cRxed){
            case PAUSE_CMD:
            {
                if(demoPlayer- >isPlayingFlag){
                    printf("pause the rtplayern");
                    pause_l(demoPlayer- >mRTplayer);
                    demoPlayer- >isPlayingFlag = 0;
                }else{
                    printf("play the rtplayern");
                    start(demoPlayer- >mRTplayer);
                    demoPlayer- >isPlayingFlag = 1;
                }
                break;
            }
            case STOP_CMD:
            {
                printf("stop the rtplayern");
                stop(demoPlayer- >mRTplayer);
                demoPlayer- >isPlayingFlag = 0;
                break;
            }
            case SEEK_TO_CMD:
            {
                printf("rtplayer seek to 10 secondn");
                seekTo(demoPlayer- >mRTplayer,10);
                break;
            }
            case SEEK_TO_CMD2:
            {
                printf("rtplayer seek to %d secondn", data);
                seekTo(demoPlayer- >mRTplayer,data);
                break;
            }
            case QUIT_CMD:
            {
                printf("quit the rtplayern");
                mRTplayerMq = INVALID_MQD;
                //mq_close(demoPlayer- >mRTplayerMq);
    

    if USE_PREPARE_ASYNC

    sem_destroy(&demoPlayer- >mPreparedSem);
    

    endif

    player_deinit(demoPlayer- >mRTplayer);
                free(demoPlayer- >pUrl);
                free(demoPlayer);
                quitFlag = 1;
                break;
            }
            case LOOP_CMD:
            {
                printf("let the rtplayer loop playn");
                demoPlayer- >isSetLoop = 1;
                setLooping(demoPlayer- >mRTplayer,1);
                break;
            }
            case GET_DURATION_CMD:
            {
                printf("get the audio durationn");
                int duration;
                getDuration(demoPlayer- >mRTplayer,&duration);
                printf("duration:%d sn",duration);
                break;
            }
            case GET_POSITION_CMD:
            {
                printf("get the current positionn");
                int position;
                getCurrentPosition(demoPlayer- >mRTplayer,&position);
                printf("current position:%d sn",position);
                break;
            }
            case HELP_CMD:
            {
                printf("show the help informationn");
                showHelp();
                break;
            }
        case INFO_CMD:
        {
        printf("**************************n");
        printf("* show media information:n");
        MediaInfo* mi = NULL;
        demoPlayer- >mMediaInfo = getMediaInfo(demoPlayer- >mRTplayer);
        if(demoPlayer- >mMediaInfo != NULL){
                        mi = demoPlayer- >mMediaInfo;
                        printf("* file size = %lld KBn",mi- >nFileSize/1024);
                        printf("* duration = %lld msn",mi- >nDurationMs);
                        printf("* bitrate = %d Kbpsn",mi- >nBitrate/1024);
                        printf("* container type = %dn",mi- >eContainerType);
                        printf("* audio stream num = %dn",mi- >nAudioStreamNum);
                        if(mi- >pAudioStreamInfo != NULL){
                            printf("* audio codec tpye = %dn",mi- >pAudioStreamInfo- >eCodecFormat);
                            printf("* audio channel num = %dn",mi- >pAudioStreamInfo- >nChannelNum);
                            printf("* audio BitsPerSample = %dn",mi- >pAudioStreamInfo- >nBitsPerSample);
                            printf("* audio sample rate  = %dn",mi- >pAudioStreamInfo- >nSampleRate);
                        }
        printf("**************************n");
                    }
                    break;
    
        }
        case SHOW_BUFFER_CMD:
        {
        printf("**************************n");
        printf("* show buffer information:n");
        player_show_buffer();
        printf("**************************n");
        break;
    
        }
            case REPLAY_CMD:
            {
                printf("replay %sn", demoPlayer- >pUrl);
                int ret;
                if(demoPlayer- >testMode){
                    printf("test mode: destroy & create instead of resetn");
                    player_deinit(demoPlayer- >mRTplayer);
                    usleep(50*1000);
                    demoPlayer- >mRTplayer = (RTPlayer*)(uintptr_t)player_init();
                    printf("demoPlayer.mRTplayer = %pn",demoPlayer- >mRTplayer);
                    if(!demoPlayer- >mRTplayer){
                        printf("init rtplayer failn");
                        free(demoPlayer- >pUrl);
                        free(demoPlayer);
                        quitFlag = 1;
                        continue;
                    }
                    registerCallback(demoPlayer- >mRTplayer, demoPlayer, callbackFromRTplayer);
                }
                else
                    reset(demoPlayer- >mRTplayer);
                ret = setDataSource_url(demoPlayer- >mRTplayer, demoPlayer, demoPlayer- >pUrl, 0);
                if(ret){
                    printf("setDataSource_url failedn");
                    break;
                }
                ret = prepare(demoPlayer- >mRTplayer);
                if(ret){
                    printf("prepare failedn");
                    break;
                }
                start(demoPlayer- >mRTplayer);
                demoPlayer- >isPlayingFlag = 1;
        if(demoPlayer- >isSetLoop)
        {
                    setLooping(demoPlayer- >mRTplayer,1);
        }
                break;
            }
            case RETRY_CMD:
            {
                int position = data;
                if(data==-1)
                    getCurrentPosition(demoPlayer- >mRTplayer,&position);
                printf("retry %sn", demoPlayer- >pUrl);
                int ret;
                if(demoPlayer- >testMode){
                    printf("test mode: destroy & create instead of resetn");
                    player_deinit(demoPlayer- >mRTplayer);
                    usleep(50*1000);
                    demoPlayer- >mRTplayer = (RTPlayer*)(uintptr_t)player_init();
                    printf("demoPlayer.mRTplayer = %pn",demoPlayer- >mRTplayer);
                    if(!demoPlayer- >mRTplayer){
                        LOGE("init rtplayer fail");
                        free(demoPlayer- >pUrl);
                        free(demoPlayer);
                        quitFlag = 1;
                        continue;
                    }
                    registerCallback(demoPlayer- >mRTplayer, demoPlayer, callbackFromRTplayer);
                }
                else
                    reset(demoPlayer- >mRTplayer);
                ret = setDataSource_url(demoPlayer- >mRTplayer, demoPlayer, demoPlayer- >pUrl, 0);
                if(ret){
                    LOGE("setDataSource_url failed");
                    rtplayer_send_cmd_force(demoPlayer- >mRTplayerMq, RETRY_CMD, position);
                    usleep(500*1000);
                    break;
                }
                ret = prepare(demoPlayer- >mRTplayer);
                if(ret){
                    LOGE("prepare failed");
                    rtplayer_send_cmd_force(demoPlayer- >mRTplayerMq, RETRY_CMD, position);
                    usleep(500*1000);
                    break;
                }
                start(demoPlayer- >mRTplayer);
                demoPlayer- >isPlayingFlag = 1;
                //seekTo(demoPlayer- >mRTplayer, position);
                if(demoPlayer- >isSetLoop)
                    setLooping(demoPlayer- >mRTplayer,1);
                break;
            }
            default:
            {
                LOGW("warning: unknown command,cmd = %d",cRxed);
                break;
            }
        }
        if(quitFlag){
            return NULL;
        }
    }
    return NULL;
    

    }
    static void callbackFromRTplayer(void* userData,int msg, int id, int ext1, int ext2){

    LOGI("call back from RTplayer,msg = %d,id = %d,ext1 = %d,ext2 = %dn",msg,id,ext1,ext2);
    
    DemoPlayerContext* pDemoPlayer = (DemoPlayerContext*)userData;
    switch(msg)
    {
        case RTPLAYER_NOTIFY_PREPARED:
        {
            printf("RTPLAYER_NOTIFY_PREPARED:has prepared.n");
    

    #if USE_PREPARE_ASYNC

    sem_post(&pDemoPlayer- >mPreparedSem);
            pDemoPlayer- >mPreparedFlag = 1;
    

    #endif

    break;
        }
        case RTPLAYER_NOTIFY_PLAYBACK_COMPLETE:
        {
            printf("RTPLAYER_NOTIFY_PLAYBACK_COMPLETE:play completen");
            pDemoPlayer- >isPlayingFlag = 0;
        if(pDemoPlayer- >inputMode)
        {
        pDemoPlayer- >quitFlag = 1;
        }
            break;
        }
        case RTPLAYER_NOTIFY_SEEK_COMPLETE:
        {
            printf("RTPLAYER_NOTIFY_SEEK_COMPLETE:seek okn");
            break;
        }
        case RTPLAYER_NOTIFY_MEDIA_ERROR:
        {
            switch (ext1)
            {
                case RTPLAYER_MEDIA_ERROR_UNKNOWN:
                {
                    printf("erro type:TPLAYER_MEDIA_ERROR_UNKNOWNn");
                    break;
                }
                case RTPLAYER_MEDIA_ERROR_UNSUPPORTED:
                {
                    printf("erro type:TPLAYER_MEDIA_ERROR_UNSUPPORTEDn");
                    break;
                }
                case RTPLAYER_MEDIA_ERROR_IO:
                {
                    printf("erro type:TPLAYER_MEDIA_ERROR_IOn");
                    break;
                }
            }
            printf("RTPLAYER_NOTIFY_MEDIA_ERRORn");
            pDemoPlayer- >mError = 1;
    

    if USE_PREPARE_ASYNC

    if(pDemoPlayer- >mPreparedFlag == 0){
                printf("recive err when preparingn");
                sem_post(&pDemoPlayer- >mPreparedSem);
            }
    

    endif

    if( pDemoPlayer- >mRTplayerMq!=INVALID_MQD ){
                rtplayer_send_cmd_force(pDemoPlayer- >mRTplayerMq, RETRY_CMD, -1);
            }
            else{
                printf("io error, mqueue not existn");
            }
            break;
        }
        case RTPLAYER_NOTIFY_NOT_SEEKABLE:
        {
            pDemoPlayer- >mSeekable = 0;
            printf("info: media source is unseekable.n");
            break;
        }
        case RTPLAYER_NOTIFY_DETAIL_INFO:
        {
            int flag = *(int *)(uintptr_t)ext2;
            //printf("detail info: %dn", flag);
            break;
        }
        default:
        {
            printf("warning: unknown callback from RTplayer.n");
            break;
        }
    }
    

    }
    int cmd_rtplayer_test(int argc, char ** argv)
    {

    int inputMode = 0;
    int testMode = 0;
    /*
    printf("argc = %dn",argc);
    for(int i=0; i < argc;i++){
        printf("argv[%d]=%sn",i,argv[i]);
    }
    */
    printf("rtplayer source:%sn", argv[1]);
    
    if(argc == 3){
        if( !strncmp("no_shell_input", argv[2], sizeof("no_shell_input")-1) ){
            argc--;
            inputMode = 1;
        }
        else if( !strncmp("test_mode", argv[2], sizeof("test_mode")-1) ){
            argc--;
            testMode = 1;
        }
    }
    if(argc != 2){
        LOGW("the parameter is error,usage is as following:");
        showHelp();
        goto rtp_failed;
    }
    

    if USE_PREPARE_ASYNC

    int waitErr = 0;
    

    endif

    DemoPlayerContext* demoPlayer = (DemoPlayerContext*)malloc(sizeof(DemoPlayerContext));
    if(demoPlayer == NULL){
        LOGE("malloc DemoPlayerContext fail");
        goto rtp_failed;
    }
    memset(demoPlayer, 0, sizeof(DemoPlayerContext));
    demoPlayer- >mSeekable = 1;
    demoPlayer- >mRTplayerMq = INVALID_MQD;
    demoPlayer- >inputMode = inputMode;
    demoPlayer- >testMode = testMode;
    demoPlayer- >quitFlag = 0;
    demoPlayer- >mMediaInfo = NULL;
    if(strlen(argv[1])<=0){
        LOGE("url error");
        goto rtp_url_failed;
    }
    demoPlayer- >pUrl = malloc(strlen(argv[1])+1);
    if(!demoPlayer- >pUrl){
        LOGE("pUrl malloc fail");
        goto rtp_url_failed;
    }
    memset(demoPlayer- >pUrl, 0, strlen(argv[1]));
    strcpy(demoPlayer- >pUrl, argv[1]);
    

    if USE_PREPARE_ASYNC

    sem_init(&demoPlayer- >mPreparedSem, 0, 0);
    

    endif

    demoPlayer- >mRTplayer = (RTPlayer*)(uintptr_t)player_init();
    LOGI("demoPlayer.mRTplayer = %p",demoPlayer- >mRTplayer);
    if(!demoPlayer- >mRTplayer){
        LOGE("init rtplayer fail");
        goto rtp_init_failed;
    }
    
    registerCallback(demoPlayer- >mRTplayer, demoPlayer, callbackFromRTplayer);
    status_t ret = setDataSource_url(demoPlayer- >mRTplayer,demoPlayer,demoPlayer- >pUrl, 0);
    if(ret){
        LOGE("set DataSource url fail");
        goto rtp_prepare_failed;
    }
    

    if USE_PREPARE_ASYNC

    demoPlayer- >mPreparedFlag = 0;
    if(prepareAsync(demoPlayer- >mRTplayer) != 0)
    {
        printf("TPlayerPrepareAsync() return fail.n");
    }else{
        printf("preparing...n");
    }
    struct timespec t;
    t.tv_nsec = 0;
    t.tv_sec = 30;
    waitErr = sem_timedwait(&demoPlayer- >mPreparedSem, &t);
    if(waitErr == -1){
        printf("prepare timeout,has wait %d sn",t.tv_sec);
        sem_destroy(&demoPlayer- >mPreparedSem);
        goto rtp_prepare_failed;
    }else if(demoPlayer.mError == 1){
        printf("prepare failn");
        sem_destroy(&demoPlayer- >mPreparedSem);
        goto rtp_prepare_failed;
    }
    printf("prepared okn");
    

    else

    ret = prepare(demoPlayer- >mRTplayer);
    if(ret){
        LOGE("prepare fail");
        goto rtp_prepare_failed;
    }
    

    endif

    start(demoPlayer- >mRTplayer);
    demoPlayer- >isPlayingFlag = 1;
    
    if( mRTplayerMq==INVALID_MQD ){
        mRTplayerMq = mq_open( pcRTplayerMqName, O_CREAT | O_RDWR, DEFAULT_MODE, &xRTplayerMqAttr );
        if(mRTplayerMq==INVALID_MQD){
            LOGE("mq_open fail");
        }
    }
    demoPlayer- >mRTplayerMq = mRTplayerMq;
    rtplayer_clear_cmd(demoPlayer- >mRTplayerMq);
    
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    struct sched_param sched;
    sched.sched_priority = 4;
    pthread_attr_setschedparam(&attr, &sched);
    pthread_attr_setstacksize(&attr, 32768);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    if( pthread_create(&demoPlayer- >mThreadId, &attr, RTplayerThread, demoPlayer) ){
        LOGE("pthread_create failed, quit the rtplayer");
        mRTplayerMq = INVALID_MQD;
        //mq_close(demoPlayer- >mRTplayerMq);
    

    if USE_PREPARE_ASYNC

    sem_destroy(&demoPlayer- >mPreparedSem);
    

    endif

    goto rtp_prepare_failed;
    }
    pthread_setname_np(demoPlayer- >mThreadId, "RTplayerThread");
    
    if(demoPlayer- >inputMode)
        goto rtp_succeed;
    while(1){
        char cRxed = getchar();
        if(cRxed==BACKGROUND_CMD){
            printf("shell input exit, rtplayer will run in the backgroundn");
            break;
        }
        rtplayer_send_cmd(demoPlayer- >mRTplayerMq, cRxed, 0);
        if(cRxed==QUIT_CMD)
            break;
        usleep(50*1000);
    }
    

    rtp_succeed:

    return 0;
    

    rtp_prepare_failed:

    player_deinit(demoPlayer- >mRTplayer);
    

    rtp_init_failed:

    free(demoPlayer- >pUrl);
    

    rtp_url_failed:

    free(demoPlayer);
    

    rtp_failed:

    return -1;
    

    }
    FINSH_FUNCTION_EXPORT_CMD(cmd_rtplayer_test, rtplayer_test, test the rtplayer);

    static int cmd_rtplayer_controller(int argc, char ** argv){

    if(mRTplayerMq==INVALID_MQD){
        printf("mRTplayerMq = INVALID_MQD!n");
        return -1;
    }
    if( (argc!=2) && (argc!=3) ){
        printf("usage:rtpc < cmd > [data]n");
        return -1;
    }
    int data = 0;
    
    if(argc==3)
        data = atoi(argv[2]);
    rtplayer_send_cmd(mRTplayerMq, argv[1][0], data);
    
    return 0;
    

    }
    FINSH_FUNCTION_EXPORT_CMD(cmd_rtplayer_controller, rtpc, control the rtplayer);

注意事项

  • 目前 rtplayer/xplayer 仅支持音频解码,且不支持对视频文件进行解封装,因此 rtplayer 播放器应用只支持音频文件的播放。
  • void registerCallback(void* handle, void* userData, player_callback_t fn) 函数必须要调用,而且 fn 不能为 NULL。
  • 回调函数中不能调用 rtplayer 的任何一个接口,如:reset、stop、start 等这些接口不能在回调函数中调用。
  • 播放本地文件的情况下,set url 时,XPlayer 会进行一次同步 prepare,用于提前获取信息给 parser,因此异步 prepare 前,应对 XPlayerSetDataSourceUrl 的返回值进行判断。
  • 改变播放器的状态,应满足状态图中的对应的函数调用流程,如播放结束后需要播放下一首歌,应调用 reset 清空信息,进入 idle 状态,再调用 setDataSource_Url 进行填充下一首歌到播放器中
  • 采取异步 prepare 时(prepareAsync),应注意添加信号量进行同步。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 播放器
    +关注

    关注

    5

    文章

    383

    浏览量

    36828
  • URL
    URL
    +关注

    关注

    0

    文章

    134

    浏览量

    14830
  • FreeRTOS
    +关注

    关注

    12

    文章

    473

    浏览量

    61349
  • 状态机
    +关注

    关注

    2

    文章

    486

    浏览量

    27182
  • 音频解码器
    +关注

    关注

    0

    文章

    26

    浏览量

    22110
  • R128
    +关注

    关注

    0

    文章

    41

    浏览量

    42
收藏 人收藏

    评论

    相关推荐

    详解R128 RTOS安全方案功能

    介绍 R128 下安全方案的功能。安全完整的方案基于标准方案扩展,覆盖硬件安全、硬件加解密引擎、安全启动、安全系统、安全存储等方面。 配置文件相关本文涉及到一些配置文件,在此进行说明。 env
    发表于 12-28 15:59

    R128 DSP开发工具安装教程

    下的 dsp_raw.bin 拷贝到 R128 根SDK 下的 board/r128s/xxx/bin/ 下,并重命名为rtos_dsp_sun20iw2p1.fex。 R128 SD
    发表于 12-28 17:21

    R128入门编写HelloWorld

    本文将介绍使用 R128 开发板从串口输出 HelloWorld 的方式介绍 SDK 软件开发流程。 载入方案我们使用的开发板是 R128-
    发表于 12-29 09:39

    R128硬件设计指南

    硬件系统框图R128是一颗专为“音视频解码”而打造的全新高集成度 SoC,主要应用于智能物联和专用语音交互处理解决方案。 单片集成 MCU+RISCV+DSP+CODEC+WIFI/BT+PMU
    发表于 01-04 09:23

    R128 SDK架构与目录结构

    HSPSRAM 以及 16M NORFLASH。本文档作为 R128 FreeRTOS SDK 开发指南,旨在帮助软件开发工程师、技术支持工程师快速上手,熟悉 R128 FreeRT
    发表于 01-05 10:05

    R128系统RTOS使用说明

    ] file 跨核心控制台由于 R128 同时运行三个独立的 RTOS,有些时候需要操作其他核心的 RTOS,每次都要在SDK切换控制台比较麻烦,所以可以使用跨核心控制台操作其他核心的 RTO
    发表于 01-05 10:22

    R128 Devkit开发板原理图模块介绍及使用说明

    :CH341SER.EXE 购买链接 百问科技淘宝店 - R128 DevKit 原理图模块介绍R128 模组R128 模组使用 SMT
    发表于 01-17 09:45

    R128芯片 基础组件开发指南——RTOS 多媒体解码

    RTOS 多媒体解码 介绍 FreeRTOS 下如何使用 rtplayer 的接口来开发播放器应用程序,方便播放器开发人员快速正确地
    发表于 10-10 13:52

    R128芯片应用开发案例——驱动 WS2812 流水灯

    数据会在第 n 个 LED 的数据前发送,不过这些数据将会是原来 n-1 个 LED 的亮度数据。 由于拥有独立的 LEDC 模块,在 R128 平台上驱动 WS2812 类似的 RGB LED
    发表于 10-10 14:08

    R128芯片应用开发案例——按键输入

    按键3脚 载入方案 我们使用的开发板是 R128-Devkit,需要开发 C906 核心的应用程序,所以载入方案选择r128s2_module_c906 $ source envse
    发表于 10-10 14:34

    R128芯片 基础组件开发指南——RTOS 多媒体编码

    RTOS 多媒体编码 介绍 FreeRTOS 下如何使用 xrecorder 的接口来开发录制应用程序,方便录制应用开发人员快速正确地开发
    发表于 10-11 09:52

    R128芯片 基础组件开发指南——RTOS 多媒体编码

    RTOS 多媒体编码 介绍 FreeRTOS 下如何使用 xrecorder 的接口来开发录制应用程序,方便录制应用开发人员快速正确地开发
    发表于 10-12 15:49

    R128软件配置——RTOS 软件包配置

    说明 了解了menuconfig的基本操作,我们再来了解一下 RTOS 的 menuconfig 具体都有是么内容。 Build target sunxi arch 分别选择芯片的系列,对于R128
    发表于 10-20 15:31

    使用R128将LVGL运行在SPI TFT GUI上

    LVGL 与 SPI TFT GUI 本次使用的是 Dshan_Display Module,如下图: 引脚配置如下: R128 Devkit TFT 模块 PA12 CS PA13 SCK
    发表于 10-23 13:56

    R128应用开发案例——获取真随机数

    获取真随机数 本文案例代码 下载地址 获取真随机数案例代码 https://www.aw-ol.com/downloads?cat=24 R128 内置了TRNG,一个真随机数发生器,随机源是 8
    发表于 10-24 17:05