FFmpeg converter transcoding end analysis

ffmpeg.exe The converter will end transcoding or encapsulation in the following three situations.

1, read to the end of the input file.

2.-t 60  The option is  used on the input file on the command line  , and only 60 seconds of input files are read for processing, and it will exit after processing 60 seconds of data.

3.-t 60  The option is  used for the output file on the command line  , and only 60 seconds of data is output to the file for saving. Once the storage is enough for 60 seconds, it will automatically exit.

The first case is the most common, the second and third cases are  trim achieved through filters.

This article mainly analyzes the logic of the first case , and readers are invited to explore the second and third cases by themselves.

The following API functions will use an error code of AVERROR_EOF to represent the end of the operation.

1, av_read_frame() , AVERROR_EOF means that the end of the input file has been read.

2, avcodec_send_packet() , it is also possible to return AVERROR_EOF when sending to the decoder  , usually because you have sent  ==   or   == 0 AVPacket to this decoder before  .  The second time you send a null or size equal to 0  to the decoder  ,  the function will return AVERROR_EOFpktnullpkt.sizeAVPacketAVPacketavcodec_send_packet()

3, avcodec_receive_frame() , reading from the decoder  AVFrame may also return AVERROR_EOF, but the premise is that you have sent  pkt ==  null or  pkt.size == 0 to this decoder before. After sending this null  AVPacket , keep reading the decoder until there is no data, it will return AVERROR_EOF.

avcodec_receive_frame() The function actually has two error codes, one is  ERROR(EAGAIN)and the other is  AVERROR_EOF,
ERROR(EAGAIN)which means that the decoder has no data to read temporarily, and you need to input more  AVPacket.
AVERROR_EOF, which means that the decoder has finished decoding, and there is no more  AVPacket input.


4,  ,  reading  av_buffersink_get_frame_flags()from  the exit filter  may also return  , but the premise is that   all  the entrance filters have been closed .buffersinkAVFrameAVERROR_EOFav_buffersrc_close()

5, avfilter_graph_request_oldest() , this function is to return how much of the filter container  AVFrame has not been read, and it may return  AVERROR_EOF, provided that  av_buffersrc_close() all  the entry filters have been closed , or the trim filter is used, it will automatically return at the time point  AVERROR_EOF

6.avcodec_receive_packet() Reading from the encoder  AVPacket may also return AVERROR_EOF, provided that you have sent null to this encoder before  AVFrame.

Let's take a look at  ffmpeg.exe how the converter uses the AVERROR_EOF return value of the above API functions.

The first is that  av_read_frame() the function returns AVERROR_EOF, which branch logic will be executed? as follows:

av_read_frame() Functions are encapsulated  get_input_packet() within functions.

It may be seen that after reading to the end of the file, it will cause  process_input_packet() the function to pass in one  NULL by  one AVPacket .

Note: All input streams of the input file will be passed in one  NULL by  one AVPacket . As mentioned in

" decode_video decoding video frame ", the NULL will be  converted  process_input_packet() to size = 0 AVPacketdecode_video()

size = 0 will  AVPacket cause the decoder to start flushing, as follows:
 

Also pay attention to the above  avcodec_send_packet() return value, although it will return  AVERROR_EOF, but  ffmpeg.c it does not handle this state, as follows:

//如果是 AVERROR_EOF 直接跳过。
if (ret < 0 && ret != AVERROR_EOF)
    return ret;

When  decode() the function returns  AVERROR_EOF , what behavior will it lead to? as follows:

Because  decode() it is a public function, it is   wrapped with the root, so  decode_video() the   return value of   the root  will bedecode_audio()decode_video()decode_audio()AVERROR_EOF

 What happens if  decode_video() the function returns  ? AVERROR_EOFas follows:

It can be seen that it will lead  eof_reached to 1, and by the way break jumps out of  while (ist->decoding_needed){...} the decoding loop.

Then it will cause the calling  send_filter_eof() function to close all the entry filters bound to the stream, as follows:

This will then result in  process_input_packet() a return of 0, as follows:

But  process_input_packet() the return value of this, I personally think it is useless at all, even if it returns 1 in several places, it will turn into 0.

