16 - FFmpeg 视频过滤器 方式2

代码等效密令【测试用】

/**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
    }
}
相关推荐
西***63472 小时前
声画合一 智控全场 —— 高清数字会议系统重构现代会议新生态
音视频·会议系统
REDcker4 小时前
RTSP 直播技术详解
linux·服务器·网络·音视频·实时音视频·直播·rtsp
微尘hjx4 小时前
【Gstreamer 应用程序开发手册 01】关于GSTREAMER
linux·音视频·媒体
石去皿4 小时前
轻量级 Web 应用 —— 把一堆图片按指定频率直接拼成视频,零特效、零依赖、零命令行
前端·音视频
runner365.git5 小时前
做一个基于ffmpeg的AI Agent智能体
人工智能·ffmpeg·大模型
进击的小头6 小时前
FIR滤波器实战:音频信号降噪
c语言·python·算法·音视频
Black蜡笔小新6 小时前
终结“监控盲区”:EasyGBS视频质量诊断技术多场景应用设计
人工智能·音视频·视频质量诊断
彷徨而立8 小时前
【FFmpeg】理解 av_packet_from_data 和 av_packet_unref 接口
ffmpeg
liliangcsdn9 小时前
视频嵌入表示生成方案的探索
数据库·人工智能·音视频
查无此人byebye9 小时前
深度解析:当前AI视频生成为何普遍“短小精悍”?
人工智能·pytorch·python·深度学习·音视频·transformer