2 * Copyright (C) 2010-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
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;
16 //#define AE_RING_BUFFER_DEBUG
18 #include "utils/log.h"
19 #include "utils/MemUtils.h"
24 * This buffer can be used by one read and one write thread at any one time
25 * without the risk of data corruption.
26 * If you intend to call the Reset() method, please use Locks.
27 * All other operations are thread-safe.
32 AERingBuffer() = default;
34 AERingBuffer(unsigned int size
, unsigned int planes
= 1) { Create(size
, planes
); }
38 #ifdef AE_RING_BUFFER_DEBUG
39 CLog::Log(LOGDEBUG
, "AERingBuffer::~AERingBuffer: Deleting buffer.");
41 for (unsigned int i
= 0; i
< m_planes
; i
++)
42 KODI::MEMORY::AlignedFree(m_Buffer
[i
]);
47 * Allocates space for buffer, and sets it's contents to 0.
49 * @return true on success, false otherwise
51 bool Create(int size
, unsigned int planes
= 1)
53 m_Buffer
= new unsigned char*[planes
];
54 for (unsigned int i
= 0; i
< planes
; i
++)
56 m_Buffer
[i
] = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(size
, 16));
59 memset(m_Buffer
[i
], 0, size
);
67 * Fills the buffer with zeros and resets the pointers.
68 * This method is not thread-safe, so before using this method
69 * please acquire a Lock()
72 #ifdef AE_RING_BUFFER_DEBUG
73 CLog::Log(LOGDEBUG
, "AERingBuffer::Reset: Buffer reset.");
82 * Writes data to buffer.
83 * Attempt to write more bytes than available results in AE_RING_BUFFER_FULL.
85 * @return AE_RING_BUFFER_OK on success, otherwise an error code
87 int Write(unsigned char *src
, unsigned int size
, unsigned int plane
= 0)
89 unsigned int space
= GetWriteSize();
91 //do we have enough space for all the data?
92 if (size
> space
|| plane
>= m_planes
)
94 #ifdef AE_RING_BUFFER_DEBUG
96 "AERingBuffer: Not enough space, ignoring data. Requested: {} Available: {}", size
,
99 return AE_RING_BUFFER_FULL
;
103 if ( m_iSize
> size
+ m_iWritePos
)
105 #ifdef AE_RING_BUFFER_DEBUG
106 CLog::Log(LOGDEBUG
, "AERingBuffer: Written to: {} size: {} space before: {}", m_iWritePos
,
109 memcpy(m_Buffer
[plane
] + m_iWritePos
, src
, size
);
114 unsigned int first
= m_iSize
- m_iWritePos
;
115 unsigned int second
= size
- first
;
116 #ifdef AE_RING_BUFFER_DEBUG
118 "AERingBuffer: Written to (split) first: {} second: {} size: {} space before: {}",
119 first
, second
, size
, space
);
121 memcpy(m_Buffer
[plane
] + m_iWritePos
, src
, first
);
122 memcpy(m_Buffer
[plane
], src
+ first
, second
);
124 if (plane
+ 1 == m_planes
)
127 return AE_RING_BUFFER_OK
;
131 * Reads data from buffer.
132 * Attempt to read more bytes than available results in RING_BUFFER_NOTAVAILABLE.
133 * Reading from empty buffer returns AE_RING_BUFFER_EMPTY
135 * @return AE_RING_BUFFER_OK on success, otherwise an error code
137 int Read(unsigned char *dest
, unsigned int size
, unsigned int plane
= 0)
139 unsigned int space
= GetReadSize();
141 //want to read more than we have written?
144 #ifdef AE_RING_BUFFER_DEBUG
145 CLog::Log(LOGDEBUG
, "AERingBuffer: Can't read from empty buffer.");
147 return AE_RING_BUFFER_EMPTY
;
150 //want to read more than we have available
151 if( size
> space
|| plane
>= m_planes
)
153 #ifdef AE_RING_BUFFER_DEBUG
154 CLog::Log(LOGDEBUG
, "AERingBuffer: Can't read {} bytes when we only have {}.", size
, space
);
156 return AE_RING_BUFFER_NOTAVAILABLE
;
160 if ( size
+ m_iReadPos
< m_iSize
)
162 #ifdef AE_RING_BUFFER_DEBUG
163 CLog::Log(LOGDEBUG
, "AERingBuffer: Reading from: {} size: {} space before: {}", m_iWritePos
,
167 memcpy(dest
, m_Buffer
[plane
] + m_iReadPos
, size
);
172 unsigned int first
= m_iSize
- m_iReadPos
;
173 unsigned int second
= size
- first
;
174 #ifdef AE_RING_BUFFER_DEBUG
176 "AERingBuffer: Reading from (split) first: {} second: {} size: {} space before: {}",
177 first
, second
, size
, space
);
181 memcpy(dest
, m_Buffer
[plane
] + m_iReadPos
, first
);
182 memcpy(dest
+ first
, m_Buffer
[plane
], second
);
185 if (plane
+ 1 == m_planes
)
188 return AE_RING_BUFFER_OK
;
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
++)
200 for (unsigned int i
=0; i
<m_iSize
; i
++)
202 if (i
>= m_iReadPos
&& i
<m_iWritePos
)
203 *dest
++ = m_Buffer
[j
][i
];
208 bufferContents
[m_iSize
*m_planes
] = '\0';
209 CLog::LogF(LOGDEBUG
, "Buffer Content: {}", reinterpret_cast<const char*>(bufferContents
));
210 KODI::MEMORY::AlignedFree(bufferContents
);
214 * Returns available space for writing to buffer.
215 * Attempt to write more bytes than available results in AE_RING_BUFFER_FULL.
217 unsigned int GetWriteSize()
219 return m_iSize
- ( m_iWritten
- m_iRead
);
223 * Returns available space for reading from buffer.
224 * Attempt to read more bytes than available results in AE_RING_BUFFER_EMPTY.
226 unsigned int GetReadSize()
228 return m_iWritten
- m_iRead
;
232 * Returns the buffer size.
234 unsigned int GetMaxSize()
240 * Returns the number of planes
242 unsigned int NumPlanes() const
248 * Increments the write pointer.
249 * Called at the end of writing to all planes.
251 void WriteFinished(unsigned int size
)
253 if ( m_iSize
> size
+ m_iWritePos
)
256 m_iWritePos
= size
- (m_iSize
- m_iWritePos
);
258 //we can increase the write count now
263 * Increments the read pointer.
264 * Called at the end of reading to all planes.
266 void ReadFinished(unsigned int size
)
268 if ( size
+ m_iReadPos
< m_iSize
)
271 m_iReadPos
= size
- (m_iSize
- m_iReadPos
);
273 //we can increase the read count now
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;