FFMPEG学习(4)-使用ffmpeg读取基本音视频文件信息,熟释AVFormatContext结构

前段时间把环境整了下,闲时学习下ffmpeg.

最近在看雷神的创作,边看,边学,感谢雷神!

头文件:

//
//  ffmpeg_read_av_info.hpp
//  ffmpegDemo
//
//  Created by fengsh on 2018/4/15.
//  Copyright © 2018年 fengsh998@163.com. All rights reserved.
//
/**
 音视频文件信息读取
 */

#ifndef ffmpeg_read_av_info_hpp
#define ffmpeg_read_av_info_hpp

#include <stdio.h>

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"

void read_av_info(const char * av_pathfile);

#endif /* ffmpeg_read_av_info_hpp */

.c文件

//
//  ffmpeg_read_av_info.c
//  ffmpegDemo
//
//  Created by fengsh on 2018/4/15.
//  QQ : 19985430
//  Copyright © 2018年 fengsh998@163.com. All rights reserved.
//
/**
    音视频文件信息读取 (ffmpeg version 3.4.2)
    control+command + 空格 打特殊符号
 
 */

/*
            FFmpeg解码流程图(参考雷神的备忘)
 
            av_register_all()
                    ↓
            avformat_open_input()
                    ↓
            avformat_find_stream_info()
                    ↓
            avcodec_find_decoder()
                    ↓
            avcodec_open2()
                    |-------------------------------------------←--------
                    ↓                                                   |
            av_read_frame()                                             |
                    ↓                                                   |
                get packet?----------YES--------------                  |
                    |                                ↓                  |
                    NO                            AVPacket              ↑
                    |                                ↓                  |
                    |                       avcodec_decode_video2()     |
                    ↓                                ↓                  |
                  close                           AVFrame               |
                                                     ↓                  |
                                              show on screen..          |
                                                     ↓                  |
                                                     |__________________|
 */

#include "ffmpeg_read_av_info.h"


char* BytesToSize( double Bytes )
{
    float tb = 1099511627776;
    float gb = 1073741824;
    float mb = 1048576;
    float kb = 1024;
    
    char returnSize[256];
    
    if( Bytes >= tb )
        sprintf(returnSize, "%.2f TB", (float)Bytes/tb);
    else if( Bytes >= gb && Bytes < tb )
        sprintf(returnSize, "%.2f GB", (float)Bytes/gb);
    else if( Bytes >= mb && Bytes < gb )
        sprintf(returnSize, "%.2f MB", (float)Bytes/mb);
    else if( Bytes >= kb && Bytes < mb )
        sprintf(returnSize, "%.2f KB", (float)Bytes/kb);
    else if ( Bytes < kb)
        sprintf(returnSize, "%.2f Bytes", Bytes);
    else
        sprintf(returnSize, "%.2f Bytes", Bytes);
    
    static char ret[256];
    strcpy(ret, returnSize);
    return ret;
}

