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

« back to all changes in this revision

Viewing changes to extras/faad2/plugins/QCDMp4/QCDMp4Tag.cpp

  • 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 <mp4.h>
2
 
#include <faad.h>
3
 
#include "QCDTagsDLL.h"
4
 
 
5
 
 
6
 
//..............................................................................
7
 
// Global Variables
8
 
 
9
 
typedef struct tag
10
 
{
11
 
    char *item;
12
 
    char *value;
13
 
} tag;
14
 
 
15
 
typedef struct medialib_tags
16
 
{
17
 
    struct tag *tags;
18
 
    unsigned int count;
19
 
} medialib_tags;
20
 
 
21
 
int tag_add_field(medialib_tags *tags, const char *item, const char *value)
22
 
{
23
 
    void *backup = (void *)tags->tags;
24
 
 
25
 
    if (!item || (item && !*item) || !value) return 0;
26
 
 
27
 
    tags->tags = (struct tag *)realloc(tags->tags, (tags->count+1) * sizeof(tag));
28
 
    if (!tags->tags) {
29
 
        if (backup) free(backup);
30
 
        return 0;
31
 
    }
32
 
    else
33
 
    {
34
 
        int i_len = strlen(item);
35
 
        int v_len = strlen(value);
36
 
 
37
 
        tags->tags[tags->count].item = (char *)malloc(i_len+1);
38
 
        tags->tags[tags->count].value = (char *)malloc(v_len+1);
39
 
 
40
 
        if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
41
 
        {
42
 
            if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
43
 
            if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
44
 
            tags->tags[tags->count].item = NULL;
45
 
            tags->tags[tags->count].value = NULL;
46
 
            return 0;
47
 
        }
48
 
 
49
 
        memcpy(tags->tags[tags->count].item, item, i_len);
50
 
        memcpy(tags->tags[tags->count].value, value, v_len);
51
 
        tags->tags[tags->count].item[i_len] = '\0';
52
 
        tags->tags[tags->count].value[v_len] = '\0';
53
 
 
54
 
        tags->count++;
55
 
        return 1;
56
 
    }
57
 
}
58
 
 
59
 
int tag_set_field(medialib_tags *tags, const char *item, const char *value)
60
 
{
61
 
    unsigned int i;
62
 
 
63
 
    if (!item || (item && !*item) || !value) return 0;
64
 
 
65
 
    for (i = 0; i < tags->count; i++)
66
 
    {
67
 
        if (!stricmp(tags->tags[i].item, item))
68
 
        {
69
 
            void *backup = (void *)tags->tags[i].value;
70
 
            int v_len = strlen(value);
71
 
 
72
 
            tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
73
 
            if (!tags->tags[i].value)
74
 
            {
75
 
                if (backup) free(backup);
76
 
                return 0;
77
 
            }
78
 
 
79
 
            memcpy(tags->tags[i].value, value, v_len);
80
 
            tags->tags[i].value[v_len] = '\0';
81
 
 
82
 
            return 1;
83
 
        }
84
 
    }
85
 
 
86
 
    return tag_add_field(tags, item, value);
87
 
}
88
 
 
89
 
void tag_delete(medialib_tags *tags)
90
 
{
91
 
    unsigned int i;
92
 
 
93
 
    for (i = 0; i < tags->count; i++)
94
 
    {
95
 
        if (tags->tags[i].item) free(tags->tags[i].item);
96
 
        if (tags->tags[i].value) free(tags->tags[i].value);
97
 
    }
98
 
 
99
 
    if (tags->tags) free(tags->tags);
100
 
 
101
 
    tags->tags = NULL;
102
 
    tags->count = 0;
103
 
}
104
 
 
105
 
int ReadMP4Tag(MP4FileHandle file, medialib_tags *tags)
106
 
{
107
 
    unsigned __int32 valueSize;
108
 
    unsigned __int8 *pValue;
109
 
    char *pName;
110
 
    unsigned int i = 0;
111
 
 
112
 
    do {
113
 
        pName = 0;
114
 
        pValue = 0;
115
 
        valueSize = 0;
116
 
 
117
 
        MP4GetMetadataByIndex(file, i, (const char **)&pName, &pValue, &valueSize);
118
 
 
119
 
        if (valueSize > 0)
120
 
        {
121
 
            char *val = (char *)malloc(valueSize+1);
122
 
            if (!val) return 0;
123
 
            memcpy(val, pValue, valueSize);
124
 
            val[valueSize] = '\0';
125
 
 
126
 
            if (pName[0] == '\xa9')
127
 
            {
128
 
                if (memcmp(pName, "ļæ½nam", 4) == 0)
129
 
                {
130
 
                    tag_add_field(tags, "title", val);
131
 
                } else if (memcmp(pName, "ļæ½ART", 4) == 0) {
132
 
                    tag_add_field(tags, "artist", val);
133
 
                } else if (memcmp(pName, "ļæ½wrt", 4) == 0) {
134
 
                    tag_add_field(tags, "writer", val);
135
 
                } else if (memcmp(pName, "ļæ½alb", 4) == 0) {
136
 
                    tag_add_field(tags, "album", val);
137
 
                } else if (memcmp(pName, "ļæ½day", 4) == 0) {
138
 
                    tag_add_field(tags, "date", val);
139
 
                } else if (memcmp(pName, "ļæ½too", 4) == 0) {
140
 
                    tag_add_field(tags, "tool", val);
141
 
                } else if (memcmp(pName, "ļæ½cmt", 4) == 0) {
142
 
                    tag_add_field(tags, "comment", val);
143
 
                } else if (memcmp(pName, "ļæ½gen", 4) == 0) {
144
 
                    tag_add_field(tags, "genre", val);
145
 
                } else {
146
 
                    tag_add_field(tags, pName, val);
147
 
                }
148
 
            } else if (memcmp(pName, "gnre", 4) == 0) {
149
 
                char *t=0;
150
 
                if (MP4GetMetadataGenre(file, &t))
151
 
                {
152
 
                    tag_add_field(tags, "genre", t);
153
 
                }
154
 
            } else if (memcmp(pName, "trkn", 4) == 0) {
155
 
                unsigned __int16 trkn = 0, tot = 0;
156
 
                char t[200];
157
 
                if (MP4GetMetadataTrack(file, &trkn, &tot))
158
 
                {
159
 
                    if (tot > 0)
160
 
                        wsprintf(t, "%d/%d", trkn, tot);
161
 
                    else
162
 
                        wsprintf(t, "%d", trkn);
163
 
                    tag_add_field(tags, "tracknumber", t);
164
 
                }
165
 
            } else if (memcmp(pName, "disk", 4) == 0) {
166
 
                unsigned __int16 disk = 0, tot = 0;
167
 
                char t[200];
168
 
                if (MP4GetMetadataDisk(file, &disk, &tot))
169
 
                {
170
 
                    if (tot > 0)
171
 
                        wsprintf(t, "%d/%d", disk, tot);
172
 
                    else
173
 
                        wsprintf(t, "%d", disk);
174
 
                    tag_add_field(tags, "disc", t);
175
 
                }
176
 
            } else if (memcmp(pName, "cpil", 4) == 0) {
177
 
                unsigned __int8 cpil = 0;
178
 
                char t[200];
179
 
                if (MP4GetMetadataCompilation(file, &cpil))
180
 
                {
181
 
                    wsprintf(t, "%d", cpil);
182
 
                    tag_add_field(tags, "compilation", t);
183
 
                }
184
 
            } else if (memcmp(pName, "tmpo", 4) == 0) {
185
 
                unsigned __int16 tempo = 0;
186
 
                char t[200];
187
 
                if (MP4GetMetadataTempo(file, &tempo))
188
 
                {
189
 
                    wsprintf(t, "%d BPM", tempo);
190
 
                    tag_add_field(tags, "tempo", t);
191
 
                }
192
 
            } else if (memcmp(pName, "NDFL", 4) == 0) {
193
 
                /* Removed */
194
 
            } else {
195
 
                tag_add_field(tags, pName, val);
196
 
            }
197
 
 
198
 
            free(val);
199
 
        }
200
 
 
201
 
        i++;
202
 
    } while (valueSize > 0);
203
 
 
204
 
    return 1;
205
 
}
206
 
 
207
 
int mp4_set_metadata(MP4FileHandle file, const char *item, const char *val)
208
 
