1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#ifndef VC_CONTAINERS_BYTESTREAM_H
28#define VC_CONTAINERS_BYTESTREAM_H
29
30/** \file
31 * Utility functions to provide a byte stream out of a list of container packets
32 */
33
34typedef struct VC_CONTAINER_BYTESTREAM_T
35{
36 VC_CONTAINER_PACKET_T *first; /**< first packet in the chain */
37 VC_CONTAINER_PACKET_T **last; /**< last packet in the chain */
38
39 VC_CONTAINER_PACKET_T *current; /**< packet containing the current read pointer */
40 size_t current_offset; /**< position of current packet (in bytes) */
41 size_t offset; /**< position within the current packet */
42
43 size_t bytes; /**< Number of bytes available in the bytestream */
44
45} VC_CONTAINER_BYTESTREAM_T;
46
47/*****************************************************************************/
48STATIC_INLINE void bytestream_init( VC_CONTAINER_BYTESTREAM_T *stream )
49{
50 stream->first = stream->current = NULL;
51 stream->last = &stream->first;
52 stream->offset = stream->current_offset = stream->bytes = 0;
53}
54
55STATIC_INLINE void bytestream_push( VC_CONTAINER_BYTESTREAM_T *stream,
56 VC_CONTAINER_PACKET_T *packet )
57{
58 *stream->last = packet;
59 stream->last = &packet->next;
60 packet->next = NULL;
61 if( !stream->current ) stream->current = packet;
62 stream->bytes += packet->size;
63}
64
65STATIC_INLINE VC_CONTAINER_PACKET_T *bytestream_pop( VC_CONTAINER_BYTESTREAM_T *stream )
66{
67 VC_CONTAINER_PACKET_T *packet = stream->first;
68
69 if( stream->current == packet )
70 return NULL;
71 vc_container_assert(packet);
72
73 stream->bytes -= packet->size;
74 stream->current_offset -= packet->size;
75 stream->first = packet->next;
76 if( !stream->first )
77 stream->last = &stream->first;
78 return packet;
79}
80
81STATIC_INLINE VC_CONTAINER_PACKET_T *bytestream_get_packet( VC_CONTAINER_BYTESTREAM_T *stream, size_t *offset )
82{
83 VC_CONTAINER_PACKET_T *packet = stream->current;
84 size_t off = stream->offset;
85
86 while(packet && packet->size == off)
87 {
88 packet = packet->next;
89 off = 0;
90 }
91
92 if (offset)
93 *offset = off;
94
95 return packet;
96}
97
98STATIC_INLINE bool bytestream_skip_packet( VC_CONTAINER_BYTESTREAM_T *stream )
99{
100 VC_CONTAINER_PACKET_T *packet = stream->current;
101
102 if( packet )
103 {
104 stream->current = packet->next;
105 stream->current_offset += (packet->size - stream->offset);
106 stream->offset = 0;
107 }
108
109 return !!packet;
110}
111
112STATIC_INLINE void bytestream_get_timestamps( VC_CONTAINER_BYTESTREAM_T *stream, int64_t *pts, int64_t *dts, bool b_same )
113{
114 VC_CONTAINER_PACKET_T *packet = bytestream_get_packet( stream, 0 );
115
116 if(packet)
117 {
118 if(b_same && packet->pts == VC_CONTAINER_TIME_UNKNOWN) packet->pts = packet->dts;
119 if(pts) *pts = packet->pts;
120 if(dts) *dts = packet->dts;
121
122 packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
123 return;
124 }
125
126 if(pts) *pts = VC_CONTAINER_TIME_UNKNOWN;
127 if(dts) *dts = VC_CONTAINER_TIME_UNKNOWN;
128}
129
130STATIC_INLINE void bytestream_get_timestamps_and_offset( VC_CONTAINER_BYTESTREAM_T *stream,
131 int64_t *pts, int64_t *dts, size_t *offset, bool b_same )
132{
133 VC_CONTAINER_PACKET_T *packet = bytestream_get_packet( stream, offset );
134
135 if(packet)
136 {
137 if(b_same && packet->pts == VC_CONTAINER_TIME_UNKNOWN) packet->pts = packet->dts;
138 if(pts) *pts = packet->pts;
139 if(dts) *dts = packet->dts;
140
141 packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
142 return;
143 }
144
145 if(pts) *pts = VC_CONTAINER_TIME_UNKNOWN;
146 if(dts) *dts = VC_CONTAINER_TIME_UNKNOWN;
147}
148
149STATIC_INLINE size_t bytestream_size( VC_CONTAINER_BYTESTREAM_T *stream )
150{
151 return stream->bytes - stream->current_offset - stream->offset;
152}
153
154STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_skip( VC_CONTAINER_BYTESTREAM_T *stream, size_t size )
155{
156 VC_CONTAINER_PACKET_T *packet;
157 size_t offset, bytes = 0, skip;
158
159 if( !size )
160 return VC_CONTAINER_SUCCESS; /* Nothing to do */
161 if( stream->bytes - stream->current_offset - stream->offset < size )
162 return VC_CONTAINER_ERROR_EOS; /* Not enough data */
163
164 for( packet = stream->current, offset = stream->offset; ;
165 packet = packet->next, offset = 0 )
166 {
167 if( packet->size - offset >= size)
168 break;
169
170 skip = packet->size - offset;
171 bytes += skip;
172 size -= skip;
173 }
174
175 stream->current = packet;
176 stream->current_offset += stream->offset - offset + bytes;
177 stream->offset = offset + size;
178 return VC_CONTAINER_SUCCESS;
179}
180
181STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_get( VC_CONTAINER_BYTESTREAM_T *stream, uint8_t *data, size_t size )
182{
183 VC_CONTAINER_PACKET_T *packet;
184 size_t offset, bytes = 0, copy;
185
186 if( !size )
187 return VC_CONTAINER_SUCCESS; /* Nothing to do */
188 if( stream->bytes - stream->current_offset - stream->offset < size )
189 return VC_CONTAINER_ERROR_EOS; /* Not enough data */
190
191 for( packet = stream->current, offset = stream->offset; ;
192 packet = packet->next, offset = 0 )
193 {
194 if( packet->size - offset >= size)
195 break;
196
197 copy = packet->size - offset;
198 memcpy( data, packet->data + offset, copy );
199 bytes += copy;
200 data += copy;
201 size -= copy;
202 }
203
204 memcpy( data, packet->data + offset, size );
205 stream->current = packet;
206 stream->current_offset += stream->offset - offset + bytes;
207 stream->offset = offset + size;
208 return VC_CONTAINER_SUCCESS;
209}
210
211STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_peek( VC_CONTAINER_BYTESTREAM_T *stream, uint8_t *data, size_t size )
212{
213 VC_CONTAINER_PACKET_T *packet;
214 size_t offset, copy;
215
216 if( !size )
217 return VC_CONTAINER_SUCCESS; /* Nothing to do */
218 if( stream->bytes - stream->current_offset - stream->offset < size )
219 return VC_CONTAINER_ERROR_EOS; /* Not enough data */
220
221 for( packet = stream->current, offset = stream->offset; ;
222 packet = packet->next, offset = 0 )
223 {
224 if( packet->size - offset >= size)
225 break;
226
227 copy = packet->size - offset;
228 memcpy( data, packet->data + offset, copy );
229 data += copy;
230 size -= copy;
231 }
232
233 memcpy( data, packet->data + offset, size );
234 return VC_CONTAINER_SUCCESS;
235}
236
237STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_peek_at( VC_CONTAINER_BYTESTREAM_T *stream,
238 size_t peek_offset, uint8_t *data, size_t size )
239{
240 VC_CONTAINER_PACKET_T *packet;
241 size_t copy;
242
243 if( !size )
244 return VC_CONTAINER_SUCCESS; /* Nothing to do */
245 if( stream->bytes - stream->current_offset - stream->offset < peek_offset + size )
246 return VC_CONTAINER_ERROR_EOS; /* Not enough data */
247
248 peek_offset += stream->offset;
249
250 /* Find the right place */
251 for( packet = stream->current; ; packet = packet->next )
252 {
253 if( packet->size > peek_offset )
254 break;
255
256 peek_offset -= packet->size;
257 }
258
259 /* Copy the data */
260 for( ; ; packet = packet->next, peek_offset = 0 )
261 {
262 if( packet->size - peek_offset >= size)
263 break;
264
265 copy = packet->size - peek_offset;
266 memcpy( data, packet->data + peek_offset, copy );
267 data += copy;
268 size -= copy;
269 }
270
271 memcpy( data, packet->data + peek_offset, size );
272 return VC_CONTAINER_SUCCESS;
273}
274
275STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_skip_byte( VC_CONTAINER_BYTESTREAM_T *stream )
276{
277 VC_CONTAINER_PACKET_T *packet = stream->current;
278
279 if( !packet )
280 return VC_CONTAINER_ERROR_EOS;
281
282 /* Fast path first */
283 if( packet->size - stream->offset )
284 {
285 stream->offset++;
286 return VC_CONTAINER_SUCCESS;
287 }
288
289 return bytestream_skip( stream, 1 );
290}
291
292STATIC_INLINE VC_CONTAINER_STATUS_T packet_peek_byte( VC_CONTAINER_BYTESTREAM_T *stream,
293 uint8_t *data )
294{
295 VC_CONTAINER_PACKET_T *packet = stream->current;
296
297 if( !packet )
298 return VC_CONTAINER_ERROR_EOS;
299
300 /* Fast path first */
301 if( packet->size - stream->offset )
302 {
303 *data = packet->data[stream->offset];
304 return VC_CONTAINER_SUCCESS;
305 }
306
307 return bytestream_peek( stream, data, 1 );
308}
309
310STATIC_INLINE VC_CONTAINER_STATUS_T packet_get_byte( VC_CONTAINER_BYTESTREAM_T *stream,
311 uint8_t *data )
312{
313 VC_CONTAINER_PACKET_T *packet = stream->current;
314
315 if( !packet )
316 return VC_CONTAINER_ERROR_EOS;
317
318 /* Fast path first */
319 if( packet->size - stream->offset )
320 {
321 *data = packet->data[stream->offset];
322 stream->offset++;
323 return VC_CONTAINER_SUCCESS;
324 }
325
326 return bytestream_get( stream, data, 1 );
327}
328
329STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_find_startcode( VC_CONTAINER_BYTESTREAM_T *stream,
330 size_t *search_offset, const uint8_t *startcode, unsigned int length )
331{
332 VC_CONTAINER_PACKET_T *packet, *backup_packet = NULL;
333 size_t position, start_offset = position = *search_offset;
334 size_t offset, backup_offset = 0;
335 unsigned int match = 0;
336
337 if( stream->bytes - stream->current_offset - stream->offset < start_offset + length )
338 return VC_CONTAINER_ERROR_EOS; /* Not enough data */
339
340 /* Find the right place */
341 for( packet = stream->current, offset = stream->offset;
342 packet != NULL; packet = packet->next, offset = 0 )
343 {
344 if( packet->size - offset > start_offset)
345 break;
346
347 start_offset -= (packet->size - offset);
348 }
349
350 /* Start the search for the start code.
351 * To make things simple we try to find a match one byte at a time. */
352 for( offset += start_offset;
353 packet != NULL; packet = packet->next, offset = 0 )
354 {
355 for( ; offset < packet->size; offset++ )
356 {
357 if( packet->data[offset] != startcode[match] )
358 {
359 if ( match ) /* False positive */
360 {
361 packet = backup_packet;
362 offset = backup_offset;
363 match = 0;
364 }
365 position++;
366 continue;
367 }
368
369 /* We've got a match */
370 if( !match++ )
371 {
372 backup_packet = packet;
373 backup_offset = offset;
374 }
375
376 if( match == length )
377 {
378 /* We have the full start code it */
379 *search_offset = position;
380 return VC_CONTAINER_SUCCESS;
381 }
382 }
383 }
384
385 *search_offset = position;
386 return VC_CONTAINER_ERROR_EOS; /* No luck in finding the start code */
387}
388
389#endif /* VC_CONTAINERS_BYTESTREAM_H */
390