~bratsche/vlc/vlc-notify-add-actions-with-server-support

« back to all changes in this revision

Viewing changes to extras/faad2/common/mp4ff/mp4tagupdate.c

  • Committer: Bazaar Package Importer
  • Date: 2008-11-28 09:29:51 UTC
  • Revision ID: jamesw@ubuntu.com-20081128092951-0y5ojboptscru17f
Tags: upstream-ubuntu-0.8.6.release.e+x264svn20071224+faad2.6.1
ImportĀ upstreamĀ versionĀ 0.8.6.release.e+x264svn20071224+faad2.6.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <stdlib.h>
2
 
#include <string.h>
3
 
#include "mp4ffint.h"
4
 
 
5
 
#ifdef USE_TAGGING
6
 
 
7
 
static uint32_t fix_byte_order_32(uint32_t src)
8
 
{
9
 
    uint32_t result;
10
 
    uint32_t a, b, c, d;
11
 
    int8_t data[4];
12
 
    
13
 
    memcpy(data,&src,sizeof(src));
14
 
    a = (uint8_t)data[0];
15
 
    b = (uint8_t)data[1];
16
 
    c = (uint8_t)data[2];
17
 
    d = (uint8_t)data[3];
18
 
 
19
 
    result = (a<<24) | (b<<16) | (c<<8) | d;
20
 
    return (uint32_t)result;
21
 
}
22
 
 
23
 
static uint16_t fix_byte_order_16(uint16_t src)
24
 
{
25
 
    uint16_t result;
26
 
    uint16_t a, b;
27
 
    int8_t data[2];
28
 
    
29
 
    memcpy(data,&src,sizeof(src));
30
 
    a = (uint8_t)data[0];
31
 
    b = (uint8_t)data[1];
32
 
 
33
 
    result = (a<<8) | b;
34
 
    return (uint16_t)result;
35
 
}
36
 
 
37
 
 
38
 
typedef struct
39
 
{
40
 
        void * data;
41
 
        unsigned written;
42
 
        unsigned allocated;
43
 
        unsigned error;
44
 
} membuffer;
45
 
 
46
 
unsigned membuffer_write(membuffer * buf,const void * ptr,unsigned bytes)
47
 
{
48
 
        unsigned dest_size = buf->written + bytes;
49
 
 
50
 
        if (buf->error) return 0;
51
 
        if (dest_size > buf->allocated)
52
 
        {
53
 
                do
54
 
                {
55
 
                        buf->allocated <<= 1;
56
 
                } while(dest_size > buf->allocated);
57
 
                
58
 
                {
59
 
                        void * newptr = realloc(buf->data,buf->allocated);
60
 
                        if (newptr==0)
61
 
                        {
62
 
                                free(buf->data);
63
 
                                buf->data = 0;
64
 
                                buf->error = 1;
65
 
                                return 0;
66
 
                        }
67
 
                        buf->data = newptr;
68
 
                }
69
 
        }
70
 
 
71
 
        if (ptr) memcpy((char*)buf->data + buf->written,ptr,bytes);
72
 
        buf->written += bytes;
73
 
        return bytes;
74
 
}
75
 
 
76
 
#define membuffer_write_data membuffer_write
77
 
 
78
 
unsigned membuffer_write_int32(membuffer * buf,uint32_t data)
79
 
