FFmpeg学习之七(视音频流缓存) 您所在的位置:网站首页 ffmpeg缓存几秒录视频 FFmpeg学习之七(视音频流缓存)

FFmpeg学习之七(视音频流缓存)

2024-06-02 16:21| 来源: 网络整理| 查看: 265

FFmpeg学习之七(视音频流缓存) 缓存队列实现源码下载1.原理2.实现细节2.1 结构体定义2.2 类定义2.3 初始化队列2.4 入队2.5 出队2.6 重置空闲队列数据 3.完整代码4.调用缓存队列实例 循环缓存队列实现原理实现细节完整代码

缓存队列实现 源码下载 视频音频缓存队列实现源码demo 1.原理

初始化固定数量的结点装入空闲队列,当相机回调产生数据后,从空闲队列头部取出一个结点将产生的每一帧图像buffer装入,然后入队到工作队列的尾部,处理buffer的线程从工作队列的头部取出一个结点中的Buffer进行处理,处理完成后会将装有次buffer的结点中data置空并重新放入空闲队列的头部以供下次使用。

我们将空闲队列设计为头进头出,影响不大,因为我们每次只需要从空闲队列中取出一个空结点以供我们装入相机数据,所以没必要按照尾进头出的方式保证结点的顺序。 我们将工作队列设计为尾进头出,因为我们要确保从相机中捕获的数据是连续的,以便后期我们播放出来的画面也是连续的,所以工作队列必须保证尾进头出。 这样做我们相当于实现了用空闲队列当做缓冲队列,在正常情况下(fps=30,即每秒产生30帧数据,大约每33ms产生一帧数据),如果在33ms内对数据进行的操作可以正常完成,则工作队列会保持始终为0或1,但是如果长期工作或遇到某一帧数据处理较慢的情况(即处理时间大于33ms)则工作队列的长度会增加,而正因为我们使用了这样的队列会保护那一帧处理慢的数据在仍然能够正常处理完。 注意:这种情景仅用于短时间内仅有几帧数据处理较慢,如果比如1s内有20几帧数据都处理很慢则可能导致工作队列太长,则体现不出此队列的优势。

