c46fcb7b9920cbef9bff41bc73a060c122333dfe
[platform/core/api/mediavision.git] / test / testsuites / common / video_helper / mv_video_helper.c
1 /**
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "mv_common.h"
18 #include "mv_video_helper.h"
19
20 #include "mv_log_cfg.h"
21
22 #include <string.h>
23 #include <stdio.h>
24
25 #include <gst/gst.h>
26 #include <gst/app/gstappsink.h>
27 #include <gst/video/video.h>
28
29 #include <pthread.h>
30
31 typedef struct _mv_video_reader_s {
32         /* Main bin */
33         GstElement *pl;
34
35         /* Pipeline structure */
36         GstElement *filesrc;
37         GstElement *decodebin;
38         GstElement *videoconvert;
39         GstElement *queue;
40         GstElement *appsink;
41
42         void *new_sample_cb_user_data;
43         void *eos_cb_user_data;
44
45         GstCaps *caps;
46         gulong pad_probe_id;
47
48         pthread_spinlock_t new_sample_cb_guard;
49         pthread_spinlock_t eos_cb_guard;
50
51         mv_video_reader_new_sample_cb new_sample_cb;
52         mv_video_reader_eos_cb eos_cb;
53 } mv_video_reader_s;
54
55 typedef struct _mv_video_writer_s {
56         /* Main bin */
57         GstElement *pl;
58
59         /* Pipeline structure */
60         GstElement *appsrc;
61         GstElement *capsfilter;
62         GstElement *videoconvert;
63         GstElement *encoder;
64         GstElement *queue;
65         GstElement *muxer;
66         GstElement *filesink;
67
68         image_data_s image_data;
69         unsigned int fps;
70         unsigned int buffer_size;
71 } mv_video_writer_s;
72
73 /* video reader internal funcitons */
74 static int _mv_video_reader_create_internals(mv_video_reader_s *reader);
75 static int _mv_video_reader_link_internals(mv_video_reader_s *reader);
76 static int _mv_video_reader_state_change(mv_video_reader_s *reader, GstState state);
77
78 /* video writer internal funciton */
79 static int _mv_video_writer_create_internals(mv_video_writer_s *writer);
80 static int _mv_video_writer_link_internals(mv_video_writer_s *writer);
81 static int _mv_video_writer_state_change(mv_video_writer_s *writer, GstState state);
82
83 static void appsink_eos(GstAppSink *appsink, gpointer user_data);
84 static GstFlowReturn appsink_newsample(GstAppSink *appsink, gpointer user_data);
85 static void cb_newpad(GstElement *decodebin, GstPad *new_pad, gpointer user_data);
86
87 static GstPadProbeReturn pad_probe_data_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
88
89 /* video reader */
90 int mv_create_video_reader(
91                 mv_video_reader_h *reader)
92 {
93         mv_video_reader_s *handle = NULL;
94         int err = MEDIA_VISION_ERROR_NONE;
95
96         if (reader == NULL) {
97                 LOGE("NULL pointer passed");
98                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
99         }
100
101         gst_init(NULL, NULL);
102
103         handle = (mv_video_reader_s *) malloc(sizeof(mv_video_reader_s));
104         if (!handle) {
105                 LOGE("Not enough memory");
106                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
107         }
108         memset(handle, 0, sizeof(mv_video_reader_s));
109
110         err = _mv_video_reader_create_internals(handle);
111         if (MEDIA_VISION_ERROR_NONE != err) {
112                 LOGE("Failed to create internals");
113                 free(handle);
114                 return err;
115         }
116
117         err = _mv_video_reader_link_internals(handle);
118         if (MEDIA_VISION_ERROR_NONE != err) {
119                 LOGE("Failed to link internals");
120                 free(handle);
121                 return err;
122         }
123
124         *reader = (mv_video_reader_s *) handle;
125
126         return err;
127 }
128
129 int mv_destroy_video_reader(
130                 mv_video_reader_h reader)
131 {
132         mv_video_reader_s *handle = NULL;
133
134         if (reader == NULL) {
135                 LOGE("NULL pointer passed");
136                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
137         }
138
139         handle = (mv_video_reader_s *) reader;
140
141         if (handle->caps && GST_OBJECT_REFCOUNT(handle->caps))
142                 gst_caps_unref(handle->caps);
143
144         if (handle->pl)
145                 gst_object_unref(handle->pl);
146
147         handle->pl = NULL;
148
149         pthread_spin_destroy(&(handle->new_sample_cb_guard));
150         pthread_spin_destroy(&(handle->eos_cb_guard));
151
152         LOGD("video reader destroyed %p", handle);
153
154         free(handle);
155
156         return MEDIA_VISION_ERROR_NONE;
157 }
158
159 int mv_video_reader_load(
160                 mv_video_reader_h reader,
161                 const char *path,
162                 image_data_s *image_data,
163                 unsigned int *fps)
164 {
165         mv_video_reader_s *handle = NULL;
166         GstVideoInfo info;
167
168         if (reader == NULL || path == NULL ||
169                 image_data == NULL || fps == NULL) {
170                 LOGE("NULL pointer passed");
171                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
172         }
173
174         handle = (mv_video_reader_s *) reader;
175
176         /* Set input file location from path */
177         g_object_set(G_OBJECT(handle->filesrc),
178                                 "location", path,
179                                 NULL);
180
181         /* Start playback */
182         if (_mv_video_reader_state_change(handle, GST_STATE_PLAYING)) {
183                 LOGE("Unable to change state");
184                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
185         }
186
187         if (_mv_video_reader_state_change(handle, GST_STATE_PAUSED)) {
188                 LOGE("Unable to change state");
189                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
190         }
191
192         if (handle->caps == NULL) {
193                 LOGE("Unable to get caps from decodebin");
194                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
195         }
196
197         gst_video_info_from_caps(&info, handle->caps);
198
199         gst_caps_unref(handle->caps);
200
201         *fps = info.fps_n/info.fps_d;
202
203         /* Fill image data */
204         image_data->image_width = info.width;
205         image_data->image_height = info.height;
206
207         /* Look to :
208          * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoFormat */
209         switch (GST_VIDEO_FORMAT_INFO_FORMAT(info.finfo)) {
210         case(GST_VIDEO_FORMAT_GRAY8):
211                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_Y800;
212                 break;
213         case(GST_VIDEO_FORMAT_I420):
214                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_I420;
215                 break;
216         case(GST_VIDEO_FORMAT_NV12):
217                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_NV12;
218                 break;
219         case(GST_VIDEO_FORMAT_YV12):
220                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_YV12;
221                 break;
222         case(GST_VIDEO_FORMAT_NV21):
223                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_NV21;
224                 break;
225         case(GST_VIDEO_FORMAT_YUY2):
226                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_YUYV;
227                 break;
228         case(GST_VIDEO_FORMAT_UYVY):
229                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_UYVY;
230                 break;
231         case(GST_VIDEO_FORMAT_RGB):
232                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_RGB888;
233                 break;
234         case(GST_VIDEO_FORMAT_RGBA):
235                 image_data->image_colorspace = MEDIA_VISION_COLORSPACE_RGBA;
236                 break;
237         default:
238                 LOGE("Video pixel format is not supported\n");
239                 return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
240         }
241
242         return MEDIA_VISION_ERROR_NONE;
243 }
244
245 int mv_video_reader_start(
246                 mv_video_reader_h reader)
247 {
248         mv_video_reader_s *handle = NULL;
249
250         if (reader == NULL) {
251                 LOGE("NULL pointer passed");
252                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
253         }
254
255         handle = (mv_video_reader_s *) reader;
256
257         /* Start playback */
258         if (_mv_video_reader_state_change(handle, GST_STATE_PLAYING)) {
259                 LOGE("Unable to change state");
260                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
261         }
262
263         return MEDIA_VISION_ERROR_NONE;
264 }
265
266 int mv_video_reader_stop(
267                 mv_video_reader_h reader)
268 {
269         mv_video_reader_s *handle = NULL;
270
271         if (reader == NULL) {
272                 LOGE("NULL pointer passed");
273                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
274         }
275
276         handle = (mv_video_reader_s *) reader;
277
278         /* Stop playback (NULL or READY) */
279         if (_mv_video_reader_state_change(handle, GST_STATE_NULL)) {
280                 LOGE("Unable to change state");
281                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
282         }
283
284         return MEDIA_VISION_ERROR_NONE;
285 }
286
287 int mv_video_reader_set_new_sample_cb(
288                 mv_video_reader_h reader,
289                 mv_video_reader_new_sample_cb callback,
290                 void *user_data)
291 {
292         mv_video_reader_s *handle = NULL;
293
294         if (reader == NULL || callback == NULL) {
295                 LOGE("NULL pointer passed");
296                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
297         }
298
299         handle = (mv_video_reader_s *) reader;
300
301         pthread_spin_lock(&(handle->new_sample_cb_guard));
302         handle->new_sample_cb = callback;
303         handle->new_sample_cb_user_data = user_data;
304         pthread_spin_unlock(&(handle->new_sample_cb_guard));
305
306         return MEDIA_VISION_ERROR_NONE;
307 }
308
309 int mv_video_reader_set_eos_cb(
310                 mv_video_reader_h reader,
311                 mv_video_reader_eos_cb callback,
312                 void *user_data)
313 {
314         mv_video_reader_s *handle = NULL;
315
316         if (reader == NULL || callback == NULL) {
317                 LOGE("NULL pointer passed");
318                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
319         }
320
321         handle = (mv_video_reader_s *) reader;
322
323         pthread_spin_lock(&(handle->eos_cb_guard));
324         handle->eos_cb = callback;
325         handle->eos_cb_user_data = user_data;
326         pthread_spin_unlock(&(handle->eos_cb_guard));
327
328         return MEDIA_VISION_ERROR_NONE;
329 }
330
331 /* Video Writer */
332 int mv_create_video_writer(
333                 mv_video_writer_h *writer)
334 {
335         mv_video_writer_s *handle = NULL;
336         int err = MEDIA_VISION_ERROR_NONE;
337
338         if (writer == NULL) {
339                 LOGE("NULL pointer passed");
340                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
341         }
342
343         gst_init(NULL, NULL);
344
345         handle = (mv_video_writer_s *) malloc(sizeof(mv_video_writer_s));
346         if (!handle) {
347                 LOGE("Not enough memory");
348                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
349         }
350         memset(handle, 0, sizeof(mv_video_writer_s));
351
352         err = _mv_video_writer_create_internals(handle);
353         if (MEDIA_VISION_ERROR_NONE != err) {
354                 LOGE("Failed to create internals");
355                 free(handle);
356                 return err;
357         }
358
359         *writer = (mv_video_writer_s *) handle;
360
361         return err;
362 }
363
364 int mv_destroy_video_writer(
365                 mv_video_writer_h writer)
366 {
367         mv_video_writer_s *handle = NULL;
368
369         if (writer == NULL) {
370                 LOGE("NULL pointer passed");
371                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
372         }
373
374         handle = (mv_video_writer_s *) writer;
375
376         _mv_video_writer_state_change(writer, GST_STATE_NULL);
377
378         if (handle->pl)
379                 gst_object_unref(handle->pl);
380
381         handle->pl = NULL;
382
383         LOGD("video writer destroyed %p", handle);
384
385         free(handle);
386
387         return MEDIA_VISION_ERROR_NONE;
388 }
389
390 int mv_video_writer_init(
391                 mv_video_writer_h writer,
392                 const char *path,
393                 image_data_s image_data,
394                 unsigned int fps)
395 {
396         mv_video_writer_s *handle = NULL;
397         unsigned int err = MEDIA_VISION_ERROR_NONE;
398
399         if (writer == NULL) {
400                 LOGE("NULL pointer passed");
401                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
402         }
403
404         handle = (mv_video_writer_s *) writer;
405
406         handle->image_data.image_width = image_data.image_width;
407         handle->image_data.image_height = image_data.image_height;
408         handle->image_data.image_colorspace = image_data.image_colorspace;
409
410         handle->fps = fps;
411
412         g_object_set(G_OBJECT(handle->filesink),
413                                         "location", path,
414                                         NULL);
415
416         err = _mv_video_writer_link_internals(handle);
417         if (MEDIA_VISION_ERROR_NONE != err) {
418                 LOGE("Failed to link internals");
419                 return err;
420         }
421
422         return err;
423 }
424
425 int mv_video_writer_write_frame(
426                 mv_video_writer_h writer,
427                 unsigned char *frame)
428 {
429         mv_video_writer_s *handle = NULL;
430         GstMapInfo info;
431         GstBuffer *buffer = NULL;
432
433         if (writer == NULL || frame == NULL) {
434                 LOGE("NULL pointer passed");
435                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
436         }
437
438         handle = (mv_video_writer_s *) writer;
439
440         buffer =  gst_buffer_new_allocate(NULL, handle->buffer_size, NULL);
441         if (!buffer) {
442                 LOGE("Unable to allocate buffer for frame");
443                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
444         }
445
446         LOGD("Copying input frame to buffer and pushing to appsrc");
447         gst_buffer_map(buffer, &info, GST_MAP_READWRITE);
448         memcpy(info.data, frame, info.size);
449         gst_buffer_unmap(buffer, &info);
450
451         if (GST_FLOW_OK !=
452                 gst_app_src_push_buffer(handle->appsrc, buffer)) {
453                 LOGE("Failed to push buffer to appsrc");
454                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
455         }
456
457         return MEDIA_VISION_ERROR_NONE;
458 }
459
460 /* Internal functions */
461 static int _mv_video_reader_create_internals(
462                 mv_video_reader_s *reader)
463 {
464         pthread_spin_init(&(reader->new_sample_cb_guard), PTHREAD_PROCESS_SHARED);
465         pthread_spin_init(&(reader->eos_cb_guard), PTHREAD_PROCESS_SHARED);
466
467         reader->pl = gst_pipeline_new(NULL);
468
469         reader->filesrc = gst_element_factory_make("filesrc", "filesrc");
470         reader->decodebin = gst_element_factory_make("decodebin", "decoder");
471         reader->videoconvert = gst_element_factory_make("videoconvert", "convert");
472         reader->queue = gst_element_factory_make("queue", "queue");
473         reader->appsink = gst_element_factory_make("appsink", "appsink");
474
475         if ((!reader->pl) ||
476                 (!reader->filesrc) ||
477                 (!reader->decodebin) ||
478                 (!reader->videoconvert) ||
479                 (!reader->queue) ||
480                 (!reader->appsink)) {
481                 LOGE("Unable to create video read pipeline elements");
482                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
483         }
484
485         gst_bin_add_many(GST_BIN(reader->pl),
486                                         reader->filesrc,
487                                         reader->decodebin,
488                                         reader->videoconvert,
489                                         reader->queue,
490                                         reader->appsink,
491                                         NULL);
492
493         return MEDIA_VISION_ERROR_NONE;
494 }
495
496 static int _mv_video_reader_link_internals(
497                 mv_video_reader_s *reader)
498 {
499         GstCaps *caps = NULL;
500         GstPad *pad = NULL;
501
502         if (!gst_element_link_many(reader->filesrc,
503                                 reader->decodebin,
504                                 NULL)) {
505                 LOGE("Unable to link filesrc to decodebin");
506                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
507         }
508
509         /* Decodebin pad will be linked during state change */
510         g_signal_connect(reader->decodebin,
511                                         "pad-added",
512                                         G_CALLBACK(cb_newpad),
513                                         reader);
514
515         if (!gst_element_link_many(reader->videoconvert,
516                         reader->queue,
517                         reader->appsink,
518                          NULL)) {
519                 LOGE("Unable to link videocovnert-queue-appsink");
520                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
521         }
522
523         caps = gst_caps_new_simple("video/x-raw",
524                                         "format", G_TYPE_STRING, "RGB",
525                                         NULL);
526
527         gst_app_sink_set_caps(GST_APP_SINK(reader->appsink), caps);
528         gst_caps_unref(caps);
529
530         /* Configure appsink */
531         gst_app_sink_set_emit_signals(GST_APP_SINK(reader->appsink), TRUE);
532         g_signal_connect(reader->appsink,
533                                         "new-sample",
534                                         G_CALLBACK(appsink_newsample),
535                                         reader);
536         g_signal_connect(reader->appsink,
537                                         "eos",
538                                         G_CALLBACK(appsink_eos),
539                                         reader);
540         g_object_set(G_OBJECT(reader->appsink),
541                                         "drop", TRUE,
542                                         "enable-last-sample", TRUE,
543                                         "sync", FALSE,
544                                         NULL);
545
546
547         /* pad probe */
548         pad = gst_element_get_static_pad(reader->queue, "src");
549
550         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
551                                         (GstPadProbeCallback)pad_probe_data_cb, reader, NULL);
552         gst_object_unref(pad);
553
554         return MEDIA_VISION_ERROR_NONE;
555 }
556
557 static int _mv_video_reader_state_change(
558                 mv_video_reader_s *reader,
559                 GstState state)
560 {
561         mv_video_reader_s *handle = (mv_video_reader_s *) reader;
562         GstStateChangeReturn state_ret = GST_STATE_CHANGE_FAILURE;
563         GstState pipeline_state = GST_STATE_NULL;
564
565         state_ret = gst_element_set_state(handle->pl,
566                                                 state);
567
568         if (GST_STATE_CHANGE_FAILURE == state_ret) {
569                 LOGE("Set state failure");
570                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
571         }
572
573         LOGI("Set state [%d], change return [%d]",
574                 state, state_ret);
575
576         state_ret = gst_element_get_state(handle->pl,
577                                         &pipeline_state,
578                                         NULL,
579                                         GST_CLOCK_TIME_NONE);
580
581         if (GST_STATE_CHANGE_FAILURE == state_ret) {
582                 LOGE("get state failure");
583                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
584         }
585
586         return MEDIA_VISION_ERROR_NONE;
587 }
588
589 static int _mv_video_writer_create_internals(
590                 mv_video_writer_s *writer)
591 {
592         writer->pl = gst_pipeline_new(NULL);
593
594         writer->appsrc = gst_element_factory_make("appsrc", "appsrc");
595         writer->capsfilter = gst_element_factory_make("capsfilter", NULL);
596         writer->videoconvert = gst_element_factory_make("videoconvert", "videoconvert");
597         writer->encoder = gst_element_factory_make("avenc_mpeg4", "encoder");
598         writer->queue = gst_element_factory_make("queue", "queue");
599         writer->muxer = gst_element_factory_make("avmux_avi", "muxer");
600         writer->filesink = gst_element_factory_make("filesink", "filesink");
601
602         if ((!writer->pl) ||
603                 (!writer->appsrc) ||
604                 (!writer->capsfilter) ||
605                 (!writer->videoconvert) ||
606                 (!writer->encoder) ||
607                 (!writer->queue) ||
608                 (!writer->muxer) ||
609                 (!writer->filesink)) {
610                 LOGE("Unable to create video read pipeline elements\n");
611                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
612         }
613
614         gst_bin_add_many(GST_BIN(writer->pl),
615                         writer->appsrc,
616                         writer->capsfilter,
617                         writer->videoconvert,
618                         writer->encoder,
619                         writer->queue,
620                         writer->muxer,
621                         writer->filesink,
622                         NULL);
623
624         return MEDIA_VISION_ERROR_NONE;
625 }
626
627 static int _mv_video_writer_link_internals(
628                 mv_video_writer_s *writer)
629 {
630         GstVideoInfo vinfo;
631         GstCaps *caps = NULL;
632         char format[6] = {0};
633
634         /* Convert from mv_colorspace to GstVideoFormat */
635         switch (writer->image_data.image_colorspace) {
636         case(MEDIA_VISION_COLORSPACE_Y800):
637                 strncpy(format, "GRAY8", 5);
638                 break;
639         case(MEDIA_VISION_COLORSPACE_I420):
640                 strncpy(format, "I420", 4);
641                 break;
642         case(MEDIA_VISION_COLORSPACE_NV12):
643                 strncpy(format, "NV12", 4);
644                 break;
645         case(MEDIA_VISION_COLORSPACE_YV12):
646                 strncpy(format, "YV12", 4);
647                 break;
648         case(MEDIA_VISION_COLORSPACE_NV21):
649                 strncpy(format, "NV21", 4);
650                 break;
651         case(MEDIA_VISION_COLORSPACE_YUYV):
652                 strncpy(format, "YUY2", 4);
653                 break;
654         case(MEDIA_VISION_COLORSPACE_UYVY):
655                 strncpy(format, "UYVY", 4);
656                 break;
657         case(MEDIA_VISION_COLORSPACE_RGB888):
658                 strncpy(format, "RGB", 3);
659                 break;
660         case(MEDIA_VISION_COLORSPACE_RGBA):
661                 strncpy(format, "RGBA", 4);
662                 break;
663         default:
664                 LOGE("Selected format %d is not supported",
665                                 writer->image_data.image_colorspace);
666                 return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
667         }
668
669         caps = gst_caps_new_simple("video/x-raw",
670                                 "format", G_TYPE_STRING, format,
671                                 "width", G_TYPE_INT, writer->image_data.image_width,
672                                 "height", G_TYPE_INT, writer->image_data.image_height,
673                                 "framerate", GST_TYPE_FRACTION, writer->fps, 1,
674                                 NULL);
675
676         if (NULL == caps) {
677                 LOGE("Failed to create new caps");
678                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
679         }
680
681         /* This is the simpler way to get buffer size */
682         if (!gst_video_info_from_caps(&vinfo, caps)) {
683                 LOGE("Unable to set buffer size");
684                 gst_caps_unref(caps);
685                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
686         }
687
688         writer->buffer_size = vinfo.size;
689
690         /* link appsrc and capsfilter */
691         if ((!gst_element_link_filtered(writer->appsrc,
692                                         writer->capsfilter,
693                                         caps))) {
694                 LOGE("Failed to link appsrc to capsfilter");
695                 gst_caps_unref(caps);
696                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
697         }
698         gst_caps_unref(caps);
699
700         if (!gst_element_link_many(writer->capsfilter,
701                                 writer->videoconvert,
702                                 writer->encoder,
703                                 writer->queue,
704                                 writer->muxer,
705                                 writer->filesink,
706                                 NULL)) {
707                 LOGE("Unable to capsfilter to filesink");
708                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
709         }
710
711         g_object_set(G_OBJECT(writer->appsrc),
712                                 "max-bytes", 0,
713                                 "blocksize", writer->buffer_size,
714                                 "stream-type", 0,
715                                 "format", GST_FORMAT_BYTES,
716                                 NULL);
717
718         if (_mv_video_writer_state_change(writer,
719                                         GST_STATE_PLAYING)) {
720                         LOGE("Unable to change video writer state");
721                         return MEDIA_VISION_ERROR_INVALID_OPERATION;
722         }
723
724         return MEDIA_VISION_ERROR_NONE;
725 }
726
727 static int _mv_video_writer_state_change(
728                 mv_video_writer_s *writer,
729                 GstState state)
730 {
731         mv_video_writer_s *handle = (mv_video_writer_s *) writer;
732         GstStateChangeReturn state_ret = GST_STATE_CHANGE_FAILURE;
733         GstState pipeline_state = GST_STATE_NULL;
734
735         state_ret = gst_element_set_state(handle->pl,
736                                                                 state);
737
738         if (GST_STATE_CHANGE_FAILURE == state_ret) {
739                 LOGE("Set state failure");
740                 return MEDIA_VISION_ERROR_INVALID_OPERATION;
741         }
742
743         LOGI("Set state [%d], change return [%d]",
744                         state, state_ret);
745
746         /* AppSrc can't go to PLAYING state before buffer is not pushed */
747
748         return MEDIA_VISION_ERROR_NONE;
749 }
750
751 /* Callbacks */
752 static GstFlowReturn appsink_newsample(
753                 GstAppSink *appsink,
754                 gpointer user_data)
755 {
756         mv_video_reader_s *handle = NULL;
757         GstSample *sample = gst_app_sink_pull_sample(appsink);
758
759         if (user_data == NULL) {
760                 LOGE("NULL pointer passed");
761                 return MEDIA_VISION_ERROR_INVALID_PARAMETER;
762         }
763
764         if (sample != NULL) {
765                 handle = (mv_video_reader_s *) user_data;
766                 GstVideoInfo vinfo;
767                 GstMapInfo info = GST_MAP_INFO_INIT;
768                 GstBuffer *buf = gst_sample_get_buffer(sample);
769                 GstCaps *caps = gst_sample_get_caps(sample);
770                 image_data_s im_data;
771                 char *buffer = NULL;
772                 unsigned int buffer_size = 0;
773
774                 LOGD("Received sample from appsink");
775
776                 /* map buffer */
777                 gst_buffer_map(buf, &info, GST_MAP_READ);
778                 buffer = (char *) info.data;
779
780                 /* Fill image data */
781                 gst_video_info_from_caps(&vinfo, caps);
782                 im_data.image_width = vinfo.width;
783                 im_data.image_height = vinfo.height;
784
785                 /* Look to :
786                  * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoFormat */
787                 switch (GST_VIDEO_FORMAT_INFO_FORMAT(vinfo.finfo)) {
788                 case(GST_VIDEO_FORMAT_GRAY8):
789                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_Y800;
790                         break;
791                 case(GST_VIDEO_FORMAT_I420):
792                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_I420;
793                         break;
794                 case(GST_VIDEO_FORMAT_NV12):
795                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_NV12;
796                         break;
797                 case(GST_VIDEO_FORMAT_YV12):
798                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_YV12;
799                         break;
800                 case(GST_VIDEO_FORMAT_NV21):
801                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_NV21;
802                         break;
803                 case(GST_VIDEO_FORMAT_YUY2):
804                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_YUYV;
805                         break;
806                 case(GST_VIDEO_FORMAT_UYVY):
807                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_UYVY;
808                         break;
809                 case(GST_VIDEO_FORMAT_RGB):
810                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGB888;
811                         break;
812                 case(GST_VIDEO_FORMAT_RGBA):
813                         im_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGBA;
814                         break;
815                 default:
816                         LOGE("Video pixel format is not supported\n");
817                         gst_buffer_unmap(buf, &info);
818                         gst_sample_unref(sample);
819                         return GST_FLOW_ERROR;
820                 }
821
822                 pthread_spin_lock(&(handle->new_sample_cb_guard));
823                 if (handle->new_sample_cb != NULL) {
824                         handle->new_sample_cb(
825                                 buffer,
826                                 info.size,
827                                 im_data,
828                                 handle->new_sample_cb_user_data);
829                 }
830                 pthread_spin_unlock(&(handle->new_sample_cb_guard));
831
832                 gst_buffer_unmap(buf, &info);
833                 gst_sample_unref(sample);
834         } else {
835                 LOGE("Failed to pull sample from appsink");
836                 return GST_FLOW_ERROR;
837         }
838
839         return GST_FLOW_OK;
840 }
841
842 static void appsink_eos(
843                 GstAppSink *appsink,
844                 gpointer user_data)
845 {
846         if (user_data == NULL) {
847                 LOGE("NULL pointer passed");
848                 return;
849         }
850
851         mv_video_reader_s *handle = (mv_video_reader_s *) user_data;
852
853         /* EOS callback to terminate reading */
854         pthread_spin_lock(&(handle->eos_cb_guard));
855         if (handle->eos_cb != NULL)
856                 handle->eos_cb(handle->eos_cb_user_data);
857
858         pthread_spin_unlock(&(handle->eos_cb_guard));
859
860
861         gst_pad_remove_probe(gst_element_get_static_pad(handle->queue, "src"), handle->pad_probe_id);
862 }
863
864 static void cb_newpad(
865                 GstElement *decodebin,
866                 GstPad *pad,
867                 gpointer user_data)
868 {
869         mv_video_reader_s *reader = (mv_video_reader_s *) user_data;
870         GstStructure *str = NULL;
871         GstCaps *caps = NULL;
872         GstPad *video_pad = NULL;
873
874         LOGI("Received pad from decodebin. Linking");
875         video_pad = gst_element_get_static_pad(reader->videoconvert, "sink");
876         if (GST_PAD_IS_LINKED(video_pad)) {
877                 LOGI("Already linked");
878                 g_object_unref(video_pad);
879                 return;
880         }
881
882         /* Check for pad is video */
883         caps = gst_pad_query_caps(pad, NULL);
884         str = gst_caps_get_structure(caps, 0);
885         if (!g_strrstr(gst_structure_get_name(str), "video")) {
886                 LOGI("Not a video pad");
887                 gst_object_unref(video_pad);
888                 return;
889         }
890         gst_caps_unref(caps);
891         gst_pad_link(pad, video_pad);
892         g_object_unref(video_pad);
893 }
894
895 static GstPadProbeReturn pad_probe_data_cb(
896         GstPad *pad,
897         GstPadProbeInfo *info,
898         gpointer user_data)
899 {
900         if (user_data == NULL)
901                 return GST_PAD_PROBE_PASS;
902
903         mv_video_reader_s *reader = (mv_video_reader_s *) user_data;
904
905         if (reader->caps == NULL) {
906                 reader->caps = gst_pad_get_current_caps(pad);
907                 reader->pad_probe_id = GST_PAD_PROBE_INFO_ID(info);
908         }
909
910         return GST_PAD_PROBE_OK;
911 }