FFmpeg API usage: obtaining video information

1. Foreword

From the beginning of this article, I will gradually go deep into the use of FFmpeg API, not just using ffmpeg command line, which is simple and powerful but has certain limitations. Using the command line, we can easily complete some of our specific work, but if we want to use ffmpeg to return the processing results to other users, or if ffmpeg needs to be embedded in our project, we must learn to use the API provided by ffmpeg to write code to complete the work.

Back to the main content of this article. First, before analyzing the video, we often need to know the video stream information contained in the media file, such as file format, playback time, video code rate, video frame rate, video codec format, audio code rate, audio sampling rate and so on. If you use the command line, you only need FFmpeg - I input Mp4 can obtain the above information. However, how to use the API provided by FFmpeg to obtain this information is the content of this article.

First, put a running result diagram. As can be seen from the figure, the information mentioned above has been obtained.

2. Code environment

I use the development environment of windows10 + qt creator, and the compilation environment is MSVC2017.

It should be noted that before using FFmpeg API to write code, add the FFmpeg to be used to the project of qt project. Station B has a video explaining how to configure the environment. The explanation is fairly clear and can be used as a reference. If you have any questions, please leave a message in the comment area and I will reply in time.

Station B qt creator+windows+ffmpeg configuration address: https://www.bilibili.com/video/BV1zN411d7st?p=4

3. Code

I encapsulate the work mentioned above into a class. If your environment is built, you can directly copy the code and run it. First run to see the effect, and then study the code carefully.

  • Class header file code (videoinformation.h)
// Copyright (c) 2021 LucasNan <nanche@mail.hfut.edu.cn> <www.kevinnan.org.cn>

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.


#ifndef VIDEOINFORMATION_H
#define VIDEOINFORMATION_H

#include <iostream>
#include <string>

extern "C"{
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
}

/* What information does the video have?
 * (1) population
 *  - Format o
 *  - Codec
 *  - file size
 *  - Duration o
 *  - Overall rate mode
 *  - Overall bit rate
 *  - date
 * (2) For video
 *  - ID             o
 *  - Format o
 *  - Bit rate o
 *  - Maximum Bitrate 
 *  - Width o
 *  - Height o
 *  - Frame rate mode
 *  - Frame rate o
 *  - Color space
 *  - chroma subsampling 
 *  - Bit depth
 *  - Stream size o
 * (3) For audio
 *  - Format o
 *  - Bit rate o
 *  - Number of channels o
 *  - Sampling rate o
 *  - Compression mode
 *  - Stream size o
 */
class VideoInformation
{
public:
    VideoInformation();

    ~VideoInformation(){
        avformat_close_input(&input_AVFormat_context_);
    }

    //@brief: get video information
    //@param: file_path: file path
    //@ret  : void
    //@birth: created by LucasNan on 20210218
    void getVideoInfo(std::string file_path);

    //@brief: get format
    //@param: void
    //@ret: video format
    //@birth: created by LucasNan on 20210219
    std::string getFormat(){
        return this->format_;
    }

    //@brief: get video length
    //@param: void
    //@ret: video length
    //@birth: created by LucasNan on 20210219
    std::string getDuration(){
        return this->duration_;
    }

    //@brief: get video frame rate
    //@param: void
    //@ret: video frame rate
    //@birth: created by LucasNan on 20210219
    int getFrameRate(){
        return this->frame_rate_;
    }

    //@brief: get the video bit rate
    //@param: void
    //@ret: average video bit rate
    //@birth: created by LucasNan on 20210219
    int getVideoAverageBitRate(){
        return this->video_average_bit_rate_;
    }

    //@brief: get video width
    //@param: void
    //@ret: video width
    //@birth: created by LucasNan on 20210219
    int getWidth(){
        return this->width_;
    }

    //@brief: get video height
    //@param: void
    //@ret: video height
    //@birth: created by LucasNan on 20210219
    int getHeight(){
        return this->height_;
    }

    //@brief: get the video stream size
    //@param: void
    //@ret: video stream size
    //@birth: created by LucasNan on 20210219
    float getVideoSize(){
        return this->video_size_;
    }

    //@brief: get the video coding format
    //@param: void
    //@ret: video coding format
    //@birth: created by LucasNan on 20210219
    std::string getVideoFormat(){
        return this->video_format_;
    }

