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_LIBMP4V2
00038
00039 #include "libmp4v2_handler.h"
00040 #include "string_converter.h"
00041 #include "common.h"
00042 #include "tools.h"
00043 #include "mem_io_handler.h"
00044 #include "content_manager.h"
00045 #include "config_manager.h"
00046
00047
00048 #undef PACKAGE
00049 #undef PACKAGE_BUGREPORT
00050 #undef PACKAGE_NAME
00051 #undef PACKAGE_STRING
00052 #undef PACKAGE_TARNAME
00053 #undef VERSION
00054 #undef TRUE
00055 #undef FALSE
00056
00057 #include LIBMP4V2_INCLUDE
00058
00059 using namespace zmm;
00060
00061 LibMP4V2Handler::LibMP4V2Handler() : MetadataHandler()
00062 {
00063 }
00064
00065 static void addMetaField(metadata_fields_t field, MP4FileHandle mp4, Ref<CdsItem> item)
00066 {
00067 String value;
00068 char* mp4_retval = NULL;
00069 u_int16_t track;
00070 u_int16_t total_tracks;
00071
00072 Ref<StringConverter> sc = StringConverter::i2i();
00073
00074 switch (field)
00075 {
00076 case M_TITLE:
00077 MP4GetMetadataName(mp4, &mp4_retval);
00078 break;
00079 case M_ARTIST:
00080 MP4GetMetadataArtist(mp4, &mp4_retval);
00081 break;
00082 case M_ALBUM:
00083 MP4GetMetadataAlbum(mp4, &mp4_retval);
00084 break;
00085 case M_DATE:
00086 MP4GetMetadataYear(mp4, &mp4_retval);
00087 if (mp4_retval)
00088 {
00089 value = mp4_retval;
00090 free(mp4_retval);
00091 if (string_ok(value))
00092 value = value + "-01-01";
00093 else
00094 return;
00095 }
00096 break;
00097 case M_GENRE:
00098 MP4GetMetadataGenre(mp4, &mp4_retval);
00099 break;
00100 case M_DESCRIPTION:
00101 MP4GetMetadataComment(mp4, &mp4_retval);
00102 break;
00103 case M_TRACKNUMBER:
00104 MP4GetMetadataTrack(mp4, &track, &total_tracks);
00105 if (track > 0)
00106 {
00107 value = String::from(track);
00108 item->setTrackNumber((int)track);
00109 }
00110 else
00111 return;
00112 break;
00113 default:
00114 return;
00115 }
00116
00117 if ((field != M_DATE) && (field != M_TRACKNUMBER) &&
00118 (mp4_retval))
00119 {
00120 value = mp4_retval;
00121 free(mp4_retval);
00122 }
00123
00124 value = trim_string(value);
00125
00126 if (string_ok(value))
00127 {
00128 item->setMetadata(MT_KEYS[field].upnp, sc->convert(value));
00129 log_debug("mp4 handler: setting metadata on item: %d, %s\n", field, sc->convert(value).c_str());
00130 }
00131 }
00132
00133 void LibMP4V2Handler::fillMetadata(Ref<CdsItem> item)
00134 {
00135 MP4FileHandle mp4;
00136
00137
00138 mp4 = MP4Read(item->getLocation().c_str());
00139 if (mp4 == MP4_INVALID_FILE_HANDLE)
00140 {
00141 log_error("Skipping metadata extraction for file %s\n",
00142 item->getLocation().c_str());
00143 return;
00144 }
00145
00146 try
00147 {
00148 for (int i = 0; i < M_MAX; i++)
00149 addMetaField((metadata_fields_t) i, mp4, item);
00150
00151 Ref<ConfigManager> cm = ConfigManager::getInstance();
00152
00153
00154
00155
00156 u_int32_t timescale = MP4GetTimeScale(mp4);
00157
00158
00159
00160
00161 MP4Duration duration = MP4GetDuration(mp4);
00162
00163 duration = duration / timescale;
00164 if (duration > 0)
00165 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_DURATION),
00166 secondsToHMS(duration));
00167
00168
00169 MP4TrackId tid = MP4FindTrackId(mp4, 0, MP4_AUDIO_TRACK_TYPE);
00170 if (tid != MP4_INVALID_TRACK_ID)
00171 {
00172 #ifdef HAVE_MP4_GET_TRACK_AUDIO_CHANNELS
00173 int temp = MP4GetTrackAudioChannels(mp4, tid);
00174 if (temp > 0)
00175 {
00176 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_NRAUDIOCHANNELS), String::from(temp));
00177
00178 timescale = MP4GetTrackTimeScale(mp4, tid);
00179 if (timescale > 0)
00180 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_SAMPLEFREQUENCY), String::from((unsigned int)timescale));
00181 }
00182 #endif
00183
00184 timescale = MP4GetTrackBitRate(mp4, tid);
00185 if (timescale > 0)
00186 {
00187 timescale = timescale / 8;
00188 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_BITRATE), String::from(timescale));
00189 }
00190 }
00191
00192 #if defined(HAVE_MAGIC)
00193 u_int8_t *art_data;
00194 u_int32_t art_data_len;
00195 String art_mimetype;
00196 #ifdef HAVE_MP4_GET_METADATA_COVER_ART_COUNT
00197 if (MP4GetMetadataCoverArtCount(mp4) &&
00198 MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len))
00199 #else
00200 MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len);
00201 #endif
00202 {
00203 if (art_data)
00204 {
00205 try
00206 {
00207 art_mimetype = ContentManager::getInstance()->getMimeTypeFromBuffer((void *)art_data, art_data_len);
00208 if (!string_ok(art_mimetype))
00209 art_mimetype = _(MIMETYPE_DEFAULT);
00210
00211 }
00212 catch (Exception ex)
00213 {
00214 free(art_data);
00215 throw ex;
00216 }
00217
00218 free(art_data);
00219 if (art_mimetype != _(MIMETYPE_DEFAULT))
00220 {
00221 Ref<CdsResource> resource(new CdsResource(CH_MP4));
00222 resource->addAttribute(MetadataHandler::getResAttrName(R_PROTOCOLINFO), renderProtocolInfo(art_mimetype));
00223 resource->addParameter(_(RESOURCE_CONTENT_TYPE), _(ID3_ALBUM_ART));
00224 item->addResource(resource);
00225 }
00226 }
00227 }
00228 #endif
00229 MP4Close(mp4);
00230 }
00231 catch (Exception ex)
00232 {
00233 MP4Close(mp4);
00234 throw ex;
00235 }
00236 }
00237
00238 Ref<IOHandler> LibMP4V2Handler::serveContent(Ref<CdsItem> item, int resNum, off_t *data_size)
00239 {
00240 MP4FileHandle mp4 = MP4Read(item->getLocation().c_str());
00241 if (mp4 == MP4_INVALID_FILE_HANDLE)
00242 {
00243 throw _Exception(_("LibMP4V2Handler: could not open file: ") + item->getLocation());
00244 }
00245
00246 Ref<CdsResource> res = item->getResource(resNum);
00247
00248 String ctype = res->getParameters()->get(_(RESOURCE_CONTENT_TYPE));
00249
00250 if (ctype != ID3_ALBUM_ART)
00251 throw _Exception(_("LibMP4V2Handler: got unknown content type: ") + ctype);
00252 #ifdef HAVE_MP4_GET_METADATA_COVER_ART_COUNT
00253 if (!MP4GetMetadataCoverArtCount(mp4))
00254 throw _Exception(_("LibMP4V2Handler: resource has no album art information"));
00255 #endif
00256 u_int8_t *art_data;
00257 u_int32_t art_data_len;
00258 if (MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len))
00259 {
00260 if (art_data)
00261 {
00262 *data_size = (off_t)art_data_len;
00263 Ref<IOHandler> h(new MemIOHandler((void *)art_data, art_data_len));
00264 free(art_data);
00265 return h;
00266 }
00267 }
00268
00269 throw _Exception(_("LibMP4V2Handler: could not serve album art "
00270 "for file") + item->getLocation() +
00271 " - embedded image not found");
00272 }
00273
00274 #endif // HAVE_LIBMP4V2