寫在前面
學習雷神的博客,向雷神致敬~
看了雷神的小學期視頻課,在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
* [email protected]
* 中國傳媒大學/數字電視技術
* 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 ][%10s]\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][%10s]\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 ] %10s\n", info, if_temp->name);
if_temp=if_temp->next;
}
//Output
while (of_temp != NULL){
sprintf(info, "%s[Out] %10s\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 %10s\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[%15s]\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;
}