Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————结合三个部分工作

前面三篇文章分别介绍了视频捕获、h264视频压缩、帧缓冲显示的实现, 现在将他们结合起来

摄像头采集到的数据, 需要交给视频压缩线程、显示线程使用, 那么我采用的方法是使用队列及链表来实现:

  1. 摄像头采集到数据后, 分别放入两个处理线程队列中, 并将相关信息放入链表中

  2. 两个线程处理完成数据后, 调用回调函数, 从链表里找到对应的节点,然后释放前面申请的资源

    /* queue.h */ #ifndef QUEUE_H #define QUEUE_H

    #include <stdint.h> #include <pthread.h>

    typedef struct QueueData { void* pData; uint32_t Length; } sQueueData;

    typedef struct { sQueueData Data[CONFIG_QUEUE_SIZE]; int HeadIndex; int TailIndex; pthread_mutex_t QueueMutex; } sQueue;

    int QueueInit(sQueue* pQueuePrivateData); int QueuePutData(sQueueData* pData); // int QueuePushBack(sQueue* pQueuePrivateData, sQueueData* pData); int QueuePopData(sQueue* pQueuePrivateData, sQueueData* pData); int QueueCallback(sQueueData* pQueueData);

    #endif

    /* queue.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "config.h" #include "queue.h"

    typedef struct LinkListNode { struct LinkListNode* pNext; uint8_t Times; void* pData; } sLinkListNode;

    static struct { int Cnt; sQueue* QueueList[CONFIG_QUEUE_LIMIT]; pthread_mutex_t QueueMutex; pthread_mutex_t LinkListMutex; sLinkListNode* pLinkListRoot;

    } sQueuePrivateData;

    int LinkedListAdd(void* pData) { sLinkListNode* pTempNode = sQueuePrivateData.pLinkListRoot;

    1if(pTempNode == NULL) { 2 // printf("Debug:LinkList root empty, inited \n"); 3 sQueuePrivateData.pLinkListRoot = malloc(sizeof(sLinkListNode)); 4 sQueuePrivateData.pLinkListRoot->pNext = NULL; 5 sQueuePrivateData.pLinkListRoot->pData = pData; 6 sQueuePrivateData.pLinkListRoot->Times = 0; 7 return 0; 8} 9 10while(pTempNode->pNext != NULL) { 11 pTempNode = pTempNode->pNext; 12} 13 14pTempNode->pNext = malloc(sizeof(sLinkListNode)); 15pTempNode->pNext->pNext = NULL; 16pTempNode->pNext->pData = pData; 17pTempNode->pNext->Times = 0; 18 19return 0;

    }

    int LinkedListDel(void* pData) { sLinkListNode* pTempNode = NULL; sLinkListNode** ppPre = &sQueuePrivateData.pLinkListRoot;

    1if(*ppPre == NULL) { 2 // printf("Error: LinkList empty\n"); 3 return -1; 4} 5 6while(*ppPre != NULL) { 7 if((*ppPre)->pData == pData) { 8 if((*ppPre)->Times == CONFIG_QUEUE_LIMIT - 1) { 9 pTempNode = (*ppPre)->pNext; 10 free(pData); 11 free(*ppPre); 12 *ppPre = pTempNode; 13 // printf("Debug: free buffer\n"); 14 break; 15 } else { 16 // printf("Debug: times not equ limit: %d times\n", (*ppPre)->Times); 17 (*ppPre)->Times++; 18 break; 19 } 20 } else { 21 ppPre = &(*ppPre)->pNext; 22 // printf("Debug: ppPre: %p\n", *ppPre); 23 // printf("Debug: next\n"); 24 } 25} 26 27return 0;

    }

    int BaseQueueInit(void) { sQueuePrivateData.Cnt = 0; for(int i = 0; i < CONFIG_QUEUE_LIMIT; i++) { sQueuePrivateData.QueueList[i] = NULL; } sLinkListNode* pTempRoot = sQueuePrivateData.pLinkListRoot; sLinkListNode* pTemp = NULL; while(pTempRoot != NULL) { pTemp = pTempRoot->pNext; free(pTempRoot); pTempRoot = pTemp; } sQueuePrivateData.pLinkListRoot = NULL;

    1pthread_mutex_init(&sQueuePrivateData.QueueMutex, NULL); 2pthread_mutex_init(&sQueuePrivateData.LinkListMutex, NULL); 3return 0;

    }

    int QueueInit(sQueue* pQueuePrivateData) { if(sQueuePrivateData.Cnt > CONFIG_QUEUE_LIMIT) { printf("Queue register count over limit"); return -1; } pthread_mutex_init(&pQueuePrivateData->QueueMutex, NULL); pQueuePrivateData->HeadIndex = 0; pQueuePrivateData->TailIndex = 0; pthread_mutex_lock(&sQueuePrivateData.QueueMutex); sQueuePrivateData.QueueList[sQueuePrivateData.Cnt] = pQueuePrivateData; sQueuePrivateData.Cnt++; pthread_mutex_unlock(&sQueuePrivateData.QueueMutex); return 0; }

    static int QueuePushBack(sQueue* pQueuePrivateData, sQueueData* pData) { int HeadIndex, TailIndex, Index; pthread_mutex_lock(&pQueuePrivateData->QueueMutex); HeadIndex = pQueuePrivateData->HeadIndex; TailIndex = pQueuePrivateData->TailIndex;

    1Index = (TailIndex + 1) % CONFIG_QUEUE_SIZE; 2if(Index == HeadIndex) { 3 // printf("Warn: queue full\n"); 4 pthread_mutex_unlock(&pQueuePrivateData->QueueMutex); 5 return -1; 6} else { 7 memcpy(&pQueuePrivateData->Data[TailIndex], pData, sizeof(sQueueData)); 8 pQueuePrivateData->TailIndex = Index; 9 pthread_mutex_unlock(&pQueuePrivateData->QueueMutex); 10 return 0; 11}

    }

    int QueuePutData(sQueueData* pData) { int Ret = -1; pthread_mutex_lock(&sQueuePrivateData.QueueMutex);

    1pthread_mutex_lock(&sQueuePrivateData.LinkListMutex); 2LinkedListAdd(pData->pData); 3pthread_mutex_unlock(&sQueuePrivateData.LinkListMutex); 4 5for(int i = 0; i < sQueuePrivateData.Cnt; i++) { 6 Ret = QueuePushBack(sQueuePrivateData.QueueList[i], pData); 7 if(Ret) { 8 QueueCallback(pData); 9 } 10} 11 12pthread_mutex_unlock(&sQueuePrivateData.QueueMutex); 13return 0;

    }

    int QueuePopData(sQueue* pQueuePrivateData, sQueueData* pData) { int HeadIndex, TailIndex;

    1pthread_mutex_lock(&pQueuePrivateData->QueueMutex); 2HeadIndex = pQueuePrivateData->HeadIndex; 3TailIndex = pQueuePrivateData->TailIndex; 4if(HeadIndex != TailIndex) { 5 memcpy(pData, &pQueuePrivateData->Data[HeadIndex], sizeof(sQueueData)); 6 pQueuePrivateData->HeadIndex = (HeadIndex + 1) % CONFIG_QUEUE_SIZE; 7 pthread_mutex_unlock(&pQueuePrivateData->QueueMutex); 8 return 0; 9} else { 10 pthread_mutex_unlock(&pQueuePrivateData->QueueMutex); 11 return -1; 12}

    }

    int QueueCallback(sQueueData* pQueueData) { pthread_mutex_lock(&sQueuePrivateData.LinkListMutex); LinkedListDel(pQueueData->pData); pthread_mutex_unlock(&sQueuePrivateData.LinkListMutex); return 0; }

    /* main.c / /*

    • author: rootming
    • date: 2019.4
    • version: v1.0 */

    /* # Video capture ## Basic note 1. use V4L2 interface open camera & capture video 2. use framebuffer driver for preview 3. text overlay video 4. use h264 algorithm compresse frame

    1## Hardware 21. Raspberry Pi 3 32. USB camera 4 5## Target 61. capture frame size: 640*480 72. display fps: >= 30fps 83. memory limit: <20M 9 10## Addtion 111. Maybe can add log library

    */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <signal.h> #include "config.h" #include "camera.h" #include "encode.h" #include "display.h" #include "queue.h"

    /* 入队列回调 / void EnQueueCallback(uint8_t pData, uint32_t Width, uint32_t Height, uint32_t Length) { sQueueData QueueData; QueueData.pData = malloc(Length); if(!QueueData.pData) { perror("Malloc failed"); return; } QueueData.Length = Length; memcpy(QueueData.pData, pData, Length); QueuePutData(&QueueData); }

    void SignalHandle(int SignalNumber) { printf("Now clean resource\n"); CameraCaptureStop(); CameraClose(); DisplayStop(); EncodeStop(); }

    int main(int Argc, char* pArgv[]) { int Ret = -1;

    1signal(SIGINT, SignalHandle); 2 3Ret = CameraOpen(CONFIG_CAPTURE_DEVICE); 4if(Ret) { 5 printf("Camera open failed \n"); 6 return -1; 7} 8 9Ret = DisplayInit(CONFIG_DISPLAY_DEV); 10 11if(Ret) { 12 printf("Diaplay open failed \n"); 13 return -1; 14} 15 16CameraCaptureCallbackSet(EnQueueCallback); 17CameraCaptureStart(); 18DisplayStart(); 19EncodeStart("test.h264"); 20 21char KeyValue = getchar(); 22printf("You press [%c] button, now stop capture\n", KeyValue); 23SignalHandle(0); 24return 0;

    }

    Makefile

    TARGET = YTC100

    CFLAG = -Wall -Werror -std=c99

    #CFLAG = -Wall -std=c99 -O2 CFLAG = -Wall -O2 LIB = -pthread -lx264

    ${TARGET}: main.o camera.o encode.o queue.o display.o gcc main.o camera.o encode.o display.o queue.o ${LIB} ${CFLAG} -o ${TARGET}

    main.o: main.c config.h gcc main.c ${CFLAG} -c -o main.o

    camera.o: camera.c camera.h config.h gcc camera.c ${CFLAG} -c -o camera.o

    encode.o: encode.c encode.h config.h gcc encode.c ${CFLAG} -c -o encode.o

    queue.o: queue.c queue.h config.h gcc queue.c ${CFLAG} -c -o queue.o

    display.o: display.c display.h config.h gcc display.c ${CFLAG} -c -o display.o

    .PHONY: clean

    clean: rm -f *.o ${TARGET}

后面的话

  1. Makefile写的比较傻, 后面可以改改
  2. 经常malloc和free不是一个好的选择, 还可以优化一下
  3. V4L2捕获视频可以使用select实现
  4. 线程中的死循环可以加入usleep让出CPU时间,降低CPU占用率
  5. 树莓派上跑640*480 30fps时, 温度达到72℃
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

4、jstack查看线程栈信息

1、介绍利用jps、top、jstack命令找到进程中耗时最大的线程,以及线程状态等等,同时最后还可以显示出死锁的线程查找:FoundoneJavaleveldeadlock即可1、jps获得进程号!(https://oscimg.oschina.net/oscnet/da00a309fa6

Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————结合三个部分工作 - HelloWorld