2.实现细节 2.1 结构体定义 节点 typedef struct KYLCustomQueueNode { void *data;//结点中使用void *类型的data存放我们需要的sampleBuffer,使用index记录当前装入结点的sampleBuffer的索引, //以便我们在取出结点时比较是否是按照顺序取出,结点中还装着同类型下一个结点的元素。 size_t size; // data size 数据大小 long index; struct KYLCustomQueueNode *next; //记录下一个节点指针 } KYLCustomQueueNode;

结点中使用void *类型的data存放我们需要的sampleBuffer,使用index记录当前装入结点的sampleBuffer的索引,以便我们在取出结点时比较是否是按照顺序取出,结点中还装着同类型下一个结点的元素。

队列类型 //队列中即为我们装载的结点数量,因为我们采用的是预先分配固定内存, //所以工作队列与空闲队列的和始终不变(因为结点中的元素不在工作队列就在空闲队列) typedef struct KYLCustomQueue { int size; KYLCustomQueueType type; //队列类型 KYLCustomQueueNode *front; //队列头 KYLCustomQueueNode *rear; //队列尾 } KYLCustomQueue;

队列中即为我们装载的结点数量,因为我们采用的是预先分配固定内存,所以工作队列与空闲队列的和始终不变(因为结点中的元素不在工作队列就在空闲队列)

2.2 类定义 class KYLQueue { public: KYLCustomQueue *m_free_queue;//空闲队列 KYLCustomQueue *m_work_queue;//工作队列 KYLQueue(); ~KYLQueue(); // Queue Operation /** 初始化队列 @param queue 队列指针 KYLCustomQueue @param type 队列类型 KYLCustomQueueType */ void InitQueue(KYLCustomQueue *queue, KYLCustomQueueType type); /** 入队 @param queue 队列指针 KYLCustomQueue @param node 队列类型 KYLCustomQueueType */ void EnQueue(KYLCustomQueue *queue, KYLCustomQueueNode *node); /** 出队 @param queue 队列指针 KYLCustomQueue @return 出队的节点指针 KYLCustomQueueNode */ KYLCustomQueueNode *DeQueue(KYLCustomQueue *queue); /** 清空队列 @param queue 队列指针KYLCustomQueue */ void ClearKYLCustomQueue(KYLCustomQueue *queue); /** 释放节点 @param node 节点指针KYLCustomQueueNode */ void FreeNode(KYLCustomQueueNode* node); /** 重置队列,释放工作队列和空闲队列资源 @param workQueue 工作队列指针 KYLCustomQueue @param freeQueue 空闲队列指针 KYLCustomQueue */ void ResetFreeQueue(KYLCustomQueue *workQueue, KYLCustomQueue *freeQueue); private: pthread_mutex_t free_queue_mutex; //互斥锁 pthread_mutex_t work_queue_mutex; };

因为涉及到异步操作,所以需要对结点的操作加锁,使用时需要先初始化队列,然后定义了入队,出队,清除队列中元素,释放结点,重置空闲队列等操作。

2.3 初始化队列 #pragma mark - Queue Size 设置队列的长度,不可过长 const int KYLCustomQueueSize = 3; KYLQueue::KYLQueue(){ m_free_queue = (KYLCustomQueue *)malloc(sizeof(struct KYLCustomQueue)); m_work_queue = (KYLCustomQueue *)malloc(sizeof(struct KYLCustomQueue)); InitQueue(m_free_queue, KYLCustomFreeQueue); InitQueue(m_work_queue, KYLCustomWorkQueue); for (int i = 0; i if (queue == NULL) { log4cplus_debug(kModuleName, "%s: current queue is NULL",__func__); return; } if (node==NULL) { log4cplus_debug(kModuleName, "%s: current node is NULL",__func__); return; } node->next = NULL; if (KYLCustomFreeQueue == queue->type) { pthread_mutex_lock(&free_queue_mutex); if (queue->front == NULL) { queue->front = node; queue->rear = node; }else { /* // tail in,head out freeQueue->rear->next = node; freeQueue->rear = node; */ // head in,head out node->next = queue->front; queue->front = node; } queue->size += 1; log4cplus_debug(kModuleName, "%s: free queue size=%d",__func__,queue->size); pthread_mutex_unlock(&free_queue_mutex); } if (KYLCustomWorkQueue == queue->type) { pthread_mutex_lock(&work_queue_mutex); //TODO static long nodeIndex = 0; node->index=(++nodeIndex); if (queue->front == NULL) { queue->front = node; queue->rear = node; }else { queue->rear->next = node; queue->rear = node; } queue->size += 1; log4cplus_debug(kModuleName, "%s: work queue size=%d",__func__,queue->size); pthread_mutex_unlock(&work_queue_mutex); } } 2.5 出队

出队操作无论空闲队列还是工作队列都是从头出,即取出当前队列头结点中的数据。

代码如下:

/** 出队 @param queue 队列指针 KYLCustomQueue @return 出队的节点指针 KYLCustomQueueNode */ KYLCustomQueueNode* KYLQueue::DeQueue(KYLCustomQueue *queue) { if (queue == NULL) { log4cplus_debug(kModuleName, "%s: current queue is NULL",__func__); return NULL; } const char *type = queue->type == KYLCustomWorkQueue ? "work queue" : "free queue"; pthread_mutex_t *queue_mutex = ((queue->type == KYLCustomWorkQueue) ? &work_queue_mutex : &free_queue_mutex); KYLCustomQueueNode *element = NULL; pthread_mutex_lock(queue_mutex); element = queue->front; if(element == NULL) { pthread_mutex_unlock(queue_mutex); log4cplus_debug(kModuleName, "%s: The node is NULL",__func__); return NULL; } queue->front = queue->front->next; queue->size -= 1; pthread_mutex_unlock(queue_mutex); log4cplus_debug(kModuleName, "%s: type=%s size=%d",__func__,type,queue->size); return element; }

注意:该结点为空与该结点中的数据为空不可混为一谈,如果该结点为空则说明没有从队列中取出结点,即空结点没有内存地址,而结点中的数据则为node->data,在本Demo中为相机产生的每一帧sampleBuffer数据。

2.6 重置空闲队列数据

当我们将执行一些中断操作,例如从本View跳转到其他View,或进入后台等操作,我们需要将工作队列中的结点均置空然后重新放回空闲队列,这样可以保证我们最初申请的结点还均有效可用,保证结点不会丢失。

代码如下:

/** 重置队列,释放工作队列和空闲队列资源 @param workQueue 工作队列指针 KYLCustomQueue @param freeQueue 空闲队列指针 KYLCustomQueue */ void KYLQueue::ResetFreeQueue(KYLCustomQueue *workQueue, KYLCustomQueue *freeQueue) { if (workQueue == NULL) { log4cplus_debug(kModuleName, "%s: The WorkQueue is NULL",__func__); return; } if (freeQueue == NULL) { log4cplus_debug(kModuleName, "%s: The FreeQueue is NULL",__func__); return; } int workQueueSize = workQueue->size; if (workQueueSize > 0) { for (int i = 0; i KYLCustomWorkQueue, KYLCustomFreeQueue } KYLCustomQueueType; typedef struct KYLCustomQueueNode { void *data;//结点中使用void *类型的data存放我们需要的sampleBuffer,使用index记录当前装入结点的sampleBuffer的索引, //以便我们在取出结点时比较是否是按照顺序取出,结点中还装着同类型下一个结点的元素。 size_t size; // data size 数据大小 long index; struct KYLCustomQueueNode *next; //记录下一个节点指针 } KYLCustomQueueNode; //队列中即为我们装载的结点数量,因为我们采用的是预先分配固定内存, //所以工作队列与空闲队列的和始终不变(因为结点中的元素不在工作队列就在空闲队列) typedef struct KYLCustomQueue { int size; KYLCustomQueueType type; //队列类型 KYLCustomQueueNode *front; //队列头 KYLCustomQueueNode *rear; //队列尾 } KYLCustomQueue; class KYLQueue { public: KYLCustomQueue *m_free_queue;//空闲队列 KYLCustomQueue *m_work_queue;//工作队列 KYLQueue(); ~KYLQueue(); // Queue Operation /** 初始化队列 @param queue 队列指针 KYLCustomQueue @param type 队列类型 KYLCustomQueueType */ void InitQueue(KYLCustomQueue *queue, KYLCustomQueueType type); /** 入队 @param queue 队列指针 KYLCustomQueue @param node 队列类型 KYLCustomQueueType */ void EnQueue(KYLCustomQueue *queue, KYLCustomQueueNode *node); /** 出队 @param queue 队列指针 KYLCustomQueue @return 出队的节点指针 KYLCustomQueueNode */ KYLCustomQueueNode *DeQueue(KYLCustomQueue *queue); /** 清空队列 @param queue 队列指针KYLCustomQueue */ void ClearKYLCustomQueue(KYLCustomQueue *queue); /** 释放节点 @param node 节点指针KYLCustomQueueNode */ void FreeNode(KYLCustomQueueNode* node); /** 重置队列,释放工作队列和空闲队列资源 @param workQueue 工作队列指针 KYLCustomQueue @param freeQueue 空闲队列指针 KYLCustomQueue */ void ResetFreeQueue(KYLCustomQueue *workQueue, KYLCustomQueue *freeQueue); private: pthread_mutex_t free_queue_mutex; //互斥锁 pthread_mutex_t work_queue_mutex; }; NS_ASSUME_NONNULL_END 实现文件 // // KYLQueue.m // yuvShowKYLDemo // // Created by yulu kong on 2019/7/31. // Copyright © 2019 yulu kong. All rights reserved. // /******************************************************************************************************************* 我们将空闲队列设计为头进头出,影响不大,因为我们每次只需要从空闲队列中取出一个空结点以供我们装入相机数据,所以没必要按照尾进头出的方式保证结点的顺序。 我们将工作队列设计为尾进头出,因为我们要确保从相机中捕获的数据是连续的,以便后期我们播放出来的画面也是连续的,所以工作队列必须保证尾进头出。 这样做我们相当于实现了用空闲队列当做缓冲队列,在正常情况 (fps=30,即每秒产生30帧数据,大约每33ms产生一帧数据),如果在33ms内对数据进行的操作可以正常完成,则工作队列会保持始终为0或1, 但是如果长期工作或遇到某一帧数据处理较慢的情况(即处理时间大于33ms)则工作队列的长度会增加, 而正因为我们使用了这样的队列会保护那一帧处理慢的数据在仍然能够正常处理完。 这种情景仅用于短时间内仅有几帧数据处理较慢,如果比如1s内有20几帧数据都处理很慢则可能导致工作队列太长,则体现不出此队列的优势。 ********************************************************************************************************************/ #import "KYLQueue.h" #import #include "log4cplus.h" #pragma mark - Queue Size 设置队列的长度,不可过长 const int KYLCustomQueueSize = 3; const static char *kModuleName = "KYLQueueProcess"; #pragma mark - Init //构造函数 KYLQueue::KYLQueue(){ m_free_queue = (KYLCustomQueue *)malloc(sizeof(struct KYLCustomQueue)); m_work_queue = (KYLCustomQueue *)malloc(sizeof(struct KYLCustomQueue)); InitQueue(m_free_queue, KYLCustomFreeQueue); InitQueue(m_work_queue, KYLCustomWorkQueue); for (int i = 0; i if (queue != NULL) { queue->type = type; queue->size = 0; queue->front = 0; queue->rear = 0; } } #pragma mark - Main Operation /** 入队 @param queue 队列指针 KYLCustomQueue @param node 队列类型 KYLCustomQueueType */ void KYLQueue::EnQueue(KYLCustomQueue *queue, KYLCustomQueueNode *node) { if (queue == NULL) { log4cplus_debug(kModuleName, "%s: current queue is NULL",__func__); return; } if (node==NULL) { log4cplus_debug(kModuleName, "%s: current node is NULL",__func__); return; } node->next = NULL; if (KYLCustomFreeQueue == queue->type) { pthread_mutex_lock(&free_queue_mutex); if (queue->front == NULL) { queue->front = node; queue->rear = node; }else { /* // tail in,head out freeQueue->rear->next = node; freeQueue->rear = node; */ // head in,head out node->next = queue->front; queue->front = node; } queue->size += 1; log4cplus_debug(kModuleName, "%s: free queue size=%d",__func__,queue->size); pthread_mutex_unlock(&free_queue_mutex); } if (KYLCustomWorkQueue == queue->type) { pthread_mutex_lock(&work_queue_mutex); //TODO static long nodeIndex = 0; node->index=(++nodeIndex); if (queue->front == NULL) { queue->front = node; queue->rear = node; }else { queue->rear->next = node; queue->rear = node; } queue->size += 1; log4cplus_debug(kModuleName, "%s: work queue size=%d",__func__,queue->size); pthread_mutex_unlock(&work_queue_mutex); } } /** 出队 @param queue 队列指针 KYLCustomQueue @return 出队的节点指针 KYLCustomQueueNode */ KYLCustomQueueNode* KYLQueue::DeQueue(KYLCustomQueue *queue) { if (queue == NULL) { log4cplus_debug(kModuleName, "%s: current queue is NULL",__func__); return NULL; } const char *type = queue->type == KYLCustomWorkQueue ? "work queue" : "free queue"; pthread_mutex_t *queue_mutex = ((queue->type == KYLCustomWorkQueue) ? &work_queue_mutex : &free_queue_mutex); KYLCustomQueueNode *element = NULL; pthread_mutex_lock(queue_mutex); element = queue->front; if(element == NULL) { pthread_mutex_unlock(queue_mutex); log4cplus_debug(kModuleName, "%s: The node is NULL",__func__); return NULL; } queue->front = queue->front->next; queue->size -= 1; pthread_mutex_unlock(queue_mutex); log4cplus_debug(kModuleName, "%s: type=%s size=%d",__func__,type,queue->size); return element; } /** 重置队列,释放工作队列和空闲队列资源 @param workQueue 工作队列指针 KYLCustomQueue @param freeQueue 空闲队列指针 KYLCustomQueue */ void KYLQueue::ResetFreeQueue(KYLCustomQueue *workQueue, KYLCustomQueue *freeQueue) { if (workQueue == NULL) { log4cplus_debug(kModuleName, "%s: The WorkQueue is NULL",__func__); return; } if (freeQueue == NULL) { log4cplus_debug(kModuleName, "%s: The FreeQueue is NULL",__func__); return; } int workQueueSize = workQueue->size; if (workQueueSize > 0) { for (int i = 0; i while (queue->size) { KYLCustomQueueNode *node = this->DeQueue(queue); this->FreeNode(node); } log4cplus_info(kModuleName, "%s: Clear KYLQueue queue",__func__); } /** 释放节点 @param node 节点指针KYLCustomQueueNode */ void KYLQueue::FreeNode(KYLCustomQueueNode* node) { if(node != NULL){ free(node->data); free(node); } } 4.调用缓存队列实例 将samplebuffer放入空闲队列 设置相机代理后,在 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 方法中将samplebuffer装入空闲队列 代码如下: #pragma mark ------------------AVCaptureVideoDataOutputSampleBufferDelegate-------------------------------- // Called whenever an AVCaptureVideoDataOutput instance outputs a new video frame. 每产生一帧视频帧时调用一次 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { // if(!CMSampleBufferDataIsReady(sampleBuffer)) { // NSLog( @"sample buffer is not ready. Skipping sample" ); // return; // } // 将相机产生的Samplebuffer入队 [self addBufferToWorkQueueWithSampleBuffer:sampleBuffer]; } - (void)addBufferToWorkQueueWithSampleBuffer:(CMSampleBufferRef)sampleBuffer { KYLCustomQueueNode *node = _captureBufferQueue->DeQueue(_captureBufferQueue->m_free_queue); if (node == NULL) { log4cplus_debug(kModuleName, "Data in , the node is NULL !"); return; } CFRetain(sampleBuffer); node->data = sampleBuffer; _captureBufferQueue->EnQueue(_captureBufferQueue->m_work_queue, node); log4cplus_debug(kModuleName, "Data in , work size = %d, free size = %d !",_captureBufferQueue->m_work_queue->size, _captureBufferQueue->m_free_queue->size); }

注意:因为相机回调中捕捉的sampleBuffer是有生命周期的所以需要手动CFRetain一下使我们队列中的结点持有它。

开启一条线程处理队列中的Buffer

使用pthread创建一条线程,每隔10ms取一次数据,我们可以在此对取到的数据进行我们想要的操作,操作完成后再将清空释放sampleBuffer再将其装入空闲队列供我们循环使用。

代码如下:

#pragma mark - 处理Samplebuffer的线程 - (void)handleCacheThread { while (true) { // 从队列取出在相机回调中放入队列的线程 KYLCustomQueueNode *node = _captureBufferQueue->DeQueue(_captureBufferQueue->m_work_queue); if (node == NULL) { log4cplus_debug(kModuleName, "Data node is NULL"); usleep(10*1000); continue; } CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)node->data; // 打印结点的index,如果连续则说明在相机回调中放入的samplebuffer是连续的 log4cplus_debug(kModuleName, "Test index : %ld",node->index); /* 可在此处理从队列中拿到的Buffer,用完后记得释放内存并将结点重新放回空闲队列 * ........ */ CFRelease(sampleBuffer); node->data = NULL; _captureBufferQueue->EnQueue(_captureBufferQueue->m_free_queue, node); } } void * startCropTask(void *param) { pthread_setname_np("TVUCropThread"); KYLTestBufferController *obj = (__bridge_transfer KYLTestBufferController *)param; [obj handleCacheThread]; return NULL; } 循环缓存队列实现 原理 实现细节 完整代码 头文件: // // KYLCircleBuf.h // yuvShowKYLDemo // // Created by yulu kong on 2019/7/27. // Copyright © 2019 yulu kong. All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN typedef struct tag_AV_VIDEO_BUF_HEAD { unsigned int head; /* Õ∑£¨±ÿ–ε»”⁄0xFF00FF */ unsigned int timestamp; // ±º‰¥¡£¨»Áπ˚ «¬ºœÒ£¨‘ÚÃÓ¬ºœÒµƒ ±º‰¥¡£¨»Áπ˚ « µ ± ”∆µ£¨‘ÚŒ™0 unsigned int len; /*≥§∂»*/ unsigned int frametype; }AV_VIDEO_BUF_HEAD; typedef struct tag_stAVStreamHead { unsigned int nCodecID; // refer to SEP2P_ENUM_AV_CODECID char nParameter; // Video: refer to SEP2P_ENUM_VIDEO_FRAME. Audio:(samplerate return m_bCreateBufSucceed;} char * ReadOneFrame(int &len); char* ReadOneFrame1(int &len, AV_VIDEO_BUF_HEAD & videobufhead); char* ReadOneFrame2(int &len, AV_STREAM_HEAD & videobufhead); private: int Read1(void* buf, int size); protected: char* m_pBuf; int m_nSize; int m_nStock; int m_nReadPos; int m_nWritePos; int m_nTimeout; NSCondition *m_Lock; private: int m_n; bool m_bCreateBufSucceed; }; NS_ASSUME_NONNULL_END 实现文件: // // KYLCircleBuf.m // yuvShowKYLDemo // // Created by yulu kong on 2019/7/27. // Copyright © 2019 yulu kong. All rights reserved. // #import "KYLCircleBuf.h" KYLCircleBuf::KYLCircleBuf() { m_pBuf = NULL; m_nSize = 0; m_nStock= 0; m_nWritePos= 0; m_nReadPos = 0; m_bCreateBufSucceed = false; m_Lock = [[NSCondition alloc] init]; } KYLCircleBuf::~KYLCircleBuf() { Release(); //[m_Lock release]; m_Lock = nil; } bool KYLCircleBuf::Create(int size) { if (size delete[] m_pBuf; m_pBuf = NULL; } m_pBuf = new char[size]; if(m_pBuf == NULL) { m_bCreateBufSucceed = false; return false; } m_nSize = size; m_nStock = 0; m_nWritePos = 0; m_nReadPos = 0; m_bCreateBufSucceed = true; return true; } void KYLCircleBuf::Release() { [m_Lock lock]; m_bCreateBufSucceed = false; if (m_pBuf == NULL) { [m_Lock unlock]; return; } if(m_pBuf != NULL) { delete[] m_pBuf; m_pBuf = NULL; } m_nSize = 0; m_nStock = 0; m_nReadPos = 0; m_nWritePos = 0; [m_Lock unlock]; } char* KYLCircleBuf::ReadOneFrame1(int &len, AV_VIDEO_BUF_HEAD & videobufhead) { [m_Lock lock]; len = 0; if(m_nStock == 0) { [m_Lock unlock]; return NULL; } char *pbuf = NULL; AV_VIDEO_BUF_HEAD videohead; int nRet = Read1((char*)&videohead, sizeof(AV_VIDEO_BUF_HEAD)); if(nRet == 0) { [m_Lock unlock]; return NULL; } pbuf = new char[videohead.len] ; nRet = Read1((char*)pbuf, videohead.len); if(nRet == 0) { delete []pbuf; pbuf = NULL; [m_Lock unlock]; return NULL; } memcpy((char*)&videobufhead, (char*)&videohead, sizeof(AV_VIDEO_BUF_HEAD)); len = videohead.len; [m_Lock unlock]; return pbuf; } char* KYLCircleBuf::ReadOneFrame2(int &len, AV_STREAM_HEAD & streambufhead) { [m_Lock lock]; len = 0; if(m_nStock == 0) { [m_Lock unlock]; return NULL; } char *pbuf = NULL; AV_STREAM_HEAD streamhead; int nRet = Read1((char*)&streamhead, sizeof(AV_STREAM_HEAD)); if(nRet == 0) { [m_Lock unlock]; return NULL; } pbuf = new char[streamhead.nStreamDataLen] ; nRet = Read1((char*)pbuf, streamhead.nStreamDataLen); if(nRet == 0) { delete []pbuf; pbuf = NULL; [m_Lock unlock]; return NULL; } memcpy((char*)&streambufhead, (char*)&streamhead, sizeof(AV_STREAM_HEAD)); len = streamhead.nStreamDataLen; [m_Lock unlock]; return pbuf; } char* KYLCircleBuf::ReadOneFrame(int &len) { [m_Lock lock]; len = 0; if(m_nStock == 0) { [m_Lock unlock]; return NULL; } char *pbuf = NULL; AV_VIDEO_BUF_HEAD videohead; int nRet = Read1((char*)&videohead, sizeof(AV_VIDEO_BUF_HEAD)); if(nRet == 0) { [m_Lock unlock]; return NULL; } pbuf = new char[videohead.len] ; if(pbuf == NULL) { [m_Lock unlock]; return NULL; } nRet = Read1((char*)pbuf, videohead.len); if(nRet == 0) { delete []pbuf; pbuf = NULL; [m_Lock unlock]; return NULL; } len = videohead.len; [m_Lock unlock]; return pbuf; } int KYLCircleBuf::Read1(void* buf, int size) { if (m_nStock memcpy(buf, &m_pBuf[m_nReadPos], size); m_nReadPos += size; } else { offs = m_nSize - m_nReadPos; if (offs > size) { memcpy(buf, &m_pBuf[m_nReadPos], size); m_nReadPos += size; } else { memcpy(buf, &m_pBuf[m_nReadPos], offs); left = size - offs; memcpy(&((char*)buf)[offs], m_pBuf, left); m_nReadPos = left; } } m_nStock -= size; return size; } //从缓存中读数据,当缓存数据不够读则读取失败,返回为0 int KYLCircleBuf::Read(void* buf, int size) { //Lock the buffer [m_Lock lock]; if (m_nStock memcpy(buf, &m_pBuf[m_nReadPos], size); m_nReadPos += size; } else { offs = m_nSize - m_nReadPos; if (offs > size) { memcpy(buf, &m_pBuf[m_nReadPos], size); m_nReadPos += size; } else { memcpy(buf, &m_pBuf[m_nReadPos], offs); left = size - offs; memcpy(&((char*)buf)[offs], m_pBuf, left); m_nReadPos = left; } } m_nStock -= size; [m_Lock unlock]; return size; } int KYLCircleBuf::ReadByPeer(void* buf, int size) { //Lock the buffer [m_Lock lock]; if(m_nStock memcpy(buf, &m_pBuf[m_nReadPos], size); }else{ offs = m_nSize - m_nReadPos; if(offs > size) { memcpy(buf, &m_pBuf[m_nReadPos], size); }else{ memcpy(buf, &m_pBuf[m_nReadPos], offs); left = size - offs; memcpy(&((char*)buf)[offs], m_pBuf, left); //m_nReadPos = left; } } [m_Lock unlock]; return size; } int KYLCircleBuf::Write(void* buf, int size) { //Lock the buffer [m_Lock lock]; // the buffer is full if (m_nStock + size > m_nSize) { [m_Lock unlock]; return 0; } int left = 0; int offs = m_nSize - m_nWritePos; if (offs > size) { memcpy(&m_pBuf[m_nWritePos], buf, size); m_nWritePos += size; } else { memcpy(&m_pBuf[m_nWritePos], buf, offs); left = size - offs; memcpy(m_pBuf, &((char*)buf)[offs], left); m_nWritePos = left; } m_nStock += size; [m_Lock unlock]; return size; } int KYLCircleBuf::GetStock() { int n; [m_Lock lock]; n = m_nStock; [m_Lock unlock]; return n; } void KYLCircleBuf::Reset() { [m_Lock lock]; m_nReadPos = 0; m_nWritePos = 0; m_nStock = 0; [m_Lock unlock]; }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有