MythTV master
ringbuffer.cpp
Go to the documentation of this file.
1/*
2 * ringbuffer.c
3 *
4 *
5 * Copyright (C) 2003 Marcus Metzler <mocm@metzlerbros.de>
6 * Metzler Brothers Systementwicklung GbR
7 * Changes to use MythTV logging
8 * Copyright (C) 2011 Gavin Hurlbut <ghurlbut@mythtv.org>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * General Public License for more details.
20 *
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
26 *
27 */
28
29#include <cstdlib>
30#include <cstring>
31#include "ringbuffer.h"
32#include "pes.h"
33
35
36#define DEBUG true
37
38int ring_init (ringbuffer *rbuf, int size)
39{
40 if (size > 0){
41 rbuf->size = size;
42 try {
43 rbuf->buffer.resize(size);
44 } catch (const std::bad_alloc& e) {
45 LOG(VB_GENERAL, LOG_ERR, "Not enough memory for ringbuffer");
46 return -1;
47 }
48 } else {
49 LOG(VB_GENERAL, LOG_ERR, "Wrong size for ringbuffer");
50 return -1;
51 }
52 rbuf->read_pos = 0;
53 rbuf->write_pos = 0;
54 return 0;
55}
56
57int ring_reinit (ringbuffer *rbuf, int size)
58{
59 if (size > (int)(rbuf->size)) {
60 try {
61 rbuf->buffer.resize(size);
62 } catch (const std::bad_alloc& e) {
63 return -1;
64 }
65 if (rbuf->write_pos < rbuf->read_pos)
66 {
67 unsigned int delta = size - rbuf->size;
68 memmove(rbuf->buffer.data() + rbuf->read_pos + delta,
69 rbuf->buffer.data() + rbuf->read_pos,
70 rbuf->size - rbuf->read_pos);
71 rbuf->read_pos += delta;
72 }
73 rbuf->size = size;
74 }
75 return 0;
76}
78{
79 rbuf->read_pos = 0;
80 rbuf->write_pos = 0;
81}
82
83
84
85void ring_destroy(ringbuffer */*rbuf*/)
86{
87}
88
89
90int ring_write(ringbuffer *rbuf, uint8_t *data, int count)
91{
92 if (count <=0 ) return 0;
93 int pos = rbuf->write_pos;
94 int rest = rbuf->size - pos;
95 int free = ring_free(rbuf);
96
97 if ( free < count ){
98 if (DEBUG) {
99 LOG(VB_GENERAL, LOG_ERR,
100 QString("ringbuffer overflow %1<%2 %3")
101 .arg(free).arg(count).arg(rbuf->size));
102 }
103 return FULL_BUFFER;
104 }
105
106 if (count >= rest){
107 memcpy (rbuf->buffer.data()+pos, data, rest);
108 if (count - rest)
109 memcpy (rbuf->buffer.data(), data+rest, count - rest);
110 rbuf->write_pos = count - rest;
111 } else {
112 memcpy (rbuf->buffer.data()+pos, data, count);
113 rbuf->write_pos += count;
114 }
115
116 if (DEBUG>1)
117 LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%")
118 .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
119 return count;
120}
121
122int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
123{
124 if (off+count > rbuf->size || off+count >ring_avail(rbuf))
125 return -1;
126 unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
127 unsigned int rest = rbuf->size - pos ;
128 unsigned int avail = ring_avail(rbuf);
129
130 if ( avail < count ){
131#if 0
132 if (DEBUG)
133 LOG(VB_GENERAL, LOG_ERR,
134 QString("ringbuffer peek underflow %1<%2 %3 %4")
135 .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
136#endif
137 return EMPTY_BUFFER;
138 }
139
140 if ( count < rest ){
141 memcpy(data, rbuf->buffer.data()+pos, count);
142 } else {
143 memcpy(data, rbuf->buffer.data()+pos, rest);
144 if ( count - rest)
145 memcpy(data+rest, rbuf->buffer.data(), count - rest);
146 }
147
148 return count;
149}
150
151int ring_peek(ringbuffer *rbuf, peek_poke_vec& data, unsigned int count, uint32_t off)
152{
153 return ring_peek(rbuf, data.data(), count, off);
154}
155
156int ring_peek(ringbuffer *rbuf, peek_poke_vec& data, uint32_t off)
157{
158 return ring_peek(rbuf, data.data(), data.size(), off);
159}
160
161int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
162{
163 if (off+count > rbuf->size || off+count >ring_avail(rbuf))
164 return -1;
165 unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
166 unsigned int rest = rbuf->size - pos ;
167 unsigned int avail = ring_avail(rbuf);
168
169 if ( avail < count ){
170#if 0
171 if (DEBUG)
172 LOG(VB_GENERAL, LOG_ERR,
173 QString("ringbuffer peek underflow %1<%2 %3 %4")
174 .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
175#endif
176 return EMPTY_BUFFER;
177 }
178
179 if ( count < rest ){
180 memcpy(rbuf->buffer.data()+pos, data, count);
181 } else {
182 memcpy(rbuf->buffer.data()+pos, data, rest);
183 if ( count - rest)
184 memcpy(rbuf->buffer.data(), data+rest, count - rest);
185 }
186
187 return count;
188}
189
190int ring_poke(ringbuffer *rbuf, peek_poke_vec& data, unsigned int count, uint32_t off)
191{
192 return ring_poke(rbuf, data.data(), count, off);
193}
194
195int ring_poke(ringbuffer *rbuf, peek_poke_vec& data, uint32_t off)
196{
197 return ring_poke(rbuf, data.data(), data.size(), off);
198}
199
200int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
201{
202 if (count <=0 ) return 0;
203 int pos = rbuf->read_pos;
204 int rest = rbuf->size - pos;
205 int avail = ring_avail(rbuf);
206
207 if ( avail < count ){
208#if 0
209 if (DEBUG)
210 LOG(VB_GENERAL, LOG_ERR,
211 QString("ringbuffer underflow %1<%2 %3 \n")
212 .arg(avail).arg(count).arg(rbuf->size));
213#endif
214 return EMPTY_BUFFER;
215 }
216
217 if ( count < rest ){
218 memcpy(data, rbuf->buffer.data()+pos, count);
219 rbuf->read_pos += count;
220 } else {
221 memcpy(data, rbuf->buffer.data()+pos, rest);
222 if ( count - rest)
223 memcpy(data+rest, rbuf->buffer.data(), count - rest);
224 rbuf->read_pos = count - rest;
225 }
226
227 if (DEBUG>1)
228 LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%")
229 .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
230 return count;
231}
232
233int ring_skip(ringbuffer *rbuf, int count)
234{
235 if (count <=0 ) return -1;
236 int pos = rbuf->read_pos;
237 int rest = rbuf->size - pos;
238 int avail = ring_avail(rbuf);
239
240 if ( avail < count ){
241#if 0
242 LOG(VB_GENERAL, LOG_ERR,
243 QString("ringbuffer skip underflow %1<%2 %3 %4\n")
244 .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
245#endif
246 return EMPTY_BUFFER;
247 }
248 if ( count < rest ){
249 rbuf->read_pos += count;
250 } else {
251 rbuf->read_pos = count - rest;
252 }
253
254 if (DEBUG>1)
255 LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%")
256 .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
257 return count;
258}
259
260
261
262int ring_write_file(ringbuffer *rbuf, int fd, int count)
263{
264 int rr = 0;
265
266 if (count <=0 ) return 0;
267 int pos = rbuf->write_pos;
268 int rest = rbuf->size - pos;
269 int free = ring_free(rbuf);
270
271 if ( free < count ){
272 if (DEBUG) {
273 LOG(VB_GENERAL, LOG_ERR,
274 QString("ringbuffer overflow %1<%2 %3 %4\n")
275 .arg(free).arg(count).arg(pos).arg(rbuf->read_pos));
276 }
277 return FULL_BUFFER;
278 }
279
280 if (count >= rest){
281 rr = read (fd, rbuf->buffer.data()+pos, rest);
282 if (rr == rest && count - rest)
283 rr += read (fd, rbuf->buffer.data(), count - rest);
284 if (rr >=0)
285 rbuf->write_pos = (pos + rr) % rbuf->size;
286 } else {
287 rr = read (fd, rbuf->buffer.data()+pos, count);
288 if (rr >=0)
289 rbuf->write_pos += rr;
290 }
291
292 if (DEBUG>1)
293 LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%")
294 .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
295 return rr;
296}
297
298
299
300int ring_read_file(ringbuffer *rbuf, int fd, int count)
301{
302 int rr = 0;
303
304 if (count <=0 ) return -1;
305 int pos = rbuf->read_pos;
306 int rest = rbuf->size - pos;
307 int avail = ring_avail(rbuf);
308
309 if ( avail < count ){
310#if 0
311 if (DEBUG)
312 LOG(VB_GENERAL, LOG_ERR,
313 QString("ringbuffer underflow %1<%2 %3 %4")
314 .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
315#endif
316 return EMPTY_BUFFER;
317 }
318
319 if (count >= rest){
320 rr = write (fd, rbuf->buffer.data()+pos, rest);
321 if (rr == rest && count - rest)
322 rr += write (fd, rbuf->buffer.data(), count - rest);
323 if (rr >=0)
324 rbuf->read_pos = (pos + rr) % rbuf->size;
325 } else {
326 rr = write (fd, rbuf->buffer.data()+pos, count);
327 if (rr >=0)
328 rbuf->read_pos += rr;
329 }
330
331
332 if (DEBUG>1)
333 LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%")
334 .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
335 return rr;
336}
337
338
339static void show(uint8_t *buf, int length)
340{
341 QString buffer;
342
343 for (int i=0; i<length; i+=16){
344 int j = 0;
345 for (j=0; j < 8 && j+i<length; j++)
346 buffer += QString("0x%1 ").arg(buf[i+j],16,2,QChar('0'));
347 for (int r=j; r<8; r++)
348 buffer += " ";
349
350 buffer += " ";
351
352 for (j=8; j < 16 && j+i<length; j++)
353 buffer += QString("0x%1 ").arg(buf[i+j],16,2,QChar('0'));
354 for (int r=j; r<16; r++)
355 buffer += " ";
356
357 for (j=0; j < 16 && j+i<length; j++){
358 switch(buf[i+j]){
359 case '0'...'Z':
360 case 'a'...'z':
361 buffer += QString(QChar(buf[i+j]));
362 break;
363 default:
364 buffer += ".";
365 }
366 }
367 LOG(VB_GENERAL, LOG_INFO, buffer);
368 }
369}
370
371void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
372{
373 if (off+count > rbuf->size || off+count >ring_avail(rbuf))
374 return;
375 unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
376 unsigned int rest = rbuf->size - pos ;
377 unsigned int avail = ring_avail(rbuf);
378
379 if ( avail < count ){
380#if 0
381 if (DEBUG)
382 LOG(VB_GENERAL, LOG_ERR,
383 QString("ringbuffer peek underflow %1<%2 %3 %4\n")
384 .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
385#endif
386 return;
387 }
388
389 if ( count < rest ){
390 show(rbuf->buffer.data()+pos, count);
391 } else {
392 show(rbuf->buffer.data()+pos, rest);
393 if ( count - rest)
394 show(rbuf->buffer.data(), count - rest);
395 }
396}
397
398
399int dummy_init(dummy_buffer *dbuf, int s)
400{
401 dbuf->size = s;
402 dbuf->fill = 0;
403 if (ring_init(&dbuf->time_index, DBUF_INDEX*sizeof(uint64_t)) < 0)
404 return -1;
405 if (ring_init(&dbuf->data_index, DBUF_INDEX*sizeof(int32_t)) < 0)
406 return -1;
407
408 return 0;
409}
410
412{
413 ring_destroy(&dbuf->time_index);
414 ring_destroy(&dbuf->data_index);
415}
416
418{
419 dbuf->fill = 0;
420 ring_clear(&dbuf->time_index);
421 ring_clear(&dbuf->data_index);
422}
423
424int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
425{
426 if (dummy_space(dbuf) < size) return -1;
427#if 0
428 LOG(VB_GENERAL, LOG_INFO, QString("add %1 ").arg(dummy_space(dbuf)));
429#endif
430 dbuf->fill += size;
431 if (ring_write(&dbuf->time_index, (uint8_t *)&time, sizeof(uint64_t)) < 0)
432 return -2;
433 if (ring_write(&dbuf->data_index, (uint8_t *)&size, sizeof(uint32_t)) < 0)
434 return -3;
435#if 0
436 LOG(VB_GENERAL, LOG_INFO,
437 QString(" - %1 = %2").arg(size).arg(dummy_space(dbuf)));
438#endif
439 return size;
440}
441
442int dummy_delete(dummy_buffer *dbuf, uint64_t time)
443{
444 uint64_t rtime = 0;
445 uint32_t size = 0;
446 int ex=0;
447 uint32_t dsize=0;
448
449 while (ex == 0)
450 {
451 if (ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
452 sizeof(uint64_t), 0)<0){
453 if (dsize) break;
454 return -1;
455 }
456 if (ptscmp(rtime,time) < 0){
457 ring_read(&dbuf->time_index,(uint8_t *) &rtime,
458 sizeof(uint64_t));
459 ring_read(&dbuf->data_index,(uint8_t *) &size,
460 sizeof(uint32_t));
461 dsize += size;
462 } else {
463 ex = 1;
464 }
465 }
466#if 0
467 LOG(VB_GENERAL, LOG_INFO, QString("delete %1 ").arg(dummy_space(dbuf)));
468#endif
469 dbuf->fill -= dsize;
470#if 0
471 LOG(VB_GENERAL, LOG_INFO,
472 QString(" + %1 = %2").arg(dsize).arg(dummy_space(dbuf)));
473#endif
474
475 return dsize;
476}
477
478#if 0
479static void dummy_print(dummy_buffer *dbuf)
480{
481 uint64_t rtime = 0;
482 uint32_t size = 0;
483 int avail = ring_avail(&dbuf->time_index) / sizeof(uint64_t);
484 for (int i = 0; i < avail; i++) {
485 ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
486 sizeof(uint64_t), i * sizeof(uint64_t));
487 ring_peek(&dbuf->data_index,(uint8_t *) &size,
488 sizeof(uint32_t), i * sizeof(uint32_t));
489
490 LOG(VB_GENERAL, LOG_INFO, QString("%1 : %2 %3").arg(i)
491 .arg(rtime).arg(size));
492 }
493 LOG(VB_GENERAL, LOG_INFO, QString("Used: %d Free: %d data-free: %d")
494 .arg(avail).arg(1000-avail).arg(dbuf->size - dbuf->fill));
495}
496#endif
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def read(device=None, features=[])
Definition: disc.py:35
def write(text, progress=True)
Definition: mythburn.py:306
int ptscmp(uint64_t pts1, uint64_t pts2)
Definition: pes.cpp:114
int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
Definition: ringbuffer.cpp:424
static void show(uint8_t *buf, int length)
Definition: ringbuffer.cpp:339
void dummy_destroy(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:411
int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:200
int ring_reinit(ringbuffer *rbuf, int size)
Definition: ringbuffer.cpp:57
int ring_write(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:90
int ring_read_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:300
int dummy_init(dummy_buffer *dbuf, int s)
Definition: ringbuffer.cpp:399
void ring_clear(ringbuffer *rbuf)
Definition: ringbuffer.cpp:77
void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:371
int dummy_delete(dummy_buffer *dbuf, uint64_t time)
Definition: ringbuffer.cpp:442
int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:122
int ring_write_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:262
int ring_skip(ringbuffer *rbuf, int count)
Definition: ringbuffer.cpp:233
void dummy_clear(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:417
#define DEBUG
Definition: ringbuffer.cpp:36
int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:161
int ring_init(ringbuffer *rbuf, int size)
Definition: ringbuffer.cpp:38
void ring_destroy(ringbuffer *)
Definition: ringbuffer.cpp:85
static unsigned int ring_avail(ringbuffer *rbuf)
Definition: ringbuffer.h:108
#define EMPTY_BUFFER
Definition: ringbuffer.h:38
static unsigned int ring_free(ringbuffer *rbuf)
Definition: ringbuffer.h:101
#define DBUF_INDEX
Definition: ringbuffer.h:47
std::vector< uint8_t > peek_poke_vec
Definition: ringbuffer.h:35
static uint32_t dummy_space(dummy_buffer *dbuf)
Definition: ringbuffer.h:117
#define FULL_BUFFER
Definition: ringbuffer.h:37
ringbuffer data_index
Definition: ringbuffer.h:53
ringbuffer time_index
Definition: ringbuffer.h:52
uint32_t size
Definition: ringbuffer.h:50
uint32_t fill
Definition: ringbuffer.h:51
int read_pos
Definition: ringbuffer.h:40
int write_pos
Definition: ringbuffer.h:41
std::vector< uint8_t > buffer
Definition: ringbuffer.h:43
uint32_t size
Definition: ringbuffer.h:42