Ffmpeg滤镜

打开设备

添加滤镜

循环录制文件

cpp 复制代码
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libswscale/swscale.h"
#include "libavutil/pixdesc.h"
#include "libavutil/hash.h"
#include "libavutil/bswap.h"
#include "libavutil/opt.h"
#include "libavutil/time.h"
#include "libavutil/timestamp.h"
#include "libavutil/pixfmt.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DEVICE_NAME "/dev/video0"
#define OUTPUT_FILE "/root/output.mp4"
#define DURATION_SEC 10 // 全局变量

AVFormatContext *in_fmt_ctx = NULL, *out_fmt_ctx = NULL;
AVCodecContext *dec_ctx = NULL, *enc_ctx = NULL;
AVFilterGraph *filter_graph = NULL;
AVFilterContext *buffersrc_ctx = NULL, *buffersink_ctx = NULL;
AVStream *in_stream = NULL, *out_stream = NULL;

AVCodecParameters *codecParameters = NULL;
int video_stream_index = -1;

int init_input_output()
{

    AVDictionary *opts = NULL;
    AVInputFormat *input_fmt = av_find_input_format("v4l2");
    av_dict_set(&opts, "video_size", "640x480", 0);
    av_dict_set(&opts, "framerate", "25", 0);
    av_dict_set(&opts, "input_format", "mjpeg", 0);
    if (avformat_open_input(&in_fmt_ctx, DEVICE_NAME, input_fmt, &opts) < 0)
    {
        fprintf(stderr, "无法打开输入设忇\n");
        return -1;
    }
    if (avformat_find_stream_info(in_fmt_ctx, NULL) < 0)
    {
        printf("open input failed\n");
        return -1;
    }

    video_stream_index = av_find_best_stream(in_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);
    in_stream = in_fmt_ctx->streams[video_stream_index];
    codecParameters = in_stream->codecpar;

    printf("codecid = %d ; h = %d ; w = %d;\n", in_stream->codecpar->codec_id, codecParameters->height, codecParameters->width);
    AVCodec *decoder = avcodec_find_decoder(in_stream->codecpar->codec_id);

    if (!decoder)

    {
        printf("upspoort decoder\n");
        return -1;
    }
    dec_ctx = avcodec_alloc_context3(decoder);
    avcodec_parameters_to_context(dec_ctx, codecParameters);

    if (avcodec_open2(dec_ctx, decoder, NULL) < 0)
    {
        printf("decoder avcodec_open2 failed\n");
        return -1;
    }
    avformat_alloc_output_context2(&out_fmt_ctx, NULL, NULL, OUTPUT_FILE);

    const AVCodec *encoder = avcodec_find_encoder_by_name("mpeg4");
    ; // avcodec_find_encoder(AV_CODEC_ID_H264);
    if (encoder == NULL)
    {
        printf("unsporrt edcodec\n");
        return -1;
    }
    out_stream = avformat_new_stream(out_fmt_ctx, NULL);

    enc_ctx = avcodec_alloc_context3(encoder);
    enc_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
    enc_ctx->codec_id = encoder->id;
    enc_ctx->width = 640;
    enc_ctx->height = 480;
    enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    enc_ctx->time_base = (AVRational){1, 25};
    enc_ctx->framerate = (AVRational){25, 1}; // in_stream->avg_frame_rate;//编码帧率按照采集帧率板
    enc_ctx->has_b_frames = 0;

    enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    // av_opt_set(enc_ctx->priv_data, "tune", "zerolatency", 0);
    int ret = -1;

    ret = avcodec_open2(enc_ctx, encoder, NULL);
    printf("ret = %d\n", ret);
    if (ret < 0)
    {
        printf(";;,,;encoder avcodec_open2 fialed\n");
        return -1;
    }
    out_stream->time_base = (AVRational){1, 25};
    avcodec_parameters_from_context(out_stream->codecpar, enc_ctx);
    if (!(out_fmt_ctx->oformat->flags & AVFMT_NOFILE))
    {
        avio_open(&out_fmt_ctx->pb, OUTPUT_FILE, AVIO_FLAG_WRITE);
    }
    avformat_write_header(out_fmt_ctx, NULL);
    return 0;
}
int init_filter_graph()
{

    if (!dec_ctx)
    {
        printf("dec_ctx is nullptr\n");
        return -1;
    }
    printf("----------->init_filter_graph\n");
    char args[512] = {0};
    char filter_descr[512] = {0};
    filter_graph = avfilter_graph_alloc();

    if (!filter_graph)
    {
        printf("filter_graph  is nullptr\n");
        return -1;
    }
    const AVFilter *buffersrc = avfilter_get_by_name("buffer");
    const AVFilter *buffersink = avfilter_get_by_name("buffersink");
    if (!buffersrc || !buffersink)
    {
        printf("buffersrc  or buffersink is nullptr\n");
        return -1;
    }
    snprintf(args, sizeof(args), "video_size=640x480:pix_fmt=%d:time_base=1/25:pixel_aspect=1/1", dec_ctx->pix_fmt);
    avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph);
    avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph);

    enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
    if (av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN) < 0)
    {
        printf("set   buufersink gesgi failed\n");
    }
    sprintf(filter_descr, "%s", "drawtext=fontfile=/usr/share/fonts/msyh.ttf:text='%{localtime\\:%Y-%m-%d  %X}':fontcolor=white:fontsize=24:x=w-tw-10:y=10");
    // sprintf(filter_descr, "%s", "drawtext=fontfile=/usr/share/fonts/msyh.ttf:text='hello':fontcolor=white:fontsize=24:x=w-tw-10:y=10");
    // sprintf(filter_descr, "%s%s%s", "drawtext=fontfile=/usr/share/fonts/msyh.ttf:","text='%{localtime\:%Y-%m-%d  %X}':","fontcolor=white:fontsize=24:x=w-tw-10:y=10");
    printf("text -> %s\n", filter_descr);
    AVFilterInOut *outputs = avfilter_inout_alloc();
    AVFilterInOut *inputs = avfilter_inout_alloc();
    outputs->name = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx = 0;
    outputs->next = NULL;
    inputs->name = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;
    if (avfilter_graph_parse_ptr(filter_graph, filter_descr, &inputs, &outputs, NULL) < 0)
    {
        return -1;
    }

    if (avfilter_graph_config(filter_graph, NULL) < 0)
    {
        return -1;
    }

    avfilter_inout_free(&inputs);
    avfilter_inout_free(&outputs);
    return 0;
}
int process_and_encode()
{
    AVPacket pkt;
    AVFrame *frame = av_frame_alloc();
    AVFrame *filt_frame = av_frame_alloc();
    int64_t start_time = av_gettime();

    while (av_gettime() - start_time < DURATION_SEC * 1000000)
    {
        if (av_read_frame(in_fmt_ctx, &pkt) >= 0 && pkt.stream_index == video_stream_index)
        {
            avcodec_send_packet(dec_ctx, &pkt);
            while (avcodec_receive_frame(dec_ctx, frame) == 0)
            {
                av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
                while (av_buffersink_get_frame(buffersink_ctx, filt_frame) >= 0)
                {
                    avcodec_send_frame(enc_ctx, filt_frame);
                    while (avcodec_receive_packet(enc_ctx, &pkt) == 0)
                    {
                        pkt.stream_index = out_stream->index;
                        pkt.pts = av_rescale_q(pkt.pts, enc_ctx->time_base, out_stream->time_base);
                        pkt.dts = av_rescale_q(pkt.dts, enc_ctx->time_base, out_stream->time_base);
                        pkt.duration = av_rescale_q(pkt.duration, enc_ctx->time_base, out_stream->time_base);
                        av_interleaved_write_frame(out_fmt_ctx, &pkt);
                        av_packet_unref(&pkt);
                    }
                    av_frame_unref(filt_frame);
                }
                av_frame_unref(frame);
            }
            av_packet_unref(&pkt);
        }
    }
    av_frame_free(&frame);
    av_frame_free(&filt_frame);
    return 0;
}

