qt: playlist: use item title if available
[vlc.git] / modules / demux / xiph.h
blobc0b2ec83301d3140e1ea5c49a2dfd23dffe9f535
1 /*****************************************************************************
2 * xiph.h: Xiph helpers
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
6 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #include <assert.h>
24 #include <limits.h>
25 #define XIPH_MAX_HEADER_COUNT (256)
27 /* Temp ffmpeg vorbis format */
28 static inline bool xiph_IsLavcFormat(const void *extra, unsigned i_extra,
29 vlc_fourcc_t i_codec)
31 switch(i_codec)
33 case VLC_CODEC_VORBIS:
34 return i_extra >= 6 && GetWBE(extra) == 30;
35 case VLC_CODEC_THEORA:
36 return i_extra >= 6 && GetWBE(extra) == 42;
37 default:
38 return false;
42 static inline unsigned xiph_CountLavcHeaders(const void *p_extra, unsigned i_extra)
44 const uint8_t *p = (const uint8_t*) p_extra;
45 const uint8_t *p_end = &p[i_extra];
46 /* Check headers count */
47 for (int i=0; i<3; i++)
49 if(p_end - p < 2)
50 return 0;
51 uint16_t i_size = GetWBE(p);
52 if(&p[2U + i_size] > p_end)
53 return 0;
54 p += 2 + i_size;
56 return 3;
59 static inline unsigned xiph_CountHeaders(const void *p_extra, unsigned i_extra)
61 const uint8_t *p = (const uint8_t*) p_extra;
62 if (!i_extra)
63 return 0;
64 /* First byte is headers count */
65 if(1U + *p > i_extra)
66 return 0;
67 return *p + 1;
70 static inline unsigned xiph_CountUnknownHeaders(const void *p_extra, unsigned i_extra,
71 vlc_fourcc_t i_codec)
73 if (xiph_IsLavcFormat(p_extra, i_extra, i_codec))
74 return xiph_CountLavcHeaders(p_extra, i_extra);
75 else
76 return xiph_CountHeaders(p_extra, i_extra);
79 static inline int xiph_SplitLavcHeaders(unsigned packet_size[],
80 const void *packet[], unsigned *packet_count,
81 unsigned i_extra, const void *p_extra)
83 const uint8_t *current = (const uint8_t *)p_extra;
84 const uint8_t *end = &current[i_extra];
85 if (i_extra < 2)
86 return VLC_EGENERIC;
87 /* Parse the packet count and their sizes */
88 const unsigned count = xiph_CountLavcHeaders(current, i_extra);
89 if(count == 0)
90 return VLC_EGENERIC;
91 if (packet_count)
92 *packet_count = count;
93 /* count is trusted here (xiph_CountHeaders) */
94 for (unsigned i=0; i < count; i++)
96 /* each payload is prefixed by word size */
97 packet_size[i] = GetWBE(current);
98 if(&current[2U + packet_size[i]] > end)
99 return VLC_EGENERIC;
100 packet[i] = current + 2;
101 current += packet_size[i] + 2;
103 return VLC_SUCCESS;
106 static inline int xiph_SplitHeaders(unsigned packet_size[],
107 const void *packet[], unsigned *packet_count,
108 unsigned i_extra, const void *p_extra)
110 const uint8_t *current = (const uint8_t *)p_extra;
111 const uint8_t *end = &current[i_extra];
112 if (i_extra < 1)
113 return VLC_EGENERIC;
115 /* Parse the packet count and their sizes */
116 const unsigned count = xiph_CountHeaders(current, i_extra);
117 if(count == 0)
118 return VLC_EGENERIC;
120 if (packet_count)
121 *packet_count = count;
123 /* - 1 byte (N-1) packets
124 * - N-1 variable length payload sizes
125 * - N-1 payloads
126 * - Nth packet (remaining) */
128 /* skip count byte header */
129 ++current;
130 /* read sizes for N-1 packets */
131 unsigned total_payload_minus_last = 0;
132 for (unsigned i = 0; i < count - 1; i++)
134 packet_size[i] = 0;
135 for (;;) {
136 if (current >= end)
137 return VLC_EGENERIC;
138 packet_size[i] += *current;
139 if (*current++ != 255)
140 break;
142 if(UINT_MAX - total_payload_minus_last < packet_size[i])
143 return VLC_EGENERIC;
144 total_payload_minus_last += packet_size[i];
146 if(current + total_payload_minus_last > end)
147 return VLC_EGENERIC;
148 /* set pointers for N-1 packets */
149 for (unsigned i = 0; i < count - 1; i++)
151 packet[i] = current;
152 current += packet_size[i];
154 /* Last packet is remaining size */
155 packet_size[count - 1] = end - current;
156 packet[count - 1] = current;
158 return VLC_SUCCESS;
161 static inline int xiph_PackHeaders(int *extra_size, void **extra,
162 unsigned packet_size[],
163 const void *const packet[],
164 unsigned packet_count)
166 if (packet_count <= 0 || packet_count > XIPH_MAX_HEADER_COUNT)
167 return VLC_EGENERIC;
169 /* Compute the size needed for the whole extra data */
170 unsigned payload_size = 0;
171 unsigned header_size = 1;
172 for (unsigned i = 0; i < packet_count; i++) {
173 payload_size += packet_size[i];
174 if (i < packet_count - 1)
175 header_size += 1 + packet_size[i] / 255;
178 /* */
179 *extra_size = header_size + payload_size;
180 *extra = malloc(*extra_size);
181 if (*extra == NULL)
182 return VLC_ENOMEM;
184 /* Write the header */
185 uint8_t *current = (uint8_t*)*extra;
186 *current++ = packet_count - 1;
187 for (unsigned i = 0; i < packet_count - 1; i++) {
188 unsigned t = packet_size[i];
189 for (;;) {
190 if (t >= 255) {
191 *current++ = 255;
192 t -= 255;
193 } else {
194 *current++ = t;
195 break;
200 /* Copy the payloads */
201 for (unsigned i = 0; i < packet_count; i++) {
202 if (packet_size[i] > 0) {
203 memcpy(current, packet[i], packet_size[i]);
204 current += packet_size[i];
207 assert(current == (uint8_t*)*extra + *extra_size);
208 return VLC_SUCCESS;
211 static inline int xiph_AppendHeaders(int *extra_size, void **extra,
212 unsigned size, const void *data)
214 unsigned packet_size[XIPH_MAX_HEADER_COUNT];
215 const void *packet[XIPH_MAX_HEADER_COUNT];
216 unsigned count;
218 if (*extra_size > 0 && *extra) {
219 if (xiph_SplitHeaders(packet_size, packet, &count, *extra_size, *extra))
220 return VLC_EGENERIC;
221 } else {
222 count = 0;
224 if (count >= XIPH_MAX_HEADER_COUNT)
225 return VLC_EGENERIC;
227 void *old = *extra;
229 packet_size[count] = size;
230 packet[count] = (void*)data;
231 if (xiph_PackHeaders(extra_size, extra, packet_size,
232 packet, count + 1)) {
233 *extra_size = 0;
234 *extra = NULL;
237 free(old);
239 if (*extra_size <= 0)
240 return VLC_EGENERIC;
241 return VLC_SUCCESS;