Linux ARM64(飞腾)/X86_64系统(麒麟 统信UOS)上实现摄像头、屏幕和麦克风采集并输出RTSP/RTMP流

本文主要是介绍Linux ARM64(飞腾)/X86_64系统(麒麟 统信UOS)上实现摄像头、屏幕和麦克风采集并输出RTSP/RTMP流,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  之前做了linux x86_64上的摄像头采集、屏幕采集和麦克风等采集,并把采集到的音视频数据实时编码输出为RTMP/RTSP流, 现在国产arm64位设备越来越多,最近对linux arm64也做了相应的支持.

  Linux上摄像头采集使用V4L2相关接口,查看摄像头设备文件可以使用(ls -l /dev/|grep video). 打开设备使用open接口就行, 例如:open("/dev/videoxx", flag).

  屏幕采集用X相关接口实现,如果是Wayland协议, 用PipeWire相关接口实现采集就好.
  麦克风采集使用ALSA或者PulseAudio.
  采集播放音频用PulseAudio.
  采集实现代码很多, 已封装好接口,下面是调用demo:

/*
* Copyright (C) 1130758427@qq.com. All rights reserved. 
* 问题沟通微信:ldxevt
*/#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>#include <assert.h>
#include <string.h>
#include <poll.h>
#include <errno.h>#include <string>
#include <vector>
#include <memory>
#include <sstream>#include <X11/Xlib.h>
#include <X11/keysym.h>#include "nt_sdk_linux_smart_log.h"
#include "nt_common_media_define.h"
#include "nt_linux_smart_publisher_sdk.h"
#include "nt_layer_conf_wrapper.h"namespace
{int EventPoll(int fd, bool is_write, int timeout_ms){int result;do{struct pollfd info;info.fd = fd;if (is_write){info.events = POLLOUT;}else{info.events = POLLIN | POLLPRI;}result = poll(&info, 1, timeout_ms);} while (result < 0 && errno == EINTR);return result;}bool MY_X11_Pending(Display* display, int timeout_ms){XFlush(display);if (XEventsQueued(display, QueuedAlready) > 0){return true;}if (EventPoll(ConnectionNumber(display), false, timeout_ms)){if (XPending(display) > 0){return true;}}return false;}Window CreateSubWindow(Display* display, int screen, Window parent){XWindowAttributes  parent_win_att;XGetWindowAttributes(display, parent, &parent_win_att);fprintf(stdout, "parent w:%d, h:%d\n", parent_win_att.width, parent_win_att.height);XSetWindowAttributes swa;swa.border_pixel = WhitePixel(display, screen);swa.event_mask = KeyPressMask | StructureNotifyMask;return XCreateWindow(display, parent, 0, 0, parent_win_att.width - 4, parent_win_att.height - 4,2, parent_win_att.depth, InputOutput, parent_win_att.visual, CWEventMask | CWBorderPixel, &swa);}class CameraInfo{public:std::string name_;std::string id_;std::vector<NT_PB_VideoCaptureCapability> capabilities_;};volatile bool g_is_exit = false;void OnSaSigaction(int signo, siginfo_t* s_info, void*){if (SIGINT == signo){g_is_exit = true;fprintf(stdout, "OnSaSigaction SIGINT si_pid=%d, pid=%d\n", (int)s_info->si_pid, (int)getpid());}else if (SIGFPE == signo){fprintf(stderr, "OnSaSigaction SIGFPE si_pid=%d, pid=%d, addr=%p\n", (int)s_info->si_pid, (int)getpid(), s_info->si_addr);switch (s_info->si_code){case FPE_INTDIV:fprintf(stderr, "OnSaSigaction SIGFPE FPE_INTDIV\n");break;case FPE_INTOVF:fprintf(stderr, "OnSaSigaction SIGFPE FPE_INTOVF\n");break;case FPE_FLTDIV:fprintf(stderr, "OnSaSigaction SIGFPE FPE_FLTDIV\n");break;case FPE_FLTOVF:fprintf(stderr, "OnSaSigaction SIGFPE FPE_FLTOVF\n");break;case FPE_FLTUND:fprintf(stderr, "OnSaSigaction SIGFPE FPE_FLTUND\n");break;case FPE_FLTRES:fprintf(stderr, "OnSaSigaction SIGFPE FPE_FLTRES\n");break;case FPE_FLTINV:fprintf(stderr, "OnSaSigaction SIGFPE FPE_FLTINV\n");break;case  FPE_FLTSUB:fprintf(stderr, "OnSaSigaction SIGFPE FPE_FLTSUB\n");break;default:break;}}}void OnSDKEventHandle(NT_HANDLE handle, NT_PVOID user_data,NT_UINT32 event_id,NT_INT64  param1,NT_INT64  param2,NT_UINT64 param3,NT_UINT64 param4,NT_PCSTR  param5,NT_PCSTR  param6,NT_PVOID  param7){if (NT_PB_E_EVENT_ID_CAPTURE_WINDOW_INVALID == event_id){fprintf(stdout, "X Window is invalid, wid=%lld, handle=%p\n", param1, handle);}}void LogInit(){SmartLogAPI log_api;memset(&log_api, 0, sizeof(log_api));GetSmartLogAPI(&log_api);log_api.SetLevel(SL_INFO_LEVEL);log_api.SetPath((NT_PVOID)"./");}bool PushSDKInit(NT_SmartPublisherSDKAPI& push_api){memset(&push_api, 0, sizeof(push_api));NT_GetSmartPublisherSDKAPI(&push_api);auto ret = push_api.Init(0, nullptr);if (NT_ERC_OK != ret){fprintf(stderr, "push_api.Init failed!\n");return false;}else{fprintf(stdout, "push_api.Init ok!\n");}return true;}std::vector<NT_UINT64> x_win_list;void GetCameraInfo(NT_SmartPublisherSDKAPI* push_api, std::vector<CameraInfo>& cameras){NT_INT32 device_number = 0;if (NT_ERC_OK != push_api->GetVideoCaptureDeviceNumber(&device_number)){return;}if (device_number < 1){return;}for (auto i = 0; i < device_number; ++i){CameraInfo info;char name[256] = { 0 };char id[1024] = { 0 };if (NT_ERC_OK != push_api->GetVideoCaptureDeviceInfo(i,name, sizeof(name) / sizeof(char),id, sizeof(id) / sizeof(char))){continue;}info.name_ = name;info.id_ = id;NT_INT32 capability_number = 0;if (NT_ERC_OK != push_api->GetVideoCaptureDeviceCapabilityNumber(id, &capability_number)){continue;}auto is_failed = false;for (auto i = 0; i < capability_number; ++i){NT_PB_VideoCaptureCapability capability = { 0, 0, 0 };if (NT_ERC_OK != push_api->GetVideoCaptureDeviceCapability(id, i, &capability)){is_failed = true;break;}info.capabilities_.push_back(capability);}if (!is_failed){cameras.push_back(info);}}}NT_HANDLE StartPush(NT_SmartPublisherSDKAPI* push_api, const std::string& rtmp_url, int dst_fps){NT_INT32 pulse_device_number = 0;if (NT_ERC_OK == push_api->GetAuidoInputDeviceNumber(2, &pulse_device_number)){fprintf(stdout, "Pulse device num:%d\n", pulse_device_number);char device_name[512];for (auto i = 0; i < pulse_device_number; ++i){if (NT_ERC_OK == push_api->GetAuidoInputDeviceName(2, i, device_name, 512)){fprintf(stdout, "index:%d name:%s\n", i, device_name);}}}NT_INT32 alsa_device_number = 0;if (pulse_device_number < 1){if (NT_ERC_OK == push_api->GetAuidoInputDeviceNumber(1, &alsa_device_number)){fprintf(stdout, "Alsa device num:%d\n", alsa_device_number);char device_name[512];for (auto i = 0; i < alsa_device_number; ++i){if (NT_ERC_OK == push_api->GetAuidoInputDeviceName(1, i, device_name, 512)){fprintf(stdout, "index:%d name:%s\n", i, device_name);}}}}NT_INT32 capture_speaker_flag = 0;if ( NT_ERC_OK == push_api->IsCanCaptureSpeaker(2, &capture_speaker_flag) ){if (capture_speaker_flag)fprintf(stdout, "Support speaker capture\n");elsefprintf(stdout, "UnSupport speaker capture\n");}NT_INT32 is_support_window_capture = 0;if (NT_ERC_OK == push_api->IsCaptureXWindowSupported(NULL, &is_support_window_capture)){if (is_support_window_capture)fprintf(stdout, "Support window capture\n");elsefprintf(stdout, "UnSupport window capture\n");}if (is_support_window_capture){NT_INT32 win_count = 0;if (NT_ERC_OK == push_api->UpdateCaptureXWindowList(NULL, &win_count) && win_count > 0 ){fprintf(stdout, "X Capture Winows list++\n");for (auto i = 0; i < win_count; ++i){NT_UINT64 wid;char title[512];if (NT_ERC_OK == push_api->GetCaptureXWindowInfo(i, &wid, title, sizeof(title) / sizeof(char))){x_win_list.push_back(wid);fprintf(stdout, "wid:%llu, title:%s\n", wid, title);}}fprintf(stdout, "X Capture Winows list--\n");}}std::vector<CameraInfo> cameras;GetCameraInfo(push_api, cameras);if (!cameras.empty()){fprintf(stdout, "cameras count:%d\n", (int)cameras.size());for (const auto& c : cameras){fprintf(stdout, "camera name:%s, id:%s, cap_num:%d\n", c.name_.c_str(), c.id_.c_str(), (int)c.capabilities_.size());for (const auto& i : c.capabilities_){fprintf(stdout, "cap w:%d, h:%d, fps:%d\n", i.width_, i.height_, i.max_frame_rate_);}}}NT_UINT32 auido_option = NT_PB_E_AUDIO_OPTION_NO_AUDIO;if (pulse_device_number > 0 || alsa_device_number > 0){auido_option = NT_PB_E_AUDIO_OPTION_CAPTURE_MIC;}else if (capture_speaker_flag){auido_option = NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER;}//auido_option = NT_PB_E_AUDIO_OPTION_CAPTURE_MIC_SPEAKER_MIXER;NT_UINT32 video_option = NT_PB_E_VIDEO_OPTION_SCREEN;if (!cameras.empty()){video_option = NT_PB_E_VIDEO_OPTION_CAMERA;}else if (is_support_window_capture){video_option = NT_PB_E_VIDEO_OPTION_WINDOW;}NT_HANDLE push_handle = nullptr;if (NT_ERC_OK != push_api->Open(&push_handle, video_option, auido_option, 0, NULL)){return nullptr;}push_api->SetEventCallBack(push_handle, nullptr, OnSDKEventHandle);if (video_option == NT_PB_E_VIDEO_OPTION_CAMERA){if (!cameras.empty()){push_api->SetVideoCaptureDeviceBaseParameter(push_handle, cameras.front().id_.c_str(),640, 480);//push_api->FlipVerticalCamera(push_handle, 1);//push_api->FlipHorizontalCamera(push_handle, 1);//push_api->RotateCamera(push_handle, 0);}}if (video_option == NT_PB_E_VIDEO_OPTION_WINDOW){if (!x_win_list.empty()){//push_api->SetCaptureXWindow(push_handle, x_win_list[0]);push_api->SetCaptureXWindow(push_handle, x_win_list.back());}}push_api->SetFrameRate(push_handle, dst_fps);push_api->SetVideoEncoder(push_handle, 0, 1, NT_MEDIA_CODEC_ID_H264, 0);push_api->SetVideoBitRate(push_handle, 2000);  push_api->SetVideoQuality(push_handle, 26); push_api->SetVideoMaxBitRate(push_handle, 4000); push_api->SetVideoKeyFrameInterval(push_handle, dst_fps*2); push_api->SetVideoEncoderProfile(push_handle, 3); // H264 highpush_api->SetVideoEncoderSpeed(push_handle, 3);if (pulse_device_number > 0){push_api->SetAudioInputLayer(push_handle, 2);push_api->SetAuidoInputDeviceId(push_handle, 0);}else if (alsa_device_number > 0){push_api->SetAudioInputLayer(push_handle, 1);push_api->SetAuidoInputDeviceId(push_handle, 0);}push_api->SetPublisherAudioCodecType(push_handle, 1);//push_api->SetMute(push_handle, 1);if ( NT_ERC_OK != push_api->SetURL(push_handle, rtmp_url.c_str(), NULL) ){push_api->Close(push_handle);push_handle = nullptr;return nullptr;}if ( NT_ERC_OK != push_api->StartPublisher(push_handle, NULL) ){push_api->Close(push_handle);push_handle = nullptr;return nullptr;}return push_handle;}
}int main(int argc, char *argv[])
{struct sigaction act;sigemptyset(&act.sa_mask);act.sa_sigaction = OnSaSigaction;act.sa_flags = SA_SIGINFO;sigaction(SIGINT, &act, NULL);sigaction(SIGFPE, &act, NULL);XInitThreads(); // X支持多线程, 必须调用auto display = XOpenDisplay(nullptr);if (!display){fprintf(stderr, "Cannot connect to X server\n");return 0;}auto screen = DefaultScreen(display);auto root = XRootWindow(display, screen);XWindowAttributes root_win_att;if (!XGetWindowAttributes(display, root, &root_win_att)){fprintf(stderr, "Get Root window attri failed\n");XCloseDisplay(display);return 0;}int main_w = root_win_att.width / 2, main_h = root_win_att.height / 2;auto black_pixel = BlackPixel(display, screen);auto white_pixel = WhitePixel(display, screen);auto main_wid = XCreateSimpleWindow(display, root, 0, 0, main_w, main_h, 0, white_pixel, black_pixel);if (!main_wid){fprintf(stderr, "Cannot Create Main Window\n");XCloseDisplay(display);return 0;}XSelectInput(display, main_wid, StructureNotifyMask | KeyPressMask);auto sub_wid = CreateSubWindow(display, screen, main_wid);if (!sub_wid){fprintf(stderr, "Cannot Create Render Window\n");XDestroyWindow(display, main_wid);XCloseDisplay(display);return 0;}XMapWindow(display, main_wid);XStoreName(display, main_wid, "Video Preview");XMapWindow(display, sub_wid);LogInit();NT_SmartPublisherSDKAPI push_api;if (!PushSDKInit(push_api)){XDestroyWindow(display, sub_wid);XDestroyWindow(display, main_wid);XCloseDisplay(display);return 0;}auto push_handle = StartPush(&push_api, "rtmp://192.168.0.131:1935/live/test", 25);if (!push_handle){fprintf(stderr, "start push failed.\n");XDestroyWindow(display, sub_wid);XDestroyWindow(display, main_wid);XCloseDisplay(display);push_api.UnInit();return 0;}// 开启预览,也可以不开启, 根据需求来push_api.SetPreviewXWindow(push_handle, "", sub_wid);push_api.StartPreview(push_handle, 0, nullptr);while (!g_is_exit){while (MY_X11_Pending(display, 10)){XEvent xev;memset(&xev, 0, sizeof(xev));XNextEvent(display, &xev);if (xev.type == ConfigureNotify){if (xev.xconfigure.window == main_wid){if (xev.xconfigure.width != main_w || xev.xconfigure.height != main_h){main_w = xev.xconfigure.width;main_h = xev.xconfigure.height;XMoveResizeWindow(display, sub_wid, 0, 0, main_w - 4, main_h - 4);}}}else if (xev.type == KeyPress){if (xev.xkey.keycode == XKeysymToKeycode(display, XK_Escape)){fprintf(stdout, "ESC Key Press\n");g_is_exit = true;}}if (g_is_exit)break;}}fprintf(stdout, "exit run loop, is_exit:%d\n", g_is_exit);push_api.StopPreview(push_handle);push_api.StopPublisher(push_handle);push_api.Close(push_handle);push_handle = nullptr;XDestroyWindow(display, sub_wid);XDestroyWindow(display, main_wid);XCloseDisplay(display);push_api.UnInit();fprintf(stdout, "SDK UnInit..\n");return 0;
}

   上面的代码音视频采集都有,视频采集有屏幕、窗口和摄像头, 音频采集麦克风、扬声器(两者混音也支持). 然后使用rtmp协议推送出去, 这里没输出rtsp流的代码,需要的话沟通就好, 不依赖QT, 但可以集成到QT项目将中, Linux arm64和x86_64都支持。如有其他问题请联系qq: 1130758427, 微信: ldxevt 。

这篇关于Linux ARM64(飞腾)/X86_64系统(麒麟 统信UOS)上实现摄像头、屏幕和麦克风采集并输出RTSP/RTMP流的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075544

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi