〇、参考

《音视频开发进阶指南:基于Android与iOS平台的实践》:7.2.1 音频队列的实现

一、最小队列

  • 使用C语言

    • C++类中的方法,对应到C中则为,结构体中的函数指针类型的属性

    • 结构体中的其他属性,称为常规属性

  • 使用链表实现,将队列元素作为有效数据封装到链表节点中,最终连接成的链表就是一个队列

typedef struct PacketQueue {PacketList *mFirst;PacketList *mLast;Mutex      *mMutex;Cond       *mCond;int (*packet_queue_put)(PacketQueue *que, Packet *pkt);int (*packet_queue_get)(PacketQueue *que, Packet *pkt, int block);
} PacketQueue;

1.0 自定义链表(节点)类型

链表的其中一个成员也是一个链表,由于这种特殊结构的存在,后面我们将链表节点类型和链表类型当成一回事,可以混用。

typedef struct PacketList{Packet *pkt;PacketList *next;
} PacketList;

1.1 队列常规属性

  1. 头节点mFirst:链表节点类型,当链表只有一个节点时,头节点同时也是尾节点

  2. 尾节点mLast:链表节点类型,当链表只有一个节点时,尾节点同时也是头节点

  3. 互斥锁mMutex:和条件变量一起保证线程安全

  4. 条件变量mCond:和互斥锁一起保证线程安全

1.2 队列函数指针属性

  1. packet_queue_put:将一个包压入队列尾

  2. packet_queue_get:从队列头获取一个包

1.2.1 packet_queque_put的实现

1.2.1.1 流程

  1. abort操作:如果队列已经abort,什么都不做,返回-1

  2. 包封装为链表节点

  3. 上锁(禁止其他线程这时候访问),准备将链表节点放入链表

  4. 挂节点:将新链表节点放入链表尾部

    • 如果队列为空,令链表节点任命为尾结点兼头节点;

    • 如果队列不空,将链表节点挂在尾节点后边,然后将链表节点任命为尾节点。

  5. 发信号:链表节点放入链表后,条件变量发送一个signal,告诉block住的线程,可以继续从队列中获取元素了

  6. 解锁

1.2.1.2 细节说明

  • 往链表中压入节点是在链表尾进行操作,一般涉及不到头节点,仅当链表为空或只有一个链表节点时,会涉及到头节点。所以压包入列时,把对头节点的操作当做特殊情况操作写在特殊情况处理if中,把对尾节点的必经操作(任命操作)写在特殊情况处理if外。

1.2.1.3 完整代码

//成功返回1
//出错或队列abort了,返回-1
int packet_queue_put(PacketQueue *que, Packet *pkt)
{PacketList *pkt_lst; //定义一个链表类型的指针 为pkt_lst分配内存, 若分配不成功返回-1;if(mAbortRequest) return -1;//2. 将包封装为链表节点pkt_lst->pkt = pkt;pkt_lst->next = NULL;//未来该包后面挂哪个包,谁也不知道,所以为NULL//3. 上锁LockMutex(que->mMutex);//4. 将链表节点放入链表尾部if(NULL == que->mLast){ //链表为空的其中一种表示方法que->mFirst = pkt_lst;}else{que->mLast->next = pkt_lst;}que->mLast = pkt_lst;//5. 发信号CondSignal(que->mCond);//6. 解锁UnlockMutex(que->mMutex);释放pkt_lst的内存;return 1;
}

1.2.2 packet_queue_get的实现

1.2.2.1 流程

  1. 上锁

  2. abort操作:如果abort了队列,什么也不做,返回-1

  3. 取节点:从链表取出头节点

    • 如果队列为空,

      • 如果block非0,表示实现一个blocking queue,则令当前线程阻塞在get方法,并解锁让其他线程得以访问队列,直到当前线程获得队列不为空的信号后,重新上锁再从队取一次包

      • 如果block为0,表示实现非blocking queue,则直接解锁后返回-1

    • 如果队列非空,取出头节点,并任命新的头节点(get方法必经操作),若新的头节点为空(即队列此时为空),则还需重新任命新的尾节点也为空

  4. 解封装:解封取出的链表节点,拿到包

  5. 解锁

