C++ 实现Buffer 动态分配管理,FIFO模式存取数据

本文在 《C++ 实现Buffer 动态分配管理代码实现 》 的基础上优化的。

之前用的数组来管理 buff,这样就有一个问题数据没有先后,
导到显示数据时,存在错乱,为此优化为 结构体指针,取数据时使用 FIFO 先进先出的模式来控制数据。

具体代码实现如下:

2019-10-22 更新代码逻辑:

头文件代码

@ receivedata.h

#ifndef RECEIVEDATA
#define RECEIVEDATA

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <signal.h>    //     signal
#include "libmsdp.h"
#include "msdp_type.h"
#include <cutils/log.h>
#include <unistd.h>    //    alarm
#include <pthread.h>
#include <dlfcn.h> 
#include "hicarnative.h"



/////////////////////////////////////////////
//     libreceivedata.cpp                    //
/////////////////////////////////////////////


extern void sendVideoDataNative(const uint8_t *pPacket, uint32_t nPktSize, int64_t timeStamp);
extern void sendMessageFromNative(int cmdCode);

int getHicarPara(const char *devSourceId,const char *localIp,const char *remoteIp,const uint8_t *sessionkey);
int hicarPostEvent(double x,double y,int action);
int setVideoParmNative(int width, int height, int frame);

void MyMSDPFree();




/////////////////////////////////////////////
//  mem_alloc.cpp                           //
/////////////////////////////////////////////

struct Video_Buffer_t{
    uint32_t lengh_buf;
    uint8_t *pbuf;             
    bool is_ready;
    bool is_using;
    int unused_cnt;    // 10: using   0: not using
	int index;
	Video_Buffer_t * next;
	Video_Buffer_t * pre;
	int64_t timeStamp;
};


#define BUFFER_NUM_INIT         7
#define BUFFER_NUM_MAX			7		// max size is 1.3824M * 5 = 6.912M
#define BUFFER_AUTO_CLEAR_TIME	3		// free unnecessary bufeer

#define BUFFER_SIZE             1920*720    // 1,382,400‬


class Memory_Manager{

public:
    Memory_Manager();
    
    ~Memory_Manager();
    

    void clear_buffer(int index);
	void clear_buffer(Video_Buffer_t * p_buff);
	void clear_an_old_buff(void);
	void update_buffer_fifo_mode();
    
    Video_Buffer_t * get_null_buffer(uint32_t size , uint32_t i_5_data);
    Video_Buffer_t * get_ready_buffer(int t);
    
    int push_buffer_data(const uint8_t *pPacket, uint32_t nPktSize, int64_t timeStamp);
    void pop_buffer_data(void);
    
    void alarm_work();


private:
    Video_Buffer_t video_buff[BUFFER_NUM_MAX];
	Video_Buffer_t * p_next_null_buff;				// point to write
	Video_Buffer_t * p_next_ready_buff;				// point to read
    int current_buff_num;

	bool g_need_update_fifo;						// if = true update

    //void free_buffer_alarm_fn(int sig);
};
extern Memory_Manager * mem_manager;

//call delete mem_manager when not use

/////////////////////////////////////////////
//  END                                       //
/////////////////////////////////////////////

#endif


具体实现代码

#include "receivedata.h"

void Memory_Manager::alarm_work()
{
    ALOGI("[Memory_Manager::alarm_work] enter \n");

	if( current_buff_num > BUFFER_NUM_INIT){
		alarm(1);
	}
}


//TODO: add timer function here, check if need release buffer
void free_buffer_alarm_fn(int sig)    
{  
    mem_manager->alarm_work();
    return;  
}  


