00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00032
00033 #ifdef HAVE_CONFIG_H
00034 #include "autoconfig.h"
00035 #endif
00036
00037 #ifdef HAVE_ID3LIB
00038
00039 #ifdef HAVE_CONFIG_H
00040 #undef HAVE_CONFIG_H // else utils.h from the id3 library tries to import "config.h"
00041
00042 #include <id3/tag.h>
00043 #include <id3/misc_support.h>
00044 #define HAVE_CONFIG_H
00045 #else
00046 #include <id3/tag.h>
00047 #include <id3/misc_support.h>
00048 #endif
00049
00050 #include "id3_handler.h"
00051 #include "string_converter.h"
00052 #include "common.h"
00053 #include "tools.h"
00054 #include "mem_io_handler.h"
00055 #include "content_manager.h"
00056 #include "config_manager.h"
00057
00058 using namespace zmm;
00059
00060 Id3Handler::Id3Handler() : MetadataHandler()
00061 {
00062 }
00063
00064 char* ID3_GetFrameContent(const ID3_Tag *tag, ID3_FrameID frameID)
00065 {
00066 char *content = NULL;
00067 ID3_Frame *frame = NULL;
00068 if (tag != NULL && (frame = tag->Find(frameID)) != NULL)
00069 {
00070 content = ID3_GetString(frame, ID3FN_TEXT);
00071 }
00072 return content;
00073 }
00074
00075 static void addID3Field(metadata_fields_t field, ID3_Tag *tag, Ref<CdsItem> item)
00076 {
00077 String value;
00078 char* ID3_retval = NULL;
00079
00080 Ref<StringConverter> sc = StringConverter::m2i();
00081 size_t genre;
00082 #if SIZEOF_SIZE_T > 4
00083 long track;
00084 #else
00085 int track;
00086 #endif
00087
00088 switch (field)
00089 {
00090 case M_TITLE:
00091 ID3_retval = ID3_GetTitle(tag);
00092 break;
00093 case M_ARTIST:
00094 ID3_retval = ID3_GetArtist(tag);
00095 break;
00096 case M_ALBUM:
00097 ID3_retval = ID3_GetAlbum(tag);
00098 break;
00099 case M_DATE:
00100 ID3_retval = ID3_GetYear(tag);
00101 value = ID3_retval;
00102 if (string_ok(value))
00103 value = value + "-01-01";
00104 else
00105 return;
00106 break;
00107 case M_GENRE:
00108 genre = ID3_GetGenreNum(tag);
00109 if (ID3_V1GENRE2DESCRIPTION(genre))
00110 value = (char *)(ID3_V1GENRE2DESCRIPTION(genre));
00111
00112 if (!string_ok(value))
00113 {
00114 ID3_retval = ID3_GetGenre(tag);
00115 value = ID3_retval;
00116 }
00117 break;
00118 case M_DESCRIPTION:
00119 ID3_retval = ID3_GetComment(tag);
00120 break;
00121 case M_TRACKNUMBER:
00122 track = ID3_GetTrackNum(tag);
00123 if (track > 0)
00124 {
00125 value = String::from(track);
00126 item->setTrackNumber((int)track);
00127 }
00128 else
00129 return;
00130 break;
00131 case M_AUTHOR:
00132 ID3_retval = ID3_GetFrameContent(tag, ID3FID_COMPOSER);
00133 break;
00134 case M_DIRECTOR:
00135 ID3_retval = ID3_GetFrameContent(tag, ID3FID_CONDUCTOR);
00136 break;
00137
00138
00139
00140 default:
00141 return;
00142 }
00143
00144 if ((field != M_GENRE) && (field != M_DATE) && (field != M_TRACKNUMBER))
00145 value = ID3_retval;
00146
00147 if (ID3_retval)
00148 delete [] ID3_retval;
00149
00150 value = trim_string(value);
00151
00152 if (string_ok(value))
00153 {
00154 item->setMetadata(MT_KEYS[field].upnp, sc->convert(value));
00155
00156 }
00157 }
00158
00159 void Id3Handler::fillMetadata(Ref<CdsItem> item)
00160 {
00161 ID3_Tag tag;
00162 const Mp3_Headerinfo* header;
00163 Ref<Array<StringBase> > aux;
00164 Ref<StringConverter> sc = StringConverter::m2i();
00165
00166
00167 tag.Link(item->getLocation().c_str());
00168
00169 for (int i = 0; i < M_MAX; i++)
00170 addID3Field((metadata_fields_t) i, &tag, item);
00171
00172 Ref<ConfigManager> cm = ConfigManager::getInstance();
00173 aux = cm->getStringArrayOption(CFG_IMPORT_LIBOPTS_ID3_AUXDATA_TAGS_LIST);
00174 if (aux != nil)
00175 {
00176 const char *temp = NULL;
00177
00178 for (int j = 0; j < aux->size(); j++)
00179 {
00180
00181 String desiredFrame(aux->get(j));
00182 if (string_ok(desiredFrame))
00183 {
00184 ID3_Tag::Iterator* frameIter = tag.CreateIterator();
00185 ID3_Frame* id3Frame = NULL;
00186 while (NULL != (id3Frame = frameIter->GetNext()))
00187 {
00188 String frameName(id3Frame->GetTextID());
00189 if (string_ok(frameName) && (frameName == desiredFrame))
00190 {
00191 ID3_Frame::Iterator* fieldIter = id3Frame->CreateIterator();
00192 ID3_Field* id3Field = NULL;
00193 while (NULL != (id3Field = fieldIter->GetNext()))
00194 {
00195 if (id3Field->GetType() == ID3FTY_TEXTSTRING)
00196 {
00197 temp = id3Field->GetRawText();
00198
00199 if (temp != NULL)
00200 {
00201 String value(temp);
00202 if (string_ok(value))
00203 {
00204 value = sc->convert(value);
00205 log_debug("Adding frame: %s with value %s\n", desiredFrame.c_str(), value.c_str());
00206 item->setAuxData(desiredFrame, value);
00207 }
00208 }
00209 }
00210 }
00211 delete fieldIter;
00212 }
00213 }
00214 delete frameIter;
00215 }
00216 }
00217 }
00218
00219
00220 header = tag.GetMp3HeaderInfo();
00221 if (header)
00222 {
00223 int temp;
00224
00225
00226 if ((header->vbr_bitrate) > 0)
00227 {
00228 temp = (header->vbr_bitrate) / 8;
00229 }
00230 else
00231 {
00232 temp = (header->bitrate) / 8;
00233 }
00234
00235 if (temp > 0)
00236 {
00237 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_BITRATE),
00238 String::from(temp));
00239 }
00240
00241 if ((header->time) > 0)
00242 {
00243 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_DURATION),
00244 secondsToHMS(header->time));
00245 }
00246
00247 if ((header->frequency) > 0)
00248 {
00249 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_SAMPLEFREQUENCY),
00250 String::from((int)(header->frequency)));
00251 }
00252
00253 temp = 0;
00254 switch(header->channelmode)
00255 {
00256 case MP3CHANNELMODE_STEREO:
00257 case MP3CHANNELMODE_JOINT_STEREO:
00258 case MP3CHANNELMODE_DUAL_CHANNEL:
00259 temp = 2;
00260 break;
00261 case MP3CHANNELMODE_SINGLE_CHANNEL:
00262 temp = 1;
00263 break;
00264 case MP3CHANNELMODE_FALSE:
00265 break;
00266 }
00267
00268 if (temp > 0)
00269 {
00270 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_NRAUDIOCHANNELS),
00271 String::from(temp));
00272 }
00273 }
00274
00275 #ifdef HAVE_ID3LIB_ALBUMART
00276
00277
00278
00279
00280
00281
00282
00283 if (ID3_HasPicture(&tag))
00284 {
00285 ID3_Frame* frame = NULL;
00286 frame = tag.Find(ID3FID_PICTURE);
00287 if (frame != NULL)
00288 {
00289 ID3_Field* art = frame->GetField(ID3FN_DATA);
00290 if (art != NULL)
00291 {
00292 Ref<StringConverter> sc = StringConverter::m2i();
00293 String art_mimetype = sc->convert(ID3_GetPictureMimeType(&tag));
00294 if (!string_ok(art_mimetype) || (art_mimetype.index('/') == -1))
00295 {
00296 #ifdef HAVE_MAGIC
00297 art_mimetype = ContentManager::getInstance()->getMimeTypeFromBuffer((void *)art->GetRawBinary(), art->Size());
00298 if (!string_ok(art_mimetype))
00299 #endif
00300 art_mimetype = _(MIMETYPE_DEFAULT);
00301 }
00302
00303
00304
00305 if (art_mimetype != _(MIMETYPE_DEFAULT))
00306 {
00307 Ref<CdsResource> resource(new CdsResource(CH_ID3));
00308 resource->addAttribute(MetadataHandler::getResAttrName(R_PROTOCOLINFO), renderProtocolInfo(art_mimetype));
00309 resource->addParameter(_(RESOURCE_CONTENT_TYPE), _(ID3_ALBUM_ART));
00310 item->addResource(resource);
00311 }
00312
00313 }
00314 }
00315 }
00316 #endif
00317 tag.Clear();
00318 }
00319
00320 Ref<IOHandler> Id3Handler::serveContent(Ref<CdsItem> item, int resNum, off_t *data_size)
00321 {
00322 ID3_Tag tag;
00323 if (tag.Link(item->getLocation().c_str()) == 0)
00324 {
00325 throw _Exception(_("Id3Handler: could not open file: ") + item->getLocation());
00326 }
00327
00328 Ref<CdsResource> res = item->getResource(resNum);
00329
00330 String ctype = res->getParameters()->get(_(RESOURCE_CONTENT_TYPE));
00331
00332 if (ctype != ID3_ALBUM_ART)
00333 throw _Exception(_("Id3Handler: got unknown content type: ") + ctype);
00334
00335 if (!ID3_HasPicture(&tag))
00336 throw _Exception(_("Id3Handler: resource has no album art information"));
00337
00338 ID3_Frame* frame = NULL;
00339 frame = tag.Find(ID3FID_PICTURE);
00340
00341 if (frame == NULL)
00342 throw _Exception(_("Id3Handler: could not server album art - empty frame"));
00343
00344 ID3_Field* art = frame->GetField(ID3FN_DATA);
00345 if (art == NULL)
00346 throw _Exception(_("Id3Handler: could not server album art - empty field"));
00347
00348 Ref<IOHandler> h(new MemIOHandler((void *)art->GetRawBinary(), art->Size()));
00349 *data_size = art->Size();
00350 tag.Clear();
00351
00352 return h;
00353 }
00354
00355 #endif // HAVE_ID3LIB