    std::string getAudioFormat(){
        return this->audio_format_;
    }


    //@brief: get the average audio bit rate
    //@param: void
    //@ret: average audio bit rate
    //@birth: created by LucasNan on 20210219
    int getAudioAverageBitRate(){
        return this->audio_average_bit_rate_;
    }

    //@brief: get the number of audio channels
    //@param: void
    //@ret: number of audio channels
    //@birth: created by LucasNan on 20210219
    int getChannelNumbers(){
        return this->channel_nums;
    }


    //@brief: get the audio sampling rate
    //@param: void
    //@ret: audio sampling rate
    //@birth: created by LucasNan on 20210219
    int getSampleRate(){
        return this->sample_rate_;
    }


    //@brief: get the audio size
    //@param: void
    //@ret: Audio size
    //@birth: created by LucasNan on 20210219
    float getAudioSize(){
        return this->audio_size_;
    }

private:
    AVFormatContext* input_AVFormat_context_;

    //Stream number
    unsigned int stream_numbers_;

    //Video stream index number
    unsigned int video_stream_index_;
    //Audio stream index number
    unsigned int audio_stream_index_;


    //(1) Overall
    std::string format_;            //format
    std::string duration_;                //duration


    //(2) For video
    int frame_rate_;                //Frame rate

    int video_average_bit_rate_;    //Average bitrate 

    int width_;                     //Video width
    int height_;                    //Video height

    float video_size_;              //Video stream size

    std::string video_format_;       //Video coding format

    //(3) For audio
    std::string audio_format_;      //Audio coding format

    int audio_average_bit_rate_;    //Average audio bit rate

    int channel_nums;               //Channels 

    int sample_rate_;               //sampling rate

    float audio_size_;              //Audio stream size

};

#endif // VIDEOINFORMATION_H

  • Class implementation code (videoinformation.cpp)
// Copyright (c) 2021 LucasNan <nanche@mail.hfut.edu.cn> <www.kevinnan.org.cn>

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include "videoinformation.h"

VideoInformation::VideoInformation()
{
    //Get dynamic memory
    input_AVFormat_context_ = avformat_alloc_context();
    //input_AVFormat_context_ = NULL;
}

