av_dump_format经验分析,FFmpeg获取媒体文件总时长(FLV获取总时长的误区)

播放器有个功能,当用户打开视频时,需要读取媒体文件的总时长等信息,不巧的时,获取FLV时总失败,下面来具体分析下FLV和MP4获取总时长的原因和区别:
在这里插入图片描述

播放器有个获取MediaInfo的接口,功能如下:

int MediaFFmpeg::DecoderGetMediaInfo(MediaInfo *mi,AVCodecContext *decodec_ctx,AVStream *stream){if(!mi || !stream || !decodec_ctx){return -1;}//videoif(stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){//获取视频总时长if(AV_NOPTS_VALUE != stream->duration){mi->duration =  stream->duration * av_q2d(stream->time_base);std::cout << "video_time : " <<(mi->duration / 3600)<< ":" <<(mi->duration % 3600) / 60<< ":" <<(mi->duration % 60) << std::endl;char formatStr[128] = {0,};sprintf(formatStr, "%02d:%02d:%02d",(mi->duration / 3600),((mi->duration % 3600) / 60),(mi->duration % 60));mi->durationFormatStr = formatStr;}else{printf("audio duration unknown ! \n");}mi->width = stream->codecpar->width;mi->height = stream->codecpar->height;}//audioelse if(stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){mi->sample_fmt                  =  AV_SAMPLE_FMT_S16;mi->sample_rate                 =   decodec_ctx->sample_rate;  //采样率/*48000; */mi->channels                    =   decodec_ctx->channels;     //通道数/*1;  */mi->nb_samples                  =   decodec_ctx->frame_size;/*1024;  */mi->audio_buffer_size           =   av_samples_get_buffer_size(NULL, mi->channels, mi->nb_samples, (enum AVSampleFormat)mi->sample_fmt, 1);   //输出buff}return 0;
}

有经验的人可能很快就能看出来是否存在问题。

总是打印duration不合法:
在这里插入图片描述

很奇怪的是,使用av_dump_format函数可以看到Duration:

Input #0, flv, from '/home/zhenghui/视频/1080P.flv':Metadata:major_brand     : isomminor_version   : 512compatible_brands: isomiso2avc1mp41description     : Packed by Bilibili XCoder v2.0.2encoder         : Lavf60.3.100Duration: 00:03:46.53, start: 0.000000, bitrate: 3309 kb/sStream #0:0: Video: flv1, yuv420p, 1920x1080, 200 kb/s, 30 fps, 30 tbr, 1k tbnStream #0:1: Audio: adpcm_swf, 44100 Hz, stereo, s16, 352 kb/s

就翻了翻ffmpeg的源码,找到了av_dump_format的源码:

