ffmpeg解码之使用C语言打印音视频信息

Posted TrueDei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ffmpeg解码之使用C语言打印音视频信息相关的知识,希望对你有一定的参考价值。

一、通过此文可以得到什么

通过此练习:

  • 1、知道了如何计算一个音频和视频的播放时间;
  • 2、知道了音视频解码的思路的大体流程,之后无非就是在这个流程上进行扩充细节;
  • 3、知道了如何通过C语言或者C++编程语言结合ffmpeg拿到一些音视频的关键信息,例如:帧率等;

二、实现思路

三、实现效果

zhenghui@zh-pc:/data/project/VSCProject/ffmpegStudy$ make
make all
make[1]: 进入目录“/data/project/VSCProject/ffmpegStudy/src”
Compiling main.cpp to main.o ..
cp hello /data/project/VSCProject/ffmpegStudy/src/../
# make 【hello】 finish !!!	
make[1]: 离开目录“/data/project/VSCProject/ffmpegStudy/src”
zhenghui@zh-pc:/data/project/VSCProject/ffmpegStudy$ 
zhenghui@zh-pc:/data/project/VSCProject/ffmpegStudy$ ./hello 
Hello World !
decode video fileName=/home/zhenghui/视频/1080P.mp4 
[NULL @ 0x5654cc332d80] Opening '/home/zhenghui/视频/1080P.mp4' for reading
[file @ 0x5654cc333380] Setting default whitelist 'file,crypto,data'
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] ISO: File Type Major Brand: isom
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Processing st: 0, edit list 0 - media time: 1072, duration: 3621888
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Offset DTS by 1072 to make first pts zero.
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Setting codecpar->delay to 2 for stream st: 0
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Processing st: 1, edit list 0 - media time: 0, duration: 9990149
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] rfps: 29.916667 0.006250
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] rfps: 30.000000 0.000066
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] rfps: 60.000000 0.000265
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] rfps: 120.000000 0.001061
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] rfps: 240.000000 0.004244
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] rfps: 29.970030 0.000868
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] rfps: 59.940060 0.003473
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] Before avformat_find_stream_info() pos: 87425182 bytes read:315205 seeks:1 nb_streams:2
[h264 @ 0x5654cc3340c0] nal_unit_type: 7(SPS), nal_ref_idc: 3
[h264 @ 0x5654cc3340c0] nal_unit_type: 8(PPS), nal_ref_idc: 3
[h264 @ 0x5654cc3340c0] nal_unit_type: 7(SPS), nal_ref_idc: 3
[h264 @ 0x5654cc3340c0] nal_unit_type: 8(PPS), nal_ref_idc: 3
[h264 @ 0x5654cc3340c0] nal_unit_type: 6(SEI), nal_ref_idc: 0
[h264 @ 0x5654cc3340c0] nal_unit_type: 5(IDR), nal_ref_idc: 3
[h264 @ 0x5654cc3340c0] Format yuv420p chosen by get_format().
[h264 @ 0x5654cc3340c0] Reinit context to 1920x1088, pix_fmt: yuv420p
[h264 @ 0x5654cc3340c0] no picture 
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] All info found
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5654cc332d80] After avformat_find_stream_info() pos: 53231 bytes read:393067 seeks:2 frames:4
video_index=0 
audio_index=1 
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/zhenghui/视频/1080P.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.29.100
    description     : Packed by Bilibili XCoder v2.0.2
  Duration: 00:03:46.53, start: 0.000000, bitrate: 3087 kb/s
  Stream #0:0[0x1](und), 3, 1/16000: Video: h264 (High), 1 reference frame (avc1 / 0x31637661), yuv420p(progressive, left), 1920x1080 (1920x1088) [SAR 1:1 DAR 16:9], 0/1, 2951 kb/s, 30 fps, 30 tbr, 16k tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und), 1, 1/44100: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
media name =/home/zhenghui/视频/1080P.mp4 
stream number: 2 
media average ratio: 3015 kbps
media total time: 0:3:46 
######## Video info: ######## 
stream index : 0 
fps:29.999914 fps
video codec : H264 
video_time : 00:03:46
######## Audio info: ######## 
stream index : 1 
stream sample_rate : 44100 Hz 
stream format : AV_SAMPLE_FMT_FLTP 
channels number:2 
audio codec:AAC 
audio_time : 00:03:46
[AVIOContext @ 0x5654cc33b7c0] Statistics: 393067 bytes read, 2 seeks
zhenghui@zh-pc:/data/project/VSCProject/ffmpegStudy$ 

四、实现源代码

0声Darren哥

#include <iostream>
#include <stdio.h>


#ifdef __cplusplus //表示是一个c++程序
extern "C"
#endif

#include <libavdevice/avdevice.h>
#include <libavutil/frame.h>
#include <libavutil/imgutils.h>
#include <libavutil/log.h>
#include <libswscale/swscale.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>

#ifdef __cplusplus

#endif