void VideoInformation::getVideoInfo(std::string file_path){

    if(avformat_open_input(&input_AVFormat_context_, file_path.c_str(), 0, NULL) < 0){
        std::cout<<"file open error!"<<std::endl;
        return;
    }

    if(avformat_find_stream_info(input_AVFormat_context_, NULL) < 0){
        printf("error");
        return ;
    }

    //Get the number of streams
    this->stream_numbers_ = input_AVFormat_context_->nb_streams;

    //Calculate video length
    int hours, mins, secs;
    secs = input_AVFormat_context_->duration / 1000000;
    mins = secs / 60;
    secs %= 60;
    hours = mins / 60;
    mins %= 60;

    //Format video length
    char duration_foramt_[128];
    sprintf(duration_foramt_, "%d:%d:%d", hours, mins, secs);
    this->duration_ = duration_foramt_;

    //av_dump_format(input_AVFormat_context_, 0, file_path.c_str(), 0);

    //Get the packaging format of the input video

    std::cout<<"format: "<<input_AVFormat_context_->streams[0]->codecpar->format<<std::endl;
    std::cout<<"bit rate: "<<input_AVFormat_context_->bit_rate/1000.0<<std::endl;

    AVInputFormat* infoFormat = input_AVFormat_context_->iformat;
    this->format_ = infoFormat->name;

    //Traverse the video stream respectively
    for(unsigned int i = 0; i < stream_numbers_; i++){
        //Take out a stream and generate an AVStream object
        AVStream* input_stream = input_AVFormat_context_->streams[i];
         //AVDictionaryEntry *lang = av_dict_get(input_stream->metadata, "language", NULL, 0);
         //std::cout<<"ddd: "<<lang->value<<std::endl;
        //Determine whether it is a video stream
        if(input_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){

            //avg_ frame_ Rate - > avrational,
            //avg_frame_rate.num: molecule
            //avg_frame_rate.den: Female
            //Get video frame rate
            this->frame_rate_ = input_stream->avg_frame_rate.num / input_stream->avg_frame_rate.den;

            //Take out the coding parameters in the video stream and generate the AVCodecParamters object
            AVCodecParameters* codec_par = input_stream->codecpar;

            //The video width, height, bit rate and video size are obtained by using the coding parameter object AVCdecParamters
            this->width_ = codec_par->width;
            this->height_ = codec_par->height;
            this->video_average_bit_rate_ = codec_par->bit_rate/1000;
            this->video_size_ = this->video_average_bit_rate_ * secs / (8.0*1024);

            //Using avcodec_ paramters_ to_ The context() function generates an AVCodecContext object
            //input_ Stream - > codec has been eliminated. It is not recommended to generate AVCodecContext in this way
            AVCodecContext* avctx_video;
            avctx_video = avcodec_alloc_context3(NULL);
            int ret = avcodec_parameters_to_context(avctx_video, codec_par);
            if (ret < 0) {
                avcodec_free_context(&avctx_video);
                return;
             }
            //Use AVCodecContext to get video coding format (not recommended)
            char buf[128];
            avcodec_string(buf, sizeof(buf), avctx_video, 0);
            //Use AVCodecParameters to get the video coding method
            this->video_format_ = avcodec_get_name((codec_par->codec_id));

         //Determine whether the audio stream is
        }else if(input_stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){

            //Generate AVcodecParamters object
            AVCodecParameters* codec_par = input_stream->codecpar;
            AVCodecContext* avctx_audio;
            avctx_audio = avcodec_alloc_context3(NULL);
            int ret = avcodec_parameters_to_context(avctx_audio, codec_par);
            if(ret < 0){
                avcodec_free_context(&avctx_audio);
                return;
            }

            this->audio_format_ = avcodec_get_name(avctx_audio->codec_id);

            this->audio_average_bit_rate_ = codec_par->bit_rate / 1000;

            this->channel_nums = codec_par->channels;

            this->sample_rate_ = codec_par->sample_rate;

            this->audio_size_ = this->audio_average_bit_rate_ * secs / (8.0*1024);
        }
    }
}
  • main.cpp code
// Copyright (c) 2021 LucasNan <nanche@mail.hfut.edu.cn> <www.kevinnan.org.cn>

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.


#include <QCoreApplication>

#include <iostream>

#include "videoinformation.h"


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);  

    //const char* file = "F:/google/durant.mp4";
    const char* file = "F:/google/Beautiful-Ambient-Mix.mp4";

    VideoInformation* v1 = new VideoInformation();
    v1->getVideoInfo(file);


    std::cout<<"duration: "<<v1->getDuration()<<std::endl<<
               "format: "<<v1->getFormat()<<std::endl<<
               "video frame rate: "<<v1->getFrameRate()<<std::endl<<
               "video bit rate: "<<v1->getVideoAverageBitRate()<<std::endl<<
               "video format: "<<v1->getVideoFormat()<<std::endl<<
               "video width: "<<v1->getWidth()<<std::endl<<
               "video height: "<<v1->getHeight()<<std::endl<<
               "video size: "<<v1->getVideoSize()<<std::endl<<
               "audio bit rate: "<<v1->getAudioAverageBitRate()<<std::endl<<
               "audio format: "<<v1->getAudioFormat()<<std::endl<<
               "audio size: "<<v1->getAudioSize()<<std::endl<<
               "audio smaple rate: "<<v1->getSampleRate()<<std::endl<<
               "audio channel numbers: "<<v1->getChannelNumbers()<<std::endl;


    return a.exec();
}

4. Why add extern"C" keyword?

Finally, I want to talk about a problem. Why use FFmpeg? Use the extern "C" keyword to contain the header file of FFmpeg.

The signature compiled in C language is_ Coder, while in C + + language, the generation of general compiler is similar to_ decode_float_float. Although there is no problem in the compilation phase, in the link phase, if the external "C" keyword is not added, the link will be generated_ decoder_float_float this method signature; If the keyword extern "C" is added, the method signature you are looking for is_ decoder. FFmpeg is written in C language. The method signatures generated when compiling FFmpeg are all C language type signatures. Therefore, the external "C" keyword must be added when referring to FFmpeg in C.

Tags: ffmpeg

Posted by abie10 on Sun, 17 Apr 2022 06:09:41 +0930