linux摄像头h264压缩,Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————结合三个部分工作...

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

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

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

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

/* queue.h */

#ifndef QUEUE_H

#define QUEUE_H

#include

#include

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

#include

#include

#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;

if(pTempNode == NULL) {

// printf("Debug:LinkList root empty, inited \n");

sQueuePrivateData.pLinkListRoot = malloc(sizeof(sLinkListNode));

sQueuePrivateData.pLinkListRoot->pNext = NULL;

sQueuePrivateData.pLinkListRoot->pData = pData;

sQueuePrivateData.pLinkListRoot->Times = 0;

return 0;

}

while(pTempNode->pNext != NULL) {

pTempNode = pTempNode->pNext;

}

pTempNode->pNext = malloc(sizeof(sLinkListNode));

pTempNode->pNext->pNext = NULL;

pTempNode->pNext->pData = pData;

pTempNode->pNext->Times = 0;

return 0;

}

int LinkedListDel(void* pData)

{

sLinkListNode* pTempNode = NULL;

sLinkListNode** ppPre = &sQueuePrivateData.pLinkListRoot;

if(*ppPre == NULL) {

// printf("Error: LinkList empty\n");

return -1;

}

while(*ppPre != NULL) {

if((*ppPre)->pData == pData) {

if((*ppPre)->Times == CONFIG_QUEUE_LIMIT - 1) {

pTempNode = (*ppPre)->pNext;

free(pData);

free(*ppPre);

*ppPre = pTempNode;

// printf("Debug: free buffer\n");

break;

} else {

// printf("Debug: times not equ limit: %d times\n", (*ppPre)->Times);

(*ppPre)->Times++;

break;

}

} else {

ppPre = &(*ppPre)->pNext;

// printf("Debug: ppPre: %p\n", *ppPre);

// printf("Debug: next\n");

}

}

return 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;

pthread_mutex_init(&sQueuePrivateData.QueueMutex, NULL);

pthread_mutex_init(&sQueuePrivateData.LinkListMutex, NULL);

return 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;

Index = (TailIndex + 1) % CONFIG_QUEUE_SIZE;

if(Index == HeadIndex) {

// printf("Warn: queue full\n");

pthread_mutex_unlock(&pQueuePrivateData->QueueMutex);

return -1;

} else {

memcpy(&pQueuePrivateData->Data[TailIndex], pData, sizeof(sQueueData));

pQueuePrivateData->TailIndex = Index;

pthread_mutex_unlock(&pQueuePrivateData->QueueMutex);

return 0;

}

}

int QueuePutData(sQueueData* pData)

{

int Ret = -1;

pthread_mutex_lock(&sQueuePrivateData.QueueMutex);

pthread_mutex_lock(&sQueuePrivateData.LinkListMutex);

LinkedListAdd(pData->pData);

pthread_mutex_unlock(&sQueuePrivateData.LinkListMutex);

for(int i = 0; i < sQueuePrivateData.Cnt; i++) {

Ret = QueuePushBack(sQueuePrivateData.QueueList[i], pData);

if(Ret) {

QueueCallback(pData);

}

}

pthread_mutex_unlock(&sQueuePrivateData.QueueMutex);

return 0;

}

int QueuePopData(sQueue* pQueuePrivateData, sQueueData* pData)

{

int HeadIndex, TailIndex;

pthread_mutex_lock(&pQueuePrivateData->QueueMutex);

HeadIndex = pQueuePrivateData->HeadIndex;

TailIndex = pQueuePrivateData->TailIndex;

if(HeadIndex != TailIndex) {

memcpy(pData, &pQueuePrivateData->Data[HeadIndex], sizeof(sQueueData));

pQueuePrivateData->HeadIndex = (HeadIndex + 1) % CONFIG_QUEUE_SIZE;

pthread_mutex_unlock(&pQueuePrivateData->QueueMutex);

return 0;

} else {

pthread_mutex_unlock(&pQueuePrivateData->QueueMutex);

return -1;

}

}

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

## Hardware

1. Raspberry Pi 3

2. USB camera

## Target

1. capture frame size: 640*480

2. display fps: >= 30fps

3. memory limit: <20M

## Addtion

1. Maybe can add log library

*/

#include

#include

#include

#include

#include

#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;

signal(SIGINT, SignalHandle);

Ret = CameraOpen(CONFIG_CAPTURE_DEVICE);

if(Ret) {

printf("Camera open failed \n");

return -1;

}

Ret = DisplayInit(CONFIG_DISPLAY_DEV);

if(Ret) {

printf("Diaplay open failed \n");

return -1;

}

CameraCaptureCallbackSet(EnQueueCallback);

CameraCaptureStart();

DisplayStart();

EncodeStart("test.h264");

char KeyValue = getchar();

printf("You press [%c] button, now stop capture\n", KeyValue);

SignalHandle(0);

return 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}

后面的话

Makefile写的比较傻, 后面可以改改

经常malloc和free不是一个好的选择, 还可以优化一下

V4L2捕获视频可以使用select实现

线程中的死循环可以加入usleep让出CPU时间,降低CPU占用率

树莓派上跑640*480 30fps时, 温度达到72℃

原文:https://www.cnblogs.com/rootming/p/10854063.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值