2
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
3
** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
5
** This program is free software; you can redistribute it and/or modify
6
** it under the terms of the GNU General Public License as published by
7
** the Free Software Foundation; either version 2 of the License, or
8
** (at your option) any later version.
10
** This program is distributed in the hope that it will be useful,
11
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
** GNU General Public License for more details.
15
** You should have received a copy of the GNU General Public License
16
** along with this program; if not, write to the Free Software
17
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
** Any non-GPL usage of this software or parts of this software is strictly
22
** Commercial non-GPL licensing of this software is possible.
23
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
25
** $Id: in_mp4.c,v 1.56 2004/10/19 18:02:10 menno Exp $
28
//#define DEBUG_OUTPUT
30
#define WIN32_LEAN_AND_MEAN
48
const char *long_ext_list = "MP4\0MPEG-4 Files (*.MP4)\0M4A\0MPEG-4 Files (*.M4A)\0AAC\0AAC Files (*.AAC)\0";
49
const char *short_ext_list = "MP4\0MPEG-4 Files (*.MP4)\0M4A\0MPEG-4 Files (*.M4A)\0";
51
static long priority_table[] = {
53
THREAD_PRIORITY_HIGHEST,
54
THREAD_PRIORITY_ABOVE_NORMAL,
55
THREAD_PRIORITY_NORMAL,
56
THREAD_PRIORITY_BELOW_NORMAL,
57
THREAD_PRIORITY_LOWEST
59
static int res_id_table[] = {
65
/*IDC_16BITS_DITHERED*/ IDC_16BITS /* temp hack */
67
static int res_table[] = {
75
static char info_fn[_MAX_PATH];
77
// post this to the main window at end of file (after playback has stopped)
78
#define WM_WA_AAC_EOF WM_USER+2
82
struct seek_list *next;
89
NeAACDecHandle hDecoder;
91
unsigned char channels;
92
double decode_pos_ms; // current decoding position, in milliseconds
93
int paused; // are we paused?
94
int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
95
char filename[_MAX_PATH];
96
int filetype; /* 0: MP4; 1: AAC */
105
mp4ff_callback_t mp4cb;
110
long m_aac_bytes_into_buffer;
111
long m_aac_bytes_consumed;
112
__int64 m_file_offset;
113
unsigned char *m_aac_buffer;
117
struct seek_list *m_head;
118
struct seek_list *m_tail;
119
unsigned long m_length;
121
/* for gapless decoding */
122
unsigned int useAacLength;
123
unsigned int framesize;
124
unsigned int initial;
125
unsigned long timescale;
128
static state mp4state;
130
static In_Module module; // the output module (declared near the bottom of this file)
132
static int killPlayThread;
133
static int PlayThreadAlive = 0; // 1=play thread still running
134
HANDLE play_thread_handle = INVALID_HANDLE_VALUE; // the handle to the decode thread
136
/* Function definitions */
137
void *decode_aac_frame(state *st, NeAACDecFrameInfo *frameInfo);
138
DWORD WINAPI MP4PlayThread(void *b); // the decode thread procedure
139
DWORD WINAPI AACPlayThread(void *b); // the decode thread procedure
142
uint32_t read_callback(void *user_data, void *buffer, uint32_t length)
144
return fread(buffer, 1, length, (FILE*)user_data);
147
uint32_t seek_callback(void *user_data, uint64_t position)
149
return fseek((FILE*)user_data, position, SEEK_SET);
152
uint32_t write_callback(void *user_data, void *buffer, uint32_t length)
154
return fwrite(buffer, 1, length, (FILE*)user_data);
157
uint32_t truncate_callback(void *user_data)
159
_chsize(fileno((FILE*)user_data), ftell((FILE*)user_data));
164
int tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value, size_t v_len)
166
void *backup = (void *)tags->tags;
168
if (!item || (item && !*item) || !value) return 0;
170
tags->tags = (mp4ff_tag_t *)realloc(tags->tags, (tags->count+1) * sizeof(mp4ff_tag_t));
172
if (backup) free(backup);
177
size_t i_len = strlen(item);
178
if (v_len == 0) v_len = strlen(value);
180
tags->tags[tags->count].item = (char *)malloc(i_len+1);
181
tags->tags[tags->count].value = (char *)malloc(v_len+1);
183
if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
185
if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
186
if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
187
tags->tags[tags->count].item = NULL;
188
tags->tags[tags->count].value = NULL;
192
memcpy(tags->tags[tags->count].item, item, i_len);
193
memcpy(tags->tags[tags->count].value, value, v_len);
194
tags->tags[tags->count].item[i_len] = '\0';
195
tags->tags[tags->count].value[v_len] = '\0';
196
// tags->tags[tags->count].len = v_len;
203
int tag_set_field(mp4ff_metadata_t *tags, const char *item, const char *value, size_t v_len)
207
if (!item || (item && !*item) || !value) return 0;
209
for (i = 0; i < tags->count; i++)
211
if (!stricmp(tags->tags[i].item, item))
213
void *backup = (void *)tags->tags[i].value;
214
if (v_len == 0) v_len = strlen(value);
216
tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
217
if (!tags->tags[i].value)
219
if (backup) free(backup);
223
memcpy(tags->tags[i].value, value, v_len);
224
tags->tags[i].value[v_len] = '\0';
225
// tags->tags[i].len = v_len;
231
return tag_add_field(tags, item, value, v_len);
234
int tag_delete(mp4ff_metadata_t *tags)
238
for (i = 0; i < tags->count; i++)
240
if (tags->tags[i].item) free(tags->tags[i].item);
241
if (tags->tags[i].value) free(tags->tags[i].value);
244
if (tags->tags) free(tags->tags);
250
int ReadMP4Tag(mp4ff_t *file, mp4ff_metadata_t *tags)
252
unsigned __int8 *pValue;
261
if (mp4ff_meta_get_by_index(file, i, (char **)&pName, &pValue))
263
char *val = (char *)strdup(pValue);
266
if (pName[0] == 'ļæ½')
268
if (memcmp(pName, "ļæ½nam", 4) == 0)
270
tag_add_field(tags, "title", val, strlen(val));
271
} else if (memcmp(pName, "ļæ½ART", 4) == 0) {
272
tag_add_field(tags, "artist", val, strlen(val));
273
} else if (memcmp(pName, "ļæ½wrt", 4) == 0) {
274
tag_add_field(tags, "writer", val, strlen(val));
275
} else if (memcmp(pName, "ļæ½alb", 4) == 0) {
276
tag_add_field(tags, "album", val, strlen(val));
277
} else if (memcmp(pName, "ļæ½day", 4) == 0) {
278
tag_add_field(tags, "date", val, strlen(val));
279
} else if (memcmp(pName, "ļæ½too", 4) == 0) {
280
tag_add_field(tags, "tool", val, strlen(val));
281
} else if (memcmp(pName, "ļæ½cmt", 4) == 0) {
282
tag_add_field(tags, "comment", val, strlen(val));
283
} else if (memcmp(pName, "ļæ½gen", 4) == 0) {
284
tag_add_field(tags, "genre", val, strlen(val));
286
tag_add_field(tags, pName, val, strlen(val));
288
} else if (memcmp(pName, "covr", 4) == 0) {
289
tag_add_field(tags, "cover", val, strlen(val));
290
} else if (memcmp(pName, "gnre", 4) == 0) {
291
tag_add_field(tags, "genre", val, strlen(val));
292
} else if (memcmp(pName, "trkn", 4) == 0) {
293
tag_add_field(tags, "tracknumber", val, strlen(val));
294
} else if (memcmp(pName, "disk", 4) == 0) {
295
tag_add_field(tags, "disc", val, strlen(val));
296
} else if (memcmp(pName, "cpil", 4) == 0) {
297
tag_add_field(tags, "compilation", val, strlen(val));
298
} else if (memcmp(pName, "tmpo", 4) == 0) {
299
tag_add_field(tags, "tempo", val, strlen(val));
300
} else if (memcmp(pName, "NDFL", 4) == 0) {
303
tag_add_field(tags, pName, val, strlen(val));
310
} while (pValue != NULL);
317
void in_mp4_DebugOutput(char *message)
321
sprintf(s, "in_mp4: %s", message);
322
OutputDebugString(s);
326
int file_length(FILE *f)
330
fseek(f, 0, SEEK_END);
332
fseek(f, cur, SEEK_SET);
337
static void show_error(HWND hwnd, char *message, ...)
340
MessageBox(hwnd, message, "Error", MB_OK);
343
static void config_init()
346
GetModuleFileName(NULL,INI_FILE,_MAX_PATH);
348
while (p >= INI_FILE && *p != '.') p--;
356
char show_errors[10];
357
char use_for_aac[10];
359
char vbr_display[10];
363
strcpy(show_errors, "1");
364
strcpy(priority, "3");
365
strcpy(resolution, "0");
366
strcpy(use_for_aac, "1");
367
strcpy(downmix, "0");
368
strcpy(vbr_display, "1");
369
strcpy(titleformat, "%7");
379
m_priority = atoi(priority);
380
m_resolution = atoi(resolution);
381
m_show_errors = atoi(show_errors);
382
m_use_for_aac = atoi(use_for_aac);
383
m_downmix = atoi(downmix);
384
m_vbr_display = atoi(vbr_display);
391
char show_errors[10];
392
char use_for_aac[10];
394
char vbr_display[10];
396
itoa(m_priority, priority, 10);
397
itoa(m_resolution, resolution, 10);
398
itoa(m_show_errors, show_errors, 10);
399
itoa(m_use_for_aac, use_for_aac, 10);
400
itoa(m_downmix, downmix, 10);
401
itoa(m_vbr_display, vbr_display, 10);
421
/* Convert UNICODE to UTF-8
422
Return number of bytes written */
423
int unicodeToUtf8 ( const WCHAR* lpWideCharStr, char* lpMultiByteStr, int cwcChars )
425
const unsigned short* pwc = (unsigned short *)lpWideCharStr;
426
unsigned char* pmb = (unsigned char *)lpMultiByteStr;
427
const unsigned short* pwce;
430
if ( cwcChars >= 0 ) {
431
pwce = pwc + cwcChars;
433
pwce = (unsigned short *)((size_t)-1);
436
while ( pwc < pwce ) {
437
unsigned short wc = *pwc++;
439
if ( wc < 0x00000080 ) {
443
if ( wc < 0x00000800 ) {
444
*pmb++ = (char)(0xC0 | ((wc >> 6) & 0x1F));
446
*pmb++ = (char)(0x80 | (wc & 0x3F));
449
if ( wc < 0x00010000 ) {
450
*pmb++ = (char)(0xE0 | ((wc >> 12) & 0x0F));
452
*pmb++ = (char)(0x80 | ((wc >> 6) & 0x3F));
454
*pmb++ = (char)(0x80 | (wc & 0x3F));
464
/* Convert UTF-8 coded string to UNICODE
465
Return number of characters converted */
466
int utf8ToUnicode ( const char* lpMultiByteStr, WCHAR* lpWideCharStr, int cmbChars )
468
const unsigned char* pmb = (unsigned char *)lpMultiByteStr;
469
unsigned short* pwc = (unsigned short *)lpWideCharStr;
470
const unsigned char* pmbe;
473
if ( cmbChars >= 0 ) {
474
pmbe = pmb + cmbChars;
476
pmbe = (unsigned char *)((size_t)-1);
479
while ( pmb < pmbe ) {
484
while ( (cc < 7) && (mb & (1 << (7 - cc)))) {
488
if ( cc == 1 || cc > 6 ) // illegal character combination for UTF-8
494
wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6);
496
if ( pmb == pmbe ) // reached end of the buffer
499
if ( ((mb >> 6) & 0x03) != 2 ) // not part of multibyte character
501
wc |= (mb & 0x3F) << ((cc - 1) * 6);
505
if ( wc & 0xFFFF0000 )
516
/* convert Windows ANSI to UTF-8 */
517
int ConvertANSIToUTF8 ( const char* ansi, char* utf8 )
519
WCHAR* wszValue; // Unicode value
527
ansi_len = strlen ( ansi );
529
if ( (wszValue = (WCHAR *)malloc ( (ansi_len + 1) * 2 )) == NULL )
532
/* Convert ANSI value to Unicode */
533
if ( (len = MultiByteToWideChar ( CP_ACP, 0, ansi, ansi_len + 1, wszValue, (ansi_len + 1) * 2 )) == 0 ) {
538
/* Convert Unicode value to UTF-8 */
539
if ( (len = unicodeToUtf8 ( wszValue, utf8, -1 )) == 0 ) {
549
/* convert UTF-8 to Windows ANSI */
550
int ConvertUTF8ToANSI ( const char* utf8, char* ansi )
552
WCHAR* wszValue; // Unicode value
560
utf8_len = strlen ( utf8 );
562
if ( (wszValue = (WCHAR *)malloc ( (utf8_len + 1) * 2 )) == NULL )
565
/* Convert UTF-8 value to Unicode */
566
if ( (len = utf8ToUnicode ( utf8, wszValue, utf8_len + 1 )) == 0 ) {
571
/* Convert Unicode value to ANSI */
572
if ( (len = WideCharToMultiByte ( CP_ACP, 0, wszValue, -1, ansi, (utf8_len + 1) * 2, NULL, NULL )) == 0 ) {
582
BOOL uSetDlgItemText(HWND hwnd, int id, const char *str)
588
if (!str) return FALSE;
589
if (!*str) return TRUE;
591
temp = malloc(len+1);
592
if (!temp) return FALSE;
593
r = ConvertUTF8ToANSI(str, temp);
595
SetDlgItemText(hwnd, id, temp);
598
return r>0 ? TRUE : FALSE;
601
UINT uGetDlgItemText(HWND hwnd, int id, char *str, int max)
607
if (!str || !max) return 0;
609
w = GetDlgItem(hwnd, id);
610
len = GetWindowTextLength(w);
611
temp = malloc(len+1);
613
utf8 = malloc((len+1)*4);
620
len = GetWindowText(w, temp, len+1);
623
len = ConvertANSIToUTF8(temp, utf8);
629
memcpy(str, utf8, len+1);
638
static void mp4fileinfo(mp4ff_t *mp4, char *info, size_t len)
640
char *ot[6] = { "NULL", "MAIN AAC", "LC AAC", "SSR AAC", "LTP AAC", "HE AAC" };
646
NeAACDecHandle hDecoder;
647
NeAACDecFrameInfo frameInfo;
648
mp4AudioSpecificConfig mp4ASC = {0};
649
unsigned char *buffer = NULL;
651
unsigned long sr = 0;
652
unsigned char ch = 0;
654
if ((track = GetAACTrack(mp4)) < 0)
660
hDecoder = NeAACDecOpen();
662
samples = mp4ff_num_samples(mp4, track);
664
mp4ff_get_decoder_config(mp4, track, &buffer, &buffer_size);
667
if (NeAACDecAudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0)
669
if (mp4ASC.frameLengthFlag == 1) f = 960.0;
670
if (mp4ASC.sbr_present_flag == 1) f *= 2;
673
if(NeAACDecInit2(hDecoder, buffer, buffer_size, &sr, &ch) < 0)
675
/* If some error initializing occured, skip the file */
684
if (mp4ff_read_sample(mp4, track, 0, &buffer, &buffer_size) == 0)
688
NeAACDecDecode(hDecoder, &frameInfo, buffer, buffer_size);
690
if (buffer) free(buffer);
692
seconds = (float)samples*(float)(f-1.0)/(float)mp4ASC.samplingFrequency;
694
wsprintf(info, "MPEG-4 %s, %d.%d secs, %d ch, %d Hz\nSBR: %s\nParametric stereo: %s",
695
ot[(mp4ASC.objectTypeIndex > 5)?0:mp4ASC.objectTypeIndex],
697
(int)(seconds*1000.0 + 0.5) % 1000,
698
mp4ASC.channelsConfiguration,
699
mp4ASC.samplingFrequency,
700
/* SBR: 0: off, 1: on; upsample, 2: on; downsampled, 3: off; upsampled */
701
(frameInfo.sbr == 0) ? "off" : ((frameInfo.sbr == 1) ? "on, normal" : ((frameInfo.sbr == 2) ? "on, downsampled" : "off, upsampled")),
702
(frameInfo.ps == 0) ? "no" : "yes");
704
NeAACDecClose(hDecoder);
707
BOOL CALLBACK mp4_info_dialog_proc(HWND hwndDlg, UINT message,
708
WPARAM wParam, LPARAM lParam)
710
char file_info[1024];
713
mp4ff_callback_t mp4cb = {0};
715
mp4ff_metadata_t tags;
718
int dummy, dummy2, dummy3;
723
in_mp4_DebugOutput("mp4_info_dialog_proc");
728
EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT), FALSE);
729
ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT), SW_HIDE);
730
EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT1), FALSE);
731
ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT1), SW_HIDE);
732
EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), FALSE);
733
ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), SW_HIDE);
735
mp4File = fopen(info_fn, "rb");
736
mp4cb.read = read_callback;
737
mp4cb.seek = seek_callback;
738
mp4cb.user_data = mp4File;
741
file = mp4ff_open_read(&mp4cb);
745
mp4fileinfo(file, file_info, 1024);
746
SetDlgItemText(hwndDlg, IDC_INFOTEXT, file_info);
751
if (mp4ff_meta_get_title(file, &pVal))
752
uSetDlgItemText(hwndDlg,IDC_METANAME, pVal);
755
if (mp4ff_meta_get_artist(file, &pVal))
756
uSetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
759
if (mp4ff_meta_get_writer(file, &pVal))
760
uSetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
763
if (mp4ff_meta_get_comment(file, &pVal))
764
uSetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
767
if (mp4ff_meta_get_album(file, &pVal))
768
uSetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
771
if (mp4ff_meta_get_genre(file, &pVal))
772
uSetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
775
if (mp4ff_meta_get_track(file, &pVal))
777
SetDlgItemText(hwndDlg,IDC_METATRACK1, pVal);
780
//mp4ff_meta_get_totaltracks(file, &pVal);
781
//SetDlgItemText(hwndDlg, IDC_METATRACK2, pVal);
785
if (mp4ff_meta_get_disc(file, &pVal))
787
SetDlgItemText(hwndDlg,IDC_METADISK1, pVal);
790
//mp4ff_meta_get_totaldiscs(file, &pVal);
791
//SetDlgItemText(hwndDlg,IDC_METADISK2, pVal);
795
if (mp4ff_meta_get_date(file, &pVal))
796
uSetDlgItemText(hwndDlg,IDC_METAYEAR, pVal);
802
if (mp4ff_meta_get_compilation(file, &pVal))
804
if (strcmp(pVal, "1") == 0)
806
SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_SETCHECK, BST_CHECKED, 0);
818
switch (LOWORD(wParam)) {
820
EndDialog(hwndDlg, wParam);
824
/* trying to edit currently playing file */
826
if (!stricmp(info_fn, mp4state.filename))
828
MessageBox(module.hMainWindow, "Please stop playback before editing tags", "in_mp4", MB_ICONINFORMATION|MB_OK);
832
/* save Metadata changes */
836
mp4File = fopen(info_fn, "rb");
837
mp4cb.read = read_callback;
838
mp4cb.seek = seek_callback;
839
mp4cb.write = write_callback;
840
mp4cb.truncate = truncate_callback;
841
mp4cb.user_data = mp4File;
844
file = mp4ff_open_read(&mp4cb);
847
ReadMP4Tag(file, &tags);
852
mp4File = fopen(info_fn, "rb+");
853
mp4cb.read = read_callback;
854
mp4cb.seek = seek_callback;
855
mp4cb.write = write_callback;
856
mp4cb.truncate = truncate_callback;
857
mp4cb.user_data = mp4File;
860
uGetDlgItemText(hwndDlg, IDC_METANAME, dummy1, 1024);
861
tag_set_field(&tags, "title", dummy1, strlen(dummy1));
863
uGetDlgItemText(hwndDlg, IDC_METAWRITER, dummy1, 1024);
864
tag_set_field(&tags, "writer", dummy1, strlen(dummy1));
866
uGetDlgItemText(hwndDlg, IDC_METAARTIST, dummy1, 1024);
867
tag_set_field(&tags, "artist", dummy1, strlen(dummy1));
869
uGetDlgItemText(hwndDlg, IDC_METAALBUM, dummy1, 1024);
870
tag_set_field(&tags, "album", dummy1, strlen(dummy1));
872
uGetDlgItemText(hwndDlg, IDC_METACOMMENTS, dummy1, 1024);
873
tag_set_field(&tags, "comment", dummy1, strlen(dummy1));
875
uGetDlgItemText(hwndDlg, IDC_METAGENRE, dummy1, 1024);
876
tag_set_field(&tags, "genre", dummy1, strlen(dummy1));
878
uGetDlgItemText(hwndDlg, IDC_METAYEAR, dummy1, 1024);
879
tag_set_field(&tags, "year", dummy1, strlen(dummy1));
881
GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
882
dummy = atoi(dummy1);
883
//GetDlgItemText(hwndDlg, IDC_METATRACK2, dummy1, 1024);
884
//dummy2 = atoi(dummy1);
885
//wsprintf(temp, "%d/%d", dummy, dummy2);
886
wsprintf(temp, "%d", dummy);
887
tag_set_field(&tags, "track", temp, strlen(dummy1));
889
GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
890
dummy = atoi(dummy1);
891
//GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
892
//dummy2 = atoi(dummy1);
893
//wsprintf(temp, "%d/%d", dummy, dummy2);
894
wsprintf(temp, "%d", dummy);
895
tag_set_field(&tags, "disc", temp, strlen(dummy1));
897
dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
898
tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"), 1);
900
mp4ff_meta_update(&mp4cb, &tags);
906
EndDialog(hwndDlg, wParam);
913
/* returns the name of the object type */
914
char *get_ot_string(int ot)
930
BOOL CALLBACK aac_info_dialog_proc(HWND hwndDlg, UINT message,
931
WPARAM wParam, LPARAM lParam)
934
char *info_text, *header_string;
937
in_mp4_DebugOutput("aac_info_dialog_proc");
942
EnableWindow(GetDlgItem(hwndDlg,IDC_USERDATA), FALSE) ;
943
ShowWindow(GetDlgItem(hwndDlg,IDC_USERDATA), SW_HIDE);
945
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC1), SW_HIDE);
946
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC2), SW_HIDE);
947
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC3), SW_HIDE);
948
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC4), SW_HIDE);
949
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC5), SW_HIDE);
950
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC6), SW_HIDE);
951
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC7), SW_HIDE);
952
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC8), SW_HIDE);
953
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC9), SW_HIDE);
954
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC10), SW_HIDE);
955
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC11), SW_HIDE);
956
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC12), SW_HIDE);
958
ShowWindow(GetDlgItem(hwndDlg,IDC_METANAME), SW_HIDE);
959
ShowWindow(GetDlgItem(hwndDlg,IDC_METAARTIST), SW_HIDE);
960
ShowWindow(GetDlgItem(hwndDlg,IDC_METAWRITER), SW_HIDE);
961
ShowWindow(GetDlgItem(hwndDlg,IDC_METACOMMENTS), SW_HIDE);
962
ShowWindow(GetDlgItem(hwndDlg,IDC_METAALBUM), SW_HIDE);
963
ShowWindow(GetDlgItem(hwndDlg,IDC_METAGENRE), SW_HIDE);
964
ShowWindow(GetDlgItem(hwndDlg,IDC_METATRACK1), SW_HIDE);
965
//ShowWindow(GetDlgItem(hwndDlg,IDC_METATRACK2), SW_HIDE);
966
ShowWindow(GetDlgItem(hwndDlg,IDC_METADISK1), SW_HIDE);
967
//ShowWindow(GetDlgItem(hwndDlg,IDC_METADISK2), SW_HIDE);
968
ShowWindow(GetDlgItem(hwndDlg,IDC_METAYEAR), SW_HIDE);
969
ShowWindow(GetDlgItem(hwndDlg,IDC_METACOMPILATION), SW_HIDE);
971
info_text = malloc(1024*sizeof(char));
973
get_AAC_format(info_fn, &aacInfo);
975
switch (aacInfo.headertype)
978
header_string = " RAW";
981
header_string = " ADIF";
984
header_string = " ADTS";
988
sprintf(info_text, "%s AAC %s%s, %d sec, %d kbps, %d Hz",
989
(aacInfo.version==2)?"MPEG-2":"MPEG-4", get_ot_string(aacInfo.object_type),
991
(int)((float)aacInfo.length/1000.0), (int)((float)aacInfo.bitrate/1000.0+0.5),
992
aacInfo.sampling_rate);
994
SetDlgItemText(hwndDlg, IDC_INFOTEXT, info_text);
1001
switch (LOWORD(wParam))
1005
EndDialog(hwndDlg, wParam);
1012
int infoDlg(char *fn, HWND hwndParent)
1014
if(!stricmp(fn + strlen(fn) - 3,"AAC"))
1016
lstrcpy(info_fn, fn);
1018
DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
1019
hwndParent, aac_info_dialog_proc);
1021
lstrcpy(info_fn, fn);
1023
DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
1024
hwndParent, mp4_info_dialog_proc);
1030
/* Get the title from the file */
1031
void ConstructTitle(mp4ff_t *file, char *filename, char *title, char *format)
1036
char *out = temp;//title;
1037
char *bound = out + sizeof(temp) - 256; //out + (MAX_PATH - 10 - 1);
1038
char *pVal, dummy1[1024];
1039
short dummy, dummy2;
1041
while (*in && out < bound)
1054
/* handle % escape sequence */
1059
if (mp4ff_meta_get_track(file, &pVal))
1061
out += wsprintf(out, "%s", pVal);
1068
if (mp4ff_meta_get_artist(file, &pVal))
1070
out += wsprintf(out, "%s", pVal);
1077
if (mp4ff_meta_get_title(file, &pVal))
1079
out += wsprintf(out, "%s", pVal);
1086
if (mp4ff_meta_get_album(file, &pVal))
1088
out += wsprintf(out, "%s", pVal);
1095
if (mp4ff_meta_get_date(file, &pVal))
1097
out += wsprintf(out, "%s", pVal);
1104
if (mp4ff_meta_get_comment(file, &pVal))
1106
out += wsprintf(out, "%s", pVal);
1113
if (mp4ff_meta_get_genre(file, &pVal))
1115
out += wsprintf(out, "%s", pVal);
1122
const char *p=strrchr(filename,'\\');
1123
if (!p) p=filename; else p++;
1124
out += ConvertANSIToUTF8(p, out);
1138
char *p=filename+lstrlen(filename);
1139
while (*p != '\\' && p >= filename) p--;
1144
int len = ConvertUTF8ToANSI(temp, dummy1);
1145
if (len > (MAX_PATH - 10 - 1)) len = (MAX_PATH - 10 - 1);
1146
memcpy(title, dummy1, len);
1151
BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message,
1152
WPARAM wParam, LPARAM lParam)
1158
SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETRANGE, TRUE, MAKELONG(1,5));
1159
SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETPOS, TRUE, m_priority);
1160
SendMessage(GetDlgItem(hwndDlg, res_id_table[m_resolution]), BM_SETCHECK, BST_CHECKED, 0);
1162
SendMessage(GetDlgItem(hwndDlg, IDC_ERROR), BM_SETCHECK, BST_CHECKED, 0);
1164
SendMessage(GetDlgItem(hwndDlg, IDC_USEFORAAC), BM_SETCHECK, BST_CHECKED, 0);
1166
SendMessage(GetDlgItem(hwndDlg, IDC_DOWNMIX), BM_SETCHECK, BST_CHECKED, 0);
1168
SendMessage(GetDlgItem(hwndDlg, IDC_VBR), BM_SETCHECK, BST_CHECKED, 0);
1169
SetDlgItemText(hwndDlg, IDC_TITLEFORMAT, titleformat);
1173
switch (LOWORD(wParam)) {
1175
EndDialog(hwndDlg, wParam);
1178
m_show_errors = SendMessage(GetDlgItem(hwndDlg, IDC_ERROR), BM_GETCHECK, 0, 0);
1179
m_use_for_aac = SendMessage(GetDlgItem(hwndDlg, IDC_USEFORAAC), BM_GETCHECK, 0, 0);
1180
m_downmix = SendMessage(GetDlgItem(hwndDlg, IDC_DOWNMIX), BM_GETCHECK, 0, 0);
1181
m_vbr_display = SendMessage(GetDlgItem(hwndDlg, IDC_VBR), BM_GETCHECK, 0, 0);
1182
GetDlgItemText(hwndDlg, IDC_TITLEFORMAT, titleformat, MAX_PATH);
1184
m_priority = SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_GETPOS, 0, 0);
1185
for (i = 0; i < 6; i++)
1187
if (SendMessage(GetDlgItem(hwndDlg, res_id_table[i]), BM_GETCHECK, 0, 0))
1199
module.FileExtensions = short_ext_list;
1201
module.FileExtensions = long_ext_list;
1204
EndDialog(hwndDlg, wParam);
1211
void config(HWND hwndParent)
1213
DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG),
1214
hwndParent, config_dialog_proc);
1219
void about(HWND hwndParent)
1221
MessageBox(hwndParent,
1222
"AudioCoding.com MPEG-4 AAC player " FAAD2_VERSION " compiled on " __DATE__ ".\n"
1223
"Visit the website for more info.\n"
1224
"Copyright 2002-2004 AudioCoding.com",
1229
int isourfile(char *fn)
1231
if (!stricmp(fn + strlen(fn) - 3,"MP4") || !stricmp(fn + strlen(fn) - 3,"M4A"))
1234
} else if (m_use_for_aac) {
1235
if (!stricmp(fn + strlen(fn) - 3,"AAC"))
1244
int fill_buffer(state *st)
1248
if (st->m_aac_bytes_consumed > 0)
1250
if (st->m_aac_bytes_into_buffer)
1252
memmove((void*)st->m_aac_buffer, (void*)(st->m_aac_buffer + st->m_aac_bytes_consumed),
1253
st->m_aac_bytes_into_buffer*sizeof(unsigned char));
1258
bread = fread((void*)(st->m_aac_buffer + st->m_aac_bytes_into_buffer),
1259
1, st->m_aac_bytes_consumed, st->aacfile);
1261
if (bread != st->m_aac_bytes_consumed)
1264
st->m_aac_bytes_into_buffer += bread;
1267
st->m_aac_bytes_consumed = 0;
1269
if (st->m_aac_bytes_into_buffer > 3)
1271
if (memcmp(st->m_aac_buffer, "TAG", 3) == 0)
1272
st->m_aac_bytes_into_buffer = 0;
1274
if (st->m_aac_bytes_into_buffer > 11)
1276
if (memcmp(st->m_aac_buffer, "LYRICSBEGIN", 11) == 0)
1277
st->m_aac_bytes_into_buffer = 0;
1279
if (st->m_aac_bytes_into_buffer > 8)
1281
if (memcmp(st->m_aac_buffer, "APETAGEX", 8) == 0)
1282
st->m_aac_bytes_into_buffer = 0;
1289
void advance_buffer(state *st, int bytes)
1291
st->m_file_offset += bytes;
1292
st->m_aac_bytes_consumed = bytes;
1293
st->m_aac_bytes_into_buffer -= bytes;
1296
int adts_parse(state *st, __int64 *bitrate, double *length)
1298
static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000};
1299
int frames, frame_length;
1300
int t_framelength = 0;
1302
double frames_per_sec, bytes_per_frame;
1304
/* Read all frames to ensure correct time and bitrate */
1305
for (frames = 0; /* */; frames++)
1309
if (st->m_aac_bytes_into_buffer > 7)
1311
/* check syncword */
1312
if (!((st->m_aac_buffer[0] == 0xFF)&&((st->m_aac_buffer[1] & 0xF6) == 0xF0)))
1315
st->m_tail->offset = st->m_file_offset;
1316
st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
1317
st->m_tail = st->m_tail->next;
1318
st->m_tail->next = NULL;
1321
samplerate = sample_rates[(st->m_aac_buffer[2]&0x3c)>>2];
1323
frame_length = ((((unsigned int)st->m_aac_buffer[3] & 0x3)) << 11)
1324
| (((unsigned int)st->m_aac_buffer[4]) << 3) | (st->m_aac_buffer[5] >> 5);
1326
t_framelength += frame_length;
1328
if (frame_length > st->m_aac_bytes_into_buffer)
1331
advance_buffer(st, frame_length);
1337
frames_per_sec = (double)samplerate/1024.0;
1339
bytes_per_frame = (double)t_framelength/(double)(frames*1000);
1341
bytes_per_frame = 0;
1342
*bitrate = (__int64)(8. * bytes_per_frame * frames_per_sec + 0.5);
1343
if (frames_per_sec != 0)
1344
*length = (double)frames/frames_per_sec;
1351
int skip_id3v2_tag()
1353
unsigned char buf[10];
1354
int bread, tagsize = 0;
1356
bread = fread(buf, 1, 10, mp4state.aacfile);
1357
if (bread != 10) return -1;
1359
if (!memcmp(buf, "ID3", 3))
1361
/* high bit is not used */
1362
tagsize = (buf[6] << 21) | (buf[7] << 14) | (buf[8] << 7) | (buf[9] << 0);
1365
fseek(mp4state.aacfile, tagsize, SEEK_SET);
1367
fseek(mp4state.aacfile, 0, SEEK_SET);
1377
int avg_bitrate, br, sr;
1378
unsigned char *buffer;
1380
NeAACDecConfigurationPtr config;
1381
unsigned char header[8];
1385
in_mp4_DebugOutput("play");
1388
memset(&mp4state, 0, sizeof(state));
1390
lstrcpy(mp4state.filename, fn);
1392
hMP4File = fopen(mp4state.filename, "rb");
1397
fread(header, 1, 8, hMP4File);
1399
mp4state.filetype = 1;
1400
if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p')
1401
mp4state.filetype = 0;
1403
if (mp4state.filetype)
1405
int tagsize = 0, tmp = 0, init;
1408
__int64 bitrate = 128;
1409
// NeAACDecFrameInfo frameInfo;
1411
module.is_seekable = 1;
1413
if (!(mp4state.aacfile = fopen(mp4state.filename, "rb")))
1419
tagsize = skip_id3v2_tag();
1420
if (tagsize<0) return 0;
1422
if (!(mp4state.m_aac_buffer = (unsigned char*)malloc(768*6)))
1424
show_error(module.hMainWindow, "Memory allocation error.");
1428
for (init=0; init<2; init++)
1430
mp4state.hDecoder = NeAACDecOpen();
1431
if (!mp4state.hDecoder)
1433
show_error(module.hMainWindow, "Unable to open decoder library.");
1437
config = NeAACDecGetCurrentConfiguration(mp4state.hDecoder);
1438
config->outputFormat = m_resolution + 1;
1439
config->downMatrix = m_downmix;
1440
NeAACDecSetConfiguration(mp4state.hDecoder, config);
1442
memset(mp4state.m_aac_buffer, 0, 768*6);
1443
bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
1444
mp4state.m_aac_bytes_into_buffer = bread;
1445
mp4state.m_aac_bytes_consumed = 0;
1446
mp4state.m_file_offset = 0;
1447
mp4state.m_at_eof = (bread != 768*6) ? 1 : 0;
1451
NeAACDecFrameInfo frameInfo;
1453
fill_buffer(&mp4state);
1455
if ((mp4state.m_aac_bytes_consumed = NeAACDecInit(mp4state.hDecoder,
1456
mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
1457
&mp4state.samplerate, &mp4state.channels)) < 0)
1459
show_error(module.hMainWindow, "Can't initialize decoder library.");
1462
advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
1465
memset(&frameInfo, 0, sizeof(NeAACDecFrameInfo));
1466
fill_buffer(&mp4state);
1467
NeAACDecDecode(mp4state.hDecoder, &frameInfo, mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer);
1468
} while (!frameInfo.samples && !frameInfo.error);
1470
if (frameInfo.error)
1472
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
1476
mp4state.channels = frameInfo.channels;
1477
mp4state.samplerate = frameInfo.samplerate;
1478
mp4state.framesize = (frameInfo.channels != 0) ? frameInfo.samples/frameInfo.channels : 0;
1480
sbr = frameInfo.sbr;
1481
profile = frameInfo.object_type;
1482
header_type = frameInfo.header_type;
1485
NeAACDecClose(mp4state.hDecoder);
1486
fseek(mp4state.aacfile, tagsize, SEEK_SET);
1490
mp4state.m_head = (struct seek_list*)malloc(sizeof(struct seek_list));
1491
mp4state.m_tail = mp4state.m_head;
1492
mp4state.m_tail->next = NULL;
1494
mp4state.m_header_type = 0;
1495
if ((mp4state.m_aac_buffer[0] == 0xFF) && ((mp4state.m_aac_buffer[1] & 0xF6) == 0xF0))
1499
adts_parse(&mp4state, &bitrate, &length);
1500
fseek(mp4state.aacfile, tagsize, SEEK_SET);
1502
bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
1504
mp4state.m_at_eof = 1;
1506
mp4state.m_at_eof = 0;
1507
mp4state.m_aac_bytes_into_buffer = bread;
1508
mp4state.m_aac_bytes_consumed = 0;
1510
mp4state.m_header_type = 1;
1512
} else if (memcmp(mp4state.m_aac_buffer, "ADIF", 4) == 0) {
1513
int skip_size = (mp4state.m_aac_buffer[4] & 0x80) ? 9 : 0;
1514
bitrate = ((unsigned int)(mp4state.m_aac_buffer[4 + skip_size] & 0x0F)<<19) |
1515
((unsigned int)mp4state.m_aac_buffer[5 + skip_size]<<11) |
1516
((unsigned int)mp4state.m_aac_buffer[6 + skip_size]<<3) |
1517
((unsigned int)mp4state.m_aac_buffer[7 + skip_size] & 0xE0);
1519
length = (double)file_length(mp4state.aacfile);
1522
module.is_seekable = 0;
1525
length = ((double)length*8.)/((double)bitrate) + 0.5;
1528
mp4state.m_header_type = 2;
1530
length = (double)file_length(mp4state.aacfile);
1531
length = ((double)length*8.)/((double)bitrate*1000.) + 0.5;
1533
module.is_seekable = 1;
1536
mp4state.m_length = (int)(length*1000.);
1538
fill_buffer(&mp4state);
1539
if ((mp4state.m_aac_bytes_consumed = NeAACDecInit(mp4state.hDecoder,
1540
mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
1541
&mp4state.samplerate, &mp4state.channels)) < 0)
1543
show_error(module.hMainWindow, "Can't initialize decoder library.");
1546
advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
1548
if (mp4state.m_header_type == 2)
1549
avg_bitrate = bitrate;
1551
avg_bitrate = bitrate*1000;
1553
mp4state.hDecoder = NeAACDecOpen();
1554
if (!mp4state.hDecoder)
1556
show_error(module.hMainWindow, "Unable to open decoder library.");
1560
config = NeAACDecGetCurrentConfiguration(mp4state.hDecoder);
1561
config->outputFormat = m_resolution + 1;
1562
config->downMatrix = m_downmix;
1563
NeAACDecSetConfiguration(mp4state.hDecoder, config);
1565
mp4state.mp4File = fopen(mp4state.filename, "rb");
1566
mp4state.mp4cb.read = read_callback;
1567
mp4state.mp4cb.seek = seek_callback;
1568
mp4state.mp4cb.user_data = mp4state.mp4File;
1571
mp4state.mp4file = mp4ff_open_read(&mp4state.mp4cb);
1572
if (!mp4state.mp4file)
1574
show_error(module.hMainWindow, "Unable to open file.");
1575
NeAACDecClose(mp4state.hDecoder);
1579
if ((mp4state.mp4track = GetAACTrack(mp4state.mp4file)) < 0)
1581
show_error(module.hMainWindow, "Unsupported Audio track type.");
1582
NeAACDecClose(mp4state.hDecoder);
1583
mp4ff_close(mp4state.mp4file);
1584
fclose(mp4state.mp4File);
1590
mp4ff_get_decoder_config(mp4state.mp4file, mp4state.mp4track,
1591
&buffer, &buffer_size);
1594
NeAACDecClose(mp4state.hDecoder);
1595
mp4ff_close(mp4state.mp4file);
1596
fclose(mp4state.mp4File);
1600
if(NeAACDecInit2(mp4state.hDecoder, buffer, buffer_size,
1601
&mp4state.samplerate, &mp4state.channels) < 0)
1603
/* If some error initializing occured, skip the file */
1604
NeAACDecClose(mp4state.hDecoder);
1605
mp4ff_close(mp4state.mp4file);
1606
fclose(mp4state.mp4File);
1607
if (buffer) free (buffer);
1611
/* for gapless decoding */
1613
mp4AudioSpecificConfig mp4ASC;
1615
mp4state.timescale = mp4ff_time_scale(mp4state.mp4file, mp4state.mp4track);
1616
mp4state.framesize = 1024;
1617
mp4state.useAacLength = 0;
1621
if (NeAACDecAudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0)
1623
if (mp4ASC.frameLengthFlag == 1) mp4state.framesize = 960;
1624
if (mp4ASC.sbr_present_flag == 1) mp4state.framesize *= 2;
1631
avg_bitrate = mp4ff_get_avg_bitrate(mp4state.mp4file, mp4state.mp4track);
1633
mp4state.numSamples = mp4ff_num_samples(mp4state.mp4file, mp4state.mp4track);
1634
mp4state.sampleId = 0;
1637
double timescale_div = 1.0 / (double)mp4ff_time_scale(mp4state.mp4file, mp4state.mp4track);
1638
int64_t duration = mp4ff_get_track_duration_use_offsets(mp4state.mp4file, mp4state.mp4track);
1641
mp4state.m_length = 0;
1643
mp4state.m_length = (int)((double)duration * timescale_div * 1000.0);
1647
module.is_seekable = 1;
1650
if (mp4state.channels == 0)
1652
show_error(module.hMainWindow, "Number of channels not supported for playback.");
1653
NeAACDecClose(mp4state.hDecoder);
1654
if (mp4state.filetype)
1655
fclose(mp4state.aacfile);
1657
mp4ff_close(mp4state.mp4file);
1658
fclose(mp4state.mp4File);
1663
if (m_downmix && (mp4state.channels == 5 || mp4state.channels == 6))
1664
mp4state.channels = 2;
1666
maxlatency = module.outMod->Open(mp4state.samplerate, (int)mp4state.channels,
1667
res_table[m_resolution], -1, -1);
1669
if (maxlatency < 0) // error opening device
1671
NeAACDecClose(mp4state.hDecoder);
1672
if (mp4state.filetype)
1673
fclose(mp4state.aacfile);
1675
mp4ff_close(mp4state.mp4file);
1676
fclose(mp4state.mp4File);
1681
mp4state.paused = 0;
1682
mp4state.decode_pos_ms = 0;
1683
mp4state.seek_needed = -1;
1685
// initialize vis stuff
1686
module.SAVSAInit(maxlatency, mp4state.samplerate);
1687
module.VSASetInfo((int)mp4state.channels, mp4state.samplerate);
1689
br = (int)floor(((float)avg_bitrate + 500.0)/1000.0 + 0.5);
1690
sr = (int)floor((float)mp4state.samplerate/1000.0 + 0.5);
1691
module.SetInfo(br, sr, (int)mp4state.channels, 1);
1693
module.outMod->SetVolume(-666); // set the output plug-ins default volume
1697
if (mp4state.filetype)
1699
if ((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AACPlayThread,
1700
(void *)&killPlayThread, 0, &thread_id)) == NULL)
1702
show_error(module.hMainWindow, "Cannot create playback thread");
1703
NeAACDecClose(mp4state.hDecoder);
1704
fclose(mp4state.aacfile);
1708
if ((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MP4PlayThread,
1709
(void *)&killPlayThread, 0, &thread_id)) == NULL)
1711
show_error(module.hMainWindow, "Cannot create playback thread");
1712
NeAACDecClose(mp4state.hDecoder);
1713
mp4ff_close(mp4state.mp4file);
1714
fclose(mp4state.mp4File);
1719
SetThreadAffinityMask(play_thread_handle, 1);
1721
SetThreadPriority(play_thread_handle, priority_table[m_priority]);
1729
in_mp4_DebugOutput("pause");
1732
mp4state.paused = 1;
1733
module.outMod->Pause(1);
1739
in_mp4_DebugOutput("unpause");
1742
mp4state.paused = 0;
1743
module.outMod->Pause(0);
1749
in_mp4_DebugOutput("ispaused");
1752
return mp4state.paused;
1755
void setvolume(int volume)
1758
in_mp4_DebugOutput("setvolume");
1761
module.outMod->SetVolume(volume);
1764
void setpan(int pan)
1767
in_mp4_DebugOutput("setpan");
1770
module.outMod->SetPan(pan);
1775
struct seek_list *target = mp4state.m_head;
1778
in_mp4_DebugOutput("stop");
1783
if (play_thread_handle != INVALID_HANDLE_VALUE)
1785
if (WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
1786
TerminateThread(play_thread_handle,0);
1787
CloseHandle(play_thread_handle);
1788
play_thread_handle = INVALID_HANDLE_VALUE;
1792
if (mp4state.m_aac_buffer)
1793
free(mp4state.m_aac_buffer);
1797
struct seek_list *tmp = target;
1798
target = target->next;
1801
NeAACDecClose(mp4state.hDecoder);
1802
if (mp4state.filetype)
1803
fclose(mp4state.aacfile);
1805
mp4ff_close(mp4state.mp4file);
1806
fclose(mp4state.mp4File);
1809
module.outMod->Close();
1810
module.SAVSADeInit();
1812
mp4state.filename[0] = '\0';
1815
int getsonglength(const char *fn)
1817
long msDuration = 0;
1819
if(!stricmp(fn + strlen(fn) - 3,"MP4") || !stricmp(fn + strlen(fn) - 3,"M4A"))
1825
mp4ff_callback_t mp4cb = {0};
1827
mp4File = fopen(fn, "rb");
1828
mp4cb.read = read_callback;
1829
mp4cb.seek = seek_callback;
1830
mp4cb.user_data = mp4File;
1833
file = mp4ff_open_read(&mp4cb);
1837
if ((track = GetAACTrack(file)) < 0)
1844
length = mp4ff_get_track_duration(file, track);
1846
msDuration = (long)((float)length*1000.0 / (float)mp4ff_time_scale(file, track) + 0.5);
1856
__int64 bitrate = 128;
1857
struct seek_list *target;
1860
memset(&len_state, 0, sizeof(state));
1862
if (!(len_state.aacfile = fopen(fn, "rb")))
1868
len_state.m_at_eof = 0;
1870
if (!(len_state.m_aac_buffer = (unsigned char*)malloc(768*6)))
1872
//console::error("Memory allocation error.", "foo_mp4");
1875
memset(len_state.m_aac_buffer, 0, 768*6);
1877
bread = fread(len_state.m_aac_buffer, 1, 768*6, len_state.aacfile);
1878
len_state.m_aac_bytes_into_buffer = bread;
1879
len_state.m_aac_bytes_consumed = 0;
1880
len_state.m_file_offset = 0;
1883
len_state.m_at_eof = 1;
1885
if (!memcmp(len_state.m_aac_buffer, "ID3", 3))
1887
/* high bit is not used */
1888
tagsize = (len_state.m_aac_buffer[6] << 21) | (len_state.m_aac_buffer[7] << 14) |
1889
(len_state.m_aac_buffer[8] << 7) | (len_state.m_aac_buffer[9] << 0);
1892
advance_buffer(&len_state, tagsize);
1895
len_state.m_head = (struct seek_list*)malloc(sizeof(struct seek_list));
1896
len_state.m_tail = len_state.m_head;
1897
len_state.m_tail->next = NULL;
1899
len_state.m_header_type = 0;
1900
if ((len_state.m_aac_buffer[0] == 0xFF) && ((len_state.m_aac_buffer[1] & 0xF6) == 0xF0))
1902
if (1) //(m_reader->can_seek())
1904
adts_parse(&len_state, &bitrate, &length);
1905
fseek(len_state.aacfile, tagsize, SEEK_SET);
1907
bread = fread(len_state.m_aac_buffer, 1, 768*6, len_state.aacfile);
1909
len_state.m_at_eof = 1;
1911
len_state.m_at_eof = 0;
1912
len_state.m_aac_bytes_into_buffer = bread;
1913
len_state.m_aac_bytes_consumed = 0;
1915
len_state.m_header_type = 1;
1917
} else if (memcmp(len_state.m_aac_buffer, "ADIF", 4) == 0) {
1918
int skip_size = (len_state.m_aac_buffer[4] & 0x80) ? 9 : 0;
1919
bitrate = ((unsigned int)(len_state.m_aac_buffer[4 + skip_size] & 0x0F)<<19) |
1920
((unsigned int)len_state.m_aac_buffer[5 + skip_size]<<11) |
1921
((unsigned int)len_state.m_aac_buffer[6 + skip_size]<<3) |
1922
((unsigned int)len_state.m_aac_buffer[7 + skip_size] & 0xE0);
1924
length = (double)file_length(len_state.aacfile);
1928
length = ((double)length*8.)/((double)bitrate) + 0.5;
1930
len_state.m_header_type = 2;
1932
length = (double)file_length(len_state.aacfile);
1933
length = ((double)length*8.)/((double)bitrate*1000.) + 0.5;
1935
len_state.m_header_type = 0;
1938
if (len_state.m_aac_buffer)
1939
free(len_state.m_aac_buffer);
1941
target = len_state.m_head;
1944
struct seek_list *tmp = target;
1945
target = target->next;
1949
fclose(len_state.aacfile);
1951
return (int)(length*1000.);
1957
if (!mp4state.filetype)
1963
if ((track = GetAACTrack(mp4state.mp4file)) < 0)
1968
length = mp4ff_get_track_duration(mp4state.mp4file, track);
1970
msDuration = (long)(length*1000.0 / (float)mp4ff_time_scale(mp4state.mp4file, track) + 0.5);
1974
return mp4state.m_length;
1981
return mp4state.decode_pos_ms+(module.outMod->GetOutputTime()-module.outMod->GetWrittenTime());
1984
void setoutputtime(int time_in_ms)
1987
in_mp4_DebugOutput("setoutputtime");
1990
mp4state.seek_needed = time_in_ms;
1993
void getfileinfo(char *filename, char *title, int *length_in_ms)
1995
if (!filename || !*filename) /* currently playing file */
1998
*length_in_ms = getlength();
2002
if (mp4state.filetype == 0)
2004
ConstructTitle(mp4state.mp4file, mp4state.filename, title, titleformat);
2007
char *tmp = PathFindFileName(mp4state.filename);
2009
tmp2 = strrchr(title, '.');
2015
*length_in_ms = getsonglength(filename);
2019
unsigned char header[8];
2020
FILE *hMP4File = fopen(filename, "rb");
2025
fread(header, 1, 8, hMP4File);
2028
if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p')
2032
mp4ff_callback_t mp4cb = {0};
2034
mp4File = fopen(filename, "rb");
2035
mp4cb.read = read_callback;
2036
mp4cb.seek = seek_callback;
2037
mp4cb.user_data = mp4File;
2039
file = mp4ff_open_read(&mp4cb);
2043
ConstructTitle(file, filename, title, titleformat);
2049
char *tmp = PathFindFileName(filename);
2051
tmp2 = strrchr(title, '.');
2058
void eq_set(int on, char data[10], int preamp)
2062
static void remap_channels(unsigned char *data, unsigned int samples, unsigned int bps)
2070
unsigned char r1, r2, r3, r4, r5, r6;
2071
for (i = 0; i < samples; i += 6)
2092
unsigned short r1, r2, r3, r4, r5, r6;
2093
unsigned short *sample_buffer = (unsigned short *)data;
2094
for (i = 0; i < samples; i += 6)
2096
r1 = sample_buffer[i];
2097
r2 = sample_buffer[i+1];
2098
r3 = sample_buffer[i+2];
2099
r4 = sample_buffer[i+3];
2100
r5 = sample_buffer[i+4];
2101
r6 = sample_buffer[i+5];
2102
sample_buffer[i] = r2;
2103
sample_buffer[i+1] = r3;
2104
sample_buffer[i+2] = r1;
2105
sample_buffer[i+3] = r6;
2106
sample_buffer[i+4] = r4;
2107
sample_buffer[i+5] = r5;
2115
unsigned int r1, r2, r3, r4, r5, r6;
2116
unsigned int *sample_buffer = (unsigned int *)data;
2117
for (i = 0; i < samples; i += 6)
2119
r1 = sample_buffer[i];
2120
r2 = sample_buffer[i+1];
2121
r3 = sample_buffer[i+2];
2122
r4 = sample_buffer[i+3];
2123
r5 = sample_buffer[i+4];
2124
r6 = sample_buffer[i+5];
2125
sample_buffer[i] = r2;
2126
sample_buffer[i+1] = r3;
2127
sample_buffer[i+2] = r1;
2128
sample_buffer[i+3] = r6;
2129
sample_buffer[i+4] = r4;
2130
sample_buffer[i+5] = r5;
2137
DWORD WINAPI MP4PlayThread(void *b)
2144
void *sample_buffer;
2145
unsigned char *buffer;
2147
NeAACDecFrameInfo frameInfo;
2150
in_mp4_DebugOutput("MP4PlayThread");
2153
PlayThreadAlive = 1;
2154
mp4state.last_frame = 0;
2155
mp4state.initial = 1;
2157
while (!*((int *)b))
2160
if (mp4state.seek_needed != -1)
2163
int32_t skip_samples = 0;
2165
module.outMod->Flush(mp4state.decode_pos_ms);
2166
duration = (int64_t)(mp4state.seek_needed/1000.0 * mp4state.samplerate + 0.5);
2167
mp4state.sampleId = mp4ff_find_sample_use_offsets(mp4state.mp4file,
2168
mp4state.mp4track, duration, &skip_samples);
2170
mp4state.decode_pos_ms = mp4state.seek_needed;
2171
mp4state.seek_needed = -1;
2176
module.outMod->CanWrite();
2178
if (!module.outMod->IsPlaying())
2180
PostMessage(module.hMainWindow, WM_WA_AAC_EOF, 0, 0);
2181
PlayThreadAlive = 0;
2186
} else if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short))) {
2188
if (mp4state.last_frame)
2194
/* for gapless decoding */
2197
unsigned int sample_count;
2198
unsigned int delay = 0;
2200
/* get acces unit from MP4 file */
2204
dur = mp4ff_get_sample_duration(mp4state.mp4file, mp4state.mp4track, mp4state.sampleId);
2205
rc = mp4ff_read_sample(mp4state.mp4file, mp4state.mp4track, mp4state.sampleId++, &buffer, &buffer_size);
2207
if (mp4state.sampleId == 1) dur = 0;
2208
if (rc == 0 || buffer == NULL)
2210
mp4state.last_frame = 1;
2211
sample_buffer = NULL;
2212
frameInfo.samples = 0;
2214
sample_buffer = NeAACDecDecode(mp4state.hDecoder, &frameInfo,
2215
buffer, buffer_size);
2217
if (frameInfo.error > 0)
2219
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
2220
mp4state.last_frame = 1;
2222
if (mp4state.sampleId >= mp4state.numSamples)
2223
mp4state.last_frame = 1;
2225
if (buffer) free(buffer);
2227
if (mp4state.useAacLength || (mp4state.timescale != mp4state.samplerate)) {
2228
sample_count = frameInfo.samples;
2230
sample_count = (unsigned int)(dur * frameInfo.channels);
2232
if (!mp4state.useAacLength && !mp4state.initial && (mp4state.sampleId < mp4state.numSamples/2) && (dur*frameInfo.channels != frameInfo.samples))
2234
//fprintf(stderr, "MP4 seems to have incorrect frame duration, using values from AAC data.\n");
2235
mp4state.useAacLength = 1;
2236
sample_count = frameInfo.samples;
2240
if (mp4state.initial && (sample_count < mp4state.framesize*mp4state.channels) && (frameInfo.samples > sample_count))
2242
delay = frameInfo.samples - sample_count;
2245
if (!killPlayThread && (sample_count > 0))
2247
buf = (char *)sample_buffer;
2248
mp4state.initial = 0;
2250
switch (res_table[m_resolution])
2267
if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
2268
remap_channels(buf, sample_count, res_table[m_resolution]);
2270
if (res_table[m_resolution] == 24)
2272
/* convert libfaad output (3 bytes packed in 4) */
2273
char *temp_buffer = convert3in4to3in3(buf, sample_count);
2274
memcpy((void*)buf, (void*)temp_buffer, sample_count*3);
2278
module.SAAddPCMData(buf, (int)mp4state.channels, res_table[m_resolution],
2279
mp4state.decode_pos_ms);
2280
module.VSAAddPCMData(buf, (int)mp4state.channels, res_table[m_resolution],
2281
mp4state.decode_pos_ms);
2282
mp4state.decode_pos_ms += (double)sample_count * 1000.0 /
2283
((double)frameInfo.samplerate * (double)frameInfo.channels);
2285
l = sample_count * res_table[m_resolution] / 8;
2287
if (module.dsp_isactive())
2289
void *dsp_buffer = malloc(l*2);
2290
memcpy(dsp_buffer, buf, l);
2292
l = module.dsp_dosamples((short*)dsp_buffer,
2293
sample_count/frameInfo.channels,
2294
res_table[m_resolution],
2296
frameInfo.samplerate) *
2297
(frameInfo.channels*(res_table[m_resolution]/8));
2299
module.outMod->Write(dsp_buffer, l);
2300
if (dsp_buffer) free(dsp_buffer);
2302
module.outMod->Write(buf, l);
2305
/* VBR bitrate display */
2309
seq_bytes += frameInfo.bytesconsumed;
2310
if (seq_frames == (int)(floor((float)frameInfo.samplerate/(float)(sample_count/frameInfo.channels) + 0.5)))
2312
module.SetInfo((int)floor(((float)seq_bytes*8.)/1000. + 0.5),
2313
(int)floor(frameInfo.samplerate/1000. + 0.5),
2314
mp4state.channels, 1);
2327
PlayThreadAlive = 0;
2332
void *decode_aac_frame(state *st, NeAACDecFrameInfo *frameInfo)
2334
void *sample_buffer = NULL;
2340
if (st->m_aac_bytes_into_buffer != 0)
2342
sample_buffer = NeAACDecDecode(st->hDecoder, frameInfo,
2343
st->m_aac_buffer, st->m_aac_bytes_into_buffer);
2345
if (st->m_header_type != 1)
2347
if (st->last_offset < st->m_file_offset)
2349
st->m_tail->offset = st->m_file_offset;
2350
st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
2351
st->m_tail = st->m_tail->next;
2352
st->m_tail->next = NULL;
2353
st->last_offset = st->m_file_offset;
2357
advance_buffer(st, frameInfo->bytesconsumed);
2362
} while (!frameInfo->samples && !frameInfo->error);
2364
return sample_buffer;
2367
int aac_seek(state *st, double seconds)
2371
struct seek_list *target = st->m_head;
2373
if (1 /*can_seek*/ && ((st->m_header_type == 1) || (seconds < st->cur_pos_sec)))
2375
frames = (int)(seconds*((double)st->samplerate/(double)st->framesize) + 0.5);
2377
for (i = 0; i < frames; i++)
2380
target = target->next;
2384
if (target->offset == 0 && frames > 0)
2386
fseek(st->aacfile, target->offset, SEEK_SET);
2387
st->m_file_offset = target->offset;
2389
bread = fread(st->m_aac_buffer, 1, 768*6, st->aacfile);
2394
st->m_aac_bytes_into_buffer = bread;
2395
st->m_aac_bytes_consumed = 0;
2396
st->m_file_offset += bread;
2398
NeAACDecPostSeekReset(st->hDecoder, -1);
2402
if (seconds > st->cur_pos_sec)
2404
NeAACDecFrameInfo frameInfo;
2406
frames = (int)((seconds - st->cur_pos_sec)*((double)st->samplerate/(double)st->framesize));
2410
for (i = 0; i < frames; i++)
2412
memset(&frameInfo, 0, sizeof(NeAACDecFrameInfo));
2413
decode_aac_frame(st, &frameInfo);
2415
if (frameInfo.error || (st->m_aac_bytes_into_buffer == 0))
2417
if (frameInfo.error)
2419
if (NeAACDecGetErrorMessage(frameInfo.error) != NULL)
2420
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
2427
NeAACDecPostSeekReset(st->hDecoder, -1);
2433
DWORD WINAPI AACPlayThread(void *b)
2441
in_mp4_DebugOutput("AACPlayThread");
2444
PlayThreadAlive = 1;
2445
mp4state.last_frame = 0;
2447
while (!*((int *)b))
2450
if (mp4state.seek_needed != -1)
2454
ms = mp4state.seek_needed/1000;
2455
if (aac_seek(&mp4state, ms)!=0)
2457
module.outMod->Flush(mp4state.decode_pos_ms);
2458
mp4state.cur_pos_sec = ms;
2459
mp4state.decode_pos_ms = mp4state.seek_needed;
2461
mp4state.seek_needed = -1;
2466
module.outMod->CanWrite();
2468
if (!module.outMod->IsPlaying())
2470
PostMessage(module.hMainWindow, WM_WA_AAC_EOF, 0, 0);
2471
PlayThreadAlive = 0;
2476
} else if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short))) {
2477
NeAACDecFrameInfo frameInfo;
2478
void *sample_buffer;
2480
memset(&frameInfo, 0, sizeof(NeAACDecFrameInfo));
2482
sample_buffer = decode_aac_frame(&mp4state, &frameInfo);
2484
if (frameInfo.error || (mp4state.m_aac_bytes_into_buffer == 0))
2486
if (frameInfo.error)
2488
if (NeAACDecGetErrorMessage(frameInfo.error) != NULL)
2489
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
2494
if (!killPlayThread && (frameInfo.samples > 0))
2496
if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
2497
remap_channels(sample_buffer, frameInfo.samples, res_table[m_resolution]);
2499
if (res_table[m_resolution] == 24)
2501
/* convert libfaad output (3 bytes packed in 4 bytes) */
2502
char *temp_buffer = convert3in4to3in3(sample_buffer, frameInfo.samples);
2503
memcpy((void*)sample_buffer, (void*)temp_buffer, frameInfo.samples*3);
2507
module.SAAddPCMData(sample_buffer, (int)mp4state.channels, res_table[m_resolution],
2508
mp4state.decode_pos_ms);
2509
module.VSAAddPCMData(sample_buffer, (int)mp4state.channels, res_table[m_resolution],
2510
mp4state.decode_pos_ms);
2511
mp4state.decode_pos_ms += (double)frameInfo.samples * 1000.0 /
2512
((double)frameInfo.samplerate* (double)frameInfo.channels);
2514
l = frameInfo.samples * res_table[m_resolution] / 8;
2516
if (module.dsp_isactive())
2518
void *dsp_buffer = malloc(l*2);
2519
memcpy(dsp_buffer, sample_buffer, l);
2521
l = module.dsp_dosamples((short*)dsp_buffer,
2522
frameInfo.samples/frameInfo.channels,
2523
res_table[m_resolution],
2525
frameInfo.samplerate) *
2526
(frameInfo.channels*(res_table[m_resolution]/8));
2528
module.outMod->Write(dsp_buffer, l);
2529
if (dsp_buffer) free(dsp_buffer);
2531
module.outMod->Write(sample_buffer, l);
2534
/* VBR bitrate display */
2538
seq_bytes += frameInfo.bytesconsumed;
2539
if (seq_frames == (int)(floor((float)frameInfo.samplerate/(float)(frameInfo.samples/frameInfo.channels) + 0.5)))
2541
module.SetInfo((int)floor(((float)seq_bytes*8.)/1000. + 0.5),
2542
(int)floor(frameInfo.samplerate/1000. + 0.5),
2543
mp4state.channels, 1);
2551
if (frameInfo.channels > 0 && mp4state.samplerate > 0)
2552
mp4state.cur_pos_sec += ((double)(frameInfo.samples/frameInfo.channels))/(double)mp4state.samplerate;
2558
PlayThreadAlive = 0;
2563
static In_Module module =
2566
"AudioCoding.com MPEG-4 AAC player: " FAAD2_VERSION " compiled on " __DATE__,
2592
0,0,0,0,0,0,0,0,0, // vis stuff
2604
__declspec(dllexport) In_Module* winampGetInModule2()
2610
module.FileExtensions = short_ext_list;
2612
module.FileExtensions = long_ext_list;
2618
/* new Media Library interface */
2620
int mp4_get_metadata(mp4ff_t *file, const char *item, char *dest, int dlen)
2622
char *pVal = NULL, dummy1[4096];
2624
if (dlen < 1) return 0;
2626
if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
2628
if (mp4ff_meta_get_track(file, &pVal))
2630
wsprintf(dummy1, "%s", pVal);
2631
strncpy(dest, dummy1, dlen-1);
2632
dest[dlen-1] = '\0';
2636
else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
2638
if (mp4ff_meta_get_disc(file, &pVal))
2640
wsprintf(dummy1, "%s", pVal);
2641
strncpy(dest, dummy1, dlen-1);
2642
dest[dlen-1] = '\0';
2646
else if (!stricmp(item, "compilation"))
2649
if (mp4ff_meta_get_compilation(file, &pVal))
2651
wsprintf(dummy1, "%s", pVal);
2652
strncpy(dest, dummy1, dlen-1);
2653
dest[dlen-1] = '\0';
2657
else if (!stricmp(item, "tempo"))
2659
if (mp4ff_meta_get_tempo(file, &pVal))
2661
wsprintf(dummy1, "%s", pVal);
2662
strncpy(dest, dummy1, dlen-1);
2663
dest[dlen-1] = '\0';
2667
else if (!stricmp(item, "artist"))
2669
if (mp4ff_meta_get_artist(file, &pVal))
2671
strncpy(dest, pVal, dlen-1);
2672
dest[dlen-1] = '\0';
2676
else if (!stricmp(item, "writer"))
2678
if (mp4ff_meta_get_writer(file, &pVal))
2680
strncpy(dest, pVal, dlen-1);
2681
dest[dlen-1] = '\0';
2685
else if (!stricmp(item, "title"))
2687
if (mp4ff_meta_get_title(file, &pVal))
2689
strncpy(dest, pVal, dlen-1);
2690
dest[dlen-1] = '\0';
2694
else if (!stricmp(item, "album"))
2696
if (mp4ff_meta_get_album(file, &pVal))
2698
strncpy(dest, pVal, dlen-1);
2699
dest[dlen-1] = '\0';
2703
else if (!stricmp(item, "date") || !stricmp(item, "year"))
2705
if (mp4ff_meta_get_date(file, &pVal))
2707
strncpy(dest, pVal, dlen-1);
2708
dest[dlen-1] = '\0';
2712
else if (!stricmp(item, "comment"))
2714
if (mp4ff_meta_get_comment(file, &pVal))
2716
strncpy(dest, pVal, dlen-1);
2717
dest[dlen-1] = '\0';
2721
else if (!stricmp(item, "genre"))
2723
if (mp4ff_meta_get_genre(file, &pVal))
2725
strncpy(dest, pVal, dlen-1);
2726
dest[dlen-1] = '\0';
2730
else if (!stricmp(item, "tool"))
2732
if (mp4ff_meta_get_tool(file, &pVal))
2734
strncpy(dest, pVal, dlen-1);
2735
dest[dlen-1] = '\0';
2742
uint32_t valueSize = 0;
2743
uint8_t *pValue = NULL;
2745
if (MP4GetMetadataFreeForm(file, (char *)item, &pValue, &valueSize))
2747
unsigned int len = (valueSize < (unsigned int)(dlen-1)) ? valueSize : (unsigned int)(dlen-1);
2748
memcpy(dest, pValue, len);
2758
__declspec(dllexport) int winampGetExtendedFileInfo(const char *fn, const char *data, char *dest, int destlen)
2760
if (!fn || (fn && !*fn) || !destlen) return 0;
2764
if (!stricmp(data, "length"))
2767
int len = getsonglength(fn);
2768
itoa(len, temp, 10);
2769
strncpy(dest, temp, destlen-1);
2770
dest[destlen-1] = '\0';
2774
char temp[2048], temp2[2048];
2776
mp4ff_callback_t mp4cb = {0};
2779
mp4File = fopen(fn, "rb");
2780
mp4cb.read = read_callback;
2781
mp4cb.seek = seek_callback;
2782
mp4cb.write = write_callback;
2783
mp4cb.truncate = truncate_callback;
2784
mp4cb.user_data = mp4File;
2787
file = mp4ff_open_read(&mp4cb);
2788
if (file == NULL) return 0;
2790
if (mp4_get_metadata(file, data, temp, sizeof(temp)))
2792
int len = ConvertUTF8ToANSI(temp, temp2);
2793
if (len > destlen-1) len = destlen-1;
2794
memcpy(dest, temp2, len);
2805
static mp4ff_metadata_t mltags = {0, 0};
2806
static BOOL medialib_init = FALSE;
2807
static char medialib_lastfn[2048] = "";
2809
__declspec(dllexport) int winampSetExtendedFileInfo(const char *fn, const char *data, char *val)
2814
if (!medialib_init || (medialib_init && stricmp(fn, medialib_lastfn))) {
2816
mp4ff_callback_t mp4cb = {0};
2818
strcpy(medialib_lastfn, fn);
2820
if (medialib_init) tag_delete(&mltags);
2822
mp4File = fopen(medialib_lastfn, "rb");
2823
mp4cb.read = read_callback;
2824
mp4cb.seek = seek_callback;
2825
mp4cb.user_data = mp4File;
2828
file = mp4ff_open_read(&mp4cb);
2829
if (file == NULL) return 0;
2831
ReadMP4Tag(file, &mltags);
2836
medialib_init = TRUE;
2840
temp = (char *)malloc((len+1)*4);
2841
if (!temp) return 0;
2843
if (ConvertANSIToUTF8(val, temp))
2846
tag_set_field(&mltags, data, temp, len);
2854
__declspec(dllexport) int winampWriteExtendedFileInfo()
2859
mp4ff_callback_t mp4cb = {0};
2861
mp4File = fopen(medialib_lastfn, "rb+");
2862
mp4cb.read = read_callback;
2863
mp4cb.seek = seek_callback;
2864
mp4cb.write = write_callback;
2865
mp4cb.truncate = truncate_callback;
2866
mp4cb.user_data = mp4File;
2868
mp4ff_meta_update(&mp4cb, &mltags);
2
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
3
** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
5
** This program is free software; you can redistribute it and/or modify
6
** it under the terms of the GNU General Public License as published by
7
** the Free Software Foundation; either version 2 of the License, or
8
** (at your option) any later version.
10
** This program is distributed in the hope that it will be useful,
11
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
** GNU General Public License for more details.
15
** You should have received a copy of the GNU General Public License
16
** along with this program; if not, write to the Free Software
17
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
** Any non-GPL usage of this software or parts of this software is strictly
22
** Commercial non-GPL licensing of this software is possible.
23
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
25
** $Id: in_mp4.c,v 1.56 2004/10/19 18:02:10 menno Exp $
28
//#define DEBUG_OUTPUT
30
#define WIN32_LEAN_AND_MEAN
48
const char *long_ext_list = "MP4\0MPEG-4 Files (*.MP4)\0M4A\0MPEG-4 Files (*.M4A)\0AAC\0AAC Files (*.AAC)\0";
49
const char *short_ext_list = "MP4\0MPEG-4 Files (*.MP4)\0M4A\0MPEG-4 Files (*.M4A)\0";
51
static long priority_table[] = {
53
THREAD_PRIORITY_HIGHEST,
54
THREAD_PRIORITY_ABOVE_NORMAL,
55
THREAD_PRIORITY_NORMAL,
56
THREAD_PRIORITY_BELOW_NORMAL,
57
THREAD_PRIORITY_LOWEST
59
static int res_id_table[] = {
65
/*IDC_16BITS_DITHERED*/ IDC_16BITS /* temp hack */
67
static int res_table[] = {
75
static char info_fn[_MAX_PATH];
77
// post this to the main window at end of file (after playback has stopped)
78
#define WM_WA_AAC_EOF WM_USER+2
82
struct seek_list *next;
89
NeAACDecHandle hDecoder;
91
unsigned char channels;
92
double decode_pos_ms; // current decoding position, in milliseconds
93
int paused; // are we paused?
94
int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
95
char filename[_MAX_PATH];
96
int filetype; /* 0: MP4; 1: AAC */
105
mp4ff_callback_t mp4cb;
110
long m_aac_bytes_into_buffer;
111
long m_aac_bytes_consumed;
112
__int64 m_file_offset;
113
unsigned char *m_aac_buffer;
117
struct seek_list *m_head;
118
struct seek_list *m_tail;
119
unsigned long m_length;
121
/* for gapless decoding */
122
unsigned int useAacLength;
123
unsigned int framesize;
124
unsigned int initial;
125
unsigned long timescale;
128
static state mp4state;
130
static In_Module module; // the output module (declared near the bottom of this file)
132
static int killPlayThread;
133
static int PlayThreadAlive = 0; // 1=play thread still running
134
HANDLE play_thread_handle = INVALID_HANDLE_VALUE; // the handle to the decode thread
136
/* Function definitions */
137
void *decode_aac_frame(state *st, NeAACDecFrameInfo *frameInfo);
138
DWORD WINAPI MP4PlayThread(void *b); // the decode thread procedure
139
DWORD WINAPI AACPlayThread(void *b); // the decode thread procedure
142
uint32_t read_callback(void *user_data, void *buffer, uint32_t length)
144
return fread(buffer, 1, length, (FILE*)user_data);
147
uint32_t seek_callback(void *user_data, uint64_t position)
149
return fseek((FILE*)user_data, position, SEEK_SET);
152
uint32_t write_callback(void *user_data, void *buffer, uint32_t length)
154
return fwrite(buffer, 1, length, (FILE*)user_data);
157
uint32_t truncate_callback(void *user_data)
159
_chsize(fileno((FILE*)user_data), ftell((FILE*)user_data));
164
int tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value, size_t v_len)
166
void *backup = (void *)tags->tags;
168
if (!item || (item && !*item) || !value) return 0;
170
tags->tags = (mp4ff_tag_t *)realloc(tags->tags, (tags->count+1) * sizeof(mp4ff_tag_t));
172
if (backup) free(backup);
177
size_t i_len = strlen(item);
178
if (v_len == 0) v_len = strlen(value);
180
tags->tags[tags->count].item = (char *)malloc(i_len+1);
181
tags->tags[tags->count].value = (char *)malloc(v_len+1);
183
if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
185
if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
186
if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
187
tags->tags[tags->count].item = NULL;
188
tags->tags[tags->count].value = NULL;
192
memcpy(tags->tags[tags->count].item, item, i_len);
193
memcpy(tags->tags[tags->count].value, value, v_len);
194
tags->tags[tags->count].item[i_len] = '\0';
195
tags->tags[tags->count].value[v_len] = '\0';
196
// tags->tags[tags->count].len = v_len;
203
int tag_set_field(mp4ff_metadata_t *tags, const char *item, const char *value, size_t v_len)
207
if (!item || (item && !*item) || !value) return 0;
209
for (i = 0; i < tags->count; i++)
211
if (!stricmp(tags->tags[i].item, item))
213
void *backup = (void *)tags->tags[i].value;
214
if (v_len == 0) v_len = strlen(value);
216
tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
217
if (!tags->tags[i].value)
219
if (backup) free(backup);
223
memcpy(tags->tags[i].value, value, v_len);
224
tags->tags[i].value[v_len] = '\0';
225
// tags->tags[i].len = v_len;
231
return tag_add_field(tags, item, value, v_len);
234
int tag_delete(mp4ff_metadata_t *tags)
238
for (i = 0; i < tags->count; i++)
240
if (tags->tags[i].item) free(tags->tags[i].item);
241
if (tags->tags[i].value) free(tags->tags[i].value);
244
if (tags->tags) free(tags->tags);
250
int ReadMP4Tag(mp4ff_t *file, mp4ff_metadata_t *tags)
252
unsigned __int8 *pValue;
261
if (mp4ff_meta_get_by_index(file, i, (char **)&pName, &pValue))
263
char *val = (char *)strdup(pValue);
266
if (pName[0] == 'ļæ½')
268
if (memcmp(pName, "ļæ½nam", 4) == 0)
270
tag_add_field(tags, "title", val, strlen(val));
271
} else if (memcmp(pName, "ļæ½ART", 4) == 0) {
272
tag_add_field(tags, "artist", val, strlen(val));
273
} else if (memcmp(pName, "ļæ½wrt", 4) == 0) {
274
tag_add_field(tags, "writer", val, strlen(val));
275
} else if (memcmp(pName, "ļæ½alb", 4) == 0) {
276
tag_add_field(tags, "album", val, strlen(val));
277
} else if (memcmp(pName, "ļæ½day", 4) == 0) {
278
tag_add_field(tags, "date", val, strlen(val));
279
} else if (memcmp(pName, "ļæ½too", 4) == 0) {
280
tag_add_field(tags, "tool", val, strlen(val));
281
} else if (memcmp(pName, "ļæ½cmt", 4) == 0) {
282
tag_add_field(tags, "comment", val, strlen(val));
283
} else if (memcmp(pName, "ļæ½gen", 4) == 0) {
284
tag_add_field(tags, "genre", val, strlen(val));
286
tag_add_field(tags, pName, val, strlen(val));
288
} else if (memcmp(pName, "covr", 4) == 0) {
289
tag_add_field(tags, "cover", val, strlen(val));
290
} else if (memcmp(pName, "gnre", 4) == 0) {
291
tag_add_field(tags, "genre", val, strlen(val));
292
} else if (memcmp(pName, "trkn", 4) == 0) {
293
tag_add_field(tags, "tracknumber", val, strlen(val));
294
} else if (memcmp(pName, "disk", 4) == 0) {
295
tag_add_field(tags, "disc", val, strlen(val));
296
} else if (memcmp(pName, "cpil", 4) == 0) {
297
tag_add_field(tags, "compilation", val, strlen(val));
298
} else if (memcmp(pName, "tmpo", 4) == 0) {
299
tag_add_field(tags, "tempo", val, strlen(val));
300
} else if (memcmp(pName, "NDFL", 4) == 0) {
303
tag_add_field(tags, pName, val, strlen(val));
310
} while (pValue != NULL);
317
void in_mp4_DebugOutput(char *message)
321
sprintf(s, "in_mp4: %s", message);
322
OutputDebugString(s);
326
int file_length(FILE *f)
330
fseek(f, 0, SEEK_END);
332
fseek(f, cur, SEEK_SET);
337
static void show_error(HWND hwnd, char *message, ...)
340
MessageBox(hwnd, message, "Error", MB_OK);
343
static void config_init()
346
GetModuleFileName(NULL,INI_FILE,_MAX_PATH);
348
while (p >= INI_FILE && *p != '.') p--;
356
char show_errors[10];
357
char use_for_aac[10];
359
char vbr_display[10];
363
strcpy(show_errors, "1");
364
strcpy(priority, "3");
365
strcpy(resolution, "0");
366
strcpy(use_for_aac, "1");
367
strcpy(downmix, "0");
368
strcpy(vbr_display, "1");
369
strcpy(titleformat, "%7");
379
m_priority = atoi(priority);
380
m_resolution = atoi(resolution);
381
m_show_errors = atoi(show_errors);
382
m_use_for_aac = atoi(use_for_aac);
383
m_downmix = atoi(downmix);
384
m_vbr_display = atoi(vbr_display);
391
char show_errors[10];
392
char use_for_aac[10];
394
char vbr_display[10];
396
itoa(m_priority, priority, 10);
397
itoa(m_resolution, resolution, 10);
398
itoa(m_show_errors, show_errors, 10);
399
itoa(m_use_for_aac, use_for_aac, 10);
400
itoa(m_downmix, downmix, 10);
401
itoa(m_vbr_display, vbr_display, 10);
421
/* Convert UNICODE to UTF-8
422
Return number of bytes written */
423
int unicodeToUtf8 ( const WCHAR* lpWideCharStr, char* lpMultiByteStr, int cwcChars )
425
const unsigned short* pwc = (unsigned short *)lpWideCharStr;
426
unsigned char* pmb = (unsigned char *)lpMultiByteStr;
427
const unsigned short* pwce;
430
if ( cwcChars >= 0 ) {
431
pwce = pwc + cwcChars;
433
pwce = (unsigned short *)((size_t)-1);
436
while ( pwc < pwce ) {
437
unsigned short wc = *pwc++;
439
if ( wc < 0x00000080 ) {
443
if ( wc < 0x00000800 ) {
444
*pmb++ = (char)(0xC0 | ((wc >> 6) & 0x1F));
446
*pmb++ = (char)(0x80 | (wc & 0x3F));
449
if ( wc < 0x00010000 ) {
450
*pmb++ = (char)(0xE0 | ((wc >> 12) & 0x0F));
452
*pmb++ = (char)(0x80 | ((wc >> 6) & 0x3F));
454
*pmb++ = (char)(0x80 | (wc & 0x3F));
464
/* Convert UTF-8 coded string to UNICODE
465
Return number of characters converted */
466
int utf8ToUnicode ( const char* lpMultiByteStr, WCHAR* lpWideCharStr, int cmbChars )
468
const unsigned char* pmb = (unsigned char *)lpMultiByteStr;
469
unsigned short* pwc = (unsigned short *)lpWideCharStr;
470
const unsigned char* pmbe;
473
if ( cmbChars >= 0 ) {
474
pmbe = pmb + cmbChars;
476
pmbe = (unsigned char *)((size_t)-1);
479
while ( pmb < pmbe ) {
484
while ( (cc < 7) && (mb & (1 << (7 - cc)))) {
488
if ( cc == 1 || cc > 6 ) // illegal character combination for UTF-8
494
wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6);
496
if ( pmb == pmbe ) // reached end of the buffer
499
if ( ((mb >> 6) & 0x03) != 2 ) // not part of multibyte character
501
wc |= (mb & 0x3F) << ((cc - 1) * 6);
505
if ( wc & 0xFFFF0000 )
516
/* convert Windows ANSI to UTF-8 */
517
int ConvertANSIToUTF8 ( const char* ansi, char* utf8 )
519
WCHAR* wszValue; // Unicode value
527
ansi_len = strlen ( ansi );
529
if ( (wszValue = (WCHAR *)malloc ( (ansi_len + 1) * 2 )) == NULL )
532
/* Convert ANSI value to Unicode */
533
if ( (len = MultiByteToWideChar ( CP_ACP, 0, ansi, ansi_len + 1, wszValue, (ansi_len + 1) * 2 )) == 0 ) {
538
/* Convert Unicode value to UTF-8 */
539
if ( (len = unicodeToUtf8 ( wszValue, utf8, -1 )) == 0 ) {
549
/* convert UTF-8 to Windows ANSI */
550
int ConvertUTF8ToANSI ( const char* utf8, char* ansi )
552
WCHAR* wszValue; // Unicode value
560
utf8_len = strlen ( utf8 );
562
if ( (wszValue = (WCHAR *)malloc ( (utf8_len + 1) * 2 )) == NULL )
565
/* Convert UTF-8 value to Unicode */
566
if ( (len = utf8ToUnicode ( utf8, wszValue, utf8_len + 1 )) == 0 ) {
571
/* Convert Unicode value to ANSI */
572
if ( (len = WideCharToMultiByte ( CP_ACP, 0, wszValue, -1, ansi, (utf8_len + 1) * 2, NULL, NULL )) == 0 ) {
582
BOOL uSetDlgItemText(HWND hwnd, int id, const char *str)
588
if (!str) return FALSE;
589
if (!*str) return TRUE;
591
temp = malloc(len+1);
592
if (!temp) return FALSE;
593
r = ConvertUTF8ToANSI(str, temp);
595
SetDlgItemText(hwnd, id, temp);
598
return r>0 ? TRUE : FALSE;
601
UINT uGetDlgItemText(HWND hwnd, int id, char *str, int max)
607
if (!str || !max) return 0;
609
w = GetDlgItem(hwnd, id);
610
len = GetWindowTextLength(w);
611
temp = malloc(len+1);
613
utf8 = malloc((len+1)*4);
620
len = GetWindowText(w, temp, len+1);
623
len = ConvertANSIToUTF8(temp, utf8);
629
memcpy(str, utf8, len+1);
638
static void mp4fileinfo(mp4ff_t *mp4, char *info, size_t len)
640
char *ot[6] = { "NULL", "MAIN AAC", "LC AAC", "SSR AAC", "LTP AAC", "HE AAC" };
646
NeAACDecHandle hDecoder;
647
NeAACDecFrameInfo frameInfo;
648
mp4AudioSpecificConfig mp4ASC = {0};
649
unsigned char *buffer = NULL;
651
unsigned long sr = 0;
652
unsigned char ch = 0;
654
if ((track = GetAACTrack(mp4)) < 0)
660
hDecoder = NeAACDecOpen();
662
samples = mp4ff_num_samples(mp4, track);
664
mp4ff_get_decoder_config(mp4, track, &buffer, &buffer_size);
667
if (NeAACDecAudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0)
669
if (mp4ASC.frameLengthFlag == 1) f = 960.0;
670
if (mp4ASC.sbr_present_flag == 1) f *= 2;
673
if(NeAACDecInit2(hDecoder, buffer, buffer_size, &sr, &ch) < 0)
675
/* If some error initializing occured, skip the file */
684
if (mp4ff_read_sample(mp4, track, 0, &buffer, &buffer_size) == 0)
688
NeAACDecDecode(hDecoder, &frameInfo, buffer, buffer_size);
690
if (buffer) free(buffer);
692
seconds = (float)samples*(float)(f-1.0)/(float)mp4ASC.samplingFrequency;
694
wsprintf(info, "MPEG-4 %s, %d.%d secs, %d ch, %d Hz\nSBR: %s\nParametric stereo: %s",
695
ot[(mp4ASC.objectTypeIndex > 5)?0:mp4ASC.objectTypeIndex],
697
(int)(seconds*1000.0 + 0.5) % 1000,
698
mp4ASC.channelsConfiguration,
699
mp4ASC.samplingFrequency,
700
/* SBR: 0: off, 1: on; upsample, 2: on; downsampled, 3: off; upsampled */
701
(frameInfo.sbr == 0) ? "off" : ((frameInfo.sbr == 1) ? "on, normal" : ((frameInfo.sbr == 2) ? "on, downsampled" : "off, upsampled")),
702
(frameInfo.ps == 0) ? "no" : "yes");
704
NeAACDecClose(hDecoder);
707
BOOL CALLBACK mp4_info_dialog_proc(HWND hwndDlg, UINT message,
708
WPARAM wParam, LPARAM lParam)
710
char file_info[1024];
713
mp4ff_callback_t mp4cb = {0};
715
mp4ff_metadata_t tags;
718
int dummy, dummy2, dummy3;
723
in_mp4_DebugOutput("mp4_info_dialog_proc");
728
EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT), FALSE);
729
ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT), SW_HIDE);
730
EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT1), FALSE);
731
ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT1), SW_HIDE);
732
EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), FALSE);
733
ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), SW_HIDE);
735
mp4File = fopen(info_fn, "rb");
736
mp4cb.read = read_callback;
737
mp4cb.seek = seek_callback;
738
mp4cb.user_data = mp4File;
741
file = mp4ff_open_read(&mp4cb);
745
mp4fileinfo(file, file_info, 1024);
746
SetDlgItemText(hwndDlg, IDC_INFOTEXT, file_info);
751
if (mp4ff_meta_get_title(file, &pVal))
752
uSetDlgItemText(hwndDlg,IDC_METANAME, pVal);
755
if (mp4ff_meta_get_artist(file, &pVal))
756
uSetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
759
if (mp4ff_meta_get_writer(file, &pVal))
760
uSetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
763
if (mp4ff_meta_get_comment(file, &pVal))
764
uSetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
767
if (mp4ff_meta_get_album(file, &pVal))
768
uSetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
771
if (mp4ff_meta_get_genre(file, &pVal))
772
uSetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
775
if (mp4ff_meta_get_track(file, &pVal))
777
SetDlgItemText(hwndDlg,IDC_METATRACK1, pVal);
780
//mp4ff_meta_get_totaltracks(file, &pVal);
781
//SetDlgItemText(hwndDlg, IDC_METATRACK2, pVal);
785
if (mp4ff_meta_get_disc(file, &pVal))
787
SetDlgItemText(hwndDlg,IDC_METADISK1, pVal);
790
//mp4ff_meta_get_totaldiscs(file, &pVal);
791
//SetDlgItemText(hwndDlg,IDC_METADISK2, pVal);
795
if (mp4ff_meta_get_date(file, &pVal))
796
uSetDlgItemText(hwndDlg,IDC_METAYEAR, pVal);
802
if (mp4ff_meta_get_compilation(file, &pVal))
804
if (strcmp(pVal, "1") == 0)
806
SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_SETCHECK, BST_CHECKED, 0);
818
switch (LOWORD(wParam)) {
820
EndDialog(hwndDlg, wParam);
824
/* trying to edit currently playing file */
826
if (!stricmp(info_fn, mp4state.filename))
828
MessageBox(module.hMainWindow, "Please stop playback before editing tags", "in_mp4", MB_ICONINFORMATION|MB_OK);
832
/* save Metadata changes */
836
mp4File = fopen(info_fn, "rb");
837
mp4cb.read = read_callback;
838
mp4cb.seek = seek_callback;
839
mp4cb.write = write_callback;
840
mp4cb.truncate = truncate_callback;
841
mp4cb.user_data = mp4File;
844
file = mp4ff_open_read(&mp4cb);
847
ReadMP4Tag(file, &tags);
852
mp4File = fopen(info_fn, "rb+");
853
mp4cb.read = read_callback;
854
mp4cb.seek = seek_callback;
855
mp4cb.write = write_callback;
856
mp4cb.truncate = truncate_callback;
857
mp4cb.user_data = mp4File;
860
uGetDlgItemText(hwndDlg, IDC_METANAME, dummy1, 1024);
861
tag_set_field(&tags, "title", dummy1, strlen(dummy1));
863
uGetDlgItemText(hwndDlg, IDC_METAWRITER, dummy1, 1024);
864
tag_set_field(&tags, "writer", dummy1, strlen(dummy1));
866
uGetDlgItemText(hwndDlg, IDC_METAARTIST, dummy1, 1024);
867
tag_set_field(&tags, "artist", dummy1, strlen(dummy1));
869
uGetDlgItemText(hwndDlg, IDC_METAALBUM, dummy1, 1024);
870
tag_set_field(&tags, "album", dummy1, strlen(dummy1));
872
uGetDlgItemText(hwndDlg, IDC_METACOMMENTS, dummy1, 1024);
873
tag_set_field(&tags, "comment", dummy1, strlen(dummy1));
875
uGetDlgItemText(hwndDlg, IDC_METAGENRE, dummy1, 1024);
876
tag_set_field(&tags, "genre", dummy1, strlen(dummy1));
878
uGetDlgItemText(hwndDlg, IDC_METAYEAR, dummy1, 1024);
879
tag_set_field(&tags, "year", dummy1, strlen(dummy1));
881
GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
882
dummy = atoi(dummy1);
883
//GetDlgItemText(hwndDlg, IDC_METATRACK2, dummy1, 1024);
884
//dummy2 = atoi(dummy1);
885
//wsprintf(temp, "%d/%d", dummy, dummy2);
886
wsprintf(temp, "%d", dummy);
887
tag_set_field(&tags, "track", temp, strlen(dummy1));
889
GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
890
dummy = atoi(dummy1);
891
//GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
892
//dummy2 = atoi(dummy1);
893
//wsprintf(temp, "%d/%d", dummy, dummy2);
894
wsprintf(temp, "%d", dummy);
895
tag_set_field(&tags, "disc", temp, strlen(dummy1));
897
dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
898
tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"), 1);
900
mp4ff_meta_update(&mp4cb, &tags);
906
EndDialog(hwndDlg, wParam);
913
/* returns the name of the object type */
914
char *get_ot_string(int ot)
930
BOOL CALLBACK aac_info_dialog_proc(HWND hwndDlg, UINT message,
931
WPARAM wParam, LPARAM lParam)
934
char *info_text, *header_string;
937
in_mp4_DebugOutput("aac_info_dialog_proc");
942
EnableWindow(GetDlgItem(hwndDlg,IDC_USERDATA), FALSE) ;
943
ShowWindow(GetDlgItem(hwndDlg,IDC_USERDATA), SW_HIDE);
945
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC1), SW_HIDE);
946
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC2), SW_HIDE);
947
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC3), SW_HIDE);
948
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC4), SW_HIDE);
949
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC5), SW_HIDE);
950
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC6), SW_HIDE);
951
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC7), SW_HIDE);
952
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC8), SW_HIDE);
953
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC9), SW_HIDE);
954
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC10), SW_HIDE);
955
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC11), SW_HIDE);
956
ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC12), SW_HIDE);
958
ShowWindow(GetDlgItem(hwndDlg,IDC_METANAME), SW_HIDE);
959
ShowWindow(GetDlgItem(hwndDlg,IDC_METAARTIST), SW_HIDE);
960
ShowWindow(GetDlgItem(hwndDlg,IDC_METAWRITER), SW_HIDE);
961
ShowWindow(GetDlgItem(hwndDlg,IDC_METACOMMENTS), SW_HIDE);
962
ShowWindow(GetDlgItem(hwndDlg,IDC_METAALBUM), SW_HIDE);
963
ShowWindow(GetDlgItem(hwndDlg,IDC_METAGENRE), SW_HIDE);
964
ShowWindow(GetDlgItem(hwndDlg,IDC_METATRACK1), SW_HIDE);
965
//ShowWindow(GetDlgItem(hwndDlg,IDC_METATRACK2), SW_HIDE);
966
ShowWindow(GetDlgItem(hwndDlg,IDC_METADISK1), SW_HIDE);
967
//ShowWindow(GetDlgItem(hwndDlg,IDC_METADISK2), SW_HIDE);
968
ShowWindow(GetDlgItem(hwndDlg,IDC_METAYEAR), SW_HIDE);
969
ShowWindow(GetDlgItem(hwndDlg,IDC_METACOMPILATION), SW_HIDE);
971
info_text = malloc(1024*sizeof(char));
973
get_AAC_format(info_fn, &aacInfo);
975
switch (aacInfo.headertype)
978
header_string = " RAW";
981
header_string = " ADIF";
984
header_string = " ADTS";
988
sprintf(info_text, "%s AAC %s%s, %d sec, %d kbps, %d Hz",
989
(aacInfo.version==2)?"MPEG-2":"MPEG-4", get_ot_string(aacInfo.object_type),
991
(int)((float)aacInfo.length/1000.0), (int)((float)aacInfo.bitrate/1000.0+0.5),
992
aacInfo.sampling_rate);
994
SetDlgItemText(hwndDlg, IDC_INFOTEXT, info_text);
1001
switch (LOWORD(wParam))
1005
EndDialog(hwndDlg, wParam);
1012
int infoDlg(char *fn, HWND hwndParent)
1014
if(!stricmp(fn + strlen(fn) - 3,"AAC"))
1016
lstrcpy(info_fn, fn);
1018
DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
1019
hwndParent, aac_info_dialog_proc);
1021
lstrcpy(info_fn, fn);
1023
DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
1024
hwndParent, mp4_info_dialog_proc);
1030
/* Get the title from the file */
1031
void ConstructTitle(mp4ff_t *file, char *filename, char *title, char *format)
1036
char *out = temp;//title;
1037
char *bound = out + sizeof(temp) - 256; //out + (MAX_PATH - 10 - 1);
1038
char *pVal, dummy1[1024];
1039
short dummy, dummy2;
1041
while (*in && out < bound)
1054
/* handle % escape sequence */
1059
if (mp4ff_meta_get_track(file, &pVal))
1061
out += wsprintf(out, "%s", pVal);
1068
if (mp4ff_meta_get_artist(file, &pVal))
1070
out += wsprintf(out, "%s", pVal);
1077
if (mp4ff_meta_get_title(file, &pVal))
1079
out += wsprintf(out, "%s", pVal);
1086
if (mp4ff_meta_get_album(file, &pVal))
1088
out += wsprintf(out, "%s", pVal);
1095
if (mp4ff_meta_get_date(file, &pVal))
1097
out += wsprintf(out, "%s", pVal);
1104
if (mp4ff_meta_get_comment(file, &pVal))
1106
out += wsprintf(out, "%s", pVal);
1113
if (mp4ff_meta_get_genre(file, &pVal))
1115
out += wsprintf(out, "%s", pVal);
1122
const char *p=strrchr(filename,'\\');
1123
if (!p) p=filename; else p++;
1124
out += ConvertANSIToUTF8(p, out);
1138
char *p=filename+lstrlen(filename);
1139
while (*p != '\\' && p >= filename) p--;
1144
int len = ConvertUTF8ToANSI(temp, dummy1);
1145
if (len > (MAX_PATH - 10 - 1)) len = (MAX_PATH - 10 - 1);
1146
memcpy(title, dummy1, len);
1151
BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message,
1152
WPARAM wParam, LPARAM lParam)
1158
SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETRANGE, TRUE, MAKELONG(1,5));
1159
SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETPOS, TRUE, m_priority);
1160
SendMessage(GetDlgItem(hwndDlg, res_id_table[m_resolution]), BM_SETCHECK, BST_CHECKED, 0);
1162
SendMessage(GetDlgItem(hwndDlg, IDC_ERROR), BM_SETCHECK, BST_CHECKED, 0);
1164
SendMessage(GetDlgItem(hwndDlg, IDC_USEFORAAC), BM_SETCHECK, BST_CHECKED, 0);
1166
SendMessage(GetDlgItem(hwndDlg, IDC_DOWNMIX), BM_SETCHECK, BST_CHECKED, 0);
1168
SendMessage(GetDlgItem(hwndDlg, IDC_VBR), BM_SETCHECK, BST_CHECKED, 0);
1169
SetDlgItemText(hwndDlg, IDC_TITLEFORMAT, titleformat);
1173
switch (LOWORD(wParam)) {
1175
EndDialog(hwndDlg, wParam);
1178
m_show_errors = SendMessage(GetDlgItem(hwndDlg, IDC_ERROR), BM_GETCHECK, 0, 0);
1179
m_use_for_aac = SendMessage(GetDlgItem(hwndDlg, IDC_USEFORAAC), BM_GETCHECK, 0, 0);
1180
m_downmix = SendMessage(GetDlgItem(hwndDlg, IDC_DOWNMIX), BM_GETCHECK, 0, 0);
1181
m_vbr_display = SendMessage(GetDlgItem(hwndDlg, IDC_VBR), BM_GETCHECK, 0, 0);
1182
GetDlgItemText(hwndDlg, IDC_TITLEFORMAT, titleformat, MAX_PATH);
1184
m_priority = SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_GETPOS, 0, 0);
1185
for (i = 0; i < 6; i++)
1187
if (SendMessage(GetDlgItem(hwndDlg, res_id_table[i]), BM_GETCHECK, 0, 0))
1199
module.FileExtensions = short_ext_list;
1201
module.FileExtensions = long_ext_list;
1204
EndDialog(hwndDlg, wParam);
1211
void config(HWND hwndParent)
1213
DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG),
1214
hwndParent, config_dialog_proc);
1219
void about(HWND hwndParent)
1221
MessageBox(hwndParent,
1222
"AudioCoding.com MPEG-4 AAC player " FAAD2_VERSION " compiled on " __DATE__ ".\n"
1223
"Visit the website for more info.\n"
1224
"Copyright 2002-2004 AudioCoding.com",
1229
int isourfile(char *fn)
1231
if (!stricmp(fn + strlen(fn) - 3,"MP4") || !stricmp(fn + strlen(fn) - 3,"M4A"))
1234
} else if (m_use_for_aac) {
1235
if (!stricmp(fn + strlen(fn) - 3,"AAC"))
1244
int fill_buffer(state *st)
1248
if (st->m_aac_bytes_consumed > 0)
1250
if (st->m_aac_bytes_into_buffer)
1252
memmove((void*)st->m_aac_buffer, (void*)(st->m_aac_buffer + st->m_aac_bytes_consumed),
1253
st->m_aac_bytes_into_buffer*sizeof(unsigned char));
1258
bread = fread((void*)(st->m_aac_buffer + st->m_aac_bytes_into_buffer),
1259
1, st->m_aac_bytes_consumed, st->aacfile);
1261
if (bread != st->m_aac_bytes_consumed)
1264
st->m_aac_bytes_into_buffer += bread;
1267
st->m_aac_bytes_consumed = 0;
1269
if (st->m_aac_bytes_into_buffer > 3)
1271
if (memcmp(st->m_aac_buffer, "TAG", 3) == 0)
1272
st->m_aac_bytes_into_buffer = 0;
1274
if (st->m_aac_bytes_into_buffer > 11)
1276
if (memcmp(st->m_aac_buffer, "LYRICSBEGIN", 11) == 0)
1277
st->m_aac_bytes_into_buffer = 0;
1279
if (st->m_aac_bytes_into_buffer > 8)
1281
if (memcmp(st->m_aac_buffer, "APETAGEX", 8) == 0)
1282
st->m_aac_bytes_into_buffer = 0;
1289
void advance_buffer(state *st, int bytes)
1291
st->m_file_offset += bytes;
1292
st->m_aac_bytes_consumed = bytes;
1293
st->m_aac_bytes_into_buffer -= bytes;
1296
int adts_parse(state *st, __int64 *bitrate, double *length)
1298
static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000};
1299
int frames, frame_length;
1300
int t_framelength = 0;
1302
double frames_per_sec, bytes_per_frame;
1304
/* Read all frames to ensure correct time and bitrate */
1305
for (frames = 0; /* */; frames++)
1309
if (st->m_aac_bytes_into_buffer > 7)
1311
/* check syncword */
1312
if (!((st->m_aac_buffer[0] == 0xFF)&&((st->m_aac_buffer[1] & 0xF6) == 0xF0)))
1315
st->m_tail->offset = st->m_file_offset;
1316
st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
1317
st->m_tail = st->m_tail->next;
1318
st->m_tail->next = NULL;
1321
samplerate = sample_rates[(st->m_aac_buffer[2]&0x3c)>>2];
1323
frame_length = ((((unsigned int)st->m_aac_buffer[3] & 0x3)) << 11)
1324
| (((unsigned int)st->m_aac_buffer[4]) << 3) | (st->m_aac_buffer[5] >> 5);
1326
t_framelength += frame_length;
1328
if (frame_length > st->m_aac_bytes_into_buffer)
1331
advance_buffer(st, frame_length);
1337
frames_per_sec = (double)samplerate/1024.0;
1339
bytes_per_frame = (double)t_framelength/(double)(frames*1000);
1341
bytes_per_frame = 0;
1342
*bitrate = (__int64)(8. * bytes_per_frame * frames_per_sec + 0.5);
1343
if (frames_per_sec != 0)
1344
*length = (double)frames/frames_per_sec;
1351
int skip_id3v2_tag()
1353
unsigned char buf[10];
1354
int bread, tagsize = 0;
1356
bread = fread(buf, 1, 10, mp4state.aacfile);
1357
if (bread != 10) return -1;
1359
if (!memcmp(buf, "ID3", 3))
1361
/* high bit is not used */
1362
tagsize = (buf[6] << 21) | (buf[7] << 14) | (buf[8] << 7) | (buf[9] << 0);
1365
fseek(mp4state.aacfile, tagsize, SEEK_SET);
1367
fseek(mp4state.aacfile, 0, SEEK_SET);
1377
int avg_bitrate, br, sr;
1378
unsigned char *buffer;
1380
NeAACDecConfigurationPtr config;
1381
unsigned char header[8];
1385
in_mp4_DebugOutput("play");
1388
memset(&mp4state, 0, sizeof(state));
1390
lstrcpy(mp4state.filename, fn);
1392
hMP4File = fopen(mp4state.filename, "rb");
1397
fread(header, 1, 8, hMP4File);
1399
mp4state.filetype = 1;
1400
if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p')
1401
mp4state.filetype = 0;
1403
if (mp4state.filetype)
1405
int tagsize = 0, tmp = 0, init;
1408
__int64 bitrate = 128;
1409
// NeAACDecFrameInfo frameInfo;
1411
module.is_seekable = 1;
1413
if (!(mp4state.aacfile = fopen(mp4state.filename, "rb")))
1419
tagsize = skip_id3v2_tag();
1420
if (tagsize<0) return 0;
1422
if (!(mp4state.m_aac_buffer = (unsigned char*)malloc(768*6)))
1424
show_error(module.hMainWindow, "Memory allocation error.");
1428
for (init=0; init<2; init++)
1430
mp4state.hDecoder = NeAACDecOpen();
1431
if (!mp4state.hDecoder)
1433
show_error(module.hMainWindow, "Unable to open decoder library.");
1437
config = NeAACDecGetCurrentConfiguration(mp4state.hDecoder);
1438
config->outputFormat = m_resolution + 1;
1439
config->downMatrix = m_downmix;
1440
NeAACDecSetConfiguration(mp4state.hDecoder, config);
1442
memset(mp4state.m_aac_buffer, 0, 768*6);
1443
bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
1444
mp4state.m_aac_bytes_into_buffer = bread;
1445
mp4state.m_aac_bytes_consumed = 0;
1446
mp4state.m_file_offset = 0;
1447
mp4state.m_at_eof = (bread != 768*6) ? 1 : 0;
1451
NeAACDecFrameInfo frameInfo;
1453
fill_buffer(&mp4state);
1455
if ((mp4state.m_aac_bytes_consumed = NeAACDecInit(mp4state.hDecoder,
1456
mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
1457
&mp4state.samplerate, &mp4state.channels)) < 0)
1459
show_error(module.hMainWindow, "Can't initialize decoder library.");
1462
advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
1465
memset(&frameInfo, 0, sizeof(NeAACDecFrameInfo));
1466
fill_buffer(&mp4state);
1467
NeAACDecDecode(mp4state.hDecoder, &frameInfo, mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer);
1468
} while (!frameInfo.samples && !frameInfo.error);
1470
if (frameInfo.error)
1472
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
1476
mp4state.channels = frameInfo.channels;
1477
mp4state.samplerate = frameInfo.samplerate;
1478
mp4state.framesize = (frameInfo.channels != 0) ? frameInfo.samples/frameInfo.channels : 0;
1480
sbr = frameInfo.sbr;
1481
profile = frameInfo.object_type;
1482
header_type = frameInfo.header_type;
1485
NeAACDecClose(mp4state.hDecoder);
1486
fseek(mp4state.aacfile, tagsize, SEEK_SET);
1490
mp4state.m_head = (struct seek_list*)malloc(sizeof(struct seek_list));
1491
mp4state.m_tail = mp4state.m_head;
1492
mp4state.m_tail->next = NULL;
1494
mp4state.m_header_type = 0;
1495
if ((mp4state.m_aac_buffer[0] == 0xFF) && ((mp4state.m_aac_buffer[1] & 0xF6) == 0xF0))
1499
adts_parse(&mp4state, &bitrate, &length);
1500
fseek(mp4state.aacfile, tagsize, SEEK_SET);
1502
bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
1504
mp4state.m_at_eof = 1;
1506
mp4state.m_at_eof = 0;
1507
mp4state.m_aac_bytes_into_buffer = bread;
1508
mp4state.m_aac_bytes_consumed = 0;
1510
mp4state.m_header_type = 1;
1512
} else if (memcmp(mp4state.m_aac_buffer, "ADIF", 4) == 0) {
1513
int skip_size = (mp4state.m_aac_buffer[4] & 0x80) ? 9 : 0;
1514
bitrate = ((unsigned int)(mp4state.m_aac_buffer[4 + skip_size] & 0x0F)<<19) |
1515
((unsigned int)mp4state.m_aac_buffer[5 + skip_size]<<11) |
1516
((unsigned int)mp4state.m_aac_buffer[6 + skip_size]<<3) |
1517
((unsigned int)mp4state.m_aac_buffer[7 + skip_size] & 0xE0);
1519
length = (double)file_length(mp4state.aacfile);
1522
module.is_seekable = 0;
1525
length = ((double)length*8.)/((double)bitrate) + 0.5;
1528
mp4state.m_header_type = 2;
1530
length = (double)file_length(mp4state.aacfile);
1531
length = ((double)length*8.)/((double)bitrate*1000.) + 0.5;
1533
module.is_seekable = 1;
1536
mp4state.m_length = (int)(length*1000.);
1538
fill_buffer(&mp4state);
1539
if ((mp4state.m_aac_bytes_consumed = NeAACDecInit(mp4state.hDecoder,
1540
mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
1541
&mp4state.samplerate, &mp4state.channels)) < 0)
1543
show_error(module.hMainWindow, "Can't initialize decoder library.");
1546
advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
1548
if (mp4state.m_header_type == 2)
1549
avg_bitrate = bitrate;
1551
avg_bitrate = bitrate*1000;
1553
mp4state.hDecoder = NeAACDecOpen();
1554
if (!mp4state.hDecoder)
1556
show_error(module.hMainWindow, "Unable to open decoder library.");
1560
config = NeAACDecGetCurrentConfiguration(mp4state.hDecoder);
1561
config->outputFormat = m_resolution + 1;
1562
config->downMatrix = m_downmix;
1563
NeAACDecSetConfiguration(mp4state.hDecoder, config);
1565
mp4state.mp4File = fopen(mp4state.filename, "rb");
1566
mp4state.mp4cb.read = read_callback;
1567
mp4state.mp4cb.seek = seek_callback;
1568
mp4state.mp4cb.user_data = mp4state.mp4File;
1571
mp4state.mp4file = mp4ff_open_read(&mp4state.mp4cb);
1572
if (!mp4state.mp4file)
1574
show_error(module.hMainWindow, "Unable to open file.");
1575
NeAACDecClose(mp4state.hDecoder);
1579
if ((mp4state.mp4track = GetAACTrack(mp4state.mp4file)) < 0)
1581
show_error(module.hMainWindow, "Unsupported Audio track type.");
1582
NeAACDecClose(mp4state.hDecoder);
1583
mp4ff_close(mp4state.mp4file);
1584
fclose(mp4state.mp4File);
1590
mp4ff_get_decoder_config(mp4state.mp4file, mp4state.mp4track,
1591
&buffer, &buffer_size);
1594
NeAACDecClose(mp4state.hDecoder);
1595
mp4ff_close(mp4state.mp4file);
1596
fclose(mp4state.mp4File);
1600
if(NeAACDecInit2(mp4state.hDecoder, buffer, buffer_size,
1601
&mp4state.samplerate, &mp4state.channels) < 0)
1603
/* If some error initializing occured, skip the file */
1604
NeAACDecClose(mp4state.hDecoder);
1605
mp4ff_close(mp4state.mp4file);
1606
fclose(mp4state.mp4File);
1607
if (buffer) free (buffer);
1611
/* for gapless decoding */
1613
mp4AudioSpecificConfig mp4ASC;
1615
mp4state.timescale = mp4ff_time_scale(mp4state.mp4file, mp4state.mp4track);
1616
mp4state.framesize = 1024;
1617
mp4state.useAacLength = 0;
1621
if (NeAACDecAudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0)
1623
if (mp4ASC.frameLengthFlag == 1) mp4state.framesize = 960;
1624
if (mp4ASC.sbr_present_flag == 1) mp4state.framesize *= 2;
1631
avg_bitrate = mp4ff_get_avg_bitrate(mp4state.mp4file, mp4state.mp4track);
1633
mp4state.numSamples = mp4ff_num_samples(mp4state.mp4file, mp4state.mp4track);
1634
mp4state.sampleId = 0;
1637
double timescale_div = 1.0 / (double)mp4ff_time_scale(mp4state.mp4file, mp4state.mp4track);
1638
int64_t duration = mp4ff_get_track_duration_use_offsets(mp4state.mp4file, mp4state.mp4track);
1641
mp4state.m_length = 0;
1643
mp4state.m_length = (int)((double)duration * timescale_div * 1000.0);
1647
module.is_seekable = 1;
1650
if (mp4state.channels == 0)
1652
show_error(module.hMainWindow, "Number of channels not supported for playback.");
1653
NeAACDecClose(mp4state.hDecoder);
1654
if (mp4state.filetype)
1655
fclose(mp4state.aacfile);
1657
mp4ff_close(mp4state.mp4file);
1658
fclose(mp4state.mp4File);
1663
if (m_downmix && (mp4state.channels == 5 || mp4state.channels == 6))
1664
mp4state.channels = 2;
1666
maxlatency = module.outMod->Open(mp4state.samplerate, (int)mp4state.channels,
1667
res_table[m_resolution], -1, -1);
1669
if (maxlatency < 0) // error opening device
1671
NeAACDecClose(mp4state.hDecoder);
1672
if (mp4state.filetype)
1673
fclose(mp4state.aacfile);
1675
mp4ff_close(mp4state.mp4file);
1676
fclose(mp4state.mp4File);
1681
mp4state.paused = 0;
1682
mp4state.decode_pos_ms = 0;
1683
mp4state.seek_needed = -1;
1685
// initialize vis stuff
1686
module.SAVSAInit(maxlatency, mp4state.samplerate);
1687
module.VSASetInfo((int)mp4state.channels, mp4state.samplerate);
1689
br = (int)floor(((float)avg_bitrate + 500.0)/1000.0 + 0.5);
1690
sr = (int)floor((float)mp4state.samplerate/1000.0 + 0.5);
1691
module.SetInfo(br, sr, (int)mp4state.channels, 1);
1693
module.outMod->SetVolume(-666); // set the output plug-ins default volume
1697
if (mp4state.filetype)
1699
if ((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AACPlayThread,
1700
(void *)&killPlayThread, 0, &thread_id)) == NULL)
1702
show_error(module.hMainWindow, "Cannot create playback thread");
1703
NeAACDecClose(mp4state.hDecoder);
1704
fclose(mp4state.aacfile);
1708
if ((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MP4PlayThread,
1709
(void *)&killPlayThread, 0, &thread_id)) == NULL)
1711
show_error(module.hMainWindow, "Cannot create playback thread");
1712
NeAACDecClose(mp4state.hDecoder);
1713
mp4ff_close(mp4state.mp4file);
1714
fclose(mp4state.mp4File);
1719
SetThreadAffinityMask(play_thread_handle, 1);
1721
SetThreadPriority(play_thread_handle, priority_table[m_priority]);
1729
in_mp4_DebugOutput("pause");
1732
mp4state.paused = 1;
1733
module.outMod->Pause(1);
1739
in_mp4_DebugOutput("unpause");
1742
mp4state.paused = 0;
1743
module.outMod->Pause(0);
1749
in_mp4_DebugOutput("ispaused");
1752
return mp4state.paused;
1755
void setvolume(int volume)
1758
in_mp4_DebugOutput("setvolume");
1761
module.outMod->SetVolume(volume);
1764
void setpan(int pan)
1767
in_mp4_DebugOutput("setpan");
1770
module.outMod->SetPan(pan);
1775
struct seek_list *target = mp4state.m_head;
1778
in_mp4_DebugOutput("stop");
1783
if (play_thread_handle != INVALID_HANDLE_VALUE)
1785
if (WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
1786
TerminateThread(play_thread_handle,0);
1787
CloseHandle(play_thread_handle);
1788
play_thread_handle = INVALID_HANDLE_VALUE;
1792
if (mp4state.m_aac_buffer)
1793
free(mp4state.m_aac_buffer);
1797
struct seek_list *tmp = target;
1798
target = target->next;
1801
NeAACDecClose(mp4state.hDecoder);
1802
if (mp4state.filetype)
1803
fclose(mp4state.aacfile);
1805
mp4ff_close(mp4state.mp4file);
1806
fclose(mp4state.mp4File);
1809
module.outMod->Close();
1810
module.SAVSADeInit();
1812
mp4state.filename[0] = '\0';
1815
int getsonglength(const char *fn)
1817
long msDuration = 0;
1819
if(!stricmp(fn + strlen(fn) - 3,"MP4") || !stricmp(fn + strlen(fn) - 3,"M4A"))
1825
mp4ff_callback_t mp4cb = {0};
1827
mp4File = fopen(fn, "rb");
1828
mp4cb.read = read_callback;
1829
mp4cb.seek = seek_callback;
1830
mp4cb.user_data = mp4File;
1833
file = mp4ff_open_read(&mp4cb);
1837
if ((track = GetAACTrack(file)) < 0)
1844
length = mp4ff_get_track_duration(file, track);
1846
msDuration = (long)((float)length*1000.0 / (float)mp4ff_time_scale(file, track) + 0.5);
1856
__int64 bitrate = 128;
1857
struct seek_list *target;
1860
memset(&len_state, 0, sizeof(state));
1862
if (!(len_state.aacfile = fopen(fn, "rb")))
1868
len_state.m_at_eof = 0;
1870
if (!(len_state.m_aac_buffer = (unsigned char*)malloc(768*6)))
1872
//console::error("Memory allocation error.", "foo_mp4");
1875
memset(len_state.m_aac_buffer, 0, 768*6);
1877
bread = fread(len_state.m_aac_buffer, 1, 768*6, len_state.aacfile);
1878
len_state.m_aac_bytes_into_buffer = bread;
1879
len_state.m_aac_bytes_consumed = 0;
1880
len_state.m_file_offset = 0;
1883
len_state.m_at_eof = 1;
1885
if (!memcmp(len_state.m_aac_buffer, "ID3", 3))
1887
/* high bit is not used */
1888
tagsize = (len_state.m_aac_buffer[6] << 21) | (len_state.m_aac_buffer[7] << 14) |
1889
(len_state.m_aac_buffer[8] << 7) | (len_state.m_aac_buffer[9] << 0);
1892
advance_buffer(&len_state, tagsize);
1895
len_state.m_head = (struct seek_list*)malloc(sizeof(struct seek_list));
1896
len_state.m_tail = len_state.m_head;
1897
len_state.m_tail->next = NULL;
1899
len_state.m_header_type = 0;
1900
if ((len_state.m_aac_buffer[0] == 0xFF) && ((len_state.m_aac_buffer[1] & 0xF6) == 0xF0))
1902
if (1) //(m_reader->can_seek())
1904
adts_parse(&len_state, &bitrate, &length);
1905
fseek(len_state.aacfile, tagsize, SEEK_SET);
1907
bread = fread(len_state.m_aac_buffer, 1, 768*6, len_state.aacfile);
1909
len_state.m_at_eof = 1;
1911
len_state.m_at_eof = 0;
1912
len_state.m_aac_bytes_into_buffer = bread;
1913
len_state.m_aac_bytes_consumed = 0;
1915
len_state.m_header_type = 1;
1917
} else if (memcmp(len_state.m_aac_buffer, "ADIF", 4) == 0) {
1918
int skip_size = (len_state.m_aac_buffer[4] & 0x80) ? 9 : 0;
1919
bitrate = ((unsigned int)(len_state.m_aac_buffer[4 + skip_size] & 0x0F)<<19) |
1920
((unsigned int)len_state.m_aac_buffer[5 + skip_size]<<11) |
1921
((unsigned int)len_state.m_aac_buffer[6 + skip_size]<<3) |
1922
((unsigned int)len_state.m_aac_buffer[7 + skip_size] & 0xE0);
1924
length = (double)file_length(len_state.aacfile);
1928
length = ((double)length*8.)/((double)bitrate) + 0.5;
1930
len_state.m_header_type = 2;
1932
length = (double)file_length(len_state.aacfile);
1933
length = ((double)length*8.)/((double)bitrate*1000.) + 0.5;
1935
len_state.m_header_type = 0;
1938
if (len_state.m_aac_buffer)
1939
free(len_state.m_aac_buffer);
1941
target = len_state.m_head;
1944
struct seek_list *tmp = target;
1945
target = target->next;
1949
fclose(len_state.aacfile);
1951
return (int)(length*1000.);
1957
if (!mp4state.filetype)
1963
if ((track = GetAACTrack(mp4state.mp4file)) < 0)
1968
length = mp4ff_get_track_duration(mp4state.mp4file, track);
1970
msDuration = (long)(length*1000.0 / (float)mp4ff_time_scale(mp4state.mp4file, track) + 0.5);
1974
return mp4state.m_length;
1981
return mp4state.decode_pos_ms+(module.outMod->GetOutputTime()-module.outMod->GetWrittenTime());
1984
void setoutputtime(int time_in_ms)
1987
in_mp4_DebugOutput("setoutputtime");
1990
mp4state.seek_needed = time_in_ms;
1993
void getfileinfo(char *filename, char *title, int *length_in_ms)
1995
if (!filename || !*filename) /* currently playing file */
1998
*length_in_ms = getlength();
2002
if (mp4state.filetype == 0)
2004
ConstructTitle(mp4state.mp4file, mp4state.filename, title, titleformat);
2007
char *tmp = PathFindFileName(mp4state.filename);
2009
tmp2 = strrchr(title, '.');
2015
*length_in_ms = getsonglength(filename);
2019
unsigned char header[8];
2020
FILE *hMP4File = fopen(filename, "rb");
2025
fread(header, 1, 8, hMP4File);
2028
if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p')
2032
mp4ff_callback_t mp4cb = {0};
2034
mp4File = fopen(filename, "rb");
2035
mp4cb.read = read_callback;
2036
mp4cb.seek = seek_callback;
2037
mp4cb.user_data = mp4File;
2039
file = mp4ff_open_read(&mp4cb);
2043
ConstructTitle(file, filename, title, titleformat);
2049
char *tmp = PathFindFileName(filename);
2051
tmp2 = strrchr(title, '.');
2058
void eq_set(int on, char data[10], int preamp)
2062
static void remap_channels(unsigned char *data, unsigned int samples, unsigned int bps)
2070
unsigned char r1, r2, r3, r4, r5, r6;
2071
for (i = 0; i < samples; i += 6)
2092
unsigned short r1, r2, r3, r4, r5, r6;
2093
unsigned short *sample_buffer = (unsigned short *)data;
2094
for (i = 0; i < samples; i += 6)
2096
r1 = sample_buffer[i];
2097
r2 = sample_buffer[i+1];
2098
r3 = sample_buffer[i+2];
2099
r4 = sample_buffer[i+3];
2100
r5 = sample_buffer[i+4];
2101
r6 = sample_buffer[i+5];
2102
sample_buffer[i] = r2;
2103
sample_buffer[i+1] = r3;
2104
sample_buffer[i+2] = r1;
2105
sample_buffer[i+3] = r6;
2106
sample_buffer[i+4] = r4;
2107
sample_buffer[i+5] = r5;
2115
unsigned int r1, r2, r3, r4, r5, r6;
2116
unsigned int *sample_buffer = (unsigned int *)data;
2117
for (i = 0; i < samples; i += 6)
2119
r1 = sample_buffer[i];
2120
r2 = sample_buffer[i+1];
2121
r3 = sample_buffer[i+2];
2122
r4 = sample_buffer[i+3];
2123
r5 = sample_buffer[i+4];
2124
r6 = sample_buffer[i+5];
2125
sample_buffer[i] = r2;
2126
sample_buffer[i+1] = r3;
2127
sample_buffer[i+2] = r1;
2128
sample_buffer[i+3] = r6;
2129
sample_buffer[i+4] = r4;
2130
sample_buffer[i+5] = r5;
2137
DWORD WINAPI MP4PlayThread(void *b)
2144
void *sample_buffer;
2145
unsigned char *buffer;
2147
NeAACDecFrameInfo frameInfo;
2150
in_mp4_DebugOutput("MP4PlayThread");
2153
PlayThreadAlive = 1;
2154
mp4state.last_frame = 0;
2155
mp4state.initial = 1;
2157
while (!*((int *)b))
2160
if (mp4state.seek_needed != -1)
2163
int32_t skip_samples = 0;
2165
module.outMod->Flush(mp4state.decode_pos_ms);
2166
duration = (int64_t)(mp4state.seek_needed/1000.0 * mp4state.samplerate + 0.5);
2167
mp4state.sampleId = mp4ff_find_sample_use_offsets(mp4state.mp4file,
2168
mp4state.mp4track, duration, &skip_samples);
2170
mp4state.decode_pos_ms = mp4state.seek_needed;
2171
mp4state.seek_needed = -1;
2176
module.outMod->CanWrite();
2178
if (!module.outMod->IsPlaying())
2180
PostMessage(module.hMainWindow, WM_WA_AAC_EOF, 0, 0);
2181
PlayThreadAlive = 0;
2186
} else if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short))) {
2188
if (mp4state.last_frame)
2194
/* for gapless decoding */
2197
unsigned int sample_count;
2198
unsigned int delay = 0;
2200
/* get acces unit from MP4 file */
2204
dur = mp4ff_get_sample_duration(mp4state.mp4file, mp4state.mp4track, mp4state.sampleId);
2205
rc = mp4ff_read_sample(mp4state.mp4file, mp4state.mp4track, mp4state.sampleId++, &buffer, &buffer_size);
2207
if (mp4state.sampleId == 1) dur = 0;
2208
if (rc == 0 || buffer == NULL)
2210
mp4state.last_frame = 1;
2211
sample_buffer = NULL;
2212
frameInfo.samples = 0;
2214
sample_buffer = NeAACDecDecode(mp4state.hDecoder, &frameInfo,
2215
buffer, buffer_size);
2217
if (frameInfo.error > 0)
2219
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
2220
mp4state.last_frame = 1;
2222
if (mp4state.sampleId >= mp4state.numSamples)
2223
mp4state.last_frame = 1;
2225
if (buffer) free(buffer);
2227
if (mp4state.useAacLength || (mp4state.timescale != mp4state.samplerate)) {
2228
sample_count = frameInfo.samples;
2230
sample_count = (unsigned int)(dur * frameInfo.channels);
2232
if (!mp4state.useAacLength && !mp4state.initial && (mp4state.sampleId < mp4state.numSamples/2) && (dur*frameInfo.channels != frameInfo.samples))
2234
//fprintf(stderr, "MP4 seems to have incorrect frame duration, using values from AAC data.\n");
2235
mp4state.useAacLength = 1;
2236
sample_count = frameInfo.samples;
2240
if (mp4state.initial && (sample_count < mp4state.framesize*mp4state.channels) && (frameInfo.samples > sample_count))
2242
delay = frameInfo.samples - sample_count;
2245
if (!killPlayThread && (sample_count > 0))
2247
buf = (char *)sample_buffer;
2248
mp4state.initial = 0;
2250
switch (res_table[m_resolution])
2267
if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
2268
remap_channels(buf, sample_count, res_table[m_resolution]);
2270
if (res_table[m_resolution] == 24)
2272
/* convert libfaad output (3 bytes packed in 4) */
2273
char *temp_buffer = convert3in4to3in3(buf, sample_count);
2274
memcpy((void*)buf, (void*)temp_buffer, sample_count*3);
2278
module.SAAddPCMData(buf, (int)mp4state.channels, res_table[m_resolution],
2279
mp4state.decode_pos_ms);
2280
module.VSAAddPCMData(buf, (int)mp4state.channels, res_table[m_resolution],
2281
mp4state.decode_pos_ms);
2282
mp4state.decode_pos_ms += (double)sample_count * 1000.0 /
2283
((double)frameInfo.samplerate * (double)frameInfo.channels);
2285
l = sample_count * res_table[m_resolution] / 8;
2287
if (module.dsp_isactive())
2289
void *dsp_buffer = malloc(l*2);
2290
memcpy(dsp_buffer, buf, l);
2292
l = module.dsp_dosamples((short*)dsp_buffer,
2293
sample_count/frameInfo.channels,
2294
res_table[m_resolution],
2296
frameInfo.samplerate) *
2297
(frameInfo.channels*(res_table[m_resolution]/8));
2299
module.outMod->Write(dsp_buffer, l);
2300
if (dsp_buffer) free(dsp_buffer);
2302
module.outMod->Write(buf, l);
2305
/* VBR bitrate display */
2309
seq_bytes += frameInfo.bytesconsumed;
2310
if (seq_frames == (int)(floor((float)frameInfo.samplerate/(float)(sample_count/frameInfo.channels) + 0.5)))
2312
module.SetInfo((int)floor(((float)seq_bytes*8.)/1000. + 0.5),
2313
(int)floor(frameInfo.samplerate/1000. + 0.5),
2314
mp4state.channels, 1);
2327
PlayThreadAlive = 0;
2332
void *decode_aac_frame(state *st, NeAACDecFrameInfo *frameInfo)
2334
void *sample_buffer = NULL;
2340
if (st->m_aac_bytes_into_buffer != 0)
2342
sample_buffer = NeAACDecDecode(st->hDecoder, frameInfo,
2343
st->m_aac_buffer, st->m_aac_bytes_into_buffer);
2345
if (st->m_header_type != 1)
2347
if (st->last_offset < st->m_file_offset)
2349
st->m_tail->offset = st->m_file_offset;
2350
st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
2351
st->m_tail = st->m_tail->next;
2352
st->m_tail->next = NULL;
2353
st->last_offset = st->m_file_offset;
2357
advance_buffer(st, frameInfo->bytesconsumed);
2362
} while (!frameInfo->samples && !frameInfo->error);
2364
return sample_buffer;
2367
int aac_seek(state *st, double seconds)
2371
struct seek_list *target = st->m_head;
2373
if (1 /*can_seek*/ && ((st->m_header_type == 1) || (seconds < st->cur_pos_sec)))
2375
frames = (int)(seconds*((double)st->samplerate/(double)st->framesize) + 0.5);
2377
for (i = 0; i < frames; i++)
2380
target = target->next;
2384
if (target->offset == 0 && frames > 0)
2386
fseek(st->aacfile, target->offset, SEEK_SET);
2387
st->m_file_offset = target->offset;
2389
bread = fread(st->m_aac_buffer, 1, 768*6, st->aacfile);
2394
st->m_aac_bytes_into_buffer = bread;
2395
st->m_aac_bytes_consumed = 0;
2396
st->m_file_offset += bread;
2398
NeAACDecPostSeekReset(st->hDecoder, -1);
2402
if (seconds > st->cur_pos_sec)
2404
NeAACDecFrameInfo frameInfo;
2406
frames = (int)((seconds - st->cur_pos_sec)*((double)st->samplerate/(double)st->framesize));
2410
for (i = 0; i < frames; i++)
2412
memset(&frameInfo, 0, sizeof(NeAACDecFrameInfo));
2413
decode_aac_frame(st, &frameInfo);
2415
if (frameInfo.error || (st->m_aac_bytes_into_buffer == 0))
2417
if (frameInfo.error)
2419
if (NeAACDecGetErrorMessage(frameInfo.error) != NULL)
2420
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
2427
NeAACDecPostSeekReset(st->hDecoder, -1);
2433
DWORD WINAPI AACPlayThread(void *b)
2441
in_mp4_DebugOutput("AACPlayThread");
2444
PlayThreadAlive = 1;
2445
mp4state.last_frame = 0;
2447
while (!*((int *)b))
2450
if (mp4state.seek_needed != -1)
2454
ms = mp4state.seek_needed/1000;
2455
if (aac_seek(&mp4state, ms)!=0)
2457
module.outMod->Flush(mp4state.decode_pos_ms);
2458
mp4state.cur_pos_sec = ms;
2459
mp4state.decode_pos_ms = mp4state.seek_needed;
2461
mp4state.seek_needed = -1;
2466
module.outMod->CanWrite();
2468
if (!module.outMod->IsPlaying())
2470
PostMessage(module.hMainWindow, WM_WA_AAC_EOF, 0, 0);
2471
PlayThreadAlive = 0;
2476
} else if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short))) {
2477
NeAACDecFrameInfo frameInfo;
2478
void *sample_buffer;
2480
memset(&frameInfo, 0, sizeof(NeAACDecFrameInfo));
2482
sample_buffer = decode_aac_frame(&mp4state, &frameInfo);
2484
if (frameInfo.error || (mp4state.m_aac_bytes_into_buffer == 0))
2486
if (frameInfo.error)
2488
if (NeAACDecGetErrorMessage(frameInfo.error) != NULL)
2489
show_error(module.hMainWindow, NeAACDecGetErrorMessage(frameInfo.error));
2494
if (!killPlayThread && (frameInfo.samples > 0))
2496
if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
2497
remap_channels(sample_buffer, frameInfo.samples, res_table[m_resolution]);
2499
if (res_table[m_resolution] == 24)
2501
/* convert libfaad output (3 bytes packed in 4 bytes) */
2502
char *temp_buffer = convert3in4to3in3(sample_buffer, frameInfo.samples);
2503
memcpy((void*)sample_buffer, (void*)temp_buffer, frameInfo.samples*3);
2507
module.SAAddPCMData(sample_buffer, (int)mp4state.channels, res_table[m_resolution],
2508
mp4state.decode_pos_ms);
2509
module.VSAAddPCMData(sample_buffer, (int)mp4state.channels, res_table[m_resolution],
2510
mp4state.decode_pos_ms);
2511
mp4state.decode_pos_ms += (double)frameInfo.samples * 1000.0 /
2512
((double)frameInfo.samplerate* (double)frameInfo.channels);
2514
l = frameInfo.samples * res_table[m_resolution] / 8;
2516
if (module.dsp_isactive())
2518
void *dsp_buffer = malloc(l*2);
2519
memcpy(dsp_buffer, sample_buffer, l);
2521
l = module.dsp_dosamples((short*)dsp_buffer,
2522
frameInfo.samples/frameInfo.channels,
2523
res_table[m_resolution],
2525
frameInfo.samplerate) *
2526
(frameInfo.channels*(res_table[m_resolution]/8));
2528
module.outMod->Write(dsp_buffer, l);
2529
if (dsp_buffer) free(dsp_buffer);
2531
module.outMod->Write(sample_buffer, l);
2534
/* VBR bitrate display */
2538
seq_bytes += frameInfo.bytesconsumed;
2539
if (seq_frames == (int)(floor((float)frameInfo.samplerate/(float)(frameInfo.samples/frameInfo.channels) + 0.5)))
2541
module.SetInfo((int)floor(((float)seq_bytes*8.)/1000. + 0.5),
2542
(int)floor(frameInfo.samplerate/1000. + 0.5),
2543
mp4state.channels, 1);
2551
if (frameInfo.channels > 0 && mp4state.samplerate > 0)
2552
mp4state.cur_pos_sec += ((double)(frameInfo.samples/frameInfo.channels))/(double)mp4state.samplerate;
2558
PlayThreadAlive = 0;
2563
static In_Module module =
2566
"AudioCoding.com MPEG-4 AAC player: " FAAD2_VERSION " compiled on " __DATE__,
2592
0,0,0,0,0,0,0,0,0, // vis stuff
2604
__declspec(dllexport) In_Module* winampGetInModule2()
2610
module.FileExtensions = short_ext_list;
2612
module.FileExtensions = long_ext_list;
2618
/* new Media Library interface */
2620
int mp4_get_metadata(mp4ff_t *file, const char *item, char *dest, int dlen)
2622
char *pVal = NULL, dummy1[4096];
2624
if (dlen < 1) return 0;
2626
if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
2628
if (mp4ff_meta_get_track(file, &pVal))
2630
wsprintf(dummy1, "%s", pVal);
2631
strncpy(dest, dummy1, dlen-1);
2632
dest[dlen-1] = '\0';
2636
else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
2638
if (mp4ff_meta_get_disc(file, &pVal))
2640
wsprintf(dummy1, "%s", pVal);
2641
strncpy(dest, dummy1, dlen-1);
2642
dest[dlen-1] = '\0';
2646
else if (!stricmp(item, "compilation"))
2649
if (mp4ff_meta_get_compilation(file, &pVal))
2651
wsprintf(dummy1, "%s", pVal);
2652
strncpy(dest, dummy1, dlen-1);
2653
dest[dlen-1] = '\0';
2657
else if (!stricmp(item, "tempo"))
2659
if (mp4ff_meta_get_tempo(file, &pVal))
2661
wsprintf(dummy1, "%s", pVal);
2662
strncpy(dest, dummy1, dlen-1);
2663
dest[dlen-1] = '\0';
2667
else if (!stricmp(item, "artist"))
2669
if (mp4ff_meta_get_artist(file, &pVal))
2671
strncpy(dest, pVal, dlen-1);
2672
dest[dlen-1] = '\0';
2676
else if (!stricmp(item, "writer"))
2678
if (mp4ff_meta_get_writer(file, &pVal))
2680
strncpy(dest, pVal, dlen-1);
2681
dest[dlen-1] = '\0';
2685
else if (!stricmp(item, "title"))
2687
if (mp4ff_meta_get_title(file, &pVal))
2689
strncpy(dest, pVal, dlen-1);
2690
dest[dlen-1] = '\0';
2694
else if (!stricmp(item, "album"))
2696
if (mp4ff_meta_get_album(file, &pVal))
2698
strncpy(dest, pVal, dlen-1);
2699
dest[dlen-1] = '\0';
2703
else if (!stricmp(item, "date") || !stricmp(item, "year"))
2705
if (mp4ff_meta_get_date(file, &pVal))
2707
strncpy(dest, pVal, dlen-1);
2708
dest[dlen-1] = '\0';
2712
else if (!stricmp(item, "comment"))
2714
if (mp4ff_meta_get_comment(file, &pVal))
2716
strncpy(dest, pVal, dlen-1);
2717
dest[dlen-1] = '\0';
2721
else if (!stricmp(item, "genre"))
2723
if (mp4ff_meta_get_genre(file, &pVal))
2725
strncpy(dest, pVal, dlen-1);
2726
dest[dlen-1] = '\0';
2730
else if (!stricmp(item, "tool"))
2732
if (mp4ff_meta_get_tool(file, &pVal))
2734
strncpy(dest, pVal, dlen-1);
2735
dest[dlen-1] = '\0';
2742
uint32_t valueSize = 0;
2743
uint8_t *pValue = NULL;
2745
if (MP4GetMetadataFreeForm(file, (char *)item, &pValue, &valueSize))
2747
unsigned int len = (valueSize < (unsigned int)(dlen-1)) ? valueSize : (unsigned int)(dlen-1);
2748
memcpy(dest, pValue, len);
2758
__declspec(dllexport) int winampGetExtendedFileInfo(const char *fn, const char *data, char *dest, int destlen)
2760
if (!fn || (fn && !*fn) || !destlen) return 0;
2764
if (!stricmp(data, "length"))
2767
int len = getsonglength(fn);
2768
itoa(len, temp, 10);
2769
strncpy(dest, temp, destlen-1);
2770
dest[destlen-1] = '\0';
2774
char temp[2048], temp2[2048];
2776
mp4ff_callback_t mp4cb = {0};
2779
mp4File = fopen(fn, "rb");
2780
mp4cb.read = read_callback;
2781
mp4cb.seek = seek_callback;
2782
mp4cb.write = write_callback;
2783
mp4cb.truncate = truncate_callback;
2784
mp4cb.user_data = mp4File;
2787
file = mp4ff_open_read(&mp4cb);
2788
if (file == NULL) return 0;
2790
if (mp4_get_metadata(file, data, temp, sizeof(temp)))
2792
int len = ConvertUTF8ToANSI(temp, temp2);
2793
if (len > destlen-1) len = destlen-1;
2794
memcpy(dest, temp2, len);
2805
static mp4ff_metadata_t mltags = {0, 0};
2806
static BOOL medialib_init = FALSE;
2807
static char medialib_lastfn[2048] = "";
2809
__declspec(dllexport) int winampSetExtendedFileInfo(const char *fn, const char *data, char *val)
2814
if (!medialib_init || (medialib_init && stricmp(fn, medialib_lastfn))) {
2816
mp4ff_callback_t mp4cb = {0};
2818
strcpy(medialib_lastfn, fn);
2820
if (medialib_init) tag_delete(&mltags);
2822
mp4File = fopen(medialib_lastfn, "rb");
2823
mp4cb.read = read_callback;
2824
mp4cb.seek = seek_callback;
2825
mp4cb.user_data = mp4File;
2828
file = mp4ff_open_read(&mp4cb);
2829
if (file == NULL) return 0;
2831
ReadMP4Tag(file, &mltags);
2836
medialib_init = TRUE;
2840
temp = (char *)malloc((len+1)*4);
2841
if (!temp) return 0;
2843
if (ConvertANSIToUTF8(val, temp))
2846
tag_set_field(&mltags, data, temp, len);
2854
__declspec(dllexport) int winampWriteExtendedFileInfo()
2859
mp4ff_callback_t mp4cb = {0};
2861
mp4File = fopen(medialib_lastfn, "rb+");
2862
mp4cb.read = read_callback;
2863
mp4cb.seek = seek_callback;
2864
mp4cb.write = write_callback;
2865
mp4cb.truncate = truncate_callback;
2866
mp4cb.user_data = mp4File;
2868
mp4ff_meta_update(&mp4cb, &mltags);