FFmpeg Filter

news/2024/7/10 21:13:32 标签: ffmpeg

原理

1.将压缩后的每一帧数据进行解码

2.对解码后的数据进行计算

3.再将处理好的数据进行编码

简单滤镜

ffplay -i /Users/king/Desktop/ffmpeg/audio/cut.mp4 -vf "drawbox=x=30:y=30:w=60:h=60:c=red"

drawbox 滤镜名字

后边用等号连接参数,参数使用冒号进行分割 

查看滤镜

ffmpeg -h filter=drawbox  

ffmpeg -filters 支持的滤镜

filter语法

在avfilter参数之间用“:”来分割 多个filter串联分割使用“,”分割。多个filter之间没有关联用“;”进行分割

ffplay -i /Users/xxxxx/Desktop/ffmpeg/audio/cut.mp4  -vf "

//
//  filter_test.c
//  ffmpegaudio
//
//  Created by KING on 2023/12/23.
//
/**
 * Set a binary option to an integer list.
 *
 * @param obj    AVClass object to set options on
 * @param name   name of the binary option
 * @param val    pointer to an integer list (must have the correct type with
 *               regard to the contents of the list)
 * @param term   list terminator (usually 0 or -1)
 * @param flags  search flags
 */
//ffplay -i /Users/king/Desktop/ffmpeg/audio/filter.yuv -pixel_format GRAY8 -video_size 1920x1080

#include "filter_test.h"
#include "libavutil/avutil.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
#include "libavutil/opt.h"
#include "libavformat/avformat.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"


const char *filter_desc = "drawbox=30:10:64:64:red";
static int init_filters(const char *filter_desc,AVFormatContext *fmt_context,AVCodecContext *codec_context,AVFilterGraph **graph, AVFilterContext **buf_ctx,AVFilterContext **buf_sink_ctx, int video_stream_index) {
    int ret = -1;
    char args[512] = {0,};
    AVRational time_base = fmt_context->streams[video_stream_index]->time_base;
    
    AVFilterInOut *inputs = avfilter_inout_alloc();
    AVFilterInOut *output = avfilter_inout_alloc();
    if (!inputs || !output){
        printf("output inputs failed\n");
        return AVERROR(ENOMEM);
    }
    
    *graph = avfilter_graph_alloc();
    if (!*graph){
        printf("graph create failed\n");
        return AVERROR(ENOMEM);
    }
    //"[in]drawbox=xxx[out]"
    const AVFilter *bufsrc = avfilter_get_by_name("buffer");
    if (!bufsrc) {
        printf("buffer src create failed\n");
        return  ret;
    }
    const AVFilter *bufsinck= avfilter_get_by_name("buffersink");
    if (!bufsinck) {
        printf("bufsinck  create failed\n");
        return ret;
    }
    
    /// 输入buffer filter创建
    snprintf(args,
            512,
            "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",codec_context->width,codec_context->height,codec_context->pix_fmt,time_base.num,time_base.den,codec_context->sample_aspect_ratio.num,codec_context->sample_aspect_ratio.den);
    ret = avfilter_graph_create_filter(buf_ctx, bufsrc, "in", args, NULL, *graph);
    if (ret < 0) {
        printf("avfilter_graph_create_filter in failed\n");
        goto __ERROR;
    }
    
    
    ///输出 buffer filter 创建
    enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P,AV_PIX_FMT_GRAY8,AV_PIX_FMT_NONE};
    ret = avfilter_graph_create_filter(buf_sink_ctx, bufsinck, "out", NULL, NULL, *graph);
    if (ret < 0) {
        printf("avfilter_graph_create_filter out failed\n");
        goto __ERROR;
    }
    av_opt_set_int_list(*buf_sink_ctx,"pix_fmts",pix_fmts,AV_PIX_FMT_NONE,AV_OPT_SEARCH_CHILDREN);
    
    // create inout
    ///输出 这里的name 是反的
    inputs->name = av_strdup("out");
    inputs->filter_ctx = *buf_sink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;
    
    /// 输入
    output->name = av_strdup("in");
    output->filter_ctx = *buf_ctx;
    output->pad_idx = 0;
    output->next = NULL;

    // create filter and graph for filter desciption
    avfilter_graph_parse_ptr(*graph, filter_desc, &inputs, &output,NULL);
    ret = avfilter_graph_config(*graph, NULL);
    if (ret < 0) {
        printf("avfilter_graph_config failed\n");
    }
__ERROR:
    avfilter_inout_free(&inputs);
    avfilter_inout_free(&output);
    return ret;
}

