mp4 and generic: produce codec string with "p" prefix for profile.
[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, "mp4");
56 DECL_STR(_container_3gp, "3gp");
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
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     "Leandro Dorileo",
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         /* fix constrained and 1b case for baseline and main */
460         if (profile == 66 || profile == 77) {
461             uint8_t *sps;
462             uint32_t spslen;
463             bool constrained = false;
464             bool level1b = false;
465
466             if (MP4HaveAtom(mp4_fh,
467                             "moov.trak.mdia.minf.stbl.stsd.avc1.avcC") &&
468                 MP4GetBytesProperty(mp4_fh, "moov.trak.mdia.minf.stbl.stsd."
469                                     "avc1.avcC.sequenceEntries."
470                                     "sequenceParameterSetNALUnit",
471                                     &sps, &spslen)) {
472                 /* SPS (Sequence Parameter Set) is:
473                  *  8 bits (1 byte) for profile_idc
474                  *  1 bit for constraint_set0_flag
475                  *  1 bit for constraint_set1_flag <- we use this for constr.
476                  *  1 bit for constraint_set2_flag
477                  *  1 bit for constraint_set3_flag <- we use this for 1b
478                  * based on ffmpeg's (libavcodec/h264_ps.c) and
479                  * x264 (encoder/set.c)
480                  */
481                 if (spslen > 1) {
482                     if ((sps[1] >> 1) & 0x1)
483                         constrained = true;
484                     if (((sps[1] >> 3) & 0x1) && level / 10 == 1)
485                         level1b = true;
486                 }
487                 free(sps);
488
489                 if (constrained) {
490                     if (profile == 66)
491                         memcpy(str_profile, "constrained-baseline",
492                                sizeof("constrained-baseline"));
493                     else
494                         memcpy(str_profile, "constrained-main",
495                                sizeof("constrained-main"));
496                 }
497
498                 if (level1b)
499                     memcpy(str_level, "1b", sizeof("1b"));
500             }
501         }
502
503         ret.len = snprintf(buf, sizeof(buf), "h264-p%s-l%s",
504                            str_profile, str_level);
505         ret.str = buf;
506         goto found;
507     } else if (strcasecmp(data_name, "mp4v") == 0 ||
508              strcasecmp(data_name, "encv") == 0) {
509         uint8_t type = MP4GetTrackEsdsObjectTypeId(mp4_fh, id);
510
511         if (type == MP4_MPEG4_VIDEO_TYPE) {
512             type = MP4GetVideoProfileLevel(mp4_fh, id);
513             ret = _find_type_str(_video_vprofiles, type);
514         } else
515             ret = _find_type_str(_video_types, type);
516         goto found;
517     }
518
519     return nullstr;
520
521 found: /* ugly, but h264 codec is composed in runtime */
522
523     if (!lms_string_size_dup(&tmp, &ret))
524         return nullstr;
525     return tmp;
526 }
527
528 static struct lms_string_size
529 _get_lang(MP4FileHandle mp4_fh, MP4TrackId id)
530 {
531     struct lms_string_size ret;
532     char buf[4];
533
534     if (!MP4GetTrackLanguage(mp4_fh, id, buf))
535         return nullstr;
536
537     if (memcmp(buf, "und", 4) == 0)
538         return nullstr;
539
540     if (!lms_string_size_strndup(&ret, buf, -1))
541         return nullstr;
542
543     return ret;
544 }
545
546 static struct lms_string_size
547 _get_container(MP4FileHandle mp4_fh)
548 {
549     const char *brand;
550
551     if (!MP4GetStringProperty(mp4_fh, "ftyp.majorBrand", &brand))
552         return _container_mp4;
553
554     if (strncasecmp(brand, "3gp", 3) == 0)
555         return _container_3gp;
556
557     /* NOTE: this should be an array, but the C wrapper of mp4v2
558      * doesn't expose a way to give the index number and
559      * ftyp.compatibleBrands is not in counted format (name[idx])
560      */
561     if (!MP4GetStringProperty(mp4_fh, "ftyp.compatibleBrands", &brand))
562         return _container_mp4;
563
564     if (strncasecmp(brand, "3gp", 3) == 0)
565         return _container_3gp;
566
567     return _container_mp4;
568 }
569
570 static int
571 _parse(struct plugin *plugin, struct lms_context *ctxt, const struct lms_file_info *finfo, void *match)
572 {
573     struct mp4_info info = { };
574     struct lms_audio_info audio_info = { };
575     struct lms_video_info video_info = { };
576     int r, stream_type = LMS_STREAM_TYPE_AUDIO;
577     MP4FileHandle mp4_fh;
578     u_int32_t num_tracks, i;
579     const MP4Tags *tags;
580
581     mp4_fh = MP4Read(finfo->path);
582     if (mp4_fh == MP4_INVALID_FILE_HANDLE) {
583         fprintf(stderr, "ERROR: cannot read mp4 file %s\n", finfo->path);
584         return -1;
585     }
586
587     tags = MP4TagsAlloc();
588     if (!tags)
589         return -1;
590
591     if (!MP4TagsFetch(tags, mp4_fh)) {
592         r = -1;
593         goto fail;
594     }
595
596     lms_string_size_strndup(&info.title, tags->name, -1);
597     lms_string_size_strndup(&info.artist, tags->artist, -1);
598
599     /* check if the file contains a video track */
600     num_tracks = MP4GetNumberOfTracks(mp4_fh, MP4_VIDEO_TRACK_TYPE, 0);
601     if (num_tracks > 0)
602         stream_type = LMS_STREAM_TYPE_VIDEO;
603
604     info.length = MP4GetDuration(mp4_fh) /
605         MP4GetTimeScale(mp4_fh) ?: 1;
606
607     if (stream_type == LMS_STREAM_TYPE_AUDIO) {
608         MP4TrackId id;
609
610         lms_string_size_strndup(&info.album, tags->album, -1);
611         lms_string_size_strndup(&info.genre, tags->genre, -1);
612         if (tags->track)
613             info.trackno = tags->track->index;
614
615         id = MP4FindTrackId(mp4_fh, 0, MP4_AUDIO_TRACK_TYPE, 0);
616         audio_info.bitrate = MP4GetTrackBitRate(mp4_fh, id);
617         audio_info.channels = MP4GetTrackAudioChannels(mp4_fh, id);
618         audio_info.sampling_rate = MP4GetTrackTimeScale(mp4_fh, id);
619         audio_info.length = info.length;
620         audio_info.codec = _get_audio_codec(mp4_fh, id);
621     } else {
622         num_tracks = MP4GetNumberOfTracks(mp4_fh, NULL, 0);
623         for (i = 0; i < num_tracks; i++) {
624             MP4TrackId id = MP4FindTrackId(mp4_fh, i, NULL, 0);
625             const char *type = MP4GetTrackType(mp4_fh, id);
626             enum lms_stream_type lmstype;
627             struct lms_stream *s;
628
629             if (strcmp(type, MP4_AUDIO_TRACK_TYPE) == 0)
630                 lmstype = LMS_STREAM_TYPE_AUDIO;
631             else if (strcmp(type, MP4_VIDEO_TRACK_TYPE) == 0)
632                 lmstype = LMS_STREAM_TYPE_VIDEO;
633             else
634                 continue;
635
636             s = calloc(1, sizeof(*s));
637             s->type = lmstype;
638             s->stream_id = id;
639             s->lang = _get_lang(mp4_fh, id);
640
641             if (lmstype == LMS_STREAM_TYPE_AUDIO) {
642                 s->codec = _get_audio_codec(mp4_fh, id);
643                 s->audio.sampling_rate = MP4GetTrackTimeScale(mp4_fh, id);
644                 s->audio.bitrate = MP4GetTrackBitRate(mp4_fh, id);
645                 s->audio.channels = MP4GetTrackAudioChannels(mp4_fh, id);
646             } else if (lmstype == LMS_STREAM_TYPE_VIDEO) {
647                 s->codec = _get_video_codec(mp4_fh, id); /* malloc() */
648                 s->video.bitrate = MP4GetTrackBitRate(mp4_fh, id);
649                 s->video.width = MP4GetTrackVideoWidth(mp4_fh, id);
650                 s->video.height = MP4GetTrackVideoHeight(mp4_fh, id);
651                 s->video.framerate = MP4GetTrackVideoFrameRate(mp4_fh, id);
652                 lms_stream_video_info_aspect_ratio_guess(&s->video);
653             }
654
655             s->next = video_info.streams;
656             video_info.streams = s;
657         }
658         video_info.length = info.length;
659     }
660
661     lms_string_size_strip_and_free(&info.title);
662     lms_string_size_strip_and_free(&info.artist);
663     lms_string_size_strip_and_free(&info.album);
664     lms_string_size_strip_and_free(&info.genre);
665
666     if (!info.title.str)
667         lms_name_from_path(&info.title, finfo->path, finfo->path_len,
668                            finfo->base, _exts[((long) match) - 1].len,
669                            NULL);
670     if (info.title.str)
671         lms_charset_conv(ctxt->cs_conv, &info.title.str, &info.title.len);
672     if (info.artist.str)
673         lms_charset_conv(ctxt->cs_conv, &info.artist.str, &info.artist.len);
674     if (info.album.str)
675         lms_charset_conv(ctxt->cs_conv, &info.album.str, &info.album.len);
676     if (info.genre.str)
677         lms_charset_conv(ctxt->cs_conv, &info.genre.str, &info.genre.len);
678
679     if (stream_type == LMS_STREAM_TYPE_AUDIO) {
680         audio_info.id = finfo->id;
681         audio_info.title = info.title;
682         audio_info.artist = info.artist;
683         audio_info.album = info.album;
684         audio_info.genre = info.genre;
685         audio_info.container = _get_container(mp4_fh);
686         audio_info.trackno = info.trackno;
687
688         r = lms_db_audio_add(plugin->audio_db, &audio_info);
689     } else {
690         video_info.id = finfo->id;
691         video_info.title = info.title;
692         video_info.artist = info.artist;
693         video_info.container = _get_container(mp4_fh);
694
695         r = lms_db_video_add(plugin->video_db, &video_info);
696     }
697
698 fail:
699     MP4TagsFree(tags);
700
701     free(info.title.str);
702     free(info.artist.str);
703     free(info.album.str);
704     free(info.genre.str);
705
706     while (video_info.streams) {
707         struct lms_stream *s = video_info.streams;
708         video_info.streams = s->next;
709         if (s->type == LMS_STREAM_TYPE_VIDEO) {
710             free(s->codec.str); /* ugly, but h264 needs alloc */
711             free(s->video.aspect_ratio.str);
712         }
713         free(s->lang.str);
714         free(s);
715     }
716
717     MP4Close(mp4_fh, 0);
718
719     return r;
720 }
721
722 static int
723 _setup(struct plugin *plugin, struct lms_context *ctxt)
724 {
725     plugin->audio_db = lms_db_audio_new(ctxt->db);
726     if (!plugin->audio_db)
727         return -1;
728     plugin->video_db = lms_db_video_new(ctxt->db);
729     if (!plugin->video_db)
730         return -1;
731
732     return 0;
733 }
734
735 static int
736 _start(struct plugin *plugin, struct lms_context *ctxt)
737 {
738     int r;
739     r = lms_db_audio_start(plugin->audio_db);
740     r |= lms_db_video_start(plugin->video_db);
741     return r;
742 }
743
744 static int
745 _finish(struct plugin *plugin, struct lms_context *ctxt)
746 {
747     if (plugin->audio_db)
748         lms_db_audio_free(plugin->audio_db);
749     if (plugin->video_db)
750         lms_db_video_free(plugin->video_db);
751
752     return 0;
753 }
754
755 static int
756 _close(struct plugin *plugin)
757 {
758     free(plugin);
759     return 0;
760 }
761
762 API struct lms_plugin *
763 lms_plugin_open(void)
764 {
765     struct plugin *plugin;
766
767     plugin = (struct plugin *)malloc(sizeof(*plugin));
768     plugin->plugin.name = _name;
769     plugin->plugin.match = (lms_plugin_match_fn_t)_match;
770     plugin->plugin.parse = (lms_plugin_parse_fn_t)_parse;
771     plugin->plugin.close = (lms_plugin_close_fn_t)_close;
772     plugin->plugin.setup = (lms_plugin_setup_fn_t)_setup;
773     plugin->plugin.start = (lms_plugin_start_fn_t)_start;
774     plugin->plugin.finish = (lms_plugin_finish_fn_t)_finish;
775     plugin->plugin.order = 0;
776
777     return (struct lms_plugin *)plugin;
778 }
779
780 API const struct lms_plugin_info *
781 lms_plugin_info(void)
782 {
783     static struct lms_plugin_info info = {
784         _name,
785         _cats,
786         "MP4 files (MP4, M4A, MOV, QT, 3GP)",
787         PV,
788         _authors,
789         "http://github.com/profusion/lightmediascanner"
790     };
791
792     return &info;
793 }