ffmpeg实战教程(五)libswscale,libavfilter实践指南
来源:互联网 发布:ubuntu解压缩zip 编辑:程序博客网 时间:2024/05/22 15:00
1.libswscale实现YUV转RGB
libswscale里面实现了各种图像像素格式的转换。
libswscale使用起来很方便,最主要的函数只有3个:
(1) sws_getContext():使用参数初始化SwsContext结构体。
(2) sws_scale():转换一帧图像。
(3) sws_freeContext():释放SwsContext结构体。
其中sws_getContext()也可以用另一个接口函数sws_getCachedContext()取代。
初始化方法
初始化SwsContext除了调用sws_getContext()之外还有另一种方法,更加灵活,可以配置更多的参数。该方法调用的函数如下所示。
(1) sws_alloc_context():为SwsContext结构体分配内存。
(2) av_opt_set_XXX():通过av_opt_set_int(),av_opt_set()…等等一系列方法设置SwsContext结构体的值。在这里需要注意,SwsContext结构体的定义看不到,所以不能对其中的成员变量直接进行赋值,必须通过av_opt_set()这类的API才能对其进行赋值。
(3) sws_init_context():初始化SwsContext结构体。
这种复杂的方法可以配置一些sws_getContext()配置不了的参数。比如说设置图像的YUV像素的取值范围是JPEG标准(Y、U、V取值范围都是0-255)还是MPEG标准(Y取值范围是16-235,U、V的取值范围是16-240)。
通过av_pix_fmt_desc_get()可以获得指定像素格式的AVPixFmtDescriptor结构体。
通过AVPixFmtDescriptor结构体可以获得不同像素格式的一些信息。例如av_get_bits_per_pixel(),通过该函数可以获得指定像素格式每个像素占用的比特数(Bit Per Pixel)。
图像拉伸
SWS_BICUBIC性能比较好;SWS_FAST_BILINEAR在性能和速度之间有一个比好好的平衡。
下面看一下运行效果图:
源代码:
#include <stdio.h>#define __STDC_CONSTANT_MACROS#ifdef _WIN32//Windowsextern "C"{#include "libswscale/swscale.h"#include "libavutil/opt.h"#include "libavutil/imgutils.h"};#else//Linux...#ifdef __cplusplusextern "C"{#endif#include <libswscale/swscale.h>#include <libavutil/opt.h>#include <libavutil/imgutils.h>#ifdef __cplusplus};#endif#endifint main(int argc, char* argv[]){ //Parameters FILE *src_file =fopen("ws.yuv", "rb"); const int src_w=1920,src_h=1080; AVPixelFormat src_pixfmt=AV_PIX_FMT_YUV420P; //该函数可以获得指定像素格式每个像素占用的比特数(Bit Per Pixel),av_pix_fmt_desc_get()可以获得指定像素格式的AVPixFmtDescriptor结构体。 int src_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(src_pixfmt)); FILE *dst_file = fopen("ws.rgb", "wb"); const int dst_w=1280,dst_h=720; AVPixelFormat dst_pixfmt=AV_PIX_FMT_RGB24; int dst_bpp=av_get_bits_per_pixel(av_pix_fmt_desc_get(dst_pixfmt));//av_pix_fmt_desc_get()可以获得指定像素格式的AVPixFmtDescriptor结构体。 //Structures uint8_t *src_data[4]; int src_linesize[4]; uint8_t *dst_data[4]; int dst_linesize[4]; int rescale_method=SWS_BICUBIC; struct SwsContext *img_convert_ctx; uint8_t *temp_buffer=(uint8_t *)malloc(src_w*src_h*src_bpp/8); int frame_idx=0; int ret=0; ret= av_image_alloc(src_data, src_linesize,src_w, src_h, src_pixfmt, 1);//分配资源控件 if (ret< 0) { printf( "Could not allocate source image\n"); return -1; } ret = av_image_alloc(dst_data, dst_linesize,dst_w, dst_h, dst_pixfmt, 1); if (ret< 0) { printf( "Could not allocate destination image\n"); return -1; } //----------------------------- img_convert_ctx =sws_alloc_context();//为SwsContext结构体分配内存。 //Show AVOption av_opt_show2(img_convert_ctx,stdout,AV_OPT_FLAG_VIDEO_PARAM,0); //Set Value av_opt_set_int(img_convert_ctx,"sws_flags",SWS_BICUBIC|SWS_PRINT_INFO,0); av_opt_set_int(img_convert_ctx,"srcw",src_w,0); av_opt_set_int(img_convert_ctx,"srch",src_h,0); av_opt_set_int(img_convert_ctx,"src_format",src_pixfmt,0); //'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255) av_opt_set_int(img_convert_ctx,"src_range",1,0); av_opt_set_int(img_convert_ctx,"dstw",dst_w,0); av_opt_set_int(img_convert_ctx,"dsth",dst_h,0); av_opt_set_int(img_convert_ctx,"dst_format",dst_pixfmt,0); av_opt_set_int(img_convert_ctx,"dst_range",1,0); sws_init_context(img_convert_ctx,NULL,NULL);//对SwsContext中的各种变量进行赋值 while(1) { if (fread(temp_buffer, 1, src_w*src_h*src_bpp/8, src_file) != src_w*src_h*src_bpp/8){ break; } switch(src_pixfmt){ case AV_PIX_FMT_GRAY8:{ memcpy(src_data[0],temp_buffer,src_w*src_h); break; } case AV_PIX_FMT_YUV420P:{ memcpy(src_data[0],temp_buffer,src_w*src_h); //Y memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/4); //U memcpy(src_data[2],temp_buffer+src_w*src_h*5/4,src_w*src_h/4); //V break; } case AV_PIX_FMT_YUV422P:{ memcpy(src_data[0],temp_buffer,src_w*src_h); //Y memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h/2); //U memcpy(src_data[2],temp_buffer+src_w*src_h*3/2,src_w*src_h/2); //V break; } case AV_PIX_FMT_YUV444P:{ memcpy(src_data[0],temp_buffer,src_w*src_h); //Y memcpy(src_data[1],temp_buffer+src_w*src_h,src_w*src_h); //U memcpy(src_data[2],temp_buffer+src_w*src_h*2,src_w*src_h); //V break; } case AV_PIX_FMT_YUYV422:{ memcpy(src_data[0],temp_buffer,src_w*src_h*2); //Packed break; } case AV_PIX_FMT_RGB24:{ memcpy(src_data[0],temp_buffer,src_w*src_h*3); //Packed break; } default:{ printf("Not Support Input Pixel Format.\n"); break; } } sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, dst_data, dst_linesize);//转换像素 printf("Finish process frame %5d\n",frame_idx); frame_idx++; switch(dst_pixfmt){ case AV_PIX_FMT_GRAY8:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); break; } case AV_PIX_FMT_YUV420P:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); //Y fwrite(dst_data[1],1,dst_w*dst_h/4,dst_file); //U fwrite(dst_data[2],1,dst_w*dst_h/4,dst_file); //V break; } case AV_PIX_FMT_YUV422P:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); //Y fwrite(dst_data[1],1,dst_w*dst_h/2,dst_file); //U fwrite(dst_data[2],1,dst_w*dst_h/2,dst_file); //V break; } case AV_PIX_FMT_YUV444P:{ fwrite(dst_data[0],1,dst_w*dst_h,dst_file); //Y fwrite(dst_data[1],1,dst_w*dst_h,dst_file); //U fwrite(dst_data[2],1,dst_w*dst_h,dst_file); //V break; } case AV_PIX_FMT_YUYV422:{ fwrite(dst_data[0],1,dst_w*dst_h*2,dst_file); //Packed break; } case AV_PIX_FMT_RGB24:{ fwrite(dst_data[0],1,dst_w*dst_h*3,dst_file); //Packed break; } default:{ printf("Not Support Output Pixel Format.\n"); break; } } } sws_freeContext(img_convert_ctx); free(temp_buffer); fclose(dst_file); av_freep(&src_data[0]); av_freep(&dst_data[0]); return 0;}
2.使用libavfilter为视音频添加特效功能
关键函数如下所示:
avfilter_register_all():注册所有AVFilter。avfilter_graph_alloc():为FilterGraph分配内存。avfilter_graph_create_filter():创建并向FilterGraph中添加一个Filter。avfilter_graph_parse_ptr():将一串通过字符串描述的Graph添加到FilterGraph中。avfilter_graph_config():检查FilterGraph的配置。av_buffersrc_add_frame():向FilterGraph中加入一个AVFrame。av_buffersink_get_frame():从FilterGraph中取出一个AVFrame。
程序中提供了几种特效:
//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=arial.ttf:fontcolor=red:fontsize=50:text='Shuo.Wang'";
输入ws.yuv,输出ws_output.yuv
原生效果如下:
const char *filter_descr = “lutyuv=’u=128:v=128’”;
const char *filter_descr = “drawtext=fontfile=arial.ttf:fontcolor=red:fontsize=50:text=’Shuo.Wang’”;
源代码如下:
#include <stdio.h>#define __STDC_CONSTANT_MACROS#ifdef _WIN32#define snprintf _snprintf//Windowsextern "C"{#include "libavfilter/avfiltergraph.h"#include "libavfilter/buffersink.h"#include "libavfilter/buffersrc.h"#include "libavutil/avutil.h"#include "libavutil/imgutils.h"};#else//Linux...#ifdef __cplusplusextern "C"{#endif#include <libavfilter/avfiltergraph.h>#include <libavfilter/buffersink.h>#include <libavfilter/buffersrc.h>#include <libavutil/avutil.h>#include <libavutil/imgutils.h>#ifdef __cplusplus};#endif#endifint main(int argc, char* argv[]){ int ret; AVFrame *frame_in; AVFrame *frame_out; unsigned char *frame_buffer_in; unsigned char *frame_buffer_out; AVFilterContext *buffersink_ctx; AVFilterContext *buffersrc_ctx; AVFilterGraph *filter_graph; static int video_stream_index = -1; //Input YUV FILE *fp_in=fopen("ws.yuv","rb+"); if(fp_in==NULL){ printf("Error open input file.\n"); return -1; } int in_width=1920; int in_height=1080; //Output YUV FILE *fp_out=fopen("ws_output.yuv","wb+"); if(fp_out==NULL){ printf("Error open output file.\n"); return -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=arial.ttf:fontcolor=red:fontsize=50:text='Shuo.Wang'"; avfilter_register_all();//注册所有AVFilter。 char args[512]; AVFilter *buffersrc = avfilter_get_by_name("buffer"); AVFilter *buffersink = avfilter_get_by_name("ffbuffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; AVBufferSinkParams *buffersink_params; filter_graph = avfilter_graph_alloc();//为FilterGraph分配内存。 /* buffer video source: the decoded frames from the decoder will be inserted here. */ snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", in_width,in_height,PIX_FMT_YUV420P, 1, 25,1,1); //创建并向FilterGraph中添加一个Filter。 ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph); if (ret < 0) { printf("Cannot create buffer source\n"); return ret; } /* buffer video sink: to terminate the filter chain. */ buffersink_params = av_buffersink_params_alloc(); buffersink_params->pixel_fmts = pix_fmts; ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, buffersink_params, filter_graph); av_free(buffersink_params); if (ret < 0) { printf("Cannot create buffer sink\n"); return ret; } /* Endpoints for the filter graph. */ 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; //将一串通过字符串描述的Graph添加到FilterGraph中。 if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_descr, &inputs, &outputs, NULL)) < 0) return ret; //检查FilterGraph的配置。 if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) return ret; frame_in=av_frame_alloc(); frame_buffer_in=(unsigned char *)av_malloc(av_image_get_buffer_size(PIX_FMT_YUV420P, in_width,in_height,1)); av_image_fill_arrays(frame_in->data, frame_in->linesize,frame_buffer_in, PIX_FMT_YUV420P,in_width, in_height,1); frame_out=av_frame_alloc(); frame_buffer_out=(unsigned char *)av_malloc(av_image_get_buffer_size(PIX_FMT_YUV420P, in_width,in_height,1)); av_image_fill_arrays(frame_out->data, frame_out->linesize,frame_buffer_out, PIX_FMT_YUV420P,in_width, in_height,1); frame_in->width=in_width; frame_in->height=in_height; frame_in->format=PIX_FMT_YUV420P; while (1) { if(fread(frame_buffer_in, 1, in_width*in_height*3/2, fp_in)!= in_width*in_height*3/2){ break; } //input Y,U,V frame_in->data[0]=frame_buffer_in; frame_in->data[1]=frame_buffer_in+in_width*in_height; frame_in->data[2]=frame_buffer_in+in_width*in_height*5/4; //向FilterGraph中加入一个AVFrame。 if (av_buffersrc_add_frame(buffersrc_ctx, frame_in) < 0) { printf( "Error while add frame.\n"); break; } /* pull filtered pictures from the filtergraph 从FilterGraph中取出一个AVFrame。*/ ret = av_buffersink_get_frame(buffersink_ctx, frame_out); if (ret < 0) break; //output Y,U,V if(frame_out->format==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,fp_out); } 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,fp_out); } 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,fp_out); } } printf("Process 1 frame!\n"); } fclose(fp_in); fclose(fp_out); av_frame_free(&frame_in); av_frame_free(&frame_out); avfilter_graph_free(&filter_graph); return 0;}
- ffmpeg实战教程(五)libswscale,libavfilter实践指南
- FFMPEG学习【libavfilter】(一)
- FFMPEG学习【libavfilter】(二)
- FFMPEG学习【libswscale】
- ffmpeg源码简析(十)libswscale中的SwsContext,sws_scale()
- RabbitMQ 实战教程(五) 主题
- 最简单的基于FFmpeg的libswscale的示例(YUV转RGB)
- 最简单的基于FFmpeg的libswscale的示例(YUV转RGB)
- 最简单的基于FFmpeg的libswscale的示例(YUV转RGB)
- 最简单的基于FFmpeg的libswscale的示例(YUV转RGB)
- 颜色格式转换: 最简单的基于FFmpeg的libswscale的示例(YUV转RGB)
- ffmpeg API 笔记:使用libavcodec/libavformat/libswscale
- FFmpeg源代码简单分析:libswscale的sws_getContext()
- FFmpeg源代码简单分析:libswscale的sws_scale()
- FFmpeg源代码简单分析:libswscale的sws_getContext()
- FFmpeg源代码简单分析:libswscale的sws_getContext()
- FFmpeg源代码分析:libswscale的sws_getContext()
- ffmpeg实战教程(十二)为视频添加/更换背景音乐
- SSH实战OA 11:BBS模块
- postman中 form-data、x-www-form-urlencoded、raw、binary的区别
- java开发系统内核:实现系统API调用
- 不容易系列之一
- android webview 加载H5页面,设置字体不随系统设置变化
- ffmpeg实战教程(五)libswscale,libavfilter实践指南
- Top100论文导读:深入理解卷积神经网络CNN(Part Ⅰ)
- 1090. Highest Price in Supply Chain 解析
- ContentResolver query 参数详解
- MySQL 8 中新的复制功能
- Mysql没有data目录
- 一张图理解MVC遵循的原则
- 利用redis缓存mysql查询结果,关于缓存命名
- C++中Vector.erase()删除某一元素的正确用法