写在前面
学习雷神的博客,向雷神致敬~
看了雷神的小学期视频课,在Github上下载了simplest_ffmpeg_player的代码,为代码加上了注释,作为留存。
2019.07.18
前置知识点 simplest_ffmpeg_helloworld.cpp注释
知识点
URLProtocol
其中 url_protocols[] 在 protocol_list.c 中
static const URLProtocol * const url_protocols[] = {
&ff_async_protocol,
&ff_cache_protocol,
&ff_concat_protocol,
&ff_crypto_protocol,
&ff_data_protocol,
&ff_ffrtmphttp_protocol,
&ff_file_protocol,
&ff_ftp_protocol,
&ff_gopher_protocol,
&ff_hls_protocol,
&ff_http_protocol,
&ff_httpproxy_protocol,
&ff_icecast_protocol,
&ff_mmsh_protocol,
&ff_mmst_protocol,
&ff_md5_protocol,
&ff_pipe_protocol,
&ff_prompeg_protocol,
&ff_rtmp_protocol,
&ff_rtmpt_protocol,
&ff_rtp_protocol,
&ff_srtp_protocol,
&ff_subfile_protocol,
&ff_tee_protocol,
&ff_tcp_protocol,
&ff_udp_protocol,
&ff_udplite_protocol,
&ff_unix_protocol,
NULL };
xxx_register_all
请参考FFmpeg源码(一)梦开始的地方——av_register_all(),包含av_register_all()、avcodec_register_all()及avfilter_register_all()的源码分析。
simplest_ffmpeg_helloworld.cpp
/**
* 最简单的FFmpeg Helloworld程序
* Simplest FFmpeg HelloWorld
*
* 雷霄骅 Lei Xiaohua
* leixiaohua1020@126.com
* 中国传媒大学/数字电视技术
* Communication University of China / Digital TV Technology
* http://blog.csdn.net/leixiaohua1020
*
*
* 本程序是基于FFmpeg函数的最简单的程序。它可以打印出FFmpeg类库的下列信息:
* Protocol: FFmpeg类库支持的协议
* AVFormat: FFmpeg类库支持的封装格式
* AVCodec: FFmpeg类库支持的编解码器
* AVFilter: FFmpeg类库支持的滤镜
* Configure: FFmpeg类库的配置信息
*
* This is the simplest program based on FFmpeg API. It can show following
* informations about FFmpeg library:
* Protocol: Protocols supported by FFmpeg.
* AVFormat: Container format supported by FFmpeg.
* AVCodec: Encoder/Decoder supported by FFmpeg.
* AVFilter: Filters supported by FFmpeg.
* Configure: configure information of FFmpeg.
*
*/
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#ifdef __cplusplus
};
#endif
#endif
//FIX
struct URLProtocol;
/**
* Protocol Support Information
* 协议支持信息(输入协议&&输出协议)
*/
char * urlprotocolinfo(){
char *info=(char *)malloc(40000);
// 将指定内存的前n个字节设置为特定的值
memset(info,0,40000);
// 注册复用器,编码器等(参考https://blog.csdn.net/asd501823206/article/details/96377773)
av_register_all();
struct URLProtocol *pup = NULL;
//Input
struct URLProtocol **p_temp = &pup;
/**
* libavformat->protocolos.c
* const char *avio_enum_protocols(void **opaque, int output)
* {
* const URLProtocol **p = *opaque;
*
* p = p ? p + 1 : url_protocols;
* *opaque = p;
* if (!*p) {
* *opaque = NULL;
* return NULL;
* }
* if ((output && (*p)->url_write) || (!output && (*p)->url_read))
* return (*p)->name;
* return avio_enum_protocols(opaque, output);
* }
*
* Iterate through names of available protocols.
* 迭代可用协议的名称。
*
* Parameters
* opaque A private pointer representing current protocol. It must be a pointer to NULL on first iteration and will be updated by successive calls to avio_enum_protocols.
* opaque 表示当前协议的私有指针。 它必须是第一次迭代时指向NULL的指针,并将通过连续调用avio_enum_protocols进行更新。
*
* output If set to 1, iterate over output protocols, otherwise over input protocols.
* output 如果设置为1,则迭代输出协议,否则迭代输入协议。
* Returns
* A static string containing the name of current protocol or NULL
* 包含当前协议名称或NULL的静态字符串
*/
avio_enum_protocols((void **)p_temp, 0);
while ((*p_temp) != NULL){
sprintf(info, "%s[In ][s]\n", info, avio_enum_protocols((void **)p_temp, 0));
}
pup = NULL;
//Output
avio_enum_protocols((void **)p_temp, 1);
while ((*p_temp) != NULL){
sprintf(info, "%s[Out][s]\n", info, avio_enum_protocols((void **)p_temp, 1));
}
return info;
}
/**
* AVFormat Support Information
*
* 获取所有复用器、解复用器并打印
*/
char * avformatinfo(){
char *info=(char *)malloc(40000);
memset(info,0,40000);
av_register_all();
/**
* libavformat->format.c中
*
* // head of registered input format linked list
* static AVInputFormat* first_iformat = NULL;
*
* AVInputFormat *av_iformat_next(const AVInputFormat *f)
* {
* if (f)
* return f->next;
* else
* return first_iformat;
* }
*
* 当传入为null时,返回所有注册的复用器的第一个。in&out逻辑相同
*
* 循环调用next,打印出format->name
*/
AVInputFormat *if_temp = av_iformat_next(NULL);
AVOutputFormat *of_temp = av_oformat_next(NULL);
//Input
while(if_temp!=NULL){
sprintf(info, "%s[In ] s\n", info, if_temp->name);
if_temp=if_temp->next;
}
//Output
while (of_temp != NULL){
sprintf(info, "%s[Out] s\n", info, of_temp->name);
of_temp = of_temp->next;
}
return info;
}
/**
* AVCodec Support Information
*
* static AVCodec *first_avcodec = NULL;
*
* AVCodec *av_codec_next(const AVCodec *c)
* {
* if (c)
* return c->next;
* else
* return first_avcodec;
* }
*
* 当传入为null时,返回所有注册的编解码器的第一个
*/
char * avcodecinfo()
{
char *info=(char *)malloc(40000);
memset(info,0,40000);
av_register_all();
AVCodec *c_temp = av_codec_next(NULL);
// 循环取下一个AVCodec
while(c_temp!=NULL){
// 解码/编码
if (c_temp->decode!=NULL){
sprintf(info, "%s[Dec]", info);
}
else{
sprintf(info, "%s[Enc]", info);
}
// Type:视频、音频、字幕
switch (c_temp->type){
case AVMEDIA_TYPE_VIDEO:
sprintf(info, "%s[Video]", info);
break;
case AVMEDIA_TYPE_AUDIO:
sprintf(info, "%s[Audio]", info);
break;
default:
sprintf(info, "%s[Other]", info);
break;
}
// name
sprintf(info, "%s s\n", info, c_temp->name);
c_temp=c_temp->next;
}
return info;
}
/**
* AVFilter Support Information
*/
char * avfilterinfo()
{
char *info=(char *)malloc(40000);
memset(info,0,40000);
/**
* 详细注册信息请查看https://blog.csdn.net/asd501823206/article/details/96377773
*/
avfilter_register_all();
/**
* libavfilter->avfilter.c
*
* static AVFilter *first_filter;
*
* const AVFilter *avfilter_next(const AVFilter *prev)
* {
* return prev ? prev->next : first_filter;
* }
*
* 循环打印出filter->name
*/
AVFilter *f_temp = (AVFilter *)avfilter_next(NULL);
while (f_temp != NULL){
sprintf(info, "%s[s]\n", info, f_temp->name);
f_temp=f_temp->next;
}
return info;
}
/**
* Configuration Information
*
* Return the libavcodec build-time configuration. 构建时的配置信息
*/
char * configurationinfo()
{
char *info=(char *)malloc(40000);
memset(info,0,40000);
// 注册复用器,编码器等(参考https://blog.csdn.net/asd501823206/article/details/96377773)
av_register_all();
sprintf(info, "%s\n", avcodec_configuration());
return info;
}
/**
* 每个函数(除了avfilterinfo)都调用了av_register_all(),av_register_all()里的ff_thread_once保证了register_all只会被调用一次
*/
int main(int argc, char* argv[])
{
char *infostr=NULL;
infostr=configurationinfo();
printf("\n<<Configuration>>\n%s",infostr);
free(infostr);
infostr=urlprotocolinfo();
printf("\n<<URLProtocol>>\n%s",infostr);
free(infostr);
infostr=avformatinfo();
printf("\n<<AVFormat>>\n%s",infostr);
free(infostr);
infostr=avcodecinfo();
printf("\n<<AVCodec>>\n%s",infostr);
free(infostr);
infostr=avfilterinfo();
printf("\n<<AVFilter>>\n%s",infostr);
free(infostr);
return 0;
}