fusion/common/ringbuffer/av_ringbuffer.c

117 lines
4.3 KiB
C
Raw Normal View History

2025-08-05 07:53:44 +00:00
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "list.h"
#include "av_ringbuffer.h"
#include "iot_math.h"
/*
* rb->read指针,
* ,
*/
static int32_t av_ringbuffer_get_frame_locked(ringbuffer *rb, ring_item *item, void *to, int8_t size){
const int32_t end_pos = (item->pos + size) - (rb->buffer + rb->capacity);
if (end_pos <= 0){
memcpy(to, item->pos, size);
}else{
memcpy(to, item->pos, size - end_pos);
memcpy(to + size - end_pos, rb->buffer, end_pos);
}
}
#if 0
uint32_t av_ringbuffer_get_video_frame(ringbuffer *rb, av_cookie *cookie, video_frame *to, uint32_t max_len, uint32_t timeout){
int32_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(video_frame));
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(video_frame));
if((to->type & FRAME_TYPE_IFRAME) && (!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(video_frame) + 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 */
}
}
}
return ret;
}
#endif
#if 1
void av_ringbuffer_test()
{
hlogi("test_av_ringbuffer\n");
#define TEST_CNT (10)
av_ringbuffer *v_ring = av_ringbuffer_init(3*1024*1024);
int i;
for(i=0;i<TEST_CNT;i++){
video_frame *vframe = avframe_create(video_frame, i+10);
vframe->chn = 0;
vframe->type = i % 15 == 0 ? FRAME_TYPE_IFRAME : FRAME_TYPE_PBFRAME;
vframe->format = VIDEO_FORMAT_H264;
vframe->seq = i;
sprintf(vframe->data, "im %d", i);
if (!av_ringbuffer_put(v_ring, vframe, vframe->data)){
hlogi("av_ringbuffer_put err:%u read:%p\n", vframe->size);
}
free(vframe);
}
hlogi("av_ringbuffer_put\n");
av_ringbuffer_dump(v_ring);
av_cookie cookie = {0};
cookie.dir = NEXT_IFRAME;
av_cookie *pcookie = &cookie;
video_frame *vframe = (video_frame*)calloc(1, sizeof(video_frame)+MAX_VFRAME_SIZE);
for(i=0;i<TEST_CNT;i++){
if (OK == av_ringbuffer_get_frame(v_ring, pcookie, vframe, i+10, 1000)){
hlogi("1 av_ringbuffer_get_video_frame i:%d seq:%u, size:%u cookie->item->seq:%u data:%s\n", i, vframe->seq, vframe->size, cookie.item->seq, vframe->data);
}else{
hlogi("1 av_ringbuffer_get_video_frame err:%d\n", i);
//break;
}
}
free(vframe);
hlogi("test_av_ringbuffer end\n");
}
#endif