图灵转世 2023-05-06 09:51 采纳率: 75%
浏览 101
已结题

视频流海康rtsp流合并字幕显示储存

1,现在要做个win10工控机上用rtsp流访问海康摄像机的h264流,工控机有串口输入一些文本信息,需要和264流合并显示在工控机的屏幕上,并且可以保存视频文字流,30分钟一个文件。。各位大拿提供解决方案.vlc二次开发,ffmpeg,等等,越方便越好

  • 写回答

7条回答 默认 最新

  • 社区专家-Monster-XH 2023-05-06 10:03
    关注
    获得9.45元问题酬金

    基于Monster 组和GPT的调写:

    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]是您要保存的文件名。

    • 2.将串口输入文本信息合并到h264流中
      用ffmpeg的“drawtext”过滤器将串口输入的文本信息合并到h264流中。以下是一个示例命令:
    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(&current_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”格式。它还可以用串口输入一个文本消息来更新文本消息。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 5月14日
  • 赞助了问题酬金15元 5月6日
  • 赞助了问题酬金15元 5月6日
  • 创建了问题 5月6日

悬赏问题

  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c