int process_and_encode1()
{
    AVPacket pkt;
    AVFrame *frame = av_frame_alloc();
    AVFrame *filt_frame = av_frame_alloc();
    int64_t start_time = av_gettime();

    int frame_count = 0; // 新忞:用于设置 filt_frame->pts

    while (frame_count <= 250)
    {
        // 1. 从输入迻取 packet
        if (av_read_frame(in_fmt_ctx, &pkt) >= 0 && pkt.stream_index == video_stream_index)
        {
            // 2. 解码
            avcodec_send_packet(dec_ctx, &pkt);
            while (avcodec_receive_frame(dec_ctx, frame) == 0)
            {
                // 3. 送入滤镜(忿 drawtext_
                av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);

                // 4. 从滤镜输凿 filtered 帿
                while (av_buffersink_get_frame(buffersink_ctx, filt_frame) >= 0)
                {
                    // ✿ 显式设置 filtered 帧的 PTS(避免编码器无法计算时长_
                    filt_frame->pts = frame_count++;

                    // 5. 编码
                    avcodec_send_frame(enc_ctx, filt_frame);
                    while (1)
                    {
                        AVPacket out_pkt;
                        av_init_packet(&out_pkt);
                        out_pkt.data = NULL;
                        out_pkt.size = 0;

                        if (avcodec_receive_packet(enc_ctx, &out_pkt) != 0)
                        {
                            break; // 暂无叿写入数据
                        }

                        // ✿ 轿换时间基(防歿不合泿 time_base 导致时长错迿_
                        av_packet_rescale_ts(&out_pkt, enc_ctx->time_base, out_stream->time_base);
                        out_pkt.stream_index = out_stream->index;

                        av_interleaved_write_frame(out_fmt_ctx, &out_pkt);
                        av_packet_unref(&out_pkt);
                    }
                    av_frame_unref(filt_frame);
                }
                av_frame_unref(frame);
            }
            av_packet_unref(&pkt);
        }
    }

    // ✿ 强制冲刷编码器缓存(flush_
    avcodec_send_frame(enc_ctx, NULL); // 通知编码噿:结束了

    while (1)
    {
        AVPacket out_pkt;
        av_init_packet(&out_pkt);
        out_pkt.data = NULL;
        out_pkt.size = 0;

        if (avcodec_receive_packet(enc_ctx, &out_pkt) != 0)
            break;

        av_packet_rescale_ts(&out_pkt, enc_ctx->time_base, out_stream->time_base);
        out_pkt.stream_index = out_stream->index;
        av_interleaved_write_frame(out_fmt_ctx, &out_pkt);
        av_packet_unref(&out_pkt);
    }

    av_frame_free(&frame);
    av_frame_free(&filt_frame);
    return 0;
}

