On 07/12/2016 10:28 AM, Nicolas George wrote:
Le quintidi 25 messidor, an CCXXIV, Marton Balint a écrit :
The fifo muxer never returns EAGAIN. It silently drops the packets in
non-blocking mode on a full queue. This behaviour is useful for the tee
muxer case, when you don't want one slow/unreliable (network) output to
block reading the input, therefore blocking fast outputs (disk) as well.
Wait a minute. This is way to specific to be the default behaviour, let
alone the only one.

As far as I know, in the current API, if the user gets a negative return
value from av_write_frame(), it should be handled as a fatal error. EAGAIN
is not handled/interpreted specially. The same is true for
av_write_trailer(), and calling av_write_trailer - regardless of the return
value - frees all private resources for the context as well, so you cannot
change the semantics of av_write_trailer to not free private data in case of
EAGAIN, because it would cause unfreed data for legacy users.
You are wrong. Returning EAGAIN so that the caller try again later is the
normal behaviour for muxers that support non-blocking operation. I grant you
that there are only between one and three of them, but still, that is how
they work.

And that is also how they are supposed to work, because that is how
non-blocking protocols work, and also how non-blocking works outside FFmpeg.
If you take a look at av_write_trailer it really frees all the resources in case of any error. There is also no other way in API to free the resources associated
with AVFormatContext, than through
av_write_trailer.
I was able to find two muxers which support AVFMT_FLAG_NONBLOCK - v4l2enc.c and pulse_audio_enc.c. Neither of these two can return EAGAIN from write_trailer_call.

Write trailer of v4l2enc.c contains simple close() call and always returns 0.

The pulse audio muxer is however similar to FIFO muxer, the mainloop of the pulse audio is being run in separate thread. If you take a look at the write_trailer of pulse audio muxer (also always returns 0):

static av_cold int pulse_write_trailer(AVFormatContext *h)
{
    PulseData *s = h->priv_data;

    if (s->mainloop) {
        ...
        pa_threaded_mainloop_unlock(s->mainloop);
        pa_threaded_mainloop_stop(s->mainloop);
        pa_threaded_mainloop_free(s->mainloop);
        s->mainloop = NULL;
    }

    return 0;
}

pa_threaded_mainloop_stop() contains:

void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) {
    ...

    pa_thread_join(m->thread);
}

So I guess the write_trailer call of pulse audio muxer should be
considered blocking too - even when AVFMT_FLAG_NONBLOCK flag is set.

I guess I could implement non-blocking calls in FIFO muxer:

- block_on_overflow should be renamed to something like drop_packets_on_overflow
  to prevent confusion...
- av_write_trailer would have to be modified not to free resources on AVERROR(EAGAIN) - separate API function for freeing AVOuputContext resources would have to be created,
  let's say av_format_deinit(AVFormatContext *).
- FIFO muxer would behave the same way as currently in case AVFMT_FLAG_NONBLOCK
  would be unset.
- In case AVFMT_FLAG_NONBLOCK would be set:
- write_packet would return AVERROR(EAGAIN) in case the queue is full if drop_packets_on_overflow was not set. If it was, it would drop packet, request queue flushing
      and return 0
- write_trailer would check if the thread is still running. If yes write_trailer request would be send
      (if it was not yet send) and AVERROR(EAGAIN) returned.
- original interrupt callback would be wrapped by custom one which would check terminating condition (flag) of FIFO first and if it would be not set, it would call the original callback. - deinit function would be modified so it would check if the thread is still running, if it was, terminating condition would be set, and pthread_join called, then resources would be freed. This can be also implemented in with use of condition variable which would be set at the moment when the thread is exiting and checked with pthread_cond_wait_timeout before pthread_join. If the time out would be reached, thread would be canceled - but canceling the thread by force can introduce many problems.

I can implement it, but I'm really in doubt if it is worth increased code
complexity and more risky situations which could happen, so I would prefer not to :)

Regards,
Jan
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to