Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2019
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / ISO Media File Format 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/isomedia_dev.h>
27 :
28 : #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)
29 :
30 385 : Bool IsHintTrack(GF_TrackBox *trak)
31 : {
32 389902 : if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_HINT) return GF_FALSE;
33 : //QT doesn't specify any InfoHeader on HintTracks
34 389829 : if (trak->Media->information->InfoHeader
35 389829 : && (trak->Media->information->InfoHeader->type != GF_ISOM_BOX_TYPE_HMHD)
36 0 : && (trak->Media->information->InfoHeader->type != GF_ISOM_BOX_TYPE_NMHD)
37 : )
38 : return GF_FALSE;
39 :
40 385 : return GF_TRUE;
41 : }
42 :
43 146697 : u32 GetHintFormat(GF_TrackBox *trak)
44 : {
45 146697 : GF_HintMediaHeaderBox *hmhd = (GF_HintMediaHeaderBox *)trak->Media->information->InfoHeader;
46 146697 : if (!hmhd || !hmhd->subType) {
47 1 : GF_Box *a = (GF_Box *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
48 1 : if (!hmhd) return a ? a->type : 0;
49 1 : if (a) hmhd->subType = a->type;
50 1 : return hmhd->subType;
51 : }
52 : return hmhd->subType;
53 : }
54 :
55 146697 : Bool CheckHintFormat(GF_TrackBox *trak, u32 HintType)
56 : {
57 : if (!IsHintTrack(trak)) return GF_FALSE;
58 146624 : if (GetHintFormat(trak) != HintType) return GF_FALSE;
59 146624 : return GF_TRUE;
60 : }
61 :
62 : #ifndef GPAC_DISABLE_ISOM_WRITE
63 :
64 59170 : GF_Err AdjustHintInfo(GF_HintSampleEntryBox *entry, u32 HintSampleNumber)
65 : {
66 : u32 offset, count, i, size;
67 : GF_Err e;
68 :
69 59170 : offset = gf_isom_hint_sample_size(entry->hint_sample) - entry->hint_sample->dataLength;
70 59170 : count = gf_list_count(entry->hint_sample->packetTable);
71 :
72 127307 : for (i=0; i<count; i++) {
73 68137 : GF_HintPacket *pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, i);
74 68137 : if (offset && entry->hint_sample->dataLength) {
75 : //adjust any offset in this packet
76 83 : e = gf_isom_hint_pck_offset(pck, offset, HintSampleNumber);
77 83 : if (e) return e;
78 : }
79 : //adjust the max packet size for this sample entry...
80 68137 : size = gf_isom_hint_pck_length(pck);
81 68137 : if (entry->MaxPacketSize < size) entry->MaxPacketSize = size;
82 : }
83 : return GF_OK;
84 : }
85 :
86 : GF_EXPORT
87 73 : GF_Err gf_isom_setup_hint_track(GF_ISOFile *movie, u32 trackNumber, GF_ISOHintFormat HintType)
88 : {
89 : GF_Err e;
90 : GF_TrackBox *trak;
91 : GF_TrackReferenceBox *tref;
92 : GF_TrackReferenceTypeBox *dpnd;
93 : GF_HintMediaHeaderBox *hmhd;
94 : //UDTA related ...
95 : GF_UserDataBox *udta;
96 :
97 :
98 : //what do we support
99 73 : switch (HintType) {
100 : case GF_ISOM_HINT_RTP:
101 : break;
102 : default:
103 : return GF_NOT_SUPPORTED;
104 : }
105 73 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
106 73 : if (e) return e;
107 :
108 73 : trak = gf_isom_get_track_from_file(movie, trackNumber);
109 73 : if (!trak) return gf_isom_last_error(movie);
110 :
111 : //check we have a hint ...
112 : if ( !IsHintTrack(trak)) {
113 : return GF_BAD_PARAM;
114 : }
115 : hmhd = (GF_HintMediaHeaderBox *)trak->Media->information->InfoHeader;
116 : //make sure the subtype was not already defined
117 73 : if (hmhd->subType) return GF_BAD_PARAM;
118 : //store the HintTrack format for later use...
119 73 : hmhd->subType = HintType;
120 :
121 :
122 : //hint tracks always have a tref and everything ...
123 73 : if (!trak->References) {
124 73 : tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TREF);
125 73 : if (!tref) return GF_OUT_OF_MEM;
126 73 : e = trak_on_child_box((GF_Box*)trak, (GF_Box *)tref, GF_FALSE);
127 73 : if (e) return e;
128 : }
129 73 : tref = trak->References;
130 :
131 : //do we have a hint reference on this trak ???
132 73 : e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_HINT, &dpnd);
133 73 : if (e) return e;
134 : //if yes, return false (existing hint track...)
135 73 : if (dpnd) return GF_BAD_PARAM;
136 :
137 : //create our dep
138 73 : dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
139 73 : if (!dpnd) return GF_OUT_OF_MEM;
140 73 : dpnd->reference_type = GF_ISOM_BOX_TYPE_HINT;
141 :
142 : //for RTP, we need to do some UDTA-related stuff...
143 73 : if (HintType != GF_ISOM_HINT_RTP) return GF_OK;
144 :
145 73 : if (!trak->udta) {
146 : //create one
147 73 : udta = (GF_UserDataBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA);
148 73 : if (!udta) return GF_OUT_OF_MEM;
149 73 : e = trak_on_child_box((GF_Box*)trak, (GF_Box *) udta, GF_FALSE);
150 73 : if (e) return e;
151 : }
152 73 : udta = trak->udta;
153 :
154 : //HNTI
155 73 : e = udta_on_child_box((GF_Box *)udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HNTI), GF_FALSE);
156 73 : if (e) return e;
157 :
158 : /*
159 : //NAME
160 : e = udta_on_child_box((GF_Box *)udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_NAME));
161 : if (e) return e;
162 : //HINF
163 : return udta_on_child_box((GF_Box *)udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HINF));
164 : */
165 73 : return GF_OK;
166 : }
167 :
168 : //to use with internally supported protocols
169 : GF_EXPORT
170 73 : GF_Err gf_isom_new_hint_description(GF_ISOFile *the_file, u32 trackNumber, s32 HintTrackVersion, s32 LastCompatibleVersion, u8 Rely, u32 *HintDescriptionIndex)
171 : {
172 : GF_Err e;
173 : u32 drefIndex;
174 : GF_TrackBox *trak;
175 : GF_HintSampleEntryBox *hdesc;
176 : GF_SampleDescriptionBox *stsd;
177 : GF_RelyHintBox *relyA;
178 :
179 73 : e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
180 73 : if (e) return e;
181 :
182 73 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
183 73 : *HintDescriptionIndex = 0;
184 73 : if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
185 :
186 73 : stsd = trak->Media->information->sampleTable->SampleDescription;
187 : //OK, create a new HintSampleDesc
188 73 : hdesc = (GF_HintSampleEntryBox *) gf_isom_box_new_parent(&stsd->child_boxes, GetHintFormat(trak));
189 73 : if (!hdesc) return GF_OUT_OF_MEM;
190 :
191 73 : if (HintTrackVersion > 0) hdesc->HintTrackVersion = HintTrackVersion;
192 73 : if (LastCompatibleVersion > 0) hdesc->LastCompatibleVersion = LastCompatibleVersion;
193 :
194 : //create a data reference - WE ONLY DEAL WITH SELF-CONTAINED HINT TRACKS
195 73 : e = Media_CreateDataRef(the_file, trak->Media->information->dataInformation->dref, NULL, NULL, &drefIndex);
196 73 : if (e) return e;
197 73 : hdesc->dataReferenceIndex = drefIndex;
198 :
199 73 : *HintDescriptionIndex = gf_list_count(stsd->child_boxes);
200 :
201 : //RTP needs a default timeScale... use the media one.
202 73 : if (CheckHintFormat(trak, GF_ISOM_HINT_RTP)) {
203 73 : e = gf_isom_rtp_set_timescale(the_file, trackNumber, *HintDescriptionIndex, trak->Media->mediaHeader->timeScale);
204 73 : if (e) return e;
205 : }
206 73 : if (!Rely) return GF_OK;
207 :
208 : //we need a rely box (common to all protocols)
209 0 : relyA = (GF_RelyHintBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_RELY);
210 0 : if (!relyA) return GF_OUT_OF_MEM;
211 0 : if (Rely == 1) {
212 0 : relyA->preferred = 1;
213 : } else {
214 0 : relyA->required = 1;
215 : }
216 : return GF_OK;
217 : }
218 :
219 :
220 : /*******************************************************************
221 : RTP WRITING API
222 : *******************************************************************/
223 :
224 : //sets the RTP TimeScale
225 : GF_EXPORT
226 146 : GF_Err gf_isom_rtp_set_timescale(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 TimeScale)
227 : {
228 : GF_TrackBox *trak;
229 : GF_HintSampleEntryBox *hdesc;
230 : u32 i, count;
231 : GF_TSHintEntryBox *ent;
232 :
233 146 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
234 146 : if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
235 :
236 : //OK, create a new HintSampleDesc
237 146 : hdesc = (GF_HintSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, HintDescriptionIndex - 1);
238 146 : if (!hdesc) return GF_BAD_PARAM;
239 :
240 146 : count = gf_list_count(hdesc->child_boxes);
241 :
242 146 : for (i=0; i< count; i++) {
243 73 : ent = (GF_TSHintEntryBox *)gf_list_get(hdesc->child_boxes, i);
244 73 : if (ent->type == GF_ISOM_BOX_TYPE_TIMS) {
245 73 : ent->timeScale = TimeScale;
246 73 : return GF_OK;
247 : }
248 : }
249 : //we have to create a new entry...
250 73 : ent = (GF_TSHintEntryBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_TIMS);
251 73 : if (!ent) return GF_OUT_OF_MEM;
252 73 : ent->timeScale = TimeScale;
253 73 : return GF_OK;
254 : }
255 :
256 : //sets the RTP TimeOffset that the server will add to the packets
257 : //if not set, the server adds a random offset
258 : GF_EXPORT
259 1 : GF_Err gf_isom_rtp_set_time_offset(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 TimeOffset)
260 : {
261 : GF_TrackBox *trak;
262 : GF_HintSampleEntryBox *hdesc;
263 : u32 i, count;
264 : GF_TimeOffHintEntryBox *ent;
265 :
266 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
267 1 : if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
268 :
269 : //OK, create a new HintSampleDesc
270 1 : hdesc = (GF_HintSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, HintDescriptionIndex - 1);
271 1 : if (!hdesc) return GF_BAD_PARAM;
272 1 : count = gf_list_count(hdesc->child_boxes);
273 :
274 2 : for (i=0; i< count; i++) {
275 1 : ent = (GF_TimeOffHintEntryBox *)gf_list_get(hdesc->child_boxes, i);
276 1 : if (ent->type == GF_ISOM_BOX_TYPE_TSRO) {
277 0 : ent->TimeOffset = TimeOffset;
278 0 : return GF_OK;
279 : }
280 : }
281 : //we have to create a new entry...
282 1 : ent = (GF_TimeOffHintEntryBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_TSRO);
283 1 : if (!ent) return GF_OUT_OF_MEM;
284 1 : ent->TimeOffset = TimeOffset;
285 :
286 1 : return GF_OK;
287 : }
288 :
289 : //sets the RTP SequenceNumber Offset that the server will add to the packets
290 : //if not set, the server adds a random offset
291 : GF_EXPORT
292 1 : GF_Err gf_isom_rtp_set_time_sequence_offset(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 SequenceNumberOffset)
293 : {
294 : GF_TrackBox *trak;
295 : GF_HintSampleEntryBox *hdesc;
296 : u32 i, count;
297 : GF_SeqOffHintEntryBox *ent;
298 :
299 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
300 1 : if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
301 :
302 : //OK, create a new HintSampleDesc
303 1 : hdesc = (GF_HintSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, HintDescriptionIndex - 1);
304 1 : if (!hdesc) return GF_BAD_PARAM;
305 1 : count = gf_list_count(hdesc->child_boxes);
306 :
307 3 : for (i=0; i< count; i++) {
308 2 : ent = (GF_SeqOffHintEntryBox *)gf_list_get(hdesc->child_boxes, i);
309 2 : if (ent->type == GF_ISOM_BOX_TYPE_SNRO) {
310 0 : ent->SeqOffset = SequenceNumberOffset;
311 0 : return GF_OK;
312 : }
313 : }
314 : //we have to create a new entry...
315 1 : ent = (GF_SeqOffHintEntryBox *) gf_isom_box_new_parent(&hdesc->child_boxes, GF_ISOM_BOX_TYPE_SNRO);
316 1 : if (!ent) return GF_OUT_OF_MEM;
317 1 : ent->SeqOffset = SequenceNumberOffset;
318 1 : return GF_OK;
319 : }
320 :
321 : //Starts a new sample for the hint track. A sample is just a collection of packets
322 : //the transmissionTime is indicated in the media timeScale of the hint track
323 : GF_EXPORT
324 59170 : GF_Err gf_isom_begin_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u32 HintDescriptionIndex, u32 TransmissionTime)
325 : {
326 : GF_TrackBox *trak;
327 : u32 descIndex, dataRefIndex;
328 : GF_HintSample *samp;
329 : GF_HintSampleEntryBox *entry;
330 : GF_Err e;
331 :
332 59170 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
333 59170 : if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
334 :
335 : //assert we're increasing the timing...
336 59170 : if (trak->Media->information->sampleTable->TimeToSample->w_LastDTS > TransmissionTime) return GF_BAD_PARAM;
337 :
338 : //store the descIndex for this sample
339 : descIndex = HintDescriptionIndex;
340 59170 : if (!HintDescriptionIndex) {
341 0 : descIndex = trak->Media->information->sampleTable->currentEntryIndex;
342 : }
343 59170 : e = Media_GetSampleDesc(trak->Media, descIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
344 59170 : if (e) return e;
345 59170 : if (!entry || !dataRefIndex) return GF_BAD_PARAM;
346 : //set the current to this one if no packet is used
347 59170 : if (entry->hint_sample) return GF_BAD_PARAM;
348 59170 : trak->Media->information->sampleTable->currentEntryIndex = descIndex;
349 :
350 : //create a new sample based on the protocol type of the hint description entry
351 59170 : samp = gf_isom_hint_sample_new(entry->type);
352 59170 : if (!samp) return GF_NOT_SUPPORTED;
353 :
354 : //OK, let's store the time of this sample
355 59170 : samp->TransmissionTime = TransmissionTime;
356 : //OK, set our sample in the entry...
357 59170 : entry->hint_sample = samp;
358 59170 : return GF_OK;
359 : }
360 :
361 : //stores the hint sample in the file
362 : //set IsRandomAccessPoint if you want to indicate that this is a random access point
363 : //in the stream
364 : GF_EXPORT
365 59170 : GF_Err gf_isom_end_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u8 IsRandomAccessPoint)
366 : {
367 : GF_TrackBox *trak;
368 : GF_HintSampleEntryBox *entry;
369 : u32 dataRefIndex;
370 : GF_Err e;
371 : GF_BitStream *bs;
372 : GF_ISOSample *samp;
373 :
374 59170 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
375 59170 : if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
376 :
377 59170 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
378 59170 : if (e) return e;
379 59170 : if (!entry->hint_sample) return GF_BAD_PARAM;
380 :
381 : //first of all, we need to adjust the offset for data referenced IN THIS hint sample
382 : //and get some PckSize
383 59170 : e = AdjustHintInfo(entry, trak->Media->information->sampleTable->SampleSize->sampleCount + 1);
384 59170 : if (e) return e;
385 :
386 : //ok, let's write the sample
387 59170 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
388 59170 : e = gf_isom_hint_sample_write(entry->hint_sample, bs);
389 59170 : if (e) {
390 0 : gf_bs_del(bs);
391 0 : return e;
392 : }
393 59170 : samp = gf_isom_sample_new();
394 59170 : samp->CTS_Offset = 0;
395 59170 : samp->IsRAP = IsRandomAccessPoint;
396 59170 : samp->DTS = entry->hint_sample->TransmissionTime;
397 : //get the sample
398 59170 : gf_bs_get_content(bs, &samp->data, &samp->dataLength);
399 59170 : gf_bs_del(bs);
400 :
401 : //finally add the sample
402 59170 : e = gf_isom_add_sample(the_file, trackNumber, trak->Media->information->sampleTable->currentEntryIndex, samp);
403 59170 : gf_isom_sample_del(&samp);
404 :
405 : //and delete the sample in our entry ...
406 59170 : gf_isom_hint_sample_del(entry->hint_sample);
407 59170 : entry->hint_sample = NULL;
408 59170 : return e;
409 : }
410 :
411 :
412 : //adds a blank chunk of data in the sample that is skipped while streaming
413 : GF_EXPORT
414 1 : GF_Err gf_isom_hint_blank_data(GF_ISOFile *the_file, u32 trackNumber, u8 AtBegin)
415 : {
416 : GF_TrackBox *trak;
417 : GF_HintSampleEntryBox *entry;
418 : u32 count;
419 : GF_HintPacket *pck;
420 : GF_EmptyDTE *dte;
421 : GF_Err e;
422 :
423 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
424 1 : if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
425 :
426 0 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
427 0 : if (e) return e;
428 0 : if (!entry->hint_sample) return GF_BAD_PARAM;
429 0 : count = gf_list_count(entry->hint_sample->packetTable);
430 0 : if (!count) return GF_BAD_PARAM;
431 0 : pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
432 :
433 0 : dte = (GF_EmptyDTE *) NewDTE(0);
434 0 : return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
435 : }
436 :
437 :
438 : //adds a chunk of data (max 14 bytes) in the packet that is directly copied
439 : //while streaming
440 : GF_EXPORT
441 49022 : GF_Err gf_isom_hint_direct_data(GF_ISOFile *the_file, u32 trackNumber, u8 *data, u32 dataLength, u8 AtBegin)
442 : {
443 : GF_TrackBox *trak;
444 : GF_HintSampleEntryBox *entry;
445 : u32 count;
446 : GF_HintPacket *pck;
447 : GF_ImmediateDTE *dte;
448 : GF_Err e;
449 : u32 offset = 0;
450 :
451 49022 : if (!dataLength) return GF_OK;
452 49022 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
453 98044 : if (!trak || !IsHintTrack(trak) || (dataLength > 14)) return GF_BAD_PARAM;
454 :
455 49022 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
456 49022 : if (e) return e;
457 49022 : if (!entry->hint_sample) return GF_BAD_PARAM;
458 49022 : count = gf_list_count(entry->hint_sample->packetTable);
459 49022 : if (!count) return GF_BAD_PARAM;
460 49022 : pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
461 :
462 49022 : dte = (GF_ImmediateDTE *) NewDTE(1);
463 49022 : memcpy(dte->data, data + offset, dataLength);
464 49022 : dte->dataLength = dataLength;
465 49022 : return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
466 : }
467 :
468 : GF_EXPORT
469 75312 : GF_Err gf_isom_hint_sample_data(GF_ISOFile *the_file, u32 trackNumber, GF_ISOTrackID SourceTrackID, u32 SampleNumber, u16 DataLength, u32 offsetInSample, u8 *extra_data, u8 AtBegin)
470 : {
471 : GF_TrackBox *trak;
472 : GF_HintSampleEntryBox *entry;
473 : u32 count;
474 : u16 refIndex;
475 : GF_HintPacket *pck;
476 : GF_SampleDTE *dte;
477 : GF_Err e;
478 : GF_TrackReferenceTypeBox *hint;
479 :
480 75312 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
481 75312 : if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
482 :
483 :
484 75312 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
485 75312 : if (e) return e;
486 75312 : if (!entry->hint_sample) return GF_BAD_PARAM;
487 75312 : count = gf_list_count(entry->hint_sample->packetTable);
488 75312 : if (!count) return GF_BAD_PARAM;
489 75312 : pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
490 :
491 75312 : dte = (GF_SampleDTE *) NewDTE(2);
492 :
493 75312 : dte->dataLength = DataLength;
494 75312 : dte->sampleNumber = SampleNumber;
495 75312 : dte->byteOffset = offsetInSample;
496 :
497 : //we're getting data from another track
498 75312 : if (SourceTrackID != trak->Header->trackID) {
499 : //get (or set) the track reference index
500 75229 : e = Track_FindRef(trak, GF_ISOM_REF_HINT, &hint);
501 75229 : if (e) return e;
502 75229 : e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
503 75229 : if (e) return e;
504 : //WARNING: IN QT, MUST BE 0-based !!!
505 75229 : dte->trackRefIndex = (u8) (refIndex - 1);
506 : } else {
507 : //we're in the hint track
508 83 : dte->trackRefIndex = (s8) -1;
509 : //basic check...
510 83 : if (SampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount + 1) {
511 0 : DelDTE((GF_GenericDTE *)dte);
512 0 : return GF_BAD_PARAM;
513 : }
514 :
515 : //are we in the current sample ??
516 83 : if (!SampleNumber || (SampleNumber == trak->Media->information->sampleTable->SampleSize->sampleCount + 1)) {
517 : //we adding some stuff in the current sample ...
518 83 : dte->byteOffset += entry->hint_sample->dataLength;
519 83 : entry->hint_sample->AdditionalData = (char*)gf_realloc(entry->hint_sample->AdditionalData, sizeof(char) * (entry->hint_sample->dataLength + DataLength));
520 83 : if (AtBegin) {
521 76 : if (entry->hint_sample->dataLength)
522 0 : memmove(entry->hint_sample->AdditionalData + DataLength, entry->hint_sample->AdditionalData, entry->hint_sample->dataLength);
523 76 : memcpy(entry->hint_sample->AdditionalData, extra_data, DataLength);
524 : /*offset existing DTE*/
525 76 : gf_isom_hint_pck_offset(pck, DataLength, SampleNumber);
526 : } else {
527 7 : memcpy(entry->hint_sample->AdditionalData + entry->hint_sample->dataLength, extra_data, DataLength);
528 : }
529 83 : entry->hint_sample->dataLength += DataLength;
530 : //and set the sample number ...
531 83 : dte->sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount + 1;
532 : }
533 : }
534 : //OK, add the entry
535 75312 : return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
536 : }
537 :
538 : GF_EXPORT
539 1 : GF_Err gf_isom_hint_sample_description_data(GF_ISOFile *the_file, u32 trackNumber, GF_ISOTrackID SourceTrackID, u32 StreamDescriptionIndex, u16 DataLength, u32 offsetInDescription, u8 AtBegin)
540 : {
541 : GF_TrackBox *trak;
542 : GF_HintSampleEntryBox *entry;
543 : u32 count;
544 : u16 refIndex;
545 : GF_HintPacket *pck;
546 : GF_StreamDescDTE *dte;
547 : GF_Err e;
548 : GF_TrackReferenceTypeBox *hint;
549 :
550 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
551 1 : if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM;
552 :
553 0 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count);
554 0 : if (e) return e;
555 0 : if (!entry->hint_sample) return GF_BAD_PARAM;
556 0 : count = gf_list_count(entry->hint_sample->packetTable);
557 0 : if (!count) return GF_BAD_PARAM;
558 0 : pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1);
559 :
560 0 : dte = (GF_StreamDescDTE *) NewDTE(3);
561 0 : dte->byteOffset = offsetInDescription;
562 0 : dte->dataLength = DataLength;
563 0 : dte->streamDescIndex = StreamDescriptionIndex;
564 0 : if (SourceTrackID == trak->Header->trackID) {
565 0 : dte->trackRefIndex = (s8) -1;
566 : } else {
567 : //get (or set) the track reference index
568 0 : e = Track_FindRef(trak, GF_ISOM_REF_HINT, &hint);
569 0 : if (e) return e;
570 0 : e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex);
571 0 : if (e) return e;
572 : //WARNING: IN QT, MUST BE 0-based !!!
573 0 : dte->trackRefIndex = (u8) (refIndex - 1);
574 : }
575 0 : return gf_isom_hint_pck_add_dte(pck, (GF_GenericDTE *)dte, AtBegin);
576 : }
577 :
578 : GF_EXPORT
579 68137 : GF_Err gf_isom_rtp_packet_set_flags(GF_ISOFile *the_file, u32 trackNumber,
580 : u8 PackingBit,
581 : u8 eXtensionBit,
582 : u8 MarkerBit,
583 : u8 disposable_packet,
584 : u8 IsRepeatedPacket)
585 : {
586 : GF_TrackBox *trak;
587 : GF_HintSampleEntryBox *entry;
588 : GF_RTPPacket *pck;
589 : u32 dataRefIndex, ind;
590 : GF_Err e;
591 :
592 68137 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
593 68137 : if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
594 :
595 68137 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
596 68137 : if (e) return e;
597 68137 : if (!entry->hint_sample) return GF_BAD_PARAM;
598 :
599 68137 : ind = gf_list_count(entry->hint_sample->packetTable);
600 68137 : if (!ind) return GF_BAD_PARAM;
601 68137 : pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, ind-1);
602 :
603 68137 : pck->P_bit = PackingBit ? 1 : 0;
604 68137 : pck->X_bit = eXtensionBit ? 1 : 0;
605 68137 : pck->M_bit = MarkerBit ? 1 : 0;
606 68137 : pck->B_bit = disposable_packet ? 1 : 0;
607 68137 : pck->R_bit = IsRepeatedPacket ? 1 : 0;
608 68137 : return GF_OK;
609 : }
610 :
611 : GF_EXPORT
612 68137 : GF_Err gf_isom_rtp_packet_begin(GF_ISOFile *the_file, u32 trackNumber,
613 : s32 relativeTime,
614 : u8 PackingBit,
615 : u8 eXtensionBit,
616 : u8 MarkerBit,
617 : u8 PayloadType,
618 : u8 B_frame,
619 : u8 IsRepeatedPacket,
620 : u16 SequenceNumber)
621 : {
622 : GF_TrackBox *trak;
623 : GF_HintSampleEntryBox *entry;
624 : GF_RTPPacket *pck;
625 : u32 dataRefIndex;
626 : GF_Err e;
627 :
628 68137 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
629 68137 : if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
630 :
631 68137 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
632 68137 : if (e) return e;
633 68137 : if (!entry->hint_sample) return GF_BAD_PARAM;
634 :
635 68137 : pck = (GF_RTPPacket *) gf_isom_hint_pck_new(entry->type);
636 :
637 68137 : pck->P_bit = PackingBit ? 1 : 0;
638 68137 : pck->X_bit = eXtensionBit ? 1 : 0;
639 68137 : pck->M_bit = MarkerBit ? 1 : 0;
640 68137 : pck->payloadType = PayloadType;
641 68137 : pck->SequenceNumber = SequenceNumber;
642 68137 : pck->B_bit = B_frame ? 1 : 0;
643 68137 : pck->R_bit = IsRepeatedPacket ? 1 : 0;
644 68137 : pck->relativeTransTime = relativeTime;
645 68137 : return gf_list_add(entry->hint_sample->packetTable, pck);
646 : }
647 :
648 :
649 : //set the time offset of this packet. This enables packets to be placed in the hint track
650 : //in decoding order, but have their presentation time-stamp in the transmitted
651 : //packet be in a different order. Typically used for MPEG video with B-frames
652 : GF_EXPORT
653 9737 : GF_Err gf_isom_rtp_packet_set_offset(GF_ISOFile *the_file, u32 trackNumber, s32 timeOffset)
654 : {
655 : GF_RTPOBox *rtpo;
656 : GF_TrackBox *trak;
657 : GF_HintSampleEntryBox *entry;
658 : GF_RTPPacket *pck;
659 : u32 dataRefIndex, i;
660 : GF_Err e;
661 :
662 9737 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
663 9737 : if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
664 :
665 9737 : e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex);
666 9737 : if (e) return e;
667 9737 : if (!entry->hint_sample) return GF_BAD_PARAM;
668 :
669 9737 : pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, gf_list_count(entry->hint_sample->packetTable) - 1);
670 9737 : if (!pck) return GF_BAD_PARAM;
671 :
672 : //look in the TLV
673 9737 : i=0;
674 19474 : while ((rtpo = (GF_RTPOBox *)gf_list_enum(pck->TLV, &i))) {
675 0 : if (rtpo->type == GF_ISOM_BOX_TYPE_RTPO) {
676 0 : rtpo->timeOffset = timeOffset;
677 0 : return GF_OK;
678 : }
679 : }
680 : //not found, add it
681 9737 : rtpo = (GF_RTPOBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_RTPO);
682 9737 : if (!rtpo) return GF_OUT_OF_MEM;
683 9737 : rtpo->timeOffset = timeOffset;
684 :
685 9737 : return gf_list_add(pck->TLV, rtpo);
686 : }
687 :
688 :
689 1315 : static void AddSDPLine(GF_List *list, char *sdp_text, Bool is_movie_sdp)
690 : {
691 : const char *sdp_order;
692 1315 : u32 i, count = gf_list_count(list);
693 1315 : char fc = sdp_text[0];
694 :
695 1315 : sdp_order = (is_movie_sdp) ? "vosiuepcbzkatr" : "micbka";
696 3367 : for (i=0; i<count; i++) {
697 2052 : char *l = (char *)gf_list_get(list, i);
698 2052 : char *s1 = (char *)strchr(sdp_order, l[0]);
699 2052 : char *s2 = (char *)strchr(sdp_order, fc);
700 2052 : if (s1 && s2 && (strlen(s2)>strlen(s1))) {
701 0 : gf_list_insert(list, sdp_text, i);
702 0 : return;
703 : }
704 : }
705 1315 : gf_list_add(list, sdp_text);
706 : }
707 :
708 371 : static void ReorderSDP(char *sdp_text, Bool is_movie_sdp)
709 : {
710 : char *cur;
711 371 : GF_List *lines = gf_list_new();
712 : cur = sdp_text;
713 1686 : while (cur) {
714 : char b;
715 1315 : char *st = strstr(cur, "\r\n");
716 : assert(st);
717 1315 : st += 2;
718 1315 : if (!st[0]) {
719 371 : AddSDPLine(lines, gf_strdup(cur), is_movie_sdp);
720 371 : break;
721 : }
722 : b = st[0];
723 944 : st[0] = 0;
724 944 : AddSDPLine(lines, gf_strdup(cur), is_movie_sdp);
725 944 : st[0] = b;
726 : cur = st;
727 : }
728 : strcpy(sdp_text, "");
729 1686 : while (gf_list_count(lines)) {
730 1315 : cur = (char *)gf_list_get(lines, 0);
731 1315 : gf_list_rem(lines, 0);
732 : strcat(sdp_text, cur);
733 1315 : gf_free(cur);
734 : }
735 371 : gf_list_del(lines);
736 371 : }
737 :
738 : //add an SDP line to the SDP container at the track level (media-specific SDP info)
739 : GF_EXPORT
740 391 : GF_Err gf_isom_sdp_add_track_line(GF_ISOFile *the_file, u32 trackNumber, const char *text)
741 : {
742 : GF_TrackBox *trak;
743 : GF_UserDataMap *map;
744 : GF_HintTrackInfoBox *hnti;
745 : GF_SDPBox *sdp;
746 : GF_Err e;
747 : char *buf;
748 :
749 391 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
750 391 : if (!trak) return GF_BAD_PARAM;
751 :
752 : //currently, only RTP hinting supports SDP
753 391 : if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
754 :
755 391 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
756 391 : if (!map) return GF_ISOM_INVALID_FILE;
757 :
758 : //we should have only one HNTI in the UDTA
759 391 : if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
760 :
761 391 : hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
762 391 : if (!hnti->SDP) {
763 73 : e = hnti_on_child_box((GF_Box*)hnti, gf_isom_box_new_parent(&hnti->child_boxes, GF_ISOM_BOX_TYPE_SDP), GF_FALSE);
764 73 : if (e) return e;
765 : }
766 391 : sdp = (GF_SDPBox *) hnti->SDP;
767 :
768 391 : if (!sdp->sdpText) {
769 73 : sdp->sdpText = (char *)gf_malloc(sizeof(char) * (strlen(text) + 3));
770 73 : if (!sdp->sdpText) return GF_OUT_OF_MEM;
771 :
772 : strcpy(sdp->sdpText, text);
773 73 : strcat(sdp->sdpText, "\r\n");
774 73 : return GF_OK;
775 : }
776 318 : buf = (char *)gf_malloc(sizeof(char) * (strlen(sdp->sdpText) + strlen(text) + 3));
777 318 : if (!buf) return GF_OUT_OF_MEM;
778 :
779 318 : strcpy(buf, sdp->sdpText);
780 : strcat(buf, text);
781 : strcat(buf, "\r\n");
782 318 : gf_free(sdp->sdpText);
783 318 : ReorderSDP(buf, GF_FALSE);
784 318 : sdp->sdpText = buf;
785 318 : return GF_OK;
786 : }
787 :
788 : //remove all SDP info at the track level
789 : GF_EXPORT
790 73 : GF_Err gf_isom_sdp_clean_track(GF_ISOFile *the_file, u32 trackNumber)
791 : {
792 : GF_TrackBox *trak;
793 : GF_UserDataMap *map;
794 : GF_HintTrackInfoBox *hnti;
795 :
796 73 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
797 73 : if (!trak) return GF_BAD_PARAM;
798 :
799 : //currently, only RTP hinting supports SDP
800 73 : if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM;
801 :
802 0 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
803 0 : if (!map) return GF_ISOM_INVALID_FILE;
804 :
805 : //we should have only one HNTI in the UDTA
806 0 : if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
807 :
808 0 : hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
809 0 : if (!hnti->SDP) return GF_OK;
810 : //and free the SDP
811 0 : gf_free(((GF_SDPBox *)hnti->SDP)->sdpText);
812 0 : ((GF_SDPBox *)hnti->SDP)->sdpText = NULL;
813 0 : return GF_OK;
814 : }
815 :
816 :
817 : //add an SDP line to the SDP container at the movie level (presentation SDP info)
818 : //NOTE: the \r\n end of line for SDP is automatically inserted
819 : GF_EXPORT
820 108 : GF_Err gf_isom_sdp_add_line(GF_ISOFile *movie, const char *text)
821 : {
822 : GF_UserDataMap *map;
823 : GF_RTPBox *rtp;
824 : GF_Err e;
825 : GF_HintTrackInfoBox *hnti;
826 : char *buf;
827 :
828 108 : if (!movie->moov) return GF_BAD_PARAM;
829 :
830 : //check if we have a udta ...
831 108 : if (!movie->moov->udta) {
832 55 : e = moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
833 55 : if (e) return e;
834 : }
835 : //find a hnti in the udta
836 108 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
837 108 : if (!map) {
838 55 : e = udta_on_child_box((GF_Box *)movie->moov->udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HNTI), GF_FALSE);
839 55 : if (e) return e;
840 55 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
841 : }
842 :
843 : //there should be one and only one hnti
844 108 : if (!gf_list_count(map->boxes) ) {
845 0 : e = udta_on_child_box((GF_Box *)movie->moov->udta, gf_isom_box_new(GF_ISOM_BOX_TYPE_HNTI), GF_FALSE);
846 0 : if (e) return e;
847 : }
848 108 : else if (gf_list_count(map->boxes) < 1) return GF_ISOM_INVALID_FILE;
849 :
850 108 : hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
851 :
852 108 : if (!hnti->SDP) {
853 55 : GF_Box *a = gf_isom_box_new_ex(GF_ISOM_BOX_TYPE_RTP, GF_ISOM_BOX_TYPE_HNTI, 0, GF_FALSE);
854 55 : if (!a) return GF_OUT_OF_MEM;
855 55 : hnti_on_child_box((GF_Box*)hnti, a, GF_FALSE);
856 55 : if (!hnti->child_boxes) hnti->child_boxes = gf_list_new();
857 55 : gf_list_add(hnti->child_boxes, a);
858 : }
859 108 : rtp = (GF_RTPBox *) hnti->SDP;
860 :
861 108 : if (!rtp->sdpText) {
862 55 : rtp->sdpText = (char*)gf_malloc(sizeof(char) * (strlen(text) + 3));
863 55 : if (!rtp->sdpText) return GF_OUT_OF_MEM;
864 :
865 : strcpy(rtp->sdpText, text);
866 55 : strcat(rtp->sdpText, "\r\n");
867 55 : return GF_OK;
868 : }
869 53 : buf = (char*)gf_malloc(sizeof(char) * (strlen(rtp->sdpText) + strlen(text) + 3));
870 53 : if (!buf) return GF_OUT_OF_MEM;
871 :
872 53 : strcpy(buf, rtp->sdpText);
873 : strcat(buf, text);
874 : strcat(buf, "\r\n");
875 53 : gf_free(rtp->sdpText);
876 53 : ReorderSDP(buf, GF_TRUE);
877 53 : rtp->sdpText = buf;
878 53 : return GF_OK;
879 : }
880 :
881 :
882 : //remove all SDP info at the movie level
883 : GF_EXPORT
884 96 : GF_Err gf_isom_sdp_clean(GF_ISOFile *movie)
885 : {
886 : GF_UserDataMap *map;
887 : GF_HintTrackInfoBox *hnti;
888 :
889 : //check if we have a udta ...
890 96 : if (!movie->moov || !movie->moov->udta) return GF_OK;
891 :
892 : //find a hnti in the udta
893 40 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
894 40 : if (!map) return GF_OK;
895 :
896 : //there should be one and only one hnti
897 40 : if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
898 40 : hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
899 :
900 : //remove and destroy the entry
901 40 : gf_list_rem(map->boxes, 0);
902 40 : gf_isom_box_del((GF_Box *)hnti);
903 40 : return GF_OK;
904 : }
905 :
906 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
907 :
908 : GF_EXPORT
909 1 : GF_Err gf_isom_sdp_get(GF_ISOFile *movie, const char **sdp, u32 *length)
910 : {
911 : GF_UserDataMap *map;
912 : GF_HintTrackInfoBox *hnti;
913 : GF_RTPBox *rtp;
914 1 : *length = 0;
915 1 : *sdp = NULL;
916 1 : if (!movie || !movie->moov) return GF_BAD_PARAM;
917 : //check if we have a udta ...
918 1 : if (!movie->moov->udta) return GF_OK;
919 :
920 : //find a hnti in the udta
921 1 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
922 1 : if (!map) return GF_OK;
923 :
924 : //there should be one and only one hnti
925 1 : if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
926 1 : hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
927 :
928 1 : if (!hnti->SDP) return GF_OK;
929 : rtp = (GF_RTPBox *) hnti->SDP;
930 :
931 1 : *length = (u32) strlen(rtp->sdpText);
932 1 : *sdp = rtp->sdpText;
933 1 : return GF_OK;
934 : }
935 :
936 : GF_EXPORT
937 2 : GF_Err gf_isom_sdp_track_get(GF_ISOFile *the_file, u32 trackNumber, const char **sdp, u32 *length)
938 : {
939 : GF_TrackBox *trak;
940 : GF_UserDataMap *map;
941 : GF_HintTrackInfoBox *hnti;
942 : GF_SDPBox *sdpa;
943 :
944 2 : *sdp = NULL;
945 2 : *length = 0;
946 :
947 2 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
948 2 : if (!trak) return GF_BAD_PARAM;
949 2 : if (!trak->udta) return GF_OK;
950 :
951 2 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HNTI, NULL);
952 2 : if (!map) return GF_ISOM_INVALID_FILE;
953 :
954 : //we should have only one HNTI in the UDTA
955 2 : if (gf_list_count(map->boxes) != 1) return GF_ISOM_INVALID_FILE;
956 :
957 2 : hnti = (GF_HintTrackInfoBox *)gf_list_get(map->boxes, 0);
958 2 : if (!hnti->SDP) return GF_OK;
959 : sdpa = (GF_SDPBox *) hnti->SDP;
960 :
961 2 : *length = (u32) strlen(sdpa->sdpText);
962 2 : *sdp = sdpa->sdpText;
963 2 : return GF_OK;
964 : }
965 :
966 :
967 : GF_EXPORT
968 1 : u32 gf_isom_get_payt_count(GF_ISOFile *the_file, u32 trackNumber)
969 : {
970 : u32 i, count;
971 : GF_TrackBox *trak;
972 : GF_UserDataMap *map;
973 : GF_HintInfoBox *hinf;
974 : GF_PAYTBox *payt;
975 :
976 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
977 1 : if (!trak) return 0;
978 :
979 1 : if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return 0;
980 1 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HINF, NULL);
981 1 : if (!map) return 0;
982 0 : if (gf_list_count(map->boxes) != 1) return 0;
983 :
984 0 : hinf = (GF_HintInfoBox *)gf_list_get(map->boxes, 0);
985 : count = 0;
986 0 : i = 0;
987 0 : while ((payt = (GF_PAYTBox*)gf_list_enum(hinf->child_boxes, &i))) {
988 0 : if (payt->type == GF_ISOM_BOX_TYPE_PAYT) count++;
989 : }
990 : return count;
991 : }
992 :
993 : GF_EXPORT
994 1 : const char *gf_isom_get_payt_info(GF_ISOFile *the_file, u32 trackNumber, u32 index, u32 *payID)
995 : {
996 : u32 i, count;
997 : GF_TrackBox *trak;
998 : GF_UserDataMap *map;
999 : GF_HintInfoBox *hinf;
1000 : GF_PAYTBox *payt;
1001 :
1002 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1003 1 : if (!trak || !index) return NULL;
1004 :
1005 0 : if (!CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return NULL;
1006 0 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_HINF, NULL);
1007 0 : if (!map) return NULL;
1008 0 : if (gf_list_count(map->boxes) != 1) return NULL;
1009 :
1010 0 : hinf = (GF_HintInfoBox *)gf_list_get(map->boxes, 0);
1011 : count = 0;
1012 0 : i = 0;
1013 0 : while ((payt = (GF_PAYTBox*)gf_list_enum(hinf->child_boxes, &i))) {
1014 0 : if (payt->type == GF_ISOM_BOX_TYPE_PAYT) {
1015 0 : count++;
1016 0 : if (count == index) {
1017 0 : if (payID) *payID=payt->payloadCode;
1018 0 : return payt->payloadString;
1019 : }
1020 : }
1021 : }
1022 : return NULL;
1023 : }
1024 :
1025 : #endif /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)*/
1026 :
|