/src/vlc/modules/packetizer/packetizer_helper.h
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * packetizer_helper.h: Packetizer helpers |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2009 Laurent Aimar |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org> |
7 | | * |
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. |
12 | | * |
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. |
17 | | * |
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 | | *****************************************************************************/ |
22 | | |
23 | | #ifndef VLC_PACKETIZER_HELPER_H_ |
24 | | #define VLC_PACKETIZER_HELPER_H_ |
25 | | |
26 | | #include <vlc_block.h> |
27 | | |
28 | | enum |
29 | | { |
30 | | STATE_NOSYNC, |
31 | | STATE_SYNC, |
32 | | STATE_HEADER, |
33 | | STATE_NEXT_SYNC, |
34 | | STATE_GET_DATA, |
35 | | STATE_SEND_DATA, |
36 | | STATE_CUSTOM_FIRST, |
37 | | }; |
38 | | |
39 | | typedef void (*packetizer_reset_t)( void *p_private, bool b_flush ); |
40 | | typedef block_t *(*packetizer_parse_t)( void *p_private, bool *pb_ts_used, block_t * ); |
41 | | typedef block_t *(*packetizer_drain_t)( void *p_private ); |
42 | | typedef int (*packetizer_validate_t)( void *p_private, block_t * ); |
43 | | |
44 | | typedef struct |
45 | | { |
46 | | int i_state; |
47 | | block_bytestream_t bytestream; |
48 | | size_t i_offset; |
49 | | |
50 | | int i_startcode; |
51 | | const uint8_t *p_startcode; |
52 | | block_startcode_helper_t pf_startcode_helper; |
53 | | |
54 | | int i_au_prepend; |
55 | | const uint8_t *p_au_prepend; |
56 | | |
57 | | unsigned i_au_min_size; |
58 | | |
59 | | void *p_private; |
60 | | packetizer_reset_t pf_reset; |
61 | | packetizer_parse_t pf_parse; |
62 | | packetizer_validate_t pf_validate; |
63 | | packetizer_drain_t pf_drain; |
64 | | |
65 | | } packetizer_t; |
66 | | |
67 | | static inline void packetizer_Init( packetizer_t *p_pack, |
68 | | const uint8_t *p_startcode, int i_startcode, |
69 | | block_startcode_helper_t pf_start_helper, |
70 | | const uint8_t *p_au_prepend, int i_au_prepend, |
71 | | unsigned i_au_min_size, |
72 | | packetizer_reset_t pf_reset, |
73 | | packetizer_parse_t pf_parse, |
74 | | packetizer_validate_t pf_validate, |
75 | | packetizer_drain_t pf_drain, |
76 | | void *p_private ) |
77 | 0 | { |
78 | 0 | p_pack->i_state = STATE_NOSYNC; |
79 | 0 | block_BytestreamInit( &p_pack->bytestream ); |
80 | 0 | p_pack->i_offset = 0; |
81 | |
|
82 | 0 | p_pack->i_au_prepend = i_au_prepend; |
83 | 0 | p_pack->p_au_prepend = p_au_prepend; |
84 | 0 | p_pack->i_au_min_size = i_au_min_size; |
85 | |
|
86 | 0 | p_pack->i_startcode = i_startcode; |
87 | 0 | p_pack->p_startcode = p_startcode; |
88 | 0 | p_pack->pf_startcode_helper = pf_start_helper; |
89 | 0 | p_pack->pf_reset = pf_reset; |
90 | 0 | p_pack->pf_parse = pf_parse; |
91 | 0 | p_pack->pf_validate = pf_validate; |
92 | 0 | p_pack->pf_drain = pf_drain; |
93 | 0 | p_pack->p_private = p_private; |
94 | 0 | } Unexecuted instantiation: a52.c:packetizer_Init Unexecuted instantiation: dts.c:packetizer_Init Unexecuted instantiation: flac.c:packetizer_Init Unexecuted instantiation: h264.c:packetizer_Init Unexecuted instantiation: hevc.c:packetizer_Init Unexecuted instantiation: mlp.c:packetizer_Init Unexecuted instantiation: mpeg4audio.c:packetizer_Init Unexecuted instantiation: mpeg4video.c:packetizer_Init Unexecuted instantiation: mpegaudio.c:packetizer_Init Unexecuted instantiation: mpegvideo.c:packetizer_Init Unexecuted instantiation: vc1.c:packetizer_Init |
95 | | |
96 | | static inline void packetizer_Clean( packetizer_t *p_pack ) |
97 | 0 | { |
98 | 0 | block_BytestreamRelease( &p_pack->bytestream ); |
99 | 0 | } Unexecuted instantiation: a52.c:packetizer_Clean Unexecuted instantiation: dts.c:packetizer_Clean Unexecuted instantiation: flac.c:packetizer_Clean Unexecuted instantiation: h264.c:packetizer_Clean Unexecuted instantiation: hevc.c:packetizer_Clean Unexecuted instantiation: mlp.c:packetizer_Clean Unexecuted instantiation: mpeg4audio.c:packetizer_Clean Unexecuted instantiation: mpeg4video.c:packetizer_Clean Unexecuted instantiation: mpegaudio.c:packetizer_Clean Unexecuted instantiation: mpegvideo.c:packetizer_Clean Unexecuted instantiation: vc1.c:packetizer_Clean |
100 | | |
101 | | static inline void packetizer_Flush( packetizer_t *p_pack ) |
102 | 0 | { |
103 | 0 | p_pack->i_state = STATE_NOSYNC; |
104 | 0 | block_BytestreamEmpty( &p_pack->bytestream ); |
105 | 0 | p_pack->i_offset = 0; |
106 | 0 | p_pack->pf_reset( p_pack->p_private, true ); |
107 | 0 | } Unexecuted instantiation: a52.c:packetizer_Flush Unexecuted instantiation: dts.c:packetizer_Flush Unexecuted instantiation: flac.c:packetizer_Flush Unexecuted instantiation: h264.c:packetizer_Flush Unexecuted instantiation: hevc.c:packetizer_Flush Unexecuted instantiation: mlp.c:packetizer_Flush Unexecuted instantiation: mpeg4audio.c:packetizer_Flush Unexecuted instantiation: mpeg4video.c:packetizer_Flush Unexecuted instantiation: mpegaudio.c:packetizer_Flush Unexecuted instantiation: mpegvideo.c:packetizer_Flush Unexecuted instantiation: vc1.c:packetizer_Flush |
108 | | |
109 | | static block_t *packetizer_PacketizeBlock( packetizer_t *p_pack, block_t **pp_block ) |
110 | 0 | { |
111 | 0 | block_t *p_block = ( pp_block ) ? *pp_block : NULL; |
112 | |
|
113 | 0 | if( p_block == NULL && p_pack->bytestream.p_block == NULL ) |
114 | 0 | return NULL; |
115 | | |
116 | 0 | if( p_block && unlikely( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) ) |
117 | 0 | { |
118 | 0 | block_t *p_drained = packetizer_PacketizeBlock( p_pack, NULL ); |
119 | 0 | if( p_drained ) |
120 | 0 | return p_drained; |
121 | | |
122 | 0 | p_pack->i_state = STATE_NOSYNC; |
123 | 0 | block_BytestreamEmpty( &p_pack->bytestream ); |
124 | 0 | p_pack->i_offset = 0; |
125 | 0 | p_pack->pf_reset( p_pack->p_private, false ); |
126 | 0 | } |
127 | | |
128 | 0 | if( p_block ) |
129 | 0 | block_BytestreamPush( &p_pack->bytestream, p_block ); |
130 | |
|
131 | 0 | for( ;; ) |
132 | 0 | { |
133 | 0 | bool b_used_ts; |
134 | 0 | block_t *p_pic; |
135 | |
|
136 | 0 | switch( p_pack->i_state ) |
137 | 0 | { |
138 | 0 | case STATE_NOSYNC: |
139 | | /* Find a startcode */ |
140 | 0 | if( !block_FindStartcodeFromOffset( &p_pack->bytestream, &p_pack->i_offset, |
141 | 0 | p_pack->p_startcode, p_pack->i_startcode, |
142 | 0 | p_pack->pf_startcode_helper, NULL ) ) |
143 | 0 | p_pack->i_state = STATE_NEXT_SYNC; |
144 | |
|
145 | 0 | if( p_pack->i_offset ) |
146 | 0 | { |
147 | 0 | block_SkipBytes( &p_pack->bytestream, p_pack->i_offset ); |
148 | 0 | p_pack->i_offset = 0; |
149 | 0 | block_BytestreamFlush( &p_pack->bytestream ); |
150 | 0 | } |
151 | |
|
152 | 0 | if( p_pack->i_state != STATE_NEXT_SYNC ) |
153 | 0 | return NULL; /* Need more data */ |
154 | | |
155 | 0 | p_pack->i_offset = 1; /* To find next startcode */ |
156 | | /* fallthrough */ |
157 | |
|
158 | 0 | case STATE_NEXT_SYNC: |
159 | | /* Find the next startcode */ |
160 | 0 | if( block_FindStartcodeFromOffset( &p_pack->bytestream, &p_pack->i_offset, |
161 | 0 | p_pack->p_startcode, p_pack->i_startcode, |
162 | 0 | p_pack->pf_startcode_helper, NULL ) ) |
163 | 0 | { |
164 | 0 | if( pp_block /* not flushing */ || !p_pack->bytestream.p_chain ) |
165 | 0 | return NULL; /* Need more data */ |
166 | | |
167 | | /* When flushing and we don't find a startcode, suppose that |
168 | | * the data extend up to the end */ |
169 | 0 | p_pack->i_offset = block_BytestreamRemaining(&p_pack->bytestream); |
170 | 0 | if( p_pack->i_offset == 0 ) |
171 | 0 | return NULL; |
172 | | |
173 | 0 | if( p_pack->i_offset <= (size_t)p_pack->i_startcode && |
174 | 0 | (p_pack->bytestream.p_block->i_flags & BLOCK_FLAG_AU_END) == 0 ) |
175 | 0 | return NULL; |
176 | 0 | } |
177 | | |
178 | 0 | block_BytestreamFlush( &p_pack->bytestream ); |
179 | | |
180 | | /* Get the new fragment and set the pts/dts */ |
181 | 0 | block_t *p_block_bytestream = p_pack->bytestream.p_block; |
182 | |
|
183 | 0 | p_pic = block_Alloc( p_pack->i_offset + p_pack->i_au_prepend ); |
184 | 0 | p_pic->i_pts = p_block_bytestream->i_pts; |
185 | 0 | p_pic->i_dts = p_block_bytestream->i_dts; |
186 | | |
187 | | /* Do not wait for next sync code if notified block ends AU */ |
188 | 0 | if( (p_block_bytestream->i_flags & BLOCK_FLAG_AU_END) && |
189 | 0 | p_block_bytestream->i_buffer == p_pack->i_offset ) |
190 | 0 | { |
191 | 0 | p_pic->i_flags |= BLOCK_FLAG_AU_END; |
192 | 0 | } |
193 | |
|
194 | 0 | block_GetBytes( &p_pack->bytestream, &p_pic->p_buffer[p_pack->i_au_prepend], |
195 | 0 | p_pic->i_buffer - p_pack->i_au_prepend ); |
196 | 0 | if( p_pack->i_au_prepend > 0 ) |
197 | 0 | memcpy( p_pic->p_buffer, p_pack->p_au_prepend, p_pack->i_au_prepend ); |
198 | |
|
199 | 0 | p_pack->i_offset = 0; |
200 | | |
201 | | /* Parse the NAL */ |
202 | 0 | if( p_pic->i_buffer < p_pack->i_au_min_size ) |
203 | 0 | { |
204 | 0 | block_Release( p_pic ); |
205 | 0 | p_pic = NULL; |
206 | 0 | } |
207 | 0 | else |
208 | 0 | { |
209 | 0 | p_pic = p_pack->pf_parse( p_pack->p_private, &b_used_ts, p_pic ); |
210 | 0 | if( b_used_ts ) |
211 | 0 | { |
212 | 0 | p_block_bytestream->i_dts = VLC_TICK_INVALID; |
213 | 0 | p_block_bytestream->i_pts = VLC_TICK_INVALID; |
214 | 0 | } |
215 | 0 | } |
216 | |
|
217 | 0 | if( !p_pic ) |
218 | 0 | { |
219 | 0 | p_pack->i_state = STATE_NOSYNC; |
220 | 0 | break; |
221 | 0 | } |
222 | 0 | if( p_pack->pf_validate( p_pack->p_private, p_pic ) ) |
223 | 0 | { |
224 | 0 | p_pack->i_state = STATE_NOSYNC; |
225 | 0 | block_Release( p_pic ); |
226 | 0 | break; |
227 | 0 | } |
228 | | |
229 | | /* So p_block doesn't get re-added several times */ |
230 | 0 | if( pp_block ) |
231 | 0 | *pp_block = block_BytestreamPop( &p_pack->bytestream ); |
232 | |
|
233 | 0 | p_pack->i_state = STATE_NOSYNC; |
234 | |
|
235 | 0 | return p_pic; |
236 | 0 | } |
237 | 0 | } |
238 | 0 | } Unexecuted instantiation: a52.c:packetizer_PacketizeBlock Unexecuted instantiation: dts.c:packetizer_PacketizeBlock Unexecuted instantiation: flac.c:packetizer_PacketizeBlock Unexecuted instantiation: h264.c:packetizer_PacketizeBlock Unexecuted instantiation: hevc.c:packetizer_PacketizeBlock Unexecuted instantiation: mlp.c:packetizer_PacketizeBlock Unexecuted instantiation: mpeg4audio.c:packetizer_PacketizeBlock Unexecuted instantiation: mpeg4video.c:packetizer_PacketizeBlock Unexecuted instantiation: mpegaudio.c:packetizer_PacketizeBlock Unexecuted instantiation: mpegvideo.c:packetizer_PacketizeBlock Unexecuted instantiation: vc1.c:packetizer_PacketizeBlock |
239 | | |
240 | | static block_t *packetizer_Packetize( packetizer_t *p_pack, block_t **pp_block ) |
241 | 0 | { |
242 | 0 | block_t *p_out = packetizer_PacketizeBlock( p_pack, pp_block ); |
243 | 0 | if( p_out ) |
244 | 0 | return p_out; |
245 | | /* handle caller drain */ |
246 | 0 | if( pp_block == NULL && p_pack->pf_drain ) |
247 | 0 | { |
248 | 0 | p_out = p_pack->pf_drain( p_pack->p_private ); |
249 | 0 | if( p_out && p_pack->pf_validate( p_pack->p_private, p_out ) ) |
250 | 0 | { |
251 | 0 | block_Release( p_out ); |
252 | 0 | p_out = NULL; |
253 | 0 | } |
254 | 0 | } |
255 | 0 | return p_out; |
256 | 0 | } Unexecuted instantiation: a52.c:packetizer_Packetize Unexecuted instantiation: dts.c:packetizer_Packetize Unexecuted instantiation: flac.c:packetizer_Packetize Unexecuted instantiation: h264.c:packetizer_Packetize Unexecuted instantiation: hevc.c:packetizer_Packetize Unexecuted instantiation: mlp.c:packetizer_Packetize Unexecuted instantiation: mpeg4audio.c:packetizer_Packetize Unexecuted instantiation: mpeg4video.c:packetizer_Packetize Unexecuted instantiation: mpegaudio.c:packetizer_Packetize Unexecuted instantiation: mpegvideo.c:packetizer_Packetize Unexecuted instantiation: vc1.c:packetizer_Packetize |
257 | | |
258 | | static inline void packetizer_Header( packetizer_t *p_pack, |
259 | | const uint8_t *p_header, int i_header ) |
260 | 0 | { |
261 | 0 | block_t *p_init = block_Alloc( i_header ); |
262 | 0 | if( !p_init ) |
263 | 0 | return; |
264 | | |
265 | 0 | memcpy( p_init->p_buffer, p_header, i_header ); |
266 | |
|
267 | 0 | block_t *p_pic; |
268 | 0 | while( ( p_pic = packetizer_Packetize( p_pack, &p_init ) ) ) |
269 | 0 | block_Release( p_pic ); /* Should not happen (only sequence header) */ |
270 | 0 | while( ( p_pic = packetizer_Packetize( p_pack, NULL ) ) ) |
271 | 0 | block_Release( p_pic ); |
272 | |
|
273 | 0 | p_pack->i_state = STATE_NOSYNC; |
274 | 0 | block_BytestreamEmpty( &p_pack->bytestream ); |
275 | 0 | p_pack->i_offset = 0; |
276 | 0 | } Unexecuted instantiation: a52.c:packetizer_Header Unexecuted instantiation: dts.c:packetizer_Header Unexecuted instantiation: flac.c:packetizer_Header Unexecuted instantiation: h264.c:packetizer_Header Unexecuted instantiation: hevc.c:packetizer_Header Unexecuted instantiation: mlp.c:packetizer_Header Unexecuted instantiation: mpeg4audio.c:packetizer_Header Unexecuted instantiation: mpeg4video.c:packetizer_Header Unexecuted instantiation: mpegaudio.c:packetizer_Header Unexecuted instantiation: mpegvideo.c:packetizer_Header Unexecuted instantiation: vc1.c:packetizer_Header |
277 | | |
278 | | #endif |
279 | | |