1.2.2.2 细节说明

  1. CondWait(&mCond,&mMutex);可以实现队列为空时的要求

  2. 当队列为空时取包,当前线程被阻塞,待队列非空后,有个重新取包的操作。这一重新取包操作通过循环实现,即将“从链表取出头节点”这一操作放入循环中,同时在队列非空时的取包操作后加上break。

  3. 由于CondWait(&mCond, &mMutex);在返回前又把mMutx给锁上了(见SDL_几个完整头文件:SDL_mutex.h:SDL_CondWait的说明),所以从链表取头节点之前的上锁操作不用放进循环

  4. 重新取包时也要判断队列是否abort了,所以判断队列是否abort了的逻辑也放入循环中,同时不能直接返回-1,因为此时已经上锁(进入循环前),要先解锁后再返回-1

  5. 从链表中取头节点是在链表头部进行操作,一般涉及不到尾节点,仅当链表为空或只有一个链表节点时,会涉及到尾节点。所以从链表中取头节点时,把对头节点的必经操作(取出头节点然后任命新的头节点)写在特殊情况处理if外,把对尾节点的操作当做特殊情况操作写在特殊情况处理if中。

1.2.2.3 完整代码

//成功返回1
//非blocking queue为空时,返回0
//出错或队列abort了返回-1int packet_queue_get(PacketQueue *que, Packet* pkt, int block){ret = 0;PacketList *pkt_lst;为pkt_lst分配内存,如果分配不成功返回-1;//1. 上锁LockMutex(que->mMutex);while(1){//2. 队列abort时的操作if(mAbortRequest){ret = -1;break;}//3. 从链表中取出头节点if(que->mFirst){ //队列非空pkt_lst = mFirst;//取出头节点mFirst = pkt_lst->next;//任命新的头节点if(NULL == mFirst){//如果新的队列为空mLast = NULL; }//4. 解封取出的链表节点,拿到包pkt = pkt_lst->pkt;ret = 1;break;}else if(0 == block){ret = 0; break;}else{CondWait(que->mCond, que->mMutex); }      }//while(1)//5. 解锁UnlockMutex(que->mMutex);释放pkt_lst的内存;return ret;
}

二、总结

  • 空队列的两种表示方法

    1. if(NULL == mFirst)

    2. if(NULL == mLast)

  • 只有一个元素的队列,该元素既是头节点也是尾节点

  • 压包入队,尾节点操作为必经操作,头节点操作为特殊情况操作

  • 取包出队,头节点操作为必经操作,尾节点操作为特殊情况操作

三、扩展功能队列

3.1 扩展常规属性

  • 队列当前元素数目

  • 队列当前字节数

3.2 扩展函数指针属性

  • abort队列

  • 销毁队列

