2 * Copyright (C) 2008 by INdT
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * @author Andre Moreira Magalhaes <andre.magalhaes@openbossa.org>
27 static const char PV[] = PACKAGE_VERSION; /* mp4.h screws PACKAGE_VERSION */
29 #include <lightmediascanner_plugin.h>
30 #include <lightmediascanner_db.h>
31 #include <shared/util.h>
33 #include <mp4v2/mp4v2.h>
39 struct lms_string_size title;
40 struct lms_string_size artist;
41 struct lms_string_size album;
42 struct lms_string_size genre;
48 struct lms_plugin plugin;
49 lms_db_audio_t *audio_db;
50 lms_db_video_t *video_db;
53 #define DECL_STR(cname, str) \
54 static const struct lms_string_size cname = LMS_STATIC_STRING_SIZE(str)
56 DECL_STR(_container, "mp4");
58 DECL_STR(_codec_audio_mpeg4aac_main, "mpeg4aac-main");
59 DECL_STR(_codec_audio_mpeg4aac_lc, "mpeg4aac-lc");
60 DECL_STR(_codec_audio_mpeg4aac_ssr, "mpeg4aac-ssr");
61 DECL_STR(_codec_audio_mpeg4aac_ltp, "mpeg4aac-ltp");
62 DECL_STR(_codec_audio_mpeg4aac_he, "mpeg4aac-he");
63 DECL_STR(_codec_audio_mpeg4aac_scalable, "mpeg4aac-scalable");
64 DECL_STR(_codec_audio_mpeg4_twinvq, "mpeg4twinvq");
65 DECL_STR(_codec_audio_mpeg4_celp, "mpeg4celp");
66 DECL_STR(_codec_audio_mpeg4_hvxc, "mpeg4hvxc");
67 DECL_STR(_codec_audio_mpeg4_tssi, "mpeg4ttsi");
68 DECL_STR(_codec_audio_mpeg4_main_synthetic,"mpeg4main-synthetic");
69 DECL_STR(_codec_audio_mpeg4_wavetable_syn, "mpeg4wavetable-syn");
70 DECL_STR(_codec_audio_mpeg4_general_midi, "mpeg4general-midi");
71 DECL_STR(_codec_audio_mpeg4_algo_syn_and_audio_fx, "mpeg4algo-syn-and-audio-fx");
72 DECL_STR(_codec_audio_mpeg4_er_aac_lc, "mpeg4er-aac-lc");
73 DECL_STR(_codec_audio_mpeg4_er_aac_ltp, "mpeg4er-aac-ltp");
74 DECL_STR(_codec_audio_mpeg4_er_aac_scalable, "mpeg4er-aac-scalable");
75 DECL_STR(_codec_audio_mpeg4_er_twinvq, "mpeg4er-twinvq");
76 DECL_STR(_codec_audio_mpeg4_er_bsac, "mpeg4er-bsac");
77 DECL_STR(_codec_audio_mpeg4_er_acc_ld, "mpeg4er-acc-ld");
78 DECL_STR(_codec_audio_mpeg4_er_celp, "mpeg4er-celp");
79 DECL_STR(_codec_audio_mpeg4_er_hvxc, "mpeg4er-hvxc");
80 DECL_STR(_codec_audio_mpeg4_er_hiln, "mpeg4er-hiln");
81 DECL_STR(_codec_audio_mpeg4_er_parametric, "mpeg4er-parametric");
82 DECL_STR(_codec_audio_mpeg4_ssc, "mpeg4ssc");
83 DECL_STR(_codec_audio_mpeg4_ps, "mpeg4ps");
84 DECL_STR(_codec_audio_mpeg4_mpeg_surround, "mpeg4mpeg-surround");
85 DECL_STR(_codec_audio_mpeg4_layer1, "mpeg4layer1");
86 DECL_STR(_codec_audio_mpeg4_layer2, "mpeg4layer2");
87 DECL_STR(_codec_audio_mpeg4_layer3, "mpeg4layer3");
88 DECL_STR(_codec_audio_mpeg4_dst, "mpeg4dst");
89 DECL_STR(_codec_audio_mpeg4_audio_lossless, "mpeg4audio-lossless");
90 DECL_STR(_codec_audio_mpeg4_sls, "mpeg4sls");
91 DECL_STR(_codec_audio_mpeg4_sls_non_core, "mpeg4sls-non-core");
93 DECL_STR(_codec_audio_mpeg2aac_main, "mpeg2aac-main");
94 DECL_STR(_codec_audio_mpeg2aac_lc, "mpeg2aac-lc");
95 DECL_STR(_codec_audio_mpeg2aac_ssr, "mpeg2aac-ssr");
96 DECL_STR(_codec_audio_mpeg2audio, "mpeg2audio");
97 DECL_STR(_codec_audio_mpeg1audio, "mpeg1audio");
98 DECL_STR(_codec_audio_pcm16le, "pcm16le");
99 DECL_STR(_codec_audio_vorbis, "vorbis");
100 DECL_STR(_codec_audio_alaw, "alaw");
101 DECL_STR(_codec_audio_ulaw, "ulaw");
102 DECL_STR(_codec_audio_g723, "g723");
103 DECL_STR(_codec_audio_pcm16be, "pcm16be");
105 DECL_STR(_codec_video_mpeg4_simple_l1, "mpeg4-simple-l1");
106 DECL_STR(_codec_video_mpeg4_simple_l2, "mpeg4-simple-l2");
107 DECL_STR(_codec_video_mpeg4_simple_l3, "mpeg4-simple-l3");
108 DECL_STR(_codec_video_mpeg4_simple_l0, "mpeg4-simple-l0");
109 DECL_STR(_codec_video_mpeg4_simple_scalable_l1, "mpeg4-simple-scalable-l1");
110 DECL_STR(_codec_video_mpeg4_simple_scalable_l2, "mpeg4-simple-scalable-l2");
111 DECL_STR(_codec_video_mpeg4_core_l1, "mpeg4-core-l1");
112 DECL_STR(_codec_video_mpeg4_core_l2, "mpeg4-core-l2");
113 DECL_STR(_codec_video_mpeg4_main_l2, "mpeg4-main-l2");
114 DECL_STR(_codec_video_mpeg4_main_l3, "mpeg4-main-l3");
115 DECL_STR(_codec_video_mpeg4_main_l4, "mpeg4-main-l4");
116 DECL_STR(_codec_video_mpeg4_nbit_l2, "mpeg4-nbit-l2");
117 DECL_STR(_codec_video_mpeg4_scalable_texture_l1, "mpeg4-scalable-texture-l1");
118 DECL_STR(_codec_video_mpeg4_simple_face_anim_l1, "mpeg4-simple-face-anim-l1");
119 DECL_STR(_codec_video_mpeg4_simple_face_anim_l2, "mpeg4-simple-face-anim-l2");
120 DECL_STR(_codec_video_mpeg4_simple_fba_l1, "mpeg4-simple-fba-l1");
121 DECL_STR(_codec_video_mpeg4_simple_fba_l2, "mpeg4-simple-fba-l2");
122 DECL_STR(_codec_video_mpeg4_basic_anim_text_l1, "mpeg4-basic-anim-text-l1");
123 DECL_STR(_codec_video_mpeg4_basic_anim_text_l2, "mpeg4-basic-anim-text-l2");
124 DECL_STR(_codec_video_mpeg4_hybrid_l1, "mpeg4-hybrid-l1");
125 DECL_STR(_codec_video_mpeg4_hybrid_l2, "mpeg4-hybrid-l2");
126 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l1, "mpeg4-adv-rt-simple-l1");
127 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l2, "mpeg4-adv-rt-simple-l2");
128 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l3, "mpeg4-adv-rt-simple-l3");
129 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l4, "mpeg4-adv-rt-simple-l4");
130 DECL_STR(_codec_video_mpeg4_core_scalable_l1, "mpeg4-core-scalable-l1");
131 DECL_STR(_codec_video_mpeg4_core_scalable_l2, "mpeg4-core-scalable-l2");
132 DECL_STR(_codec_video_mpeg4_core_scalable_l3, "mpeg4-core-scalable-l3");
133 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l1, "mpeg4-adv-coding-efficiency-l1");
134 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l2, "mpeg4-adv-coding-efficiency-l2");
135 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l3, "mpeg4-adv-coding-efficiency-l3");
136 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l4, "mpeg4-adv-coding-efficiency-l4");
137 DECL_STR(_codec_video_mpeg4_adv_core_l1, "mpeg4-adv-core-l1");
138 DECL_STR(_codec_video_mpeg4_adv_core_l2, "mpeg4-adv-core-l2");
139 DECL_STR(_codec_video_mpeg4_adv_scalable_texture_l1, "mpeg4-adv-scalable-texture-l1");
140 DECL_STR(_codec_video_mpeg4_adv_scalable_texture_l2, "mpeg4-adv-scalable-texture-l2");
141 DECL_STR(_codec_video_mpeg4_adv_scalable_texture_l3, "mpeg4-adv-scalable-texture-l3");
142 DECL_STR(_codec_video_mpeg4_simple_studio_l1, "mpeg4-simple-studio-l1");
143 DECL_STR(_codec_video_mpeg4_simple_studio_l2, "mpeg4-simple-studio-l2");
144 DECL_STR(_codec_video_mpeg4_simple_studio_l3, "mpeg4-simple-studio-l3");
145 DECL_STR(_codec_video_mpeg4_simple_studio_l4, "mpeg4-simple-studio-l4");
146 DECL_STR(_codec_video_mpeg4_core_studio_l1, "mpeg4-core-studio-l1");
147 DECL_STR(_codec_video_mpeg4_core_studio_l2, "mpeg4-core-studio-l2");
148 DECL_STR(_codec_video_mpeg4_core_studio_l3, "mpeg4-core-studio-l3");
149 DECL_STR(_codec_video_mpeg4_core_studio_l4, "mpeg4-core-studio-l4");
150 DECL_STR(_codec_video_mpeg4_adv_simple_l0, "mpeg4-adv-simple-l0");
151 DECL_STR(_codec_video_mpeg4_adv_simple_l1, "mpeg4-adv-simple-l1");
152 DECL_STR(_codec_video_mpeg4_adv_simple_l2, "mpeg4-adv-simple-l2");
153 DECL_STR(_codec_video_mpeg4_adv_simple_l3, "mpeg4-adv-simple-l3");
154 DECL_STR(_codec_video_mpeg4_adv_simple_l4, "mpeg4-adv-simple-l4");
155 DECL_STR(_codec_video_mpeg4_adv_simple_l5, "mpeg4-adv-simple-l5");
156 DECL_STR(_codec_video_mpeg4_adv_simple_l3b, "mpeg4-adv-simple-l3b");
157 DECL_STR(_codec_video_mpeg4_fgs_l0, "mpeg4-fgs-l0");
158 DECL_STR(_codec_video_mpeg4_fgs_l1, "mpeg4-fgs-l1");
159 DECL_STR(_codec_video_mpeg4_fgs_l2, "mpeg4-fgs-l2");
160 DECL_STR(_codec_video_mpeg4_fgs_l3, "mpeg4-fgs-l3");
161 DECL_STR(_codec_video_mpeg4_fgs_l4, "mpeg4-fgs-l4");
162 DECL_STR(_codec_video_mpeg4_fgs_l5, "mpeg4-fgs-l5");
164 DECL_STR(_codec_video_mpeg2_simple, "mpeg2-simple");
165 DECL_STR(_codec_video_mpeg2_main, "mpeg2-main");
166 DECL_STR(_codec_video_mpeg2_snr, "mpeg2-snr");
167 DECL_STR(_codec_video_mpeg2_spatial, "mpeg2-spatial");
168 DECL_STR(_codec_video_mpeg2_high, "mpeg2-high");
169 DECL_STR(_codec_video_mpeg2_422, "mpeg2-422");
170 DECL_STR(_codec_video_mpeg1, "mpeg1");
171 DECL_STR(_codec_video_jpeg, "jpeg");
172 DECL_STR(_codec_video_yuv12, "yuv12");
173 DECL_STR(_codec_video_h263, "h263");
174 DECL_STR(_codec_video_h261, "h261");
176 DECL_STR(_codec_audio_amr, "amr");
177 DECL_STR(_codec_audio_amr_wb, "amr-wb");
182 const struct lms_string_size *str;
185 static const struct lms_string_size *_audio_codecs[] = {
186 &_codec_audio_mpeg4aac_main,
187 &_codec_audio_mpeg4aac_lc,
188 &_codec_audio_mpeg4aac_ssr,
189 &_codec_audio_mpeg4aac_ltp,
190 &_codec_audio_mpeg4aac_he,
191 &_codec_audio_mpeg4aac_scalable,
192 &_codec_audio_mpeg4_twinvq,
193 &_codec_audio_mpeg4_celp,
194 &_codec_audio_mpeg4_hvxc,
197 &_codec_audio_mpeg4_tssi,
198 &_codec_audio_mpeg4_main_synthetic,
199 &_codec_audio_mpeg4_wavetable_syn,
200 &_codec_audio_mpeg4_general_midi,
201 &_codec_audio_mpeg4_algo_syn_and_audio_fx,
202 &_codec_audio_mpeg4_er_aac_lc,
204 &_codec_audio_mpeg4_er_aac_ltp,
205 &_codec_audio_mpeg4_er_aac_scalable,
206 &_codec_audio_mpeg4_er_twinvq,
207 &_codec_audio_mpeg4_er_bsac,
208 &_codec_audio_mpeg4_er_acc_ld,
209 &_codec_audio_mpeg4_er_celp,
210 &_codec_audio_mpeg4_er_hvxc,
211 &_codec_audio_mpeg4_er_hiln,
212 &_codec_audio_mpeg4_er_parametric,
213 &_codec_audio_mpeg4_ssc,
214 &_codec_audio_mpeg4_ps,
215 &_codec_audio_mpeg4_mpeg_surround,
217 &_codec_audio_mpeg4_layer1,
218 &_codec_audio_mpeg4_layer2,
219 &_codec_audio_mpeg4_layer3,
220 &_codec_audio_mpeg4_dst,
221 &_codec_audio_mpeg4_audio_lossless,
222 &_codec_audio_mpeg4_sls,
223 &_codec_audio_mpeg4_sls_non_core
226 static const struct type_str _audio_types[] = {
227 {MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, &_codec_audio_mpeg2aac_main},
228 {MP4_MPEG2_AAC_LC_AUDIO_TYPE, &_codec_audio_mpeg2aac_lc},
229 {MP4_MPEG2_AAC_SSR_AUDIO_TYPE, &_codec_audio_mpeg2aac_ssr},
230 {MP4_MPEG2_AUDIO_TYPE, &_codec_audio_mpeg2audio},
231 {MP4_MPEG1_AUDIO_TYPE, &_codec_audio_mpeg1audio},
232 {MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE, &_codec_audio_pcm16le},
233 {MP4_VORBIS_AUDIO_TYPE, &_codec_audio_vorbis},
234 {MP4_ALAW_AUDIO_TYPE, &_codec_audio_alaw},
235 {MP4_ULAW_AUDIO_TYPE, &_codec_audio_ulaw},
236 {MP4_G723_AUDIO_TYPE, &_codec_audio_g723},
237 {MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE, &_codec_audio_pcm16be},
241 static const struct type_str _video_vprofiles[] = {
242 {MPEG4_SP_L1, &_codec_video_mpeg4_simple_l1},
243 {MPEG4_SP_L2, &_codec_video_mpeg4_simple_l2},
244 {MPEG4_SP_L3, &_codec_video_mpeg4_simple_l3},
245 {MPEG4_SP_L0, &_codec_video_mpeg4_simple_l0},
246 {MPEG4_SSP_L1, &_codec_video_mpeg4_simple_scalable_l1},
247 {MPEG4_SSP_L2, &_codec_video_mpeg4_simple_scalable_l2},
248 {MPEG4_CP_L1, &_codec_video_mpeg4_core_l1},
249 {MPEG4_CP_L2, &_codec_video_mpeg4_core_l2},
250 {MPEG4_MP_L2, &_codec_video_mpeg4_main_l2},
251 {MPEG4_MP_L3, &_codec_video_mpeg4_main_l3},
252 {MPEG4_MP_L4, &_codec_video_mpeg4_main_l4},
253 {MPEG4_NBP_L2, &_codec_video_mpeg4_nbit_l2},
254 {MPEG4_STP_L1, &_codec_video_mpeg4_scalable_texture_l1},
255 {MPEG4_SFAP_L1, &_codec_video_mpeg4_simple_face_anim_l1},
256 {MPEG4_SFAP_L2, &_codec_video_mpeg4_simple_face_anim_l2},
257 {MPEG4_SFBAP_L1, &_codec_video_mpeg4_simple_fba_l1},
258 {MPEG4_SFBAP_L2, &_codec_video_mpeg4_simple_fba_l2},
259 {MPEG4_BATP_L1, &_codec_video_mpeg4_basic_anim_text_l1},
260 {MPEG4_BATP_L2, &_codec_video_mpeg4_basic_anim_text_l2},
261 {MPEG4_HP_L1, &_codec_video_mpeg4_hybrid_l1},
262 {MPEG4_HP_L2, &_codec_video_mpeg4_hybrid_l2},
263 {MPEG4_ARTSP_L1, &_codec_video_mpeg4_adv_rt_simple_l1},
264 {MPEG4_ARTSP_L2, &_codec_video_mpeg4_adv_rt_simple_l2},
265 {MPEG4_ARTSP_L3, &_codec_video_mpeg4_adv_rt_simple_l3},
266 {MPEG4_ARTSP_L4, &_codec_video_mpeg4_adv_rt_simple_l4},
267 {MPEG4_CSP_L1, &_codec_video_mpeg4_core_scalable_l1},
268 {MPEG4_CSP_L2, &_codec_video_mpeg4_core_scalable_l2},
269 {MPEG4_CSP_L3, &_codec_video_mpeg4_core_scalable_l3},
270 {MPEG4_ACEP_L1, &_codec_video_mpeg4_adv_coding_efficiency_l1},
271 {MPEG4_ACEP_L2, &_codec_video_mpeg4_adv_coding_efficiency_l2},
272 {MPEG4_ACEP_L3, &_codec_video_mpeg4_adv_coding_efficiency_l3},
273 {MPEG4_ACEP_L4, &_codec_video_mpeg4_adv_coding_efficiency_l4},
274 {MPEG4_ACP_L1, &_codec_video_mpeg4_adv_core_l1},
275 {MPEG4_ACP_L2, &_codec_video_mpeg4_adv_core_l2},
276 {MPEG4_AST_L1, &_codec_video_mpeg4_adv_scalable_texture_l1},
277 {MPEG4_AST_L2, &_codec_video_mpeg4_adv_scalable_texture_l2},
278 {MPEG4_AST_L3, &_codec_video_mpeg4_adv_scalable_texture_l3},
279 {MPEG4_S_STUDIO_P_L1, &_codec_video_mpeg4_simple_studio_l1},
280 {MPEG4_S_STUDIO_P_L2, &_codec_video_mpeg4_simple_studio_l2},
281 {MPEG4_S_STUDIO_P_L3, &_codec_video_mpeg4_simple_studio_l3},
282 {MPEG4_S_STUDIO_P_L4, &_codec_video_mpeg4_simple_studio_l4},
283 {MPEG4_C_STUDIO_P_L1, &_codec_video_mpeg4_core_studio_l1},
284 {MPEG4_C_STUDIO_P_L2, &_codec_video_mpeg4_core_studio_l2},
285 {MPEG4_C_STUDIO_P_L3, &_codec_video_mpeg4_core_studio_l3},
286 {MPEG4_C_STUDIO_P_L4, &_codec_video_mpeg4_core_studio_l4},
287 {MPEG4_ASP_L0, &_codec_video_mpeg4_adv_simple_l0},
288 {MPEG4_ASP_L1, &_codec_video_mpeg4_adv_simple_l1},
289 {MPEG4_ASP_L2, &_codec_video_mpeg4_adv_simple_l2},
290 {MPEG4_ASP_L3, &_codec_video_mpeg4_adv_simple_l3},
291 {MPEG4_ASP_L4, &_codec_video_mpeg4_adv_simple_l4},
292 {MPEG4_ASP_L5, &_codec_video_mpeg4_adv_simple_l5},
293 {MPEG4_ASP_L3B, &_codec_video_mpeg4_adv_simple_l3b},
294 {MPEG4_FGSP_L0, &_codec_video_mpeg4_fgs_l0},
295 {MPEG4_FGSP_L1, &_codec_video_mpeg4_fgs_l1},
296 {MPEG4_FGSP_L2, &_codec_video_mpeg4_fgs_l2},
297 {MPEG4_FGSP_L3, &_codec_video_mpeg4_fgs_l3},
298 {MPEG4_FGSP_L4, &_codec_video_mpeg4_fgs_l4},
299 {MPEG4_FGSP_L5, &_codec_video_mpeg4_fgs_l5},
303 static const struct type_str _video_types[] = {
304 {MP4_MPEG2_SIMPLE_VIDEO_TYPE, &_codec_video_mpeg2_simple},
305 {MP4_MPEG2_MAIN_VIDEO_TYPE, &_codec_video_mpeg2_main},
306 {MP4_MPEG2_SNR_VIDEO_TYPE, &_codec_video_mpeg2_snr},
307 {MP4_MPEG2_SPATIAL_VIDEO_TYPE, &_codec_video_mpeg2_spatial},
308 {MP4_MPEG2_HIGH_VIDEO_TYPE, &_codec_video_mpeg2_high},
309 {MP4_MPEG2_442_VIDEO_TYPE, &_codec_video_mpeg2_422},
310 {MP4_MPEG1_VIDEO_TYPE, &_codec_video_mpeg1},
311 {MP4_JPEG_VIDEO_TYPE, &_codec_video_jpeg},
312 {MP4_YUV12_VIDEO_TYPE, &_codec_video_yuv12},
313 {MP4_H263_VIDEO_TYPE, &_codec_video_h263},
314 {MP4_H261_VIDEO_TYPE, &_codec_video_h261},
319 static const char _name[] = "mp4";
320 static const struct lms_string_size _exts[] = {
321 LMS_STATIC_STRING_SIZE(".mp4"),
322 LMS_STATIC_STRING_SIZE(".m4a"),
323 LMS_STATIC_STRING_SIZE(".m4v"),
324 LMS_STATIC_STRING_SIZE(".mov"),
325 LMS_STATIC_STRING_SIZE(".qt"),
326 LMS_STATIC_STRING_SIZE(".3gp")
328 static const char *_cats[] = {
334 static const char *_authors[] = {
335 "Andre Moreira Magalhaes",
337 "Gustavo Sverzut Barbieri",
341 static const struct lms_string_size nullstr = { };
344 _match(struct plugin *p, const char *path, int len, int base)
348 i = lms_which_extension(path, len, _exts, LMS_ARRAY_SIZE(_exts));
352 return (void*)(i + 1);
355 static inline struct lms_string_size
356 _find_type_str(const struct type_str *base, uint8_t type)
358 const struct type_str *itr;
360 for (itr = base; itr->str != NULL; itr++) {
361 if (itr->type == type)
368 static struct lms_string_size
369 _get_audio_codec(MP4FileHandle mp4_fh, MP4TrackId id)
371 const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
376 if (strcasecmp(data_name, "samr") == 0)
377 return _codec_audio_amr;
378 if (strcasecmp(data_name, "sawb") == 0)
379 return _codec_audio_amr_wb;
380 if (strcasecmp(data_name, "mp4a") != 0)
383 type = MP4GetTrackEsdsObjectTypeId(mp4_fh, id);
384 if (type == MP4_MPEG4_AUDIO_TYPE) {
385 type = MP4GetTrackAudioMpeg4Type(mp4_fh, id);
386 if (type == 0 || type > LMS_ARRAY_SIZE(_audio_codecs) ||
387 _audio_codecs[type - 1] == NULL)
390 return *_audio_codecs[type - 1];
393 return _find_type_str(_audio_types, type);
396 /* WARNING: returned str is malloc()'ed if not NULL, use free() */
397 static struct lms_string_size
398 _get_video_codec(MP4FileHandle mp4_fh, MP4TrackId id)
400 const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
401 struct lms_string_size ret = {}, tmp;
408 if (strcasecmp(data_name, "encv") == 0) {
409 if (!MP4GetTrackMediaDataOriginalFormat(mp4_fh, id, ofmt, sizeof(ofmt)))
413 if (strcasecmp(data_name, "s263") == 0) {
414 ret = _codec_video_h263;
418 if (strcasecmp(data_name, "avc1") == 0 ||
419 strcasecmp(ofmt, "264b") == 0) {
420 uint8_t profile, level;
421 char str_profile[64], str_level[64];
423 if (!MP4GetTrackH264ProfileLevel(mp4_fh, id, &profile, &level)) {
429 memcpy(str_profile, "baseline", sizeof("baseline"));
432 memcpy(str_profile, "main", sizeof("main"));
435 memcpy(str_profile, "extended", sizeof("extended"));
438 memcpy(str_profile, "high", sizeof("high"));
441 memcpy(str_profile, "high-10", sizeof("high-10"));
444 memcpy(str_profile, "high-422", sizeof("high-422"));
447 memcpy(str_profile, "high-444", sizeof("high-444"));
450 snprintf(str_profile, sizeof(str_profile), "unknown-%d", profile);
454 snprintf(str_level, sizeof(str_level), "%u", level / 10);
456 snprintf(str_level, sizeof(str_level), "%u.%u", level / 10,
459 ret.len = snprintf(buf, sizeof(buf), "h264-%s-%s",
460 str_profile, str_level);
463 } else if (strcasecmp(data_name, "mp4v") == 0 ||
464 strcasecmp(data_name, "encv") == 0) {
465 uint8_t type = MP4GetTrackEsdsObjectTypeId(mp4_fh, id);
467 if (type == MP4_MPEG4_VIDEO_TYPE) {
468 type = MP4GetVideoProfileLevel(mp4_fh, id);
469 ret = _find_type_str(_video_vprofiles, type);
471 ret = _find_type_str(_video_types, type);
477 found: /* ugly, but h264 codec is composed in runtime */
479 if (!lms_string_size_dup(&tmp, &ret))
484 static struct lms_string_size
485 _get_lang(MP4FileHandle mp4_fh, MP4TrackId id)
487 struct lms_string_size ret;
490 if (!MP4GetTrackLanguage(mp4_fh, id, buf))
493 if (memcmp(buf, "und", 4) == 0)
496 if (!lms_string_size_strndup(&ret, buf, -1))
502 static struct lms_string_size
503 _guess_aspect_ratio(const struct lms_stream_video_info *info)
507 struct lms_string_size str;
508 } *itr, known_ratios[] = {
509 {16.0 / 9.0, LMS_STATIC_STRING_SIZE("16:9")},
510 {4.0 / 3.0, LMS_STATIC_STRING_SIZE("4:3")},
511 {3.0 / 2.0, LMS_STATIC_STRING_SIZE("3:2")},
512 {5.0 / 3.0, LMS_STATIC_STRING_SIZE("5:3")},
513 {8.0 / 5.0, LMS_STATIC_STRING_SIZE("8:5")},
514 {1.85, LMS_STATIC_STRING_SIZE("1.85:1")},
515 {1.4142, LMS_STATIC_STRING_SIZE("1.41:1")},
516 {2.39, LMS_STATIC_STRING_SIZE("2.39:1")},
517 {16.18 / 10.0, LMS_STATIC_STRING_SIZE("16.18:10")},
522 if (info->width == 0 || info->height == 0)
525 ratio = (double)info->width / (double)info->height;
526 for (itr = known_ratios; itr->ratio > 0.0; itr++) {
527 if (fabs(ratio - itr->ratio) <= 0.01)
535 _parse(struct plugin *plugin, struct lms_context *ctxt, const struct lms_file_info *finfo, void *match)
537 struct mp4_info info = { };
538 struct lms_audio_info audio_info = { };
539 struct lms_video_info video_info = { };
540 int r, stream_type = LMS_STREAM_TYPE_AUDIO;
541 MP4FileHandle mp4_fh;
542 u_int32_t num_tracks, i;
545 mp4_fh = MP4Read(finfo->path);
546 if (mp4_fh == MP4_INVALID_FILE_HANDLE) {
547 fprintf(stderr, "ERROR: cannot read mp4 file %s\n", finfo->path);
551 tags = MP4TagsAlloc();
555 if (!MP4TagsFetch(tags, mp4_fh)) {
560 lms_string_size_strndup(&info.title, tags->name, -1);
561 lms_string_size_strndup(&info.artist, tags->artist, -1);
563 /* check if the file contains a video track */
564 num_tracks = MP4GetNumberOfTracks(mp4_fh, MP4_VIDEO_TRACK_TYPE, 0);
566 stream_type = LMS_STREAM_TYPE_VIDEO;
568 info.length = MP4GetDuration(mp4_fh) /
569 MP4GetTimeScale(mp4_fh) ?: 1;
571 if (stream_type == LMS_STREAM_TYPE_AUDIO) {
574 lms_string_size_strndup(&info.album, tags->album, -1);
575 lms_string_size_strndup(&info.genre, tags->genre, -1);
577 info.trackno = tags->track->index;
579 id = MP4FindTrackId(mp4_fh, 0, MP4_AUDIO_TRACK_TYPE, 0);
580 audio_info.bitrate = MP4GetTrackBitRate(mp4_fh, id);
581 audio_info.channels = MP4GetTrackAudioChannels(mp4_fh, id);
582 audio_info.sampling_rate = MP4GetTrackTimeScale(mp4_fh, id);
583 audio_info.length = info.length;
584 audio_info.codec = _get_audio_codec(mp4_fh, id);
586 num_tracks = MP4GetNumberOfTracks(mp4_fh, NULL, 0);
587 for (i = 0; i < num_tracks; i++) {
588 MP4TrackId id = MP4FindTrackId(mp4_fh, i, NULL, 0);
589 const char *type = MP4GetTrackType(mp4_fh, id);
590 enum lms_stream_type lmstype;
591 struct lms_stream *s;
593 if (strcmp(type, MP4_AUDIO_TRACK_TYPE) == 0)
594 lmstype = LMS_STREAM_TYPE_AUDIO;
595 else if (strcmp(type, MP4_VIDEO_TRACK_TYPE) == 0)
596 lmstype = LMS_STREAM_TYPE_VIDEO;
600 s = calloc(1, sizeof(*s));
603 s->lang = _get_lang(mp4_fh, id);
605 if (lmstype == LMS_STREAM_TYPE_AUDIO) {
606 s->codec = _get_audio_codec(mp4_fh, id);
607 s->audio.sampling_rate = MP4GetTrackTimeScale(mp4_fh, id);
608 s->audio.bitrate = MP4GetTrackBitRate(mp4_fh, id);
609 s->audio.channels = MP4GetTrackAudioChannels(mp4_fh, id);
610 } else if (lmstype == LMS_STREAM_TYPE_VIDEO) {
611 s->codec = _get_video_codec(mp4_fh, id); /* malloc() */
612 s->video.bitrate = MP4GetTrackBitRate(mp4_fh, id);
613 s->video.width = MP4GetTrackVideoWidth(mp4_fh, id);
614 s->video.height = MP4GetTrackVideoHeight(mp4_fh, id);
615 s->video.framerate = MP4GetTrackVideoFrameRate(mp4_fh, id);
616 s->video.aspect_ratio = _guess_aspect_ratio(&s->video);
619 s->next = video_info.streams;
620 video_info.streams = s;
622 video_info.length = info.length;
624 #undef STR_FIELD_FROM_TAG
626 lms_string_size_strip_and_free(&info.title);
627 lms_string_size_strip_and_free(&info.artist);
628 lms_string_size_strip_and_free(&info.album);
629 lms_string_size_strip_and_free(&info.genre);
632 info.title = str_extract_name_from_path(finfo->path, finfo->path_len,
634 &_exts[((long) match) - 1],
637 lms_charset_conv(ctxt->cs_conv, &info.title.str, &info.title.len);
639 lms_charset_conv(ctxt->cs_conv, &info.artist.str, &info.artist.len);
641 lms_charset_conv(ctxt->cs_conv, &info.album.str, &info.album.len);
643 lms_charset_conv(ctxt->cs_conv, &info.genre.str, &info.genre.len);
645 if (stream_type == LMS_STREAM_TYPE_AUDIO) {
646 audio_info.id = finfo->id;
647 audio_info.title = info.title;
648 audio_info.artist = info.artist;
649 audio_info.album = info.album;
650 audio_info.genre = info.genre;
651 audio_info.container = _container;
652 audio_info.trackno = info.trackno;
653 r = lms_db_audio_add(plugin->audio_db, &audio_info);
655 video_info.id = finfo->id;
656 video_info.title = info.title;
657 video_info.artist = info.artist;
658 video_info.container = _container;
659 r = lms_db_video_add(plugin->video_db, &video_info);
665 free(info.title.str);
666 free(info.artist.str);
667 free(info.album.str);
668 free(info.genre.str);
670 while (video_info.streams) {
671 struct lms_stream *s = video_info.streams;
672 video_info.streams = s->next;
673 if (s->type == LMS_STREAM_TYPE_VIDEO)
674 free(s->codec.str); /* ugly, but h264 needs alloc */
685 _setup(struct plugin *plugin, struct lms_context *ctxt)
687 plugin->audio_db = lms_db_audio_new(ctxt->db);
688 if (!plugin->audio_db)
690 plugin->video_db = lms_db_video_new(ctxt->db);
691 if (!plugin->video_db)
698 _start(struct plugin *plugin, struct lms_context *ctxt)
701 r = lms_db_audio_start(plugin->audio_db);
702 r |= lms_db_video_start(plugin->video_db);
707 _finish(struct plugin *plugin, struct lms_context *ctxt)
709 if (plugin->audio_db)
710 lms_db_audio_free(plugin->audio_db);
711 if (plugin->video_db)
712 lms_db_video_free(plugin->video_db);
718 _close(struct plugin *plugin)
724 API struct lms_plugin *
725 lms_plugin_open(void)
727 struct plugin *plugin;
729 plugin = (struct plugin *)malloc(sizeof(*plugin));
730 plugin->plugin.name = _name;
731 plugin->plugin.match = (lms_plugin_match_fn_t)_match;
732 plugin->plugin.parse = (lms_plugin_parse_fn_t)_parse;
733 plugin->plugin.close = (lms_plugin_close_fn_t)_close;
734 plugin->plugin.setup = (lms_plugin_setup_fn_t)_setup;
735 plugin->plugin.start = (lms_plugin_start_fn_t)_start;
736 plugin->plugin.finish = (lms_plugin_finish_fn_t)_finish;
738 return (struct lms_plugin *)plugin;
741 API const struct lms_plugin_info *
742 lms_plugin_info(void)
744 static struct lms_plugin_info info = {
747 "MP4 files (MP4, M4A, MOV, QT, 3GP)",
750 "http://lms.garage.maemo.org"