当前位置: 首页 > article >正文

从H264视频中获取宽、高、帧率、比特率等属性信息

背景

最近整理视频编解码的代码,早前在jetson上封装了jetson multimedia作为视频编解码的类,供其他同事和其他组使用,但该解码接口有一个问题,无法首先获取视频宽高信息,更无法直接获取视频的帧率、比特率等信息。

解决方法

  1. 使用ffmpeg库,命令行参数不适合代码集成
  2. 使用ffmpeg的API接口进行封装

源码实现

// ffmpeg_videoinfo.h

#ifndef FFMPEG_VIDEOINFO_H
#define FFMPEG_VIDEOINFO_H

#include <iostream>
#include <memory>

struct VideoAsset {
    float width; 
    float height;
    float fps;
    float bitrate; /** bit per second */
    float duration; /** seconds */
};

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

int GetVideoInfo(const char *in_file,  std::shared_ptr<VideoAsset> &info);

#ifdef __cplusplus
};
#endif

#endif  // FFMPEG_VIDEOINFO_H
// ffmpeg_videoinfo.cpp


#include "ffmpeg_videoinfo.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>

int GetVideoInfo(const char *in_file,  std::shared_ptr<VideoAsset> &info){
  // 注册所有格式和编解码器
    av_register_all();

    // 创建一个格式上下文(Format Context)
    AVFormatContext* formatContext = nullptr;
    if (avformat_open_input(&formatContext, in_file, nullptr, nullptr) != 0) {
        fprintf(stderr, "Could not open input file '%s'", in_file);
        return -1;
    }

    // 获取流信息
    if (avformat_find_stream_info(formatContext, nullptr) < 0) {
        fprintf(stderr, "Could not find stream information '%s'", in_file);
        return -1;
    }

    // 查找视频流
    int videoStreamIndex = -1;
    for (unsigned i = 0; i < formatContext->nb_streams; i++) {
        if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }

    if (videoStreamIndex == -1) {
        fprintf(stderr, "Could not find video stream '%s'", in_file);
        return -1;
    }

    // 获取视频流的编码参数
    AVCodecParameters* codecParameters = formatContext->streams[videoStreamIndex]->codecpar;
    AVStream* videoStream = formatContext->streams[videoStreamIndex];
    info->fps = av_q2d(videoStream->avg_frame_rate);
    info->width = codecParameters->width;
    info->height = codecParameters->height;

    int64_t totalSize = 0;
    int64_t totalDuration = 0;
    AVPacket packet;
    while (av_read_frame(formatContext, &packet) >= 0) {
        if (packet.stream_index == 0) {
            totalSize += packet.size;
            totalDuration += packet.duration;
        }
        av_packet_unref(&packet);
    }

    AVRational timeBase = videoStream->time_base; /** 时间基 */
    info->duration = (float)totalDuration * av_q2d(timeBase);
    info->bitrate = (totalDuration > 0) ? (totalSize * 8.0 / info->duration) : 0.0;

    // 清理
    avformat_close_input(&formatContext);

    return 0;
}
#ifdef __cplusplus
};
#endif
// 测试脚本 test_single_videoinfo.cpp



#include "ffmpeg_videoinfo.h"

int main(int argc, char **argv) {
  if(argc<2){
    return 1;
  }
  const std::string &input_h264=argv[1];

  std::shared_ptr<VideoAsset> video_info_ptr = std::make_shared<VideoAsset>();
  // VideoAsset video_info;
  int status_code = GetVideoInfo(input_h264.c_str(), video_info_ptr);
  if (status_code < 0) {
    printf("GetVideoInfo failed\n");
    return -1;
  }
  printf("bitrate:%f, duration:%f, fps:%f, height:%f, width:%f\n",
         video_info_ptr->bitrate, video_info_ptr->duration, 
         video_info_ptr->fps, video_info_ptr->height, 
         video_info_ptr->width);
  return 1;
}
# CMakelist.txt核心

add_executable(test_video_info test_single_videoinfo.cpp ffmpeg_videoinfo.h ffmpeg_videoinfo.cpp)
target_compile_features(test_video_info PRIVATE cxx_std_14)
target_link_libraries(test_video_info avcodec avutil avformat)
# 测试

./test_video_info /data/videos/l4t.h264

# 输出信息示例
[h264 @ 0xaaaac14b16a0] Stream #0: not enough frames to estimate rate; consider increasing probesize
bitrate:30681866.000000, duration:164.490005, fps:20.000000, height:2160.000000, width:3840.000000

后记

本人对ffmpeg接口并不熟悉,以上根据文档及搜索结果进行的实现,不敢保证没有bug,如果各位遇到问题,可以留言交流


http://www.kler.cn/a/395222.html

相关文章:

  • Webkit 滚动条样式属性
  • 多进程/线程并发服务器
  • 缓存与数据库不一致的解决方案:深入理解与实践
  • C语言入门到精通(第六版)——第十六章
  • 微服务各组件整合
  • 结构体是否包含特定类型的成员变量
  • VUE3中Element table表头动态展示合计信息(不是表尾合计)
  • 【C#/C++】C++/CL中String^的含义和举例,C++层需要调用C#层对象时...
  • 数据结构--数组
  • 算法|牛客网华为机试41-52C++
  • LeetCode-222.完全二叉树的节点个数
  • DVWA靶场通关——SQL Injection篇
  • c++ shared_ptr 常见构造函数
  • GIT:如何查找已删除的文件的历史记录
  • caozha-pinyin(中文转拼音源码)
  • 【ubuntu18.04】vm虚拟机复制粘贴键不能用-最后无奈换版本
  • 数据结构---详解双向链表
  • Leecode刷题C语言之统计好节点的数目
  • uniapp luch-request 使用教程+响应对象创建
  • 异步处理之async/await使用技巧分享
  • 【广西-柳州】《柳州市本级信息化建设项目预算支出标准(试行)》(柳财审〔2020〕16号 )-省市费用标准解读系列11
  • Windows搭建流媒体服务并使用ffmpeg推流播放rtsp和rtmp流
  • 【redis】redis
  • c# 在10万条数据中判断是否存在很慢问题
  • 【金猿案例展】科技日报——大数据科技资讯服务平台
  • DB-GPT系列(五):DB-GPT六大基础应用场景part2