22 |
22 |
#include "merge/output_control.h"
|
23 |
23 |
#include "output/p_mpeg4_p10.h"
|
24 |
24 |
|
|
25 |
static uint32_t RB32(const uint8_t *d)
|
|
26 |
{
|
|
27 |
return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
|
|
28 |
}
|
|
29 |
|
|
30 |
static uint32_t RB24(const uint8_t *d)
|
|
31 |
{
|
|
32 |
return (d[0] << 16) | (d[1] << 8) | d[2];
|
|
33 |
}
|
|
34 |
|
|
35 |
class mpeg4_p10_io
|
|
36 |
{
|
|
37 |
public:
|
|
38 |
mpeg4_p10_io(uint32_t len);
|
|
39 |
virtual ~mpeg4_p10_io();
|
|
40 |
|
|
41 |
void put_le16(unsigned int val);
|
|
42 |
void put_be16(unsigned int val);
|
|
43 |
void put_le24(unsigned int val);
|
|
44 |
void put_le32(unsigned int val);
|
|
45 |
void put_be32(unsigned int val);
|
|
46 |
void put_byte(unsigned int val);
|
|
47 |
void put_buffer(const uint8_t* buffer,unsigned int len);
|
|
48 |
|
|
49 |
int32_t flush (uint8_t **buf);
|
|
50 |
|
|
51 |
|
|
52 |
uint8_t *_buffer;
|
|
53 |
int _buffer_pos;
|
|
54 |
uint32_t _buffer_size;
|
|
55 |
|
|
56 |
};
|
|
57 |
|
|
58 |
|
|
59 |
mpeg4_p10_io::mpeg4_p10_io(uint32_t len)
|
|
60 |
{
|
|
61 |
_buffer_size = len;
|
|
62 |
_buffer = (uint8_t*)malloc(_buffer_size);
|
|
63 |
_buffer_pos = 0;
|
|
64 |
}
|
|
65 |
mpeg4_p10_io::~mpeg4_p10_io()
|
|
66 |
{
|
|
67 |
}
|
|
68 |
|
|
69 |
int32_t mpeg4_p10_io::flush(uint8_t **buf)
|
|
70 |
{
|
|
71 |
*buf = _buffer;
|
|
72 |
return (_buffer_pos);
|
|
73 |
}
|
|
74 |
|
|
75 |
void mpeg4_p10_io::put_byte(unsigned int val)
|
|
76 |
{
|
|
77 |
if ((_buffer_pos + 1) > _buffer_size) {
|
|
78 |
_buffer_size += 1024;
|
|
79 |
_buffer = (uint8_t*)realloc(_buffer,_buffer_size);
|
|
80 |
}
|
|
81 |
_buffer[_buffer_pos++] = val & 0xFF;
|
|
82 |
}
|
|
83 |
void mpeg4_p10_io::put_buffer(const uint8_t* buffer,unsigned int len)
|
|
84 |
{
|
|
85 |
if ((_buffer_pos + len) > _buffer_size) {
|
|
86 |
_buffer_size += len +1024;
|
|
87 |
_buffer = (uint8_t*)realloc(_buffer,_buffer_size);
|
|
88 |
}
|
|
89 |
memcpy(_buffer+_buffer_pos,buffer,len);
|
|
90 |
_buffer_pos += len;
|
|
91 |
}
|
|
92 |
void mpeg4_p10_io::put_le16(unsigned int val)
|
|
93 |
{
|
|
94 |
put_byte(val);
|
|
95 |
put_byte(val >> 8);
|
|
96 |
}
|
|
97 |
|
|
98 |
void mpeg4_p10_io::put_be16(unsigned int val)
|
|
99 |
{
|
|
100 |
put_byte(val >> 8);
|
|
101 |
put_byte(val);
|
|
102 |
}
|
|
103 |
|
|
104 |
void mpeg4_p10_io::put_le24(unsigned int val)
|
|
105 |
{
|
|
106 |
put_le16(val & 0xffff);
|
|
107 |
put_byte(val >> 16);
|
|
108 |
}
|
|
109 |
void mpeg4_p10_io::put_le32(unsigned int val)
|
|
110 |
{
|
|
111 |
put_byte(val);
|
|
112 |
put_byte(val >> 8);
|
|
113 |
put_byte(val >> 16);
|
|
114 |
put_byte(val >> 24);
|
|
115 |
|
|
116 |
}
|
|
117 |
void mpeg4_p10_io::put_be32(unsigned int val)
|
|
118 |
{
|
|
119 |
put_byte(val >> 24);
|
|
120 |
put_byte(val >> 16);
|
|
121 |
put_byte(val >> 8);
|
|
122 |
put_byte(val);
|
|
123 |
|
|
124 |
}
|
|
125 |
|
|
126 |
const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end)
|
|
127 |
{
|
|
128 |
int i;
|
|
129 |
|
|
130 |
uint32_t sc=0xFFFFFFFF;
|
|
131 |
size_t len = (end -p)+1;
|
|
132 |
for (i=0;i<len;i++)
|
|
133 |
{
|
|
134 |
sc = (sc <<8) | p[i];
|
|
135 |
if((sc & 0xffffff00) == 0x00000100) {
|
|
136 |
return p+i-3;
|
|
137 |
}
|
|
138 |
|
|
139 |
}
|
|
140 |
return end;
|
|
141 |
}
|
|
142 |
|
|
143 |
int avc_parse_nal_units(mpeg4_p10_io *pb, const uint8_t *buf_in, int size)
|
|
144 |
{
|
|
145 |
const uint8_t *p = buf_in;
|
|
146 |
const uint8_t *end = p + size;
|
|
147 |
const uint8_t *nal_start, *nal_end;
|
|
148 |
|
|
149 |
|
|
150 |
size = 0;
|
|
151 |
nal_start = avc_find_startcode(p, end);
|
|
152 |
while (nal_start < end) {
|
|
153 |
while(!*(nal_start++));
|
|
154 |
if (nal_start >= end)
|
|
155 |
break;
|
|
156 |
nal_end = avc_find_startcode(nal_start, end);
|
|
157 |
|
|
158 |
int l = nal_end - nal_start;
|
|
159 |
|
|
160 |
if (l) {
|
|
161 |
pb->put_be32(l);
|
|
162 |
//printf("l %d\n",l);
|
|
163 |
pb->put_buffer(nal_start, l);
|
|
164 |
size += 4 + l;
|
|
165 |
}
|
|
166 |
nal_start = nal_end;
|
|
167 |
|
|
168 |
}
|
|
169 |
//printf("size=%d\n", size);
|
|
170 |
return size;
|
|
171 |
}
|
|
172 |
|
|
173 |
|
|
174 |
int avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
|
|
175 |
{
|
|
176 |
mpeg4_p10_io pb(*size*2);
|
|
177 |
|
|
178 |
avc_parse_nal_units(&pb, buf_in, *size);
|
|
179 |
if (*buf)
|
|
180 |
free(*buf);
|
|
181 |
*size = pb.flush( buf);
|
|
182 |
return 0;
|
|
183 |
}
|
|
184 |
static int isom_write_avcc(mpeg4_p10_io *pb, const uint8_t *data, int len)
|
|
185 |
{
|
|
186 |
if (len > 6) {
|
|
187 |
/* check for h264 start code */
|
|
188 |
if (RB32(data) == 0x00000001 ||
|
|
189 |
RB24(data) == 0x000001) {
|
|
190 |
uint8_t *buf=NULL, *end, *start;
|
|
191 |
uint32_t *sps_size_array=0, *pps_size_array=0;
|
|
192 |
uint32_t pps_count=0,sps_count=0;
|
|
193 |
uint8_t **sps_array=0, **pps_array=0;
|
|
194 |
int i;
|
|
195 |
|
|
196 |
int ret = avc_parse_nal_units_buf(data, &buf, &len);
|
|
197 |
if (ret < 0)
|
|
198 |
return ret;
|
|
199 |
start = buf;
|
|
200 |
end = buf + len;
|
|
201 |
|
|
202 |
/* look for sps and pps */
|
|
203 |
while (buf < end) {
|
|
204 |
unsigned int size;
|
|
205 |
uint8_t nal_type;
|
|
206 |
size = RB32(buf);
|
|
207 |
nal_type = buf[4] & 0x1f;
|
|
208 |
if (nal_type == 7) { /* SPS */
|
|
209 |
sps_array = (uint8_t**)realloc(sps_array,sizeof(uint8_t*)*(sps_count+1));
|
|
210 |
sps_size_array = (uint32_t*)realloc(sps_size_array,sizeof(uint32_t)*(sps_count+1));
|
|
211 |
sps_array[sps_count] = buf + 4;
|
|
212 |
sps_size_array[sps_count] = size;
|
|
213 |
sps_count++;
|
|
214 |
} else if (nal_type == 8) { /* PPS */
|
|
215 |
pps_size_array = (uint32_t*)realloc(pps_size_array,sizeof(uint32_t)*(pps_count+1));
|
|
216 |
pps_array = (uint8_t**)realloc(pps_array,sizeof (uint8_t*)*(pps_count+1));
|
|
217 |
pps_array[pps_count] = buf + 4;
|
|
218 |
pps_size_array[pps_count] = size;
|
|
219 |
pps_count++;
|
|
220 |
}
|
|
221 |
buf += size + 4;
|
|
222 |
}
|
|
223 |
if(!sps_count || !pps_count) {
|
|
224 |
free(start);
|
|
225 |
if (sps_count)
|
|
226 |
free(sps_array);
|
|
227 |
if (pps_count)
|
|
228 |
free(pps_array);
|
|
229 |
return -1;
|
|
230 |
}
|
|
231 |
|
|
232 |
pb->put_byte( 1); /* version */
|
|
233 |
pb->put_byte( sps_array[0][1]); /* profile */
|
|
234 |
pb->put_byte( sps_array[0][2]); /* profile compat */
|
|
235 |
pb->put_byte( sps_array[0][3]); /* level */
|
|
236 |
pb->put_byte( 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
|
|
237 |
pb->put_byte( 0xe0+sps_count); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
|
|
238 |
for (i=0;i<(int)sps_count;i++) {
|
|
239 |
pb->put_be16( sps_size_array[i]);
|
|
240 |
pb->put_buffer(sps_array[i], sps_size_array[i]);
|
|
241 |
}
|
|
242 |
|
|
243 |
pb->put_byte(pps_count); /* number of pps */
|
|
244 |
for (i=0;i<(int)pps_count;i++) {
|
|
245 |
pb->put_be16(pps_size_array[i]);
|
|
246 |
pb->put_buffer(pps_array[i], pps_size_array[i]);
|
|
247 |
}
|
|
248 |
free(start);
|
|
249 |
|
|
250 |
if (sps_count)
|
|
251 |
free(sps_array);
|
|
252 |
if (pps_count)
|
|
253 |
free(pps_array);
|
|
254 |
} else {
|
|
255 |
//put_buffer(pb, data, len);
|
|
256 |
}
|
|
257 |
}
|
|
258 |
return 0;
|
|
259 |
}
|
25 |
260 |
mpeg4_p10_video_packetizer_c::
|
26 |
261 |
mpeg4_p10_video_packetizer_c(generic_reader_c *p_reader,
|
27 |
262 |
track_info_c &p_ti,
|
... | ... | |
32 |
267 |
, m_nalu_size_len_src(0)
|
33 |
268 |
, m_nalu_size_len_dst(0)
|
34 |
269 |
, m_max_nalu_size(0)
|
|
270 |
, m_header(0)
|
|
271 |
, m_header_len(0)
|
35 |
272 |
{
|
|
273 |
|
36 |
274 |
m_relaxed_timecode_checking = true;
|
37 |
275 |
|
38 |
|
setup_nalu_size_len_change();
|
39 |
276 |
|
40 |
|
if ((NULL != m_ti.m_private_data) && (0 < m_ti.m_private_size))
|
41 |
|
set_codec_private(m_ti.m_private_data, m_ti.m_private_size);
|
|
277 |
if ((NULL != m_ti.m_private_data) && (0 < m_ti.m_private_size)) {
|
|
278 |
|
|
279 |
uint8_t *privateData;
|
|
280 |
int32_t privateDataLen;
|
|
281 |
|
|
282 |
m_header_len = m_ti.m_private_size;
|
|
283 |
m_header = (uint8_t *)malloc(m_header_len);
|
|
284 |
memcpy(m_header,m_ti.m_private_data,m_header_len);
|
|
285 |
mpeg4_p10_io pb(m_ti.m_private_size*2);
|
|
286 |
isom_write_avcc(&pb, m_ti.m_private_data, m_ti.m_private_size);
|
|
287 |
privateDataLen = pb.flush(&privateData);
|
|
288 |
|
|
289 |
set_codec_private(privateData, privateDataLen);
|
|
290 |
|
|
291 |
free( m_ti.m_private_data);
|
|
292 |
m_ti.m_private_data = privateData;
|
|
293 |
m_ti.m_private_size = privateDataLen;
|
|
294 |
}
|
42 |
295 |
|
|
296 |
setup_nalu_size_len_change();
|
43 |
297 |
if (4 == m_nalu_size_len_dst)
|
44 |
298 |
set_default_compression_method(COMPRESSION_MPEG4_P10);
|
45 |
299 |
}
|
46 |
300 |
|
47 |
301 |
void
|
48 |
302 |
mpeg4_p10_video_packetizer_c::set_headers() {
|
|
303 |
|
49 |
304 |
if ((NULL != m_ti.m_private_data) && (0 < m_ti.m_private_size))
|
50 |
305 |
extract_aspect_ratio();
|
51 |
306 |
|
... | ... | |
54 |
309 |
|
55 |
310 |
void
|
56 |
311 |
mpeg4_p10_video_packetizer_c::extract_aspect_ratio() {
|
|
312 |
|
57 |
313 |
uint32_t num, den;
|
58 |
314 |
|
59 |
315 |
if (mpeg4::p10::extract_par(m_ti.m_private_data, m_ti.m_private_size, num, den) && (0 != num) && (0 != den)) {
|
... | ... | |
71 |
327 |
}
|
72 |
328 |
}
|
73 |
329 |
|
|
330 |
|
|
331 |
|
|
332 |
void
|
|
333 |
mpeg4_p10_video_packetizer_c::patch_packet(packet_cptr packet) {
|
|
334 |
|
|
335 |
unsigned char *src = packet->data->get_buffer();
|
|
336 |
int size = packet->data->get_size();
|
|
337 |
uint8_t*new_payload=0;
|
|
338 |
uint32_t new_payload_len=0;
|
|
339 |
|
|
340 |
if (!src || !size)
|
|
341 |
return;
|
|
342 |
mpeg4_p10_io pb(size*2);
|
|
343 |
|
|
344 |
if (packet->is_key_frame() && m_header)
|
|
345 |
avc_parse_nal_units(&pb, m_header, m_header_len);
|
|
346 |
avc_parse_nal_units(&pb, src, size);
|
|
347 |
|
|
348 |
new_payload_len = pb.flush( &new_payload);
|
|
349 |
|
|
350 |
|
|
351 |
|
|
352 |
packet->data = memory_cptr(new memory_c((unsigned char *)safemalloc(new_payload_len), new_payload_len, true));
|
|
353 |
|
|
354 |
// Copy the NALUs and write the new sized length field.
|
|
355 |
unsigned char *dst = packet->data->get_buffer();
|
|
356 |
memcpy(dst,new_payload,new_payload_len);
|
|
357 |
|
|
358 |
packet->data->set_size(new_payload_len);
|
|
359 |
|
|
360 |
free (new_payload);
|
|
361 |
}
|
|
362 |
|
74 |
363 |
int
|
75 |
364 |
mpeg4_p10_video_packetizer_c::process(packet_cptr packet) {
|
|
365 |
|
76 |
366 |
if (VFT_PFRAMEAUTOMATIC == packet->bref) {
|
77 |
367 |
packet->fref = -1;
|
78 |
368 |
packet->bref = m_ref_timecode;
|
... | ... | |
80 |
370 |
|
81 |
371 |
m_ref_timecode = packet->timecode;
|
82 |
372 |
|
|
373 |
|
|
374 |
patch_packet(packet);
|
83 |
375 |
if (m_nalu_size_len_dst && (m_nalu_size_len_dst != m_nalu_size_len_src))
|
84 |
376 |
change_nalu_size_len(packet);
|
85 |
377 |
|
... | ... | |
91 |
383 |
connection_result_e
|
92 |
384 |
mpeg4_p10_video_packetizer_c::can_connect_to(generic_packetizer_c *src,
|
93 |
385 |
std::string &error_message) {
|
|
386 |
|
94 |
387 |
mpeg4_p10_video_packetizer_c *vsrc = dynamic_cast<mpeg4_p10_video_packetizer_c *>(src);
|
95 |
388 |
if (NULL == vsrc)
|
96 |
389 |
return CAN_CONNECT_NO_FORMAT;
|
... | ... | |
109 |
402 |
|
110 |
403 |
void
|
111 |
404 |
mpeg4_p10_video_packetizer_c::setup_nalu_size_len_change() {
|
|
405 |
|
112 |
406 |
if (!m_ti.m_private_data || (5 > m_ti.m_private_size))
|
113 |
407 |
return;
|
114 |
408 |
|
115 |
409 |
m_nalu_size_len_src = (m_ti.m_private_data[4] & 0x03) + 1;
|
116 |
410 |
m_nalu_size_len_dst = m_nalu_size_len_src;
|
117 |
|
|
|
411 |
|
118 |
412 |
if (!m_ti.m_nalu_size_length || (m_ti.m_nalu_size_length == m_nalu_size_len_src))
|
119 |
413 |
return;
|
120 |
414 |
|
... | ... | |
129 |
423 |
|
130 |
424 |
void
|
131 |
425 |
mpeg4_p10_video_packetizer_c::change_nalu_size_len(packet_cptr packet) {
|
|
426 |
|
132 |
427 |
unsigned char *src = packet->data->get_buffer();
|
133 |
428 |
int size = packet->data->get_size();
|
134 |
429 |
|
... | ... | |
146 |
441 |
|
147 |
442 |
int nalu_size = 0;
|
148 |
443 |
int i;
|
|
444 |
|
149 |
445 |
for (i = 0; i < m_nalu_size_len_src; ++i)
|
150 |
446 |
nalu_size = (nalu_size << 8) + src[src_pos + i];
|
151 |
447 |
|
... | ... | |
160 |
456 |
nalu_sizes.push_back(nalu_size);
|
161 |
457 |
}
|
162 |
458 |
|
|
459 |
|
163 |
460 |
// Allocate memory if the new NALU size length is greater
|
164 |
461 |
// than the previous one. Otherwise reuse the existing memory.
|
165 |
462 |
if (m_nalu_size_len_dst > m_nalu_size_len_src) {
|
... | ... | |
167 |
464 |
packet->data = memory_cptr(new memory_c((unsigned char *)safemalloc(new_size), new_size, true));
|
168 |
465 |
}
|
169 |
466 |
|
|
467 |
|
170 |
468 |
// Copy the NALUs and write the new sized length field.
|
171 |
469 |
unsigned char *dst = packet->data->get_buffer();
|
172 |
470 |
src_pos = 0;
|
173 |
471 |
int dst_pos = 0;
|
174 |
472 |
|
|
473 |
|
175 |
474 |
size_t i;
|
176 |
475 |
for (i = 0; nalu_sizes.size() > i; ++i) {
|
177 |
476 |
int nalu_size = nalu_sizes[i];
|
|
477 |
|
178 |
478 |
|
179 |
479 |
int shift;
|
180 |
480 |
for (shift = 0; shift < m_nalu_size_len_dst; ++shift)
|
... | ... | |
186 |
486 |
dst_pos += m_nalu_size_len_dst + nalu_size;
|
187 |
487 |
}
|
188 |
488 |
|
|
489 |
|
189 |
490 |
packet->data->set_size(dst_pos);
|
190 |
491 |
}
|