[FFmpeg-devel] [PATCH] avformat/mpegts: use a buffer pool for PES payloads

Marton Balint cus at passwd.hu
Thu Apr 2 22:54:34 EEST 2020



On Thu, 2 Apr 2020, James Almer wrote:

> On 4/2/2020 3:49 PM, Marton Balint wrote:
>> 
>> 
>> On Thu, 2 Apr 2020, James Almer wrote:
>> 
>>> On 4/2/2020 3:27 PM, Marton Balint wrote:
>>>>
>>>>
>>>> On Thu, 2 Apr 2020, Marton Balint wrote:
>>>>
>>>>>
>>>>>
>>>>> On Thu, 2 Apr 2020, James Almer wrote:
>>>>>
>>>>>> On 3/29/2020 6:07 PM, James Almer wrote:
>>>>>>> This produces a small speed up in demuxing
>>>>>>>
>>>>>>> Signed-off-by: James Almer <jamrial at gmail.com>
>>>>>>> ---
>>>>>>>  libavformat/mpegts.c | 20 ++++++++++++++++----
>>>>>>>  1 file changed, 16 insertions(+), 4 deletions(-)
>>>>>>>
>>>>>>> diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
>>>>>>> index 7f56bacb2c..7746a524c4 100644
>>>>>>> --- a/libavformat/mpegts.c
>>>>>>> +++ b/libavformat/mpegts.c
>>>>>>> @@ -157,6 +157,8 @@ struct MpegTSContext {
>>>>>>>      int resync_size;
>>>>>>>      int merge_pmt_versions;
>>>>>>>
>>>>>>> +    AVBufferPool *pool;
>>>>>>> +
>>>>>>>      /******************************************/
>>>>>>>      /* private mpegts data */
>>>>>>>      /* scan context */
>>>>>>> @@ -1177,8 +1179,7 @@ static int mpegts_push_data(MpegTSFilter
>>>>>>> *filter,
>>>>>>>                          pes->total_size = MAX_PES_PAYLOAD;
>>>>>>>
>>>>>>>                      /* allocate pes buffer */
>>>>>>> -                    pes->buffer = av_buffer_alloc(pes->total_size +
>>>>>>> - 
>>>>> AV_INPUT_BUFFER_PADDING_SIZE);
>>>>>>> +                    pes->buffer = av_buffer_pool_get(ts->pool);
>>>>>>>                      if (!pes->buffer)
>>>>>>>                          return AVERROR(ENOMEM);
>>>>>>>
>>>>>>> @@ -1351,8 +1352,7 @@ skip:
>>>>>>>                      if (ret < 0)
>>>>>>>                          return ret;
>>>>>>>                      pes->total_size = MAX_PES_PAYLOAD;
>>>>>>> -                    pes->buffer = av_buffer_alloc(pes->total_size +
>>>>>>> - 
>>>>> AV_INPUT_BUFFER_PADDING_SIZE);
>>>>>>> +                    pes->buffer = av_buffer_pool_get(ts->pool);
>>>>>>>                      if (!pes->buffer)
>>>>>>>                          return AVERROR(ENOMEM);
>>>>>>>                      ts->stop_parse = 1;
>>>>>>> @@ -3032,6 +3032,10 @@ static int mpegts_read_header(AVFormatContext
>>>>>>> *s)
>>>>>>>      ts->stream     = s;
>>>>>>>      ts->auto_guess = 0;
>>>>>>>
>>>>>>> +    ts->pool = av_buffer_pool_init(MAX_PES_PAYLOAD + 
>>>>> AV_INPUT_BUFFER_PADDING_SIZE, NULL);
>>>>>>> +    if (!ts->pool)
>>>>>>> +        return AVERROR(ENOMEM);
>>>>>>> +
>>>>>>>      if (s->iformat == &ff_mpegts_demuxer) {
>>>>>>>          /* normal demux */
>>>>>>>
>>>>>>> @@ -3200,6 +3204,8 @@ static void mpegts_free(MpegTSContext *ts)
>>>>>>>
>>>>>>>      clear_programs(ts);
>>>>>>>
>>>>>>> +    av_buffer_pool_uninit(&ts->pool);
>>>>>>> +
>>>>>>>      for (i = 0; i < NB_PID_MAX; i++)
>>>>>>>          if (ts->pids[i])
>>>>>>>              mpegts_close_filter(ts, ts->pids[i]);
>>>>>>> @@ -3295,6 +3301,12 @@ MpegTSContext 
>>>>> *avpriv_mpegts_parse_open(AVFormatContext *s)
>>>>>>>      ts->stream = s;
>>>>>>>      ts->auto_guess = 1;
>>>>>>>
>>>>>>> +    ts->pool = av_buffer_pool_init(MAX_PES_PAYLOAD + 
>>>>> AV_INPUT_BUFFER_PADDING_SIZE, NULL);
>>>>>>> +    if (!ts->pool) {
>>>>>>> +        av_free(ts);
>>>>>>> +        return NULL;
>>>>>>> +    }
>>>>>>> +
>>>>>>>      mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
>>>>>>>      mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
>>>>>>>      mpegts_open_section_filter(ts, EIT_PID, eit_cb, ts, 1);
>>>>>>
>>>>>> Will apply soon if no one objects.
>>>>>
>>>>> LGTM.
>>>>
>>>> On second thought aint this going to waste too much memory on small
>>>> packets? If packets are queued somewhere it can make a huge difference
>>>> if every buffer is 200kb...
>>>>
>>>> Does the speedup goes away if only unbound packets make use of the
>>>> buffer pool?
>>>>
>>>> Thanks,
>>>> Marton
>>>
>>> I tried these two LG 4k HDR sample videos, and the pool was never bigger
>>> than 3 to 5 buffers for the entire demuxing process.
>> 
>> That is the case if there is no packet buffering, like in ffmpeg using a
>> single input. But in ffplay or a lot of other apps packets are
>> pre-buffered to remove the latency of the source media. An app could
>> have assumed that if it buffers 1 MB of packets it will not consume a
>> lot more than 1 MB of memory.
>> 
>>>
>>> I'll bench again with your suggestion, but i don't think it will be a
>>> problem even as is.
>> 
>> Maybe we should create log2(MAX_PACKET_SIZE) number of buffer pools
>> instead? In that case the memory wasted is at most 100%... Still not
>> very good, but a lot more acceptable.
>
> I don't think that's possible, or worth trying. There's currently no way
> to query the amount of buffers in a given pool, and definitely no way to
> know what buffers will be returned to a pool once all their references
> are freed, other than keeping track of them within the muxer.

I meant something like this:

required_size = pes->total_size + AV_INPUT_BUFFER_PADDING;
index = av_log2(requred_size);
if (!ts->pools[index]) {
    pool_size = FFMIN(MAX_PES_PAYLOAD + AV_INPUT_BUFFER_PADDING, 2 << index);
    ts->pools[index] = av_buffer_pool_init(pool_size);
}
pes->buffer = av_buffer_pool_get(ts->pool[index]);


>
> I'll try limiting the usage of the pool to unbound packets only, but i
> suspect it will not make much of a difference compared to no pool usage
> at all.

Yeah, I expect this outcome as well.

Regards,
Marton


More information about the ffmpeg-devel mailing list