FFMPEG學習(4)-使用ffmpeg讀取基本音視頻文件信息,熟釋AVFormatContext結構

前段時間把環境整了下,閒時學習下ffmpeg.

最近在看雷神的創作,邊看,邊學,感謝雷神!

頭文件:

//
//  ffmpeg_read_av_info.hpp
//  ffmpegDemo
//
//  Created by fengsh on 2018/4/15.
//  Copyright © 2018年 [email protected]. 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年 [email protected]. 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版本的工具玩玩。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章