{
209
 
    if (!item || (item && !*item) || !val || (val && !*val)) return 0;
210
 
 
211
 
    if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
212
 
    {
213
 
        unsigned __int16 trkn, tot;
214
 
        int t1 = 0, t2 = 0;
215
 
        sscanf(val, "%d/%d", &t1, &t2);
216
 
        trkn = t1, tot = t2;
217
 
        if (!trkn) return 1;
218
 
        if (MP4SetMetadataTrack(file, trkn, tot)) return 1;
219
 
    }
220
 
    else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
221
 
    {
222
 
        unsigned __int16 disk, tot;
223
 
        int t1 = 0, t2 = 0;
224
 
        sscanf(val, "%d/%d", &t1, &t2);
225
 
        disk = t1, tot = t2;
226
 
        if (!disk) return 1;
227
 
        if (MP4SetMetadataDisk(file, disk, tot)) return 1;
228
 
    }
229
 
    else if (!stricmp(item, "compilation"))
230
 
    {
231
 
        unsigned __int8 cpil = atoi(val);
232
 
        if (!cpil) return 1;
233
 
        if (MP4SetMetadataCompilation(file, cpil)) return 1;
234
 
    }
235
 
    else if (!stricmp(item, "tempo"))
236
 
    {
237
 
        unsigned __int16 tempo = atoi(val);
238
 
        if (!tempo) return 1;
239
 
        if (MP4SetMetadataTempo(file, tempo)) return 1;
240
 
    }
241
 
    else if (!stricmp(item, "artist"))
242
 
    {
243
 
        if (MP4SetMetadataArtist(file, val)) return 1;
244
 
    }
245
 
    else if (!stricmp(item, "writer"))
246
 
    {
247
 
        if (MP4SetMetadataWriter(file, val)) return 1;
248
 
    }
249
 
    else if (!stricmp(item, "title"))
250
 
    {
251
 
        if (MP4SetMetadataName(file, val)) return 1;
252
 
    }
253
 
    else if (!stricmp(item, "album"))
254
 
    {
255
 
        if (MP4SetMetadataAlbum(file, val)) return 1;
256
 
    }
257
 
    else if (!stricmp(item, "date") || !stricmp(item, "year"))
258
 
    {
259
 
        if (MP4SetMetadataYear(file, val)) return 1;
260
 
    }
261
 
    else if (!stricmp(item, "comment"))
262
 
    {
263
 
        if (MP4SetMetadataComment(file, val)) return 1;
264
 
    }
265
 
    else if (!stricmp(item, "genre"))
266
 
    {
267
 
        if (MP4SetMetadataGenre(file, val)) return 1;
268
 
    }
269
 
    else if (!stricmp(item, "tool"))
270
 
    {
271
 
        if (MP4SetMetadataTool(file, val)) return 1;
272
 
    }
273
 
    else
274
 
    {
275
 
        if (MP4SetMetadataFreeForm(file, (char *)item, (u_int8_t *)val, (u_int32_t)strlen(val) + 1)) return 1;
276
 
    }
277
 
 
278
 
    return 0;
279
 
}
280
 
 
281
 
void WriteMP4Tag(MP4FileHandle file, const medialib_tags *tags)
282
 
{
283
 
    unsigned int i;
284
 
 
285
 
    for (i = 0; i < tags->count; i++)
286
 
    {
287
 
        const char *item = tags->tags[i].item;
288
 
        const char *value = tags->tags[i].value;
289
 
 
290
 
        if (value && *value)
291
 
        {
292
 
            mp4_set_metadata(file, item, value);
293
 
        }
294
 
    }
295
 
}
296
 
 
297
 
QCDModInitTag   ModInitTag;
298
 
 
299
 
medialib_tags tags;
300
 
 
301
 
BOOL uSetDlgItemText(void *tagHandle, int fieldId, const char *str);
302
 
UINT uGetDlgItemText(void *tagHandle, int fieldId, char *str, int max);
303
 
 
304
 
//------------------------------------------------------------------------------
305
 
 
306
 
PLUGIN_API QCDModInitTag* TAGEDITORDLL_ENTRY_POINT()
307
 
{       
308
 
        ModInitTag.size                 = sizeof(QCDModInitTag);
309
 
        ModInitTag.version              = PLUGIN_API_VERSION;
310
 
        ModInitTag.ShutDown             = ShutDown_Tag;
311
 
 
312
 
        ModInitTag.Read                 = Read_Tag;
313
 
        ModInitTag.Write                = Write_Tag;    // Leave null for operations that plugin does not support
314
 
        ModInitTag.Strip                = Strip_Tag;    // ie: if plugin only reads tags, leave Write and Strip null
315
 
 
316
 
        ModInitTag.description  = "MP4 Tags";
317
 
        ModInitTag.defaultexts  = "MP4:M4A";
318
 
 
319
 
        return &ModInitTag;
320
 
}
321
 
 
322
 
//-----------------------------------------------------------------------------
323
 
 
324
 
void ShutDown_Tag(int flags)
325
 
{
326
 
        // TODO:
327
 
        // prepare plugin to be unloaded. All allocations should be freed.
328
 
        // flags param is unused
329
 
        tag_delete(&tags);
330
 
}
331
 
 
332
 
//-----------------------------------------------------------------------------
333
 
 
334
 
bool Read_Tag(LPCSTR filename, void* tagHandle)
335
 
{
336
 
        // TODO:
337
 
        // read metadata from tag and set each field to tagHandle
338
 
        // only TAGFIELD_* are supported (see QCDModTagEditor.h)
339
 
 
340
 
        // example of how to set value to tagHandle
341
 
        // use SetFieldA for ASCII or MultiBytes strings.
342
 
        // use SetFieldW for UNICODE strings
343
 
        //
344
 
        //      ModInitTag.SetFieldW(tagHandle, TAGFIELD_COMPOSER, szwValue);
345
 
 
346
 
        // return true for successfull read, false for failure
347
 
 
348
 
        MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
349
 
        char *pVal, dummy1[1024];
350
 
        short dummy, dummy2;
351
 
        u_int32_t valueSize = 0;
352
 
 
353
 
#ifdef DEBUG_OUTPUT
354
 
        in_mp4_DebugOutput("mp4_tag_read");
355
 
#endif
356
 
 
357
 
        file = MP4Read(filename, 0);
358
 
 
359
 
        if (file == MP4_INVALID_FILE_HANDLE)
360
 
                return false;
361
 
 
362
 
        /* get Metadata */
363
 
 
364
 
        pVal = NULL;
365
 
        MP4GetMetadataName(file, &pVal);
366
 
        uSetDlgItemText(tagHandle, TAGFIELD_TITLE, pVal);
367
 
 
368
 
        pVal = NULL;
369
 
        MP4GetMetadataArtist(file, &pVal);
370
 
        uSetDlgItemText(tagHandle, TAGFIELD_ARTIST, pVal);
371
 
 
372
 
        pVal = NULL;
373
 
        MP4GetMetadataWriter(file, &pVal);
374
 
        uSetDlgItemText(tagHandle, TAGFIELD_COMPOSER, pVal);
375
 
 
376
 
        pVal = NULL;
377
 
        MP4GetMetadataComment(file, &pVal);
378
 
        uSetDlgItemText(tagHandle, TAGFIELD_COMMENT, pVal);
379
 
 
380
 
        pVal = NULL;
381
 
        MP4GetMetadataAlbum(file, &pVal);
382
 
        uSetDlgItemText(tagHandle, TAGFIELD_ALBUM, pVal);
383
 
 
384
 
        pVal = NULL;
385
 
        MP4GetMetadataGenre(file, &pVal);
386
 
        uSetDlgItemText(tagHandle, TAGFIELD_GENRE, pVal);
387
 
 
388
 
        //dummy = 0;
389
 
        //MP4GetMetadataTempo(file, &dummy);
390
 
        //if (dummy)
391
 
        //{
392
 
        //      wsprintf(dummy1, "%d", dummy);
393
 
        //      SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
394
 
        //}
395
 
 
396
 
        dummy = 0; dummy2 = 0;
397
 
        MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
398
 
        if (dummy)
399
 
        {
400
 
                wsprintf(dummy1, "%d", dummy);
401
 
                ModInitTag.SetFieldA(tagHandle, TAGFIELD_TRACK, dummy1);
402
 
        }
403
 
        //if (dumm2)
404
 
        //{
405
 
        //      wsprintf(dummy1, "%d", dummy2);
406
 
        //      SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
407
 
        //}
408
 
 
409
 
        //dummy = 0; dummy2 = 0;
410
 
        //MP4GetMetadataDisk(file, &dummy, &dummy2);
411
 
        //if (dummy)
412
 
        //{
413
 
        //      wsprintf(dummy1, "%d", dummy);
414
 
        //      SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
415
 
        //}
416
 
        //if (dummy)
417
 
        //{
418
 
        //      wsprintf(dummy1, "%d", dummy2);
419
 
        //      SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
420
 
        //}
421
 
 
422
 
        pVal = NULL;
423
 
        if (MP4GetMetadataYear(file, &pVal))
424
 
                uSetDlgItemText(tagHandle, TAGFIELD_YEAR, pVal);
425
 
 
426
 
        //dummy3 = 0;
427
 
        //MP4GetMetadataCompilation(file, &dummy3);
428
 
        //if (dummy3)
429
 
        //      SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_SETCHECK, BST_CHECKED, 0);
430
 
 
431
 
        pVal = NULL;
432
 
        MP4GetMetadataTool(file, &pVal);
433
 
        uSetDlgItemText(tagHandle, TAGFIELD_ENCODER, pVal);
434
 
 
435
 
        pVal = NULL;
436
 
        MP4GetMetadataFreeForm(file, "CONDUCTOR", (unsigned __int8**)&pVal, &valueSize);
437
 
        uSetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, pVal);