Memory_Manager::Memory_Manager()
{
    ALOGI("[Memory_Manager::Memory_Manager] enter ");

    current_buff_num = BUFFER_NUM_INIT;

    for(int i=0; i < current_buff_num; i++){ // 0 1
        clear_buffer(i);
        video_buff[i].pbuf = (uint8_t *) malloc(BUFFER_SIZE);
		video_buff[i].index = i;
    }
    
    for(int i=current_buff_num; i < BUFFER_NUM_MAX; i++){ // 2 3 4
		video_buff[i].index = i;
        clear_buffer(i);
    }
	

	p_next_null_buff  = &(video_buff[0]);
	p_next_ready_buff = &(video_buff[0]);

	// use fifo mode
	update_buffer_fifo_mode();
    
    signal(SIGALRM, free_buffer_alarm_fn);
}
    

Memory_Manager::~Memory_Manager()
{
    ALOGI("[Memory_Manager::~Memory_Manager] enter ");
    for(int i=0; i < current_buff_num; i++){
        if((NULL != video_buff[i].pbuf))
            free(video_buff[i].pbuf);
        
        video_buff[i].pbuf = NULL;
        clear_buffer(i);
		video_buff[i].next = NULL;
		video_buff[i].pre = NULL;
    }
	p_next_null_buff = NULL;
	p_next_ready_buff = NULL;
}


void Memory_Manager::clear_buffer(int index)
{                
    video_buff[index].is_ready = false;
    video_buff[index].is_using = false;
    video_buff[index].lengh_buf = 0;
	video_buff[index].timeStamp = 0;
    video_buff[index].unused_cnt = BUFFER_AUTO_CLEAR_TIME;
    ALOGI("[Memory_Manager::clear_buffer] start clear video_buff_%d, size=%d +++ ",  index , video_buff[index].lengh_buf);
}

void Memory_Manager::clear_buffer(Video_Buffer_t * p_buff)
{                 
    p_buff->is_ready = false;
    p_buff->is_using = false;
    p_buff->lengh_buf = 0;
	p_buff->timeStamp = 0;
    p_buff->unused_cnt = BUFFER_AUTO_CLEAR_TIME;
    ALOGI("[Memory_Manager::clear_buffer] start clear video_buff_%d, size=%d +++ ",  p_buff->index , p_buff->lengh_buf);
}

void Memory_Manager::clear_an_old_buff(void)
{                
	Video_Buffer_t * p_buff = p_next_null_buff;
	int i = 0;
	int return_flag = 0;

	while(p_buff != NULL)
	{
		if( (p_buff->pbuf)[4] & 0xf == 0x7 ){
			ALOGI("[Memory_Manager::get_buffer_for_I] let data go ****** ######, skip it , index=%d, lengh_buf=%d, I_data(0x%x)=0x%x +++ ",  
							p_buff->index , p_buff->lengh_buf, (p_buff->pbuf)[4] , 0xf & ((p_buff->pbuf)[4]) );
			p_buff = p_buff->next;
			continue;		
		}

		if(return_flag == 1){
			ALOGI("[Memory_Manager::get_buffer_for_I] let data go ****** , flag=%d, start to clear buff index=%d, lengh_buf=%d, I_data(0x%x)=0x%x +++ ",  
							return_flag, p_buff->index , p_buff->lengh_buf, (p_buff->pbuf)[4] , 0xf & ((p_buff->pbuf)[4]) );

			memset(p_buff->pbuf , 0 , BUFFER_SIZE);
			clear_buffer(p_buff);
			p_next_null_buff = p_buff;	
			break;	
		}

		
		if(p_buff->lengh_buf >= 900){
			ALOGI("[Memory_Manager::get_buffer_for_I] let data go ****** ######, skip it , index=%d, lengh_buf=%d, I_data(0x%x)=0x%x +++ ",  
							p_buff->index , p_buff->lengh_buf, (p_buff->pbuf)[4] , 0xf & ((p_buff->pbuf)[4]) );
			p_buff = p_buff->next;
			continue;	
		}
		else
		{
			ALOGI("[Memory_Manager::get_buffer_for_I] let data go ****** , start to clear buff index=%d, lengh_buf=%d, I_data(0x%x)=0x%x +++ ",  
							p_buff->index , p_buff->lengh_buf, (p_buff->pbuf)[4] , 0xf & ((p_buff->pbuf)[4]) );

			memset(p_buff->pbuf , 0 , BUFFER_SIZE);
			clear_buffer(p_buff);
			p_next_null_buff = p_buff;
			break;
		}


		if(return_flag != 1){
			i++;
			if(i > current_buff_num){
				p_buff = p_next_null_buff;
				return_flag = 1;
			}	
		}
	}
}


