From 6cba6655177cde6c6e651275907e41d996949824 Mon Sep 17 00:00:00 2001 From: "jk7744.park" Date: Sat, 31 Jan 2015 16:26:44 +0900 Subject: tizen 2.3 release --- AUTHORS | 2 + CMakeLists.txt | 98 +++ LICENSE.APLv2 | 206 +++++++ NOTICE | 3 + capi-media-codec.manifest | 8 + capi-media-codec.pc.in | 15 + doc/media_codec_doc.h | 42 ++ include/media_codec.h | 445 ++++++++++++++ include/media_codec_port.h | 283 +++++++++ include/media_codec_port_gst.h | 136 +++++ include/media_codec_private.h | 122 ++++ include/media_codec_queue.h | 60 ++ include/media_codec_spec_emul.h | 94 +++ include/media_codec_util.h | 74 +++ packaging/capi-media-codec.spec | 83 +++ src/media_codec.c | 512 ++++++++++++++++ src/media_codec_port.c | 868 ++++++++++++++++++++++++++ src/media_codec_port_gst.c | 1074 ++++++++++++++++++++++++++++++++ src/media_codec_queue.c | 102 ++++ src/media_codec_util.c | 33 + test/CMakeLists.txt | 23 + test/media_codec_test.c | 1276 +++++++++++++++++++++++++++++++++++++++ test/tags | 44 ++ 23 files changed, 5603 insertions(+) create mode 100644 AUTHORS create mode 100755 CMakeLists.txt create mode 100644 LICENSE.APLv2 create mode 100644 NOTICE create mode 100644 capi-media-codec.manifest create mode 100644 capi-media-codec.pc.in create mode 100644 doc/media_codec_doc.h create mode 100755 include/media_codec.h create mode 100755 include/media_codec_port.h create mode 100755 include/media_codec_port_gst.h create mode 100755 include/media_codec_private.h create mode 100644 include/media_codec_queue.h create mode 100755 include/media_codec_spec_emul.h create mode 100755 include/media_codec_util.h create mode 100755 packaging/capi-media-codec.spec create mode 100755 src/media_codec.c create mode 100755 src/media_codec_port.c create mode 100755 src/media_codec_port_gst.c create mode 100644 src/media_codec_queue.c create mode 100644 src/media_codec_util.c create mode 100644 test/CMakeLists.txt create mode 100755 test/media_codec_test.c create mode 100644 test/tags diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..b01c60f --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Kangho Hur +Seungkeun Lee 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. + + + diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..ccdad52 --- /dev/null +++ b/NOTICE @@ -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 @@ + + + + + + + + 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 + * + * @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..284656f --- /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 +#include +#include + +#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 2.3 + */ +typedef struct mediacodec_s *mediacodec_h; + +/** + * @brief Enumeration of media codec support type + * @since_tizen 2.3 + * @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 2.3 + */ +typedef enum +{ + MEDIACODEC_NONE = 0x0, + MEDIACODEC_L16 = 0x1010, + MEDIACODEC_ALAW = 0x1020, + MEDIACODEC_ULAW = 0x1030, + MEDIACODEC_AMR = 0x1040, + MEDIACODEC_G729 = 0x1050, + MEDIACODEC_AAC = 0x1060, + MEDIACODEC_MP3 = 0x1070, + + MEDIACODEC_H261 = 0x2010, + MEDIACODEC_H263 = 0x2020, + MEDIACODEC_H264 = 0x2030, + MEDIACODEC_MJPEG = 0x2040, + MEDIACODEC_MPEG1 = 0x2050, + MEDIACODEC_MPEG2 = 0x2060, + MEDIACODEC_MPEG4 = 0x2070, +} mediacodec_codec_type_e; + +/** + * @brief Enumeration of media codec error + * @since_tizen 2.3 + */ +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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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 2.3 + * @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..c44048e --- /dev/null +++ b/include/media_codec_port.h @@ -0,0 +1,283 @@ +/* +* 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 +#include +#include +#include + +#include +#include +#include + + +/*=========================================================================================== +| | +| 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; + +/* gst port layer */ +typedef struct _mc_gst_port_t mc_gst_port_t; +typedef struct _mc_gst_core_t mc_gst_core_t; + +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 frame_width; + int frame_height; + int bitrate; + int fps; + int qp_min; + int qp_max; + int vbvbuffer_size; + int level; + int profile; + + int samplerate; + int channel; + int bit; +}; + +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 +{ + GstState state; + bool output_allocated; + bool encoder; + bool video; + bool is_hw; + + mediacodec_codec_type_e codec_id; + media_format_h output_fmt; + mc_gst_port_t *ports[2]; + + /* gst stuffs */ + GstElement* pipeline; + GstElement* appsrc; + GstElement* converter; + GstElement* fakesink; + GstElement* codec; + + gulong signal_handoff; + gint bus_whatch_id; + + mc_aqueue_t *available_queue; + GQueue *output_queue; + + mc_decoder_info_t *dec_info; + mc_encoder_info_t *enc_info; + + void* user_cb[_MEDIACODEC_EVENT_TYPE_NUM]; + void* user_data[_MEDIACODEC_EVENT_TYPE_NUM]; + + gchar *factory_name; + gchar *mime; +}; + +/* Codec Private data */ +struct _mc_handle_t +{ + void *hcodec; /**< codec handle */ + int state; /**< mc current state */ + mediacodec_port_type_e port_type; + bool is_encoder; + bool is_video; + bool is_hw; + bool is_codec_config; /** < codec config data for first frame(SPS - using in AVC) */ + bool output_allocated; + bool is_prepared; + + int frame_count; + int out_buf_cnt; + int *out_buf_ref; + + mediacodec_codec_type_e codec_id; + + /* for gst port */ + mc_gst_port_t *gst_ports[2]; + mc_gst_core_t *gst_core; + + /* for Decoder */ + mc_decoder_info_t *dec_info; + + /* for Encoder */ + mc_encoder_info_t *enc_info; + + /* for process done cb */ + void* user_cb[_MEDIACODEC_EVENT_TYPE_NUM]; + void* user_data[_MEDIACODEC_EVENT_TYPE_NUM]; + + mc_codec_spec_t g_media_codec_spec_emul[MC_MAX_NUM_CODEC]; +}; + +/*=========================================================================================== +| | +| 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_reset(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..97fddd8 --- /dev/null +++ b/include/media_codec_port_gst.h @@ -0,0 +1,136 @@ + +/* +* 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#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 + +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 +{ + /* width of each image plane */ + int w[SCMN_IMGB_MAX_PLANE]; + /* height of each image plane */ + int h[SCMN_IMGB_MAX_PLANE]; + /* stride of each image plane */ + int s[SCMN_IMGB_MAX_PLANE]; + /* elevation of each image plane */ + int e[SCMN_IMGB_MAX_PLANE]; + /* user space address of each image plane */ + void *a[SCMN_IMGB_MAX_PLANE]; + /* physical address of each image plane, if needs */ + void *p[SCMN_IMGB_MAX_PLANE]; + /* color space type of image */ + int cs; + /* left postion, if needs */ + int x; + /* top position, if needs */ + int y; + /* to align memory */ + int __dummy2; + /* arbitrary data */ + int data[16]; + /* DMABUF fd of each image plane */ + int dma_buf_fd[SCMN_IMGB_MAX_PLANE]; + /* buffer share method */ + int buf_share_method; /* will be 2(BUF_SHARE_METHOD_TIZEN_BUFFER)*/ + /* Y plane size in case of ST12 */ + int y_size; + /* UV plane size in case of ST12 */ + int uv_size; + /* Tizen buffer object of each image plane */ + tbm_bo bo[SCMN_IMGB_MAX_PLANE]; + /* JPEG data */ + void *jpeg_data; + /* JPEG size */ + int jpeg_size; + /* TZ memory buffer */ + int tz_enable; +} SCMN_IMGB; + +typedef struct { + GstBuffer buffer; + mc_gst_core_t* core; + media_packet_h pkt; +} mc_gst_buffer; + +typedef void (*mediacodec_internal_fillbuffer_cb)(media_packet_h pkt, bool avail_output, void *user_data); + +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_gst_core_t *core); +mc_ret_e mc_gst_unprepare(mc_gst_core_t *core); + +mc_ret_e mc_gst_creat_handle(mc_gst_core_t *core); +mc_ret_e mc_gst_delete(mc_gst_core_t *core); + +mc_ret_e mc_gst_process_input(mc_gst_core_t *core, media_packet_h inbuf, uint64_t timeOutUs); +mc_ret_e mc_gst_get_output(mc_gst_core_t *core, media_packet_h *outbuf, uint64_t timeOutUs); + +mc_ret_e mc_gst_set_vdec_info(mc_gst_core_t *core); +mc_ret_e mc_gst_set_venc_info(mc_gst_core_t *core); + +#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 +#include + +#include + +#include + +#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 100644 index 0000000..c9bf23d --- /dev/null +++ b/include/media_codec_queue.h @@ -0,0 +1,60 @@ +/* +* 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 + +#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(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..40df2a2 --- /dev/null +++ b/include/media_codec_spec_emul.h @@ -0,0 +1,94 @@ +/* +* 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 + +#define MC_MAX_NUM_CODEC 4 +#define MC_MAX_NUM_MAP 4 +#define MC_MAX_FACTORY_STRLEN 20 + +enum { DECODER, ENCODER }; +enum { SOFTWARE, HARDWARE }; + +//typedef struct _mc_codec_mimetype_t mc_codec_mimetype_t; +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 mime; + mediacodec_support_type_e codec_type; + mediacodec_support_type_e support_type; + mediacodec_port_type_e port_type; +}; + +struct _mc_codec_type_t +{ + char *factory_name; + media_format_mimetype_e out_format; + char *mime; +}; + +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[MC_MAX_NUM_CODEC] = +{ + {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} +}; + +static const mc_codec_map_t encoder_map[] = +{ +#ifdef ENABLE_FFMPEG_CODEC + {MEDIACODEC_H263, SOFTWARE, {"ffenc_h263p", MEDIA_FORMAT_H263P, "video/x-raw-yuv"}}, + {MEDIACODEC_AAC, SOFTWARE, {"ffenc_aac", MEDIA_FORMAT_AAC, "audio/x-raw-int"}} +#else + {MEDIACODEC_H263, SOFTWARE, {"maru_h263penc", MEDIA_FORMAT_H263P, "video/x-raw-yuv"}}, + {MEDIACODEC_AAC, SOFTWARE, {"maru_aacenc", MEDIA_FORMAT_AAC, "audio/x-raw-int"}} +#endif +}; + +static const mc_codec_map_t decoder_map[] = +{ +#ifdef ENABLE_FFMPEG_CODEC + {MEDIACODEC_H264, SOFTWARE, {"ffdec_h264", MEDIA_FORMAT_I420, "video/x-h264"}}, + {MEDIACODEC_AAC, SOFTWARE, {"ffdec_aac", MEDIA_FORMAT_PCM, "audio/mpeg"}} +#else + {MEDIACODEC_H264, SOFTWARE, {"maru_h264dec", MEDIA_FORMAT_I420, "video/x-h264"}}, + {MEDIACODEC_AAC, SOFTWARE, {"maru_aacdec", MEDIA_FORMAT_PCM, "audio/mpeg"}} +#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..21e9947 --- /dev/null +++ b/include/media_codec_util.h @@ -0,0 +1,74 @@ +/* +* 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 +#include +#include +#include +//#include + +#ifdef __cplusplus +extern "C" { +#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 mc_sem; + +struct mc_sem +{ + GCond *condition; + GMutex *mutex; + int counter; +}; + +void *mc_aligned_malloc(int size, int alignment); +void mc_aligned_free(void *mem); + +mc_sem *mc_sem_new(); +void mc_sem_free(mc_sem *sem); +void mc_sem_down(mc_sem *sem); +void mc_sem_up(mc_sem *sem); + +#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..e8740ab --- /dev/null +++ b/packaging/capi-media-codec.spec @@ -0,0 +1,83 @@ +Name: capi-media-codec +Summary: A Media Codec library in Tizen Native API +Version: 0.1.1 +Release: 0 +Group: TO_BE/FILLED_IN +License: TO BE FILLED IN +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: TO_BE/FILLED_IN +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 +mkdir -p %{buildroot}/opt/usr/devel +cp test/media_codec_test %{buildroot}/opt/usr/devel +cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} + +%make_install + +%post +/sbin/ldconfig + +%postun -p /sbin/ldconfig + + +%files +%manifest capi-media-codec.manifest +%{_libdir}/libcapi-media-codec.so.* +%{_datadir}/license/%{name} +/opt/usr/devel/* +#%{_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 +#include +#include +#include +#include +#include + +#include + +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..2387b71 --- /dev/null +++ b/src/media_codec_port.c @@ -0,0 +1,868 @@ +/* +* 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 +#include +#include + +#include + +#include +#include +#include +#include + +#include + +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_codec_config = false; + new_mediacodec->output_allocated = false; + new_mediacodec->is_prepared = false; + new_mediacodec->codec_id = MEDIACODEC_NONE; + + new_mediacodec->gst_ports[0] = NULL; + new_mediacodec->gst_ports[1] = NULL; + + new_mediacodec->gst_core = NULL; + new_mediacodec->dec_info = NULL; + new_mediacodec->enc_info = NULL; + + memcpy(new_mediacodec->g_media_codec_spec_emul, spec_emul, sizeof(mc_codec_spec_t)*MC_MAX_NUM_CODEC); + + *mediacodec = (MMHandleType)new_mediacodec; + + return ret; + + // TO DO +ERROR: + if ( new_mediacodec ) + { + // TO DO + // If we need destroy and release for others (cmd, mutex..) + 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; + } + + if(mc_handle->gst_core != NULL) + { + if(mc_gst_unprepare(mc_handle->gst_core) != MC_ERROR_NONE) + { + LOGE("mc_gst_unprepare() failed"); + return MC_ERROR; + } + mc_gst_core_free(mc_handle->gst_core); + mc_handle->gst_core = NULL; + } + + mc_handle->is_prepared = false; + + g_free(mc_handle->dec_info); + g_free(mc_handle->enc_info); + + + /* 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; + + 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; + + 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, + MC_PARAM_ERROR,"MEDIACODEC_ERROR_INVALID_PARAMETER"); + + if (mc_handle->dec_info == NULL) + { + mc_handle->dec_info = g_new0(mc_decoder_info_t, 1); + } + + mc_handle->dec_info->width = width; + mc_handle->dec_info->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, + MC_PARAM_ERROR, "MEDIACODEC_ERROR_INVALID_PARAMETER"); + + if(mc_handle->enc_info == NULL) + { + mc_handle->enc_info = g_new0(mc_encoder_info_t, 1); + } + + mc_handle->enc_info->frame_width = width; + mc_handle->enc_info->frame_height = height; + mc_handle->enc_info->fps = fps; + mc_handle->enc_info->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, + MC_PARAM_ERROR, "MEDIACODEC_ERROR_INVALID_PARAMETER"); + + if (mc_handle->dec_info == NULL) + { + mc_handle->dec_info = g_new0(mc_decoder_info_t, 1); + } + + mc_handle->dec_info->samplerate = samplerate; + mc_handle->dec_info->channel = channel; + mc_handle->dec_info->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, + MC_PARAM_ERROR, "MEDIACODEC_ERROR_INVALID_PARAMETER"); + + if(mc_handle->enc_info == NULL) + { + mc_handle->enc_info = g_new0(mc_encoder_info_t, 1); + } + + mc_handle->enc_info->samplerate = samplerate; + mc_handle->enc_info->channel = channel; + mc_handle->enc_info->bit = bit; + mc_handle->enc_info->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; + media_format_mimetype_e mimetype; + + if (!mc_handle) + { + LOGE("fail invaild param\n"); + return MC_INVALID_ARG; + } + + if(!mc_handle->is_prepared) + return MC_NOT_INITIALIZED; + + /* setting core details */ + switch ( mc_handle->port_type ) + { + case MEDIACODEC_PORT_TYPE_GENERAL: + { + /* + //!!!! need to set data to omx/gen core need to seperate + mc_handle->gen_core->output_fmt = mc_handle->output_fmt; + mc_handle->gen_core->encoder = mc_handle->is_encoder; + + if(mc_handle->is_encoder) + { + mc_encoder_info_t *info; + + info = mc_handle->enc_info; + mc_handle->gen_core->enc_info = mc_handle->enc_info; + + media_format_set_video_info(mc_handle->output_fmt, mc_handle->mimetype, info->frame_width, info->frame_height, info->bitrate, 0); + } + else + { + mc_decoder_info_t *info; + + info = mc_handle->dec_info; + mc_handle->gen_core->dec_info = mc_handle->dec_info; + media_format_set_video_info(mc_handle->output_fmt, mc_handle->mimetype, info->width, info->height, 0, 0); + } + + ret = mc_general_init(mc_handle->gen_core); + */ + } + break; + + case MEDIACODEC_PORT_TYPE_OMX: + { + //et = mc_omx_init(mc_handle); + //ret = mc_omx_create_handle(mc_handle); + } + break; + + case MEDIACODEC_PORT_TYPE_GST: + { + int i; + int codec_list; + static const mc_codec_map_t *codec_map; + + mc_gst_core_t* new_core = mc_gst_core_new(); + // !!!! null check + + new_core->encoder = mc_handle->is_encoder; + new_core->is_hw = mc_handle->is_hw; + new_core->video = mc_handle->is_video; + new_core->codec_id = mc_handle->codec_id; + + /* setting internal callbacks */ + 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]); + } + } + + if(new_core->output_fmt == NULL) + { + if(media_format_create(&new_core->output_fmt) != MEDIA_FORMAT_ERROR_NONE) + { + LOGE("media format create failed"); + } + LOGD("pkt_fmt is allocated"); + } + + if(new_core->encoder) + { + codec_list = sizeof(encoder_map) / sizeof(encoder_map[0]); + codec_map = encoder_map; + } + else + { + codec_list = sizeof(decoder_map) / sizeof(decoder_map[0]); + codec_map = decoder_map; + } + + for(i = 0; i < codec_list; i++) + { + if((new_core->codec_id == codec_map[i].id) && (new_core->is_hw == codec_map[i].hardware)) + break; + } + + if(i == codec_list) + return MC_NOT_SUPPORTED; + + new_core->factory_name = codec_map[i].type.factory_name; + + mimetype = codec_map[i].type.out_format; + + new_core->mime = codec_map[i].type.mime; + + LOGD("factory name : %s, output_fmt : %x mime : %s", new_core->factory_name, mimetype, new_core->mime); + + if(mc_handle->is_encoder) + { + mc_encoder_info_t *info; + + info = mc_handle->enc_info; + new_core->enc_info = mc_handle->enc_info; + + if (new_core->video) + { + media_format_set_video_mime(new_core->output_fmt, mimetype); + media_format_set_video_width(new_core->output_fmt, info->frame_width); + media_format_set_video_height(new_core->output_fmt, info->frame_height); + media_format_set_video_avg_bps(new_core->output_fmt, info->bitrate); + } + else + { + media_format_set_audio_mime(new_core->output_fmt, mimetype); + media_format_set_audio_channel(new_core->output_fmt, info->channel); + media_format_set_audio_samplerate(new_core->output_fmt, info->samplerate); + media_format_set_audio_bit(new_core->output_fmt, info->bit); + media_format_set_audio_avg_bps(new_core->output_fmt, info->bitrate); + } + + } + else + { + mc_decoder_info_t *info; + + info = mc_handle->dec_info; + new_core->dec_info = mc_handle->dec_info; + if (new_core->video) + { + media_format_set_video_mime(new_core->output_fmt, mimetype); + media_format_set_video_width(new_core->output_fmt, info->width); + media_format_set_video_height(new_core->output_fmt, info->height); + } + else + { + media_format_set_audio_mime(new_core->output_fmt, mimetype); + media_format_set_audio_channel(new_core->output_fmt, info->channel); + media_format_set_audio_samplerate(new_core->output_fmt, info->samplerate); + media_format_set_audio_bit(new_core->output_fmt, info->bit); + } + + } + + LOGD("is_encoder (%d) is_video (%d)", new_core->encoder, new_core->video); + mc_handle->gst_core = new_core; + mc_gst_prepare(mc_handle->gst_core); + } + break; + + default: + break; + } + + 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; + } + + /* deinit core details */ + switch ( mc_handle->port_type ) + { + case MEDIACODEC_PORT_TYPE_GENERAL: + { + //ret = mc_general_deinit(mc_handle->gen_core); + } + break; + + case MEDIACODEC_PORT_TYPE_OMX: + { + //ret = mc_omx_deinit(mc_handle); + } + break; + + case MEDIACODEC_PORT_TYPE_GST: + { + ret = mc_gst_unprepare(mc_handle->gst_core); + + if(mc_handle->gst_core != NULL) + { + mc_gst_core_free(mc_handle->gst_core); + mc_handle->gst_core = NULL; + } + } + break; + + default: + break; + } + + 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; + + 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; + } + + if((buf_data == NULL) || (buf_size == 0)) + { + LOGE("invaild input buffer"); + return MC_INVALID_IN_BUF; + } + + 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->gst_core, inbuf, timeOutUs); + } + break; + + default: + break; + } + + 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; + } + + /* 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->gst_core, outbuf, timeOutUs); + } + break; + + default: + break; + } + + 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..77bedca --- /dev/null +++ b/src/media_codec_port_gst.c @@ -0,0 +1,1074 @@ +/* +* 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* +* Internal Implementation +*/ +static gpointer feed_task(gpointer data); +static media_packet_h get_input_buffer(mc_gst_core_t *core); + +static gboolean __mc_gst_init_gstreamer(mc_gst_core_t* core); +static mc_ret_e _mc_gst_create_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 void _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstCaps **caps); +static mc_gst_buffer* _mc_gst_media_packet_to_gstbuffer(mc_gst_core_t* core, GstCaps **caps, media_packet_h pkt, bool codec_config); +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_call(GstBus *bus, GstMessage *msg, gpointer data); +static SCMN_IMGB* __mc_gst_make_tbm_buffer(mc_gst_core_t* core, media_packet_h pkt); + +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* __mc_gst_buffer_new(mc_gst_core_t* core); +static void __mc_gst_buffer_finalize(mc_gst_buffer *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 GstBufferClass *mc_gst_buffer_parent_class = NULL; + +#define GST_TYPE_MC_BUFFER (__mc_gst_buffer_get_type()) + +/* + * mc_gst_core functions +*/ +mc_gst_core_t *mc_gst_core_new() // @ +{ + mc_gst_core_t *core; + + 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->output_queue = g_queue_new(); + + g_atomic_int_set(&core->available_queue->running, 1); + core->available_queue->thread = g_thread_create(feed_task, core, TRUE, NULL); // !!!! move to mc_gst_prepare() + core->dec_info = g_new0(mc_decoder_info_t, 1); + core->enc_info = g_new0(mc_encoder_info_t, 1); + + LOGD("mc_gst_core_new() is created"); + + return core; +} + +void mc_gst_core_free(mc_gst_core_t *core) // @ +{ + mc_aqueue_t *async_queue; + + async_queue = core->available_queue; + 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("g_thread_join"); + + mc_async_queue_free(async_queue->input); + 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); + core = NULL; + + LOGD("gst_core is freed"); + + return; +} + +/* + * mc_gst_port functions + */ +mc_gst_port_t *mc_gst_port_new(mc_gst_core_t *core) +{ + mc_gst_port_t *port; + + 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(); + port->queue = g_queue_new(); + port->buffer_cond = g_cond_new(); + + LOGD("gst_port is created"); + return port; +} + +void mc_gst_port_free(mc_gst_port_t *port) +{ + g_mutex_free(port->mutex); + g_queue_free(port->queue); + g_cond_free(port->buffer_cond); + + //destroy buffers + g_free(port); + LOGD("gst_port is freed"); + + return; +} + +static void _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstCaps **caps) +{ + guint format; + + format = __mc_get_gst_input_format(pkt, core->is_hw); + + if(!core->encoder && core->video) + { + *caps = gst_caps_new_simple ("video/x-h264", + "width", G_TYPE_INT, core->dec_info->width, + "height", G_TYPE_INT, core->dec_info->height, + "framerate", GST_TYPE_FRACTION, 30, 1, NULL); + } + else if (core->encoder && core->video && core->is_hw) + { + *caps = gst_caps_new_simple ("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, format, + "width", G_TYPE_INT, core->enc_info->frame_width, + "height", G_TYPE_INT, core->enc_info->frame_height, + "framerate", GST_TYPE_FRACTION, core->enc_info->fps, 1, NULL); + + g_object_set (GST_OBJECT(core->codec), "bitrate", core->enc_info->bitrate*1000, NULL); + } + else if (core->encoder && core->video && !core->is_hw) + { + *caps = gst_caps_new_simple ("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, format, + "width", G_TYPE_INT, core->enc_info->frame_width, + "height", G_TYPE_INT, core->enc_info->frame_height, + "framerate", GST_TYPE_FRACTION, core->enc_info->fps, 1, NULL); + + g_object_set (GST_OBJECT(core->codec), "bitrate", core->enc_info->bitrate*1000, NULL); + } + else if(!core->encoder && !core->video) + { + *caps = gst_caps_new_simple("audio/mpeg", + "mpegversion", G_TYPE_INT, 4, + "channels", G_TYPE_INT, 2, + "rate", G_TYPE_INT, 48000, + NULL); + } + else if(core->encoder && !core->video) + { + *caps = gst_caps_new_simple("audio/x-raw-int", + "signed", G_TYPE_BOOLEAN, TRUE, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "channels", G_TYPE_INT, 2, + "rate", G_TYPE_INT, 48000, NULL); + } +} + +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* buff = NULL; + GstCaps *new_caps = NULL; + bool initiative = true; + + while(g_atomic_int_get(&core->available_queue->running)) + { + in_buf = get_input_buffer(core); + + if(!in_buf) + goto EXIT; + + if(media_packet_is_codec_config(in_buf, &codec_config) != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_is_codec_config failed"); + goto EXIT; + } + + if(media_packet_is_end_of_stream(in_buf, &eos) != MEDIA_PACKET_ERROR_NONE) + { + LOGE("media_packet_is_end_of_stream failed"); + goto EXIT; + } + + if(codec_config) + initiative = true; + + if(initiative) + { + _mc_gst_update_caps(core, in_buf, &new_caps); + LOGD("caps updated"); + } + + buff = _mc_gst_media_packet_to_gstbuffer(core, &new_caps, in_buf, codec_config); + if (!buff) + { + LOGW("gstbuffer can't make"); + if (core->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR]) + { + ((mc_error_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR])(MC_INVALID_IN_BUF, core->user_data[_MEDIACODEC_EVENT_TYPE_ERROR]); + } + goto EXIT; + } + + /* inject buffer */ + ret = gst_app_src_push_buffer(GST_APP_SRC(core->appsrc), (GstBuffer*)buff); + if(ret != GST_FLOW_OK) + { + LOGE("Failed to push gst buffer"); + goto EXIT; + } + + if (eos) + { + g_signal_emit_by_name(core->appsrc, "end-of-stream", &ret); + } + initiative = false; + continue; + +EXIT: + LOGI("status : in_buf : %p, codec_config : %d, eos : %d in feed_task", in_buf, codec_config, eos); + } + if(new_caps) + { + gst_caps_unref(new_caps); + } + LOGD("feed task finished"); + return NULL; +} + +media_packet_h 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_gst_core_t *core) +{ + int ret = MC_ERROR_NONE; + + if (!core) + return MC_PARAM_ERROR; + + /* create basic core elements */ + ret = _mc_gst_create_pipeline(core); + + LOGD("initialized..."); + return ret; +} + +mc_ret_e mc_gst_unprepare(mc_gst_core_t *core) +{ + int ret = MC_ERROR_NONE; + + if (!core) + return ret; + + 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); + } + + if(core->bus_whatch_id) + g_source_remove(core->bus_whatch_id); + + MEDIACODEC_ELEMENT_SET_STATE(core->pipeline, GST_STATE_NULL); + + gst_object_unref(GST_OBJECT(core->pipeline)); + } + return ret; + +STATE_CHANGE_FAILED: + if(core->pipeline) + gst_object_unref(GST_OBJECT(core->pipeline)); + + return MC_ERROR; +} + +mc_ret_e mc_gst_process_input(mc_gst_core_t *core, media_packet_h inbuf, uint64_t timeOutUs) +{ + int ret = MC_ERROR_NONE; + + mc_async_queue_push(core->available_queue->input, inbuf); + + return ret; +} + +mc_ret_e mc_gst_get_output(mc_gst_core_t *core, media_packet_h *outbuf, uint64_t timeOutUs) +{ + int ret = MC_ERROR_NONE; + media_packet_h out_pkt = NULL; + + g_mutex_lock(core->ports[1]->mutex); + + if(!g_queue_is_empty(core->output_queue)) + { + out_pkt = g_queue_pop_head(core->output_queue); + LOGD("pop from output_queue : %p", core->output_queue); + } + else + { + ret = MC_OUTPUT_BUFFER_EMPTY; + LOGD("output_queue is empty"); + } + *outbuf = out_pkt; + LOGD("output buf : %p", *outbuf); + + g_mutex_unlock(core->ports[1]->mutex); + + return ret; +} + +static gboolean __mc_gst_init_gstreamer(mc_gst_core_t* core) +{ +#if 1 + 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; + + 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 ) + 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; + + 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 ); +#endif + return FALSE; +} + +mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t* core) +{ + GstBus *bus = NULL; + + if (!__mc_gst_init_gstreamer(core)) + { + LOGE ("gstreamer initialize fail"); + return MC_NOT_INITIALIZED; + } + core->codec = gst_element_factory_make(core->factory_name, NULL); + + if(!core->codec) + { + LOGE ("codec element create fail"); + goto ERROR; + } + + 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; + } + + /* add elements */ + 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); + g_object_set (GST_OBJECT(core->codec), "byte-stream", TRUE, 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_call, core); + gst_object_unref (bus); + + /* 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); + + /* set state PLAYING */ + MEDIACODEC_ELEMENT_SET_STATE(GST_ELEMENT_CAST(core->pipeline), GST_STATE_PLAYING); + + 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->converter) + gst_object_unref(GST_OBJECT(core->converter)); + + if(core->fakesink) + gst_object_unref(GST_OBJECT(core->fakesink)); + + 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; + + out_pkt = __mc_gst_gstbuffer_to_media_packet(core, buffer); + + /* push it to output buffer queue */ + g_queue_push_tail(core->output_queue, out_pkt); + + 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]); + } +} + +int __mc_output_buffer_finalize_cb(media_packet_h packet, int error_code, void *user_data) +{ + //GstBuffer* buffer = NULL; + void* buffer = NULL; + media_packet_get_extra(packet, &buffer); + LOGD("!!!! finalized_gst_buffer = %p", buffer); + gst_buffer_unref((GstBuffer*)buffer); + + 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* _mc_gst_media_packet_to_gstbuffer(mc_gst_core_t* core, GstCaps **caps, media_packet_h pkt, bool codec_config) +{ + mc_gst_buffer* buff = NULL; + void* buf_data = NULL; + uint64_t buf_size = 0; + uint64_t pts = 0, dur = 0; + int ret = MEDIA_PACKET_ERROR_NONE; + + /* copy media_packet to new gstbuffer */ + ret = media_packet_get_buffer_size(pkt, &buf_size); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGW("buffer size get fail"); + } + + ret = media_packet_get_buffer_data_ptr(pkt, &buf_data); + if (ret != MEDIA_PACKET_ERROR_NONE) + { + LOGW("buffer size get fail"); + return NULL; + } + + if (core->encoder && core->video && core->is_hw) + { + SCMN_IMGB *imgb = NULL; + buff = __mc_gst_buffer_new(core); + buff->pkt = pkt; + GST_BUFFER_DATA(buff) = buf_data; + GST_BUFFER_SIZE (buff) = buf_size; + imgb = __mc_gst_make_tbm_buffer(core, pkt); + + if (!imgb) + { + LOGE("get imgb failed"); + return NULL; + } + GST_BUFFER_MALLOCDATA(buff) = (guint8 *)imgb; + } + else + { + buff = __mc_gst_buffer_new (core); + buff->pkt = pkt; + GST_BUFFER_DATA(buff) = buf_data; + GST_BUFFER_SIZE (buff) = buf_size; + } + + /* pts */ + media_packet_get_pts(pkt, &pts); + GST_BUFFER_TIMESTAMP(buff) = (GstClockTime) pts; + LOGD("input pts = %llu, GST_BUFFER_TIMESTAMP = %" GST_TIME_FORMAT, pts, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buff))); + + /* 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* buffer) +{ + media_packet_h out_pkt = NULL; + media_format_h out_fmt = NULL; + void* pkt_data = NULL; + + if (!buffer) + return NULL; + + out_fmt = core->output_fmt; + + if (!core->encoder && core->video && core->is_hw) + { + int i = 0;; + int bo_num = 0; + + SCMN_IMGB *psimgb = NULL; + tbm_surface_h tsurf = NULL; + psimgb = (SCMN_IMGB*)GST_BUFFER_MALLOCDATA(buffer); + /* create tbm surface */ + for (i = 0; i < SCMN_IMGB_MAX_PLANE; i++) + { + if (psimgb->bo[i]) + { + bo_num++; + } + } + + if (bo_num > 0) + { + tsurf = tbm_surface_internal_create_with_bos(core->dec_info->width, core->dec_info->height, TBM_FORMAT_NV12, (tbm_bo *)psimgb->bo, bo_num); + LOGD("tbm surface %p", tsurf); + } + + if (tsurf) + { + media_packet_create_from_tbm_surface(out_fmt, tsurf, (media_packet_finalize_cb)__mc_output_buffer_finalize_cb, core, &out_pkt); + LOGD("!!!! create_gst_buffer = %p", out_pkt); + media_packet_set_extra(out_pkt, buffer); + media_packet_set_buffer_size(out_pkt, GST_BUFFER_SIZE(buffer)); + media_packet_set_pts(out_pkt, GST_BUFFER_TIMESTAMP(buffer)); + } + } + else + { + /* create media_packet with given gstbuffer */ + media_packet_create_alloc(out_fmt, __mc_output_buffer_finalize_cb, core, &out_pkt); + media_packet_set_extra(out_pkt, buffer); + LOGD("!!!! create_gst_buffer = %p", buffer); + + // !!!! this time do memcpy because no way to set data ptr to media packet. + media_packet_set_buffer_size(out_pkt, GST_BUFFER_SIZE(buffer)); + media_packet_get_buffer_data_ptr(out_pkt, &pkt_data); + memcpy(pkt_data, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); + media_packet_set_pts(out_pkt, GST_BUFFER_TIMESTAMP(buffer)); + } + gst_buffer_ref(buffer); + return out_pkt; +} + +gboolean __mc_gst_bus_call (GstBus *bus, GstMessage *msg, gpointer data) +{ + int ret = MC_ERROR_NONE; + mc_gst_core_t *core = (mc_gst_core_t*)data; + + switch (GST_MESSAGE_TYPE (msg)) { + + case GST_MESSAGE_EOS: + { + 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]); + } + //gst_object_unref(msg); + + return TRUE; +} + +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; + + 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); + + /*psimgb->a[0] point to vitual address of output buffer*/ + psimgb->buf_share_method = BUF_SHARE_METHOD_TIZEN_BUFFER; + psimgb->bo[0] = bo; + psimgb->a[0] = handle.ptr; + psimgb->w[0] = core->enc_info->frame_width; + psimgb->h[0] = core->enc_info->frame_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), + 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* __mc_gst_buffer_new(mc_gst_core_t* core) +{ + mc_gst_buffer *ret = NULL; + ret = (mc_gst_buffer *)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 *buffer) +{ + mc_gst_core_t *core = buffer->core; + SCMN_IMGB *imgb = NULL; + + if (GST_BUFFER_MALLOCDATA(buffer)) + { + imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buffer); + if (imgb) + { + free(imgb); + imgb = NULL; + GST_BUFFER_MALLOCDATA(buffer) = NULL; + } + } + + GST_BUFFER_DATA(buffer) = NULL; + + 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); + } + + 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)); + } + + 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, MEDIACODEC_ERROR_NOT_INITIALIZED); + + 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, MEDIACODEC_ERROR_NOT_INITIALIZED); + + 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, MEDIACODEC_ERROR_NOT_INITIALIZED); + + 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, MEDIACODEC_ERROR_NOT_INITIALIZED); + g_return_val_if_fail(error, MEDIACODEC_ERROR_INVALID_PARAMETER); + g_return_val_if_fail (message, MEDIACODEC_ERROR_INVALID_PARAMETER); + + 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; +} diff --git a/src/media_codec_queue.c b/src/media_codec_queue.c new file mode 100644 index 0000000..8c11c26 --- /dev/null +++ b/src/media_codec_queue.c @@ -0,0 +1,102 @@ +#include + +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 (); + async_queue->mutex = g_mutex_new (); + async_queue->enabled = TRUE; + + return async_queue; +} + +void mc_async_queue_free (async_queue_t * async_queue) +{ + g_cond_free (async_queue->condition); + g_mutex_free (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; +} + +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 100644 index 0000000..4c1b8ee --- /dev/null +++ b/src/media_codec_util.c @@ -0,0 +1,33 @@ +#include + +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); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..9b5dc2a --- /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}") + +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..6bf4dec --- /dev/null +++ b/test/media_codec_test.c @@ -0,0 +1,1276 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include // !!!! remove it +#include // !!!! remove it + +//#include +//#include +//#include +//#include +//#include + +#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; + +GThread *pa_thread; +gint pa_running = 0; +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) + { + exit(1); + } + 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) + { + exit(1); + } + 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> 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; +} + +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_to_packet(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"); + + g_atomic_int_set(&pa_running, 0); + g_thread_join(pa_thread); + + 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_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 + { + mimetype |= MEDIA_FORMAT_AAC; + } + 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; +} + + + +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; + 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 == 1258) + ret = media_packet_set_flags(in_buf, MEDIA_PACKET_END_OF_STREAM); + + buf_size = bytestream2nalunit(fp_src, data); + } + else + buf_size = extract_input_aacdec(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); + 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 = %lld\n",__func__, buf_size); +#if DUMP_OUTBUF + media_packet_get_buffer_data_ptr(output_buf, &data); + if ((!use_video) && (use_encoder)) + { + if (buf_size > 0) + { + add_adts_to_packet(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; +} + +int _mediacodec_pa_runcheck(void) +{ + return pa_running; +} + +static gpointer _feed_pa(gpointer data) +{ + int ret = 0; + + while (1) //FIXME crash g_atomic_int_get(&pa_running) + { + if (!_mediacodec_pa_runcheck()) + break; + ret = _mediacodec_process_input(); + if (ret == MEDIACODEC_ERROR_INVALID_PARAMETER) + break; +// ret = _mediacodec_get_output(); + usleep(100); + } +/* + while (1) //FIXME crash g_atomic_int_get(&pa_running) + { + if (!_mediacodec_pa_runcheck()) + break; + ret = _mediacodec_get_output(); + usleep(100); + } +*/ + g_print("_feed_pa task finished\n"); + return NULL; +} + +void _mediacodec_process_all(void) +{ + g_print("_mediacodec_process_all\n"); + pa_running = 1; + pa_thread = g_thread_create(_feed_pa, GINT_TO_POINTER(1), TRUE, NULL); + 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, falgs.\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 -- cgit v1.2.3