void read_av_info(const char * av_pathfile)
{
    AVFormatContext     *pfmtCxt    = NULL;
    
    int                 audioStreamIdx  = -1;
    int                 videoStreamIdx  = -1;
    //初始化 libavformat和注册所有的muxers、demuxers和protocols
    av_register_all();
    
    //以输入方式打开一个媒体文件,也即源文件
    int ok = avformat_open_input(&pfmtCxt, av_pathfile, NULL, NULL);
    if (ok != 0) {
        printf("Could not open file.");
    }
    
    //通过读取媒体文件的中的包来获取媒体文件中的流信息,对于没有头信息的文件如(mpeg)是非常有用的
    //也就是把媒体文件中的音视频流等信息读出来,保存在容器中,以便解码时使用
    ok = avformat_find_stream_info(pfmtCxt, NULL);
    if (ok != 0) {
        printf("find stream info error.");
    }
    
    for (int i = 0; i < pfmtCxt->nb_streams; i++) {
        if (pfmtCxt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIdx = i;
        } else if (pfmtCxt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audioStreamIdx = i;
        }
    }
    
    AVStream *videostream = NULL;
    AVStream *audiostream = NULL;
    if (videoStreamIdx != -1) {
        videostream = pfmtCxt->streams[videoStreamIdx];
    }
    if (audioStreamIdx != -1) {
        audiostream = pfmtCxt->streams[audioStreamIdx];
    }
    printf("==============================av_dump_format==================================\n");
    av_dump_format(pfmtCxt, 0, 0, 0);
    /*******************************输出相关media文件信息*******************************/
    printf("===========================================================================\n");
    printf("文件名 : %s \n",pfmtCxt->url);
    printf("输入格式 : %s \n全称 : %s \n",pfmtCxt->iformat->name,pfmtCxt->iformat->long_name);
    
    int64_t tns, thh, tmm, tss;
    tns  = pfmtCxt->duration / 1000000;
    thh  = tns / 3600;
    tmm  = (tns % 3600) / 60;
    tss  = (tns % 60);
    
    printf("总时长 : %f ms,fmt:%02lld:%02lld:%02lld \n总比特率 : %f kbs\n",(pfmtCxt->duration * 1.0 / AV_TIME_BASE) * 1000,thh,tmm,tss,pfmtCxt->bit_rate / 1000.0);//1000 bit/s = 1 kbit/s
    double fsize = (pfmtCxt->duration * 1.0 / AV_TIME_BASE * pfmtCxt->bit_rate / 8.0);
    printf("文件大小 : %s\n",BytesToSize(fsize));
    printf("协议白名单 : %s \n协义黑名单 : %s\n",pfmtCxt->protocol_whitelist,pfmtCxt->protocol_blacklist);
    printf("数据包的最大数量 : %d\n",pfmtCxt->max_ts_probe);
    printf("最大缓冲时间 : %lld\n",pfmtCxt->max_interleave_delta);
    printf("缓冲帧的最大缓冲 : %u Bytes\n",pfmtCxt->max_picture_buffer);
    printf("metadata:\n");
    AVDictionary *metadata = pfmtCxt->metadata;
    if (metadata) {
        AVDictionaryEntry *entry = NULL;
        while ((entry = av_dict_get(metadata, "", entry, AV_DICT_IGNORE_SUFFIX))) {
            printf("\t%s : %s\n",entry->key,entry->value);
        }
    }
    if (videostream) {
        printf("视频流信息(%s):\n",av_get_media_type_string(videostream->codecpar->codec_type));
        printf("\tStream #%d\n",videoStreamIdx);
        printf("\t总帧数 : %lld\n",videostream->nb_frames);
        const char *avcodocname = avcodec_get_name(videostream->codecpar->codec_id);
        const char *profilestring = avcodec_profile_name(videostream->codecpar->codec_id,videostream->codecpar->profile);
        char * codec_fourcc = av_fourcc2str(videostream->codecpar->codec_tag);
        printf("\t编码方式 : %s\n\tCodec Profile : %s\n\tCodec FourCC : %s\n",avcodocname,profilestring,codec_fourcc);
        ///如果是C++引用(AVPixelFormat)注意下强转类型
        const char *pix_fmt_name = videostream->codecpar->format == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(videostream->codecpar->format);
        
        printf("\t显示编码格式(color space) : %s \n",pix_fmt_name);
        printf("\t宽 : %d pixels,高 : %d pixels \n",videostream->codecpar->width,videostream->codecpar->height);
        AVRational display_aspect_ratio;
        av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
                  videostream->codecpar->width  * (int64_t)videostream->sample_aspect_ratio.num,
                  videostream->codecpar->height * (int64_t)videostream->sample_aspect_ratio.den,
                  1024 * 1024);
        printf("\tsimple_aspect_ratio(SAR) : %d : %d\n\tdisplay_aspect_ratio(DAR) : %d : %d \n",videostream->sample_aspect_ratio.num,
               videostream->sample_aspect_ratio.den,display_aspect_ratio.num,display_aspect_ratio.den);
        printf("\t最低帧率 : %f fps\n\t平均帧率 : %f fps\n",av_q2d(videostream->r_frame_rate),av_q2d(videostream->avg_frame_rate));
        printf("\t每个像素点的比特数 : %d bits\n",videostream->codecpar->bits_per_raw_sample);
        printf("\t每个像素点编码比特数 : %d bits\n",videostream->codecpar->bits_per_coded_sample); //YUV三个分量每个分量是8,即24
        printf("\t视频流比特率 : %f kbps\n",videostream->codecpar->bit_rate / 1000.0);
        printf("\t基准时间 : %d / %d = %f \n",videostream->time_base.num,videostream->time_base.den,av_q2d(videostream->time_base));
        printf("\t视频流时长 : %f ms\n",videostream->duration * av_q2d(videostream->time_base) * 1000);
        printf("\t帧率(tbr) : %f\n",av_q2d(videostream->r_frame_rate));
        printf("\t文件层的时间精度(tbn) : %f\n",1/av_q2d(videostream->time_base));
        printf("\t视频层的时间精度(tbc) : %f\n",1/av_q2d(videostream->codec ->time_base));
        
        double s = videostream->duration * av_q2d(videostream->time_base);
        int64_t tbits = videostream->codecpar->bit_rate * s;
        double stsize = tbits / 8;
        printf("\t视频流大小(Bytes) : %s \n",BytesToSize(stsize));
        printf("\tmetadata:\n");
        
        AVDictionary *metadata = videostream->metadata;
        if (metadata) {
            AVDictionaryEntry *entry = NULL;
            while ((entry = av_dict_get(metadata, "", entry, AV_DICT_IGNORE_SUFFIX))) {
                printf("\t\t%s : %s\n",entry->key,entry->value);
            }
        }
    }
    
    if (audiostream) {
        printf("音频流信息(%s):\n",av_get_media_type_string(audiostream->codecpar->codec_type));
        printf("\tStream #%d\n",audioStreamIdx);
        printf("\t音频时长 : %f ms\n",audiostream->duration * av_q2d(audiostream->time_base) * 1000);
        const char *avcodocname = avcodec_get_name(audiostream->codecpar->codec_id);
        const char *profilestring = avcodec_profile_name(audiostream->codecpar->codec_id,audiostream->codecpar->profile);
        char * codec_fourcc = av_fourcc2str(audiostream->codecpar->codec_tag);
        printf("\t编码格式 %s (%s,%s)\n",avcodocname,profilestring,codec_fourcc);
        printf("\t音频采样率 : %d Hz\n",audiostream->codecpar->sample_rate);
        printf("\t音频声道数 : %d \n",audiostream->codecpar->channels);
        printf("\t音频流比特率 : %f kbps\n",audiostream->codecpar->bit_rate / 1000.0);
        double s = audiostream->duration * av_q2d(audiostream->time_base);
        int64_t tbits = audiostream->codecpar->bit_rate * s;
        double stsize = tbits / 8;
        printf("\t音频流大小(Bytes) : %s\n",BytesToSize(stsize));
    }
    
}