438
 
 
439
 
        pVal = NULL;
440
 
        MP4GetMetadataFreeForm(file, "ORCHESTRA", (unsigned __int8**)&pVal, &valueSize);
441
 
        uSetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, pVal);
442
 
 
443
 
        pVal = NULL;
444
 
        MP4GetMetadataFreeForm(file, "YEARCOMPOSED", (unsigned __int8**)&pVal, &valueSize);
445
 
        uSetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, pVal);
446
 
 
447
 
        pVal = NULL;
448
 
        MP4GetMetadataFreeForm(file, "ORIGARTIST", (unsigned __int8**)&pVal, &valueSize);
449
 
        uSetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, pVal);
450
 
 
451
 
        pVal = NULL;
452
 
        MP4GetMetadataFreeForm(file, "LABEL", (unsigned __int8**)&pVal, &valueSize);
453
 
        uSetDlgItemText(tagHandle, TAGFIELD_LABEL, pVal);
454
 
 
455
 
        pVal = NULL;
456
 
        MP4GetMetadataFreeForm(file, "COPYRIGHT", (unsigned __int8**)&pVal, &valueSize);
457
 
        uSetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, pVal);
458
 
 
459
 
        pVal = NULL;
460
 
        MP4GetMetadataFreeForm(file, "CDDBTAGID", (unsigned __int8**)&pVal, &valueSize);
461
 
        uSetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, pVal);
462
 
 
463
 
        /* ! Metadata */
464
 
 
465
 
        MP4Close(file);
466
 
 
467
 
        return true;
468
 
}
469
 
 
470
 
//-----------------------------------------------------------------------------
471
 
 
472
 
bool Write_Tag(LPCSTR filename, void* tagHandle)
473
 
{
474
 
        // TODO:
475
 
        // read metadata from tagHandle and set each field to supported tag
476
 
        // only TAGFIELD_* are supported (see QCDModTagEditor.h)
477
 
 
478
 
        // example of how to get value from tagHandle
479
 
        // use SetFieldA for ASCII or MultiBytes strings.
480
 
        // use SetFieldW for UNICODE strings
481
 
        //
482
 
        // szwValue = ModInitTag.GetFieldW(tagHandle, TAGFIELD_ORCHESTRA);
483
 
 
484
 
        // write tag to file
485
 
 
486
 
        MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
487
 
    char dummy1[1024];
488
 
    char temp[1024];
489
 
    short dummy, dummy2;
490
 
 
491
 
#ifdef DEBUG_OUTPUT
492
 
    in_mp4_DebugOutput("mp4_tag_write");
493
 
#endif
494
 
 
495
 
        /* save Metadata changes */
496
 
 
497
 
        tag_delete(&tags);
498
 
        file = MP4Read(filename, 0);
499
 
        if (file != MP4_INVALID_FILE_HANDLE)
500
 
        {
501
 
                ReadMP4Tag(file, &tags);
502
 
                MP4Close(file);
503
 
 
504
 
                file = MP4Modify(filename, 0, 0);
505
 
                if (file != MP4_INVALID_FILE_HANDLE)
506
 
                {
507
 
                        MP4MetadataDelete(file);
508
 
                        MP4Close(file);
509
 
                }
510
 
        }
511
 
 
512
 
        file = MP4Modify(filename, 0, 0);
513
 
        if (file == MP4_INVALID_FILE_HANDLE)
514
 
        {
515
 
                tag_delete(&tags);
516
 
                //EndDialog(hwndDlg, wParam);
517
 
                return false;
518
 
        }
519
 
 
520
 
        uGetDlgItemText(tagHandle, TAGFIELD_TITLE, dummy1, 1024);
521
 
        tag_set_field(&tags, "title", dummy1);
522
 
 
523
 
        uGetDlgItemText(tagHandle, TAGFIELD_COMPOSER, dummy1, 1024);
524
 
        tag_set_field(&tags, "writer", dummy1);
525
 
 
526
 
        uGetDlgItemText(tagHandle, TAGFIELD_ARTIST, dummy1, 1024);
527
 
        tag_set_field(&tags, "artist", dummy1);
528
 
 
529
 
        uGetDlgItemText(tagHandle, TAGFIELD_ALBUM, dummy1, 1024);
530
 
        tag_set_field(&tags, "album", dummy1);
531
 
 
532
 
        uGetDlgItemText(tagHandle, TAGFIELD_COMMENT, dummy1, 1024);
533
 
        tag_set_field(&tags, "comment", dummy1);
534
 
 
535
 
        uGetDlgItemText(tagHandle, TAGFIELD_GENRE, dummy1, 1024);
536
 
        tag_set_field(&tags, "genre", dummy1);
537
 
 
538
 
        uGetDlgItemText(tagHandle, TAGFIELD_YEAR, dummy1, 1024);
539
 
        tag_set_field(&tags, "year", dummy1);
540
 
 
541
 
        dummy = 0;
542
 
        MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
543
 
        memcpy(dummy1, ModInitTag.GetFieldA(tagHandle, TAGFIELD_TRACK), sizeof(dummy1));
544
 
        dummy = atoi(dummy1);
545
 
        wsprintf(temp, "%d/%d", dummy, dummy2);
546
 
        tag_set_field(&tags, "track", temp);
547
 
 
548
 
        //GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
549
 
        //dummy = atoi(dummy1);
550
 
        //GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
551
 
        //dummy2 = atoi(dummy1);
552
 
        //wsprintf(temp, "%d/%d", dummy, dummy2);
553
 
        //tag_set_field(&tags, "disc", temp);
554
 
 
555
 
        //GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
556
 
        //tag_set_field(&tags, "tempo", dummy1);
557
 
 
558
 
        //dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
559
 
        //tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"));
560
 
 
561
 
        uGetDlgItemText(tagHandle, TAGFIELD_ENCODER, dummy1, 1024);
562
 
        tag_set_field(&tags, "tool", dummy1);
563
 
 
564
 
        uGetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, dummy1, 1024);
565
 
        tag_set_field(&tags, "CONDUCTOR", dummy1);
566
 
 
567
 
        uGetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, dummy1, 1024);
568
 
        tag_set_field(&tags, "ORCHESTRA", dummy1);
569
 
 
570
 
        uGetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, dummy1, 1024);
571
 
        tag_set_field(&tags, "YEARCOMPOSED", dummy1);
572
 
 
573
 
        uGetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, dummy1, 1024);
574
 
        tag_set_field(&tags, "ORIGARTIST", dummy1);
575
 
 
576
 
        uGetDlgItemText(tagHandle, TAGFIELD_LABEL, dummy1, 1024);
577
 
        tag_set_field(&tags, "LABEL", dummy1);
578
 
 
579
 
        uGetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, dummy1, 1024);
580
 
        tag_set_field(&tags, "COPYRIGHT", dummy1);
581
 
 
582
 
        uGetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, dummy1, 1024);
583
 
        tag_set_field(&tags, "CDDBTAGID", dummy1);
584
 
 
585
 
        WriteMP4Tag(file, &tags);
586
 
 
587
 
        MP4Close(file);
588
 
 
589
 
        MP4Optimize(filename, NULL, 0);
590
 
        /* ! */
591
 
 
592
 
        return true;
593
 
}
594
 
 
595
 
//-----------------------------------------------------------------------------
596
 
 
597
 
bool Strip_Tag(LPCSTR filename)
598
 
{
599
 
        // TODO:
600
 
        // remove tag from file.
601
 
        // do whatever is need to remove the supported tag from filename
602
 
 
603
 
        // return true for successfull strip, false for failure
604
 
 
605
 
        MP4FileHandle file;
606
 
 
607
 
        file = MP4Modify(filename, 0, 0);
608
 
        if (file == MP4_INVALID_FILE_HANDLE)
609
 
                return false;
610
 
        
611
 
        MP4MetadataDelete(file);
612
 
 
613
 
        MP4Close(file);
614
 
 
615
 
        return true;
616
 
}
617
 
 
618
 
//-----------------------------------------------------------------------------
619
 
 
620
 
