The old version of ffmpeg program, at the beginning of the program, is usually AV_ register_ After all. 4. X, this function is obsolete and does not need to be called. Let's take ffmpeg4.4 as an example. First, let's take a look at the change description of the official version features (doc\APIchanges):
2018-02-06 - 0694d87024 - lavf 58.9.100 - avformat.h Deprecate use of av_register_input_format(), av_register_output_format(), av_register_all(), av_iformat_next(), av_oformat_next(). Add av_demuxer_iterate(), and av_muxer_iterate().
You can see av_register_all has been marked obsolete
So how does the new version of ffmpeg save calling this function
Start with AV_ register_ This function is to register various muxers, demuxers, encoders, decoders, etc., and string various categories into a linked list. For the analysis of this function, please refer to Dr. Lei's chapter: ffmpeg source code simple analysis: av_register_all() .
Let's take multiplexers as an example. In the new version, all multiplexers are organized into a global static array. It is located in libavformat\format.c, as follows:
libavformat\format.c: static const AVOutputFormat * const muxer_list[] = { &ff_a64_muxer, &ff_ac3_muxer, &ff_adts_muxer, &ff_adx_muxer, &ff_aiff_muxer, &ff_alp_muxer, &ff_amr_muxer, ......, }
Some students will find that their source code does not have libavformat\muxer_list.c file. This is because this file is generated according to the actual configuration when the configure command is executed. As follows, this file will be automatically generated after the configure command is executed
configure: # generate the lists of enabled components print_enabled_components(){ file=$1 struct_name=$2 name=$3 shift 3 echo "static const $struct_name * const $name[] = {" > $TMPH for c in $*; do if enabled $c; then case $name in filter_list) eval c=\$full_filter_name_${c%_filter} ;; indev_list) c=${c%_indev}_demuxer ;; outdev_list) c=${c%_outdev}_muxer ;; esac printf " &ff_%s,\n" $c >> $TMPH fi done if [ "$name" = "filter_list" ]; then for c in asrc_abuffer vsrc_buffer asink_abuffer vsink_buffer; do printf " &ff_%s,\n" $c >> $TMPH done fi echo " NULL };" >> $TMPH cp_if_changed $TMPH $file } ...... print_enabled_components libavformat/muxer_list.c AVOutputFormat muxer_list $MUXER_LIST ......
In order to be compatible with the old code, the new version of AV_ register_ The all function remains
libavformat\allformats.c: void av_register_all(void) { ff_thread_once(&av_format_next_init, av_format_init_next); } static void av_format_init_next(void) { ...... for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) { if (prevout) prevout->next = out; prevout = out; } ...... }
As you can see, call av_register_all can connect all multiplexers into a linked list through the next pointer. Is the chain connected with next still useful? Is the next pointer still functional? We don't call av_register_all, which logic will string all multiplexers into a linked list?
To solve these mysteries, we should start with the traversal of the multiplexer. The traversal of the multiplexer in the old version of ffmpeg is through AV_ oformat_ The function of the new version of ffmpeg is also abandoned. AV is used to traverse the multiplexer_ muxer_ iterate.
libavformat\allformats.c: const AVOutputFormat *av_muxer_iterate(void **opaque) { static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1; uintptr_t i = (uintptr_t)*opaque; const AVOutputFormat *f = NULL; if (i < size) { f = muxer_list[i]; } else if (outdev_list) { f = outdev_list[i - size]; } if (f) *opaque = (void*)(i + 1); return f; }
As you can see, av_muxer_iterate traversal does not depend on the next pointer. It is done through the array subscript. We can traverse all multiplexers through the following code
#include <stdio.h> #include "libavformat/avformat.h" int main() { void *ofmt_opaque = NULL; const AVOutputFormat *ofmt = NULL; while ((ofmt = av_muxer_iterate(&ofmt_opaque))) { printf("short name:%-30s long name:%-50s next point:0x%llx \n",ofmt->name,ofmt->long_name,ofmt->next); } }
The output is as follows:
short name:a64 long name:a64 - video for Commodore 64 next point:0x0 short name:ac3 long name:raw AC-3 next point:0x0 short name:adts long name:ADTS AAC (Advanced Audio Coding) next point:0x0 short name:adx long name:CRI ADX next point:0x0 short name:aiff long name:Audio IFF next point:0x0 short name:alp long name:LEGO Racers ALP next point:0x0 short name:amr long name:3GPP AMR next point:0x0 short name:amv long name:AMV next point:0x0 ......
I specially printed the value of the next pointer to show that the traversal does not actually depend on next. Next is a null pointer
There is another question, the old version of the traversal function AV_ oformat_ Can next still be used? The answer is yes. And there is no need to call AV_ register_ It can be used in the case of all
libavformat\allformats.c AVOutputFormat *av_oformat_next(const AVOutputFormat *f) { ff_thread_once(&av_format_next_init, av_format_init_next); if (f) ...... return f->next; ...... else { void *opaque = NULL; return (AVOutputFormat *)av_muxer_iterate(&opaque); } }
You should note that AV_ oformat_ The first line of code of the next function, the first line of code and AV_ register_ The logic of all is the same. That is, if the old traversal method is used, all multiplexers will be concatenated into a linked list through the next pointer again