ffmpeg中缓冲代码分析

读包操作分析

 
  1. //链表元素结构体

  2. typedef struct MyAVPacketList {

  3. AVPacket pkt;

  4. struct MyAVPacketList *next;//指向下一个元素

  5. int serial;

  6. } MyAVPacketList;

  7. //包队列,先进FIFO队列

  8. typedef struct PacketQueue {

  9. MyAVPacketList *first_pkt, *last_pkt;//队首,队尾指针

    扫描二维码关注公众号,回复: 3123117 查看本文章
  10. int nb_packets;//包数量,也就是队列元素数量

  11. int size;//占用内存大小

  12. int abort_request;//用户退出请求标志

  13. int serial;//序列,作拖动时用,作为区分前后帧序列

  14. SDL_mutex *mutex;//互斥锁

  15. SDL_cond *cond;//条件锁

  16. } PacketQueue;

入队操作:

 
  1. static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)

  2. {

  3. MyAVPacketList *pkt1;

  4. //用户放弃,返回

  5. if (q->abort_request)

  6. return -1;

  7.  
  8. pkt1 = (MyAVPacketList*)av_malloc(sizeof(MyAVPacketList));

  9. if (!pkt1)

  10. return -1;

  11. pkt1->pkt = *pkt;

  12. pkt1->next = NULL;

  13. if (pkt == &flush_pkt)//入队的包为flush标签包,serial自加,表示另外一个系列

  14. q->serial++;

  15. pkt1->serial = q->serial;

  16.  
  17. if (!q->last_pkt)//队列为空

  18. q->first_pkt = pkt1;

  19. else

  20. q->last_pkt->next = pkt1;//不为空,加到队尾

  21. q->last_pkt = pkt1;//将队尾设为当前入队包

  22. q->nb_packets++;//数量增加

  23. q->size += pkt1->pkt.size + sizeof(*pkt1);//更新内存使用量

  24. /* XXX: should duplicate packet data in DV case */

  25. SDL_CondSignal(q->cond);//条件变量解锁

  26. return 0;

  27. }

 
  1. //入队API,调用此函数是线程安全的

  2. static int packet_queue_put(PacketQueue *q, AVPacket *pkt)

  3. {

  4. int ret;

  5.  
  6. /* duplicate the packet */

  7. if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)

  8. return -1;

  9.  
  10. SDL_LockMutex(q->mutex);

  11. ret = packet_queue_put_private(q, pkt);

  12. SDL_UnlockMutex(q->mutex);

  13.  
  14. if (pkt != &flush_pkt && ret < 0)

  15. av_free_packet(pkt);

  16.  
  17. return ret;

  18. }


