61d996822ea8f227e3e006f426f568392e4fd314
[platform/core/multimedia/libmm-streamrecorder.git] / src / mm_streamrecorder_fileinfo.c
1 /*
2  * libmm-streamrecorder
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 /*=======================================================================================
23 |  INCLUDE FILES                                                                        |
24 =======================================================================================*/
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <sys/vfs.h>                    /* struct statfs */
28
29 #include "mm_streamrecorder_internal.h"
30 #include "mm_streamrecorder_util.h"
31 #include "mm_streamrecorder_fileinfo.h"
32
33 /*-----------------------------------------------------------------------
34 |    GLOBAL VARIABLE DEFINITIONS for internal                           |
35 -----------------------------------------------------------------------*/
36
37 /*-----------------------------------------------------------------------
38 |    LOCAL VARIABLE DEFINITIONS for internal                            |
39 -----------------------------------------------------------------------*/
40
41 /*---------------------------------------------------------------------------
42 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
43 ---------------------------------------------------------------------------*/
44 /* STATIC INTERNAL FUNCTION */
45
46 /*===========================================================================================
47 |                                                                                                                                                                                       |
48 |  FUNCTION DEFINITIONS                                                                                                                                         |
49 ========================================================================================== */
50 /*---------------------------------------------------------------------------
51 |    GLOBAL FUNCTION DEFINITIONS:                                                                                       |
52 ---------------------------------------------------------------------------*/
53
54 gboolean _mmstreamrecorder_find_fourcc(FILE *f, guint32 tag_fourcc, gboolean do_rewind)
55 {
56         guchar buf[8];
57
58         if (do_rewind)
59                 rewind(f);
60
61         while (fread(&buf, sizeof(guchar), 8, f) > 0) {
62                 unsigned long long buf_size = 0;
63                 unsigned int buf_fourcc = MMSTREAMRECORDER_FOURCC(buf[4], buf[5], buf[6], buf[7]);
64
65                 if (tag_fourcc == buf_fourcc) {
66                         _mmstreamrec_dbg_log("find tag : %c%c%c%c", MMSTREAMRECORDER_FOURCC_ARGS(tag_fourcc));
67                         return TRUE;
68                 } else if ((buf_fourcc == MMSTREAMRECORDER_FOURCC('m', 'o', 'o', 'v')) && (tag_fourcc != buf_fourcc)) {
69                         if (_mmstreamrecorder_find_fourcc(f, tag_fourcc, FALSE))
70                                 return TRUE;
71                         else
72                                 continue;
73                 } else {
74                         _mmstreamrec_dbg_log("skip [%c%c%c%c] tag", MMSTREAMRECORDER_FOURCC_ARGS(buf_fourcc));
75
76                         buf_size = (unsigned long long)_mmstreamrecorder_get_container_size(buf);
77                         buf_size = buf_size - 8;        /* include tag */
78
79                         do {
80                                 if (buf_size > _MMSTREAMRECORDER_MAX_INT) {
81                                         _mmstreamrec_dbg_log("seek %d", _MMSTREAMRECORDER_MAX_INT);
82                                         if (fseek(f, _MMSTREAMRECORDER_MAX_INT, SEEK_CUR) != 0) {
83                                                 _mmstreamrec_dbg_err("fseek() fail");
84                                                 return FALSE;
85                                         }
86
87                                         buf_size -= _MMSTREAMRECORDER_MAX_INT;
88                                 } else {
89                                         _mmstreamrec_dbg_log("seek %d", buf_size);
90                                         if (fseek(f, buf_size, SEEK_CUR) != 0) {
91                                                 _mmstreamrec_dbg_err("fseek() fail");
92                                                 return FALSE;
93                                         }
94                                         break;
95                                 }
96                         } while (TRUE);
97                 }
98         }
99
100         _mmstreamrec_dbg_log("cannot find tag : %c%c%c%c", MMSTREAMRECORDER_FOURCC_ARGS(tag_fourcc));
101
102         return FALSE;
103 }
104
105 gboolean _mmstreamrecorder_update_composition_matrix(FILE *f, int orientation)
106 {
107         /* for 0 degree */
108         guint32 a = 0x00010000;
109         guint32 b = 0;
110         guint32 c = 0;
111         guint32 d = 0x00010000;
112
113         switch (orientation) {
114         case MM_STREAMRECORDER_TAG_VIDEO_ORT_90:        /* 90 degree */
115                 a = 0;
116                 b = 0x00010000;
117                 c = 0xffff0000;
118                 d = 0;
119                 break;
120         case MM_STREAMRECORDER_TAG_VIDEO_ORT_180:       /* 180 degree */
121                 a = 0xffff0000;
122                 d = 0xffff0000;
123                 break;
124         case MM_STREAMRECORDER_TAG_VIDEO_ORT_270:       /* 270 degree */
125                 a = 0;
126                 b = 0xffff0000;
127                 c = 0x00010000;
128                 d = 0;
129                 break;
130         case MM_STREAMRECORDER_TAG_VIDEO_ORT_NONE:      /* 0 degree */
131         default:
132                 break;
133         }
134
135         write_to_32(f, a);
136         write_to_32(f, b);
137         write_to_32(f, 0);
138         write_to_32(f, c);
139         write_to_32(f, d);
140         write_to_32(f, 0);
141         write_to_32(f, 0);
142         write_to_32(f, 0);
143         write_to_32(f, 0x40000000);
144
145         _mmstreamrec_dbg_log("orientation : %d, write data 0x%x 0x%x 0x%x 0x%x", orientation, a, b, c, d);
146
147         return TRUE;
148 }
149
150 guint64 _mmstreamrecorder_get_container_size(const guchar *size)
151 {
152         guint64 result = 0;
153         guint64 temp = 0;
154
155         temp = size[0];
156         result = temp << 24;
157         temp = size[1];
158         result = result | (temp << 16);
159         temp = size[2];
160         result = result | (temp << 8);
161         result = result | size[3];
162
163         _mmstreamrec_dbg_log("result : %lld", (unsigned long long)result);
164
165         return result;
166 }
167
168 gboolean _mmstreamrecorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos)
169 {
170         _mmstreamrec_dbg_log("size : %" G_GINT64_FORMAT "", curr_pos - prev_pos);
171         if (fseek(f, prev_pos, SEEK_SET) != 0) {
172                 _mmstreamrec_dbg_err("fseek() fail");
173                 return FALSE;
174         }
175
176         if (!write_to_32(f, curr_pos - prev_pos))
177                 return FALSE;
178
179         if (fseek(f, curr_pos, SEEK_SET) != 0) {
180                 _mmstreamrec_dbg_err("fseek() fail");
181                 return FALSE;
182         }
183
184         return TRUE;
185 }
186
187 gboolean _mmstreamrecorder_write_udta_m4a(FILE *f)
188 {
189         gint64 current_pos, pos;
190
191         _mmstreamrec_dbg_log("");
192
193         if ((pos = ftell(f)) < 0) {
194                 _mmstreamrec_dbg_err("ftell() returns negative value");
195                 return FALSE;
196         }
197
198         if (!write_to_32(f, 0))         /* udta atomic size */
199                 return FALSE;
200
201         if (!write_tag(f, "udta"))      /* user data fourcc */
202                 return FALSE;
203
204         if ((current_pos = ftell(f)) < 0) {
205                 _mmstreamrec_dbg_err("ftell() returns negative value");
206                 return FALSE;
207         }
208
209         if (!_mmstreamrecorder_update_size(f, pos, current_pos))
210                 return FALSE;
211
212         return TRUE;
213 }
214
215 gboolean _mmstreamrecorder_write_udta(FILE *f, _MMStreamRecorderLocationInfo info)
216 {
217         gint64 current_pos, pos;
218
219         _mmstreamrec_dbg_log("");
220
221         if ((pos = ftell(f)) < 0) {
222                 _mmstreamrec_dbg_err("ftell() returns negative value");
223                 return FALSE;
224         }
225
226         if (!write_to_32(f, 0))         /*size */
227                 return FALSE;
228
229         if (!write_tag(f, "udta"))      /* type */
230                 return FALSE;
231
232         if ((current_pos = ftell(f)) < 0) {
233                 _mmstreamrec_dbg_err("ftell() returns negative value");
234                 return FALSE;
235         }
236
237         if (!_mmstreamrecorder_update_size(f, pos, current_pos))
238                 return FALSE;
239
240         return TRUE;
241 }
242
243 /* START TAG HERE */
244 gboolean _mmstreamrecorder_audio_add_metadata_info_m4a(MMHandleType handle)
245 {
246         FILE *f = NULL;
247         guchar buf[4];
248         guint64 udta_size = 0;
249         gint64 current_pos = 0;
250         gint64 moov_pos = 0;
251         gint64 udta_pos = 0;
252         char err_msg[128] = { '\0', };
253
254         _MMStreamRecorderFileInfo *finfo = NULL;
255         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
256         _MMStreamRecorderSubContext *sc = NULL;
257
258         mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
259         sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
260
261         mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
262         mmf_return_val_if_fail(sc->info_file, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
263
264         finfo = sc->info_file;
265
266         f = fopen(finfo->filename, "rb+");
267         if (f == NULL) {
268                 strerror_r(errno, err_msg, 128);
269                 _mmstreamrec_dbg_err("file open failed [%s]", err_msg);
270                 return FALSE;
271         }
272
273         /* find udta container.
274            if, there are udta container, write loci box after that
275            else, make udta container and write loci box. */
276         if (_mmstreamrecorder_find_fourcc(f, MMSTREAMRECORDER_FOURCC('u', 'd', 't', 'a'), TRUE)) {
277                 size_t nread = 0;
278
279                 _mmstreamrec_dbg_log("find udta container");
280
281                 /* read size */
282                 if (fseek(f, -8L, SEEK_CUR) != 0)
283                         goto fail;
284
285                 udta_pos = ftell(f);
286                 if (udta_pos < 0)
287                         goto ftell_fail;
288
289                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
290
291                 _mmstreamrec_dbg_log("recorded file fread %d", nread);
292
293                 udta_size = _mmstreamrecorder_get_container_size(buf);
294
295                 /* goto end of udta and write 'smta' box */
296                 if (fseek(f, (udta_size - 4L), SEEK_CUR) != 0)
297                         goto fail;
298
299                 current_pos = ftell(f);
300                 if (current_pos < 0)
301                         goto ftell_fail;
302
303                 if (!_mmstreamrecorder_update_size(f, udta_pos, current_pos))
304                         goto fail;
305         } else {
306                 _mmstreamrec_dbg_log("No udta container");
307                 if (fseek(f, 0, SEEK_END) != 0)
308                         goto fail;
309
310                 if (!_mmstreamrecorder_write_udta_m4a(f))
311                         goto fail;
312         }
313
314         /* find moov container.
315            update moov container size. */
316         if ((current_pos = ftell(f)) < 0)
317                 goto ftell_fail;
318
319         if (_mmstreamrecorder_find_fourcc(f, MMSTREAMRECORDER_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
320
321                 _mmstreamrec_dbg_log("found moov container");
322                 if (fseek(f, -8L, SEEK_CUR) != 0)
323                         goto fail;
324
325                 moov_pos = ftell(f);
326                 if (moov_pos < 0)
327                         goto ftell_fail;
328
329                 if (!_mmstreamrecorder_update_size(f, moov_pos, current_pos))
330                         goto fail;
331
332         } else {
333                 _mmstreamrec_dbg_err("No 'moov' container");
334                 goto fail;
335         }
336
337         fclose(f);
338         return TRUE;
339
340  fail:
341         fclose(f);
342         return FALSE;
343
344  ftell_fail:
345         _mmstreamrec_dbg_err("ftell() returns negative value.");
346         fclose(f);
347         return FALSE;
348 }
349
350 /* END TAG HERE */