correct printf formats
[platform/core/uifw/libtdm.git] / src / tdm_capture.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43 #include "tdm_helper.h"
44
45 #define CAPTURE_FUNC_ENTRY() \
46         tdm_func_capture *func_capture; \
47         tdm_private_display *private_display; \
48         tdm_private_capture *private_capture; \
49         tdm_error ret = TDM_ERROR_NONE; \
50         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER); \
51         private_capture = (tdm_private_capture*)capture; \
52         private_display = private_capture->private_display; \
53         func_capture = &private_display->func_capture
54
55 static void
56 _tdm_capture_print_list(struct list_head *list)
57 {
58         tdm_capture_private_buffer *b = NULL;
59         char str[512], *p;
60         int len = sizeof(str);
61
62         TDM_RETURN_IF_FAIL(list != NULL);
63
64         p = str;
65         LIST_FOR_EACH_ENTRY(b, list, link) {
66                 if (len > 0) {
67                         int l = snprintf(p, len, " (%p)", b->buffer);
68                         p += l;
69                         len -= l;
70                 } else
71                         break;
72         }
73
74         TDM_INFO("\t %s", str);
75 }
76
77 static tdm_capture_private_buffer *
78 _tdm_capture_find_tbm_buffer(struct list_head *list, tbm_surface_h buffer)
79 {
80         tdm_capture_private_buffer *b = NULL, *bb = NULL;
81
82         LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) {
83                 if (b->buffer == buffer)
84                         return b;
85         }
86
87         return NULL;
88 }
89
90 static tdm_capture_private_buffer *
91 _tdm_capture_find_buffer(struct list_head *list, tdm_capture_private_buffer *capture_buffer)
92 {
93         tdm_capture_private_buffer *b = NULL, *bb = NULL;
94
95         LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) {
96                 if (b == capture_buffer)
97                         return b;
98         }
99
100         return NULL;
101 }
102
103 INTERN void
104 tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
105                                         void *user_data)
106 {
107         tdm_private_capture *private_capture = user_data;
108         tdm_private_display *private_display = private_capture->private_display;
109         tdm_capture_private_buffer *capture_buffer = NULL, *first_entry = NULL;
110
111         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
112
113         if (private_capture->owner_tid != syscall(SYS_gettid)) {
114                 tdm_thread_cb_capture_done capture_done;
115                 tdm_error ret;
116
117                 capture_done.base.type = TDM_THREAD_CB_CAPTURE_DONE;
118                 capture_done.base.length = sizeof capture_done;
119                 capture_done.capture_stamp = private_capture->stamp;
120                 capture_done.buffer = buffer;
121                 capture_done.user_data = user_data;
122
123                 ret = tdm_thread_send_cb(private_display->private_loop, &capture_done.base);
124                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
125
126                 return;
127         }
128
129         if (private_capture->owner_tid != syscall(SYS_gettid))
130                 TDM_NEVER_GET_HERE();
131
132         if (tdm_debug_dump & TDM_DUMP_FLAG_CAPTURE) {
133                 /* LCOV_EXCL_START */
134                 char str[TDM_PATH_LEN];
135                 static int i;
136                 snprintf(str, TDM_PATH_LEN, "capture_%03d", i++);
137                 tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str);
138                 /* LCOV_EXCL_STOP */
139         }
140
141         if (tdm_debug_module & TDM_DEBUG_BUFFER)
142                 TDM_INFO("capture(%p) done: %p", private_capture, buffer);
143
144         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
145                 tbm_bo bo = tbm_surface_internal_get_bo(buffer, 0);
146                 TDM_TRACE_ASYNC_END((intptr_t)private_capture, "[CAPTURE] %d", tbm_bo_export(bo));
147         }
148
149         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
150                 first_entry = container_of((&private_capture->buffer_list)->next, capture_buffer, link);
151                 if (first_entry->buffer != buffer)
152                         TDM_ERR("buffer(%p) is skipped", first_entry->buffer);
153         } else {
154                 TDM_NEVER_GET_HERE();
155         }
156
157         if ((capture_buffer = _tdm_capture_find_tbm_buffer(&private_capture->buffer_list, buffer))) {
158                 LIST_DEL(&capture_buffer->link);
159                 LIST_DELINIT(&capture_buffer->commit_link);
160
161                 _pthread_mutex_unlock(&private_display->lock);
162                 if (private_capture->done_func)
163                         private_capture->done_func(capture_buffer, buffer, private_capture->done_user_data);
164                 tdm_buffer_unref_backend(buffer);
165                 _pthread_mutex_lock(&private_display->lock);
166
167                 free(capture_buffer);
168         }
169 }
170
171 INTERN tdm_private_capture *
172 tdm_capture_find_stamp(tdm_private_display *private_display, double stamp)
173 {
174         tdm_private_capture *private_capture = NULL;
175
176         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
177
178         LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, display_link) {
179                 if (private_capture->stamp == stamp)
180                         return private_capture;
181         }
182
183         return NULL;
184 }
185
186 INTERN tdm_private_capture *
187 tdm_capture_create_output_internal(tdm_private_output *private_output,
188                                                                    tdm_error *error)
189 {
190         tdm_private_display *private_display = private_output->private_display;
191         tdm_func_output *func_output = &private_display->func_output;
192         tdm_func_capture *func_capture = &private_display->func_capture;
193         tdm_private_capture *private_capture = NULL;
194         tdm_capture *capture_backend = NULL;
195         tdm_error ret = TDM_ERROR_NONE;
196
197         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
198
199         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
200                 /* LCOV_EXCL_START */
201                 TDM_ERR("no capture capability");
202                 if (error)
203                         *error = TDM_ERROR_NO_CAPABILITY;
204                 return NULL;
205                 /* LCOV_EXCL_STOP */
206         }
207
208         if (!(private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT)) {
209                 /* LCOV_EXCL_START */
210                 TDM_ERR("no output capture capability");
211                 if (error)
212                         *error = TDM_ERROR_NO_CAPABILITY;
213                 return NULL;
214                 /* LCOV_EXCL_STOP */
215         }
216
217         capture_backend = func_output->output_create_capture(
218                                                   private_output->output_backend, &ret);
219         if (ret != TDM_ERROR_NONE) {
220                 /* LCOV_EXCL_START */
221                 if (error)
222                         *error = ret;
223                 return NULL;
224                 /* LCOV_EXCL_STOP */
225         }
226
227         private_capture = calloc(1, sizeof(tdm_private_capture));
228         if (!private_capture) {
229                 /* LCOV_EXCL_START */
230                 TDM_ERR("failed: alloc memory");
231                 func_capture->capture_destroy(capture_backend);
232                 if (error)
233                         *error = TDM_ERROR_OUT_OF_MEMORY;
234                 return NULL;
235                 /* LCOV_EXCL_STOP */
236         }
237
238         ret = func_capture->capture_set_done_handler(capture_backend,
239                         tdm_capture_cb_done, private_capture);
240         if (ret != TDM_ERROR_NONE) {
241                 /* LCOV_EXCL_START */
242                 TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
243                 func_capture->capture_destroy(capture_backend);
244                 if (error)
245                         *error = ret;
246                 return NULL;
247                 /* LCOV_EXCL_STOP */
248         }
249
250         private_capture->stamp = tdm_helper_get_time();
251         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
252                 private_capture->stamp++;
253
254         LIST_ADD(&private_capture->link, &private_output->capture_list);
255         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
256
257         private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
258         private_capture->private_display = private_display;
259         private_capture->private_output = private_output;
260         private_capture->private_layer = NULL;
261         private_capture->capture_backend = capture_backend;
262         private_capture->owner_tid = syscall(SYS_gettid);
263
264         LIST_INITHEAD(&private_capture->pending_buffer_list);
265         LIST_INITHEAD(&private_capture->buffer_list);
266
267         TDM_DBG("capture(%p) create", private_capture);
268
269         if (error)
270                 *error = TDM_ERROR_NONE;
271
272         return private_capture;
273 }
274
275 /* LCOV_EXCL_START */
276 INTERN tdm_private_capture *
277 tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
278                                                                   tdm_error *error)
279 {
280         tdm_private_output *private_output = private_layer->private_output;
281         tdm_private_display *private_display = private_output->private_display;
282         tdm_func_layer *func_layer = &private_display->func_layer;
283         tdm_func_capture *func_capture = &private_display->func_capture;
284         tdm_private_capture *private_capture = NULL;
285         tdm_capture *capture_backend = NULL;
286         tdm_error ret = TDM_ERROR_NONE;
287
288         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
289
290         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
291                 TDM_ERR("no capture capability");
292                 if (error)
293                         *error = TDM_ERROR_NO_CAPABILITY;
294                 return NULL;
295         }
296
297         if (!(private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER)) {
298                 TDM_ERR("no layer capture capability");
299                 if (error)
300                         *error = TDM_ERROR_NO_CAPABILITY;
301                 return NULL;
302         }
303
304         capture_backend = func_layer->layer_create_capture(private_layer->layer_backend,
305                                           &ret);
306         if (ret != TDM_ERROR_NONE)
307                 return NULL;
308
309         private_capture = calloc(1, sizeof(tdm_private_capture));
310         if (!private_capture) {
311                 TDM_ERR("failed: alloc memory");
312                 func_capture->capture_destroy(capture_backend);
313                 if (error)
314                         *error = TDM_ERROR_OUT_OF_MEMORY;
315                 return NULL;
316         }
317
318         private_capture->stamp = tdm_helper_get_time();
319         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
320                 private_capture->stamp++;
321
322         LIST_ADD(&private_capture->link, &private_layer->capture_list);
323         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
324
325         private_capture->target = TDM_CAPTURE_TARGET_LAYER;
326         private_capture->private_display = private_display;
327         private_capture->private_output = private_output;
328         private_capture->private_layer = private_layer;
329         private_capture->capture_backend = capture_backend;
330         private_capture->owner_tid = syscall(SYS_gettid);
331
332         LIST_INITHEAD(&private_capture->pending_buffer_list);
333         LIST_INITHEAD(&private_capture->buffer_list);
334
335         TDM_DBG("capture(%p) create", private_capture);
336
337         if (error)
338                 *error = TDM_ERROR_NONE;
339
340         return private_capture;
341 }
342 /* LCOV_EXCL_STOP */
343
344 INTERN void
345 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
346 {
347         tdm_private_display *private_display;
348         tdm_func_capture *func_capture;
349         tdm_capture_private_buffer *b = NULL, *bb = NULL;
350         struct list_head clone_list;
351
352         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
353
354         if (!private_capture)
355                 return;
356
357         private_display = private_capture->private_display;
358
359         LIST_DEL(&private_capture->link);
360         LIST_DEL(&private_capture->display_link);
361
362         func_capture = &private_capture->private_display->func_capture;
363         func_capture->capture_destroy(private_capture->capture_backend);
364
365         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
366                 TDM_WRN("capture(%p) not finished:", private_capture);
367                 _tdm_capture_print_list(&private_capture->pending_buffer_list);
368
369                 LIST_INITHEAD(&clone_list);
370                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
371                         LIST_DEL(&b->link);
372                         LIST_ADDTAIL(&b->link, &clone_list);
373                 }
374
375                 _pthread_mutex_unlock(&private_display->lock);
376                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &clone_list, link) {
377                         LIST_DEL(&b->link);
378
379                         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
380                                 tbm_bo bo = tbm_surface_internal_get_bo(b->buffer, 0);
381                                 TDM_TRACE_ASYNC_END((intptr_t)private_capture, "[CAPTURE] %d", tbm_bo_export(bo));
382                         }
383
384                         tdm_buffer_unref_backend(b->buffer);
385                         free(b);
386                 }
387                 _pthread_mutex_lock(&private_display->lock);
388         }
389
390         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
391                 TDM_WRN("capture(%p) not finished:", private_capture);
392                 _tdm_capture_print_list(&private_capture->buffer_list);
393
394                 LIST_INITHEAD(&clone_list);
395                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) {
396                         LIST_DEL(&b->link);
397                         LIST_ADDTAIL(&b->link, &clone_list);
398                 }
399
400                 _pthread_mutex_unlock(&private_display->lock);
401                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &clone_list, link) {
402                         LIST_DEL(&b->link);
403
404                         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
405                                 tbm_bo bo = tbm_surface_internal_get_bo(b->buffer, 0);
406                                 TDM_TRACE_ASYNC_END((intptr_t)private_capture, "[CAPTURE] %d", tbm_bo_export(bo));
407                         }
408
409                         tdm_buffer_unref_backend(b->buffer);
410                         free(b);
411                 }
412                 _pthread_mutex_lock(&private_display->lock);
413         }
414
415         private_capture->stamp = 0;
416         free(private_capture);
417 }
418
419 EXTERN void
420 tdm_capture_destroy(tdm_capture *capture)
421 {
422         tdm_private_capture *private_capture = capture;
423         tdm_private_display *private_display;
424
425         if (!private_capture)
426                 return;
427
428         TDM_DBG("capture(%p) destroy", private_capture);
429
430         private_display = private_capture->private_display;
431
432         _pthread_mutex_lock(&private_display->lock);
433         tdm_capture_destroy_internal(private_capture);
434         _pthread_mutex_unlock(&private_display->lock);
435 }
436
437 EXTERN tdm_error
438 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
439 {
440         CAPTURE_FUNC_ENTRY();
441
442         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
443         TDM_RETURN_VAL_IF_FAIL(info->type != 0, TDM_ERROR_INVALID_PARAMETER);
444
445         _pthread_mutex_lock(&private_display->lock);
446
447         if (!func_capture->capture_set_info) {
448                 /* LCOV_EXCL_START */
449                 _pthread_mutex_unlock(&private_display->lock);
450                 TDM_DBG("failed: not implemented!!");
451                 return TDM_ERROR_NOT_IMPLEMENTED;
452                 /* LCOV_EXCL_STOP */
453         }
454
455         if (info->type == TDM_CAPTURE_TYPE_STREAM && info->frequency == 0) {
456                 tdm_private_output *private_output = private_capture->private_output;
457                 info->frequency = private_output->current_mode->vrefresh;
458         }
459
460         TDM_INFO("capture(%p) info: dst(%ux%u %u,%u %ux%u %c%c%c%c) trans(%d) type(%d) freq(%d) flags(%x)",
461                          private_capture,
462                          info->dst_config.size.h, info->dst_config.size.v,
463                          info->dst_config.pos.x, info->dst_config.pos.y,
464                          info->dst_config.pos.w, info->dst_config.pos.h,
465                          FOURCC_STR(info->dst_config.format),
466                          info->transform, info->type, info->frequency, info->flags);
467
468         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
469         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
470
471         private_capture->info = *info;
472
473         _pthread_mutex_unlock(&private_display->lock);
474
475         return ret;
476 }
477
478 EXTERN tdm_error
479 tdm_capture_set_done_handler(tdm_capture *capture, tdm_capture_done_handler func, void *user_data)
480 {
481         tdm_private_display *private_display;
482         tdm_private_capture *private_capture;
483         tdm_error ret = TDM_ERROR_NONE;
484
485         TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER);
486
487         private_capture = (tdm_private_capture*)capture;
488         private_display = private_capture->private_display;
489
490         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
491
492         _pthread_mutex_lock(&private_display->lock);
493
494         private_capture->done_func = func;
495         private_capture->done_user_data = user_data;
496
497         _pthread_mutex_unlock(&private_display->lock);
498
499         return ret;
500 }
501
502 EXTERN tdm_error
503 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
504 {
505         tdm_capture_private_buffer *capture_buffer;
506
507         CAPTURE_FUNC_ENTRY();
508
509         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
510
511         _pthread_mutex_lock(&private_display->lock);
512
513         if (!func_capture->capture_attach) {
514                 /* LCOV_EXCL_START */
515                 _pthread_mutex_unlock(&private_display->lock);
516                 TDM_DBG("failed: not implemented!!");
517                 return TDM_ERROR_NOT_IMPLEMENTED;
518                 /* LCOV_EXCL_STOP */
519         }
520
521         if (tdm_display_check_module_abi(private_display, 1, 2) &&
522                 private_display->caps_capture.max_attach_count > 0) {
523                 /* LCOV_EXCL_START */
524                 int length = LIST_LENGTH(&private_capture->pending_buffer_list) +
525                                          LIST_LENGTH(&private_capture->buffer_list);
526                 if (length >= private_display->caps_capture.max_attach_count) {
527                         _pthread_mutex_unlock(&private_display->lock);
528                         TDM_DBG("failed: too many attached!! max_attach_count(%d)",
529                                         private_display->caps_capture.max_attach_count);
530                         return TDM_ERROR_BAD_REQUEST;
531                 }
532                 /* LCOV_EXCL_STOP */
533         }
534
535         capture_buffer = calloc(1, sizeof * capture_buffer);
536         if (!capture_buffer) {
537                 /* LCOV_EXCL_START */
538                 _pthread_mutex_unlock(&private_display->lock);
539                 TDM_ERR("alloc failed");
540                 return TDM_ERROR_OUT_OF_MEMORY;
541                 /* LCOV_EXCL_STOP */
542         }
543
544         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
545         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
546
547         if (ret != TDM_ERROR_NONE) {
548                 /* LCOV_EXCL_START */
549                 free(capture_buffer);
550                 _pthread_mutex_unlock(&private_display->lock);
551                 TDM_ERR("attach failed");
552                 return ret;
553                 /* LCOV_EXCL_STOP */
554         }
555
556         LIST_ADDTAIL(&capture_buffer->link, &private_capture->pending_buffer_list);
557         capture_buffer->buffer = tdm_buffer_ref_backend(buffer);
558
559         if (tdm_debug_module & TDM_DEBUG_BUFFER) {
560                 TDM_INFO("capture(%p) attached:", private_capture);
561                 tdm_buffer_list_dump(&private_capture->buffer_list);
562         }
563
564         if (tdm_ttrace_module & TDM_TTRACE_CAPTURE) {
565                 tbm_bo bo = tbm_surface_internal_get_bo(buffer, 0);
566                 TDM_TRACE_ASYNC_BEGIN((intptr_t)capture, "[CAPTURE] %d", tbm_bo_export(bo));
567         }
568
569         _pthread_mutex_unlock(&private_display->lock);
570
571         return ret;
572 }
573
574 EXTERN tdm_error
575 tdm_capture_commit(tdm_capture *capture)
576 {
577         tdm_capture_private_buffer *b = NULL, *bb = NULL;
578         tdm_private_output *private_output;
579         struct list_head commit_buffer_list;
580
581         CAPTURE_FUNC_ENTRY();
582
583         _pthread_mutex_lock(&private_display->lock);
584
585         private_output = private_capture->private_output;
586
587         /* TODO: possible when standby mode? can't decide it yet. no scenario. */
588         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
589                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
590                                 tdm_dpms_str(private_output->current_dpms_value));
591                 _pthread_mutex_unlock(&private_display->lock);
592                 return TDM_ERROR_BAD_REQUEST;
593         }
594
595         if (!func_capture->capture_commit) {
596                 /* LCOV_EXCL_START */
597                 _pthread_mutex_unlock(&private_display->lock);
598                 TDM_DBG("failed: not implemented!!");
599                 return TDM_ERROR_NOT_IMPLEMENTED;
600                 /* LCOV_EXCL_STOP */
601         }
602
603         LIST_INITHEAD(&commit_buffer_list);
604
605         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
606                 LIST_DEL(&b->link);
607                 LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
608                 LIST_ADDTAIL(&b->commit_link, &commit_buffer_list);
609         }
610
611         ret = func_capture->capture_commit(private_capture->capture_backend);
612         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
613
614         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &commit_buffer_list, commit_link) {
615                 LIST_DELINIT(&b->commit_link);
616
617                 if (!_tdm_capture_find_buffer(&private_capture->buffer_list, b))
618                         continue;
619
620                 if (ret != TDM_ERROR_NONE) {
621                         /* LCOV_EXCL_START */
622                         /* Not to call the user release handler when failed.
623                          * Do we have to call this function here really?
624                          * User better use set_done_handler to know when pp is done. Using
625                          * buffer_release_handler is not good.
626                          */
627                         tdm_buffer_remove_release_handler_internal(b->buffer);
628
629                         _pthread_mutex_unlock(&private_display->lock);
630                         tdm_buffer_unref_backend(b->buffer);
631                         _pthread_mutex_lock(&private_display->lock);
632                         LIST_DEL(&b->link);
633
634                         free(b);
635                         /* LCOV_EXCL_STOP */
636                 }
637         }
638
639         _pthread_mutex_unlock(&private_display->lock);
640
641         return ret;
642 }