Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/ietf_dev.h>
27 :
28 : #ifndef GPAC_DISABLE_STREAMING
29 :
30 : #include <gpac/constants.h>
31 :
32 : //get the size of the RSLH section given the GF_SLHeader and the SLMap
33 25192 : static u32 gf_rtp_build_au_hdr_size(GP_RTPPacketizer *builder, GF_SLHeader *slh)
34 : {
35 : u32 nbBits = 0;
36 :
37 : /*sel enc*/
38 25192 : if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) nbBits += 8;
39 : /*Note: ISMACryp ALWAYS indicates IV (BSO) and KEYIDX, even when sample is not encrypted. This is
40 : quite a waste when using selective encryption....*/
41 :
42 : /*IV*/
43 25192 : nbBits += builder->first_sl_in_rtp ? 8*builder->slMap.IV_length : 8*builder->slMap.IV_delta_length;
44 : /*keyIndicator*/
45 25192 : if (builder->first_sl_in_rtp || (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU)) {
46 14502 : nbBits += 8*builder->slMap.KI_length;
47 : }
48 :
49 : /*no input header specified, compute the MAX size*/
50 25192 : if (!slh) {
51 : /*size length*/
52 0 : if (!builder->slMap.ConstantSize) nbBits += builder->slMap.SizeLength;
53 : /*AU index length*/
54 0 : nbBits += builder->first_sl_in_rtp ? builder->slMap.IndexLength : builder->slMap.IndexDeltaLength;
55 : /*CTS flag*/
56 0 : if (builder->slMap.CTSDeltaLength) {
57 0 : nbBits += 1;
58 : /*all non-first packets have the CTS written if asked*/
59 0 : if (!builder->first_sl_in_rtp) nbBits += builder->slMap.CTSDeltaLength;
60 : }
61 0 : if (builder->slMap.DTSDeltaLength) nbBits += 1 + builder->slMap.DTSDeltaLength;
62 0 : if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) nbBits += 8;
63 : return nbBits;
64 : }
65 :
66 : /*size length*/
67 25192 : if (!builder->slMap.ConstantSize) nbBits += builder->slMap.SizeLength;
68 :
69 : /*AU index*/
70 25192 : if (builder->first_sl_in_rtp) {
71 14502 : if (builder->slMap.IndexLength) nbBits += builder->slMap.IndexLength;
72 : } else {
73 10690 : if (builder->slMap.IndexDeltaLength) nbBits += builder->slMap.IndexDeltaLength;
74 : }
75 :
76 : /*CTS Flag*/
77 25192 : if (builder->slMap.CTSDeltaLength) {
78 : /*CTS not written if first SL*/
79 0 : if (builder->first_sl_in_rtp) slh->compositionTimeStampFlag = 0;
80 : /*but CTS flag is always written*/
81 0 : nbBits += 1;
82 : } else {
83 25192 : slh->compositionTimeStampFlag = 0;
84 : }
85 : /*CTS*/
86 25192 : if (slh->compositionTimeStampFlag) nbBits += builder->slMap.CTSDeltaLength;
87 :
88 : /*DTS Flag*/
89 25192 : if (builder->slMap.DTSDeltaLength) {
90 3157 : nbBits += 1;
91 : } else {
92 22035 : slh->decodingTimeStampFlag = 0;
93 : }
94 : /*DTS*/
95 25192 : if (slh->decodingTimeStampFlag) nbBits += builder->slMap.DTSDeltaLength;
96 : /*RAP indication*/
97 25192 : if (builder->slMap.RandomAccessIndication) nbBits ++;
98 : /*streamState indication*/
99 25192 : nbBits += builder->slMap.StreamStateIndication;
100 :
101 25192 : return nbBits;
102 : }
103 :
104 :
105 : /*write the AU header section - return the nb of BITS written for AU header*/
106 20996 : u32 gf_rtp_build_au_hdr_write(GP_RTPPacketizer *builder, u32 PayloadSize, u32 RTP_TS)
107 : {
108 : u32 nbBits = 0;
109 : s32 delta;
110 :
111 : /*selective encryption*/
112 20996 : if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) {
113 0 : gf_bs_write_int(builder->pck_hdr, builder->is_encrypted, 1);
114 0 : gf_bs_write_int(builder->pck_hdr, 0, 7);
115 : nbBits = 8;
116 : }
117 : /*IV*/
118 20996 : if (builder->first_sl_in_rtp) {
119 14502 : if (builder->slMap.IV_length) {
120 1016 : gf_bs_write_long_int(builder->pck_hdr, builder->IV, 8*builder->slMap.IV_length);
121 1016 : nbBits += 8*builder->slMap.IV_length;
122 : }
123 : } else if (builder->slMap.IV_delta_length) {
124 : /*NOT SUPPORTED!!! this only applies to interleaving*/
125 : }
126 : /*key*/
127 20996 : if (builder->slMap.KI_length) {
128 0 : if (builder->first_sl_in_rtp || (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU)) {
129 0 : if (builder->key_indicator) gf_bs_write_data(builder->pck_hdr, builder->key_indicator, builder->slMap.KI_length);
130 0 : else gf_bs_write_int(builder->pck_hdr, 0, 8*builder->slMap.KI_length);
131 0 : nbBits += 8*builder->slMap.KI_length;
132 : }
133 : }
134 :
135 :
136 : /*size length*/
137 20996 : if (builder->slMap.ConstantSize) {
138 0 : if (PayloadSize != builder->slMap.ConstantSize) return nbBits;
139 20996 : } else if (builder->slMap.SizeLength) {
140 : /*write the AU size - if not enough bytes (real-time cases) set size to 0*/
141 10712 : if (builder->sl_header.accessUnitLength >= (1<<builder->slMap.SizeLength)) {
142 0 : gf_bs_write_int(builder->pck_hdr, 0, builder->slMap.SizeLength);
143 : } else {
144 10712 : gf_bs_write_int(builder->pck_hdr, builder->sl_header.accessUnitLength, builder->slMap.SizeLength);
145 : }
146 10712 : nbBits += builder->slMap.SizeLength;
147 : }
148 : /*AU index*/
149 20996 : if (builder->first_sl_in_rtp) {
150 14502 : if (builder->slMap.IndexLength) {
151 4218 : gf_bs_write_int(builder->pck_hdr, builder->sl_header.AU_sequenceNumber, builder->slMap.IndexLength);
152 4218 : nbBits += builder->slMap.IndexLength;
153 : }
154 : } else {
155 6494 : if (builder->slMap.IndexDeltaLength) {
156 : //check interleaving, otherwise force default (which is currently always the case)
157 6494 : delta = builder->sl_header.AU_sequenceNumber - builder->last_au_sn;
158 6494 : delta -= 1;
159 6494 : gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.IndexDeltaLength);
160 6494 : nbBits += builder->slMap.IndexDeltaLength;
161 : }
162 : }
163 :
164 : /*CTS Flag*/
165 20996 : if (builder->slMap.CTSDeltaLength) {
166 0 : if (builder->first_sl_in_rtp) {
167 0 : builder->sl_header.compositionTimeStampFlag = 0;
168 0 : builder->sl_header.compositionTimeStamp = RTP_TS;
169 : }
170 0 : gf_bs_write_int(builder->pck_hdr, builder->sl_header.compositionTimeStampFlag, 1);
171 0 : nbBits += 1;
172 : }
173 : /*CTS*/
174 20996 : if (builder->sl_header.compositionTimeStampFlag) {
175 0 : delta = (u32) builder->sl_header.compositionTimeStamp - RTP_TS;
176 0 : gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.CTSDeltaLength);
177 0 : nbBits += builder->slMap.CTSDeltaLength;
178 : }
179 : /*DTS Flag*/
180 20996 : if (builder->slMap.DTSDeltaLength) {
181 3157 : gf_bs_write_int(builder->pck_hdr, builder->sl_header.decodingTimeStampFlag, 1);
182 3157 : nbBits += 1;
183 : }
184 : /*DTS*/
185 20996 : if (builder->sl_header.decodingTimeStampFlag) {
186 3157 : delta = (u32) (builder->sl_header.compositionTimeStamp - builder->sl_header.decodingTimeStamp);
187 3157 : gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.DTSDeltaLength);
188 3157 : nbBits += builder->slMap.DTSDeltaLength;
189 : }
190 : /*RAP indication*/
191 20996 : if (builder->slMap.RandomAccessIndication) {
192 956 : gf_bs_write_int(builder->pck_hdr, builder->sl_header.randomAccessPointFlag, 1);
193 956 : nbBits ++;
194 : }
195 : /*stream state - write AUSeqNum*/
196 20996 : if (builder->slMap.StreamStateIndication) {
197 5 : gf_bs_write_int(builder->pck_hdr, builder->sl_header.AU_sequenceNumber, builder->slMap.StreamStateIndication);
198 5 : nbBits += builder->slMap.StreamStateIndication;
199 : }
200 :
201 : return nbBits;
202 : }
203 :
204 :
205 18214 : GF_Err gp_rtp_builder_do_mpeg4(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
206 : {
207 : u8 *sl_buffer, *payl_buffer;
208 : u32 sl_buffer_size, payl_buffer_size;
209 : u32 auh_size_tmp, bytesLeftInPacket, infoSize, pckSize;
210 : u64 pos;
211 : u8 flush_pck, no_split;
212 :
213 : flush_pck = 0;
214 :
215 : bytesLeftInPacket = data_size;
216 : /*flush everything*/
217 18214 : if (!data) {
218 45 : if (builder->payload) goto flush_packet;
219 : return GF_OK;
220 : }
221 18169 : if (builder->payload && builder->force_flush) goto flush_packet;
222 :
223 : //go till done
224 43377 : while (bytesLeftInPacket) {
225 : no_split = 0;
226 :
227 25192 : if (builder->sl_header.accessUnitStartFlag) {
228 : //init SL
229 22365 : if (builder->sl_header.compositionTimeStamp != builder->sl_header.decodingTimeStamp) {
230 844 : builder->sl_header.decodingTimeStampFlag = 1;
231 : }
232 22365 : builder->sl_header.compositionTimeStampFlag = 1;
233 22365 : builder->sl_header.accessUnitLength = FullAUSize;
234 :
235 : //init some vars - based on the available size and the TS
236 : //we decide if we go with the same RTP TS serie or not
237 22365 : if (builder->payload) {
238 : //don't store more than what we can (that is 2^slMap->CTSDelta - 1)
239 10690 : if ( (builder->flags & GP_RTP_PCK_SIGNAL_TS)
240 0 : && (builder->sl_header.compositionTimeStamp - builder->rtp_header.TimeStamp >= (u32) ( 1 << builder->slMap.CTSDeltaLength) ) ) {
241 : goto flush_packet;
242 : }
243 : //don't split AU if # TS , start a new RTP pck
244 10690 : if (builder->sl_header.compositionTimeStamp != builder->rtp_header.TimeStamp)
245 : no_split = 1;
246 : }
247 : }
248 :
249 : /*new RTP Packet*/
250 25192 : if (!builder->payload) {
251 : /*first SL in RTP*/
252 14502 : builder->first_sl_in_rtp = GF_TRUE;
253 :
254 : /*if this is the end of an AU we will set it to 0 as soon as an AU is splitted*/
255 14502 : builder->rtp_header.Marker = 1;
256 14502 : builder->rtp_header.PayloadType = builder->PayloadType;
257 14502 : builder->rtp_header.SequenceNumber += 1;
258 :
259 14502 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
260 : /*prepare the mapped headers*/
261 14502 : builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
262 14502 : builder->payload = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
263 14502 : builder->bytesInPacket = 0;
264 :
265 : /*in multiSL there is a MSLHSize structure on 2 bytes*/
266 14502 : builder->auh_size = 0;
267 14502 : if (builder->has_AU_header) {
268 8156 : builder->auh_size = 16;
269 8156 : gf_bs_write_int(builder->pck_hdr, 0, 16);
270 : }
271 : flush_pck = 0;
272 : /*and create packet*/
273 14502 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
274 : }
275 :
276 : //make sure we are not interleaving too much - this should never happen actually
277 25192 : if (builder->slMap.IndexDeltaLength
278 14908 : && !builder->first_sl_in_rtp
279 10690 : && (builder->sl_header.AU_sequenceNumber - builder->last_au_sn >= (u32) 1<<builder->slMap.IndexDeltaLength)) {
280 : //we cannot write this packet here
281 : goto flush_packet;
282 : }
283 : /*check max ptime*/
284 25192 : if (builder->max_ptime && ( (u32) builder->sl_header.compositionTimeStamp >= builder->rtp_header.TimeStamp + builder->max_ptime) )
285 : goto flush_packet;
286 :
287 25192 : auh_size_tmp = gf_rtp_build_au_hdr_size(builder, &builder->sl_header);
288 :
289 25192 : infoSize = auh_size_tmp + builder->auh_size;
290 25192 : infoSize /= 8;
291 : /*align*/
292 25192 : if ( (builder->auh_size + auh_size_tmp) % 8) infoSize += 1;
293 :
294 :
295 25192 : if (bytesLeftInPacket + infoSize + builder->bytesInPacket <= builder->Path_MTU) {
296 : //End of our data chunk
297 : pckSize = bytesLeftInPacket;
298 18169 : builder->sl_header.accessUnitEndFlag = IsAUEnd;
299 :
300 18169 : builder->auh_size += auh_size_tmp;
301 :
302 18169 : builder->sl_header.paddingFlag = builder->sl_header.paddingBits ? 1 : 0;
303 : } else {
304 :
305 : //AU cannot fit in packet. If no split, start a new packet
306 7023 : if (no_split) goto flush_packet;
307 :
308 2827 : builder->auh_size += auh_size_tmp;
309 :
310 2827 : pckSize = builder->Path_MTU - (infoSize + builder->bytesInPacket);
311 : //that's the end of the rtp packet
312 : flush_pck = 1;
313 : //but not of the AU -> marker is 0
314 2827 : builder->rtp_header.Marker = 0;
315 : }
316 :
317 20996 : gf_rtp_build_au_hdr_write(builder, pckSize, builder->rtp_header.TimeStamp);
318 :
319 : //notify the user of our data structure
320 20996 : if (builder->OnDataReference)
321 20498 : builder->OnDataReference(builder->cbk_obj, pckSize, data_size - bytesLeftInPacket);
322 : else
323 498 : gf_bs_write_data(builder->payload, data + (data_size - bytesLeftInPacket), pckSize);
324 :
325 :
326 20996 : bytesLeftInPacket -= pckSize;
327 20996 : builder->bytesInPacket += pckSize;
328 : /*update IV*/
329 20996 : builder->IV += pckSize;
330 20996 : builder->sl_header.paddingFlag = 0;
331 20996 : builder->sl_header.accessUnitStartFlag = 0;
332 :
333 : //we are splitting a payload, auto increment SL seq num
334 20996 : if (bytesLeftInPacket) {
335 2827 : builder->sl_header.packetSequenceNumber += 1;
336 18169 : } else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) {
337 7458 : builder->rtp_header.Marker = 1;
338 : flush_pck = 1;
339 : }
340 :
341 : //first SL in RTP is done
342 20996 : builder->first_sl_in_rtp = GF_FALSE;
343 :
344 : //store current sl
345 20996 : builder->last_au_sn = builder->sl_header.AU_sequenceNumber;
346 :
347 31707 : if (!flush_pck) continue;
348 :
349 : //done with the packet
350 14497 : flush_packet:
351 :
352 14497 : gf_bs_align(builder->pck_hdr);
353 :
354 : /*no aux data yet*/
355 14497 : if (builder->slMap.AuxiliaryDataSizeLength) {
356 : //write RSLH after the MSLH
357 0 : gf_bs_write_int(builder->pck_hdr, 0, builder->slMap.AuxiliaryDataSizeLength);
358 : }
359 : /*rewrite the size header*/
360 14497 : if (builder->has_AU_header) {
361 8151 : pos = gf_bs_get_position(builder->pck_hdr);
362 8151 : gf_bs_seek(builder->pck_hdr, 0);
363 8151 : builder->auh_size -= 16;
364 8151 : gf_bs_write_int(builder->pck_hdr, builder->auh_size, 16);
365 8151 : gf_bs_seek(builder->pck_hdr, pos);
366 : }
367 :
368 14497 : sl_buffer = NULL;
369 14497 : gf_bs_get_content(builder->pck_hdr, &sl_buffer, &sl_buffer_size);
370 : //delete our bitstream
371 14497 : gf_bs_del(builder->pck_hdr);
372 14497 : builder->pck_hdr = NULL;
373 :
374 14497 : payl_buffer = NULL;
375 14497 : payl_buffer_size = 0;
376 14497 : if (!builder->OnDataReference)
377 130 : gf_bs_get_content(builder->payload, &payl_buffer, &payl_buffer_size);
378 :
379 14497 : gf_bs_del(builder->payload);
380 14497 : builder->payload = NULL;
381 :
382 : /*notify header*/
383 14497 : builder->OnData(builder->cbk_obj, sl_buffer, sl_buffer_size, GF_TRUE);
384 : /*notify payload*/
385 14497 : if (payl_buffer) {
386 130 : builder->OnData(builder->cbk_obj, payl_buffer, payl_buffer_size, GF_FALSE);
387 130 : gf_free(payl_buffer);
388 : }
389 : /*flush packet*/
390 14497 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
391 14497 : gf_free(sl_buffer);
392 : }
393 : //packet is done, update AU markers
394 18185 : if (IsAUEnd) {
395 18185 : builder->sl_header.accessUnitStartFlag = 1;
396 18185 : builder->sl_header.accessUnitEndFlag = 0;
397 : }
398 : return GF_OK;
399 : }
400 :
401 :
402 3721 : GF_Err gp_rtp_builder_do_avc(GP_RTPPacketizer *builder, u8 *nalu, u32 nalu_size, u8 IsAUEnd, u32 FullAUSize)
403 : {
404 : u32 do_flush, bytesLeft, size, nal_type;
405 : char shdr[2];
406 : char stap_hdr;
407 :
408 : do_flush = 0;
409 3721 : if (!nalu) do_flush = 1;
410 : /*we only do STAP or SINGLE modes*/
411 3705 : else if (builder->sl_header.accessUnitStartFlag) do_flush = 1;
412 : /*we must NOT fragment a NALU*/
413 1529 : else if (builder->bytesInPacket + nalu_size >= builder->Path_MTU) do_flush = 2;
414 : /*aggregation is disabled*/
415 722 : else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) do_flush = 2;
416 :
417 3721 : if (builder->bytesInPacket && do_flush) {
418 1228 : builder->rtp_header.Marker = (do_flush==1) ? 1 : 0;
419 1228 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
420 1228 : builder->bytesInPacket = 0;
421 : }
422 :
423 3721 : if (!nalu) return GF_OK;
424 :
425 : /*need a new RTP packet*/
426 3705 : if (!builder->bytesInPacket) {
427 3705 : builder->rtp_header.PayloadType = builder->PayloadType;
428 3705 : builder->rtp_header.Marker = 0;
429 3705 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
430 3705 : builder->rtp_header.SequenceNumber += 1;
431 3705 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
432 3705 : builder->avc_non_idr = GF_TRUE;
433 : }
434 :
435 : /*check NAL type to see if disposable or not*/
436 3705 : nal_type = nalu[0] & 0x1F;
437 : switch (nal_type) {
438 : case GF_AVC_NALU_NON_IDR_SLICE:
439 : case GF_AVC_NALU_ACCESS_UNIT:
440 : case GF_AVC_NALU_END_OF_SEQ:
441 : case GF_AVC_NALU_END_OF_STREAM:
442 : case GF_AVC_NALU_FILLER_DATA:
443 : break;
444 1579 : default:
445 1579 : builder->avc_non_idr = GF_FALSE;
446 1579 : break;
447 : }
448 :
449 : /*at this point we're sure the NALU fits in current packet OR must be splitted*/
450 :
451 : /*pb: we don't know if next NALU from this AU will be small enough to fit in the packet, so we always
452 : go for stap...*/
453 3705 : if (builder->bytesInPacket+nalu_size<builder->Path_MTU) {
454 : Bool use_stap = GF_TRUE;
455 : /*if this is the AU end and no NALU in packet, go for single mode*/
456 2678 : if (IsAUEnd && !builder->bytesInPacket) use_stap = GF_FALSE;
457 :
458 : if (use_stap) {
459 : /*declare STAP-A NAL*/
460 1228 : if (!builder->bytesInPacket) {
461 : /*copy over F and NRI from first nal in packet and assign type*/
462 1228 : stap_hdr = (nalu[0] & 0xE0) | 24;
463 1228 : builder->OnData(builder->cbk_obj, (char *) &stap_hdr, 1, GF_FALSE);
464 1228 : builder->bytesInPacket = 1;
465 : }
466 : /*add NALU size*/
467 1228 : shdr[0] = nalu_size>>8;
468 1228 : shdr[1] = nalu_size&0x00ff;
469 1228 : builder->OnData(builder->cbk_obj, (char *)shdr, 2, GF_FALSE);
470 1228 : builder->bytesInPacket += 2;
471 : }
472 : /*add data*/
473 2678 : if (builder->OnDataReference)
474 2561 : builder->OnDataReference(builder->cbk_obj, nalu_size, 0);
475 : else
476 117 : builder->OnData(builder->cbk_obj, nalu, nalu_size, GF_FALSE);
477 :
478 2678 : builder->bytesInPacket += nalu_size;
479 :
480 2678 : if (IsAUEnd) {
481 1450 : builder->rtp_header.Marker = 1;
482 1450 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
483 1450 : builder->bytesInPacket = 0;
484 : }
485 : }
486 : /*fragmentation unit*/
487 : else {
488 : u32 offset;
489 : assert(nalu_size>=builder->Path_MTU);
490 : assert(!builder->bytesInPacket);
491 : /*FU payload doesn't have the NAL hdr*/
492 1027 : bytesLeft = nalu_size - 1;
493 : offset = 1;
494 4583 : while (bytesLeft) {
495 2529 : if (2 + bytesLeft > builder->Path_MTU) {
496 1502 : size = builder->Path_MTU - 2;
497 : } else {
498 : size = bytesLeft;
499 : }
500 :
501 : /*copy over F and NRI from nal in packet and assign type*/
502 2529 : shdr[0] = (nalu[0] & 0xE0) | 28;
503 : /*copy over NAL type from nal and set start bit and end bit*/
504 2529 : shdr[1] = (nalu[0] & 0x1F);
505 : /*start bit*/
506 2529 : if (offset==1) shdr[1] |= 0x80;
507 : /*end bit*/
508 1502 : else if (size == bytesLeft) shdr[1] |= 0x40;
509 :
510 2529 : builder->OnData(builder->cbk_obj, (char *)shdr, 2, GF_FALSE);
511 :
512 : /*add data*/
513 2529 : if (builder->OnDataReference)
514 2477 : builder->OnDataReference(builder->cbk_obj, size, offset);
515 : else
516 52 : builder->OnData(builder->cbk_obj, nalu+offset, size, GF_FALSE);
517 :
518 2529 : offset += size;
519 2529 : bytesLeft -= size;
520 :
521 : /*flush no matter what (FUs cannot be agreggated)*/
522 2529 : builder->rtp_header.Marker = (IsAUEnd && !bytesLeft) ? 1 : 0;
523 2529 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
524 2529 : builder->bytesInPacket = 0;
525 :
526 2529 : if (bytesLeft) {
527 1502 : builder->rtp_header.PayloadType = builder->PayloadType;
528 1502 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
529 1502 : builder->rtp_header.SequenceNumber += 1;
530 1502 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
531 : }
532 : }
533 : }
534 :
535 : return GF_OK;
536 : }
537 :
538 2786 : GF_Err gp_rtp_builder_do_hevc(GP_RTPPacketizer *builder, u8 *nalu, u32 nalu_size, u8 IsAUEnd, u32 FullAUSize)
539 : {
540 : u32 do_flush, bytesLeft, size;
541 :
542 : do_flush = 0;
543 2786 : if (!nalu) do_flush = 1;
544 2783 : else if (builder->sl_header.accessUnitStartFlag) do_flush = 1;
545 : /*we must NOT fragment a NALU*/
546 2504 : else if (builder->bytesInPacket + nalu_size + 4 >= builder->Path_MTU) do_flush = 2; //2 bytes PayloadHdr for AP + 2 bytes NAL size
547 : /*aggregation is disabled*/
548 2199 : else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) do_flush = 2;
549 :
550 2786 : if (builder->bytesInPacket && do_flush) {
551 539 : builder->rtp_header.Marker = (do_flush==1) ? 1 : 0;
552 : /*insert payload_hdr in case of AP*/
553 539 : if (strlen(builder->hevc_payload_hdr)) {
554 299 : builder->OnData(builder->cbk_obj, (char *)builder->hevc_payload_hdr, 2, GF_TRUE);
555 : memset(builder->hevc_payload_hdr, 0, 2);
556 : }
557 539 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
558 539 : builder->bytesInPacket = 0;
559 : }
560 :
561 2786 : if (!nalu) return GF_OK;
562 :
563 : /*need a new RTP packet*/
564 2783 : if (!builder->bytesInPacket) {
565 845 : builder->rtp_header.PayloadType = builder->PayloadType;
566 845 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
567 845 : builder->rtp_header.SequenceNumber += 1;
568 845 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
569 : }
570 :
571 : /*at this point we're sure the NALU fits in current packet OR must be splitted*/
572 : /*check that we should use single NALU packet mode or aggreation packets mode*/
573 2783 : if (builder->bytesInPacket+nalu_size+4 < builder->Path_MTU) {
574 2756 : Bool use_AP = (builder->flags & GP_RTP_PCK_USE_MULTI) ? GF_TRUE : GF_FALSE;
575 : /*if this is the AU end and no NALU in packet, go for single NALU packet mode*/
576 2756 : if (IsAUEnd && !builder->bytesInPacket) use_AP = GF_FALSE;
577 :
578 2727 : if (use_AP) {
579 : char nal_s[2];
580 : /*declare PayloadHdr for AP*/
581 2487 : if (!builder->bytesInPacket) {
582 : /*copy F bit and assign type*/
583 549 : builder->hevc_payload_hdr[0] = (nalu[0] & 0x81) | (48 << 1);
584 : /*copy LayerId and TID*/
585 549 : builder->hevc_payload_hdr[1] = nalu[1];
586 : }
587 : else {
588 : /*F bit of AP is 0 if the F nit of each aggreated NALU is 0; otherwise its must be 1*/
589 : /*LayerId and TID must ne the lowest value of LayerId and TID of all aggreated NALU*/
590 : u8 cur_LayerId, cur_TID, new_LayerId, new_TID;
591 :
592 1938 : builder->hevc_payload_hdr[0] |= (nalu[0] & 0x80);
593 1938 : cur_LayerId = ((builder->hevc_payload_hdr[0] & 0x01) << 5) + ((builder->hevc_payload_hdr[1] & 0xF8) >> 3);
594 1938 : new_LayerId = ((nalu[0] & 0x01) << 5) + ((nalu[1] & 0xF8) >> 3);
595 1938 : if (cur_LayerId > new_LayerId) {
596 0 : builder->hevc_payload_hdr[0] = (builder->hevc_payload_hdr[0] & 0xFE) | (nalu[0] & 0x01);
597 0 : builder->hevc_payload_hdr[1] = (builder->hevc_payload_hdr[1] & 0x07) | (nalu[1] & 0xF8);
598 : }
599 1938 : cur_TID = builder->hevc_payload_hdr[1] & 0x07;
600 1938 : new_TID = nalu[1] & 0x07;
601 1938 : if (cur_TID > new_TID) {
602 0 : builder->hevc_payload_hdr[1] = (builder->hevc_payload_hdr[1] & 0xF8) | (nalu[1] & 0x07);
603 : }
604 : }
605 :
606 : /*add NALU size*/
607 2487 : nal_s[0] = nalu_size>>8;
608 2487 : nal_s[1] = nalu_size&0x00ff;
609 2487 : builder->OnData(builder->cbk_obj, (char *)nal_s, 2, GF_FALSE);
610 2487 : builder->bytesInPacket += 2;
611 : }
612 : /*add data*/
613 2756 : if (builder->OnDataReference)
614 2489 : builder->OnDataReference(builder->cbk_obj, nalu_size, 0);
615 : else
616 267 : builder->OnData(builder->cbk_obj, nalu, nalu_size, GF_FALSE);
617 :
618 2756 : builder->bytesInPacket += nalu_size;
619 :
620 2756 : if (IsAUEnd) {
621 279 : builder->rtp_header.Marker = 1;
622 279 : if (strlen(builder->hevc_payload_hdr)) {
623 250 : builder->OnData(builder->cbk_obj, (char *)builder->hevc_payload_hdr, 2, GF_TRUE);
624 : memset(builder->hevc_payload_hdr, 0, 2);
625 : }
626 279 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
627 279 : builder->bytesInPacket = 0;
628 : }
629 : }
630 : /*fragmentation unit*/
631 : else {
632 : u32 offset;
633 : char payload_hdr[2];
634 : char shdr;
635 :
636 : assert(nalu_size + 4 >=builder->Path_MTU);
637 : assert(!builder->bytesInPacket);
638 :
639 : /*FU payload doesn't have the NAL hdr (2 bytes*/
640 27 : bytesLeft = nalu_size - 2;
641 : offset = 2;
642 158 : while (bytesLeft) {
643 104 : if (3 + bytesLeft > builder->Path_MTU) {
644 77 : size = builder->Path_MTU - 3;
645 : } else {
646 : size = bytesLeft;
647 : }
648 :
649 : /*declare PayloadHdr for FU*/
650 : memset(payload_hdr, 0, 2);
651 : /*copy F bit and assign type*/
652 104 : payload_hdr[0] = (nalu[0] & 0x81) | (49 << 1);
653 : /*copy LayerId and TID*/
654 104 : payload_hdr[1] = nalu[1];
655 104 : builder->OnData(builder->cbk_obj, (char *)payload_hdr, 2, GF_FALSE);
656 :
657 : /*declare FU header*/
658 : shdr = 0;
659 : /*assign type*/
660 104 : shdr |= (nalu[0] & 0x7E) >> 1;
661 : /*start bit*/
662 104 : if (offset==2) shdr |= 0x80;
663 : /*end bit*/
664 77 : else if (size == bytesLeft) shdr |= 0x40;
665 :
666 104 : builder->OnData(builder->cbk_obj, &shdr, 1, GF_FALSE);
667 :
668 : /*add data*/
669 104 : if (builder->OnDataReference)
670 90 : builder->OnDataReference(builder->cbk_obj, size, offset);
671 : else
672 14 : builder->OnData(builder->cbk_obj, nalu+offset, size, GF_FALSE);
673 :
674 104 : offset += size;
675 104 : bytesLeft -= size;
676 :
677 : /*flush no matter what (FUs cannot be agreggated)*/
678 104 : builder->rtp_header.Marker = (IsAUEnd && !bytesLeft) ? 1 : 0;
679 104 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
680 104 : builder->bytesInPacket = 0;
681 :
682 104 : if (bytesLeft) {
683 77 : builder->rtp_header.PayloadType = builder->PayloadType;
684 77 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
685 77 : builder->rtp_header.SequenceNumber += 1;
686 77 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
687 : }
688 : }
689 : }
690 : return GF_OK;
691 : }
692 :
693 0 : void latm_flush(GP_RTPPacketizer *builder)
694 : {
695 10 : if (builder->bytesInPacket) {
696 9 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
697 9 : builder->bytesInPacket = 0;
698 : }
699 10 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
700 0 : }
701 :
702 49 : GF_Err gp_rtp_builder_do_latm(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration)
703 : {
704 : u32 size, latm_hdr_size, i, data_offset;
705 : Bool fragmented;
706 :
707 49 : if (!data) {
708 : latm_flush(builder);
709 2 : return GF_OK;
710 : }
711 :
712 47 : if ((builder->flags & GP_RTP_PCK_USE_MULTI) && builder->max_ptime) {
713 0 : if ((u32) builder->sl_header.compositionTimeStamp + duration >= builder->rtp_header.TimeStamp + builder->max_ptime)
714 : latm_flush(builder);
715 : }
716 : /*compute max size for frame, flush current if this doesn't fit*/
717 47 : latm_hdr_size = (data_size / 255) + 1;
718 47 : if (latm_hdr_size+data_size > builder->Path_MTU - builder->bytesInPacket) {
719 : latm_flush(builder);
720 : }
721 :
722 : data_offset = 0;
723 : fragmented = GF_FALSE;
724 94 : while (data_size > 0) {
725 : u8 *latm_hdr;
726 47 : latm_hdr_size = (data_size / 255) + 1;
727 : /*fragmenting*/
728 47 : if (latm_hdr_size + data_size > builder->Path_MTU) {
729 : assert(!builder->bytesInPacket);
730 : fragmented = GF_TRUE;
731 0 : latm_hdr_size = (builder->Path_MTU / 255) + 1;
732 0 : size = builder->Path_MTU - latm_hdr_size;
733 0 : builder->rtp_header.Marker = 0;
734 : }
735 : /*last fragment or full AU*/
736 : else {
737 : fragmented = GF_FALSE;
738 : size = data_size;
739 47 : builder->rtp_header.Marker = 1;
740 : }
741 47 : data_size -= size;
742 :
743 : /*create new RTP Packet if needed*/
744 47 : if (!builder->bytesInPacket) {
745 9 : builder->rtp_header.SequenceNumber += 1;
746 9 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
747 9 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
748 : }
749 :
750 : /* compute AudioMuxUnit header */
751 47 : latm_hdr_size = (size / 255) + 1;
752 47 : latm_hdr = (unsigned char *)gf_malloc( sizeof(char) * latm_hdr_size);
753 47 : for (i=0; i<latm_hdr_size-1; i++) latm_hdr[i] = 255;
754 47 : latm_hdr[latm_hdr_size-1] = size % 255;
755 :
756 : /*add LATM header IN ORDER in case we aggregate audioMuxElements in RTP*/
757 47 : builder->OnData(builder->cbk_obj, (char*) latm_hdr, latm_hdr_size, GF_FALSE);
758 47 : builder->bytesInPacket += latm_hdr_size;
759 47 : gf_free(latm_hdr);
760 :
761 : /*add payload*/
762 47 : if (builder->OnDataReference) {
763 0 : builder->OnDataReference(builder->cbk_obj, size, data_offset);
764 : } else
765 47 : builder->OnData(builder->cbk_obj, data, size, GF_FALSE);
766 :
767 47 : builder->bytesInPacket += size;
768 :
769 47 : data_offset += size;
770 :
771 : /*fragmented AU, always flush packet*/
772 47 : if (!builder->rtp_header.Marker) latm_flush(builder);
773 : }
774 : /*if the AU has been fragmented or we don't use RTP aggregation, flush*/
775 47 : if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) fragmented = GF_TRUE;
776 47 : if (fragmented) latm_flush(builder);
777 :
778 : return GF_OK;
779 : }
780 :
781 :
782 : #endif /*GPAC_DISABLE_STREAMING*/
|