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 
38 int ring_init (ringbuffer *rbuf, int size)
39 {
40  if (size > 0){
41  rbuf->size = size;
42  rbuf->buffer = (uint8_t *) malloc(sizeof(uint8_t)*size);
43  if (rbuf->buffer == nullptr)
44  {
45  LOG(VB_GENERAL, LOG_ERR,
46  "Not enough memory for ringbuffer");
47  return -1;
48  }
49  } else {
50  LOG(VB_GENERAL, LOG_ERR, "Wrong size for ringbuffer");
51  return -1;
52  }
53  rbuf->read_pos = 0;
54  rbuf->write_pos = 0;
55  return 0;
56 }
57 
58 int ring_reinit (ringbuffer *rbuf, int size)
59 {
60  if (size > (int)(rbuf->size)) {
61  auto *tmpalloc = (uint8_t *) realloc(rbuf->buffer,
62  sizeof(uint8_t)*size);
63  if (! tmpalloc)
64  return -1;
65  rbuf->buffer = tmpalloc;
66  if (rbuf->write_pos < rbuf->read_pos)
67  {
68  unsigned int delta = size - rbuf->size;
69  memmove(rbuf->buffer + rbuf->read_pos + delta,
70  rbuf->buffer + rbuf->read_pos,
71  rbuf->size - rbuf->read_pos);
72  rbuf->read_pos += delta;
73  }
74  rbuf->size = size;
75  }
76  return 0;
77 }
79 {
80  rbuf->read_pos = 0;
81  rbuf->write_pos = 0;
82 }
83 
84 
85 
87 {
88  free(rbuf->buffer);
89 }
90 
91 
92 int ring_write(ringbuffer *rbuf, uint8_t *data, int count)
93 {
94  if (count <=0 ) return 0;
95  int pos = rbuf->write_pos;
96  int rest = rbuf->size - pos;
97  int free = ring_free(rbuf);
98 
99  if ( free < count ){
100  if (DEBUG) {
101  LOG(VB_GENERAL, LOG_ERR,
102  QString("ringbuffer overflow %1<%2 %3")
103  .arg(free).arg(count).arg(rbuf->size));
104  }
105  return FULL_BUFFER;
106  }
107 
108  if (count >= rest){
109  memcpy (rbuf->buffer+pos, data, rest);
110  if (count - rest)
111  memcpy (rbuf->buffer, data+rest, count - rest);
112  rbuf->write_pos = count - rest;
113  } else {
114  memcpy (rbuf->buffer+pos, data, count);
115  rbuf->write_pos += count;
116  }
117 
118  if (DEBUG>1)
119  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%%")
120  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
121  return count;
122 }
123 
124 int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
125 {
126  if (off+count > rbuf->size || off+count >ring_avail(rbuf))
127  return -1;
128  unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
129  unsigned int rest = rbuf->size - pos ;
130  unsigned int avail = ring_avail(rbuf);
131 
132  if ( avail < count ){
133 #if 0
134  if (DEBUG)
135  LOG(VB_GENERAL, LOG_ERR,
136  QString("ringbuffer peek underflow %1<%2 %3 %4")
137  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
138 #endif
139  return EMPTY_BUFFER;
140  }
141 
142  if ( count < rest ){
143  memcpy(data, rbuf->buffer+pos, count);
144  } else {
145  memcpy(data, rbuf->buffer+pos, rest);
146  if ( count - rest)
147  memcpy(data+rest, rbuf->buffer, count - rest);
148  }
149 
150  return count;
151 }
152 
153 int ring_peek(ringbuffer *rbuf, peek_poke_vec& data, unsigned int count, uint32_t off)
154 {
155  return ring_peek(rbuf, data.data(), count, off);
156 }
157 
158 int ring_peek(ringbuffer *rbuf, peek_poke_vec& data, uint32_t off)
159 {
160  return ring_peek(rbuf, data.data(), data.size(), off);
161 }
162 
163 int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
164 {
165  if (off+count > rbuf->size || off+count >ring_avail(rbuf))
166  return -1;
167  unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
168  unsigned int rest = rbuf->size - pos ;
169  unsigned int avail = ring_avail(rbuf);
170 
171  if ( avail < count ){
172 #if 0
173  if (DEBUG)
174  LOG(VB_GENERAL, LOG_ERR,
175  QString("ringbuffer peek underflow %1<%2 %3 %4")
176  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
177 #endif
178  return EMPTY_BUFFER;
179  }
180 
181  if ( count < rest ){
182  memcpy(rbuf->buffer+pos, data, count);
183  } else {
184  memcpy(rbuf->buffer+pos, data, rest);
185  if ( count - rest)
186  memcpy(rbuf->buffer, data+rest, count - rest);
187  }
188 
189  return count;
190 }
191 
192 int ring_poke(ringbuffer *rbuf, peek_poke_vec& data, unsigned int count, uint32_t off)
193 {
194  return ring_poke(rbuf, data.data(), count, off);
195 }
196 
197 int ring_poke(ringbuffer *rbuf, peek_poke_vec& data, uint32_t off)
198 {
199  return ring_poke(rbuf, data.data(), data.size(), off);
200 }
201 
202 int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
203 {
204  if (count <=0 ) return 0;
205  int pos = rbuf->read_pos;
206  int rest = rbuf->size - pos;
207  int avail = ring_avail(rbuf);
208 
209  if ( avail < count ){
210 #if 0
211  if (DEBUG)
212  LOG(VB_GENERAL, LOG_ERR,
213  QString("ringbuffer underflow %1<%2 %3 \n")
214  .arg(avail).arg(count).arg(rbuf->size));
215 #endif
216  return EMPTY_BUFFER;
217  }
218 
219  if ( count < rest ){
220  memcpy(data, rbuf->buffer+pos, count);
221  rbuf->read_pos += count;
222  } else {
223  memcpy(data, rbuf->buffer+pos, rest);
224  if ( count - rest)
225  memcpy(data+rest, rbuf->buffer, count - rest);
226  rbuf->read_pos = count - rest;
227  }
228 
229  if (DEBUG>1)
230  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%%")
231  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
232  return count;
233 }
234 
235 int ring_skip(ringbuffer *rbuf, int count)
236 {
237  if (count <=0 ) return -1;
238  int pos = rbuf->read_pos;
239  int rest = rbuf->size - pos;
240  int avail = ring_avail(rbuf);
241 
242  if ( avail < count ){
243 #if 0
244  LOG(VB_GENERAL, LOG_ERR,
245  QString("ringbuffer skip underflow %1<%2 %3 %4\n")
246  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
247 #endif
248  return EMPTY_BUFFER;
249  }
250  if ( count < rest ){
251  rbuf->read_pos += count;
252  } else {
253  rbuf->read_pos = count - rest;
254  }
255 
256  if (DEBUG>1)
257  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%%")
258  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
259  return count;
260 }
261 
262 
263 
264 int ring_write_file(ringbuffer *rbuf, int fd, int count)
265 {
266  int rr = 0;
267 
268  if (count <=0 ) return 0;
269  int pos = rbuf->write_pos;
270  int rest = rbuf->size - pos;
271  int free = ring_free(rbuf);
272 
273  if ( free < count ){
274  if (DEBUG) {
275  LOG(VB_GENERAL, LOG_ERR,
276  QString("ringbuffer overflow %1<%2 %3 %4\n")
277  .arg(free).arg(count).arg(pos).arg(rbuf->read_pos));
278  }
279  return FULL_BUFFER;
280  }
281 
282  if (count >= rest){
283  rr = read (fd, rbuf->buffer+pos, rest);
284  if (rr == rest && count - rest)
285  rr += read (fd, rbuf->buffer, count - rest);
286  if (rr >=0)
287  rbuf->write_pos = (pos + rr) % rbuf->size;
288  } else {
289  rr = read (fd, rbuf->buffer+pos, count);
290  if (rr >=0)
291  rbuf->write_pos += rr;
292  }
293 
294  if (DEBUG>1)
295  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %.2f%%")
296  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
297  return rr;
298 }
299 
300 
301 
302 int ring_read_file(ringbuffer *rbuf, int fd, int count)
303 {
304  int rr = 0;
305 
306  if (count <=0 ) return -1;
307  int pos = rbuf->read_pos;
308  int rest = rbuf->size - pos;
309  int avail = ring_avail(rbuf);
310 
311  if ( avail < count ){
312 #if 0
313  if (DEBUG)
314  LOG(VB_GENERAL, LOG_ERR,
315  QString("ringbuffer underflow %1<%2 %3 %4")
316  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
317 #endif
318  return EMPTY_BUFFER;
319  }
320 
321  if (count >= rest){
322  rr = write (fd, rbuf->buffer+pos, rest);
323  if (rr == rest && count - rest)
324  rr += write (fd, rbuf->buffer, count - rest);
325  if (rr >=0)
326  rbuf->read_pos = (pos + rr) % rbuf->size;
327  } else {
328  rr = write (fd, rbuf->buffer+pos, count);
329  if (rr >=0)
330  rbuf->read_pos += rr;
331  }
332 
333 
334  if (DEBUG>1)
335  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%%")
336  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
337  return rr;
338 }
339 
340 
341 static void show(uint8_t *buf, int length)
342 {
343  QString buffer;
344 
345  for (int i=0; i<length; i+=16){
346  int j = 0;
347  for (j=0; j < 8 && j+i<length; j++)
348  buffer += QString("0x%1 ").arg(buf[i+j],16,2,QChar('0'));
349  for (int r=j; r<8; r++)
350  buffer += " ";
351 
352  buffer += " ";
353 
354  for (j=8; j < 16 && j+i<length; j++)
355  buffer += QString("0x%1 ").arg(buf[i+j],16,2,QChar('0'));
356  for (int r=j; r<16; r++)
357  buffer += " ";
358 
359  for (j=0; j < 16 && j+i<length; j++){
360  switch(buf[i+j]){
361  case '0'...'Z':
362  case 'a'...'z':
363  buffer += QString(QChar(buf[i+j]));
364  break;
365  default:
366  buffer += ".";
367  }
368  }
369  LOG(VB_GENERAL, LOG_INFO, buffer);
370  }
371 }
372 
373 void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
374 {
375  if (off+count > rbuf->size || off+count >ring_avail(rbuf))
376  return;
377  unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
378  unsigned int rest = rbuf->size - pos ;
379  unsigned int avail = ring_avail(rbuf);
380 
381  if ( avail < count ){
382 #if 0
383  if (DEBUG)
384  LOG(VB_GENERAL, LOG_ERR,
385  QString("ringbuffer peek underflow %1<%2 %3 %4\n")
386  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
387 #endif
388  return;
389  }
390 
391  if ( count < rest ){
392  show(rbuf->buffer+pos, count);
393  } else {
394  show(rbuf->buffer+pos, rest);
395  if ( count - rest)
396  show(rbuf->buffer, count - rest);
397  }
398 }
399 
400 
401 int dummy_init(dummy_buffer *dbuf, int s)
402 {
403  dbuf->size = s;
404  dbuf->fill = 0;
405  if (ring_init(&dbuf->time_index, DBUF_INDEX*sizeof(uint64_t)) < 0)
406  return -1;
407  if (ring_init(&dbuf->data_index, DBUF_INDEX*sizeof(int32_t)) < 0)
408  return -1;
409 
410  return 0;
411 }
412 
414 {
415  ring_destroy(&dbuf->time_index);
416  ring_destroy(&dbuf->data_index);
417 }
418 
420 {
421  dbuf->fill = 0;
422  ring_clear(&dbuf->time_index);
423  ring_clear(&dbuf->data_index);
424 }
425 
426 int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
427 {
428  if (dummy_space(dbuf) < size) return -1;
429 #if 0
430  LOG(VB_GENERAL, LOG_INFO, QString("add %1 ").arg(dummy_space(dbuf)));
431 #endif
432  dbuf->fill += size;
433  if (ring_write(&dbuf->time_index, (uint8_t *)&time, sizeof(uint64_t)) < 0)
434  return -2;
435  if (ring_write(&dbuf->data_index, (uint8_t *)&size, sizeof(uint32_t)) < 0)
436  return -3;
437 #if 0
438  LOG(VB_GENERAL, LOG_INFO,
439  QString(" - %1 = %2").arg(size).arg(dummy_space(dbuf)));
440 #endif
441  return size;
442 }
443 
444 int dummy_delete(dummy_buffer *dbuf, uint64_t time)
445 {
446  uint64_t rtime = 0;
447  uint32_t size = 0;
448  int ex=0;
449  uint32_t dsize=0;
450 
451  do {
452  if (ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
453  sizeof(uint64_t), 0)<0){
454  if (dsize) break;
455  return -1;
456  }
457  if (ptscmp(rtime,time) < 0){
458  ring_read(&dbuf->time_index,(uint8_t *) &rtime,
459  sizeof(uint64_t));
460  ring_read(&dbuf->data_index,(uint8_t *) &size,
461  sizeof(uint32_t));
462  dsize += size;
463  } else {
464  ex = 1;
465  }
466  } while (ex == 0);
467 #if 0
468  LOG(VB_GENERAL, LOG_INFO, QString("delete %1 ").arg(dummy_space(dbuf)));
469 #endif
470  dbuf->fill -= dsize;
471 #if 0
472  LOG(VB_GENERAL, LOG_INFO,
473  QString(" + %1 = %2").arg(dsize).arg(dummy_space(dbuf)));
474 #endif
475 
476  return dsize;
477 }
478 
479 #if 0
480 static void dummy_print(dummy_buffer *dbuf)
481 {
482  uint64_t rtime = 0;
483  uint32_t size = 0;
484  int avail = ring_avail(&dbuf->time_index) / sizeof(uint64_t);
485  for (int i = 0; i < avail; i++) {
486  ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
487  sizeof(uint64_t), i * sizeof(uint64_t));
488  ring_peek(&dbuf->data_index,(uint8_t *) &size,
489  sizeof(uint32_t), i * sizeof(uint32_t));
490 
491  LOG(VB_GENERAL, LOG_INFO, QString("%1 : %2 %3").arg(i)
492  .arg(rtime).arg(size));
493  }
494  LOG(VB_GENERAL, LOG_INFO, QString("Used: %d Free: %d data-free: %d")
495  .arg(avail).arg(1000-avail).arg(dbuf->size - dbuf->fill));
496 }
497 #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:401
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:124
dummy_delete
int dummy_delete(dummy_buffer *dbuf, uint64_t time)
Definition: ringbuffer.cpp:444
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
dummy_buffer::data_index
ringbuffer data_index
Definition: ringbuffer.h:53
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ring_read_file
int ring_read_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:302
show
static void show(uint8_t *buf, int length)
Definition: ringbuffer.cpp:341
ring_show
void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:373
ring_destroy
void ring_destroy(ringbuffer *rbuf)
Definition: ringbuffer.cpp:86
dummy_buffer::time_index
ringbuffer time_index
Definition: ringbuffer.h:52
ring_clear
void ring_clear(ringbuffer *rbuf)
Definition: ringbuffer.cpp:78
mythlogging.h
dummy_destroy
void dummy_destroy(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:413
ring_write_file
int ring_write_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:264
dummy_add
int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
Definition: ringbuffer.cpp:426
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:92
EMPTY_BUFFER
#define EMPTY_BUFFER
Definition: ringbuffer.h:38
dummy_clear
void dummy_clear(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:419
ring_read
int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:202
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:58
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:235
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:163
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