/* Convert UNICODE to UTF-8
621
 
   Return number of bytes written */
622
 
int unicodeToUtf8 ( const WCHAR* lpWideCharStr, char* lpMultiByteStr, int cwcChars )
623
 
{
624
 
    const unsigned short*   pwc = (unsigned short *)lpWideCharStr;
625
 
    unsigned char*          pmb = (unsigned char  *)lpMultiByteStr;
626
 
    const unsigned short*   pwce;
627
 
    size_t  cBytes = 0;
628
 
 
629
 
    if ( cwcChars >= 0 ) {
630
 
        pwce = pwc + cwcChars;
631
 
    } else {
632
 
        pwce = (unsigned short *)((size_t)-1);
633
 
    }
634
 
 
635
 
    while ( pwc < pwce ) {
636
 
        unsigned short  wc = *pwc++;
637
 
 
638
 
        if ( wc < 0x00000080 ) {
639
 
            *pmb++ = (char)wc;
640
 
            cBytes++;
641
 
        } else
642
 
        if ( wc < 0x00000800 ) {
643
 
            *pmb++ = (char)(0xC0 | ((wc >>  6) & 0x1F));
644
 
            cBytes++;
645
 
            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
646
 
            cBytes++;
647
 
        } else
648
 
        if ( wc < 0x00010000 ) {
649
 
            *pmb++ = (char)(0xE0 | ((wc >> 12) & 0x0F));
650
 
            cBytes++;
651
 
            *pmb++ = (char)(0x80 | ((wc >>  6) & 0x3F));
652
 
            cBytes++;
653
 
            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
654
 
            cBytes++;
655
 
        }
656
 
        if ( wc == L'\0' )
657
 
            return cBytes;
658
 
    }
659
 
 
660
 
    return cBytes;
661
 
}
662
 
 
663
 
/* Convert UTF-8 coded string to UNICODE
664
 
   Return number of characters converted */
665
 
int utf8ToUnicode ( const char* lpMultiByteStr, WCHAR* lpWideCharStr, int cmbChars )
666
 
{
667
 
    const unsigned char*    pmb = (unsigned char  *)lpMultiByteStr;
668
 
    unsigned short*         pwc = (unsigned short *)lpWideCharStr;
669
 
    const unsigned char*    pmbe;
670
 
    size_t  cwChars = 0;
671
 
 
672
 
    if ( cmbChars >= 0 ) {
673
 
        pmbe = pmb + cmbChars;
674
 
    } else {
675
 
        pmbe = (unsigned char *)((size_t)-1);
676
 
    }
677
 
 
678
 
    while ( pmb < pmbe ) {
679
 
        char            mb = *pmb++;
680
 
        unsigned int    cc = 0;
681
 
        unsigned int    wc;
682
 
 
683
 
        while ( (cc < 7) && (mb & (1 << (7 - cc)))) {
684
 
            cc++;
685
 
        }
686
 
 
687
 
        if ( cc == 1 || cc > 6 )                    // illegal character combination for UTF-8
688
 
            continue;
689
 
 
690
 
        if ( cc == 0 ) {
691
 
            wc = mb;
692
 
        } else {
693
 
            wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6);
694
 
            while ( --cc > 0 ) {
695
 
                if ( pmb == pmbe )                  // reached end of the buffer
696
 
                    return cwChars;
697
 
                mb = *pmb++;
698
 
                if ( ((mb >> 6) & 0x03) != 2 )      // not part of multibyte character
699
 
                    return cwChars;
700
 
                wc |= (mb & 0x3F) << ((cc - 1) * 6);
701
 
            }
702
 
        }
703
 
 
704
 
        if ( wc & 0xFFFF0000 )
705
 
            wc = L'?';
706
 
        *pwc++ = wc;
707
 
        cwChars++;
708
 
        if ( wc == L'\0' )
709
 
            return cwChars;
710
 
    }
711
 
 
712
 
    return cwChars;
713
 
}
714
 
 
715
 
/* convert Windows ANSI to UTF-8 */
716
 
int ConvertANSIToUTF8 ( const char* ansi, char* utf8 )
717
 
{
718
 
    WCHAR*  wszValue;          // Unicode value
719
 
    size_t  ansi_len;
720
 
    size_t  len;
721
 
 
722
 
    *utf8 = '\0';
723
 
    if ( ansi == NULL )
724
 
        return 0;
725
 
 
726
 
    ansi_len = strlen ( ansi );
727
 
 
728
 
    if ( (wszValue = (WCHAR *)malloc ( (ansi_len + 1) * 2 )) == NULL )
729
 
        return 0;
730
 
 
731
 
    /* Convert ANSI value to Unicode */
732
 
    if ( (len = MultiByteToWideChar ( CP_ACP, 0, ansi, ansi_len + 1, wszValue, (ansi_len + 1) * 2 )) == 0 ) {
733
 
        free ( wszValue );
734
 
        return 0;
735
 
    }
736
 
 
737
 
    /* Convert Unicode value to UTF-8 */
738
 
    if ( (len = unicodeToUtf8 ( wszValue, utf8, -1 )) == 0 ) {
739
 
        free ( wszValue );
740
 
        return 0;
741
 
    }
742
 
 
743
 
    free ( wszValue );
744
 
 
745
 
    return len-1;
746
 
}
747
 
 
748
 
/* convert UTF-8 to Windows ANSI */
749
 
int ConvertUTF8ToANSI ( const char* utf8, char* ansi )
750
 
{
751
 
    WCHAR*  wszValue;          // Unicode value
752
 
    size_t  utf8_len;
753
 
    size_t  len;
754
 
 
755
 
    *ansi = '\0';
756
 
    if ( utf8 == NULL )
757
 
        return 0;
758
 
 
759
 
    utf8_len = strlen ( utf8 );
760
 
 
761
 
    if ( (wszValue = (WCHAR *)malloc ( (utf8_len + 1) * 2 )) == NULL )
762
 
        return 0;
763
 
 
764
 
    /* Convert UTF-8 value to Unicode */
765
 
    if ( (len = utf8ToUnicode ( utf8, wszValue, utf8_len + 1 )) == 0 ) {
766
 
        free ( wszValue );
767
 
        return 0;
768
 
    }
769
 
 
770
 
    /* Convert Unicode value to ANSI */
771
 
    if ( (len = WideCharToMultiByte ( CP_ACP, 0, wszValue, -1, ansi, (utf8_len + 1) * 2, NULL, NULL )) == 0 ) {
772
 
        free ( wszValue );
773
 
        return 0;
774
 
    }
775
 
 
776
 
    free ( wszValue );
777
 
 
778
 
    return len-1;
779
 
}
780
 
 
781
 
BOOL uSetDlgItemText(void *tagHandle, int fieldId, const char *str)
782
 
{
783
 
    char *temp;
784
 
    size_t len;
785
 
    int r;
786
 
 
787
 
    if (!str) return FALSE;
788
 
        if (!*str) return FALSE;
789
 
    len = strlen(str);
790
 
    temp = (char *)malloc(len+1);
791
 
    if (!temp) return FALSE;
792
 
        memset(temp, '\0', len+1);
793
 
    r = ConvertUTF8ToANSI(str, temp);
794
 
    if (r > 0)
795
 
        ModInitTag.SetFieldA(tagHandle, fieldId, temp);
796
 
    free(temp);
797
 
 
798
 
    return r>0 ? TRUE : FALSE;
799
 
}
800
 
 
801
 
UINT uGetDlgItemText(void *tagHandle, int fieldId, char *str, int max)
802
 
{
803
 
    char *temp, *utf8;;
804
 
    int len;
805
 
 
806
 
        const char *p;
807
 
 
808
 
    if (!str || !max) return 0;
809
 
    len = strlen( ModInitTag.GetFieldA(tagHandle, fieldId) );
810
 
    temp = (char *)malloc(len+1);
811
 
    if (!temp) return 0;
812
 
    utf8 = (char *)malloc((len+1)*4);
813
 
    if (!utf8)
814
 
    {
815
 
        free(temp);
816
 
        return 0;
817
 
    }
818
 
 
819
 
        memset(temp, '\0', len+1);
820
 
        memset(utf8, '\0', (len+1)*4);
821
 
        memset(str, '\0', max);
822
 
        p = ModInitTag.GetFieldA(tagHandle, fieldId);
823
 
        memcpy(temp, p, len+1);
824
 
    if (len > 0)
825
 
    {
826
 
        len = ConvertANSIToUTF8(temp, utf8);
827
 
        if (len > max-1)
828
 
        {
829
 
            len = max-1;
830
 
            utf8[max] = '\0';
831
 
        }
832
 
        memcpy(str, utf8, len+1);
833
 
    }
834
 
 
835
 
    free(temp);
836
 
    free(utf8);
837
 
 
838
 
    return len;
839
 
}
 