由于视频解码线程,音频播放(主线程)同时访问包队列,所以需要加互斥锁。

 
  1. //将一个空包入队

  2. static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)

  3. {

  4. AVPacket pkt1, *pkt = &pkt1;

  5. av_init_packet(pkt);

  6. pkt->data = NULL;

  7. pkt->size = 0;

  8. pkt->stream_index = stream_index;

  9. return packet_queue_put(q, pkt);

  10. }

 
  1. //队列初始化

  2. static void packet_queue_init(PacketQueue *q)

  3. {

  4. memset(q, 0, sizeof(PacketQueue));

  5. q->mutex = SDL_CreateMutex();

  6. q->cond = SDL_CreateCond();

  7. q->abort_request = 1;

  8. }

 
  1. //释放队列空间

  2. static void packet_queue_destroy(PacketQueue *q)

  3. {

  4. packet_queue_flush(q);

  5. SDL_DestroyMutex(q->mutex);

  6. SDL_DestroyCond(q->cond);

  7. }

  8. //用户取消

  9. static void packet_queue_abort(PacketQueue *q)

  10. {

  11. SDL_LockMutex(q->mutex);

  12.  
  13. q->abort_request = 1;

  14.  
  15. SDL_CondSignal(q->cond);

  16.  
  17. SDL_UnlockMutex(q->mutex);

  18. }

  19. //队列开启

  20. static void packet_queue_start(PacketQueue *q)

  21. {

  22. SDL_LockMutex(q->mutex);

  23. q->abort_request = 0;

  24. packet_queue_put_private(q, &flush_pkt);

  25. SDL_UnlockMutex(q->mutex);

  26. }

  27.  
  28. /* return < 0 if aborted, 0 if no packet and > 0 if packet. */

  29. //出队操作

  30. static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)

  31. {

  32. MyAVPacketList *pkt1;

  33. int ret;

  34.  
  35. SDL_LockMutex(q->mutex);

  36.  
  37. for (;;) {

  38. if (q->abort_request) {

  39. ret = -1;

  40. break;

  41. }

  42. //取队头元素

  43. pkt1 = q->first_pkt;

  44. if (pkt1) {

  45. q->first_pkt = pkt1->next;

  46. if (!q->first_pkt)

  47. q->last_pkt = NULL;

  48. q->nb_packets--;

  49. q->size -= pkt1->pkt.size + sizeof(*pkt1);

  50. *pkt = pkt1->pkt;

  51. if (serial)

  52. *serial = pkt1->serial;

  53. av_free(pkt1);

  54. ret = 1;

  55. break;

  56. } else if (!block) {

  57. ret = 0;

  58. break;

  59. } else {//队列为空,阻塞在队列条件变量上

  60. SDL_CondWait(q->cond, q->mutex);

  61. }

  62. }

  63. SDL_UnlockMutex(q->mutex);

  64. return ret;

  65. }

  66. //读取一帧

  67. int av_read_frame(AVFormatContext *s, AVPacket *pkt)

  68. {

  69. const int genpts = s->flags & AVFMT_FLAG_GENPTS;

  70. int eof = 0;

  71. int ret;

  72. AVStream *st;

  73. //如果没有设置生成时间戳标志

  74. if (!genpts) {

  75. //包FIFO队列不为空,从队列中出队,否则从文件中读取

  76. ret = s->packet_buffer ?

  77. read_from_packet_buffer(&s->packet_buffer, &s->packet_buffer_end, pkt) :

  78. read_frame_internal(s, pkt);

  79. if (ret < 0)

  80. return ret;

  81. goto return_packet;

  82. }

  83. //设置了生成时间戳

  84. for (;;) {

  85. //队列头

  86. AVPacketList *pktl = s->packet_buffer;

  87.  
  88. if (pktl) {

  89. AVPacket *next_pkt = &pktl->pkt;

  90. //如果解码时间戳有效

  91. if (next_pkt->dts != AV_NOPTS_VALUE) {

  92. int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;//获取时间戳压缩位数

  93. // last dts seen for this stream. if any of packets following

  94. // current one had no dts, we will set this to AV_NOPTS_VALUE.

  95. int64_t last_dts = next_pkt->dts;

  96. while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {

  97. //时间戳无效

  98. if (pktl->pkt.stream_index == next_pkt->stream_index &&

  99. (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) {

  100. if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { //not b frame

  101. next_pkt->pts = pktl->pkt.dts;

  102. }

  103. if (last_dts != AV_NOPTS_VALUE) {

  104. // Once last dts was set to AV_NOPTS_VALUE, we don't change it.

  105. last_dts = pktl->pkt.dts;

  106. }

  107. }

  108. pktl = pktl->next;

  109. }

  110. if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {

  111. // Fixing the last reference frame had none pts issue (For MXF etc).

  112. // We only do this when

  113. // 1. eof.

  114. // 2. we are not able to resolve a pts value for current packet.

  115. // 3. the packets for this stream at the end of the files had valid dts.

  116. next_pkt->pts = last_dts + next_pkt->duration;

  117. }

  118. pktl = s->packet_buffer;

  119. }

  120.  
  121. /* read packet from packet buffer, if there is data */

  122. if (!(next_pkt->pts == AV_NOPTS_VALUE &&

  123. next_pkt->dts != AV_NOPTS_VALUE && !eof)) {

  124. ret = read_from_packet_buffer(&s->packet_buffer,

  125. &s->packet_buffer_end, pkt);

  126. goto return_packet;

  127. }

  128. }

  129.  
  130. ret = read_frame_internal(s, pkt);

  131. if (ret < 0) {

  132. if (pktl && ret != AVERROR(EAGAIN)) {

  133. eof = 1;

  134. continue;

  135. } else

  136. return ret;

  137. }

  138. //拷贝副本,并添加到队列中

  139. if (av_dup_packet(add_to_pktbuf(&s->packet_buffer, pkt,

  140. &s->packet_buffer_end)) < 0)

  141. return AVERROR(ENOMEM);

  142. }

  143.  
  144. return_packet:

  145.  
  146. st = s->streams[pkt->stream_index];

  147. if (st->skip_samples) {

  148. uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);

  149. if (p) {

  150. AV_WL32(p, st->skip_samples);

  151. av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples);

  152. }

  153. st->skip_samples = 0;

  154. }

  155.  
  156. if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) {

  157. ff_reduce_index(s, st->index);

  158. av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);

  159. }

  160.  
  161. if (is_relative(pkt->dts))

  162. pkt->dts -= RELATIVE_TS_BASE;

  163. if (is_relative(pkt->pts))

  164. pkt->pts -= RELATIVE_TS_BASE;

  165.  
  166. return ret;

  167. }

 
  1. //flush 队列

  2. static void packet_queue_flush(PacketQueue *q)

  3. {

  4. MyAVPacketList *pkt, *pkt1;

  5.  
  6. SDL_LockMutex(q->mutex);

  7. for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {

  8. pkt1 = pkt->next;

  9. av_free_packet(&pkt->pkt);

  10. av_freep(&pkt);

  11. }

  12. q->last_pkt = NULL;

  13. q->first_pkt = NULL;

  14. q->nb_packets = 0;

  15. q->size = 0;

  16. SDL_UnlockMutex(q->mutex);

  17. }


ffmpeg纯属个人喜好而了解,定有许多疏漏之处,欢迎指正! 

猜你喜欢

转载自blog.csdn.net/special00/article/details/82563998
今日推荐