使用FFmpeg API获取flv视频时长

2020-04-22 15:59:38 浏览数 (1)

哈喽,这一篇记录一个小小的关于FFmpeg的使用,借助FFmpeg的API接口获取flv格式视频的时长。

查阅资料后,AVFormatContext中的duration字段可以获取视频时常,于是写出了如下代码:

代码语言:javascript复制
#include <stdio.h>
#include <iostream>
extern "C" {
#include <libavformat/avformat.h>
}
#pragma comment(lib, "avformat.lib")
int main(int argc, char *argv[]) {
       if (argc < 2) {
              std::cout << "Usage: [programe] [intput_video_path/url]" << std::endl;
              return -1;
       }
       char *inputUrl = argv[1];
       AVFormatContext *fmtCtx = NULL;
       int ret;
       ret = avformat_network_init();
       if (ret < 0) {
              std::cout << "avformat_network_init failed " << std::endl;
              return -1;
       }
       fmtCtx = avformat_alloc_context();
       if (NULL == fmtCtx) {
              std::cout << "avformat_alloc_context failed " << std::endl;
              return -2;
       }
       ret = avformat_open_input(&fmtCtx, inputUrl, NULL, NULL);
       if (ret < 0) {
              std::cout << "avformat_open_input failed " << std::endl;
              return -3;
       }
       int videoIndex = -1;
       
       int nbStreams = fmtCtx->nb_streams;
       for (int i = 0; i < nbStreams; i  ) {
              // fmtCtx->streams[i]->codec 新版ffmpeg已弃用
              if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
                     videoIndex = i;
              }
       }
       std::cout << "----------输入流信息---------------" << std::endl;
       av_dump_format(fmtCtx, 0, inputUrl, NULL);
       long duration = fmtCtx->duration;  //微秒数
       std::cout << "duration: " << duration << std::endl;
       std::cout << "视频时常为: " << duration / 1000.0 / 1000.0 << "s" <<  std::endl;
       system("pause");
       return 0;
}

结果如下:

发现获取的视频时长为0,按照排查问题的一般思路,试试别的格式的文件是否也会有问题。尝试将文件更换为MP4文件,发现可以正常获取时长,如下图:

甚是不理解啊,经查阅资料发现,对于flv文件需要首先调用avformat_find_stream_info, 才可正常的获取视频时长,这一过程中,同时还发现另外一种获取视频时常的方式:FFmpeg对于 AVFormatContext->stream->codec的弃用(改为codecpar),修改后的代码如下:

代码语言:javascript复制
#include <stdio.h>#include <iostream>extern "C" {#include <libavformat/avformat.h>}#pragma comment(lib, "avformat.lib")int main(int argc, char *argv[]) {       if (argc < 2) {              std::cout << "Usage: [programe] [intput_video_path/url]" << std::endl;              return -1;       }       char *inputUrl = argv[1];       AVFormatContext *fmtCtx = NULL;       int ret;       ret = avformat_network_init();       if (ret < 0) {              std::cout << "avformat_network_init failed " << std::endl;              return -1;       }       fmtCtx = avformat_alloc_context();       if (NULL == fmtCtx) {              std::cout << "avformat_alloc_context failed " << std::endl;              return -2;       }       ret = avformat_open_input(&fmtCtx, inputUrl, NULL, NULL);       if (ret < 0) {              std::cout << "avformat_open_input failed " << std::endl;              return -3;       }       ret = avformat_find_stream_info(fmtCtx, NULL);       if (ret < 0) {              std::cout << "avformat_find_stream_info failed " << std::endl;              return -4;       }       int videoIndex = -1;              int nbStreams = fmtCtx->nb_streams;       for (int i = 0; i < nbStreams; i  ) {              // fmtCtx->streams[i]->codec 新版ffmpeg已弃用              if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {                     videoIndex = i;              }       }       std::cout << "----------输入流信息---------------" << std::endl;       av_dump_format(fmtCtx, 0, inputUrl, NULL);       long duration = fmtCtx->duration;  //微秒数       std::cout << "duration: " << duration << std::endl;       std::cout << "视频时常为: " << duration / 1000.0 / 1000.0 << "s" <<  std::endl;       // for flv file       int seconds = fmtCtx->streams[videoIndex]->duration * fmtCtx->streams[videoIndex]->time_base.num / fmtCtx->streams[videoIndex]->time_base.den;       std::cout << "flv file duratio: " << seconds << std::endl;       system("pause");       return 0;}

其中:另外一种获取视频时长的方式为:

代码语言:javascript复制
int seconds = fmtCtx->streams[videoIndex]->duration * fmtCtx->streams[videoIndex]->time_base.num / fmtCtx->streams[videoIndex]->time_base.den;
       std::cout << "flv file duratio: " << seconds << std::endl;

FFmpeg弃用codec的修改为:

代码语言:javascript复制
for (int i = 0; i < nbStreams; i  ) {
              // fmtCtx->streams[i]->codec 新版ffmpeg已弃用
              if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
                     videoIndex = i;
              }
       }

调用avformat_find_stream_info的部分为:

代码语言:javascript复制
       ret = avformat_find_stream_info(fmtCtx, NULL);
       if (ret < 0) {
              std::cout << "avformat_find_stream_info failed " << std::endl;
              return -4;
       }

修改后调用结果为:

终于可以成功获取flv格式视频的时长。可以动手去试试了!

0 人点赞