使用ffmpeg的filter处理yuv数据包括split filter(分流)、crop filter(裁剪)、vflip filter(垂直向上的翻转)、overlay filter(合成)

该代码示例演示了如何使用ffmpeg库进行YUV数据处理,包括使用splitfilter进行视频分流,cropfilter进行裁剪,vflipfilter实现垂直翻转,以及overlayfilter进行图像合成。通过创建和配置AVFilterGraph,建立过滤器之间的链接,并读取写入YUV数据,实现了视频帧的处理和输出。
摘要由CSDN通过智能技术生成

使用ffmpeg的filter处理yuv数据包括split filter(分流)、crop filter(裁剪)、vflip filter(垂直向上的翻转)、overlay filter(合成)

#include <stdio.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>


int main()
{
    printf("Hello video mark!\n");
    int ret = 0;
    FILE* infile = NULL;
    const char* infileName = "768x320.yuv";
    fopen_s(&infile, infileName, "rb+");
    if(!infile)
    {
        printf("fopen_s() infile failed!\n");
        return -1;
    }

    int in_width = 768;
    int in_height = 320;

    FILE* outfile = NULL;
    const char* outfileName = "out_mark.yuv";
    fopen_s(&outfile, outfileName, "wb");
    if(!outfile)
    {
        printf("fopen_s() outfile failed!\n");
        return -1;
    }

    //注册初始化所有过滤器
    avfilter_register_all();

    //用于整个过滤流程的一个封装
    AVFilterGraph* filter_grah = avfilter_graph_alloc();
    if(!filter_grah)
    {
        printf("avfilter_graph_alloc() failed!\n");
        return -1;
    }

    char args[512];
    sprintf(args,
            "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
            in_width, in_height, AV_PIX_FMT_YUV420P,
            1, 25, 1, 1);

    //获取一个用于AVFilterGraph输入的过滤器
    AVFilter* buffersSrc = avfilter_get_by_name("buffer");
    AVFilterContext* bufferSrc_ctx;
    //将bufferSrc添加到AVFilterGraph中
    //args是用在bufferSrc的参数
    ret = avfilter_graph_create_filter(&bufferSrc_ctx, buffersSrc,
                                       "in", args, NULL, filter_grah);
    if(ret < 0)
    {
        printf("avfilter_graph_create_filter() buffersSrc failed!\n");
        return -1;
    }

    AVBufferSinkParams* bufferSinkParams;
    AVFilterContext* bufferSink_ctx;
    //获取一个用于AVFilterGraph输出的过滤器
    AVFilter* bufferSink = avfilter_get_by_name("buffersink");
    enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
    bufferSinkParams = av_buffersink_params_alloc();
    bufferSinkParams->pixel_fmts = pix_fmts;
    ret = avfilter_graph_create_filter(&bufferSink_ctx, bufferSink,
                                       "out", NULL, bufferSinkParams, filter_grah);
    if(ret < 0)
    {
        printf("avfilter_graph_create_filter() bufferSink failed!\n");
        return -1;
    }


    //split filter(分流)
    AVFilter* splitFilter = avfilter_get_by_name("split");
    AVFilterContext* splitFilter_ctx;
    //outputs=2 分流2通道
    ret = avfilter_graph_create_filter(&splitFilter_ctx, splitFilter, "split",
                                       "outputs=2", NULL, filter_grah);
    if(ret < 0)
    {
        printf("avfilter_graph_create_filter() splitFilter failed!\n");
        return -1;
    }

    //crop filter(裁剪)
    AVFilter* cropFilter = avfilter_get_by_name("crop");
    AVFilterContext* cropFilter_ctx;
    ret = avfilter_graph_create_filter(&cropFilter_ctx, cropFilter, "crop",
                                       "out_w=iw:out_h=ih/2:x=0:y=0", NULL, filter_grah);

    if(ret < 0)
    {
        printf("avfilter_graph_create_filter() cropFilter failed!\n");
        return -1;
    }


    //vflip filter(垂直向上的翻转)
    AVFilter* vflipFilter = avfilter_get_by_name("vflip");
    AVFilterContext* vflipFilter_ctx;
    ret = avfilter_graph_create_filter(&vflipFilter_ctx, vflipFilter, "vflip",
                                       NULL, NULL, filter_grah);
    if(ret < 0)
    {
        printf("avfilter_graph_create_filter() vflipFilter failed!\n");
        return -1;
    }


    //overlay filter(合成)
    AVFilter* overlayFilter = avfilter_get_by_name("overlay");
    AVFilterContext* overlayFilter_ctx;
    ret = avfilter_graph_create_filter(&overlayFilter_ctx, overlayFilter, "overlay",
                                       "y=0:H/2", NULL, filter_grah);

    if(ret < 0)
    {
        printf("avfilter_graph_create_filter() overlayFilter failed!\n");
        return -1;
    }


    //srcFilter -> splitFilter
    //srcpad、dstpad是一个索引,通道的索引
    ret = avfilter_link(bufferSrc_ctx, 0, splitFilter_ctx, 0);
    if(ret != 0)
    {
        printf("avfilter_link() srcFilter -> splitFilter failed!\n");
        return -1;
    }

    //splitFilter[0] -> overlayfilter[0]
    ret = avfilter_link(splitFilter_ctx, 0, overlayFilter_ctx, 0);
    if(ret != 0)
    {
        printf("avfilter_link() splitFilter[0] -> overlayfilter[0] failed!\n");
        return -1;
    }

    //splitFilter[1] -> cropFilter
    ret = avfilter_link(splitFilter_ctx, 1, cropFilter_ctx, 0);
    if(ret != 0)
    {
        printf("avfilter_link() splitFilter[1] -> cropFilter failed!\n");
        return -1;
    }
\
    //cropFilter -> vflipFilter
    ret = avfilter_link(cropFilter_ctx, 0, vflipFilter_ctx, 0);
    if(ret != 0)
    {
        printf("avfilter_link() cropFilter -> vflipFilter failed!\n");
        return -1;
    }

    //vflipFilter -> overlayfilter[1]
    ret = avfilter_link(vflipFilter_ctx, 0, overlayFilter_ctx, 1);
    if(ret != 0)
    {
        printf("avfilter_link() vflipFilter -> overlayfilter[1] failed!\n");
        return -1;
    }

    //overlayfilter -> bufferSink
    ret = avfilter_link(overlayFilter_ctx, 0, bufferSink_ctx, 0);
    if(ret != 0)
    {
        printf("avfilter_link() overlayfilter -> bufferSink failed!\n");
        return -1;
    }

    //确认所有过滤器的连接
    ret = avfilter_graph_config(filter_grah, NULL);
    if(ret < 0)
    {
        printf("avfilter_graph_config() failed!\n");
        return -1;
    }

    //打印filtergraph的信息
    char* graph_str = avfilter_graph_dump(filter_grah, NULL);
    printf("\n%s\n", graph_str);
    av_free(graph_str);

    //输入帧
    AVFrame* frame_in = av_frame_alloc();
    unsigned char* frame_buffer_in = (unsigned char*)av_malloc(
                                        av_image_get_buffer_size(AV_PIX_FMT_YUV420P, in_width, in_height, 1));

    //输出帧
    AVFrame* frame_out = av_frame_alloc();

    frame_in->width = in_width;
    frame_in->height = in_height;
    frame_in->format = AV_PIX_FMT_YUV420P;

    uint32_t frame_size = in_width * in_height * 3 / 2;

    while (1)
    {
        //读取yuv数据
        if(fread(frame_buffer_in, 1, frame_size, infile) != frame_size)
        {
            break;
        }

        av_image_fill_arrays(frame_in->data, frame_in->linesize, frame_buffer_in, AV_PIX_FMT_YUV420P, in_width, in_height, 1);


        //添加帧数据到过滤器
        if(av_buffersrc_add_frame(bufferSrc_ctx, frame_in) < 0)
        {
            printf("av_buffersrc_add_frame() failed!\n");
            break;
        }


        //获取输出帧数据
        ret = av_buffersink_get_frame(bufferSink_ctx, frame_out);
        if(ret < 0)
        {
            printf("av_buffersink_get_frame() failed!\n");
            break;
        }


        //输出文件
        if(frame_out->format == AV_PIX_FMT_YUV420P)
        {
            for (int i = 0; i < frame_out->height; i++) {
                fwrite(frame_out->data[0] + frame_out->linesize[0] * i, 1, frame_out->width, outfile);
            }
            for (int i = 0; i < frame_out->height / 2; i++) {
                fwrite(frame_out->data[1] + frame_out->linesize[1] * i, 1, frame_out->width / 2, outfile);
            }
            for (int i = 0; i < frame_out->height / 2; i++) {
                fwrite(frame_out->data[2] + frame_out->linesize[2] * i, 1, frame_out->width / 2, outfile);
            }
        }

        av_frame_unref(frame_out);

    }

    fclose(infile);
    fclose(outfile);

    av_frame_free(&frame_in);
    av_frame_free(&frame_out);
    avfilter_graph_free(&filter_grah);
    printf("end video mark!\n");
    return 0;
}```

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Ffmpeg是一款开源的视频处理软件,可以通过Filter进行视频处理Filter可以对视频进行裁剪、缩放、色彩调整、添加水印等各种处理。下面是使用Filter的一些示例命令: 1. 裁剪视频: ``` ffmpeg -i input.mp4 -vf "crop=720:480:20:20" output.mp4 ``` 该命令将输入视频裁剪为720x480的大小,左边和上边各留出20像素的边距。 2. 缩放视频: ``` ffmpeg -i input.mp4 -vf "scale=320:240" output.mp4 ``` 该命令将输入视频缩放为320x240的大小。 3. 调整视频色彩: ``` ffmpeg -i input.mp4 -vf "eq=brightness=0.2:saturation=1.5" output.mp4 ``` 该命令将输入视频亮度降低20%,饱和度增加50%。 4. 添加水印: ``` ffmpeg -i input.mp4 -i watermark.png -filter_complex "overlay=10:10" output.mp4 ``` 该命令将输入视频和水印图片叠加在一起,水印位置为视频左上角偏移10像素。 以上仅是Filter的一些示例,Ffmpeg支持更多的Filter,可根据需要自行查阅文档使用。 ### 回答2: FFmpeg是一款开源的多媒体处理工具,可以实现视频和音频的录制、转码、编辑等功能。在使用FFmpeg进行视频处理时,Filter是一项重要的功能,可以用来对视频进行各种处理和效果的添加。 FFmpegFilter是通过-vf(video filter)参数来实现的。在命令行中加入-vf参数后,可以添加各种不同的Filter,以达到不同的视频效果。例如,可以使用Filter来实现对视频裁剪、旋转、缩放等操作。 具体使用Filter的语法如下: -vf "filter_name=parameter1:value1,parameter2:value2,..." 其中,filter_name表示要使用Filter名称,parameter表示该Filter的具体参数,value表示参数的值。不同的Filter会有不同的参数,需要根据具体需求进行设置。 例如,要对视频进行旋转的话,可以使用rotate Filter。具体使用方法如下: -vf "rotate=angle=30" 通过以上命令,即可将视频旋转30度。同样的方式,对于其他Filter,只需要将filter_name和parameter替换为对应的值即可。 另外,在Filter中还可以使用Filter链,即将多个Filter串联使用,实现复杂的效果。通过在-vf参数中添加多个Filter,并使用逗号分隔,可以将多个Filter依次执行。 总之,FFmpeg中的Filter功能强大且灵活,可以实现对视频进行各种处理和效果的添加。通过适当的命令行参数设置,可以轻松实现对视频进行裁剪、旋转、缩放等操作,丰富视频的视觉效果。 ### 回答3: FFmpeg 是一款功能强大的多媒体处理工具,可以用于音视频文件的转换、剪辑、处理等。FilterFFmpeg 的一个重要功能,可以用来对音视频进行各种滤镜处理使用 FFmpeg 进行滤镜处理一般需要以下几个步骤: 1. 首先,需要了解 FFmpeg 支持的滤镜和其参数。可以通过命令 `ffmpeg -filters` 查看所有可用滤镜列表,以及命令 `ffmpeg -h filter=<滤镜名称>` 查看特定滤镜的详细参数信息。 2. 选择合适的滤镜后,需要通过命令行指定输入文件和输出文件,以及滤镜参数。下面是一个使用 FFmpeg 添加文本水印的命令示例: ``` ffmpeg -i input.mp4 -vf "drawtext=text='Hello World':fontfile=Arial.ttf:fontsize=24:fontcolor=white:x=10:y=10" output.mp4 ``` 这个命令会将输入文件 `input.mp4` 进行滤镜处理,添加一个文本水印,输出为 `output.mp4`。其中,`drawtext` 是指定滤镜为文本水印,后面的参数是具体的水印文字内容、字体文件、字体大小、字体颜色以及位置等信息。 3. 根据需要,可以添加多个滤镜和参数。可以通过 `;` 或者 `,` 分隔多个滤镜。例如: ``` ffmpeg -i input.mp4 -vf "scale=640:480,rotate=30*PI/180" output.mp4 ``` 这个命令会先将输入文件 `input.mp4` 进行尺寸缩放,然后再旋转一定角度后输出为 `output.mp4`。 4. 最后,运行命令进行滤镜处理。运行命令后,FFmpeg 会按照指定参数进行滤镜处理,并生成输出文件。 需要注意的是,在使用 FFmpeg 进行滤镜处理时,可以根据实际需求选择不同的滤镜和参数,也可以自定义滤镜,以实现特定的效果。同时,滤镜的顺序也可能会影响最终的效果,所以需要根据具体情况进行调整。 总之,FFmpeg 的滤镜功能强大且灵活,可以应用于音视频的各种处理场景,帮助我们实现更多的创意和效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值