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 21421 : static void rtp_amr_flush(GP_RTPPacketizer *builder)
33 : {
34 : u8 *hdr;
35 : u32 hdr_size;
36 21425 : if (!builder->bytesInPacket) return;
37 21417 : gf_bs_get_content(builder->pck_hdr, &hdr, &hdr_size);
38 21417 : gf_bs_del(builder->pck_hdr);
39 21417 : builder->pck_hdr = NULL;
40 : /*overwrite last frame F bit*/
41 21417 : hdr[builder->last_au_sn] &= 0x7F;
42 21417 : builder->OnData(builder->cbk_obj, hdr, hdr_size, GF_TRUE);
43 21417 : gf_free(hdr);
44 21417 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
45 21417 : builder->bytesInPacket = 0;
46 21417 : builder->last_au_sn = 0;
47 : }
48 :
49 21421 : GF_Err gp_rtp_builder_do_amr(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
50 : {
51 : u32 offset, rtp_ts, block_size;
52 :
53 21421 : if (!data) {
54 4 : rtp_amr_flush(builder);
55 4 : return GF_OK;
56 : }
57 :
58 21417 : rtp_ts = (u32) builder->sl_header.compositionTimeStamp;
59 :
60 : offset = 0;
61 64251 : while (data_size>offset) {
62 21417 : u8 ft = (data[offset] & 0x78) >> 3;
63 : u8 size;
64 :
65 21417 : if (builder->rtp_payt == GF_RTP_PAYT_AMR_WB) {
66 19869 : size = (u32)GF_AMR_WB_FRAME_SIZE[ft];
67 : block_size = 320;
68 : } else {
69 1548 : size = (u32)GF_AMR_FRAME_SIZE[ft];
70 : block_size = 160;
71 : }
72 :
73 : /*packet full or too long*/
74 21417 : if (builder->bytesInPacket + 1 + size > builder->Path_MTU)
75 0 : rtp_amr_flush(builder);
76 :
77 : /*need new*/
78 21417 : if (!builder->bytesInPacket) {
79 21417 : builder->rtp_header.TimeStamp = rtp_ts;
80 21417 : builder->rtp_header.Marker = 0; /*never set*/
81 21417 : builder->rtp_header.SequenceNumber += 1;
82 21417 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
83 : assert(builder->pck_hdr==NULL);
84 :
85 : /*always have header and TOC*/
86 21417 : builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
87 : /*CMR + res (all 0, no interleaving)*/
88 21417 : gf_bs_write_int(builder->pck_hdr, ft, 4);
89 21417 : gf_bs_write_int(builder->pck_hdr, 0, 4);
90 21417 : builder->bytesInPacket = 1;
91 : /*no interleaving*/
92 : }
93 :
94 : /*F always to 1*/
95 21417 : gf_bs_write_int(builder->pck_hdr, 1, 1);
96 21417 : gf_bs_write_int(builder->pck_hdr, ft, 4);
97 : /*Q*/
98 21417 : gf_bs_write_int(builder->pck_hdr, (data[offset] & 0x4) ? 1 : 0, 1);
99 21417 : gf_bs_write_int(builder->pck_hdr, 0, 2);
100 21417 : builder->bytesInPacket ++;
101 :
102 : /*remove frame type byte*/
103 21417 : offset++;
104 :
105 : /*add frame data without rate_type byte header*/
106 21417 : if (builder->OnDataReference) {
107 21366 : builder->OnDataReference(builder->cbk_obj, size, offset);
108 : } else {
109 51 : builder->OnData(builder->cbk_obj, data+offset, size, GF_FALSE);
110 : }
111 21417 : builder->last_au_sn++;
112 21417 : builder->bytesInPacket += size;
113 21417 : offset += size;
114 21417 : rtp_ts += block_size;
115 : assert(builder->bytesInPacket<=builder->Path_MTU);
116 : /*take care of aggregation, flush if needed*/
117 21417 : if (builder->last_au_sn==builder->auh_size) rtp_amr_flush(builder);
118 : }
119 : return GF_OK;
120 : }
121 :
122 : static GFINLINE u8 qes_get_rate_size(u32 idx, const unsigned int *rates, const unsigned int nb_rates)
123 : {
124 : u32 i;
125 42614 : for (i=0; i<nb_rates; i++) {
126 58350 : if (rates[2*i]==idx) return rates[2*i+1];
127 : }
128 : return 0;
129 : }
130 :
131 555 : GF_Err gp_rtp_builder_do_qcelp(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
132 : {
133 : u32 offset, rtp_ts;
134 : u8 hdr;
135 :
136 555 : if (!data) {
137 3 : if (builder->bytesInPacket) builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
138 3 : builder->bytesInPacket = 0;
139 3 : builder->last_au_sn = 0;
140 3 : return GF_OK;
141 : }
142 :
143 552 : rtp_ts = (u32) builder->sl_header.compositionTimeStamp;
144 :
145 :
146 : offset = 0;
147 1656 : while (data_size>offset) {
148 552 : u8 frame_type = data[offset];
149 552 : u8 size = qes_get_rate_size(frame_type, GF_QCELP_RATE_TO_SIZE, GF_QCELP_RATE_TO_SIZE_NB);
150 : /*reserved, not sent)*/
151 552 : if (frame_type>=5) {
152 0 : offset += size;
153 0 : continue;
154 : }
155 : /*packet full or too long*/
156 552 : if (builder->bytesInPacket + size > builder->Path_MTU) {
157 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
158 0 : builder->bytesInPacket = 0;
159 0 : builder->last_au_sn = 0;
160 : }
161 :
162 : /*need new*/
163 552 : if (!builder->bytesInPacket) {
164 552 : builder->rtp_header.TimeStamp = rtp_ts;
165 552 : builder->rtp_header.Marker = 0; /*never set*/
166 552 : builder->rtp_header.SequenceNumber += 1;
167 552 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
168 552 : hdr = 0;/*no interleaving*/
169 552 : builder->OnData(builder->cbk_obj, (char*)&hdr, 1, GF_FALSE);
170 552 : builder->bytesInPacket = 1;
171 : }
172 552 : if (builder->OnDataReference) {
173 501 : builder->OnDataReference(builder->cbk_obj, size, offset);
174 : } else {
175 51 : builder->OnData(builder->cbk_obj, data+offset, size, GF_FALSE);
176 : }
177 552 : builder->bytesInPacket += size;
178 552 : offset += size;
179 552 : rtp_ts += 160;
180 : assert(builder->bytesInPacket<=builder->Path_MTU);
181 :
182 : /*take care of aggregation, flush if needed*/
183 552 : builder->last_au_sn++;
184 552 : if (builder->last_au_sn==builder->auh_size) {
185 552 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
186 552 : builder->bytesInPacket = 0;
187 552 : builder->last_au_sn = 0;
188 : }
189 : }
190 : return GF_OK;
191 : }
192 :
193 15185 : static void rtp_evrc_smv_flush(GP_RTPPacketizer *builder)
194 : {
195 15185 : if (!builder->bytesInPacket) return;
196 15184 : if (builder->auh_size>1) {
197 : u8 *hdr;
198 : u32 hdr_size;
199 : /*padding*/
200 0 : if (builder->last_au_sn % 2) gf_bs_write_int(builder->pck_hdr, 0, 4);
201 0 : gf_bs_get_content(builder->pck_hdr, &hdr, &hdr_size);
202 0 : gf_bs_del(builder->pck_hdr);
203 0 : builder->pck_hdr = NULL;
204 : /*overwrite count*/
205 0 : hdr[0] = 0;
206 0 : hdr[1] = builder->last_au_sn-1;/*MMM + frameCount-1*/
207 0 : builder->OnData(builder->cbk_obj, hdr, hdr_size, GF_TRUE);
208 0 : gf_free(hdr);
209 : }
210 15184 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
211 15184 : builder->bytesInPacket = 0;
212 15184 : builder->last_au_sn = 0;
213 : }
214 :
215 15185 : GF_Err gp_rtp_builder_do_smv(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
216 : {
217 : u32 offset, rtp_ts;
218 :
219 15185 : if (!data) {
220 1 : rtp_evrc_smv_flush(builder);
221 1 : return GF_OK;
222 : }
223 :
224 15184 : rtp_ts = (u32) builder->sl_header.compositionTimeStamp;
225 :
226 : offset = 0;
227 45552 : while (data_size>offset) {
228 15184 : u8 frame_type = data[offset];
229 15184 : u8 size = qes_get_rate_size(frame_type, GF_SMV_EVRC_RATE_TO_SIZE, GF_SMV_EVRC_RATE_TO_SIZE_NB);
230 :
231 : /*reserved, not sent)*/
232 15184 : if (frame_type>=5) {
233 0 : offset += size;
234 0 : continue;
235 : }
236 : /*packet full or too long*/
237 15184 : if (builder->bytesInPacket + size > builder->Path_MTU)
238 0 : rtp_evrc_smv_flush(builder);
239 :
240 : /*need new*/
241 15184 : if (!builder->bytesInPacket) {
242 15184 : builder->rtp_header.TimeStamp = rtp_ts;
243 15184 : builder->rtp_header.Marker = 0; /*never set*/
244 15184 : builder->rtp_header.SequenceNumber += 1;
245 15184 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
246 : assert(builder->pck_hdr==NULL);
247 :
248 15184 : if (builder->auh_size>1) {
249 0 : builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
250 : /*RRLLLNNN (all 0, no interleaving)*/
251 0 : gf_bs_write_u8(builder->pck_hdr, 0);
252 : /*MMM + count-1 : overridden when flushing*/
253 0 : gf_bs_write_u8(builder->pck_hdr, 0);
254 0 : builder->bytesInPacket = 2;
255 : }
256 : }
257 :
258 : /*bundle mode: cat rate byte to TOC, on 4 bits*/
259 15184 : if (builder->auh_size>1) {
260 0 : gf_bs_write_int(builder->pck_hdr, data[offset], 4);
261 0 : if (!(builder->last_au_sn % 2)) builder->bytesInPacket += 1;
262 : }
263 : /*note that EVEN in header-free format the rate_type byte is removed*/
264 15184 : offset++;
265 15184 : size--;
266 :
267 : /*add frame data without rate_type byte header*/
268 15184 : if (builder->OnDataReference) {
269 15184 : builder->OnDataReference(builder->cbk_obj, size, offset);
270 : } else {
271 0 : builder->OnData(builder->cbk_obj, data+offset, size, GF_FALSE);
272 : }
273 15184 : builder->last_au_sn++;
274 15184 : builder->bytesInPacket += size;
275 15184 : offset += size;
276 15184 : rtp_ts += 160;
277 : assert(builder->bytesInPacket<=builder->Path_MTU);
278 : /*take care of aggregation, flush if needed*/
279 15184 : if (builder->last_au_sn==builder->auh_size) rtp_evrc_smv_flush(builder);
280 : }
281 : return GF_OK;
282 : }
283 :
284 463 : GF_Err gp_rtp_builder_do_h263(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
285 : {
286 : u8 hdr[2];
287 : Bool Pbit;
288 : u32 offset, size, max_size;
289 :
290 463 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
291 :
292 : /*the H263 hinter doesn't perform inter-sample concatenation*/
293 463 : if (!data) return GF_OK;
294 :
295 : Pbit = GF_TRUE;
296 :
297 : /*skip 16 0'ed bits of start code*/
298 : offset = 2;
299 460 : data_size -= 2;
300 460 : max_size = builder->Path_MTU - 2;
301 :
302 1380 : while(data_size > 0) {
303 : GF_BitStream *bs;
304 460 : if(data_size > max_size) {
305 : size = max_size;
306 0 : builder->rtp_header.Marker = 0;
307 : } else {
308 : size = data_size;
309 460 : builder->rtp_header.Marker = 1;
310 : }
311 :
312 460 : data_size -= size;
313 :
314 : /*create new RTP Packet */
315 460 : builder->rtp_header.SequenceNumber += 1;
316 460 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
317 :
318 460 : bs = gf_bs_new(hdr, 2, GF_BITSTREAM_WRITE);
319 460 : gf_bs_write_int(bs, 0, 5);
320 460 : gf_bs_write_int(bs, Pbit, 1);
321 460 : gf_bs_write_int(bs, 0, 10);
322 460 : gf_bs_del(bs);
323 :
324 : /*add header*/
325 460 : builder->OnData(builder->cbk_obj, (char*) hdr, 2, GF_TRUE);
326 : /*add payload*/
327 460 : if (builder->OnDataReference)
328 443 : builder->OnDataReference(builder->cbk_obj, size, offset);
329 : else
330 17 : builder->OnData(builder->cbk_obj, data + offset, size, GF_FALSE);
331 :
332 460 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
333 :
334 460 : offset += size;
335 : Pbit = GF_FALSE;
336 : }
337 : return GF_OK;
338 : }
339 :
340 55 : GF_Err gp_rtp_builder_do_mp2t(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
341 : {
342 : u32 offset, size, max_size;
343 :
344 55 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
345 :
346 55 : if (!data) return GF_OK;
347 :
348 54 : max_size = builder->Path_MTU;
349 : offset = 0;
350 162 : while (data_size > 0) {
351 54 : if (data_size > max_size) {
352 0 : size = max_size / 188;
353 0 : size *= 188;
354 : } else {
355 : size = data_size;
356 : }
357 :
358 54 : data_size -= size;
359 :
360 : /*create new RTP Packet */
361 54 : builder->rtp_header.SequenceNumber += 1;
362 54 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
363 :
364 : /*add payload*/
365 54 : if (builder->OnDataReference)
366 0 : builder->OnDataReference(builder->cbk_obj, size, offset);
367 : else
368 54 : builder->OnData(builder->cbk_obj, data + offset, size, GF_TRUE);
369 :
370 54 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
371 :
372 54 : offset += size;
373 : }
374 : return GF_OK;
375 : }
376 1932 : GF_Err gp_rtp_builder_do_tx3g(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration, u8 descIndex)
377 : {
378 : GF_BitStream *bs;
379 : u8 *hdr;
380 : u32 samp_size, txt_size, pay_start, hdr_size, txt_done, cur_frag, nb_frag;
381 : Bool is_utf_16 = GF_FALSE;
382 :
383 1932 : if (!data) {
384 : /*flush packet*/
385 9 : if (builder->bytesInPacket) {
386 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
387 0 : builder->bytesInPacket = 0;
388 : }
389 : return GF_OK;
390 : }
391 : /*cfg packet*/
392 1923 : txt_size = data[0];
393 1923 : txt_size <<= 8;
394 1923 : txt_size |= (unsigned char) data[1];
395 : /*remove BOM*/
396 : pay_start = 2;
397 1923 : if (txt_size>2) {
398 : /*seems 3GP only accepts BE UTF-16 (no LE, no UTF32)*/
399 958 : if (((u8) data[2]==(u8) 0xFE) && ((u8) data[3]==(u8) 0xFF)) {
400 : is_utf_16 = GF_TRUE;
401 : pay_start = 4;
402 0 : txt_size -= 2;
403 : }
404 : }
405 1923 : samp_size = data_size - pay_start;
406 :
407 : /*if TTU does not fit in packet flush packet*/
408 1923 : if (builder->bytesInPacket && (builder->bytesInPacket + 3 + 6 + samp_size > builder->Path_MTU)) {
409 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
410 0 : builder->bytesInPacket = 0;
411 : }
412 : //we only deal with static SIDX
413 1923 : descIndex += GF_RTP_TX3G_SIDX_OFFSET;
414 :
415 : /*first TTU in packet*/
416 1923 : if (!builder->bytesInPacket) {
417 1923 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
418 1923 : builder->rtp_header.Marker = 1;
419 1923 : builder->rtp_header.SequenceNumber += 1;
420 1923 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
421 : }
422 : /*fits entirely*/
423 1923 : if (builder->bytesInPacket + 3 + 6 + samp_size <= builder->Path_MTU) {
424 1923 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
425 1923 : gf_bs_write_int(bs, is_utf_16, 1);
426 1923 : gf_bs_write_int(bs, 0, 4);
427 1923 : gf_bs_write_int(bs, 1, 3);
428 1923 : gf_bs_write_u16(bs, 8 + samp_size);
429 1923 : gf_bs_write_u8(bs, descIndex);
430 1923 : gf_bs_write_u24(bs, duration);
431 1923 : gf_bs_write_u16(bs, txt_size);
432 1923 : gf_bs_get_content(bs, &hdr, &hdr_size);
433 1923 : gf_bs_del(bs);
434 1923 : builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, GF_FALSE);
435 1923 : builder->bytesInPacket += hdr_size;
436 1923 : gf_free(hdr);
437 :
438 1923 : if (txt_size) {
439 958 : if (builder->OnDataReference) {
440 957 : builder->OnDataReference(builder->cbk_obj, samp_size, pay_start);
441 : } else {
442 1 : builder->OnData(builder->cbk_obj, data + pay_start, samp_size, GF_FALSE);
443 : }
444 958 : builder->bytesInPacket += samp_size;
445 : }
446 : /*disable aggregation*/
447 1923 : if (!(builder->flags & GP_RTP_PCK_USE_MULTI)) {
448 1923 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
449 1923 : builder->bytesInPacket = 0;
450 : }
451 : return GF_OK;
452 : }
453 : /*doesn't fit and already data, flush packet*/
454 0 : if (builder->bytesInPacket) {
455 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
456 0 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
457 : /*split unit*/
458 0 : builder->rtp_header.Marker = 0;
459 0 : builder->rtp_header.SequenceNumber += 1;
460 0 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
461 0 : builder->bytesInPacket = 0;
462 : }
463 : /*write all type2 units (text only) - FIXME: split at char boundaries, NOT SUPPORTED YET*/
464 : txt_done = 0;
465 : nb_frag = 1;
466 : /*all fragments needed for Type2 units*/
467 0 : while (txt_done + (builder->Path_MTU-10) < txt_size) {
468 : txt_done += (builder->Path_MTU-10);
469 0 : nb_frag += 1;
470 : }
471 : /*all fragments needed for Type3/4 units*/
472 : txt_done = txt_size;
473 0 : while (txt_done + (builder->Path_MTU-7) < samp_size) {
474 : txt_done += (builder->Path_MTU-7);
475 0 : nb_frag += 1;
476 : }
477 :
478 :
479 : cur_frag = 0;
480 : txt_done = 0;
481 0 : while (txt_done<txt_size) {
482 : u32 size;
483 0 : if (txt_done + (builder->Path_MTU-10) < txt_size) {
484 0 : size = builder->Path_MTU-10;
485 : } else {
486 0 : size = txt_size - txt_done;
487 : }
488 :
489 0 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
490 0 : gf_bs_write_int(bs, is_utf_16, 1);
491 0 : gf_bs_write_int(bs, 0, 4);
492 0 : gf_bs_write_int(bs, 2, 3);
493 0 : gf_bs_write_u16(bs, 9 + size);
494 0 : gf_bs_write_int(bs, nb_frag, 4);
495 0 : gf_bs_write_int(bs, cur_frag, 4);
496 0 : gf_bs_write_u24(bs, duration);
497 0 : gf_bs_write_u8(bs, descIndex);
498 : /*SLEN is the full original length minus text len and BOM (put here for buffer allocation purposes)*/
499 0 : gf_bs_write_u16(bs, samp_size);
500 0 : gf_bs_get_content(bs, &hdr, &hdr_size);
501 0 : gf_bs_del(bs);
502 0 : builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, GF_FALSE);
503 0 : builder->bytesInPacket += hdr_size;
504 0 : gf_free(hdr);
505 :
506 0 : if (builder->OnDataReference) {
507 0 : builder->OnDataReference(builder->cbk_obj, size, pay_start + txt_done);
508 : } else {
509 0 : builder->OnData(builder->cbk_obj, data + pay_start + txt_done, size, GF_FALSE);
510 : }
511 0 : builder->bytesInPacket += size;
512 0 : cur_frag++;
513 :
514 : /*flush packet*/
515 0 : if (cur_frag == nb_frag) {
516 : txt_done = txt_size;
517 0 : if (pay_start + txt_done == data_size) {
518 0 : builder->rtp_header.Marker = 1;
519 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
520 0 : builder->bytesInPacket = 0;
521 : }
522 : } else {
523 0 : txt_done += size;
524 0 : builder->rtp_header.Marker = 0;
525 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
526 0 : builder->rtp_header.SequenceNumber += 1;
527 0 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
528 0 : builder->bytesInPacket = 0;
529 : }
530 : }
531 :
532 : txt_done = txt_size;
533 :
534 : /*write all modifiers - OPT: split at modifiers boundaries*/
535 0 : while (txt_done<samp_size) {
536 : u32 size, type;
537 0 : type = (txt_done == txt_size) ? 3 : 4;
538 :
539 0 : if (txt_done + (builder->Path_MTU-7) < samp_size) {
540 0 : size = builder->Path_MTU-10;
541 : } else {
542 0 : size = samp_size - txt_done;
543 : }
544 :
545 0 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
546 0 : gf_bs_write_int(bs, is_utf_16, 1);
547 0 : gf_bs_write_int(bs, 0, 4);
548 0 : gf_bs_write_int(bs, type, 3);
549 0 : gf_bs_write_u16(bs, 6 + size);
550 0 : gf_bs_write_int(bs, nb_frag, 4);
551 0 : gf_bs_write_int(bs, cur_frag, 4);
552 0 : gf_bs_write_u24(bs, duration);
553 :
554 0 : gf_bs_get_content(bs, &hdr, &hdr_size);
555 0 : gf_bs_del(bs);
556 0 : builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, GF_FALSE);
557 0 : builder->bytesInPacket += hdr_size;
558 0 : gf_free(hdr);
559 :
560 0 : if (builder->OnDataReference) {
561 0 : builder->OnDataReference(builder->cbk_obj, size, pay_start + txt_done);
562 : } else {
563 0 : builder->OnData(builder->cbk_obj, data + pay_start + txt_done, size, GF_FALSE);
564 : }
565 0 : builder->bytesInPacket += size;
566 0 : cur_frag++;
567 0 : if (cur_frag==nb_frag) {
568 0 : builder->rtp_header.Marker = 1;
569 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
570 0 : builder->bytesInPacket = 0;
571 : } else {
572 0 : builder->rtp_header.Marker = 0;
573 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
574 0 : builder->rtp_header.SequenceNumber += 1;
575 0 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
576 0 : builder->bytesInPacket = 0;
577 : }
578 0 : txt_done += size;
579 : }
580 : return GF_OK;
581 : }
582 :
583 :
584 : #if GPAC_ENABLE_3GPP_DIMS_RTP
585 : GF_Err gp_rtp_builder_do_dims(GP_RTPPacketizer *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration)
586 : {
587 : u32 frag_state;
588 : GF_BitStream *bs;
589 : u32 offset;
590 : Bool is_last_du;
591 :
592 : /*the DIMS hinter doesn't perform inter-sample concatenation*/
593 : if (!data) return GF_OK;
594 :
595 : offset = 0;
596 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
597 : bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
598 : while (offset < data_size) {
599 : u32 du_offset = 0;
600 : u32 hdr_offset = 0;
601 : u32 orig_size, du_size;
602 :
603 : orig_size = du_size = 2+gf_bs_read_u16(bs);
604 : /*if dims size is >0xFFFF, use our internal hack for large units*/
605 : if (du_size==2) {
606 : orig_size = du_size = 2+gf_bs_read_u32(bs);
607 : hdr_offset = 4;
608 : }
609 : gf_bs_skip_bytes(bs, du_size-2);
610 :
611 : /*prepare M-bit*/
612 : is_last_du = (offset+du_size==data_size) ? GF_TRUE : GF_FALSE;
613 :
614 : frag_state = 0;
615 : while (du_size) {
616 : u32 size_offset = 0;
617 : u32 size;
618 : //size = du_size;
619 :
620 : /*does not fit, flush required*/
621 : if (builder->bytesInPacket && (du_size + 1 + builder->bytesInPacket > builder->Path_MTU)) {
622 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
623 : builder->bytesInPacket = 0;
624 : }
625 :
626 : /*fragmentation required*/
627 : if (du_size + 1 > builder->Path_MTU) {
628 : size = builder->Path_MTU - 1;
629 : /*first fragment*/
630 : if (!frag_state) {
631 : /*size field is skipped !!*/
632 : size_offset = 2 + hdr_offset;
633 : frag_state = 1;
634 :
635 : while (du_size - size_offset <= size) {
636 : size--;
637 : }
638 : }
639 : /*any middle fragment*/
640 : else frag_state = 2;
641 :
642 : builder->rtp_header.Marker = 0;
643 : }
644 : /*last fragment*/
645 : else if (frag_state) {
646 : size = du_size;
647 : frag_state = 3;
648 : builder->rtp_header.Marker = is_last_du;
649 : } else {
650 : size = du_size;
651 : builder->rtp_header.Marker = is_last_du;
652 : }
653 :
654 : if (frag_state && builder->bytesInPacket) {
655 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
656 : builder->bytesInPacket = 0;
657 : }
658 :
659 : /*need a new packet*/
660 : if (!builder->bytesInPacket) {
661 : char dims_rtp_hdr[1];
662 :
663 : /*the unit is critical, increase counter (coded on 3 bits)*/
664 : if (! (data[2+hdr_offset] & GF_DIMS_UNIT_P) && (frag_state <= 1) ) {
665 : builder->last_au_sn++;
666 : builder->last_au_sn %= 8;
667 : }
668 : /*set CTR value*/
669 : dims_rtp_hdr[0] = builder->last_au_sn;
670 : /*if M-bit is set in the dims unit header, replicate it*/
671 : if (data[2+hdr_offset] & (1<<1) ) dims_rtp_hdr[0] |= (1<<6);
672 : /*add unit fragmentation type*/
673 : dims_rtp_hdr[0] |= (frag_state<<3);
674 :
675 : builder->rtp_header.SequenceNumber += 1;
676 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
677 : builder->OnData(builder->cbk_obj, (char *) dims_rtp_hdr, 1, GF_TRUE);
678 : builder->bytesInPacket = 1;
679 : }
680 :
681 : /*add payload*/
682 : if (builder->OnDataReference)
683 : builder->OnDataReference(builder->cbk_obj, size, offset+du_offset+size_offset);
684 : else
685 : builder->OnData(builder->cbk_obj, data+offset+du_offset+size_offset, size, GF_FALSE);
686 :
687 : /*if fragmentation, force packet flush even on last packet since aggregation unit do not
688 : use the same packet format*/
689 : if (frag_state) {
690 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
691 : builder->bytesInPacket = 0;
692 : } else {
693 : builder->bytesInPacket += size;
694 : }
695 : du_offset += size+size_offset;
696 : assert(du_size>= size+size_offset);
697 : du_size -= size+size_offset;
698 : }
699 : offset += orig_size;
700 : }
701 : if (builder->bytesInPacket) {
702 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
703 : builder->bytesInPacket = 0;
704 : }
705 : gf_bs_del(bs);
706 : return GF_OK;
707 : }
708 : #endif
709 :
710 :
711 :
712 61 : static void gf_rtp_ac3_flush(GP_RTPPacketizer *builder)
713 : {
714 : char hdr[2];
715 64 : if (!builder->bytesInPacket) return;
716 :
717 58 : hdr[0] = builder->ac3_ft;
718 58 : hdr[1] = builder->last_au_sn;
719 58 : builder->OnData(builder->cbk_obj, hdr, 2, GF_TRUE);
720 :
721 58 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
722 58 : builder->bytesInPacket = 0;
723 58 : builder->last_au_sn = 0;
724 58 : builder->ac3_ft = 0;
725 : }
726 :
727 61 : GF_Err gp_rtp_builder_do_ac3(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
728 : {
729 : char hdr[2];
730 : u32 offset, nb_pck;
731 :
732 : /*flush*/
733 61 : if (!data) {
734 3 : gf_rtp_ac3_flush(builder);
735 3 : return GF_OK;
736 : }
737 :
738 58 : if (
739 : /*AU does not fit*/
740 58 : (builder->bytesInPacket + data_size > builder->Path_MTU)
741 58 : ||
742 : /*aggregation is not enabled*/
743 58 : !(builder->flags & GP_RTP_PCK_USE_MULTI)
744 0 : ||
745 : /*max ptime is exceeded*/
746 0 : (builder->max_ptime && ( (u32) builder->sl_header.compositionTimeStamp >= builder->rtp_header.TimeStamp + builder->max_ptime) )
747 :
748 : ) {
749 58 : gf_rtp_ac3_flush(builder);
750 : }
751 :
752 : /*fits*/
753 58 : if (builder->bytesInPacket + data_size < builder->Path_MTU) {
754 : /*need a new packet*/
755 58 : if (!builder->bytesInPacket) {
756 58 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
757 58 : builder->ac3_ft = 0;
758 58 : builder->rtp_header.Marker = 1;
759 58 : builder->rtp_header.SequenceNumber += 1;
760 58 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
761 : /*2 bytes header*/
762 58 : builder->bytesInPacket = 2;
763 : }
764 :
765 : /*add payload*/
766 58 : if (builder->OnDataReference)
767 29 : builder->OnDataReference(builder->cbk_obj, data_size, 0);
768 : else
769 29 : builder->OnData(builder->cbk_obj, data, data_size, GF_FALSE);
770 :
771 58 : builder->bytesInPacket += data_size;
772 58 : builder->last_au_sn++;
773 58 : return GF_OK;
774 : }
775 :
776 : /*need fragmentation*/
777 : assert(!builder->bytesInPacket);
778 : offset = 0;
779 0 : nb_pck = data_size / (builder->Path_MTU-2);
780 0 : if (data_size % (builder->Path_MTU-2)) nb_pck++;
781 0 : builder->last_au_sn = nb_pck;
782 :
783 0 : while (offset < data_size) {
784 0 : u32 pck_size = MIN(data_size-offset, builder->Path_MTU-2);
785 :
786 0 : builder->rtp_header.Marker = 0;
787 0 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
788 0 : builder->rtp_header.SequenceNumber += 1;
789 :
790 0 : if (!offset) {
791 0 : builder->ac3_ft = (pck_size > 5*data_size/8) ? 1 : 2;
792 : } else {
793 0 : builder->ac3_ft = 3;
794 0 : if (offset + pck_size == data_size)
795 0 : builder->rtp_header.Marker = 1;
796 : }
797 0 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
798 :
799 0 : hdr[0] = builder->ac3_ft;
800 0 : hdr[1] = builder->last_au_sn;
801 0 : builder->OnData(builder->cbk_obj, hdr, 2, GF_TRUE);
802 :
803 : /*add payload*/
804 0 : if (builder->OnDataReference)
805 0 : builder->OnDataReference(builder->cbk_obj, pck_size, offset);
806 : else
807 0 : builder->OnData(builder->cbk_obj, data+offset, pck_size, GF_FALSE);
808 :
809 0 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
810 0 : offset += pck_size;
811 0 : builder->bytesInPacket = 0;
812 : }
813 :
814 : return GF_OK;
815 : }
816 :
817 : #endif /*GPAC_DISABLE_STREAMING*/
818 :
|