• ffmpeg把RTSP流分段录制成MP4,如果能把ffmpeg.exe改成ffmpeg.dll用,那音视频开发的难度直接就降一个维度啊


    比如,原来我们要用ffmpeg录一段RTSP视频流转成MP4,我们有两种方案:

    方案一:可以使用以下命令将rtsp流分段存储为mp4文件

    ffmpeg -i rtsp://example.com/stream -vcodec copy -acodec aac -f segment -segment_time 3600 -reset_timestamps 1 -strftime 1 output_%Y-%m-%d_%H-%M-%S.mp4

    ffmpeg将RTSP录像成mp4

    方案二:可以直接调用ffmpeg库avcodec、avfilter代码,有门槛,要研究,用大模型生成一段代码看看:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    extern "C" {
        #include 
        #include 
        #include 
    }
    
    int main(int argc, char **argv) {
        AVFormatContext *pFormatCtx = NULL;
        int videoStream;
        AVCodecContext *pCodecCtx = NULL;
        AVCodec *pCodec = NULL;
        AVPacket packet;
        FILE *videoFile = NULL;
        struct SwsContext *img_convert_ctx;
        int64_t start_time, end_time, duration;
        double framerate = 25.0; // 帧率,需要根据实际情况调整
        int i, ret, got_output;
        uint8_t *outbuf[1024]; // 输出缓冲区大小,需要根据实际情况调整
        int outbuf_size; // 输出缓冲区大小,需要根据实际情况调整
        start_time = (int64_t)time(NULL); // 开始时间,单位为秒
        videoFile = fopen("output.ts", "wb"); // 输出文件名,需要根据实际情况调整
        if (!videoFile) {
            printf("Could not open output file for writing
    ");
            return -1;
        }
        outbuf_size = av_image_get_buffer_size((AVPixelFormat)AV_PIX_FMT_YUV420P, videoStream, 1920, 1080, 1); // 获取输出缓冲区大小,需要根据实际情况调整
        outbuf = (uint8_t*)av_malloc(outbuf_size); // 分配输出缓冲区,需要根据实际情况调整
        ret = avformat_new_stream(&pFormatCtx, NULL); // 创建视频流上下文,需要根据实际情况调整
        if (ret < 0) {
            printf("Error: could not create output format context
    ");
            exit(1);
        } else {
            ret = avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar); // 设置解码器参数,需要根据实际情况调整
            if (ret < 0) {
                printf("Error: could not initialize the codec context
    ");
                exit(1);
            } else {
                ret = avcodec_open2(pCodecCtx, pCodec, NULL); // 打开解码器,需要根据实际情况调整
                if (ret < 0) {
                    printf("Error: Could not open codec
    ");
                    exit(1);
                } else {
                    while (1) { // 循环处理视频流数据,需要根据实际情况调整
                        ret = av_read_frame(pFormatCtx, &packet); // 读取视频帧数据,需要根据实际情况调整
                        if (ret == 0) { // 如果读取到数据包,则进行处理,需要根据实际情况调整
                            // ... 在这里添加你的代码来处理视频帧数据 ...
                        } else if (ret < 0 && ret != AVERROR(EAGAIN)) { // 如果发生错误,则打印错误信息并退出程序,需要根据实际情况调整
                            char errorbuf[1024];
                            av_strerror(ret, errorbuf, sizeof(errorbuf));
                            printf("%s
    ", errorbuf);
                            exit(1);
                        } else if (ret == AVERROR(EAGAIN)) { // 如果发生EAGAIN错误,则等待一段时间后继续读取数据包,需要根据实际情况调整
                            usleep(200000); // 等待200ms,单位为微秒,需要根据实际情况调整
                        } else if (ret == AVERROR_EOF) { // 如果发生EOF错误,则表示已经读取完所有数据包,需要根据实际情况调整
                            break; // 结束循环,需要根据实际情况调整
                        } else if (ret < 0 && ret != AVERROR(EAGAIN)) { // 如果发生其他错误,则打印错误信息并退出程序,需要根据实际情况调整
                            char errorbuf[1024];
                            av_strerror(ret, errorbuf, sizeof(errorbuf));
                            printf("%s
    ", errorbuf);
                            exit(1);
                        } else if (ret >= 0) { // 如果成功读取到数据包,则进行处理,需要根据实际情况调整
                            // ... 在这里添加你的代码来处理视频帧数据 ...
                        } else { // 如果发生未知错误,则打印错误信息并退出程序,需要根据实际情况调整
                            char errorbuf[1024];
                            av_strerror(ret, errorbuf, sizeof(errorbuf));
                            printf("%s
    ", errorbuf);
                            exit(1);
                        }
                    } // while循环结束条件 ... 在这里添加你的代码 ... } } } } /* end of main() */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 方案一通过exec调用,但是有一个弊端就是不好控制,不能自动重连,进程管理需要不断自己维护;
    • 方案二就是开发成本较高,太复杂了,不同级别的开发写出来的效果参差不齐;

    有没有一个能把方案一和方案二结合起来的方法?

    有,他来了:EasyAVFilter!简单的几个接口,就能解决ffmpeg开发门槛的问题:

    方法名称说明
    EasyAVFilter_Create创建句柄,相当于创建了一个ffmpeg.exe
    EasyAVFilter_Release释放句柄
    EasyAVFilter_SetCallback设置回调函数和自定义指针,回调过程中的各种媒体信息/连接信息/转码进度
    EasyAVFilter_AddInput添加输入参数(源地址)
    EasyAVFilter_AddFilter添加中间参数,如:转码,兼容ffmpeg命令所有参数(例如-vcodec copy -acodec aac)
    EasyAVFilter_SetOutput设置输出参数(目标地址)
    EasyAVFilter_GetFilters获取所有参数(review参数输入是否正确)
    EasyAVFilter_Start开始工作
    EasyAVFilter_Stop停止工作

    详细信息可以直接看https://www.easydarwin.org/tools/153.html,具体用法和场景,后续逐步介绍;

  • 相关阅读:
    Git 忽略.gitignore文件自身/git仅本地忽略某些文件
    vue3 的 ref、 toRef 、 toRefs
    CCKS2023:基于企业数仓和大语言模型构建面向场景的智能应用
    练习计划 05——这一天是这一年的第几天?
    1、HTML初识_排版、图片、音频、视频、超链接标签和绝对、相对路径学习
    面向交通运输的计算机视觉和深度学习2
    让你说一说Sass、Less 的区别是什么,你知道吗?
    网络安全(黑客)自学
    第六节:如何解决@ComponentScan只能扫描当前包及子包(自学Spring boot 3.x的第一天)
    Jetpack Compose 和 SwiftUI 与 Flutter 的比较
  • 原文地址:https://blog.csdn.net/xiejiashu/article/details/132417973