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_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
152 {
153  if (off+count > rbuf->size || off+count >ring_avail(rbuf))
154  return -1;
155  unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
156  unsigned int rest = rbuf->size - pos ;
157  unsigned int avail = ring_avail(rbuf);
158 
159  if ( avail < count ){
160 #if 0
161  if (DEBUG)
162  LOG(VB_GENERAL, LOG_ERR,
163  QString("ringbuffer peek underflow %1<%2 %3 %4")
164  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
165 #endif
166  return EMPTY_BUFFER;
167  }
168 
169  if ( count < rest ){
170  memcpy(rbuf->buffer+pos, data, count);
171  } else {
172  memcpy(rbuf->buffer+pos, data, rest);
173  if ( count - rest)
174  memcpy(rbuf->buffer, data+rest, count - rest);
175  }
176 
177  return count;
178 }
179 
180 int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
181 {
182  if (count <=0 ) return 0;
183  int pos = rbuf->read_pos;
184  int rest = rbuf->size - pos;
185  int avail = ring_avail(rbuf);
186 
187  if ( avail < count ){
188 #if 0
189  if (DEBUG)
190  LOG(VB_GENERAL, LOG_ERR,
191  QString("ringbuffer underflow %1<%2 %3 \n")
192  .arg(avail).arg(count).arg(rbuf->size));
193 #endif
194  return EMPTY_BUFFER;
195  }
196 
197  if ( count < rest ){
198  memcpy(data, rbuf->buffer+pos, count);
199  rbuf->read_pos += count;
200  } else {
201  memcpy(data, rbuf->buffer+pos, rest);
202  if ( count - rest)
203  memcpy(data+rest, rbuf->buffer, count - rest);
204  rbuf->read_pos = count - rest;
205  }
206 
207  if (DEBUG>1)
208  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%%")
209  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
210  return count;
211 }
212 
213 int ring_skip(ringbuffer *rbuf, int count)
214 {
215  if (count <=0 ) return -1;
216  int pos = rbuf->read_pos;
217  int rest = rbuf->size - pos;
218  int avail = ring_avail(rbuf);
219 
220  if ( avail < count ){
221 #if 0
222  LOG(VB_GENERAL, LOG_ERR,
223  QString("ringbuffer skip underflow %1<%2 %3 %4\n")
224  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
225 #endif
226  return EMPTY_BUFFER;
227  }
228  if ( count < rest ){
229  rbuf->read_pos += count;
230  } else {
231  rbuf->read_pos = count - rest;
232  }
233 
234  if (DEBUG>1)
235  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%%")
236  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
237  return count;
238 }
239 
240 
241 
242 int ring_write_file(ringbuffer *rbuf, int fd, int count)
243 {
244  int rr = 0;
245 
246  if (count <=0 ) return 0;
247  int pos = rbuf->write_pos;
248  int rest = rbuf->size - pos;
249  int free = ring_free(rbuf);
250 
251  if ( free < count ){
252  if (DEBUG) {
253  LOG(VB_GENERAL, LOG_ERR,
254  QString("ringbuffer overflow %1<%2 %3 %4\n")
255  .arg(free).arg(count).arg(pos).arg(rbuf->read_pos));
256  }
257  return FULL_BUFFER;
258  }
259 
260  if (count >= rest){
261  rr = read (fd, rbuf->buffer+pos, rest);
262  if (rr == rest && count - rest)
263  rr += read (fd, rbuf->buffer, count - rest);
264  if (rr >=0)
265  rbuf->write_pos = (pos + rr) % rbuf->size;
266  } else {
267  rr = read (fd, rbuf->buffer+pos, count);
268  if (rr >=0)
269  rbuf->write_pos += rr;
270  }
271 
272  if (DEBUG>1)
273  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %.2f%%")
274  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
275  return rr;
276 }
277 
278 
279 
280 int ring_read_file(ringbuffer *rbuf, int fd, int count)
281 {
282  int rr = 0;
283 
284  if (count <=0 ) return -1;
285  int pos = rbuf->read_pos;
286  int rest = rbuf->size - pos;
287  int avail = ring_avail(rbuf);
288 
289  if ( avail < count ){
290 #if 0
291  if (DEBUG)
292  LOG(VB_GENERAL, LOG_ERR,
293  QString("ringbuffer underflow %1<%2 %3 %4")
294  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
295 #endif
296  return EMPTY_BUFFER;
297  }
298 
299  if (count >= rest){
300  rr = write (fd, rbuf->buffer+pos, rest);
301  if (rr == rest && count - rest)
302  rr += write (fd, rbuf->buffer, count - rest);
303  if (rr >=0)
304  rbuf->read_pos = (pos + rr) % rbuf->size;
305  } else {
306  rr = write (fd, rbuf->buffer+pos, count);
307  if (rr >=0)
308  rbuf->read_pos += rr;
309  }
310 
311 
312  if (DEBUG>1)
313  LOG(VB_GENERAL, LOG_ERR, QString("Buffer empty %1%%")
314  .arg(ring_free(rbuf)*100.0/rbuf->size, 0,'f',2,QChar('0')));
315  return rr;
316 }
317 
318 
319 static void show(uint8_t *buf, int length)
320 {
321  char temp[8];
322  char buffer[100];
323  buffer[0] = '\0';
324 
325  for (int i=0; i<length; i+=16){
326  int j = 0;
327  for (j=0; j < 8 && j+i<length; j++)
328  {
329  std::sprintf(temp, "0x%02x ", (int)(buf[i+j]));
330  std::strcat(buffer, temp);
331  }
332  for (int r=j; r<8; r++)
333  std::strcat(buffer, " ");
334 
335  std::strcat(buffer," ");
336 
337  for (j=8; j < 16 && j+i<length; j++)
338  {
339  std::sprintf(temp, "0x%02x ", (int)(buf[i+j]));
340  std::strcat(buffer, temp);
341  }
342  for (int r=j; r<16; r++)
343  std::strcat(buffer, " ");
344 
345  for (j=0; j < 16 && j+i<length; j++){
346  switch(buf[i+j]){
347  case '0'...'Z':
348  case 'a'...'z':
349  std::sprintf(temp, "%c", buf[i+j]);
350  break;
351  default:
352  std::sprintf(temp, ".");
353  }
354  std::strcat(buffer, temp);
355  }
356  LOG(VB_GENERAL, LOG_INFO, buffer);
357  }
358 }
359 
360 void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
361 {
362  if (off+count > rbuf->size || off+count >ring_avail(rbuf))
363  return;
364  unsigned int pos = (rbuf->read_pos+off)%rbuf->size;
365  unsigned int rest = rbuf->size - pos ;
366  unsigned int avail = ring_avail(rbuf);
367 
368  if ( avail < count ){
369 #if 0
370  if (DEBUG)
371  LOG(VB_GENERAL, LOG_ERR,
372  QString("ringbuffer peek underflow %1<%2 %3 %4\n")
373  .arg(avail).arg(count).arg(pos).arg(rbuf->write_pos));
374 #endif
375  return;
376  }
377 
378  if ( count < rest ){
379  show(rbuf->buffer+pos, count);
380  } else {
381  show(rbuf->buffer+pos, rest);
382  if ( count - rest)
383  show(rbuf->buffer, count - rest);
384  }
385 }
386 
387 
388 int dummy_init(dummy_buffer *dbuf, int s)
389 {
390  dbuf->size = s;
391  dbuf->fill = 0;
392  if (ring_init(&dbuf->time_index, DBUF_INDEX*sizeof(uint64_t)) < 0)
393  return -1;
394  if (ring_init(&dbuf->data_index, DBUF_INDEX*sizeof(int32_t)) < 0)
395  return -1;
396 
397  return 0;
398 }
399 
401 {
402  ring_destroy(&dbuf->time_index);
403  ring_destroy(&dbuf->data_index);
404 }
405 
407 {
408  dbuf->fill = 0;
409  ring_clear(&dbuf->time_index);
410  ring_clear(&dbuf->data_index);
411 }
412 
413 int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
414 {
415  if (dummy_space(dbuf) < size) return -1;
416 #if 0
417  LOG(VB_GENERAL, LOG_INFO, QString("add %1 ").arg(dummy_space(dbuf)));
418 #endif
419  dbuf->fill += size;
420  if (ring_write(&dbuf->time_index, (uint8_t *)&time, sizeof(uint64_t)) < 0)
421  return -2;
422  if (ring_write(&dbuf->data_index, (uint8_t *)&size, sizeof(uint32_t)) < 0)
423  return -3;
424 #if 0
425  LOG(VB_GENERAL, LOG_INFO,
426  QString(" - %1 = %2").arg(size).arg(dummy_space(dbuf)));
427 #endif
428  return size;
429 }
430 
431 int dummy_delete(dummy_buffer *dbuf, uint64_t time)
432 {
433  uint64_t rtime = 0;
434  uint32_t size = 0;
435  int ex=0;
436  uint32_t dsize=0;
437 
438  do {
439  if (ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
440  sizeof(uint64_t), 0)<0){
441  if (dsize) break;
442  return -1;
443  }
444  if (ptscmp(rtime,time) < 0){
445  ring_read(&dbuf->time_index,(uint8_t *) &rtime,
446  sizeof(uint64_t));
447  ring_read(&dbuf->data_index,(uint8_t *) &size,
448  sizeof(uint32_t));
449  dsize += size;
450  } else ex = 1;
451  } while (ex == 0);
452 #if 0
453  LOG(VB_GENERAL, LOG_INFO, QString("delete %1 ").arg(dummy_space(dbuf)));
454 #endif
455  dbuf->fill -= dsize;
456 #if 0
457  LOG(VB_GENERAL, LOG_INFO,
458  QString(" + %1 = %2").arg(dsize).arg(dummy_space(dbuf)));
459 #endif
460 
461  return dsize;
462 }
463 
464 #if 0
465 static void dummy_print(dummy_buffer *dbuf)
466 {
467  uint64_t rtime = 0;
468  uint32_t size = 0;
469  int avail = ring_avail(&dbuf->time_index) / sizeof(uint64_t);
470  for (int i = 0; i < avail; i++) {
471  ring_peek(&dbuf->time_index,(uint8_t *) &rtime,
472  sizeof(uint64_t), i * sizeof(uint64_t));
473  ring_peek(&dbuf->data_index,(uint8_t *) &size,
474  sizeof(uint32_t), i * sizeof(uint32_t));
475 
476  LOG(VB_GENERAL, LOG_INFO, QString("%1 : %2 %3").arg(i)
477  .arg(rtime).arg(size));
478  }
479  LOG(VB_GENERAL, LOG_INFO, QString("Used: %d Free: %d data-free: %d")
480  .arg(avail).arg(1000-avail).arg(dbuf->size - dbuf->fill));
481 }
482 #endif
def write(text, progress=True)
Definition: mythburn.py:308
int write_pos
Definition: ringbuffer.h:38
int dummy_add(dummy_buffer *dbuf, uint64_t time, uint32_t size)
Definition: ringbuffer.cpp:413
int ring_write(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:90
void dummy_clear(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:406
ringbuffer time_index
Definition: ringbuffer.h:49
static uint32_t dummy_space(dummy_buffer *dbuf)
Definition: ringbuffer.h:108
int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:180
uint32_t size
Definition: ringbuffer.h:47
#define FULL_BUFFER
Definition: ringbuffer.h:34
int ring_reinit(ringbuffer *rbuf, int size)
Definition: ringbuffer.cpp:56
def read(device=None, features=[])
Definition: disc.py:35
int ring_skip(ringbuffer *rbuf, int count)
Definition: ringbuffer.cpp:213
static unsigned int ring_avail(ringbuffer *rbuf)
Definition: ringbuffer.h:99
int ring_poke(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:151
int dummy_init(dummy_buffer *dbuf, int s)
Definition: ringbuffer.cpp:388
int ring_init(ringbuffer *rbuf, int size)
Definition: ringbuffer.cpp:38
#define DEBUG
Definition: ringbuffer.cpp:36
int dummy_delete(dummy_buffer *dbuf, uint64_t time)
Definition: ringbuffer.cpp:431
uint8_t * buffer
Definition: ringbuffer.h:40
static unsigned int ring_free(ringbuffer *rbuf)
Definition: ringbuffer.h:92
int ring_peek(ringbuffer *rbuf, uint8_t *data, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:122
static void show(uint8_t *buf, int length)
Definition: ringbuffer.cpp:319
uint32_t size
Definition: ringbuffer.h:39
int ring_read_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:280
uint32_t fill
Definition: ringbuffer.h:48
void ring_destroy(ringbuffer *rbuf)
Definition: ringbuffer.cpp:84
int read_pos
Definition: ringbuffer.h:37
#define EMPTY_BUFFER
Definition: ringbuffer.h:35
void ring_show(ringbuffer *rbuf, unsigned int count, uint32_t off)
Definition: ringbuffer.cpp:360
void ring_clear(ringbuffer *rbuf)
Definition: ringbuffer.cpp:76
void dummy_destroy(dummy_buffer *dbuf)
Definition: ringbuffer.cpp:400
int ring_write_file(ringbuffer *rbuf, int fd, int count)
Definition: ringbuffer.cpp:242
int ptscmp(uint64_t pts1, uint64_t pts2)
Definition: pes.cpp:113
ringbuffer data_index
Definition: ringbuffer.h:50
#define DBUF_INDEX
Definition: ringbuffer.h:44
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23