xbmc
AERingBuffer.h
1 /*
2  * Copyright (C) 2010-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #define AE_RING_BUFFER_OK 0;
12 #define AE_RING_BUFFER_EMPTY 1;
13 #define AE_RING_BUFFER_FULL 2;
14 #define AE_RING_BUFFER_NOTAVAILABLE 3;
15 
16 //#define AE_RING_BUFFER_DEBUG
17 
18 #include "utils/log.h"
19 #include "utils/MemUtils.h"
20 
21 #include <string.h>
22 
29 class AERingBuffer {
30 
31 public:
32  AERingBuffer() = default;
33 
34  AERingBuffer(unsigned int size, unsigned int planes = 1) { Create(size, planes); }
35 
36  ~AERingBuffer()
37  {
38 #ifdef AE_RING_BUFFER_DEBUG
39  CLog::Log(LOGDEBUG, "AERingBuffer::~AERingBuffer: Deleting buffer.");
40 #endif
41  for (unsigned int i = 0; i < m_planes; i++)
42  KODI::MEMORY::AlignedFree(m_Buffer[i]);
43  delete[] m_Buffer;
44  }
45 
51  bool Create(int size, unsigned int planes = 1)
52  {
53  m_Buffer = new unsigned char*[planes];
54  for (unsigned int i = 0; i < planes; i++)
55  {
56  m_Buffer[i] = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(size, 16));
57  if (!m_Buffer[i])
58  return false;
59  memset(m_Buffer[i], 0, size);
60  }
61  m_iSize = size;
62  m_planes = planes;
63  return true;
64  }
65 
71  void Reset() {
72 #ifdef AE_RING_BUFFER_DEBUG
73  CLog::Log(LOGDEBUG, "AERingBuffer::Reset: Buffer reset.");
74 #endif
75  m_iWritten = 0;
76  m_iRead = 0;
77  m_iReadPos = 0;
78  m_iWritePos = 0;
79  }
80 
87  int Write(unsigned char *src, unsigned int size, unsigned int plane = 0)
88  {
89  unsigned int space = GetWriteSize();
90 
91  //do we have enough space for all the data?
92  if (size > space || plane >= m_planes)
93  {
94 #ifdef AE_RING_BUFFER_DEBUG
95  CLog::Log(LOGDEBUG,
96  "AERingBuffer: Not enough space, ignoring data. Requested: {} Available: {}", size,
97  space);
98 #endif
99  return AE_RING_BUFFER_FULL;
100  }
101 
102  //no wrapping?
103  if ( m_iSize > size + m_iWritePos )
104  {
105 #ifdef AE_RING_BUFFER_DEBUG
106  CLog::Log(LOGDEBUG, "AERingBuffer: Written to: {} size: {} space before: {}", m_iWritePos,
107  size, space);
108 #endif
109  memcpy(m_Buffer[plane] + m_iWritePos, src, size);
110  }
111  //need to wrap
112  else
113  {
114  unsigned int first = m_iSize - m_iWritePos;
115  unsigned int second = size - first;
116 #ifdef AE_RING_BUFFER_DEBUG
117  CLog::Log(LOGDEBUG,
118  "AERingBuffer: Written to (split) first: {} second: {} size: {} space before: {}",
119  first, second, size, space);
120 #endif
121  memcpy(m_Buffer[plane] + m_iWritePos, src, first);
122  memcpy(m_Buffer[plane], src + first, second);
123  }
124  if (plane + 1 == m_planes)
125  WriteFinished(size);
126 
127  return AE_RING_BUFFER_OK;
128  }
129 
137  int Read(unsigned char *dest, unsigned int size, unsigned int plane = 0)
138  {
139  unsigned int space = GetReadSize();
140 
141  //want to read more than we have written?
142  if( space == 0 )
143  {
144 #ifdef AE_RING_BUFFER_DEBUG
145  CLog::Log(LOGDEBUG, "AERingBuffer: Can't read from empty buffer.");
146 #endif
147  return AE_RING_BUFFER_EMPTY;
148  }
149 
150  //want to read more than we have available
151  if( size > space || plane >= m_planes)
152  {
153 #ifdef AE_RING_BUFFER_DEBUG
154  CLog::Log(LOGDEBUG, "AERingBuffer: Can't read {} bytes when we only have {}.", size, space);
155 #endif
156  return AE_RING_BUFFER_NOTAVAILABLE;
157  }
158 
159  //no wrapping?
160  if ( size + m_iReadPos < m_iSize )
161  {
162 #ifdef AE_RING_BUFFER_DEBUG
163  CLog::Log(LOGDEBUG, "AERingBuffer: Reading from: {} size: {} space before: {}", m_iWritePos,
164  size, space);
165 #endif
166  if (dest)
167  memcpy(dest, m_Buffer[plane] + m_iReadPos, size);
168  }
169  //need to wrap
170  else
171  {
172  unsigned int first = m_iSize - m_iReadPos;
173  unsigned int second = size - first;
174 #ifdef AE_RING_BUFFER_DEBUG
175  CLog::Log(LOGDEBUG,
176  "AERingBuffer: Reading from (split) first: {} second: {} size: {} space before: {}",
177  first, second, size, space);
178 #endif
179  if (dest)
180  {
181  memcpy(dest, m_Buffer[plane] + m_iReadPos, first);
182  memcpy(dest + first, m_Buffer[plane], second);
183  }
184  }
185  if (plane + 1 == m_planes)
186  ReadFinished(size);
187 
188  return AE_RING_BUFFER_OK;
189  }
190 
194  void Dump()
195  {
196  unsigned char *bufferContents = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(m_iSize * m_planes + 1, 16));
197  unsigned char *dest = bufferContents;
198  for (unsigned int j = 0; j < m_planes; j++)
199  {
200  for (unsigned int i=0; i<m_iSize; i++)
201  {
202  if (i >= m_iReadPos && i<m_iWritePos)
203  *dest++ = m_Buffer[j][i];
204  else
205  *dest++ = '_';
206  }
207  }
208  bufferContents[m_iSize*m_planes] = '\0';
209  CLog::LogF(LOGDEBUG, "Buffer Content: {}", reinterpret_cast<const char*>(bufferContents));
210  KODI::MEMORY::AlignedFree(bufferContents);
211  }
212 
217  unsigned int GetWriteSize()
218  {
219  return m_iSize - ( m_iWritten - m_iRead );
220  }
221 
226  unsigned int GetReadSize()
227  {
228  return m_iWritten - m_iRead;
229  }
230 
234  unsigned int GetMaxSize()
235  {
236  return m_iSize;
237  }
238 
242  unsigned int NumPlanes() const
243  {
244  return m_planes;
245  }
246 private:
251  void WriteFinished(unsigned int size)
252  {
253  if ( m_iSize > size + m_iWritePos )
254  m_iWritePos += size;
255  else // wrapping
256  m_iWritePos = size - (m_iSize - m_iWritePos);
257 
258  //we can increase the write count now
259  m_iWritten+=size;
260  }
261 
266  void ReadFinished(unsigned int size)
267  {
268  if ( size + m_iReadPos < m_iSize )
269  m_iReadPos += size;
270  else
271  m_iReadPos = size - (m_iSize - m_iReadPos);
272 
273  //we can increase the read count now
274  m_iRead+=size;
275  }
276 
277  unsigned int m_iReadPos = 0;
278  unsigned int m_iWritePos = 0;
279  unsigned int m_iRead = 0;
280  unsigned int m_iWritten = 0;
281  unsigned int m_iSize = 0;
282  unsigned int m_planes = 0;
283  unsigned char** m_Buffer = nullptr;
284 };
unsigned int GetReadSize()
Returns available space for reading from buffer.
Definition: AERingBuffer.h:226
unsigned int NumPlanes() const
Returns the number of planes.
Definition: AERingBuffer.h:242
void Dump()
Dumps the buffer.
Definition: AERingBuffer.h:194
bool Create(int size, unsigned int planes=1)
Allocates space for buffer, and sets it&#39;s contents to 0.
Definition: AERingBuffer.h:51
This buffer can be used by one read and one write thread at any one time without the risk of data cor...
Definition: AERingBuffer.h:29
void Reset()
Fills the buffer with zeros and resets the pointers.
Definition: AERingBuffer.h:71
unsigned int GetWriteSize()
Returns available space for writing to buffer.
Definition: AERingBuffer.h:217
int Read(unsigned char *dest, unsigned int size, unsigned int plane=0)
Reads data from buffer.
Definition: AERingBuffer.h:137
int Write(unsigned char *src, unsigned int size, unsigned int plane=0)
Writes data to buffer.
Definition: AERingBuffer.h:87
unsigned int GetMaxSize()
Returns the buffer size.
Definition: AERingBuffer.h:234