1
#include <mp4.h>
 
2
#include <faad.h>
 
3
#include "QCDTagsDLL.h"
 
4
 
 
5
 
 
6
//..............................................................................
 
7
// Global Variables
 
8
 
 
9
typedef struct tag
 
10
{
 
11
    char *item;
 
12
    char *value;
 
13
} tag;
 
14
 
 
15
typedef struct medialib_tags
 
16
{
 
17
    struct tag *tags;
 
18
    unsigned int count;
 
19
} medialib_tags;
 
20
 
 
21
int tag_add_field(medialib_tags *tags, const char *item, const char *value)
 
22
{
 
23
    void *backup = (void *)tags->tags;
 
24
 
 
25
    if (!item || (item && !*item) || !value) return 0;
 
26
 
 
27
    tags->tags = (struct tag *)realloc(tags->tags, (tags->count+1) * sizeof(tag));
 
28
    if (!tags->tags) {
 
29
        if (backup) free(backup);
 
30
        return 0;
 
31
    }
 
32
    else
 
33
    {
 
34
        int i_len = strlen(item);
 
35
        int v_len = strlen(value);
 
36
 
 
37
        tags->tags[tags->count].item = (char *)malloc(i_len+1);
 
38
        tags->tags[tags->count].value = (char *)malloc(v_len+1);
 
39
 
 
40
        if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
 
41
        {
 
42
            if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
 
43
            if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
 
44
            tags->tags[tags->count].item = NULL;
 
45
            tags->tags[tags->count].value = NULL;
 
46
            return 0;
 
47
        }
 
48
 
 
49
        memcpy(tags->tags[tags->count].item, item, i_len);
 
50
        memcpy(tags->tags[tags->count].value, value, v_len);
 
51
        tags->tags[tags->count].item[i_len] = '\0';
 
52
        tags->tags[tags->count].value[v_len] = '\0';
 
53
 
 
54
        tags->count++;
 
55
        return 1;
 
56
    }
 
57
}
 
58
 
 
59
int tag_set_field(medialib_tags *tags, const char *item, const char *value)
 
60
{
 
61
    unsigned int i;
 
62
 
 
63
    if (!item || (item && !*item) || !value) return 0;
 
64
 
 
65
    for (i = 0; i < tags->count; i++)
 
66
    {
 
67
        if (!stricmp(tags->tags[i].item, item))
 
68
        {
 
69
            void *backup = (void *)tags->tags[i].value;
 
70
            int v_len = strlen(value);
 
71
 
 
72
            tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
 
73
            if (!tags->tags[i].value)
 
74
            {
 
75
                if (backup) free(backup);
 
76
                return 0;
 
77
            }
 
78
 
 
79
            memcpy(tags->tags[i].value, value, v_len);
 
80
            tags->tags[i].value[v_len] = '\0';
 
81
 
 
82
            return 1;
 
83
        }
 
84
    }
 
85
 
 
86
    return tag_add_field(tags, item, value);
 
87
}
 
88
 
 
89
void tag_delete(medialib_tags *tags)
 
90
{
 
91
    unsigned int i;
 
92
 
 
93
    for (i = 0; i < tags->count; i++)
 
94
    {
 
95
        if (tags->tags[i].item) free(tags->tags[i].item);
 
96
        if (tags->tags[i].value) free(tags->tags[i].value);
 
97
    }
 
98
 
 
99
    if (tags->tags) free(tags->tags);
 
100
 
 
101
    tags->tags = NULL;
 
102
    tags->count = 0;
 
103
}
 
104
 
 
105
int ReadMP4Tag(MP4FileHandle file, medialib_tags *tags)
 
106
{
 
107
    unsigned __int32 valueSize;
 
108
    unsigned __int8 *pValue;
 
109
    char *pName;
 
110
    unsigned int i = 0;
 
111
 
 
112
    do {
 
113
        pName = 0;
 
114
        pValue = 0;
 
115
        valueSize = 0;
 
116
 
 
117
        MP4GetMetadataByIndex(file, i, (const char **)&pName, &pValue, &valueSize);
 
118
 
 
119
        if (valueSize > 0)
 
120
        {
 
121
            char *val = (char *)malloc(valueSize+1);
 
122
            if (!val) return 0;
 
123
            memcpy(val, pValue, valueSize);
 
124
            val[valueSize] = '\0';
 
125
 
 
126
            if (pName[0] == '\xa9')
 
127
            {
 
128
                if (memcmp(pName, "ļæ½nam", 4) == 0)
 
129
                {
 
130
                    tag_add_field(tags, "title", val);
 
131
                } else if (memcmp(pName, "ļæ½ART", 4) == 0) {
 
132
                    tag_add_field(tags, "artist", val);
 
133
                } else if (memcmp(pName, "ļæ½wrt", 4) == 0) {
 
134
                    tag_add_field(tags, "writer", val);
 
135
                } else if (memcmp(pName, "ļæ½alb", 4) == 0) {
 
136
                    tag_add_field(tags, "album", val);
 
137
                } else if (memcmp(pName, "ļæ½day", 4) == 0) {
 
138
                    tag_add_field(tags, "date", val);
 
139
                } else if (memcmp(pName, "ļæ½too", 4) == 0) {
 
140
                    tag_add_field(tags, "tool", val);
 
141
                } else if (memcmp(pName, "ļæ½cmt", 4) == 0) {
 
142
                    tag_add_field(tags, "comment", val);
 
143
                } else if (memcmp(pName, "ļæ½gen", 4) == 0) {
 
144
                    tag_add_field(tags, "genre", val);
 
145
                } else {
 
146
                    tag_add_field(tags, pName, val);
 
147
                }
 
148
            } else if (memcmp(pName, "gnre", 4) == 0) {
 
149
                char *t=0;
 
150
                if (MP4GetMetadataGenre(file, &t))
 
151
                {
 
152
                    tag_add_field(tags, "genre", t);
 
153
                }
 
154
            } else if (memcmp(pName, "trkn", 4) == 0) {
 
155
                unsigned __int16 trkn = 0, tot = 0;
 
156
                char t[200];
 
157
                if (MP4GetMetadataTrack(file, &trkn, &tot))
 
158
                {
 
159
                    if (tot > 0)
 
160
                        wsprintf(t, "%d/%d", trkn, tot);
 
161
                    else
 
162
                        wsprintf(t, "%d", trkn);
 
163
                    tag_add_field(tags, "tracknumber", t);
 
164
                }
 
165
            } else if (memcmp(pName, "disk", 4) == 0) {
 
166
                unsigned __int16 disk = 0, tot = 0;
 
167
                char t[200];
 
168
                if (MP4GetMetadataDisk(file, &disk, &tot))
 
169
                {
 
170
                    if (tot > 0)
 
171
                        wsprintf(t, "%d/%d", disk, tot);
 
172
                    else
 
173
                        wsprintf(t, "%d", disk);
 
174
                    tag_add_field(tags, "disc", t);
 
175
                }
 
176
            } else if (memcmp(pName, "cpil", 4) == 0) {
 
177
                unsigned __int8 cpil = 0;
 
178
                char t[200];
 
179
                if (MP4GetMetadataCompilation(file, &cpil))
 
180
                {
 
181
                    wsprintf(t, "%d", cpil);
 
182
                    tag_add_field(tags, "compilation", t);
 
183
                }
 
184
            } else if (memcmp(pName, "tmpo", 4) == 0) {
 
185
                unsigned __int16 tempo = 0;
 
186
                char t[200];
 
187
                if (MP4GetMetadataTempo(file, &tempo))
 
188
                {
 
189
                    wsprintf(t, "%d BPM", tempo);
 
190
                    tag_add_field(tags, "tempo", t);
 
191
                }
 
192
            } else if (memcmp(pName, "NDFL", 4) == 0) {
 
193
                /* Removed */
 
194
            } else {
 
195
                tag_add_field(tags, pName, val);
 
196
            }
 
197
 
 
198
            free(val);
 
199
        }
 
200
 
 
201
        i++;
 
202
    } while (valueSize > 0);
 
203
 
 
204
    return 1;
 
205
}
 
206
 
 
207
int mp4_set_metadata(MP4FileHandle file, const char *item, const char *val)
 
