FFmpeg对输入数据的接收是通过FIFO实现的。
下面将对UDP实时TS流进行数据结构和流程分析
1. 相关的数据结构的定义
顶层的所有URL数据结构定义
- typedef struct URLContext {
- const AVClass *av_class; ///< information for av_log(). Set by url_open().
- struct URLProtocol *prot;
- int flags;
- int is_streamed; /**< true if streamed (no seek possible), default = false */
- int max_packet_size;
- /**< if non zero, the stream is packetized with this max packet size */
- void *priv_data;
-
- char *filename; /**< specified URL */
- int is_connected;
- } URLContext;
FIFO的定义:
- typedef struct AVFifoBuffer {
- uint8_t *buffer;
- uint8_t *rptr, *wptr, *end;
- uint32_t rndx, wndx;
- } AVFifoBuffer;
UDP数据结构定义
- typedef struct {
- int udp_fd;
- int ttl;
- int buffer_size;
- int is_multicast;
- int local_port;
- int reuse_socket;
- struct sockaddr_storage dest_addr;
- int dest_addr_len;
- int is_connected;
-
- /* Circular Buffer variables for use in UDP receive code */
- int circular_buffer_size;
- AVFifoBuffer *fifo;
- int circular_buffer_error;
- #if HAVE_PTHREADS
- pthread_t circular_buffer_thread;
- #endif
- } UDPContext;
2. 初始化UDP的socket,并接收数据
- /* put it in UDP context ,return non zero if error */
- static int udp_open(URLContext *h, const char *uri, int flags)
- {
- ...
- UDPContext *s = NULL;
- s = av_mallocz(sizeof(UDPContext));
- h->priv_data = s;
- 进行UDP的相关设置;
- s->circular_buffer_size = 7*188*65536;
- if (!is_output && s->circular_buffer_size)
- {
- /* start the task going */
- s->fifo = av_fifo_alloc(s->circular_buffer_size);
-
- /*
- * 启动UDP数据接收线程,
- * 使得实时数据的接收和转码并行进行。
- */
- if (pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h))
- {
- av_log(h, AV_LOG_ERROR, "pthread_create failed\n");
- goto fail;
- }
- }
- }
- /* 初始化输入数据的FIFO */
- void av_fifo_reset(AVFifoBuffer *f)
- {
- f->wptr = f->rptr = f->buffer;
- f->wndx = f->rndx = 0;
- }
- /*
- * 函数功能:
- * 从UDP对应的socket中接收数据,
- * 并存储到FIFO中
- */
- void *circular_buffer_task( void *_URLContext)
- {
- URLContext *h = _URLContext;
- UDPContext *s = h->priv_data;
- for ( ; ; )
- {
- ...
-
- /*
- * 将从socket s->udp_fd接收到的数据
- * 存储到由s->fifo->wptr指定的s->fifo->buffer的位置
- */
- len = recv(s->udp_fd, s->fifo->wptr, left, 0);
- s->fifo->wptr += len;
- /* FIFO的循环使用 */
- if (s->fifo->wptr >= s->fifo->end)
- s->fifo->wptr = s->fifo->buffer;
- s->fifo->wndx += len;
- }
- }
3. mpeg2-TS解析时的数据使用
函数调用关系图与从FIFO中获取数据的代码
- av_demuxer_open()
- |
- V
- mpegts_read_header()
- |
- V
- avio_read()
- |
- V
- ffurl_read()
- |
- V
- int udp_read(URLContext *h, uint8_t *buf, int size)
- {
- UDPContext *s = h->priv_data;
- int ret;
- int avail;
- fd_set rfds;
- struct timeval tv;
- if (s->fifo)
- {
- do
- {
- /* 查看FIFO中现有多少字节数据可用 */
- avail = av_fifo_size(s->fifo);
- if (avail)
- {
- // Maximum amount available
- size = FFMIN( avail, size);
-
- /* 将FIFO s->fifo中的数据复制size个字节到buf中 */
- av_fifo_generic_read(s->fifo, buf, size, NULL);
- return size;
- }
- else
- { ... }
- } while( 1);
- }
- ...
- }
4. 总的来说,
UDP的数据(UDPContext)都是通过URLContext的"void *priv_data"以指针的方式来传递;
阅读(513) | 评论(0) | 转发(0) |