[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