Let's take a look at the main function first: (omitted a lot of irrelevant code)
Int main (INT argc, char ** argv) <br/>{< br/> optionscontext o = {0}; <br/> int64_t Ti; </P> <p> // initialization of the structure related to the command line analysis. The reset_options (& O, 0 ); </P> <p> // set the log level <br/> av_log_set_flags (av_log_skip_repeated); <br/> parse_loglevel (argc, argv, options ); </P> <p> If (argc> 1 &&! Strcmp (argv [1], "-d") {<br/> run_as_daemon = 1; <br/> av_log_set_callback (log_callback_null); <br/> argc --; <br/> argv ++; <br/>}</P> <p> // register components <br/> avcodec_register_all (); <br/> # If config_avdevice <br/> avdevice_register_all (); <br/> # endif <br/> # If config_avfilter <br/> avfilter_register_all (); <br/> # endif <br/> av_register_all (); <br/> // initialize the network. For Windows, <br/> avformat_network_init (); </P> <p> show_banner (); </P> <p> term_init (); </P> <p> // analyze the parameters input by the command line <br/> parse_options (& O, argc, argv, options, opt_output_file ); </P> <p> // file conversion occurs in this function <br/> If (transcode (output_files, nb_output_files, input_files, nb_input_files) <0) <br/> exit_program (1); </P> <p> exit_program (0); <br/> return 0; <br/>}< br/>
The following is the transcode () function, and the conversion occurs in it. No nonsense. Let's take a look at the annotations. It should be very detailed.
Static int transcode (<br/> outputfile * output_files, // array of output files <br/> int nb_output_files, // number of output files <br/> inputfile * input_files, // input file array <br/> int nb_input_files) // number of input files <br/> {<br/> int ret, I; <br/> avformatcontext * Is, * OS; <br/> outputstream * ost; <br/> inputstream * IST; <br/> uint8_t * no_packet; <br/> int no_packet_count = 0; <br/> int64_t timer_start; <br/> int key; </P> <p> If (! (No_packet = av_mallocz (nb_input_files) <br/> exit_program (1); </P> <p> // sets encoding parameters to enable encoder of all output streams, open the decoder of all input streams and write the file header of all output files, so you have prepared <br/> ret = transcode_init (output_files, nb_output_files, input_files, nb_input_files ); <br/> If (Ret <0) <br/> goto fail; </P> <p> If (! Using_stdin) {<br/> av_log (null, av_log_info, "press [Q] to stop, [?] For Help \ n "); <br/>}</P> <p> timer_start = av_gettime (); </P> <p> // loop, exit after receiving the system signal <br/> for (; received_sigterm = 0;) <br/>{< br/> int file_index, ist_index; <br/> avpacket Pkt; <br/> int64_t ipts_min; <br/> double opts_min; <br/> int64_t cur_time = av_gettime (); </P> <p> ipts_min = int64_max; <br/> opts_min = 1e100; <br/>/* If 'q' pressed, exits */<br/> If (! Using_stdin) <br/>{< br/> // first, check the key that the user pressed and respond accordingly to the data key. <br/> static int64_t last_time; <br/> If (received_nb_signals) <br/> break; <br/>/* read_key () returns 0 on EOF */<br/> If (cur_time-last_time >=100000 &&! Run_as_daemon) {<br/> key = read_key (); <br/> last_time = cur_time; <br/>} else {<br/> ............................. .... <br/>}</P> <p>/* select the stream that we must read now by looking at the <br/> smallest output PTS */<br/>/ /The purpose of the following loop is to find the smallest output PTS (that is, the closest to the current one) <br/> file_index =-1; <br/> for (I = 0; I <nb_output_streams; I ++) {<br/> outputfile *; <br/> int64_t IPTS; <br/> double opts; <br/> Ost = & Output_streams [I]; // loop every output stream <br/> of = & output_files [Ost-> file_index]; // output file corresponding to the output stream <br/> OS = output_files [Ost-> file_index]. CTX; // formatcontext of the output stream <br/> ist = & input_streams [Ost-> source_index]; // input stream corresponding to the output stream </P> <p> If (Ost-> is_past_recording_time | // has the recording time passed? (You may have specified a recording time period) <br/> no_packet [ist-> file_index] | // No data in the corresponding input stream during this time period? <Br/> (OS-> Pb & avio_tell (OS-> Pb)> = of-> limit_filesize) // determines whether the recording range is exceeded (also specified by the user) <br/> continue; // Yes, match one of the preceding statements, then let's look at the next output stream. </P> <p> // determine whether the file of the current input stream can be used (I don't know) <br/> opts = Ost-> St-> PTS. val * av_q2d (Ost-> St-> time_base); <br/> IPTS = ist-> PTS; <br/> If (! Input_files [ist-> file_index]. eof_reached) {<br/> If (IPTS <ipts_min) {<br/> // record every time a smaller input stream of PTS is found, in this way, the minimum input stream <br/> // PTS and the serial number of the input file are found after all the output streams are cyclically. <br/> ipts_min = IPTS; <br/> If (input_sync) <br/> file_index = ist-> file_index; <br/>}< br/> If (OPTs <opts_min) {<br/> opts_min = opts; <br/> If (! Input_sync) <br/> file_index = ist-> file_index; <br/>}</P> <p> // does the following sentence mean: if the current output stream has received the number of frames, when the number of output frames specified by the user is exceeded, <br/> // all output streams corresponding to the output file of the current output stream are counted as exceeding the video recording time? <Br/> If (Ost-> frame_number> = Ost-> max_frames) {<br/> Int J; <br/> for (j = 0; j <of-> CTX-> nb_streams; j ++) <br/> output_streams [of-> ost_index + J]. is_past_recording_time = 1; <br/> continue; <br/>}< br/>/* If none, if is finished */<br/> If (file_index <0) {<br/> // if no suitable input file is found <br/> If (no_packet_count) {<br/> // if data is temporarily unavailable to some input files, it is still not an end <br/> no_packet_count = 0; <br/> memset (no_packet, 0, nb _ Input_files); <br/> usleep (10000); <br/> continue; <br/>}< br/> // The conversion is complete, jump out of the big loop <br/> break; <br/>}</P> <p> // read a frame from the found input file (either audio or video ), and put it in the FIFO queue <br/> is = input_files [file_index]. CTX; <br/> ret = av_read_frame (is, & Pkt); <br/> If (ret = averror (eagain )) {<br/> // when no data is available for the moment <br/> no_packet [file_index] = 1; <br/> no_packet_count ++; <br/> continue; <br/>}</P> <p> // the following code checks whether an input file exists. <br/> If (Ret <0) {<br/> in Put_files [file_index]. eof_reached = 1; <br/> If (opt_shortest) <br/> break; <br/> else <br/> continue; <br/>}</P> <p> no_packet_count = 0; <br/> memset (no_packet, 0, nb_input_files); </P> <p> If (do_pkt_dump) {<br/> av_pkt_dump_log2 (null, av_log_debug, & Pkt, do_hex_dump, <br/> is-> streams [Pkt. stream_index]); <br/>}< br/>/* the following test is needed in case new streams appear <br/> dynamically in Stream: W E ignore them */<br/> // If a stream suddenly pops up in the input file, we will not bird it <br/> If (Pkt. stream_index> = input_files [file_index]. nb_streams) <br/> goto discard_packet; </P> <p> // gets the input stream corresponding to the currently obtained frame <br/> ist_index = input_files [file_index]. ist_index + Pkt. stream_index; <br/> ist = & input_streams [ist_index]; <br/> If (IST-> discard) <br/> goto discard_packet; </P> <p> // repeat the frame timestamp <br/> If (Pkt. DTS! = Av_nopts_value) <br/> Pkt. DTS + = av_rescale_q (input_files [ist-> file_index]. ts_offset, <br/> av_time_base_q, ist-> St-> time_base); <br/> If (Pkt. PTS! = Av_nopts_value) <br/> Pkt. PTS + = av_rescale_q (input_files [ist-> file_index]. ts_offset, <br/> av_time_base_q, ist-> St-> time_base); </P> <p> If (Pkt. PTS! = Av_nopts_value) <br/> Pkt. PTs * = ist-> ts_scale; <br/> If (Pkt. DTS! = Av_nopts_value) <br/> Pkt. DTS * = ist-> ts_scale; </P> <p> If (Pkt. DTS! = Av_nopts_value & ist-> next_pts! = Av_nopts_value <br/> & (is-> iformat-> flags & avfmt_ts_discont) <br/>{< br/> int64_t pkt_dts = av_rescale_q (Pkt. DTS, ist-> St-> time_base, <br/> av_time_base_q); <br/> int64_t Delta = pkt_dts-ist-> next_pts; <br/> If (delta <-1ll * dts_delta_threshold * av_time_base <br/> | (delta> 1ll * dts_delta_threshold * av_time_base <br/> & ist-> st-> codec-> codec_type <br/>! = Avmedia_type_subtitle) <br/> | pkt_dts + 1 <ist-> PTS )&&! Copy_ts) <br/>{< br/> input_files [ist-> file_index]. ts_offset-= delta; <br/> av_log (null, av_log_debug, <br/> "timestamp discontinuity %" prid64 ", new offset = %" prid64 "\ n ", <br/> delta, input_files [ist-> file_index]. ts_offset); <br/> Pkt. DTS-= av_rescale_q (delta, av_time_base_q, ist-> St-> time_base); <br/> If (Pkt. PTS! = Av_nopts_value) <br/> Pkt. PTS-= av_rescale_q (delta, av_time_base_q, ist-> St-> time_base ); <br/>}</P> <p> // converts the frame and writes it to the output file. <br/> If (output_packet (IST, output_streams, nb_output_streams, & Pkt) <0) {<br/> av_log (null, av_log_error, <br/> "error while decoding stream # % d: % d \ n ", <br/> ist-> file_index, ist-> St-> index); <br/> If (exit_on_error) <br/> exit_program (1 ); <br/> av_free_packet (& Pkt); <br/> cont Inue; <br/>}</P> <p> discard_packet: <br/> av_free_packet (& Pkt ); </P> <p>/* dump report by using the output first video and audio streams */<br/> print_report (output_files, output_streams, nb_output_streams, 0, <br/> timer_start, cur_time); <br/>}</P> <p> // the file has been processed, write the remaining data in the buffer to the output file <br/> for (I = 0; I <nb_input_streams; I ++) {<br/> ist = & input_streams [I]; <br/> If (IST-> decoding_needed) {<br/> output_packet (IST, output_streams, nb_output_streams, null); <br/>}< br/> flush_encoders (output_streams, nb_output_streams ); </P> <p> term_exit (); </P> <p> // write the end of the output file (some do not need it ). <br/> for (I = 0; I <nb_output_files; I ++) {<br/> OS = output_files [I]. CTX; <br/> av_write_trailer (OS ); <br/>}</P> <p>/* dump report by using the first video and audio streams */<br/> print_report (output_files, output_streams, nb_output_stre AMS, 1, <br/> timer_start, av_gettime (); </P> <p> // disable all encoders <br/> for (I = 0; I <nb_output_streams; I ++) {<br/> Ost = & output_streams [I]; <br/> If (Ost-> encoding_needed) {<br/> av_freep (& Ost-> St-> codec-> stats_in); <br/> avcodec_close (Ost-> St-> codec ); <br/>}< br/> # If config_avfilter <br/> avfilter_graph_free (& Ost-> graph ); <br/> # endif <br/>}</P> <p> // disable all decoders <br/> for (I = 0; I <nb_input_streams; I ++) {<br /> Ist = & input_streams [I]; <br/> If (IST-> decoding_needed) {<br/> avcodec_close (IST-> St-> codec ); <br/>}</P> <p>/* finished! */<Br/> ret = 0; </P> <p> fail: av_freep (& bit_buffer); <br/> av_freep (& no_packet ); </P> <p> If (output_streams) {<br/> for (I = 0; I <nb_output_streams; I ++) {<br/> Ost = & output_streams [I]; <br/> If (OST) {<br/> If (Ost-> stream_copy) <br/> av_freep (& Ost-> St-> codec-> extradata); <br/> If (Ost-> logfile) {<br/> fclose (Ost-> logfile); <br/> Ost-> logfile = NULL; <br/>}< br/> av_1_o_free (Ost-> FIFO ); /* works even if FIFO is not <br/> initialized but set to zero */<br/> av_freep (& Ost-> St-> codec-> subtitle_header ); <br/> av_free (Ost-> resample_frame.data [0]); <br/> av_free (Ost-> forced_kf_pts); <br/> If (Ost-> video_resample) <br/> sws_freecontext (Ost-> img_resample_ctx); <br/> swr_free (& Ost-> SWR); <br/> av_dict_free (& Ost-> opts ); <br/>}< br/> return ret; <br/>}< br/>