{
80
 
        uint8_t temp[4] = {(uint8_t)(data>>24),(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};   
81
 
        return membuffer_write_data(buf,temp,4);
82
 
}
83
 
 
84
 
unsigned membuffer_write_int24(membuffer * buf,uint32_t data)
85
 
{
86
 
        uint8_t temp[3] = {(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};
87
 
        return membuffer_write_data(buf,temp,3);
88
 
}
89
 
 
90
 
unsigned membuffer_write_int16(membuffer * buf,uint16_t data)
91
 
{
92
 
        uint8_t temp[2] = {(uint8_t)(data>>8),(uint8_t)data};
93
 
        return membuffer_write_data(buf,temp,2);
94
 
}
95
 
 
96
 
unsigned membuffer_write_atom_name(membuffer * buf,const char * data)
97
 
{
98
 
        return membuffer_write_data(buf,data,4)==4 ? 1 : 0;
99
 
}
100
 
 
101
 
void membuffer_write_atom(membuffer * buf,const char * name,unsigned size,const void * data)
102
 
{
103
 
        membuffer_write_int32(buf,size + 8);
104
 
        membuffer_write_atom_name(buf,name);
105
 
        membuffer_write_data(buf,data,size);
106
 
}
107
 
 
108
 
unsigned membuffer_write_string(membuffer * buf,const char * data)
109
 
{
110
 
        return membuffer_write_data(buf,data,strlen(data));
111
 
}
112
 
 
113
 
unsigned membuffer_write_int8(membuffer * buf,uint8_t data)
114
 
{
115
 
        return membuffer_write_data(buf,&data,1);
116
 
}
117
 
 
118
 
void * membuffer_get_ptr(const membuffer * buf)
119
 
{
120
 
        return buf->data;
121
 
}
122
 
 
123
 
unsigned membuffer_get_size(const membuffer * buf)
124
 
{
125
 
        return buf->written;
126
 
}
127
 
 
128
 
unsigned membuffer_error(const membuffer * buf)
129
 
{
130
 
        return buf->error;
131
 
}
132
 
 
133
 
void membuffer_set_error(membuffer * buf) {buf->error = 1;}
134
 
 
135
 
unsigned membuffer_transfer_from_file(membuffer * buf,mp4ff_t * src,unsigned bytes)
136
 
{
137
 
        unsigned oldsize;
138
 
        void * bufptr;
139
 
        
140
 
        oldsize = membuffer_get_size(buf);
141
 
        if (membuffer_write_data(buf,0,bytes) != bytes) return 0;
142
 
 
143
 
        bufptr = membuffer_get_ptr(buf);
144
 
        if (bufptr==0) return 0;
145
 
        
146
 
        if ((unsigned)mp4ff_read_data(src,(char*)bufptr + oldsize,bytes)!=bytes)
147
 
        {
148
 
                membuffer_set_error(buf);
149
 
                return 0;
150
 
        }
151
 
        
152
 
        return bytes;
153
 
}
154
 
 
155
 
 
156
 
membuffer * membuffer_create()
157
 
{
158
 
        const unsigned initial_size = 256;
159
 
 
160
 
        membuffer * buf = (membuffer *) malloc(sizeof(membuffer));
161
 
        buf->data = malloc(initial_size);
162
 
        buf->written = 0;
163
 
        buf->allocated = initial_size;
164
 
        buf->error = buf->data == 0 ? 1 : 0;
165
 
 
166
 
        return buf;
167
 
}
168
 
 
169
 
void membuffer_free(membuffer * buf)
170
 
{
171
 
        if (buf->data) free(buf->data);
172
 
        free(buf);
173
 
}
174
 
 
175
 
void * membuffer_detach(membuffer * buf)
176
 
{
177
 
        void * ret;
178
 
 
179
 
        if (buf->error) return 0;
180
 
 
181
 
        ret = realloc(buf->data,buf->written);
182
 
        
183
 
        if (ret == 0) free(buf->data);
184
 
 
185
 
        buf->data = 0;
186
 
        buf->error = 1;
187
 
        
188
 
        return ret;
189
 
}
190
 
 
191
 
#if 0
192
 
/* metadata tag structure */
193
 
typedef struct
194
 
{
195
 
    char *item;
196
 
    char *value;
197
 
} mp4ff_tag_t;
198
 
 
199
 
/* metadata list structure */
200
 
typedef struct
201
 
{
202
 
    mp4ff_tag_t *tags;
203
 
    uint32_t count;
204
 
} mp4ff_metadata_t;
205
 
#endif
206
 
 
207
 
typedef struct
208
 
{
209
 
        const char * atom;
210
 
        const char * name;      
211
 
} stdmeta_entry;
212
 
 
213
 
static stdmeta_entry stdmetas[] = 
214
 
{
215
 
        {"ļæ½nam","title"},
216
 
        {"ļæ½ART","artist"},
217
 
        {"ļæ½wrt","writer"},
218
 
        {"ļæ½alb","album"},
219
 
        {"ļæ½day","date"},
220
 
        {"ļæ½too","tool"},
221
 
        {"ļæ½cmt","comment"},
222
 
//      {"ļæ½gen","genre"},
223
 
        {"cpil","compilation"},
224
 
//      {"trkn","track"},
225
 
//      {"disk","disc"},
226
 
//      {"gnre","genre"},
227
 
        {"covr","cover"},
228
 
};
229
 
 
230
 
 
231
 
static const char* find_standard_meta(const char * name) //returns atom name if found, 0 if not
232
 
{
233
 
        unsigned n;
234
 
        for(n=0;n<sizeof(stdmetas)/sizeof(stdmetas[0]);n++)
235
 
        {
236
 
                if (!stricmp(name,stdmetas[n].name)) return stdmetas[n].atom;
237
 
        }
238
 
    return 0;
239
 
}
240
 
 
241
 
static void membuffer_write_track_tag(membuffer * buf,const char * name,uint32_t index,uint32_t total)
242
 
{
243
 
        membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
244
 
        membuffer_write_atom_name(buf,name);
245
 
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
246
 
        membuffer_write_atom_name(buf,"data");
247
 
        membuffer_write_int32(buf,0);//flags
248
 
        membuffer_write_int32(buf,0);//reserved
249
 
        membuffer_write_int16(buf,0);
250
 
        membuffer_write_int16(buf,(uint16_t)index);//track number
251
 
        membuffer_write_int16(buf,(uint16_t)total);//total tracks
252
 
        membuffer_write_int16(buf,0);
253
 
}
254
 
 
255
 
static void membuffer_write_int16_tag(membuffer * buf,const char * name,uint16_t value)
256
 
{
257
 
        membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
258
 
        membuffer_write_atom_name(buf,name);
259
 
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
260
 
        membuffer_write_atom_name(buf,"data");
261
 
        membuffer_write_int32(buf,0);//flags
262
 
        membuffer_write_int32(buf,0);//reserved
263
 
        membuffer_write_int16(buf,value);//value
264
 
}
265
 
 
266
 
static void membuffer_write_std_tag(membuffer * buf,const char * name,const char * value)
267
 
{
268
 
        membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value) );
269
 
        membuffer_write_atom_name(buf,name);
270
 
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
271
 
        membuffer_write_atom_name(buf,"data");
272
 
        membuffer_write_int32(buf,1);//flags
273
 
        membuffer_write_int32(buf,0);//reserved
274
 
        membuffer_write_data(buf,value,strlen(value));
275
 
}
276
 
 
277
 
static void membuffer_write_custom_tag(membuffer * buf,const char * name,const char * value)
278
 
{
279
 
        membuffer_write_int32(buf,8 /*atom header*/ + 0x1C /*weirdo itunes atom*/ + 12 /*name atom header*/ + strlen(name) + 16 /*data atom header + flags*/ + strlen(value) );
280
 
        membuffer_write_atom_name(buf,"----");
281
 
        membuffer_write_int32(buf,0x1C);//weirdo itunes atom
282
 
        membuffer_write_atom_name(buf,"mean");
283
 
        membuffer_write_int32(buf,0);
284
 
        membuffer_write_data(buf,"com.apple.iTunes",16);
285
 
        membuffer_write_int32(buf,12 + strlen(name));
286
 
        membuffer_write_atom_name(buf,"name");
287
 
        membuffer_write_int32(buf,0);
288
 
        membuffer_write_data(buf,name,strlen(name));
289
 
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
290
 
        membuffer_write_atom_name(buf,"data");
291
 
        membuffer_write_int32(buf,1);//flags
292
 
        membuffer_write_int32(buf,0);//reserved
293
 
        membuffer_write_data(buf,value,strlen(value));
294
 
 
295
 
}
296
 
 
297
 
static uint32_t myatoi(const char * param)
298
 
{
299
 
        return param ? atoi(param) : 0;
300
 
}
301
 
 
302
 
