代码等效密令【测试用】
/**ffmpeg -i 9.5.flv -vf "split[main][tmp];[tmp]crop=iw:ih/2:0:0,vflip[flip];[main][flip]overlay=0:H/2" -b:v 500k -vcodec libx264 9.5 out.flv
* -vf:视频滤镜选项,后面跟着的字符串指定了要应用的多个滤镜。
* 视频滤镜部分 (-vf "...")
* split[main][tmp]:这个滤镜将输入视频流分成两个相同的流,分别标记为 [main] 和 [tmp]。
* [tmp]crop=iw:ih/2:0:0:在 [tmp] 流上应用 crop 滤镜,将其裁剪为原始宽度 (iw) 和高度的一半 (ih/2),左上角的起始点为 (0,0)。这样将只保留视频的上半部分。
* vflip:在裁剪后的流上应用 vflip 滤镜,表示垂直翻转该流。
* [flip]:标记翻转后的流为 [flip]。
* [main][flip]overlay=0:H/2:将 [main] 流(未裁剪的原始视频)和 [flip] 流(翻转后的一半视频)叠加。
* 这里 overlay 的参数 0:H/2 表示将 [flip] 流放置在原始视频的下半部分,0 是 x 轴的偏移量,H/2 是 y 轴的偏移量,表示将翻转后的流叠加在原始流的下方。
* 编码及输出部分
* -b:v 500k:设置输出视频的比特率为 500 kbps。这影响了输出视频的质量和文件大小。
* -vcodec libx264:指定使用 libx264 编解码器来编码视频流,这是一种广泛使用的 H.264 视频编解码库。
* 9.5 out.flv:指定输出文件名为 out.flv。
**/
cpp
int InitFilters(const int width, const int height, const int format,
AVFilterGraph **FilterGraph, AVFilterContext **ResultSinkCtx /*输出*/, AVFilterContext **MainSrcCtx /*输入*/)
{
AVFilterInOut *inputs = NULL;
AVFilterInOut *outputs = NULL;
*FilterGraph = avfilter_graph_alloc();
if ((*FilterGraph) == NULL)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avfilter graph alloc *FilterGraph error -- line:%d\n", __FUNCTION__, __LINE__);
return -1;
}
char args[1024] = {0};
#ifdef OUTS
snprintf(args, sizeof(args),
"buffer=video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d[v0];" // Parsed_buffer_0
"[v0]split[main][tmp];" // Parsed_split_1
"[tmp]crop=iw:ih/2:0:0,vflip[flip];" // Parsed_crop_2 -> Parsed_vflip_3
"[main]buffersink;" // Parsed_overlay_4
"[flip]buffersink", // Parsed_buffersink_5
width, height, format, 1, 25, 1, 1);
#else
snprintf(args, sizeof(args),
"buffer=video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d[v0];" // Parsed_buffer_0
"[v0]split[main][tmp];" // Parsed_split_1
"[tmp]crop=iw:ih/2:0:0,vflip[flip];" // Parsed_crop_2 -> Parsed_vflip_3
"[main][flip]overlay=0:H/2[result];" // Parsed_overlay_4
"[result]buffersink", // Parsed_buffersink_5
width, height, format, 1, 25, 1, 1);
#endif
av_log(NULL, AV_LOG_INFO, "[%s] args:%s -- line:%d\n", __FUNCTION__, args, __LINE__);
// 将由字符串描述的图形添加到图形中。 -- 内部组织 Filter
int ret = avfilter_graph_parse2(*FilterGraph, args, &inputs, &outputs);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avfilter graph parse error:%s -- line:%d\n", __FUNCTION__, av_err2str(ret), __LINE__);
return ret;
}
// 检查有效性并配置图中的所有链接和格式。 -- 提交过滤器
ret = avfilter_graph_config(*FilterGraph, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avfilter graph config error:%s -- line:%d\n", __FUNCTION__, av_err2str(ret), __LINE__);
return ret;
}
// 从AVFilterGraph解析字符串中获取AVFilterContext
*MainSrcCtx = avfilter_graph_get_filter(*FilterGraph, "Parsed_buffer_0");
if ((*MainSrcCtx) == NULL)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avfilter graph get filter Buffer_0 failed -- line:%d\n", __FUNCTION__, __LINE__);
return -1;
}
*ResultSinkCtx = avfilter_graph_get_filter(*FilterGraph, "Parsed_buffersink_5");
if ((*ResultSinkCtx) == NULL)
{
av_log(NULL, AV_LOG_ERROR, "[%s] avfilter graph get filter Parsed_buffersink_5 failed -- line:%d\n", __FUNCTION__, __LINE__);
return -1;
}
av_log(NULL, AV_LOG_WARNING, "[%s] SinkWidth:%d, SinkHeight:%d, SinkFormat:%d, -- line:%d\n", __FUNCTION__, av_buffersink_get_w(*ResultSinkCtx), av_buffersink_get_h(*ResultSinkCtx), av_buffersink_get_format(*ResultSinkCtx), __LINE__);
char *GraphString = avfilter_graph_dump(*FilterGraph, NULL);
if (GraphString != NULL)
{
FILE *GraphFile = fopen("Graph.txt", "w"); // 打印 filterfraph 的 具体情况
if (GraphFile != NULL)
{
fwrite(GraphString, 1, strlen(GraphString), GraphFile);
fclose(GraphFile);
}
}
av_free(GraphString);
return 0;
}
cpp
int Filter_2(const char *inFileName, const char *outFileName)
{
FILE *IN_FILE = fopen(inFileName, "rb+");
FILE *OUT_FILE = fopen(outFileName, "wb");
if (IN_FILE == NULL || OUT_FILE == NULL)
{
av_log(NULL, AV_LOG_ERROR, "[%s] open file error! -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
uint16_t InWidth = 1920;
uint16_t InHeight = 1080;
// FilterGraph - 对filters系统的整体管理
AVFilterGraph *FilterGraph;
AVFilterContext *ResultSinkCtx = NULL;
AVFilterContext *MainSrcCtx = NULL;
int ret = InitFilters(InWidth, InHeight, AV_PIX_FMT_YUV420P, &FilterGraph, &ResultSinkCtx, &MainSrcCtx);
if (ret < 0 || (FilterGraph == NULL) || (ResultSinkCtx == NULL) || (MainSrcCtx == NULL))
{
av_log(NULL, AV_LOG_ERROR, "[%s] InitFilters error! -- line:%d\n", __FUNCTION__, __LINE__);
return -1;
}
AVFrame *InFrame = av_frame_alloc();
uint8_t *InFrameBuffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, InWidth, InHeight, 1));
av_image_fill_arrays(InFrame->data, InFrame->linesize, InFrameBuffer, AV_PIX_FMT_YUV420P, InWidth, InHeight, 1);
AVFrame *OutFrame = av_frame_alloc();
uint8_t *OutFrameBuffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, InWidth, InHeight, 1));
av_image_fill_arrays(OutFrame->data, OutFrame->linesize, OutFrameBuffer, AV_PIX_FMT_YUV420P, InWidth, InHeight, 1);
InFrame->width = InWidth;
InFrame->height = InHeight;
InFrame->format = AV_PIX_FMT_YUV420P;
uint32_t FrameCount = 0;
size_t ReadSize = 0;
size_t PictureSize = InWidth * InHeight * 3 / 2;
do
{
ReadSize = fread(InFrameBuffer, 1, PictureSize, IN_FILE); /*一次读取一张图*/
// input Y,U.V
InFrame->data[0] = InFrameBuffer;
InFrame->data[1] = InFrameBuffer + InWidth * InHeight;
InFrame->data[2] = InFrameBuffer + InWidth * InHeight * 5 / 4;
ret = av_buffersrc_add_frame(MainSrcCtx, InFrame);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] Error while add frame -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
// pull filtered pictrues from the filtergraph
ret = av_buffersink_get_frame(ResultSinkCtx, OutFrame);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "[%s] Error while get frame -- line:%d\n", __FUNCTION__, __LINE__);
goto _end;
}
// output Y,U,V
if (OutFrame->format == AV_PIX_FMT_YUV420P) // YYYY..U..V..
{
for (int i = 0; i < OutFrame->height; i++)
fwrite(OutFrame->data[0] /*Y*/ + OutFrame->linesize[0] * i, 1, OutFrame->width, OUT_FILE);
for (int i = 0; i < OutFrame->height / 2; i++)
fwrite(OutFrame->data[1] /*U*/ + OutFrame->linesize[1] * i, 1, OutFrame->width / 2, OUT_FILE);
for (int i = 0; i < OutFrame->height / 2; i++)
fwrite(OutFrame->data[2] /*V*/ + OutFrame->linesize[2] * i, 1, OutFrame->width / 2, OUT_FILE);
}
if (++FrameCount % 25 == 0)
av_log(NULL, AV_LOG_INFO, "[%s] %d frames have been processed -- line:%d\n", __FUNCTION__, FrameCount, __LINE__);
av_frame_unref(OutFrame);
} while (ReadSize >= PictureSize);
_end:
if (IN_FILE != NULL)
{
fclose(IN_FILE);
}
if (OUT_FILE != NULL)
{
fclose(OUT_FILE);
}
if (InFrame != NULL)
{
av_frame_free(&InFrame);
}
if (OutFrame != NULL)
{
av_frame_free(&OutFrame);
}
if (FilterGraph != NULL)
{
avfilter_graph_free(&FilterGraph); // 内部去释放 AVFilterContext
}
}