[FFmpeg-devel] [libavformat/avio.c] how to handle small FLV packets with LIBRTMP integration enabled

Albert Andaluz Gonzalez aandaluz at mediapro.tv
Tue Jun 26 14:34:50 EEST 2018


Hello everyone,
we use ffmpeg libraries to ingest our video streams using the RTMP protocol . So far we use the librtmp backend instead of the built-in implementation  since we  require  Flash url Autentication parameters  (needed for many CDN's ), Until now, we were using ffmpeg 2.7.0 successfully to do this  but as we upgraded to newer master builds (i.e, 387464b) we found that many times av_interleaved_write calls would be stuck when writing small audio or video packets .

Since we could not find a definitive cause for this , we built ffmpeg & librmtp libraries in debug mode to review the call stack. We have discovered that when our program hangs the retry_transfer_wrapper (avio.c) loop never breaks:

https://github.com/FFmpeg/FFmpeg/blob/4ac88ba5487e026bf81da565f97cfcf8f920657d/libavformat/avio.c#L376

while (len < size_min) { 
[...]
ret = transfer_func(h, buf + len, size - len);
[...]

 else if (ret == AVERROR_EOF)
            return (len > 0) ? len : AVERROR_EOF;
        else if (ret < 0)
            return ret;
 [...]
len += ret; //loop counter
}
Further debugging showed us that transfer_func actually calls RTMP_Write  from Librtmp (rtmp.c. 
https://git.ffmpeg.org/gitweb/rtmpdump.git/blob_plain/HEAD:/librtmp/rtmp.c)
 This callback returns 0 when packet size is less than 11 bytes (size-len) 
[...]
    if (size < 11) {
      /* FLV pkt too small */
      return 0;
    }
[...]

So, if transfer_func = 0, there is no way to break the loop since this special case is not handled (ret ==0).

We reviewed history for avio.c and we found that in commit 858db4b01fa2b55ee55056c033054ca54ac9b0fd  , the error handling mechanism was changed so that  0 was no longer threated as an EOF:
https://github.com/FFmpeg/FFmpeg/commit/858db4b01fa2b55ee55056c033054ca54ac9b0fd

 According to commit message, "...In case of returning >= 0, url_read/url_write is retried until error is returned.". Ever since then, the code in master does not seem to handle "LIBRTMP: FLV special case for  packet too small (code =0)". Previously, in  ffmpeg 2.7.0,)  an error code 0 would return len (0) and break the loop:
https://github.com/FFmpeg/FFmpeg/blob/6e94e77632df457da03b5c27fff8a1b976f6994d/libavformat/avio.c#L324


We where thinking about adding a custom handler for ret =0 in avio.c to handle this case.
[.]
} else if (ret == AVERROR_EOF)
            return (len > 0) ? len : AVERROR_EOF;
        else if (ret < 0)
            return ret;
        else if (ret == 0) ///handle "LIBRTMP FLV packet too small code" here
            return len;
        if (ret) {
            fast_retries = FFMAX(fast_retries, 2);
            wait_since = 0;
        }

However, we don't want to formally submit  this patch right now, since  we don't know how this could impact other protocols and parts of ffmpeg. Moreover, commit 858db4b also modified aviobuf.c cache.c  , so we would prefer to discuss with the ffmpeg community  if this is a valid approach.


Regards,
Albert Andaluz
Research Engineer


MEDIAPRO
Av. Diagonal 177, Planta 14
08018 Barcelona - Spain
Landline: +34 93 476 1551 (ext. 2327)
aandaluz (at) mediapro.tv
www.automatic.tv





More information about the ffmpeg-devel mailing list