208
{
 
209
    if (!item || (item && !*item) || !val || (val && !*val)) return 0;
 
210
 
 
211
    if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
 
212
    {
 
213
        unsigned __int16 trkn, tot;
 
214
        int t1 = 0, t2 = 0;
 
215
        sscanf(val, "%d/%d", &t1, &t2);
 
216
        trkn = t1, tot = t2;
 
217
        if (!trkn) return 1;
 
218
        if (MP4SetMetadataTrack(file, trkn, tot)) return 1;
 
219
    }
 
220
    else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
 
221
    {
 
222
        unsigned __int16 disk, tot;
 
223
        int t1 = 0, t2 = 0;
 
224
        sscanf(val, "%d/%d", &t1, &t2);
 
225
        disk = t1, tot = t2;
 
226
        if (!disk) return 1;
 
227
        if (MP4SetMetadataDisk(file, disk, tot)) return 1;
 
228
    }
 
229
    else if (!stricmp(item, "compilation"))
 
230
    {
 
231
        unsigned __int8 cpil = atoi(val);
 
232
        if (!cpil) return 1;
 
233
        if (MP4SetMetadataCompilation(file, cpil)) return 1;
 
234
    }
 
235
    else if (!stricmp(item, "tempo"))
 
236
    {
 
237
        unsigned __int16 tempo = atoi(val);
 
238
        if (!tempo) return 1;
 
239
        if (MP4SetMetadataTempo(file, tempo)) return 1;
 
240
    }
 
241
    else if (!stricmp(item, "artist"))
 
242
    {
 
243
        if (MP4SetMetadataArtist(file, val)) return 1;
 
244
    }
 
245
    else if (!stricmp(item, "writer"))
 
246
    {
 
247
        if (MP4SetMetadataWriter(file, val)) return 1;
 
248
    }
 
249
    else if (!stricmp(item, "title"))
 
250
    {
 
251
        if (MP4SetMetadataName(file, val)) return 1;
 
252
    }
 
253
    else if (!stricmp(item, "album"))
 
254
    {
 
255
        if (MP4SetMetadataAlbum(file, val)) return 1;
 
256
    }
 
257
    else if (!stricmp(item, "date") || !stricmp(item, "year"))
 
258
    {
 
259
        if (MP4SetMetadataYear(file, val)) return 1;
 
260
    }
 
261
    else if (!stricmp(item, "comment"))
 
262
    {
 
263
        if (MP4SetMetadataComment(file, val)) return 1;
 
264
    }
 
265
    else if (!stricmp(item, "genre"))
 
266
    {
 
267
        if (MP4SetMetadataGenre(file, val)) return 1;
 
268
    }
 
269
    else if (!stricmp(item, "tool"))
 
270
    {
 
271
        if (MP4SetMetadataTool(file, val)) return 1;
 
272
    }
 
273
    else
 
274
    {
 
275
        if (MP4SetMetadataFreeForm(file, (char *)item, (u_int8_t *)val, (u_int32_t)strlen(val) + 1)) return 1;
 
276
    }
 
277
 
 
278
    return 0;
 
279
}
 
280
 
 
281
void WriteMP4Tag(MP4FileHandle file, const medialib_tags *tags)
 
282
{
 
283
    unsigned int i;
 
284
 
 
285
    for (i = 0; i < tags->count; i++)
 
286
    {
 
287
        const char *item = tags->tags[i].item;
 
288
        const char *value = tags->tags[i].value;
 
289
 
 
290
        if (value && *value)
 
291
        {
 
292
            mp4_set_metadata(file, item, value);
 
293
        }
 
294
    }
 
295
}
 
296
 
 
297
QCDModInitTag   ModInitTag;
 
298
 
 
299
medialib_tags tags;
 
300
 
 
301
BOOL uSetDlgItemText(void *tagHandle, int fieldId, const char *str);
 
302
UINT uGetDlgItemText(void *tagHandle, int fieldId, char *str, int max);
 
303
 
 
304
//------------------------------------------------------------------------------
 
305
 
 
306
PLUGIN_API QCDModInitTag* TAGEDITORDLL_ENTRY_POINT()
 
307
{       
 
308
        ModInitTag.size                 = sizeof(QCDModInitTag);
 
309
        ModInitTag.version              = PLUGIN_API_VERSION;
 
310
        ModInitTag.ShutDown             = ShutDown_Tag;
 
311
 
 
312
        ModInitTag.Read                 = Read_Tag;
 
313
        ModInitTag.Write                = Write_Tag;    // Leave null for operations that plugin does not support
 
314
        ModInitTag.Strip                = Strip_Tag;    // ie: if plugin only reads tags, leave Write and Strip null
 
315
 
 
316
        ModInitTag.description  = "MP4 Tags";
 
317
        ModInitTag.defaultexts  = "MP4:M4A";
 
318
 
 
319
        return &ModInitTag;
 
320
}
 
321
 
 
322
//-----------------------------------------------------------------------------
 
323
 
 
324
void ShutDown_Tag(int flags)
 
325
{
 
326
        // TODO:
 
327
        // prepare plugin to be unloaded. All allocations should be freed.
 
328
        // flags param is unused
 
329
        tag_delete(&tags);
 
330
}
 
331
 
 
332
//-----------------------------------------------------------------------------
 
333
 
 
334
bool Read_Tag(LPCSTR filename, void* tagHandle)
 
335
{
 
336
        // TODO:
 
337
        // read metadata from tag and set each field to tagHandle
 
338
        // only TAGFIELD_* are supported (see QCDModTagEditor.h)
 
339
 
 
340
        // example of how to set value to tagHandle
 
341
        // use SetFieldA for ASCII or MultiBytes strings.
 
342
        // use SetFieldW for UNICODE strings
 
343
        //
 
344
        //      ModInitTag.SetFieldW(tagHandle, TAGFIELD_COMPOSER, szwValue);
 
345
 
 
346
        // return true for successfull read, false for failure
 
347
 
 
348
        MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
 
349
        char *pVal, dummy1[1024];
 
350
        short dummy, dummy2;
 
351
        u_int32_t valueSize = 0;
 
352
 
 
353
#ifdef DEBUG_OUTPUT
 
354
        in_mp4_DebugOutput("mp4_tag_read");
 
355
#endif
 
356
 
 
357
        file = MP4Read(filename, 0);
 
358
 
 
359
        if (file == MP4_INVALID_FILE_HANDLE)
 
360
                return false;
 
361
 
 
362
        /* get Metadata */
 
363
 
 
364
        pVal = NULL;
 
365
        MP4GetMetadataName(file, &pVal);
 
366
        uSetDlgItemText(tagHandle, TAGFIELD_TITLE, pVal);
 
367
 
 
368
        pVal = NULL;
 
369
        MP4GetMetadataArtist(file, &pVal);
 
370
        uSetDlgItemText(tagHandle, TAGFIELD_ARTIST, pVal);
 
371
 
 
372
        pVal = NULL;
 
373
        MP4GetMetadataWriter(file, &pVal);
 
374
        uSetDlgItemText(tagHandle, TAGFIELD_COMPOSER, pVal);
 
375
 
 
376
        pVal = NULL;
 
377
        MP4GetMetadataComment(file, &pVal);
 
378
        uSetDlgItemText(tagHandle, TAGFIELD_COMMENT, pVal);
 
379
 
 
380
        pVal = NULL;
 
381
        MP4GetMetadataAlbum(file, &pVal);
 
382
        uSetDlgItemText(tagHandle, TAGFIELD_ALBUM, pVal);
 
383
 
 
384
        pVal = NULL;
 
385
        MP4GetMetadataGenre(file, &pVal);
 
386
        uSetDlgItemText(tagHandle, TAGFIELD_GENRE, pVal);
 
387
 
 
388
        //dummy = 0;
 
389
        //MP4GetMetadataTempo(file, &dummy);
 
390
        //if (dummy)
 
391
        //{
 
392
        //      wsprintf(dummy1, "%d", dummy);
 
393
        //      SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
 
394
        //}
 
395
 
 
396
        dummy = 0; dummy2 = 0;
 
397
        MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
 
398
        if (dummy)
 
399
        {
 
400
                wsprintf(dummy1, "%d", dummy);
 
401
                ModInitTag.SetFieldA(tagHandle, TAGFIELD_TRACK, dummy1);
 
402
        }
 
403
        //if (dumm2)
 
404
        //{
 
405
        //      wsprintf(dummy1, "%d", dummy2);
 
406
        //      SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
 
407
        //}
 
408
 
 
409
        //dummy = 0; dummy2 = 0;
 
410
        //MP4GetMetadataDisk(file, &dummy, &dummy2);
 
411
        //if (dummy)
 
412
        //{
 
413
        //      wsprintf(dummy1, "%d", dummy);
 
414
        //      SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
 
415
        //}
 
416
        //if (dummy)
 
417
        //{
 
418
        //      wsprintf(dummy1, "%d", dummy2);
 
419
        //      SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
 
420
        //}
 
421
 
 
422
        pVal = NULL;
 
423
        if (MP4GetMetadataYear(file, &pVal))
 
424
                uSetDlgItemText(tagHandle, TAGFIELD_YEAR, pVal);
 
425
 
 
426
        //dummy3 = 0;
 
427
        //MP4GetMetadataCompilation(file, &dummy3);
 
428
        //if (dummy3)
 
429
        //      SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_SETCHECK, BST_CHECKED, 0);
 
430
 
 
431
        pVal = NULL;
 
432
        MP4GetMetadataTool(file, &pVal);
 
433
        uSetDlgItemText(tagHandle, TAGFIELD_ENCODER, pVal);
 
434
 
 
435
        pVal = NULL;
 
436
        MP4GetMetadataFreeForm(file, "CONDUCTOR", (unsigned __int8**)&pVal, &valueSize);
 
437
        uSetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, pVal);
 
