当前位置:网站首页>Ffmpeg (I) AV_ register_ all()
Ffmpeg (I) AV_ register_ all()
2022-06-28 08:24:00 【qq_ thirty-seven million seven hundred and five thousand five h】
ffmpeg
av_register_all
FFmpeg in av_register_all() The function is used to register all muxers、demuxers And protocols.FFmpeg4.0 Used to store with a linked list muxer/demuxer,FFmpeg4.0 Later, it will be stored in array , also av_register_all Method has been marked obsolete ,av_register_input_format and av_register_output_format Also marked obsolete .
av_register_all() The statement for is located at libavformat/avformat.h Header file , In the new version 4.0 in the future , You don't need to call this method , All modules can be used directly .
The document mentions avfilter modular :avfilter_register()、avfilter_register_all() and avfilter_next() Deprecated , add to av_filter_iterate() To iterate through .avformat modular :av_register_input_format()、av_register_output_format()、av_register_all() Etc. are out of date , add to av_demuxer_iterate() and av_muxer_iterate() To iterate through .avcodec modular :avcodec_register()、avcodec_register_all()、av_register_codec_parser() Etc. are out of date , add to av_codec_iterae() and av_parser_iterate() To iterate through .
avformat Module registration function changes , Change linked list storage to array storage , Add... At run time muxer And demuxer To the linked list , It is automatically generated at compile time and saved in the array .
Generally we use FFMpeg When doing encoding and decoding, you will call av_register_all() This function starts with , Complete the basic initialization work . As for what it initializes , Let's look directly at the code .
void av_register_all(void)
{
static int initialized; // Flag bit indicates whether it has been initialized
if (initialized)
return;
initialized = 1;
avcodec_register_all(); // Register codecs
/* (de)muxers */ // Register multiplexer and demultiplexer
REGISTER_MUXER (A64, a64);
REGISTER_DEMUXER (AA, aa);
REGISTER_DEMUXER (AAC, aac);
REGISTER_MUXDEMUX(AC3, ac3);
REGISTER_DEMUXER (ACM, acm);
REGISTER_DEMUXER (ACT, act);
..........
}
Speaking of this , It should be explained first FFMpeg The design idea inside . Register these codecs and with us here ( Explain ) Multiplexer at FFMpeg What is the concept in the source code of .
stay FFMepg in , Like codec , They are all maintained by a global linked list . Registration is actually adding nodes to these global linked lists , Each node maintains the relevant information of an encoder or decoder and the interoperable function pointers .
Understand the concept of such a registration . So we can take a look at the code that follows . First look at avcodec_register_all() This function .
void avcodec_register_all(void)
{
static int initialized;
if (initialized)
return;
initialized = 1;
/* hardware accelerators */
REGISTER_HWACCEL(H263_VAAPI, h263_vaapi);
REGISTER_HWACCEL(H263_VIDEOTOOLBOX, h263_videotoolbox);
REGISTER_HWACCEL(H264_D3D11VA, h264_d3d11va);
REGISTER_HWACCEL(H264_DXVA2, h264_dxva2);
REGISTER_HWACCEL(H264_MMAL, h264_mmal);
REGISTER_HWACCEL(H264_QSV, h264_qsv);
REGISTER_HWACCEL(H264_VAAPI, h264_vaapi);
REGISTER_HWACCEL(H264_VDA, h264_vda);
REGISTER_HWACCEL(H264_VDA_OLD, h264_vda_old);
............
/* video codecs */
REGISTER_ENCODER(A64MULTI, a64multi);
REGISTER_ENCODER(A64MULTI5, a64multi5);
REGISTER_DECODER(AASC, aasc);
REGISTER_DECODER(AIC, aic);
REGISTER_ENCDEC (ALIAS_PIX, alias_pix);
REGISTER_ENCDEC (AMV, amv);
REGISTER_DECODER(ANM, anm);
REGISTER_DECODER(ANSI, ansi);
REGISTER_ENCDEC (APNG, apng);
REGISTER_ENCDEC (ASV1, asv1);
.............
}
Then let's take a look at REGISTER_HWACCEL(H263_VIDEOTOOLBOX, h263_videotoolbox); What has this code done .
#define REGISTER_HWACCEL(X, x) \
{ \
extern AVHWAccel ff_##x##_hwaccel; \
if (CONFIG_##X##_HWACCEL) \
av_register_hwaccel(&ff_##x##_hwaccel); \
}
Obviously this is a macro . If it is expanded and restored according to the above sentence, it should be :
extern AVHWAccel ff_h263_videotoolbox_hwaccel;
if (CONFIG_H263_VIDEOTOOLBOX_HWACCEL)
av_register_hwaccel(&ff_videotoolbox_hwaccel);
The first sentence indicates that such a variable should have been defined elsewhere ff_h263_videotoolbox_hwaccel Then we search this variable in the source code and find , Don't define it in libavcodec/videotoolbox.c Inside .
AVHWAccel ff_h263_videotoolbox_hwaccel = {
.name = "h263_videotoolbox",
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H263,
.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
.alloc_frame = ff_videotoolbox_alloc_frame,
.start_frame = videotoolbox_mpeg_start_frame,
.decode_slice = videotoolbox_mpeg_decode_slice,
.end_frame = videotoolbox_mpeg_end_frame,
.uninit = ff_videotoolbox_uninit,
.priv_data_size = sizeof(VTContext),
};
Complete code as above , So let's see AVHWAccel The definition of this type .
/**
* @defgroup lavc_hwaccel AVHWAccel
* @{
*/
typedef struct AVHWAccel {
/**
* Name of the hardware accelerated codec.
* The name is globally unique among encoders and among decoders (but an
* encoder and a decoder can share the same name).
*/
const char *name;
/**
* Type of codec implemented by the hardware accelerator.
*
* See AVMEDIA_TYPE_xxx
*/
enum AVMediaType type;
/**
* Codec implemented by the hardware accelerator.
*
* See AV_CODEC_ID_xxx
*/
enum AVCodecID id;
/**
* Supported pixel format.
*
* Only hardware accelerated formats are supported here.
*/
enum AVPixelFormat pix_fmt;
/**
* Hardware accelerated codec capabilities.
* see HWACCEL_CODEC_CAP_*
*/
int capabilities;
/*****************************************************************
* No fields below this line are part of the public API. They
* may not be used outside of libavcodec and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
struct AVHWAccel *next;
/**
* Allocate a custom buffer
*/
int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame);
/**
* Called at the beginning of each frame or field picture.
*
* Meaningful frame information (codec specific) is guaranteed to
* be parsed at this point. This function is mandatory.
*
* Note that buf can be NULL along with buf_size set to 0.
* Otherwise, this means the whole frame is available at this point.
*
* @param avctx the codec context
* @param buf the frame data buffer base
* @param buf_size the size of the frame in bytes
* @return zero if successful, a negative value otherwise
*/
int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
/**
* Callback for each slice.
*
* Meaningful slice information (codec specific) is guaranteed to
* be parsed at this point. This function is mandatory.
* The only exception is XvMC, that works on MB level.
*
* @param avctx the codec context
* @param buf the slice data buffer base
* @param buf_size the size of the slice in bytes
* @return zero if successful, a negative value otherwise
*/
int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
/**
* Called at the end of each frame or field picture.
*
* The whole picture is parsed at this point and can now be sent
* to the hardware accelerator. This function is mandatory.
*
* @param avctx the codec context
* @return zero if successful, a negative value otherwise
*/
int (*end_frame)(AVCodecContext *avctx);
/**
* Size of per-frame hardware accelerator private data.
*
* Private data is allocated with av_mallocz() before
* AVCodecContext.get_buffer() and deallocated after
* AVCodecContext.release_buffer().
*/
int frame_priv_data_size;
/**
* Called for every Macroblock in a slice.
*
* XvMC uses it to replace the ff_mpv_decode_mb().
* Instead of decoding to raw picture, MB parameters are
* stored in an array provided by the video driver.
*
* @param s the mpeg context
*/
void (*decode_mb)(struct MpegEncContext *s);
/**
* Initialize the hwaccel private data.
*
* This will be called from ff_get_format(), after hwaccel and
* hwaccel_context are set and the hwaccel private data in AVCodecInternal
* is allocated.
*/
int (*init)(AVCodecContext *avctx);
/**
* Uninitialize the hwaccel private data.
*
* This will be called from get_format() or avcodec_close(), after hwaccel
* and hwaccel_context are already uninitialized.
*/
int (*uninit)(AVCodecContext *avctx);
/**
* Size of the private data to allocate in
* AVCodecInternal.hwaccel_priv_data.
*/
int priv_data_size;
} AVHWAccel;
You can find The protected operation functions are :alloc_frame , start_frame, decode_slice, end_frame, decode_mb, init, uninit . from ff_h263_videotoolbox_hwaccel We can find in the definition of , It's worth it alloc_frame, start_frame, decode_slice, end_frame, uninit Here are a few ways .
Let's look at it in detail av_register_hwaccel(&ff_videotoolbox_hwaccel) What does this function do .
void av_register_hwaccel(AVHWAccel *hwaccel)
{
AVHWAccel **p = last_hwaccel;
hwaccel->next = NULL;
while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel))
p = &(*p)->next;
last_hwaccel = &hwaccel->next;
}
This is very straightforward , Is doing a linked list addition operation . And what is the definition of its linked list ? as follows :
static AVHWAccel *first_hwaccel = NULL;
static AVHWAccel **last_hwaccel = &first_hwaccel;
such , The entire hardware accelerator registration process is completed . With first_hwaccel Is the head node .
alike , We can find out , Codec registration is also the same routine , Only the codec uses AVCodec This structure represents . alike , Define a global ff_x_encoder perhaps ff_x_decoder, Then in their respective implementation files , Realization AVCodec The method defined in . The function pointer is assigned to ff_x_encode perhaps ff_x_decoder. Corresponding Parser This is how you register .
So down , All the registration work is finished ,avcodec_register_all Then you can retire with success . The result is several initialized global linked lists .
notes : If we want to go to FFMpeg Add a codec inside . Then we just need to implement the corresponding methods , And then in avcodec_register_all Complete the registration operation , In this way, the codec added by itself can be FFMpeg Used .
Okay , The analysis forgot avcodec_register_all() This code , Then the next step is to register some multiplexers and demultiplexers . This one mainly looks at three macros :
#define REGISTER_MUXER(X, x) \
{ \
extern AVOutputFormat ff_##x##_muxer; \
if (CONFIG_##X##_MUXER) \
av_register_output_format(&ff_##x##_muxer); \
}
#define REGISTER_DEMUXER(X, x) \
{ \
extern AVInputFormat ff_##x##_demuxer; \
if (CONFIG_##X##_DEMUXER) \
av_register_input_format(&ff_##x##_demuxer); \
}
#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)
among AVOutputFormat The structure represents the recombiner .AVInputFormat Represents a decomposing device . After the registration is completed, two will be generated, respectively first_iformat and first_oformat It is the global linked list of the head node .
thus , Whole av_register_all The work of the function is done .
av_register_all() The function is in libavformat/allformates.c In the definition of , For initialization libavformat And register all the wrappers , Unpacker and protocol . In the old version (3.x In the early ) Of ffmpeg This function is the beginning of almost all applications . Use version 4.x Of FFMPEG In many cases, this function is not directly called to register the encapsulation and de encapsulation , This function is also declared as deprecated 了 . But this does not prevent preschoolers from reading and learning this function . Because there are many places worth studying , There are many others ffmpeg Functions will be used in the interface and ideas .
Say more , What is unpacking :
If you want to convert common video source data to pictures that can be seen by the naked eye on the TV screen or computer 、 Video frame , The following steps are required
Video source (RTSP,RTMP,HTTP, Ordinary documents, etc ) -> [ After the settlement of the agreement ] -> Video file or video stream (FLV,MKV,AVI etc. )-> [ After unpacking ] -> Video data (H264、HEVC Video data ) And audio data (MP3,WMA etc. )-> [ Video data decoded ] ->YUV Video frame , Last YUV Video frames can be displayed and played and captured by human eyes .
go back to av_register_all(), The code content of the function is very simple , Only the following lines
void av_register_all(void) {
ff_thread_once(&av_format_next_init, av_format_init_next);
}
A very short function contains three elements ,ff_thread_once( A function ),av_format_next_init( A macro defined variable ) as well as av_format_init_next( A function ).
The actual meaning of these three lines of code is to use the function ff_thread_once Function to execute the function av_format_init_next() function , And the first parameter defines the variable for the macro av_format_next_init.
It is worth noting that , Below this function are two functions :
void av_register_input_format(AVInputFormat *format)
{
ff_thread_once(&av_format_next_init, av_format_init_next);
}
void av_register_output_format(AVOutputFormat *format)
{
ff_thread_once(&av_format_next_init, av_format_init_next);
}
Function content , That is, what they do is exactly the same , Just different names , It's registration inputformat and outputformat Function follows register_all What is done is exactly the same .
ff_thread_once()
ff_thread_once() Is defined in libavutil/thread.h For thread safety . stay thread.h In the document , In a os2threads.h library , Will pass the following define Point to pthread_once function :
#define ff_thread_once(control, routine) pthread_once(control, routine)
In all cases , It creates its own function :
static inline int ff_thread_once(char *control, void (*routine)(void)) {
if (!*control) {
routine();
*control = 1;
}
return 0;
} // This function is also very easy to see through a control To guarantee routine Function will be executed only once .
So actually pthread_once():thread.h Different thread libraries are introduced according to different platforms , Cut out unnecessary code , The order of import and stock in is shown in the following code : Find priority to use pthread.h library -> secondly os2threads.h library -> Again w32pthreads.h.pthread_once Mapping to different thread libraries on different platforms pthread_once function .
So in general , The main function of this function is to ensure that the incoming function will only be executed once in a multi-threaded environment . Different process functions are used according to different platforms .
av_format_next_init
This variable is defined in allformat.c Inside the document :
static AVOnce av_format_next_init = AV_ONCE_INIT;
AVOnce It's also defined in thread.h Internal
#define AVOnce pthread_once_t
stay thread.h Inside , In different circumstances ,AVOnce It also has different contents
#define AVOnce pthread_once_t
#define AVOnce char
This variable is also used to ensure that the incoming function will be executed only once in the case of multithreading , For different environments ,AVOnce Different variables are used to implement this function .
av_format_init_next()
Yes ff_thread_once() The function passed in is av_formate_init_next(), The function is as follows :
static void av_format_init_next(void)
{
AVOutputFormat *prevout = NULL, *out;
AVInputFormat *previn = NULL, *in;
ff_mutex_lock(&avpriv_register_devices_mutex);
for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) {
if (prevout)
prevout->next = out;
prevout = out;
}
if (outdev_list) {
for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) {
if (prevout)
prevout->next = out;
prevout = out;
}
}
for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) {
if (previn)
previn->next = in;
previn = in;
}
if (indev_list) {
for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) {
if (previn)
previn->next = in;
previn = in;
}
}
ff_mutex_unlock(&avpriv_register_devices_mutex);
}
The purpose of this function is to muxer_list Output packaging structure in AVOutputFormat String together to form a one-way linked list , When outdev_list When it's not empty , take outdev_list Medium AVOutputFormat They are also strung in the back . In the same way demuxer_list The input encapsulation structure in AVInputFormat Wear them one by one to form a one-way linked list , At the same time indev_list When it's not empty , take indev_list Medium AVInputFormat They are also strung together and hung at the back .
Used before code ff_mutex_lock() function , To ensure the safety of function concurrency , Concurrent lock on . Pass in the parameter avpriv_register_devices_mutex Is defined as
static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER;
It can be traced back to its definition as #define AVMutex pthread_mutex_t, It's defined in libavutil/thread.h in , And ptread_once The function is the same , Use different thread libraries for different platforms , Map to the corresponding mutex variable .
About muxer_list.c and demuxer_list.c
Function list, namely mutex_list and demutex_list Two static arrays are defined in libavformat/muxer_list.c Source files and libavformat/demuxer_list.c In the source file . The details are as follows :
static const AVOutputFormat *muxer_list[] = {
&ff_a64_muxer,
......
&ff_yuv4mpegpipe_muxer,
NULL };
static const AVInputFormat *demuxer_list[] = {
&ff_aa_demuxer,
......
&ff_libmodplug_demuxer,
NULL };
It is worth noting that , The two here list Source file ,libavformat/muxer_list.c and libavformat/demuxer_list.c You can't see it in the downloaded source code , Only execution FFMPEG Root directory configure File can generate these two list file . The purpose of doing this is to make sure that the user ffmpeg When you add encapsulation and de encapsulation in , This allows the user to encapsulate / The unpacker is written to list in
outdev_list and indev_list And with avdevice_register_all() The relationship between
outdev_list && indev_list The definition of is also in allformat.c The file of , As shown below :
static const AVInputFormat * const *indev_list = NULL;
static const AVOutputFormat * const *outdev_list = NULL;
Both of these pointers start with NULL, How can I mount other list On the top ?
The answer is allformat.c In file . There is a function in this code avpriv_register_devices(), Is for ffmpeg Other registered functions of . Find the header file for its declaration , by libavformat/internal.h
void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[]) {
ff_mutex_lock(&avpriv_register_devices_mutex);
outdev_list = o;
indev_list = i;
ff_mutex_unlock(&avpriv_register_devices_mutex);
#if FF_API_NEXT
av_format_init_next();
#endif
}
So these two tables are actually initialized by other function calls , The function that calls this method is libavdevice/alldevice.c Of avdevice_register_all() function , It is also an initial registration function that is often used .
void avdevice_register_all(void)
{
avpriv_register_devices(outdev_list, indev_list);
}
Incoming two list Parameters ,outdev_list It's defined in libavdevice/outdev_list.c,indev_list It's defined in libavdevice/indev_list.c in ,list All of them are AVInputFormat and AVOutputFormat object
static const AVInputFormat * const indev_list[] = {
&ff_alsa_demuxer,
&ff_fbdev_demuxer,
&ff_lavfi_demuxer,
&ff_oss_demuxer,
&ff_sndio_demuxer,
&ff_v4l2_demuxer,
&ff_xcbgrab_demuxer,
NULL };
static const AVOutputFormat * const outdev_list[] = {
&ff_alsa_muxer,
&ff_fbdev_muxer,
&ff_oss_muxer,
&ff_sdl2_muxer,
&ff_sndio_muxer,
&ff_v4l2_muxer,
&ff_xv_muxer,
NULL };
So far, actually av_register_all() We have also learned about the preliminary entry of the function , It's amazing , In the process of reading the source code and tracing the source , even avdevice_register_all() Some of the things we do are also absorbed by preschool students .
av_register_all
First, check whether it has been called , If called , Then go straight back . Initialize all encapsulation and unpacker ( Also called multiplexer and demultiplexer ), such as flv mp4 mp3
mov, But when the source code of this function starts, it will call avcodec_register_all(…) To register all codecs and decoders . So what is registration , Is to put av_register_all What is mentioned in the code is ffmpeg All supported encapsulation formats are added to the linked list , When you need it later, you can find it in the linked list .
avcodec_register_all
First, check whether it has been registered , If you register , Then return to .
Initialize all codecs , Such as h264,h265 etc. , The decoder and encoder also maintain a linked list to store all supported codecs .
avformat_network_init
Initialize all network libraries , such as rtmp,rtsp etc. .
边栏推荐
- cuda和cudnn和tensorrt的理解
- 城联优品向英德捐赠抗洪救灾爱心物资
- Oracle RAC -- understanding of VIP
- 2022第六季完美童模 佛山赛区 初赛圆满落幕
- The RAC cannot connect to the database normally after modifying the scan IP. The ora-12514 problem is handled
- DB
- B_QuRT_User_Guide(26)
- [learning notes] shortest path + spanning tree
- Redis02 -- an operation command of five data types for ending redis (it can be learned, reviewed, interviewed and collected for backup)
- 图像翻译:UVCGAN: UNET VISION TRANSFORMER CYCLE-CONSISTENT GAN FOR UNPAIRED IMAGE-TO-IMAGE TRANSLATION
猜你喜欢

