diff options
author | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 22:09:59 +0900 |
---|---|---|
committer | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 22:09:59 +0900 |
commit | 76414ed7332777509a4c804fe5ea97a6400ee181 (patch) | |
tree | bf8acd3df6088361dd0970c664b8038379c6a92b | |
parent | c0042c2301a81d955ecde28c64e577f3a2426fca (diff) | |
download | mediacodec-76414ed7332777509a4c804fe5ea97a6400ee181.tar.gz mediacodec-76414ed7332777509a4c804fe5ea97a6400ee181.tar.bz2 mediacodec-76414ed7332777509a4c804fe5ea97a6400ee181.zip |
tizen 2.3.1 releasetizen_2.3.1_releasesubmit/tizen_2.3.1/20150915.075806tizen_2.3.1
-rw-r--r-- | AUTHORS | 2 | ||||
-rwxr-xr-x | CMakeLists.txt | 98 | ||||
-rw-r--r-- | LICENSE.APLv2 | 206 | ||||
-rw-r--r-- | NOTICE | 3 | ||||
-rw-r--r-- | capi-media-codec.manifest | 8 | ||||
-rw-r--r-- | capi-media-codec.pc.in | 15 | ||||
-rw-r--r-- | doc/media_codec_doc.h | 42 | ||||
-rwxr-xr-x | include/media_codec.h | 445 | ||||
-rwxr-xr-x | include/media_codec_port.h | 225 | ||||
-rwxr-xr-x | include/media_codec_port_gst.h | 210 | ||||
-rwxr-xr-x | include/media_codec_private.h | 122 | ||||
-rwxr-xr-x | include/media_codec_queue.h | 62 | ||||
-rwxr-xr-x | include/media_codec_spec_emul.h | 91 | ||||
-rwxr-xr-x | include/media_codec_util.h | 84 | ||||
-rwxr-xr-x | packaging/capi-media-codec.spec | 81 | ||||
-rwxr-xr-x | src/media_codec.c | 512 | ||||
-rwxr-xr-x | src/media_codec_port.c | 748 | ||||
-rwxr-xr-x | src/media_codec_port_gst.c | 2192 | ||||
-rwxr-xr-x | src/media_codec_queue.c | 131 | ||||
-rwxr-xr-x | src/media_codec_util.c | 114 | ||||
-rw-r--r-- | test/CMakeLists.txt | 23 | ||||
-rwxr-xr-x | test/media_codec_test.c | 1433 | ||||
-rw-r--r-- | test/tags | 44 |
23 files changed, 6891 insertions, 0 deletions
@@ -0,0 +1,2 @@ +Kangho Hur <kanho.hur@samsung.com> +Seungkeun Lee <sngn.lee@samsung.com> diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..e0daaf3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,98 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "capi-media-codec") + +PROJECT(${fw_name}) + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR}) + +SET(dependents "dlog glib-2.0 mm-common capi-media-tool libtbm libdri2 gstreamer-0.10 gstreamer-plugins-base-0.10 gstreamer-app-0.10" ) +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-0.10 gstreamer-plugins-base-0.10 gstreamer-app-0.10" ) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "-I./include -I./include/headers ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib") + +aux_source_directory(src SOURCES) +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +INSTALL(TARGETS ${fw_name} DESTINATION lib) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/media + FILES_MATCHING + PATTERN "media_codec_*.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" + ) + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_dependents}) +SET(PC_LDFLAGS -l${fw_name}) +SET(PC_CFLAGS -I\${includedir}/media) + +CONFIGURE_FILE( + ${fw_name}.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION lib/pkgconfig) + +ADD_SUBDIRECTORY(test) + +IF(UNIX) + +ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) +ADD_CUSTOM_COMMAND( + DEPENDS clean + COMMENT "distribution clean" + COMMAND find + ARGS . + -not -name config.cmake -and \( + -name tester.c -or + -name Testing -or + -name CMakeFiles -or + -name cmake.depends -or + -name cmake.check_depends -or + -name CMakeCache.txt -or + -name cmake.check_cache -or + -name *.cmake -or + -name Makefile -or + -name core -or + -name core.* -or + -name gmon.out -or + -name install_manifest.txt -or + -name *.pc -or + -name *~ \) + | grep -v TC | xargs rm -rf + TARGET distclean + VERBATIM +) + +ENDIF(UNIX) + diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..bbe9d02 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,206 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+
+
+
@@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE file for Apache License terms and conditions. diff --git a/capi-media-codec.manifest b/capi-media-codec.manifest new file mode 100644 index 0000000..e3deed8 --- /dev/null +++ b/capi-media-codec.manifest @@ -0,0 +1,8 @@ +<manifest> + <request> + <domain name="_" /> + </request> + <assign> + <filesystem path="/usr/bin/player_test" label="_" exec_label="none" /> + </assign> +</manifest> diff --git a/capi-media-codec.pc.in b/capi-media-codec.pc.in new file mode 100644 index 0000000..5d02f8d --- /dev/null +++ b/capi-media-codec.pc.in @@ -0,0 +1,15 @@ + +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=/usr/lib +includedir=/usr/include/media + +Name: @PC_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} + diff --git a/doc/media_codec_doc.h b/doc/media_codec_doc.h new file mode 100644 index 0000000..28971c8 --- /dev/null +++ b/doc/media_codec_doc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 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_DOC_H__ +#define __TIZEN_MEDIA_CODEC_DOC_H__ + + +/** + * @file media_codec_doc.h + * @brief This file contains high level documentation of the CAPI MEDIA CODEC API. + */ + +/** + * @defgroup CAPI_MEDIA_CODEC_MODULE Media Codec + * @brief The @ref CAPI_MEDIA_CODEC_MODULE APIs provides functions for encodinging and decoding using media data + * @ingroup CAPI_MEDIA_FRAMEWORK + * + * @section CAPI_MEDIA_CODEC_MODULE_HEADER Required Header + * \#include <media_codec.h> + * + * @section CAPI_MEDIA_CODEC_MODULE_OVERVIEW Overview + * + * 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 + * must be stripped off. media_packet is used for zero-copy. + * + */ + +#endif // __TIZEN_MEDIA_CODEC_DOC_H__ diff --git a/include/media_codec.h b/include/media_codec.h new file mode 100755 index 0000000..678123e --- /dev/null +++ b/include/media_codec.h @@ -0,0 +1,445 @@ +/* +* Copyright (c) 2011 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_H__ +#define __TIZEN_MEDIA_CODEC_H__ + +#include <tizen.h> +#include <stdint.h> +#include <media_packet.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @file media_codec.h +* @brief This file contains the capi media codec API. +*/ + +/** +* @addtogroup CAPI_MEDIA_CODEC_MODULE +* @{ +*/ + +/** + * @brief Media Codec type handle. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + */ +typedef struct mediacodec_s *mediacodec_h; + +/** + * @brief Enumeration of media codec support type + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @remarks If this codec is to be used as an encoder or decoder, the codec flag must be set to #MEDIACODEC_ENCODER or + * #MEDIACODEC_DECODER. If user doesn't set optional flag, default flags will be set to #MEDIACODEC_SUPPORT_TYPE_HW. + */ +typedef enum +{ + MEDIACODEC_ENCODER = 0x1, /**< This flag is for using the encoder */ + MEDIACODEC_DECODER = 0x2, /**< This flag is for using the decoder */ + MEDIACODEC_SUPPORT_TYPE_HW = 0x4, /**< This is an optional flag for using the h/w codec */ + MEDIACODEC_SUPPORT_TYPE_SW = 0x8, /**< This is an optional flag for using the s/w codec */ +} mediacodec_support_type_e; + +/** + * @brief Enumerations of media codec type + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + */ +typedef enum +{ + MEDIACODEC_NONE = 0x0, /**< NONE*/ + MEDIACODEC_L16 = 0x1010, /**< L16*/ + MEDIACODEC_ALAW = 0x1020, /**< ALAW*/ + MEDIACODEC_ULAW = 0x1030, /**< ULAW*/ + MEDIACODEC_AMR = 0x1040, /**< AMR*/ + MEDIACODEC_G729 = 0x1050, /**< G729*/ + MEDIACODEC_AAC = 0x1060, /**< AAC*/ + MEDIACODEC_MP3 = 0x1070, /**< MP3*/ + + MEDIACODEC_H261 = 0x2010, /**< H.261*/ + MEDIACODEC_H263 = 0x2020, /**< H.263*/ + MEDIACODEC_H264 = 0x2030, /**< H.264*/ + MEDIACODEC_MJPEG = 0x2040, /**< MJPEG*/ + MEDIACODEC_MPEG1 = 0x2050, /**< MPEG1*/ + MEDIACODEC_MPEG2 = 0x2060, /**< MPEG2*/ + MEDIACODEC_MPEG4 = 0x2070, /**< MPEG4*/ +} mediacodec_codec_type_e; + +/** + * @brief Enumeration of media codec error + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + */ +typedef enum +{ + MEDIACODEC_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + MEDIACODEC_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + MEDIACODEC_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + MEDIACODEC_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */ + MEDIACODEC_ERROR_NOT_SUPPORTED_ON_DEVICE = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ + MEDIACODEC_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + MEDIACODEC_ERROR_INVALID_STATE = TIZEN_ERROR_MEDIACODEC | 0x01, /**< Invalid state */ + MEDIACODEC_ERROR_INVALID_INBUFFER = TIZEN_ERROR_MEDIACODEC | 0x02, /**< Invalid input buffer */ + MEDIACODEC_ERROR_INVALID_OUTBUFFER = TIZEN_ERROR_MEDIACODEC | 0x03, /**< Invalid output buffer */ + MEDIACODEC_ERROR_INTERNAL = TIZEN_ERROR_MEDIACODEC | 0x04, /**< Internal error */ + MEDIACODEC_ERROR_NOT_INITIALIZED = TIZEN_ERROR_MEDIACODEC | 0x05, /**< Not initialized mediacodec */ + MEDIACODEC_ERROR_INVALID_STREAM = TIZEN_ERROR_MEDIACODEC | 0x06, /**< Invalid stream */ + MEDIACODEC_ERROR_CODEC_NOT_FOUND = TIZEN_ERROR_MEDIACODEC | 0x07, /**< Not supported format */ + MEDIACODEC_ERROR_DECODE = TIZEN_ERROR_MEDIACODEC | 0x08, /**< Error while decoding data */ + MEDIACODEC_ERROR_NO_FREE_SPACE = TIZEN_ERROR_MEDIACODEC | 0x09, /**< Out of storage */ + MEDIACODEC_ERROR_STREAM_NOT_FOUND = TIZEN_ERROR_MEDIACODEC | 0x0a, /**< Cannot find stream */ + MEDIACODEC_ERROR_NOT_SUPPORTED_FORMAT = TIZEN_ERROR_MEDIACODEC | 0x0b, /**< Not supported format */ + MEDIACODEC_ERROR_BUFFER_NOT_AVAILABLE = TIZEN_ERROR_MEDIACODEC | 0x0c, /**< Not available buffer */ +} mediacodec_error_e; + +/** + * @brief Called when the input buffer(pkt) used up. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @details It will be invoked when mediacodec has used input buffer. + * @param[in] pkt The media packet handle + * @param[in] user_data The user data passed from the callback registration function + * @pre It will be invoked when input buffer process completed if you register this callback using mediacodec_set_input_buffer_used_cb(). + * @see mediacodec_set_input_buffer_used_cb() + * @see mediacodec_unset_input_buffer_used_cb() + */ +typedef void (*mediacodec_input_buffer_used_cb)(media_packet_h pkt, void *user_data); + +/** + * @brief Called when the output buffer is available. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @details It will be invoked when mediacodec has output buffer. + * @param[in] pkt The media packet handle + * @param[in] user_data The user data passed from the callback registration function + * @pre It will be invoked when mediacodec process completed(had output buffer) if you register this callback using mediacodec_set_fill_buffer_cb(). + * @see mediacodec_set_output_buffer_available_cb() + * @see mediacodec_unset_output_buffer_available_cb() + */ +typedef void (*mediacodec_output_buffer_available_cb)(media_packet_h pkt, void *user_data); + +/** + * @brief Called when the error has occured + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @details It will be invoked when the error has occured. + * @param[in] error_code 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(). + * @see mediacodec_set_error_cb() + * @see mediacodec_unset_error_cb() + */ +typedef void (*mediacodec_error_cb)(mediacodec_error_e error, void *user_data); + +/** + * @brief Called when there is no data to decode/encode + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @details It will be invoked when the end-of-stream is reached. + * @param[in] user_data The user data passed from the callback registration function + * @pre It will be invoked when the eos event generate if you register this callback using mediacodec_set_eos_cb(). + * @see mediacodec_set_eos_cb() + * @see mediacodec_unset_eos_cb() + */ +typedef void (*mediacodec_eos_cb)(void *user_data); + +/** + * @brief Creates a mediacodec handle for decoding/encoding + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @remarks you must release @a mediacodec using mediacodec_destroy().\n + * Although you can create multiple mediacodec handles at the same time, + * the mediacodec cannot guarantee proper operation because of limited resources, like + * audio or display device. + * + * @param[out] mediacodec A new handle to mediacodec + * @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 + */ +int mediacodec_create(mediacodec_h *mediacodec); + +/** + * @brief Destroys the mediacodec handle and releases all its resources. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @remarks To completely shutdown the mediacodec operation, call this function with a valid player handle from any + * mediacodec + * + * @param[in] mediacodec The handle to mediacodec 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_OUT_OF_MEMORY Out of memory + * @retval #MEDIACODEC_ERROR_INVALID_OPERATION Invalid operation + */ +int mediacodec_destroy(mediacodec_h mediacodec); + +/** + * @brief Sets the codec type and decoder/encoder. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @remarks If this codec is to be used as a decoder, pass the #MEDIACODEC_DECODER flag. + * If this codec is to be used as an encoder, pass the #MEDIACODEC_ENCODER flag. + * By default, It is used hardware default setting. If user want software setting, pass the + * #MEDIACODEC_SUPPORT_TYPE_SW flags. + * @param[in] mediacodec The handle of mediacodec + * @param[in] codec_id The identifier of the codec type of the decoder/encoder + * @param[in] flags The encoding/decoding scheme. + * @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_CODEC_NOT_FOUND Codec not found + */ +int mediacodec_set_codec(mediacodec_h mediacodec, mediacodec_codec_type_e codec_id, mediacodec_support_type_e flags); + +/** + * @brief Sets the default info for the video decoder + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] width The width for video decoding. + * @param[in] height The height for video decoding. + * @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 + */ +int mediacodec_set_vdec_info(mediacodec_h mediacodec, int width, int height); + +/** + * @brief Sets the default info for the video encoder + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @remarks The frame rate is the speed of recording and the speed of playback. + * If user wants the default setting for ratecontrol, set @a target_bits to @c 0. + * @param[in] mediacodec The handle to mediacodec + * @param[in] width The width for video encoding. + * @param[in] height The height for video encoding. + * @param[in] fps The frame rate in frames per second. + * @param[in] target_bits The target bitrates in bits per second.(a unit of kbit) + * @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 + */ +int mediacodec_set_venc_info(mediacodec_h mediacodec, int width, int height, int fps, int target_bits); + +/** + * @brief Sets the default info for the audio decoder + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] samplerate The samplerate for audio decoding. + * @param[in] channel The channels for audio decoding. + * @param[in] bit The bits resolution for audio decoding. + * @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 + */ +int mediacodec_set_adec_info(mediacodec_h mediacodec, int samplerate, int channel, int bit); + +/** + * @brief Sets the default info for the audio encdoer + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] samplerate The samplerate for audio encoding. + * @param[in] channel The channels for audio encoding. + * @param[in] bit The bits resolution for audio encoding. + * @param[in] bitrate The bitrate for audio encoding. + * @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 + */ +int mediacodec_set_aenc_info(mediacodec_h mediacodec, int samplerate, int channel, int bit, int bitrate); + +/** + * @brief Prepares @a mediacodec for encoding/decoding. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @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 + * @pre The mediacodec should call mediacodec_set_codec()and mediacodec_set_vdec_info()/mediacodec_set_venc_info() before calling mediacodec_prepare() + * If the decoder is set by mediacodec_set_codec(), mediacodec_set_vdec_info() should be called. If the encoder is set by + * mediacodec_set_codec(), mediacodec_set_venc_info() should be called. + */ +int mediacodec_prepare(mediacodec_h mediacodec); + +/** + * @brief Unprepares @a mediacodec for encoding/decoding. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @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 + */ +int mediacodec_unprepare(mediacodec_h mediacodec); + +/** + * @brief Decodes/Encodes a packet. The function passed undecoded/unencoded packet to the input queue and decode/encode a + * frame sequentially. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] inbuf The current input format for the decoder/encoder + * @param[in] timeOutUs The timeout in microseconds. \n + * The input buffer wait up to "timeOutUs" microseconds. + * @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 + */ +int mediacodec_process_input (mediacodec_h mediacodec, media_packet_h inbuf, uint64_t timeOutUs); + +/** + * @brief Gets the decoded or encoded packet from the output queue. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] outbuf The current output of the decoder/encoder. this function passed decoded/encoded frame to output + * queue. + * @param[in] timeOutUs The timeout in microseconds. \n + * The input buffer wait up to "timeOutUs" microseconds. + * @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 + */ +int mediacodec_get_output (mediacodec_h mediacodec, media_packet_h *outbuf, uint64_t timeOutUs); + +/** + * @brief set empty buffer callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @pre mediacodec_set_input_buffer_used_cb should be called before mediacodec_preare(). + * @post mediacodec_input_buffer_used_cb will be invoked. + * @see mediacodec_set_input_buffer_used_cb() + * @see mediacodec_unset_input_buffer_used_cb() + */ +int mediacodec_set_input_buffer_used_cb(mediacodec_h mediacodec, mediacodec_input_buffer_used_cb callback, void* user_data); + +/** + * @brief unset input buffer used callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @see mediacodec_set_input_buffer_used_cb() + */ +int mediacodec_unset_input_buffer_used_cb(mediacodec_h mediacodec); + +/** + * @brief set output buffer available callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @pre mediacodec_set_output_buffer_available_cb should be called before mediacodec_preare(). + * @post mediacodec_output_buffer_available_cb will be invoked. + * @see mediacodec_set_output_buffer_available_cb() + * @see mediacodec_unset_output_buffer_available_cb() + */ +int mediacodec_set_output_buffer_available_cb(mediacodec_h mediacodec, mediacodec_output_buffer_available_cb callback, void* user_data); + +/** + * @brief unset output buffer available callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @see mediacodec_set_output_buffer_available_cb() + */ +int mediacodec_unset_output_buffer_available_cb(mediacodec_h mediacodec); + +/** + * @brief set error callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @pre mediacodec_set_error_cb should be called before mediacodec_preare(). + * @post mediacodec_error_cb will be invoked. + * @see mediacodec_set_error_cb() + * @see mediacodec_unset_error_cb() + */ +int mediacodec_set_error_cb(mediacodec_h mediacodec, mediacodec_error_cb callback, void* user_data); + +/** + * @brief unset error callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @see mediacodec_set_error_cb() + */ +int mediacodec_unset_error_cb(mediacodec_h mediacodec); + +/** + * @brief set eos callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @pre mediacodec_set_eos_cb should be called before mediacodec_preare(). + * @post mediacodec_eos_cb will be invoked. + * @see mediacodec_set_eos_cb() + * @see mediacodec_unset_eos_cb() + */ +int mediacodec_set_eos_cb(mediacodec_h mediacodec, mediacodec_eos_cb callback, void* user_data); + +/** + * @brief unset eos callback the media codec for process, asynchronously. + * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif + * @param[in] mediacodec The handle to mediacodec + * @return @c 0 on success, otherwise a negative error value + * @retval #MEDIACODEC_ERROR_NONE Successful + * @retval #MEDIACODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @see mediacodec_set_event_handler_cb() + */ +int mediacodec_unset_eos_cb(mediacodec_h mediacodec); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CODEC_H__ */ + diff --git a/include/media_codec_port.h b/include/media_codec_port.h new file mode 100755 index 0000000..92d80f2 --- /dev/null +++ b/include/media_codec_port.h @@ -0,0 +1,225 @@ +/* +* Copyright (c) 2011 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_PORT_H__ +#define __TIZEN_MEDIA_CODEC_PORT_H__ + +#include <tizen.h> +#include <glib.h> +#include <dlfcn.h> +#include <gst/gst.h> + +#include <media_codec.h> +#include <media_codec_queue.h> +#include <media_codec_spec_emul.h> + + +/*=========================================================================================== +| | +| GLOBAL DEFINITIONS AND DECLARATIONS FOR MODULE | +| | +========================================================================================== */ + +/*--------------------------------------------------------------------------- +| GLOBAL #defines: | +---------------------------------------------------------------------------*/ +#define OUT_BUF_SIZE 9000000 +#define CHECK_BIT(x, y) (((x) >> (y)) & 0x01) +#define GET_IS_ENCODER(x) CHECK_BIT(x, 0) +#define GET_IS_DECODER(x) CHECK_BIT(x, 1) +#define GET_IS_HW(x) CHECK_BIT(x, 2) +#define GET_IS_SW(x) CHECK_BIT(x, 3) + +//#define GET_IS_OMX(x) CHECK_BIT(x, 4) +//#define GET_IS_GEN(x) CHECK_BIT(x, 5) + + +/*--------------------------------------------------------------------------- +| GLOBAL CONSTANT DEFINITIONS: | +---------------------------------------------------------------------------*/ +/** + * @brief Enumerations of media codec port's retrun value + */ +typedef enum +{ + MC_ERROR_NONE = 0, + MC_ERROR = -1, /**< codec happens error */ + MC_MEMORY_ERROR = -2, /**< codec memory is not enough */ + MC_PARAM_ERROR = -3, /**< codec parameter is error */ + MC_INVALID_ARG = -4, /** < codec has invalid arguments */ + MC_PERMISSION_DENIED = -5, + MC_INVALID_STATUS = -6, /**< codec works at invalid status */ + MC_NOT_SUPPORTED = -7, /**< codec can't support this specific video format */ + MC_INVALID_IN_BUF = -8, + MC_INVALID_OUT_BUF = -9, + MC_INTERNAL_ERROR = -10, + MC_HW_ERROR = -11, /**< codec happens hardware error */ + MC_NOT_INITIALIZED = -12, + MC_INVALID_STREAM = -13, + MC_CODEC_NOT_FOUND = -14, + MC_ERROR_DECODE = -15, + MC_OUTPUT_BUFFER_EMPTY = -16, + MC_OUTPUT_BUFFER_OVERFLOW = -17, /**< codec output buffer is overflow */ + MC_MEMORY_ALLOCED = -18, /**< codec has got memory and can decode one frame */ +} mc_ret_e; + +/*--------------------------------------------------------------------------- +| GLOBAL DATA TYPE DEFINITIONS: | +---------------------------------------------------------------------------*/ +/** + * @brief Called when the dequeue input buffer done + * @details It will be invoked when mediacodec has released dequeue buffer. + * @param[in] user_data The user data passed from the callback registration function + * @pre It will be invoked when dequeue buffer process completed if you register this callback using mediacodec_set_dequeue_input_buffer_cb(). + * @see mediacodec_set_dequeue_input_buffer_cb() + * @see mediacodec_unset_dequeue_input_buffer_cb() + */ + +typedef struct _mc_decoder_info_t mc_decoder_info_t; +typedef struct _mc_encoder_info_t mc_encoder_info_t; +typedef struct _mc_handle_t mc_handle_t; + +#define MEDIACODEC_CMD_LOCK(x_mediacodec) g_mutex_lock(&((mc_handle_t*)x_mediacodec)->cmd_lock ) +#define MEDIACODEC_CMD_UNLOCK(x_mediacodec) g_mutex_unlock( &((mc_handle_t*)x_mediacodec)->cmd_lock ) + +typedef void (*mc_dequeue_input_buffer_cb)(media_packet_h pkt, void *user_data); +typedef void (*mc_empty_buffer_cb)(media_packet_h pkt, void *user_data); +typedef void (*mc_fill_buffer_cb)(media_packet_h pkt, void *user_data); +typedef void (*mc_error_cb)(mediacodec_error_e error, void *user_data); +typedef void (*mc_eos_cb)(void *user_data); + +typedef enum { + _MEDIACODEC_EVENT_TYPE_COMPLETE, + _MEDIACODEC_EVENT_TYPE_EMPTYBUFFER, + _MEDIACODEC_EVENT_TYPE_FILLBUFFER, + _MEDIACODEC_EVENT_TYPE_ERROR, + _MEDIACODEC_EVENT_TYPE_EOS, + _MEDIACODEC_EVENT_TYPE_INTERNAL_FILLBUFFER, + _MEDIACODEC_EVENT_TYPE_NUM +} _mediacodec_event_e; + + +typedef enum _mc_codec_port_type_e +{ + CODEC_PORT_TYPE_GENERAL, + CODEC_PORT_TYPE_OMX, + CODEC_PORT_TYPE_GST, + CODEC_PORT_TYPE_MAX, +} mc_codec_port_type_e; + +struct _mc_decoder_info_t +{ + int width; + int height; + int actwidth; + int actheight; + + int samplerate; + int channel; + int bit; +}; + +struct _mc_encoder_info_t +{ + int width; + int height; + int bitrate; + int format; + int fps; + int qp_min; + int qp_max; + int vbvbuffer_size; + int level; + int profile; + + int samplerate; + int channel; + int bit; +}; + + +/* Codec Private data */ +struct _mc_handle_t +{ + int state; /**< mc current state */ + bool is_encoder; + bool is_video; + bool is_hw; + bool is_prepared; + + GMutex cmd_lock; + mediacodec_port_type_e port_type; + mediacodec_codec_type_e codec_id; + + void *ports[2]; + void *core; + + union + { + mc_decoder_info_t decoder; + mc_encoder_info_t encoder; + } info; + + /* for process done cb */ + void* user_cb[_MEDIACODEC_EVENT_TYPE_NUM]; + void* user_data[_MEDIACODEC_EVENT_TYPE_NUM]; + +}; + +/*=========================================================================================== +| | +| GLOBAL FUNCTION PROTOTYPES | +| | +========================================================================================== */ + +#ifdef __cplusplus +extern "C" { +#endif + +int mc_create(MMHandleType *mediacodec); +int mc_destroy(MMHandleType mediacodec); + +int mc_set_codec(MMHandleType mediacodec, mediacodec_codec_type_e codec_id, mediacodec_support_type_e flags); + +int mc_set_vdec_info(MMHandleType mediacodec, int width, int height); +int mc_set_venc_info(MMHandleType mediacodec, int width, int height, int fps, int target_bits); + +int mc_set_adec_info(MMHandleType mediacodec, int samplerate, int channel, int bit); +int mc_set_aenc_info(MMHandleType mediacodec, int samplerate, int channel, int bit, int bitrate); + +int mc_prepare(MMHandleType mediacodec); +int mc_unprepare(MMHandleType mediacodec); + +int mc_process_input(MMHandleType mediacodec, media_packet_h inbuf, uint64_t timeOutUs); +int mc_get_output(MMHandleType mediacodec, media_packet_h *outbuf, uint64_t timeOutUs); + +int mc_set_empty_buffer_cb(MMHandleType mediacodec, mediacodec_input_buffer_used_cb callback, void* user_data); +int mc_unset_empty_buffer_cb(MMHandleType mediacodec); + +int mc_set_fill_buffer_cb(MMHandleType mediacodec, mediacodec_output_buffer_available_cb callback, void* user_data); +int mc_unset_fill_buffer_cb(MMHandleType mediacodec); + +int mc_set_error_cb(MMHandleType mediacodec, mediacodec_error_cb callback, void* user_data); +int mc_unset_error_cb(MMHandleType mediacodec); + +int mc_set_eos_cb(MMHandleType mediacodec, mediacodec_eos_cb callback, void* user_data); +int mc_unset_eos_cb(MMHandleType mediacodec); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CODEC_PORT_H__ */ diff --git a/include/media_codec_port_gst.h b/include/media_codec_port_gst.h new file mode 100755 index 0000000..4a3dd5c --- /dev/null +++ b/include/media_codec_port_gst.h @@ -0,0 +1,210 @@ + +/* +* Copyright (c) 2011 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_PORT_GST_H__ +#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 <tbm_type.h> +#include <tbm_surface.h> +#include <tbm_bufmgr.h> +#include <tbm_surface_internal.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 +#define MMPLAYER_FENTER(); debug_fenter(); +#define MMPLAYER_FLEAVE(); debug_fleave(); +#else +#define MMPLAYER_FENTER(); LOGW("%s Enter",__FUNCTION__); +#define MMPLAYER_FLEAVE(); LOGW("%s Exit",__FUNCTION__); +#endif + + +#define GST_INIT_STRUCTURE(param) \ + memset(&(param), 0, sizeof(param)); + +#define MEDIACODEC_ELEMENT_SET_STATE( x_element, x_state ) \ +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; \ +} + +#define SCMN_IMGB_MAX_PLANE 4 +#define TBM_API_CHANGE //this need for temporary test - tbm_surface_internal_create_with_bos() API change +/* gst port layer */ +typedef struct _mc_gst_port_t mc_gst_port_t; +typedef struct _mc_gst_core_t mc_gst_core_t; +typedef struct _mc_gst_buffer_t mc_gst_buffer_t; + +typedef enum { + BUF_SHARE_METHOD_PADDR = 0, + BUF_SHARE_METHOD_FD, + BUF_SHARE_METHOD_TIZEN_BUFFER, + BUF_SHARE_METHOD_FLUSH_BUFFER +} buf_share_method_t; + +#ifdef TIZEN_PROFILE_LITE +struct ion_mmu_data { + int fd_buffer; + unsigned long iova_addr; + size_t iova_size; +}; +#endif + +typedef struct +{ + int w[SCMN_IMGB_MAX_PLANE]; /* width of each image plane */ + int h[SCMN_IMGB_MAX_PLANE]; /* height of each image plane */ + int s[SCMN_IMGB_MAX_PLANE]; /* stride of each image plane */ + int e[SCMN_IMGB_MAX_PLANE]; /* elevation of each image plane */ + void *a[SCMN_IMGB_MAX_PLANE]; /* user space address of each image plane */ + void *p[SCMN_IMGB_MAX_PLANE]; /* physical address of each image plane, if needs */ + int cs; /* color space type of image */ + int x; /* left postion, if needs */ + int y; /* top position, if needs */ + int __dummy2; /* to align memory */ + int data[16]; /* arbitrary data */ + int dma_buf_fd[SCMN_IMGB_MAX_PLANE]; /* DMABUF fd of each image plane */ + /* buffer share method */ + int buf_share_method; /* will be 2(BUF_SHARE_METHOD_TIZEN_BUFFER)*/ + int y_size; /* Y plane size in case of ST12 */ + /* UV plane size in case of ST12 */ + int uv_size; /* UV plane size in case of ST12 */ + tbm_bo bo[SCMN_IMGB_MAX_PLANE]; /* Tizen buffer object of each image plane */ + void *jpeg_data; /* JPEG data */ + int jpeg_size; /* JPEG size */ + int tz_enable; /* TZ memory buffer */ +} SCMN_IMGB; + +struct _mc_gst_port_t +{ + mc_gst_core_t *core; + unsigned int num_buffers; + unsigned int buffer_size; + unsigned int index; + bool is_allocated; + media_packet_h *buffers; + //GSem + GQueue *queue; + GMutex mutex; + GCond buffer_cond; +}; + +struct _mc_gst_core_t +{ + int(**vtable)(); + const char *mime; + int format; + GstElement* pipeline; + GstElement* appsrc; + GstElement* fakesink; + GstElement* codec; + SCMN_IMGB *psimgb; + + GMainContext *thread_default; + gulong signal_handoff; + gint bus_whatch_id; + gint probe_id; + + GMutex eos_mutex; + GMutex eos_wait_mutex; + GMutex drain_mutex; + GMutex prepare_lock; + GCond eos_cond; + GCond eos_waiting_cond; + //mc_sem_t *push_sem; + //mc_sem_t *pop_sem; + + GstState state; + bool output_allocated; + bool encoder; + bool video; + bool is_hw; + bool eos; + bool eos_waiting; + bool codec_config; + bool need_feed; + int prepare_count; + int num_live_buffers; + + mediacodec_codec_type_e codec_id; + media_format_h output_fmt; + mc_gst_port_t *ports[2]; + + mc_aqueue_t *available_queue; + GQueue *output_queue; + + void *codec_info; + + void* user_cb[_MEDIACODEC_EVENT_TYPE_NUM]; + void* user_data[_MEDIACODEC_EVENT_TYPE_NUM]; + +}; + +struct _mc_gst_buffer_t +{ + GstBuffer buffer; + mc_gst_core_t* core; + media_packet_h pkt; +}; + +enum { fill_inbuf, fill_outbuf, create_caps }; + +int __mc_fill_input_buffer(mc_gst_core_t *core, mc_gst_buffer_t *buff); +int __mc_fill_output_buffer(mc_gst_core_t *core, GstBuffer *buff, media_packet_h *out_pkt); +int __mc_create_caps(mc_gst_core_t *core, GstCaps **caps); + +int __mc_fill_inbuf_with_bo(mc_gst_core_t *core, mc_gst_buffer_t *buff); +int __mc_fill_inbuf_with_packet(mc_gst_core_t *core, mc_gst_buffer_t *buff); + +int __mc_fill_outbuf_with_bo(mc_gst_core_t *core, GstBuffer *buff, media_packet_h *out_pkt); +int __mc_fill_outbuf_with_packet(mc_gst_core_t *core, GstBuffer *buff, media_packet_h *out_pkt); + +int __mc_venc_caps(mc_gst_core_t *core, GstCaps **caps); +int __mc_vdec_caps(mc_gst_core_t *core, GstCaps **caps); +int __mc_aenc_caps(mc_gst_core_t *core, GstCaps **caps); +int __mc_adec_caps(mc_gst_core_t *core, GstCaps **caps); +int __mc_mp3dec_caps(mc_gst_core_t *core, GstCaps **caps); +int __mc_h263enc_caps(mc_gst_core_t *core, GstCaps **caps); + +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); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CODEC_PORT_GST_H__ */ diff --git a/include/media_codec_private.h b/include/media_codec_private.h new file mode 100755 index 0000000..7bc76fc --- /dev/null +++ b/include/media_codec_private.h @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2011 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_PRIVATE_H__ +#define __TIZEN_MEDIA_CODEC_PRIVATE_H__ + +#include <tizen.h> +#include <stdint.h> + +#include <media_codec.h> + +#include <mm_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "TIZEN_N_MEDIACODEC" + + +#define MEDIACODEC_CHECK_CONDITION(condition,error,msg) \ + if(condition) {} else \ + { LOGE("[%s] %s(0x%08x)",__FUNCTION__, msg,error); return error;}; \ + +#define MEDIACODEC_INSTANCE_CHECK(mediacodec) \ + MEDIACODEC_CHECK_CONDITION(mediacodec != NULL, MEDIACODEC_ERROR_INVALID_PARAMETER,"MEDIACODEC_ERROR_INVALID_PARAMETER") + +#define MEDIACODEC_STATE_CHECK(mediacodec,expected_state) \ + MEDIACODEC_CHECK_CONDITION(mediacodec->state == expected_state,MEDIACODEC_ERROR_INVALID_STATE,"MEDIACODEC_ERROR_INVALID_STATE") + +#define MEDIACODEC_NULL_ARG_CHECK(arg) \ + MEDIACODEC_CHECK_CONDITION(arg != NULL,MEDIACODEC_ERROR_INVALID_PARAMETER,"MEDIACODEC_ERROR_INVALID_PARAMETER") + +/** + * @brief Enumeration of media codec state + * @since_tizen 2.3 + */ +typedef enum +{ + MEDIACODEC_STATE_NONE = 0, /**< Media codec is not created */ + MEDIACODEC_STATE_IDLE, /**< Media codec is created, but not prepared */ + MEDIACODEC_STATE_READY, /**< Media codec is ready to process */ + MEDIACODEC_STATE_EXCUTE, /**< Media codec is executing media */ +} mediacodec_state_e; + +typedef enum +{ + MEDIACODEC_SUPPORT_TYPE_OMX = 0x10, /**< This is optional flag for using openmax il */ + MEDIACODEC_SUPPORT_TYPE_GEN = 0x20 /**< This is optional flag for using general codec */ +} mediacodec_internal_support_type_e; + +typedef enum +{ + MEDIACODEC_PORT_TYPE_GENERAL, + MEDIACODEC_PORT_TYPE_OMX, + MEDIACODEC_PORT_TYPE_GST, + MEDIACODEC_PORT_TYPE_MAX, +} mediacodec_port_type_e; + +/** + * @brief Media Codec's format for configuring codec. + */ +typedef struct _mediacodecformat_s { + // Video + int fps; + int height; + int width; + float aspect; + bool vfr; + int level; + int profile; + + // Audio + int channels; + int samplerate; + int bitrate; + + // Codec Extra Data + void * extradata; + unsigned int extrasize; +} mediacodec_format_s; + +typedef struct _mediacodec_s { + MMHandleType mc_handle; + int state; + bool is_omx; + char *m_mime; + + mediacodec_input_buffer_used_cb empty_buffer_cb; + void* empty_buffer_cb_userdata; + mediacodec_output_buffer_available_cb fill_buffer_cb; + void* fill_buffer_cb_userdata; + mediacodec_error_cb error_cb; + void* error_cb_userdata; + mediacodec_eos_cb eos_cb; + void* eos_cb_userdata; + +} mediacodec_s; + +bool __mediacodec_state_validate(mediacodec_h mediacodec, mediacodec_state_e threshold); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CODEC_PRIVATE_H__ */ diff --git a/include/media_codec_queue.h b/include/media_codec_queue.h new file mode 100755 index 0000000..428a53c --- /dev/null +++ b/include/media_codec_queue.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2011 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_QUEUE_H__ +#define __TIZEN_MEDIA_CODEC_QUEUE_H__ + +#include <glib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _async_queue { + GMutex mutex; + GCond condition; + GList *head; + GList *tail; + guint length; + gboolean enabled; +} async_queue_t; + +typedef struct _mc_aqueue { + GThread *thread; + gint running; + async_queue_t *input; + async_queue_t *output; +} mc_aqueue_t; + +async_queue_t *mc_async_queue_new(); + +void mc_async_queue_free(async_queue_t *async_queue); + +void mc_async_queue_push(async_queue_t *async_queue, gpointer data); + +gpointer mc_async_queue_pop_forced (async_queue_t * async_queue); + +gpointer mc_async_queue_pop(async_queue_t *async_queue); + +void mc_async_queue_disable (async_queue_t *async_queue); + +void mc_async_queue_enable (async_queue_t *async_queue); + +void mc_async_queue_flush(async_queue_t *async_queue); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CODEC_QUEUE_H__ */ diff --git a/include/media_codec_spec_emul.h b/include/media_codec_spec_emul.h new file mode 100755 index 0000000..597d4b0 --- /dev/null +++ b/include/media_codec_spec_emul.h @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2011 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_EMUL_H__ +#define __TIZEN_MEDIA_CODEC_EMUL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <media_codec_private.h> + +enum { DECODER, ENCODER }; +enum { SOFTWARE, HARDWARE }; + +typedef struct _mc_codec_spec_t mc_codec_spec_t; +typedef struct _mc_codec_map_t mc_codec_map_t; +typedef struct _mc_codec_type_t mc_codec_type_t; + +struct _mc_codec_spec_t +{ + mediacodec_codec_type_e codec_id; + mediacodec_support_type_e codec_type; + mediacodec_port_type_e port_type; +}; + +struct _mc_codec_type_t +{ + char *factory_name; + char *mime; + media_format_mimetype_e out_format; +}; + +struct _mc_codec_map_t +{ + mediacodec_codec_type_e id; + bool hardware; + mc_codec_type_t type; +}; + +static const mc_codec_spec_t spec_emul[] = +{ + {MEDIACODEC_H264, MEDIACODEC_DECODER | MEDIACODEC_SUPPORT_TYPE_SW, MEDIACODEC_PORT_TYPE_GST}, + {MEDIACODEC_H263, MEDIACODEC_ENCODER | MEDIACODEC_SUPPORT_TYPE_SW, MEDIACODEC_PORT_TYPE_GST}, + {MEDIACODEC_AAC, MEDIACODEC_ENCODER | MEDIACODEC_SUPPORT_TYPE_SW, MEDIACODEC_PORT_TYPE_GST}, + {MEDIACODEC_AAC, MEDIACODEC_DECODER | MEDIACODEC_SUPPORT_TYPE_SW, MEDIACODEC_PORT_TYPE_GST}, + {MEDIACODEC_MP3, MEDIACODEC_DECODER | MEDIACODEC_SUPPORT_TYPE_SW, MEDIACODEC_PORT_TYPE_GST} +}; + +static const mc_codec_map_t encoder_map[] = +{ +#ifdef ENABLE_FFMPEG_CODEC + {MEDIACODEC_H263, SOFTWARE, {"ffenc_h263", "video/x-raw-yuv", MEDIA_FORMAT_H263P }}, + {MEDIACODEC_AAC, SOFTWARE, {"ffenc_aac", "audio/x-raw-int", MEDIA_FORMAT_AAC}} +#else + {MEDIACODEC_H263, SOFTWARE, {"maru_h263enc", "video/x-raw-yuv", MEDIA_FORMAT_H263P}}, + {MEDIACODEC_AAC, SOFTWARE, {"maru_aacenc", "audio/x-raw-int", MEDIA_FORMAT_AAC}} +#endif +}; + +static const mc_codec_map_t decoder_map[] = +{ +#ifdef ENABLE_FFMPEG_CODEC + {MEDIACODEC_H264, SOFTWARE, {"ffdec_h264", "video/x-h264", MEDIA_FORMAT_I420}}, + {MEDIACODEC_AAC, SOFTWARE, {"ffdec_aac", "audio/mpeg", MEDIA_FORMAT_PCM}}, + {MEDIACODEC_MP3, SOFTWARE, {"ffdec_mp3", "audio/mpeg", MEDIA_FORMAT_PCM}} +#else + {MEDIACODEC_H264, SOFTWARE, {"maru_h264dec", "video/x-h264", MEDIA_FORMAT_I420}}, + {MEDIACODEC_AAC, SOFTWARE, {"maru_aacdec", "audio/mpeg", MEDIA_FORMAT_PCM}}, + {MEDIACODEC_MP3, SOFTWARE, {"maru_mp3dec", "audio/mpeg", MEDIA_FORMAT_PCM}} +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CODEC_EMUL_H__ */ diff --git a/include/media_codec_util.h b/include/media_codec_util.h new file mode 100755 index 0000000..5acf139 --- /dev/null +++ b/include/media_codec_util.h @@ -0,0 +1,84 @@ +/* +* Copyright (c) 2011 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_UTIL_H__ +#define __TIZEN_MEDIA_CODEC_UTIL_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <glib.h> +#include <tizen.h> +//#include <mm_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if 1 +#define MEDIACODEC_FENTER(); LOGI("%s Enter",__FUNCTION__); +#define MEDIACODEC_FLEAVE(); LOGI("%s Exit",__FUNCTION__); +#else +#define MEDIACODEC_FENTER(); LOGD("%s Enter",__FUNCTION__); +#define MEDIACODEC_FLEAVE(); LOGD("%s Exit",__FUNCTION__); +#endif + + +typedef enum +{ + CODEC_RET_SUCCESS = 0, + CODEC_RET_FAIL = -1, + CODEC_RET_NOT_SUPPORT = -2, + CODEC_RET_INVALID_ARG = -3, + CODEC_RET_INVALID_CONFIG = -4, + CODEC_RET_CORRUPTED_BS = -5, + CODEC_RET_SMALL_IMG_BUF = -6, + CODEC_RET_HW_ERROR = -7, + CODEC_RET_NOT_AVAILABLE = -8, + CODEC_RET_NOT_EXPECTED = -9, + CODEC_RET_UNKNOWN_ERR = -100, +} CodecRet; + +typedef struct _mc_sem_t mc_sem_t; + +struct _mc_sem_t +{ + GCond cond; + GMutex mutex; + int counter; +}; + +void *mc_aligned_malloc(int size, int alignment); +void mc_aligned_free(void *mem); + +mc_sem_t *mc_sem_new(); +void mc_sem_free(mc_sem_t *sem); +void mc_sem_down(mc_sem_t *sem); +void mc_sem_up(mc_sem_t *sem); +void mc_hex_dump(char *desc, void *addr, int len); + +#define MC_FREEIF(x) \ +if ( x ) \ + g_free( x ); \ +x = NULL; + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_CODEC_UTIL_H__ */ diff --git a/packaging/capi-media-codec.spec b/packaging/capi-media-codec.spec new file mode 100755 index 0000000..d6c1027 --- /dev/null +++ b/packaging/capi-media-codec.spec @@ -0,0 +1,81 @@ +Name: capi-media-codec +Summary: A Media Codec library in Tizen Native API +Version: 0.1.2 +Release: 0 +Group: Multimedia/API +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(mm-common) +BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(capi-media-tool) +BuildRequires: pkgconfig(libtbm) +BuildRequires: pkgconfig(gstreamer-0.10) +BuildRequires: pkgconfig(gstreamer-plugins-base-0.10) +BuildRequires: pkgconfig(gstreamer-app-0.10) +BuildRequires: pkgconfig(libdri2) + +Requires(post): /sbin/ldconfig +Requires(post): libprivilege-control +Requires(postun): /sbin/ldconfig + +%description + + +%package devel +Summary: A Media Player library in Tizen Native API (Development) +Group: Multimedia/API +Requires: %{name} = %{version}-%{release} + +%description devel + +%prep +%setup -q + + +%build +%if 0%{?sec_build_binary_debug_enable} +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" +%endif +%ifarch %{arm} +export CFLAGS="$CFLAGS -DENABLE_FFMPEG_CODEC" +%endif + +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} + + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +mkdir -p %{buildroot}/usr/bin +cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} +cp test/media_codec_test %{buildroot}/usr/bin +%make_install + +%post +/sbin/ldconfig + +%postun -p /sbin/ldconfig + + +%files +%manifest capi-media-codec.manifest +%{_libdir}/libcapi-media-codec.so.* +%{_datadir}/license/%{name} +/usr/bin/* +#%{_bindir}/* + +%files devel +%{_includedir}/media/*.h +%{_libdir}/pkgconfig/*.pc +%{_libdir}/libcapi-media-codec.so + + diff --git a/src/media_codec.c b/src/media_codec.c new file mode 100755 index 0000000..75988a3 --- /dev/null +++ b/src/media_codec.c @@ -0,0 +1,512 @@ +/* +* Copyright (c) 2011 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <media_codec.h> +#include <media_codec_private.h> +#include <media_codec_port.h> + +#include <dlog.h> + +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_error_cb(mediacodec_error_e error, void *user_data); +static gboolean __mediacodec_eos_cb(void *user_data); + +/* +* Internal Implementation +*/ +int __convert_error_code(int code, char* func_name) +{ + int ret = MEDIACODEC_ERROR_INVALID_OPERATION; + char* msg = "MEDIACOODEC_INVALID_OPERATION"; + switch(code) + { + case MC_ERROR_NONE: + ret = MEDIACODEC_ERROR_NONE; + msg = "MEDIACODEC_ERROR_NONE"; + break; + case MC_PARAM_ERROR: + case MC_INVALID_ARG: + ret = MEDIACODEC_ERROR_INVALID_PARAMETER; + msg = "MEDIACODEC_ERROR_INVALID_PARAMETER"; + break; + case MC_PERMISSION_DENIED: + ret = MEDIACODEC_ERROR_PERMISSION_DENIED; + msg = "MEDIACODEC_ERROR_PERMISSION_DENIED"; + break; + case MC_INVALID_STATUS: + ret = MEDIACODEC_ERROR_INVALID_STATE; + msg = "MEDIACODEC_ERROR_INVALID_STATE"; + break; + case MC_NOT_SUPPORTED: + ret = MEDIACODEC_ERROR_NOT_SUPPORTED_ON_DEVICE; + msg = "MEDIACODEC_ERROR_NOT_SUPPORTED_ON_DEVICE"; + break; + case MC_ERROR: + case MC_INTERNAL_ERROR: + case MC_HW_ERROR: + ret = MEDIACODEC_ERROR_INVALID_OPERATION; + msg = "MEDIACODEC_ERROR_INVALID_OPERATION"; + break; + case MC_INVALID_STREAM: + ret = MEDIACODEC_ERROR_INVALID_STREAM; + msg = "MEDIACODEC_ERROR_INVALID_STREAM"; + break; + case MC_CODEC_NOT_FOUND: + ret = MEDIACODEC_ERROR_CODEC_NOT_FOUND; + msg = "MEDIACODEC_ERROR_CODEC_NOT_FOUND"; + break; + case MC_ERROR_DECODE: + ret = MEDIACODEC_ERROR_DECODE; + msg = "MEDIACODEC_ERROR_DECODE"; + break; + case MC_INVALID_IN_BUF: + ret = MEDIACODEC_ERROR_INVALID_INBUFFER; + msg = "MEDIACODEC_ERROR_INVALID_INBUFFER"; + break; + case MC_INVALID_OUT_BUF: + ret = MEDIACODEC_ERROR_INVALID_OUTBUFFER; + msg = "MEDIACODEC_ERROR_INVALID_OUTBUFFER"; + break; + case MC_NOT_INITIALIZED: + ret = MEDIACODEC_ERROR_NOT_INITIALIZED; + msg = "MEDIACODEC_ERROR_NOT_INITIALIZED"; + break; + case MC_OUTPUT_BUFFER_EMPTY: + case MC_OUTPUT_BUFFER_OVERFLOW: + ret = MEDIACODEC_ERROR_BUFFER_NOT_AVAILABLE; + msg = "MEDIACODEC_ERROR_BUFFER_NOT_AVAILABLE"; + break; + default: + ret = MEDIACODEC_ERROR_INTERNAL; + msg = "MEDIACODEC_ERROR_INTERNAL"; + break; + } + LOGD("[%s] %s(0x%08x) : core fw error(0x%x)", func_name, msg, ret, code); + return ret; +} + +bool __mediacodec_state_validate(mediacodec_h mediacodec, mediacodec_state_e threshold) +{ + mediacodec_s * handle = (mediacodec_s *) mediacodec; + + if(handle->state < threshold) + return FALSE; + return TRUE; +} + + +int mediacodec_create(mediacodec_h *mediacodec) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s *handle; + int ret; + + LOGD ("mediacodec_create..\n"); + + handle = (mediacodec_s*)malloc( sizeof(mediacodec_s)); + if (handle != NULL) + { + memset(handle, 0 , sizeof(mediacodec_s)); + } + else + { + LOGE("MEDIACODEC_ERROR_OUT_OF_MEMORY(0x%08x)", MEDIACODEC_ERROR_OUT_OF_MEMORY); + return MEDIACODEC_ERROR_OUT_OF_MEMORY; + } + + ret = mc_create(&handle->mc_handle); + if (ret != MEDIACODEC_ERROR_NONE) + { + LOGE("MEDIACODEC_ERROR_INVALID_OPERATION(0x%08x)", MEDIACODEC_ERROR_INVALID_OPERATION); + handle->state = MEDIACODEC_STATE_NONE; + free(handle); + handle = NULL; + return MEDIACODEC_ERROR_INVALID_OPERATION; + } + else + { + *mediacodec = (mediacodec_h) handle; + handle->state = MEDIACODEC_STATE_IDLE; + LOGD("new handle : %p", *mediacodec); + } + + /* set callback */ + mc_set_empty_buffer_cb(handle->mc_handle, (mediacodec_input_buffer_used_cb)__mediacodec_empty_buffer_cb, handle); + mc_set_fill_buffer_cb(handle->mc_handle, (mediacodec_output_buffer_available_cb)__mediacodec_fill_buffer_cb, handle); + mc_set_error_cb(handle->mc_handle, (mediacodec_error_cb)__mediacodec_error_cb, handle); + mc_set_eos_cb(handle->mc_handle, (mediacodec_eos_cb)__mediacodec_eos_cb, handle); + + return MEDIACODEC_ERROR_NONE; + +} + +int mediacodec_destroy(mediacodec_h mediacodec) +{ + LOGD ("[%s] Start, handle to destroy : %p", __FUNCTION__, mediacodec); + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + + int ret = mc_destroy(handle->mc_handle); + if (ret != MEDIACODEC_ERROR_NONE) { + LOGD("MEDIACODEC_ERROR_INVALID_OPERATION(0x%08x)", MEDIACODEC_ERROR_INVALID_OPERATION); + return MEDIACODEC_ERROR_INVALID_OPERATION; + } + else + { + handle->state = MEDIACODEC_STATE_NONE; + free(handle); + handle = NULL; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_set_codec(mediacodec_h mediacodec, mediacodec_codec_type_e codec_id, mediacodec_support_type_e flags) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + int ret = mc_set_codec(handle->mc_handle, codec_id, flags); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + handle->state = MEDIACODEC_STATE_IDLE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_set_vdec_info(mediacodec_h mediacodec, int width, int height) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + int ret = mc_set_vdec_info(handle->mc_handle, width, height); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + handle->state = MEDIACODEC_STATE_IDLE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_set_venc_info(mediacodec_h mediacodec, int width, int height, int fps, int target_bits) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + int ret = mc_set_venc_info(handle->mc_handle, width, height, fps, target_bits); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + handle->state = MEDIACODEC_STATE_IDLE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_set_adec_info(mediacodec_h mediacodec, int samplerate, int channel, int bit) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + int ret = mc_set_adec_info(handle->mc_handle, samplerate, channel, bit); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + handle->state = MEDIACODEC_STATE_IDLE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_set_aenc_info(mediacodec_h mediacodec, int samplerate, int channel, int bit, int bitrate) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + int ret = mc_set_aenc_info(handle->mc_handle, samplerate, channel, bit, bitrate); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + handle->state = MEDIACODEC_STATE_IDLE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_prepare(mediacodec_h mediacodec) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + int ret = mc_prepare(handle->mc_handle); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + handle->state = MEDIACODEC_STATE_READY; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_unprepare(mediacodec_h mediacodec) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + + int ret = mc_unprepare(handle->mc_handle); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + handle->state = MEDIACODEC_STATE_IDLE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_process_input(mediacodec_h mediacodec, media_packet_h inbuf, uint64_t timeOutUs) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_READY); + + int ret = mc_process_input(handle->mc_handle, inbuf, timeOutUs); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + //handle->state = MEDIACODEC_STATE_EXCUTE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_get_output(mediacodec_h mediacodec, media_packet_h *outbuf, uint64_t timeOutUs) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_READY); + + int ret = mc_get_output(handle->mc_handle, outbuf, timeOutUs); + + if (ret != MEDIACODEC_ERROR_NONE) + { + return __convert_error_code(ret,(char*)__FUNCTION__); + } + else + { + //handle->state = MEDIACODEC_STATE_EXCUTE; + return MEDIACODEC_ERROR_NONE; + } +} + +int mediacodec_set_input_buffer_used_cb(mediacodec_h mediacodec, mediacodec_input_buffer_used_cb callback, void* user_data) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + handle->empty_buffer_cb = callback; + handle->empty_buffer_cb_userdata = user_data; + + LOGD("set empty_buffer_cb(%p)", callback); + + return MEDIACODEC_ERROR_NONE; +} + +int mediacodec_unset_input_buffer_used_cb(mediacodec_h mediacodec) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + + handle->empty_buffer_cb = NULL; + handle->empty_buffer_cb_userdata = NULL; + + return MEDIACODEC_ERROR_NONE; +} + + +int mediacodec_set_output_buffer_available_cb(mediacodec_h mediacodec, mediacodec_output_buffer_available_cb callback, void* user_data) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + handle->fill_buffer_cb = callback; + handle->fill_buffer_cb_userdata = user_data; + + LOGD("set fill_buffer_cb(%p)", callback); + + return MEDIACODEC_ERROR_NONE; + +} + +int mediacodec_unset_output_buffer_available_cb(mediacodec_h mediacodec) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + + handle->fill_buffer_cb = NULL; + handle->fill_buffer_cb_userdata = NULL; + + return MEDIACODEC_ERROR_NONE; +} + +int mediacodec_set_error_cb(mediacodec_h mediacodec, mediacodec_error_cb callback, void* user_data) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + handle->error_cb = callback; + handle->error_cb_userdata = user_data; + + LOGD("set error_cb(%p)", callback); + + return MEDIACODEC_ERROR_NONE; + +} + +int mediacodec_unset_error_cb(mediacodec_h mediacodec) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + + handle->error_cb = NULL; + handle->error_cb_userdata = NULL; + + return MEDIACODEC_ERROR_NONE; +} + +int mediacodec_set_eos_cb(mediacodec_h mediacodec, mediacodec_eos_cb callback, void* user_data) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + MEDIACODEC_STATE_CHECK(handle, MEDIACODEC_STATE_IDLE); + + handle->eos_cb = callback; + handle->eos_cb_userdata = user_data; + + LOGD("set eos_cb(%p)", callback); + + return MEDIACODEC_ERROR_NONE; + +} + +int mediacodec_unset_eos_cb(mediacodec_h mediacodec) +{ + MEDIACODEC_INSTANCE_CHECK(mediacodec); + mediacodec_s * handle = (mediacodec_s *) mediacodec; + + handle->eos_cb = NULL; + handle->eos_cb_userdata = NULL; + + return MEDIACODEC_ERROR_NONE; +} + +static gboolean __mediacodec_empty_buffer_cb(media_packet_h pkt, void *user_data) +{ + if(user_data == NULL || pkt == NULL) + return 0; + + mediacodec_s * handle = (mediacodec_s *) user_data; + + if ( handle->empty_buffer_cb ) + { + ((mediacodec_input_buffer_used_cb)handle->empty_buffer_cb)(pkt, handle->empty_buffer_cb_userdata); + } + + return 1; +} + +static gboolean __mediacodec_fill_buffer_cb(media_packet_h pkt, void *user_data) +{ + if(user_data == NULL || pkt == NULL) + return 0; + + mediacodec_s * handle = (mediacodec_s *) user_data; + + if ( handle->fill_buffer_cb ) + { + ((mediacodec_output_buffer_available_cb)handle->fill_buffer_cb)(pkt, handle->fill_buffer_cb_userdata); + } + + return 1; +} + +static gboolean __mediacodec_error_cb(mediacodec_error_e error, void *user_data) +{ + if(user_data == NULL) + return 0; + + mediacodec_s * handle = (mediacodec_s *) user_data; + + if ( handle->error_cb ) + { + ((mediacodec_error_cb)handle->error_cb)(error, handle->error_cb_userdata); + } + + return 1; +} + +static gboolean __mediacodec_eos_cb(void *user_data) +{ + if(user_data == NULL) + return 0; + + mediacodec_s * handle = (mediacodec_s *) user_data; + + if ( handle->eos_cb ) + { + ((mediacodec_eos_cb)handle->eos_cb)(handle->eos_cb_userdata); + } + + return 1; +} diff --git a/src/media_codec_port.c b/src/media_codec_port.c new file mode 100755 index 0000000..112b788 --- /dev/null +++ b/src/media_codec_port.c @@ -0,0 +1,748 @@ +/* +* Copyright (c) 2011 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <dlog.h> + +#include <media_codec.h> +#include <media_codec_private.h> +#include <media_codec_port.h> +#include <media_codec_port_gst.h> + +#include <media_codec_spec_emul.h> + +//static gboolean _mc_check_is_supported(mc_handle_t* mc_handle, mediacodec_codec_type_e codec_id, mediacodec_support_type_e flags); + +int mc_create(MMHandleType *mediacodec) +{ + mc_handle_t* new_mediacodec = NULL; + int ret = MC_ERROR_NONE; + + /* alloc mediacodec structure */ + new_mediacodec = (mc_handle_t*)g_malloc(sizeof(mc_handle_t)); + if ( ! new_mediacodec ) + { + LOGE("Cannot allocate memory for player\n"); + ret = MC_ERROR; + goto ERROR; + } + memset(new_mediacodec, 0, sizeof(mc_handle_t)); + + new_mediacodec->is_encoder = false; + new_mediacodec->is_video = false; + new_mediacodec->is_hw = true; + new_mediacodec->is_prepared = false; + new_mediacodec->codec_id = MEDIACODEC_NONE; + + new_mediacodec->ports[0] = NULL; + new_mediacodec->ports[1] = NULL; + + new_mediacodec->core = NULL; + + g_mutex_init(&new_mediacodec->cmd_lock); + /* + if(!new_mediacodec->cmd_lock) + { + LOGE("failed to create cmd_lock"); + goto ERROR; + } + */ + *mediacodec = (MMHandleType)new_mediacodec; + + return ret; + + // TO DO +ERROR: + // TO DO + // If we need destroy and release for others (cmd, mutex..) + g_mutex_clear(&new_mediacodec->cmd_lock); + free(new_mediacodec); + new_mediacodec = NULL; + return MC_INVALID_ARG; + + return ret; +} + +int mc_destroy(MMHandleType mediacodec) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + MEDIACODEC_CMD_LOCK( mediacodec ); + + LOGD("mediacodec : %p", mediacodec); + + if(mc_handle->core != NULL) + { + if(mc_gst_unprepare(mc_handle) != MC_ERROR_NONE) + { + LOGE("mc_gst_unprepare() failed"); + return MC_ERROR; + } + } + + mc_handle->is_prepared = false; + + MEDIACODEC_CMD_UNLOCK( mediacodec ); + + /* free mediacodec structure */ + if(mc_handle) { + g_free( (void*)mc_handle ); + mc_handle = NULL; + } + return ret; +} + +int mc_set_codec(MMHandleType mediacodec, mediacodec_codec_type_e codec_id, mediacodec_support_type_e flags) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + static const int support_list = sizeof(spec_emul) / sizeof(spec_emul[0]); + int i; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + // Mandatory setting + if ( !GET_IS_ENCODER(flags) && !GET_IS_DECODER(flags) ) + { + LOGE("should be encoder or decoder\n"); + return MC_PARAM_ERROR; + } +/* + if(!_mc_check_is_supported(mc_handle, codec_id, flags)) + return MC_NOT_SUPPORTED; +*/ + for(i = 0; i < support_list; i++) + { + if((codec_id == spec_emul[i].codec_id) && (flags == spec_emul[i].codec_type)) + { + break; + } + } + + LOGD("support_list : %d, i : %d", support_list, i); + + if(i == support_list) + return MC_NOT_SUPPORTED; + + mc_handle->port_type = spec_emul[i].port_type; + + mc_handle->is_encoder = GET_IS_ENCODER(flags) ? 1 : 0; + mc_handle->is_hw = GET_IS_HW(flags) ? 1 : 0; + mc_handle->codec_id = codec_id; + mc_handle->is_video = CHECK_BIT(codec_id, 13); + + mc_handle->is_prepared = false; + + LOGD("encoder : %d, hardware : %d, codec_id : %x, video : %d", + mc_handle->is_encoder, mc_handle->is_hw, mc_handle->codec_id, mc_handle->is_video); +#if 0 + // mc_handle->is_omx = use_omx; + // !!!! make it dynamic + mc_handle->port_type = MEDIACODEC_PORT_TYPE_GST; + + // !!!! only gst case is here. expend it to all. + if (encoder) + { + switch(codec_id) + { + case MEDIACODEC_H264: + mc_handle->supported_codec = GST_ENCODE_H264; + mc_handle->mimetype = MEDIA_FORMAT_H264_HP; + mc_handle->is_video = 1; + break; + case MEDIACODEC_AAC: + mc_handle->supported_codec = GST_ENCODE_AAC; + mc_handle->mimetype = MEDIA_FORMAT_AAC; + mc_handle->is_video = 0; + break; + default: + LOGE("NOT SUPPORTED!!!!"); + break; + } + + mc_handle->is_encoder = true; + } + else + { + switch(codec_id) + { + case MEDIACODEC_H264: + mc_handle->supported_codec = GST_DECODE_H264; + mc_handle->mimetype = MEDIA_FORMAT_NV12; + mc_handle->is_video = 1; + break; + case MEDIACODEC_AAC: + mc_handle->supported_codec = GST_DECODE_AAC; + mc_handle->mimetype = MEDIA_FORMAT_PCM; + mc_handle->is_video = 0; + break; + default: + LOGE("NOT SUPPORTED!!!!"); + break; + } + + // !!!! check if need to be dynamic + mc_handle->is_encoder = false; + } +#endif + return ret; +} + +int mc_set_vdec_info(MMHandleType mediacodec, int width, int height) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if ((width <= 0) || (height <= 0)) + return MC_PARAM_ERROR; + + MEDIACODEC_CHECK_CONDITION(mc_handle->codec_id && mc_handle->is_video && !mc_handle->is_encoder, + MEDIACODEC_ERROR_INVALID_PARAMETER,"MEDIACODEC_ERROR_INVALID_PARAMETER"); + + mc_handle->info.decoder.width = width; + mc_handle->info.decoder.height = height; + + mc_handle->is_prepared = true; + + return ret; +} + +int mc_set_venc_info(MMHandleType mediacodec, int width, int height, int fps, int target_bits) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if ((width <= 0) || (height <= 0)) + return MC_PARAM_ERROR; + + MEDIACODEC_CHECK_CONDITION(mc_handle->codec_id && mc_handle->is_video && mc_handle->is_encoder, + MEDIACODEC_ERROR_INVALID_PARAMETER, "MEDIACODEC_ERROR_INVALID_PARAMETER"); + + mc_handle->info.encoder.width = width; + mc_handle->info.encoder.height = height; + mc_handle->info.encoder.fps = fps; + mc_handle->info.encoder.bitrate = target_bits; + + mc_handle->is_prepared = true; + + return ret; +} + +int mc_set_adec_info(MMHandleType mediacodec, int samplerate, int channel, int bit) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if ((samplerate <= 0) || (channel <= 0) || (bit <= 0)) + return MC_PARAM_ERROR; + + MEDIACODEC_CHECK_CONDITION(mc_handle->codec_id && !mc_handle->is_video && !mc_handle->is_encoder, + MEDIACODEC_ERROR_INVALID_PARAMETER, "MEDIACODEC_ERROR_INVALID_PARAMETER"); + + mc_handle->info.decoder.samplerate = samplerate; + mc_handle->info.decoder.channel = channel; + mc_handle->info.decoder.bit = bit; + + mc_handle->is_prepared = true; + + return ret; +} + +int mc_set_aenc_info(MMHandleType mediacodec, int samplerate, int channel, int bit, int bitrate) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if ((samplerate <= 0) || (channel <= 0) || (bit <= 0)) + return MC_PARAM_ERROR; + + MEDIACODEC_CHECK_CONDITION(mc_handle->codec_id && !mc_handle->is_video && mc_handle->is_encoder, + MEDIACODEC_ERROR_INVALID_PARAMETER, "MEDIACODEC_ERROR_INVALID_PARAMETER"); + + mc_handle->info.encoder.samplerate = samplerate; + mc_handle->info.encoder.channel = channel; + mc_handle->info.encoder.bit = bit; + mc_handle->info.encoder.bitrate = bitrate; + + mc_handle->is_prepared = true; + + return ret; +} + +int mc_prepare(MMHandleType mediacodec) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if(!mc_handle->is_prepared) + return MC_NOT_INITIALIZED; + + MEDIACODEC_CMD_LOCK( mediacodec ); + + /* setting core details */ + switch ( mc_handle->port_type ) + { + case MEDIACODEC_PORT_TYPE_GENERAL: + { + } + break; + + case MEDIACODEC_PORT_TYPE_OMX: + { + } + break; + + case MEDIACODEC_PORT_TYPE_GST: + { + mc_gst_prepare(mc_handle); + } + break; + + default: + break; + } + + MEDIACODEC_CMD_UNLOCK( mediacodec ); + + return ret; +} + +int mc_unprepare(MMHandleType mediacodec) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + MEDIACODEC_CMD_LOCK( mediacodec ); + + /* deinit core details */ + switch ( mc_handle->port_type ) + { + case MEDIACODEC_PORT_TYPE_GENERAL: + { + } + break; + + case MEDIACODEC_PORT_TYPE_OMX: + { + } + break; + + case MEDIACODEC_PORT_TYPE_GST: + { + ret = mc_gst_unprepare(mc_handle); + } + break; + + default: + break; + } + + MEDIACODEC_CMD_UNLOCK( mediacodec ); + + return ret; +} + +int mc_process_input(MMHandleType mediacodec, media_packet_h inbuf, uint64_t timeOutUs ) +{ + int ret = MC_ERROR_NONE; + uint64_t buf_size = 0; + void *buf_data = NULL; + bool eos = false; + + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + ret = media_packet_get_buffer_size(inbuf, &buf_size); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("invaild input buffer"); + return MC_INVALID_IN_BUF; + } + + ret = media_packet_get_buffer_data_ptr(inbuf, &buf_data); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("invaild input buffer"); + return MC_INVALID_IN_BUF; + } + + ret = media_packet_is_end_of_stream(inbuf, &eos); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGE("invaild input buffer"); + return MC_INVALID_IN_BUF; + } + + if(!eos) + { + if((buf_data == NULL) || (buf_size == 0)) + { + LOGE("invaild input buffer"); + return MC_INVALID_IN_BUF; + } + } + + MEDIACODEC_CMD_LOCK( mediacodec ); + + switch ( mc_handle->port_type ) + { + case MEDIACODEC_PORT_TYPE_GENERAL: + { + //ret = mc_general_process_input(mc_handle->gen_core, inbuf, timeOutUs); + } + break; + + case MEDIACODEC_PORT_TYPE_OMX: + { + //ret = mc_omx_process_input(mc_handle, inbuf, timeOutUs); + } + break; + + case MEDIACODEC_PORT_TYPE_GST: + { + ret = mc_gst_process_input(mc_handle, inbuf, timeOutUs); + } + break; + + default: + break; + } + + MEDIACODEC_CMD_UNLOCK( mediacodec ); + + return ret; +} + +int mc_get_output(MMHandleType mediacodec, media_packet_h *outbuf, uint64_t timeOutUs) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + MEDIACODEC_CMD_LOCK( mediacodec ); + + /* setting core details */ + switch ( mc_handle->port_type ) + { + case MEDIACODEC_PORT_TYPE_GENERAL: + { + //ret= mc_general_get_output(mc_handle->gen_core, outbuf, timeOutUs); + } + break; + + case MEDIACODEC_PORT_TYPE_OMX: + { + //ret = mc_omx_get_output(mc_handle, outbuf, timeOutUs); + } + break; + + case MEDIACODEC_PORT_TYPE_GST: + { + ret = mc_gst_get_output(mc_handle, outbuf, timeOutUs); + } + break; + + default: + break; + } + + MEDIACODEC_CMD_UNLOCK( mediacodec ); + + return ret; +} + +int mc_set_empty_buffer_cb(MMHandleType mediacodec, mediacodec_input_buffer_used_cb callback, void* user_data) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if(mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]) + { + LOGE("Already set mediacodec_empty_buffer_cb\n"); + return MC_PARAM_ERROR; + } + else + { + if (!callback) + { + return MC_INVALID_ARG; + } + + LOGD("Set empty buffer callback(cb = %p, data = %p)\n", callback, user_data); + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER] = (mc_empty_buffer_cb) callback; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER] = user_data; + return MC_ERROR_NONE; + } + + return ret; +} +int mc_unset_empty_buffer_cb(MMHandleType mediacodec) +{ + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER] = NULL; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER] = NULL; + + return MC_ERROR_NONE; +} + +int mc_set_fill_buffer_cb(MMHandleType mediacodec, mediacodec_output_buffer_available_cb callback, void* user_data) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if(mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER]) + { + LOGE("Already set mediacodec_fill_buffer_cb\n"); + return MC_PARAM_ERROR; + } + else + { + if (!callback) { + return MC_INVALID_ARG; + } + + LOGD("Set fill buffer callback(cb = %p, data = %p)\n", callback, user_data); + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER] = (mc_fill_buffer_cb) callback; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_FILLBUFFER] = user_data; + return MC_ERROR_NONE; + } + + return ret; +} +int mc_unset_fill_buffer_cb(MMHandleType mediacodec) +{ + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER] = NULL; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_FILLBUFFER] = NULL; + + return MC_ERROR_NONE; +} + +int mc_set_error_cb(MMHandleType mediacodec, mediacodec_error_cb callback, void* user_data) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if(mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR]) + { + LOGE("Already set mediacodec_fill_buffer_cb\n"); + return MC_PARAM_ERROR; + } + else + { + if (!callback) { + return MC_INVALID_ARG; + } + + LOGD("Set event handler callback(cb = %p, data = %p)\n", callback, user_data); + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR] = (mc_error_cb) callback; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_ERROR] = user_data; + return MC_ERROR_NONE; + } + + return ret; +} + +int mc_unset_error_cb(MMHandleType mediacodec) +{ + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR] = NULL; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_ERROR] = NULL; + + return MC_ERROR_NONE; +} + +int mc_set_eos_cb(MMHandleType mediacodec, mediacodec_eos_cb callback, void* user_data) +{ + int ret = MC_ERROR_NONE; + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if(mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) + { + LOGE("Already set mediacodec_fill_buffer_cb\n"); + return MC_PARAM_ERROR; + } + else + { + if (!callback) { + return MC_INVALID_ARG; + } + + LOGD("Set event handler callback(cb = %p, data = %p)\n", callback, user_data); + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_EOS] = (mc_eos_cb) callback; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_EOS] = user_data; + return MC_ERROR_NONE; + } + + return ret; +} + +int mc_unset_eos_cb(MMHandleType mediacodec) +{ + mc_handle_t* mc_handle = (mc_handle_t*) mediacodec; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + mc_handle->user_cb[_MEDIACODEC_EVENT_TYPE_EOS] = NULL; + mc_handle->user_data[_MEDIACODEC_EVENT_TYPE_EOS] = NULL; + + return MC_ERROR_NONE; +} +/* +gboolean _mc_check_is_supported(mc_handle_t* mc_handle, mediacodec_codec_type_e codec_id, mediacodec_support_type_e flags) +{ + int i=0; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return FALSE; + } + + for (i = 0; i < MC_MAX_NUM_CODEC; i++) + { + if (mc_handle->g_media_codec_spec_emul[i].mime == codec_id) + { + if (mc_handle->g_media_codec_spec_emul[i].codec_type & (flags & 0x3)) + { + if (mc_handle->g_media_codec_spec_emul[i].support_type & (flags & 0xC)) + { + mc_handle->port_type = mc_handle->g_media_codec_spec_emul[i].port_type; + LOGD("port type : %d", mc_handle->port_type); + return TRUE; + } + } + + } + } + + return FALSE; +} +*/ diff --git a/src/media_codec_port_gst.c b/src/media_codec_port_gst.c new file mode 100755 index 0000000..170b45b --- /dev/null +++ b/src/media_codec_port_gst.c @@ -0,0 +1,2192 @@ +/* +* Copyright (c) 2011 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 <glib.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlog.h> +#include <media_codec_queue.h> +#include <media_codec_port_gst.h> +#include <media_codec_util.h> + +#include <gst/gst.h> +#include <gst/gstelement.h> +#include <gst/app/gstappsrc.h> + +#ifdef TIZEN_PROFILE_LITE +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/ion.h> +#endif + +#define GST_MC_EVENT_CODEC_DATA "GstEventCodecData" +/* +* Internal Implementation +*/ +static gpointer feed_task(gpointer data); +static media_packet_h _mc_get_input_buffer(mc_gst_core_t *core); + +static gboolean __mc_gst_init_gstreamer(); +static int _mc_output_media_packet_new(mc_gst_core_t *core, bool video, bool encoder, media_format_mimetype_e out_mime); +static mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t* core, gchar *factory_name); +static mc_ret_e _mc_gst_destroy_pipeline(mc_gst_core_t *core); +static void __mc_gst_buffer_add (GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer data); +static int __mc_output_buffer_finalize_cb(media_packet_h packet, int error_code, void *user_data); +static int __mc_output_packet_buffer_finalize_cb(media_packet_h packet, int error_code, void *user_data); + +static void _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstCaps **caps); +static mc_gst_buffer_t* _mc_gst_media_packet_to_gstbuffer(mc_gst_core_t* core, GstCaps **caps, media_packet_h pkt, bool codec_config); +static int _mc_gst_gstbuffer_to_appsrc(mc_gst_core_t *core, mc_gst_buffer_t *buff); +static guint32 __mc_get_gst_input_format(media_packet_h packet, bool is_hw); +static media_packet_h __mc_gst_gstbuffer_to_media_packet(mc_gst_core_t* core, GstBuffer* buffer); +static gboolean __mc_gst_bus_callback(GstBus *bus, GstMessage *msg, gpointer data); +static GstBusSyncReply __mc_gst_bus_sync_callback(GstBus * bus, GstMessage *msg, gpointer data); +static SCMN_IMGB* __mc_gst_make_tbm_buffer(mc_gst_core_t* core, media_packet_h pkt); +static gboolean event_probe_cb(GstPad *pad, GstEvent *event, gpointer user_data); +static GType __mc_gst_buffer_get_type(void); +static void __mc_gst_buffer_class_init(gpointer g_class, gpointer class_data); +static mc_gst_buffer_t* __mc_gst_buffer_new(mc_gst_core_t* core); +static void __mc_gst_buffer_finalize(mc_gst_buffer_t *buffer); + +static gint __gst_handle_stream_error(mc_gst_core_t* core, GError* error, GstMessage * message); +static gint __gst_transform_gsterror( mc_gst_core_t *core, GstMessage * message, GError* error ); +static gint __gst_handle_resource_error(mc_gst_core_t* core, int code ); +static gint __gst_handle_library_error(mc_gst_core_t* core, int code); +static gint __gst_handle_core_error(mc_gst_core_t* core, int code ); + +static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboolean is_encoder, gboolean is_hw); +#ifdef TIZEN_PROFILE_LITE +static int __tbm_get_physical_addr_bo(tbm_bo_handle tbm_bo_handle_fd_t, int* phy_addr, int* phy_size); +#endif +static void _mc_gst_set_flush_input(mc_gst_core_t *core); +static void _mc_gst_set_flush_output(mc_gst_core_t *core); + +static GstBufferClass *mc_gst_buffer_parent_class = NULL; + +#define GST_TYPE_MC_BUFFER (__mc_gst_buffer_get_type()) + +//static uint64_t wait_until = g_get_monotonic_time() + G_TIME_SPAN_SECOND / 2; + +int(*vdec_vtable[])() = {&__mc_fill_inbuf_with_packet, &__mc_fill_outbuf_with_packet, &__mc_vdec_caps}; +int(*venc_vtable[])() = {&__mc_fill_inbuf_with_packet, &__mc_fill_outbuf_with_packet, &__mc_venc_caps}; +int(*adec_vtable[])() = {&__mc_fill_inbuf_with_packet, &__mc_fill_outbuf_with_packet, &__mc_adec_caps}; +int(*aenc_vtable[])() = {&__mc_fill_inbuf_with_packet, &__mc_fill_outbuf_with_packet, &__mc_aenc_caps}; +int(*mp3dec_vtable[])() = {&__mc_fill_inbuf_with_packet, &__mc_fill_outbuf_with_packet, &__mc_mp3dec_caps}; +int(*h264dec_vtable[])() = {&__mc_fill_inbuf_with_packet, &__mc_fill_outbuf_with_bo, &__mc_vdec_caps}; +int(*h264enc_vtable[])() = {&__mc_fill_inbuf_with_bo, &__mc_fill_outbuf_with_packet, &__mc_venc_caps}; +int(*h263dec_vtable[])() = {&__mc_fill_inbuf_with_packet, &__mc_fill_outbuf_with_bo, &__mc_vdec_caps}; +int(*h263enc_vtable[])() = {&__mc_fill_inbuf_with_bo, &__mc_fill_outbuf_with_packet, &__mc_h263enc_caps}; + +/* + * mc_gst_object functions +*/ +int __mc_fill_input_buffer(mc_gst_core_t *core, mc_gst_buffer_t *buff) +{ + return core->vtable[fill_inbuf](core, buff); +} + +int __mc_fill_output_buffer(mc_gst_core_t *core, GstBuffer* buff, media_packet_h *out_pkt) +{ + return core->vtable[fill_outbuf](core, buff, out_pkt); +} + +int __mc_create_caps(mc_gst_core_t *core, GstCaps **caps) +{ + return core->vtable[create_caps](core, caps); +} + +int __mc_fill_inbuf_with_bo(mc_gst_core_t *core, mc_gst_buffer_t *buff) +{ + int ret = MC_ERROR_NONE; + void* buf_data = NULL; + uint64_t buf_size = 0; + + MEDIACODEC_FENTER(); + + if (!buff->pkt) + { + LOGE("output is null"); + return MC_INTERNAL_ERROR; + } + + /* copy media_packet to new gstbuffer */ + ret = media_packet_get_buffer_size(buff->pkt, &buf_size); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGW("buffer size get fail"); + } + + ret = media_packet_get_buffer_data_ptr(buff->pkt, &buf_data); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGW("buffer size get fail"); + return MC_INTERNAL_ERROR; + } + + SCMN_IMGB *imgb = NULL; + GST_BUFFER_DATA(buff) = buf_data; + GST_BUFFER_SIZE (buff) = buf_size; + imgb = __mc_gst_make_tbm_buffer(core, buff->pkt); + + if (!imgb) + { + LOGE("get imgb failed"); + return MC_INTERNAL_ERROR; + } + GST_BUFFER_MALLOCDATA(buff) = (guint8 *)imgb; + + LOGD("__mc_fill_inbuf_with_bo :%llu", buf_size); + + MEDIACODEC_FLEAVE(); + + return ret; +} + +int __mc_fill_inbuf_with_packet(mc_gst_core_t *core, mc_gst_buffer_t *buff) +{ + int ret = MEDIA_PACKET_ERROR_NONE; + void* buf_data = NULL; + uint64_t buf_size = 0; + + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + MEDIACODEC_FENTER(); + + /* copy media_packet to new gstbuffer */ + ret = media_packet_get_buffer_size(buff->pkt, &buf_size); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGW("buffer size get fail"); + return ret; + } + + ret = media_packet_get_buffer_data_ptr(buff->pkt, &buf_data); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGW("buffer size get fail"); + return ret; + } + + //mc_hex_dump("nal", buf_data, 8); + GST_BUFFER_DATA(buff) = buf_data; + GST_BUFFER_SIZE (buff) = buf_size; + + LOGD("filled with packet,%d, %p", (int)buf_size, buf_data); + MEDIACODEC_FLEAVE(); + + return ret; +} + +int __mc_fill_outbuf_with_bo(mc_gst_core_t *core, GstBuffer *buff, media_packet_h* out_pkt) +{ + int i = 0;; + int bo_num = 0; + + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + g_return_val_if_fail (buff != NULL, MC_PARAM_ERROR); + + MEDIACODEC_FENTER(); + + SCMN_IMGB *psimgb = NULL; + tbm_surface_h tsurf = NULL; + psimgb = (SCMN_IMGB*)GST_BUFFER_MALLOCDATA(buff); + mc_decoder_info_t *codec_info = (mc_decoder_info_t *)core->codec_info; +#ifdef TBM_API_CHANGE + tbm_surface_info_s tsurf_info; + memset(&tsurf_info, 0x0, sizeof(tbm_surface_info_s)); +#endif + + /* create tbm surface */ + for (i = 0; i < SCMN_IMGB_MAX_PLANE; i++) + { + if (psimgb->bo[i]) + { + bo_num++; +#ifdef TBM_API_CHANGE + tsurf_info.planes[i].stride = psimgb->s[i]; +#endif + } + } + + if (bo_num > 0) + { +#ifdef TBM_API_CHANGE + tsurf_info.width = codec_info->width; + tsurf_info.height = codec_info->height; + tsurf_info.format = TBM_FORMAT_NV12; // bo_format + tsurf_info.bpp = tbm_surface_internal_get_bpp(TBM_FORMAT_NV12); + tsurf_info.num_planes = tbm_surface_internal_get_num_planes(TBM_FORMAT_NV12); + tsurf_info.size = 0; + + for(i = 0; i < tsurf_info.num_planes; i++) { + tsurf_info.planes[i].stride = psimgb->s[i]; + tsurf_info.planes[i].size = psimgb->s[i] * psimgb->e[i]; + + if(i < bo_num) + tsurf_info.planes[i].offset = 0; + else + tsurf_info.planes[i].offset = tsurf_info.planes[i - 1].size; + tsurf_info.size += tsurf_info.planes[i].size; + } + + tsurf = tbm_surface_internal_create_with_bos(&tsurf_info, (tbm_bo *)psimgb->bo, bo_num); + LOGD("[NEW API] tbm surface %p", tsurf); +#else + tsurf = tbm_surface_internal_create_with_bos(codec_info->width, codec_info->height, TBM_FORMAT_NV12, (tbm_bo *)psimgb->bo, bo_num); + LOGD("[OLD API] tbm surface %p", tsurf); +#endif + } + + if (tsurf) + { + media_packet_create_from_tbm_surface(core->output_fmt, tsurf, (media_packet_finalize_cb)__mc_output_buffer_finalize_cb, core, out_pkt); + LOGD("output pkt = %p", *out_pkt); + media_packet_set_extra(*out_pkt, buff); + media_packet_set_buffer_size(*out_pkt, GST_BUFFER_SIZE(buff)); + media_packet_set_pts(*out_pkt, GST_BUFFER_TIMESTAMP(buff)); + } + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + + +int __mc_fill_outbuf_with_packet(mc_gst_core_t *core, GstBuffer *buff, media_packet_h *out_pkt) +{ + void* pkt_data = NULL; + + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + g_return_val_if_fail (buff != NULL, MC_PARAM_ERROR); + + MEDIACODEC_FENTER(); + + media_packet_create_alloc(core->output_fmt, __mc_output_packet_buffer_finalize_cb, core, out_pkt); + + if (!out_pkt) + { + LOGE("out_pkt is null"); + return MC_MEMORY_ERROR; + } + + media_packet_set_extra(*out_pkt, buff); + LOGI("create_gst_buffer = %p", buff); + LOGI("gstbuffer refcount %d", GST_MINI_OBJECT_REFCOUNT_VALUE(buff)); + + // !!!! this time do memcpy because no way to set data ptr to media packet. + media_packet_set_buffer_size(*out_pkt, GST_BUFFER_SIZE(buff)); + media_packet_get_buffer_data_ptr(*out_pkt, &pkt_data); + + if (!pkt_data) + { + media_packet_destroy(*out_pkt); + return MC_OUTPUT_BUFFER_EMPTY; + } + + memcpy(pkt_data, GST_BUFFER_DATA(buff), GST_BUFFER_SIZE(buff)); + media_packet_set_pts(*out_pkt, GST_BUFFER_TIMESTAMP(buff)); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +int __mc_venc_caps(mc_gst_core_t *core, GstCaps **caps) +{ + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + MEDIACODEC_FENTER(); + + mc_encoder_info_t *enc_info = (mc_encoder_info_t*)core->codec_info; + + *caps = gst_caps_new_simple(core->mime, + "format", GST_TYPE_FOURCC, core->format, + "width", G_TYPE_INT, enc_info->width, + "height", G_TYPE_INT, enc_info->height, + "framerate", GST_TYPE_FRACTION, enc_info->fps, 1, NULL); + + g_object_set (GST_OBJECT(core->codec), "byte-stream", TRUE, NULL); + g_object_set (GST_OBJECT(core->codec), "bitrate", enc_info->bitrate*1000, NULL); + + LOGD("%d, %d, %d, %d", core->format, enc_info->width, enc_info->height, enc_info->fps); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +int __mc_h263enc_caps(mc_gst_core_t *core, GstCaps **caps) +{ + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + mc_encoder_info_t *enc_info = (mc_encoder_info_t*)core->codec_info; + + MEDIACODEC_FENTER(); + + *caps = gst_caps_new_simple(core->mime, + "format", GST_TYPE_FOURCC, core->format, + "width", G_TYPE_INT, enc_info->width, + "height", G_TYPE_INT, enc_info->height, + "framerate", GST_TYPE_FRACTION, enc_info->fps, 1, NULL); + + g_object_set (GST_OBJECT(core->codec), "bitrate", enc_info->bitrate*1000, NULL); + + LOGD("%d, %d, %d, %d", core->format, enc_info->width, enc_info->height, enc_info->fps); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +int __mc_mp3dec_caps(mc_gst_core_t *core, GstCaps **caps) +{ + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + MEDIACODEC_FENTER(); + + mc_decoder_info_t *dec_info = (mc_decoder_info_t*)core->codec_info; + + *caps = gst_caps_new_simple(core->mime, + "mpegversion", G_TYPE_INT, 1, + "layer", G_TYPE_INT, 3, + "channels", G_TYPE_INT, dec_info->channel, + "rate", G_TYPE_INT, dec_info->samplerate, + NULL); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +int __mc_vdec_caps(mc_gst_core_t *core, GstCaps **caps) +{ + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + MEDIACODEC_FENTER(); + + mc_decoder_info_t *dec_info = (mc_decoder_info_t*)core->codec_info; + + LOGD("%d, %d, ", dec_info->width, dec_info->height); + *caps = gst_caps_new_simple(core->mime, + "width", G_TYPE_INT, dec_info->width, + "height", G_TYPE_INT, dec_info->height, + "framerate", GST_TYPE_FRACTION, 30, 1, NULL); + + LOGD("mime : %s, widht :%d, height : %d", core->mime, dec_info->width, dec_info->height); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +int __mc_aenc_caps(mc_gst_core_t *core, GstCaps **caps) +{ + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + mc_encoder_info_t *enc_info = (mc_encoder_info_t*)core->codec_info; + + MEDIACODEC_FENTER(); + + *caps = gst_caps_new_simple(core->mime, + "signed", G_TYPE_BOOLEAN, TRUE, + "width", G_TYPE_INT, enc_info->bit, + "depth", G_TYPE_INT, enc_info->bit, + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "channels", G_TYPE_INT, enc_info->channel, + "rate", G_TYPE_INT, enc_info->samplerate, NULL); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +int __mc_adec_caps(mc_gst_core_t *core, GstCaps **caps) +{ + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + mc_decoder_info_t *dec_info = (mc_decoder_info_t*)core->codec_info; + + MEDIACODEC_FENTER(); + + *caps = gst_caps_new_simple(core->mime, + "mpegversion", G_TYPE_INT, 4, + "channels", G_TYPE_INT, dec_info->channel, + "rate", G_TYPE_INT, dec_info->samplerate, + NULL); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +int _mc_output_media_packet_new(mc_gst_core_t *core, bool video, bool encoder, media_format_mimetype_e out_mime) +{ + MEDIACODEC_FENTER(); + + if(media_format_create(&core->output_fmt) != MEDIA_FORMAT_ERROR_NONE) + { + LOGE("media format create failed"); + return MC_ERROR; + } + + if(encoder) + { + mc_encoder_info_t *info; + + info = (mc_encoder_info_t*)core->codec_info; + + if (video) + { + media_format_set_video_mime(core->output_fmt, out_mime); + media_format_set_video_width(core->output_fmt, info->width); + media_format_set_video_height(core->output_fmt, info->height); + media_format_set_video_avg_bps(core->output_fmt, info->bitrate); + } + else + { + media_format_set_audio_mime(core->output_fmt, out_mime); + media_format_set_audio_channel(core->output_fmt, info->channel); + media_format_set_audio_samplerate(core->output_fmt, info->samplerate); + media_format_set_audio_bit(core->output_fmt, info->bit); + media_format_set_audio_avg_bps(core->output_fmt, info->bitrate); + } + } + else + { + mc_decoder_info_t *info; + + info = (mc_decoder_info_t*)core->codec_info; + + if (video) + { + media_format_set_video_mime(core->output_fmt, out_mime); + media_format_set_video_width(core->output_fmt, info->width); + media_format_set_video_height(core->output_fmt, info->height); + } + else + { + media_format_set_audio_mime(core->output_fmt, out_mime); + media_format_set_audio_channel(core->output_fmt, info->channel); + media_format_set_audio_samplerate(core->output_fmt, info->samplerate); + media_format_set_audio_bit(core->output_fmt, info->bit); + } + } + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; +} + +/* + * mc_gst_core functions +*/ +mc_gst_core_t *mc_gst_core_new() +{ + mc_gst_core_t *core; + + MEDIACODEC_FENTER(); + + core = g_new0(mc_gst_core_t, 1); + + /* 0 : input, 1 : output */ + core->ports[0] = NULL; + core->ports[1] = mc_gst_port_new(core); + core->ports[1]->index = 1; + + core->available_queue = g_new0(mc_aqueue_t, 1); + core->available_queue->input = mc_async_queue_new(); + + //core->eos_mutex = g_mutex_new(); + g_mutex_init(&core->eos_mutex); + //core->eos_wait_mutex = g_mutex_new(); + g_mutex_init(&core->eos_wait_mutex); + //core->drain_mutex = g_mutex_new(); + g_mutex_init(&core->drain_mutex); + //core->eos_cond = g_cond_new(); + g_cond_init(&core->eos_cond); + //core->eos_waiting_cond = g_cond_new(); + g_cond_init(&core->eos_waiting_cond); + //core->prepare_lock = g_mutex_new(); + g_mutex_init(&core->prepare_lock); + //core->push_sem = mc_sem_new(); + //core->pop_sem = mc_sem_new(); + + core->need_feed = false; + core->eos = false; + core->eos_waiting = false; + core->prepare_count = 0; + //g_atomic_int_set(&core->num_live_buffers, 0); + + g_atomic_int_set(&core->available_queue->running, 1); + //core->available_queue->thread = g_thread_create(feed_task, core, TRUE, NULL); + core->available_queue->thread = g_thread_new("feed thread", &feed_task, core); + + MEDIACODEC_FLEAVE(); + + return core; +} + +void mc_gst_core_free(mc_gst_core_t *core) +{ + mc_aqueue_t *async_queue; + + MEDIACODEC_FENTER(); + + async_queue = core->available_queue; + + _mc_gst_set_flush_input(core); + mc_async_queue_disable(async_queue->input); + //mc_async_queue_flush(async_queue->input); + + g_atomic_int_set(&async_queue->running, 0); + g_thread_join(async_queue->thread); + LOGD("@%p g_thread_join", core); + + //mc_sem_free(core->push_sem); + //mc_sem_free(core->pop_sem); + //g_mutex_free(core->drain_mutex); + g_mutex_clear(&core->drain_mutex); + //g_mutex_free(core->eos_mutex); + g_mutex_clear(&core->eos_mutex); + //g_mutex_free(core->eos_wait_mutex); + g_mutex_clear(&core->eos_wait_mutex); + //g_mutex_free(core->prepare_lock); + g_mutex_clear(&core->prepare_lock); + //g_cond_free(core->eos_cond); + g_cond_clear(&core->eos_cond); + //g_cond_free(core->eos_waiting_cond); + g_cond_clear(&core->eos_waiting_cond); + + + mc_async_queue_free(async_queue->input); + //mc_async_queue_free(async_queue->output); + //g_queue_free(core->output_queue); + + if(core->ports[1] != NULL) + { + mc_gst_port_free(core->ports[1]); + core->ports[1] = NULL; + } + + g_free(core); + + MEDIACODEC_FLEAVE(); +} + +/* + * mc_gst_port functions + */ +mc_gst_port_t *mc_gst_port_new(mc_gst_core_t *core) +{ + mc_gst_port_t *port; + + MEDIACODEC_FENTER(); + + port = g_new0(mc_gst_port_t, 1); + port->core = core; + port->num_buffers = -1; + port->buffer_size = 0; + port->is_allocated = 0; + port->buffers = NULL; + + //port->mutex = g_mutex_new(); + g_mutex_init(&port->mutex); + //port->buffer_cond = g_cond_new(); + g_cond_init(&port->buffer_cond); + port->queue = g_queue_new(); + + MEDIACODEC_FLEAVE(); + + return port; +} + +void mc_gst_port_free(mc_gst_port_t *port) +{ + MEDIACODEC_FENTER(); + + g_mutex_clear(&port->mutex); + g_cond_clear(&port->buffer_cond); + g_queue_free(port->queue); + + //destroy buffers + g_free(port); + + MEDIACODEC_FLEAVE(); + + return; +} + +static void _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstCaps **caps) +{ + //TODO remove is_hw param + core->format = __mc_get_gst_input_format(pkt, core->is_hw); + + __mc_create_caps(core, caps); +} + +static gboolean event_probe_cb(GstPad *pad, GstEvent *event, gpointer user_data) +{ + mc_gst_core_t *core = (mc_gst_core_t*)user_data; + const GstStructure *s; + gboolean codec_config = false; + //uint64_t wait_until = g_get_monotonic_time() + G_TIME_SPAN_SECOND / 2; + + switch(GST_EVENT_TYPE (event)) + { + case GST_EVENT_CUSTOM_DOWNSTREAM: + { + s = gst_event_get_structure (event); + if(gst_structure_has_name (s, GST_MC_EVENT_CODEC_DATA)) + { + gst_structure_get_boolean (s, "codec_config", &codec_config); + core->codec_config = codec_config; + LOGD("codec_config : %d", codec_config); + } + break; + } +#if 0 + case GST_EVENT_EOS: + { + g_mutex_lock(core->eos_mutex); + + core->eos = true; + g_cond_signal(core->eos_cond); + LOGD("send eos signal"); + + g_mutex_unlock(core->eos_mutex); + LOGD ("End of stream\n"); + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) + { + ((mc_eos_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS])(core->user_data[_MEDIACODEC_EVENT_TYPE_EOS]); + } + g_mutex_lock(core->eos_mutex); +/* + while(!core->eos) + { + LOGD("waiting for eos signal..."); + //g_cond_wait(core->eos_cond, core->eos_mutex); + if(!g_cond_wait_until(core->eos_cond, core->eos_mutex, wait_until)) + { + core->eos = true; + LOGD("time out"); + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) + { + ((mc_eos_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS])(core->user_data[_MEDIACODEC_EVENT_TYPE_EOS]); + } + + } + else + LOGD("recevied signal"); + } + + //_mc_gst_set_flush_input(core); + core->eos = false; + LOGD("eos flag set to false"); + + g_mutex_unlock(core->eos_mutex); +*/ + break; + + } +#endif + default: + break; + } + return true; +} + +static gpointer feed_task(gpointer data) +{ + mc_gst_core_t *core = (mc_gst_core_t*)data; + int ret = MC_ERROR_NONE; + bool codec_config = FALSE; + bool eos = FALSE; + media_packet_h in_buf = NULL; + mc_gst_buffer_t* buff = NULL; + GstCaps *new_caps = NULL; + bool initiative = true; + //uint64_t wait_until = g_get_monotonic_time() + G_TIME_SPAN_SECOND / 2; + MEDIACODEC_FENTER(); + + while(g_atomic_int_get(&core->available_queue->running)) + { + LOGD("waiting for next input...."); + in_buf = _mc_get_input_buffer(core); + + if(!in_buf) + goto LEAVE; + + if(media_packet_is_codec_config(in_buf, &codec_config) != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_is_codec_config failed"); + goto ERROR; + } + + if(media_packet_is_end_of_stream(in_buf, &eos) != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_is_end_of_stream failed"); + goto ERROR; + } + + if(codec_config) + initiative = true; + + if(eos) + { + g_mutex_lock(&core->eos_wait_mutex); + core->eos_waiting = true; + g_mutex_unlock(&core->eos_wait_mutex); + } + + if(initiative) + { + GstStructure *s; + GstEvent *event; + GstPad *pad; + + _mc_gst_update_caps(core, in_buf, &new_caps); + gst_app_src_set_caps(GST_APP_SRC(core->appsrc), new_caps); + + pad = gst_element_get_static_pad(core->appsrc, "src"); + s = gst_structure_new (GST_MC_EVENT_CODEC_DATA, + "codec_config", G_TYPE_BOOLEAN, true, NULL); + event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s); + gst_pad_push_event (pad,event); + gst_object_unref(pad); + + LOGD("caps updated"); + } + + buff = _mc_gst_media_packet_to_gstbuffer(core, &new_caps, in_buf, codec_config); + if (!buff) + { + LOGW("gstbuffer can't make"); + goto ERROR; + } + LOGD("gstbuffer refcount %d", GST_MINI_OBJECT_REFCOUNT_VALUE(buff)); + + g_mutex_lock(&core->drain_mutex); + /* inject buffer */ + ret = _mc_gst_gstbuffer_to_appsrc(core, buff); + if(ret != GST_FLOW_OK) + { + LOGE("Failed to push gst buffer"); + g_mutex_unlock(&core->drain_mutex); + goto ERROR; + } + LOGD("after refcount %d", GST_MINI_OBJECT_REFCOUNT_VALUE(buff)); + + initiative = false; + g_mutex_unlock(&core->drain_mutex); + +#if 1 + if (eos) + { + LOGD("end of stream"); + //goto EOS; + + uint64_t wait_until = g_get_monotonic_time() + G_TIME_SPAN_SECOND / 2; + + g_signal_emit_by_name(core->appsrc, "end-of-stream", &ret); + + while(!core->eos) + { + LOGD("waiting for eos signal..."); + if(!g_cond_wait_until(&core->eos_cond, &core->eos_mutex, wait_until)) + { + core->eos = true; + LOGD("time out"); + } + else + LOGD("recevied signal"); + } + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) + { + LOGD("eos callback invoked"); + ((mc_eos_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS])(core->user_data[_MEDIACODEC_EVENT_TYPE_EOS]); + } +#if 1 + core->eos = false; + core->eos_waiting = false; + initiative = true; + g_cond_signal(&core->eos_waiting_cond); + LOGD("eos flag set to false"); +#endif +/* + + core->eos = true; + _mc_gst_set_flush_input(core); + + + g_mutex_lock(core->eos_mutex); + + core->eos = false; + initiative = true; + + g_mutex_unlock(core->eos_mutex); + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) + { + ((mc_eos_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS])(core->user_data[_MEDIACODEC_EVENT_TYPE_EOS]); + LOGD("send eos callback"); + } + //g_signal_emit_by_name(core->appsrc, "end-of-stream", &ret); +*/ + + } +#endif + continue; +ERROR: + + g_mutex_lock(&core->drain_mutex); + _mc_gst_set_flush_input(core); + g_mutex_unlock(&core->drain_mutex); + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR]) + { + ((mc_error_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR])(MC_INTERNAL_ERROR, core->user_data[_MEDIACODEC_EVENT_TYPE_ERROR]); + } + + continue; +/* +EOS: + + g_signal_emit_by_name(core->appsrc, "end-of-stream", &ret); + + while(!core->eos) + { + LOGD("waiting for eos signal..."); + //g_cond_wait(core->eos_cond, core->eos_mutex); + if(!g_cond_wait_until(core->eos_cond, core->eos_mutex, wait_until)) + { + core->eos = true; + LOGD("time out"); + + } + else + LOGD("recevied signal"); + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) + { + LOGD("eos callback invoked"); + ((mc_eos_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS])(core->user_data[_MEDIACODEC_EVENT_TYPE_EOS]); + } + } + + core->eos = false; + core->eos_waiting = false; + g_cond_signal(core->eos_waiting_cond); + initiative = true; + LOGD("eos flag set to false"); + continue; +*/ +LEAVE: + //LOGE("status : in_buf : %p, codec_config : %d, eos : %d, encoder : %d in feed_task", in_buf, codec_config, eos, core->encoder); + continue; + + } + + if(new_caps) + { + gst_caps_unref(new_caps); + } + LOGI("status : in_buf : %p, codec_config : %d, eos : %d, video : %d, encoder : %d in feed_task", in_buf, codec_config, eos, core->video, core->encoder); + LOGD("feed task finished %p v(%d)e(%d)", core, core->video, core->encoder); + MEDIACODEC_FLEAVE(); + + return NULL; +} + +static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboolean encoder, gboolean is_hw) +{ + g_return_val_if_fail (core != NULL, MC_PARAM_ERROR); + + switch (id) + { + case MEDIACODEC_AAC: + { + LOGD("aac vtable"); + core->vtable = encoder ? aenc_vtable : adec_vtable; + break; + } + case MEDIACODEC_MP3: + { + LOGD("mp3 vtable"); + core->vtable = encoder ? aenc_vtable :mp3dec_vtable; + break; + } + case MEDIACODEC_H263: + { + LOGD("h263 vtable"); + if(is_hw) + core->vtable = encoder ? h263enc_vtable : h263dec_vtable; + else + core->vtable = encoder ? venc_vtable : vdec_vtable; + break; + } + case MEDIACODEC_H264: + { + LOGD("h264 vtable"); + if(is_hw) + core->vtable = encoder ? h264enc_vtable : h264dec_vtable; + else + core->vtable = encoder ? venc_vtable : vdec_vtable; + break; + } + default: + break; + } + + return MC_ERROR_NONE; +} + +static int _mc_gst_gstbuffer_to_appsrc(mc_gst_core_t *core, mc_gst_buffer_t *buff) +{ + int ret = MC_ERROR_NONE; + MEDIACODEC_FENTER(); + + ret = gst_app_src_push_buffer(GST_APP_SRC(core->appsrc), (GstBuffer*)buff); + + MEDIACODEC_FLEAVE(); + + return ret; +} + +media_packet_h _mc_get_input_buffer(mc_gst_core_t *core) +{ + LOGD("waiting for input..."); + return mc_async_queue_pop(core->available_queue->input); +} + +mc_ret_e mc_gst_prepare(mc_handle_t *mc_handle) +{ + int ret = MC_ERROR_NONE; + media_format_mimetype_e out_mime; + int i = 0; + + if (!mc_handle) + return MC_PARAM_ERROR; + + mediacodec_codec_type_e id; + bool video; + bool encoder; + bool hardware; + gchar *factory_name = NULL; + static const mc_codec_map_t *codec_map; + //media_packet_h out_pkt = NULL; + + MEDIACODEC_FENTER(); + + id = mc_handle->codec_id; + video = mc_handle->is_video; + encoder = mc_handle->is_encoder; + hardware = mc_handle->is_hw; + + const int codec_list = encoder ? (sizeof(encoder_map) / sizeof(encoder_map[0])) : (sizeof(decoder_map) / sizeof(decoder_map[0])); + + codec_map = encoder ? encoder_map : decoder_map; + + for(i = 0; i < codec_list; i++) + { + if((id == codec_map[i].id) && (hardware == codec_map[i].hardware)) + break; + } + + if( i == codec_list ) + return MC_NOT_SUPPORTED; + + factory_name = codec_map[i].type.factory_name; + out_mime = codec_map[i].type.out_format; + + /* gst_core create */ + mc_gst_core_t* new_core = mc_gst_core_new(); + + new_core->mime = codec_map[i].type.mime; + new_core->is_hw = hardware; + new_core->eos = false; + new_core->encoder = encoder; + new_core->video = video; + new_core->codec_info = encoder ? (void*)&mc_handle->info.encoder : (void*)&mc_handle->info.decoder; + + LOGD("@%p(%p) core is initializing...v(%d)e(%d)", mc_handle, new_core, new_core->video, new_core->encoder); + LOGD("factory name : %s, output_fmt : %x, mime %s", factory_name, out_mime, new_core->mime); + + /* create media_packet for output fmt */ + if ( (ret = _mc_output_media_packet_new(new_core, video, encoder, out_mime)) != MC_ERROR_NONE) + { + LOGE("Failed to create output pakcet"); + return ret; + } + + /* link vtable */ + if((ret = _mc_link_vtable(new_core, id, encoder, hardware)) != MC_ERROR_NONE) + { + LOGE("vtable link failed"); + return ret; + } + + for (i = 0; i < _MEDIACODEC_EVENT_TYPE_INTERNAL_FILLBUFFER ; i++) + { + LOGD("copy cb function [%d]", i); + if (mc_handle->user_cb[i]) + { + new_core->user_cb[i] = mc_handle->user_cb[i]; + new_core->user_data[i] = mc_handle->user_data[i]; + LOGD("user_cb[%d] %p, %p", i, new_core->user_cb[i], mc_handle->user_cb[i]); + } + } + + mc_handle->core = new_core; + + /* create basic core elements */ + ret = _mc_gst_create_pipeline(mc_handle->core, factory_name); + + MEDIACODEC_FLEAVE(); + + return ret; +} + +mc_ret_e mc_gst_unprepare(mc_handle_t *mc_handle) +{ + int i; + int ret = MC_ERROR_NONE; + mc_gst_core_t *core = NULL; + uint64_t wait_until = g_get_monotonic_time() + G_TIME_SPAN_SECOND / 2; + + MEDIACODEC_FENTER(); + + if (!mc_handle) + return MC_PARAM_ERROR; + + core = (mc_gst_core_t*)mc_handle->core; + + if(core) + { + LOGD("@%p(%p) core is uninitializing... v(%d)e(%d)",mc_handle, core, core->video, core->encoder); + + g_mutex_lock(&core->eos_wait_mutex); + + if(core->eos_waiting) + { + LOGD("waiting for eos is finished"); + if(!g_cond_wait_until(&core->eos_waiting_cond, &core->eos_wait_mutex, wait_until)) + { + core->eos_waiting = false; + LOGD("time out"); + } + else + { + LOGD("recevied signal from feed_task"); + } + + } + g_mutex_unlock(&core->eos_wait_mutex); + + + LOGD("%p/%p(%d) input flush", mc_handle, core, core->encoder); + g_mutex_lock(&core->drain_mutex); + + _mc_gst_set_flush_input(core); + + g_mutex_unlock(&core->drain_mutex); + + + + _mc_gst_set_flush_output(core); + + + /* unset callback */ + for (i = 0; i < _MEDIACODEC_EVENT_TYPE_INTERNAL_FILLBUFFER ; i++) + { + LOGD("unset cb function [%d]", i); + if (mc_handle->user_cb[i]) + { + core->user_cb[i] = NULL; + core->user_data[i] = NULL; + LOGD("user_cb[%d] %p, %p", i, core->user_cb[i], mc_handle->user_cb[i]); + } + } + + ret = _mc_gst_destroy_pipeline(core); + + if(core != NULL) + { + mc_gst_core_free(core); + mc_handle->core = NULL; + } + } + + MEDIACODEC_FLEAVE(); + + return ret; +} + +mc_ret_e mc_gst_process_input(mc_handle_t *mc_handle, media_packet_h inbuf, uint64_t timeOutUs) +{ + int ret = MC_ERROR_NONE; + mc_gst_core_t *core = NULL; + + if (!mc_handle) + return MC_PARAM_ERROR; + + core = (mc_gst_core_t*)mc_handle->core; + LOGI("@%p v(%d)e(%d)process_input", core, core->video, core->encoder); + + MEDIACODEC_FENTER(); + + g_mutex_lock(&core->eos_mutex); + + if(!core->eos) + mc_async_queue_push(core->available_queue->input, inbuf); + else + ret = MC_INVALID_IN_BUF; + + g_mutex_unlock(&core->eos_mutex); + + MEDIACODEC_FLEAVE(); + + return ret; +} + +mc_ret_e mc_gst_get_output(mc_handle_t *mc_handle, media_packet_h *outbuf, uint64_t timeOutUs) +{ + int ret = MC_ERROR_NONE; + mc_gst_core_t *core = NULL; + media_packet_h out_pkt = NULL; + + if (!mc_handle) + return MC_PARAM_ERROR; + + MEDIACODEC_FENTER(); + + core = (mc_gst_core_t*)mc_handle->core; + LOGI("@%p v(%d)e(%d) get_output", core, core->video, core->encoder); + + g_mutex_lock(&core->ports[1]->mutex); + + if(!g_queue_is_empty(core->ports[1]->queue)) + { + out_pkt = g_queue_pop_head(core->ports[1]->queue); + LOGD("pop from output_queue : %p", out_pkt); + } + else + { + ret = MC_OUTPUT_BUFFER_EMPTY; + LOGD("output_queue is empty"); + } + *outbuf = out_pkt; + + g_mutex_unlock(&core->ports[1]->mutex); + + MEDIACODEC_FLEAVE(); + + return ret; +} + +mc_ret_e mc_gst_flush_buffers(mc_handle_t *mc_handle) +{ + int ret = MC_ERROR_NONE; + mc_gst_core_t *core = NULL; + + if (!mc_handle) + return MC_PARAM_ERROR; + + MEDIACODEC_FENTER(); + + core = (mc_gst_core_t*)mc_handle->core; + LOGI("@%p v(%d)e(%d) get_output", core, core->video, core->encoder); + + _mc_gst_set_flush_input(core); + _mc_gst_set_flush_output(core); + + MEDIACODEC_FLEAVE(); + + return ret; +} + +static gboolean __mc_gst_init_gstreamer() +{ + static gboolean initialized = FALSE; + static const int max_argc = 50; + gint* argc = NULL; + gchar** argv = NULL; + gchar** argv2 = NULL; + GError *err = NULL; + int i = 0; + int arg_count = 0; + + MEDIACODEC_FENTER(); + + if ( initialized ) + { + LOGD("gstreamer already initialized.\n"); + return TRUE; + } + + /* alloc */ + argc = malloc( sizeof(int) ); + argv = malloc( sizeof(gchar*) * max_argc ); + argv2 = malloc( sizeof(gchar*) * max_argc ); + + if ( !argc || !argv || !argv2 ) + goto ERROR; + + memset( argv, 0, sizeof(gchar*) * max_argc ); + memset( argv2, 0, sizeof(gchar*) * max_argc ); + + /* add initial */ + *argc = 1; + argv[0] = g_strdup( "media codec" ); + + /* we would not do fork for scanning plugins */ + argv[*argc] = g_strdup("--gst-disable-registry-fork"); + (*argc)++; + + /* check disable registry scan */ + argv[*argc] = g_strdup("--gst-disable-registry-update"); + (*argc)++; + + /* check disable segtrap */ + argv[*argc] = g_strdup("--gst-disable-segtrap"); + (*argc)++; + + LOGD("initializing gstreamer with following parameter\n"); + LOGD("argc : %d\n", *argc); + arg_count = *argc; + + for ( i = 0; i < arg_count; i++ ) + { + argv2[i] = argv[i]; + LOGD("argv[%d] : %s\n", i, argv2[i]); + } + + /* initializing gstreamer */ + if ( ! gst_init_check (argc, &argv, &err)) + { + LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); + if (err) + { + g_error_free (err); + } + + goto ERROR; + } + + /* release */ + for ( i = 0; i < arg_count; i++ ) + { + //debug_log("release - argv[%d] : %s\n", i, argv2[i]); + MC_FREEIF( argv2[i] ); + } + + MC_FREEIF( argv ); + MC_FREEIF( argv2 ); + MC_FREEIF( argc ); + + /* done */ + initialized = TRUE; + + MEDIACODEC_FLEAVE(); + + return TRUE; + +ERROR: + + /* release */ + for ( i = 0; i < arg_count; i++ ) + { + LOGD("free[%d] : %s\n", i, argv2[i]); + MC_FREEIF( argv2[i] ); + } + + MC_FREEIF( argv ); + MC_FREEIF( argv2 ); + MC_FREEIF( argc ); + + return FALSE; +} + +mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t* core, gchar *factory_name) +{ + GstBus *bus = NULL; + GstPad *pad = NULL; + + MEDIACODEC_FENTER(); + + g_mutex_lock(&core->prepare_lock); + if(core->prepare_count == 0) + { + + if (!__mc_gst_init_gstreamer()) + { + LOGE ("gstreamer initialize fail"); + g_mutex_unlock(&core->prepare_lock); + return MC_NOT_INITIALIZED; + } + core->codec = gst_element_factory_make(factory_name, NULL); + + if(!core->codec) + { + LOGE ("codec element create fail"); + goto ERROR; + } + + LOGD("@%p v(%d)e(%d) create_pipeline", core, core->video, core->encoder); + MEDIACODEC_ELEMENT_SET_STATE(core->codec, GST_STATE_READY); + + /* create common elements */ + core->pipeline = gst_pipeline_new(NULL); + + if (!core->pipeline) + { + LOGE ("pipeline create fail"); + goto ERROR; + } + + core->appsrc = gst_element_factory_make("appsrc", NULL); + + if (!core->appsrc) + { + LOGE ("appsrc can't create"); + goto ERROR; + } + + core->fakesink = gst_element_factory_make("fakesink", NULL); + + if (!core->fakesink) + { + LOGE ("fakesink create fail"); + goto ERROR; + } + g_object_set(core->fakesink, "enable-last-buffer", FALSE, NULL); + + //__mc_link_elements(core); + gst_bin_add_many(GST_BIN(core->pipeline), core->appsrc, core->codec, core->fakesink, NULL); + + /* link elements */ + gst_element_link_many(core->appsrc, core->codec, core->fakesink, NULL); + + /* connect signals, bus watcher */ + + bus = gst_pipeline_get_bus (GST_PIPELINE (core->pipeline)); + core->bus_whatch_id = gst_bus_add_watch (bus, __mc_gst_bus_callback, core); + core->thread_default = g_main_context_get_thread_default(); + + /* set sync handler to get tag synchronously */ + gst_bus_set_sync_handler(bus, __mc_gst_bus_sync_callback, core); + + gst_object_unref (GST_OBJECT(bus)); + + /* add pad probe */ + pad = gst_element_get_static_pad(core->fakesink, "sink"); + core->probe_id = gst_pad_add_event_probe(pad, G_CALLBACK(event_probe_cb), core); + gst_object_unref (pad); + + /* connect handoff */ + g_object_set (GST_OBJECT(core->fakesink), "signal-handoffs", TRUE, NULL); + core->signal_handoff = g_signal_connect(core->fakesink, "handoff", G_CALLBACK(__mc_gst_buffer_add), core); + /* + __mc_create_caps(core, &caps); + + gst_app_src_set_caps(GST_APP_SRC(core->appsrc), caps); + gst_caps_unref(caps); + */ + /* set state PLAYING */ + MEDIACODEC_ELEMENT_SET_STATE(GST_ELEMENT_CAST(core->pipeline), GST_STATE_PLAYING); + + //g_mutex_unlock(core->prepare_lock); + + } + core->prepare_count++; + g_mutex_unlock(&core->prepare_lock); + + MEDIACODEC_FLEAVE(); + + return MC_ERROR_NONE; + +STATE_CHANGE_FAILED: +ERROR: + + if(core->codec) + gst_object_unref(GST_OBJECT(core->codec)); + + if(core->pipeline) + gst_object_unref(GST_OBJECT(core->pipeline)); + + if(core->appsrc) + gst_object_unref(GST_OBJECT(core->appsrc)); + + if(core->fakesink) + gst_object_unref(GST_OBJECT(core->fakesink)); + + g_mutex_unlock(&core->prepare_lock); + + return MC_ERROR; +} + +mc_ret_e _mc_gst_destroy_pipeline(mc_gst_core_t *core) +{ + int ret = MC_ERROR_NONE; + GstPad *pad = NULL; + + MEDIACODEC_FENTER(); + + g_mutex_lock(&core->prepare_lock); + core->prepare_count--; + if(core->prepare_count == 0) + { + + if(core->pipeline) + { + /* disconnect signal */ + if(core->fakesink && GST_IS_ELEMENT(core->fakesink)) + { + if(g_signal_handler_is_connected(core->fakesink, core->signal_handoff)) + { + g_signal_handler_disconnect(core->fakesink, core->signal_handoff); + LOGD("handoff signal destroy"); + } + } + + if(core->bus_whatch_id) + { + GSource *source = NULL; + source = g_main_context_find_source_by_id (core->thread_default, core->bus_whatch_id); + g_source_destroy(source); + //g_source_remove(core->bus_whatch_id); + LOGD("bus_whatch_id destroy"); + } + + pad = gst_element_get_static_pad(core->fakesink, "sink"); + gst_pad_remove_event_probe(pad, core->probe_id); + g_object_unref(pad); + + MEDIACODEC_ELEMENT_SET_STATE(core->pipeline, GST_STATE_NULL); + + gst_object_unref(GST_OBJECT(core->pipeline)); + } + } + + LOGD("@%p v(%d)e(%d) destroy_pipeline : %d ", core, core->video, core->encoder, core->prepare_count); + g_mutex_unlock(&core->prepare_lock); + + MEDIACODEC_FLEAVE(); + + return ret; + +STATE_CHANGE_FAILED: + if(core->pipeline) + gst_object_unref(GST_OBJECT(core->pipeline)); + + LOGD("@%p v(%d)e(%d) destroy_pipeline failed", core, core->video, core->encoder); + g_mutex_unlock(&core->prepare_lock); + + return MC_ERROR; +} + +void __mc_gst_buffer_add (GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + mc_gst_core_t* core = (mc_gst_core_t*) data; + + media_packet_h out_pkt = NULL; + + MEDIACODEC_FENTER(); + + //g_atomic_int_int(&core->num_live_buffers); + LOGI("@%p(%d)", core, core->encoder); + + out_pkt = __mc_gst_gstbuffer_to_media_packet(core, buffer); + if (out_pkt == NULL) + { + LOGE("out_pkt create failed."); + return; + } + + if(core->encoder && core->codec_config) + { + media_packet_set_flags(out_pkt, MEDIA_PACKET_CODEC_CONFIG); + LOGD("set the codec data %p", buffer); + } + core->codec_config = false; + + g_mutex_lock(&core->ports[1]->mutex); + /* push it to output buffer queue */ + //g_queue_push_tail(core->output_queue, out_pkt); + g_queue_push_tail(core->ports[1]->queue, out_pkt); + + g_mutex_unlock(&core->ports[1]->mutex); + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER]) + { + ((mc_fill_buffer_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_FILLBUFFER])(out_pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_FILLBUFFER]); + } + + MEDIACODEC_FLEAVE(); +} + +static int __mc_output_packet_buffer_finalize_cb(media_packet_h packet, int error_code, void *user_data) +{ + void* buffer = NULL; + + MEDIACODEC_FENTER(); + + LOGD("packet finalized: %p", packet); + media_packet_get_extra(packet, &buffer); + gst_buffer_unref((GstBuffer*)buffer); + + MEDIACODEC_FLEAVE(); + + return MEDIA_PACKET_FINALIZE; +} + +int __mc_output_buffer_finalize_cb(media_packet_h packet, int error_code, void *user_data) +{ + void* buffer = NULL; + SCMN_IMGB *imgb = NULL; + tbm_surface_h surface = NULL; + bool has_tbm_surface = false; + + MEDIACODEC_FENTER(); + + media_packet_has_tbm_surface_buffer(packet, &has_tbm_surface); + LOGI("has_tbm_surface : %d", has_tbm_surface); + + if(has_tbm_surface) + { + LOGI("destroy tbm surface"); + media_packet_get_tbm_surface(packet, &surface); + tbm_surface_destroy(surface); + } + media_packet_get_extra(packet, &buffer); + LOGD("finalized_gst_buffer = %p", buffer); + LOGI("gstbuffer refcount %d", GST_MINI_OBJECT_REFCOUNT_VALUE(buffer)); + if (GST_BUFFER_MALLOCDATA(buffer)) + { + imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buffer); + if (imgb) + { + LOGI("imgb is destroyed"); + free(imgb); + imgb = NULL; + GST_BUFFER_MALLOCDATA(buffer) = NULL; + } + } + + //GST_BUFFER_DATA(buffer) = NULL; + gst_buffer_unref((GstBuffer*)buffer); + + MEDIACODEC_FLEAVE(); + return MEDIA_PACKET_FINALIZE; +} + +guint32 __mc_get_gst_input_format(media_packet_h packet, bool is_hw) +{ + guint32 format = 0; + media_format_h fmt = NULL; + media_format_mimetype_e mimetype = 0; + + media_packet_get_format(packet, &fmt); + media_format_get_video_info(fmt, &mimetype, NULL, NULL, NULL, NULL); + LOGD("input packet mimetype : %x", mimetype); + + switch(mimetype) + { + case MEDIA_FORMAT_I420: + format = GST_MAKE_FOURCC ('I', '4', '2', '0'); + break; + case MEDIA_FORMAT_NV12: + if (is_hw) + format = GST_MAKE_FOURCC ('S', 'N', '1', '2'); + else + format = GST_MAKE_FOURCC ('N', 'V', '1', '2'); + break; + default: + break; + } + return format; +} + + +mc_gst_buffer_t* _mc_gst_media_packet_to_gstbuffer(mc_gst_core_t* core, GstCaps **caps, media_packet_h pkt, bool codec_config) +{ + mc_gst_buffer_t* buff = NULL; + uint64_t pts = 0, dur = 0; + + buff = __mc_gst_buffer_new(core); + buff->pkt = pkt; + + //mc_hex_dump("nal", pkt, 8); + + __mc_fill_input_buffer(core, buff); + + /* pts */ + media_packet_get_pts(pkt, &pts); + GST_BUFFER_TIMESTAMP(buff) = (GstClockTime) pts; + LOGD("GST_BUFFER_TIMESTAMP = %"GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buff))); + LOGD("PTS = %llu", pts); + + /* duration */ + media_packet_get_duration(pkt, &dur); + GST_BUFFER_DURATION(buff) = dur; + + GST_BUFFER_CAPS(buff) = gst_caps_copy(*caps); + + return buff; +} + +media_packet_h __mc_gst_gstbuffer_to_media_packet(mc_gst_core_t* core, GstBuffer* buff) +{ + media_packet_h out_pkt = NULL; + mc_ret_e ret = MC_ERROR_NONE; + if (!buff) + return NULL; + + ret = __mc_fill_output_buffer(core, buff, &out_pkt); + if (ret != MC_ERROR_NONE) + { + gst_buffer_ref(buff); + return NULL; + } + + gst_buffer_ref(buff); + + return out_pkt; +} + +gboolean __mc_gst_bus_callback (GstBus *bus, GstMessage *msg, gpointer data) +{ + int ret = MC_ERROR_NONE; + mc_gst_core_t *core = (mc_gst_core_t*)data; + LOGD("@%p v(%d)e(%d)", core, core->video, core->encoder); + + switch (GST_MESSAGE_TYPE (msg)) { + + case GST_MESSAGE_EOS: + { + core->eos = true; + g_cond_signal(&core->eos_cond); + LOGD("send eos signal"); + + LOGD ("End of stream\n"); +/* + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS]) + { + ((mc_eos_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EOS])(core->user_data[_MEDIACODEC_EVENT_TYPE_EOS]); + } +*/ + } + break; + + case GST_MESSAGE_ERROR: + { + GError* error = NULL; + + gst_message_parse_error (msg, &error, NULL); + + if (!error) + { + LOGW("GST error message parsing failed"); + break; + } + + LOGW ("Error: %s\n", error->message); + + if(error) + { + if(error->domain == GST_STREAM_ERROR) + { + ret = __gst_handle_stream_error(core, error, msg); + } + else if (error->domain == GST_RESOURCE_ERROR) + { + ret = __gst_handle_resource_error(core, error->code); + } + else if (error->domain == GST_LIBRARY_ERROR) + { + ret = __gst_handle_library_error(core, error->code); + } + else if (error->domain == GST_CORE_ERROR) + { + ret = __gst_handle_core_error(core, error->code); + } + else + { + LOGW("Unexpected error has occured"); + } + } + g_error_free (error); + } + break; + + default: + break; + } + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR]) + { + ((mc_error_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR])(ret, core->user_data[_MEDIACODEC_EVENT_TYPE_ERROR]); + } + + return TRUE; +} + +static gboolean +__mc_gst_check_useful_message(mc_gst_core_t *core, GstMessage *msg) +{ + gboolean retval = false; + + if(!core->pipeline) + { + LOGE("mediacodec pipeline handle is null"); + return true; + } + + switch (GST_MESSAGE_TYPE (msg)) + { + case GST_MESSAGE_TAG: + case GST_MESSAGE_EOS: + case GST_MESSAGE_ERROR: + case GST_MESSAGE_WARNING: + retval = true; + break; + default: + retval = false; + break; + } + + return retval; +} + +static GstBusSyncReply +__mc_gst_bus_sync_callback(GstBus *bus, GstMessage *msg, gpointer data) +{ + mc_gst_core_t *core = (mc_gst_core_t*)data; + GstBusSyncReply reply = GST_BUS_DROP; + + if(!core->pipeline) + { + LOGE("mediacodec pipeline handle is null"); + return GST_BUS_PASS; + } + + if(!__mc_gst_check_useful_message(core, msg)) + { + gst_message_unref(msg); + return GST_BUS_DROP; + } + + switch (GST_MESSAGE_TYPE (msg)) + { + case GST_MESSAGE_STATE_CHANGED: + __mc_gst_bus_callback(NULL, msg, core); + //__mediacodec_gst_callback(NULL, msg, core); + reply = GST_BUS_DROP; + break; + + default: + reply = GST_BUS_PASS; + break; + } + + if( reply == GST_BUS_DROP ) + gst_message_unref(msg); + + return reply; +} + +static SCMN_IMGB * __mc_gst_make_tbm_buffer(mc_gst_core_t* core, media_packet_h pkt) +{ + tbm_surface_h surface = NULL; + tbm_bo bo = NULL; + mc_encoder_info_t *enc_info = (mc_encoder_info_t*)core->codec_info; + + if (!pkt) { + LOGE("output is null"); + return NULL; + } + + SCMN_IMGB *psimgb = NULL; + psimgb = (SCMN_IMGB *)malloc(sizeof(SCMN_IMGB)); + if (!psimgb) { + LOGE("Failed to alloc SCMN_IMGB"); + return NULL; + } + memset(psimgb, 0x00, sizeof(SCMN_IMGB)); + + media_packet_get_tbm_surface(pkt, &surface); + bo = tbm_surface_internal_get_bo(surface, 0); + + tbm_bo_handle handle = tbm_bo_get_handle(bo, TBM_DEVICE_CPU); +#ifdef TIZEN_PROFILE_LITE + int phy_addr = 0; + int phy_size = 0; + tbm_bo_handle handle_fd = tbm_bo_get_handle(bo, TBM_DEVICE_MM); + + if (__tbm_get_physical_addr_bo(handle_fd, &phy_addr, &phy_size) == 0) + { + psimgb->p[0] = (void*)phy_addr; + } +#endif + + psimgb->buf_share_method = BUF_SHARE_METHOD_TIZEN_BUFFER; + psimgb->bo[0] = bo; + psimgb->a[0] = handle.ptr; + psimgb->w[0] = enc_info->width; + psimgb->h[0] = enc_info->height; + psimgb->s[0] = psimgb->w[0]; + psimgb->e[0] = psimgb->h[0]; + + return psimgb; +} + +static GType __mc_gst_buffer_get_type(void) +{ + static GType _mc_gst_buffer_type; + + if (G_UNLIKELY(_mc_gst_buffer_type == 0)) { + static const GTypeInfo mc_gst_buffer_info = { + sizeof (GstBufferClass), + NULL, + NULL, + __mc_gst_buffer_class_init, + NULL, + NULL, + sizeof (mc_gst_buffer_t), + 0, + NULL, + NULL + }; + + _mc_gst_buffer_type = g_type_register_static(GST_TYPE_BUFFER, + "McGstBuffer", + &mc_gst_buffer_info, + 0); + } + + return _mc_gst_buffer_type; +} + +static void __mc_gst_buffer_class_init(gpointer g_class, gpointer class_data) +{ + GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS(g_class); + mc_gst_buffer_parent_class = g_type_class_peek_parent(g_class); + mini_object_class->finalize = (GstMiniObjectFinalizeFunction)__mc_gst_buffer_finalize; +} + +static mc_gst_buffer_t* __mc_gst_buffer_new(mc_gst_core_t* core) +{ + mc_gst_buffer_t *ret = NULL; + ret = (mc_gst_buffer_t *)gst_mini_object_new(GST_TYPE_MC_BUFFER); + LOGD("creating buffer : %p", ret); + ret->core = core; + return ret; +} + +static void __mc_gst_buffer_finalize(mc_gst_buffer_t *buffer) +{ + SCMN_IMGB *imgb = NULL; + mc_gst_core_t *core = buffer->core; + + LOGD("__mc_gst_buffer_finalize() is called"); + if (GST_BUFFER_MALLOCDATA(buffer)) + { + imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buffer); + if (imgb) + { + LOGI("imgb is destroyed"); + free(imgb); + imgb = NULL; + GST_BUFFER_MALLOCDATA(buffer) = NULL; + } + } + + //GST_BUFFER_DATA(buffer) = NULL; + + if (GST_MINI_OBJECT_CLASS (mc_gst_buffer_parent_class)->finalize) { + GST_MINI_OBJECT_CLASS (mc_gst_buffer_parent_class)->finalize (GST_MINI_OBJECT(buffer)); + } + + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]) + { + ((mc_empty_buffer_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER])(buffer->pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]); + LOGD("finalize, pkt : %p, buffer : %p", buffer->pkt, buffer); + } + + return; +} + +static gint __gst_handle_core_error(mc_gst_core_t* core, int code ) +{ + gint trans_err = MEDIACODEC_ERROR_NONE; + + g_return_val_if_fail(core, MC_PARAM_ERROR); + + switch ( code ) + { + case GST_CORE_ERROR_MISSING_PLUGIN: + return MEDIACODEC_ERROR_NOT_SUPPORTED_FORMAT; + case GST_CORE_ERROR_STATE_CHANGE: + case GST_CORE_ERROR_SEEK: + case GST_CORE_ERROR_NOT_IMPLEMENTED: + case GST_CORE_ERROR_FAILED: + case GST_CORE_ERROR_TOO_LAZY: + case GST_CORE_ERROR_PAD: + case GST_CORE_ERROR_THREAD: + case GST_CORE_ERROR_NEGOTIATION: + case GST_CORE_ERROR_EVENT: + case GST_CORE_ERROR_CAPS: + case GST_CORE_ERROR_TAG: + case GST_CORE_ERROR_CLOCK: + case GST_CORE_ERROR_DISABLED: + default: + trans_err = MEDIACODEC_ERROR_INVALID_STREAM; + break; + } + + return trans_err; +} + +static gint __gst_handle_library_error(mc_gst_core_t* core, int code) +{ + gint trans_err = MEDIACODEC_ERROR_NONE; + + g_return_val_if_fail(core, MC_PARAM_ERROR); + + switch ( code ) + { + case GST_LIBRARY_ERROR_FAILED: + case GST_LIBRARY_ERROR_TOO_LAZY: + case GST_LIBRARY_ERROR_INIT: + case GST_LIBRARY_ERROR_SHUTDOWN: + case GST_LIBRARY_ERROR_SETTINGS: + case GST_LIBRARY_ERROR_ENCODE: + default: + trans_err = MEDIACODEC_ERROR_INVALID_STREAM; + break; + } + + return trans_err; +} + + +static gint __gst_handle_resource_error(mc_gst_core_t* core, int code ) +{ + gint trans_err = MEDIACODEC_ERROR_NONE; + + g_return_val_if_fail(core, MC_PARAM_ERROR); + + switch ( code ) + { + case GST_RESOURCE_ERROR_NO_SPACE_LEFT: + trans_err = MEDIACODEC_ERROR_NO_FREE_SPACE; + break; + case GST_RESOURCE_ERROR_WRITE: + case GST_RESOURCE_ERROR_FAILED: + case GST_RESOURCE_ERROR_SEEK: + case GST_RESOURCE_ERROR_TOO_LAZY: + case GST_RESOURCE_ERROR_BUSY: + case GST_RESOURCE_ERROR_OPEN_WRITE: + case GST_RESOURCE_ERROR_OPEN_READ_WRITE: + case GST_RESOURCE_ERROR_CLOSE: + case GST_RESOURCE_ERROR_SYNC: + case GST_RESOURCE_ERROR_SETTINGS: + default: + trans_err = MEDIACODEC_ERROR_INTERNAL; + break; + } + + return trans_err; +} + +static gint __gst_handle_stream_error(mc_gst_core_t* core, GError* error, GstMessage * message) +{ + gint trans_err = MEDIACODEC_ERROR_NONE; + + g_return_val_if_fail(core, MC_PARAM_ERROR); + g_return_val_if_fail(error, MC_PARAM_ERROR); + g_return_val_if_fail (message, MC_PARAM_ERROR); + + switch ( error->code ) + { + case GST_STREAM_ERROR_FAILED: + case GST_STREAM_ERROR_TYPE_NOT_FOUND: + case GST_STREAM_ERROR_DECODE: + case GST_STREAM_ERROR_WRONG_TYPE: + case GST_STREAM_ERROR_DECRYPT: + case GST_STREAM_ERROR_DECRYPT_NOKEY: + case GST_STREAM_ERROR_CODEC_NOT_FOUND: + trans_err = __gst_transform_gsterror( core, message, error ); + break; + + case GST_STREAM_ERROR_NOT_IMPLEMENTED: + case GST_STREAM_ERROR_TOO_LAZY: + case GST_STREAM_ERROR_ENCODE: + case GST_STREAM_ERROR_DEMUX: + case GST_STREAM_ERROR_MUX: + case GST_STREAM_ERROR_FORMAT: + default: + trans_err = MEDIACODEC_ERROR_INVALID_STREAM; + break; + } + + return trans_err; +} + +static gint __gst_transform_gsterror( mc_gst_core_t *core, GstMessage * message, GError* error ) +{ + gchar *src_element_name = NULL; + GstElement *src_element = NULL; + GstElementFactory *factory = NULL; + const gchar* klass = NULL; + + + src_element = GST_ELEMENT_CAST(message->src); + if ( !src_element ) + goto INTERNAL_ERROR; + + src_element_name = GST_ELEMENT_NAME(src_element); + if ( !src_element_name ) + goto INTERNAL_ERROR; + + factory = gst_element_get_factory(src_element); + if ( !factory ) + goto INTERNAL_ERROR; + + klass = gst_element_factory_get_klass(factory); + if ( !klass ) + goto INTERNAL_ERROR; + + LOGD("error code=%d, msg=%s, src element=%s, class=%s\n", + error->code, error->message, src_element_name, klass); + + switch ( error->code ) + { + case GST_STREAM_ERROR_DECODE: + return MEDIACODEC_ERROR_INVALID_STREAM; + break; + + case GST_STREAM_ERROR_CODEC_NOT_FOUND: + case GST_STREAM_ERROR_TYPE_NOT_FOUND: + case GST_STREAM_ERROR_WRONG_TYPE: + return MEDIACODEC_ERROR_NOT_SUPPORTED_FORMAT; + break; + + case GST_STREAM_ERROR_FAILED: + return MEDIACODEC_ERROR_NOT_SUPPORTED_FORMAT; + break; + + default: + break; + } + + return MEDIACODEC_ERROR_INVALID_STREAM; + +INTERNAL_ERROR: + return MEDIACODEC_ERROR_INTERNAL; +} + +static void _mc_gst_set_flush_input(mc_gst_core_t *core) +{ + media_packet_h pkt = NULL; + + LOGI("_mc_gst_set_flush_input is called"); + while( pkt != mc_async_queue_pop_forced(core->available_queue->input) ) + { + LOGD("%p pkt is poped"); + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]) + { + ((mc_empty_buffer_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]) + (pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]); + } + } + + mc_async_queue_flush(core->available_queue->input); +} + +static void _mc_gst_set_flush_output(mc_gst_core_t *core) +{ + media_packet_h pkt = NULL; + + LOGI("_mc_gst_set_flush_output is called"); + g_mutex_lock(&core->ports[1]->mutex); + + if(!g_queue_is_empty(core->ports[1]->queue)) + { + while(pkt != g_queue_pop_head(core->ports[1]->queue)) + { + LOGD("outpkt in output_queue : %p", pkt); + media_packet_destroy(pkt); + } + } + + g_mutex_unlock(&core->ports[1]->mutex); +} + +#ifdef TIZEN_PROFILE_LITE +int __tbm_get_physical_addr_bo(tbm_bo_handle tbm_bo_handle_fd_t, int* phy_addr, int* phy_size) +{ + int tbm_bo_handle_fd; + + int ret=0; + + tbm_bo_handle_fd = tbm_bo_handle_fd_t.u32; + + int open_flags = O_RDWR; + int ion_fd = -1; + + struct ion_mmu_data mmu_data; + struct ion_custom_data custom_data; + + mmu_data.fd_buffer = tbm_bo_handle_fd; + custom_data.cmd = 4; + custom_data.arg = (unsigned long)&mmu_data; + + ion_fd = open ("/dev/ion", open_flags); + if (ion_fd < 0) + { + LOGE ("[tbm_get_physical_addr_bo] ion_fd open device failed"); + } + + if (ioctl(ion_fd, ION_IOC_CUSTOM, &custom_data)<0) + { + LOGE ("[tbm_get_physical_addr_bo] ION_IOC_CUSTOM fails %d %s",errno,strerror(errno)); + ret=-1; + } + + if (!ret) + { + *phy_addr = mmu_data.iova_addr; + *phy_size = mmu_data.iova_size; + } + else + { + *phy_addr = 0; + *phy_size = 0; + LOGW ("[tbm_get_physical_addr_bo] getting physical address is failed. phy_addr = 0"); + } + + if (ion_fd != -1) + { + close (ion_fd); + ion_fd = -1; + } + + return 0; +} +#endif diff --git a/src/media_codec_queue.c b/src/media_codec_queue.c new file mode 100755 index 0000000..c719bf3 --- /dev/null +++ b/src/media_codec_queue.c @@ -0,0 +1,131 @@ +#include <media_codec_queue.h> + +async_queue_t *mc_async_queue_new (void) +{ + async_queue_t *async_queue; + + async_queue = g_slice_new0 (async_queue_t); + + //async_queue->condition = g_cond_new (); + g_cond_init (&async_queue->condition); + //async_queue->mutex = g_mutex_new (); + g_mutex_init(&async_queue->mutex); + async_queue->enabled = TRUE; + + return async_queue; +} + +void mc_async_queue_free (async_queue_t * async_queue) +{ + //g_cond_free (async_queue->condition); + g_cond_clear (&async_queue->condition); + //g_mutex_free (async_queue->mutex); + g_mutex_clear (&async_queue->mutex); + + g_list_free (async_queue->head); + g_slice_free (async_queue_t, async_queue); +} + +void mc_async_queue_push (async_queue_t * async_queue, gpointer data) +{ + g_mutex_lock (&async_queue->mutex); + + async_queue->tail = g_list_append(async_queue->tail, data); + if(async_queue->tail && async_queue->tail->next) + async_queue->tail = async_queue->tail->next; + else + async_queue->head = async_queue->tail; + + async_queue->length++; + + g_cond_signal (&async_queue->condition); + //LOGD("queue pushed : %p, %d, %p",queue, async_queue->length, data); + + g_mutex_unlock (&async_queue->mutex); +} + +gpointer mc_async_queue_pop (async_queue_t * async_queue) +{ + gpointer data = NULL; + + g_mutex_lock (&async_queue->mutex); + + if (!async_queue->enabled) { + /* g_warning ("not enabled!"); */ + goto leave; + } + + if (!async_queue->head) { + g_cond_wait (&async_queue->condition, &async_queue->mutex); + } + + if (async_queue->head) { + GList *node = async_queue->head; + data = node->data; + + async_queue->head = node->next; + if (async_queue->head) + async_queue->head->prev = NULL; + else + async_queue->tail = NULL; + async_queue->length--; + //LOGD("async queue poped : %p, %d, %p",queue, async_queue->length, data); + g_list_free_1 (node); + } + +leave: + g_mutex_unlock (&async_queue->mutex); + + return data; +} + +gpointer mc_async_queue_pop_forced (async_queue_t * async_queue) +{ + gpointer data = NULL; + + g_mutex_lock (&async_queue->mutex); + + if (async_queue->head) { + GList *node = async_queue->head; + data = node->data; + + async_queue->head = node->next; + if (async_queue->head) + async_queue->head->prev = NULL; + else + async_queue->tail = NULL; + async_queue->length--; + //LOGD("async queue poped : %p, %d, %p",queue, async_queue->length, data); + g_list_free_1 (node); + } + + g_mutex_unlock (&async_queue->mutex); + + return data; +} + +void mc_async_queue_disable (async_queue_t * async_queue) +{ + g_mutex_lock (&async_queue->mutex); + async_queue->enabled = FALSE; + g_cond_broadcast (&async_queue->condition); + g_mutex_unlock (&async_queue->mutex); +} + +void mc_async_queue_enable (async_queue_t * async_queue) +{ + g_mutex_lock (&async_queue->mutex); + async_queue->enabled = TRUE; + g_mutex_unlock (&async_queue->mutex); +} + +void mc_async_queue_flush(async_queue_t *async_queue) +{ + g_mutex_lock(&async_queue->mutex); + + g_list_free(async_queue->head); + async_queue->head = async_queue->tail = NULL; + async_queue->length = 0; + + g_mutex_unlock(&async_queue->mutex); +} diff --git a/src/media_codec_util.c b/src/media_codec_util.c new file mode 100755 index 0000000..71d8262 --- /dev/null +++ b/src/media_codec_util.c @@ -0,0 +1,114 @@ +#include <media_codec_util.h> + +void *mc_aligned_malloc(int size, int alignment) +{ + unsigned char *pMem; + unsigned char *tmp; + + if((tmp = (unsigned char *)malloc(size + alignment)) != NULL) + { + pMem = (unsigned char*)((unsigned int)(tmp + alignment - 1) & (~(unsigned int)(alignment -1))); + + if(pMem == tmp) + pMem += alignment; + + *(pMem - 1) = (unsigned int)(pMem - tmp); + + return ((void*) pMem); + } + return NULL; +} + +void mc_aligned_free(void *mem) +{ + unsigned char *ptr; + + if(mem == NULL) + return; + + ptr = mem; + ptr -= *(ptr-1); + + free(ptr); +} + +mc_sem_t *mc_sem_new() +{ + mc_sem_t *sem; + sem = g_new(mc_sem_t, 1); + //sem->cond = g_cond_new(); + g_cond_init(&sem->cond); + //sem->mutex = g_mutex_new(); + g_mutex_init(&sem->mutex); + sem->counter = 0; + + return sem; +} + +void mc_sem_free(mc_sem_t *sem) +{ + //g_cond_free(sem->cond); + g_cond_clear(&sem->cond); + //g_mutex_free(sem->mutex); + g_mutex_clear(&sem->mutex); + g_free(sem); +} + +void mc_sem_down(mc_sem_t *sem) +{ + g_mutex_lock(&sem->mutex); + + while(sem->counter == 0) + g_cond_wait(&sem->cond, &sem->mutex); + sem->counter--; + + g_mutex_unlock(&sem->mutex); +} + +void mc_sem_up(mc_sem_t *sem) +{ + g_mutex_lock(&sem->mutex); + + sem->counter++; + g_cond_signal(&sem->cond); + + g_mutex_unlock(&sem->mutex); + +} + +void mc_hex_dump(char *desc, void *addr, int len) +{ + int i; + unsigned char buff[17]; + unsigned char *pc = (unsigned char*)addr; + + if (desc != NULL) + printf("%s:\n", desc); + + for (i = 0; i < len; i++) + { + + if ((i % 16) == 0) + { + if (i != 0) + printf(" %s\n", buff); + + printf(" %04x ", i); + } + + printf(" %02x", pc[i]); + + if ((pc[i] < 0x20) || (pc[i] > 0x7e)) + buff[i % 16] = '.'; + else + buff[i % 16] = pc[i]; + buff[(i % 16) + 1] = '\0'; + } + + while ((i % 16) != 0) { + printf(" "); + i++; + } + printf(" %s\n", buff); +} + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..7b7990e --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,23 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_test "${fw_name}-test") + +INCLUDE_DIRECTORIES(../include) +INCLUDE_DIRECTORIES(../include/headers) +link_directories(${CMAKE_SOURCE_DIR}/../) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_test} REQUIRED appcore-efl) +FOREACH(flag ${${fw_test}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -pie") + +aux_source_directory(. sources) +FOREACH(src ${sources}) + GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) + MESSAGE("${src_name}") + ADD_EXECUTABLE(${src_name} ${src}) + TARGET_LINK_LIBRARIES(${src_name} capi-media-codec ${${fw_test}_LDFLAGS}) +ENDFOREACH() + diff --git a/test/media_codec_test.c b/test/media_codec_test.c new file mode 100755 index 0000000..e0a0690 --- /dev/null +++ b/test/media_codec_test.c @@ -0,0 +1,1433 @@ +/* + * Copyright (c) 2011 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <glib.h> +#include <Elementary.h> +#include <appcore-efl.h> + +#include <media_codec.h> +#include <media_packet.h> +#include <media_codec_queue.h> // !!!! remove it +#include <media_codec_port.h> // !!!! remove it + +//#include <media_codec_private.h> +//#include <media_codec_port_general.h> +//#include <media_codec_port_omx.h> +//#include <media_codec_port.h> +//#include <media_codec_util.h> + +#define PACKAGE "media_codec_test" +#define TEST_FILE_SIZE (10 * 1024 * 1024) //10M - test case +#define MAX_STRING_LEN 256 +#define MAX_HANDLE 10 +#define DEFAULT_OUT_BUF_WIDTH 640 +#define DEFAULT_OUT_BUF_HEIGHT 480 +#define OUTBUF_SIZE (DEFAULT_OUT_BUF_WIDTH * DEFAULT_OUT_BUF_HEIGHT * 3 / 2) + +#define DEFAULT_SAMPPLERATE 44100 +#define DEFAULT_CHANNEL 2 +#define DEFAULT_BIT 16 +#define DEFAULT_BITRATE 128 +#define DEFAULT_SAMPLEBYTE 1024 +#define ADTS_HEADER_SIZE 7 + +#define DUMP_OUTBUF 1 +#define MAX_INPUT_BUF_NUM 20 +#define USE_INPUT_QUEUE 1 + + +//extern int file_handle_args (int argc, char ** argv, int flag); + +/* + * Test MAIN + */ + +enum +{ + CURRENT_STATUS_MAINMENU, + CURRENT_STATUS_FILENAME, + CURRENT_STATUS_CREATE, + CURRENT_STATUS_DESTROY, + CURRENT_STATUS_SET_CODEC, + CURRENT_STATUS_SET_VDEC_INFO, + CURRENT_STATUS_SET_VENC_INFO, + CURRENT_STATUS_SET_ADEC_INFO, + CURRENT_STATUS_SET_AENC_INFO, + CURRENT_STATUS_PREPARE, + CURRENT_STATUS_UNPREPARE, + CURRENT_STATUS_PROCESS_INPUT, + CURRENT_STATUS_GET_OUTPUT, + CURRENT_STATUS_RESET_OUTPUT_BUFFER, + CURRENT_STATUS_SET_SIZE, +}; + +int g_menu_state = CURRENT_STATUS_MAINMENU; +int g_handle_num = 1; +static mediacodec_h g_media_codec[MAX_HANDLE] = {0}; +char g_uri[MAX_STRING_LEN]; +FILE *fp_src = NULL; +media_format_h input_fmt = NULL; +#if USE_INPUT_QUEUE +media_packet_h *input_buf = NULL; +#else +media_packet_h in_buf = NULL; +#endif +media_packet_h output_buf = NULL; +async_queue_t *input_avaliable = NULL; + +//static GThread *thread; + +uint64_t pts = 0; + +static int width = DEFAULT_OUT_BUF_WIDTH; +static int height = DEFAULT_OUT_BUF_HEIGHT; +static float fps = 0; +static int target_bits = 0; + +static int samplerate = DEFAULT_SAMPPLERATE; +static int channel = DEFAULT_CHANNEL; +static int bit = DEFAULT_BIT; +static int bitrate = DEFAULT_BITRATE; +static int samplebyte = DEFAULT_SAMPLEBYTE; +unsigned char buf_adts[ADTS_HEADER_SIZE]; + +media_format_mimetype_e mimetype; + +int use_video = 0; +int use_encoder = 0; +int frame_count = 0; + +#if DUMP_OUTBUF +FILE *fp_out = NULL; +#endif +//static gpointer _feed_pa(gpointer data); +static void display_sub_basic(); +static int _mediacodec_get_output(void); +static void _mediacodec_empty_buffer_cb(media_packet_h pkt, void *user_data); +static void _mediacodec_fill_buffer_cb(media_packet_h pkt, void *user_data); + +static int _create_app(void *data) +{ + printf("My app is going alive!\n"); + return 0; +} + +static int _terminate_app(void *data) +{ + printf("My app is going gone!\n"); + return 0; +} + + +struct appcore_ops ops = { + .create = _create_app, + .terminate = _terminate_app, +}; + +unsigned int bytestream2nalunit(FILE *fd, unsigned char* nal) +{ + int nal_length = 0; + size_t result; + int read_size = 1; + unsigned char buffer[1000000]; + unsigned char val, zero_count, i; + + zero_count = 0; + if (feof(fd)) + return 0; + + result = fread(buffer, 1, read_size, fd); + + if(result != read_size) + { + exit(1); + } + val = buffer[0]; + while (!val) + { + if ((zero_count == 2 || zero_count == 3) && val == 1) + { + break; + } + zero_count++; + result = fread(buffer, 1, read_size, fd); + + if(result != read_size) + { + break; + } + val = buffer[0]; + } + nal[nal_length++] = 0; + nal[nal_length++] = 0; + nal[nal_length++] = 0; + nal[nal_length++] = 1; + zero_count = 0; + while(1) + { + if (feof(fd)) + return nal_length; + + result = fread(buffer, 1, read_size, fd); + if(result != read_size) + { + break; + } + val = buffer[0]; + + if (!val) + { + zero_count++; + } + else + { + if ((zero_count == 2 || zero_count == 3 || zero_count == 4) && (val == 1)) + { + break; + } + else + { + for (i = 0; i<zero_count; i++) + { + nal[nal_length++] = 0; + } + nal[nal_length++] = val; + zero_count = 0; + } + } + } + + fseek(fd, -(zero_count + 1), SEEK_CUR); + + return nal_length; +} + +unsigned int bytestream2yuv420(FILE *fd, unsigned char* yuv) +{ + size_t result; + int read_size; + unsigned char buffer[1000000]; + + if (feof(fd)) + return 0; + + read_size = width*height*3/2; + + result = fread(buffer, 1,read_size, fd); + if(result != read_size) + { + exit(1); + } + + memcpy(yuv, buffer, width*height*3/2); + + return width*height*3/2; +} + + +/** + * Extract Input data for MP3 decoder + * (MPEG-1/2/2.5 layer 3) + * As-Is : Extractor code support only mp3 file exclude ID3tag, So mp3 file should start mp3 sync format. (0xffe0) + * To-Be : Will support mp3 file include ID3tag (v1,v2) + **/ + +static const guint mp3types_bitrates[2][3][16] = { +{ + {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,} + }, +{ + {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,} + }, +}; + +static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000}, + {22050, 24000, 16000}, + {11025, 12000, 8000} +}; + +unsigned int extract_input_mp3dec(FILE *fd, unsigned char* mp3data) +{ + int readsize; + size_t result; + unsigned char buffer[1000000]; + guint header; + guint padding, bitrate, lsf, layer, mpg25; + guint hdr_bitrate, sf; + + if (feof(fd)) + return 0; + + result = fread(buffer, 1, 4, fd); //mp3 header + if(result != 4) { + g_print ("[ERROR] fread size is %d\n", result); + return -1; + } + + header = GST_READ_UINT32_BE (buffer); +#if 1 //normal extract code + if (header == 0) { + g_print ("[ERROR] read header size is 0\n"); + return -1; + } + + /* if it's not a valid sync */ + if ((header & 0xffe00000) != 0xffe00000) { + g_print ("[ERROR] invalid sync\n"); + return -1; + } + + /* if it's an invalid MPEG version */ + if (((header >> 19) & 3) == 0x1) { + g_print ("[ERROR] invalid MPEG version: %d\n", (header >> 19) & 3); + return -1; + } else { + if (header & (1 << 20)) { + lsf = (header & (1 << 19)) ? 0 : 1; + mpg25 = 0; + } else { + lsf = 1; + mpg25 = 1; + } + } + + /* if it's an invalid layer */ + if (!((header >> 17) & 3)) { + g_print("[ERROR] invalid layer: %d\n", (header >> 17) & 3); + return -1; + } else { + layer = 4 - ((header >> 17) & 0x3); + } + + /* if it's an invalid bitrate */ + if (((header >> 12) & 0xf) == 0xf) { + g_print ("[ERROR] invalid bitrate: %d\n", (header >> 12) & 0xf); + return -1; + } else { + bitrate = (header >> 12) & 0xF; + hdr_bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000; + /* The caller has ensured we have a valid header, so bitrate can't be zero here. */ + if(hdr_bitrate == 0) + return -1; + } + + /* if it's an invalid samplerate */ + if (((header >> 10) & 0x3) == 0x3) { + g_print ("[ERROR] invalid samplerate: %d\n", (header >> 10) & 0x3); + return -4; + } else { + sf = (header >> 10) & 0x3; + sf = mp3types_freqs[lsf + mpg25][sf]; + } + + padding = (header >> 9) & 0x1; + + switch (layer) { + case 1: + readsize = 4 * ((hdr_bitrate * 12) / sf + padding); + break; + case 2: + readsize = (hdr_bitrate * 144) / sf + padding; + break; + default: + case 3: + readsize = (hdr_bitrate * 144) / (sf << lsf) + padding; + break; + } +#else //simple extract code - hard coding test code for supporting only 'test.mp3' + readsize = 1044 + ((header >> 9) & 0x1); //only simple test => (1044 + padding) +#endif + + if (readsize > 0) { + result = fread(buffer+4, 1, (readsize - 4), fd); + memcpy(mp3data, buffer,readsize); + } else { + readsize = 0; + g_print("[FAIL] Not found mp3 frame sync.....\n"); + } + + return readsize; +} + + +/** + * Extract Input data for AAC decoder + * (case of (LC profile) ADTS format) + **/ +unsigned int extract_input_aacdec(FILE *fd, unsigned char* aacdata) +{ + int readsize; + size_t result; + unsigned char buffer[1000000]; + + if (feof(fd)) + return 0; + + result = fread(buffer, 1, 6, fd); //adts header + if(result != 6) + { + exit(1); + } + + if ((buffer != NULL) && (buffer[0] == 0xff) && ((buffer[1] & 0xf6) == 0xf0)) { + readsize = ((buffer[3] & 0x03) << 11) | (buffer[4] << 3) | ((buffer[5] & 0xe0) >> 5); + result = fread(buffer+6, 1,(readsize - 6), fd); + memcpy(aacdata, buffer,readsize); + } else { + readsize = 0; + g_print("[FAIL] Not found aac frame sync.....\n"); + } + + return readsize; +} + +/** + * Extract Input data for AAC encoder + **/ +unsigned int extract_input_aacenc(FILE *fd, unsigned char* rawdata) +{ + int readsize; + size_t result; + unsigned char buffer[1000000]; + + if (feof(fd)) + return 0; + + readsize = ((samplebyte*channel)*(bit/8)); + result = fread(buffer, 1, readsize, fd); + if(result != readsize) + { + exit(1); + } + + memcpy(rawdata, buffer,readsize); + + return readsize; +} + +/** + * Add ADTS header at the beginning of each and every AAC packet. + * This is needed as MediaCodec encoder generates a packet of raw AAC data. + * Note the packetLen must count in the ADTS header itself. + **/ +void add_adts_header_for_aacenc(unsigned char *buffer, int packetLen) { + int profile = 2; //AAC LC (0x01) + int freqIdx = 3; //48KHz (0x03) + int chanCfg = 2; //CPE (0x02) + + if (samplerate == 96000) freqIdx = 0; + else if (samplerate == 88200) freqIdx = 1; + else if (samplerate == 64000) freqIdx = 2; + else if (samplerate == 48000) freqIdx = 3; + else if (samplerate == 44100) freqIdx = 4; + else if (samplerate == 32000) freqIdx = 5; + else if (samplerate == 24000) freqIdx = 6; + else if (samplerate == 22050) freqIdx = 7; + else if (samplerate == 16000) freqIdx = 8; + else if (samplerate == 12000) freqIdx = 9; + else if (samplerate == 11025) freqIdx = 10; + else if (samplerate == 8000) freqIdx = 11; + + if ((channel == 1) || (channel == 2)) + chanCfg = channel; + + // fill in ADTS data + buffer[0] = (char)0xFF; + buffer[1] = (char)0xF1; + buffer[2] = (char)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2)); + buffer[3] = (char)(((chanCfg&3)<<6) + (packetLen>>11)); + buffer[4] = (char)((packetLen&0x7FF) >> 3); + buffer[5] = (char)(((packetLen&7)<<5) + 0x1F); + buffer[6] = (char)0xFC; +} + +static void input_filepath(char *filename) +{ + int len = strlen(filename); + int i = 0; + + if(len < 0 || len > MAX_STRING_LEN) + return; + + for(i = 0; i < g_handle_num; i++) + { + if(g_media_codec[i] != NULL) + { + mediacodec_unprepare(g_media_codec[i]); + mediacodec_destroy(g_media_codec[i]); + g_media_codec[i] = NULL; + } + + if (mediacodec_create(&g_media_codec[i]) != MEDIACODEC_ERROR_NONE) + { + g_print("mediacodec create is failed\n"); + } + } + //input_fmt = (media_format_s *) malloc(sizeof(media_format_s)); + //memset(input_fmt, 0, sizeof(media_format_s)); + media_format_create(&input_fmt); + +#if DUMP_OUTBUF + fp_out = fopen("/opt/usr/media/codec_dump.out", "wb"); +#endif + + strncpy (g_uri, filename, len); + + return; +} + +void _allocate_buf(void) +{ +#if USE_INPUT_QUEUE + int i = 0; + + // !!!! remove dependency on internal headers. + input_avaliable = mc_async_queue_new(); + input_buf = (media_packet_h *)malloc(sizeof(media_packet_h)*MAX_INPUT_BUF_NUM); + + for (i = 0; i < MAX_INPUT_BUF_NUM; i++) + { + media_packet_create_alloc(input_fmt, NULL, NULL, &input_buf[i]); + g_print("input queue buf = %p\n", input_buf[i]); + mc_async_queue_push(input_avaliable, input_buf[i]); + } +#else + media_packet_create_alloc(input_fmt, NULL, NULL, &in_buf); + //media_format_unref(input_fmt); + g_print("input queue buf = %p\n", in_buf); +#endif + return; +} + +#if USE_INPUT_QUEUE +void _free_buf(void) +{ + int i = 0; + + if (input_avaliable) + mc_async_queue_free(input_avaliable); + + if (input_buf) + { + for (i = 0; i < MAX_INPUT_BUF_NUM; i++) + { + if(input_buf[i]) + { + media_packet_destroy(input_buf[i]); + } + } + media_format_unref(input_fmt); + input_fmt = NULL; + free(input_buf); + input_buf = NULL; + } + return; +} +#endif + +static void _mediacodec_empty_buffer_cb(media_packet_h pkt, void *user_data) +{ + if (pkt != NULL) + { +#if USE_INPUT_QUEUE + media_packet_unset_flags(pkt, MEDIA_PACKET_CODEC_CONFIG); + mc_async_queue_push(input_avaliable, pkt); + g_print("availablebuf = %p\n", pkt); +#else + g_print("Used input buffer = %p\n", pkt); + media_packet_destroy(pkt); +#endif + } + return; +} + +static void _mediacodec_fill_buffer_cb(media_packet_h pkt, void *user_data) +{ + if (pkt != NULL) + { + _mediacodec_get_output(); + } + return; +} + +static void _mediacodec_eos_cb(void *user_data) +{ + g_print("event : eos\n"); +} + +void _mediacodec_destroy(void) +{ + int i = 0; + g_print("mediacodec_destroy\n"); + + for (i = 0; i < g_handle_num; i++) + { + if(g_media_codec[i] != NULL) + { + //mediacodec_unprepare(g_media_codec[i]); + mediacodec_destroy(g_media_codec[i]); + g_media_codec[i] = NULL; + } + } +#if USE_INPUT_QUEUE + _free_buf(); +#endif + if (fp_src) + fclose(fp_src); +#if DUMP_OUTBUF + if (fp_out) + fclose(fp_out); +#endif + return; +} + +void _mediacodec_set_codec(int codecid, int flag) +{ + int encoder = 0; + g_print("_mediacodec_configure\n"); + g_print("codecid = %x, flag = %d\n", codecid, flag); + if (g_media_codec[0] != NULL) + { + mediacodec_set_codec(g_media_codec[0], (mediacodec_codec_type_e)codecid, flag); + encoder = GET_IS_ENCODER(flag) ? 1 : 0; + if (use_video) + { + if (encoder) + { + //input_fmt->mimetype |= MEDIA_FORMAT_RAW; + //input_fmt->mimetype |= MEDIA_FORMAT_NV12; + mimetype |= MEDIA_FORMAT_RAW; + mimetype |= MEDIA_FORMAT_NV12; + //mimetype |= MEDIA_FORMAT_I420; + } + else + { + //input_fmt->mimetype |= MEDIA_FORMAT_H264_SP; + mimetype |= MEDIA_FORMAT_H264_SP; + } + mimetype |= MEDIA_FORMAT_VIDEO; + } + else + { + if (encoder) + { + mimetype |= MEDIA_FORMAT_RAW; + mimetype |= MEDIA_FORMAT_PCM; + } + else + { + if (codecid == MEDIACODEC_AAC) + mimetype |= MEDIA_FORMAT_AAC; /* MPEG-2 : (*.aac, adts) */ + else if (codecid == MEDIACODEC_MP3) + mimetype |= MEDIA_FORMAT_MP3; + } + mimetype |= MEDIA_FORMAT_AUDIO; + g_print(" [audio test] mimetype (0x%x)\n", mimetype); + } + } + else + { + g_print("mediacodec handle is not created\n"); + } + return; +} + +void _mediacodec_set_vdec_info(int width, int height) +{ + g_print("_mediacodec_set_vdec_info\n"); + g_print("width = %d, height = %d\n", width, height); + if (g_media_codec[0] != NULL) + { + mediacodec_set_vdec_info(g_media_codec[0], width, height); + //input_fmt->detail.video.width = width; + //input_fmt->detail.video.height = height; + } + else + { + g_print("mediacodec handle is not created\n"); + } + return; +} + +void _mediacodec_set_venc_info(int width, int height, float fps, int target_bits) +{ + g_print("_mediacodec_set_venc_info\n"); + if (g_media_codec[0] != NULL) + { + mediacodec_set_venc_info(g_media_codec[0], width, height, fps, target_bits); + //input_fmt->detail.video.width = width; + //input_fmt->detail.video.height = height; + } + else + { + g_print("mediacodec handle is not created\n"); + } + return; +} + +void _mediacodec_set_adec_info(int samplerate, int chnnel, int bit) +{ + g_print("_mediacodec_set_adec_info\n"); + g_print("samplerate = %d, channel = %d, bit = %d\n", samplerate, chnnel, bit); + if (g_media_codec[0] != NULL) + { + mediacodec_set_adec_info(g_media_codec[0], samplerate, chnnel, bit); + } + else + { + g_print("mediacodec handle is not created\n"); + } + return; +} + +void _mediacodec_set_aenc_info(int samplerate, int chnnel, int bit, int bitrate) +{ + g_print("_mediacodec_set_aenc_info\n"); + g_print("samplerate = %d, channel = %d, bit = %d, bitrate = %d\n", samplerate, chnnel, bit, bitrate); + if (g_media_codec[0] != NULL) + { + mediacodec_set_aenc_info(g_media_codec[0], samplerate, chnnel, bit, bitrate); + } + else + { + g_print("mediacodec handle is not created\n"); + } + return; +} + + +void _mediacodec_prepare(void) +{ + int i = 0; + int err = 0; + if (use_video) + { + media_format_set_video_mime(input_fmt, mimetype); + media_format_set_video_width(input_fmt, width); + media_format_set_video_height(input_fmt, height); + media_format_set_video_avg_bps(input_fmt, target_bits); + } + else + { + g_print(" [audio test] mimetype (0x%x), channel(%d), samplerate (%d), bit (%d)\n", mimetype, channel, samplerate, bit); + media_format_set_audio_mime(input_fmt, mimetype); + media_format_set_audio_channel(input_fmt, channel); + media_format_set_audio_samplerate(input_fmt, samplerate); + media_format_set_audio_bit(input_fmt, bit); + } + + for (i=0; i < g_handle_num; i++) + { + if(g_media_codec[i] != NULL) + { + mediacodec_set_input_buffer_used_cb(g_media_codec[i], _mediacodec_empty_buffer_cb, g_media_codec[i]); + mediacodec_set_output_buffer_available_cb(g_media_codec[i], _mediacodec_fill_buffer_cb, g_media_codec[i]); + mediacodec_set_eos_cb(g_media_codec[i], _mediacodec_eos_cb, g_media_codec[i]); + + err = mediacodec_prepare(g_media_codec[i]); + + if (err != MEDIACODEC_ERROR_NONE) + { + g_print("mediacodec_prepare failed error = %d \n", err); + } +#if USE_INPUT_QUEUE + _allocate_buf(); +#endif + } + else + { + g_print("mediacodec handle is not created\n"); + } + } + frame_count = 0; + + return; +} +/* +static gpointer +feed_thread(gpointer data) +{ + int i; + int err = 0; + + for (i=0; i < g_handle_num; i++) + { + if(g_media_codec[i] != NULL) + { + mediacodec_unset_input_buffer_used_cb(g_media_codec[i]); + mediacodec_unset_output_buffer_available_cb(g_media_codec[i]); + + err = mediacodec_unprepare(g_media_codec[i]); + if (err != MEDIACODEC_ERROR_NONE) + { + g_print("mediacodec_unprepare failed error = %d \n", err); + } + } + else + { + g_print("mediacodec handle is not created\n"); + } + } + g_print("mediacodec unprepare is called"); + + return NULL; +} +*/ + +void _mediacodec_unprepare(void) +{ + int i = 0; + int err = 0; + g_print("_mediacodec_unprepare\n"); + + for (i=0; i < g_handle_num; i++) + { + if(g_media_codec[i] != NULL) + { + mediacodec_unset_input_buffer_used_cb(g_media_codec[i]); + mediacodec_unset_output_buffer_available_cb(g_media_codec[i]); + + err = mediacodec_unprepare(g_media_codec[i]); + if (err != MEDIACODEC_ERROR_NONE) + { + g_print("mediacodec_unprepare failed error = %d \n", err); + } + } + else + { + g_print("mediacodec handle is not created\n"); + } + } + frame_count = 0; + + //thread = g_thread_create(feed_thread, sejun, TRUE, NULL); + return; +} + +int _mediacodec_process_input(void) +{ + g_print("_mediacodec_process_input\n"); + unsigned int buf_size = 0; +#if USE_INPUT_QUEUE + media_packet_h in_buf = NULL; +#endif + void *data = NULL; + int ret = 0; + + if (g_media_codec[0] == NULL) + { + g_print("mediacodec handle is not created\n"); + return MEDIACODEC_ERROR_INVALID_PARAMETER; + } + + if (fp_src == NULL) + { + fp_src = fopen(g_uri, "r"); + if (fp_src == NULL) + { + g_print("%s file open failed\n", g_uri); + return MEDIACODEC_ERROR_INVALID_PARAMETER; + } + } +#if USE_INPUT_QUEUE + in_buf = mc_async_queue_pop(input_avaliable); +#else + _allocate_buf(); +#endif + + + if (in_buf != NULL) + { + media_packet_get_buffer_data_ptr(in_buf, &data); + if(data == NULL) + return MEDIACODEC_ERROR_INVALID_PARAMETER; + + if (use_encoder) + { + if (use_video) + { + buf_size = bytestream2yuv420(fp_src, data); + media_packet_set_pts (in_buf, pts); + g_print("input pts = %llu\n", pts); + if (fps != 0) + { + pts += (GST_SECOND / fps); + } + } + else + { + buf_size = extract_input_aacenc(fp_src, data); + media_packet_set_pts (in_buf, pts); + g_print("input pts = %llu\n", pts); + if (samplerate != 0) + { + pts += ((GST_SECOND / samplerate) * samplebyte); + } + } + } + else + { + if (use_video) + { + if(frame_count == 0) + ret = media_packet_set_flags(in_buf, MEDIA_PACKET_CODEC_CONFIG); + else if(frame_count == 300) + ret = media_packet_set_flags(in_buf, MEDIA_PACKET_END_OF_STREAM); + + buf_size = bytestream2nalunit(fp_src, data); + } + else + { + if (mimetype == MEDIA_FORMAT_AAC) + { + buf_size = extract_input_aacdec(fp_src, data); + } + else if (mimetype == MEDIA_FORMAT_MP3) + { + buf_size = extract_input_mp3dec(fp_src, data); + } + } + } + + if (buf_size == 0) + { + g_print("input file read failed\n"); + return MEDIACODEC_ERROR_INVALID_PARAMETER; + } + + media_packet_set_buffer_size(in_buf, buf_size); + g_print("%s - input_buf size = %d (0x%x), frame_count : %d\n",__func__, buf_size, buf_size, frame_count); + ret = mediacodec_process_input (g_media_codec[0], in_buf, 0); + if(frame_count == 300) + return MEDIACODEC_ERROR_INVALID_INBUFFER; + frame_count++; + return ret; + } + + return MEDIACODEC_ERROR_NONE; +} + +int _mediacodec_get_output(void) +{ + int err = 0; + uint64_t buf_size = 0; + void *data = NULL; + g_print("_mediacodec_get_output\n"); + if (g_media_codec[0] == NULL) + { + g_print("mediacodec handle is not created\n"); + return MEDIACODEC_ERROR_INVALID_PARAMETER; + } + + err = mediacodec_get_output(g_media_codec[0], &output_buf, 0); + if( err == MEDIACODEC_ERROR_NONE) + { + media_packet_get_buffer_size(output_buf, &buf_size); + g_print("%s - output_buf size =%p, %lld\n",__func__, output_buf, buf_size); +#if DUMP_OUTBUF + media_packet_get_buffer_data_ptr(output_buf, &data); + if ((!use_video) && (use_encoder)) + { + if (buf_size > 0) + { + /* This is used only AAC encoder case for adding each ADTS frame header */ + add_adts_header_for_aacenc(buf_adts, (buf_size+ADTS_HEADER_SIZE)); + fwrite(&buf_adts[0], 1, ADTS_HEADER_SIZE, fp_out); + } + } + + if (data != NULL) + fwrite(data, 1, buf_size, fp_out); +#endif +// printf("%s - output_buf : %p\n",__func__, output_buf); +// mediacodec_reset_output_buffer(g_media_codec[0], &output_buf); + media_packet_destroy(output_buf); + } + else + { + g_print("get_output failed err = %d\n", err); + return err; + } + + return MEDIACODEC_ERROR_NONE; +} + +void _mediacodec_reset_output_buffer(void) +{ + g_print("_media_codec_reset_output_buffer\n"); + if (g_media_codec[0] == NULL) + { + g_print("mediacodec handle is not created\n"); + return; + } +/* + if(output_buf == NULL) + { + g_print("output buffer is NULL"); + return; + } +*/ + //mediacodec_reset_output_buffer(g_media_codec[0], &output_buf); + return; +} + +void _mediacodec_process_input_n(int num) +{ + int i = 0; + int ret = 0; + for (i =0; i < num; i++) + { + ret = _mediacodec_process_input(); + if (ret != 0) + g_print ("_mediacodec_process_input err = %d\n", ret); + } + return; +} + +void _mediacodec_get_output_n(int num) +{ + int i = 0; + int ret = 0; + for (i =0; i < num; i++) + { + ret = _mediacodec_get_output(); + if (ret != 0) + g_print ("_mediacodec_get_output err = %d\n", ret); + } + return; +} + +void _mediacodec_process_all(void) +{ + g_print("_mediacodec_process_all\n"); + int ret = MEDIACODEC_ERROR_NONE; + + while(1) + { + ret = _mediacodec_process_input(); + + if(ret != MEDIACODEC_ERROR_NONE) + break; + } + + return; +} + + +void quit_program(void) +{ + int i = 0; + + for (i = 0; i < g_handle_num; i++) + { + if(g_media_codec[i]!=NULL) + { + mediacodec_unprepare(g_media_codec[i]); + mediacodec_destroy(g_media_codec[i]); + g_media_codec[i] = NULL; + } + } + elm_exit(); +} + +void reset_menu_state() +{ + g_menu_state = CURRENT_STATUS_MAINMENU; + return; +} + +void _interpret_main_menu(char *cmd) +{ + int len = strlen(cmd); + if (len == 1) + { + if (strncmp(cmd, "a", 1) == 0) + { + g_menu_state = CURRENT_STATUS_FILENAME; + } + else if (strncmp(cmd, "o", 1) == 0) + { + g_menu_state = CURRENT_STATUS_GET_OUTPUT; + } + else if (strncmp(cmd, "q", 1) == 0) + { + quit_program(); + } + else + { + g_print("unknown menu \n"); + } + } + else if (len == 2) + { + if (strncmp(cmd, "pr", 2) == 0) + { + _mediacodec_prepare(); + } + else if (strncmp(cmd, "sc", 2) == 0) + { + g_menu_state = CURRENT_STATUS_SET_CODEC; + } + else if (strncmp(cmd, "vd", 2) == 0) + { + g_menu_state = CURRENT_STATUS_SET_VDEC_INFO; + } + else if (strncmp(cmd, "ve", 2) == 0) + { + g_menu_state = CURRENT_STATUS_SET_VENC_INFO; + } + else if (strncmp(cmd, "ad", 2) == 0) + { + g_menu_state = CURRENT_STATUS_SET_ADEC_INFO; + } + else if (strncmp(cmd, "ae", 2) == 0) + { + g_menu_state = CURRENT_STATUS_SET_AENC_INFO; + } + else if (strncmp(cmd, "pi", 2) == 0) + { + g_menu_state = CURRENT_STATUS_PROCESS_INPUT; + } + else if (strncmp(cmd, "rb", 2) == 0) + { + _mediacodec_reset_output_buffer(); + } + else if (strncmp(cmd, "pa", 2) == 0) + { + _mediacodec_process_all(); + } + else if (strncmp(cmd, "un", 2) == 0) + { + _mediacodec_unprepare(); + } + else if (strncmp(cmd, "dt", 2) == 0) + { + _mediacodec_destroy(); + } + else + { + g_print("unknown menu \n"); + } + } + else + { + g_print("unknown menu \n"); + } + return; +} + +static void displaymenu(void) +{ + if (g_menu_state == CURRENT_STATUS_MAINMENU) + { + display_sub_basic(); + } + else if (g_menu_state == CURRENT_STATUS_FILENAME) + { + g_print("*** input mediapath.\n"); + } + else if (g_menu_state == CURRENT_STATUS_SET_CODEC) + { + g_print("*** Codec id : L16 = 1 Flags : MEDIACODEC_ENCODER = 1\n"); + g_print(" ALAW = 2 MEDIACODEC_DECODER = 2\n"); + g_print(" ULAW = 3 MEDIACODEC_SUPPORT_TYPE_HW = 4,\n"); + g_print(" AMR = 4 MEDIACODEC_SUPPORT_TYPE_SW = 8,\n"); + g_print(" G729 = 5 MEDIACODEC_SUPPORT_TYPE_OMX = 16\n"); + g_print(" AAC = 6 MEDIACODEC_SUPPORT_TYPE_GEN = 32,\n"); + g_print(" MP3 = 7\n"); + g_print(" H261 = 101\n"); + g_print(" H263 = 102\n"); + g_print(" H264 = 103\n"); + g_print(" MJPEG = 104\n"); + g_print(" MPEG1 = 105\n"); + g_print(" MPEG2 = 106\n"); + g_print(" MPEG4 = 107\n"); + g_print("*** input codec id, flags.\n"); + } + else if (g_menu_state == CURRENT_STATUS_SET_VDEC_INFO) + { + g_print("*** input video decode configure.(width, height)\n"); + } + else if (g_menu_state == CURRENT_STATUS_SET_VENC_INFO) + { + g_print("*** input video encode configure.(width, height, fps, target_bits)\n"); + } + else if (g_menu_state == CURRENT_STATUS_SET_ADEC_INFO) + { + g_print("*** input audio decode configure.(samplerate, channel, bit)\n"); + } + else if (g_menu_state == CURRENT_STATUS_SET_AENC_INFO) + { + g_print("*** input audio encode configure.(samplerate, channel, bit, bitrate)\n"); + } + else if (g_menu_state == CURRENT_STATUS_PROCESS_INPUT) + { + g_print("*** input dec process number\n"); + } + else if (g_menu_state == CURRENT_STATUS_GET_OUTPUT) + { + g_print("*** input get output buffer number\n"); + } + else + { + g_print("*** unknown status.\n"); + quit_program(); + } + g_print(" >>> "); +} + +gboolean timeout_menu_display(void* data) +{ + displaymenu(); + return FALSE; +} + + +static void interpret (char *cmd) +{ + switch (g_menu_state) + { + case CURRENT_STATUS_MAINMENU: + { + _interpret_main_menu(cmd); + } + break; + case CURRENT_STATUS_FILENAME: + { + input_filepath(cmd); + reset_menu_state(); + } + break; + case CURRENT_STATUS_SET_CODEC: + { + static int codecid = 0; + static int flag = 0; + static int cnt = 0; + + int tmp; + char **ptr = NULL; + switch (cnt) + { + case 0: + tmp = atoi(cmd); + + if(tmp > 100) + { + tmp = strtol(cmd, ptr, 16); + codecid = 0x2000 + ((tmp & 0xFF) << 4); + use_video = 1; + } + else + { + codecid = 0x1000 + (tmp<<4); + } + cnt++; + break; + case 1: + flag = atoi(cmd); + if (GET_IS_ENCODER(flag)) + use_encoder = 1; + else if (GET_IS_DECODER(flag)) + use_encoder = 0; + _mediacodec_set_codec(codecid, flag); + reset_menu_state(); + codecid = 0; + flag = 0; + cnt = 0; + break; + default: + break; + } + } + break; + case CURRENT_STATUS_SET_VDEC_INFO: + { + static int cnt = 0; + switch (cnt) + { + case 0: + width = atoi(cmd); + cnt++; + break; + case 1: + height = atoi(cmd); + _mediacodec_set_vdec_info(width, height); + reset_menu_state(); + cnt = 0; + break; + default: + break; + } + }break; + case CURRENT_STATUS_SET_VENC_INFO: + { + static int cnt = 0; + switch (cnt) { + case 0: + width = atoi(cmd); + cnt++; + break; + case 1: + height = atoi(cmd); + cnt++; + break; + case 2: + fps = atol(cmd); + cnt++; + break; + case 3: + target_bits = atoi(cmd); + g_print("width = %d, height = %d, fps = %f, target_bits = %d\n", width, height, fps, target_bits); + _mediacodec_set_venc_info(width, height, fps, target_bits); + reset_menu_state(); + cnt = 0; + break; + default: + break; + } + } + break; + case CURRENT_STATUS_SET_ADEC_INFO: + { + static int cnt = 0; + switch (cnt) + { + case 0: + samplerate = atoi(cmd); + cnt++; + break; + case 1: + channel = atoi(cmd); + cnt++; + break; + case 2: + bit = atoi(cmd); + _mediacodec_set_adec_info(samplerate, channel,bit); + reset_menu_state(); + cnt = 0; + break; + default: + break; + } + }break; + case CURRENT_STATUS_SET_AENC_INFO: + { + static int cnt = 0; + switch (cnt) + { + case 0: + samplerate = atoi(cmd); + cnt++; + break; + case 1: + channel = atoi(cmd); + cnt++; + break; + case 2: + bit = atoi(cmd); + cnt++; + break; + case 3: + bitrate = atoi(cmd); + _mediacodec_set_aenc_info(samplerate, channel,bit,bitrate); + reset_menu_state(); + cnt = 0; + break; + default: + break; + } + }break; + case CURRENT_STATUS_PROCESS_INPUT: + { + static int num = 0; + num = atoi(cmd); + _mediacodec_process_input_n(num); + reset_menu_state(); + } + break; + case CURRENT_STATUS_GET_OUTPUT: + { + static int num = 0; + num = atoi(cmd); + _mediacodec_get_output_n(num); + reset_menu_state(); + } + break; + default: + break; + } + + g_timeout_add(100, timeout_menu_display, 0); +} + +static void display_sub_basic() +{ + g_print("\n"); + g_print("=========================================================================================\n"); + g_print(" media codec test\n"); + g_print("-----------------------------------------------------------------------------------------\n"); + g_print("a. Create \t"); + g_print("sc. Set codec \t\t"); + g_print("vd. Set vdec info w, h\t"); + g_print("ve. Set venc info \n"); + g_print("ad. Set adec info s, c, b\t"); + g_print("ae. Set aenc info \n"); + g_print("pr. Prepare \t"); + g_print("pi. Process input \t"); + g_print("o. Get output \t\t"); + g_print("rb. Reset output buffer \n"); + g_print("pa. Process all frames \n"); + g_print("un. Unprepare \t"); + g_print("dt. Destroy \t\t"); + g_print("q. quite test suite \t"); + g_print("\n"); + g_print("=========================================================================================\n"); +} + +gboolean input (GIOChannel *channel) +{ + gchar buf[MAX_STRING_LEN]; + gsize read; + GError *error = NULL; + + g_io_channel_read_chars(channel, buf, MAX_STRING_LEN, &read, &error); + buf[read] = '\0'; + g_strstrip(buf); + interpret (buf); + + return TRUE; +} + +int main(int argc, char *argv[]) +{ + GIOChannel *stdin_channel; + stdin_channel = g_io_channel_unix_new(0); + g_io_channel_set_flags (stdin_channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch (stdin_channel, G_IO_IN, (GIOFunc)input, NULL); + + displaymenu(); + + ops.data = NULL; + + return appcore_efl_main(PACKAGE, &argc, &argv, &ops); + +} diff --git a/test/tags b/test/tags new file mode 100644 index 0000000..95f511d --- /dev/null +++ b/test/tags @@ -0,0 +1,44 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.9~svn20110310 // +CURRENT_STATUS_DESTROY videowall/player_vw_test.c /^ CURRENT_STATUS_DESTROY,$/;" e enum:__anon1 file: +CURRENT_STATUS_FILENAME videowall/player_vw_test.c /^ CURRENT_STATUS_FILENAME,$/;" e enum:__anon1 file: +CURRENT_STATUS_HANDLE_NUM videowall/player_vw_test.c /^ CURRENT_STATUS_HANDLE_NUM,$/;" e enum:__anon1 file: +CURRENT_STATUS_LOOP videowall/player_vw_test.c /^ CURRENT_STATUS_LOOP,$/;" e enum:__anon1 file: +CURRENT_STATUS_MAINMENU videowall/player_vw_test.c /^ CURRENT_STATUS_MAINMENU,$/;" e enum:__anon1 file: +CURRENT_STATUS_PAUSE videowall/player_vw_test.c /^ CURRENT_STATUS_PAUSE,$/;" e enum:__anon1 file: +CURRENT_STATUS_PLAY videowall/player_vw_test.c /^ CURRENT_STATUS_PLAY,$/;" e enum:__anon1 file: +MAX_STRING_LEN videowall/player_vw_test.c 27;" d file: +TEST_FILE_SIZE media_codec_test.c 26;" d file: +VIDEO_DUMP_PATH_PREFIX videowall/player_vw_test.c 28;" d file: +__interpret_input videowall/player_vw_test.c /^static void __interpret_input(char *cmd)$/;" f file: signature:(char *cmd) +__interpret_main videowall/player_vw_test.c /^static void __interpret_main(char *cmd)$/;" f file: signature:(char *cmd) +__print_menu videowall/player_vw_test.c /^static void __print_menu()$/;" f file: +__quit videowall/player_vw_test.c /^static void __quit()$/;" f file: +__reset_menu_state videowall/player_vw_test.c /^static void __reset_menu_state(void)$/;" f file: signature:(void) +__timeout_get_current videowall/player_vw_test.c /^static gboolean __timeout_get_current(void* data)$/;" f file: signature:(void* data) +_completed_cb videowall/player_vw_test.c /^static void _completed_cb(void *user_data)$/;" f file: signature:(void *user_data) +_frame_decoded_cb videowall/player_vw_test.c /^static void _frame_decoded_cb(unsigned char *data, int size, void *user_data)$/;" f file: signature:(unsigned char *data, int size, void *user_data) +_get_status videowall/player_vw_test.c /^static void _get_status()$/;" f file: +_input videowall/player_vw_test.c /^static gboolean _input(GIOChannel *channel)$/;" f file: signature:(GIOChannel *channel) +_setup_dump videowall/player_vw_test.c /^static void _setup_dump()$/;" f file: +file_handle_args media_codec_test.c /^extern int file_handle_args (int argc, char ** argv, int flag);$/;" p file: signature:(int argc, char ** argv, int flag) +file_handle_args media_codec_test.c /^int file_handle_args (int argc, char ** argv, int flag)$/;" f signature:(int argc, char ** argv, int flag) +fnp media_codec_test.c /^char *fnp;$/;" v +g_dump_fd videowall/player_vw_test.c /^FILE *g_dump_fd;$/;" v +g_loop videowall/player_vw_test.c /^GMainLoop *g_loop;$/;" v +g_menu_state videowall/player_vw_test.c /^int g_menu_state = CURRENT_STATUS_MAINMENU;$/;" v +g_player videowall/player_vw_test.c /^static vw_player_h g_player;$/;" v file: +g_uri videowall/player_vw_test.c /^char g_uri[MAX_STRING_LEN];$/;" v +inf media_codec_test.c /^ FILE *inf, *outf;$/;" v +inf media_codec_test.c /^ int inf, outf;$/;" v +input_filename videowall/player_vw_test.c /^static void input_filename(char *filename)$/;" f file: signature:(char *filename) +main media_codec_test.c /^int main (int argc, char ** argv)$/;" f signature:(int argc, char ** argv) +main videowall/player_vw_test.c /^int main(int argc, char *argv[])$/;" f signature:(int argc, char *argv[]) +outf media_codec_test.c /^ FILE *inf, *outf;$/;" v +outf media_codec_test.c /^ int inf, outf;$/;" v +szInputName media_codec_test.c /^char szInputName[255];$/;" v +szOutputName media_codec_test.c /^char szOutputName[255];$/;" v |