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>
32 #include <mp4v2/mp4v2.h>
38 struct lms_string_size title;
39 struct lms_string_size artist;
40 struct lms_string_size album;
41 struct lms_string_size genre;
47 struct lms_plugin plugin;
48 lms_db_audio_t *audio_db;
49 lms_db_video_t *video_db;
52 #define DECL_STR(cname, str) \
53 static const struct lms_string_size cname = LMS_STATIC_STRING_SIZE(str)
55 DECL_STR(_container, "mp4");
57 DECL_STR(_codec_audio_mpeg4aac_main, "mpeg4aac-main");
58 DECL_STR(_codec_audio_mpeg4aac_lc, "mpeg4aac-lc");
59 DECL_STR(_codec_audio_mpeg4aac_ssr, "mpeg4aac-ssr");
60 DECL_STR(_codec_audio_mpeg4aac_ltp, "mpeg4aac-ltp");
61 DECL_STR(_codec_audio_mpeg4aac_he, "mpeg4aac-he");
62 DECL_STR(_codec_audio_mpeg4aac_scalable, "mpeg4aac-scalable");
63 DECL_STR(_codec_audio_mpeg4_twinvq, "mpeg4twinvq");
64 DECL_STR(_codec_audio_mpeg4_celp, "mpeg4celp");
65 DECL_STR(_codec_audio_mpeg4_hvxc, "mpeg4hvxc");
66 DECL_STR(_codec_audio_mpeg4_tssi, "mpeg4ttsi");
67 DECL_STR(_codec_audio_mpeg4_main_synthetic,"mpeg4main-synthetic");
68 DECL_STR(_codec_audio_mpeg4_wavetable_syn, "mpeg4wavetable-syn");
69 DECL_STR(_codec_audio_mpeg4_general_midi, "mpeg4general-midi");
70 DECL_STR(_codec_audio_mpeg4_algo_syn_and_audio_fx, "mpeg4algo-syn-and-audio-fx");
71 DECL_STR(_codec_audio_mpeg4_er_aac_lc, "mpeg4er-aac-lc");
72 DECL_STR(_codec_audio_mpeg4_er_aac_ltp, "mpeg4er-aac-ltp");
73 DECL_STR(_codec_audio_mpeg4_er_aac_scalable, "mpeg4er-aac-scalable");
74 DECL_STR(_codec_audio_mpeg4_er_twinvq, "mpeg4er-twinvq");
75 DECL_STR(_codec_audio_mpeg4_er_bsac, "mpeg4er-bsac");
76 DECL_STR(_codec_audio_mpeg4_er_acc_ld, "mpeg4er-acc-ld");
77 DECL_STR(_codec_audio_mpeg4_er_celp, "mpeg4er-celp");
78 DECL_STR(_codec_audio_mpeg4_er_hvxc, "mpeg4er-hvxc");
79 DECL_STR(_codec_audio_mpeg4_er_hiln, "mpeg4er-hiln");
80 DECL_STR(_codec_audio_mpeg4_er_parametric, "mpeg4er-parametric");
81 DECL_STR(_codec_audio_mpeg4_ssc, "mpeg4ssc");
82 DECL_STR(_codec_audio_mpeg4_ps, "mpeg4ps");
83 DECL_STR(_codec_audio_mpeg4_mpeg_surround, "mpeg4mpeg-surround");
84 DECL_STR(_codec_audio_mpeg4_layer1, "mpeg4layer1");
85 DECL_STR(_codec_audio_mpeg4_layer2, "mpeg4layer2");
86 DECL_STR(_codec_audio_mpeg4_layer3, "mpeg4layer3");
87 DECL_STR(_codec_audio_mpeg4_dst, "mpeg4dst");
88 DECL_STR(_codec_audio_mpeg4_audio_lossless, "mpeg4audio-lossless");
89 DECL_STR(_codec_audio_mpeg4_sls, "mpeg4sls");
90 DECL_STR(_codec_audio_mpeg4_sls_non_core, "mpeg4sls-non-core");
92 DECL_STR(_codec_audio_mpeg2aac_main, "mpeg2aac-main");
93 DECL_STR(_codec_audio_mpeg2aac_lc, "mpeg2aac-lc");
94 DECL_STR(_codec_audio_mpeg2aac_ssr, "mpeg2aac-ssr");
95 DECL_STR(_codec_audio_mpeg2audio, "mpeg2audio");
96 DECL_STR(_codec_audio_mpeg1audio, "mpeg1audio");
97 DECL_STR(_codec_audio_pcm16le, "pcm16le");
98 DECL_STR(_codec_audio_vorbis, "vorbis");
99 DECL_STR(_codec_audio_alaw, "alaw");
100 DECL_STR(_codec_audio_ulaw, "ulaw");
101 DECL_STR(_codec_audio_g723, "g723");
102 DECL_STR(_codec_audio_pcm16be, "pcm16be");
104 DECL_STR(_codec_video_mpeg4_simple_l1, "mpeg4-simple-l1");
105 DECL_STR(_codec_video_mpeg4_simple_l2, "mpeg4-simple-l2");
106 DECL_STR(_codec_video_mpeg4_simple_l3, "mpeg4-simple-l3");
107 DECL_STR(_codec_video_mpeg4_simple_l0, "mpeg4-simple-l0");
108 DECL_STR(_codec_video_mpeg4_simple_scalable_l1, "mpeg4-simple-scalable-l1");
109 DECL_STR(_codec_video_mpeg4_simple_scalable_l2, "mpeg4-simple-scalable-l2");
110 DECL_STR(_codec_video_mpeg4_core_l1, "mpeg4-core-l1");
111 DECL_STR(_codec_video_mpeg4_core_l2, "mpeg4-core-l2");
112 DECL_STR(_codec_video_mpeg4_main_l2, "mpeg4-main-l2");
113 DECL_STR(_codec_video_mpeg4_main_l3, "mpeg4-main-l3");
114 DECL_STR(_codec_video_mpeg4_main_l4, "mpeg4-main-l4");
115 DECL_STR(_codec_video_mpeg4_nbit_l2, "mpeg4-nbit-l2");
116 DECL_STR(_codec_video_mpeg4_scalable_texture_l1, "mpeg4-scalable-texture-l1");
117 DECL_STR(_codec_video_mpeg4_simple_face_anim_l1, "mpeg4-simple-face-anim-l1");
118 DECL_STR(_codec_video_mpeg4_simple_face_anim_l2, "mpeg4-simple-face-anim-l2");
119 DECL_STR(_codec_video_mpeg4_simple_fba_l1, "mpeg4-simple-fba-l1");
120 DECL_STR(_codec_video_mpeg4_simple_fba_l2, "mpeg4-simple-fba-l2");
121 DECL_STR(_codec_video_mpeg4_basic_anim_text_l1, "mpeg4-basic-anim-text-l1");
122 DECL_STR(_codec_video_mpeg4_basic_anim_text_l2, "mpeg4-basic-anim-text-l2");
123 DECL_STR(_codec_video_mpeg4_hybrid_l1, "mpeg4-hybrid-l1");
124 DECL_STR(_codec_video_mpeg4_hybrid_l2, "mpeg4-hybrid-l2");
125 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l1, "mpeg4-adv-rt-simple-l1");
126 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l2, "mpeg4-adv-rt-simple-l2");
127 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l3, "mpeg4-adv-rt-simple-l3");
128 DECL_STR(_codec_video_mpeg4_adv_rt_simple_l4, "mpeg4-adv-rt-simple-l4");
129 DECL_STR(_codec_video_mpeg4_core_scalable_l1, "mpeg4-core-scalable-l1");
130 DECL_STR(_codec_video_mpeg4_core_scalable_l2, "mpeg4-core-scalable-l2");
131 DECL_STR(_codec_video_mpeg4_core_scalable_l3, "mpeg4-core-scalable-l3");
132 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l1, "mpeg4-adv-coding-efficiency-l1");
133 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l2, "mpeg4-adv-coding-efficiency-l2");
134 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l3, "mpeg4-adv-coding-efficiency-l3");
135 DECL_STR(_codec_video_mpeg4_adv_coding_efficiency_l4, "mpeg4-adv-coding-efficiency-l4");
136 DECL_STR(_codec_video_mpeg4_adv_core_l1, "mpeg4-adv-core-l1");
137 DECL_STR(_codec_video_mpeg4_adv_core_l2, "mpeg4-adv-core-l2");
138 DECL_STR(_codec_video_mpeg4_adv_scalable_texture_l1, "mpeg4-adv-scalable-texture-l1");
139 DECL_STR(_codec_video_mpeg4_adv_scalable_texture_l2, "mpeg4-adv-scalable-texture-l2");
140 DECL_STR(_codec_video_mpeg4_adv_scalable_texture_l3, "mpeg4-adv-scalable-texture-l3");
141 DECL_STR(_codec_video_mpeg4_simple_studio_l1, "mpeg4-simple-studio-l1");
142 DECL_STR(_codec_video_mpeg4_simple_studio_l2, "mpeg4-simple-studio-l2");
143 DECL_STR(_codec_video_mpeg4_simple_studio_l3, "mpeg4-simple-studio-l3");
144 DECL_STR(_codec_video_mpeg4_simple_studio_l4, "mpeg4-simple-studio-l4");
145 DECL_STR(_codec_video_mpeg4_core_studio_l1, "mpeg4-core-studio-l1");
146 DECL_STR(_codec_video_mpeg4_core_studio_l2, "mpeg4-core-studio-l2");
147 DECL_STR(_codec_video_mpeg4_core_studio_l3, "mpeg4-core-studio-l3");
148 DECL_STR(_codec_video_mpeg4_core_studio_l4, "mpeg4-core-studio-l4");
149 DECL_STR(_codec_video_mpeg4_adv_simple_l0, "mpeg4-adv-simple-l0");
150 DECL_STR(_codec_video_mpeg4_adv_simple_l1, "mpeg4-adv-simple-l1");
151 DECL_STR(_codec_video_mpeg4_adv_simple_l2, "mpeg4-adv-simple-l2");
152 DECL_STR(_codec_video_mpeg4_adv_simple_l3, "mpeg4-adv-simple-l3");
153 DECL_STR(_codec_video_mpeg4_adv_simple_l4, "mpeg4-adv-simple-l4");
154 DECL_STR(_codec_video_mpeg4_adv_simple_l5, "mpeg4-adv-simple-l5");
155 DECL_STR(_codec_video_mpeg4_adv_simple_l3b, "mpeg4-adv-simple-l3b");
156 DECL_STR(_codec_video_mpeg4_fgs_l0, "mpeg4-fgs-l0");
157 DECL_STR(_codec_video_mpeg4_fgs_l1, "mpeg4-fgs-l1");
158 DECL_STR(_codec_video_mpeg4_fgs_l2, "mpeg4-fgs-l2");
159 DECL_STR(_codec_video_mpeg4_fgs_l3, "mpeg4-fgs-l3");
160 DECL_STR(_codec_video_mpeg4_fgs_l4, "mpeg4-fgs-l4");
161 DECL_STR(_codec_video_mpeg4_fgs_l5, "mpeg4-fgs-l5");
163 DECL_STR(_codec_video_mpeg2_simple, "mpeg2-simple");
164 DECL_STR(_codec_video_mpeg2_main, "mpeg2-main");
165 DECL_STR(_codec_video_mpeg2_snr, "mpeg2-snr");
166 DECL_STR(_codec_video_mpeg2_spatial, "mpeg2-spatial");
167 DECL_STR(_codec_video_mpeg2_high, "mpeg2-high");
168 DECL_STR(_codec_video_mpeg2_422, "mpeg2-422");
169 DECL_STR(_codec_video_mpeg1, "mpeg1");
170 DECL_STR(_codec_video_jpeg, "jpeg");
171 DECL_STR(_codec_video_yuv12, "yuv12");
172 DECL_STR(_codec_video_h263, "h263");
173 DECL_STR(_codec_video_h261, "h261");
175 DECL_STR(_codec_audio_amr, "amr");
176 DECL_STR(_codec_audio_amr_wb, "amr-wb");
181 const struct lms_string_size *str;
184 static const struct lms_string_size *_audio_codecs[] = {
185 &_codec_audio_mpeg4aac_main,
186 &_codec_audio_mpeg4aac_lc,
187 &_codec_audio_mpeg4aac_ssr,
188 &_codec_audio_mpeg4aac_ltp,
189 &_codec_audio_mpeg4aac_he,
190 &_codec_audio_mpeg4aac_scalable,
191 &_codec_audio_mpeg4_twinvq,
192 &_codec_audio_mpeg4_celp,
193 &_codec_audio_mpeg4_hvxc,
196 &_codec_audio_mpeg4_tssi,
197 &_codec_audio_mpeg4_main_synthetic,
198 &_codec_audio_mpeg4_wavetable_syn,
199 &_codec_audio_mpeg4_general_midi,
200 &_codec_audio_mpeg4_algo_syn_and_audio_fx,
201 &_codec_audio_mpeg4_er_aac_lc,
203 &_codec_audio_mpeg4_er_aac_ltp,
204 &_codec_audio_mpeg4_er_aac_scalable,
205 &_codec_audio_mpeg4_er_twinvq,
206 &_codec_audio_mpeg4_er_bsac,
207 &_codec_audio_mpeg4_er_acc_ld,
208 &_codec_audio_mpeg4_er_celp,
209 &_codec_audio_mpeg4_er_hvxc,
210 &_codec_audio_mpeg4_er_hiln,
211 &_codec_audio_mpeg4_er_parametric,
212 &_codec_audio_mpeg4_ssc,
213 &_codec_audio_mpeg4_ps,
214 &_codec_audio_mpeg4_mpeg_surround,
216 &_codec_audio_mpeg4_layer1,
217 &_codec_audio_mpeg4_layer2,
218 &_codec_audio_mpeg4_layer3,
219 &_codec_audio_mpeg4_dst,
220 &_codec_audio_mpeg4_audio_lossless,
221 &_codec_audio_mpeg4_sls,
222 &_codec_audio_mpeg4_sls_non_core
225 static const struct type_str _audio_types[] = {
226 {MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, &_codec_audio_mpeg2aac_main},
227 {MP4_MPEG2_AAC_LC_AUDIO_TYPE, &_codec_audio_mpeg2aac_lc},
228 {MP4_MPEG2_AAC_SSR_AUDIO_TYPE, &_codec_audio_mpeg2aac_ssr},
229 {MP4_MPEG2_AUDIO_TYPE, &_codec_audio_mpeg2audio},
230 {MP4_MPEG1_AUDIO_TYPE, &_codec_audio_mpeg1audio},
231 {MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE, &_codec_audio_pcm16le},
232 {MP4_VORBIS_AUDIO_TYPE, &_codec_audio_vorbis},
233 {MP4_ALAW_AUDIO_TYPE, &_codec_audio_alaw},
234 {MP4_ULAW_AUDIO_TYPE, &_codec_audio_ulaw},
235 {MP4_G723_AUDIO_TYPE, &_codec_audio_g723},
236 {MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE, &_codec_audio_pcm16be},
240 static const struct type_str _video_vprofiles[] = {
241 {MPEG4_SP_L1, &_codec_video_mpeg4_simple_l1},
242 {MPEG4_SP_L2, &_codec_video_mpeg4_simple_l2},
243 {MPEG4_SP_L3, &_codec_video_mpeg4_simple_l3},
244 {MPEG4_SP_L0, &_codec_video_mpeg4_simple_l0},
245 {MPEG4_SSP_L1, &_codec_video_mpeg4_simple_scalable_l1},
246 {MPEG4_SSP_L2, &_codec_video_mpeg4_simple_scalable_l2},
247 {MPEG4_CP_L1, &_codec_video_mpeg4_core_l1},
248 {MPEG4_CP_L2, &_codec_video_mpeg4_core_l2},
249 {MPEG4_MP_L2, &_codec_video_mpeg4_main_l2},
250 {MPEG4_MP_L3, &_codec_video_mpeg4_main_l3},
251 {MPEG4_MP_L4, &_codec_video_mpeg4_main_l4},
252 {MPEG4_NBP_L2, &_codec_video_mpeg4_nbit_l2},
253 {MPEG4_STP_L1, &_codec_video_mpeg4_scalable_texture_l1},
254 {MPEG4_SFAP_L1, &_codec_video_mpeg4_simple_face_anim_l1},
255 {MPEG4_SFAP_L2, &_codec_video_mpeg4_simple_face_anim_l2},
256 {MPEG4_SFBAP_L1, &_codec_video_mpeg4_simple_fba_l1},
257 {MPEG4_SFBAP_L2, &_codec_video_mpeg4_simple_fba_l2},
258 {MPEG4_BATP_L1, &_codec_video_mpeg4_basic_anim_text_l1},
259 {MPEG4_BATP_L2, &_codec_video_mpeg4_basic_anim_text_l2},
260 {MPEG4_HP_L1, &_codec_video_mpeg4_hybrid_l1},
261 {MPEG4_HP_L2, &_codec_video_mpeg4_hybrid_l2},
262 {MPEG4_ARTSP_L1, &_codec_video_mpeg4_adv_rt_simple_l1},
263 {MPEG4_ARTSP_L2, &_codec_video_mpeg4_adv_rt_simple_l2},
264 {MPEG4_ARTSP_L3, &_codec_video_mpeg4_adv_rt_simple_l3},
265 {MPEG4_ARTSP_L4, &_codec_video_mpeg4_adv_rt_simple_l4},
266 {MPEG4_CSP_L1, &_codec_video_mpeg4_core_scalable_l1},
267 {MPEG4_CSP_L2, &_codec_video_mpeg4_core_scalable_l2},
268 {MPEG4_CSP_L3, &_codec_video_mpeg4_core_scalable_l3},
269 {MPEG4_ACEP_L1, &_codec_video_mpeg4_adv_coding_efficiency_l1},
270 {MPEG4_ACEP_L2, &_codec_video_mpeg4_adv_coding_efficiency_l2},
271 {MPEG4_ACEP_L3, &_codec_video_mpeg4_adv_coding_efficiency_l3},
272 {MPEG4_ACEP_L4, &_codec_video_mpeg4_adv_coding_efficiency_l4},
273 {MPEG4_ACP_L1, &_codec_video_mpeg4_adv_core_l1},
274 {MPEG4_ACP_L2, &_codec_video_mpeg4_adv_core_l2},
275 {MPEG4_AST_L1, &_codec_video_mpeg4_adv_scalable_texture_l1},
276 {MPEG4_AST_L2, &_codec_video_mpeg4_adv_scalable_texture_l2},
277 {MPEG4_AST_L3, &_codec_video_mpeg4_adv_scalable_texture_l3},
278 {MPEG4_S_STUDIO_P_L1, &_codec_video_mpeg4_simple_studio_l1},
279 {MPEG4_S_STUDIO_P_L2, &_codec_video_mpeg4_simple_studio_l2},
280 {MPEG4_S_STUDIO_P_L3, &_codec_video_mpeg4_simple_studio_l3},
281 {MPEG4_S_STUDIO_P_L4, &_codec_video_mpeg4_simple_studio_l4},
282 {MPEG4_C_STUDIO_P_L1, &_codec_video_mpeg4_core_studio_l1},
283 {MPEG4_C_STUDIO_P_L2, &_codec_video_mpeg4_core_studio_l2},
284 {MPEG4_C_STUDIO_P_L3, &_codec_video_mpeg4_core_studio_l3},
285 {MPEG4_C_STUDIO_P_L4, &_codec_video_mpeg4_core_studio_l4},
286 {MPEG4_ASP_L0, &_codec_video_mpeg4_adv_simple_l0},
287 {MPEG4_ASP_L1, &_codec_video_mpeg4_adv_simple_l1},
288 {MPEG4_ASP_L2, &_codec_video_mpeg4_adv_simple_l2},
289 {MPEG4_ASP_L3, &_codec_video_mpeg4_adv_simple_l3},
290 {MPEG4_ASP_L4, &_codec_video_mpeg4_adv_simple_l4},
291 {MPEG4_ASP_L5, &_codec_video_mpeg4_adv_simple_l5},
292 {MPEG4_ASP_L3B, &_codec_video_mpeg4_adv_simple_l3b},
293 {MPEG4_FGSP_L0, &_codec_video_mpeg4_fgs_l0},
294 {MPEG4_FGSP_L1, &_codec_video_mpeg4_fgs_l1},
295 {MPEG4_FGSP_L2, &_codec_video_mpeg4_fgs_l2},
296 {MPEG4_FGSP_L3, &_codec_video_mpeg4_fgs_l3},
297 {MPEG4_FGSP_L4, &_codec_video_mpeg4_fgs_l4},
298 {MPEG4_FGSP_L5, &_codec_video_mpeg4_fgs_l5},
302 static const struct type_str _video_types[] = {
303 {MP4_MPEG2_SIMPLE_VIDEO_TYPE, &_codec_video_mpeg2_simple},
304 {MP4_MPEG2_MAIN_VIDEO_TYPE, &_codec_video_mpeg2_main},
305 {MP4_MPEG2_SNR_VIDEO_TYPE, &_codec_video_mpeg2_snr},
306 {MP4_MPEG2_SPATIAL_VIDEO_TYPE, &_codec_video_mpeg2_spatial},
307 {MP4_MPEG2_HIGH_VIDEO_TYPE, &_codec_video_mpeg2_high},
308 {MP4_MPEG2_442_VIDEO_TYPE, &_codec_video_mpeg2_422},
309 {MP4_MPEG1_VIDEO_TYPE, &_codec_video_mpeg1},
310 {MP4_JPEG_VIDEO_TYPE, &_codec_video_jpeg},
311 {MP4_YUV12_VIDEO_TYPE, &_codec_video_yuv12},
312 {MP4_H263_VIDEO_TYPE, &_codec_video_h263},
313 {MP4_H261_VIDEO_TYPE, &_codec_video_h261},
318 static const char _name[] = "mp4";
319 static const struct lms_string_size _exts[] = {
320 LMS_STATIC_STRING_SIZE(".mp4"),
321 LMS_STATIC_STRING_SIZE(".m4a"),
322 LMS_STATIC_STRING_SIZE(".m4v"),
323 LMS_STATIC_STRING_SIZE(".mov"),
324 LMS_STATIC_STRING_SIZE(".qt"),
325 LMS_STATIC_STRING_SIZE(".3gp")
327 static const char *_cats[] = {
333 static const char *_authors[] = {
334 "Andre Moreira Magalhaes",
336 "Gustavo Sverzut Barbieri",
340 static const struct lms_string_size nullstr = { };
343 _match(struct plugin *p, const char *path, int len, int base)
347 i = lms_which_extension(path, len, _exts, LMS_ARRAY_SIZE(_exts));
351 return (void*)(i + 1);
354 static inline struct lms_string_size
355 _find_type_str(const struct type_str *base, uint8_t type)
357 const struct type_str *itr;
359 for (itr = base; itr->str != NULL; itr++) {
360 if (itr->type == type)
367 static struct lms_string_size
368 _get_audio_codec(MP4FileHandle mp4_fh, MP4TrackId id)
370 const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
375 if (strcasecmp(data_name, "samr") == 0)
376 return _codec_audio_amr;
377 if (strcasecmp(data_name, "sawb") == 0)
378 return _codec_audio_amr_wb;
379 if (strcasecmp(data_name, "mp4a") != 0)
382 type = MP4GetTrackEsdsObjectTypeId(mp4_fh, id);
383 if (type == MP4_MPEG4_AUDIO_TYPE) {
384 type = MP4GetTrackAudioMpeg4Type(mp4_fh, id);
385 if (type == 0 || type > LMS_ARRAY_SIZE(_audio_codecs) ||
386 _audio_codecs[type - 1] == NULL)
389 return *_audio_codecs[type - 1];
392 return _find_type_str(_audio_types, type);
395 /* WARNING: returned str is malloc()'ed if not NULL, use free() */
396 static struct lms_string_size
397 _get_video_codec(MP4FileHandle mp4_fh, MP4TrackId id)
399 const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
400 struct lms_string_size ret = {}, tmp;
407 if (strcasecmp(data_name, "encv") == 0) {
408 if (!MP4GetTrackMediaDataOriginalFormat(mp4_fh, id, ofmt, sizeof(ofmt)))
412 if (strcasecmp(data_name, "s263") == 0) {
413 ret = _codec_video_h263;
417 if (strcasecmp(data_name, "avc1") == 0 ||
418 strcasecmp(ofmt, "264b") == 0) {
419 uint8_t profile, level;
420 char str_profile[64], str_level[64];
422 if (!MP4GetTrackH264ProfileLevel(mp4_fh, id, &profile, &level)) {
428 memcpy(str_profile, "baseline", sizeof("baseline"));
431 memcpy(str_profile, "main", sizeof("main"));
434 memcpy(str_profile, "extended", sizeof("extended"));
437 memcpy(str_profile, "high", sizeof("high"));
440 memcpy(str_profile, "high-10", sizeof("high-10"));
443 memcpy(str_profile, "high-422", sizeof("high-422"));
446 memcpy(str_profile, "high-444", sizeof("high-444"));
449 snprintf(str_profile, sizeof(str_profile), "unknown-%d", profile);
453 snprintf(str_level, sizeof(str_level), "%u", level / 10);
455 snprintf(str_level, sizeof(str_level), "%u.%u", level / 10,
458 ret.len = snprintf(buf, sizeof(buf), "h264-%s-%s",
459 str_profile, str_level);
462 } else if (strcasecmp(data_name, "mp4v") == 0 ||
463 strcasecmp(data_name, "encv") == 0) {
464 uint8_t type = MP4GetTrackEsdsObjectTypeId(mp4_fh, id);
466 if (type == MP4_MPEG4_VIDEO_TYPE) {
467 type = MP4GetVideoProfileLevel(mp4_fh, id);
468 ret = _find_type_str(_video_vprofiles, type);
470 ret = _find_type_str(_video_types, type);
476 found: /* ugly, but h264 codec is composed in runtime */
478 if (!lms_string_size_dup(&tmp, &ret))
483 static struct lms_string_size
484 _get_lang(MP4FileHandle mp4_fh, MP4TrackId id)
486 struct lms_string_size ret;
489 if (!MP4GetTrackLanguage(mp4_fh, id, buf))
492 if (memcmp(buf, "und", 4) == 0)
495 if (!lms_string_size_strndup(&ret, buf, -1))
502 _parse(struct plugin *plugin, struct lms_context *ctxt, const struct lms_file_info *finfo, void *match)
504 struct mp4_info info = { };
505 struct lms_audio_info audio_info = { };
506 struct lms_video_info video_info = { };
507 int r, stream_type = LMS_STREAM_TYPE_AUDIO;
508 MP4FileHandle mp4_fh;
509 u_int32_t num_tracks, i;
512 mp4_fh = MP4Read(finfo->path);
513 if (mp4_fh == MP4_INVALID_FILE_HANDLE) {
514 fprintf(stderr, "ERROR: cannot read mp4 file %s\n", finfo->path);
518 tags = MP4TagsAlloc();
522 if (!MP4TagsFetch(tags, mp4_fh)) {
527 lms_string_size_strndup(&info.title, tags->name, -1);
528 lms_string_size_strndup(&info.artist, tags->artist, -1);
530 /* check if the file contains a video track */
531 num_tracks = MP4GetNumberOfTracks(mp4_fh, MP4_VIDEO_TRACK_TYPE, 0);
533 stream_type = LMS_STREAM_TYPE_VIDEO;
535 info.length = MP4GetDuration(mp4_fh) /
536 MP4GetTimeScale(mp4_fh) ?: 1;
538 if (stream_type == LMS_STREAM_TYPE_AUDIO) {
541 lms_string_size_strndup(&info.album, tags->album, -1);
542 lms_string_size_strndup(&info.genre, tags->genre, -1);
544 info.trackno = tags->track->index;
546 id = MP4FindTrackId(mp4_fh, 0, MP4_AUDIO_TRACK_TYPE, 0);
547 audio_info.bitrate = MP4GetTrackBitRate(mp4_fh, id);
548 audio_info.channels = MP4GetTrackAudioChannels(mp4_fh, id);
549 audio_info.sampling_rate = MP4GetTrackTimeScale(mp4_fh, id);
550 audio_info.length = info.length;
551 audio_info.codec = _get_audio_codec(mp4_fh, id);
553 num_tracks = MP4GetNumberOfTracks(mp4_fh, NULL, 0);
554 for (i = 0; i < num_tracks; i++) {
555 MP4TrackId id = MP4FindTrackId(mp4_fh, i, NULL, 0);
556 const char *type = MP4GetTrackType(mp4_fh, id);
557 enum lms_stream_type lmstype;
558 struct lms_stream *s;
560 if (strcmp(type, MP4_AUDIO_TRACK_TYPE) == 0)
561 lmstype = LMS_STREAM_TYPE_AUDIO;
562 else if (strcmp(type, MP4_VIDEO_TRACK_TYPE) == 0)
563 lmstype = LMS_STREAM_TYPE_VIDEO;
567 s = calloc(1, sizeof(*s));
570 s->lang = _get_lang(mp4_fh, id);
572 if (lmstype == LMS_STREAM_TYPE_AUDIO) {
573 s->codec = _get_audio_codec(mp4_fh, id);
574 s->audio.sampling_rate = MP4GetTrackTimeScale(mp4_fh, id);
575 s->audio.bitrate = MP4GetTrackBitRate(mp4_fh, id);
576 s->audio.channels = MP4GetTrackAudioChannels(mp4_fh, id);
577 } else if (lmstype == LMS_STREAM_TYPE_VIDEO) {
578 s->codec = _get_video_codec(mp4_fh, id); /* malloc() */
579 s->video.bitrate = MP4GetTrackBitRate(mp4_fh, id);
580 s->video.width = MP4GetTrackVideoWidth(mp4_fh, id);
581 s->video.height = MP4GetTrackVideoHeight(mp4_fh, id);
582 s->video.framerate = MP4GetTrackVideoFrameRate(mp4_fh, id);
583 lms_stream_video_info_aspect_ratio_guess(&s->video);
586 s->next = video_info.streams;
587 video_info.streams = s;
589 video_info.length = info.length;
592 lms_string_size_strip_and_free(&info.title);
593 lms_string_size_strip_and_free(&info.artist);
594 lms_string_size_strip_and_free(&info.album);
595 lms_string_size_strip_and_free(&info.genre);
598 lms_name_from_path(&info.title, finfo->path, finfo->path_len,
599 finfo->base, _exts[((long) match) - 1].len,
602 lms_charset_conv(ctxt->cs_conv, &info.title.str, &info.title.len);
604 lms_charset_conv(ctxt->cs_conv, &info.artist.str, &info.artist.len);
606 lms_charset_conv(ctxt->cs_conv, &info.album.str, &info.album.len);
608 lms_charset_conv(ctxt->cs_conv, &info.genre.str, &info.genre.len);
610 if (stream_type == LMS_STREAM_TYPE_AUDIO) {
611 audio_info.id = finfo->id;
612 audio_info.title = info.title;
613 audio_info.artist = info.artist;
614 audio_info.album = info.album;
615 audio_info.genre = info.genre;
616 audio_info.container = _container;
617 audio_info.trackno = info.trackno;
618 r = lms_db_audio_add(plugin->audio_db, &audio_info);
620 video_info.id = finfo->id;
621 video_info.title = info.title;
622 video_info.artist = info.artist;
623 video_info.container = _container;
624 r = lms_db_video_add(plugin->video_db, &video_info);
630 free(info.title.str);
631 free(info.artist.str);
632 free(info.album.str);
633 free(info.genre.str);
635 while (video_info.streams) {
636 struct lms_stream *s = video_info.streams;
637 video_info.streams = s->next;
638 if (s->type == LMS_STREAM_TYPE_VIDEO) {
639 free(s->codec.str); /* ugly, but h264 needs alloc */
640 free(s->video.aspect_ratio.str);
652 _setup(struct plugin *plugin, struct lms_context *ctxt)
654 plugin->audio_db = lms_db_audio_new(ctxt->db);
655 if (!plugin->audio_db)
657 plugin->video_db = lms_db_video_new(ctxt->db);
658 if (!plugin->video_db)
665 _start(struct plugin *plugin, struct lms_context *ctxt)
668 r = lms_db_audio_start(plugin->audio_db);
669 r |= lms_db_video_start(plugin->video_db);
674 _finish(struct plugin *plugin, struct lms_context *ctxt)
676 if (plugin->audio_db)
677 lms_db_audio_free(plugin->audio_db);
678 if (plugin->video_db)
679 lms_db_video_free(plugin->video_db);
685 _close(struct plugin *plugin)
691 API struct lms_plugin *
692 lms_plugin_open(void)
694 struct plugin *plugin;
696 plugin = (struct plugin *)malloc(sizeof(*plugin));
697 plugin->plugin.name = _name;
698 plugin->plugin.match = (lms_plugin_match_fn_t)_match;
699 plugin->plugin.parse = (lms_plugin_parse_fn_t)_parse;
700 plugin->plugin.close = (lms_plugin_close_fn_t)_close;
701 plugin->plugin.setup = (lms_plugin_setup_fn_t)_setup;
702 plugin->plugin.start = (lms_plugin_start_fn_t)_start;
703 plugin->plugin.finish = (lms_plugin_finish_fn_t)_finish;
705 return (struct lms_plugin *)plugin;
708 API const struct lms_plugin_info *
709 lms_plugin_info(void)
711 static struct lms_plugin_info info = {
714 "MP4 files (MP4, M4A, MOV, QT, 3GP)",
717 "http://lms.garage.maemo.org"