mod_musicindex  1.4.1
playlist-flac.c
Go to the documentation of this file.
1 /*
2  * playlist-flac.c
3  * mod_musicindex
4  *
5  * $Id: playlist-flac.c 1010 2012-08-07 13:38:34Z varenet $
6  *
7  * Created by Regis BOUDIN on Thu Jun 30 2004.
8  * Copyright (c) 2004 Regis BOUDIN
9  * Copyright (c) 2004-2005,2007 Thibaut VARENE
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 2.1,
13  * as published by the Free Software Foundation.
14  *
15  */
16 
31 #include "playlist.h"
32 #include "playlist-flac.h"
33 
34 #include <FLAC/format.h>
35 #include <FLAC/metadata.h>
36 
37 #ifdef HAVE_SYS_STAT_H
38 #include <sys/stat.h>
39 #endif
40 
52 static inline short flac_ext_check(const char *const filename)
53 {
54  const char *const ext = strrchr(filename, '.');
55  if (ext && (!strncasecmp(ext, ".fla", 4)))
56  return TRUE;
57  return FALSE;
58 }
59 
74 mu_ent *make_flac_entry(request_rec *r, apr_pool_t *pool, FILE *const in,
75  const char *const filename)
76 {
77  const mu_config *const conf = (mu_config *)ap_get_module_config(r->per_dir_config, &musicindex_module);
78  mu_ent *p = NULL;
79  struct stat filestat;
80  FLAC__StreamMetadata streaminfo;
81  FLAC__Metadata_SimpleIterator *iterator;
82 
83  if (!flac_ext_check(filename) || !FLAC__metadata_get_streaminfo(filename, &streaminfo))
84  return NULL;
85 
86  fstat(fileno(in), &filestat);
87 
88  p = NEW_ENT(pool);
89  if (p == NULL)
90  return NULL;
91 
92  p->filetype = FT_FLAC;
93  p->flags |= EF_VBR;
94 
95  p->size = filestat.st_size;
96  p->mtime = filestat.st_mtime;
97 
98  fclose(in); /* No longer using the provided fstream */
99 
100  if (conf->options & (MI_QUICKPL))
101  p->bitrate = p->length = p->freq = 0;
102  else {
103  /* FLAC codec doesn't provide the information we need, so we have to make it up by ourselves...
104  We should check the correctness of the sample_rate using the appropriate FLAC_ function btw */
105  p->bitrate = (8 * filestat.st_size) / (streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
106  p->length = (unsigned short)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
107  p->freq = streaminfo.data.stream_info.sample_rate;
108  }
109 
110  iterator = FLAC__metadata_simple_iterator_new();
111 
112  if (!iterator)
113  goto exit;
114 
115  if (FLAC__metadata_simple_iterator_init(iterator, filename, true, true)) {
116  FLAC__StreamMetadata *block = NULL;
117  const FLAC__StreamMetadata_VorbisComment *vc = NULL;
118  register unsigned short i;
119  do {
120  if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_VORBIS_COMMENT)
121  continue;
122 
123  block = FLAC__metadata_simple_iterator_get_block(iterator);
124  if(block == NULL)
125  continue;
126 
127  /* If we reached that point, then we have found something! */
128  vc = &block->data.vorbis_comment;
129  for(i = 0; i < vc->num_comments; i++) {
130  if (!strncasecmp((char *)vc->comments[i].entry, "album=", 6))
131  p->album = apr_pstrndup(pool, (char *)vc->comments[i].entry+6, vc->comments[i].length-6);
132  else if (!strncasecmp((char *)vc->comments[i].entry, "artist=", 7))
133  p->artist = apr_pstrndup(pool, (char *)vc->comments[i].entry+7, vc->comments[i].length-7);
134  else if (!strncasecmp((char *)vc->comments[i].entry, "title=", 6))
135  p->title = apr_pstrndup(pool, (char *)vc->comments[i].entry+6, vc->comments[i].length-6);
136  else if (!strncasecmp((char *)vc->comments[i].entry, "tracknumber=", 12))
137  p->track = atoi((char *)vc->comments[i].entry+12);
138  else if (!strncasecmp((char *)vc->comments[i].entry, "discnumber=", 11))
139  p->posn = atoi((char *)vc->comments[i].entry+11);
140  else if (!strncasecmp((char *)vc->comments[i].entry, "date=", 5))
141  p->date = atoi((char *)vc->comments[i].entry+5);
142  }
143  FLAC__metadata_object_delete(block);
144 
145  break;
146  } while (FLAC__metadata_simple_iterator_next(iterator));
147  }
148  FLAC__metadata_simple_iterator_delete(iterator);
149 
150 exit:
151  return p;
152 }