source: titan/minidlna-1.0.22/tagutils/tagutils-mp3.c @ 13567

Last change on this file since 13567 was 13567, checked in by obi, 11 years ago

[titan] add minidlna-1.0.22 first step

File size: 17.3 KB
Line 
1//=========================================================================
2// FILENAME     : tagutils-mp3.c
3// DESCRIPTION  : MP3 metadata reader
4//=========================================================================
5// Copyright (c) 2008- NETGEAR, Inc. All Rights Reserved.
6//=========================================================================
7
8/*
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * This file is derived from mt-daap project.
25 */
26
27static int
28_get_mp3tags(char *file, struct song_metadata *psong)
29{
30        struct id3_file *pid3file;
31        struct id3_tag *pid3tag;
32        struct id3_frame *pid3frame;
33        int err;
34        int index;
35        int used;
36        unsigned char *utf8_text;
37        int genre = WINAMP_GENRE_UNKNOWN;
38        int have_utf8;
39        int have_text;
40        id3_ucs4_t const *native_text;
41        char *tmp;
42        int got_numeric_genre;
43        id3_byte_t const *image;
44        id3_length_t image_size = 0;
45
46        pid3file = id3_file_open(file, ID3_FILE_MODE_READONLY);
47        if(!pid3file)
48        {
49                DPRINTF(E_ERROR, L_SCANNER, "Cannot open %s\n", file);
50                return -1;
51        }
52
53        pid3tag = id3_file_tag(pid3file);
54
55        if(!pid3tag)
56        {
57                err = errno;
58                id3_file_close(pid3file);
59                errno = err;
60                DPRINTF(E_WARN, L_SCANNER, "Cannot get ID3 tag for %s\n", file);
61                return -1;
62        }
63
64        index = 0;
65        while((pid3frame = id3_tag_findframe(pid3tag, "", index)))
66        {
67                used = 0;
68                utf8_text = NULL;
69                native_text = NULL;
70                have_utf8 = 0;
71                have_text = 0;
72
73                if(!strcmp(pid3frame->id, "YTCP"))   /* for id3v2.2 */
74                {
75                        psong->compilation = 1;
76                        DPRINTF(E_DEBUG, L_SCANNER, "Compilation: %d [%s]\n", psong->compilation, basename(file));
77                }
78                else if(!strcmp(pid3frame->id, "APIC") && !image_size)
79                {
80                        if( (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpeg") == 0) ||
81                            (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "jpeg") == 0) )
82                        {
83                                image = id3_field_getbinarydata(&pid3frame->fields[4], &image_size);
84                                if( image_size )
85                                {
86                                        psong->image = malloc(image_size);
87                                        memcpy(psong->image, image, image_size);
88                                        psong->image_size = image_size;
89                                        //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Found thumbnail: %d\n", psong->image_size);
90                                }
91                        }
92                }
93
94                if(((pid3frame->id[0] == 'T') || (strcmp(pid3frame->id, "COMM") == 0)) &&
95                   (id3_field_getnstrings(&pid3frame->fields[1])))
96                        have_text = 1;
97
98                if(have_text)
99                {
100                        native_text = id3_field_getstrings(&pid3frame->fields[1], 0);
101
102                        if(native_text)
103                        {
104                                have_utf8 = 1;
105                                if(lang_index >= 0)
106                                        utf8_text = _get_utf8_text(native_text); // through iconv
107                                else
108                                        utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
109
110                                if(!strcmp(pid3frame->id, "TIT2"))
111                                {
112                                        used = 1;
113                                        psong->title = (char*)utf8_text;
114                                }
115                                else if(!strcmp(pid3frame->id, "TPE1"))
116                                {
117                                        used = 1;
118                                        psong->contributor[ROLE_ARTIST] = (char*)utf8_text;
119                                }
120                                else if(!strcmp(pid3frame->id, "TALB"))
121                                {
122                                        used = 1;
123                                        psong->album = (char*)utf8_text;
124                                }
125                                else if(!strcmp(pid3frame->id, "TCOM"))
126                                {
127                                        used = 1;
128                                        psong->contributor[ROLE_COMPOSER] = (char*)utf8_text;
129                                }
130                                else if(!strcmp(pid3frame->id, "TIT1"))
131                                {
132                                        used = 1;
133                                        psong->grouping = (char*)utf8_text;
134                                }
135                                else if(!strcmp(pid3frame->id, "TPE2"))
136                                {
137                                        used = 1;
138                                        psong->contributor[ROLE_BAND] = (char*)utf8_text;
139                                }
140                                else if(!strcmp(pid3frame->id, "TPE3"))
141                                {
142                                        used = 1;
143                                        psong->contributor[ROLE_CONDUCTOR] = (char*)utf8_text;
144                                }
145                                else if(!strcmp(pid3frame->id, "TCON"))
146                                {
147                                        used = 1;
148                                        psong->genre = (char*)utf8_text;
149                                        got_numeric_genre = 0;
150                                        if(psong->genre)
151                                        {
152                                                if(!strlen(psong->genre))
153                                                {
154                                                        genre = WINAMP_GENRE_UNKNOWN;
155                                                        got_numeric_genre = 1;
156                                                }
157                                                else if(isdigit(psong->genre[0]))
158                                                {
159                                                        genre = atoi(psong->genre);
160                                                        got_numeric_genre = 1;
161                                                }
162                                                else if((psong->genre[0] == '(') && (isdigit(psong->genre[1])))
163                                                {
164                                                        genre = atoi((char*)&psong->genre[1]);
165                                                        got_numeric_genre = 1;
166                                                }
167
168                                                if(got_numeric_genre)
169                                                {
170                                                        if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
171                                                                genre = WINAMP_GENRE_UNKNOWN;
172                                                        free(psong->genre);
173                                                        psong->genre = strdup(winamp_genre[genre]);
174                                                }
175                                        }
176                                }
177                                else if(!strcmp(pid3frame->id, "COMM"))
178                                {
179                                        used = 1;
180                                        psong->comment = (char*)utf8_text;
181                                }
182                                else if(!strcmp(pid3frame->id, "TPOS"))
183                                {
184                                        tmp = (char*)utf8_text;
185                                        strsep(&tmp, "/");
186                                        if(tmp)
187                                        {
188                                                psong->total_discs = atoi(tmp);
189                                        }
190                                        psong->disc = atoi((char*)utf8_text);
191                                }
192                                else if(!strcmp(pid3frame->id, "TRCK"))
193                                {
194                                        tmp = (char*)utf8_text;
195                                        strsep(&tmp, "/");
196                                        if(tmp)
197                                        {
198                                                psong->total_tracks = atoi(tmp);
199                                        }
200                                        psong->track = atoi((char*)utf8_text);
201                                }
202                                else if(!strcmp(pid3frame->id, "TDRC"))
203                                {
204                                        psong->year = atoi((char*)utf8_text);
205                                }
206                                else if(!strcmp(pid3frame->id, "TLEN"))
207                                {
208                                        psong->song_length = atoi((char*)utf8_text);
209                                }
210                                else if(!strcmp(pid3frame->id, "TBPM"))
211                                {
212                                        psong->bpm = atoi((char*)utf8_text);
213                                }
214                                else if(!strcmp(pid3frame->id, "TCMP"))
215                                {
216                                        psong->compilation = (char)atoi((char*)utf8_text);
217                                }
218                        }
219                }
220
221                // check if text tag
222                if((!used) && (have_utf8) && (utf8_text))
223                        free(utf8_text);
224
225                // v2 COMM
226                if((!strcmp(pid3frame->id, "COMM")) && (pid3frame->nfields == 4))
227                {
228                        native_text = id3_field_getstring(&pid3frame->fields[2]);
229                        if(native_text)
230                        {
231                                utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
232                                if((utf8_text) && (strncasecmp((char*)utf8_text, "iTun", 4) != 0))
233                                {
234                                        // read comment
235                                        if(utf8_text)
236                                                free(utf8_text);
237
238                                        native_text = id3_field_getfullstring(&pid3frame->fields[3]);
239                                        if(native_text)
240                                        {
241                                                utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
242                                                if(utf8_text)
243                                                {
244                                                        if (psong->comment)
245                                                                free(psong->comment);
246                                                        psong->comment = (char*)utf8_text;
247                                                }
248                                        }
249                                }
250                                else
251                                {
252                                        if(utf8_text)
253                                                free(utf8_text);
254                                }
255                        }
256                }
257
258                index++;
259        }
260
261        id3_file_close(pid3file);
262        //DEBUG DPRINTF(E_INFO, L_SCANNER, "Got id3 tag successfully for file=%s\n", file);
263        return 0;
264}
265
266// _decode_mp3_frame
267static int
268_decode_mp3_frame(unsigned char *frame, struct mp3_frameinfo *pfi)
269{
270        int ver;
271        int layer_index;
272        int sample_index;
273        int bitrate_index;
274        int samplerate_index;
275
276        if((frame[0] != 0xFF) || (frame[1] < 224))
277        {
278                pfi->is_valid = 0;
279                return -1;
280        }
281
282        ver = (frame[1] & 0x18) >> 3;
283        pfi->layer = 4 - ((frame[1] & 0x6) >> 1);
284
285        layer_index = sample_index = -1;
286
287        switch(ver)
288        {
289        case 0:
290                pfi->mpeg_version = 0x25;       // 2.5
291                sample_index = 2;
292                if(pfi->layer == 1)
293                        layer_index = 3;
294                if((pfi->layer == 2) || (pfi->layer == 3))
295                        layer_index = 4;
296                break;
297        case 2:
298                pfi->mpeg_version = 0x20;       // 2.0
299                sample_index = 1;
300                if(pfi->layer == 1)
301                        layer_index = 3;
302                if((pfi->layer == 2) || (pfi->layer == 3))
303                        layer_index = 4;
304                break;
305        case 3:
306                pfi->mpeg_version = 0x10;       // 1.0
307                sample_index = 0;
308                if(pfi->layer == 1)
309                        layer_index = 0;
310                if(pfi->layer == 2)
311                        layer_index = 1;
312                if(pfi->layer == 3)
313                        layer_index = 2;
314                break;
315        }
316
317        if((layer_index < 0) || (layer_index > 4))
318        {
319                pfi->is_valid = 0;
320                return -1;
321        }
322
323        if((sample_index < 0) || (sample_index >= 2))
324        {
325                pfi->is_valid = 0;
326                return -1;
327        }
328
329        if(pfi->layer == 1) pfi->samples_per_frame = 384;
330        if(pfi->layer == 2) pfi->samples_per_frame = 1152;
331        if(pfi->layer == 3)
332        {
333                if(pfi->mpeg_version == 0x10)
334                        pfi->samples_per_frame = 1152;
335                else
336                        pfi->samples_per_frame = 576;
337        }
338
339        bitrate_index = (frame[2] & 0xF0) >> 4;
340        samplerate_index = (frame[2] & 0x0C) >> 2;
341
342        if((bitrate_index == 0xF) || (bitrate_index == 0x0))
343        {
344                pfi->is_valid = 0;
345                return -1;
346        }
347
348        if(samplerate_index == 3)
349        {
350                pfi->is_valid = 0;
351                return -1;
352        }
353
354
355        pfi->bitrate = bitrate_tbl[layer_index][bitrate_index];
356        pfi->samplerate = sample_rate_tbl[sample_index][samplerate_index];
357
358        if((frame[3] & 0xC0 >> 6) == 3)
359                pfi->stereo = 0;
360        else
361                pfi->stereo = 1;
362
363        if(frame[2] & 0x02)
364                pfi->padding = 1;
365        else
366                pfi->padding = 0;
367
368        if(pfi->mpeg_version == 0x10)
369        {
370                if(pfi->stereo)
371                        pfi->xing_offset = 32;
372                else
373                        pfi->xing_offset = 17;
374        }
375        else
376        {
377                if(pfi->stereo)
378                        pfi->xing_offset = 17;
379                else
380                        pfi->xing_offset = 9;
381        }
382
383        pfi->crc_protected = frame[1] & 0xFE;
384
385        if(pfi->layer == 1)
386                pfi->frame_length = (12 * pfi->bitrate * 1000 / pfi->samplerate + pfi->padding) * 4;
387        else
388                pfi->frame_length = 144 * pfi->bitrate * 1000 / pfi->samplerate + pfi->padding;
389
390        if((pfi->frame_length > 2880) || (pfi->frame_length <= 0))
391        {
392                pfi->is_valid = 0;
393                return -1;
394        }
395
396        pfi->is_valid = 1;
397        return 0;
398}
399
400// _mp3_get_average_bitrate
401//    read from midle of file, and estimate
402static void _mp3_get_average_bitrate(FILE *infile, struct mp3_frameinfo *pfi, const char *fname)
403{
404        off_t file_size;
405        unsigned char frame_buffer[2900];
406        unsigned char header[4];
407        int index = 0;
408        int found = 0;
409        off_t pos;
410        struct mp3_frameinfo fi;
411        int frame_count = 0;
412        int bitrate_total = 0;
413
414        fseek(infile, 0, SEEK_END);
415        file_size = ftell(infile);
416
417        pos = file_size >> 1;
418
419        /* now, find the first frame */
420        fseek(infile, pos, SEEK_SET);
421        if(fread(frame_buffer, 1, sizeof(frame_buffer), infile) != sizeof(frame_buffer))
422                return;
423
424        while(!found)
425        {
426                while((frame_buffer[index] != 0xFF) && (index < (sizeof(frame_buffer) - 4)))
427                        index++;
428
429                if(index >= (sizeof(frame_buffer) - 4))   // max mp3 framesize = 2880
430                {
431                        DPRINTF(E_DEBUG, L_SCANNER, "Could not find frame for %s\n", basename((char *)fname));
432                        return;
433                }
434
435                if(!_decode_mp3_frame(&frame_buffer[index], &fi))
436                {
437                        /* see if next frame is valid */
438                        fseek(infile, pos + index + fi.frame_length, SEEK_SET);
439                        if(fread(header, 1, sizeof(header), infile) != sizeof(header))
440                        {
441                                DPRINTF(E_DEBUG, L_SCANNER, "Could not read frame header for %s\n", basename((char *)fname));
442                                return;
443                        }
444
445                        if(!_decode_mp3_frame(header, &fi))
446                                found = 1;
447                }
448
449                if(!found)
450                        index++;
451        }
452
453        pos += index;
454
455        // got first frame
456        while(frame_count < 10)
457        {
458                fseek(infile, pos, SEEK_SET);
459                if(fread(header, 1, sizeof(header), infile) != sizeof(header))
460                {
461                        DPRINTF(E_DEBUG, L_SCANNER, "Could not read frame header for %s\n", basename((char *)fname));
462                        return;
463                }
464                if(_decode_mp3_frame(header, &fi))
465                {
466                        DPRINTF(E_DEBUG, L_SCANNER, "Invalid frame header while averaging %s\n", basename((char *)fname));
467                        return;
468                }
469
470                bitrate_total += fi.bitrate;
471                frame_count++;
472                pos += fi.frame_length;
473        }
474
475        pfi->bitrate = bitrate_total / frame_count;
476
477        return;
478}
479
480// _mp3_get_frame_count
481//   do brute scan
482static void __attribute__((unused))
483_mp3_get_frame_count(FILE *infile, struct mp3_frameinfo *pfi)
484{
485        int pos;
486        int frames = 0;
487        unsigned char frame_buffer[4];
488        struct mp3_frameinfo fi;
489        off_t file_size;
490        int err = 0;
491        int cbr = 1;
492        int last_bitrate = 0;
493
494        fseek(infile, 0, SEEK_END);
495        file_size = ftell(infile);
496
497        pos = pfi->frame_offset;
498
499        while(1)
500        {
501                err = 1;
502
503                fseek(infile, pos, SEEK_SET);
504                if(fread(frame_buffer, 1, sizeof(frame_buffer), infile) == sizeof(frame_buffer))
505                {
506                        // valid frame?
507                        if(!_decode_mp3_frame(frame_buffer, &fi))
508                        {
509                                frames++;
510                                pos += fi.frame_length;
511                                err = 0;
512
513                                if((last_bitrate) && (fi.bitrate != last_bitrate))
514                                        cbr = 0;
515                                last_bitrate = fi.bitrate;
516
517                                // no sense to scan cbr
518                                if(cbr && (frames > 100))
519                                {
520                                        DPRINTF(E_DEBUG, L_SCANNER, "File appears to be CBR... quitting frame _mp3_get_frame_count()\n");
521                                        return;
522                                }
523                        }
524                }
525
526                if(err)
527                {
528                        if(pos > (file_size - 4096))
529                        {
530                                pfi->number_of_frames = frames;
531                                return;
532                        }
533                        else
534                        {
535                                DPRINTF(E_ERROR, L_SCANNER, "Frame count aborted on error.  Pos=%d, Count=%d\n",
536                                        pos, frames);
537                                return;
538                        }
539                }
540        }
541}
542
543// _get_mp3fileinfo
544static int
545_get_mp3fileinfo(char *file, struct song_metadata *psong)
546{
547        FILE *infile;
548        struct id3header *pid3;
549        struct mp3_frameinfo fi;
550        unsigned int size = 0;
551        unsigned int n_read;
552        off_t fp_size = 0;
553        off_t file_size;
554        unsigned char buffer[1024];
555        int index;
556
557        int xing_flags;
558        int found;
559
560        int first_check = 0;
561        char frame_buffer[4];
562
563        char id3v1taghdr[4];
564
565        if(!(infile = fopen(file, "rb")))
566        {
567                DPRINTF(E_ERROR, L_SCANNER, "Could not open %s for reading\n", file);
568                return -1;
569        }
570
571        memset((void*)&fi, 0, sizeof(fi));
572
573        fseek(infile, 0, SEEK_END);
574        file_size = ftell(infile);
575        fseek(infile, 0, SEEK_SET);
576
577        if(fread(buffer, 1, sizeof(buffer), infile) != sizeof(buffer))
578        {
579                if(ferror(infile))
580                {
581                        DPRINTF(E_ERROR, L_SCANNER, "Error reading: %s [%s]\n", strerror(errno), file);
582                }
583                else
584                {
585                        DPRINTF(E_WARN, L_SCANNER, "File too small. Probably corrupted. [%s]\n", file);
586                }
587                fclose(infile);
588                return -1;
589        }
590
591        pid3 = (struct id3header*)buffer;
592
593        found = 0;
594        fp_size = 0;
595
596        if(strncmp((char*)pid3->id, "ID3", 3) == 0)
597        {
598                char tagversion[16];
599
600                /* found an ID3 header... */
601                size = (pid3->size[0] << 21 | pid3->size[1] << 14 |
602                        pid3->size[2] << 7 | pid3->size[3]);
603                fp_size = size + sizeof(struct id3header);
604                first_check = 1;
605
606                snprintf(tagversion, sizeof(tagversion), "ID3v2.%d.%d",
607                         pid3->version[0], pid3->version[1]);
608                psong->tagversion = strdup(tagversion);
609        }
610
611        index = 0;
612
613        /* Here we start the brute-force header seeking.  Sure wish there
614         * weren't so many crappy mp3 files out there
615         */
616
617        while(!found)
618        {
619                fseek(infile, fp_size, SEEK_SET);
620                if((n_read = fread(buffer, 1, sizeof(buffer), infile)) < 4)   // at least mp3 frame header size (i.e. 4 bytes)
621                {
622                        fclose(infile);
623                        return 0;
624                }
625
626                index = 0;
627                while(!found)
628                {
629                        while((buffer[index] != 0xFF) && (index < (n_read - 50)))
630                                index++;
631
632                        if((first_check) && (index))
633                        {
634                                fp_size = 0;
635                                first_check = 0;
636                                if(n_read < sizeof(buffer))
637                                {
638                                        fclose(infile);
639                                        return 0;
640                                }
641                                break;
642                        }
643
644                        if(index > (n_read - 50))
645                        {
646                                fp_size += index;
647                                if(n_read < sizeof(buffer))
648                                {
649                                        fclose(infile);
650                                        return 0;
651                                }
652                                break;
653                        }
654
655                        if(!_decode_mp3_frame(&buffer[index], &fi))
656                        {
657                                if(!strncasecmp((char*)&buffer[index + fi.xing_offset + 4], "XING", 4))
658                                {
659                                        /* no need to check further... if there is a xing header there,
660                                         * this is definately a valid frame */
661                                        found = 1;
662                                        fp_size += index;
663                                }
664                                else
665                                {
666                                        /* No Xing... check for next frame to validate current fram is correct */
667                                        fseek(infile, fp_size + index + fi.frame_length, SEEK_SET);
668                                        if(fread(frame_buffer, 1, sizeof(frame_buffer), infile) == sizeof(frame_buffer))
669                                        {
670                                                if(!_decode_mp3_frame((unsigned char*)frame_buffer, &fi))
671                                                {
672                                                        found = 1;
673                                                        fp_size += index;
674                                                }
675                                        }
676                                        else
677                                        {
678                                                DPRINTF(E_ERROR, L_SCANNER, "Could not read frame header: %s\n", file);
679                                                fclose(infile);
680                                                return 0;
681                                        }
682
683                                        if(!found)
684                                        {
685                                                // cannot find second frame. Song may be too short. So assume first frame is valid.
686                                                found = 1;
687                                                fp_size += index;
688                                        }
689                                }
690                        }
691
692                        if(!found)
693                        {
694                                index++;
695                                if(first_check)
696                                {
697                                        DPRINTF(E_INFO, L_SCANNER, "Bad header... dropping back for full frame search [%s]\n", psong->path);
698                                        first_check = 0;
699                                        fp_size = 0;
700                                        break;
701                                }
702                        }
703                }
704        }
705
706        fi.frame_offset = fp_size;
707
708        psong->audio_offset = fp_size;
709        psong->audio_size = file_size - fp_size;
710        // check if last 128 bytes is ID3v1.0 ID3v1.1 tag
711        fseek(infile, file_size - 128, SEEK_SET);
712        if(fread(id3v1taghdr, 1, 4, infile) == 4)
713        {
714                if(id3v1taghdr[0] == 'T' && id3v1taghdr[1] == 'A' && id3v1taghdr[2] == 'G')
715                {
716                        psong->audio_size -= 128;
717                }
718        }
719
720        if(_decode_mp3_frame(&buffer[index], &fi))
721        {
722                fclose(infile);
723                DPRINTF(E_ERROR, L_SCANNER, "Could not find sync frame: %s\n", file);
724                return 0;
725        }
726
727        /* now check for an XING header */
728        psong->vbr_scale = -1;
729        if(!strncasecmp((char*)&buffer[index + fi.xing_offset + 4], "XING", 4))
730        {
731                xing_flags = buffer[index+fi.xing_offset+4+4] << 24 |
732                             buffer[index+fi.xing_offset+4+5] << 16 |
733                             buffer[index+fi.xing_offset+4+6] << 8 |
734                             buffer[index+fi.xing_offset+4+7];
735                psong->vbr_scale = 78;
736
737                if(xing_flags & 0x1)
738                {
739                        /* Frames field is valid... */
740                        fi.number_of_frames = buffer[index+fi.xing_offset+4+8] << 24 |
741                                              buffer[index+fi.xing_offset+4+9] << 16 |
742                                              buffer[index+fi.xing_offset+4+10] << 8 |
743                                              buffer[index+fi.xing_offset+4+11];
744                }
745        }
746
747        if((fi.number_of_frames == 0) && (!psong->song_length))
748        {
749                _mp3_get_average_bitrate(infile, &fi, file);
750        }
751
752        psong->bitrate = fi.bitrate * 1000;
753        psong->samplerate = fi.samplerate;
754
755        if(!psong->song_length)
756        {
757                if(fi.number_of_frames)
758                {
759                        psong->song_length = (int)((double)(fi.number_of_frames * fi.samples_per_frame * 1000.) /
760                                                   (double)fi.samplerate);
761                        psong->vbr_scale = 78;
762                }
763                else
764                {
765                        psong->song_length = (int)((double)(file_size - fp_size) * 8. /
766                                                   (double)fi.bitrate);
767                }
768        }
769        psong->channels = fi.stereo ? 2 : 1;
770
771        fclose(infile);
772        //DEBUG DPRINTF(E_INFO, L_SCANNER, "Got fileinfo successfully for file=%s song_length=%d\n", file, psong->song_length);
773
774        psong->blockalignment = 1;
775        asprintf(&(psong->dlna_pn), "MP3");
776
777        return 0;
778}
Note: See TracBrowser for help on using the repository browser.