initial commit

This commit is contained in:
2025-08-05 15:53:44 +08:00
commit 09dc02ae52
553 changed files with 137665 additions and 0 deletions

116
common/ringbuffer/av_ringbuffer.c Executable file
View File

@@ -0,0 +1,116 @@
#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

113
common/ringbuffer/av_ringbuffer.h Executable file
View File

@@ -0,0 +1,113 @@
/*************************************************
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

320
common/ringbuffer/ringbuffer.c Executable file
View File

@@ -0,0 +1,320 @@
/*************************************************
File name : ringbuffer.c
Module : audio and video library functions
Author : amir
Created on : 2022-01-25
Description :
Function implement required by the mutex interface
Modify History:
1. Date: Author: Modification:
202405 罗启宏 增加lock需求
*************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "ringbuffer.h"
#include "iot_math.h"
#include "hlog.h"
/**
* @brief
*
* @param size
*
* @return
*/
ringbuffer *ringbuffer_init(uint32_t capacity/*, gfp_t gfp_mask*/)
{
#if 0
/* 检查时候是2的指数倍 */
if (size & (size-1))
{
// size = 1UL << (roundup_pow_of_two(size) + 1);
size = roundup_pow_of_two(size);
}
#endif
ringbuffer *rb = (ringbuffer*)calloc(1, sizeof(ringbuffer));
int8_t *buffer = (int8_t *)malloc(capacity);
if (rb && buffer){
hmutex_init(&rb->mutex);
if (!buffer)
{
free(rb);
rb = NULL;
}else{
rb->capacity = capacity;
rb->buffer = buffer;
INIT_LIST_HEAD(&rb->list[RING_LIST_USING]);
INIT_LIST_HEAD(&rb->list[RING_LIST_FREE]);
ringbuffer_reset(rb);
hsem_init(&rb->sem, 0);
}
}else{
free(rb);
free(buffer);
rb = NULL;
buffer = NULL;
}
return rb;
}
void ringbuffer_deinit(ringbuffer *rb){
hmutex_t mutex = rb->mutex;
ringbuffer_reset(rb);
hmutex_lock(&mutex);
hsem_destroy(&rb->sem);
free(rb->buffer);
free(rb);
hmutex_unlock(&mutex);
hmutex_destroy(&mutex);
}
void ringbuffer_reset(ringbuffer *rb)
{
hmutex_lock(&rb->mutex);
uint16_t i = 0;
for(i=0; i<RING_LIST_MAX; i++){
struct list_head *pos, *n;
list_for_each_safe(pos, n, &rb->list[i]) {
ring_item *item = list_entry(rb->list[i].next, ring_item, link);
list_del(&item->link);
free(item);
}
}
rb->last_drop_seq = UINT32_MAX;
rb->latest_item = NULL;
rb->write = rb->read = rb->buffer;
hmutex_unlock(&rb->mutex);
}
int32_t ringbuffer_size(ringbuffer *rb){
//hloge("rb->write:%u rb->read:%u\n", rb->write, rb->read);
uint32_t size;
hmutex_lock(&rb->mutex);
if (rb->write >= rb->read){
size = (rb->write - rb->read);
}else{
size = rb->capacity - (rb->read - rb->write);
}
hmutex_unlock(&rb->mutex);
return size;
}
int32_t ringbuffer_get_freesize(ringbuffer *rb){
hmutex_lock(&rb->mutex);
uint32_t freesize = rb->write >= rb->read ? rb->capacity - (rb->write - rb->read) : ( rb->read - rb->write);
hmutex_unlock(&rb->mutex);
return freesize;
}
uint32_t ringbuffer_get_lastseq_locked(ringbuffer *rb){
uint32_t seq = rb->latest_item ? rb->latest_item->seq : UINT32_MAX;
return seq;
}
#define ringbuffer_freesize_locked(rb)(\
rb->write >= rb->read ? rb->capacity - (rb->write - rb->read) : ( rb->read - rb->write)\
)
//get the count of items in ringbuffer
int32_t ringbuffer_item_count(ringbuffer *rb){
uint32_t count = 0;
hmutex_lock(&rb->mutex);
struct list_head *pos, *n;
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING]) {
count++;
}
hmutex_unlock(&rb->mutex);
return count;
}
//put in data
ring_item *ringbuffer_put2(ringbuffer *rb, const char *data1, uint32_t data1_size, const char *data2, uint32_t data2_size){
ring_item *item = NULL;
uint32_t total_size = data1_size + data2_size;
if (total_size > rb->capacity){
return item;
}
hmutex_lock(&rb->mutex);
if (list_empty(&rb->list[RING_LIST_FREE])){//if no free item then to malloc one
item = (ring_item *)malloc(sizeof(ring_item));
}else{//get free item
item = list_entry(rb->list[RING_LIST_FREE].next, ring_item, link);
list_del(&item->link);
}
if (item){
//hloge("ringbuffer_put2:%u:%u:%u:%u\n", rb->write, rb->write + total_size, rb->read, rb->buffer + rb->capacity);
if (rb->write == rb->read && rb->read == rb->buffer + rb->capacity ){
rb->write = rb->read = rb->buffer;
//hloge("reset ringbuffer_put2:%u:%u:%u\n", rb->write, rb->read, rb->buffer + rb->capacity);
if (!list_empty(&rb->list[RING_LIST_USING])){
hloge("error RING_LIST_USING should be empty \n\n");
}
}
/*round to remove oldest item until there is enought space to add new one*/
while(!list_empty(&rb->list[RING_LIST_USING]) && ringbuffer_freesize_locked(rb) < total_size){
ring_item *item_oldest = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
list_del(&item_oldest->link);
list_add_tail(&item_oldest->link, &rb->list[RING_LIST_FREE]);
rb->last_drop_seq = item_oldest->seq;
/*move read to next item.pos*/
ring_item *next = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
rb->read = next->pos;
}
item->pos = rb->write;//data write here
item->size = total_size;
item->seq = rb->latest_item ? rb->latest_item->seq + 1 : 0; /* +1 */
rb->latest_item = item; /*记录最新的一个, 且不会被删除, 同时seq已是最新的*/
list_add_tail(&item->link, &rb->list[RING_LIST_USING]);
/*buffer---read---write----end*/
/*|---------|-------|--------|*/
/*tail_left = end - write */
uint32_t tail_left = (rb->capacity - (rb->write - rb->buffer));
if (tail_left >= total_size){
memcpy(item->pos, data1, data1_size);
if (data2 && data2_size){
memcpy(item->pos + data1_size, data2, data2_size);
}
rb->write += total_size;
}else{
if (tail_left >= data1_size){
memcpy(item->pos, data1, data1_size);//write to tail
if (data2 && data2_size){
memcpy(item->pos + data1_size, data2, tail_left - data1_size);
memcpy(rb->buffer, data2 + (tail_left - data1_size), data2_size - (tail_left - data1_size));
}
}else{
memcpy(item->pos, data1, tail_left);//write to tail
memcpy(rb->buffer, data1 + tail_left, data1_size - tail_left);
if (data2 && data2_size){
memcpy(rb->buffer + (data1_size - tail_left), data2, data2_size);
}
}
rb->write = rb->buffer + total_size - tail_left;// write = buffer + left
}
hsem_post(&rb->sem);
}
hmutex_unlock(&rb->mutex);
//hloge("rb->write:%p item->size:%u read:%p\n", rb->write, item->size, rb->read);
return item;
}
/**
* @brief
*
* @param rb
* @param to
* @param len
*
* @return success(0) or fail(-1)
*/
int32_t ringbuffer_pop(ringbuffer *rb, char *to, uint32_t *len)
{
int32_t ret = -1;
hmutex_lock(&rb->mutex);
if (!list_empty(&rb->list[RING_LIST_USING])){
ring_item *item = list_entry(rb->list[RING_LIST_USING].next, ring_item, link);
list_del(&item->link);
/*buffer-----read-----write----end*/
/*|---------|---------|----------|*/
/*item->pos + item->size > end ? */
/*then end_pos = item->pos + item->size - end */
const int32_t end_pos = (item->pos + item->size) - (rb->buffer + rb->capacity);/* 如果 end 没到尾 */
if (end_pos <=0){
rb->read = item->pos + item->size;
memcpy(to, item->pos, item->size);
}else{
memcpy(to, item->pos, item->size - end_pos);
memcpy(to + item->size - end_pos, rb->buffer, end_pos);
rb->read = rb->buffer + end_pos;
}
//hloge("ringbuffer_pop end_pos:%d item->size:%u pos:%u, buffer:%u, read:%u\n", end_pos, item->size,item->pos, rb->capacity,rb->read);
if (len){
*len = item->size;
}
list_add_tail(&item->link, &rb->list[RING_LIST_FREE]);
ret = 0;
}
hmutex_unlock(&rb->mutex);
return ret;
}
void ringbuffer_dump(ringbuffer *rb){
uint32_t i = 0;
struct list_head *pos, *n;
hmutex_lock(&rb->mutex);
list_for_each_safe(pos, n, &rb->list[RING_LIST_USING]) {
ring_item *item = list_entry(pos, ring_item, link);
hlogw("%s %02u item:%p size:%u pos:%p seq:%u\n", __func__, i++, item, item->size, item->pos, item->pos);
}
hmutex_unlock(&rb->mutex);
}
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int32_t ringbuffer_test()
{
#define BUF_SIZE (64)
#define TEST_STR "1234567891234567891234567891234567891234567891234567544656"
char *ssss = malloc(64);
ringbuffer * rb = ringbuffer_init(600);
if (rb == NULL )
{
return -1;
}
int i;
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
for(i=0; i<10;i++){
uint32_t len;
ringbuffer_pop(rb, ssss, &len);
hlogd("%02d ssss:%s", i, ssss);
}
ringbuffer_dump(rb);
hlogd("1 ringbuffer_test ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
hlogd("11 ringbuffer_tes ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
ringbuffer_put(rb, TEST_STR, 60);
}
ringbuffer_dump(rb);
hlogd("2 ringbuffer_test ringbuffer_size:%d\n\n", ringbuffer_size(rb));
for(i=0; i<10;i++){
uint32_t len;
char outbuf[100]={0};
ringbuffer_pop(rb, outbuf, &len);
hlogd("i:02%d len:%d, outbuf:%s\n", i, len, outbuf);
}
ringbuffer_deinit(rb);
return EXIT_SUCCESS;
}
#if 0
https://blog.csdn.net/u011569253/article/details/71637100
https://www.linuxidc.com/Linux/2016-12/137936.htm
#endif

94
common/ringbuffer/ringbuffer.h Executable file
View File

@@ -0,0 +1,94 @@
/*
* =====================================================================================
* Copyright (c), 2013-2020, Jz.
* Filename: ringbuffer.h
* Author: linux kernel,
* Organization: jz
*
* =====================================================================================
*/
/*************************************************
File name : ringbuffer.h
Module : common
Author : amir
Created on : 2023-01-6
Description :
a ringbuffer to store data(copy)
Modify History:
1. Date: Author: Modification:
*************************************************/
#ifndef __RINGBUFFER_H__
#define __RINGBUFFER_H__
#include <stdint.h>
#include "list.h"
#include "hmutex.h"
#include "hbase.h"
enum{
RING_LIST_FREE = 0,
RING_LIST_USING,
RING_LIST_MAX,
};
typedef struct{
struct list_head link;
int8_t *pos;
uint32_t size;
uint32_t seq; /* start from 0, 不是视频的seq, ringbuffer 内部的seq */
}ring_item;
typedef struct{
struct list_head list[RING_LIST_MAX];
hmutex_t mutex;
hsem_t sem;
int8_t *buffer;/* the buffer holding the data */
uint32_t capacity;/* the capacity of the allocated buffer */
int8_t *write;/* data is added at offset (write % size) */
int8_t *read;/* data is extracted from off. (read % size) */
ring_item *latest_item; /* 最新一个 item, seq 第一个为0, 并自增, 无的时候是 UINT32_MAX*/
uint32_t last_drop_seq; /* 最后因buffer不足,被丢弃的seq*/
}ringbuffer;
ringbuffer * ringbuffer_init(uint32_t size);
void ringbuffer_deinit(ringbuffer *rb);
void ringbuffer_reset(ringbuffer *rb);
//put in data
/*
* 返回被最后丢掉的seq
*/
#define ringbuffer_put(_fifo, _data, _size) ringbuffer_put2(_fifo, _data, _size, NULL, 0)
//put in 2 data
/*
* 返回被最后新增的item
*/
ring_item *ringbuffer_put2(ringbuffer *rb, const char *data1, uint32_t data1_size, const char *data2, uint32_t data2_size);
//pop out data
int32_t ringbuffer_pop(ringbuffer *rb, char *to, uint32_t *len);
//get the size of data in ringbuffer
int32_t ringbuffer_size(ringbuffer *rb);
//get the hv_free size of data in ringbuffer
int32_t ringbuffer_get_freesize(ringbuffer *rb);
/*
* 返回UINT32_MAX无数据
*/
uint32_t ringbuffer_get_lastseq_locked(ringbuffer *rb);
//get the count of items in ringbuffer
int32_t ringbuffer_item_count(ringbuffer *rb);
void ringbuffer_dump(ringbuffer *rb);
int32_t ringbuffer_test();
#endif