1 /*****************************************************************************
2 * packetizer_helper.h: Packetizer helpers
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #ifndef VLC_PACKETIZER_HELPER_H_
25 #define VLC_PACKETIZER_HELPER_H_
27 #include <vlc_block.h>
39 typedef void (*packetizer_reset_t
)( void *p_private
, bool b_broken
);
40 typedef block_t
*(*packetizer_parse_t
)( void *p_private
, bool *pb_ts_used
, block_t
* );
41 typedef int (*packetizer_validate_t
)( void *p_private
, block_t
* );
46 block_bytestream_t bytestream
;
50 const uint8_t *p_startcode
;
51 block_startcode_helper_t pf_startcode_helper
;
54 const uint8_t *p_au_prepend
;
56 unsigned i_au_min_size
;
59 packetizer_reset_t pf_reset
;
60 packetizer_parse_t pf_parse
;
61 packetizer_validate_t pf_validate
;
65 static inline void packetizer_Init( packetizer_t
*p_pack
,
66 const uint8_t *p_startcode
, int i_startcode
,
67 block_startcode_helper_t pf_start_helper
,
68 const uint8_t *p_au_prepend
, int i_au_prepend
,
69 unsigned i_au_min_size
,
70 packetizer_reset_t pf_reset
,
71 packetizer_parse_t pf_parse
,
72 packetizer_validate_t pf_validate
,
75 p_pack
->i_state
= STATE_NOSYNC
;
76 block_BytestreamInit( &p_pack
->bytestream
);
79 p_pack
->i_au_prepend
= i_au_prepend
;
80 p_pack
->p_au_prepend
= p_au_prepend
;
81 p_pack
->i_au_min_size
= i_au_min_size
;
83 p_pack
->i_startcode
= i_startcode
;
84 p_pack
->p_startcode
= p_startcode
;
85 p_pack
->pf_startcode_helper
= pf_start_helper
;
86 p_pack
->pf_reset
= pf_reset
;
87 p_pack
->pf_parse
= pf_parse
;
88 p_pack
->pf_validate
= pf_validate
;
89 p_pack
->p_private
= p_private
;
92 static inline void packetizer_Clean( packetizer_t
*p_pack
)
94 block_BytestreamRelease( &p_pack
->bytestream
);
97 static inline void packetizer_Flush( packetizer_t
*p_pack
)
99 p_pack
->i_state
= STATE_NOSYNC
;
100 block_BytestreamEmpty( &p_pack
->bytestream
);
101 p_pack
->i_offset
= 0;
102 p_pack
->pf_reset( p_pack
->p_private
, true );
105 static inline block_t
*packetizer_Packetize( packetizer_t
*p_pack
, block_t
**pp_block
)
107 block_t
*p_block
= ( pp_block
) ? *pp_block
: NULL
;
109 if( p_block
== NULL
&& p_pack
->bytestream
.p_block
== NULL
)
110 return NULL
; /* nothing to do */
112 if( p_block
&& unlikely( p_block
->i_flags
&(BLOCK_FLAG_DISCONTINUITY
|BLOCK_FLAG_CORRUPTED
) ) )
114 block_t
*p_drained
= packetizer_Packetize( p_pack
, NULL
);
118 const bool b_broken
= !!( p_block
->i_flags
&BLOCK_FLAG_CORRUPTED
);
119 p_pack
->i_state
= STATE_NOSYNC
;
120 block_BytestreamEmpty( &p_pack
->bytestream
);
121 p_pack
->i_offset
= 0;
122 p_pack
->pf_reset( p_pack
->p_private
, b_broken
);
125 block_Release( p_block
);
131 block_BytestreamPush( &p_pack
->bytestream
, p_block
);
138 switch( p_pack
->i_state
)
141 /* Find a startcode */
142 if( !block_FindStartcodeFromOffset( &p_pack
->bytestream
, &p_pack
->i_offset
,
143 p_pack
->p_startcode
, p_pack
->i_startcode
,
144 p_pack
->pf_startcode_helper
, NULL
) )
145 p_pack
->i_state
= STATE_NEXT_SYNC
;
147 if( p_pack
->i_offset
)
149 block_SkipBytes( &p_pack
->bytestream
, p_pack
->i_offset
);
150 p_pack
->i_offset
= 0;
151 block_BytestreamFlush( &p_pack
->bytestream
);
154 if( p_pack
->i_state
!= STATE_NEXT_SYNC
)
155 return NULL
; /* Need more data */
157 p_pack
->i_offset
= 1; /* To find next startcode */
160 case STATE_NEXT_SYNC
:
161 /* Find the next startcode */
162 if( block_FindStartcodeFromOffset( &p_pack
->bytestream
, &p_pack
->i_offset
,
163 p_pack
->p_startcode
, p_pack
->i_startcode
,
164 p_pack
->pf_startcode_helper
, NULL
) )
166 if( pp_block
/* not flushing */ || !p_pack
->bytestream
.p_chain
)
167 return NULL
; /* Need more data */
169 /* When flusing and we don't find a startcode, suppose that
170 * the data extend up to the end */
171 block_ChainProperties( p_pack
->bytestream
.p_chain
,
172 NULL
, &p_pack
->i_offset
, NULL
);
173 p_pack
->i_offset
-= p_pack
->bytestream
.i_block_offset
;
175 if( p_pack
->i_offset
<= (size_t)p_pack
->i_startcode
)
179 block_BytestreamFlush( &p_pack
->bytestream
);
181 /* Get the new fragment and set the pts/dts */
182 block_t
*p_block_bytestream
= p_pack
->bytestream
.p_block
;
184 p_pic
= block_Alloc( p_pack
->i_offset
+ p_pack
->i_au_prepend
);
185 p_pic
->i_pts
= p_block_bytestream
->i_pts
;
186 p_pic
->i_dts
= p_block_bytestream
->i_dts
;
188 block_GetBytes( &p_pack
->bytestream
, &p_pic
->p_buffer
[p_pack
->i_au_prepend
],
189 p_pic
->i_buffer
- p_pack
->i_au_prepend
);
190 if( p_pack
->i_au_prepend
> 0 )
191 memcpy( p_pic
->p_buffer
, p_pack
->p_au_prepend
, p_pack
->i_au_prepend
);
193 p_pack
->i_offset
= 0;
196 if( p_pic
->i_buffer
< p_pack
->i_au_min_size
)
198 block_Release( p_pic
);
203 p_pic
= p_pack
->pf_parse( p_pack
->p_private
, &b_used_ts
, p_pic
);
206 p_block_bytestream
->i_dts
= VLC_TS_INVALID
;
207 p_block_bytestream
->i_pts
= VLC_TS_INVALID
;
213 p_pack
->i_state
= STATE_NOSYNC
;
216 if( p_pack
->pf_validate( p_pack
->p_private
, p_pic
) )
218 p_pack
->i_state
= STATE_NOSYNC
;
219 block_Release( p_pic
);
223 /* So p_block doesn't get re-added several times */
225 *pp_block
= block_BytestreamPop( &p_pack
->bytestream
);
227 p_pack
->i_state
= STATE_NOSYNC
;
234 static inline void packetizer_Header( packetizer_t
*p_pack
,
235 const uint8_t *p_header
, int i_header
)
237 block_t
*p_init
= block_Alloc( i_header
);
241 memcpy( p_init
->p_buffer
, p_header
, i_header
);
244 while( ( p_pic
= packetizer_Packetize( p_pack
, &p_init
) ) )
245 block_Release( p_pic
); /* Should not happen (only sequence header) */
246 while( ( p_pic
= packetizer_Packetize( p_pack
, NULL
) ) )
247 block_Release( p_pic
);
249 p_pack
->i_state
= STATE_NOSYNC
;
250 block_BytestreamEmpty( &p_pack
->bytestream
);
251 p_pack
->i_offset
= 0;