int create_filter(char *file_name,  AVFormatContext **fmt_context,AVCodecContext **codec_context, int *video_stream_index, AVCodec **dec) {
    int ret = 0;
    ret = avformat_open_input(fmt_context, file_name, NULL, NULL);
    if (ret < 0) {
        printf("open fail");
    }
    
    ret = avformat_find_stream_info(*fmt_context, NULL);
    if (ret < 0) {
        printf("avformat_find_stream_info fail");
    }
    
    ret = av_find_best_stream(*fmt_context, AVMEDIA_TYPE_VIDEO, -1, -1, dec,0);
    if (ret < 0) {
        printf("av_find_best_stream fail");
    }
    *video_stream_index = ret;
    *codec_context = avcodec_alloc_context3(*dec);
    if (!codec_context) {
        printf("codec_context fdailed");
    }
    
    avcodec_parameters_to_context(*codec_context, (*fmt_context)->streams[*video_stream_index]->codecpar);
    
    ///打开解码器
    ret = avcodec_open2(*codec_context, *dec, NULL);
    if (ret < 0) {
        printf("avcodec_open2 fail");
    }
    return ret;
}
static int do_frame(AVFrame *filter_frame, FILE *out) {
    int ret = 0;
    fwrite(filter_frame->data[0], 1, filter_frame->width * filter_frame->height, out);
    fflush(out);
    return ret;
}
static int filter_video(AVFilterContext*buf_ctx,AVFilterContext*buf_sink_ctx, AVFrame *frame, AVFrame *filter_frame,FILE *out) {
    int ret = 0;
    
    ret = av_buffersrc_add_frame(buf_ctx, frame);
    if (ret < 0) {
        printf("av_buffersrc_add_frame failed");
        return ret;
    }
    while (1) {
        ret = av_buffersink_get_frame(buf_sink_ctx, filter_frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        }

        if (ret < 0) {
            return ret;
        }
        do_frame(filter_frame,out);
        av_frame_unref(filter_frame);
    }
    av_frame_unref(frame);
    return ret;
}

static int decode_frame_and_filter(AVFilterContext*buf_ctx,AVFilterContext*buf_sink_ctx,AVCodecContext* codec_context,AVFrame *frame, AVFrame *filter_frame, FILE *out) {
    int ret = 0;
    ret = avcodec_receive_frame(codec_context, frame);
    if (ret < 0) {
        if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
            printf("avcodec_receive_frame failed");
        }
        return ret;
    }
    return filter_video(buf_ctx,buf_sink_ctx,frame,filter_frame,out);
}

void player_filter_test() {
    const  char *filter_desc="drawbox=30:10:64:64:red";
//    const  char *filter_desc="movie=/xxx/docs/media/16324057162865/16324083424959.png,scale=64:64[wm];[in][wm]overlay=30:10";

    AVFormatContext *fmt_context = NULL;
    AVCodec *dec = NULL;
    AVCodecContext *codec_context = NULL;
    int video_stream_index = 0;
    AVFilterContext *buf_ctx = NULL;
    AVFilterContext *buf_sink_ctx = NULL;
    AVFilterGraph *graph = NULL;

    const  char *file_name = "/Users/king/Desktop/ffmpeg/audio/cut.mp4";
    AVPacket packet;
    AVFrame *frame = NULL;
    AVFrame *filter_frame = NULL;
    FILE *out = NULL;
    int ret = 0;
    frame = av_frame_alloc();
    filter_frame = av_frame_alloc();
    out = fopen("/Users/king/Desktop/ffmpeg/audio/filter.yuv", "wb+");
    if (!out) {
        printf("FILE fail");
        goto __ERROR;
    }
    if (!frame || !filter_frame) {
        printf("init_frame fail");
        goto __ERROR;
    }

    if ((ret = create_filter(file_name,&fmt_context,&codec_context,&video_stream_index,&dec)) < 0) {
        printf("create_filter fail");
    } else  {
        if ((ret = init_filters(filter_desc,fmt_context,codec_context,&graph,&buf_ctx,&buf_sink_ctx,video_stream_index))  < 0) {
            printf("init_filters fail");
            goto __ERROR;
        }
    }
    while (1) {
        if((ret = av_read_frame(fmt_context,&packet)) < 0) {
            break;
        }
        if (packet.stream_index == video_stream_index) {
            if ( (ret = avcodec_send_packet(codec_context, &packet)) < 0) {
                printf("avcodec_send_packet failed\n");
                break;
            }
            if ((ret = decode_frame_and_filter(buf_ctx,buf_sink_ctx,codec_context,frame,filter_frame,out)) < 0) {
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                    continue;;
                }
                printf("decode_frame_and_filter failed\n");
                break;
            }
        }
    }
    
