a8916e2f7b6e3be3c173514b5080e16faea29fba
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_util.c
1 /*
2  * libmm-camcorder
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jeongmo Yang <jm80.yang@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/stat.h>
28 #include <camsrcjpegenc.h>
29 #include <sys/vfs.h> /* struct statfs */
30 #include <gst/video/video-info.h>
31
32 #include "mm_camcorder_internal.h"
33 #include "mm_camcorder_util.h"
34 #include <mm_util_imgp.h>
35
36 /*-----------------------------------------------------------------------
37 |    GLOBAL VARIABLE DEFINITIONS for internal                           |
38 -----------------------------------------------------------------------*/
39
40 /*-----------------------------------------------------------------------
41 |    LOCAL VARIABLE DEFINITIONS for internal                            |
42 -----------------------------------------------------------------------*/
43 #define TIME_STRING_MAX_LEN     64
44
45 #define FPUTC_CHECK(x_char, x_file)\
46 {\
47         if (fputc(x_char, x_file) == EOF) \
48         {\
49                 _mmcam_dbg_err("[Critical] fputc() returns fail.\n");   \
50                 return FALSE;\
51         }\
52 }
53 #define FPUTS_CHECK(x_str, x_file)\
54 {\
55         if (fputs(x_str, x_file) == EOF) \
56         {\
57                 _mmcam_dbg_err("[Critical] fputs() returns fail.\n");\
58                 SAFE_FREE(str); \
59                 return FALSE;\
60         }\
61 }
62
63 /*---------------------------------------------------------------------------
64 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
65 ---------------------------------------------------------------------------*/
66 /* STATIC INTERNAL FUNCTION */
67         
68 //static gint           skip_mdat(FILE *f);
69 static guint16           get_language_code(const char *str);
70 static gchar*            str_to_utf8(const gchar *str);
71 static inline gboolean   write_tag(FILE *f, const gchar *tag);
72 static inline gboolean   write_to_32(FILE *f, guint val);
73 static inline gboolean   write_to_16(FILE *f, guint val);
74 static inline gboolean   write_to_24(FILE *f, guint val);
75
76 /*===========================================================================================
77 |                                                                                                                                                                                       |
78 |  FUNCTION DEFINITIONS                                                                                                                                         |
79 |                                                                                                                                                                                       |
80 ========================================================================================== */
81 /*---------------------------------------------------------------------------
82 |    GLOBAL FUNCTION DEFINITIONS:                                                                                       |
83 ---------------------------------------------------------------------------*/
84
85 gint32 _mmcamcorder_double_to_fix(gdouble d_number)
86 {
87         return (gint32) (d_number * 65536.0);
88 }
89
90 // find top level tag only, do not use this function for finding sub level tags
91 gint _mmcamcorder_find_tag(FILE *f, guint32 tag_fourcc, gboolean do_rewind)
92 {
93         guchar buf[8];
94
95         if (do_rewind) {
96                 rewind(f);
97         }
98
99         while (fread(&buf, sizeof(guchar), 8, f)>0) {
100                 unsigned long long buf_size = 0;
101                 unsigned int buf_fourcc = MMCAM_FOURCC(buf[4], buf[5], buf[6], buf[7]);
102
103                 if (tag_fourcc == buf_fourcc) {
104                         _mmcam_dbg_log("find tag : %c%c%c%c", MMCAM_FOURCC_ARGS(tag_fourcc));
105                         return TRUE;
106                 } else {
107                         _mmcam_dbg_log("skip [%c%c%c%c] tag", MMCAM_FOURCC_ARGS(buf_fourcc));
108
109                         buf_size = (unsigned long long)_mmcamcorder_get_container_size(buf);
110                         buf_size = buf_size - 8; /* include tag */
111
112                         do {
113                                 if (buf_size > _MMCAMCORDER_MAX_INT) {
114                                         _mmcam_dbg_log("seek %d", _MMCAMCORDER_MAX_INT);
115                                         if (fseek(f, _MMCAMCORDER_MAX_INT, SEEK_CUR) != 0) {
116                                                 _mmcam_dbg_err("fseek() fail");
117                                                 return FALSE;
118                                         }
119
120                                         buf_size -= _MMCAMCORDER_MAX_INT;
121                                 } else {
122                                         _mmcam_dbg_log("seek %d", buf_size);
123                                         if (fseek(f, buf_size, SEEK_CUR) != 0) {
124                                                 _mmcam_dbg_err("fseek() fail");
125                                                 return FALSE;
126                                         }
127                                         break;
128                                 }
129                         } while (TRUE);
130                 }
131         }
132
133         _mmcam_dbg_log("cannot find tag : %c%c%c%c", MMCAM_FOURCC_ARGS(tag_fourcc));
134
135         return FALSE;
136 }
137
138 gboolean _mmcamcorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos)
139 {
140         _mmcam_dbg_log("size : %"G_GINT64_FORMAT"", curr_pos-prev_pos);
141         if(fseek(f, prev_pos, SEEK_SET) != 0)
142         {
143                 _mmcam_dbg_err("fseek() fail");
144                 return FALSE;
145         }
146
147         if (!write_to_32(f, curr_pos -prev_pos))
148                 return FALSE;
149         
150         if(fseek(f, curr_pos, SEEK_SET) != 0)
151         {
152                 _mmcam_dbg_err("fseek() fail");
153                 return FALSE;
154         }
155         
156         return TRUE;
157 }
158
159 gboolean _mmcamcorder_write_loci(FILE *f, _MMCamcorderLocationInfo info)
160 {
161         gint64 current_pos, pos;
162         gchar *str = NULL;
163
164         _mmcam_dbg_log("");
165
166         if((pos = ftell(f))<0)
167         {
168                 _mmcam_dbg_err("ftell() returns negative value");       
169                 return FALSE;
170         }
171         
172         if(!write_to_32(f, 0)) //size
173                 return FALSE;
174         
175         if(!write_tag(f, "loci"))       // type
176                 return FALSE;
177         
178         FPUTC_CHECK(0, f);              // version
179
180         if(!write_to_24(f, 0))  // flags
181                 return FALSE;
182         
183         if(!write_to_16(f, get_language_code("eng"))) // language
184                 return FALSE;
185         
186         str = str_to_utf8("location_name");
187         
188         FPUTS_CHECK(str, f); // name
189         SAFE_FREE(str);
190         
191         FPUTC_CHECK('\0', f);
192         FPUTC_CHECK(0, f);              //role
193         
194         if(!write_to_32(f, info.longitude))     // Longitude
195                 return FALSE;
196         
197         if(!write_to_32(f, info.latitude)) // Latitude
198                 return FALSE;
199         
200         if(! write_to_32(f, info.altitude))     // Altitude
201                 return FALSE;
202         
203         str = str_to_utf8("Astronomical_body");
204         FPUTS_CHECK(str, f);//Astronomical_body
205         SAFE_FREE(str);
206         
207         FPUTC_CHECK('\0', f);
208         
209         str = str_to_utf8("Additional_notes");
210         FPUTS_CHECK(str, f); // Additional_notes
211         SAFE_FREE(str);
212         
213         FPUTC_CHECK('\0', f);
214         
215         if((current_pos = ftell(f))<0)
216         {
217                 _mmcam_dbg_err("ftell() returns negative value");       
218                 return FALSE;
219         }
220         
221         if(! _mmcamcorder_update_size(f, pos, current_pos))
222                 return FALSE;
223
224         return TRUE;
225 }
226
227 gboolean _mmcamcorder_write_udta(FILE *f, _MMCamcorderLocationInfo info)
228 {
229         gint64 current_pos, pos;
230
231         _mmcam_dbg_log("");
232  
233         if((pos = ftell(f))<0)
234         {
235                 _mmcam_dbg_err("ftell() returns negative value");       
236                 return FALSE;
237         }
238         
239         if(!write_to_32(f, 0))  //size 
240                 return FALSE;
241         
242         if(!write_tag(f, "udta"))       // type 
243                 return FALSE;
244         
245         if(! _mmcamcorder_write_loci(f, info))
246                 return FALSE;
247         
248         if((current_pos = ftell(f))<0)
249         {
250                 _mmcam_dbg_err("ftell() returns negative value");
251                 return FALSE;
252         }
253  
254         if(! _mmcamcorder_update_size(f, pos, current_pos))
255                 return FALSE;
256  
257
258         return TRUE;
259 }
260
261
262 guint64 _mmcamcorder_get_container_size(const guchar *size)
263 {
264         guint64 result = 0;
265         guint64 temp = 0;
266
267         temp = size[0];
268         result = temp << 24;
269         temp = size[1];
270         result = result | (temp << 16);
271         temp = size[2];
272         result = result | (temp << 8);
273         result = result | size[3];
274
275         _mmcam_dbg_log("result : %lld", (unsigned long long)result);
276
277         return result;
278 }
279
280
281 gboolean _mmcamcorder_update_composition_matrix(FILE *f, int orientation)
282 {
283         /* for 0 degree */
284         guint32 a = 0x00010000;
285         guint32 b = 0;
286         guint32 c = 0;
287         guint32 d = 0x00010000;
288
289         switch (orientation) {
290         case MM_CAMCORDER_TAG_VIDEO_ORT_90:/* 90 degree */
291                 a = 0;
292                 b = 0x00010000;
293                 c = 0xffff0000;
294                 d = 0;
295                 break;
296         case MM_CAMCORDER_TAG_VIDEO_ORT_180:/* 180 degree */
297                 a = 0xffff0000;
298                 d = 0xffff0000;
299                 break;
300         case MM_CAMCORDER_TAG_VIDEO_ORT_270:/* 270 degree */
301                 a = 0;
302                 b = 0xffff0000;
303                 c = 0x00010000;
304                 d = 0;
305                 break;
306         case MM_CAMCORDER_TAG_VIDEO_ORT_NONE:/* 0 degree */
307         default:
308                 break;
309         }
310
311         write_to_32(f, a);
312         write_to_32(f, b);
313         write_to_32(f, 0);
314         write_to_32(f, c);
315         write_to_32(f, d);
316         write_to_32(f, 0);
317         write_to_32(f, 0);
318         write_to_32(f, 0);
319         write_to_32(f, 0x40000000);
320
321         _mmcam_dbg_log("orientation : %d, write data 0x%x 0x%x 0x%x 0x%x",
322                        orientation, a, b, c, d);
323
324         return TRUE;
325 }
326
327
328 int _mmcamcorder_get_freespace(const gchar *path, guint64 *free_space)
329 {
330         struct statfs fs;
331
332         g_assert(path);
333
334         if (!g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
335                 _mmcam_dbg_log("File(%s) doesn't exist.", path);
336                 return -2;
337         }
338
339         if (-1 == statfs(path, &fs)) {
340                 _mmcam_dbg_log("Getting free space is failed.(%s)", path);
341                 return -1;
342         }
343
344         *free_space = (guint64)fs.f_bsize * fs.f_bavail;
345         return 1;
346 }
347
348
349 int _mmcamcorder_get_file_size(const char *filename, guint64 *size)
350 {
351         struct stat buf;
352
353         if (stat(filename, &buf) != 0)
354                 return -1;
355         *size = (guint64)buf.st_size;
356         return 1;
357 }
358
359
360 void _mmcamcorder_remove_buffer_probe(MMHandleType handle, _MMCamcorderHandlerCategory category)
361 {
362         mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle);
363         GList *list = NULL;
364         MMCamcorderHandlerItem *item = NULL;
365
366         mmf_return_if_fail(hcamcorder);
367
368         if(!hcamcorder->buffer_probes)
369         {
370                 _mmcam_dbg_err("Fail to remove buffer probe, list for buffer probe is NULL");
371         }
372
373         list = hcamcorder->buffer_probes;
374
375         while(list)
376         {       
377                 item = list->data;
378
379                 if(!item)
380                 {
381                         _mmcam_dbg_err("Remove buffer probe faild, the item is NULL");
382                         list =  g_list_next(list);
383                         continue;                       
384                 }
385
386                 if(item->category & category)
387                 {
388                 
389                         if(item->object && GST_IS_PAD(item->object))
390                         {
391                                 _mmcam_dbg_log("Remove buffer probe on [%s:%s] - [ID : %lu], [Category : %x]", 
392                                                 GST_DEBUG_PAD_NAME(item->object), item->handler_id,  item->category);
393                 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
394                         }
395                         else
396                         {
397                                 _mmcam_dbg_warn("Remove buffer probe faild, the pad is null or not pad, just remove item from list and free it");
398                         }                       
399                         
400                         list =  g_list_next(list);
401                         hcamcorder->buffer_probes = g_list_remove(hcamcorder->buffer_probes, item);
402                         SAFE_FREE(item);
403                 }
404                 else
405                 {
406                         _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
407                         list =  g_list_next(list);
408                 }
409         }
410
411         if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL)
412         {
413                 g_list_free(hcamcorder->buffer_probes);
414                 hcamcorder->buffer_probes = NULL;
415         }
416 }
417
418 void _mmcamcorder_remove_event_probe(MMHandleType handle, _MMCamcorderHandlerCategory category)
419 {
420         mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle);
421         GList *list = NULL;
422         MMCamcorderHandlerItem *item = NULL;
423
424         mmf_return_if_fail(hcamcorder);
425
426         if(!hcamcorder->event_probes)
427         {
428                 _mmcam_dbg_err("Fail to remove event probe, list for event probe is NULL");
429         }
430
431         list = hcamcorder->event_probes;
432
433         while(list)
434         {       
435                 item = list->data;
436
437                 if(!item)
438                 {
439                         _mmcam_dbg_err("Remove event probe faild, the item is NULL");
440                         list =  g_list_next(list);
441                         continue;                       
442                 }
443
444                 if(item->category & category)
445                 {
446                 
447                         if(item->object && GST_IS_PAD(item->object))
448                         {
449                                 _mmcam_dbg_log("Remove event probe on [%s:%s] - [ID : %lu], [Category : %x]", 
450                                                 GST_DEBUG_PAD_NAME(item->object), item->handler_id,  item->category);
451                 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
452                         }
453                         else
454                         {
455                                 _mmcam_dbg_warn("Remove event probe faild, the pad is null or not pad, just remove item from list and free it");
456                         }                       
457                         
458                         list =  g_list_next(list);
459                         hcamcorder->event_probes = g_list_remove(hcamcorder->event_probes, item);
460                         SAFE_FREE(item);
461                 }
462                 else
463                 {
464                         _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
465                         list =  g_list_next(list);
466                 }
467         }
468
469         if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL)
470         {
471                 g_list_free(hcamcorder->event_probes);
472                 hcamcorder->event_probes = NULL;
473         }       
474 }
475
476 void _mmcamcorder_remove_data_probe(MMHandleType handle, _MMCamcorderHandlerCategory category)
477 {
478         mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle);
479         GList *list = NULL;
480         MMCamcorderHandlerItem *item = NULL;
481
482         mmf_return_if_fail(hcamcorder);
483
484         if(!hcamcorder->data_probes)
485         {
486                 _mmcam_dbg_err("Fail to remove data probe, list for data probe is NULL");
487         }
488
489         list = hcamcorder->data_probes;
490
491         while(list)
492         {       
493                 item = list->data;
494
495                 if(!item)
496                 {
497                         _mmcam_dbg_err("Remove data probe faild, the item is NULL");
498                         list =  g_list_next(list);
499                         continue;                       
500                 }
501
502                 if(item->category & category)
503                 {
504                 
505                         if(item->object && GST_IS_PAD(item->object))
506                         {
507                                 _mmcam_dbg_log("Remove data probe on [%s:%s] - [ID : %lu], [Category : %x]", 
508                                                 GST_DEBUG_PAD_NAME(item->object), item->handler_id,  item->category);
509                 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
510                         }
511                         else
512                         {
513                                 _mmcam_dbg_warn("Remove data probe faild, the pad is null or not pad, just remove item from list and free it");
514                         }                       
515                         
516                         list =  g_list_next(list);
517                         hcamcorder->data_probes = g_list_remove(hcamcorder->data_probes, item);
518                         SAFE_FREE(item);
519                 }
520                 else
521                 {
522                         _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
523                         list =  g_list_next(list);
524                 }
525         }
526
527         if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL)
528         {
529                 g_list_free(hcamcorder->data_probes);
530                 hcamcorder->data_probes = NULL;
531         }               
532 }
533
534 void _mmcamcorder_disconnect_signal(MMHandleType handle, _MMCamcorderHandlerCategory category)
535 {
536         mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle);
537         GList *list = NULL;
538         MMCamcorderHandlerItem *item = NULL;
539
540         mmf_return_if_fail(hcamcorder);
541
542         if(!hcamcorder->signals)
543         {
544                 _mmcam_dbg_err("Fail to disconnect signals, list for signal is NULL");
545         }
546
547         list = hcamcorder->signals;
548
549         while(list)
550         {       
551                 item = list->data;
552
553                 if(!item)
554                 {
555                         _mmcam_dbg_err("Fail to Disconnecting signal, the item is NULL");
556                         list =  g_list_next(list);
557                         continue;                       
558                 }
559
560                 if(item->category & category)
561                 {
562                 
563                         if(item->object && GST_IS_ELEMENT(item->object))
564                         {
565                                 if ( g_signal_handler_is_connected ( item->object, item->handler_id ) )
566                                 {
567                                         _mmcam_dbg_log("Disconnect signal from [%s] : [ID : %lu], [Category : %x]", 
568                                                                         GST_OBJECT_NAME(item->object), item->handler_id,  item->category);                      
569                                         g_signal_handler_disconnect ( item->object, item->handler_id );
570                                 }
571                                 else
572                                 {
573                                         _mmcam_dbg_warn("Signal was not connected, cannot disconnect it :  [%s]  [ID : %lu], [Category : %x]", 
574                                                                                 GST_OBJECT_NAME(item->object), item->handler_id,  item->category);
575                                 }
576
577                         }
578                         else
579                         {
580                                 _mmcam_dbg_err("Fail to Disconnecting signal, the element is null or not element, just remove item from list and free it");
581                         }                       
582                         
583                         list =  g_list_next(list);
584                         hcamcorder->signals = g_list_remove(hcamcorder->signals, item);
585                         SAFE_FREE(item);
586                 }
587                 else
588                 {
589                         _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
590                         list =  g_list_next(list);
591                 }
592         }
593
594         if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL)
595         {
596                 g_list_free(hcamcorder->signals);
597                 hcamcorder->signals = NULL;
598         }               
599 }
600
601 void _mmcamcorder_remove_all_handlers(MMHandleType handle,  _MMCamcorderHandlerCategory category)
602 {
603         mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle);
604
605         _mmcam_dbg_log("ENTER");        
606
607         if(hcamcorder->signals)
608                 _mmcamcorder_disconnect_signal((MMHandleType)hcamcorder, category);
609         if(hcamcorder->data_probes)
610                 _mmcamcorder_remove_data_probe((MMHandleType)hcamcorder, category);
611         if(hcamcorder->event_probes)
612                 _mmcamcorder_remove_event_probe((MMHandleType)hcamcorder, category);    
613         if(hcamcorder->buffer_probes)
614                 _mmcamcorder_remove_buffer_probe((MMHandleType)hcamcorder, category);
615
616         _mmcam_dbg_log("LEAVE");
617 }
618
619
620 void _mmcamcorder_element_release_noti(gpointer data, GObject *where_the_object_was)
621 {
622         int i=0;
623         _MMCamcorderSubContext *sc = (_MMCamcorderSubContext *)data;    
624         mmf_return_if_fail(sc);
625         mmf_return_if_fail(sc->element);
626
627         for (i = 0 ; i < _MMCamcorder_PIPELINE_ELEMENT_NUM ; i++) {
628                 if (sc->element[i].gst && (G_OBJECT(sc->element[i].gst) == where_the_object_was)) {
629                         _mmcam_dbg_log("The element[%d][%p] is finalized", sc->element[i].id, sc->element[i].gst);
630                         sc->element[i].gst = NULL;
631                         sc->element[i].id = _MMCAMCORDER_NONE;
632                         break;
633                 }
634         }
635 }
636
637
638 gboolean
639 _mmcamcroder_msg_callback(void *data)
640 {
641         _MMCamcorderMsgItem *item = (_MMCamcorderMsgItem*)data;
642         mmf_camcorder_t *hcamcorder = NULL;
643         mmf_return_val_if_fail(item, FALSE);
644
645         hcamcorder = MMF_CAMCORDER(item->handle);
646         mmf_return_val_if_fail(hcamcorder, FALSE);
647
648         /*_mmcam_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hcamcorder->msg_cb, hcamcorder->msg_data, item);*/
649
650         _MMCAMCORDER_LOCK_MESSAGE_CALLBACK(hcamcorder);
651
652         /* check delay of CAPTURED message */
653         if (item->id == MM_MESSAGE_CAMCORDER_CAPTURED) {
654                 MMTA_ACUM_ITEM_END("                CAPTURED MESSAGE DELAY", FALSE);
655         }
656
657         if ((hcamcorder) && (hcamcorder->msg_cb)) {
658                 hcamcorder->msg_cb(item->id, (MMMessageParamType*)(&(item->param)), hcamcorder->msg_cb_param);
659         }
660
661         _MMCAMCORDER_UNLOCK_MESSAGE_CALLBACK(hcamcorder);
662
663         _MMCAMCORDER_LOCK((MMHandleType)hcamcorder);
664
665         if (hcamcorder->msg_data) {
666                 hcamcorder->msg_data = g_list_remove(hcamcorder->msg_data, item);
667         }
668
669         /* release allocated memory */
670         if (item->id == MM_MESSAGE_CAMCORDER_FACE_DETECT_INFO) {
671                 MMCamFaceDetectInfo *cam_fd_info = (MMCamFaceDetectInfo *)item->param.data;
672                 if (cam_fd_info) {
673                         SAFE_FREE(cam_fd_info->face_info);
674                         free(cam_fd_info);
675                         cam_fd_info = NULL;
676                 }
677
678                 item->param.data = NULL;
679                 item->param.size = 0;
680         }
681
682         free(item);
683         item = NULL;
684
685         _MMCAMCORDER_UNLOCK((MMHandleType)hcamcorder);
686
687         /* For not being called again */
688         return FALSE;
689 }
690
691
692 gboolean
693 _mmcamcroder_send_message(MMHandleType handle, _MMCamcorderMsgItem *data)
694 {
695         mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle);
696         _MMCamcorderMsgItem *item = NULL;
697
698         mmf_return_val_if_fail(hcamcorder, FALSE);
699         mmf_return_val_if_fail(data, FALSE);
700
701         switch (data->id)
702         {
703                 case MM_MESSAGE_CAMCORDER_STATE_CHANGED:
704                 case MM_MESSAGE_CAMCORDER_STATE_CHANGED_BY_ASM:
705                         data->param.union_type = MM_MSG_UNION_STATE;
706                         break;
707                 case MM_MESSAGE_CAMCORDER_RECORDING_STATUS:
708                         data->param.union_type = MM_MSG_UNION_RECORDING_STATUS;
709                         break;
710                 case MM_MESSAGE_CAMCORDER_FIRMWARE_UPDATE:
711                         data->param.union_type = MM_MSG_UNION_FIRMWARE;
712                         break;
713                 case MM_MESSAGE_CAMCORDER_CURRENT_VOLUME:
714                         data->param.union_type = MM_MSG_UNION_REC_VOLUME_DB;
715                         break;
716                 case MM_MESSAGE_CAMCORDER_TIME_LIMIT:
717                 case MM_MESSAGE_CAMCORDER_MAX_SIZE:
718                 case MM_MESSAGE_CAMCORDER_NO_FREE_SPACE:
719                 case MM_MESSAGE_CAMCORDER_ERROR:
720                 case MM_MESSAGE_CAMCORDER_FOCUS_CHANGED:
721                 case MM_MESSAGE_CAMCORDER_CAPTURED:
722                 case MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED:
723                 case MM_MESSAGE_CAMCORDER_AUDIO_CAPTURED:
724                 case MM_MESSAGE_READY_TO_RESUME:
725                 default:
726                         data->param.union_type = MM_MSG_UNION_CODE;
727                         break;
728         }
729
730         item = g_malloc(sizeof(_MMCamcorderMsgItem));
731         memcpy(item, data, sizeof(_MMCamcorderMsgItem));
732         item->handle = handle;
733
734         _MMCAMCORDER_LOCK(handle);
735         hcamcorder->msg_data = g_list_append(hcamcorder->msg_data, item);
736 //      _mmcam_dbg_log("item[%p]", item);
737
738         /* Use DEFAULT priority */
739         g_idle_add_full(G_PRIORITY_DEFAULT, _mmcamcroder_msg_callback, item, NULL);
740
741         _MMCAMCORDER_UNLOCK(handle);
742
743         return TRUE;
744 }
745
746
747 void
748 _mmcamcroder_remove_message_all(MMHandleType handle)
749 {
750         mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle);
751         _MMCamcorderMsgItem *item = NULL;
752         gboolean ret = TRUE;
753         GList *list = NULL;
754
755         mmf_return_if_fail(hcamcorder);
756
757         _MMCAMCORDER_LOCK(handle);
758
759         if(!hcamcorder->msg_data)
760         {
761                 _mmcam_dbg_log("No message data is remained.");
762         }
763         else
764         {
765                 list = hcamcorder->msg_data;
766
767                 while(list)
768                 {
769                         item = list->data;
770                         list =  g_list_next(list);
771
772                         if(!item)
773                         {
774                                 _mmcam_dbg_err("Fail to remove message. The item is NULL");
775                         }
776                         else
777                         {
778                                 ret = g_idle_remove_by_data (item);
779                                 _mmcam_dbg_log("Remove item[%p]. ret[%d]", item, ret);
780
781                                 hcamcorder->msg_data = g_list_remove(hcamcorder->msg_data, item);
782
783                                 SAFE_FREE(item);
784                         }
785                 }
786
787                 g_list_free(hcamcorder->msg_data);
788                 hcamcorder->msg_data = NULL;
789         }
790
791         /* remove idle function for playing capture sound */
792         do {
793                 ret = g_idle_remove_by_data(hcamcorder);
794                 _mmcam_dbg_log("remove idle function for playing capture sound. ret[%d]", ret);
795         } while (ret);
796
797         _MMCAMCORDER_UNLOCK(handle);
798
799         return;
800 }
801
802
803 void
804 _mmcamcorder_err_trace_write( char *str_filename, char *func_name, int line_num, char *fmt, ... )
805 {
806         FILE *f    = NULL;
807         va_list ap = {0};
808         char time_string[TIME_STRING_MAX_LEN] = {'\0',};
809
810         time_t current_time;
811         struct tm new_time;
812
813         mmf_return_if_fail( str_filename );
814
815         current_time = time( NULL );
816         localtime_r( &current_time, &new_time );
817
818         f = fopen( str_filename, "a" );
819         if( f == NULL )
820         {
821                 _mmcam_dbg_warn( "Failed to open file.[%s]", str_filename );
822                 return;
823         }
824
825         asctime_r(&new_time, time_string);
826         fprintf( f, "[%.19s][%05d][%s]", time_string, line_num, func_name );
827
828         va_start( ap, fmt );
829         vfprintf( f, fmt, ap );
830         va_end( ap );
831
832         fprintf( f, "\n" );
833
834         fclose( f );
835 }
836
837 int _mmcamcorder_get_pixel_format(GstCaps *caps)
838 {
839         const GstStructure *structure;
840         const char *media_type;
841         GstVideoInfo media_info;
842         MMPixelFormatType type = 0;
843         unsigned int fourcc = 0;
844         
845     mmf_return_val_if_fail( caps != NULL, MM_PIXEL_FORMAT_INVALID );
846
847         structure = gst_caps_get_structure (caps, 0);
848         media_type = gst_structure_get_name (structure);
849
850         if (!strcmp (media_type, "image/jpeg") )
851         {
852                 _mmcam_dbg_log("It is jpeg.");
853                 type = MM_PIXEL_FORMAT_ENCODED;
854         }
855         else if (!strcmp (media_type, "video/x-raw")
856                 && gst_video_info_from_caps(&media_info, caps)
857                 && GST_VIDEO_INFO_IS_YUV(&media_info))
858         {
859                 _mmcam_dbg_log("It is yuv.");
860                 fourcc = gst_video_format_to_fourcc(GST_VIDEO_INFO_FORMAT(&media_info));
861                 type = _mmcamcorder_get_pixtype(fourcc);
862         }
863         else
864         {
865                 _mmcam_dbg_err("Not supported format");
866                 type = MM_PIXEL_FORMAT_INVALID;
867         }
868         
869         _mmcam_dbg_log( "Type [%d]", type );
870
871         return type;
872 }
873
874 unsigned int _mmcamcorder_get_fourcc(int pixtype, int codectype, int use_zero_copy_format)
875 {
876         unsigned int fourcc = 0;
877
878         _mmcam_dbg_log("pixtype(%d)", pixtype);
879
880         switch (pixtype) {
881         case MM_PIXEL_FORMAT_NV12:
882                 if (use_zero_copy_format) {
883                         fourcc = GST_MAKE_FOURCC ('S', 'N', '1', '2');
884                 } else {
885                         fourcc = GST_MAKE_FOURCC ('N', 'V', '1', '2');
886                 }
887                 break;
888         case MM_PIXEL_FORMAT_YUYV:
889                 if (use_zero_copy_format) {
890                         fourcc = GST_MAKE_FOURCC ('S', 'U', 'Y', 'V');
891                 } else {
892                         fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
893                 }
894                 break;
895         case MM_PIXEL_FORMAT_UYVY:
896                 if (use_zero_copy_format) {
897                         fourcc = GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y');
898                 } else {
899                         fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
900                 }
901                 break;
902         case MM_PIXEL_FORMAT_I420:
903                 if (use_zero_copy_format) {
904                         fourcc = GST_MAKE_FOURCC ('S', '4', '2', '0');
905                 } else {
906                         fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
907                 }
908                 break;
909         case MM_PIXEL_FORMAT_YV12:
910                 fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
911                 break;
912         case MM_PIXEL_FORMAT_422P:
913                 fourcc = GST_MAKE_FOURCC ('4', '2', '2', 'P');
914                 break;
915         case MM_PIXEL_FORMAT_RGB565:
916                 fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 'P');
917                 break;
918         case MM_PIXEL_FORMAT_RGB888:
919                 fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', '3');
920                 break;
921         case MM_PIXEL_FORMAT_ENCODED:
922                 if (codectype == MM_IMAGE_CODEC_JPEG) {
923                         fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G');
924                 } else if (codectype == MM_IMAGE_CODEC_JPEG_SRW) {
925                         fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G'); /*TODO: JPEG+SamsungRAW format */
926                 } else if (codectype == MM_IMAGE_CODEC_SRW) {
927                         fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G'); /*TODO: SamsungRAW format */
928                 } else if (codectype == MM_IMAGE_CODEC_PNG) {
929                         fourcc = GST_MAKE_FOURCC ('P', 'N', 'G', ' ');
930                 } else {
931                         /* Please let us know what other fourcces are. ex) BMP, GIF?*/
932                         fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G');
933                 }
934                 break;
935         case MM_PIXEL_FORMAT_ITLV_JPEG_UYVY:
936                 fourcc = GST_MAKE_FOURCC('I','T','L','V');
937                 break;
938         default:
939                 _mmcam_dbg_log("Not proper pixel type[%d]. Set default - I420", pixtype);
940                 if (use_zero_copy_format) {
941                         fourcc = GST_MAKE_FOURCC ('S', '4', '2', '0');
942                 } else {
943                         fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
944                 }
945                 break;
946         }
947
948         return fourcc;
949 }
950
951
952 int _mmcamcorder_get_pixtype(unsigned int fourcc)
953 {
954         int pixtype = MM_PIXEL_FORMAT_INVALID;
955         char *pfourcc = (char*)&fourcc;
956         _mmcam_dbg_log("fourcc(%c%c%c%c)", pfourcc[0], pfourcc[1], pfourcc[2], pfourcc[3]);
957
958         switch (fourcc) {
959         case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
960         case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
961                 pixtype = MM_PIXEL_FORMAT_NV12;
962                 break;
963         case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
964         case GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V'):
965         case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
966                 pixtype = MM_PIXEL_FORMAT_YUYV;
967                 break;
968         case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'):
969         case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
970                 pixtype = MM_PIXEL_FORMAT_UYVY;
971                 break;
972         case GST_MAKE_FOURCC ('S', '4', '2', '0'):
973         case GST_MAKE_FOURCC ('I', '4', '2', '0'):
974                 pixtype = MM_PIXEL_FORMAT_I420;
975                 break;
976         case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
977                 pixtype = MM_PIXEL_FORMAT_YV12;
978                 break;
979         case GST_MAKE_FOURCC ('4', '2', '2', 'P'):
980                 pixtype = MM_PIXEL_FORMAT_422P;
981                 break;
982         case GST_MAKE_FOURCC ('R', 'G', 'B', 'P'):
983                 pixtype = MM_PIXEL_FORMAT_RGB565;
984                 break;
985         case GST_MAKE_FOURCC ('R', 'G', 'B', '3'):
986                 pixtype = MM_PIXEL_FORMAT_RGB888;
987                 break;
988         case GST_MAKE_FOURCC ('A', 'R', 'G', 'B'):
989         case GST_MAKE_FOURCC ('x', 'R', 'G', 'B'):
990                 pixtype = MM_PIXEL_FORMAT_ARGB;
991                 break;
992         case GST_MAKE_FOURCC ('B', 'G', 'R', 'A'):
993         case GST_MAKE_FOURCC ('B', 'G', 'R', 'x'):
994                 pixtype = MM_PIXEL_FORMAT_RGBA;
995                 break;
996         case GST_MAKE_FOURCC ('J', 'P', 'E', 'G'):
997         case GST_MAKE_FOURCC ('P', 'N', 'G', ' '):
998                 pixtype = MM_PIXEL_FORMAT_ENCODED;
999                 break;
1000         /*FIXME*/
1001         case GST_MAKE_FOURCC ('I', 'T', 'L', 'V'):
1002                 pixtype = MM_PIXEL_FORMAT_ITLV_JPEG_UYVY;
1003                 break;
1004         default:
1005                 _mmcam_dbg_log("Not supported fourcc type(%x)", fourcc);
1006                 pixtype = MM_PIXEL_FORMAT_INVALID;
1007                 break;
1008         }
1009
1010         return pixtype;
1011 }
1012
1013
1014 gboolean
1015 _mmcamcorder_add_elements_to_bin( GstBin *bin, GList *element_list )
1016 {
1017         GList *local_list = element_list;
1018         _MMCamcorderGstElement *element = NULL;
1019
1020         mmf_return_val_if_fail( bin && local_list, FALSE );
1021
1022         while( local_list )
1023         {
1024                 element = (_MMCamcorderGstElement*)local_list->data;
1025                 if( element && element->gst )
1026                 {
1027                         if( !gst_bin_add( bin, GST_ELEMENT(element->gst) ) )
1028                         {
1029                                 _mmcam_dbg_err( "Add element [%s] to bin [%s] FAILED",
1030                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
1031                                                 GST_ELEMENT_NAME(GST_ELEMENT(bin)) );
1032                                 return FALSE;
1033                         }
1034                         else
1035                         {
1036                                 _mmcam_dbg_log( "Add element [%s] to bin [%s] OK",
1037                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
1038                                                 GST_ELEMENT_NAME(GST_ELEMENT(bin)) );
1039                         }
1040                 }
1041
1042                 local_list = local_list->next;
1043         }
1044
1045         return TRUE;
1046 }
1047
1048 gboolean
1049 _mmcamcorder_link_elements( GList *element_list )
1050 {
1051         GList                  *local_list  = element_list;
1052         _MMCamcorderGstElement *element     = NULL;
1053         _MMCamcorderGstElement *pre_element = NULL;
1054
1055         mmf_return_val_if_fail( local_list, FALSE );
1056
1057         pre_element = (_MMCamcorderGstElement*)local_list->data;
1058         local_list = local_list->next;
1059
1060         while( local_list )
1061         {
1062                 element = (_MMCamcorderGstElement*)local_list->data;
1063                 if( element && element->gst )
1064                 {
1065                         if( _MM_GST_ELEMENT_LINK( GST_ELEMENT(pre_element->gst), GST_ELEMENT(element->gst) ) )
1066                         {
1067                                 _mmcam_dbg_log( "Link [%s] to [%s] OK",
1068                                                 GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)),
1069                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
1070                         }
1071                         else
1072                         {
1073                                 _mmcam_dbg_err( "Link [%s] to [%s] FAILED",
1074                                                 GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)),
1075                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
1076                                 return FALSE;
1077                         }
1078                 }
1079
1080                 pre_element = element;
1081                 local_list = local_list->next;
1082         }
1083
1084         return TRUE;
1085 }
1086
1087
1088 gboolean _mmcamcorder_resize_frame(unsigned char *src_data, int src_width, int src_height, int src_length, int src_format,
1089                                    unsigned char **dst_data, int *dst_width, int *dst_height, int *dst_length)
1090 {
1091         int ret = TRUE;
1092         int mm_ret = MM_ERROR_NONE;
1093         int input_format = MM_UTIL_IMG_FMT_YUV420;
1094         unsigned char *dst_tmp_data = NULL;
1095
1096         if (!src_data || !dst_data || !dst_width || !dst_height || !dst_length) {
1097                 _mmcam_dbg_err("something is NULL %p,%p,%p,%p,%p",
1098                                src_data, dst_data, dst_width, dst_height, dst_length);
1099                 return FALSE;
1100         }
1101
1102         /* set input format for mm-util */
1103         switch (src_format) {
1104         case MM_PIXEL_FORMAT_I420:
1105                 input_format = MM_UTIL_IMG_FMT_I420;
1106                 break;
1107         case MM_PIXEL_FORMAT_YV12:
1108                 input_format = MM_UTIL_IMG_FMT_YUV420;
1109                 break;
1110         case MM_PIXEL_FORMAT_NV12:
1111                 input_format = MM_UTIL_IMG_FMT_NV12;
1112                 break;
1113         case MM_PIXEL_FORMAT_YUYV:
1114                 input_format = MM_UTIL_IMG_FMT_YUYV;
1115                 break;
1116         case MM_PIXEL_FORMAT_UYVY:
1117                 input_format = MM_UTIL_IMG_FMT_UYVY;
1118                 break;
1119         default:
1120                 _mmcam_dbg_err("NOT supported format", src_format);
1121                 return FALSE;
1122         }
1123
1124         _mmcam_dbg_log("src size %dx%d -> dst size %dx%d",
1125                         src_width, src_height, *dst_width, *dst_height);
1126
1127         /* get length of resized image */
1128         __ta__("        mm_util_get_image_size 2",
1129     mm_ret = mm_util_get_image_size(input_format, *dst_width, *dst_height, (unsigned int*)dst_length);
1130         );
1131         if (mm_ret != MM_ERROR_NONE) {
1132                 GST_ERROR("mm_util_get_image_size failed 0x%x", ret);
1133                 return FALSE;
1134         }
1135
1136         _mmcam_dbg_log("dst_length : %d", *dst_length);
1137
1138         dst_tmp_data = (unsigned char *)malloc(*dst_length);
1139         if (dst_tmp_data == NULL) {
1140                 _mmcam_dbg_err("failed to alloc dst_thumb_size(size %d)", *dst_length);
1141                 return FALSE;
1142         }
1143
1144         __ta__("        mm_util_resize_image",
1145         mm_ret = mm_util_resize_image(src_data, src_width, src_height, input_format,
1146                                   dst_tmp_data, (unsigned int*)dst_width, (unsigned int*)dst_height);
1147         );
1148         if (mm_ret != MM_ERROR_NONE) {
1149                 GST_ERROR("mm_util_resize_image failed 0x%x", ret);
1150                 free(dst_tmp_data);
1151                 return FALSE;
1152         }
1153
1154         *dst_data = dst_tmp_data;
1155
1156         _mmcam_dbg_log("resize done %p, %dx%d", *dst_data, *dst_width, *dst_height);
1157
1158         return TRUE;
1159 }
1160
1161
1162 gboolean _mmcamcorder_encode_jpeg(void *src_data, unsigned int src_width, unsigned int src_height,
1163                                   int src_format, unsigned int src_length, unsigned int jpeg_quality,
1164                                   void **result_data, unsigned int *result_length)
1165 {
1166         int ret = 0;
1167         int i = 0;
1168         int enc_type = JPEG_ENCODER_SOFTWARE;
1169         guint32 src_fourcc = 0;
1170         gboolean do_encode = FALSE;
1171         jpegenc_parameter enc_param;
1172         static jpegenc_info enc_info = {-1,};
1173
1174         _mmcam_dbg_log("START");
1175
1176         mmf_return_val_if_fail(src_data && result_data && result_length, FALSE);
1177
1178         CLEAR(enc_param);
1179
1180         if (enc_info.sw_support == -1) {
1181                 CLEAR(enc_info);
1182                 __ta__("camsrcjpegenc_get_info",
1183                 camsrcjpegenc_get_info(&enc_info);
1184                 );
1185         }
1186
1187         src_fourcc = _mmcamcorder_get_fourcc(src_format, 0, FALSE);
1188         camsrcjpegenc_get_src_fmt(src_fourcc, &(enc_param.src_fmt));
1189
1190         if (enc_param.src_fmt == COLOR_FORMAT_NOT_SUPPORT) {
1191                 _mmcam_dbg_err("Not Supported FOURCC(format:%d)", src_format);
1192                 return FALSE;
1193         }
1194
1195         /* check H/W encoder */
1196         if (enc_info.hw_support) {
1197                 _mmcam_dbg_log("check H/W encoder supported format list");
1198                 /* Check supported format */
1199                 for (i = 0 ; i < enc_info.hw_enc.input_fmt_num ; i++) {
1200                         if (enc_param.src_fmt == enc_info.hw_enc.input_fmt_list[i]) {
1201                                 do_encode = TRUE;
1202                                 break;
1203                         }
1204                 }
1205
1206                 if (do_encode) {
1207                         enc_type = JPEG_ENCODER_HARDWARE;
1208                 }
1209         }
1210
1211         /* check S/W encoder */
1212         if (!do_encode && enc_info.sw_support) {
1213                 _mmcam_dbg_log("check S/W encoder supported format list");
1214                 /* Check supported format */
1215                 for (i = 0 ; i < enc_info.sw_enc.input_fmt_num ; i++) {
1216                         if (enc_param.src_fmt == enc_info.sw_enc.input_fmt_list[i]) {
1217                                 do_encode = TRUE;
1218                                 break;
1219                         }
1220                 }
1221
1222                 if (do_encode) {
1223                         enc_type = JPEG_ENCODER_SOFTWARE;
1224                 }
1225         }
1226
1227         if (do_encode) {
1228                 enc_param.src_data = src_data;
1229                 enc_param.width = src_width;
1230                 enc_param.height = src_height;
1231                 enc_param.src_len = src_length;
1232                 enc_param.jpeg_mode = JPEG_MODE_BASELINE;
1233                 enc_param.jpeg_quality = jpeg_quality;
1234
1235                 _mmcam_dbg_log("%ux%u, size %u, quality %u, type %d",
1236                                src_width, src_height, src_length,
1237                                jpeg_quality, enc_type);
1238
1239                 __ta__("                    camsrcjpegenc_encode",
1240                 ret = camsrcjpegenc_encode(&enc_info, enc_type, &enc_param );
1241                 );
1242                 if (ret == CAMSRC_JPEGENC_ERROR_NONE) {
1243                         *result_data = enc_param.result_data;
1244                         *result_length = enc_param.result_len;
1245
1246                         _mmcam_dbg_log("JPEG encode length(%d)", *result_length);
1247
1248                         return TRUE;
1249                 } else {
1250                         _mmcam_dbg_err("camsrcjpegenc_encode failed(%x)", ret);
1251                         return FALSE;
1252                 }
1253         }
1254
1255         _mmcam_dbg_err("No encoder supports %d format", src_format);
1256
1257         return FALSE;
1258 }
1259
1260
1261 static guint16 get_language_code(const char *str)
1262 {
1263     return (guint16) (((str[0]-0x60) & 0x1F) << 10) + (((str[1]-0x60) & 0x1F) << 5) + ((str[2]-0x60) & 0x1F);
1264 }
1265
1266 static gchar * str_to_utf8(const gchar *str)
1267 {
1268         return g_convert (str, -1, "UTF-8", "ASCII", NULL, NULL, NULL);
1269 }
1270
1271 static inline gboolean write_tag(FILE *f, const gchar *tag)
1272 {
1273         while(*tag)
1274                 FPUTC_CHECK(*tag++, f);
1275
1276         return TRUE;    
1277 }
1278
1279 static inline gboolean write_to_32(FILE *f, guint val)
1280 {
1281         FPUTC_CHECK(val >> 24, f);
1282         FPUTC_CHECK(val >> 16, f);
1283         FPUTC_CHECK(val >> 8, f);
1284         FPUTC_CHECK(val, f);
1285         return TRUE;
1286 }
1287
1288 static inline gboolean write_to_16(FILE *f, guint val)
1289 {
1290         FPUTC_CHECK(val >> 8, f);
1291         FPUTC_CHECK(val, f);
1292         return TRUE;    
1293 }
1294
1295 static inline gboolean write_to_24(FILE *f, guint val)
1296 {
1297         write_to_16(f, val >> 8);
1298         FPUTC_CHECK(val, f);
1299         return TRUE;    
1300 }