packetizer: h264: prefix poc_context_t
[vlc.git] / modules / packetizer / hxxx_nal.c
blobeb899c6976ea1f2ab13e857c0ac845f07e5aee6f
1 /*****************************************************************************
2 * Copyright © 2015 VideoLAN Authors
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17 *****************************************************************************/
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
22 #include "hxxx_nal.h"
24 #include <vlc_block.h>
26 static bool block_WillRealloc( block_t *p_block, ssize_t i_prebody, size_t i_body )
28 if( i_prebody <= 0 && i_body <= (size_t)(-i_prebody) )
29 return false;
30 else
31 return ( i_prebody + i_body <= p_block->i_size );
34 static inline void hxxx_WritePrefix( uint8_t i_nal_length_size, uint8_t *p_dest, uint32_t i_payload )
36 if( i_nal_length_size == 4 )
37 SetDWBE( p_dest, i_payload );
38 else if( i_nal_length_size == 2 )
39 SetWBE( p_dest, i_payload );
40 else
41 *p_dest = i_payload;
44 block_t *hxxx_AnnexB_to_xVC( block_t *p_block, uint8_t i_nal_length_size )
46 unsigned i_nalcount = 0;
47 unsigned i_list = 16;
48 struct nalmoves_e
50 const uint8_t *p; /* start of prefixed nal */
51 uint8_t prefix; /* startcode length */
52 off_t move; /* move offset */
53 } *p_list = NULL;
55 if(!p_block->i_buffer || p_block->p_buffer[0])
56 goto error;
58 if(! (p_list = malloc( sizeof(*p_list) * i_list )) )
59 goto error;
61 /* Search all startcode of size 3 */
62 const uint8_t *p_buf = p_block->p_buffer;
63 const uint8_t *p_end = &p_block->p_buffer[p_block->i_buffer];
64 unsigned i_bitflow = 0;
65 off_t i_move = 0;
66 while( p_buf != p_end )
68 i_bitflow <<= 1;
69 if( !*p_buf )
71 i_bitflow |= 1;
73 else if( *p_buf == 0x01 && (i_bitflow & 0x06) == 0x06 ) /* >= two zero prefixed 1 */
75 if( i_bitflow & 0x08 ) /* three zero prefixed 1 */
77 p_list[i_nalcount].p = &p_buf[-3];
78 p_list[i_nalcount].prefix = 4;
80 else /* two zero prefixed 1 */
82 p_list[i_nalcount].p = &p_buf[-2];
83 p_list[i_nalcount].prefix = 3;
85 i_move += (off_t) i_nal_length_size - p_list[i_nalcount].prefix;
86 p_list[i_nalcount++].move = i_move;
88 /* Check and realloc our list */
89 if(i_nalcount == i_list)
91 i_list += 16;
92 struct nalmoves_e *p_new = realloc( p_list, sizeof(*p_new) * i_list );
93 if(unlikely(!p_new))
94 goto error;
95 p_list = p_new;
98 p_buf++;
101 if( !i_nalcount )
102 goto error;
104 /* Optimization for 1 NAL block only case */
105 if( i_nalcount == 1 && block_WillRealloc( p_block, p_list[0].move, p_block->i_buffer ) )
107 uint32_t i_payload = p_block->i_buffer - p_list[0].prefix;
108 block_t *p_newblock = block_Realloc( p_block, p_list[0].move, p_block->i_buffer );
109 if( unlikely(!p_newblock) )
110 goto error;
111 p_block = p_newblock;
112 hxxx_WritePrefix( i_nal_length_size, p_block->p_buffer , i_payload );
113 free( p_list );
114 return p_block;
117 block_t *p_release = NULL;
118 const uint8_t *p_source = NULL;
119 const uint8_t *p_sourceend = NULL;
120 uint8_t *p_dest = NULL;
121 const size_t i_dest = p_block->i_buffer + p_list[i_nalcount - 1].move;
123 if( p_list[i_nalcount - 1].move != 0 || i_nal_length_size != 4 ) /* We'll need to grow or shrink */
125 /* If we grow in size, try using realloc to avoid memcpy */
126 if( p_list[i_nalcount - 1].move > 0 && block_WillRealloc( p_block, 0, i_dest ) )
128 uint32_t i_sizebackup = p_block->i_buffer;
129 block_t *p_newblock = block_Realloc( p_block, 0, i_dest );
130 if( unlikely(!p_newblock) )
131 goto error;
133 p_block = p_newblock;
134 p_sourceend = &p_block->p_buffer[i_sizebackup];
135 p_source = p_dest = p_block->p_buffer;
137 else
139 block_t *p_newblock = block_Alloc( i_dest );
140 if( unlikely(!p_newblock) )
141 goto error;
143 p_release = p_block; /* Will be released after use */
144 p_source = p_release->p_buffer;
145 p_sourceend = &p_release->p_buffer[p_release->i_buffer];
147 p_block = p_newblock;
148 p_dest = p_newblock->p_buffer;
151 else
153 p_source = p_dest = p_block->p_buffer;
154 p_sourceend = &p_block->p_buffer[p_block->i_buffer];
157 if(!p_dest)
158 goto error;
160 /* Do reverse order moves, so we never overlap when growing only */
161 for( unsigned i=i_nalcount; i!=0; i-- )
163 const uint8_t *p_readstart = p_list[i - 1].p;
164 uint32_t i_payload = p_sourceend - p_readstart - p_list[i - 1].prefix;
165 off_t offset = p_list[i - 1].p - p_source + p_list[i - 1].prefix + p_list[i - 1].move;
166 // printf(" move offset %ld, length = %ld prefix %ld move %ld\n", p_readstart - p_source, i_payload, p_list[i - 1].prefix, p_list[i-1].move);
168 /* move in same / copy between buffers */
169 memmove( &p_dest[ offset ], &p_list[i - 1].p[ p_list[i - 1].prefix ], i_payload );
171 hxxx_WritePrefix( i_nal_length_size, &p_dest[ offset - i_nal_length_size ] , i_payload );
173 p_sourceend = p_readstart;
176 if( p_release )
177 block_Release( p_release );
178 free( p_list );
179 return p_block;
181 error:
182 free( p_list );
183 block_Release( p_block );
184 return NULL;