1. ffmpeg 视频解码一
2. ffmpeg 视频解码二
3. ffmpeg 音频解码一
4. ffmpeg 音频解码二
5. ffmpeg 音视频解码
6. ffmpeg 视频编码一
7. ffmpeg 视频编码一(精简版)
8. ffmpeg 视频编码二(基于 libswscale 转换视频)
9. ffmpeg 过滤器libavfilter的使用
10. ffmpeg 视频编码三(基于 libavfilter 转换视频)

前言

前面已经使用 libswscale 这个库已经实现了对视频的缩放,也提了点还有种方式也可以处理我们的视频,那就是libavfilter,这篇就简要说一下这个库的简单使用吧。

基本流程

首先看一下大致使用流程吧

  • 由流程图可以看出使用这个库大致分为两步

    1. 初始化阶段
      这里主要是构建我们需要使用的filter,我们想要使用什么过滤器啊之类的,都在这里完成。
    2. 处理阶段
      这里就是使用我们刚刚初始化的filter了,看流程图应该看出来了,很简单,就两个函数,帧送往filter和从filter获取帧。

源代码


#pragma once
#define __STDC_CONSTANT_MACROS
#define _CRT_SECURE_NO_WARNINGSextern "C"
{#include "libavutil/imgutils.h"#include "libavutil/opt.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
}using namespace std;#define INPUT_FILE_NAME "lh_online.yuv"
#define OUTPUT_FILE_NAME "lh_online_tmp.yuv"//原视频相关参数//视频类型
#define SOURCE_AV_PIX_FMT_YUV AV_PIX_FMT_YUV420P
//的视频宽度
#define SOURCE_VIDEO_WIDTH 512
//视频高度
#define SOURCE_VIDEO_HEIGHT 288//编码相关参数//带编码视频类型
#define ENC_AV_PIX_FMT_YUV AV_PIX_FMT_YUV420P
//如果过滤器宽高有变化,这里也要变
//编码之后的视频宽度
#define ENC_VIDEO_WIDTH 512
//编码之后的视频高度
#define ENC_VIDEO_HEIGHT 512
//time_base  AVRational{1,15}
//一秒多少张图片(原视频是15。)
#define ENC_TIME_BASE_DEN 15AVFilterContext* buffersink_ctx;
AVFilterContext* buffersrc_ctx;
AVFilterGraph* filter_graph;AVFrame* frame, * tmp_frame;
int ret;//和编码的视频帧的宽高一样
//下面的一些计算是以上面的宏定义的
const char* filters_descr =  "[in]scale=512:512[out]";  //"[in]scale=512:288[out]";
//const char* filters_descr = "drawbox=x=100:y=100:w=100:h=100:color=red";
//const char* filters_descr = "drawtext=fontfile=方正粗黑宋简体.ttf:fontsize=32:fontcolor=red:text='Hello Word'";static int init_filter_graph()
{char args[512];int ret = 0;const AVFilter* buffersrc = avfilter_get_by_name("buffer");const AVFilter* buffersink = avfilter_get_by_name("buffersink");AVFilterInOut* outputs = avfilter_inout_alloc();AVFilterInOut* inputs = avfilter_inout_alloc();enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };filter_graph = avfilter_graph_alloc();if (!outputs || !inputs || !filter_graph) {ret = AVERROR(ENOMEM);goto clearup;}/* 缓冲视频源:从解码器解码的帧将被插入这里. */
snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d",SOURCE_VIDEO_WIDTH, SOURCE_VIDEO_HEIGHT, SOURCE_AV_PIX_FMT_YUV,1, ENC_TIME_BASE_DEN);ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",args, NULL, filter_graph);
if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");goto clearup;
}/* 缓冲视频接收:终止过滤器链. */
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",NULL, NULL, filter_graph);
if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");goto clearup;
}ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");goto clearup;
}/** 指定输入*/
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 ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,&inputs, &outputs, NULL)) < 0)goto clearup;if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)goto clearup;clearup:avfilter_inout_free(&inputs);avfilter_inout_free(&outputs);return ret;
}int main(int argc, char* argv[])
{//-------初始化一些配置---startint i = 0;int video_size = 0;int y_size = 0;size_t  data_size;uint8_t* temp_buffer;FILE* ofile;//输入视频基本信息//获得YUV420P像素格式每个像素占用的比特数(Bit Per Pixel)int src_bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(SOURCE_AV_PIX_FMT_YUV));//打开输入文件FILE* src_file = fopen(INPUT_FILE_NAME, "rb");if (!src_file ) {av_log(NULL, AV_LOG_ERROR, "Could not open \s.\n", INPUT_FILE_NAME);exit(1);}//打开输出文件ofile = fopen(OUTPUT_FILE_NAME, "wb+");if (!ofile) {av_log(NULL, AV_LOG_ERROR, "Could not open \s.\n", OUTPUT_FILE_NAME);exit(1);}//分配AVFrametmp_frame = av_frame_alloc();if (!tmp_frame) {fprintf(stderr, "Could not allocate video tmp_frame\n");exit(1);}tmp_frame->format = ENC_AV_PIX_FMT_YUV;tmp_frame->width = ENC_VIDEO_WIDTH;tmp_frame->height = ENC_VIDEO_HEIGHT;frame = av_frame_alloc();if (!frame) {fprintf(stderr, "Could not allocate video frame\n");exit(1);}frame->format = SOURCE_AV_PIX_FMT_YUV;frame->width = SOURCE_VIDEO_WIDTH;frame->height = SOURCE_VIDEO_HEIGHT;//计算 YUV420P 格式的图像需要占用的空间大小,分配内存空间temp_buffer = (uint8_t*)av_malloc(av_image_get_buffer_size(SOURCE_AV_PIX_FMT_YUV, SOURCE_VIDEO_WIDTH, SOURCE_VIDEO_HEIGHT, 1));//分配缓冲区并填入dst_data dst_linesizeif ((ret = av_image_alloc(frame->data, frame->linesize,SOURCE_VIDEO_WIDTH, SOURCE_VIDEO_HEIGHT, SOURCE_AV_PIX_FMT_YUV, 1)) < 0) {fprintf(stderr, "Could not allocate source image\n");goto end;}//分配缓冲区并填入dst_data dst_linesizeif ((ret = av_image_alloc(tmp_frame->data, tmp_frame->linesize,ENC_VIDEO_WIDTH, ENC_VIDEO_HEIGHT, ENC_AV_PIX_FMT_YUV, 1)) < 0) {fprintf(stderr, "Could not allocate source image\n");goto end;}//-------初始化一些配置---endret = init_filter_graph();if (ret < 0) {fprintf(stderr, "Unable to init filter graph:");goto end;}video_size = SOURCE_VIDEO_WIDTH * SOURCE_VIDEO_HEIGHT;y_size = ENC_VIDEO_WIDTH * ENC_VIDEO_HEIGHT;while (!feof(src_file)) {//读取数据 ,这里根据视频宽高和像素大小填充temp_bufferdata_size = fread(temp_buffer, 1, video_size * src_bpp / 8, src_file);if (!data_size)break;//填充 framememcpy(frame->data[0], temp_buffer, video_size);                    //Ymemcpy(frame->data[1], temp_buffer + video_size, video_size / 4);      //Umemcpy(frame->data[2], temp_buffer + video_size * 5 / 4, video_size / 4);  //V//转换一帧图像。/* 将frame发送到graph进行处理. */ret = av_buffersrc_add_frame(buffersrc_ctx, frame);if (ret < 0) {av_frame_unref(frame);fprintf(stderr, "Error submitting the frame to the filtergraph:");return ret;}/* 获取数据 */while ((ret = av_buffersink_get_frame(buffersink_ctx, tmp_frame)) >= 0) {/* now do something with our filtered frame *///写入文件y_size = tmp_frame->width * tmp_frame->height;printf("%d,%d \n",tmp_frame->width, tmp_frame->height);fwrite(tmp_frame->data[0], 1, y_size, ofile);    //Yfwrite(tmp_frame->data[1], 1, y_size / 4, ofile);  //Ufwrite(tmp_frame->data[2], 1, y_size / 4, ofile);  //Vav_frame_unref(tmp_frame);}if (ret == AVERROR(EAGAIN)) {continue;}else if (ret == AVERROR_EOF) {break;}else if (ret < 0) {fprintf(stderr, "Error filtering the data:");goto end;}}end://资源释放avfilter_graph_free(&filter_graph);av_frame_free(&tmp_frame);av_frame_free(&frame);return 0;}

一些效果演示

  1. [in]scale=512:512[out]

  2. drawbox=x=100:y=100:w=100:h=100:color=red

  3. drawtext=fontfile=方正粗黑宋简体.ttf:fontsize=32:fontcolor=red:text=‘Hello Word’

  • 注意:

    • filters_descr 这里就是设置的地方,和命令行类似,还有种写法是单个编写,有兴趣的可以去研究下

    • 支持所有fempeg里面filter支持的写法

    • 具体可参照下面官方文档

      http://ffmpeg.org/ffmpeg-filters.html
      http://ffmpeg.org/doxygen/trunk/filtering_video_8c-example.html

到此,filter的基本使用就介绍到这里了,虽然这里直展示了视频的一些效果,但音频是一样的,如果有必要,后面再写一篇音频的filter吧。

好了,下篇就使用这个来处理我们的视频吧。

ffmpeg 过滤器libavfilter的使用相关推荐

  1. FFmpeg过滤器框架分析

    FFmpeg过滤器框架分析 目录 主要结构体和API介绍 AVFilterGraph-对filters系统的整体管理 AVFilter-定义filter本身的能⼒ AVFilterContext-fi ...

  2. ffmpeg 视频编码三(基于 libavfilter 转换视频)

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  3. ffmpeg 音频解码一

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  4. ffmpeg 音频解码二

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  5. ffmpeg 视频编码一(精简版)

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  6. ffmpeg 视频解码一

    1. ffmpeg 视频解码一 2. ffmpeg 视频解码二 3. ffmpeg 音频解码一 4. ffmpeg 音频解码二 5. ffmpeg 音视频解码 6. ffmpeg 视频编码一 7. f ...

  7. 【FFmpeg】ffmpeg工具源码分析(四):filter(过滤器、滤镜)详解

    1.简介 FFmpeg用来处理音视频,实现处理功能的核心就是filter(滤镜),和我们使用的美颜功能的滤镜意思差不多,FFmpeg的filter(滤镜)不仅可以处理视频,还能处理音频.字幕等. 官方 ...

  8. FFmpeg filter过滤器使用详解

    1.FFmpeg过滤器简介 FFmpeg filter 提供了很多音视频特效处理功能,比如视频缩放.截取.翻转.叠加等. FFmpeg有很多已经实现好的滤波器,这些滤波器的实现位于libavfilte ...

  9. ffmpeg 缩放算法_抖音快手短视频分屏怎么做?ffmpeg scale过滤器了解下

    原标题:抖音快手短视频分屏怎么做?ffmpeg scale过滤器了解下 引言 我们每天都在使用的抖音,快手,西瓜视频等APP,里面有为数众多的视频文件.对于这些文件,我们需要考虑各个手机厂商的品牌手机 ...

最新文章

  1. lex 词法分析 linux,lex语言词法分析
  2. vue 计算属性和data_vue之watch和计算属性computed
  3. js表单验证处理和childNodes 和children 的区别
  4. UVA - 400 Unix ls
  5. xcode+文字支持html元素,iOS使用UITextview实现富文本编辑
  6. DTS开发记录(序)
  7. 《局域网聊天——Android》
  8. matlab中函数绝对值图像,ex的图像(绝对值的函数图像口诀)
  9. 策略设计模式_设计模式之 策略模式
  10. Object-C使用NSLog打印日志
  11. mybaitis快速生成_Mybatis中使用mybatis-generator结合Ant脚本快速自动生成Model、Mapper等文件...
  12. Java 跑酷游戏 rush,翻转跑酷游戏安卓下载|翻转跑酷最新版(Flip Rush)下载v1.0.5-乐游网安卓下载...
  13. 第 1 篇 Scrum 冲刺博客
  14. 在mybatis里面设置不同数据库运行环境和适应性问题
  15. c++中 . 和 - 的区别
  16. 看了有多个人格的人,自己拍的视频
  17. 计算机物理学知识点,初中物理知识点计算公式表总结
  18. python爬网站信息_一个爬取实习僧网站信息的爬虫
  19. 工程师软技能~聊聊价值,价值观和价值积累
  20. usercity 小程序_微信小程序API 用户信息 wx.getUserInfo(OBJECT)

热门文章

  1. Arthas - 阿尔萨斯 - 入门使用(Arthas插件)
  2. 经典算法之黑色星期五
  3. 蓝桥杯真题系列:C语言A组奇妙的数字
  4. python计算圆周率
  5. 利用HTML5的canvas进行鼠标写字
  6. 029 | 安亚同城网商业计划书 | 大学生创新训练项目申请书 | 极致技术工厂
  7. 苹果CEO史蒂夫·乔布斯(Steve Jobs),2005年,斯坦福大学
  8. SpringMvc工作流程图讲解
  9. react 前端分页查询数据导出excel
  10. mount ntfs分区和配置xmms手记(转)