438
 
 
439
        pVal = NULL;
 
440
        MP4GetMetadataFreeForm(file, "ORCHESTRA", (unsigned __int8**)&pVal, &valueSize);
 
441
        uSetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, pVal);
 
442
 
 
443
        pVal = NULL;
 
444
        MP4GetMetadataFreeForm(file, "YEARCOMPOSED", (unsigned __int8**)&pVal, &valueSize);
 
445
        uSetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, pVal);
 
446
 
 
447
        pVal = NULL;
 
448
        MP4GetMetadataFreeForm(file, "ORIGARTIST", (unsigned __int8**)&pVal, &valueSize);
 
449
        uSetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, pVal);
 
450
 
 
451
        pVal = NULL;
 
452
        MP4GetMetadataFreeForm(file, "LABEL", (unsigned __int8**)&pVal, &valueSize);
 
453
        uSetDlgItemText(tagHandle, TAGFIELD_LABEL, pVal);
 
454
 
 
455
        pVal = NULL;
 
456
        MP4GetMetadataFreeForm(file, "COPYRIGHT", (unsigned __int8**)&pVal, &valueSize);
 
457
        uSetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, pVal);
 
458
 
 
459
        pVal = NULL;
 
460
        MP4GetMetadataFreeForm(file, "CDDBTAGID", (unsigned __int8**)&pVal, &valueSize);
 
461
        uSetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, pVal);
 
462
 
 
463
        /* ! Metadata */
 
464
 
 
465
        MP4Close(file);
 
466
 
 
467
        return true;
 
468
}
 
469
 
 
470
//-----------------------------------------------------------------------------
 
471
 
 
472
bool Write_Tag(LPCSTR filename, void* tagHandle)
 
473
{
 
474
        // TODO:
 
475
        // read metadata from tagHandle and set each field to supported tag
 
476
        // only TAGFIELD_* are supported (see QCDModTagEditor.h)
 
477
 
 
478
        // example of how to get value from tagHandle
 
479
        // use SetFieldA for ASCII or MultiBytes strings.
 
480
        // use SetFieldW for UNICODE strings
 
481
        //
 
482
        // szwValue = ModInitTag.GetFieldW(tagHandle, TAGFIELD_ORCHESTRA);
 
483
 
 
484
        // write tag to file
 
485
 
 
486
        MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
 
487
    char dummy1[1024];
 
488
    char temp[1024];
 
489
    short dummy, dummy2;
 
490
 
 
491
#ifdef DEBUG_OUTPUT
 
492
    in_mp4_DebugOutput("mp4_tag_write");
 
493
#endif
 
494
 
 
495
        /* save Metadata changes */
 
496
 
 
497
        tag_delete(&tags);
 
498
        file = MP4Read(filename, 0);
 
499
        if (file != MP4_INVALID_FILE_HANDLE)
 
500
        {
 
501
                ReadMP4Tag(file, &tags);
 
502
                MP4Close(file);
 
503
 
 
504
                file = MP4Modify(filename, 0, 0);
 
505
                if (file != MP4_INVALID_FILE_HANDLE)
 
506
                {
 
507
                        MP4MetadataDelete(file);
 
508
                        MP4Close(file);
 
509
                }
 
510
        }
 
511
 
 
512
        file = MP4Modify(filename, 0, 0);
 
513
        if (file == MP4_INVALID_FILE_HANDLE)
 
514
        {
 
515
                tag_delete(&tags);
 
516
                //EndDialog(hwndDlg, wParam);
 
517
                return false;
 
518
        }
 
519
 
 
520
        uGetDlgItemText(tagHandle, TAGFIELD_TITLE, dummy1, 1024);
 
521
        tag_set_field(&tags, "title", dummy1);
 
522
 
 
523
        uGetDlgItemText(tagHandle, TAGFIELD_COMPOSER, dummy1, 1024);
 
524
        tag_set_field(&tags, "writer", dummy1);
 
525
 
 
526
        uGetDlgItemText(tagHandle, TAGFIELD_ARTIST, dummy1, 1024);
 
527
        tag_set_field(&tags, "artist", dummy1);
 
528
 
 
529
        uGetDlgItemText(tagHandle, TAGFIELD_ALBUM, dummy1, 1024);
 
530
        tag_set_field(&tags, "album", dummy1);
 
531
 
 
532
        uGetDlgItemText(tagHandle, TAGFIELD_COMMENT, dummy1, 1024);
 
533
        tag_set_field(&tags, "comment", dummy1);
 
534
 
 
535
        uGetDlgItemText(tagHandle, TAGFIELD_GENRE, dummy1, 1024);
 
536
        tag_set_field(&tags, "genre", dummy1);
 
537
 
 
538
        uGetDlgItemText(tagHandle, TAGFIELD_YEAR, dummy1, 1024);
 
539
        tag_set_field(&tags, "year", dummy1);
 
540
 
 
541
        dummy = 0;
 
542
        MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
 
543
        memcpy(dummy1, ModInitTag.GetFieldA(tagHandle, TAGFIELD_TRACK), sizeof(dummy1));
 
544
        dummy = atoi(dummy1);
 
545
        wsprintf(temp, "%d/%d", dummy, dummy2);
 
546
        tag_set_field(&tags, "track", temp);
 
547
 
 
548
        //GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
 
549
        //dummy = atoi(dummy1);
 
550
        //GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
 
551
        //dummy2 = atoi(dummy1);
 
552
        //wsprintf(temp, "%d/%d", dummy, dummy2);
 
553
        //tag_set_field(&tags, "disc", temp);
 
554
 
 
555
        //GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
 
556
        //tag_set_field(&tags, "tempo", dummy1);
 
557
 
 
558
        //dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
 
559
        //tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"));
 
560
 
 
561
        uGetDlgItemText(tagHandle, TAGFIELD_ENCODER, dummy1, 1024);
 
562
        tag_set_field(&tags, "tool", dummy1);
 
563
 
 
564
        uGetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, dummy1, 1024);
 
565
        tag_set_field(&tags, "CONDUCTOR", dummy1);
 
566
 
 
567
        uGetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, dummy1, 1024);
 
568
        tag_set_field(&tags, "ORCHESTRA", dummy1);
 
569
 
 
570
        uGetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, dummy1, 1024);
 
571
        tag_set_field(&tags, "YEARCOMPOSED", dummy1);
 
572
 
 
573
        uGetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, dummy1, 1024);
 
574
        tag_set_field(&tags, "ORIGARTIST", dummy1);
 
575
 
 
576
        uGetDlgItemText(tagHandle, TAGFIELD_LABEL, dummy1, 1024);
 
577
        tag_set_field(&tags, "LABEL", dummy1);
 
578
 
 
579
        uGetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, dummy1, 1024);
 
580
        tag_set_field(&tags, "COPYRIGHT", dummy1);
 
581
 
 
582
        uGetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, dummy1, 1024);
 
583
        tag_set_field(&tags, "CDDBTAGID", dummy1);
 
584
 
 
585
        WriteMP4Tag(file, &tags);
 
586
 
 
587
        MP4Close(file);
 
588
 
 
589
        MP4Optimize(filename, NULL, 0);
 
590
        /* ! */
 
591
 
 
592
        return true;
 
593
}
 
594
 
 
595
//-----------------------------------------------------------------------------
 
596
 
 
597
bool Strip_Tag(LPCSTR filename)
 
598
{
 
599
        // TODO:
 
600
        // remove tag from file.
 
601
        // do whatever is need to remove the supported tag from filename
 
602
 
 
603
        // return true for successfull strip, false for failure
 
604
 
 
605
        MP4FileHandle file;
 
606
 
 
607
        file = MP4Modify(filename, 0, 0);
 
608
        if (file == MP4_INVALID_FILE_HANDLE)
 
609
                return false;
 
610
        
 
611
        MP4MetadataDelete(file);
 
612
 
 
613
        MP4Close(file);
 
614
 
 
615
        return true;
 
616
}
 
617
 
 
618
//-----------------------------------------------------------------------------
 
619
 
 
620
/* Convert UNICODE to UTF-8
 
621
   Return number of bytes written */
 