__ERROR:
    if (out) {
        fclose(out);
    }
    if (fmt_context) {
        avformat_free_context(fmt_context);
    }
    if (codec_context) {
        avcodec_free_context(&codec_context);
    }
    if (graph) {
        avfilter_graph_free(&graph);
    }
    
    if (buf_ctx) {
        avfilter_free(buf_ctx);
    }
    if (buf_sink_ctx) {
        avfilter_free(buf_sink_ctx);
    }
    if (dec) {
        av_free(dec);
    }


    printf("finish");
}


// 创建graph avfilter_graph_alloc()
// 创建buffer filter 和 buffersink filter
//分析 filter描述符号 并构建avfiltergraph
// 使创建好的avfiltergraph生效

/// 使用filter
/// 1.获得解码后的原始数据pcm/yuv
/// 2.将数据添加到bufferfilter中去
/// 3.从buffer sink中读取处理好的数据
/// 当所有的数据处理完之后 释放资源


//实现自己的filter
//找一个现成的filter为模版
//替换代码中所有filter name 关键字
/// 修改libavfilter 中的makefile 增加新的filter
/// 修改allfilter.c增加新的filter 并重新编译ffmpeg
///

"

通过api的方式使用filter的流程

1.设置filter描述符 (vf 后边的)

2.初始化filter 

3.进行滤镜处理

4.释放filter资源

ffmpeg -i input.mp4 -vf "setpts=0.5*PTS[v]" speed2.0.mp4

特殊filter

buffer filter 

buffersink filter 


http://www.niftyadmin.cn/n/5292603.html

相关文章

java 程序堵塞的排查方式

java 程序堵塞的排查方式 当java 程序堵塞 任何异常 信息&#xff0c;该如何排查。## 死锁问题先确实是否死锁问题&#xff0c;使用arthas &#xff0c;执行 thread -b 命令。不是死锁问题&#xff0c;执行 jstack 命令 保留 当前执行命令。## 分析Jstack未知全貌 不予置评打完…

第十一章 Stream消息驱动

Stream消息驱动 gitee:springcloud_study: springcloud&#xff1a;服务集群、注册中心、配置中心&#xff08;热更新&#xff09;、服务网关&#xff08;校验、路由、负载均衡&#xff09;、分布式缓存、分布式搜索、消息队列&#xff08;异步通信&#xff09;、数据库集群、…

【AI】图像识别和无人零售

目录 一、引言 二、AI商品识别的定义 三、所用技术 四、解决方案的种类 五、发展历程 六、瓶颈 七、未来趋势 一、引言 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;AI商品识别已经成为无人零售领域的一项关键技术。特别是在智能无人售货柜等场景…

redis cluster判断key属于那个分片。

一、判断阿里云 redis cluster&#xff0c;的key属于那个分片。 阿里云特有的命令info key 可以查看key属于那个slot&#xff0c;那个分片 命令行查看&#xff1a; xxxx:6379> info key xxxx_compressed_xxx slot:4941 node_index:9 xxxx:6379> cluster keyslot xxxx_…

Vue 监听状态 watch 与监听状态 watchEffect

监听状态 watch watch 函数用于监听响应式数据的变化。 使用 watch 函数监听基于 ref 创建的响应式数据 (基本数据类型)。 import { ref, watch } from "vue" export default {setup() {const text ref("")watch(text, (current, previous) > {conso…

Midjourney怎么用?超全AI绘画Midjourney关键词

MidTool&#xff08;https://www.aimidtool.com/&#xff09;是一款强大的绘图软件&#xff0c;它融合了人工智能与人类创意的能力&#xff0c;采用最先进的AIGC技术&#xff0c;MidTool可以根据描述和参考图像&#xff0c;快速、准确地生成符合要求的绘画作品。不仅可以模拟各…

uniapp-H5项目的坑

先推荐个插件库-非常好用&#xff1a;https://ext.dcloud.net.cn/ 一、uniapp h5 适配pc端 1、问题&#xff1a;屏幕尺寸在400px~960px之间页面排版错乱 2、解决方法&#xff1a;在page.json文件中 "globalStyle": {"navigationStyle": "custom&quo…

人机协同编程pyqt/pyside界面开发——第一章pyqt/pyside编程基础

环境安装:https://www.bilibili.com/video/BV1wc411D7WF/ 特别说明本文章适用于出于科研需要,用到这部分技术的,对其中的技术细节并未作过多的探究。而把侧重点放在科研工作者,如何通过这项技术的使用来达到自己的目的。尽可能的做到需要什么讲什么,用到什么学什么。这可以…