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 
34 #include "mythlogging.h"
35 
36 #define DEBUG true
37 
38 int ring_init (ringbuffer *rbuf, int size)
39 {
40  if (size > 0){
41  rbuf->size = size;
42  if( !(rbuf->buffer = (uint8_t *) malloc(sizeof(uint8_t)*size)) ){
43  LOG(VB_GENERAL, LOG_ERR,
44  "Not enough memory for ringbuffer");
45  return -1;
46  }
47  } else {
48  LOG(VB_GENERAL, LOG_ERR, "Wrong size for ringbuffer");
49  return -1;
50  }
51  rbuf->read_pos = 0;
52  rbuf->write_pos = 0;
53  return 0;
54 }
55 
56 int ring_reinit (ringbuffer *rbuf, int size)
57 {
58  if (size > (int)(rbuf->size)) {
59  auto *tmpalloc = (uint8_t *) realloc(rbuf->buffer,
60  sizeof(uint8_t)*size);
61  if (! tmpalloc)
62  return -1;
63  rbuf->buffer = tmpalloc;
64  if (rbuf->write_pos < rbuf->read_pos)
65  {
66  unsigned int delta = size - rbuf->size;
67  memmove(rbuf->buffer + rbuf->read_pos + delta,
68  rbuf->buffer + rbuf->read_pos,
69  rbuf->size - rbuf->read_pos);
70  rbuf->read_pos += delta;
71  }
72  rbuf->size = size;
73  }
74  return 0;
75 }
77 {
78  rbuf->read_pos = 0;
79  rbuf->write_pos = 0;
80 }
81 
82 
83 
85 {
86  free(rbuf->buffer);
87 }
88 
89 
90 int 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+pos, data, rest);
108  if (count - rest)
109  memcpy (rbuf->buffer, data+rest, count - rest);
110  rbuf->write_pos = count - rest;
111  } else {
112  memcpy (rbuf->buffer+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 
122 int 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+pos, count);
142  } else {
143  memcpy(data, rbuf->buffer+pos, rest);
144  if ( count - rest)
145  memcpy(data+rest, rbuf->buffer, count - rest);
146  }
147 
148  return count;
149 }
150 
151 int 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 
156 int ring_peek(ringbuffer *rbuf, peek_poke_vec data, uint32_t off)
157 {
158  return ring_peek(rbuf, data.data(), data.size(), off);
159 }
160 
161 int 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+pos, data, count);
181  } else {
182  memcpy(rbuf->buffer+pos, data, rest);
183  if ( count - rest)
184  memcpy(rbuf->buffer, data+rest, count - rest);
185  }
186 
187  return count;
188 }
189 
190 int 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 
195 int ring_poke(ringbuffer *rbuf, peek_poke_vec data, uint32_t off)
196 {
197  return ring_poke(rbuf, data.data(), data.size(), off);
198 }
199 
200 int 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+pos, count);
219  rbuf->read_pos += count;
220  } else {
221  memcpy(data, rbuf->buffer+pos, rest);
222  if ( count - rest)
223  memcpy(data+rest, rbuf->buffer, 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 
233 int 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 
262 int 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+pos, rest);
282  if (rr == rest && count - rest)
283  rr += read (fd, rbuf->buffer, count - rest);
284  if (rr >=0)
285  rbuf->write_pos = (pos + rr) % rbuf->size;
286  } else {
287  rr = read (fd, rbuf->buffer+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 %.2f%%")
294  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
295  return rr;
296 }
297 
298 
299 
300 int 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+pos, rest);
321  if (rr == rest && count - rest)
322  rr += write (fd, rbuf->buffer, count - rest);
323  if (rr >=0)
324  rbuf->read_pos = (pos + rr) % rbuf->size;
325  } else {
326  rr = write (fd, rbuf->buffer+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 
339 static 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(buf[i+j]);
362  break;
363  default:
364  buffer += ".";
365  }
366  }
367  LOG(VB_GENERAL, LOG_INFO, buffer);
368  }
369 }
370 
371 void 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+pos, count);
391  } else {
392  show(rbuf->buffer+pos, rest);
393  if ( count - rest)
394  show(rbuf->buffer, count - rest);
395  }
396 }
397 
398 
399 int 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 
424 int 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 
442 int 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  do {
450  if (ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
451  sizeof(uint64_t), 0)<0){
452  if (dsize) break;
453  return -1;
454  }
455  if (ptscmp(rtime,time) < 0){
456  ring_read(&dbuf->time_index,(uint8_t *) &rtime,
457  sizeof(uint64_t));
458  ring_read(&dbuf->data_index,(uint8_t *) &size,
459  sizeof(uint32_t));
460  dsize += size;
461  } else ex = 1;
462  } while (ex == 0);
463 #if 0
464  LOG(VB_GENERAL, LOG_INFO, QString("delete %1 ").arg(dummy_space(dbuf)));
465 #endif
466  dbuf->fill -= dsize;
467 #if 0
468  LOG(VB_GENERAL, LOG_INFO,
469  QString(" + %1 = %2").arg(dsize).arg(dummy_space(dbuf)));
470 #endif
471 
472  return dsize;
473 }
474 
475 #if 0
476 static void dummy_print(dummy_buffer *dbuf)
477 {
478  uint64_t rtime = 0;
479  uint32_t size = 0;
480  int avail = ring_avail(&dbuf->time_index) / sizeof(uint64_t);
481  for (int i = 0; i < avail; i++) {
482  ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
483  sizeof(uint64_t), i * sizeof(uint64_t));
484  ring_peek(&dbuf->data_index,(uint8_t *) &size,
485  sizeof(uint32_t), i * sizeof(uint32_t));
486 
487  LOG(VB_GENERAL, LOG_INFO, QString("%1 : %2 %3").arg(i)
488  .arg(rtime).arg(size));
489  }
490  LOG(VB_GENERAL, LOG_INFO, QString("Used: %d Free: %d data-free: %d")
491  .arg(avail).arg(1000-avail).arg(dbuf->size - dbuf->fill));
492 }
493 #endif
ring_free
static unsigned int ring_free(ringbuffer *rbuf)
Definition: ringbuffer.h:101
dummy_init
int dummy_init(dummy_buffer *dbuf, int s)
Definition: ringbuffer.cpp:399
ring_init
int ring_init(ringbuffer *rbuf, int size)
Definition: ringbuffer.cpp:38
ringbuffer.h
DEBUG
#define DEBUG
Definition: ringbuffer.cpp:36
ringbuffer::write_pos
int write_pos
Definition: ringbuffer.h:41
pes.h
dummy_buffer::size
uint32_t size
Definition: ringbuffer.h:50
ring_peek
int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:122
dummy_delete
int dummy_delete(dummy_buffer *dbuf, uint64_t time)
Definition: ringbuffer.cpp:442
ringbuffer
Definition: ringbuffer.h:39
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
arg
arg(title).arg(filename).arg(doDelete))
dummy_buffer::data_index
ringbuffer data_index
Definition: ringbuffer.h:53
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
ring_read_file
int ring_read_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:300
show
static void show(uint8_t *buf, int length)
Definition: ringbuffer.cpp:339
ring_show
void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:371
ring_destroy
void ring_destroy(ringbuffer *rbuf)
Definition: ringbuffer.cpp:84
dummy_buffer::time_index
ringbuffer time_index
Definition: ringbuffer.h:52
ring_clear
void ring_clear(ringbuffer *rbuf)
Definition: ringbuffer.cpp:76
mythlogging.h
dummy_destroy
void dummy_destroy(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:411
ring_write_file
int ring_write_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:262
dummy_add
int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
Definition: ringbuffer.cpp:424
ringbuffer::buffer
uint8_t * buffer
Definition: ringbuffer.h:43
DBUF_INDEX
#define DBUF_INDEX
Definition: ringbuffer.h:47
ringbuffer::size
uint32_t size
Definition: ringbuffer.h:42
ring_write
int ring_write(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:90
EMPTY_BUFFER
#define EMPTY_BUFFER
Definition: ringbuffer.h:38
dummy_clear
void dummy_clear(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:417
ring_read
int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:200
dummy_buffer
Definition: ringbuffer.h:49
ring_avail
static unsigned int ring_avail(ringbuffer *rbuf)
Definition: ringbuffer.h:108
ring_reinit
int ring_reinit(ringbuffer *rbuf, int size)
Definition: ringbuffer.cpp:56
dummy_space
static uint32_t dummy_space(dummy_buffer *dbuf)
Definition: ringbuffer.h:117
ring_skip
int ring_skip(ringbuffer *rbuf, int count)
Definition: ringbuffer.cpp:233
ringbuffer::read_pos
int read_pos
Definition: ringbuffer.h:40
ptscmp
int ptscmp(uint64_t pts1, uint64_t pts2)
Definition: pes.cpp:114
ring_poke
int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:161
FULL_BUFFER
#define FULL_BUFFER
Definition: ringbuffer.h:37
dummy_buffer::fill
uint32_t fill
Definition: ringbuffer.h:51
peek_poke_vec
std::vector< uint8_t > peek_poke_vec
Definition: ringbuffer.h:35