622
int unicodeToUtf8 ( const WCHAR* lpWideCharStr, char* lpMultiByteStr, int cwcChars )
 
623
{
 
624
    const unsigned short*   pwc = (unsigned short *)lpWideCharStr;
 
625
    unsigned char*          pmb = (unsigned char  *)lpMultiByteStr;
 
626
    const unsigned short*   pwce;
 
627
    size_t  cBytes = 0;
 
628
 
 
629
    if ( cwcChars >= 0 ) {
 
630
        pwce = pwc + cwcChars;
 
631
    } else {
 
632
        pwce = (unsigned short *)((size_t)-1);
 
633
    }
 
634
 
 
635
    while ( pwc < pwce ) {
 
636
        unsigned short  wc = *pwc++;
 
637
 
 
638
        if ( wc < 0x00000080 ) {
 
639
            *pmb++ = (char)wc;
 
640
            cBytes++;
 
641
        } else
 
642
        if ( wc < 0x00000800 ) {
 
643
            *pmb++ = (char)(0xC0 | ((wc >>  6) & 0x1F));
 
644
            cBytes++;
 
645
            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
 
646
            cBytes++;
 
647
        } else
 
648
        if ( wc < 0x00010000 ) {
 
649
            *pmb++ = (char)(0xE0 | ((wc >> 12) & 0x0F));
 
650
            cBytes++;
 
651
            *pmb++ = (char)(0x80 | ((wc >>  6) & 0x3F));
 
652
            cBytes++;
 
653
            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
 
654
            cBytes++;
 
655
        }
 
656
        if ( wc == L'\0' )
 
657
            return cBytes;
 
658
    }
 
659
 
 
660
    return cBytes;
 
661
}
 
662
 
 
663
/* Convert UTF-8 coded string to UNICODE
 
664
   Return number of characters converted */
 
665
int utf8ToUnicode ( const char* lpMultiByteStr, WCHAR* lpWideCharStr, int cmbChars )
 
666
{
 
667
    const unsigned char*    pmb = (unsigned char  *)lpMultiByteStr;
 
668
    unsigned short*         pwc = (unsigned short *)lpWideCharStr;
 
669
    const unsigned char*    pmbe;
 
670
    size_t  cwChars = 0;
 
671
 
 
672
    if ( cmbChars >= 0 ) {
 
673
        pmbe = pmb + cmbChars;
 
674
    } else {
 
675
        pmbe = (unsigned char *)((size_t)-1);
 
676
    }
 
677
 
 
678
    while ( pmb < pmbe ) {
 
679
        char            mb = *pmb++;
 
680
        unsigned int    cc = 0;
 
681
        unsigned int    wc;
 
682
 
 
683
        while ( (cc < 7) && (mb & (1 << (7 - cc)))) {
 
684
            cc++;
 
685
        }
 
686
 
 
687
        if ( cc == 1 || cc > 6 )                    // illegal character combination for UTF-8
 
688
            continue;
 
689
 
 
690
        if ( cc == 0 ) {
 
691
            wc = mb;
 
692
        } else {
 
693
            wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6);
 
694
            while ( --cc > 0 ) {
 
695
                if ( pmb == pmbe )                  // reached end of the buffer
 
696
                    return cwChars;
 
697
                mb = *pmb++;
 
698
                if ( ((mb >> 6) & 0x03) != 2 )      // not part of multibyte character
 
699
                    return cwChars;
 
700
                wc |= (mb & 0x3F) << ((cc - 1) * 6);
 
701
            }
 
702
        }
 
703
 
 
704
        if ( wc & 0xFFFF0000 )
 
705
            wc = L'?';
 
706
        *pwc++ = wc;
 
707
        cwChars++;
 
708
        if ( wc == L'\0' )
 
709
            return cwChars;
 
710
    }
 
711
 
 
712
    return cwChars;
 
713
}
 
714
 
 
715
/* convert Windows ANSI to UTF-8 */
 
716
int ConvertANSIToUTF8 ( const char* ansi, char* utf8 )
 
717
{
 
718
    WCHAR*  wszValue;          // Unicode value
 
719
    size_t  ansi_len;
 
720
    size_t  len;
 
721
 
 
722
    *utf8 = '\0';
 
723
    if ( ansi == NULL )
 
724
        return 0;
 
725
 
 
726
    ansi_len = strlen ( ansi );
 
727
 
 
728
    if ( (wszValue = (WCHAR *)malloc ( (ansi_len + 1) * 2 )) == NULL )
 
729
        return 0;
 
730
 
 
731
    /* Convert ANSI value to Unicode */
 
732
    if ( (len = MultiByteToWideChar ( CP_ACP, 0, ansi, ansi_len + 1, wszValue, (ansi_len + 1) * 2 )) == 0 ) {
 
733
        free ( wszValue );
 
734
        return 0;
 
735
    }
 
736
 
 
737
    /* Convert Unicode value to UTF-8 */
 
738
    if ( (len = unicodeToUtf8 ( wszValue, utf8, -1 )) == 0 ) {
 
739
        free ( wszValue );
 
740
        return 0;
 
741
    }
 
742
 
 
743
    free ( wszValue );
 
744
 
 
745
    return len-1;
 
746
}
 
747
 
 
748
/* convert UTF-8 to Windows ANSI */
 
749
int ConvertUTF8ToANSI ( const char* utf8, char* ansi )
 
750
{
 
751
    WCHAR*  wszValue;          // Unicode value
 
752
    size_t  utf8_len;
 
753
    size_t  len;
 
754
 
 
755
    *ansi = '\0';
 
756
    if ( utf8 == NULL )
 
757
        return 0;
 
758
 
 
759
    utf8_len = strlen ( utf8 );
 
760
 
 
761
    if ( (wszValue = (WCHAR *)malloc ( (utf8_len + 1) * 2 )) == NULL )
 
762
        return 0;
 
763
 
 
764
    /* Convert UTF-8 value to Unicode */
 
765
    if ( (len = utf8ToUnicode ( utf8, wszValue, utf8_len + 1 )) == 0 ) {
 
766
        free ( wszValue );
 
767
        return 0;
 
768
    }
 
769
 
 
770
    /* Convert Unicode value to ANSI */
 
771
    if ( (len = WideCharToMultiByte ( CP_ACP, 0, wszValue, -1, ansi, (utf8_len + 1) * 2, NULL, NULL )) == 0 ) {
 
772
        free ( wszValue );
 
773
        return 0;
 
774
    }
 
775
 
 
776
    free ( wszValue );
 
777
 
 
778
    return len-1;
 
779
}
 
780
 
 
781
BOOL uSetDlgItemText(void *tagHandle, int fieldId, const char *str)
 
782
{
 
783
    char *temp;
 
784
    size_t len;
 
785
    int r;
 
786
 
 
787
    if (!str) return FALSE;
 
788
        if (!*str) return FALSE;
 
789
    len = strlen(str);
 
790
    temp = (char *)malloc(len+1);
 
791
    if (!temp) return FALSE;
 
792
        memset(temp, '\0', len+1);
 
793
    r = ConvertUTF8ToANSI(str, temp);
 
794
    if (r > 0)
 
795
        ModInitTag.SetFieldA(tagHandle, fieldId, temp);
 
796
    free(temp);
 
797
 
 
798
    return r>0 ? TRUE : FALSE;
 
799
}
 
800
 
 
801
UINT uGetDlgItemText(void *tagHandle, int fieldId, char *str, int max)
 
802
{
 
803
    char *temp, *utf8;;
 
804
    int len;
 
805
 
 
806
        const char *p;
 
807
 
 
808
    if (!str || !max) return 0;
 
809
    len = strlen( ModInitTag.GetFieldA(tagHandle, fieldId) );
 
810
    temp = (char *)malloc(len+1);
 
811
    if (!temp) return 0;
 
812
    utf8 = (char *)malloc((len+1)*4);
 
813
    if (!utf8)
 
814
    {
 
815
        free(temp);
 
816
        return 0;
 
817
    }
 
818
 
 
819
        memset(temp, '\0', len+1);
 
820
        memset(utf8, '\0', (len+1)*4);
 
821
        memset(str, '\0', max);
 
822
        p = ModInitTag.GetFieldA(tagHandle, fieldId);
 
823
        memcpy(temp, p, len+1);
 
824
    if (len > 0)
 
825
    {
 
826
        len = ConvertANSIToUTF8(temp, utf8);
 
827
        if (len > max-1)
 
828
        {
 
829
            len = max-1;
 
830
            utf8[max] = '\0';
 
831
        }
 
832
        memcpy(str, utf8, len+1);
 
833
    }
 
834
 
 
835
    free(temp);
 
836
    free(utf8);
 
837
 
 
838
    return len;
 
839
}