114 lines
4.5 KiB
C
Executable File
114 lines
4.5 KiB
C
Executable File
/*************************************************
|
|
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
|