SET(INC_DIR include)
INCLUDE_DIRECTORIES(${INC_DIR})
-SET(dependents "dlog glib-2.0 mm-common libtbm capi-media-tool iniparser gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 capi-system-info mm-resource-manager gstreamer-allocators-1.0" )
-SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 mm-resource-manager gstreamer-allocators-1.0" )
+SET(dependents "dlog glib-2.0 mm-common libtbm capi-media-tool iniparser gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 capi-system-info gstreamer-allocators-1.0")
+SET(pc_dependents "capi-base-common capi-media-tool")
+IF(TIZEN_FEATURE_MM_RESOURCE_MANAGER)
+SET(dependents "${dependents} mm-resource-manager")
+ENDIF(TIZEN_FEATURE_MM_RESOURCE_MANAGER)
INCLUDE(FindPkgConfig)
pkg_check_modules(${fw_name} REQUIRED ${dependents})
ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
ADD_DEFINITIONS("-DTIZEN_DEBUG")
+IF(TIZEN_FEATURE_MM_RESOURCE_MANAGER)
+ADD_DEFINITIONS("-DUSE_MM_RESOURCE_MANAGER")
+ENDIF(TIZEN_FEATURE_MM_RESOURCE_MANAGER)
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}")
*
* To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n
*
- * More details on featuring your application can be found from <a href="https://developer.tizen.org/development/tizen-studio/native-tools/configuring-your-app/manifest-text-editor#feature"><b>Feature Element</b>.</a>
+ * More details on featuring your application can be found from <a href="https://docs.tizen.org/application/tizen-studio/native-tools/manifest-text-editor#feature-element"><b>Feature Element</b>.</a>
*
* MEDIA CODEC API allows :
* The API allows you to direct access to the media codec on device. It operates on "raw" data, so any file headers
typedef void (*mediacodec_output_buffer_available_cb)(media_packet_h packet, void *user_data);
/**
- * @brief Called when the error has occured.
- * @details It will be invoked when the error has occured.
+ * @brief Called when the error has occurred.
+ * @details It will be invoked when the error has occurred.
* Following error codes can be delivered.
* #MEDIACODEC_ERROR_INTERNAL,
* #MEDIACODEC_ERROR_INVALID_STREAM,
* @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
* @param[in] error The error code
* @param[in] user_data The user data passed from the callback registration function
- * @pre It will be invoked when the error has occured if you register this callback using mediacodec_set_error_cb().
+ * @pre It will be invoked when the error has occurred if you register this callback using mediacodec_set_error_cb().
* @see mediacodec_set_error_cb()
* @see mediacodec_unset_error_cb()
*/
#define MEDIA_CODEC_INI_DEFAULT_PATH SYSCONFDIR"/multimedia/mmfw_media_codec.ini"
#define MEDIA_CODEC_INI_MAX_STRLEN 256
+#define MEDIA_CODEC_INI_CNAME_LEN 16
#define DEFAULT_PORT "GST_PORT"
#define MEDIA_CODEC_MAX_CODEC_TYPE 100
#define MEDIA_CODEC_MAX_CODEC_ROLE 4
typedef struct _mc_ini_t mc_ini_t;
struct _codec_list_t {
- gchar cname[MEDIA_CODEC_INI_MAX_STRLEN];
+ gchar cname[MEDIA_CODEC_INI_CNAME_LEN];
mediacodec_codec_type_e ctype;
};
#define __TIZEN_MEDIA_CODEC_PORT_GST_H__
#include <unistd.h>
-#include <tizen.h>
#include <media_codec.h>
#include <media_codec_private.h>
#include <media_codec_port.h>
#include <media_codec_bitstream.h>
-#include <tbm_type.h>
#include <tbm_surface.h>
-#include <tbm_bufmgr.h>
#include <tbm_surface_internal.h>
#include <gst/video/video-format.h>
#include <gst/allocators/gsttizenmemory.h>
#define GST_INIT_STRUCTURE(param) \
memset(&(param), 0, sizeof(param));
-#define MEDIACODEC_ELEMENT_SET_STATE(x_element, x_state) \
- do { \
- LOGD("setting state [%s:%d] to [%s]\n", #x_state, x_state, GST_ELEMENT_NAME(x_element)); \
- if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(x_element, x_state)) { \
- LOGE("failed to set state %s to %s\n", #x_state, GST_ELEMENT_NAME(x_element)); \
- goto STATE_CHANGE_FAILED; \
- } \
- } while (0)
#define SCMN_IMGB_MAX_PLANE 4
#define TBM_API_CHANGE
};
enum { fill_inbuf, fill_outbuf };
-
-int __mc_fill_input_buffer(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
-int __mc_fill_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
-
-int __mc_fill_input_buffer_with_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
-int __mc_fill_input_buffer_with_adec_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
-int __mc_fill_input_buffer_with_venc_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
-
-int __mc_fill_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
-int __mc_fill_aenc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
-int __mc_fill_venc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
-int __mc_fill_vdec_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
-
-mc_gst_core_t *mc_gst_core_new();
-void mc_gst_core_free(mc_gst_core_t *core);
-
-mc_gst_port_t *mc_gst_port_new(mc_gst_core_t *core);
-void mc_gst_port_free(mc_gst_port_t *port);
-
mc_ret_e mc_gst_prepare(mc_handle_t *mc_handle);
mc_ret_e mc_gst_unprepare(mc_handle_t *mc_handle);
-mc_ret_e mc_gst_process_input(mc_handle_t *mc_handle, media_packet_h inbuf, uint64_t timeOutUs);
-mc_ret_e mc_gst_get_output(mc_handle_t *mc_handle, media_packet_h *outbuf, uint64_t timeOutUs);
+mc_ret_e mc_gst_process_input(mc_handle_t *mc_handle, media_packet_h inbuf, uint64_t timeout_us);
+mc_ret_e mc_gst_get_output(mc_handle_t *mc_handle, media_packet_h *outbuf, uint64_t timeout_us);
mc_ret_e mc_gst_flush_buffers(mc_handle_t *mc_handle);
#include <media_codec.h>
#include <mm_types.h>
+#ifdef USE_MM_RESOURCE_MANAGER
#include <mm_resource_manager.h>
+#endif
#ifdef __cplusplus
extern "C" {
#define MEDIACODEC_CHECK_CONDITION(condition, error, msg) \
- if (condition) {} else \
- {LOGE("[%s] %s(0x%08x)", __FUNCTION__, msg, error); return error; }; \
+ if (!(condition)) {LOGE("%s(0x%08x)", msg, error); return error; }
#define MEDIACODEC_INSTANCE_CHECK(mediacodec) \
MEDIACODEC_CHECK_CONDITION(mediacodec != NULL, MEDIACODEC_ERROR_INVALID_PARAMETER, "MEDIACODEC_ERROR_INVALID_PARAMETER")
int state;
bool is_omx;
char *m_mime;
+#ifdef USE_MM_RESOURCE_MANAGER
mm_resource_manager_res_h codec_resource;
+#endif
mediacodec_input_buffer_used_cb empty_buffer_cb;
void* empty_buffer_cb_userdata;
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef __TIZEN_MEDIA_CODEC_SYNC_INTERNAL_H__
+#define __TIZEN_MEDIA_CODEC_SYNC_INTERNAL_H__
+
+#include <media_codec.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+* @file media_codec_sync_internal.h
+* @brief This file contains the internal capi media codec sync API.
+*/
+
+/**
+* @addtogroup CAPI_MEDIA_CODEC_SYNC_MODULE
+* @{
+*/
+
+/**
+ * @brief Media Codec Sync type handle.
+ * @since_tizen 5.5
+ */
+typedef struct mediacodecsync_s *mediacodecsync_h;
+
+
+typedef enum {
+ MEDIACODECSYNC_STATE_CREATED = 0, /**< Media codec sync is created */
+ MEDIACODECSYNC_STATE_READY, /**< Media codec sync is ready to run */
+ MEDIACODECSYNC_STATE_RUNNING, /**< Media codec sync is running */
+ MEDIACODECSYNC_STATE_PAUSED /**< Media codec sync is paused */
+} mediacodecsync_state_e;
+
+typedef enum {
+ MEDIACODECSYNC_PACKET_TYPE_AUDIO = 0,
+ MEDIACODECSYNC_PACKET_TYPE_VIDEO
+} mediacodecsync_packet_type_e;
+
+typedef void (*mediacodecsync_buffer_used_cb)(media_packet_h packet, mediacodecsync_packet_type_e type, void *user_data);
+
+/**
+ * @brief Creates a mediacodecsync handle for synchronous AV rendering.
+ * @since_tizen 5.5
+ * @remarks you must release @a mediacodecsync using mediacodecsync_destroy().\n
+ * Although you can create multiple mediacodecsync handles at the same time,
+ * the mediacodec cannot guarantee proper operation because of limited resources, like
+ * audio or display device.
+ *
+ * @param[in] callback The callback function to register
+ * @param[in] user_data The user data to be passed to the callback function
+ * @param[out] mediacodecsync A new handle to mediacodecsync
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @post If it succeeds, the state will be #MEDIACODECSYNC_STATE_CREATED.
+ */
+int mediacodecsync_create(mediacodecsync_buffer_used_cb callback, void *userdata, mediacodecsync_h *mediacodecsync);
+
+/**
+ * @brief Destroys the mediacodecsync handle and releases all its resources.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync to be destroyed.
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state should be #MEDIACODECSYNC_STATE_CREATED.
+ */
+int mediacodecsync_destroy(mediacodecsync_h mediacodecsync);
+
+/**
+ * @brief Sets the media format to be rendered.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The mediacodecsync handle
+ * @param[in] audio_format The #media_format_h of audio data
+ * @param[in] video_format The #media_format_h of video data
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_NOT_SUPPORTED_ON_DEVICE Not supported on device
+ * @pre The state should be #MEDIACODECSYNC_STATE_CREATED.
+ * @pre The media format has been created and the required values have been set.
+ * @see media_format_set_video_mime()
+ * @see media_format_set_audio_mime()
+ * @see media_format_set_video_width()
+ * @see media_format_set_video_height()
+ * @see media_format_set_video_avg_bps()
+ * @see media_format_set_video_frame_rate()
+ * @see media_format_set_audio_channel()
+ * @see media_format_set_audio_samplerate()
+ * @see media_format_set_audio_bit()
+ * @see media_format_set_audio_avg_bps()
+ */
+int mediacodecsync_set_format(mediacodecsync_h mediacodecsync, media_format_h audio_format, media_format_h video_format);
+
+/**
+ * @brief Prepares @a mediacodecsync for synchronous rendering.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #MEDIACODEC_ERROR_RESOURCE_OVERLOADED Exceed the instance limits
+ * @retval #MEDIACODEC_ERROR_INTERNAL Internal error
+ * @pre The mediacodecsync should call mediacodecsync_set_format() before calling mediacodec_prepare().
+ * @pre The state should be #MEDIACODECSYNC_STATE_CREATED.
+ * @post If it succeeds, the state will be #MEDIACODECSYNC_STATE_READY.
+ */
+int mediacodecsync_prepare(mediacodecsync_h mediacodecsync);
+
+/**
+ * @brief Unprepares @a mediacodecsync.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state should be #MEDIACODECSYNC_STATE_READY.
+ * @post If it succeeds, the state will be #MEDIACODECSYNC_STATE_CREATED.
+ */
+int mediacodecsync_unprepare(mediacodecsync_h mediacodecsync);
+
+/**
+ * @brief Runs @a mediacodecsync.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state should be #MEDIACODECSYNC_STATE_READY or #MEDIACODECSYNC_STATE_PAUSED.
+ * @post If it succeeds, the state will be #MEDIACODECSYNC_STATE_RUNNING.
+ */
+int mediacodecsync_run(mediacodecsync_h mediacodecsync);
+
+/**
+ * @brief Stops @a mediacodecsync.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state should be #MEDIACODECSYNC_STATE_RUN or #MEDIACODECSYNC_STATE_PAUSED.
+ * @post If it succeeds, the state will be #MEDIACODECSYNC_STATE_READY.
+ */
+int mediacodecsync_stop(mediacodecsync_h mediacodecsync);
+
+/**
+ * @brief Pauses @a mediacodecsync.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state should be #MEDIACODECSYNC_STATE_RUN.
+ * @post If it succeeds, the state will be #MEDIACODECSYNC_STATE_PAUSED.
+ */
+int mediacodecsync_pause(mediacodecsync_h mediacodecsync);
+
+/**
+ * @brief Pushes packets to render.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync
+ * @param[in] packet The packet to render
+ * @param[in] type The type of packet
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre The state should be #MEDIACODECSYNC_STATE_RUN.
+ */
+int mediacodecsync_push_packet(mediacodecsync_h mediacodecsync, media_packet_h packet, mediacodecsync_packet_type_e type);
+
+/**
+ * @brief Gets state of @a mediacodecsync.
+ * @since_tizen 5.5
+ * @param[in] mediacodecsync The handle to mediacodecsync
+ * @param[out] state The state of mediacodecsync
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIACODEC_ERROR_NONE Successful
+ * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation
+ */
+int mediacodecsync_get_state(mediacodecsync_h mediacodecsync, mediacodecsync_state_e *state);
+
+/**
+ * @}
+ */
+#ifdef __cplusplus
+}
+#endif
+#endif /*__TIZEN_MEDIA_CODEC_INTERNAL_H__*/
--- /dev/null
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef __TIZEN_MEDIA_CODEC_SYNC_PRIVATE_H__
+#define __TIZEN_MEDIA_CODEC_SYNC_PRIVATE_H__
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gst/gst.h>
+#include <gst/allocators/gsttizenmemory.h>
+#include <gst/app/gstappsrc.h>
+#include <media_codec_private.h>
+#include <media_codec_sync_internal.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ MEDIACODECSYNC_PIPELINE = 0,
+ MEDIACODECSYNC_ELEMENT_APPSRC,
+ MEDIACODECSYNC_ELEMENT_CAPS,
+ MEDIACODECSYNC_ELEMENT_QUE,
+ MEDIACODECSYNC_ELEMENT_SINK,
+ MEDIACODECSYNC_ELEMENT_NUM
+};
+
+#define AUDIO_FORMAT_TABLE_SIZE 15
+#define VIDEO_FORMAT_TABLE_SIZE 8
+
+typedef struct _format_table {
+ media_format_mimetype_e mime_type;
+ char *format_string;
+} format_table;
+
+typedef struct _packet_info {
+ bool has_tbm_surface;
+ void *data;
+ uint64_t data_size;
+ uint64_t dts;
+ uint64_t pts;
+ uint64_t duration;
+} packet_info;
+
+typedef struct _mediacodecsync_s {
+ GMutex lock;
+ media_format_h audio_format;
+ media_format_h video_format;
+
+ GstAllocator *allocator;
+ GstClock *clock;
+ GstElement *audio_pipe[MEDIACODECSYNC_ELEMENT_NUM];
+ GstElement *video_pipe[MEDIACODECSYNC_ELEMENT_NUM];
+ GstCaps *video_caps;
+ GstVideoInfo video_info;
+
+ mediacodecsync_buffer_used_cb buffer_used_cb;
+ void *buffer_used_cb_userdata;
+
+ mediacodecsync_state_e state;
+} mediacodecsync_s;
+
+typedef struct _GstMCSBuffer {
+ GstBuffer *gst_buffer;
+ int type;
+ mediacodecsync_s *handle;
+ media_packet_h packet;
+} GstMCSBuffer;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIZEN_MEDIA_CODEC_SYNC_PRIVATE_H__ */
Name: capi-media-codec
Summary: A Media Codec library in Tizen Native API
-Version: 0.6.0
+Version: 0.6.10
Release: 0
Group: Multimedia/API
License: Apache-2.0
BuildRequires: pkgconfig(gstreamer-app-1.0)
BuildRequires: pkgconfig(capi-system-info)
BuildRequires: pkgconfig(iniparser)
+%if "%{tizen_profile_name}" != "tv"
BuildRequires: pkgconfig(mm-resource-manager)
+%endif
#BuildRequires: pkgconfig(capi-media-camera)
#BuildRequires: pkgconfig(capi-mediademuxer)
#BuildRequires: pkgconfig(capi-mediamuxer)
%description devel
+%if 0%{?gcov:1}
+%package gcov
+Summary: Line Coverage of Media Codec library in Tizen Native API
+Group: Development/Multimedia
+
+%description gcov
+Collection of files related to Line Coverage. It is tested as gcov for a media codec library in Tizen native API
+%endif
+
%prep
%setup -q
%endif
MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
-%cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
-
+%cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \
+%if "%{tizen_profile_name}" == "tv"
+ -DTIZEN_FEATURE_MM_RESOURCE_MANAGER=NO
+%else
+ -DTIZEN_FEATURE_MM_RESOURCE_MANAGER=YES
+%endif
make %{?jobs:-j%jobs}
+%if 0%{?gcov:1}
+mkdir -p gcov-obj
+find . -name '*.gcno' -exec cp '{}' gcov-obj ';'
+%endif
+
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}/usr/bin
%make_install
+%if 0%{?gcov:1}
+mkdir -p %{buildroot}%{_datadir}/gcov/obj
+install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
+%endif
+
+
%post
/sbin/ldconfig
%{_libdir}/pkgconfig/*.pc
%{_libdir}/libcapi-media-codec.so
+%if 0%{?gcov:1}
+%files gcov
+%{_datadir}/gcov/obj/*
+%endif
#define MC_PREALLOCATED_HANDLE_ARRAY_SIZE 16
-static mm_resource_manager_h resource_manager;
-static GPtrArray *mediacodec_handles;
-static GMutex mediacodec_handles_lock;
+#ifdef USE_MM_RESOURCE_MANAGER
+static mm_resource_manager_h g_mc_resource_manager;
+static GPtrArray *g_mediacodec_handles;
+static GMutex g_mediacodec_lock;
+#endif
static gboolean __mediacodec_empty_buffer_cb(media_packet_h pkt, void *user_data);
static gboolean __mediacodec_fill_buffer_cb(media_packet_h pkt, void *user_data);
static gboolean __mediacodec_eos_cb(void *user_data);
static gboolean __mediacodec_supported_codec_cb(mediacodec_codec_type_e codec_type, void *user_data);
static gboolean __mediacodec_buffer_status_cb(mediacodec_status_e status, void *user_data);
+#ifdef USE_MM_RESOURCE_MANAGER
static void __mediacodec_init_lib() __attribute__((constructor));
static void __mediacodec_deinit_lib() __attribute__((destructor));
static int __mediacodec_resource_release_cb(mm_resource_manager_h rm,
mm_resource_manager_res_h resource_h, void *user_data);
+#endif
/*
* Internal Implementation
LOGD("mediacodec_create..");
- if (resource_manager == NULL)
- return MEDIACODEC_ERROR_INTERNAL;
+#ifdef USE_MM_RESOURCE_MANAGER
+ g_mutex_lock(&g_mediacodec_lock);
+
+ if (!g_mc_resource_manager) {
+ int mm_ret = mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
+ __mediacodec_resource_release_cb, NULL, &g_mc_resource_manager);
+ if (mm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ g_mutex_unlock(&g_mediacodec_lock);
+ LOGE("mm_resource_manager_create failed 0x%x", mm_ret);
+ return MEDIACODEC_ERROR_INTERNAL;
+ }
+ }
+
+ g_mutex_unlock(&g_mediacodec_lock);
+#endif
handle = (mediacodec_s *)malloc(sizeof(mediacodec_s));
if (handle != NULL) {
mc_set_buffer_status_cb(handle->mc_handle, (mediacodec_buffer_status_cb)__mediacodec_buffer_status_cb, handle);
mc_set_supported_codec_cb(handle->mc_handle, (mediacodec_supported_codec_cb)__mediacodec_supported_codec_cb, handle);
- g_mutex_lock(&mediacodec_handles_lock);
- g_ptr_array_insert(mediacodec_handles, -1, *mediacodec);
- g_mutex_unlock(&mediacodec_handles_lock);
+#ifdef USE_MM_RESOURCE_MANAGER
+ g_mutex_lock(&g_mediacodec_lock);
+ g_ptr_array_insert(g_mediacodec_handles, -1, *mediacodec);
+ g_mutex_unlock(&g_mediacodec_lock);
+#endif
return MEDIACODEC_ERROR_NONE;
LOGD("MEDIACODEC_ERROR_INVALID_OPERATION(0x%08x)", MEDIACODEC_ERROR_INVALID_OPERATION); //LCOV_EXCL_LINE
return MEDIACODEC_ERROR_INVALID_OPERATION;
} else {
- g_mutex_lock(&mediacodec_handles_lock);
- g_ptr_array_remove_fast(mediacodec_handles, mediacodec);
- g_mutex_unlock(&mediacodec_handles_lock);
+#ifdef USE_MM_RESOURCE_MANAGER
+ g_mutex_lock(&g_mediacodec_lock);
+ g_ptr_array_remove_fast(g_mediacodec_handles, mediacodec);
+ g_mutex_unlock(&g_mediacodec_lock);
+#endif
handle->state = MEDIACODEC_STATE_NONE;
free(handle);
{
MEDIACODEC_INSTANCE_CHECK(mediacodec);
mediacodec_s *handle = (mediacodec_s *)mediacodec;
+#ifdef USE_MM_RESOURCE_MANAGER
mc_handle_t *mc_handle = (mc_handle_t *) handle->mc_handle;
int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
mm_resource_manager_res_h resource;
+#endif
MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE);
+#ifdef USE_MM_RESOURCE_MANAGER
if (mc_handle->is_hw && mc_handle->is_video) {
if (handle->codec_resource) {
* Additional info can be found in doxygen comments of mm_resource_manager.h
*/
//LCOV_EXCL_START
- rm_ret = mm_resource_manager_mark_for_acquire(resource_manager,
+ rm_ret = mm_resource_manager_mark_for_acquire(g_mc_resource_manager,
mc_handle->is_encoder ?
MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER :
MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
1, &resource);
- if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
- switch (rm_ret) {
+ if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
LOGE("Failed to acquire resource manager %x", rm_ret);
+ switch (rm_ret) {
case MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED:
return MEDIACODEC_ERROR_NOT_SUPPORTED_ON_DEVICE;
case MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH:
default:
return MEDIACODEC_ERROR_INTERNAL;
}
+ }
- rm_ret = mm_resource_manager_commit(resource_manager);
+ rm_ret = mm_resource_manager_commit(g_mc_resource_manager);
if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
- mm_resource_manager_mark_for_release(resource_manager, resource);
+ mm_resource_manager_mark_for_release(g_mc_resource_manager, resource);
LOGE("Failed to commit resource manager : %x", rm_ret);
return MEDIACODEC_ERROR_INTERNAL;
}
handle->codec_resource = resource;
//LCOV_EXCL_STOP
}
+#endif
int ret = mc_prepare(handle->mc_handle);
{
MEDIACODEC_INSTANCE_CHECK(mediacodec);
mediacodec_s *handle = (mediacodec_s *)mediacodec;
+#ifdef USE_MM_RESOURCE_MANAGER
int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+#endif
int ret = mc_unprepare(handle->mc_handle);
if (ret != MEDIACODEC_ERROR_NONE) {
return __convert_error_code(ret, (char *)__FUNCTION__);
} else {
+#ifdef USE_MM_RESOURCE_MANAGER
if (handle->codec_resource != NULL) {
//LCOV_EXCL_START
- mm_resource_manager_mark_for_release(resource_manager,
+ mm_resource_manager_mark_for_release(g_mc_resource_manager,
handle->codec_resource);
handle->codec_resource = NULL;
- rm_ret = mm_resource_manager_commit(resource_manager);
+ rm_ret = mm_resource_manager_commit(g_mc_resource_manager);
if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
- mm_resource_manager_mark_for_release(resource_manager, handle->codec_resource);
+ mm_resource_manager_mark_for_release(g_mc_resource_manager, handle->codec_resource);
switch (rm_ret) {
case MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY:
return MEDIACODEC_ERROR_RESOURCE_OVERLOADED;
} else {
LOGD("No codec resource to release. Probably resource release cb called\n");
}
+#endif
handle->state = MEDIACODEC_STATE_IDLE;
return MEDIACODEC_ERROR_NONE;
return 1;
}
+#ifdef USE_MM_RESOURCE_MANAGER
//LCOV_EXCL_START
static int __mediacodec_resource_release_cb(mm_resource_manager_h rm,
mm_resource_manager_res_h resource_h, void *user_data)
int i;
mediacodec_s *handle;
- g_mutex_lock(&mediacodec_handles_lock);
- for (i = 0; i < mediacodec_handles->len; i++) {
- handle = g_ptr_array_index(mediacodec_handles, i);
+ g_mutex_lock(&g_mediacodec_lock);
+ for (i = 0; i < g_mediacodec_handles->len; i++) {
+ handle = g_ptr_array_index(g_mediacodec_handles, i);
if (handle->codec_resource == resource_h) {
/*
* TODO
break;
}
}
- g_mutex_unlock(&mediacodec_handles_lock);
+ g_mutex_unlock(&g_mediacodec_lock);
return FALSE;
}
//LCOV_EXCL_STOP
+
static void __mediacodec_init_lib()
{
- mediacodec_handles = g_ptr_array_sized_new(MC_PREALLOCATED_HANDLE_ARRAY_SIZE);
+ LOGD("START");
- if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
- __mediacodec_resource_release_cb, NULL, &resource_manager)) {
- LOGE("Failed to initialize resource manager"); //LCOV_EXCL_LINE
- g_ptr_array_unref(mediacodec_handles);
- }
+ g_mutex_init(&g_mediacodec_lock);
+ g_mediacodec_handles = g_ptr_array_sized_new(MC_PREALLOCATED_HANDLE_ARRAY_SIZE);
+
+ LOGD("DONE");
}
static void __mediacodec_deinit_lib()
{
- if (resource_manager != NULL)
- mm_resource_manager_destroy(resource_manager);
- g_ptr_array_unref(mediacodec_handles);
+ LOGD("START");
+
+ if (g_mc_resource_manager != NULL)
+ mm_resource_manager_destroy(g_mc_resource_manager);
+
+ g_ptr_array_unref(g_mediacodec_handles);
+ g_mutex_clear(&g_mediacodec_lock);
+
+ LOGD("DONE");
}
+#endif
+
/* macro */
#define MEDIA_CODEC_INI_GET_STRING(x_dict, x_item, x_ini, x_default) \
do {\
- gchar* str = iniparser_getstring(x_dict, x_ini, x_default); \
+ const char *str = iniparser_getstring(x_dict, x_ini, x_default); \
\
if (str && \
(strlen(str) > 0) && \
(strlen(str) < MEDIA_CODEC_INI_MAX_STRLEN)) \
- strncpy(x_item, str, strlen(str) + 1); \
+ strncpy(x_item, str, MEDIA_CODEC_INI_MAX_STRLEN - 1); \
else \
- strncpy(x_item, x_default, strlen(x_default) + 1); \
+ strncpy(x_item, x_default, MEDIA_CODEC_INI_MAX_STRLEN - 1); \
} while (0)
#define MEDIA_CODEC_INI_GET_STRING_FROM_LIST(x_dict, x_list, x_ini, x_default) \
#define MEDIA_CODEC_INI_GET_COLOR(x_dict, x_item, x_ini, x_default) \
do {\
- gchar* str = iniparser_getstring(x_dict, x_ini, x_default); \
+ const char *str = iniparser_getstring(x_dict, x_ini, x_default); \
\
if (str && \
(strlen(str) > 0) && \
int _mediacodec_foreach_supported_codec(mediacodec_supported_codec_cb callback, void *user_data)
{
- int ret = MEDIACODEC_NONE;
int i;
int index;
for (i = 0; i < CODEC_NR_ITEMS; i++) {
if (codec[i]) {
index = (int)simple_to_codec_type_enumeration(i);
- if (!callback(index, user_data))
- goto CALLBACK_ERROR;
+ if (!callback(index, user_data)) {
+ LOGW("stop foreach callback");
+ break;
+ }
}
}
- if (!callback(-1, user_data)) {
- ret = MEDIACODEC_ERROR_INTERNAL;
- goto CALLBACK_ERROR;
- }
+ LOGD("done");
-CALLBACK_ERROR:
- LOGD("foreach callback returned error");
- return ret;
+ return MEDIACODEC_ERROR_NONE;
}
int mc_get_packet_pool(MMHandleType mediacodec, media_packet_pool_h *pool)
GstCaps *_mc_gst_vid_caps_new(mc_gst_core_t *core, mediacodec_codec_type_e codec_id, gint index);
GstCaps *_mc_gst_aud_caps_new(mc_gst_core_t *core, mediacodec_codec_type_e codec_id, gint index);
+static int __mc_fill_input_buffer(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
+static int __mc_fill_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
+
+static int __mc_fill_input_buffer_with_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
+static int __mc_fill_input_buffer_with_adec_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
+static int __mc_fill_input_buffer_with_venc_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer);
+
+static int __mc_fill_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
+static int __mc_fill_aenc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
+static int __mc_fill_venc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
+static int __mc_fill_vdec_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer);
+
+static mc_gst_core_t *mc_gst_core_new();
+static void mc_gst_core_free(mc_gst_core_t *core);
+
+static mc_gst_port_t *mc_gst_port_new(mc_gst_core_t *core);
+static void mc_gst_port_free(mc_gst_port_t *port);
/* video vtable */
int(*vdec_vtable[])() = {&__mc_fill_input_buffer_with_packet, &__mc_fill_packet_with_output_buffer};
int(*venc_vtable[])() = {&__mc_fill_input_buffer_with_packet, &__mc_fill_packet_with_output_buffer};
int(*adec_wma_vtable[])() = {&__mc_fill_input_buffer_with_packet, /* WMA Decoder Vtable */
&__mc_fill_packet_with_output_buffer};
+#define MEDIACODEC_ELEMENT_SET_STATE(x_element, x_state) \
+ do { \
+ LOGD("setting state [%s:%d] to [%s]\n", #x_state, x_state, GST_ELEMENT_NAME(x_element)); \
+ if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(x_element, x_state)) { \
+ LOGE("failed to set state %s to %s\n", #x_state, GST_ELEMENT_NAME(x_element)); \
+ goto STATE_CHANGE_FAILED; \
+ } \
+ } while (0)
/*
* fill_inbuf virtual functions
return ret;
}
-int __mc_fill_input_buffer_with_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer)
+static int __mc_fill_input_buffer_with_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer)
{
gint ret = MC_ERROR_NONE;
void *buf_data = NULL;
return ret;
}
-int __mc_fill_input_buffer_with_adec_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer)
+static int __mc_fill_input_buffer_with_adec_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer)
{
gint ret = MC_ERROR_NONE;
uint64_t buf_size = 0;
return ret;
}
-int __mc_fill_input_buffer_with_venc_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer)
+static int __mc_fill_input_buffer_with_venc_packet(mc_gst_core_t *core, media_packet_h packet, GstMCBuffer *mcbuffer)
{
gint ret = MC_ERROR_NONE;
gint i;
* fill_outbuf virtual functions
*/
-int __mc_fill_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
+static int __mc_fill_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
{
return core->vtable[fill_outbuf](core, data, size, mcbuffer);
}
-int __mc_fill_vdec_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
+static int __mc_fill_vdec_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
{
int i;
int stride_width;
return MC_ERROR_NONE;
}
-int __mc_fill_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
+static int __mc_fill_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
{
gint ret = MC_ERROR_NONE;
gchar *ext_mem = NULL;
return MC_ERROR_NONE;
}
-int __mc_fill_venc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
+static int __mc_fill_venc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
{
gint ret = MC_ERROR_NONE;
bool codec_config = FALSE;
return ret;
}
-int __mc_fill_aenc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
+static int __mc_fill_aenc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
{
int ret = MC_ERROR_NONE;
gint mem_size = 0;
/*
* mc_gst_core functions
*/
-mc_gst_core_t *mc_gst_core_new()
+static mc_gst_core_t *mc_gst_core_new()
{
mc_gst_core_t *core;
core->available_queue = g_new0(mc_aqueue_t, 1);
core->available_queue->input = mc_async_queue_new();
- mc_async_queue_enable(core->available_queue->input);
g_mutex_init(&core->eos_mutex);
g_cond_init(&core->eos_cond);
return core;
}
-void mc_gst_core_free(mc_gst_core_t *core)
+static void mc_gst_core_free(mc_gst_core_t *core)
{
MEDIACODEC_FENTER();
/*
* mc_gst_port functions
*/
-mc_gst_port_t *mc_gst_port_new(mc_gst_core_t *core)
+static mc_gst_port_t *mc_gst_port_new(mc_gst_core_t *core)
{
MEDIACODEC_FENTER();
return port;
}
-void mc_gst_port_free(mc_gst_port_t *port)
+static void mc_gst_port_free(mc_gst_port_t *port)
{
MEDIACODEC_FENTER();
return ret;
}
-mc_ret_e mc_gst_process_input(mc_handle_t *mc_handle, media_packet_h inbuf, uint64_t timeOutUs)
+mc_ret_e mc_gst_process_input(mc_handle_t *mc_handle, media_packet_h inbuf, uint64_t timeout_us)
{
MEDIACODEC_FENTER();
return ret;
}
-mc_ret_e mc_gst_get_output(mc_handle_t *mc_handle, media_packet_h *outbuf, uint64_t timeOutUs)
+mc_ret_e mc_gst_get_output(mc_handle_t *mc_handle, media_packet_h *outbuf, uint64_t timeout_us)
{
gint ret = MC_ERROR_NONE;
gint64 end_time = -1;
media_packet_h out_packet = NULL;
MEDIACODEC_FENTER();
- end_time = g_get_monotonic_time() + timeOutUs;
+ end_time = g_get_monotonic_time() + timeout_us;
if (!mc_handle)
return MC_PARAM_ERROR;
* will not be invoked
*/
gst_buffer_unref(mcbuffer->buffer);
- free(mcbuffer);
+ g_free(mcbuffer);
return NULL;
}
media_packet_h packet = NULL;
MEDIACODEC_FENTER();
- if (media_packet_create_alloc(fmt, __mc_output_buffer_finalize_cb, mcbuffer, &packet)) {
- LOGE("media_packet_create_alloc failed\n");
+ if (media_packet_create(fmt, __mc_output_buffer_finalize_cb, mcbuffer, &packet)) {
+ LOGE("media_packet_create failed\n");
ret = MC_ERROR;
goto ERROR;
}
return;
LOGD("============>>>>> _finalize_cb : %p, %p", mcbuffer, mcbuffer->packet);
- mc_gst_core_t *core = (mc_gst_core_t *)mcbuffer->core;
- _mc_gst_handle_input_buffer_used(core, mcbuffer->packet);
+ _mc_gst_handle_input_buffer_used(mcbuffer->core, mcbuffer->packet);
g_free(mcbuffer);
- mcbuffer = NULL;
MEDIACODEC_FLEAVE();
-
- return;
}
static GstMCBuffer *gst_mediacodec_buffer_new(mc_gst_core_t *core, media_packet_h packet, uint64_t size)
mcbuffer = (GstMCBuffer *)g_malloc0(sizeof(GstMCBuffer));
- if (mcbuffer == NULL) {
- LOGE("malloc fail");
- return NULL;
- }
-
mcbuffer->buffer = gst_buffer_new();
mcbuffer->buf_size = 0;
--- /dev/null
+/*
+ * Copyright (c) 2019 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 <inttypes.h>
+#include <dlog.h>
+#include <media_codec_sync_private.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "TIZEN_N_MEDIACODECSYNC"
+
+#define PIPELINE_NAME_AUDIO "MEDIACODECSYNC_AUDIO"
+#define PIPELINE_NAME_VIDEO "MEDIACODECSYNC_VIDEO"
+
+#define _MEDIACODECSYNC_PIPELINE_MAKE(handle, pipeline, name) \
+ do { \
+ if (pipeline) { \
+ gst_object_unref(pipeline); \
+ pipeline = NULL; \
+ } \
+ pipeline = gst_pipeline_new(name); \
+ if (!pipeline) { \
+ LOGE("create pipeline[%s] failed", name); \
+ goto _CREATE_PIPELINE_FAILED; \
+ } \
+ g_object_weak_ref(G_OBJECT(pipeline), (GWeakNotify)__mediacodecsync_element_release_noti, handle); \
+ LOGD("create pipeline [%s] done", name); \
+ } while (0)
+
+#define _MEDIACODECSYNC_ELEMENT_MAKE(handle, element, name, prefix, nick) \
+ do { \
+ char nick_name[24]; \
+ if (element) { \
+ gst_object_unref(element); \
+ element = NULL; \
+ } \
+ snprintf(nick_name, sizeof(nick_name), "%s%s", prefix, nick); \
+ element = gst_element_factory_make(name, nick_name); \
+ if (!element) { \
+ LOGE("create element[%s,%s] failed", name, nick_name); \
+ goto _CREATE_PIPELINE_FAILED; \
+ } \
+ g_object_weak_ref(G_OBJECT(element), (GWeakNotify)__mediacodecsync_element_release_noti, handle); \
+ LOGD("create element [%s,%s] done", name, nick_name); \
+ } while (0)
+
+#define _MEDIACODECSYNC_ELEMENT_REMOVE(element) \
+ do { \
+ if (element != NULL) \
+ gst_object_unref(element); \
+ } while (0)
+
+
+
+static void __mediacodecsync_need_audio_data_cb(GstElement *appsrc, guint size, gpointer data)
+{
+ /*mediacodecsync_s *handle = (mediacodecsync_s *)data;*/
+
+ LOGI("audio data is needed");
+}
+
+
+static void __mediacodecsync_enough_audio_data_cb(GstElement *appsrc, gpointer data)
+{
+ /*mediacodecsync_s *handle = (mediacodecsync_s *)data;*/
+
+ LOGI("audio data is enough");
+}
+
+
+static void __mediacodecsync_need_video_data_cb(GstElement *appsrc, guint size, gpointer data)
+{
+ /*mediacodecsync_s *handle = (mediacodecsync_s *)data;*/
+
+ LOGI("video data is needed");
+}
+
+
+static void __mediacodecsync_enough_video_data_cb(GstElement *appsrc, gpointer data)
+{
+ /*mediacodecsync_s *handle = (mediacodecsync_s *)data;*/
+
+ LOGI("video data is enough");
+}
+
+
+static int _mediacodecsync_get_packet_info(media_packet_h packet, packet_info *info)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ bool has_tbm_surface = false;
+ void *data = NULL;
+ uint64_t data_size = 0;
+ uint64_t dts = 0;
+ uint64_t pts = 0;
+ uint64_t duration = 0;
+
+ if (!packet || !info) {
+ LOGE("NULL params %p %p", packet, info);
+ return MEDIACODEC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* get packet info */
+ ret = media_packet_has_tbm_surface_buffer(packet, &has_tbm_surface);
+ ret |= media_packet_get_buffer_data_ptr(packet, &data);
+ ret |= media_packet_get_buffer_size(packet, &data_size);
+ ret |= media_packet_get_dts(packet, &dts);
+ ret |= media_packet_get_pts(packet, &pts);
+ ret |= media_packet_get_duration(packet, &duration);
+
+ if (ret == MEDIACODEC_ERROR_NONE) {
+ info->has_tbm_surface = has_tbm_surface;
+ info->data = data;
+ info->data_size = data_size;
+ info->dts = dts;
+ info->pts = pts;
+ info->duration = duration;
+
+ LOGI("packet info[%u], %p, size %"PRIu64", dts %"PRIu64", pts %"PRIu64", duration %"PRIu64,
+ has_tbm_surface, data, data_size, dts, pts, duration);
+ }
+
+ return ret;
+}
+
+
+static void _mediacodecsync_gst_buffer_finalize(GstMCSBuffer *mcs_buffer)
+{
+ mediacodecsync_s *handle = NULL;
+
+ if (!mcs_buffer || !mcs_buffer->handle) {
+ LOGE("NULL buffer(%p) or handle", mcs_buffer);
+ return;
+ }
+
+ handle = mcs_buffer->handle;
+
+ LOGI("[type %d] mcs_buffer %p, gst buffer %p, packet %p",
+ mcs_buffer->type, mcs_buffer, mcs_buffer->gst_buffer, mcs_buffer->packet);
+
+ if (mcs_buffer->packet) {
+ if (handle->buffer_used_cb)
+ handle->buffer_used_cb(mcs_buffer->packet, mcs_buffer->type, handle->buffer_used_cb_userdata);
+ else
+ LOGE("No buffer used callback");
+ }
+
+ free(mcs_buffer);
+}
+
+
+static GstMCSBuffer *_mediacodecsync_gst_buffer_new(mediacodecsync_s *handle, media_packet_h packet, int type)
+{
+ GstMCSBuffer *new_buffer = NULL;
+ GstMemory *memory = NULL;
+ tbm_surface_h tbm_surface = NULL;
+ packet_info info;
+
+ if (!handle || !packet) {
+ LOGE("invalid params %p, %p", handle, packet);
+ return NULL;
+ }
+
+ /* get packet info */
+ if (_mediacodecsync_get_packet_info(packet, &info) != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("_mediacodecsync_get_packet_info failed");
+ return NULL;
+ }
+
+ new_buffer = (GstMCSBuffer *)calloc(1, sizeof(GstMCSBuffer));
+ if (!new_buffer) {
+ LOGE("GstMCSBuffer alloc failed");
+ return NULL;
+ }
+
+ new_buffer->gst_buffer = gst_buffer_new();
+ new_buffer->type = type;
+ new_buffer->packet = packet;
+ new_buffer->handle = handle;
+
+ if (info.has_tbm_surface) {
+ /* get tbm surface from packet */
+ if (media_packet_get_tbm_surface(packet, &tbm_surface) != MEDIA_PACKET_ERROR_NONE) {
+ LOGE("get tbm surface failed");
+ goto _BUFFER_NEW_FAILED;
+ }
+
+ /* create tizen memory for gst buffer with tbm surface */
+ memory = gst_tizen_allocator_alloc_surface(handle->allocator,
+ &handle->video_info, tbm_surface, (gpointer)new_buffer,
+ (GDestroyNotify)_mediacodecsync_gst_buffer_finalize);
+ } else {
+ /* If tbm is not used, the data from packet will be used. */
+ memory = gst_memory_new_wrapped(0, info.data, (gsize)info.data_size,
+ 0, (gsize)info.data_size, (gpointer)new_buffer,
+ (GDestroyNotify)_mediacodecsync_gst_buffer_finalize);
+ }
+
+ if (!memory) {
+ LOGE("GstMemory failed");
+ goto _BUFFER_NEW_FAILED;
+ }
+
+ gst_buffer_append_memory(new_buffer->gst_buffer, memory);
+
+ /* set buffer meta */
+ gst_buffer_set_size(new_buffer->gst_buffer, info.data_size);
+ GST_BUFFER_DTS(new_buffer->gst_buffer) = info.dts;
+ GST_BUFFER_PTS(new_buffer->gst_buffer) = info.pts;
+ GST_BUFFER_DURATION(new_buffer->gst_buffer) = info.duration;
+ GST_BUFFER_OFFSET(new_buffer->gst_buffer) = 0;
+ GST_BUFFER_OFFSET_END(new_buffer->gst_buffer) = info.data_size;
+
+ return new_buffer;
+
+_BUFFER_NEW_FAILED:
+ gst_buffer_unref(new_buffer->gst_buffer);
+ free(new_buffer);
+ return NULL;
+}
+
+static void __mediacodecsync_element_release_noti(gpointer data, GObject *obj)
+{
+ int i = 0;
+ mediacodecsync_s *handle = (mediacodecsync_s *)data;
+
+ if (!handle) {
+ LOGE("NULL handle");
+ return;
+ }
+
+ for (i = 0 ; i < MEDIACODECSYNC_ELEMENT_NUM ; i++) {
+ if (handle->audio_pipe[i] && G_OBJECT(handle->audio_pipe[i]) == obj) {
+ LOGD("audio element[%d] was released", i);
+ handle->audio_pipe[i] = NULL;
+ return;
+ }
+ }
+
+ for (i = 0 ; i < MEDIACODECSYNC_ELEMENT_NUM ; i++) {
+ if (handle->video_pipe[i] && G_OBJECT(handle->video_pipe[i]) == obj) {
+ LOGD("video element[%d] was released", i);
+ handle->video_pipe[i] = NULL;
+ return;
+ }
+ }
+
+ LOGW("no matched element [%p]", obj);
+}
+
+
+static GstCaps *_mediacodecsync_make_caps_from_mediaformat(media_format_h format)
+{
+ int i = 0;
+ GstCaps *new_caps = NULL;
+ media_format_type_e type = MEDIA_FORMAT_NONE;
+ media_format_mimetype_e mime_type = 0;
+
+ format_table audio_table[AUDIO_FORMAT_TABLE_SIZE] = {
+ {MEDIA_FORMAT_PCM, "S16LE"},
+ {MEDIA_FORMAT_PCM_S16LE, "S16LE"},
+ {MEDIA_FORMAT_PCM_S24LE, "S24LE"},
+ {MEDIA_FORMAT_PCM_S32LE, "S32LE"},
+ {MEDIA_FORMAT_PCM_S16BE, "S16BE"},
+ {MEDIA_FORMAT_PCM_S24BE, "S24BE"},
+ {MEDIA_FORMAT_PCM_S32BE, "S32BE"},
+ {MEDIA_FORMAT_PCM_F32LE, "F32LE"},
+ {MEDIA_FORMAT_PCM_F32BE, "F32BE"},
+ {MEDIA_FORMAT_PCM_U16LE, "U16LE"},
+ {MEDIA_FORMAT_PCM_U24LE, "U24LE"},
+ {MEDIA_FORMAT_PCM_U32LE, "U32LE"},
+ {MEDIA_FORMAT_PCM_U16BE, "U16BE"},
+ {MEDIA_FORMAT_PCM_U24BE, "U24BE"},
+ {MEDIA_FORMAT_PCM_U32BE, "U32BE"}
+ };
+ format_table video_table[VIDEO_FORMAT_TABLE_SIZE] = {
+ {MEDIA_FORMAT_I420, "I420"},
+ {MEDIA_FORMAT_NV12, "SN12"},
+ {MEDIA_FORMAT_NV12T, "NV12T"},
+ {MEDIA_FORMAT_YV12, "YV12"},
+ {MEDIA_FORMAT_NV21, "NV21"},
+ {MEDIA_FORMAT_NV16, "NV16"},
+ {MEDIA_FORMAT_YUYV, "YUYV"},
+ {MEDIA_FORMAT_UYVY, "UYVY"}
+ };
+
+ if (media_format_get_type(format, &type) != MEDIA_FORMAT_ERROR_NONE) {
+ LOGE("get type failed");
+ return NULL;
+ }
+
+ if (type & MEDIA_FORMAT_AUDIO) {
+ int channel;
+ int samplerate;
+ int bit;
+
+ if (media_format_get_audio_info(format, &mime_type, &channel,
+ &samplerate, &bit, NULL) != MEDIA_FORMAT_ERROR_NONE) {
+ LOGE("get audio info failed");
+ return NULL;
+ }
+
+ for (i = 0 ; i < AUDIO_FORMAT_TABLE_SIZE ; i++) {
+ if (audio_table[i].mime_type == mime_type) {
+ new_caps = gst_caps_new_simple("audio/x-raw",
+ "rate", G_TYPE_INT, samplerate,
+ "channels", G_TYPE_INT, channel,
+ "format", G_TYPE_STRING, audio_table[i].format_string,
+ NULL);
+ break;
+ }
+ }
+ } else if (type & MEDIA_FORMAT_VIDEO) {
+ int width;
+ int height;
+
+ if (media_format_get_video_info(format, &mime_type,
+ &width, &height, NULL, NULL) != MEDIA_FORMAT_ERROR_NONE) {
+ LOGE("get video info failed");
+ return NULL;
+ }
+
+ for (i = 0 ; i < VIDEO_FORMAT_TABLE_SIZE ; i++) {
+ if (video_table[i].mime_type == mime_type) {
+ new_caps = gst_caps_new_simple("video/x-raw",
+ "format", G_TYPE_STRING, video_table[i].format_string,
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ "framerate", GST_TYPE_FRACTION, 30, 1,
+ NULL);
+ break;
+ }
+ }
+ }
+
+ if (new_caps) {
+ gchar *caps_string = gst_caps_to_string(new_caps);
+ if (caps_string) {
+ LOGD("caps [%s]", caps_string);
+ g_free(caps_string);
+ }
+ } else {
+ LOGE("new caps failed [type:0x%x,0x%x]", type, mime_type);
+ }
+
+ return new_caps;
+}
+
+
+static void _mediacodecsync_destroy_pipeline(GstElement *pipeline[MEDIACODECSYNC_ELEMENT_NUM])
+{
+ GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
+
+ if (!pipeline[MEDIACODECSYNC_PIPELINE]) {
+ LOGW("NULL pipeline");
+ return;
+ }
+
+ result = gst_element_set_state(pipeline[MEDIACODECSYNC_PIPELINE], GST_STATE_NULL);
+
+ LOGD("set state NULL : %d", result);
+
+ _MEDIACODECSYNC_ELEMENT_REMOVE(pipeline[MEDIACODECSYNC_PIPELINE]);
+ _MEDIACODECSYNC_ELEMENT_REMOVE(pipeline[MEDIACODECSYNC_ELEMENT_APPSRC]);
+ _MEDIACODECSYNC_ELEMENT_REMOVE(pipeline[MEDIACODECSYNC_ELEMENT_CAPS]);
+ _MEDIACODECSYNC_ELEMENT_REMOVE(pipeline[MEDIACODECSYNC_ELEMENT_QUE]);
+ _MEDIACODECSYNC_ELEMENT_REMOVE(pipeline[MEDIACODECSYNC_ELEMENT_SINK]);
+}
+
+
+static int _mediacodecsync_create_pipeline(mediacodecsync_s *handle, media_format_h format,
+ GstElement *pipeline[MEDIACODECSYNC_ELEMENT_NUM], const char *pipe_name, const char *nick_prefix,
+ GCallback need_data_cb, GCallback enough_data_cb, GstCaps **out_caps)
+{
+ GstCaps *caps = NULL;
+
+ LOGD("name : %s", pipe_name);
+
+ /* main pipeline */
+ _MEDIACODECSYNC_PIPELINE_MAKE(handle, pipeline[MEDIACODECSYNC_PIPELINE], pipe_name);
+
+ /* elements */
+ _MEDIACODECSYNC_ELEMENT_MAKE(handle, pipeline[MEDIACODECSYNC_ELEMENT_APPSRC], "appsrc", nick_prefix, "src");
+ _MEDIACODECSYNC_ELEMENT_MAKE(handle, pipeline[MEDIACODECSYNC_ELEMENT_CAPS], "capsfilter", nick_prefix, "caps");
+
+ if (!strncmp(nick_prefix, "audio", 5)) {
+ _MEDIACODECSYNC_ELEMENT_MAKE(handle, pipeline[MEDIACODECSYNC_ELEMENT_QUE], "queue", nick_prefix, "queue");
+ _MEDIACODECSYNC_ELEMENT_MAKE(handle, pipeline[MEDIACODECSYNC_ELEMENT_SINK], "pulsesink", nick_prefix, "sink");
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_SINK]), "qos", 1, NULL);
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_SINK]), "provide-clock", 0, NULL);
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_SINK]), "slave-method", 2, NULL); /* GST_AUDIO_BASE_SINK_SLAVE_NONE */
+ } else {
+ _MEDIACODECSYNC_ELEMENT_MAKE(handle, pipeline[MEDIACODECSYNC_ELEMENT_QUE], "queue", nick_prefix, "queue");
+ _MEDIACODECSYNC_ELEMENT_MAKE(handle, pipeline[MEDIACODECSYNC_ELEMENT_SINK], "tizenwlsink", nick_prefix, "sink");
+
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_SINK]), "use-tbm", 1, NULL);
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_SINK]), "enable-last-sample", 0, NULL);
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_SINK]), "show-preroll-frame", 0, NULL);
+ }
+
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_APPSRC]), "max-bytes", (guint64)0, NULL); /* unlimited */
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_QUE]), "max-size-time", 0, NULL);
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_QUE]), "max-size-bytes", 0, NULL);
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_QUE]), "max-size-buffers", 0, NULL);
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_APPSRC]), "format", 3, NULL); /* GST_FORMAT_TIME */
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_SINK]), "sync", 1, NULL);
+
+ /* add elements to pipeline */
+ gst_bin_add_many(GST_BIN(pipeline[MEDIACODECSYNC_PIPELINE]),
+ pipeline[MEDIACODECSYNC_ELEMENT_APPSRC],
+ pipeline[MEDIACODECSYNC_ELEMENT_CAPS],
+ pipeline[MEDIACODECSYNC_ELEMENT_QUE],
+ pipeline[MEDIACODECSYNC_ELEMENT_SINK],
+ NULL);
+
+ /* link elements */
+ if (!(gst_element_link_many(pipeline[MEDIACODECSYNC_ELEMENT_APPSRC],
+ pipeline[MEDIACODECSYNC_ELEMENT_CAPS],
+ pipeline[MEDIACODECSYNC_ELEMENT_QUE],
+ pipeline[MEDIACODECSYNC_ELEMENT_SINK],
+ NULL))) {
+ LOGE("link elements failed");
+ goto _CREATE_PIPELINE_FAILED;
+ }
+
+ /* set capsfilter */
+ caps = _mediacodecsync_make_caps_from_mediaformat(format);
+ if (!caps) {
+ LOGE("pipeline caps failed");
+ goto _CREATE_PIPELINE_FAILED;
+ }
+
+ g_object_set(G_OBJECT(pipeline[MEDIACODECSYNC_ELEMENT_CAPS]), "caps", caps, NULL);
+
+ if (out_caps) {
+ if (*out_caps) {
+ LOGD("unref previous video_caps %p", *out_caps);
+ gst_caps_unref(*out_caps);
+ *out_caps = NULL;
+ }
+
+ *out_caps = caps;
+ } else {
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+
+ g_signal_connect(pipeline[MEDIACODECSYNC_ELEMENT_APPSRC], "need-data", need_data_cb, handle);
+ g_signal_connect(pipeline[MEDIACODECSYNC_ELEMENT_APPSRC], "enough-data", enough_data_cb, handle);
+
+ LOGD("done");
+
+ return MEDIACODEC_ERROR_NONE;
+
+_CREATE_PIPELINE_FAILED:
+ LOGE("[%s] failed", pipe_name);
+
+ _mediacodecsync_destroy_pipeline(pipeline);
+
+ return MEDIACODEC_ERROR_INTERNAL;
+}
+
+
+static int _mediacodecsync_prepare_pipeline(mediacodecsync_s *handle)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ GstClock *clock = NULL;
+ GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
+
+ LOGD("enter");
+
+ if (handle->audio_format) {
+ /* create audio pipeline */
+ ret = _mediacodecsync_create_pipeline(handle, handle->audio_format,
+ handle->audio_pipe, PIPELINE_NAME_AUDIO, "audio",
+ (GCallback)__mediacodecsync_need_audio_data_cb,
+ (GCallback)__mediacodecsync_enough_audio_data_cb,
+ NULL);
+ if (ret != MEDIACODEC_ERROR_NONE)
+ return ret;
+
+ /* set state */
+ result = gst_element_set_state(handle->audio_pipe[MEDIACODECSYNC_PIPELINE], GST_STATE_PAUSED);
+ if (result == GST_STATE_CHANGE_FAILURE) {
+ LOGE("state change failed - VIDEO pipeline");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _PREPARE_FAILED;
+ }
+
+ LOGD("audio pipeline done");
+ }
+
+ if (handle->video_format) {
+ /* create video pipeline */
+ ret = _mediacodecsync_create_pipeline(handle, handle->video_format,
+ handle->video_pipe, PIPELINE_NAME_VIDEO, "video",
+ (GCallback)__mediacodecsync_need_video_data_cb,
+ (GCallback)__mediacodecsync_enough_video_data_cb,
+ &handle->video_caps);
+ if (ret != MEDIACODEC_ERROR_NONE)
+ goto _PREPARE_FAILED;
+
+ /* get video info */
+ if (!gst_video_info_from_caps(&handle->video_info, handle->video_caps)) {
+ LOGE("failed to get video info");
+ goto _PREPARE_FAILED;
+ }
+
+ /* set state */
+ result = gst_element_set_state(handle->video_pipe[MEDIACODECSYNC_PIPELINE], GST_STATE_PAUSED);
+ if (result == GST_STATE_CHANGE_FAILURE) {
+ LOGE("state change failed - VIDEO pipeline");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _PREPARE_FAILED;
+ }
+
+ LOGD("video pipeline done");
+
+ /* share clock to synchronize */
+ if (handle->audio_pipe[MEDIACODECSYNC_PIPELINE]) {
+ LOGD("set clock of audio pipeline to video pipeline");
+
+ clock = gst_pipeline_get_clock(GST_PIPELINE(handle->audio_pipe[MEDIACODECSYNC_PIPELINE]));
+
+ if (!gst_pipeline_set_clock(GST_PIPELINE(handle->video_pipe[MEDIACODECSYNC_PIPELINE]), clock))
+ LOGW("failed to set clock to video pipeline");
+
+ gst_object_unref(clock);
+ clock = NULL;
+ }
+ }
+
+ LOGD("done");
+
+ return ret;
+
+_PREPARE_FAILED:
+ _mediacodecsync_destroy_pipeline(handle->audio_pipe);
+ _mediacodecsync_destroy_pipeline(handle->video_pipe);
+
+ return ret;
+}
+
+
+static void _mediacodecsync_unprepare_pipeline(mediacodecsync_s *handle)
+{
+ _mediacodecsync_destroy_pipeline(handle->audio_pipe);
+ _mediacodecsync_destroy_pipeline(handle->video_pipe);
+}
+
+
+
+int mediacodecsync_create(mediacodecsync_buffer_used_cb callback, void *userdata, mediacodecsync_h *mediacodecsync)
+{
+ mediacodecsync_s *new_handle = NULL;
+
+ MEDIACODEC_NULL_ARG_CHECK(mediacodecsync);
+ MEDIACODEC_NULL_ARG_CHECK(callback);
+
+ LOGD("enter");
+
+ new_handle = (mediacodecsync_s *)malloc(sizeof(mediacodecsync_s));
+ if (new_handle == NULL) {
+ LOGE("handle allocation failed");
+ return MEDIACODEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset(new_handle, 0x0, sizeof(mediacodecsync_s));
+
+ new_handle->buffer_used_cb = callback;
+ new_handle->buffer_used_cb_userdata = userdata;
+ new_handle->state = MEDIACODECSYNC_STATE_CREATED;
+ new_handle->allocator = gst_tizen_allocator_new();
+ g_mutex_init(&new_handle->lock);
+
+ *mediacodecsync = (mediacodecsync_h)new_handle;
+
+ LOGD("new handle : %p", *mediacodecsync);
+
+ return MEDIACODEC_ERROR_NONE;
+}
+
+
+int mediacodecsync_destroy(mediacodecsync_h mediacodecsync)
+{
+ mediacodecsync_s *handle = NULL;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ LOGD("handle to destroy : %p", handle);
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIACODECSYNC_STATE_CREATED) {
+ LOGE("invalid state %d", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIACODEC_ERROR_INVALID_STATE;
+ }
+
+ if (handle->audio_format) {
+ media_format_unref(handle->audio_format);
+ handle->audio_format = NULL;
+ }
+
+ if (handle->video_format) {
+ media_format_unref(handle->video_format);
+ handle->video_format = NULL;
+ }
+
+ if (handle->video_caps) {
+ gst_caps_unref(handle->video_caps);
+ handle->video_caps = NULL;
+ }
+
+ g_mutex_unlock(&handle->lock);
+
+ g_mutex_clear(&handle->lock);
+
+ free(handle);
+
+ LOGD("done");
+
+ return MEDIACODEC_ERROR_NONE;
+}
+
+
+int mediacodecsync_set_format(mediacodecsync_h mediacodecsync, media_format_h audio_format, media_format_h video_format)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ mediacodecsync_s *handle = NULL;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ if (!audio_format && !video_format) {
+ LOGE("all formats are NULL");
+ return MEDIACODEC_ERROR_INVALID_PARAMETER;
+ }
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIACODECSYNC_STATE_CREATED) {
+ LOGE("invalid state %d", handle->state);
+ ret = MEDIACODEC_ERROR_INVALID_STATE;
+ goto _SET_FORMAT_DONE;
+ }
+
+ if (audio_format) {
+ LOGD("set audio format : %p", audio_format);
+
+ if (media_format_ref(audio_format) != MEDIACODEC_ERROR_NONE) {
+ LOGE("audio format ref failed");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _SET_FORMAT_DONE;
+ }
+
+ if (handle->audio_format)
+ media_format_unref(handle->audio_format);
+
+ handle->audio_format = audio_format;
+ }
+
+ if (video_format) {
+ LOGD("set video format : %p", video_format);
+
+ if (media_format_ref(video_format) != MEDIACODEC_ERROR_NONE) {
+ LOGE("video format ref failed");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _SET_FORMAT_DONE;
+ }
+
+ if (handle->video_format)
+ media_format_unref(handle->video_format);
+
+ handle->video_format = video_format;
+ }
+
+_SET_FORMAT_DONE:
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int mediacodecsync_prepare(mediacodecsync_h mediacodecsync)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ mediacodecsync_s *handle = NULL;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIACODECSYNC_STATE_CREATED) {
+ LOGE("invalid state %d", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIACODEC_ERROR_INVALID_STATE;
+ }
+
+ ret = _mediacodecsync_prepare_pipeline(handle);
+ if (ret == MEDIACODEC_ERROR_NONE)
+ handle->state = MEDIACODECSYNC_STATE_READY;
+
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int mediacodecsync_unprepare(mediacodecsync_h mediacodecsync)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ mediacodecsync_s *handle = NULL;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIACODECSYNC_STATE_READY) {
+ LOGE("invalid state %d", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIACODEC_ERROR_INVALID_STATE;
+ }
+
+ _mediacodecsync_unprepare_pipeline(handle);
+ handle->state = MEDIACODECSYNC_STATE_CREATED;
+
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int mediacodecsync_run(mediacodecsync_h mediacodecsync)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ mediacodecsync_s *handle = NULL;
+ GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIACODECSYNC_STATE_READY &&
+ handle->state != MEDIACODECSYNC_STATE_PAUSED) {
+ LOGE("invalid state %d", handle->state);
+ ret = MEDIACODEC_ERROR_INVALID_STATE;
+ goto _RUN_DONE;
+ }
+
+ /* set state */
+ if (handle->audio_pipe[MEDIACODECSYNC_PIPELINE]) {
+ result = gst_element_set_state(handle->audio_pipe[MEDIACODECSYNC_PIPELINE], GST_STATE_PLAYING);
+ if (result == GST_STATE_CHANGE_FAILURE) {
+ LOGE("state change failed - AUDIO pipeline");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _RUN_DONE;
+ }
+ }
+
+ if (handle->video_pipe[MEDIACODECSYNC_PIPELINE]) {
+ result = gst_element_set_state(handle->video_pipe[MEDIACODECSYNC_PIPELINE], GST_STATE_PLAYING);
+ if (result == GST_STATE_CHANGE_FAILURE) {
+ LOGE("state change failed - VIDEO pipeline");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _RUN_DONE;
+ }
+ }
+
+ LOGD("pipeline is now playing");
+ handle->state = MEDIACODECSYNC_STATE_RUNNING;
+
+_RUN_DONE:
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int mediacodecsync_stop(mediacodecsync_h mediacodecsync)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ mediacodecsync_s *handle = NULL;
+ GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state < MEDIACODECSYNC_STATE_RUNNING) {
+ LOGE("invalid state %d", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIACODEC_ERROR_INVALID_STATE;
+ }
+
+ /* set state */
+ result = gst_element_set_state(handle->video_pipe[MEDIACODECSYNC_PIPELINE], GST_STATE_READY);
+ if (result == GST_STATE_CHANGE_FAILURE) {
+ LOGE("state change failed - VIDEO pipeline");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ } else {
+ LOGD("pipeline is ready");
+ handle->state = MEDIACODECSYNC_STATE_READY;
+ }
+
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int mediacodecsync_pause(mediacodecsync_h mediacodecsync)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ mediacodecsync_s *handle = NULL;
+ GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIACODECSYNC_STATE_RUNNING) {
+ LOGE("invalid state %d", handle->state);
+ g_mutex_unlock(&handle->lock);
+ return MEDIACODEC_ERROR_INVALID_STATE;
+ }
+
+ /* set state */
+ result = gst_element_set_state(handle->video_pipe[MEDIACODECSYNC_PIPELINE], GST_STATE_PAUSED);
+ if (result == GST_STATE_CHANGE_FAILURE) {
+ LOGE("state change failed - VIDEO pipeline");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ } else {
+ LOGD("pipeline is paused");
+ handle->state = MEDIACODECSYNC_STATE_PAUSED;
+ }
+
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+static int _mediacodecsync_push_packet_to_pipeline(GstElement *appsrc, GstBuffer *buffer)
+{
+ GstFlowReturn gst_ret = GST_FLOW_OK;
+
+ if (!appsrc || !buffer) {
+ LOGE("NULL params %p,%p", appsrc, buffer);
+ return MEDIACODEC_ERROR_INTERNAL;
+ }
+
+ gst_ret = gst_app_src_push_buffer((GstAppSrc *)appsrc, buffer);
+ if (gst_ret != GST_FLOW_OK) {
+ LOGE("appsrc push failed %d", gst_ret);
+ return MEDIACODEC_ERROR_INTERNAL;
+ }
+
+ return MEDIACODEC_ERROR_NONE;
+}
+
+
+int mediacodecsync_push_packet(mediacodecsync_h mediacodecsync, media_packet_h packet, mediacodecsync_packet_type_e type)
+{
+ int ret = MEDIACODEC_ERROR_NONE;
+ mediacodecsync_s *handle = NULL;
+ GstMCSBuffer *mcs_buffer = NULL;
+ GstElement *appsrc = NULL;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ g_mutex_lock(&handle->lock);
+
+ if (handle->state != MEDIACODECSYNC_STATE_RUNNING) {
+ LOGE("invalid state %d", handle->state);
+ ret = MEDIACODEC_ERROR_INVALID_STATE;
+ goto _PUSH_PACKET_DONE;
+ }
+
+ mcs_buffer = _mediacodecsync_gst_buffer_new(handle, packet, type);
+ if (!mcs_buffer) {
+ LOGE("mediacodecsync new buffer failed");
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _PUSH_PACKET_DONE;
+ }
+
+ LOGI("type %u, new buffer %p [gst %p][packet %p]",
+ type, mcs_buffer, mcs_buffer->gst_buffer, packet);
+
+ switch (type) {
+ case MEDIACODECSYNC_PACKET_TYPE_AUDIO:
+ appsrc = handle->audio_pipe[MEDIACODECSYNC_ELEMENT_APPSRC];
+ break;
+ case MEDIACODECSYNC_PACKET_TYPE_VIDEO:
+ appsrc = handle->video_pipe[MEDIACODECSYNC_ELEMENT_APPSRC];
+ break;
+ default:
+ LOGE("unhandled packet type %u, release created buffer", type);
+ gst_buffer_unref(mcs_buffer->gst_buffer);
+ ret = MEDIACODEC_ERROR_INTERNAL;
+ goto _PUSH_PACKET_DONE;
+ }
+
+ ret = _mediacodecsync_push_packet_to_pipeline(appsrc, mcs_buffer->gst_buffer);
+
+_PUSH_PACKET_DONE:
+ g_mutex_unlock(&handle->lock);
+
+ return ret;
+}
+
+
+int mediacodecsync_get_state(mediacodecsync_h mediacodecsync, mediacodecsync_state_e *state)
+{
+ mediacodecsync_s *handle = NULL;
+
+ MEDIACODEC_INSTANCE_CHECK(mediacodecsync);
+ MEDIACODEC_NULL_ARG_CHECK(state);
+
+ handle = (mediacodecsync_s *)mediacodecsync;
+
+ *state = handle->state;
+
+ LOGI("state %u", *state);
+
+ return MEDIACODEC_ERROR_NONE;
+}