/************************************************* File name : av_ringbuffer.h Module : audio and video library functions Author : amir Created on : 2022-01-27 Description : 主要是每个"caller"可以带自己的index向一份共享的av_buffer取自己预期的内容(有的caller快,有的慢), 如果没有数了就sem等待. Modify History: 1. Date: Author: Modification: *************************************************/ #ifndef AV_RINGBUFFER #define AV_RINGBUFFER #include #include "ringbuffer.h" #include "hal_interface_video.h" enum{ NEXT_IFRAME = 0, /* next key frame */ LATEST_IFRAME /* latest key frame */ }; typedef struct{ ring_item *item; /* 根据item->seq来向前搜索, 这样不同的任务带自己的cookie可以取自己期望的下一帧 */ uint8_t dir; //dir = NEXT_IFRAME, 向前搜索大于seq和pts的帧(最旧的一个I帧); dir = LATEST_IFRAME, 相反如直播需要实时(最新的一个I帧) }av_cookie; #define avframe_create(_frame_type, _size) ({\ _frame_type *frame = (_frame_type *)malloc(sizeof(_frame_type) + _size);\ if (frame){frame->size = _size;}\ frame;\ }) typedef ringbuffer av_ringbuffer; //init an av_ringbuffer //return av_ringbuffer if success /* * 通常audio 和 video 各申请一个av_ringbuffer */ #define av_ringbuffer_init(_size) ringbuffer_init(_size) //deinit an av_ringbuffer #define av_ringbuffer_deinit(_av) ringbuffer_deinit(_av) //put a pointer of a frame, special for a frame from lower callback and frame strcut and data in seperate memory //eg: frame.size = av.size; // av_ringbuffer_put(&frame, av.data) /* * put vframe_s 或 aframe_s */ #define av_ringbuffer_put(_av, _pframe, _data) ({\ ring_item *item = ringbuffer_put2(_av, (int8_t*)_pframe, sizeof(*_pframe), _data, _pframe->size);\ item;}) /* * 根据cookie来移动自己的next_seq, audio and video frame 共用 **/ #define av_ringbuffer_get_frame(rb, cookie, to, max_len,timeout) ({\ uint32_t ret = NG;\ ring_item *item = NULL;\ hmutex_lock(&rb->mutex);\ if (!list_empty(&rb->list[RING_LIST_USING])){\ if (cookie->item && /* 正常情况直接获取下一个帧, 否则进入后面的异常情况去搜索 */\ (cookie->item->seq > rb->last_drop_seq || rb->last_drop_seq == UINT32_MAX) && cookie->item->seq < ringbuffer_get_lastseq_locked(rb)) {/* 直接获取下一个*/\ item = list_entry(cookie->item->link.next, ring_item, link);\ }else if (cookie->dir == LATEST_IFRAME){/*直播查找最新的关键帧*/\ struct list_head *pos, *n;\ list_for_each_prev_safe(pos, n, &rb->list[RING_LIST_USING])\ {\ ring_item* tmp_item = list_entry(pos, ring_item, link);\ av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(*to));\ if((to->type & FRAME_TYPE_IFRAME) && (!cookie->item || tmp_item->seq >= cookie->item->seq)){\ item = tmp_item;\ break;\ }\ }\ }else{/* dir = NEXT_IFRAME 查找比cookie->item新的关键帧, 如oss, 又不想丢太多 */\ struct list_head *pos, *n;\ list_for_each_safe(pos, n, &rb->list[RING_LIST_USING])\ {\ ring_item* tmp_item = list_entry(pos, ring_item, link);\ av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(*to));\ if(((to->type & FRAME_TYPE_IFRAME)||(to->type & FRAME_TYPE_AUDIO)) && (!cookie->item || tmp_item->seq >= cookie->item->seq)/*&& (to->ts >= cookie->startPTS)*/) {/*头一个, 或者 下一个*/\ item = tmp_item;\ break;\ }\ }\ }\ }\ hmutex_unlock(&rb->mutex);\ if ( item ) {\ cookie->item = item;\ av_ringbuffer_get_frame_locked(rb, item, to, sizeof(*to) + item->size);\ /*hlogd("av_ringbuffer_get_video_frame %u %X %u\n", cookie->item->seq, rb->last_drop_seq, ringbuffer_get_lastseq_locked(rb));*/\ ret = OK;\ } else {\ ret = NG;\ if (timeout) {\ if ( hsem_wait_for(&rb->sem, timeout) ){/* 没有数据,调用端再重新call */\ /* 正常, 收到了sem, 有新的av帧送入 */\ } else {\ /* 超时没收到 sem */\ }\ }\ }\ ret;}) #define av_ringbuffer_dump ringbuffer_dump void av_ringbuffer_test(); #endif