static uint32_t create_ilst(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
303
 
{
304
 
        membuffer * buf = membuffer_create();
305
 
        unsigned metaptr;
306
 
        char * mask = (char*)malloc(data->count);
307
 
        memset(mask,0,data->count);
308
 
 
309
 
        {
310
 
                const char * tracknumber_ptr = 0, * totaltracks_ptr = 0;
311
 
                const char * discnumber_ptr = 0, * totaldiscs_ptr = 0;
312
 
                const char * genre_ptr = 0, * tempo_ptr = 0;
313
 
                for(metaptr = 0; metaptr < data->count; metaptr++)
314
 
                {
315
 
                        mp4ff_tag_t * tag = &data->tags[metaptr];
316
 
                        if (!stricmp(tag->item,"tracknumber") || !stricmp(tag->item,"track"))
317
 
                        {
318
 
                                if (tracknumber_ptr==0) tracknumber_ptr = tag->value;
319
 
                                mask[metaptr] = 1;
320
 
                        }
321
 
                        else if (!stricmp(tag->item,"totaltracks"))
322
 
                        {
323
 
                                if (totaltracks_ptr==0) totaltracks_ptr = tag->value;
324
 
                                mask[metaptr] = 1;
325
 
                        }
326
 
                        else if (!stricmp(tag->item,"discnumber") || !stricmp(tag->item,"disc"))
327
 
                        {
328
 
                                if (discnumber_ptr==0) discnumber_ptr = tag->value;
329
 
                                mask[metaptr] = 1;
330
 
                        }
331
 
                        else if (!stricmp(tag->item,"totaldiscs"))
332
 
                        {
333
 
                                if (totaldiscs_ptr==0) totaldiscs_ptr = tag->value;
334
 
                                mask[metaptr] = 1;
335
 
                        }
336
 
                        else if (!stricmp(tag->item,"genre"))
337
 
                        {
338
 
                                if (genre_ptr==0) genre_ptr = tag->value;
339
 
                                mask[metaptr] = 1;
340
 
                        }
341
 
                        else if (!stricmp(tag->item,"tempo"))
342
 
                        {
343
 
                                if (tempo_ptr==0) tempo_ptr = tag->value;
344
 
                                mask[metaptr] = 1;
345
 
                        }
346
 
 
347
 
                }
348
 
 
349
 
                if (tracknumber_ptr) membuffer_write_track_tag(buf,"trkn",myatoi(tracknumber_ptr),myatoi(totaltracks_ptr));
350
 
                if (discnumber_ptr) membuffer_write_track_tag(buf,"disk",myatoi(discnumber_ptr),myatoi(totaldiscs_ptr));
351
 
                if (tempo_ptr) membuffer_write_int16_tag(buf,"tmpo",(uint16_t)myatoi(tempo_ptr));
352
 
 
353
 
                if (genre_ptr)
354
 
                {
355
 
                        uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
356
 
                        if (index==0)
357
 
                                membuffer_write_std_tag(buf,"ļæ½gen",genre_ptr);
358
 
                        else
359
 
                                membuffer_write_int16_tag(buf,"gnre",(uint16_t)index);
360
 
                }
361
 
        }
362
 
        
363
 
        for(metaptr = 0; metaptr < data->count; metaptr++)
364
 
        {
365
 
                if (!mask[metaptr])
366
 
                {
367
 
                        mp4ff_tag_t * tag = &data->tags[metaptr];
368
 
                        const char * std_meta_atom = find_standard_meta(tag->item);
369
 
                        if (std_meta_atom)
370
 
                        {
371
 
                                membuffer_write_std_tag(buf,std_meta_atom,tag->value);
372
 
                        }
373
 
                        else
374
 
                        {
375
 
                                membuffer_write_custom_tag(buf,tag->item,tag->value);
376
 
                        }
377
 
                }
378
 
        }
379
 
 
380
 
        free(mask);
381
 
 
382
 
        if (membuffer_error(buf))
383
 
        {
384
 
                membuffer_free(buf);
385
 
                return 0;
386
 
        }
387
 
 
388
 
        *out_size = membuffer_get_size(buf);
389
 
        *out_buffer = membuffer_detach(buf);
390
 
        membuffer_free(buf);
391
 
 
392
 
        return 1;
393
 
}
394
 
 
395
 
static uint32_t find_atom(mp4ff_t * f,uint64_t base,uint32_t size,const char * name)
396
 
{
397
 
        uint32_t remaining = size;
398
 
        uint64_t atom_offset = base;
399
 
        for(;;)
400
 
        {
401
 
                char atom_name[4];
402
 
                uint32_t atom_size;
403
 
 
404
 
                mp4ff_set_position(f,atom_offset);
405
 
                
406
 
                if (remaining < 8) break;
407
 
                atom_size = mp4ff_read_int32(f);
408
 
                if (atom_size > remaining || atom_size < 8) break;
409
 
                mp4ff_read_data(f,atom_name,4);
410
 
                
411
 
                if (!memcmp(atom_name,name,4))
412
 
                {
413
 
                        mp4ff_set_position(f,atom_offset);
414
 
                        return 1;
415
 
                }
416
 
                
417
 
                remaining -= atom_size;
418
 
                atom_offset += atom_size;
419
 
        }
420
 
        return 0;
421
 
}
422
 
 
423
 
static uint32_t find_atom_v2(mp4ff_t * f,uint64_t base,uint32_t size,const char * name,uint32_t extraheaders,const char * name_inside)
424
 
{
425
 
        uint64_t first_base = (uint64_t)(-1);
426
 
        while(find_atom(f,base,size,name))//try to find atom <name> with atom <name_inside> in it
427
 
        {
428
 
                uint64_t mybase = mp4ff_position(f);
429
 
                uint32_t mysize = mp4ff_read_int32(f);
430
 
 
431
 
                if (first_base == (uint64_t)(-1)) first_base = mybase;
432
 
 
433
 
                if (mysize < 8 + extraheaders) break;
434
 
 
435
 
                if (find_atom(f,mybase+(8+extraheaders),mysize-(8+extraheaders),name_inside))
436
 
                {
437
 
                        mp4ff_set_position(f,mybase);
438
 
                        return 2;
439
 
                }
440
 
                base += mysize;
441
 
                if (size<=mysize) {size=0;break;}
442
 
                size -= mysize;
443
 
        }
444
 
 
445
 
        if (first_base != (uint64_t)(-1))//wanted atom inside not found
446
 
        {
447
 
                mp4ff_set_position(f,first_base);
448
 
                return 1;
449
 
        }
450
 
        else return 0;  
451
 
}
452
 
 
453
 
static uint32_t create_meta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
454
 
{
455
 
        membuffer * buf;
456
 
        uint32_t ilst_size;
457
 
        void * ilst_buffer;
458
 
 
459
 
        if (!create_ilst(data,&ilst_buffer,&ilst_size)) return 0;
460
 
 
461
 
        buf = membuffer_create();
462
 
 
463
 
        membuffer_write_int32(buf,0);
464
 
        membuffer_write_atom(buf,"ilst",ilst_size,ilst_buffer);
465
 
        free(ilst_buffer);
466
 
 
467
 
        *out_size = membuffer_get_size(buf);
468
 
        *out_buffer = membuffer_detach(buf);
469
 
        membuffer_free(buf);
470
 
        return 1;
471
 
}
472
 
 
473
 
static uint32_t create_udta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
474
 
{
475
 
        membuffer * buf;
476
 
        uint32_t meta_size;
477
 
        void * meta_buffer;
478
 
 
479
 
        if (!create_meta(data,&meta_buffer,&meta_size)) return 0;
480
 
 
481
 
        buf = membuffer_create();
482
 
 
483
 
        membuffer_write_atom(buf,"meta",meta_size,meta_buffer);
484
 
 
485
 
        free(meta_buffer);
486
 
 
487
 
        *out_size = membuffer_get_size(buf);
488
 
        *out_buffer = membuffer_detach(buf);
489
 
        membuffer_free(buf);
490
 
        return 1;
491
 
}
492
 
 
493
 
static uint32_t modify_moov(mp4ff_t * f,const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
494
 
{
495
 
        uint64_t total_base = f->moov_offset + 8;
496
 
        uint32_t total_size = (uint32_t)(f->moov_size - 8);
497
 
 
498
 
        uint64_t udta_offset,meta_offset,ilst_offset;
499
 
        uint32_t udta_size,  meta_size,  ilst_size;
500
 
        
501
 
        uint32_t new_ilst_size;
502
 
        void * new_ilst_buffer;
503
 
        
504
 
        uint8_t * p_out;
505
 
        int32_t size_delta;
506
 
        
507
 
        
508
 
        if (!find_atom_v2(f,total_base,total_size,"udta",0,"meta"))
509
 
        {
510
 
                membuffer * buf;
511
 
                void * new_udta_buffer;
512
 
                uint32_t new_udta_size;
513
 
                if (!create_udta(data,&new_udta_buffer,&new_udta_size)) return 0;
514
 
                
515
 
                buf = membuffer_create();
516
 
                mp4ff_set_position(f,total_base);
517
 
                membuffer_transfer_from_file(buf,f,total_size);
518
 
                
519
 
                membuffer_write_atom(buf,"udta",new_udta_size,new_udta_buffer);
520
 
 
521
 
                free(new_udta_buffer);
522
 
        
523
 
                *out_size = membuffer_get_size(buf);
524
 
                *out_buffer = membuffer_detach(buf);
525
 
                membuffer_free(buf);
526
 
                return 1;               
527
 
        }
528
 
        else
529
 
        {
530
 
                udta_offset = mp4ff_position(f);
531
 
                udta_size = mp4ff_read_int32(f);
532
 
                if (!find_atom_v2(f,udta_offset+8,udta_size-8,"meta",4,"ilst"))
533
 
                {
534
 
                        membuffer * buf;
535
 
                        void * new_meta_buffer;
536
 
                        uint32_t new_meta_size;
537
 
                        if (!create_meta(data,&new_meta_buffer,&new_meta_size)) return 0;
538
 
                        
539
 
                        buf = membuffer_create();
540
 
                        mp4ff_set_position(f,total_base);
541
 
                        membuffer_transfer_from_file(buf,f,(uint32_t)(udta_offset - total_base));
542
 
                        
543
 
                        membuffer_write_int32(buf,udta_size + 8 + new_meta_size);
544
 
                        membuffer_write_atom_name(buf,"udta");
545
 
                        membuffer_transfer_from_file(buf,f,udta_size);
546
 
                                                
547
 
                        membuffer_write_atom(buf,"meta",new_meta_size,new_meta_buffer);
548
 
                        free(new_meta_buffer);
549
 
                
550
 
                        *out_size = membuffer_get_size(buf);
551
 
                        *out_buffer = membuffer_detach(buf);
552
 
                        membuffer_free(buf);
553
 
                        return 1;               
554
 
                }
555
 
                meta_offset = mp4ff_position(f);
556
 
                meta_size = mp4ff_read_int32(f);
557
 
                if (!find_atom(f,meta_offset+12,meta_size-12,"ilst")) return 0;//shouldn't happen, find_atom_v2 above takes care of it
558
 
                ilst_offset = mp4ff_position(f);
559
 
                ilst_size = mp4ff_read_int32(f);
560
 
 
561
 
                if (!create_ilst(data,&new_ilst_buffer,&new_ilst_size)) return 0;
562
 
                
563
 
                size_delta = new_ilst_size - (ilst_size - 8);
564
 
 
565
 
                *out_size = total_size + size_delta;
566
 
                *out_buffer = malloc(*out_size);
567
 
                if (*out_buffer == 0)
568
 
                {
569
 
                        free(new_ilst_buffer);
570
 
                        return 0;
571
 
                }
572
 
 
573
 
                p_out = (uint8_t*)*out_buffer;
574
 
                
575
 
                mp4ff_set_position(f,total_base);
576
 
                mp4ff_read_data(f,p_out,(uint32_t)(udta_offset - total_base )); p_out += (uint32_t)(udta_offset - total_base );
577
 
                *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
578
 
                mp4ff_read_data(f,p_out,4); p_out += 4;
579
 
                mp4ff_read_data(f,p_out,(uint32_t)(meta_offset - udta_offset - 8)); p_out += (uint32_t)(meta_offset - udta_offset - 8);
580
 
                *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
581
 
                mp4ff_read_data(f,p_out,4); p_out += 4;
582
 
                mp4ff_read_data(f,p_out,(uint32_t)(ilst_offset - meta_offset - 8)); p_out += (uint32_t)(ilst_offset - meta_offset - 8);
583
 
                *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
584
 
                mp4ff_read_data(f,p_out,4); p_out += 4;
585
 
 
586
 
                memcpy(p_out,new_ilst_buffer,new_ilst_size);
587
 
                p_out += new_ilst_size;
588
 
 
589
 
                mp4ff_set_position(f,ilst_offset + ilst_size);
590
 
                mp4ff_read_data(f,p_out,(uint32_t)(total_size - (ilst_offset - total_base) - ilst_size));
591
 
 
592
 
                free(new_ilst_buffer);
593
 
        }
594
 
        return 1;
595
 
 
596
 
}
597
 
 
598
 
int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data)
599
 
{
600
 
        void * new_moov_data;
601
 
        uint32_t new_moov_size;
602
 
 
603
 
    mp4ff_t *ff = malloc(sizeof(mp4ff_t));
604
 
 
605
 
    memset(ff, 0, sizeof(mp4ff_t));
606
 
    ff->stream = f;
607
 
        mp4ff_set_position(ff,0);
608
 
 
609
 
    parse_atoms(ff,1);
610
 
 
611
 
 
612
 
        if (!modify_moov(ff,data,&new_moov_data,&new_moov_size))
613
 
        {
614
 
                mp4ff_close(ff);
615
 
                return 0;
616
 
        }
617
 
 
618
 
    /* copy moov atom to end of the file */
619
 
    if (ff->last_atom != ATOM_MOOV)
620
 
    {
621
 
        char *free_data = "free";
622
 
 
623
 
        /* rename old moov to free */
624
 
        mp4ff_set_position(ff, ff->moov_offset + 4);
625
 
        mp4ff_write_data(ff, free_data, 4);
626
 
        
627
 
        mp4ff_set_position(ff, ff->file_size);
628
 
                mp4ff_write_int32(ff,new_moov_size + 8);
629
 
                mp4ff_write_data(ff,"moov",4);
630
 
                mp4ff_write_data(ff, new_moov_data, new_moov_size);
631
 
    }
632
 
        else
633
 
        {
634
 
        mp4ff_set_position(ff, ff->moov_offset);
635
 
                mp4ff_write_int32(ff,new_moov_size + 8);
636
 
                mp4ff_write_data(ff,"moov",4);
637
 
                mp4ff_write_data(ff, new_moov_data, new_moov_size);
638
 
        }
639
 
 
640
 
        mp4ff_truncate(ff);
641
 
 
642
 
        mp4ff_close(ff);
643
 
    return 1;
644
 
}
645
 
#endif
 
1
#include <stdlib.h>
 
2
#include <string.h>
 
3
#include "mp4ffint.h"
 
4
 
 
5
#ifdef USE_TAGGING
 
6
 
 
7
static uint32_t fix_byte_order_32(uint32_t src)
 
8
{
 
9
    uint32_t result;
 
10
    uint32_t a, b, c, d;
 
11
    int8_t data[4];
 
12
    
 
13
    memcpy(data,&src,sizeof(src));
 
14
    a = (uint8_t)data[0];
 
15
    b = (uint8_t)data[1];
 
16
    c = (uint8_t)data[2];
 
17
    d = (uint8_t)data[3];
 
18
 
 
19
    result = (a<<24) | (b<<16) | (c<<8) | d;
 
20
    return (uint32_t)result;
 
21
}
 
22
 
 
23
static uint16_t fix_byte_order_16(uint16_t src)
 
24
{
 
25
    uint16_t result;
 
26
    uint16_t a, b;
 
27
    int8_t data[2];
 
28
    
 
29
    memcpy(data,&src,sizeof(src));
 
30
    a = (uint8_t)data[0];
 
31
    b = (uint8_t)data[1];
 
32
 
 
33
    result = (a<<8) | b;
 
34
    return (uint16_t)result;
 
35
}
 
36
 
 
37
 
 
38
typedef struct
 
39
{
 
40
        void * data;
 
41
        unsigned written;
 
42
        unsigned allocated;
 
43
        unsigned error;
 
44
} membuffer;
 
45
 
 
46
unsigned membuffer_write(membuffer * buf,const void * ptr,unsigned bytes)
 
47
{
 
48
        unsigned dest_size = buf->written + bytes;
 
49
 
 
50
        if (buf->error) return 0;
 
51
        if (dest_size > buf->allocated)
 
52
        {
 
53
                do
 
54
                {
 
55
                        buf->allocated <<= 1;
 
56
                } while(dest_size > buf->allocated);
 
57
                
 
58
                {
 
59
                        void * newptr = realloc(buf->data,buf->allocated);
 
60
                        if (newptr==0)
 
61
                        {
 
62
                                free(buf->data);
 
63
                                buf->data = 0;
 
64
                                buf->error = 1;
 
65
                                return 0;
 
66
                        }
 
67
                        buf->data = newptr;
 
68
                }
 
69
        }
 
70
 
 
71
        if (ptr) memcpy((char*)buf->data + buf->written,ptr,bytes);
 
72
        buf->written += bytes;
 
73
        return bytes;
 
74
}
 
75
 
 
76
#define membuffer_write_data membuffer_write
 
77
 
 
78
unsigned membuffer_write_int32(membuffer * buf,uint32_t data)
 
79
{
 
80
        uint8_t temp[4] = {(uint8_t)(data>>24),(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};   
 
81
        return membuffer_write_data(buf,temp,4);
 
82
}
 
83
 
 
84
unsigned membuffer_write_int24(membuffer * buf,uint32_t data)
 
85
{
 
86
        uint8_t temp[3] = {(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};
 
87
        return membuffer_write_data(buf,temp,3);
 
88
}
 
89
 
 
90
unsigned membuffer_write_int16(membuffer * buf,uint16_t data)
 
91
{
 
92
        uint8_t temp[2] = {(uint8_t)(data>>8),(uint8_t)data};
 
93
        return membuffer_write_data(buf,temp,2);
 
94
}
 
95
 
 
96
unsigned membuffer_write_atom_name(membuffer * buf,const char * data)
 
97
{
 
98
        return membuffer_write_data(buf,data,4)==4 ? 1 : 0;
 
99
}
 
100
 
 
101
void membuffer_write_atom(membuffer * buf,const char * name,unsigned size,const void * data)
 
102
{
 
103
        membuffer_write_int32(buf,size + 8);
 
104
        membuffer_write_atom_name(buf,name);
 
105
        membuffer_write_data(buf,data,size);
 
106
}
 
107
 
 
108
unsigned membuffer_write_string(membuffer * buf,const char * data)
 
109
{
 
110
        return membuffer_write_data(buf,data,strlen(data));
 
111
}
 
112
 
 
113
unsigned membuffer_write_int8(membuffer * buf,uint8_t data)
 
114
{
 
115
        return membuffer_write_data(buf,&data,1);
 
116
}
 
117
 
 
118
void * membuffer_get_ptr(const membuffer * buf)
 
119
{
 
120
        return buf->data;
 
121
}
 
122
 
 
123
unsigned membuffer_get_size(const membuffer * buf)
 
124
{
 
125
        return buf->written;
 
126
}
 
127
 
 
128
unsigned membuffer_error(const membuffer * buf)
 
129
{
 
130
        return buf->error;
 
131
}
 
132
 
 
133
void membuffer_set_error(membuffer * buf) {buf->error = 1;}
 
134
 
 
135
unsigned membuffer_transfer_from_file(membuffer * buf,mp4ff_t * src,unsigned bytes)
 
136
{
 
137
        unsigned oldsize;
 
138
        void * bufptr;
 
139
        
 
140
        oldsize = membuffer_get_size(buf);
 
141
        if (membuffer_write_data(buf,0,bytes) != bytes) return 0;
 
142
 
 
143
        bufptr = membuffer_get_ptr(buf);
 
144
        if (bufptr==0) return 0;
 
145
        
 
146
        if ((unsigned)mp4ff_read_data(src,(char*)bufptr + oldsize,bytes)!=bytes)
 
147
        {
 
148
                membuffer_set_error(buf);
 
149
                return 0;
 
150
        }
 
151
        
 
152
        return bytes;
 
153
}
 
154
 
 
155
 
 
156
membuffer * membuffer_create()
 
157
{
 
158
        const unsigned initial_size = 256;
 
159
 
 
160
        membuffer * buf = (membuffer *) malloc(sizeof(membuffer));
 
161
        buf->data = malloc(initial_size);
 
162
        buf->written = 0;
 
163
        buf->allocated = initial_size;
 
164
        buf->error = buf->data == 0 ? 1 : 0;
 
165
 
 
166
        return buf;
 
167
}
 
168
 
 
169
void membuffer_free(membuffer * buf)
 
170
{
 
171
        if (buf->data) free(buf->data);
 
172
        free(buf);
 
173
}
 
174
 
 
175
void * membuffer_detach(membuffer * buf)
 
176
{
 
177
        void * ret;
 
178
 
 
179
        if (buf->error) return 0;
 
180
 
 
181
        ret = realloc(buf->data,buf->written);
 
182
        
 
183
        if (ret == 0) free(buf->data);
 
184
 
 
185
        buf->data = 0;
 
186
        buf->error = 1;
 
187
        
 
188
        return ret;
 
189
}
 
190
 
 
191
#if 0
 
192
/* metadata tag structure */
 
193
typedef struct
 
194
{
 
195
    char *item;
 
196
    char *value;
 
197
} mp4ff_tag_t;
 
198
 
 
199
/* metadata list structure */
 
200
typedef struct
 
201
{
 
202
    mp4ff_tag_t *tags;
 
203
    uint32_t count;
 
204
} mp4ff_metadata_t;
 
205
#endif
 
206
 
 
207
typedef struct
 
208
{
 
209
        const char * atom;
 
210
        const char * name;      
 
211
} stdmeta_entry;
 
212
 
 
213
static stdmeta_entry stdmetas[] = 
 
214
{
 
215
        {"ļæ½nam","title"},
 
216
        {"ļæ½ART","artist"},
 
217
        {"ļæ½wrt","writer"},
 
218
        {"ļæ½alb","album"},
 
219
        {"ļæ½day","date"},
 
220
        {"ļæ½too","tool"},
 
221
        {"ļæ½cmt","comment"},
 
222
//      {"ļæ½gen","genre"},
 
223
        {"cpil","compilation"},
 
224
//      {"trkn","track"},
 
225
//      {"disk","disc"},
 
226
//      {"gnre","genre"},
 
227
        {"covr","cover"},
 
228
};
 
229
 
 
230
 
 
231
static const char* find_standard_meta(const char * name) //returns atom name if found, 0 if not
 
232
{
 
233
        unsigned n;
 
234
        for(n=0;n<sizeof(stdmetas)/sizeof(stdmetas[0]);n++)
 
235
        {
 
236
                if (!stricmp(name,stdmetas[n].name)) return stdmetas[n].atom;
 
237
        }
 
238
    return 0;
 
239
}
 
240
 
 
241
static void membuffer_write_track_tag(membuffer * buf,const char * name,uint32_t index,uint32_t total)
 
242
{
 
243
        membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
 
244
        membuffer_write_atom_name(buf,name);
 
245
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
 
246
        membuffer_write_atom_name(buf,"data");
 
247
        membuffer_write_int32(buf,0);//flags
 
248
        membuffer_write_int32(buf,0);//reserved
 
249
        membuffer_write_int16(buf,0);
 
250
        membuffer_write_int16(buf,(uint16_t)index);//track number
 
251
        membuffer_write_int16(buf,(uint16_t)total);//total tracks
 
252
        membuffer_write_int16(buf,0);
 
253
}
 
254
 
 
255
static void membuffer_write_int16_tag(membuffer * buf,const char * name,uint16_t value)
 
256
{
 
257
        membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
 
258
        membuffer_write_atom_name(buf,name);
 
259
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
 
260
        membuffer_write_atom_name(buf,"data");
 
261
        membuffer_write_int32(buf,0);//flags
 
262
        membuffer_write_int32(buf,0);//reserved
 
263
        membuffer_write_int16(buf,value);//value
 
264
}
 
265
 
 
266
static void membuffer_write_std_tag(membuffer * buf,const char * name,const char * value)
 
267
{
 
268
        membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value) );
 
269
        membuffer_write_atom_name(buf,name);
 
270
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
 
271
        membuffer_write_atom_name(buf,"data");
 
272
        membuffer_write_int32(buf,1);//flags
 
273
        membuffer_write_int32(buf,0);//reserved
 
274
        membuffer_write_data(buf,value,strlen(value));
 
275
}
 
276
 
 
277
static void membuffer_write_custom_tag(membuffer * buf,const char * name,const char * value)
 
278
{
 
279
        membuffer_write_int32(buf,8 /*atom header*/ + 0x1C /*weirdo itunes atom*/ + 12 /*name atom header*/ + strlen(name) + 16 /*data atom header + flags*/ + strlen(value) );
 
280
        membuffer_write_atom_name(buf,"----");
 
281
        membuffer_write_int32(buf,0x1C);//weirdo itunes atom
 
282
        membuffer_write_atom_name(buf,"mean");
 
283
        membuffer_write_int32(buf,0);
 
284
        membuffer_write_data(buf,"com.apple.iTunes",16);
 
285
        membuffer_write_int32(buf,12 + strlen(name));
 
286
        membuffer_write_atom_name(buf,"name");
 
287
        membuffer_write_int32(buf,0);
 
288
        membuffer_write_data(buf,name,strlen(name));
 
289
        membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
 
290
        membuffer_write_atom_name(buf,"data");
 
291
        membuffer_write_int32(buf,1);//flags
 
292
        membuffer_write_int32(buf,0);//reserved
 
293
        membuffer_write_data(buf,value,strlen(value));
 
294
 
 
295
}
 
296
 
 
297
static uint32_t myatoi(const char * param)
 
298
{
 
299
        return param ? atoi(param) : 0;
 
300
}
 
301
 
 
302
static uint32_t create_ilst(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
 
303
{
 
304
        membuffer * buf = membuffer_create();
 
305
        unsigned metaptr;
 
306
        char * mask = (char*)malloc(data->count);
 
307
        memset(mask,0,data->count);
 
308
 
 
309
        {
 
310
                const char * tracknumber_ptr = 0, * totaltracks_ptr = 0;
 
311
                const char * discnumber_ptr = 0, * totaldiscs_ptr = 0;
 
312
                const char * genre_ptr = 0, * tempo_ptr = 0;
 
313
                for(metaptr = 0; metaptr < data->count; metaptr++)
 
314
                {
 
315
                        mp4ff_tag_t * tag = &data->tags[metaptr];
 
316
                        if (!stricmp(tag->item,"tracknumber") || !stricmp(tag->item,"track"))
 
317
                        {
 
318
                                if (tracknumber_ptr==0) tracknumber_ptr = tag->value;
 
319
                                mask[metaptr] = 1;
 
320
                        }
 
321
                        else if (!stricmp(tag->item,"totaltracks"))
 
322
                        {
 
323
                                if (totaltracks_ptr==0) totaltracks_ptr = tag->value;
 
324
                                mask[metaptr] = 1;
 
325
                        }
 
326
                        else if (!stricmp(tag->item,"discnumber") || !stricmp(tag->item,"disc"))
 
327
                        {
 
328
                                if (discnumber_ptr==0) discnumber_ptr = tag->value;
 
329
                                mask[metaptr] = 1;
 
330
                        }
 
331
                        else if (!stricmp(tag->item,"totaldiscs"))
 
332
                        {
 
333
                                if (totaldiscs_ptr==0) totaldiscs_ptr = tag->value;
 
334
                                mask[metaptr] = 1;
 
335
                        }
 
336
                        else if (!stricmp(tag->item,"genre"))
 
337
                        {
 
338
                                if (genre_ptr==0) genre_ptr = tag->value;
 
339
                                mask[metaptr] = 1;
 
340
                        }
 
341
                        else if (!stricmp(tag->item,"tempo"))
 
342
                        {
 
343
                                if (tempo_ptr==0) tempo_ptr = tag->value;
 
344
                                mask[metaptr] = 1;
 
345
                        }
 
346
 
 
347
                }
 
348
 
 
349
                if (tracknumber_ptr) membuffer_write_track_tag(buf,"trkn",myatoi(tracknumber_ptr),myatoi(totaltracks_ptr));
 
350
                if (discnumber_ptr) membuffer_write_track_tag(buf,"disk",myatoi(discnumber_ptr),myatoi(totaldiscs_ptr));
 
351
                if (tempo_ptr) membuffer_write_int16_tag(buf,"tmpo",(uint16_t)myatoi(tempo_ptr));
 
352
 
 
353
                if (genre_ptr)
 
354
                {
 
355
                        uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
 
356
                        if (index==0)
 
357
                                membuffer_write_std_tag(buf,"ļæ½gen",genre_ptr);
 
358
                        else
 
359
                                membuffer_write_int16_tag(buf,"gnre",(uint16_t)index);
 
360
                }
 
361
        }
 
362
        
 
363
        for(metaptr = 0; metaptr < data->count; metaptr++)
 
364
        {
 
365
                if (!mask[metaptr])
 
366
                {
 
367
                        mp4ff_tag_t * tag = &data->tags[metaptr];
 
368
                        const char * std_meta_atom = find_standard_meta(tag->item);
 
369
                        if (std_meta_atom)
 
370
                        {
 
371
                                membuffer_write_std_tag(buf,std_meta_atom,tag->value);
 
372
                        }
 
373
                        else
 
374
                        {
 
375
                                membuffer_write_custom_tag(buf,tag->item,tag->value);
 
376
                        }
 
377
                }
 
378
        }
 
379
 
 
380
        free(mask);
 
381
 
 
382
        if (membuffer_error(buf))
 
383
        {
 
384
                membuffer_free(buf);
 
385
                return 0;
 
386
        }
 
387
 
 
388
        *out_size = membuffer_get_size(buf);
 
389
        *out_buffer = membuffer_detach(buf);
 
390
        membuffer_free(buf);
 
391
 
 
392
        return 1;
 
393
}
 
394
 
 
395
static uint32_t find_atom(mp4ff_t * f,uint64_t base,uint32_t size,const char * name)
 
396
{
 
397
        uint32_t remaining = size;
 
398
        uint64_t atom_offset = base;
 
399
        for(;;)
 
400
        {
 
401
                char atom_name[4];
 
402
                uint32_t atom_size;
 
403
 
 
404
                mp4ff_set_position(f,atom_offset);
 
405
                
 
406
                if (remaining < 8) break;
 
407
                atom_size = mp4ff_read_int32(f);
 
408
                if (atom_size > remaining || atom_size < 8) break;
 
409
                mp4ff_read_data(f,atom_name,4);
 
410
                
 
411
                if (!memcmp(atom_name,name,4))
 
412
                {
 
413
                        mp4ff_set_position(f,atom_offset);
 
414
                        return 1;
 
415
                }
 
416
                
 
417
                remaining -= atom_size;
 
418
                atom_offset += atom_size;
 
419
        }
 
420
        return 0;
 
421
}
 
422
 
 
423
static uint32_t find_atom_v2(mp4ff_t * f,uint64_t base,uint32_t size,const char * name,uint32_t extraheaders,const char * name_inside)
 
424
{
 
425
        uint64_t first_base = (uint64_t)(-1);
 
426
        while(find_atom(f,base,size,name))//try to find atom <name> with atom <name_inside> in it
 
427
        {
 
428
                uint64_t mybase = mp4ff_position(f);
 
429
                uint32_t mysize = mp4ff_read_int32(f);
 
430
 
 
431
                if (first_base == (uint64_t)(-1)) first_base = mybase;
 
432
 
 
433
                if (mysize < 8 + extraheaders) break;
 
434
 
 
435
                if (find_atom(f,mybase+(8+extraheaders),mysize-(8+extraheaders),name_inside))
 
436
                {
 
437
                        mp4ff_set_position(f,mybase);
 
438
                        return 2;
 
439
                }
 
440
                base += mysize;
 
441
                if (size<=mysize) {size=0;break;}
 
442
                size -= mysize;
 
443
        }
 
444
 
 
445
        if (first_base != (uint64_t)(-1))//wanted atom inside not found
 
446
        {
 
447
                mp4ff_set_position(f,first_base);
 
448
                return 1;
 
449
        }
 
450
        else return 0;  
 
451
}
 
452
 
 
453
static uint32_t create_meta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
 
454
{
 
455
        membuffer * buf;
 
456
        uint32_t ilst_size;
 
457
        void * ilst_buffer;
 
458
 
 
459
        if (!create_ilst(data,&ilst_buffer,&ilst_size)) return 0;
 
460
 
 
461
        buf = membuffer_create();
 
462
 
 
463
        membuffer_write_int32(buf,0);
 
464
        membuffer_write_atom(buf,"ilst",ilst_size,ilst_buffer);
 
465
        free(ilst_buffer);
 
466
 
 
467
        *out_size = membuffer_get_size(buf);
 
468
        *out_buffer = membuffer_detach(buf);
 
469
        membuffer_free(buf);
 
470
        return 1;
 
471
}
 
472
 
 
473
static uint32_t create_udta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
 
474
{
 
475
        membuffer * buf;
 
476
        uint32_t meta_size;
 
477
        void * meta_buffer;
 
478
 
 
479
        if (!create_meta(data,&meta_buffer,&meta_size)) return 0;
 
480
 
 
481
        buf = membuffer_create();
 
482
 
 
483
        membuffer_write_atom(buf,"meta",meta_size,meta_buffer);
 
484
 
 
485
        free(meta_buffer);
 
486
 
 
487
        *out_size = membuffer_get_size(buf);
 
488
        *out_buffer = membuffer_detach(buf);
 
489
        membuffer_free(buf);
 
490
        return 1;
 
491
}
 
492
 
 
493
static uint32_t modify_moov(mp4ff_t * f,const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
 
494
{
 
495
        uint64_t total_base = f->moov_offset + 8;
 
496
        uint32_t total_size = (uint32_t)(f->moov_size - 8);
 
497
 
 
498
        uint64_t udta_offset,meta_offset,ilst_offset;
 
499
        uint32_t udta_size,  meta_size,  ilst_size;
 
500
        
 
501
        uint32_t new_ilst_size;
 
502
        void * new_ilst_buffer;
 
503
        
 
504
        uint8_t * p_out;
 
505
        int32_t size_delta;
 
506
        
 
507
        
 
508
        if (!find_atom_v2(f,total_base,total_size,"udta",0,"meta"))
 
509
        {
 
510
                membuffer * buf;
 
511
                void * new_udta_buffer;
 
512
                uint32_t new_udta_size;
 
513
                if (!create_udta(data,&new_udta_buffer,&new_udta_size)) return 0;
 
514
                
 
515
                buf = membuffer_create();
 
516
                mp4ff_set_position(f,total_base);
 
517
                membuffer_transfer_from_file(buf,f,total_size);
 
518
                
 
519
                membuffer_write_atom(buf,"udta",new_udta_size,new_udta_buffer);
 
520
 
 
521
                free(new_udta_buffer);
 
522
        
 
523
                *out_size = membuffer_get_size(buf);
 
524
                *out_buffer = membuffer_detach(buf);
 
525
                membuffer_free(buf);
 
526
                return 1;               
 
527
        }
 
528
        else
 
529
        {
 
530
                udta_offset = mp4ff_position(f);
 
531
                udta_size = mp4ff_read_int32(f);
 
532
                if (!find_atom_v2(f,udta_offset+8,udta_size-8,"meta",4,"ilst"))
 
533
                {
 
534
                        membuffer * buf;
 
535
                        void * new_meta_buffer;
 
536
                        uint32_t new_meta_size;
 
537
                        if (!create_meta(data,&new_meta_buffer,&new_meta_size)) return 0;
 
538
                        
 
539
                        buf = membuffer_create();
 
540
                        mp4ff_set_position(f,total_base);
 
541
                        membuffer_transfer_from_file(buf,f,(uint32_t)(udta_offset - total_base));
 
542
                        
 
543
                        membuffer_write_int32(buf,udta_size + 8 + new_meta_size);
 
544
                        membuffer_write_atom_name(buf,"udta");
 
545
                        membuffer_transfer_from_file(buf,f,udta_size);
 
546
                                                
 
547
                        membuffer_write_atom(buf,"meta",new_meta_size,new_meta_buffer);
 
548
                        free(new_meta_buffer);
 
549
                
 
550
                        *out_size = membuffer_get_size(buf);
 
551
                        *out_buffer = membuffer_detach(buf);
 
552
                        membuffer_free(buf);
 
553
                        return 1;               
 
554
                }
 
555
                meta_offset = mp4ff_position(f);
 
556
                meta_size = mp4ff_read_int32(f);
 
557
                if (!find_atom(f,meta_offset+12,meta_size-12,"ilst")) return 0;//shouldn't happen, find_atom_v2 above takes care of it
 
558
                ilst_offset = mp4ff_position(f);
 
559
                ilst_size = mp4ff_read_int32(f);
 
560
 
 
561
                if (!create_ilst(data,&new_ilst_buffer,&new_ilst_size)) return 0;
 
562
                
 
563
                size_delta = new_ilst_size - (ilst_size - 8);
 
564
 
 
565
                *out_size = total_size + size_delta;
 
566
                *out_buffer = malloc(*out_size);
 
567
                if (*out_buffer == 0)
 
568
                {
 
569
                        free(new_ilst_buffer);
 
570
                        return 0;
 
571
                }
 
572
 
 
573
                p_out = (uint8_t*)*out_buffer;
 
574
                
 
575
                mp4ff_set_position(f,total_base);
 
576
                mp4ff_read_data(f,p_out,(uint32_t)(udta_offset - total_base )); p_out += (uint32_t)(udta_offset - total_base );
 
577
                *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
 
578
                mp4ff_read_data(f,p_out,4); p_out += 4;
 
579
                mp4ff_read_data(f,p_out,(uint32_t)(meta_offset - udta_offset - 8)); p_out += (uint32_t)(meta_offset - udta_offset - 8);
 
580
                *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
 
581
                mp4ff_read_data(f,p_out,4); p_out += 4;
 
582
                mp4ff_read_data(f,p_out,(uint32_t)(ilst_offset - meta_offset - 8)); p_out += (uint32_t)(ilst_offset - meta_offset - 8);
 
583
                *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
 
584
                mp4ff_read_data(f,p_out,4); p_out += 4;
 
585
 
 
586
                memcpy(p_out,new_ilst_buffer,new_ilst_size);
 
587
                p_out += new_ilst_size;
 
588
 
 
589
                mp4ff_set_position(f,ilst_offset + ilst_size);
 
590
                mp4ff_read_data(f,p_out,(uint32_t)(total_size - (ilst_offset - total_base) - ilst_size));
 
591
 
 
592
                free(new_ilst_buffer);
 
593
        }
 
594
        return 1;
 
595
 
 
596
}
 
597
 
 
598
int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data)
 
599
{
 
600
        void * new_moov_data;
 
601
        uint32_t new_moov_size;
 
602
 
 
603
    mp4ff_t *ff = malloc(sizeof(mp4ff_t));
 
604
 
 
605
    memset(ff, 0, sizeof(mp4ff_t));
 
606
    ff->stream = f;
 
607
        mp4ff_set_position(ff,0);
 
608
 
 
609
    parse_atoms(ff,1);
 
610
 
 
611
 
 
612
        if (!modify_moov(ff,data,&new_moov_data,&new_moov_size))
 
613
        {
 
614
                mp4ff_close(ff);
 
615
                return 0;
 
616
        }
 
617
 
 
618
    /* copy moov atom to end of the file */
 
619
    if (ff->last_atom != ATOM_MOOV)
 
620
    {
 
621
        char *free_data = "free";
 
622
 
 
623
        /* rename old moov to free */
 
624
        mp4ff_set_position(ff, ff->moov_offset + 4);
 
625
        mp4ff_write_data(ff, free_data, 4);
 
626
        
 
627
        mp4ff_set_position(ff, ff->file_size);
 
628
                mp4ff_write_int32(ff,new_moov_size + 8);
 
629
                mp4ff_write_data(ff,"moov",4);
 
630
                mp4ff_write_data(ff, new_moov_data, new_moov_size);
 
631
    }
 
632
        else
 
633
        {
 
634
        mp4ff_set_position(ff, ff->moov_offset);
 
635
                mp4ff_write_int32(ff,new_moov_size + 8);
 
636
                mp4ff_write_data(ff,"moov",4);
 
637
                mp4ff_write_data(ff, new_moov_data, new_moov_size);
 
638
        }
 
639
 
 
640
        mp4ff_truncate(ff);
 
641
 
 
642
        mp4ff_close(ff);
 
643
    return 1;
 
644
}
 
645
#endif