文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-07-05 15:02

关注

这篇文章主要介绍了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视频旋转显示”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