其他分享
首页 > 其他分享> > ffmpeg学习(4)协议解析、封装解析

ffmpeg学习(4)协议解析、封装解析

作者:互联网

这里介绍ffmpeg打开一个输入进行协议封装解析,输入可以是本地文件、也可以是视频流信息。以一个最简单示例代码开始,后面再对代码进行说明。

示例代码

#include <stdio.h>

#ifdef __cplusplus  
extern "C" {
#endif  

#include "libavformat/avformat.h"

#ifdef __cplusplus  
}
#endif 

int main()
{
    int ret;

    AVFormatContext* input_fmt_ctx = NULL; // 必须设置NULL

    // 打开输入
    const char* input_file = "../files/Titanic.mkv";
    //const char* input_file = "../files/Titanic.mp4";
    //const char* input_file = "rtmp://58.200.131.2:1935/livetv/cctv1";
    //const char* input_file = "http://ivi.bupt.edu.cn/hls/cctv6.m3u8";

    if((ret = avformat_open_input(&input_fmt_ctx, input_file, NULL, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
        return ret;
    }

    // 分析流信息
    if((ret = avformat_find_stream_info(input_fmt_ctx, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
        return ret;
    }

    // 打印信息
    av_dump_format(input_fmt_ctx, 0, input_file, 0);


    // 关闭输入
    avformat_close_input(&input_fmt_ctx);

    return 0;
}

运行后结果如下
在这里插入图片描述
这个截图打印出了视频文件Titanic.mkv信息,视频时长、码率,以及音频、视频两路流的编码信息。这个截图应该很眼熟,就是ffmpeg运行时打印输出的信息。

其他输入截图如下
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
代码说明

在介绍示例相关api函数前,先关注下条件编译下引用ffmpeg头文件的问题。

#ifdef __cplusplus  
extern "C" {
#endif  

#include "libavformat/avformat.h"

#ifdef __cplusplus  
}
#endif

宏__cplusplus仅在c++环境下定义,如果是c编译环境,上述等效为一行

#include "libavformat/avformat.h"

否则,在C++环境下等效为

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

在C++下,函数支持重载,函数签名与c截然不同;使用extern “C”{} 的括号体内所有头文件定义的函数后,将告知编译器使用c的函数签名规则去从对应的lib中查找其实现,否则将提示无法解析的外部符号。

AVFormatContext 结构体的说明见 文章 结构体分析AVFormatContext

avformat_open_input()

用于打开多媒体输入并且获得一些相关的信息,其声明位于libavformat\avformat.h,如下

/**
 * Open an input stream and read the header. The codecs are not opened.
 * The stream must be closed with avformat_close_input().
 *
 * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
 *           May be a pointer to NULL, in which case an AVFormatContext is allocated by this
 *           function and written into ps.
 *           Note that a user-supplied AVFormatContext will be freed on failure.
 * @param url URL of the stream to open.
 * @param fmt If non-NULL, this parameter forces a specific input format.
 *            Otherwise the format is autodetected.
 * @param options  A dictionary filled with AVFormatContext and demuxer-private options.
 *                 On return this parameter will be destroyed and replaced with a dict containing
 *                 options that were not found. May be NULL.
 *
 * @return 0 on success, a negative AVERROR on failure.
 *
 * @note If you want to use custom IO, preallocate the format context and set its pb field.
 */
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);

英文注释比较详细,参数再解释如下

函数执行成功的话,其返回值大于等于0。

avformat_find_stream_info()

经过avformat_open_input()调用后已经解析一部分的码流编码信息,但可能不完整不正确。需要进一步调用此函数读取一部分视音频数据并且获得更加完善的编码信息,特别是对于一些无文件头的输入是必要的。其声明位于libavformat\avformat.h,如下所示

/**
 * Read packets of a media file to get stream information. This
 * is useful for file formats with no headers such as MPEG. This
 * function also computes the real framerate in case of MPEG-2 repeat
 * frame mode.
 * The logical file position is not changed by this function;
 * examined packets may be buffered for later processing.
 *
 * @param ic media file handle
 * @param options  If non-NULL, an ic.nb_streams long array of pointers to
 *                 dictionaries, where i-th member contains options for
 *                 codec corresponding to i-th stream.
 *                 On return each dictionary will be filled with options that were not found.
 * @return >=0 if OK, AVERROR_xxx on error
 *
 * @note this function isn't guaranteed to open all the codecs, so
 *       options being non-empty at return is a perfectly normal behavior.
 *
 * @todo Let the user decide somehow what information is needed so that
 *       we do not waste time getting stuff the user does not need.
 */
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

对于无文件头信息的输入会读取部分数据,但是不会改变后续处理的逻辑位置,可以理解为后续读取将从第一个码流包开始。

av_dump_format()

打印关于输入或输出格式的详细信息,例如持续时间,比特率,流,容器,程序,元数据,边数据,编解码器和时基。

/**
 * Print detailed information about the input or output format, such as
 * duration, bitrate, streams, container, programs, metadata, side data,
 * codec and time base.
 *
 * @param ic        the context to analyze
 * @param index     index of the stream to dump information about
 * @param url       the URL to print, such as source or destination file
 * @param is_output Select whether the specified context is an input(0) or output(1)
 */ */
void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output);

参数ic为待分析打印的输入封装上下文的指针,url用于显示的源或输出的文件名,要注意参数is_output如果是输入必须设置为0,输出必须设置为1

avformat_close_input()

关闭一个AVFormatContext,和avformat_open_input()成对使用。声明位于libavformat\avformat.h,如下所示

/**
 * Close an opened input AVFormatContext. Free it and all its contents
 * and set *s to NULL.
 */
void avformat_close_input(AVFormatContext **s);

标签:NULL,封装,ffmpeg,AVFormatContext,stream,avformat,file,input,解析
来源: https://blog.csdn.net/wanggao_1990/article/details/115721931