void av_dump_format(AVFormatContext *ic, int index,const char *url, int is_output)
{int i;uint8_t *printed = ic->nb_streams ? av_mallocz(ic->nb_streams) : NULL;if (ic->nb_streams && !printed)return;av_log(NULL, AV_LOG_INFO, "%s #%d, %s, %s '%s':\n",is_output ? "Output" : "Input",index,is_output ? ic->oformat->name : ic->iformat->name,is_output ? "to" : "from", url);dump_metadata(NULL, ic->metadata, "  ");if (!is_output) {av_log(NULL, AV_LOG_INFO, "  Duration: ");if (ic->duration != AV_NOPTS_VALUE) {int64_t hours, mins, secs, us;int64_t duration = ic->duration + (ic->duration <= INT64_MAX - 5000 ? 5000 : 0);secs  = duration / AV_TIME_BASE;us    = duration % AV_TIME_BASE;mins  = secs / 60;secs %= 60;hours = mins / 60;mins %= 60;av_log(NULL, AV_LOG_INFO, "%02"PRId64":%02"PRId64":%02"PRId64".%02"PRId64"", hours, mins, secs,(100 * us) / AV_TIME_BASE);} else {av_log(NULL, AV_LOG_INFO, "N/A");}if (ic->start_time != AV_NOPTS_VALUE) {int secs, us;av_log(NULL, AV_LOG_INFO, ", start: ");secs = llabs(ic->start_time / AV_TIME_BASE);us   = llabs(ic->start_time % AV_TIME_BASE);av_log(NULL, AV_LOG_INFO, "%s%d.%06d",ic->start_time >= 0 ? "" : "-",secs,(int) av_rescale(us, 1000000, AV_TIME_BASE));}av_log(NULL, AV_LOG_INFO, ", bitrate: ");if (ic->bit_rate)av_log(NULL, AV_LOG_INFO, "%"PRId64" kb/s", ic->bit_rate / 1000);elseav_log(NULL, AV_LOG_INFO, "N/A");av_log(NULL, AV_LOG_INFO, "\n");}if (ic->nb_chapters)av_log(NULL, AV_LOG_INFO, "  Chapters:\n");for (i = 0; i < ic->nb_chapters; i++) {const AVChapter *ch = ic->chapters[i];av_log(NULL, AV_LOG_INFO, "    Chapter #%d:%d: ", index, i);av_log(NULL, AV_LOG_INFO,"start %f, ", ch->start * av_q2d(ch->time_base));av_log(NULL, AV_LOG_INFO,"end %f\n", ch->end * av_q2d(ch->time_base));dump_metadata(NULL, ch->metadata, "      ");}if (ic->nb_programs) {int j, k, total = 0;for (j = 0; j < ic->nb_programs; j++) {const AVProgram *program = ic->programs[j];const AVDictionaryEntry *name = av_dict_get(program->metadata,"name", NULL, 0);av_log(NULL, AV_LOG_INFO, "  Program %d %s\n", program->id,name ? name->value : "");dump_metadata(NULL, program->metadata, "    ");for (k = 0; k < program->nb_stream_indexes; k++) {dump_stream_format(ic, program->stream_index[k],index, is_output);printed[program->stream_index[k]] = 1;}total += program->nb_stream_indexes;}if (total < ic->nb_streams)av_log(NULL, AV_LOG_INFO, "  No Program\n");}for (i = 0; i < ic->nb_streams; i++)if (!printed[i])dump_stream_format(ic, i, index, is_output);av_free(printed);
}

av_dump_format函数中使用的是AVFormatContext中的duration,而我使用的是AVStream的duration。
在这里插入图片描述

Debug了一下:AVFormatContext中的duration确实存在:
在这里插入图片描述

继续跟踪到AVStream的调用位置,确实不存在:
在这里插入图片描述

最终修改如下得已解决:

