minor: remove left over "#undef STR_FIELD_FROM_TAG"
[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
32 #include <mp4v2/mp4v2.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <math.h>
36
37 struct mp4_info {
38     struct lms_string_size title;
39     struct lms_string_size artist;
40     struct lms_string_size album;
41     struct lms_string_size genre;
42     uint16_t trackno;
43     uint64_t length;
44 };
45
46 struct plugin {
47     struct lms_plugin plugin;
48     lms_db_audio_t *audio_db;
49     lms_db_video_t *video_db;
50 };
51
52 #define DECL_STR(cname, str)                                            \
53     static const struct lms_string_size cname = LMS_STATIC_STRING_SIZE(str)
54
55 DECL_STR(_container, "mp4");
56
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");
91
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");
103
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");
162
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");
174
175 DECL_STR(_codec_audio_amr, "amr");
176 DECL_STR(_codec_audio_amr_wb, "amr-wb");
177 #undef DECL_STR
178
179 struct type_str {
180     uint8_t type;
181     const struct lms_string_size *str;
182 };
183
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,
194     NULL,
195     NULL,
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,
202     NULL,
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,
215     NULL,
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
223 };
224
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},
237     {}
238 };
239
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},
299     {}
300 };
301
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},
314     {}
315 };
316
317
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")
326 };
327 static const char *_cats[] = {
328     "multimedia",
329     "audio",
330     "video",
331     NULL
332 };
333 static const char *_authors[] = {
334     "Andre Moreira Magalhaes",
335     "Lucas De Marchi",
336     "Gustavo Sverzut Barbieri",
337     NULL
338 };
339
340 static const struct lms_string_size nullstr = { };
341
342 static void *
343 _match(struct plugin *p, const char *path, int len, int base)
344 {
345     long i;
346
347     i = lms_which_extension(path, len, _exts, LMS_ARRAY_SIZE(_exts));
348     if (i < 0)
349       return NULL;
350     else
351       return (void*)(i + 1);
352 }
353
354 static inline struct lms_string_size
355 _find_type_str(const struct type_str *base, uint8_t type)
356 {
357     const struct type_str *itr;
358
359     for (itr = base; itr->str != NULL; itr++) {
360         if (itr->type == type)
361             return *itr->str;
362     }
363
364     return nullstr;
365 }
366
367 static struct lms_string_size
368 _get_audio_codec(MP4FileHandle mp4_fh, MP4TrackId id)
369 {
370     const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
371     uint8_t type;
372
373     if (!data_name)
374         return nullstr;
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)
380         return nullstr;
381
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)
387             return nullstr;
388
389         return *_audio_codecs[type - 1];
390     }
391
392     return _find_type_str(_audio_types, type);
393 }
394
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)
398 {
399     const char *data_name = MP4GetTrackMediaDataName(mp4_fh, id);
400     struct lms_string_size ret = {}, tmp;
401     char buf[256];
402     char ofmt[8] = {};
403
404     if (!data_name)
405         return nullstr;
406
407     if (strcasecmp(data_name, "encv") == 0) {
408         if (!MP4GetTrackMediaDataOriginalFormat(mp4_fh, id, ofmt, sizeof(ofmt)))
409             return nullstr;
410     }
411
412     if (strcasecmp(data_name, "s263") == 0) {
413         ret = _codec_video_h263;
414         goto found;
415     }
416
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];
421
422         if (!MP4GetTrackH264ProfileLevel(mp4_fh, id, &profile, &level)) {
423             return nullstr;
424         }
425
426         switch (profile) {
427         case 66:
428             memcpy(str_profile, "baseline", sizeof("baseline"));
429             break;
430         case 77:
431             memcpy(str_profile, "main", sizeof("main"));
432             break;
433         case 88:
434             memcpy(str_profile, "extended", sizeof("extended"));
435             break;
436         case 100:
437             memcpy(str_profile, "high", sizeof("high"));
438             break;
439         case 110:
440             memcpy(str_profile, "high-10", sizeof("high-10"));
441             break;
442         case 122:
443             memcpy(str_profile, "high-422", sizeof("high-422"));
444             break;
445         case 144:
446             memcpy(str_profile, "high-444", sizeof("high-444"));
447             break;
448         default:
449             snprintf(str_profile, sizeof(str_profile), "unknown-%d", profile);
450         }
451
452         if (level % 10 == 0)
453             snprintf(str_level, sizeof(str_level), "%u", level / 10);
454         else
455             snprintf(str_level, sizeof(str_level), "%u.%u", level / 10,
456                      level % 10);
457
458         ret.len = snprintf(buf, sizeof(buf), "h264-%s-%s",
459                            str_profile, str_level);
460         ret.str = buf;
461         goto found;
462     } else if (strcasecmp(data_name, "mp4v") == 0 ||
463              strcasecmp(data_name, "encv") == 0) {
464         uint8_t type = MP4GetTrackEsdsObjectTypeId(mp4_fh, id);
465
466         if (type == MP4_MPEG4_VIDEO_TYPE) {
467             type = MP4GetVideoProfileLevel(mp4_fh, id);
468             ret = _find_type_str(_video_vprofiles, type);
469         } else
470             ret = _find_type_str(_video_types, type);
471         goto found;
472     }
473
474     return nullstr;
475
476 found: /* ugly, but h264 codec is composed in runtime */
477
478     if (!lms_string_size_dup(&tmp, &ret))
479         return nullstr;
480     return tmp;
481 }
482
483 static struct lms_string_size
484 _get_lang(MP4FileHandle mp4_fh, MP4TrackId id)
485 {
486     struct lms_string_size ret;
487     char buf[4];
488
489     if (!MP4GetTrackLanguage(mp4_fh, id, buf))
490         return nullstr;
491
492     if (memcmp(buf, "und", 4) == 0)
493         return nullstr;
494
495     if (!lms_string_size_strndup(&ret, buf, -1))
496         return nullstr;
497
498     return ret;
499 }
500
501 static int
502 _parse(struct plugin *plugin, struct lms_context *ctxt, const struct lms_file_info *finfo, void *match)
503 {
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;
510     const MP4Tags *tags;
511
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);
515         return -1;
516     }
517
518     tags = MP4TagsAlloc();
519     if (!tags)
520         return -1;
521
522     if (!MP4TagsFetch(tags, mp4_fh)) {
523         r = -1;
524         goto fail;
525     }
526
527     lms_string_size_strndup(&info.title, tags->name, -1);
528     lms_string_size_strndup(&info.artist, tags->artist, -1);
529
530     /* check if the file contains a video track */
531     num_tracks = MP4GetNumberOfTracks(mp4_fh, MP4_VIDEO_TRACK_TYPE, 0);
532     if (num_tracks > 0)
533         stream_type = LMS_STREAM_TYPE_VIDEO;
534
535     info.length = MP4GetDuration(mp4_fh) /
536         MP4GetTimeScale(mp4_fh) ?: 1;
537
538     if (stream_type == LMS_STREAM_TYPE_AUDIO) {
539         MP4TrackId id;
540
541         lms_string_size_strndup(&info.album, tags->album, -1);
542         lms_string_size_strndup(&info.genre, tags->genre, -1);
543         if (tags->track)
544             info.trackno = tags->track->index;
545
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);
552     } else {
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;
559
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;
564             else
565                 continue;
566
567             s = calloc(1, sizeof(*s));
568             s->type = lmstype;
569             s->stream_id = id;
570             s->lang = _get_lang(mp4_fh, id);
571
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);
584             }
585
586             s->next = video_info.streams;
587             video_info.streams = s;
588         }
589         video_info.length = info.length;
590     }
591
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);
596
597     if (!info.title.str)
598         lms_name_from_path(&info.title, finfo->path, finfo->path_len,
599                            finfo->base, _exts[((long) match) - 1].len,
600                            NULL);
601     if (info.title.str)
602         lms_charset_conv(ctxt->cs_conv, &info.title.str, &info.title.len);
603     if (info.artist.str)
604         lms_charset_conv(ctxt->cs_conv, &info.artist.str, &info.artist.len);
605     if (info.album.str)
606         lms_charset_conv(ctxt->cs_conv, &info.album.str, &info.album.len);
607     if (info.genre.str)
608         lms_charset_conv(ctxt->cs_conv, &info.genre.str, &info.genre.len);
609
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);
619     } else {
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);
625     }
626
627 fail:
628     MP4TagsFree(tags);
629
630     free(info.title.str);
631     free(info.artist.str);
632     free(info.album.str);
633     free(info.genre.str);
634
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);
641         }
642         free(s->lang.str);
643         free(s);
644     }
645
646     MP4Close(mp4_fh, 0);
647
648     return r;
649 }
650
651 static int
652 _setup(struct plugin *plugin, struct lms_context *ctxt)
653 {
654     plugin->audio_db = lms_db_audio_new(ctxt->db);
655     if (!plugin->audio_db)
656         return -1;
657     plugin->video_db = lms_db_video_new(ctxt->db);
658     if (!plugin->video_db)
659         return -1;
660
661     return 0;
662 }
663
664 static int
665 _start(struct plugin *plugin, struct lms_context *ctxt)
666 {
667     int r;
668     r = lms_db_audio_start(plugin->audio_db);
669     r |= lms_db_video_start(plugin->video_db);
670     return r;
671 }
672
673 static int
674 _finish(struct plugin *plugin, struct lms_context *ctxt)
675 {
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);
680
681     return 0;
682 }
683
684 static int
685 _close(struct plugin *plugin)
686 {
687     free(plugin);
688     return 0;
689 }
690
691 API struct lms_plugin *
692 lms_plugin_open(void)
693 {
694     struct plugin *plugin;
695
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;
704
705     return (struct lms_plugin *)plugin;
706 }
707
708 API const struct lms_plugin_info *
709 lms_plugin_info(void)
710 {
711     static struct lms_plugin_info info = {
712         _name,
713         _cats,
714         "MP4 files (MP4, M4A, MOV, QT, 3GP)",
715         PV,
716         _authors,
717         "http://lms.garage.maemo.org"
718     };
719
720     return &info;
721 }