ffmpeg视频添加filter-yuv

ffmpeg视频添加filter-yuv

直接上代码,具体问题请看注释。

//main.cpp

#define __STDC_CONSTANT_MACROS  

#include <stdio.h>
#include <stdlib.h>

extern "C"  
{  
#include "libavformat/avformat.h"  
#include "libavformat/avio.h"  
#include "libavcodec/avcodec.h"  
#include "libswscale/swscale.h"  
#include "libavutil/avutil.h"  
#include "libavutil/mathematics.h"  
#include "libswresample/swresample.h"  
#include "libavutil/opt.h"  
#include "libavutil/channel_layout.h"  
#include "libavutil/samplefmt.h"  
#include "libavdevice/avdevice.h"  //摄像头所用  
#include "libavfilter/avfilter.h"  
#include "libavutil/error.h"  
#include "libavutil/mathematics.h"    
#include "libavutil/time.h"    
#include "libavutil/fifo.h"  
#include "libavutil/audio_fifo.h"   //这里是做分片时候重采样编码音频用的  
#include "libavfilter/avfiltergraph.h"  
#include "libavfilter/buffersink.h" //filter会用到
#include "libavfilter/buffersrc.h"  //filter会用到
#include "inttypes.h"  
#include "stdint.h"  
};  

#pragma comment(lib,"avformat.lib")  
#pragma comment(lib,"avcodec.lib")  
#pragma comment(lib,"avdevice.lib")  
#pragma comment(lib,"avfilter.lib")  
#pragma comment(lib,"avutil.lib")  
#pragma comment(lib,"postproc.lib")  
#pragma comment(lib,"swresample.lib")  
#pragma comment(lib,"swscale.lib")  

#define WIDTH 352 
#define HEIGHT 288
#define VIEO_PIX 0       //AV_PIX_FMT_YUV420P
#define TIMEBASE_NUM 1
#define TIMEBASE_DEN 25
/*
SAR_x     DAR_x * height
-------- = --------------------
SAR_y     DAR_y * width
*/
#define SAR_X        1
#define SAR_Y        1

//滤镜的内容;
//const char *filter_descr = "lutyuv='u=128:v=128'";      //变成灰色  
//const char *filter_descr = "boxblur";                   //模糊处理
//const char *filter_descr = "hflip";  
//const char *filter_descr = "hue='h=60:s=-3'";  
//const char *filter_descr = "crop=2/3*in_w:2/3*in_h";  
//const char *filter_descr = "drawbox=x=100:y=100:w=100:h=100:color=pink@0.5";  
const char *filter_descr = "drawtext=fontfile=../simhei.ttf:fontcolor=black:fontsize=50:text='zhuweigang'";   //字母ttf文件
/* other way:
   scale=78:24 [scl]; [scl] transpose=cclock // assumes "[in]" and "[out]" to be input output pads respectively
*/

//图表FilterGraph
static AVFilterGraph *m_filter_graph = NULL;
//输入filter的context
static AVFilterContext *buffersrc_ctx = NULL;
//输出filter的context
static AVFilterContext *buffersink_ctx = NULL;

//初始化filter
static int init_filters(const char *filters_descr)
{
	int ret = 0;
	char video_info_args[512] = {0};                                               //视频的基本信息,包括宽高,timebase等填入的字符串数组
    AVFilter *buffersrc  = avfilter_get_by_name("buffer");                         //输入filter
    AVFilter *buffersink = avfilter_get_by_name("buffersink");                     //输出filter
    AVFilterInOut *outputs = avfilter_inout_alloc();                               //输入filter的pin,名称out
    AVFilterInOut *inputs  = avfilter_inout_alloc();                               //输出filter的pin,名称in

	//初始化图表filter graph,filter分为grarph,输入pin和输出pin
    m_filter_graph = avfilter_graph_alloc();
    if (!outputs || !inputs || !m_filter_graph) 
	{
        ret = AVERROR(ENOMEM);
        goto end;
    }

    /* buffer video source: the decoded frames from the decoder will be inserted here. */
	//宽,高,pix格式,timebase(codec层,如果是裸流可以填写帧率1:25),SAR(通过DAR和宽高算出的,不知道可以填写1:1)
    _snprintf(video_info_args, sizeof(video_info_args),
            "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
            WIDTH, HEIGHT, VIEO_PIX,
            TIMEBASE_NUM, TIMEBASE_DEN,
            SAR_X,SAR_Y);

	//创建输入filter,并通过输入filter获取到该filter的context信息
    ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
                                       video_info_args, NULL, m_filter_graph);
    if (ret < 0) 
	{
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
        goto end;
    }

    /* buffer video sink: to terminate the filter chain. */
	//创建输出filter,并通过输出filter获取到该filter的context信息
    ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
                                       NULL, NULL, m_filter_graph);
    if (ret < 0)
	{
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
        goto end;
    }

    /*
     * Set the endpoints for the filter graph. The m_filter_graph will
     * be linked to the graph described by filters_descr.
     */

    /*
     * The buffer source output must be connected to the input pad of
     * the first filter described by filters_descr; since the first
     * filter input label is not specified, it is set to "in" by
     * default.
     */
    outputs->name       = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx    = 0;
    outputs->next       = NULL;

    /*
     * The buffer sink input must be connected to the output pad of
     * the last filter described by filters_descr; since the last
     * filter output label is not specified, it is set to "out" by
     * default.
     */
    inputs->name       = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx    = 0;
    inputs->next       = NULL;

	//解析连接两个pin的命令
    if ((ret = avfilter_graph_parse_ptr(m_filter_graph, filters_descr,
                                    &inputs, &outputs, NULL)) < 0)
	{
        goto end;
	}

	//检查并连接filter
    if ((ret = avfilter_graph_config(m_filter_graph, NULL)) < 0)
	{
        goto end;
	}