音视频开发中的队列实现相关推荐

  1. 直播软件搭建音视频开发中的视频采集

    直播软件搭建音视频开发中的视频采集 前言 在直播和短视频行业日益火热的发展形势下,音视频开发(采集.编解码.传输.播放.美颜)等技术也随之成为开发者们关注的重点,本系列文章就音视频开发过程中所运用到的 ...

  2. 音视频开发中常见基础问题总结

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/54962205 前言:音视频中一些 ...

  3. 18个实时音视频开发中会用到开源项目

    实时音视频的开发学习有很多可以参考的开源项目.一个实时音视频应用共包括几个环节:采集.编码.前后处理.传输.解码.缓冲.渲染等很多环节.每一个细分环节,还有更细分的技术模块.比如,前后处理环节有美颜. ...

  4. 关于在Android音视频开发中,Google API的MediaCodeC与成熟开源编码器X264的应用对比及使用场景

    在2019年的一个大项目中,有一个功能模块让笔者感触颇深,那就是实时音视频的预览,当然这不是普通的开开直播,画面出来了就完了那么简单,如果你是一个开发者,那么你肯定知道同样大小的一张图片里,色彩丰富的 ...

  5. 音视频开发必看:“秒变萝莉音”,游戏中的变声是如何实现的

    0.引 自从有了"变声",你永远猜不到隔着网线的另一边和你开黑的队友到底是男是女. 当然,天然会伪音的我们学不来,也没必要,这里主要跟大家分享一个一篇关于音视频开发中的变声实现的技 ...

  6. Android音视频开发基础(六):学习MediaCodec API,完成视频H.264的解码

    前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了<Android 音视频从入门到提高 - 任务列表>.本文是Android音视 ...

  7. FFmpeg 工具:音视频开发都用它,快@你兄弟来看丨音视频工具

    (本文基本逻辑:ffmpeg 常用命令介绍 → ffplay 常用命令介绍 → ffprobe 常用命令介绍) 从事音视频开发的程序员几乎都应该知道或使用过 FFmpeg.FFmpeg 是一个开源软件 ...

  8. Android 音视频开发相关知识

    音视频开发技能 要在Android上进行音视频开发,需要掌握以下技能: Android开发:首先,您需要掌握Android应用程序的基本开发技能,包括Java或Kotlin编程语言,Android S ...

  9. 音视频开发——H265码流解析

    概述 H.265技术的应用 编码技术主要运用于视频播放设备.软件应用以及拍摄.录制视频的设备.人们最熟悉的莫过于PPS网络视频播放器.在PC屏客户端产品上面,PPS已经于2013年初推出了基于H.26 ...

最新文章

  1. sap data service安装方法
  2. [SpringBoot]全局异常处理
  3. java难点解析(七)-抽象类
  4. 看懂OpenCV中IplImage转换成CvMat的语句:CvMat sstub, *src = cvGetMat(srcarr, sstub);
  5. PAT甲级1020 Tree Traversals:[C++题解]树的遍历、由中序序列和后序序列递归建树
  6. SAP Spartacus的site context配置参数SiteContextParamsService
  7. 使用OpenSSL加密,使用Java解密,使​​用OpenSSL RSA公钥
  8. cortex-m3 操作模式 寄存器组 异常类型 堆栈 中断
  9. 《十四堂人生创意课》读书笔记,思维导图
  10. html基本进阶知识【转】
  11. 计算机音乐数字乐谱fade,faded简谱_faded数字简谱
  12. 小程序 开发版 上传大小受限制
  13. 求救 关于ORA-01115的错误
  14. idea-2017破解教程
  15. 推荐免费下载430套大型企业管理源码 下载地址:http://www.hur.cn/tg/linkin.asp?linkid=205389 下载地址:[URL=http://www.hur.cn/t
  16. 趋势 | 极简再见,极繁回潮
  17. gitee 上传代码时报错git did not exit cleanly (exit code 1)
  18. 马克下, 初识 runtime (一)
  19. python0表示剪刀_简化Python代码(石头、纸、剪刀)
  20. poj2245Lotto

热门文章

  1. Elasticsearch7.X 入门学习第九课笔记-----聚合分析Aggregation
  2. 一个脚本还你清爽体验
  3. 2022届秋招面经--秋招笔试(2)
  4. 牛顿迭代法的公式推导
  5. javaScript正则表达式截取字符串【截取中间、截取前面、截取后面】
  6. 分享在github超酷超炫特效动画,不看你会后悔的。
  7. sina网页新闻小偷原理及源代码(java版)
  8. html中%3ch3%3e有颜色吗,在增强 iOS 通知系统这件事上,IFTTT 和 Pushover 谁做得更好?...
  9. android 音符动画效果,纯css实现音符跳动效果
  10. 打印1到最大的n位数(Java)