Coverage Report

Created: 2025-08-11 06:44

/src/mpv/demux/packet_pool.c
Line
Count
Source
1
/*
2
 * This file is part of mpv.
3
 *
4
 * mpv is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * mpv is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
#include "packet_pool.h"
19
20
#include <libavcodec/packet.h>
21
22
#include "config.h"
23
24
#include "common/global.h"
25
#include "osdep/threads.h"
26
#include "packet.h"
27
28
struct demux_packet_pool {
29
    mp_mutex lock;
30
    struct demux_packet *packets;
31
};
32
33
static void uninit(void *p)
34
164k
{
35
164k
    struct demux_packet_pool *pool = p;
36
164k
    demux_packet_pool_clear(pool);
37
164k
    mp_mutex_destroy(&pool->lock);
38
164k
}
39
40
static void free_demux_packets(struct demux_packet *dp)
41
164k
{
42
2.96M
    while (dp) {
43
2.80M
        struct demux_packet *next = dp->next;
44
2.80M
        free_demux_packet(dp);
45
2.80M
        dp = next;
46
2.80M
    }
47
164k
}
48
49
void demux_packet_pool_init(struct mpv_global *global)
50
164k
{
51
164k
    struct demux_packet_pool *pool = talloc(global, struct demux_packet_pool);
52
164k
    talloc_set_destructor(pool, uninit);
53
164k
    mp_mutex_init(&pool->lock);
54
164k
    pool->packets = NULL;
55
56
164k
    mp_assert(!global->packet_pool);
57
164k
    global->packet_pool = pool;
58
164k
}
59
60
struct demux_packet_pool *demux_packet_pool_get(struct mpv_global *global)
61
5.32M
{
62
    // Currently all clients use the same packet pool. There is no additional
63
    // state for each client, may be extended in the future.
64
5.32M
    return global->packet_pool;
65
5.32M
}
66
67
void demux_packet_pool_clear(struct demux_packet_pool *pool)
68
164k
{
69
164k
    mp_mutex_lock(&pool->lock);
70
164k
    struct demux_packet *dp = pool->packets;
71
164k
    pool->packets = NULL;
72
164k
    mp_mutex_unlock(&pool->lock);
73
164k
    free_demux_packets(dp);
74
164k
}
75
76
void demux_packet_pool_push(struct demux_packet_pool *pool,
77
                            struct demux_packet *dp)
78
13.7M
{
79
13.7M
    if (!dp)
80
65.8k
        return;
81
13.6M
    dp->next = NULL;
82
13.6M
    demux_packet_pool_prepend(pool, dp, dp);
83
13.6M
}
84
85
void demux_packet_pool_prepend(struct demux_packet_pool *pool,
86
                               struct demux_packet *head, struct demux_packet *tail)
87
14.0M
{
88
14.0M
    if (!head)
89
397k
        return;
90
13.7M
    mp_assert(tail);
91
13.7M
    mp_assert(head != tail ? !!head->next : !head->next);
92
93
13.7M
    mp_mutex_lock(&pool->lock);
94
13.7M
    tail->next = pool->packets;
95
13.7M
    pool->packets = head;
96
#if HAVE_DISABLE_PACKET_POOL
97
    struct demux_packet *dp = pool->packets;
98
    pool->packets = NULL;
99
#endif
100
13.7M
    mp_mutex_unlock(&pool->lock);
101
102
#if HAVE_DISABLE_PACKET_POOL
103
    free_demux_packets(dp);
104
#endif
105
13.7M
}
106
107
struct demux_packet *demux_packet_pool_pop(struct demux_packet_pool *pool)
108
15.6M
{
109
15.6M
    mp_mutex_lock(&pool->lock);
110
15.6M
    struct demux_packet *dp = pool->packets;
111
15.6M
    if (dp) {
112
12.8M
        pool->packets = dp->next;
113
12.8M
        dp->next = NULL;
114
12.8M
    }
115
15.6M
    mp_mutex_unlock(&pool->lock);
116
117
    // Clear the packet from possible external references. This is done in the
118
    // pop function instead of prepend to distribute the load of clearing packets.
119
    // packet_create() is called at a reasonable rate, so it's fine to clear
120
    // a single packet at a time. This avoids the need to clear potentially
121
    // hundreds of thousands of packets at once when file playback is stopped,
122
    // which would require a significant amount of time to iterate over all packets.
123
15.6M
    if (dp) {
124
12.8M
        if (dp->avpacket)
125
12.8M
            av_packet_unref(dp->avpacket);
126
12.8M
        ta_free_children(dp);
127
12.8M
    }
128
129
15.6M
    return dp;
130
15.6M
}