1,现在要做个win10工控机上用rtsp流访问海康摄像机的h264流,工控机有串口输入一些文本信息,需要和264流合并显示在工控机的屏幕上,并且可以保存视频文字流,30分钟一个文件。。各位大拿提供解决方案.vlc二次开发,ffmpeg,等等,越方便越好
1.
通过ffmpeg获取rtsp流
使用ffmpeg可以轻松地获取海康摄像机的rtsp流。您可以使用以下命令从rtsp URL获取h264流:
ffmpeg -i rtsp://[username]:[password]@[IP]:[port]/[channel] -vcodec copy -an -f h264 [output_file].h264
其中,[username]和[password]是海康摄像机的用户名和密码,[IP]是摄像机的IP地址,[port]是rtsp端口号,[channel]是您要使用的摄像机的通道号。[output_file]是您要保存的文件名。
ffmpeg -i [input_file].h264 -vf "drawtext=text='[text]':fontsize=20:fontcolor=white:x=10:y=10" -codec copy [output_file].h264
3.其中,[input_file]是您之前从rtsp流中提取的h264流文件名,[text]是您要合并的文本信息。此命令将在左上角添加一个白色文本框,显示您输入的文本信息。
保存视频和文字流
用ffmpeg的“segment”和“mux”功能将视频和文字流分段并保存为文件。以下是一个示例命令:
ffmpeg -i [input_file].h264 -vf "drawtext=text='[text]':fontsize=20:fontcolor=white:x=10:y=10" -segment_time 1800 -f segment -segment_format mp4 -reset_timestamps 1 -strftime 1 [output_file]_%Y-%m-%d_%H-%M-%S.mp4 -map 0 -c copy -f segment -segment_time 1800 -reset_timestamps 1 -strftime 1 [output_file]_%Y-%m-%d_%H-%M-%S.txt
此命令将视频和文字流分段并保存为每个30分钟一个文件的mp4和txt文件。可以将[output_file]替换为您想要的文件名。
这些命令可以结合在一起,以便可以一次运行所有步骤。
5.用FFmpeg和OpenCV这两个库来处理视频流和字幕。
#include <iostream>
#include <string>
#include <sstream>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <libavutil/opt.h>
#include <libavutil/time.h>
}
using namespace std;
using namespace cv;
int main()
{
// Initialize FFmpeg
av_register_all();
avcodec_register_all();
avformat_network_init();
// Input RTSP URL and the text message from serial port
string rtsp_url = "rtsp://username:password@192.168.0.1:554/stream1";
string text_message = "Hello, world!";
// Open the RTSP stream
AVFormatContext* input_context = NULL;
if (avformat_open_input(&input_context, rtsp_url.c_str(), NULL, NULL) < 0)
{
cout << "Failed to open the RTSP stream." << endl;
return -1;
}
// Find the video stream information
if (avformat_find_stream_info(input_context, NULL) < 0)
{
cout << "Failed to find the video stream information." << endl;
return -1;
}
// Find the video stream
int video_stream_index = -1;
AVCodecParameters* video_codec_parameters = NULL;
AVCodec* video_codec = NULL;
for (int i = 0; i < input_context->nb_streams; i++)
{
if (input_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
video_stream_index = i;
video_codec_parameters = input_context->streams[i]->codecpar;
video_codec = avcodec_find_decoder(video_codec_parameters->codec_id);
break;
}
}
// Open the video codec
AVCodecContext* video_codec_context = avcodec_alloc_context3(video_codec);
avcodec_parameters_to_context(video_codec_context, video_codec_parameters);
if (avcodec_open2(video_codec_context, video_codec, NULL) < 0)
{
cout << "Failed to open the video codec." << endl;
return -1;
}
// Allocate the frame and packet
AVFrame* frame = av_frame_alloc();
AVPacket* packet = av_packet_alloc();
// Create the window for display
namedWindow("Video", WINDOW_NORMAL);
// Create the font and text message
int font_face = FONT_HERSHEY_SIMPLEX;
double font_scale = 1.5;
int thickness = 2;
int baseline = 0;
Size text_size = getTextSize(text_message, font_face, font_scale, thickness, &baseline);
Point text_origin((text_size.width / 2), (text_size.height / 2));
Scalar text_color(255, 255, 255);
Mat text_image(text_size.height * 2, text_size.width * 2, CV_8UC3, Scalar(0,0, 0));
// Create the video writer
string video_filename;
time_t current_time = time(NULL);
struct tm* time_info = localtime(¤t_time);
char time_str[80];
strftime(time_str, sizeof(time_str), "%Y-%m-%d_%H-%M-%S", time_info);
video_filename = "output_" + string(time_str) + ".avi";
int fourcc = VideoWriter::fourcc('M', 'J', 'P', 'G');
double fps = 30.0;
Size video_size(video_codec_context->width, video_codec_context->height + text_size.height);
VideoWriter video_writer(video_filename, fourcc, fps, video_size, true);
// Start the loop for reading frames
while (av_read_frame(input_context, packet) >= 0)
{
// Check if the packet is for video stream
if (packet->stream_index == video_stream_index)
{
// Decode the video packet
int ret = avcodec_send_packet(video_codec_context, packet);
if (ret < 0)
{
cout << "Error decoding video packet." << endl;
continue;
}
while (ret >= 0)
{
ret = avcodec_receive_frame(video_codec_context, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
cout << "Error decoding video frame." << endl;
continue;
}
// Convert the video frame to OpenCV Mat
Mat video_image(frame->height, frame->width, CV_8UC3, frame->data[0], frame->linesize[0]);
cvtColor(video_image, video_image, COLOR_YUV2BGR);
// Add the text message to the image
putText(text_image, text_message, text_origin, font_face, font_scale, text_color, thickness);
// Create the combined image
Mat combined_image(video_size.height, video_size.width, CV_8UC3);
Mat roi(combined_image, Rect(0, 0, video_codec_context->width, video_codec_context->height));
video_image.copyTo(roi);
roi = Mat(combined_image, Rect(0, video_codec_context->height, text_size.width, text_size.height));
text_image(Rect(0, 0, text_size.width, text_size.height)).copyTo(roi);
// Display the combined image
imshow("Video", combined_image);
// Write the combined image to video file
video_writer.write(combined_image);
// Release the frame
av_frame_unref(frame);
}
}
// Release the packet
av_packet_unref(packet);
// Wait for a key press or a timeout
if (waitKey(1) >= 0)
{
break;
}
}
// Release the resources
av_packet_free(&packet);
av_frame_free(&frame);
avcodec_free_context(&video_codec_context);
avformat_close_input(&input_context);
avformat_network_deinit();
destroyAllWindows();
return 0;
这个示例代码会打开RTSP流,并在视频上方显示一个文本消息。它使用OpenCV显示视频和文本消息,使用FFmpeg保存视频。输出视频文件名是带有当前日期和时间的“output_yyyy-mm-dd_HH-MM-SS.avi”格式。它还可以用串口输入一个文本消息来更新文本消息。
谢谢Monster-XH给的方案,但是还有个问题,就是每30分钟存一个文件,是视频流文字流合起来的视频,需要用ffmpeg,opencv的方案,谁解决,再赏15元
大致思路如下,供你参考:
1、确保海康摄像机支持RTSP流和H264编码【可以查看设备文档来确认这一点】
2、安装并配置海康工控机软件【提供访问摄像机和通信的API接口】
3、安装并配置RTSP服务器【可以使用命令行或者web浏览器等方式访问RTSP服务器,确认是否允许发送和接收视频流】
4、将海康摄像机连接到工控机【通过串口连接】
5、配置RTSP服务器以允许视频流和文本流同时传输,可以参照下面命令:
ffmpeg -re -i <input_stream_url> -c:v libx264 -c:a aac -b:a 128k -f flv rtsp://<rtsp_server_url>
【<input_stream_url> 是输入流的RTSP地址,-re参数启用回调,-c:v libx264 指定使用H264编码器,-c:a aac 指定使用AAC编码器,-b:a 128k 指定分辨率为128kbps,-f flv 指定输出为FLV格式,rtsp://<rtsp_server_url> 是RTSP服务器的URL】
6、设置海康摄像机以保存每30分钟的视频文件,可以参考下面命令:
ffmpeg -re -i <input_stream_url> -c:v libx264 -c:a aac -b:a 128k -f flv rtsp://<rtsp_server_url> -ts 30 -c:s 640x480 -pix_fmt yuv420p <output_file_path>
【<input_stream_url> 是输入流的RTSP地址,-re参数启用回调,-c:v libx264 指定使用H264编码器,-c:a aac 指定使用AAC编码器,-b:a 128k 指定分辨率为128kbps,-f flv 指定输出为FLV格式,-ts 30 表示30分钟间隔保存,-c:s 640x480 指定输出分辨率为640x480,-pix_fmt yuv420p 指定输出格式为YUV420P,<output_file_path> 是输出文件的路径】
引用chatGPT作答,以下是一份示例代码,用于连接海康摄像机的RTSP流并从串口接收文本信息,然后将文本信息叠加到视频流上并保存为视频文件。请注意,该代码只是一个示例,您需要根据您的实际需求进行修改和优化。
import cv2
import serial
import time
# 打开串口并配置
ser = serial.Serial('COM1', 9600, timeout=0.5)
# 连接海康摄像机的RTSP流
url = 'rtsp://username:password@192.168.1.100:554/streaming/channels/1'
cap = cv2.VideoCapture(url)
# 获取视频帧的宽度和高度
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 设置保存视频的参数
fourcc = cv2.VideoWriter_fourcc(*'XVID')
filename = time.strftime('%Y-%m-%d_%H-%M-%S.avi')
out = cv2.VideoWriter(filename, fourcc, 20.0, (width, height))
# 读取串口数据并将其叠加到视频帧上
while True:
ret, frame = cap.read()
if ret:
# 从串口读取文本信息
text = ser.readline().decode().strip()
# 在视频帧上叠加文本信息
cv2.putText(frame, text, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# 显示视频帧
cv2.imshow('frame', frame)
# 保存视频帧
out.write(frame)
# 按下q键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()
ser.close()
在上面的代码中,您需要将“COM1”替换为您实际使用的串口号,并将“username”和“password”替换为您海康摄像机的用户名和密码。您还需要根据实际情况修改视频帧的保存参数。在代码运行期间,您可以通过在串口中输入文本信息来测试程序是否正常工作。按下“q”键可以退出循环并停止保存视频文件。
基于new bing 的参考:
可以将视频流和文字流合并到一起,并使用FFmpeg进行处理。
具体方案如下:
需要注意的是,为了保证每个视频文件的完整性,建议在生成新文件前等待一段时间,以确保当前视频文件中的所有帧都被处理完毕。
以下是示例代码实现:
import cv2
import subprocess
import datetime
# 设置视频宽高和帧率
width = 640
height = 480
fps = 25
# 打开海康摄像机的h264流
cap = cv2.VideoCapture("rtsp://your_ip_address/h264_stream")
# 打开串口,并读取文本信息
ser = serial.Serial(port='/dev/ttyUSB0', baudrate=9600, timeout=1)
# 设置当前时间,并计算出下一个时间片
now_time = datetime.datetime.now()
next_time = now_time + datetime.timedelta(minutes=30)
# 定义 FFmpeg 相关参数
command = ['ffmpeg',
'-y',
'-f', 'rawvideo',
'-pixel_format', 'bgr24',
'-video_size', f'{width}x{height}',
'-framerate', str(fps),
'-i', '-',
'-c:v', 'libx264',
'-crf', '23',
'-preset', 'ultrafast',
'-tune', 'zerolatency',
'-pix_fmt', 'yuv420p',
'-movflags', 'frag_keyframe+empty_moov',
'-metadata', f'creation_time={now_time.strftime("%Y-%m-%d %H:%M:%S")}',
'-metadata', 'encoder="built on binjie09\'s AI assistant"',
'-muxdelay', '0.1',
'-segment_time', '1800',
'-reset_timestamps', '1',
'-strftime', '1',
'output_%Y%m%d_%H%M%S.mp4']
process = subprocess.Popen(command, stdin=subprocess.PIPE)
while True:
# 读取视频帧
ret, frame = cap.read()
if not ret:
break
# 从串口读取文本信息
text = ser.readline().decode('utf-8').strip()
# 在视频帧上添加文字
cv2.putText(frame, text, (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# 将视频帧写入 FFmpeg 的 stdin 中
process.stdin.write(frame.tostring())
# 如果当前时间超过了下一个时间片,就关闭上一个 FFmpeg 进程,并生成新的文件
if datetime.datetime.now() >= next_time:
process.stdin.close()
process.wait()
now_time = datetime.datetime.now()
next_time = now_time + datetime.timedelta(minutes=30)
filename = now_time.strftime('output_%Y%m%d_%H%M%S.mp4')
command[-1] = filename
process = subprocess.Popen(command, stdin=subprocess.PIPE)
# 关闭串口和摄像机
ser.close()
cap.release()
# 关闭最后一个 FFmpeg 进程
process.stdin.close()
process.wait()