"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/tagutils/tagutils-dsf.c" (24 Nov 2020, 11280 Bytes) of package /linux/privat/minidlna-1.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tagutils-dsf.c" see the Fossies "Dox" file reference documentation.

    1 //=========================================================================
    2 // FILENAME : tagutils-dsf.c
    3 // DESCRIPTION  : DSF metadata reader
    4 //=========================================================================
    5 // Copyright (c) 2014 Takeshich NAKAMURA
    6 // based on tagutils-mp3.c
    7 //=========================================================================
    8 
    9 /*
   10  * This program is free software; you can redistribute it and/or modify
   11  * it under the terms of the GNU General Public License as published by
   12  * the Free Software Foundation; either version 2 of the License, or
   13  * (at your option) any later version.
   14  *
   15  * This program is distributed in the hope that it will be useful,
   16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  * GNU General Public License for more details.
   19  *
   20  * You should have received a copy of the GNU General Public License
   21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
   22  */
   23 
   24 #define GET_DSF_INT64(p) ((((uint64_t)((p)[7])) << 56) |   \
   25               (((uint64_t)((p)[6])) << 48) |   \
   26               (((uint64_t)((p)[5])) << 40) |   \
   27               (((uint64_t)((p)[4])) << 32) |   \
   28               (((uint64_t)((p)[3])) << 24) |   \
   29               (((uint64_t)((p)[2])) << 16) |   \
   30               (((uint64_t)((p)[1])) << 8) |    \
   31               (((uint64_t)((p)[0]))))
   32 
   33 #define GET_DSF_INT32(p) ((((uint8_t)((p)[3])) << 24) |   \
   34               (((uint8_t)((p)[2])) << 16) |   \
   35               (((uint8_t)((p)[1])) << 8) |     \
   36               (((uint8_t)((p)[0]))))
   37 
   38 static int
   39 _get_dsftags(char *file, struct song_metadata *psong)
   40 {
   41     struct id3_tag *pid3tag;
   42     struct id3_frame *pid3frame;
   43     int err;
   44     int index;
   45     int used;
   46     unsigned char *utf8_text;
   47     int genre = WINAMP_GENRE_UNKNOWN;
   48     int have_utf8;
   49     int have_text;
   50     id3_ucs4_t const *native_text;
   51     char *tmp;
   52     int got_numeric_genre;
   53     id3_byte_t const *image;
   54     id3_length_t image_size = 0;
   55 
   56     FILE *fp;
   57     struct id3header *pid3;
   58     uint32_t len;
   59     unsigned char hdr[28] = { 0 };
   60     uint64_t total_size = 0;
   61     uint64_t pointer_to_metadata_chunk = 0;
   62     uint64_t metadata_chunk_size = 0;
   63     unsigned char *id3tagbuf = NULL;
   64 
   65     //DEBUG DPRINTF(E_DEBUG,L_SCANNER,"Getting DSF file info\n");
   66 
   67     if ((fp = fopen(file, "rb")) == NULL)
   68     {
   69         DPRINTF(E_WARN, L_SCANNER, "Could not create file handle\n");
   70         return -1;
   71     }
   72 
   73     len = 28;
   74     if (!(len = fread(hdr, len, 1, fp)))
   75     {
   76         DPRINTF(E_WARN, L_SCANNER, "Could not read DSD Chunk from %s\n", file);
   77         fclose(fp);
   78         return -1;
   79     }
   80 
   81     if (strncmp((char*)hdr, "DSD ", 4))
   82     {
   83         DPRINTF(E_WARN, L_SCANNER, "Invalid DSD Chunk header in %s\n", file);
   84         fclose(fp);
   85         return -1;
   86     }
   87 
   88     total_size = GET_DSF_INT64(hdr + 12);
   89     pointer_to_metadata_chunk = GET_DSF_INT64(hdr + 20);
   90 
   91     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", total_size);
   92     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", pointer_to_metadata_chunk);
   93     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%llu\n", metadata_chunk_size);
   94 
   95     //check invalid metadata
   96     if (total_size == 0)
   97     {
   98         fclose(fp);
   99         DPRINTF(E_INFO, L_SCANNER, "Invalid TotalDataSize in %s\n", file);
  100         return 0;
  101     }
  102 
  103     if (pointer_to_metadata_chunk == 0)
  104     {
  105         fclose(fp);
  106         DPRINTF(E_INFO, L_SCANNER, "Metadata doesn't exist %s\n", file);
  107         return 0;
  108     }
  109 
  110     if (total_size > pointer_to_metadata_chunk)
  111     {
  112         metadata_chunk_size = total_size - pointer_to_metadata_chunk;
  113     }
  114     else
  115     {
  116         fclose(fp);
  117         DPRINTF(E_INFO, L_SCANNER, "Invalid PointerToMetadata in %s\n", file);
  118         return 0;
  119     }
  120 
  121     fseeko(fp, pointer_to_metadata_chunk, SEEK_SET);
  122 
  123     id3tagbuf = (unsigned char*)malloc(sizeof(unsigned char) * metadata_chunk_size);
  124     if (id3tagbuf == NULL)
  125     {
  126         fclose(fp);
  127         DPRINTF(E_WARN, L_SCANNER, "Out of memory.Big MetadataSize in %s\n", file);
  128         return -1;
  129     }
  130     memset(id3tagbuf, 0, sizeof(unsigned char) * metadata_chunk_size);
  131 
  132     if (!(len = fread(id3tagbuf, metadata_chunk_size, 1, fp)))
  133     {
  134         fclose(fp);
  135         free(id3tagbuf);
  136         DPRINTF(E_WARN, L_SCANNER, "Could not read Metadata Chunk from %s\n", file);
  137         return -1;
  138     }
  139 
  140     pid3tag = id3_tag_parse(id3tagbuf, metadata_chunk_size);
  141 
  142     if (!pid3tag)
  143     {
  144         free(id3tagbuf);
  145         err = errno;
  146         errno = err;
  147         DPRINTF(E_WARN, L_SCANNER, "Cannot get ID3 tag for %s\n", file);
  148         return -1;
  149     }
  150 
  151     pid3 = (struct id3header*)id3tagbuf;
  152 
  153     if (strncmp((char*)pid3->id, "ID3", 3) == 0)
  154     {
  155         char tagversion[16];
  156 
  157         /* found an ID3 header... */
  158         snprintf(tagversion, sizeof(tagversion), "ID3v2.%d.%d",
  159              pid3->version[0], pid3->version[1]);
  160         psong->tagversion = strdup(tagversion);
  161     }
  162     pid3 = NULL;
  163 
  164     index = 0;
  165     while ((pid3frame = id3_tag_findframe(pid3tag, "", index)))
  166     {
  167         used = 0;
  168         utf8_text = NULL;
  169         native_text = NULL;
  170         have_utf8 = 0;
  171         have_text = 0;
  172 
  173         if (!strcmp(pid3frame->id, "YTCP"))   /* for id3v2.2 */
  174         {
  175             psong->compilation = 1;
  176             DPRINTF(E_DEBUG, L_SCANNER, "Compilation: %d [%s]\n", psong->compilation, basename(file));
  177         }
  178         else if (!strcmp(pid3frame->id, "APIC") && !image_size)
  179         {
  180             if ((strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpeg") == 0) ||
  181                 (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "image/jpg") == 0) ||
  182                 (strcmp((char*)id3_field_getlatin1(&pid3frame->fields[1]), "jpeg") == 0))
  183             {
  184                 image = id3_field_getbinarydata(&pid3frame->fields[4], &image_size);
  185                 if (image_size)
  186                 {
  187                     psong->image = malloc(image_size);
  188                     memcpy(psong->image, image, image_size);
  189                     psong->image_size = image_size;
  190                     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Found thumbnail: %d\n", psong->image_size);
  191                 }
  192             }
  193         }
  194 
  195         if (((pid3frame->id[0] == 'T') || (strcmp(pid3frame->id, "COMM") == 0)) &&
  196             (id3_field_getnstrings(&pid3frame->fields[1])))
  197             have_text = 1;
  198 
  199         if (have_text)
  200         {
  201             native_text = id3_field_getstrings(&pid3frame->fields[1], 0);
  202 
  203             if (native_text)
  204             {
  205                 have_utf8 = 1;
  206                 if (lang_index >= 0)
  207                     utf8_text = _get_utf8_text(native_text); // through iconv
  208                 else
  209                     utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
  210 
  211                 if (!strcmp(pid3frame->id, "TIT2"))
  212                 {
  213                     used = 1;
  214                     psong->title = (char*)utf8_text;
  215                 }
  216                 else if (!strcmp(pid3frame->id, "TPE1"))
  217                 {
  218                     used = 1;
  219                     psong->contributor[ROLE_ARTIST] = (char*)utf8_text;
  220                 }
  221                 else if (!strcmp(pid3frame->id, "TALB"))
  222                 {
  223                     used = 1;
  224                     psong->album = (char*)utf8_text;
  225                 }
  226                 else if (!strcmp(pid3frame->id, "TCOM"))
  227                 {
  228                     used = 1;
  229                     psong->contributor[ROLE_COMPOSER] = (char*)utf8_text;
  230                 }
  231                 else if (!strcmp(pid3frame->id, "TIT1"))
  232                 {
  233                     used = 1;
  234                     psong->grouping = (char*)utf8_text;
  235                 }
  236                 else if (!strcmp(pid3frame->id, "TPE2"))
  237                 {
  238                     used = 1;
  239                     psong->contributor[ROLE_BAND] = (char*)utf8_text;
  240                 }
  241                 else if (!strcmp(pid3frame->id, "TPE3"))
  242                 {
  243                     used = 1;
  244                     psong->contributor[ROLE_CONDUCTOR] = (char*)utf8_text;
  245                 }
  246                 else if (!strcmp(pid3frame->id, "TCON"))
  247                 {
  248                     used = 1;
  249                     psong->genre = (char*)utf8_text;
  250                     got_numeric_genre = 0;
  251                     if (psong->genre)
  252                     {
  253                         if (!strlen(psong->genre))
  254                         {
  255                             genre = WINAMP_GENRE_UNKNOWN;
  256                             got_numeric_genre = 1;
  257                         }
  258                         else if (isdigit(psong->genre[0]))
  259                         {
  260                             genre = atoi(psong->genre);
  261                             got_numeric_genre = 1;
  262                         }
  263                         else if ((psong->genre[0] == '(') && (isdigit(psong->genre[1])))
  264                         {
  265                             genre = atoi((char*)&psong->genre[1]);
  266                             got_numeric_genre = 1;
  267                         }
  268 
  269                         if (got_numeric_genre)
  270                         {
  271                             if ((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN))
  272                                 genre = WINAMP_GENRE_UNKNOWN;
  273                             free(psong->genre);
  274                             psong->genre = strdup(winamp_genre[genre]);
  275                         }
  276                     }
  277                 }
  278                 else if (!strcmp(pid3frame->id, "COMM"))
  279                 {
  280                     used = 1;
  281                     psong->comment = (char*)utf8_text;
  282                 }
  283                 else if (!strcmp(pid3frame->id, "TPOS"))
  284                 {
  285                     tmp = (char*)utf8_text;
  286                     strsep(&tmp, "/");
  287                     if (tmp)
  288                     {
  289                         psong->total_discs = atoi(tmp);
  290                     }
  291                     psong->disc = atoi((char*)utf8_text);
  292                 }
  293                 else if (!strcmp(pid3frame->id, "TRCK"))
  294                 {
  295                     tmp = (char*)utf8_text;
  296                     strsep(&tmp, "/");
  297                     if (tmp)
  298                     {
  299                         psong->total_tracks = atoi(tmp);
  300                     }
  301                     psong->track = atoi((char*)utf8_text);
  302                 }
  303                 else if (!strcmp(pid3frame->id, "TDRC"))
  304                 {
  305                     psong->year = atoi((char*)utf8_text);
  306                 }
  307                 else if (!strcmp(pid3frame->id, "TLEN"))
  308                 {
  309                     psong->song_length = atoi((char*)utf8_text);
  310                 }
  311                 else if (!strcmp(pid3frame->id, "TBPM"))
  312                 {
  313                     psong->bpm = atoi((char*)utf8_text);
  314                 }
  315                 else if (!strcmp(pid3frame->id, "TCMP"))
  316                 {
  317                     psong->compilation = (char)atoi((char*)utf8_text);
  318                 }
  319             }
  320         }
  321 
  322         // check if text tag
  323         if ((!used) && (have_utf8) && (utf8_text))
  324             free(utf8_text);
  325 
  326         // v2 COMM
  327         if ((!strcmp(pid3frame->id, "COMM")) && (pid3frame->nfields == 4))
  328         {
  329             native_text = id3_field_getstring(&pid3frame->fields[2]);
  330             if (native_text)
  331             {
  332                 utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
  333                 if ((utf8_text) && (strncasecmp((char*)utf8_text, "iTun", 4) != 0))
  334                 {
  335                     // read comment
  336                     free(utf8_text);
  337 
  338                     native_text = id3_field_getfullstring(&pid3frame->fields[3]);
  339                     if (native_text)
  340                     {
  341                         utf8_text = (unsigned char*)id3_ucs4_utf8duplicate(native_text);
  342                         if (utf8_text)
  343                         {
  344                             free(psong->comment);
  345                             psong->comment = (char*)utf8_text;
  346                         }
  347                     }
  348                 }
  349                 else
  350                 {
  351                     free(utf8_text);
  352                 }
  353             }
  354         }
  355 
  356         index++;
  357     }
  358 
  359     id3_tag_delete(pid3tag);
  360     free(id3tagbuf);
  361     fclose(fp);
  362     //DPRINTF(E_DEBUG, L_SCANNER, "Got id3tag successfully for file=%s\n", file);
  363     return 0;
  364 }
  365 
  366 static int
  367 _get_dsffileinfo(char *file, struct song_metadata *psong)
  368 {
  369     FILE *fp;
  370     int len = 80;
  371     unsigned char hdr[len];
  372     uint32_t channelnum;
  373     uint32_t samplingfrequency;
  374     uint32_t bitpersample;
  375     uint64_t samplecount;
  376 
  377     if ((fp = fopen(file, "rb")) == NULL)
  378     {
  379         DPRINTF(E_WARN, L_SCANNER, "Could not create file handle\n");
  380         return -1;
  381     }
  382 
  383     if (!(len = fread(hdr, len, 1, fp)))
  384     {
  385         DPRINTF(E_WARN, L_SCANNER, "Could not read chunks from %s\n", file);
  386         fclose(fp);
  387         return -1;
  388     }
  389 
  390     if (strncmp((char*)hdr, "DSD ", 4))
  391     {
  392         DPRINTF(E_WARN, L_SCANNER, "Invalid DSD Chunk headerin %s\n", file);
  393         fclose(fp);
  394         return -1;
  395     }
  396 
  397     if (strncmp((char*)hdr + 28, "fmt ", 4))
  398     {
  399         DPRINTF(E_WARN, L_SCANNER, "Invalid fmt Chunk header in %s\n", file);
  400         fclose(fp);
  401         return -1;
  402     }
  403 
  404     channelnum = GET_DSF_INT32(hdr + 52);
  405     samplingfrequency = GET_DSF_INT32(hdr + 56);
  406     bitpersample = GET_DSF_INT32(hdr + 60);
  407     samplecount = GET_DSF_INT64(hdr + 64);
  408 
  409     psong->bitrate = channelnum * samplingfrequency * bitpersample;
  410     psong->samplesize = bitpersample;
  411     psong->samplerate = samplingfrequency;
  412     psong->song_length = (samplecount / samplingfrequency) * 1000;
  413     psong->channels = channelnum;
  414 
  415     DPRINTF(E_MAXDEBUG, L_SCANNER, "Got file info successfully for %s\n", file);
  416     //DEBUG DPRINTF(E_MAXDEBUG, L_SCANNER, "bitrate is  %d\n", psong->bitrate);
  417     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplesize is  %d\n", psong->samplesize);
  418     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplerate is  %d\n", psong->samplerate);
  419     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "song_length is  %d\n", psong->song_length);
  420     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "channels are  %d\n", psong->channels);
  421     //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "samplecount are  %lld\n", samplecount);
  422     fclose(fp);
  423 
  424     xasprintf(&(psong->dlna_pn), "DSF");
  425     return 0;
  426 }