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