void Memory_Manager::update_buffer_fifo_mode()
{
	if( p_next_null_buff != NULL )
	{
		if(p_next_ready_buff != NULL)
		{
			ALOGI("[Memory_Manager::%s - %d] +++ current_buff_num=%d , next_null index=%d, next_ready index=%d", 	__func__, __LINE__,
								current_buff_num,  p_next_null_buff->index,  p_next_ready_buff->index);
		}else{
			ALOGI("[Memory_Manager::%s - %d] +++ current_buff_num=%d , next_null index=%d, next_ready index is NULL ", 	__func__, __LINE__,
								current_buff_num,  p_next_null_buff->index );
		}
	}

    for(int i=0; i < current_buff_num; i++){
		if(i == 0){
			video_buff[i].next = &video_buff[i+1];
			video_buff[i].pre = &video_buff[current_buff_num-1];
		}else if(i == (current_buff_num-1)){
			video_buff[i].next = &video_buff[0];
			video_buff[i].pre = &video_buff[i-1];
		}else{
			video_buff[i].next = &video_buff[i+1];
			video_buff[i].pre = &video_buff[i-1];
		}
		ALOGI("[Memory_Manager::%s - %d] ", __func__, __LINE__);
		
		ALOGI("[Memory_Manager::%s - %d]  %d <- [%d] -> %d) \n", __func__, __LINE__,
					(video_buff[i].next)->index, video_buff[i].index, (video_buff[i].pre)->index);
		
    }
	
	for(int i=current_buff_num; i < BUFFER_NUM_MAX; i++){ // 2 3 4
		video_buff[i].next = NULL;
		video_buff[i].pre = NULL;
    }
}


Video_Buffer_t * Memory_Manager::get_null_buffer(uint32_t size, uint32_t i_5_data)
{
	Video_Buffer_t * p_buff = p_next_null_buff;

	
	if( (p_buff != NULL) && (0 == p_buff->lengh_buf) && (false == p_buff->is_using) && (false == p_buff->is_ready))
	{
		p_next_null_buff = p_buff->next;
		ALOGI("[Memory_Manager::get_null_buffer ok] return index = %d , next index= %d +++ ", p_buff->index, p_next_null_buff->index);
		
		return p_buff;
	}
			

	

    /// TODO CHECK:  Buffer is not enough, alloc a new one
    if(current_buff_num < BUFFER_NUM_MAX){
        
        current_buff_num++;
        ALOGI("[Memory_Manager::get_null_buffer] Buffer is not enough, alloc a new one, current_buff_num=%d ", current_buff_num);
        
        clear_buffer( current_buff_num-1 );

        video_buff[ current_buff_num-1 ].pbuf = (uint8_t *) malloc(BUFFER_SIZE);
        
        video_buff[ current_buff_num-1].unused_cnt = BUFFER_AUTO_CLEAR_TIME;
		
		// use fifo mode, not  update here
		update_buffer_fifo_mode();
		
		p_buff = &video_buff[ current_buff_num-1];
		p_next_null_buff = p_buff->next;

		ALOGI("[Memory_Manager::get_null_buffer] Buffer is not enough, return index = %d , next index= %d +++ ", p_buff->index, p_next_null_buff->index);

        
        // TODO: start a timer every 1s, Check if need free then
        alarm(1);

        return p_buff;
    }
	else
	{
		ALOGI("[Memory_Manager::get_null_buffer] let data go ++++++,  current_buff_num=%d, current index=%d / lengh_buf=%d, next nPktSize=%d, i_5_data(0x%x)=0x%x\n",
             current_buff_num , p_buff->index,  p_buff->lengh_buf , size, i_5_data, i_5_data & 0x0f);
	}

	clear_an_old_buff();

	p_buff = p_next_null_buff;
	p_next_null_buff = p_buff->next;

    ALOGI("[Memory_Manager::get_null_buffer] let data go ------ ,  current_buff_num=%d,return index = %d, next nPktSize=%d, i_5_data(0x%x)=0x%x", 
							current_buff_num , p_buff->index , size, i_5_data, i_5_data & 0x0f);
    return p_buff;
}