int main()
{

    printf("this is ffmpeg drawtext test  mjpeg\n");
    av_register_all();
    avcodec_register_all();
    avdevice_register_all();
    avfilter_register_all();
    avformat_network_init();
    int ret = -1;

    ret = init_input_output();
    printf("reto = %d\n", ret);
    if (ret < 0)
    {
        return -1;
    }

    ret = -1;
    ret = init_filter_graph();
    printf("ret1 = %d\n", ret);
    if (ret < 0)
    {
        return -1;
    }
    ret = -1;
    ret = process_and_encode1();
    printf("ret2 = %d\n", ret);
    if (ret < 0)
    {
        return -1;
    }
    // 清理资源
    av_write_trailer(out_fmt_ctx);
    if (!(out_fmt_ctx->oformat->flags & AVFMT_NOFILE))
    {

        avio_closep(&out_fmt_ctx->pb);
        avcodec_free_context(&dec_ctx);
        avcodec_free_context(&enc_ctx);
        avformat_close_input(&in_fmt_ctx);
        avformat_free_context(out_fmt_ctx);
        avfilter_graph_free(&filter_graph);
    }

    return 0;
}
相关推荐
Tanecious.15 分钟前
C++--红黑树封装实现set和map
网络·c++
愚润求学3 小时前
【动态规划】01背包问题
c++·算法·leetcode·动态规划
源代码•宸3 小时前
C++高频知识点(十三)
开发语言·c++·经验分享·面经
lhxcc_fly4 小时前
mmap映射文件
c++·地址映射文件·!fd
闻缺陷则喜何志丹7 小时前
【并集查找 虚拟节点】P1783 海滩防御|省选-
数据结构·c++·洛谷·并集查找·虚拟节点
用户6853000754757 小时前
双指针法解决力扣922题:按奇偶排序数组II的完整指南
c++
CodeWithMe8 小时前
【读书笔记】《C++ Software Design》第十章与第十一章 The Singleton Pattern & The Last Guideline
开发语言·c++·设计模式
UP_Continue8 小时前
C++--List的模拟实现
开发语言·c++
GiraKoo9 小时前
【GiraKoo】Google Test (gtest) 单元测试框架
c++