int MediaFFmpeg::DecoderGetMediaInfo(MediaInfo *mi,AVFormatContext *ic,AVCodecContext *decodec_ctx,AVStream *stream){if(!mi || !stream || !decodec_ctx){return -1;}//videoif(stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){//获取视频总时长if(AV_NOPTS_VALUE != ic->duration){int64_t hours, mins, secs, us;int64_t duration = ic->duration + (ic->duration <= INT64_MAX - 5000 ? 5000 : 0);secs  = duration / AV_TIME_BASE;us    = duration % AV_TIME_BASE;mins  = secs / 60;secs %= 60;hours = mins / 60;mins %= 60;mi->duration = duration;char formatStr[128] = {0,};sprintf(formatStr, "%02ld:%02ld:%02ld",hours,mins,secs);
//            mi->duration =  ic->duration * av_q2d(stream->time_base);
//            std::cout << "video_time : " <<
//                    (mi->duration / 3600)<< ":" <<
//                    (mi->duration % 3600) / 60<< ":" <<
//                    (mi->duration % 60) << std::endl;//            char formatStr[128] = {0,};
//                    sprintf(formatStr, "%02d:%02d:%02d",
//                    (mi->duration / 3600),
//                    ((mi->duration % 3600) / 60),
//                    (mi->duration % 60));std::cout << "video_time : " << formatStr;mi->durationFormatStr = formatStr;}else{printf("audio duration unknown ! \n");}mi->width = stream->codecpar->width;mi->height = stream->codecpar->height;}.........return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/839432.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

echarts全局设置饼图的颜色

&#x1f337;第一步 在js文件中写入你需要的颜色 这里的颜色也可以写渐变的 &#x1f337;下一步 在main.is中引用全局挂载 &#x1f337;最后一步 在初始化的时候加一个macarons即可 &#x1f337;第一步 在js文件中写入你需要的颜色 这里的颜色也可以写渐变的 (functi…

探索k8s集群中kubectl的陈述式资源管理

一、k8s集群资源管理方式分类 1.1陈述式资源管理方式&#xff1a;增删查比较方便&#xff0c;但是改非常不方便 使用一条kubectl命令和参数选项来实现资源对象管理操作 即通过命令的方式来实 1.2声明式资源管理方式&#xff1a;yaml文件管理 使用yaml配置文件或者json配置文…

【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法

文章目录 前言 Timer中断调度 Event中断调度 StateFlow调度 分析和应用 总结 参考资料 前言 近期在一些嵌入式系统开发项目中&#xff0c;在使用嵌入式处理器时&#xff0c;遇到了挺多费时费力的事情。所以利用晚上和周末时间&#xff0c;在这些方面深入研究了一下&…

Joomla 3.7.0 (CVE-2017-8917) SQL注入漏洞环境

1 漏洞概述 Joomla是一个基于PHP的内容管理系统&#xff08;CMS&#xff09;&#xff0c;广泛应用于各类网站。2017年&#xff0c;Joomla 3.7.0版本被发现存在SQL注入漏洞&#xff08;CVE-2017-8917&#xff09;&#xff0c;攻击者可以利用该漏洞对数据库进行未授权查询或操作…

The Sandbox 和 Bitkub 联手增强东南亚元宇宙中心

作为去中心化游戏虚拟世界和区块链平台的先驱&#xff0c;The Sandbox 正与泰国领先的区块链网络 Bitkub Blockchain Technology Co., Ltd. 展开创新合作。双方合作的目的是将Bitkub元宇宙的影响力扩展到The Sandbox&#xff0c;建立一个元宇宙中心&#xff0c;向用户承诺从 Bi…

C# GetManifestResourceStream 获取项目资源为null解决方案(亲测)

GetManifestResourceStream 获取项目资源为null 使用Stream s assembly.GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name resourceName) 获取资源文件&#xff0c;返回流为null&#xff0c;如图所示&#xff1a; 解决方案 设置资源文件的 属性&…

<MySQL> 【数据类型】

目录 一、数据类型一览 二、整型 &#xff08;一&#xff09;INT &#xff08;二&#xff09;BIT 三、浮点数 &#xff08;一&#xff09;FLOAT &#xff08;二&#xff09;DECIMAL &#xff08;三&#xff09;如何选择 四、字符 &#xff08;一&#xff09;CHAR &a…

超简单白话文机器学习 - 支持向量机SVM(含算法讲解,公式全解,手写代码实现,调包实现)

1. 支持向量机SVM 支持向量机&#xff0c;因其英文名为support vector machine&#xff0c;故一般简称SVM&#xff0c;通俗来讲&#xff0c;它是一种二类分类模型&#xff0c;其基本模型定义为特征空间上的间隔最大的线性分类器&#xff0c;其学习策略便是间隔最大化&#xff…

优雅草便民工具v2.0.4更新

优雅草便民工具v2.0.4更新 优雅草便民工具v2.0.4更新 2024年5月20日v2.0.4更新优雅草便民工具youyacao-tools-增加淘宝联想词功能和ai绘画功能apk下载 https://fenfacun.youyacao.com/tools204.apk 介绍 优雅草便民工具是一款由成都市一颗优雅草科技有限公司打造的便民查询公益…

JVM(8):虚拟机性能分析和故障解决工具之jinfo工具

1 jinfo(Configuration Info forJava)作用 实时地查看和调整虚拟机各项参数 2 命令格式 jinfo [options] 参数解释&#xff1a; 第一个参数&#xff1a;options no option&#xff1a;输出全部的参数和系统属性-flag name&#xff1a;输出对应名称的参数-flag [|-]name&am…

