diff options
Diffstat (limited to 'test/testsuites/common/video_helper/mv_video_helper.c')
-rw-r--r-- | test/testsuites/common/video_helper/mv_video_helper.c | 926 |
1 files changed, 926 insertions, 0 deletions
diff --git a/test/testsuites/common/video_helper/mv_video_helper.c b/test/testsuites/common/video_helper/mv_video_helper.c new file mode 100644 index 00000000..7674d917 --- /dev/null +++ b/test/testsuites/common/video_helper/mv_video_helper.c @@ -0,0 +1,926 @@ +/** + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mv_common.h" +#include "mv_video_helper.h" + +#include "mv_log_cfg.h" + +#include <string.h> +#include <stdio.h> + +#include <gst/gst.h> +#include <gst/app/gstappsink.h> +#include <gst/video/video.h> + +#include <pthread.h> + +typedef struct _mv_video_reader_s +{ + /* Main bin */ + GstElement *pl; + + /* Pipeline structure */ + GstElement *filesrc; + GstElement *decodebin; + GstElement *videoconvert; + GstElement *appsink; + + void *new_sample_cb_user_data; + void *eos_cb_user_data; + + GstCaps *caps; + + pthread_spinlock_t new_sample_cb_guard; + pthread_spinlock_t eos_cb_guard; + + mv_video_reader_new_sample_cb new_sample_cb; + mv_video_reader_eos_cb eos_cb; +} mv_video_reader_s; + +typedef struct _mv_video_writer_s +{ + /* Main bin */ + GstElement *pl; + + /* Pipeline structure */ + GstElement *appsrc; + GstElement *capsfilter; + GstElement *videoconvert; + GstElement *encoder; + GstElement *queue; + GstElement *muxer; + GstElement *filesink; + + image_data_s image_data; + unsigned int fps; + unsigned int buffer_size; +} mv_video_writer_s; + +/* video reader internal funcitons */ +static int _mv_video_reader_create_internals(mv_video_reader_s *reader); +static int _mv_video_reader_link_internals(mv_video_reader_s *reader); +static int _mv_video_reader_state_change(mv_video_reader_s *reader, GstState state); + +/* video writer internal funciton */ +static int _mv_video_writer_create_internals(mv_video_writer_s *writer); +static int _mv_video_writer_link_internals(mv_video_writer_s *writer); +static int _mv_video_writer_state_change(mv_video_writer_s *writer, GstState state); + +static void appsink_eos(GstAppSink *appsink, gpointer user_data); +static GstFlowReturn appsink_newsample(GstAppSink *appsink, gpointer user_data); +static void cb_newpad(GstElement *decodebin, GstPad *new_pad, gpointer user_data); + +/* video reader */ +int mv_create_video_reader( + mv_video_reader_h *reader) +{ + mv_video_reader_s *handle = NULL; + int err = MEDIA_VISION_ERROR_NONE; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + gst_init(NULL, NULL); + + handle = (mv_video_reader_s *) malloc(sizeof(mv_video_reader_s)); + if (!handle) + { + LOGE("Not enough memory"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + memset(handle, 0, sizeof(mv_video_reader_s)); + + err = _mv_video_reader_create_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to create internals"); + free(handle); + return err; + } + + err = _mv_video_reader_link_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to link internals"); + free(handle); + return err; + } + + *reader = (mv_video_reader_s *) handle; + + return err; +} + +int mv_destroy_video_reader( + mv_video_reader_h reader) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + if (handle->caps && GST_OBJECT_REFCOUNT(handle->caps)) + { + gst_caps_unref(handle->caps); + } + + if (handle->pl) + { + gst_object_unref(handle->pl); + } + handle->pl = NULL; + + pthread_spin_destroy(&(handle->new_sample_cb_guard)); + pthread_spin_destroy(&(handle->eos_cb_guard)); + + LOGD("video reader destroyed %p", handle); + + free(handle); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_load( + mv_video_reader_h reader, + const char *path, + image_data_s *image_data, + unsigned int *fps) +{ + mv_video_reader_s *handle = NULL; + GstVideoInfo info; + + if (reader == NULL || path == NULL || + image_data == NULL || fps == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + /* Set input file location from path */ + g_object_set(G_OBJECT(handle->filesrc), + "location", path, + NULL); + + /* Start playback */ + if (_mv_video_reader_state_change(handle, GST_STATE_PLAYING)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + if (_mv_video_reader_state_change(handle, GST_STATE_PAUSED)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + if (handle->caps == NULL) + { + LOGE("Unable to get caps from decodebin"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + gst_video_info_from_caps(&info, handle->caps); + gst_caps_unref(handle->caps); + + *fps = info.fps_n/info.fps_d; + + /* Fill image data */ + image_data->image_width = info.width; + image_data->image_height = info.height; + + /* Look to : + * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoFormat */ + switch(GST_VIDEO_FORMAT_INFO_FORMAT(info.finfo)) + { + case(GST_VIDEO_FORMAT_GRAY8): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_Y800; + break; + case(GST_VIDEO_FORMAT_I420): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_I420; + break; + case(GST_VIDEO_FORMAT_NV12): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_NV12; + break; + case(GST_VIDEO_FORMAT_YV12): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_YV12; + break; + case(GST_VIDEO_FORMAT_NV21): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_NV21; + break; + case(GST_VIDEO_FORMAT_YUY2): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_YUYV; + break; + case(GST_VIDEO_FORMAT_UYVY): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_UYVY; + break; + case(GST_VIDEO_FORMAT_RGB): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_RGB888; + break; + case(GST_VIDEO_FORMAT_RGBA): + image_data->image_colorspace = MEDIA_VISION_COLORSPACE_RGBA; + break; + default: + LOGE("Video pixel format is not supported\n"); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_start( + mv_video_reader_h reader) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + /* Start playback */ + if (_mv_video_reader_state_change(handle, GST_STATE_PLAYING)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_stop( + mv_video_reader_h reader) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + /* Stop playback (NULL or READY) */ + if (_mv_video_reader_state_change(handle, GST_STATE_NULL)) + { + LOGE("Unable to change state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_set_new_sample_cb( + mv_video_reader_h reader, + mv_video_reader_new_sample_cb callback, + void *user_data) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL || callback == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + pthread_spin_lock(&(handle->new_sample_cb_guard)); + handle->new_sample_cb = callback; + handle->new_sample_cb_user_data = user_data; + pthread_spin_unlock(&(handle->new_sample_cb_guard)); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_reader_set_eos_cb( + mv_video_reader_h reader, + mv_video_reader_eos_cb callback, + void *user_data) +{ + mv_video_reader_s *handle = NULL; + + if (reader == NULL || callback == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_reader_s *) reader; + + pthread_spin_lock(&(handle->eos_cb_guard)); + handle->eos_cb = callback; + handle->eos_cb_user_data = user_data; + pthread_spin_unlock(&(handle->eos_cb_guard)); + + return MEDIA_VISION_ERROR_NONE; +} + +/* Video Writer */ +int mv_create_video_writer( + mv_video_writer_h *writer) +{ + mv_video_writer_s *handle = NULL; + int err = MEDIA_VISION_ERROR_NONE; + + if (writer == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + gst_init(NULL, NULL); + + handle = (mv_video_writer_s *) malloc(sizeof(mv_video_writer_s)); + if (!handle) + { + LOGE("Not enough memory"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + memset(handle, 0, sizeof(mv_video_writer_s)); + + err = _mv_video_writer_create_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to create internals"); + free(handle); + return err; + } + + *writer = (mv_video_writer_s *) handle; + + return err; +} + +int mv_destroy_video_writer( + mv_video_writer_h writer) +{ + mv_video_writer_s *handle = NULL; + + if (writer == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_writer_s *) writer; + + _mv_video_writer_state_change(writer, GST_STATE_NULL); + + if (handle->pl) + { + gst_object_unref(handle->pl); + } + handle->pl = NULL; + + LOGD("video writer destroyed %p", handle); + + free(handle); + + return MEDIA_VISION_ERROR_NONE; +} + +int mv_video_writer_init( + mv_video_writer_h writer, + const char *path, + image_data_s image_data, + unsigned int fps) +{ + mv_video_writer_s *handle = NULL; + unsigned int err = MEDIA_VISION_ERROR_NONE; + + if (writer == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_writer_s *) writer; + + handle->image_data.image_width = image_data.image_width; + handle->image_data.image_height = image_data.image_height; + handle->image_data.image_colorspace = image_data.image_colorspace; + + handle->fps = fps; + + g_object_set(G_OBJECT(handle->filesink), + "location", path, + NULL); + + err = _mv_video_writer_link_internals(handle); + if (MEDIA_VISION_ERROR_NONE != err) + { + LOGE("Failed to link internals"); + return err; + } + + return err; +} + +int mv_video_writer_write_frame( + mv_video_writer_h writer, + unsigned char *frame) +{ + mv_video_writer_s *handle = NULL; + GstMapInfo info; + GstBuffer *buffer = NULL; + + if (writer == NULL || frame == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + handle = (mv_video_writer_s *) writer; + + buffer = gst_buffer_new_allocate(NULL, handle->buffer_size, NULL); + if (!buffer) + { + LOGE("Unable to allocate buffer for frame"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + LOGD("Copying input frame to buffer and pushing to appsrc"); + gst_buffer_map(buffer, &info, GST_MAP_READWRITE); + memcpy(info.data, frame, info.size); + gst_buffer_unmap(buffer, &info); + + if (GST_FLOW_OK != + gst_app_src_push_buffer(handle->appsrc, buffer)) + { + LOGE("Failed to push buffer to appsrc"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +/* Internal functions */ +static int _mv_video_reader_create_internals( + mv_video_reader_s *reader) +{ + pthread_spin_init(&(reader->new_sample_cb_guard), PTHREAD_PROCESS_SHARED); + pthread_spin_init(&(reader->eos_cb_guard), PTHREAD_PROCESS_SHARED); + + reader->pl = gst_pipeline_new(NULL); + + reader->filesrc = gst_element_factory_make("filesrc", "filesrc"); + reader->decodebin = gst_element_factory_make("decodebin", "decoder"); + reader->videoconvert = gst_element_factory_make("videoconvert", "convert"); + reader->appsink = gst_element_factory_make("appsink", "appsink"); + + if ((!reader->pl) || + (!reader->filesrc) || + (!reader->decodebin) || + (!reader->videoconvert) || + (!reader->appsink)) + { + LOGE("Unable to create video read pipeline elements"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + gst_bin_add_many(GST_BIN(reader->pl), + reader->filesrc, + reader->decodebin, + reader->videoconvert, + reader->appsink, + NULL); + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_reader_link_internals( + mv_video_reader_s *reader) +{ + GstCaps *caps = NULL; + + if (!gst_element_link_many(reader->filesrc, + reader->decodebin, + NULL)) + { + LOGE("Unable to link filesrc to decodebin"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + /* Decodebin pad will be linked during state change */ + g_signal_connect(reader->decodebin, + "pad-added", + G_CALLBACK(cb_newpad), + reader); + + if (!gst_element_link_many(reader->videoconvert, + reader->appsink, NULL)) + { + LOGE("Unable to link filesrc to decodebin"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + caps = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, "RGB", + NULL); + + gst_app_sink_set_caps(GST_APP_SINK(reader->appsink), caps); + gst_caps_unref(caps); + + /* Configure appsink */ + gst_app_sink_set_emit_signals(GST_APP_SINK(reader->appsink), TRUE); + g_signal_connect(reader->appsink, + "new-sample", + G_CALLBACK(appsink_newsample), + reader); + g_signal_connect(reader->appsink, + "eos", + G_CALLBACK(appsink_eos), + reader); + g_object_set(G_OBJECT(reader->appsink), + "drop", TRUE, + "enable-last-sample", TRUE, + "sync", FALSE, + NULL); + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_reader_state_change( + mv_video_reader_s *reader, + GstState state) +{ + mv_video_reader_s *handle = (mv_video_reader_s *) reader; + GstStateChangeReturn state_ret = GST_STATE_CHANGE_FAILURE; + GstState pipeline_state = GST_STATE_NULL; + + state_ret = gst_element_set_state(handle->pl, + state); + + if (GST_STATE_CHANGE_FAILURE == state_ret) + { + LOGE("Set state failure"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + LOGI("Set state [%d], change return [%d]", + state, state_ret); + + state_ret = gst_element_get_state(handle->pl, + &pipeline_state, + NULL, + GST_CLOCK_TIME_NONE); + + if (GST_STATE_CHANGE_FAILURE == state_ret) + { + LOGE("get state failure"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_writer_create_internals( + mv_video_writer_s *writer) +{ + writer->pl = gst_pipeline_new(NULL); + + writer->appsrc = gst_element_factory_make("appsrc", "appsrc"); + writer->capsfilter = gst_element_factory_make("capsfilter", NULL); + writer->videoconvert = gst_element_factory_make("videoconvert", "videoconvert"); + writer->encoder = gst_element_factory_make("avenc_mpeg4", "encoder"); + writer->queue = gst_element_factory_make("queue", "queue"); + writer->muxer = gst_element_factory_make("avmux_avi", "muxer"); + writer->filesink = gst_element_factory_make("filesink", "filesink"); + + if ((!writer->pl) || + (!writer->appsrc) || + (!writer->capsfilter) || + (!writer->videoconvert) || + (!writer->encoder) || + (!writer->queue) || + (!writer->muxer) || + (!writer->filesink)) + { + LOGE("Unable to create video read pipeline elements\n"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + gst_bin_add_many(GST_BIN(writer->pl), + writer->appsrc, + writer->capsfilter, + writer->videoconvert, + writer->encoder, + writer->queue, + writer->muxer, + writer->filesink, + NULL); + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_writer_link_internals( + mv_video_writer_s *writer) +{ + GstVideoInfo vinfo; + GstCaps *caps = NULL; + char format[6] = {0}; + + /* Convert from mv_colorspace to GstVideoFormat */ + switch(writer->image_data.image_colorspace) + { + case(MEDIA_VISION_COLORSPACE_Y800): + strncpy(format, "GRAY8", 5); + break; + case(MEDIA_VISION_COLORSPACE_I420): + strncpy(format, "I420", 4); + break; + case(MEDIA_VISION_COLORSPACE_NV12): + strncpy(format, "NV12", 4); + break; + case(MEDIA_VISION_COLORSPACE_YV12): + strncpy(format, "YV12", 4); + break; + case(MEDIA_VISION_COLORSPACE_NV21): + strncpy(format, "NV21", 4); + break; + case(MEDIA_VISION_COLORSPACE_YUYV): + strncpy(format, "YUY2", 4); + break; + case(MEDIA_VISION_COLORSPACE_UYVY): + strncpy(format, "UYVY", 4); + break; + case(MEDIA_VISION_COLORSPACE_RGB888): + strncpy(format, "RGB", 3); + break; + case(MEDIA_VISION_COLORSPACE_RGBA): + strncpy(format, "RGBA", 4); + break; + default: + LOGE("Selected format %d is not supported", + writer->image_data.image_colorspace); + return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT; + } + + caps = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, format, + "width", G_TYPE_INT, writer->image_data.image_width, + "height", G_TYPE_INT, writer->image_data.image_height, + "framerate", GST_TYPE_FRACTION, writer->fps, 1, + NULL); + + if (NULL == caps) + { + LOGE("Failed to create new caps"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + /* This is the simpler way to get buffer size */ + if (!gst_video_info_from_caps(&vinfo, caps)) + { + LOGE("Unable to set buffer size"); + gst_caps_unref(caps); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + writer->buffer_size = vinfo.size; + + /* link appsrc and capsfilter */ + if ((!gst_element_link_filtered(writer->appsrc, + writer->capsfilter, + caps))) + { + LOGE("Failed to link appsrc to capsfilter"); + gst_caps_unref(caps); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + gst_caps_unref(caps); + + if (!gst_element_link_many(writer->capsfilter, + writer->videoconvert, + writer->encoder, + writer->queue, + writer->muxer, + writer->filesink, + NULL)) + { + LOGE("Unable to capsfilter to filesink"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + g_object_set(G_OBJECT(writer->appsrc), + "max-bytes", 0, + "blocksize", writer->buffer_size, + "stream-type", 0, + "format", GST_FORMAT_BYTES, + NULL); + + if (_mv_video_writer_state_change(writer, + GST_STATE_PLAYING)) + { + LOGE("Unable to change video writer state"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + return MEDIA_VISION_ERROR_NONE; +} + +static int _mv_video_writer_state_change( + mv_video_writer_s *writer, + GstState state) +{ + mv_video_writer_s *handle = (mv_video_writer_s *) writer; + GstStateChangeReturn state_ret = GST_STATE_CHANGE_FAILURE; + GstState pipeline_state = GST_STATE_NULL; + + state_ret = gst_element_set_state(handle->pl, + state); + + if (GST_STATE_CHANGE_FAILURE == state_ret) + { + LOGE("Set state failure"); + return MEDIA_VISION_ERROR_INVALID_OPERATION; + } + + LOGI("Set state [%d], change return [%d]", + state, state_ret); + + /* AppSrc can't go to PLAYING state before buffer is not pushed */ + + return MEDIA_VISION_ERROR_NONE; +} + +/* Callbacks */ +static GstFlowReturn appsink_newsample( + GstAppSink *appsink, + gpointer user_data) +{ + mv_video_reader_s *handle = NULL; + GstSample *sample = gst_app_sink_pull_sample(appsink); + + if (user_data == NULL) + { + LOGE("NULL pointer passed"); + return MEDIA_VISION_ERROR_INVALID_PARAMETER; + } + + if (sample != NULL) + { + handle = (mv_video_reader_s *) user_data; + GstVideoInfo vinfo; + GstMapInfo info = GST_MAP_INFO_INIT; + GstBuffer *buf = gst_sample_get_buffer(sample); + GstCaps *caps = gst_sample_get_caps(sample); + image_data_s im_data; + char *buffer = NULL; + unsigned int buffer_size = 0; + + LOGD("Received sample from appsink"); + + /* map buffer */ + gst_buffer_map(buf, &info, GST_MAP_READ); + buffer = (char *) info.data; + + /* Fill image data */ + gst_video_info_from_caps(&vinfo, caps); + im_data.image_width = vinfo.width; + im_data.image_height = vinfo.height; + + /* Look to : + * http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoFormat */ + switch(GST_VIDEO_FORMAT_INFO_FORMAT(vinfo.finfo)) + { + case(GST_VIDEO_FORMAT_GRAY8): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_Y800; + break; + case(GST_VIDEO_FORMAT_I420): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_I420; + break; + case(GST_VIDEO_FORMAT_NV12): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_NV12; + break; + case(GST_VIDEO_FORMAT_YV12): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_YV12; + break; + case(GST_VIDEO_FORMAT_NV21): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_NV21; + break; + case(GST_VIDEO_FORMAT_YUY2): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_YUYV; + break; + case(GST_VIDEO_FORMAT_UYVY): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_UYVY; + break; + case(GST_VIDEO_FORMAT_RGB): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGB888; + break; + case(GST_VIDEO_FORMAT_RGBA): + im_data.image_colorspace = MEDIA_VISION_COLORSPACE_RGBA; + break; + default: + LOGE("Video pixel format is not supported\n"); + + gst_buffer_unmap(buf, &info); + gst_sample_unref(sample); + return GST_FLOW_ERROR; + } + + pthread_spin_lock(&(handle->new_sample_cb_guard)); + if (handle->new_sample_cb != NULL) + { + handle->new_sample_cb( + buffer, + info.size, + im_data, + handle->new_sample_cb_user_data); + } + pthread_spin_unlock(&(handle->new_sample_cb_guard)); + + gst_buffer_unmap(buf, &info); + gst_sample_unref(sample); + } + else + { + LOGE("Failed to pull sample from appsink"); + return GST_FLOW_ERROR; + } + + return GST_FLOW_OK; +} + +static void appsink_eos( + GstAppSink *appsink, + gpointer user_data) +{ + if (user_data == NULL) + { + LOGE("NULL pointer passed"); + return; + } + + mv_video_reader_s *handle = (mv_video_reader_s *) user_data; + + /* EOS callback to terminate reading */ + pthread_spin_lock(&(handle->eos_cb_guard)); + if (handle->eos_cb != NULL) + { + handle->eos_cb(handle->eos_cb_user_data); + } + pthread_spin_unlock(&(handle->eos_cb_guard)); +} + +static void cb_newpad( + GstElement *decodebin, + GstPad *pad, + gpointer user_data) +{ + mv_video_reader_s *reader = (mv_video_reader_s *) user_data; + GstStructure *str = NULL; + GstCaps *caps = NULL; + GstPad *video_pad = NULL; + + LOGI("Received pad from decodebin. Linking"); + video_pad = gst_element_get_static_pad(reader->videoconvert, "sink"); + if (GST_PAD_IS_LINKED(video_pad)) + { + LOGI("Already linked"); + g_object_unref(video_pad); + return; + } + + /* Check for pad is video */ + reader->caps = gst_pad_query_caps(pad, NULL); + str = gst_caps_get_structure(reader->caps, 0); + if (!g_strrstr(gst_structure_get_name(str), "video")) + { + LOGI("Not a video pad"); + gst_object_unref(video_pad); + return; + } + + gst_pad_link(pad, video_pad); + g_object_unref(video_pad); +} |