/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 | } |