//g++ -I ../include/ hello_world.cpp -o hello_world -L../lib/ -lavcodec -lavdevice -lavfilter -lavformat -lavutil
void decode()

    char *fileName = "/home/zhenghui/视频/1080P.mp4"; 

    printf("decode video fileName=%s \\n",fileName);

    int ret = 0;
    // 1、分配解复用器上下文
    AVFormatContext *ctx = NULL;
    ctx = avformat_alloc_context(); 

    // 2、根据url打开本地文件或网络流
    ret = avformat_open_input(&ctx,fileName,NULL,NULL);

    if(ret < 0)
    
        printf("打开%s失败 ! \\n",fileName);
        return;
    

    // 3、读取媒体的部分数据包,获取码流信息
    ret = avformat_find_stream_info(ctx,NULL);
    if(ret < 0)
        printf("获取码流信息失败 !\\n");
        return;
    

    // 3、获取音频流和视频流的索引
    int video_index = -1;
    int audio_index = -1;

    video_index = av_find_best_stream(ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
    printf("video_index=%d \\n",video_index);

    audio_index = av_find_best_stream(ctx,AVMEDIA_TYPE_AUDIO,-1,-1,NULL,0);
    printf("audio_index=%d \\n",audio_index);

    // 打印流信息
    av_dump_format(ctx,0,fileName,0);

    //打印媒体文件url
    printf("media name =%s \\n",ctx->url);
    //打印流数量
    printf("stream number: %d \\n",ctx->nb_streams);
    //打印码率
    printf("media average ratio: %lld kbps\\n",(int64_t)(ctx->bit_rate/1024));

    //打印时长
    int total_seconds,hour,minute,second;
    //ctx->duration的单位是微妙,先转换成秒,再进行转换成其他的时间单位就比较简单了
    total_seconds = (ctx->duration) / AV_TIME_BASE;
    hour = total_seconds / 3600;
    minute = (total_seconds % 3600) /60;
    second = (total_seconds % 60);

    // 文件总时长
    printf("media total time: %d:%d:%d \\n",hour,minute,second);

    //老版本查找流索引
    for(int i = 0;i < ctx->nb_streams;i++)
        AVStream  *av_stream = ctx->streams[i];

        //判断流是什么类型
        //视频流
        if( AVMEDIA_TYPE_VIDEO == av_stream->codecpar->codec_type)
        
            printf("######## Video info: ######## \\n");
            // 流索引
            printf("stream index : %d \\n",av_stream->index);
            //帧率
            printf("fps:%lf fps\\n",av_q2d(av_stream->avg_frame_rate));

            if(AV_CODEC_ID_MPEG4 == av_stream->codecpar->codec_id)
            
                printf("video codec : MPEG4 \\n");
            
            else if(AV_CODEC_ID_H264 == av_stream->codecpar->codec_id)
            
                printf("video codec : H264 \\n");
            else 
            
                printf("video codec other value=%d \\n", av_stream->codecpar->codec_id);
            

            //获取视频总时长
            if(AV_NOPTS_VALUE != av_stream->duration)
            
                int video_time =av_stream->duration * av_q2d(av_stream->time_base);
                printf("video_time : %02d:%02d:%02d\\n" ,
                (video_time / 3600),
                (video_time % 3600) / 60,
                (video_time % 60)
                );
            
            else
                printf("audio duration unknown ! \\n");
            
        
        //音频流
        else if(AVMEDIA_TYPE_AUDIO == av_stream->codecpar->codec_type)
        
            printf("######## Audio info: ######## \\n");
            // 流索引
            printf("stream index : %d \\n",av_stream->index);

            // 音频编解码器的采样率 单位Hz
            printf("stream sample_rate : %d Hz \\n",av_stream->codecpar->sample_rate);

            //音频采样格式
            if(AV_SAMPLE_FMT_FLTP == av_stream->codecpar->format)
            
                printf("stream format : AV_SAMPLE_FMT_FLTP \\n");
            
            else  if(AV_SAMPLE_FMT_S16P == av_stream->codecpar->format)
            
                printf("stream format : AV_SAMPLE_FMT_S16P \\n");
            else
                printf("stream format : other; value=%d \\n",av_stream->codecpar->format);
            

            // 音频信道数目
            printf("channels number:%d \\n",av_stream->codecpar->channels);

            //音频压缩编码格式
            if(AV_CODEC_ID_AAC == av_stream->codecpar->codec_id)
            
                printf("audio codec:AAC \\n");
            else if(AV_CODEC_ID_MP3 == av_stream->codecpar->codec_id)
            
                printf("audio codec:MP3 \\n");
            else
                printf("audio codec : other; value=%d \\n",av_stream->codecpar->codec_id);
            

            //获取视频总时长
            if(AV_NOPTS_VALUE != av_stream->duration)
            
                int audio_time =av_stream->duration * av_q2d(av_stream->time_base);
                printf("audio_time : %02d:%02d:%02d\\n" ,
                (audio_time / 3600),
                (audio_time % 3600) / 60,
                (audio_time % 60)
                );
            
            else
                printf("audio duration unknown ! \\n");
            

            audio_index = i;
        

    

    if(ctx)
        avformat_close_input(&ctx);


int main() 
    // 设置控制台输出级别
    av_log_set_level(AV_LOG_DEBUG);
    // // 打印输出字符串Hello World !
    av_log(NULL, AV_LOG_DEBUG, "%s", "Hello World !\\n");

    decode();
    return 0;


以上是关于ffmpeg解码之使用C语言打印音视频信息的主要内容,如果未能解决你的问题,请参考以下文章

2023-02-21:请用go语言调用ffmpeg,解码mp4文件,输出视频信息和总帧数。

基于FFmpeg的视频播放器之四:视频解码

第十章 视频播放器开发之音频播放

2023-02-18:ffmpeg是c编写的音视频编解码库,请问用go语言如何调用?例子是03输出版本号。

最简单的基于FFmpeg的移动端例子:IOS 视频解码器

基于FFmpeg的视频播放器之七:音频解码