Prometheus service discovery

叠加阶梯图和线图及合并线图和针状图

The maximum number of Rac open file descriptors, and the processing of hard check failure

2022第六季完美童模 佛山赛区 初赛圆满落幕

Connaissez - vous le protocole TCP (2)?

VMware Workstation related issues

About using font icons in placeholder

Idea related issues

App automated testing appium Tutorial Part 1 - advanced supplementary content

AWS builds a virtual infrastructure including servers and networks (2)
随机推荐
DB
Usage record of Xintang nuc980: self made development board (based on nuc980dk61yc)
NLP sequence can completely simulate human brain intelligence
解决npm ERR! Unexpected end of JSON input while parsing near问题
Image translation /transformer:ittr: unpaired image to image translation with transformers
Redis deployment under Linux & redis startup
Discussion on the application of GIS 3D system in mining industry
探讨gis三维系统在矿山行业中的应用
关于在cmd中MySQL不能插中文数据的原因
【Go ~ 0到1 】 第一天 6月24 变量,条件判断 循环语句
Do you know TCP protocol (2)?
广州:金融新活水 文企新机遇
AI首席架构师8-AICA-高翔 《深入理解和实践飞桨2.0》
块级元素上下左右居中的两个小技巧
WasmEdge 0.10.0 发布!全新的插件扩展机制、Socket API 增强、LLVM 14 支持
A - 深海探险
On the solution of insufficient swap partition
微内核Zephyr获众多厂家支持!
Selenium reptile
The RAC cannot connect to the database normally after modifying the scan IP. The ora-12514 problem is handled