Qt音视频开发之怎么实现ffmpeg视频旋转显示

发布时间:2023-03-22 11:26:06 作者:iii
来源:亿速云 阅读:129

这篇文章主要介绍了Qt音视频开发之怎么实现ffmpeg视频旋转显示的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Qt音视频开发之怎么实现ffmpeg视频旋转显示文章都会有所收获,下面我们一起来看看吧。

一、前言

用手机或者平板拍摄的视频文件,很可能是旋转的,比如分辨率是1280x720,确是垂直的,相当于分辨率变成了720x1280,如果不做旋转处理的话,那脑袋必须歪着看才行,这样看起来太难受,所以一定要想办法解析到视频的旋转角度,然后根据这个角度重新绘制。在窗体那边也需要调整对应的分辨率,一般都是宽度高度互换。其实早期的很多播放器比如vlc2版本的播放器也是不支持旋转的,从vlc3开始内置会自动给旋转,估计这种场景越来越多,毕竟现在智能手机大行其道,用手机拍摄的视频很多都是竖屏的。

在ffmpeg中旋转frame帧数据,有多种方式,方式一是直接通过运算逐行取出数据,重新组织旋转后的视频帧数据;方式二通过滤镜来实现。最开始还没学会用ffmpeg的滤镜的时候,用的就是方式一,通俗易懂,但是很傻,尤其是运算很占CPU,毕竟for循环来个很多次挨个取数据又重新组织数据。自从学会用ffmpeg滤镜以后,从滤镜大全中找到了居然也支持旋转,而且任意角度旋转都可以,甚至镜像操作,这就非常强大了,马上将这个架构的旋转部分全部换成了滤镜旋转,连之前用于旋转的中间过渡帧数据变量都不需要,代码更精简,功能更强大,拓展性更好,这其实就是一个不断精进迭代的过程,第一步解决从无到有的过程,后面才是持续不断的完善。

二、相关代码

int FFmpegFilter::initFilter(AbstractVideoThread *thread, AVStream *stream, AVCodecContext *avctx, FilterData &filterData)
{
    int result = -1;
    if (!filterData.enable) {
        return result;
    }

    //貌似硬解码不支持滤镜
    if (filterData.formatIn == AV_PIX_FMT_NV12) {
        return result;
    }

    //先释放相关资源
    freeFilter(filterData);

    //获取滤镜字符串
    QString filters = getFilter(filterData);
    if (filters.isEmpty()) {
        return result;
    }

    //输入帧序列的参数信息
    QStringList listArg;
    listArg << QString("video_size=%1x%2").arg(avctx->width).arg(avctx->height);
    listArg << QString("pix_fmt=%1").arg(avctx->pix_fmt);
    listArg << QString("time_base=%1/%2").arg(stream->time_base.num).arg(stream->time_base.den);
    listArg << QString("pixel_aspect=%1/%2").arg(avctx->sample_aspect_ratio.num).arg(avctx->sample_aspect_ratio.den);
    QString args = listArg.join(":");

    //输入帧格式
    enum AVPixelFormat pix_fmts[] = {filterData.formatIn, AV_PIX_FMT_NONE};

    //获取要使用的滤镜
    const AVFilter *filterSrc = avfilter_get_by_name("buffer");
    const AVFilter *filterSink = avfilter_get_by_name("buffersink");

    //创建输入输出滤镜参数
    AVFilterInOut *inputs = avfilter_inout_alloc();
    AVFilterInOut *outputs = avfilter_inout_alloc();

    //创建滤镜容器
    filterData.filterGraph = avfilter_graph_alloc();
    if (!inputs || !outputs || !filterData.filterGraph) {
        result = AVERROR(ENOMEM);
        goto end;
    }

    //创建输入滤镜
    result = avfilter_graph_create_filter(&filterData.filterSrcCtx, filterSrc, "in", args.toUtf8().constData(), NULL, filterData.filterGraph);
    if (result < 0) {
        thread->debug("滤镜处理", QString("创建输入滤镜失败: %1").arg(FFmpegHelper::getError(result)), "");
        goto end;
    }

    //创建输出滤镜
    result = avfilter_graph_create_filter(&filterData.filterSinkCtx, filterSink, "out", NULL, NULL, filterData.filterGraph);
    if (result < 0) {
        thread->debug("滤镜处理", QString("创建输出滤镜失败: %1").arg(FFmpegHelper::getError(result)), "");
        goto end;
    }

    //设置输出滤镜格式
    result = av_opt_set_int_list(filterData.filterSinkCtx, "pix_fmts", pix_fmts, filterData.formatOut, AV_OPT_SEARCH_CHILDREN);
    if (result < 0) {
        thread->debug("滤镜处理", QString("设置输出滤镜格式: %1").arg(FFmpegHelper::getError(result)), "");
        goto end;
    }

    //设置滤镜的参数
    outputs->name = av_strdup("in");
    outputs->filter_ctx = filterData.filterSrcCtx;
    outputs->pad_idx = 0;
    outputs->next = NULL;

    inputs->name = av_strdup("out");
    inputs->filter_ctx = filterData.filterSinkCtx;
    inputs->pad_idx = 0;
    inputs->next = NULL;

    //初始化滤镜
    result = avfilter_graph_parse_ptr(filterData.filterGraph, filters.toUtf8().constData(), &inputs, &outputs, NULL);
    if (result < 0) {
        thread->debug("滤镜处理", QString("初始化滤镜失败: %1").arg(FFmpegHelper::getError(result)), "");
        goto end;
    }

    //应用滤镜配置
    result = avfilter_graph_config(filterData.filterGraph, NULL);
    if (result < 0) {
        thread->debug("滤镜处理", QString("应用滤镜配置失败: %1").arg(FFmpegHelper::getError(result)), "");
        goto end;
    }

end:
    //释放对应的输入输出
    avfilter_inout_free(&inputs);
    avfilter_inout_free(&outputs);
    filterData.isOk = (result >= 0);
    return result;
}

void FFmpegFilter::freeFilter(FilterData &filterData)
{
    if (filterData.isOk) {
        filterData.enable = true;
        filterData.init = true;
        filterData.isOk = false;

        avfilter_free(filterData.filterSrcCtx);
        avfilter_free(filterData.filterSinkCtx);
        avfilter_graph_free(&filterData.filterGraph);
        filterData.filterSrcCtx = NULL;
        filterData.filterSinkCtx = NULL;
        filterData.filterGraph = NULL;
    }
}

五、功能特点

5.1 基础功能

5.2 特色功能

5.3 视频控件

关于“Qt音视频开发之怎么实现ffmpeg视频旋转显示”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Qt音视频开发之怎么实现ffmpeg视频旋转显示”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. 如何在SAIL-IMX6q中添加qt桌面应用程序?
  2. qt输出支持的数据库驱动

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

qt ffmpeg

上一篇:Java中HashMap获取值的方式有哪些

下一篇:如何使用Python对网易云歌单数据分析及可视化

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》