introduce and use helpers lms_string_size_strndup() and lms_string_size_dup()
[platform/upstream/lightmediascanner.git] / src / plugins / mp4 / mp4.c
1 /**
2  * Copyright (C) 2008 by INdT
3  *
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.
8  *
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.
13  *
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.
17  *
18  * @author Andre Moreira Magalhaes <andre.magalhaes@openbossa.org>
19  */
20
21 /**
22  * @brief
23  *
24  * mp4 file parser.
25  */
26
27 static const char PV[] = PACKAGE_VERSION; /* mp4.h screws PACKAGE_VERSION */
28
29 #include <lightmediascanner_plugin.h>
30 #include <lightmediascanner_db.h>
31 #include <shared/util.h>
32
33 #include <mp4v2/mp4v2.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <math.h>
37
38 struct mp4_info {
39     struct lms_string_size title;
40     struct lms_string_size artist;
41     struct lms_string_size album;
42     struct lms_string_size genre;
43     uint16_t trackno;
44     uint64_t length;
45 };
46
47 struct plugin {
48     struct lms_plugin plugin;
49     lms_db_audio_t *audio_db;
50     lms_db_video_t *video_db;
51 };
52
53 #define DECL_STR(cname, str)                                            \
54     static const struct lms_string_size cname = LMS_STATIC_STRING_SIZE(str)
55
56 DECL_STR(_container, "mp4");
57
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");
92
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");
104
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");
163
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");
175
176 DECL_STR(_codec_audio_amr, "amr");
177 DECL_STR(_codec_audio_amr_wb, "amr-wb");
178 #undef DECL_STR
179
180 struct type_str {
181     uint8_t type;
182     const struct lms_string_size *str;
183 };
184
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,
195     NULL,
196     NULL,
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,
203     NULL,
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,
216     NULL,
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
224 };
225
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},
238     {}
239 };
240
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},
300     {}
301 };
302
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},
315     {}
316 };
317
318
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")
327 };
328 static const char *_cats[] = {
329     "multimedia",
330     "audio",
331     "video",
332     NULL
333 };
334 static const char *_authors[] = {
335     "Andre Moreira Magalhaes",
336     "Lucas De Marchi",
337     "Gustavo Sverzut Barbieri",
338     NULL
339 };
340
341 static const struct lms_string_size nullstr = { };
342
343 static void *
344 _match(struct plugin *p, const char *path, int len, int base)
345 {
346     long i;
347
348     i = lms_which_extension(path, len, _exts, LMS_ARRAY_SIZE(_exts));
349     if (i < 0)
350       return NULL;
351     else
352       return (void*)(i + 1);
353 }
354
355 static inline struct lms_string_size
356 _find_type_str(const struct type_str *base, uint8_t type)
357 {
358     const struct type_str *itr;
359
360     for (itr = base; itr->str != NULL; itr++) {
361         if (itr->type == type)
362             return *itr->str;
363     }
364
365     return nullstr;
366 }
367
368 static struct lms_string_size
369 _get_audio_codec(MP4FileHandle mp4_fh, MP4TrackId id)
370 {
371     const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
372     uint8_t type;
373
374     if (!data_name)
375         return nullstr;
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)
381         return nullstr;
382
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)
388             return nullstr;
389
390         return *_audio_codecs[type - 1];
391     }
392
393     return _find_type_str(_audio_types, type);
394 }
395
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)
399 {
400     const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
401     struct lms_string_size ret = {}, tmp;
402     char buf[256];
403     char ofmt[8] = {};
404
405     if (!data_name)
406         return nullstr;
407
408     if (strcasecmp(data_name, "encv") == 0) {
409         if (!MP4GetTrackMediaDataOriginalFormat(mp4_fh, id, ofmt, sizeof(ofmt)))
410             return nullstr;
411     }
412
413     if (strcasecmp(data_name, "s263") == 0) {
414         ret = _codec_video_h263;
415         goto found;
416     }
417
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];
422
423         if (!MP4GetTrackH264ProfileLevel(mp4_fh, id, &profile, &level)) {
424             return nullstr;
425         }
426
427         switch (profile) {
428         case 66:
429             memcpy(str_profile, "baseline", sizeof("baseline"));
430             break;
431         case 77:
432             memcpy(str_profile, "main", sizeof("main"));
433             break;
434         case 88:
435             memcpy(str_profile, "extended", sizeof("extended"));
436             break;
437         case 100:
438             memcpy(str_profile, "high", sizeof("high"));
439             break;
440         case 110:
441             memcpy(str_profile, "high-10", sizeof("high-10"));
442             break;
443         case 122:
444             memcpy(str_profile, "high-422", sizeof("high-422"));
445             break;
446         case 144:
447             memcpy(str_profile, "high-444", sizeof("high-444"));
448             break;
449         default:
450             snprintf(str_profile, sizeof(str_profile), "unknown-%d", profile);
451         }
452
453         if (level % 10 == 0)
454             snprintf(str_level, sizeof(str_level), "%u", level / 10);
455         else
456             snprintf(str_level, sizeof(str_level), "%u.%u", level / 10,
457                      level % 10);
458
459         ret.len = snprintf(buf, sizeof(buf), "h264-%s-%s",
460                            str_profile, str_level);
461         ret.str = buf;
462         goto found;
463     } else if (strcasecmp(data_name, "mp4v") == 0 ||
464              strcasecmp(data_name, "encv") == 0) {
465         uint8_t type = MP4GetTrackEsdsObjectTypeId(mp4_fh, id);
466
467         if (type == MP4_MPEG4_VIDEO_TYPE) {
468             type = MP4GetVideoProfileLevel(mp4_fh, id);
469             ret = _find_type_str(_video_vprofiles, type);
470         } else
471             ret = _find_type_str(_video_types, type);
472         goto found;
473     }
474
475     return nullstr;
476
477 found: /* ugly, but h264 codec is composed in runtime */
478
479     if (!lms_string_size_dup(&tmp, &ret))
480         return nullstr;
481     return tmp;
482 }
483
484 static struct lms_string_size
485 _get_lang(MP4FileHandle mp4_fh, MP4TrackId id)
486 {
487     struct lms_string_size ret;
488     char buf[4];
489
490     if (!MP4GetTrackLanguage(mp4_fh, id, buf))
491         return nullstr;
492
493     if (memcmp(buf, "und", 4) == 0)
494         return nullstr;
495
496     if (!lms_string_size_strndup(&ret, buf, -1))
497         return nullstr;
498
499     return ret;
500 }
501
502 static struct lms_string_size
503 _guess_aspect_ratio(const struct lms_stream_video_info *info)
504 {
505     static struct {
506         double ratio;
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")},
518         {-1.0, {NULL, 0}}
519     };
520     double ratio;
521
522     if (info->width == 0 || info->height == 0)
523         return nullstr;
524
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)
528             return itr->str;
529     }
530
531     return nullstr;
532 }
533
534 static int
535 _parse(struct plugin *plugin, struct lms_context *ctxt, const struct lms_file_info *finfo, void *match)
536 {
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;
543     const MP4Tags *tags;
544
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);
548         return -1;
549     }
550
551     tags = MP4TagsAlloc();
552     if (!tags)
553         return -1;
554
555     if (!MP4TagsFetch(tags, mp4_fh)) {
556         r = -1;
557         goto fail;
558     }
559
560     lms_string_size_strndup(&info.title, tags->name, -1);
561     lms_string_size_strndup(&info.artist, tags->artist, -1);
562
563     /* check if the file contains a video track */
564     num_tracks = MP4GetNumberOfTracks(mp4_fh, MP4_VIDEO_TRACK_TYPE, 0);
565     if (num_tracks > 0)
566         stream_type = LMS_STREAM_TYPE_VIDEO;
567
568     info.length = MP4GetDuration(mp4_fh) /
569         MP4GetTimeScale(mp4_fh) ?: 1;
570
571     if (stream_type == LMS_STREAM_TYPE_AUDIO) {
572         MP4TrackId id;
573
574         lms_string_size_strndup(&info.album, tags->album, -1);
575         lms_string_size_strndup(&info.genre, tags->genre, -1);
576         if (tags->track)
577             info.trackno = tags->track->index;
578
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);
585     } else {
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;
592
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;
597             else
598                 continue;
599
600             s = calloc(1, sizeof(*s));
601             s->type = lmstype;
602             s->stream_id = id;
603             s->lang = _get_lang(mp4_fh, id);
604
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);
617             }
618
619             s->next = video_info.streams;
620             video_info.streams = s;
621         }
622         video_info.length = info.length;
623     }
624 #undef STR_FIELD_FROM_TAG
625
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);
630
631     if (!info.title.str)
632         info.title = str_extract_name_from_path(finfo->path, finfo->path_len,
633                                                 finfo->base,
634                                                 &_exts[((long) match) - 1],
635                                                 NULL);
636     if (info.title.str)
637         lms_charset_conv(ctxt->cs_conv, &info.title.str, &info.title.len);
638     if (info.artist.str)
639         lms_charset_conv(ctxt->cs_conv, &info.artist.str, &info.artist.len);
640     if (info.album.str)
641         lms_charset_conv(ctxt->cs_conv, &info.album.str, &info.album.len);
642     if (info.genre.str)
643         lms_charset_conv(ctxt->cs_conv, &info.genre.str, &info.genre.len);
644
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);
654     } else {
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);
660     }
661
662 fail:
663     MP4TagsFree(tags);
664
665     free(info.title.str);
666     free(info.artist.str);
667     free(info.album.str);
668     free(info.genre.str);
669
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 */
675         free(s->lang.str);
676         free(s);
677     }
678
679     MP4Close(mp4_fh, 0);
680
681     return r;
682 }
683
684 static int
685 _setup(struct plugin *plugin, struct lms_context *ctxt)
686 {
687     plugin->audio_db = lms_db_audio_new(ctxt->db);
688     if (!plugin->audio_db)
689         return -1;
690     plugin->video_db = lms_db_video_new(ctxt->db);
691     if (!plugin->video_db)
692         return -1;
693
694     return 0;
695 }
696
697 static int
698 _start(struct plugin *plugin, struct lms_context *ctxt)
699 {
700     int r;
701     r = lms_db_audio_start(plugin->audio_db);
702     r |= lms_db_video_start(plugin->video_db);
703     return r;
704 }
705
706 static int
707 _finish(struct plugin *plugin, struct lms_context *ctxt)
708 {
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);
713
714     return 0;
715 }
716
717 static int
718 _close(struct plugin *plugin)
719 {
720     free(plugin);
721     return 0;
722 }
723
724 API struct lms_plugin *
725 lms_plugin_open(void)
726 {
727     struct plugin *plugin;
728
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;
737
738     return (struct lms_plugin *)plugin;
739 }
740
741 API const struct lms_plugin_info *
742 lms_plugin_info(void)
743 {
744     static struct lms_plugin_info info = {
745         _name,
746         _cats,
747         "MP4 files (MP4, M4A, MOV, QT, 3GP)",
748         PV,
749         _authors,
750         "http://lms.garage.maemo.org"
751     };
752
753     return &info;
754 }