6. Spring面试题汇总

Java全栈面试题汇总目录-CSDN博客 1. 什么是Spring框架? Spring是一种轻量级开发框架&#xff0c;旨在提高开发人员的开发效率以及系统的可维护性。 我们一般说Spring框架指的都是Spring Framework&#xff0c;它是很多模块的集合&#xff0c;使用这些模块可以很方便地协助…

如何轻松访问 Android 手机和平板电脑上的内部存储

概括 在数字设备领域&#xff0c;我们的智能手机充当虚拟金库&#xff0c;在其范围内存储个人数据、珍贵记忆和重要信息的宝库。因此&#xff0c;我们将指导您如何访问 Android 上的内部存储&#xff0c;确保您可以安全、轻松地检查内部文件系统并管理文件。同时&#xff0c;您…

无人机监测系统:天空之眼,精准掌握地球脉动

在当今信息化快速发展的时代&#xff0c;无人机技术以其独特的优势&#xff0c;正在成为资源调查、环境监测和规划支持的重要工具。无人机监测系统通过搭载多种传感器和设备&#xff0c;能够快速、高效地获取地表信息&#xff0c;为决策提供科学依据。 项目背景 随着全球环境…

Llama 3 CPU推理优化指南

备受期待的 Meta 第三代 Llama 现已发布&#xff0c;我想确保你知道如何以最佳方式部署这种最先进的 (SoTA) LLM。在本教程中&#xff0c;我们将重点介绍如何执行仅权重量化 (WOQ) 来压缩 8B 参数模型并改善推理延迟&#xff0c;但首先&#xff0c;让我们讨论一下 Meta Llama 3…

CSS基础(第五天)

目录 定位 为什么需要定位 定位组成 边偏移 静态定位 static&#xff08;了解&#xff09; 相对定位 relative 绝对定位 absolute&#xff08;重要&#xff09; 子绝父相的由来 固定定位 fixed &#xff08;重要&#xff09; 粘性定位 sticky&#xff08;了解&#xff…

常见算法(2)

1.冒泡排序 定义&#xff1a;相邻的数据两两比较&#xff0c;小的放前面&#xff0c;大的放后面。 public class test {public static void main(String [] arg) {int [] arr {2,4,5,3,6,1};//冒泡排序&#xff0c;排序次数arr.length-1for(int i0;i<arr.length-1;i) {f…

二叉树(详解)

在了解二叉树之前呢我们先来了解一下树形结构&#xff0c;因为二叉树就是树形结构的一种特殊情况&#xff0c;它有这非常好的性质&#xff0c;是很常用的一种结构。 目录 一.什么是树形结构&#xff1f; 二.树形结构常见的名词 三.树的存储 四.二叉树 1.二叉树的概念 2.…

私有云和多云管理平台 | Cloudpods v3.10.15 正式发布

功能优化 【主机】裸金属详情页增加部分属性信息【监控】优化告警策略&#xff0c;支持同时设置多监控指标【主机】支持透传设备自动探测【主机】LVM 块存储支持快照【监控】简化 Telegraf 容器的挂载点【主机】新建 VMware 支持同时填写备注信息【存储】KVM 支持对接 LVM 存储…

ubuntu2404 AMD64 编译并安装virtualbox7.0.18

ubuntu2404 AMD64 编译并安装virtualbox7.0.18 0、官方参考文档&#xff1a; https://www.virtualbox.org/wiki/Linux%20build%20instructions 1、下载源码&#xff1a; $ wget https://download.virtualbox.org/virtualbox/7.0.18/VirtualBox-7.0.18.tar.bz2 2、安装库&…

2024最新彩虹聚合DNS管理系统源码v1.3 全开源

2024最新彩虹聚合DNS管理系统源码v1.3 全开源 聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、DNSLA、CloudFlare。 本系统支持多用户&#xff0c;每个用户可分配不同的域名解…