/src/gpac/src/isomedia/media_odf.c
Line | Count | Source |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2000-2025 |
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 | | #ifndef GPAC_DISABLE_ISOM |
29 | | |
30 | | // Rewrite the good dependencies when an OD AU is extracted from the file |
31 | | GF_Err Media_RewriteODFrame(GF_MediaBox *mdia, GF_ISOSample *sample) |
32 | 0 | { |
33 | 0 | GF_Err e; |
34 | 0 | GF_ODCodec *ODdecode; |
35 | 0 | GF_ODCodec *ODencode; |
36 | 0 | GF_ODCom *com; |
37 | | |
38 | | //the commands we proceed |
39 | 0 | GF_ESDUpdate *esdU, *esdU2; |
40 | 0 | GF_ESDRemove *esdR, *esdR2; |
41 | 0 | GF_ODUpdate *odU, *odU2; |
42 | | |
43 | | //the desc they contain |
44 | 0 | GF_ObjectDescriptor *od; |
45 | 0 | GF_IsomObjectDescriptor *isom_od; |
46 | 0 | GF_ESD *esd; |
47 | 0 | GF_ES_ID_Ref *ref; |
48 | 0 | GF_Descriptor *desc; |
49 | 0 | GF_TrackReferenceTypeBox *mpod; |
50 | 0 | u32 i, j, skipped; |
51 | |
|
52 | 0 | if (!mdia || !sample || !sample->data || !sample->dataLength) return GF_BAD_PARAM; |
53 | | |
54 | 0 | mpod = NULL; |
55 | 0 | e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod); |
56 | 0 | if (e) return e; |
57 | | //no references, nothing to do... |
58 | 0 | if (!mpod || !mpod->trackIDs) return GF_OK; |
59 | | |
60 | 0 | ODdecode = gf_odf_codec_new(); |
61 | 0 | if (!ODdecode) return GF_OUT_OF_MEM; |
62 | 0 | ODencode = gf_odf_codec_new(); |
63 | 0 | if (!ODencode) { |
64 | 0 | gf_odf_codec_del(ODdecode); |
65 | 0 | return GF_OUT_OF_MEM; |
66 | 0 | } |
67 | 0 | e = gf_odf_codec_set_au(ODdecode, sample->data, sample->dataLength); |
68 | 0 | if (e) goto err_exit; |
69 | 0 | e = gf_odf_codec_decode(ODdecode); |
70 | 0 | if (e) goto err_exit; |
71 | | |
72 | 0 | while (1) { |
73 | 0 | com = gf_odf_codec_get_com(ODdecode); |
74 | 0 | if (!com) break; |
75 | | |
76 | | //we only need to rewrite commands with ESDs inside: ESDUpdate and ODUpdate |
77 | 0 | switch (com->tag) { |
78 | 0 | case GF_ODF_OD_UPDATE_TAG: |
79 | 0 | odU = (GF_ODUpdate *) com; |
80 | 0 | odU2 = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); |
81 | |
|
82 | 0 | i=0; |
83 | 0 | while ((desc = (GF_Descriptor*)gf_list_enum(odU->objectDescriptors, &i))) { |
84 | 0 | switch (desc->tag) { |
85 | 0 | case GF_ODF_OD_TAG: |
86 | 0 | case GF_ODF_ISOM_OD_TAG: |
87 | | //IOD can be used in OD streams |
88 | 0 | case GF_ODF_ISOM_IOD_TAG: |
89 | 0 | break; |
90 | 0 | default: |
91 | 0 | return GF_ISOM_INVALID_FILE; |
92 | 0 | } |
93 | 0 | e = gf_odf_desc_copy(desc, (GF_Descriptor **)&isom_od); |
94 | 0 | if (e) goto err_exit; |
95 | | |
96 | | //create our OD... |
97 | 0 | if (desc->tag == GF_ODF_ISOM_IOD_TAG) { |
98 | 0 | od = (GF_ObjectDescriptor *) gf_malloc(sizeof(GF_InitialObjectDescriptor)); |
99 | 0 | } else { |
100 | 0 | od = (GF_ObjectDescriptor *) gf_malloc(sizeof(GF_ObjectDescriptor)); |
101 | 0 | } |
102 | 0 | if (!od) { |
103 | 0 | e = GF_OUT_OF_MEM; |
104 | 0 | goto err_exit; |
105 | 0 | } |
106 | 0 | od->ESDescriptors = gf_list_new(); |
107 | | //and duplicate... |
108 | 0 | od->objectDescriptorID = isom_od->objectDescriptorID; |
109 | 0 | od->tag = GF_ODF_OD_TAG; |
110 | 0 | od->URLString = isom_od->URLString; |
111 | 0 | isom_od->URLString = NULL; |
112 | 0 | od->extensionDescriptors = isom_od->extensionDescriptors; |
113 | 0 | isom_od->extensionDescriptors = NULL; |
114 | 0 | od->IPMP_Descriptors = isom_od->IPMP_Descriptors; |
115 | 0 | isom_od->IPMP_Descriptors = NULL; |
116 | 0 | od->OCIDescriptors = isom_od->OCIDescriptors; |
117 | 0 | isom_od->OCIDescriptors = NULL; |
118 | | |
119 | | //init as IOD |
120 | 0 | if (isom_od->tag == GF_ODF_ISOM_IOD_TAG) { |
121 | 0 | ((GF_InitialObjectDescriptor *)od)->audio_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->audio_profileAndLevel; |
122 | 0 | ((GF_InitialObjectDescriptor *)od)->inlineProfileFlag = ((GF_IsomInitialObjectDescriptor *)isom_od)->inlineProfileFlag; |
123 | 0 | ((GF_InitialObjectDescriptor *)od)->graphics_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->graphics_profileAndLevel; |
124 | 0 | ((GF_InitialObjectDescriptor *)od)->OD_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->OD_profileAndLevel; |
125 | 0 | ((GF_InitialObjectDescriptor *)od)->scene_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->scene_profileAndLevel; |
126 | 0 | ((GF_InitialObjectDescriptor *)od)->visual_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->visual_profileAndLevel; |
127 | 0 | ((GF_InitialObjectDescriptor *)od)->IPMPToolList = ((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList; |
128 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList = NULL; |
129 | 0 | } |
130 | | |
131 | | //then rewrite the ESDesc |
132 | 0 | j=0; |
133 | 0 | while ((ref = (GF_ES_ID_Ref*)gf_list_enum(isom_od->ES_ID_RefDescriptors, &j))) { |
134 | 0 | if (!mpod->trackIDs || !ref->trackRef || (ref->trackRef>mpod->trackIDCount)) continue; |
135 | | //if the ref index is not valid, skip this desc... |
136 | 0 | if (gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue; |
137 | | //OK, get the esd |
138 | 0 | e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd); |
139 | 0 | if (!e) e = gf_odf_desc_add_desc((GF_Descriptor *) od, (GF_Descriptor *) esd); |
140 | 0 | if (e) { |
141 | 0 | gf_odf_desc_del((GF_Descriptor *)od); |
142 | 0 | gf_odf_com_del((GF_ODCom **)&odU2); |
143 | 0 | gf_odf_desc_del((GF_Descriptor *)isom_od); |
144 | 0 | gf_odf_com_del((GF_ODCom **)&odU); |
145 | 0 | goto err_exit; |
146 | 0 | } |
147 | |
|
148 | 0 | } |
149 | | //delete our desc |
150 | 0 | gf_odf_desc_del((GF_Descriptor *)isom_od); |
151 | 0 | gf_list_add(odU2->objectDescriptors, od); |
152 | 0 | } |
153 | | //clean a bit |
154 | 0 | gf_odf_com_del((GF_ODCom **)&odU); |
155 | 0 | gf_odf_codec_add_com(ODencode, (GF_ODCom *)odU2); |
156 | 0 | break; |
157 | | |
158 | 0 | case GF_ODF_ESD_UPDATE_TAG: |
159 | 0 | esdU = (GF_ESDUpdate *) com; |
160 | 0 | esdU2 = (GF_ESDUpdate *) gf_odf_com_new(GF_ODF_ESD_UPDATE_TAG); |
161 | 0 | esdU2->ODID = esdU->ODID; |
162 | 0 | i=0; |
163 | 0 | while ((ref = (GF_ES_ID_Ref*)gf_list_enum(esdU->ESDescriptors, &i))) { |
164 | 0 | if (!mpod->trackIDs || !ref->trackRef || (ref->trackRef>mpod->trackIDCount)) continue; |
165 | | //if the ref index is not valid, skip this desc... |
166 | 0 | if (gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue; |
167 | | //OK, get the esd |
168 | 0 | e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd); |
169 | 0 | if (e) goto err_exit; |
170 | 0 | gf_list_add(esdU2->ESDescriptors, esd); |
171 | 0 | } |
172 | 0 | gf_odf_com_del((GF_ODCom **)&esdU); |
173 | 0 | gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdU2); |
174 | 0 | break; |
175 | | |
176 | | //brand new case: the ESRemove follows the same principle according to the spec... |
177 | 0 | case GF_ODF_ESD_REMOVE_REF_TAG: |
178 | | //both commands have the same structure, only the tags change |
179 | 0 | esdR = (GF_ESDRemove *) com; |
180 | 0 | esdR2 = (GF_ESDRemove *) gf_odf_com_new(GF_ODF_ESD_REMOVE_TAG); |
181 | 0 | esdR2->ODID = esdR->ODID; |
182 | 0 | esdR2->NbESDs = esdR->NbESDs; |
183 | | //alloc our stuff |
184 | 0 | esdR2->ES_ID = (unsigned short*)gf_malloc(sizeof(u32) * esdR->NbESDs); |
185 | 0 | if (!esdR2->ES_ID) { |
186 | 0 | e = GF_OUT_OF_MEM; |
187 | 0 | goto err_exit; |
188 | 0 | } |
189 | 0 | skipped = 0; |
190 | | //get the ES_ID in the mpod indicated in the ES_ID[] |
191 | 0 | for (i = 0; i < esdR->NbESDs; i++) { |
192 | 0 | if (!mpod->trackIDs || !esdR->ES_ID[i] || (esdR->ES_ID[i]>mpod->trackIDCount)) continue; |
193 | | //if the ref index is not valid, remove this desc... |
194 | 0 | if (gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[esdR->ES_ID[i] - 1]) == NULL) { |
195 | 0 | skipped ++; |
196 | 0 | } else { |
197 | | //the command in the file has the ref index of the trackID in the mpod |
198 | 0 | esdR2->ES_ID[i - skipped] = mpod->trackIDs[esdR->ES_ID[i] - 1]; |
199 | 0 | } |
200 | 0 | } |
201 | | //gf_realloc... |
202 | 0 | if (skipped && (skipped != esdR2->NbESDs) ) { |
203 | 0 | esdR2->NbESDs -= skipped; |
204 | 0 | esdR2->ES_ID = (unsigned short*)gf_realloc(esdR2->ES_ID, sizeof(u32) * esdR2->NbESDs); |
205 | 0 | } |
206 | 0 | gf_odf_com_del((GF_ODCom **)&esdR); |
207 | 0 | gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdR2); |
208 | 0 | break; |
209 | | |
210 | 0 | default: |
211 | 0 | e = gf_odf_codec_add_com(ODencode, com); |
212 | 0 | if (e) goto err_exit; |
213 | 0 | } |
214 | 0 | } |
215 | | //encode our new AU |
216 | 0 | e = gf_odf_codec_encode(ODencode, 1); |
217 | 0 | if (e) goto err_exit; |
218 | | |
219 | | //and set the buffer in the sample |
220 | 0 | gf_free(sample->data); |
221 | 0 | sample->data = NULL; |
222 | 0 | sample->dataLength = 0; |
223 | 0 | e = gf_odf_codec_get_au(ODencode, &sample->data, &sample->dataLength); |
224 | |
|
225 | 0 | err_exit: |
226 | 0 | gf_odf_codec_del(ODdecode); |
227 | 0 | gf_odf_codec_del(ODencode); |
228 | 0 | return e; |
229 | 0 | } |
230 | | |
231 | | |
232 | | // Update the dependencies when an OD AU is inserted in the file |
233 | | GF_Err Media_ParseODFrame(GF_MediaBox *mdia, const GF_ISOSample *sample, GF_ISOSample **od_samp) |
234 | 0 | { |
235 | 0 | GF_TrackReferenceBox *tref; |
236 | 0 | GF_TrackReferenceTypeBox *mpod; |
237 | 0 | GF_Err e; |
238 | 0 | GF_ODCom *com; |
239 | 0 | GF_ODCodec *ODencode; |
240 | 0 | GF_ODCodec *ODdecode; |
241 | 0 | u32 i, j; |
242 | | //the commands we proceed |
243 | 0 | GF_ESDUpdate *esdU, *esdU2; |
244 | 0 | GF_ESDRemove *esdR, *esdR2; |
245 | 0 | GF_ODUpdate *odU, *odU2; |
246 | | |
247 | | //the desc they contain |
248 | 0 | GF_ObjectDescriptor *od; |
249 | 0 | GF_IsomObjectDescriptor *isom_od; |
250 | 0 | GF_ESD *esd; |
251 | 0 | GF_ES_ID_Ref *ref; |
252 | 0 | GF_Descriptor *desc; |
253 | |
|
254 | 0 | *od_samp = NULL; |
255 | 0 | if (!mdia || !sample || !sample->data || !sample->dataLength) return GF_BAD_PARAM; |
256 | | |
257 | | //First find the references, and create them if none |
258 | 0 | tref = mdia->mediaTrack->References; |
259 | 0 | if (!tref) { |
260 | 0 | tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&mdia->mediaTrack->child_boxes, GF_ISOM_BOX_TYPE_TREF); |
261 | 0 | if (!tref) return GF_OUT_OF_MEM; |
262 | 0 | e = trak_on_child_box((GF_Box*)mdia->mediaTrack, (GF_Box *) tref, GF_FALSE); |
263 | 0 | if (e) return e; |
264 | 0 | } |
265 | | //then find the OD reference, and create it if none |
266 | 0 | e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod); |
267 | 0 | if (e) return e; |
268 | 0 | if (!mpod) { |
269 | 0 | mpod = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT); |
270 | 0 | if (!mpod) return GF_OUT_OF_MEM; |
271 | 0 | mpod->reference_type = GF_ISOM_BOX_TYPE_MPOD; |
272 | 0 | } |
273 | | |
274 | | //OK, create our codecs |
275 | 0 | ODencode = gf_odf_codec_new(); |
276 | 0 | if (!ODencode) return GF_OUT_OF_MEM; |
277 | 0 | ODdecode = gf_odf_codec_new(); |
278 | 0 | if (!ODdecode) return GF_OUT_OF_MEM; |
279 | | |
280 | 0 | e = gf_odf_codec_set_au(ODdecode, sample->data, sample->dataLength); |
281 | 0 | if (e) goto err_exit; |
282 | 0 | e = gf_odf_codec_decode(ODdecode); |
283 | 0 | if (e) goto err_exit; |
284 | | |
285 | 0 | while (1) { |
286 | 0 | com = gf_odf_codec_get_com(ODdecode); |
287 | 0 | if (!com) break; |
288 | | |
289 | | //check our commands |
290 | 0 | switch (com->tag) { |
291 | | //Rewrite OD Update |
292 | 0 | case GF_ODF_OD_UPDATE_TAG: |
293 | | //duplicate our command |
294 | 0 | odU = (GF_ODUpdate *) com; |
295 | 0 | odU2 = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); |
296 | |
|
297 | 0 | i=0; |
298 | 0 | while ((desc = (GF_Descriptor*)gf_list_enum(odU->objectDescriptors, &i))) { |
299 | | //both OD and IODs are accepted |
300 | 0 | switch (desc->tag) { |
301 | 0 | case GF_ODF_OD_TAG: |
302 | 0 | case GF_ODF_IOD_TAG: |
303 | 0 | break; |
304 | 0 | default: |
305 | 0 | e = GF_ODF_INVALID_DESCRIPTOR; |
306 | 0 | goto err_exit; |
307 | 0 | } |
308 | | //get the esd |
309 | 0 | e = gf_odf_desc_copy(desc, (GF_Descriptor **)&od); |
310 | 0 | if (e) goto err_exit; |
311 | 0 | if (desc->tag == GF_ODF_OD_TAG) { |
312 | 0 | isom_od = (GF_IsomObjectDescriptor *) gf_malloc(sizeof(GF_IsomObjectDescriptor)); |
313 | 0 | if (!isom_od) return GF_OUT_OF_MEM; |
314 | 0 | isom_od->tag = GF_ODF_ISOM_OD_TAG; |
315 | 0 | } else { |
316 | 0 | isom_od = (GF_IsomObjectDescriptor *) gf_malloc(sizeof(GF_IsomInitialObjectDescriptor)); |
317 | 0 | if (!isom_od) return GF_OUT_OF_MEM; |
318 | 0 | isom_od->tag = GF_ODF_ISOM_IOD_TAG; |
319 | | //copy PL |
320 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->inlineProfileFlag = ((GF_InitialObjectDescriptor *)od)->inlineProfileFlag; |
321 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->graphics_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->graphics_profileAndLevel; |
322 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->audio_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->audio_profileAndLevel; |
323 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->OD_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->OD_profileAndLevel; |
324 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->scene_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->scene_profileAndLevel; |
325 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->visual_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->visual_profileAndLevel; |
326 | 0 | ((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList = ((GF_InitialObjectDescriptor *)od)->IPMPToolList; |
327 | 0 | ((GF_InitialObjectDescriptor *)od)->IPMPToolList = NULL; |
328 | 0 | } |
329 | | //in OD stream only ref desc are accepted |
330 | 0 | isom_od->ES_ID_RefDescriptors = gf_list_new(); |
331 | 0 | isom_od->ES_ID_IncDescriptors = NULL; |
332 | | |
333 | | //TO DO: check that a given sampleDescription exists |
334 | 0 | isom_od->extensionDescriptors = od->extensionDescriptors; |
335 | 0 | od->extensionDescriptors = NULL; |
336 | 0 | isom_od->IPMP_Descriptors = od->IPMP_Descriptors; |
337 | 0 | od->IPMP_Descriptors = NULL; |
338 | 0 | isom_od->OCIDescriptors = od->OCIDescriptors; |
339 | 0 | od->OCIDescriptors = NULL; |
340 | 0 | isom_od->URLString = od->URLString; |
341 | 0 | od->URLString = NULL; |
342 | 0 | isom_od->objectDescriptorID = od->objectDescriptorID; |
343 | |
|
344 | 0 | j=0; |
345 | 0 | while ((esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &j))) { |
346 | 0 | ref = (GF_ES_ID_Ref *) gf_odf_desc_new(GF_ODF_ESD_REF_TAG); |
347 | 0 | if (!esd->ESID) { |
348 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOM] Missing ESID on ESD, cannot add track reference in OD frame")); |
349 | 0 | e = GF_BAD_PARAM; |
350 | 0 | goto err_exit; |
351 | 0 | } |
352 | | //1 to 1 mapping trackID and ESID. Add this track to MPOD |
353 | | //if track does not exist, this will be remove while reading the OD stream |
354 | 0 | e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef); |
355 | 0 | if (e) goto err_exit; |
356 | 0 | e = gf_odf_desc_add_desc((GF_Descriptor *)isom_od, (GF_Descriptor *)ref); |
357 | 0 | if (e) goto err_exit; |
358 | 0 | } |
359 | | //delete our desc |
360 | 0 | gf_odf_desc_del((GF_Descriptor *)od); |
361 | | //and add the new one to our command |
362 | 0 | gf_list_add(odU2->objectDescriptors, isom_od); |
363 | 0 | } |
364 | | //delete the command |
365 | 0 | gf_odf_com_del((GF_ODCom **)&odU); |
366 | | //and add the new one to the codec |
367 | 0 | gf_odf_codec_add_com(ODencode, (GF_ODCom *)odU2); |
368 | 0 | break; |
369 | | |
370 | | //Rewrite ESD Update |
371 | 0 | case GF_ODF_ESD_UPDATE_TAG: |
372 | 0 | esdU = (GF_ESDUpdate *) com; |
373 | 0 | esdU2 = (GF_ESDUpdate *) gf_odf_com_new(GF_ODF_ESD_UPDATE_TAG); |
374 | 0 | esdU2->ODID = esdU->ODID; |
375 | 0 | i=0; |
376 | 0 | while ((esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &i))) { |
377 | 0 | ref = (GF_ES_ID_Ref *) gf_odf_desc_new(GF_ODF_ESD_REF_TAG); |
378 | | //1 to 1 mapping trackID and ESID |
379 | 0 | e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef); |
380 | 0 | if (e) goto err_exit; |
381 | 0 | e = gf_list_add(esdU2->ESDescriptors, ref); |
382 | 0 | if (e) goto err_exit; |
383 | 0 | } |
384 | 0 | gf_odf_com_del((GF_ODCom **)&esdU); |
385 | 0 | gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdU2); |
386 | 0 | break; |
387 | | |
388 | | //Brand new case: the ESRemove has to be rewritten too according to the specs... |
389 | 0 | case GF_ODF_ESD_REMOVE_TAG: |
390 | 0 | esdR = (GF_ESDRemove *) com; |
391 | 0 | esdR2 = (GF_ESDRemove *) gf_odf_com_new(GF_ODF_ESD_REMOVE_TAG); |
392 | | //change the tag for the file format |
393 | 0 | esdR2->tag = GF_ODF_ESD_REMOVE_REF_TAG; |
394 | 0 | esdR2->ODID = esdR->ODID; |
395 | 0 | esdR2->NbESDs = esdR->NbESDs; |
396 | 0 | if (esdR->NbESDs) { |
397 | | //alloc our stuff |
398 | 0 | esdR2->ES_ID = (unsigned short*)gf_malloc(sizeof(u32) * esdR->NbESDs); |
399 | 0 | if (!esdR2->ES_ID) { |
400 | 0 | e = GF_OUT_OF_MEM; |
401 | 0 | goto err_exit; |
402 | 0 | } |
403 | 0 | for (i = 0; i < esdR->NbESDs; i++) { |
404 | | //1 to 1 mapping trackID and ESID |
405 | 0 | e = reftype_AddRefTrack(mpod, esdR->ES_ID[i], &esdR2->ES_ID[i]); |
406 | 0 | if (e) goto err_exit; |
407 | 0 | } |
408 | 0 | } |
409 | 0 | gf_odf_com_del(&com); |
410 | 0 | gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdR2); |
411 | 0 | break; |
412 | | |
413 | | //Add the command as is |
414 | 0 | default: |
415 | 0 | e = gf_odf_codec_add_com(ODencode, com); |
416 | 0 | if (e) goto err_exit; |
417 | 0 | } |
418 | 0 | } |
419 | | |
420 | | //encode our new AU |
421 | 0 | e = gf_odf_codec_encode(ODencode, 1); |
422 | 0 | if (e) goto err_exit; |
423 | | |
424 | | //and set the buffer in the sample |
425 | 0 | *od_samp = gf_isom_sample_new(); |
426 | 0 | (*od_samp)->CTS_Offset = sample->CTS_Offset; |
427 | 0 | (*od_samp)->DTS = sample->DTS; |
428 | 0 | (*od_samp)->IsRAP = sample->IsRAP; |
429 | 0 | e = gf_odf_codec_get_au(ODencode, & (*od_samp)->data, & (*od_samp)->dataLength); |
430 | 0 | if (e) { |
431 | 0 | gf_isom_sample_del(od_samp); |
432 | 0 | *od_samp = NULL; |
433 | 0 | } |
434 | |
|
435 | 0 | err_exit: |
436 | |
|
437 | 0 | gf_odf_codec_del(ODencode); |
438 | 0 | gf_odf_codec_del(ODdecode); |
439 | 0 | return e; |
440 | 0 | } |
441 | | |
442 | | |
443 | | |
444 | | // Rewrite the good dependencies when an OD AU is extracted from the file |
445 | | static u32 Media_FindOD_ID(GF_MediaBox *mdia, GF_ISOSample *sample, u32 track_id) |
446 | 0 | { |
447 | 0 | GF_Err e; |
448 | 0 | GF_ODCodec *ODdecode; |
449 | 0 | GF_ODCom *com; |
450 | 0 | u32 the_od_id; |
451 | 0 | GF_ODUpdate *odU; |
452 | 0 | GF_ESD *esd; |
453 | 0 | GF_Descriptor *desc; |
454 | 0 | GF_TrackReferenceTypeBox *mpod; |
455 | 0 | u32 i, j; |
456 | |
|
457 | 0 | if (!mdia || !sample || !sample->data || !sample->dataLength) return 0; |
458 | | |
459 | 0 | mpod = NULL; |
460 | 0 | e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod); |
461 | 0 | if (e) return 0; |
462 | | //no references, nothing to do... |
463 | 0 | if (!mpod) return 0; |
464 | | |
465 | 0 | the_od_id = 0; |
466 | |
|
467 | 0 | ODdecode = gf_odf_codec_new(); |
468 | 0 | if (!ODdecode) return 0; |
469 | 0 | e = gf_odf_codec_set_au(ODdecode, sample->data, sample->dataLength); |
470 | 0 | if (e) goto err_exit; |
471 | 0 | e = gf_odf_codec_decode(ODdecode); |
472 | 0 | if (e) goto err_exit; |
473 | | |
474 | 0 | while (1) { |
475 | 0 | GF_List *esd_list = NULL; |
476 | 0 | com = gf_odf_codec_get_com(ODdecode); |
477 | 0 | if (!com) break; |
478 | 0 | if (com->tag != GF_ODF_OD_UPDATE_TAG) continue; |
479 | 0 | odU = (GF_ODUpdate *) com; |
480 | |
|
481 | 0 | i=0; |
482 | 0 | while ((desc = (GF_Descriptor*)gf_list_enum(odU->objectDescriptors, &i))) { |
483 | 0 | switch (desc->tag) { |
484 | 0 | case GF_ODF_OD_TAG: |
485 | 0 | case GF_ODF_IOD_TAG: |
486 | 0 | esd_list = ((GF_ObjectDescriptor *)desc)->ESDescriptors; |
487 | 0 | break; |
488 | 0 | default: |
489 | 0 | continue; |
490 | 0 | } |
491 | 0 | j=0; |
492 | 0 | while ((esd = (GF_ESD*)gf_list_enum( esd_list, &j))) { |
493 | 0 | if (esd->ESID==track_id) { |
494 | 0 | the_od_id = ((GF_IsomObjectDescriptor*)desc)->objectDescriptorID; |
495 | 0 | break; |
496 | 0 | } |
497 | 0 | } |
498 | 0 | if (the_od_id) break; |
499 | 0 | } |
500 | 0 | gf_odf_com_del((GF_ODCom **)&odU); |
501 | 0 | if (the_od_id) break; |
502 | 0 | } |
503 | | |
504 | 0 | err_exit: |
505 | 0 | gf_odf_codec_del(ODdecode); |
506 | 0 | return the_od_id; //still 0 if error, no need to check for e |
507 | 0 | } |
508 | | |
509 | | |
510 | | GF_EXPORT |
511 | | u32 gf_isom_find_od_id_for_track(GF_ISOFile *file, u32 track) |
512 | 0 | { |
513 | 0 | u32 i, j, di, the_od_id; |
514 | 0 | GF_TrackBox *od_tk; |
515 | 0 | GF_TrackBox *tk = gf_isom_get_track_box(file, track); |
516 | 0 | if (!tk) return 0; |
517 | | |
518 | 0 | i=0; |
519 | 0 | while ( (od_tk = (GF_TrackBox*)gf_list_enum(file->moov->trackList, &i))) { |
520 | 0 | if (!od_tk || !od_tk->Media || !od_tk->Media->handler || !od_tk->Media->information || |
521 | 0 | !od_tk->Media->information->sampleTable || !od_tk->Media->information->sampleTable->SampleSize ) { |
522 | |
|
523 | 0 | continue; |
524 | 0 | } |
525 | | |
526 | | |
527 | 0 | if (od_tk->Media->handler->handlerType != GF_ISOM_MEDIA_OD) continue; |
528 | | |
529 | 0 | for (j=0; j<od_tk->Media->information->sampleTable->SampleSize->sampleCount; j++) { |
530 | 0 | GF_ISOSample *samp = gf_isom_get_sample(file, i, j+1, &di); |
531 | 0 | the_od_id = Media_FindOD_ID(od_tk->Media, samp, tk->Header->trackID); |
532 | 0 | gf_isom_sample_del(&samp); |
533 | 0 | if (the_od_id) return the_od_id; |
534 | 0 | } |
535 | 0 | } |
536 | 0 | return 0; |
537 | 0 | } |
538 | | |
539 | | #endif /*GPAC_DISABLE_ISOM*/ |