// get a data to upload
Video_Buffer_t *  Memory_Manager::get_ready_buffer(int t)
{
	Video_Buffer_t * p_buff = NULL;
	
	// get the next buff
	if( NULL == p_next_ready_buff) // For first pop
	{  
		p_buff = &(video_buff[0]);
		p_next_ready_buff = &(video_buff[0]);
		ALOGI_D("[Memory_Manager::get_ready_buffer] set next display buff = buff[%d] ",p_next_ready_buff->index);
	}
	else
	{
		p_buff = p_next_ready_buff;
	}
	
	// check and return
	if( p_buff != NULL )
	{		 
		if((0 != p_buff->lengh_buf) && (true == p_buff->is_ready))
		{ 
			p_next_ready_buff = p_buff->next;
			ALOGI_D("[Memory_Manager::get_ready_buffer ok] return current index = %d , next index= %d +++ ", p_buff->index, p_next_null_buff->index);
			
			return p_buff;
		}
	}

	//print log if error
	ALOGI_D("[Memory_Manager::get_ready_buffer] p_next_ready_buff is_ready=%d, is_using=%d, pbuf not null=%d, lengh_buf=%d, index=%d \n",
             p_buff->is_ready, 
             p_buff->is_using, 
             (NULL != p_buff->pbuf) ? 1 : 0, 
             p_buff->lengh_buf, 
             p_buff->index );

	if(t == 1)
		ALOGI_D("[Memory_Manager::get_ready_buffer] has no ready buff !!! ");
    
    return NULL;
}

int Memory_Manager::push_buffer_data(const uint8_t *pPacket, uint32_t nPktSize, int64_t timeStamp)
{
    Video_Buffer_t * p_buff = NULL;
	uint8_t  i_4_data_tmp = pPacket[4];

    p_buff = get_null_buffer(nPktSize, i_4_data_tmp);
    
    if( (0 != p_buff->lengh_buf) ){
		ALOGI_D("[Memory_Manager::push_buffer_data] lengh_buf = %d, return  ", p_buff->lengh_buf);
    
        return -1;
    }
    
    p_buff->lengh_buf = nPktSize;
	p_buff->timeStamp = timeStamp;
    memcpy(p_buff->pbuf, (uint8_t *)pPacket, nPktSize);
    
    p_buff->is_ready = true;
    p_buff->is_using = false;

	if( NULL == p_next_ready_buff) // For first pop
	{  
		p_next_ready_buff = p_buff;
		ALOGI_D("[Memory_Manager::push_buffer_data] set next display buff = buff[%d] ",p_next_ready_buff->index);
	}
  
    return 0;
}


void Memory_Manager::pop_buffer_data(void)
{
	Video_Buffer_t * p_buff = NULL;
    p_buff = get_ready_buffer(0);
        
    while(p_buff != NULL)
    {
        p_buff->is_using = true;
        
        sendVideoDataNative(p_buff->pbuf, p_buff->lengh_buf, p_buff->timeStamp);
		ALOGI_D("[Memory_Manager::pop_buffer_data] buff=%p, index=%d, nPktSize = %d,  timeStamp = %ll",p_buff,  p_buff->index,  p_buff->lengh_buf, p_buff->timeStamp);
        
        memset(p_buff->pbuf , 0 , BUFFER_SIZE);
        clear_buffer(p_buff);
        
		// get next ok buffer
        p_buff = get_ready_buffer(1);
    }
}


发布了329 篇原创文章 · 获赞 66 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Ciellee/article/details/102566712