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
    }
}
相关推荐
翱翔-蓝天7 小时前
抖音视频下载工具
音视频
AI服务老曹9 小时前
包含网络、平台、数据及安全四大体系的智慧快消开源了
运维·人工智能·安全·开源·音视频
孤舟簔笠翁9 小时前
【Audio开发三】音频audio中帧frameSize ,周期大小periodsize,缓冲区buffer原理详解以及代码流程分析
音视频
思陌Ai算法定制10 小时前
图神经网络+多模态:视频动作分割的轻量高效新解法
人工智能·深度学习·神经网络·机器学习·音视频·医学影像
逼子格12 小时前
十三种物联网/通信模块综合对比——《数据手册--物联网/通信模块》
嵌入式硬件·物联网·音视频·硬件工程师·硬件测试·硬件笔试真题·通信模块
菊风 Juphoon13 小时前
菊风RTC 2.0 开发者文档正式发布,解锁音视频新体验!
音视频·实时音视频
JHC00000016 小时前
ubuntu 下调用系统麦克风,以及faster-whisper-medium 处理音频转写文本
ubuntu·whisper·音视频
六bring个六1 天前
相机功能特性(QCamera::Feature)详解
音视频·qt6.3
EasyGBS1 天前
国标GB28181协议EasyCVR视频融合平台:5G时代远程监控赋能通信基站安全管理
大数据·网络·人工智能·安全·音视频
斗锋在干嘛1 天前
Android 回答视频边播放边下载的问题
android·jvm·音视频