1 /**
2 * Packet management
3 * Copyright (C) 2008 Andreas Öman
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #include "tvheadend.h"
21 #include "packet.h"
22 #include "string.h"
23 #include "atomic.h"
24 #include "memoryinfo.h"
25
26 #ifndef PKTBUF_DATA_ALIGN
27 #define PKTBUF_DATA_ALIGN 64
28 #endif
29
30 memoryinfo_t pkt_memoryinfo = { .my_name = "Packets" };
31 memoryinfo_t pktbuf_memoryinfo = { .my_name = "Packet buffers" };
32 memoryinfo_t pktref_memoryinfo = { .my_name = "Packet references" };
33
34 /*
35 *
36 */
37 static void
pkt_destroy(th_pkt_t * pkt)38 pkt_destroy(th_pkt_t *pkt)
39 {
40 if (pkt) {
41 pktbuf_ref_dec(pkt->pkt_payload);
42 pktbuf_ref_dec(pkt->pkt_meta);
43
44 free(pkt);
45 memoryinfo_free(&pkt_memoryinfo, sizeof(*pkt));
46 }
47 }
48
49
50 /**
51 * Allocate a new packet and give it a refcount of one (which caller is
52 * suppoed to take care of)
53 */
54 th_pkt_t *
pkt_alloc(streaming_component_type_t type,const void * data,size_t datalen,int64_t pts,int64_t dts)55 pkt_alloc(streaming_component_type_t type, const void *data, size_t datalen,
56 int64_t pts, int64_t dts)
57 {
58 th_pkt_t *pkt;
59
60 pkt = calloc(1, sizeof(th_pkt_t));
61 if (pkt) {
62 pkt->pkt_type = type;
63 if(datalen)
64 pkt->pkt_payload = pktbuf_alloc(data, datalen);
65 pkt->pkt_dts = dts;
66 pkt->pkt_pts = pts;
67 pkt->pkt_refcount = 1;
68 memoryinfo_alloc(&pkt_memoryinfo, sizeof(*pkt));
69 }
70 return pkt;
71 }
72
73
74 /**
75 *
76 */
77 th_pkt_t *
pkt_copy_shallow(th_pkt_t * pkt)78 pkt_copy_shallow(th_pkt_t *pkt)
79 {
80 th_pkt_t *n = malloc(sizeof(th_pkt_t));
81
82 if (n) {
83 *n = *pkt;
84
85 n->pkt_refcount = 1;
86
87 pktbuf_ref_inc(n->pkt_meta);
88 pktbuf_ref_inc(n->pkt_payload);
89
90 memoryinfo_alloc(&pkt_memoryinfo, sizeof(*pkt));
91 }
92
93 return n;
94 }
95
96
97 /**
98 *
99 */
100 th_pkt_t *
pkt_copy_nodata(th_pkt_t * pkt)101 pkt_copy_nodata(th_pkt_t *pkt)
102 {
103 th_pkt_t *n = malloc(sizeof(th_pkt_t));
104
105 if (n) {
106 *n = *pkt;
107
108 n->pkt_refcount = 1;
109
110 n->pkt_meta = n->pkt_payload = NULL;
111
112 memoryinfo_alloc(&pkt_memoryinfo, sizeof(*pkt));
113 }
114
115 return n;
116 }
117
118
119 /**
120 *
121 */
122 void
pkt_ref_dec(th_pkt_t * pkt)123 pkt_ref_dec(th_pkt_t *pkt)
124 {
125 if((atomic_add(&pkt->pkt_refcount, -1)) == 1)
126 pkt_destroy(pkt);
127 }
128
129
130 /**
131 *
132 */
133 void
pkt_ref_inc(th_pkt_t * pkt)134 pkt_ref_inc(th_pkt_t *pkt)
135 {
136 atomic_add(&pkt->pkt_refcount, 1);
137 }
138
139 /**
140 *
141 */
142 void
pkt_ref_inc_poly(th_pkt_t * pkt,int n)143 pkt_ref_inc_poly(th_pkt_t *pkt, int n)
144 {
145 atomic_add(&pkt->pkt_refcount, n);
146 }
147
148 /**
149 *
150 */
151 void
pkt_trace_(const char * file,int line,int subsys,th_pkt_t * pkt,const char * fmt,...)152 pkt_trace_(const char *file, int line, int subsys, th_pkt_t *pkt,
153 const char *fmt, ...)
154 {
155 char buf[512], _dts[22], _pts[22], _type[2];
156 va_list args;
157
158 va_start(args, fmt);
159 if (SCT_ISVIDEO(pkt->pkt_type) && pkt->v.pkt_frametype) {
160 _type[0] = pkt_frametype_to_char(pkt->v.pkt_frametype);
161 _type[1] = '\0';
162 } else {
163 _type[0] = '\0';
164 }
165 snprintf(buf, sizeof(buf),
166 "%s%spkt stream %d %s%s%s"
167 " dts %s pts %s"
168 " dur %d len %zu err %i%s",
169 fmt ? fmt : "",
170 fmt ? " (" : "",
171 pkt->pkt_componentindex,
172 streaming_component_type2txt(pkt->pkt_type),
173 _type[0] ? " type " : "", _type,
174 pts_to_string(pkt->pkt_dts, _dts),
175 pts_to_string(pkt->pkt_pts, _pts),
176 pkt->pkt_duration,
177 pktbuf_len(pkt->pkt_payload),
178 pkt->pkt_err,
179 fmt ? ")" : "");
180 tvhlogv(file, line, LOG_TRACE, subsys, buf, &args);
181 va_end(args);
182 }
183
184 /**
185 *
186 */
187 void
pktref_clear_queue(struct th_pktref_queue * q)188 pktref_clear_queue(struct th_pktref_queue *q)
189 {
190 th_pktref_t *pr;
191
192 if (q) {
193 while((pr = TAILQ_FIRST(q)) != NULL) {
194 TAILQ_REMOVE(q, pr, pr_link);
195 pkt_ref_dec(pr->pr_pkt);
196 free(pr);
197 memoryinfo_free(&pktref_memoryinfo, sizeof(*pr));
198 }
199 }
200 }
201
202
203 /**
204 * Reference count is transfered to queue
205 */
206 void
pktref_enqueue(struct th_pktref_queue * q,th_pkt_t * pkt)207 pktref_enqueue(struct th_pktref_queue *q, th_pkt_t *pkt)
208 {
209 th_pktref_t *pr = malloc(sizeof(th_pktref_t));
210 if (pr) {
211 pr->pr_pkt = pkt;
212 TAILQ_INSERT_TAIL(q, pr, pr_link);
213 memoryinfo_alloc(&pktref_memoryinfo, sizeof(*pr));
214 }
215 }
216
217
218 /**
219 *
220 */
221 void
pktref_remove(struct th_pktref_queue * q,th_pktref_t * pr)222 pktref_remove(struct th_pktref_queue *q, th_pktref_t *pr)
223 {
224 if (pr) {
225 if (q)
226 TAILQ_REMOVE(q, pr, pr_link);
227 pkt_ref_dec(pr->pr_pkt);
228 free(pr);
229 memoryinfo_free(&pktref_memoryinfo, sizeof(*pr));
230 }
231 }
232
233 /**
234 *
235 */
236 th_pkt_t *
pktref_get_first(struct th_pktref_queue * q)237 pktref_get_first(struct th_pktref_queue *q)
238 {
239 th_pktref_t *pr;
240 th_pkt_t *pkt;
241
242 pr = TAILQ_FIRST(q);
243 if (pr) {
244 pkt = pr->pr_pkt;
245 TAILQ_REMOVE(q, pr, pr_link);
246 free(pr);
247 memoryinfo_free(&pktref_memoryinfo, sizeof(*pr));
248 return pkt;
249 }
250 return NULL;
251 }
252
253 /**
254 *
255 */
256 void
pktref_insert_head(struct th_pktref_queue * q,th_pkt_t * pkt)257 pktref_insert_head(struct th_pktref_queue *q, th_pkt_t *pkt)
258 {
259 th_pktref_t *pr;
260
261 pr = pktref_create(pkt);
262 TAILQ_INSERT_HEAD(q, pr, pr_link);
263 }
264
265 /**
266 *
267 */
268 th_pktref_t *
pktref_create(th_pkt_t * pkt)269 pktref_create(th_pkt_t *pkt)
270 {
271 th_pktref_t *pr = malloc(sizeof(th_pktref_t));
272 if (pr) {
273 pr->pr_pkt = pkt;
274 memoryinfo_alloc(&pktref_memoryinfo, sizeof(*pr));
275 }
276 return pr;
277 }
278
279 /*
280 *
281 */
282
283 void
pktbuf_destroy(pktbuf_t * pb)284 pktbuf_destroy(pktbuf_t *pb)
285 {
286 if (pb) {
287 memoryinfo_free(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
288 free(pb->pb_data);
289 free(pb);
290 }
291 }
292
293 void
pktbuf_ref_dec(pktbuf_t * pb)294 pktbuf_ref_dec(pktbuf_t *pb)
295 {
296 if (pb) {
297 if((atomic_add(&pb->pb_refcount, -1)) == 1) {
298 memoryinfo_free(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
299 free(pb->pb_data);
300 free(pb);
301 }
302 }
303 }
304
305 pktbuf_t *
pktbuf_ref_inc(pktbuf_t * pb)306 pktbuf_ref_inc(pktbuf_t *pb)
307 {
308 if (pb) {
309 atomic_add(&pb->pb_refcount, 1);
310 return pb;
311 }
312 return NULL;
313 }
314
315 pktbuf_t *
pktbuf_alloc(const void * data,size_t size)316 pktbuf_alloc(const void *data, size_t size)
317 {
318 pktbuf_t *pb = malloc(sizeof(pktbuf_t));
319
320 if (pb == NULL) return NULL;
321 pb->pb_refcount = 1;
322 pb->pb_size = size;
323 pb->pb_err = 0;
324 if(size > 0) {
325 pb->pb_data = malloc(size);
326 if (pb->pb_data != NULL) {
327 if (data != NULL)
328 memcpy(pb->pb_data, data, size);
329 } else {
330 pb->pb_size = 0;
331 }
332 } else {
333 pb->pb_data = NULL;
334 }
335 memoryinfo_alloc(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
336 return pb;
337 }
338
339 pktbuf_t *
pktbuf_make(void * data,size_t size)340 pktbuf_make(void *data, size_t size)
341 {
342 pktbuf_t *pb = malloc(sizeof(pktbuf_t));
343 if (pb) {
344 pb->pb_refcount = 1;
345 pb->pb_size = size;
346 pb->pb_data = data;
347 memoryinfo_alloc(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
348 }
349 return pb;
350 }
351
352 pktbuf_t *
pktbuf_append(pktbuf_t * pb,const void * data,size_t size)353 pktbuf_append(pktbuf_t *pb, const void *data, size_t size)
354 {
355 void *ndata;
356 if (pb == NULL)
357 return pktbuf_alloc(data, size);
358 ndata = realloc(pb->pb_data, pb->pb_size + size);
359 if (ndata) {
360 pb->pb_data = ndata;
361 memcpy(ndata + pb->pb_size, data, size);
362 pb->pb_size += size;
363 memoryinfo_append(&pktbuf_memoryinfo, size);
364 }
365 return pb;
366 }
367
368 /*
369 *
370 */
371
pts_to_string(int64_t pts,char * buf)372 const char *pts_to_string(int64_t pts, char *buf)
373 {
374 if (pts == PTS_UNSET)
375 return strcpy(buf, "<unset>");
376 snprintf(buf, 22, "%"PRId64, pts);
377 return buf;
378 }
379