Skip DPM check if audio is disabled when start recording
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_videorec.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 <gst/video/cameracontrol.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
29
30 /*---------------------------------------------------------------------------------------
31 |    GLOBAL VARIABLE DEFINITIONS for internal                                                                                   |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_LOCATION_INFO              /* for add gps information */
34 #define MAX_ERROR_MESSAGE_LEN                   128
35
36 /*---------------------------------------------------------------------------------------
37 |    LOCAL VARIABLE DEFINITIONS for internal                                                                                    |
38 ---------------------------------------------------------------------------------------*/
39 #define _MMCAMCORDER_MINIMUM_FRAME              5
40 #define _MMCAMCORDER_RETRIAL_COUNT              10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME    200000  /* ms */
42 #define _OFFSET_COMPOSITION_MATRIX              40L
43 #define _GOP_GEN_INTERVAL                               1000000000      /*nano seconds*/
44
45 /*---------------------------------------------------------------------------------------
46 |    LOCAL FUNCTION PROTOTYPES:                                                                                                                 |
47 ---------------------------------------------------------------------------------------*/
48 /* STATIC INTERNAL FUNCTION */
49 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
56 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
57
58 /*=======================================================================================
59 |  FUNCTION DEFINITIONS                                                                 |
60 =======================================================================================*/
61 /*---------------------------------------------------------------------------------------
62 |    GLOBAL FUNCTION DEFINITIONS:                                                       |
63 ---------------------------------------------------------------------------------------*/
64 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
65 {
66         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
67         _MMCamcorderSubContext *sc = NULL;
68
69         GstBuffer *buffer = gst_sample_get_buffer(sample);
70         mmf_return_val_if_fail(buffer, FALSE);
71         mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
72         mmf_return_val_if_fail(hcamcorder, FALSE);
73
74         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
75         mmf_return_val_if_fail(sc, FALSE);
76
77         /*
78         _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
79                 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
80         */
81
82         /* push buffer in appsrc to encode */
83         if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
84             sc->info_video->record_dual_stream &&
85             sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
86                 GstFlowReturn ret = 0;
87                 GstClock *pipe_clock = NULL;
88
89                 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
90                         if (sc->info_video->is_firstframe) {
91                                 sc->info_video->is_firstframe = FALSE;
92                                 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
93                                 if (pipe_clock) {
94                                         gst_object_ref(pipe_clock);
95                                         sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer) - (gst_clock_get_time(pipe_clock) - GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
96                                         gst_object_unref(pipe_clock);
97                                 }
98                         }
99                 } else {
100                         if (sc->info_video->is_firstframe) {
101                                 sc->info_video->is_firstframe = FALSE;
102                                 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
103                         }
104                 }
105
106                 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS(buffer) - sc->info_video->base_video_ts;
107                 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
108
109                 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
110                 if (ret != GST_FLOW_OK && ret != GST_FLOW_FLUSHING) {
111                         _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
112                         gst_buffer_unref(buffer);
113                         buffer = NULL;
114                 }
115
116                 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
117         } else {
118                 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
119                         sc->info_video->push_encoding_buffer);
120
121                 gst_buffer_unref(buffer);
122                 buffer = NULL;
123         }
124
125         return TRUE;
126 }
127
128
129 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
130 {
131         int i = 0;
132         int err = MM_ERROR_NONE;
133         const char* gst_element_rsink_name = NULL;
134
135         GstBus *bus = NULL;
136         GstPad *srcpad = NULL;
137         GstPad *sinkpad = NULL;
138
139         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
140         _MMCamcorderSubContext *sc = NULL;
141
142         type_element *RecordsinkElement = NULL;
143
144         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
145
146         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
147         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
148         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
149
150         _mmcam_dbg_warn("start");
151
152         err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
153         if (err != MM_ERROR_NONE)
154                 return err;
155
156         /* Main pipeline */
157         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
158                 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
159                         sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
160                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
161         }
162
163         _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
164
165         /* get audio disable */
166         mm_camcorder_get_attributes(handle, NULL,
167                 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
168                 NULL);
169
170         _mmcam_dbg_log("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d",
171                 sc->audio_disable, sc->is_modified_rate);
172
173         sc->audio_disable |= sc->is_modified_rate;
174
175         if (sc->audio_disable == FALSE) {
176                 /* create audiosrc bin */
177                 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
178                 if (err != MM_ERROR_NONE)
179                         return err;
180         }
181
182         err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
183         if (err != MM_ERROR_NONE)
184                 return err;
185
186         if (sc->audio_disable == FALSE) {
187                 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
188                         sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
189         }
190
191         /* add element and encodesink bin to encode main pipeline */
192         gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
193                 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
194                 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
195                 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
196                 NULL);
197
198         /* Link each element : appsrc - capsfilter - encodesink bin */
199         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
200         sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
201         _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
202
203         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
204         sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
205         _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
206
207         if (sc->audio_disable == FALSE) {
208                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
209                 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
210                 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
211         }
212
213         _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
214                 CONFIGURE_CATEGORY_MAIN_RECORD,
215                 "RecordsinkElement",
216                 &RecordsinkElement);
217         _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
218
219         /* set data probe function */
220
221         /* register message cb */
222
223         /* set data probe functions */
224         if (sc->audio_disable == FALSE) {
225                 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
226                 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
227                         __mmcamcorder_audioque_dataprobe, hcamcorder);
228                 gst_object_unref(sinkpad);
229                 sinkpad = NULL;
230
231                 /* for voice mute */
232                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
233                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
234                         __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
235                 gst_object_unref(srcpad);
236                 srcpad = NULL;
237
238                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
239                         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
240                         MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
241                                 __mmcamcorder_eventprobe_monitor, hcamcorder);
242                         gst_object_unref(srcpad);
243                         srcpad = NULL;
244                 }
245         }
246
247         if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
248                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
249                 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
250                         __mmcamcorder_eventprobe_monitor, hcamcorder);
251                 gst_object_unref(srcpad);
252                 srcpad = NULL;
253         }
254
255         if (sc->audio_disable) {
256                 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
257                 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
258                         __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
259                 gst_object_unref(sinkpad);
260                 sinkpad = NULL;
261         }
262
263         if (!strcmp(gst_element_rsink_name, "filesink")) {
264                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
265                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
266                         __mmcamcorder_video_dataprobe_record, hcamcorder);
267                 gst_object_unref(srcpad);
268                 srcpad = NULL;
269
270                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
271                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
272                         __mmcamcorder_audio_dataprobe_check, hcamcorder);
273                 gst_object_unref(srcpad);
274                 srcpad = NULL;
275         }
276
277         sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
278         MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
279                 __mmcamcorder_muxed_dataprobe, hcamcorder);
280         MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
281                 __mmcamcorder_eventprobe_monitor, hcamcorder);
282         gst_object_unref(sinkpad);
283         sinkpad = NULL;
284
285         bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
286
287         /* register pipeline message callback */
288         hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
289
290         /* set sync handler */
291         gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
292
293         gst_object_unref(bus);
294         bus = NULL;
295
296         return MM_ERROR_NONE;
297
298 pipeline_creation_error:
299         for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
300                 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
301
302         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
303         return err;
304 }
305
306
307 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
308 {
309         GstPad *srcpad = NULL;
310         GstPad *sinkpad = NULL;
311         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
312         _MMCamcorderSubContext *sc = NULL;
313
314         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
315
316         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
317         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
318         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
319
320         _mmcam_dbg_log("");
321
322         if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
323                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
324                 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
325                 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
326
327                 /* release audiosrc bin */
328                 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
329                         sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
330
331                 /*
332                         To avoid conflicting between old elements and newly created elements,
333                         I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
334                         This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
335                         So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
336                         It's because the pipeline of audio recording destroys at the same time,
337                         and '_mmcamcorder_element_release_noti' will perfom removing handle.
338                 */
339                 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
340
341                 _mmcam_dbg_log("Audio pipeline removed");
342         }
343
344         return MM_ERROR_NONE;
345 }
346
347
348 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
349 {
350         GstPad *reqpad = NULL;
351         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
352         _MMCamcorderSubContext *sc = NULL;
353 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
354         int ret = MM_ERROR_NONE;
355         MMCamcorderResourceManager *resource_manager = NULL;
356 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
357
358         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
359
360         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
361         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
362         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
363
364         _mmcam_dbg_log("");
365
366         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
367                 /* release request pad */
368                 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
369                 if (reqpad) {
370                         gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
371                         gst_object_unref(reqpad);
372                         reqpad = NULL;
373                 }
374
375                 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
376                 if (reqpad) {
377                         gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
378                         gst_object_unref(reqpad);
379                         reqpad = NULL;
380                 }
381
382                 /* release encode main pipeline */
383                 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
384
385                 /*
386                         To avoid conflicting between old elements and newly created elements,
387                         I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
388                         This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
389                         So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
390                         It's because the pipeline of audio recording destroys at the same time,
391                         and '_mmcamcorder_element_release_noti' will perfom removing handle.
392                 */
393                 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
394                         _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
395
396                 _mmcam_dbg_warn("Encoder pipeline removed");
397
398 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
399                 resource_manager = &hcamcorder->resource_manager_sub;
400
401                 _mmcam_dbg_warn("lock resource - cb calling %d", resource_manager->is_release_cb_calling);
402
403                 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
404
405                 if (resource_manager->is_release_cb_calling == FALSE) {
406                         /* release resource */
407                         ret = _mmcamcorder_resource_manager_release(resource_manager);
408
409                         _mmcam_dbg_warn("release resource 0x%x", ret);
410 #ifdef _MMCAMCORDER_MURPHY_WAIT_TO_RELEASE_SUB_RESOURCE
411                         if (resource_manager->acquire_remain < resource_manager->acquire_count) {
412                                 /* wait for resource release */
413                                 gint64 end_time = g_get_monotonic_time() + (__MMCAMCORDER_RESOURCE_WAIT_TIME * G_TIME_SPAN_SECOND);
414                                 _mmcam_dbg_log("resource is not released all. wait for signal...");
415                                 _MMCAMCORDER_RESOURCE_WAIT_UNTIL(hcamcorder, end_time);
416                         }
417 #endif /* _MMCAMCORDER_MURPHY_WAIT_TO_RELEASE_SUB_RESOURCE */
418                 }
419
420                 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
421
422                 _mmcam_dbg_warn("unlock resource");
423 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
424         }
425
426         return MM_ERROR_NONE;
427 }
428
429
430 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
431 {
432         int ret = MM_ERROR_NONE;
433         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
434         _MMCamcorderSubContext *sc = NULL;
435
436         GstBus *bus = NULL;
437
438         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
439         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
440         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
441
442         _mmcam_dbg_log("start");
443
444         if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
445                 _mmcam_dbg_warn("pipeline is not existed.");
446                 return MM_ERROR_NONE;
447         }
448
449         _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
450
451         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
452         if (ret != MM_ERROR_NONE) {
453                 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
454                 return ret;
455         }
456
457         bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
458
459         /* remove audio pipeline first */
460         ret = _mmcamcorder_remove_audio_pipeline(handle);
461         if (ret != MM_ERROR_NONE) {
462                 _mmcam_dbg_err("Fail to remove audio pipeline");
463                 return ret;
464         }
465
466         ret = _mmcamcorder_remove_encode_pipeline(handle);
467         if (ret != MM_ERROR_NONE) {
468                 _mmcam_dbg_err("Fail to remove encoder pipeline");
469                 return ret;
470         }
471
472         /* Remove pipeline message callback */
473         if (hcamcorder->encode_pipeline_cb_event_id != 0) {
474                 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
475                 hcamcorder->encode_pipeline_cb_event_id = 0;
476         }
477
478         /* Remove remained message */
479         if (bus) {
480                 GstMessage *gst_msg = NULL;
481                 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
482                         _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
483                         gst_message_unref(gst_msg);
484                         gst_msg = NULL;
485                 }
486                 gst_object_unref(bus);
487                 bus = NULL;
488         }
489
490         _mmcam_dbg_log("done");
491
492         return ret;
493 }
494
495
496 int _mmcamcorder_video_command(MMHandleType handle, int command)
497 {
498         int size = 0;
499         int fileformat = 0;
500         int count = 0;
501         int ret = MM_ERROR_NONE;
502         double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
503         char *err_name = NULL;
504         char *temp_filename = NULL;
505         GstCameraControl *CameraControl = NULL;
506         GstCameraControlChannel *CameraControlChannel = NULL;
507         const GList *controls = NULL;
508         const GList *item = NULL;
509
510         gint fps = 0;
511         GstElement *pipeline = NULL;
512
513         _MMCamcorderVideoInfo *info = NULL;
514         _MMCamcorderSubContext *sc = NULL;
515         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
516
517         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
518
519         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
520         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
521         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
522         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
523
524         info = sc->info_video;
525
526         _mmcam_dbg_log("Command(%d)", command);
527
528         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
529
530         switch (command) {
531         case _MMCamcorder_CMD_RECORD:
532         {
533                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
534                         /**
535                          * start recording
536                          */
537                         guint imax_size = 0;
538                         guint imax_time = 0;
539                         int ret_free_space = 0;
540                         char *dir_name = NULL;
541                         guint64 free_space = 0;
542                         int file_system_type = 0;
543                         int root_directory_length = 0;
544
545                         /* Recording */
546                         _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
547
548 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
549                         /* check connection */
550                         ret = _mmcamcorder_resource_check_connection(&hcamcorder->resource_manager_sub);
551                         if (ret != MM_ERROR_NONE)
552                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
553
554                         /* create resource set */
555                         ret = _mmcamcorder_resource_create_resource_set(&hcamcorder->resource_manager_sub);
556                         if (ret != MM_ERROR_NONE)
557                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
558
559                         hcamcorder->resource_manager_sub.acquire_count = 0;
560
561                         /* prepare resource manager for H/W encoder */
562                         ret = _mmcamcorder_resource_manager_prepare(&hcamcorder->resource_manager_sub, MM_CAMCORDER_RESOURCE_TYPE_VIDEO_ENCODER);
563                         if (ret != MM_ERROR_NONE) {
564                                 _mmcam_dbg_err("could not prepare for video_encoder resource");
565                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
566                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
567                         }
568
569                         /* acquire resources */
570                         _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
571
572                         ret = _mmcamcorder_resource_manager_acquire(&hcamcorder->resource_manager_sub);
573                         if (ret != MM_ERROR_NONE) {
574                                 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
575                                 _mmcam_dbg_err("could not acquire resource");
576                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
577                         }
578
579                         if (hcamcorder->resource_manager_sub.acquire_remain > 0) {
580                                 gint64 end_time = 0;
581
582                                 _mmcam_dbg_warn("wait for resource state change");
583
584                                 /* wait for resource state change */
585                                 end_time = g_get_monotonic_time() + (__MMCAMCORDER_RESOURCE_WAIT_TIME * G_TIME_SPAN_SECOND);
586
587                                 if (_MMCAMCORDER_RESOURCE_WAIT_UNTIL(hcamcorder, end_time)) {
588                                         _mmcam_dbg_warn("signal received");
589                                 } else {
590                                         _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
591                                         _mmcam_dbg_err("timeout");
592                                         ret = MM_ERROR_RESOURCE_INTERNAL;
593                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
594                                 }
595                         } else {
596                                 _mmcam_dbg_log("already acquired");
597                         }
598
599                         _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
600 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
601
602                         /* init record_dual_stream */
603                         info->record_dual_stream = FALSE;
604
605                         ret = mm_camcorder_get_attributes(handle, &err_name,
606                                 MMCAM_CAMERA_FPS, &fps,
607                                 MMCAM_CAMERA_WIDTH, &(info->preview_width),
608                                 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
609                                 MMCAM_VIDEO_WIDTH, &(info->video_width),
610                                 MMCAM_VIDEO_HEIGHT, &(info->video_height),
611                                 MMCAM_FILE_FORMAT, &fileformat,
612                                 MMCAM_TARGET_FILENAME, &temp_filename, &size,
613                                 MMCAM_TARGET_MAX_SIZE, &imax_size,
614                                 MMCAM_TARGET_TIME_LIMIT, &imax_time,
615                                 MMCAM_FILE_FORMAT, &(info->fileformat),
616                                 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
617                                 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
618                                 NULL);
619                         if (ret != MM_ERROR_NONE) {
620                                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
621                                 SAFE_FREE(err_name);
622                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
623                         }
624
625                         if (temp_filename == NULL) {
626                                 _mmcam_dbg_err("filename is not set");
627                                 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
628                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
629                         }
630
631                         /* set max size */
632                         if (imax_size <= 0)
633                                 info->max_size = 0; /* do not check */
634                         else
635                                 info->max_size = ((guint64)imax_size) << 10; /* to byte */
636
637                         /* set max time */
638                         if (imax_time <= 0)
639                                 info->max_time = 0; /* do not check */
640                         else
641                                 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
642
643                         dir_name = g_path_get_dirname(temp_filename);
644                         if (dir_name) {
645                                 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
646                                 if (ret != 0) {
647                                         _mmcam_dbg_err("get storage info failed");
648                                         g_free(dir_name);
649                                         dir_name = NULL;
650                                         return MM_ERROR_OUT_OF_STORAGE;
651                                 }
652
653                                 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
654
655                                 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
656
657                                 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
658                                         /* MSDOS_SUPER_MAGIC : 0x4d44 */
659                                         if (file_system_type == MSDOS_SUPER_MAGIC &&
660                                             (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
661                                                 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
662                                                         info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
663                                                 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
664                                         } else {
665                                                 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
666                                                         file_system_type, info->max_size);
667                                         }
668                                 } else {
669                                         _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
670                                 }
671
672                                 g_free(dir_name);
673                                 dir_name = NULL;
674                         } else {
675                                 _mmcam_dbg_err("failed to get directory name");
676                                 ret_free_space = -1;
677                         }
678
679                         if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
680                                 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
681                                         ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
682                                 return MM_ERROR_OUT_OF_STORAGE;
683                         }
684
685                         g_mutex_lock(&hcamcorder->task_thread_lock);
686                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
687                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
688                                 /* Play record start sound */
689                                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
690                         }
691                         g_mutex_unlock(&hcamcorder->task_thread_lock);
692
693                         _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
694
695                         if (info->video_width == 0 || info->video_height == 0) {
696                                 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
697                                         info->video_width, info->video_height, info->preview_width, info->preview_height);
698                                 info->video_width = info->preview_width;
699                                 info->video_height = info->preview_height;
700                         }
701
702                         if (info->support_dual_stream) {
703                                 _mmcam_dbg_warn("DUAL STREAM MODE");
704
705                                 info->record_dual_stream = TRUE;
706
707                                 /* No need to restart preview */
708                                 info->restart_preview = FALSE;
709
710                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
711                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
712                         } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
713                                 info->preview_width == info->video_width &&
714                                 info->preview_height == info->video_height) {
715                                 _mmcam_dbg_log("H264 preview mode and same resolution");
716
717                                 /* No need to restart preview */
718                                 info->restart_preview = FALSE;
719                         } else {
720                                 /* always need to restart preview  */
721                                 info->restart_preview = TRUE;
722                         }
723
724                         /* set recording hint */
725                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
726
727                         if (info->restart_preview) {
728                                 /* stop preview and set new size */
729                                 _mmcam_dbg_log("restart preview");
730
731                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
732                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
733                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
734
735                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
736
737                                 /* check decoder recreation */
738                                 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
739                                         _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
740                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
741                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
742                                 }
743
744                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
745                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
746                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
747
748                                 if (ret != MM_ERROR_NONE)
749                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
750
751                                 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
752                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
753                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
754                                 }
755
756                                 /* Start preview again with new setting */
757                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
758                                 if (ret != MM_ERROR_NONE)
759                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
760
761                                 if (motion_rate < 1.0) {
762                                         _mmcam_dbg_warn("wait for stabilization of frame");
763                                         usleep(300000);
764                                 }
765                         } else {
766                                 _mmcam_dbg_log("no need to restart preview");
767                         }
768
769                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
770                                 CONFIGURE_CATEGORY_MAIN_RECORD,
771                                 "DropVideoFrame",
772                                 &(sc->drop_vframe));
773
774                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
775                                 CONFIGURE_CATEGORY_MAIN_RECORD,
776                                 "PassFirstVideoFrame",
777                                 &(sc->pass_first_vframe));
778
779                         _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
780                                 sc->drop_vframe, sc->pass_first_vframe);
781
782                         info->record_drop_count = (guint)motion_rate;
783                         info->record_motion_rate = motion_rate;
784                         if (sc->is_modified_rate)
785                                 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
786                         else
787                                 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
788
789                         _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
790                                 fps, info->record_motion_rate, info->record_timestamp_ratio);
791
792                         /* set push buffer flag */
793                         info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
794                         info->base_video_ts = 0;
795
796                         /* connect video stream cb signal */
797                         /*130826 Connect video stream cb for handling fast record frame cb*/
798                         if (info->record_dual_stream) {
799                                 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
800                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
801                         }
802
803                         /* start video stream */
804                         if (info->record_dual_stream) {
805                                 CameraControl =  GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
806                                 if (CameraControl) {
807                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
808
809                                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
810                                         gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
811
812                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
813                                 } else {
814                                         _mmcam_dbg_err("could not get camera control");
815                                 }
816                         }
817
818                         /* check pre-created encode pipeline */
819                         g_mutex_lock(&hcamcorder->task_thread_lock);
820                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
821                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
822                                 /* create encoding pipeline */
823                                 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
824                                 if (ret != MM_ERROR_NONE) {
825                                         g_mutex_unlock(&hcamcorder->task_thread_lock);
826                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
827                                 }
828                         }
829                         g_mutex_unlock(&hcamcorder->task_thread_lock);
830
831                         /* check recording start sound */
832                         _mmcamcorder_sound_solo_play_wait(handle);
833
834                         /**< To fix video recording hanging
835                                 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
836                                 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
837                                  basetime wouldn't change if you set (GstClockTime)0.
838                                 3. Move set start time position below PAUSED of pipeline.
839                         */
840                         /*
841                         gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
842                         gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
843                         */
844
845                         info->video_frame_count = 0;
846                         info->is_firstframe = TRUE;
847                         info->audio_frame_count = 0;
848                         info->filesize = 0;
849                         sc->ferror_send = FALSE;
850                         sc->ferror_count = 0;
851                         hcamcorder->error_occurs = FALSE;
852                         sc->bget_eos = FALSE;
853                         sc->muxed_stream_offset = 0;
854
855                         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
856                         if (ret != MM_ERROR_NONE) {
857                                 /* stop video stream */
858                                 if (info->record_dual_stream) {
859                                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
860                                         if (CameraControl) {
861                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
862
863                                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
864                                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
865
866                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
867                                         } else {
868                                                 _mmcam_dbg_err("failed to get camera control");
869                                         }
870                                 }
871
872                                 /* Remove recorder pipeline and recording file which size maybe zero */
873                                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
874                                 if (info->filename) {
875                                         _mmcam_dbg_log("file delete(%s)", info->filename);
876                                         unlink(info->filename);
877                                 }
878                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
879                         }
880
881                         /*set the camera control to create the GOP so that video record will get a new key frame*/
882                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
883                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
884                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
885                                 controls = gst_camera_control_list_channels(CameraControl);
886                                 if (controls != NULL) {
887                                         for (item = controls ; item && item->data ; item = item->next) {
888                                                 CameraControlChannel = item->data;
889                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
890                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
891                                                         /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
892                                                         break;
893                                                 }
894                                         }
895
896                                         if (item == NULL)
897                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
898                                 }
899                         } else {
900                                 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
901                                         sc->info_image->preview_format);
902                         }
903                 } else {
904                         /* Resume case */
905
906                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
907                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
908                                 /* generate and I-frame on resuming */
909                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
910                                 controls = gst_camera_control_list_channels(CameraControl);
911                                 if (controls != NULL) {
912                                         for (item = controls ; item && item->data ; item = item->next) {
913                                                 CameraControlChannel = item->data;
914                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
915                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
916                                                         /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
917                                                         break;
918                                                 }
919                                         }
920
921                                         if (item == NULL)
922                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
923                                 }
924                         }
925
926                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
927
928                         _mmcam_dbg_log("Object property settings done");
929                 }
930         }
931                 break;
932         case _MMCamcorder_CMD_PAUSE:
933         {
934                 if (info->b_commiting) {
935                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
936                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
937                 }
938
939                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
940                         if (sc->audio_disable) {
941                                 /* check only video frame */
942                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
943                                         break;
944                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
945                                         _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
946                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
947                                 } else {
948                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
949                                 }
950
951                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
952                         } else {
953                                 /* check both of video and audio frame */
954                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
955                                         break;
956                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
957                                         _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
958                                                 info->video_frame_count, info->audio_frame_count);
959                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
960                                 } else {
961                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
962                                                 count, info->video_frame_count, info->audio_frame_count);
963                                 }
964
965                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
966                         }
967                 }
968
969                 /* block encodebin */
970                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
971                 break;
972         }
973         case _MMCamcorder_CMD_CANCEL:
974         {
975                 if (info->b_commiting) {
976                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
977                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
978                 }
979
980                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
981                         /* capturing */
982                         if (hcamcorder->capture_in_recording == FALSE) {
983                                 break;
984                         } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
985                                 _mmcam_dbg_err("Failed to Wait capture data");
986                                 hcamcorder->capture_in_recording = FALSE;
987                                 break;
988                         } else {
989                                 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
990                         }
991
992                         usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
993                 }
994
995                 /* block push buffer */
996                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
997
998                 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
999                 if (ret != MM_ERROR_NONE)
1000                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1001
1002                 /* set recording hint */
1003                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1004
1005                 /* stop video stream */
1006                 if (info->record_dual_stream) {
1007                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1008                         if (CameraControl) {
1009                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1010
1011                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1012                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1013
1014                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1015                         } else {
1016                                 _mmcam_dbg_err("failed to get camera control");
1017                         }
1018                 }
1019
1020                 if (info->restart_preview) {
1021                         /* restart preview */
1022                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1023                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1024                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1025
1026                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1027
1028                         /* check decoder recreation */
1029                         if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1030                                 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1031                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1032                         }
1033
1034                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1035                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1036                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1037
1038                         if (ret != MM_ERROR_NONE)
1039                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1040
1041                         /* reset restart_preview for inset window layout */
1042                         info->restart_preview = FALSE;
1043
1044                         if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1045                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1046                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1047                         }
1048
1049                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1050                         if (ret != MM_ERROR_NONE)
1051                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1052                 }
1053
1054                 /* remove target file */
1055                 if (info->filename) {
1056                         _mmcam_dbg_log("file delete(%s)", info->filename);
1057                         unlink(info->filename);
1058                 }
1059
1060                 sc->isMaxsizePausing = FALSE;
1061                 sc->isMaxtimePausing = FALSE;
1062
1063                 sc->display_interval = 0;
1064                 sc->previous_slot_time = 0;
1065                 info->video_frame_count = 0;
1066                 info->audio_frame_count = 0;
1067                 info->filesize = 0;
1068                 hcamcorder->capture_in_recording = FALSE;
1069                 break;
1070         }
1071         case _MMCamcorder_CMD_COMMIT:
1072         {
1073                 if (info->b_commiting) {
1074                         _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1075                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1076                 } else {
1077                         _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1078                         info->b_commiting = TRUE;
1079                         sc->bget_eos = FALSE;
1080                 }
1081
1082                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1083                         if (sc->audio_disable) {
1084                                 /* check only video frame */
1085                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1086                                     hcamcorder->capture_in_recording == FALSE) {
1087                                         break;
1088                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1089                                         _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1090                                                 info->video_frame_count, hcamcorder->capture_in_recording);
1091
1092                                         if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1093                                                 _mmcam_dbg_warn("video frames are enough. keep going...");
1094                                         } else {
1095                                                 info->b_commiting = FALSE;
1096                                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1097                                         }
1098                                 } else {
1099                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1100                                                 count, info->video_frame_count, hcamcorder->capture_in_recording);
1101                                 }
1102                         } else {
1103                                 /* check both of video and audio frame */
1104                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1105                                     info->audio_frame_count &&
1106                                     hcamcorder->capture_in_recording == FALSE) {
1107                                         break;
1108                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1109                                         _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1110                                                 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1111
1112                                         if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1113                                                 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1114                                         } else {
1115                                                 info->b_commiting = FALSE;
1116                                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1117                                         }
1118
1119                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1120                                 } else {
1121                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1122                                                 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1123                                 }
1124                         }
1125
1126                         if (hcamcorder->capture_in_recording) {
1127                                 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1128                                 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1129                                         _mmcam_dbg_warn("signal received");
1130                                 } else {
1131                                         _mmcam_dbg_warn("timeout");
1132                                 }
1133                         } else {
1134                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1135                         }
1136                 }
1137
1138                 /* block push buffer */
1139                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1140                 _mmcam_dbg_log("block push buffer to appsrc");
1141
1142                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1143                         if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1144                                 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1145                         } else {
1146                                 _mmcam_dbg_err("VIDEO: send EOS failed");
1147                                 info->b_commiting = FALSE;
1148                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1149                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1150                         }
1151                 } else {
1152                         _mmcam_dbg_err("No video stream source");
1153                         info->b_commiting = FALSE;
1154                         ret = MM_ERROR_CAMCORDER_INTERNAL;
1155                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1156                 }
1157
1158                 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1159                         if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1160                                 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1161                         } else {
1162                                 _mmcam_dbg_err("AUDIO: send EOS failed");
1163                                 info->b_commiting = FALSE;
1164                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1165                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1166                         }
1167                 } else {
1168                         _mmcam_dbg_log("No audio stream");
1169                 }
1170
1171                 /* sc */
1172                 sc->display_interval = 0;
1173                 sc->previous_slot_time = 0;
1174
1175                 /* Wait EOS */
1176                 _mmcam_dbg_log("Start to wait EOS");
1177                 ret = _mmcamcorder_get_eos_message(handle);
1178                 if (ret != MM_ERROR_NONE) {
1179                         info->b_commiting = FALSE;
1180                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1181                 }
1182
1183                 /* reset flag */
1184                 hcamcorder->capture_in_recording = FALSE;
1185         }
1186                 break;
1187         default:
1188                 ret =  MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1189                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1190         }
1191
1192         return MM_ERROR_NONE;
1193
1194 _ERR_CAMCORDER_VIDEO_COMMAND:
1195         if (command == _MMCamcorder_CMD_RECORD)
1196                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1197
1198         return ret;
1199 }
1200
1201
1202 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1203 {
1204         int ret = MM_ERROR_NONE;
1205         int enabletag = 0;
1206         guint64 file_size = 0;
1207
1208         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1209         _MMCamcorderSubContext *sc = NULL;
1210         _MMCamcorderVideoInfo *info = NULL;
1211         _MMCamcorderMsgItem msg;
1212         MMCamRecordingReport *report = NULL;
1213
1214         mmf_return_val_if_fail(hcamcorder, FALSE);
1215
1216         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1217         mmf_return_val_if_fail(sc, FALSE);
1218         mmf_return_val_if_fail(sc->info_video, FALSE);
1219
1220         info = sc->info_video;
1221
1222         _mmcam_dbg_err("");
1223
1224         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1225                 /* Play record stop sound */
1226                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1227         } else {
1228                 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1229
1230                 _mmcamcorder_sound_init(handle);
1231
1232                 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1233
1234                 _mmcamcorder_sound_finalize(handle);
1235         }
1236
1237         /* remove blocking part */
1238         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1239
1240         mm_camcorder_get_attributes(handle, NULL,
1241                 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1242                 NULL);
1243
1244         ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1245         if (ret != MM_ERROR_NONE)
1246                 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1247
1248         /* set recording hint */
1249         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1250
1251         /* stop video stream */
1252         if (info->record_dual_stream) {
1253                 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1254                 if (control) {
1255                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1256
1257                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1258                         gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1259
1260                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1261                 } else {
1262                         _mmcam_dbg_err("failed to get camera control");
1263                 }
1264         }
1265
1266         if (enabletag && !(sc->ferror_send)) {
1267                 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1268                 if (ret) {
1269                         _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1270                 } else {
1271                         _mmcam_dbg_err("Writing location information FAILED !!");
1272                 }
1273         }
1274
1275         /* Check file size */
1276         if (info->max_size > 0) {
1277                 _mmcamcorder_get_file_size(info->filename, &file_size);
1278                 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1279                                            info->max_size, file_size);
1280
1281                 if (file_size > info->max_size) {
1282                         _MMCamcorderMsgItem message;
1283                         _mmcam_dbg_err("File size is greater than max size !!");
1284                         message.id = MM_MESSAGE_CAMCORDER_ERROR;
1285                         message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1286                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1287                 }
1288         }
1289
1290         if (info->restart_preview) {
1291                 /* block queue */
1292                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1293                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1294                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1295
1296                 _mmcam_dbg_log("Set state of pipeline as READY");
1297                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1298
1299                 /* check decoder recreation */
1300                 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1301                         _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1302                         ret = MM_ERROR_CAMCORDER_INTERNAL;
1303                 }
1304
1305                 /* unblock queue */
1306                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1307                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1308                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1309
1310                 if (ret != MM_ERROR_NONE) {
1311                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1312                         msg.param.code = ret;
1313                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1314                         _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1315                 }
1316
1317                 /* reset restart_preview for inset window layout */
1318                 info->restart_preview = FALSE;
1319
1320                 /* recover preview size */
1321                 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1322
1323                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1324                 /* Do not return when error is occurred.
1325                    Recording file was created successfully, but starting pipeline failed */
1326                 if (ret != MM_ERROR_NONE) {
1327                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1328                         msg.param.code = ret;
1329                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1330                         _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1331                 }
1332         } else {
1333                 _mmcam_dbg_log("No need to restart preview");
1334         }
1335
1336         /* Send recording report to application */
1337         msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1338         report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1339         if (!report) {
1340                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1341         } else {
1342                 report->recording_filename = g_strdup(info->filename);
1343                 msg.param.data = report;
1344                 msg.param.code = 1;
1345                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1346         }
1347
1348         /* Finishing */
1349         sc->pipeline_time = 0;
1350         sc->pause_time = 0;
1351         sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1352         sc->isMaxtimePausing = FALSE;
1353         hcamcorder->error_occurs = FALSE;
1354
1355         info->video_frame_count = 0;
1356         info->audio_frame_count = 0;
1357         info->filesize = 0;
1358         info->b_commiting = FALSE;
1359
1360         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1361                 /* check recording stop sound */
1362                 _mmcamcorder_sound_solo_play_wait(handle);
1363         }
1364
1365         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1366
1367         return TRUE;
1368 }
1369
1370
1371 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1372 {
1373         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1374         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1375         GstMapInfo mapinfo;
1376         _MMCamcorderSubContext *sc = NULL;
1377         _MMCamcorderVideoInfo *videoinfo = NULL;
1378         _MMCamcorderMsgItem msg;
1379         guint64 buffer_size = 0;
1380         guint64 trailer_size = 0;
1381         guint64 max_size = 0;
1382
1383         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1384         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1385         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1386
1387         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1388         videoinfo = sc->info_video;
1389
1390         /* get buffer size */
1391         if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1392                 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1393                 return GST_PAD_PROBE_OK;
1394         }
1395
1396         buffer_size = mapinfo.size;
1397         gst_buffer_unmap(buffer, &mapinfo);
1398
1399         /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1400
1401         g_mutex_lock(&videoinfo->size_check_lock);
1402
1403         if (videoinfo->audio_frame_count == 0) {
1404                 videoinfo->filesize += buffer_size;
1405                 videoinfo->audio_frame_count++;
1406                 g_mutex_unlock(&videoinfo->size_check_lock);
1407                 return GST_PAD_PROBE_OK;
1408         }
1409
1410         if (sc->ferror_send || sc->isMaxsizePausing) {
1411                 _mmcam_dbg_warn("Recording is paused, drop frames");
1412                 g_mutex_unlock(&videoinfo->size_check_lock);
1413                 return GST_PAD_PROBE_DROP;
1414         }
1415
1416         /* get trailer size */
1417         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1418                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1419         } else {
1420                 trailer_size = 0;
1421         }
1422
1423         /* check max size of recorded file */
1424         max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1425         if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1426                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1427                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1428                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1429                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1430                         " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1431                         videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1432
1433                 if (!sc->isMaxsizePausing) {
1434                         sc->isMaxsizePausing = TRUE;
1435                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1436                         if (pipeline_state == GST_STATE_PLAYING)
1437                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1438
1439                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1440                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1441                 }
1442
1443                 g_mutex_unlock(&videoinfo->size_check_lock);
1444
1445                 return FALSE;
1446         }
1447
1448         videoinfo->filesize += buffer_size;
1449         videoinfo->audio_frame_count++;
1450
1451         g_mutex_unlock(&videoinfo->size_check_lock);
1452
1453         return GST_PAD_PROBE_OK;
1454 }
1455
1456
1457 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1458 {
1459         gint ret = 0;
1460         guint vq_size = 0;
1461         guint aq_size = 0;
1462         guint64 free_space = 0;
1463         guint64 buffer_size = 0;
1464         guint64 trailer_size = 0;
1465         guint64 queued_buffer = 0;
1466         guint64 max_size = 0;
1467         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1468         GstMapInfo mapinfo;
1469         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1470
1471         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1472         _MMCamcorderMsgItem msg;
1473         _MMCamcorderSubContext *sc = NULL;
1474         _MMCamcorderVideoInfo *videoinfo = NULL;
1475
1476         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1477         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1478
1479         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1480         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1481         videoinfo = sc->info_video;
1482
1483         /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1484         if (sc->ferror_send) {
1485                 _mmcam_dbg_warn("file write error, drop frames");
1486                 return GST_PAD_PROBE_DROP;
1487         }
1488
1489         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1490         buffer_size = mapinfo.size;
1491         gst_buffer_unmap(buffer, &mapinfo);
1492
1493         videoinfo->video_frame_count++;
1494         if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1495                 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1496                         info->video_frame_count); */
1497                 g_mutex_lock(&videoinfo->size_check_lock);
1498                 videoinfo->filesize += buffer_size;
1499                 g_mutex_unlock(&videoinfo->size_check_lock);
1500                 return GST_PAD_PROBE_OK;
1501         }
1502
1503         /* get trailer size */
1504         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1505                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1506         } else {
1507                 trailer_size = 0;
1508         }
1509
1510         /* check free space */
1511         ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1512         if (ret != 0) {
1513                 _mmcam_dbg_err("Error occured. [%d]", ret);
1514                 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1515                         sc->ferror_send = TRUE;
1516
1517                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1518                         msg.param.code = MM_ERROR_FILE_READ;
1519
1520                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1521                 } else {
1522                         sc->ferror_count++;
1523                 }
1524
1525                 return GST_PAD_PROBE_DROP; /* skip this buffer */
1526         }
1527
1528         if (free_space == 0) {
1529                 /* check storage state */
1530                 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1531
1532                 _mmcam_dbg_warn("storage state %d", storage_state);
1533
1534                 if (storage_state == STORAGE_STATE_REMOVED ||
1535                         storage_state == STORAGE_STATE_UNMOUNTABLE) {
1536                         _mmcam_dbg_err("storage was removed!");
1537
1538                         _MMCAMCORDER_LOCK(hcamcorder);
1539
1540                         if (sc->ferror_send == FALSE) {
1541                                 _mmcam_dbg_err("OUT_OF_STORAGE error");
1542
1543                                 sc->ferror_send = TRUE;
1544
1545                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1546
1547                                 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1548                                 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1549
1550                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1551                         } else {
1552                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1553                                 _mmcam_dbg_warn("error was already sent");
1554                         }
1555
1556                         return GST_PAD_PROBE_DROP;
1557                 }
1558         }
1559
1560         /* get queued buffer size */
1561         if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1562                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1563         }
1564
1565         if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1566                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1567         }
1568
1569         queued_buffer = aq_size + vq_size;
1570
1571         if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1572                 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1573                 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1574                         " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1575                         free_space, trailer_size, buffer_size, queued_buffer);
1576
1577                 if (!sc->isMaxsizePausing) {
1578                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1579                         sc->isMaxsizePausing = TRUE;
1580
1581                         msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1582                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1583                 }
1584
1585                 return GST_PAD_PROBE_DROP;
1586         }
1587
1588         g_mutex_lock(&videoinfo->size_check_lock);
1589
1590         /* check max size of recorded file */
1591         max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1592         if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1593                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1594                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1595                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1596                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1597                         " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1598                         videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1599
1600                 if (!sc->isMaxsizePausing) {
1601                         sc->isMaxsizePausing = TRUE;
1602                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1603                         if (pipeline_state == GST_STATE_PLAYING)
1604                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1605
1606                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1607                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1608                 }
1609
1610                 g_mutex_unlock(&videoinfo->size_check_lock);
1611
1612                 return GST_PAD_PROBE_DROP;
1613         }
1614
1615         videoinfo->filesize += (guint64)buffer_size;
1616
1617         /*
1618         _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1619         */
1620
1621         g_mutex_unlock(&videoinfo->size_check_lock);
1622
1623         return GST_PAD_PROBE_OK;
1624 }
1625
1626
1627 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1628 {
1629         guint64 trailer_size = 0;
1630         guint64 rec_pipe_time = 0;
1631         unsigned int remained_time = 0;
1632
1633         GstClockTime b_time;
1634
1635         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1636         _MMCamcorderMsgItem msg;
1637         _MMCamcorderSubContext *sc = NULL;
1638         _MMCamcorderVideoInfo *videoinfo = NULL;
1639
1640         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1641
1642         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1643         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1644
1645         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1646         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1647         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1648
1649         videoinfo = sc->info_video;
1650
1651         b_time = GST_BUFFER_PTS(buffer);
1652
1653         rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1654
1655         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1656                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1657         } else {
1658                 trailer_size = 0;
1659         }
1660
1661         /* check max time */
1662         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1663                 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1664                         rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1665
1666                 if (!sc->isMaxtimePausing) {
1667                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1668
1669                         sc->isMaxtimePausing = TRUE;
1670
1671                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1672                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1673                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1674                         msg.param.recording_status.remained_time = 0;
1675                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1676
1677                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1678                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1679                 }
1680
1681                 return GST_PAD_PROBE_DROP;
1682         }
1683
1684         /* calculate remained time can be recorded */
1685         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1686                 remained_time = videoinfo->max_time - rec_pipe_time;
1687         } else if (videoinfo->max_size > 0) {
1688                 long double max_size = (long double)videoinfo->max_size;
1689                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1690
1691                 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1692         }
1693
1694         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1695         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1696         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1697         msg.param.recording_status.remained_time = remained_time;
1698         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1699
1700         /*
1701         _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1702                 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1703         */
1704
1705         if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1706                 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1707
1708                 /*
1709                 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1710                         record_motion_rate, videoinfo->record_drop_count);
1711                 */
1712
1713                 /* drop some frame if fast motion */
1714                 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1715                         if (record_motion_rate != (videoinfo->record_drop_count++)) {
1716                                 /*
1717                                 _mmcam_dbg_warn("drop frame");
1718                                 */
1719                                 return GST_PAD_PROBE_DROP;
1720                         }
1721
1722                         videoinfo->record_drop_count = 1;
1723                         /*
1724                         _mmcam_dbg_warn("pass frame");
1725                         */
1726                 }
1727
1728                 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1729                 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1730         }
1731
1732         return GST_PAD_PROBE_OK;
1733 }
1734
1735
1736 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1737 {
1738         _MMCamcorderMsgItem msg;
1739         guint64 trailer_size = 0;
1740         guint64 rec_pipe_time = 0;
1741         _MMCamcorderSubContext *sc = NULL;
1742         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1743         _MMCamcorderVideoInfo *videoinfo = NULL;
1744         unsigned int remained_time = 0;
1745         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1746
1747         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1748         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1749         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1750
1751         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1752         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1753         mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1754
1755         videoinfo = sc->info_video;
1756
1757         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1758                 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1759                 return GST_PAD_PROBE_OK;
1760         }
1761
1762         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1763
1764         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1765                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1766         } else {
1767                 trailer_size = 0;
1768         }
1769
1770         /* calculate remained time can be recorded */
1771         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1772                 remained_time = videoinfo->max_time - rec_pipe_time;
1773         } else if (videoinfo->max_size > 0) {
1774                 long double max_size = (long double)videoinfo->max_size;
1775                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1776
1777                 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1778         }
1779
1780         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1781                 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1782                         rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1783
1784                 if (!sc->isMaxtimePausing) {
1785                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1786
1787                         sc->isMaxtimePausing = TRUE;
1788
1789                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1790                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1791                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1792                         msg.param.recording_status.remained_time = 0;
1793                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1794
1795                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1796                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1797                 }
1798
1799                 return GST_PAD_PROBE_DROP;
1800         }
1801
1802         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1803         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1804         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1805         msg.param.recording_status.remained_time = remained_time;
1806         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1807
1808         /*
1809         _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1810                 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1811         */
1812
1813         return GST_PAD_PROBE_OK;
1814 }
1815
1816
1817 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1818 {
1819         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1820         double volume = 0.0;
1821         int format = 0;
1822         int channel = 0;
1823         int err = MM_ERROR_UNKNOWN;
1824         char *err_name = NULL;
1825         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1826         GstMapInfo mapinfo;
1827
1828         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1829         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1830
1831         /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1832         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1833                 MMCAM_AUDIO_VOLUME, &volume,
1834                 MMCAM_AUDIO_FORMAT, &format,
1835                 MMCAM_AUDIO_CHANNEL, &channel,
1836                 NULL);
1837         if (err != MM_ERROR_NONE) {
1838                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1839                 SAFE_FREE(err_name);
1840                 return err;
1841         }
1842
1843         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1844
1845         gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1846
1847         /* Set audio stream NULL */
1848         if (volume == 0.0)
1849                 memset(mapinfo.data, 0, mapinfo.size);
1850
1851         /* CALL audio stream callback */
1852         if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1853                 MMCamcorderAudioStreamDataType stream;
1854
1855                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1856                         _mmcam_dbg_warn("Not ready for stream callback");
1857                         gst_buffer_unmap(buffer, &mapinfo);
1858                         return GST_PAD_PROBE_OK;
1859                 }
1860
1861                 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1862                         GST_BUFFER_DATA(buffer), width, height, format);*/
1863
1864                 stream.data = (void *)mapinfo.data;
1865                 stream.format = format;
1866                 stream.channel = channel;
1867                 stream.length = mapinfo.size;
1868                 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1869
1870                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1871
1872                 if (hcamcorder->astream_cb)
1873                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1874
1875                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1876         }
1877
1878         gst_buffer_unmap(buffer, &mapinfo);
1879         return GST_PAD_PROBE_OK;
1880 }
1881
1882
1883 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1884 {
1885         gboolean bret = FALSE;
1886
1887         switch (fileformat) {
1888         case MM_FILE_FORMAT_3GP:
1889         case MM_FILE_FORMAT_MP4:
1890                 bret = __mmcamcorder_add_metadata_mp4(handle);
1891                 break;
1892         default:
1893                 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1894                 break;
1895         }
1896
1897         return bret;
1898 }
1899
1900
1901 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1902 {
1903         FILE *f = NULL;
1904         guchar buf[4];
1905         guint64 udta_size = 0;
1906         gint64 current_pos = 0;
1907         gint64 moov_pos = 0;
1908         gint64 udta_pos = 0;
1909         gdouble longitude = 0;
1910         gdouble latitude = 0;
1911         gdouble altitude = 0;
1912         int err = 0;
1913         int orientation = 0;
1914         int gps_enable = 0;
1915         char *err_name = NULL;
1916         char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1917         _MMCamcorderLocationInfo location_info = {0, 0, 0};
1918         _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1919
1920         _MMCamcorderVideoInfo *info = NULL;
1921         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1922         _MMCamcorderSubContext *sc = NULL;
1923
1924         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1925         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1926
1927         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1928         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1929
1930         _mmcam_dbg_log("");
1931
1932         info = sc->info_video;
1933
1934         f = fopen64(info->filename, "rb+");
1935         if (f == NULL) {
1936                 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1937                 _mmcam_dbg_err("file open failed [%s]", err_msg);
1938                 return FALSE;
1939         }
1940
1941         mm_camcorder_get_attributes(handle, &err_name,
1942                 MMCAM_TAG_LATITUDE, &latitude,
1943                 MMCAM_TAG_LONGITUDE, &longitude,
1944                 MMCAM_TAG_ALTITUDE, &altitude,
1945                 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1946                 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1947                 NULL);
1948         if (err_name) {
1949                 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1950                 SAFE_FREE(err_name);
1951         }
1952
1953         location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1954         location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1955         location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1956         geo_info.longitude = longitude *10000;
1957         geo_info.latitude = latitude *10000;
1958         geo_info.altitude = altitude *10000;
1959         /* find udta container.
1960            if, there are udta container, write loci box after that
1961            else, make udta container and write loci box. */
1962         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1963                 size_t nread = 0;
1964
1965                 _mmcam_dbg_log("find udta container");
1966
1967                 /* read size */
1968                 if (fseek(f, -8L, SEEK_CUR) != 0)
1969                         goto fail;
1970
1971                 udta_pos = ftello(f);
1972                 if (udta_pos < 0)
1973                         goto ftell_fail;
1974
1975                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1976
1977                 _mmcam_dbg_log("recorded file fread %d", nread);
1978
1979                 udta_size = _mmcamcorder_get_container_size(buf);
1980
1981                 /* goto end of udta and write 'loci' box */
1982                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1983                         goto fail;
1984
1985                 if (gps_enable) {
1986                         if (!_mmcamcorder_write_loci(f, location_info)) {
1987                                 _mmcam_dbg_err("failed to write loci");
1988                                 goto fail;
1989                         }
1990
1991                         if (!_mmcamcorder_write_geodata(f, geo_info)) {
1992                                 _mmcam_dbg_err("failed to write geodata");
1993                                 goto fail;
1994                         }
1995                 }
1996
1997                 current_pos = ftello(f);
1998                 if (current_pos < 0)
1999                         goto ftell_fail;
2000
2001                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
2002                         goto fail;
2003         } else {
2004                 _mmcam_dbg_log("No udta container");
2005                 if (fseek(f, 0, SEEK_END) != 0)
2006                         goto fail;
2007
2008                 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
2009                         _mmcam_dbg_err("failed to write udta");
2010                         goto fail;
2011                 }
2012         }
2013
2014         /* find moov container.
2015            update moov container size. */
2016         if ((current_pos = ftello(f)) < 0)
2017                 goto ftell_fail;
2018
2019         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
2020                 gint64 internal_pos = ftello(f);
2021
2022                 _mmcam_dbg_log("found moov container");
2023                 if (fseek(f, -8L, SEEK_CUR) != 0)
2024                         goto fail;
2025
2026                 moov_pos = ftello(f);
2027                 if (moov_pos < 0)
2028                         goto ftell_fail;
2029
2030                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2031                         goto fail;
2032
2033                 /* add orientation info */
2034                 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2035                         _mmcam_dbg_err("fseek failed : errno %d", errno);
2036                         goto fail;
2037                 }
2038
2039                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2040                         _mmcam_dbg_err("failed to find [trak] tag");
2041                         goto fail;
2042                 }
2043
2044                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2045                         _mmcam_dbg_err("failed to find [tkhd] tag");
2046                         goto fail;
2047                 }
2048
2049                 _mmcam_dbg_log("found [tkhd] tag");
2050
2051                 /* seek to start position of composition matrix */
2052                 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2053
2054                 /* update composition matrix for orientation */
2055                 _mmcamcorder_update_composition_matrix(f, orientation);
2056         } else {
2057                 _mmcam_dbg_err("No 'moov' container");
2058                 goto fail;
2059         }
2060
2061         fclose(f);
2062         return TRUE;
2063
2064 fail:
2065         fclose(f);
2066         return FALSE;
2067
2068 ftell_fail:
2069         _mmcam_dbg_err("ftell() returns negative value.");
2070         fclose(f);
2071         return FALSE;
2072 }
2073
2074
2075 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2076 {
2077         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2078         _MMCamcorderSubContext *sc = NULL;
2079
2080         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2081
2082         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2083         mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2084
2085         /* check video source element */
2086         if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2087                 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2088                 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2089                         _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2090                         G_CALLBACK(__mmcamcorder_video_stream_cb),
2091                         hcamcorder);
2092                 return MM_ERROR_NONE;
2093         } else {
2094                 _mmcam_dbg_err("videosrc element is not created yet");
2095                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2096         }
2097 }
2098
2099
2100 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2101 {
2102         int ret = MM_ERROR_NONE;
2103
2104         _MMCamcorderVideoInfo *info = NULL;
2105         _MMCamcorderSubContext *sc = NULL;
2106         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2107
2108         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2109
2110         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2111         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2112         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2113
2114         info = sc->info_video;
2115
2116         _mmcam_dbg_warn("start");
2117
2118         /* create encoding pipeline */
2119         ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2120         if (ret != MM_ERROR_NONE)
2121                 goto _ERR_PREPARE_RECORD;
2122
2123         if (info->filename == NULL) {
2124                 char *temp_filename = NULL;
2125                 int size = 0;
2126
2127                 mm_camcorder_get_attributes(handle, NULL,
2128                         MMCAM_TARGET_FILENAME, &temp_filename, &size,
2129                         NULL);
2130                 if (temp_filename)
2131                         info->filename = g_strdup(temp_filename);
2132
2133                 if (!info->filename) {
2134                         _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2135                         goto _ERR_PREPARE_RECORD;
2136                 }
2137         }
2138
2139         _mmcam_dbg_log("Record file name [%s]", info->filename);
2140
2141         MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2142         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2143
2144         /* Adjust display FPS */
2145         sc->display_interval = 0;
2146         sc->previous_slot_time = 0;
2147
2148         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2149         if (ret != MM_ERROR_NONE)
2150                 goto _ERR_PREPARE_RECORD;
2151
2152         _mmcam_dbg_warn("done");
2153
2154         return ret;
2155
2156 _ERR_PREPARE_RECORD:
2157         /* Remove recorder pipeline and recording file which size maybe zero */
2158         _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2159         if (info && info->filename) {
2160                 _mmcam_dbg_log("file delete(%s)", info->filename);
2161                 unlink(info->filename);
2162         }
2163
2164         return ret;
2165 }