Although  process_input_packet() the return value of is useless, when it passes NULL, after execution, everything in the decoder  AVFrame has been spit out and sent to the filter for processing.

And it will be  ifile->eof_reached set to 1, as follows:

Therefore, the end process of the entire decoder is to return EOF , av_read_frame() causing the decoder to spit out all the files  AVFrame, and after passing all the  AVFrame events to the filter, then close the entry filter, and then  ifile->eof_reached set it to 1, which means that the input file has been processed .

The whole process is as follows:
 

There is another important point in the above picture, that is, when  ifile->eof_reached it is set to 1, it will return immediately  AVERROR(EAGAIN).
When  process_input() the function returns  AVERROR(EAGAIN), this will result in  transcode_step() a non-execution

reap_filters() , returns 0 directly. as follows:
 

 Set to 1  when the input stream has been processed, the decoder has spit it out  AVFrame, and the ingress filter has  been disabled.ifile->eof_reachedsend_filter_eof()

Once the entrance filter is closed, av_buffersink_get_frame_flags() or  avfilter_graph_request_oldest() there is a chance to return  AVERROR_EOF.

First look at  av_buffersink_get_frame_flags() the behavior of the function returning AVERROR_EOF, as follows:

av_buffersink_get_frame_flags() is encapsulated  reap_filters() inside.

 

It can be seen  av_buffersink_get_frame_flags() that the function returning AVERROR_EOF will cause  do_video_out() NULL to be passed, but after actual debugging, it is found that this NULL will cause the encoder to be flushed, and it will not cause NULL to be passed  AVPacket to the encoder

Pass NULL  AVPacket to refresh the encoder, which will  flush_encoders() be done in the function.

Therefore,  we don't need to pay attention toav_buffersink_get_frame_flags()  the behavior of the function returning AVERROR_EOF .

Supplement: do_video_out(of, ost, NULL); It is not used to refresh the encoder, it should be used to refresh the remaining frames of the frame rate change , as follows:

//next_picture 等于 NULL
if (!next_picture) {
    //end, flushing
    nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],
                                        ost->last_nb0_frames[1],
                                        ost->last_nb0_frames[2]);
}

avfilter_graph_request_oldest()AVERROR_EOF However, special attention should be paid to the case of  function return  .
Because the entry filter was closed before, when the container has no data to read,  avfilter_graph_request_oldest() it will return

AVERROR_EOF,as follows:
 

avfilter_graph_request_oldest() returns  AVERROR_EOF, resulting in two behaviors.

1, reap_filter(1) , the parameter is 1, so  the remaining frames of the frame rate change will be flushed , but the encoder will not be flushed.

2,close_output_stream(graph->outputs[i]->ost) , set  finished the state of the output stream.

ost->finished |= ENCODER_FINISHED;

This  finished state is particularly important.

In the previous flowchart, you can see that ffmpeg.exe it will be executed in a loop  transcode_step() , as follows:

ffmpeg.exe Under what circumstances will the converter jump out of the above  while cycle?

Answer: It is  finished judged by the state of the output stream, as follows:

At this point, the end processing logic of ffmpeg.exe has gone 80%, and has jumped out of  while (!received_sigterm) the loop.

However, the encoder has not been flushed at this time,  do_video_out(of, ost, NULL); and the encoder has not been flushed at this time.

The flushing of the encoder is  while (!received_sigterm) operated after jumping out of the loop , as follows:
 

flush_encoder() The function is not too complicated, so I won't explain it.

At the end, there is still an  av_write_trailer() operation to write the tail information of the file, as follows:

There are also some operations to release various resources that will not be explained.

ffmpeg.exe The conversion of the converter is completed and the analysis is completed.

Analysis of the end of transcoding of the original  FFmpeg converter - Nuggets

★The business card at the end of the article can receive audio and video development learning materials for free, including (FFmpeg, webRTC, rtmp, hls, rtsp, ffplay, srs) and audio and video learning roadmaps, etc.

see below!

Guess you like

Origin blog.csdn.net/yinshipin007/article/details/132214795