fusion/common/ringbuffer/av_ringbuffer.h

114 lines
4.5 KiB
C
Raw Permalink Normal View History

2025-08-05 07:53:44 +00:00
/*************************************************
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 <stdint.h>
#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