end:
    avfilter_inout_free(&inputs);
    avfilter_inout_free(&outputs);

    return ret;
}

int main(int argc, char **argv)
{
    int ret;
    AVFrame *frame_in = av_frame_alloc();
    AVFrame *frame_out = av_frame_alloc();
	unsigned char *frame_buffer_in = NULL;  
	unsigned char *frame_buffer_out = NULL;  
	int In_size = 0;
	int Out_size = 0;
	int Read_size = 0;

	//Input YUV  
	FILE * fp_in = fopen("../352_288_yuv420p.yuv","rb+");  
	if(fp_in == NULL)
	{  
		printf("Error open input file.\n");  
		goto end;  
	}  
	//Output YUV  
	FILE * fp_out = fopen("../output.yuv","wb+");  
	if(fp_out == NULL)
	{  
		printf("Error open output file.\n");  
		goto end;  
	} 

	av_register_all();
	avfilter_register_all();

    if (!frame_in || !frame_out)
	{
        printf("Could not allocate frame");
        goto end;
    }
	if ((ret = init_filters(filter_descr)) < 0)
	{
		printf("Could not init_filters");
		goto end;
	}

	//分配一个AVFrame并设置默认值-输入
	frame_in = av_frame_alloc(); 
	if (frame_in == NULL)
	{
		printf("error av_frame_alloc frame_in\n");
		goto end;
	}
	In_size  = avpicture_get_size((AVPixelFormat)VIEO_PIX, WIDTH,HEIGHT);
	frame_buffer_in =( uint8_t *)malloc(In_size * 3 * sizeof(char)); //最大分配的空间,能满足yuv的各种格式
	avpicture_fill((AVPicture *)frame_in, (unsigned char *)frame_buffer_in, (AVPixelFormat)VIEO_PIX,WIDTH, HEIGHT); //内存关联
	frame_in->format=VIEO_PIX; 
	frame_in->width=WIDTH;  
	frame_in->height=HEIGHT;   

	//分配一个AVFrame并设置默认值-输出
	frame_out = av_frame_alloc(); 
	if (frame_out == NULL)
	{
		printf("error av_frame_alloc frame_out\n");
		goto end;
	}
	Out_size  = avpicture_get_size((AVPixelFormat)VIEO_PIX, WIDTH,HEIGHT);
	frame_buffer_out =( uint8_t *)malloc(Out_size * 3 * sizeof(char)); //最大分配的空间,能满足yuv的各种格式
	avpicture_fill((AVPicture *)frame_out, (unsigned char *)frame_buffer_out, (AVPixelFormat)VIEO_PIX,WIDTH, HEIGHT); //内存关联 

    /* read all yuv data */
	while(!feof(fp_in)) //如果未到文件的末尾
	{
		switch (VIEO_PIX)
		{
		case PIX_FMT_YUV420P :  //和I420相同 ,yuv12的u,v分量位置相反
			Read_size = fread(frame_buffer_in,sizeof(char),WIDTH * HEIGHT * 3/2,fp_in); //获取y,u,v偏移量 
			break;
		case AV_PIX_FMT_NV12 :
			Read_size = fread(frame_buffer_in,sizeof(char),WIDTH * HEIGHT * 3/2,fp_in); //获取y,u,v偏移量 
			break;
		case AV_PIX_FMT_NV21 :
			Read_size = fread(frame_buffer_in,sizeof(char),WIDTH * HEIGHT * 3/2,fp_in); //获取y,u,v偏移量 
			break;
		case PIX_FMT_YUV422P: 
			Read_size = fread(frame_buffer_in,sizeof(char),WIDTH * HEIGHT * 2,fp_in); //获取y,u,v偏移量 
			break;
		case AV_PIX_FMT_YUYV422 :                  //YUVY:(实际格式与YUY2相同)
			Read_size = fread(frame_buffer_in,sizeof(char),WIDTH * HEIGHT * 2,fp_in); //获取y,u,v偏移量 
			break;              
		case AV_PIX_FMT_UYVY422 :                  //UYVY
			Read_size = fread(frame_buffer_in,sizeof(char),WIDTH * HEIGHT * 2,fp_in); //获取y,u,v偏移量 
			break;
		case PIX_FMT_YUV444P:
			Read_size = fread(frame_buffer_in,sizeof(char),WIDTH * HEIGHT * 3,fp_in);   //获取y,u,v偏移量 
			break;
		default:
			printf("文件格式暂时不支持\n");
			goto end;
		}

		/* push the decoded frame into the filtergraph */
		if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame_in, AV_BUFFERSRC_FLAG_KEEP_REF) < 0)
		{
			printf("Error while feeding the filtergraph\n");
			break;
		}

		/* pull filtered frames from the filtergraph */
		ret = av_buffersink_get_frame(buffersink_ctx, frame_out);
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
		{
			printf("av_buffersink_get_frame error\n");
			goto end;
		}

		int i = 0;
		int j = 0;
		int k = 0;
		//output Y,U,V  
		if (VIEO_PIX == AV_PIX_FMT_YUV420P) //如果是yuv420p的  
		{  
			for(i = 0 ; i < HEIGHT ; i++)  
			{  
				memcpy(frame_buffer_out+WIDTH*i,  
					frame_out->data[0]+frame_out->linesize[0]*i,  
					WIDTH);  
			}  
			for(j = 0 ; j < HEIGHT/2 ; j++)  
			{  
				memcpy(frame_buffer_out+WIDTH*i+WIDTH/2*j,  
					frame_out->data[1]+frame_out->linesize[1]*j,  
					WIDTH/2);  
			}  
			for(k  =0 ; k < HEIGHT/2 ; k++)  
			{  
				memcpy(frame_buffer_out+WIDTH*i+WIDTH/2*j+WIDTH/2*k,  
					frame_out->data[2]+frame_out->linesize[2]*k,   
					WIDTH/2);  
			}  
		}  
		else if (VIEO_PIX == AV_PIX_FMT_YUV422P)//如果是yuv422p的  
		{  
			for(i = 0 ; i < HEIGHT ; i++)  
			{  
				memcpy(frame_buffer_out+WIDTH*i,  
					frame_out->data[0]+frame_out->linesize[0]*i,  
					WIDTH);  
			}  
			for(j = 0 ; j < HEIGHT ; j++)  
			{  
				memcpy(frame_buffer_out+WIDTH*i+WIDTH/2*j,  
					frame_out->data[1]+frame_out->linesize[1]*j,  
					WIDTH/2);  
			}  
			for(k  =0 ; k < HEIGHT ; k++)  
			{  
				memcpy(frame_buffer_out+WIDTH*i+WIDTH/2*j+WIDTH/2*k,  
					frame_out->data[2]+frame_out->linesize[2]*k,   
					WIDTH/2);  
			}  
		}  
		else  
		{  
			//可扩展  
		}

		fwrite(frame_buffer_out, 1, Out_size, fp_out); 
    }
end:
	fclose(fp_in);  
	fclose(fp_out);
    avfilter_graph_free(&m_filter_graph);
    av_frame_free(&frame_in);
    av_frame_free(&frame_out);
	if (frame_buffer_in)
	{
		free(frame_buffer_in);
		frame_buffer_in = NULL;
	}
	if (frame_buffer_out)
	{
		free(frame_buffer_out);
		frame_buffer_out = NULL;
	}

	printf("enter any key exit\n");
	return getchar();
}

//程序运行效果



如有错误请指正:

交流请加QQ群:62054820
QQ:379969650.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值