SDL条件变量,锁机制

最近看FFmpeg 源码,其中有用到SDL,在这学习一下。
SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。

总之SDL是一款跨平台的多媒体开源库,用处很多。

                                     SDL 结构
接触到SDL是在FFmpeg 中ffplay.c 中队列PacketQueue的操作,

typedef struct MyAVPacketList {
    AVPacket pkt;
    struct MyAVPacketList *next;
    int serial;
} MyAVPacketList;

typedef struct PacketQueue {
    MyAVPacketList *first_pkt, *last_pkt;
    int nb_packets;// 队列中packet的数量
    int size; // 队列所占内存空间大小
    int64_t duration;// 队列中所有packet总的播放时长
    int abort_request;// 播放序列,所谓播放序列就是一段连续的播放动作,一个seek操作会启动一段新的播放序列
    int serial;
    SDL_mutex *mutex;//互斥量
    SDL_cond *cond;//条件变量
} PacketQueue;

栈(LIFO)是一种表,队列(FIFO)也是一种表。数组是表的一种实现方式,链表也是表的一种实现方式,例如FIFO既可以用数组实现,也可以用链表实现。PacketQueue是用链表实现的一个FIFO。
以下是PackQueue 的相关操作:

/* packet queue handling */
static int packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();//初始化互斥锁
    if (!q->mutex) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    q->cond = SDL_CreateCond();//初始化信号量
    if (!q->cond) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    q->abort_request = 1;
    return 0;
}

static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
    MyAVPacketList *pkt1;

    if (q->abort_request)
       return -1;

    pkt1 = av_malloc(sizeof(MyAVPacketList));
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;
    if (pkt == &flush_pkt)
        q->serial++;
    pkt1->serial = q->serial;

    if (!q->last_pkt)
        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++;
    q->size += pkt1->pkt.size + sizeof(*pkt1);
    q->duration += pkt1->pkt.duration;
    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);//SDL_CondSignal解锁->发送条件信号-> 加锁,方便等待数据的地方唤醒
    return 0;
}

static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
    int ret;

    SDL_LockMutex(q->mutex);//加锁
    ret = packet_queue_put_private(q, pkt);//SDL_CondSignal 解锁->发送条件信号-> 加锁,方便等待数据的地方唤醒
    SDL_UnlockMutex(q->mutex);//解锁

    if (pkt != &flush_pkt && ret < 0)
        av_packet_unref(pkt);

    return ret;
}

/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
{
    MyAVPacketList *pkt1;
    int ret;

    SDL_LockMutex(q->mutex);//收到信号后,获得锁,锁定mutex

    for (;;) {
        if (q->abort_request) {
            ret = -1;
            break;
        }

        pkt1 = q->first_pkt;
        if (pkt1) { // 队列非空,取一个出来
            q->first_pkt = pkt1->next;
            if (!q->first_pkt)
                q->last_pkt = NULL;
            q->nb_packets--;
            q->size -= pkt1->pkt.size + sizeof(*pkt1);
            q->duration -= pkt1->pkt.duration;
            *pkt = pkt1->pkt;
            if (serial)
                *serial = pkt1->serial;
            av_free(pkt1);
            ret = 1;
            break;
        } else if (!block) {// 队列空且阻塞标志无效,则立即退出
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
/*SDL_CondWait先检测是否满足条件, 若不满足,解锁mutex,wait,
  直至被SDL_CondSignal()函数或者SDL_CondBroadcast()函数通知,则锁(mutex)被重新锁定并返回,接着继续往下执行
*/
        }
    }
    SDL_UnlockMutex(q->mutex);//解锁
    return ret;
}


 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值