ffmpeg解析mpeg2ts时的数据结构分析

FFmpeg对输入数据的接收是通过FIFO实现的。
下面将对UDP实时TS流进行数据结构和流程分析

1. 相关的数据结构的定义
顶层的所有URL数据结构定义
  1. typedef struct URLContext {
  2.   const AVClass *av_class; ///< information for av_log(). Set by url_open(). 
  3.   struct URLProtocol *prot; 
  4.   int flags; 
  5.   int is_streamed; /**< true if streamed (no seek possible), default = false */ 
  6.   int max_packet_size; 
  7.          /**< if non zero, the stream is packetized with this max packet size */

  8.   void *priv_data;
  9.                                                                    
  10.   char *filename; /**< specified URL */ 
  11.   int is_connected;
  12. } URLContext;

FIFO的定义:
  1. typedef struct AVFifoBuffer {
  2.     uint8_t *buffer;
  3.     uint8_t *rptr, *wptr, *end;
  4.     uint32_t rndx, wndx;
  5. } AVFifoBuffer;

UDP数据结构定义
  1. typedef struct {
  2.   int udp_fd;
  3.   int ttl;
  4.   int buffer_size;
  5.   int is_multicast;

  6.   int local_port;
  7.   int reuse_socket;
  8.   struct sockaddr_storage dest_addr;
  9.   int dest_addr_len;
  10.   int is_connected;
  11.  
  12.   /* Circular Buffer variables for use in UDP receive code */ 
  13.   int circular_buffer_size;
  14.   AVFifoBuffer *fifo;
  15.   int circular_buffer_error;

  16. #if HAVE_PTHREADS
  17.     pthread_t circular_buffer_thread;
  18. #endif
  19. } UDPContext;

2. 初始化UDP的socket,并接收数据
  1. /* put it in UDP context ,return non zero if error */
  2. static int udp_open(URLContext *h, const char *uri, int flags)
  3. {
  4.   ... 
  5.   UDPContext *= NULL;

  6.   s = av_mallocz(sizeof(UDPContext));

  7.   h->priv_data = s;

  8.   进行UDP的相关设置;

  9.   s->circular_buffer_size = 7*188*65536;

  10.   if (!is_output && s->circular_buffer_size) 
  11.   {
  12.     /* start the task going */
  13.     s->fifo = av_fifo_alloc(s->circular_buffer_size);
  14.     
  15.     /* 
  16.      * 启动UDP数据接收线程,
  17.      * 使得实时数据的接收和转码并行进行。 
  18.      */
  19.     if (pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h)) 
  20.     {
  21.       av_log(h, AV_LOG_ERROR, "pthread_create failed\n");
  22.       goto fail;
  23.     }
  24.   }
  25. }

  1. /* 初始化输入数据的FIFO */
  2. void av_fifo_reset(AVFifoBuffer *f)
  3. { 
  4.   f->wptr = f->rptr = f->buffer;
  5.   f->wndx = f->rndx = 0;
  6. }


  7. /*
  8.  * 函数功能:
  9.  * 从UDP对应的socket中接收数据,
  10.  * 并存储到FIFO中
  11.  */
  12. void *circular_buffer_task( void *_URLContext)
  13. { 
  14.   URLContext *= _URLContext;
  15.   UDPContext *= h->priv_data;

  16.   for ( ; ; )
  17.   {
  18.     ...
  19.     
  20.     /* 
  21.      * 将从socket s->udp_fd接收到的数据
  22.      * 存储到由s->fifo->wptr指定的s->fifo->buffer的位置
  23.      */
  24.     len = recv(s->udp_fd, s->fifo->wptr, left, 0);
  25.     s->fifo->wptr += len;

  26.     /* FIFO的循环使用 */
  27.     if (s->fifo->wptr >= s->fifo->end)
  28.       s->fifo->wptr = s->fifo->buffer;
  29.     s->fifo->wndx += len;
  30.   }
  31. }

3. mpeg2-TS解析时的数据使用
函数调用关系图与从FIFO中获取数据的代码
  1. av_demuxer_open()
  2.   |
  3.   V
  4. mpegts_read_header()
  5.   |
  6.   V
  7. avio_read()
  8.   |
  9.   V
  10. ffurl_read()
  11.   |
  12.   V
  13. int udp_read(URLContext *h, uint8_t *buf, int size)
  14. {
  15.   UDPContext *= h->priv_data;
  16.   int ret;
  17.   int avail;
  18.   fd_set rfds;
  19.   struct timeval tv;

  20.   if (s->fifo) 
  21.   {
  22.     do 
  23.     {
  24.       /* 查看FIFO中现有多少字节数据可用 */
  25.       avail = av_fifo_size(s->fifo);
  26.       if (avail) 
  27.       {
  28.         // Maximum amount available
  29.         size = FFMIN( avail, size);
  30.         
  31.         /* 将FIFO s->fifo中的数据复制size个字节到buf中 */
  32.         av_fifo_generic_read(s->fifo, buf, size, NULL);
  33.         return size;
  34.       }
  35.       else 
  36.       { ... }
  37.     } while( 1);
  38.   }
  39.   ...
  40. }

4. 总的来说,
UDP的数据(UDPContext)都是通过URLContext的"void *priv_data"以指针的方式来传递;

你可能感兴趣的:(ffmpeg,ffmpeg,ffmpeg,mpegts)