输出的结果 :

==============================av_dump_format==================================
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '(null)':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.41.100
    comment         : vid:74f08a0dec84478db32d577dc195f449
  Duration: 00:02:58.64, start: 0.000000, bitrate: 518 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 854x480 [SAR 1280:1281 DAR 16:9], 450 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (HE-AAC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 63 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
===========================================================================
文件名 : /Users/fengsh/Documents/ffmpeg/test.mp4 
输入格式 : mov,mp4,m4a,3gp,3g2,mj2 
全称 : QuickTime / MOV 
总时长 : 178641.000000 ms,fmt:00:02:58 
总比特率 : 518.820000 kbs
文件大小 : 11.05 MB
协议白名单 : file,crypto 
协义黑名单 : (null)
数据包的最大数量 : 50
最大缓冲时间 : 10000000
缓冲帧的最大缓冲 : 3041280 Bytes
metadata:
	major_brand : isom
	minor_version : 512
	compatible_brands : isomiso2avc1mp41
	encoder : Lavf57.41.100
	comment : vid:74f08a0dec84478db32d577dc195f449
视频流信息(video):
	Stream #0
	总帧数 : 4460
	编码方式 : h264
	Codec Profile : High
	Codec FourCC : avc1
	显示编码格式(color space) : yuv420p 
	宽 : 854 pixels,高 : 480 pixels 
	simple_aspect_ratio(SAR) : 1280 : 1281
	display_aspect_ratio(DAR) : 16 : 9 
	最低帧率 : 25.000000 fps
	平均帧率 : 25.000000 fps
	每个像素点的比特数 : 8 bits
	每个像素点编码比特数 : 24 bits
	视频流比特率 : 450.393000 kbps
	基准时间 : 1 / 12800 = 0.000078 
	视频流时长 : 178400.000000 ms
	帧率(tbr) : 25.000000
	文件层的时间精度(tbn) : 12800.000000
	视频层的时间精度(tbc) : 50.000000
	视频流大小(Bytes) : 9.58 MB 
	metadata:
		language : und
		handler_name : VideoHandler
音频流信息(audio):
	Stream #1
	音频时长 : 178526.009070 ms
	编码格式 aac (HE-AAC,mp4a)
	音频采样率 : 44100 Hz
	音频声道数 : 2 
	音频流比特率 : 63.971000 kbps
	音频流大小(Bytes) : 1.36 MB
估计还有其它格式的文件还没有考虑到,后面熟释了,搞个mac版本的工具玩玩。
阅读更多

没有更多推荐了,返回首页