雷神simplest_ffmpeg_player解析(二)

寫在前面

學習雷神的博客,向雷神致敬~

看了雷神的小學期視頻課,在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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章