Initialize the code with P4 INT CL9254461 42/261242/8 tizen_tv_devel
authorchuanji.tang <chuanji.tang@samsung.com>
Wed, 14 Jul 2021 00:59:04 +0000 (08:59 +0800)
committerchuanji.tang <chuanji.tang@samsung.com>
Thu, 15 Jul 2021 08:51:46 +0000 (16:51 +0800)
Change-Id: I11d6c1454f8c7596844028e062adb5cdbe70becf

196 files changed:
AUTHORS [new file with mode: 0755]
CMakeLists.txt [new file with mode: 0755]
LICENSE.APLv2 [new file with mode: 0755]
README.md [new file with mode: 0755]
build.sh [new file with mode: 0755]
capi-trackrenderer-tv.pc.in [new file with mode: 0755]
docs/class_diagram/adapter/bms_avplayer_player_adapter(1).plantuml [new file with mode: 0755]
docs/class_diagram/adapter/bms_avplayer_player_adapter(1).png [new file with mode: 0755]
docs/class_diagram/adapter/bms_avplayer_player_adapter(2).plantuml [new file with mode: 0755]
docs/class_diagram/adapter/bms_avplayer_player_adapter(2).png [new file with mode: 0755]
docs/class_diagram/adapter/trackrenderer_adapter.plantuml [new file with mode: 0755]
docs/class_diagram/adapter/webapi_avplay_player_adapter.plantuml [new file with mode: 0755]
docs/class_diagram/adapter/webapi_avplay_player_adapter.png [new file with mode: 0755]
docs/class_diagram/adapter/webmedia_mse_eme.plantuml [new file with mode: 0755]
docs/class_diagram/bmservice_drmmanager_plusplayer.plantuml [new file with mode: 0755]
docs/class_diagram/details/defaultplayer.plantuml [new file with mode: 0755]
docs/class_diagram/details/trackrenderer.plantuml [new file with mode: 0755]
docs/class_diagram/details/tracksource_compositor.plantuml [new file with mode: 0755]
docs/class_diagram/esplusplayer.plantuml [new file with mode: 0755]
docs/class_diagram/plusplayer.plantuml [new file with mode: 0755]
docs/class_diagram/plusplayer.png [new file with mode: 0755]
docs/class_diagram/plusplayer_simple.plantuml [new file with mode: 0755]
docs/coding_rule.md [new file with mode: 0755]
docs/dot_graph/plusplayer_renderer_start.png [new file with mode: 0755]
docs/dot_graph/plusplayer_renderer_stop.png [new file with mode: 0755]
docs/dot_graph/plusplayer_src_start.png [new file with mode: 0755]
docs/dot_graph/plusplayer_src_stop.png [new file with mode: 0755]
docs/downloadable/class_diagram.plantuml [new file with mode: 0755]
docs/downloadable/version_control.plantuml [new file with mode: 0755]
docs/downloadable/version_control_sequence.plantuml [new file with mode: 0755]
docs/gtest_guide.md [new file with mode: 0755]
docs/module_view/libav-common.plantuml [new file with mode: 0755]
docs/module_view/uses_view.plantuml [new file with mode: 0755]
docs/module_view/uses_view.png [new file with mode: 0755]
docs/plusplayer_guide.md [new file with mode: 0755]
docs/reference/PlantUML_Language_Reference_Guide.pdf [new file with mode: 0755]
docs/sequence_activity_diagram/avplusplayer_adapter/avplusplayer_adapter_sequence_diagram.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/dash_drm_playback/dash_drm_playback_base_flow_1.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/source_change/source_change_base_flow_1.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/trackrenderer_adapter/trackrenderer_adapter.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tracksource/tracksource_alternative_flow_1.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tracksource/tracksource_base_flow_1.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_1.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_2.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_3.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tvplus_update_activity_diagram/risk_management_lib_api_validation.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tvplus_update_activity_diagram/update_procedure.plantuml [new file with mode: 0755]
docs/sequence_activity_diagram/tvplusplusplayerhelper/tvplusplusplayerhelper_sequence_diagram.plantuml [new file with mode: 0755]
docs/state_diagram/plusplayer_internal_state_diagram.png [new file with mode: 0755]
docs/state_diagram/state_diagram.plantuml [new file with mode: 0755]
docs/state_diagram/state_diagram_v2_substatemachine.plantuml [new file with mode: 0755]
include/trackrenderer_capi/buffer.h [new file with mode: 0755]
include/trackrenderer_capi/decoderinputbuffer.h [new file with mode: 0755]
include/trackrenderer_capi/display.h [new file with mode: 0755]
include/trackrenderer_capi/drm.h [new file with mode: 0755]
include/trackrenderer_capi/error.h [new file with mode: 0755]
include/trackrenderer_capi/event.h [new file with mode: 0755]
include/trackrenderer_capi/iniproperty.h [new file with mode: 0755]
include/trackrenderer_capi/latency.h [new file with mode: 0755]
include/trackrenderer_capi/state.h [new file with mode: 0755]
include/trackrenderer_capi/submitstatus.h [new file with mode: 0755]
include/trackrenderer_capi/track.h [new file with mode: 0755]
include/trackrenderer_capi/track_capi.h [new file with mode: 0755]
include/trackrenderer_capi/trackrenderer_capi.h [new file with mode: 0755]
include/trackrenderer_capi/trackrenderer_internal.h [new file with mode: 0755]
out/docs/class_diagram/adapter/bms_avplayer_player_adapter(1)/bms_avplayer_player_adapter(1).png [new file with mode: 0755]
out/docs/class_diagram/adapter/bms_avplayer_player_adapter(2)/bms_avplayer_player_adapter(2).png [new file with mode: 0755]
out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 1.png [new file with mode: 0755]
out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 2.png [new file with mode: 0755]
out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter.png [new file with mode: 0755]
out/docs/class_diagram/bmservice_drmmanager_plusplayer/bmservice_drmmanager_plusplayer.png [new file with mode: 0755]
out/docs/class_diagram/details/defaultplayer/DefaultPlayer.png [new file with mode: 0755]
out/docs/class_diagram/details/trackrenderer/TrackRenderer.png [new file with mode: 0755]
out/docs/class_diagram/details/tracksource_compositor/TrackSource & Compositor.png [new file with mode: 0755]
out/docs/class_diagram/esplusplayer/esplusplayer.png [new file with mode: 0755]
out/docs/class_diagram/plusplayer/plusplayer.png [new file with mode: 0755]
out/docs/class_diagram/plusplayer_simple/plusplayer_simple.png [new file with mode: 0755]
out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 1.png [new file with mode: 0755]
out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 2.png [new file with mode: 0755]
out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 1.png [new file with mode: 0755]
out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 2.png [new file with mode: 0755]
out/docs/module_view/libav-common/reduced downloadable module size by libav-common dash hls http streaming module.png [new file with mode: 0755]
out/docs/module_view/uses_view/module view uses view.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/source_change/source_change_base_flow_1/source_change_base_flow_1.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/tracksource/tracksource_alternative_flow_1/tracksource_alternative_flow_1.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/tracksource/tracksource_base_flow_1/tracksource_base_flow_1.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_1/tracksource_exception_flow_1.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_2/tracksource_exception_flow_2.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_3/tracksource_exception_flow_3.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/risk_management_lib_api_validation/risk_management_lib_api_validation.png [new file with mode: 0755]
out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/update_procedure/TVPlus Player update process.png [new file with mode: 0755]
out/docs/state_diagram/state_diagram/plusplayer_internal_state_diagram.png [new file with mode: 0755]
out/docs/state_diagram/state_diagram_v2_substatemachine/plusplayer_internal_state_diagram.png [new file with mode: 0755]
packaging/capi-trackrenderer-tv.manifest [new file with mode: 0755]
packaging/capi-trackrenderer-tv.spec [new file with mode: 0755]
src/CMakeLists.txt [new file with mode: 0755]
src/audio_easing_controller.cpp [new file with mode: 0755]
src/caps_recipes.cpp [new file with mode: 0755]
src/decoderinputbuffer.cpp [new file with mode: 0755]
src/display.cpp [new file with mode: 0755]
src/error.cpp [new file with mode: 0755]
src/gst_utils.cpp [new file with mode: 0755]
src/gstcaps_builder.cpp [new file with mode: 0755]
src/gstobject_guard.cpp [new file with mode: 0755]
src/gstsignal_holder.cpp [new file with mode: 0755]
src/include_internal/trackrenderer/audio_controller/audio_easing_controller.h [new file with mode: 0755]
src/include_internal/trackrenderer/audio_controller/resyncaudio/default_policy.hpp [new file with mode: 0755]
src/include_internal/trackrenderer/audio_controller/resyncaudio/dummy_policy.hpp [new file with mode: 0755]
src/include_internal/trackrenderer/audio_controller/resyncaudio/policies.h [new file with mode: 0755]
src/include_internal/trackrenderer/audio_controller/resyncaudio/swdecoder_policy.hpp [new file with mode: 0755]
src/include_internal/trackrenderer/audio_controller/resyncaudio_policy.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/appinfo.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/attribute.hpp [new file with mode: 0755]
src/include_internal/trackrenderer/core/audioeasinginfo.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/buffer.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/caps_recipes.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/decoderinputbuffer.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/display.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/drm.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/elements.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/error.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/event.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/gst_utils.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/gstcaps_builder.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/gstobject_guard.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/gstsignal_holder.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/latency.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/picturequality.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/pipeline.hpp [new file with mode: 0755]
src/include_internal/trackrenderer/core/screen_saver.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/stream.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/subtitle_attr.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/track.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/track_util.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/utils/log.h [new file with mode: 0755]
src/include_internal/trackrenderer/core/utils/product_cfg.h [new file with mode: 0755]
src/include_internal/trackrenderer/display.h [new file with mode: 0755]
src/include_internal/trackrenderer/error.h [new file with mode: 0755]
src/include_internal/trackrenderer/latency_manager.h [new file with mode: 0755]
src/include_internal/trackrenderer/latency_status_listener.h [new file with mode: 0755]
src/include_internal/trackrenderer/resource.h [new file with mode: 0755]
src/include_internal/trackrenderer/resource_conflict_listener.h [new file with mode: 0755]
src/include_internal/trackrenderer/resourcemanager.h [new file with mode: 0755]
src/include_internal/trackrenderer/subtitle_attr_parser.h [new file with mode: 0755]
src/include_internal/trackrenderer/trackrenderer.h [new file with mode: 0755]
src/include_internal/trackrenderer/trackrenderer_attr.h [new file with mode: 0755]
src/include_internal/trackrenderer/trackrenderer_capi_utils.h [new file with mode: 0755]
src/include_internal/trackrenderer/trackrenderer_debug.h [new file with mode: 0755]
src/include_internal/trackrenderer/trackrenderer_vconf.h [new file with mode: 0755]
src/include_internal/trackrenderer/version.h [new file with mode: 0755]
src/include_internal/trackrenderer/vr360.h [new file with mode: 0755]
src/latency_manager.cpp [new file with mode: 0755]
src/pipeline.cpp [new file with mode: 0755]
src/resourcemanager.cpp [new file with mode: 0755]
src/screen_saver.cpp [new file with mode: 0755]
src/subtitle_attr_parser.cpp [new file with mode: 0755]
src/track_capi.cpp [new file with mode: 0755]
src/track_util.cpp [new file with mode: 0755]
src/trackrenderer.cpp [new file with mode: 0755]
src/trackrenderer_attr.cpp [new file with mode: 0755]
src/trackrenderer_capi.cpp [new file with mode: 0755]
src/trackrenderer_capi_utils.cpp [new file with mode: 0755]
src/trackrenderer_debug.cpp [new file with mode: 0755]
src/trackrenderer_vconf.cpp [new file with mode: 0755]
src/vr360.cpp [new file with mode: 0755]
tomato/tc/TCList.dat [new file with mode: 0755]
tomato/tc/TCList_test_1.dat [new file with mode: 0755]
tomato/tc/TCList_test_2.dat [new file with mode: 0755]
tomato/tc/TCList_test_3.dat [new file with mode: 0755]
tomato/tc/TCList_test_4.dat [new file with mode: 0755]
tomato/tc/TCList_test_5.dat [new file with mode: 0755]
tomato/tc/TCList_test_6.dat [new file with mode: 0755]
tomato/tc/TCList_test_7.dat [new file with mode: 0755]
tomato/tc/testfarm_script.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_1.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_2.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_3.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_4.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_5.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_6.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_7.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_plusplayer_all.xml [new file with mode: 0755]
ut/CMakeLists.txt [new file with mode: 0755]
ut/README.md [new file with mode: 0755]
ut/cpplint.py [new file with mode: 0755]
ut/include/appwindow.h [new file with mode: 0755]
ut/include/esplusplayer/eseventlistener.hpp [new file with mode: 0755]
ut/include/esplusplayer/esreader.hpp [new file with mode: 0755]
ut/include/plusplayer/tclist.h [new file with mode: 0755]
ut/include/plusplayer/utility.h [new file with mode: 0755]
ut/include/streamreader.hpp [new file with mode: 0755]
ut/src/tclist.cpp [new file with mode: 0755]
ut/src/ut_main.cpp [new file with mode: 0755]
ut/src/ut_trackrenderer.cpp [new file with mode: 0755]
ut/src/ut_trackrenderer2.cpp [new file with mode: 0755]
ut/src/ut_trackrenderer_capi.cpp [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
new file mode 100755 (executable)
index 0000000..d3f5a12
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+\r
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f3f1f9b
--- /dev/null
@@ -0,0 +1,60 @@
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+
+PROJECT(capi-trackrenderer-tv)
+SET(description "new multimedia player, object-oriented model")
+SET(PC_NAME "capi-trackrenderer-tv")
+SET(PC_LDFLAGS "-ltrackrenderer")
+
+SET(INC_DIR ${PROJECT_SOURCE_DIR}/include/)
+INCLUDE_DIRECTORIES(${INC_DIR})
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+CONFIGURE_FILE(capi-trackrenderer-tv.pc.in
+  capi-trackrenderer-tv.pc
+  @ONLY
+)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/capi-trackrenderer-tv.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+
+ADD_SUBDIRECTORY(src)
+
+OPTION(TRACKRENDERER_BUILD_UT "Build capi-trackrenderer-tv ut codes" OFF)
+IF(TRACKRENDERER_BUILD_UT)
+ADD_SUBDIRECTORY(ut)
+ENDIF(TRACKRENDERER_BUILD_UT)
+
+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)
+
+MESSAGE( STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR} )
+MESSAGE( STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR} )
+MESSAGE( STATUS "LIB_INSTALL_DIR: " ${LIB_INSTALL_DIR} )
+MESSAGE( STATUS "INC_DIR: " ${INC_DIR} )
diff --git a/LICENSE.APLv2 b/LICENSE.APLv2
new file mode 100755 (executable)
index 0000000..9c13a9b
--- /dev/null
@@ -0,0 +1,204 @@
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+\r
+                                 Apache License\r
+                           Version 2.0, January 2004\r
+                        http://www.apache.org/licenses/\r
+\r
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+   1. Definitions.\r
+\r
+      "License" shall mean the terms and conditions for use, reproduction,\r
+      and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+      "Licensor" shall mean the copyright owner or entity authorized by\r
+      the copyright owner that is granting the License.\r
+\r
+      "Legal Entity" shall mean the union of the acting entity and all\r
+      other entities that control, are controlled by, or are under common\r
+      control with that entity. For the purposes of this definition,\r
+      "control" means (i) the power, direct or indirect, to cause the\r
+      direction or management of such entity, whether by contract or\r
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+      outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+      "You" (or "Your") shall mean an individual or Legal Entity\r
+      exercising permissions granted by this License.\r
+\r
+      "Source" form shall mean the preferred form for making modifications,\r
+      including but not limited to software source code, documentation\r
+      source, and configuration files.\r
+\r
+      "Object" form shall mean any form resulting from mechanical\r
+      transformation or translation of a Source form, including but\r
+      not limited to compiled object code, generated documentation,\r
+      and conversions to other media types.\r
+\r
+      "Work" shall mean the work of authorship, whether in Source or\r
+      Object form, made available under the License, as indicated by a\r
+      copyright notice that is included in or attached to the work\r
+      (an example is provided in the Appendix below).\r
+\r
+      "Derivative Works" shall mean any work, whether in Source or Object\r
+      form, that is based on (or derived from) the Work and for which the\r
+      editorial revisions, annotations, elaborations, or other modifications\r
+      represent, as a whole, an original work of authorship. For the purposes\r
+      of this License, Derivative Works shall not include works that remain\r
+      separable from, or merely link (or bind by name) to the interfaces of,\r
+      the Work and Derivative Works thereof.\r
+\r
+      "Contribution" shall mean any work of authorship, including\r
+      the original version of the Work and any modifications or additions\r
+      to that Work or Derivative Works thereof, that is intentionally\r
+      submitted to Licensor for inclusion in the Work by the copyright owner\r
+      or by an individual or Legal Entity authorized to submit on behalf of\r
+      the copyright owner. For the purposes of this definition, "submitted"\r
+      means any form of electronic, verbal, or written communication sent\r
+      to the Licensor or its representatives, including but not limited to\r
+      communication on electronic mailing lists, source code control systems,\r
+      and issue tracking systems that are managed by, or on behalf of, the\r
+      Licensor for the purpose of discussing and improving the Work, but\r
+      excluding communication that is conspicuously marked or otherwise\r
+      designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+      "Contributor" shall mean Licensor and any individual or Legal Entity\r
+      on behalf of whom a Contribution has been received by Licensor and\r
+      subsequently incorporated within the Work.\r
+\r
+   2. Grant of Copyright License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      copyright license to reproduce, prepare Derivative Works of,\r
+      publicly display, publicly perform, sublicense, and distribute the\r
+      Work and such Derivative Works in Source or Object form.\r
+\r
+   3. Grant of Patent License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      (except as stated in this section) patent license to make, have made,\r
+      use, offer to sell, sell, import, and otherwise transfer the Work,\r
+      where such license applies only to those patent claims licensable\r
+      by such Contributor that are necessarily infringed by their\r
+      Contribution(s) alone or by combination of their Contribution(s)\r
+      with the Work to which such Contribution(s) was submitted. If You\r
+      institute patent litigation against any entity (including a\r
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+      or a Contribution incorporated within the Work constitutes direct\r
+      or contributory patent infringement, then any patent licenses\r
+      granted to You under this License for that Work shall terminate\r
+      as of the date such litigation is filed.\r
+\r
+   4. Redistribution. You may reproduce and distribute copies of the\r
+      Work or Derivative Works thereof in any medium, with or without\r
+      modifications, and in Source or Object form, provided that You\r
+      meet the following conditions:\r
+\r
+      (a) You must give any other recipients of the Work or\r
+          Derivative Works a copy of this License; and\r
+\r
+      (b) You must cause any modified files to carry prominent notices\r
+          stating that You changed the files; and\r
+\r
+      (c) You must retain, in the Source form of any Derivative Works\r
+          that You distribute, all copyright, patent, trademark, and\r
+          attribution notices from the Source form of the Work,\r
+          excluding those notices that do not pertain to any part of\r
+          the Derivative Works; and\r
+\r
+      (d) If the Work includes a "NOTICE" text file as part of its\r
+          distribution, then any Derivative Works that You distribute must\r
+          include a readable copy of the attribution notices contained\r
+          within such NOTICE file, excluding those notices that do not\r
+          pertain to any part of the Derivative Works, in at least one\r
+          of the following places: within a NOTICE text file distributed\r
+          as part of the Derivative Works; within the Source form or\r
+          documentation, if provided along with the Derivative Works; or,\r
+          within a display generated by the Derivative Works, if and\r
+          wherever such third-party notices normally appear. The contents\r
+          of the NOTICE file are for informational purposes only and\r
+          do not modify the License. You may add Your own attribution\r
+          notices within Derivative Works that You distribute, alongside\r
+          or as an addendum to the NOTICE text from the Work, provided\r
+          that such additional attribution notices cannot be construed\r
+          as modifying the License.\r
+\r
+      You may add Your own copyright statement to Your modifications and\r
+      may provide additional or different license terms and conditions\r
+      for use, reproduction, or distribution of Your modifications, or\r
+      for any such Derivative Works as a whole, provided Your use,\r
+      reproduction, and distribution of the Work otherwise complies with\r
+      the conditions stated in this License.\r
+\r
+   5. Submission of Contributions. Unless You explicitly state otherwise,\r
+      any Contribution intentionally submitted for inclusion in the Work\r
+      by You to the Licensor shall be under the terms and conditions of\r
+      this License, without any additional terms or conditions.\r
+      Notwithstanding the above, nothing herein shall supersede or modify\r
+      the terms of any separate license agreement you may have executed\r
+      with Licensor regarding such Contributions.\r
+\r
+   6. Trademarks. This License does not grant permission to use the trade\r
+      names, trademarks, service marks, or product names of the Licensor,\r
+      except as required for reasonable and customary use in describing the\r
+      origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+   7. Disclaimer of Warranty. Unless required by applicable law or\r
+      agreed to in writing, Licensor provides the Work (and each\r
+      Contributor provides its Contributions) on an "AS IS" BASIS,\r
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+      implied, including, without limitation, any warranties or conditions\r
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+      PARTICULAR PURPOSE. You are solely responsible for determining the\r
+      appropriateness of using or redistributing the Work and assume any\r
+      risks associated with Your exercise of permissions under this License.\r
+\r
+   8. Limitation of Liability. In no event and under no legal theory,\r
+      whether in tort (including negligence), contract, or otherwise,\r
+      unless required by applicable law (such as deliberate and grossly\r
+      negligent acts) or agreed to in writing, shall any Contributor be\r
+      liable to You for damages, including any direct, indirect, special,\r
+      incidental, or consequential damages of any character arising as a\r
+      result of this License or out of the use or inability to use the\r
+      Work (including but not limited to damages for loss of goodwill,\r
+      work stoppage, computer failure or malfunction, or any and all\r
+      other commercial damages or losses), even if such Contributor\r
+      has been advised of the possibility of such damages.\r
+\r
+   9. Accepting Warranty or Additional Liability. While redistributing\r
+      the Work or Derivative Works thereof, You may choose to offer,\r
+      and charge a fee for, acceptance of support, warranty, indemnity,\r
+      or other liability obligations and/or rights consistent with this\r
+      License. However, in accepting such obligations, You may act only\r
+      on Your own behalf and on Your sole responsibility, not on behalf\r
+      of any other Contributor, and only if You agree to indemnify,\r
+      defend, and hold each Contributor harmless for any liability\r
+      incurred by, or claims asserted against, such Contributor by reason\r
+      of your accepting any such warranty or additional liability.\r
+\r
+   END OF TERMS AND CONDITIONS\r
+\r
+   APPENDIX: How to apply the Apache License to your work.\r
+\r
+      To apply the Apache License to your work, attach the following\r
+      boilerplate notice, with the fields enclosed by brackets "[]"\r
+      replaced with your own identifying information. (Don't include\r
+      the brackets!)  The text should be enclosed in the appropriate\r
+      comment syntax for the file format. We also recommend that a\r
+      file or class name and description of purpose be included on the\r
+      same "printed page" as the copyright notice for easier\r
+      identification within third-party archives.\r
+\r
+   Copyright [yyyy] [name of copyright owner]\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
diff --git a/README.md b/README.md
new file mode 100755 (executable)
index 0000000..604ee64
--- /dev/null
+++ b/README.md
@@ -0,0 +1,76 @@
+#* * PlusPlayer * * #\r
+  PlusPlayer is a new multimedia player object-oriented designed.\r
+\r
+## Notice\r
+  * 18_Plusplayer\r
+    - Confluence\r
+    - SW High Level Design doc.\r
+\r
+## Goals ##\r
+  * Improve maintainability / extensibility / reusability\r
+    - object oriented design\r
+    - separate the modules into high-variation part and low-variation part\r
+    - decoupling between each streaming services\r
+  * Simplification\r
+    - simplified pipeline , creates static pipeline\r
+  * Easy to upgrade\r
+    - support downloadable features (planned)\r
+\r
+## Architecture Design ##\r
+  * PlusPlayer consists of TypeFinder / TrackSource / TrackRenderer / DefaultPlayer objects.\r
+    * TypeFinder\r
+      - Probing source type by inspecting probing data\r
+      - use gstreamer typefinder plugin\r
+    * TrackSource\r
+      - Fetching data from server , demuxing , controling demuxed packet buffers\r
+      - a pipeline consists of `src - typefinder - demuxer - multiqueue - inputselector - fakesink`\r
+        - plz refer to `${plusplayer_workspace}/docs/dot/plusplayer_src_start.png`\r
+    * TrackRenderer\r
+      - maintains a pipeline consists of `appsrc - omx - sink` elements\r
+        - plz refer to `${plusplayer_workspace}/docs/dot/plusplayer_renderer_start.png`\r
+  * Class diagram\r
+    * ${plusplayer_workspace}/docs/class_diagram.plantuml\r
+    * or you can directly download it from [class_diagram.plantuml]\r
+\r
+## Development ##\r
+  * GitHub Project :\r
+    * All the milestones / activities (Codes , CodeReview , Design , Issues , etc) are being uploaded here\r
+  * Codereview on Github\r
+    - Each Developers should fork master branch and work on their own forked project.\r
+    - developer should submit pull-request to apply their changes\r
+      * all developers must sync their forked project with the latest master prior to sumit pull-request. so that we can avoid merge conflicts.\r
+    - everyone can join the codereviews\r
+  * the coding style follows Google C++ coding style guide. refer to [CODING STYLE](### coding-style)\r
+  * Test Driven Development (use gtest - plusplayer_ut -for their implementation and verifications)\r
+\r
+#### GTest guide ####\r
+  * To write Unit test case for PlusPlayer\r
+    * docs/gtest_guide.md\r
+    * Check Reference section of above link for more detailed documents.\r
+    * example\r
+    ```\r
+    sh-3.2# plusplayer_ut --gtest_filter="AvPlusPlayerTest.play"\r
+    ```\r
+\r
+#### Coding Rule Check ####\r
+  * check your coding style using **cpplint.py** before uploading your codes\r
+    > e.g) $ **cpplint.py** cpp_style_test.cpp\r
+  * Or check your coding style and fix your codes automatically using **clang-format**\r
+    > e.g) $ **clang-format-3.4** cpp_style_test.cpp -style=google **-i**\r
+\r
+#### Build ####\r
+  > 1. Clone or Download plusplayer package.\r
+  > 2. $ gbs -c ~/gbsconf/gbs_3_0.conf  build -A armv7l --include-all --clean -B ~/GBS_ROOT_PLUSPLAYER\r
+\r
+#### Understanding the codes ####\r
+ to understand PlusPlayer concept quickly\r
+ plz refer to\r
+  - ${plusplayer_workspace}/ut/porting/webapi-plugins-avplay/src/avplusplayer.cc/h\r
+  - ${plusplayer_workspace}/src/player/defaultplayer.cpp/h\r
+  - ${plusplayer_workspace}/docs/class_diagram.txt\r
+\r
+#### CODING STYLE ####\r
+  'Google C++ Style Guide' based coding.\r
+  > Translated(Korean)\r
+  > Original(English)\r
+  > [[CodingRule.md]]\r
diff --git a/build.sh b/build.sh
new file mode 100755 (executable)
index 0000000..83d83cc
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,34 @@
+export BMS_SERVICE_DIR=~/bms-service\r
+\r
+#rm -f ./*build.log\r
+tizen clean -- ./src/plusplayer-core\r
+tizen clean -- ./src/tracksource\r
+tizen clean -- ./src/plusplayer\r
+\r
+#Debug mode\r
+#tizen build-native -C Debug -a arm  -- ./plusplayer-core -j 16 > plusplayer-core-build.log\r
+tizen build-native -C Debug -a arm -c gcc -- ./src/plusplayer-core\r
+tizen build-native -C Debug -a arm -c gcc -- ./src/tracksource\r
+tizen build-native -C Debug -a arm -c gcc -- ./src/plusplayer\r
+\r
+tizen cli-config "profiles.path=`eval echo $HOME`/tizen-studio-data/profile/profiles.xml"\r
+tizen security-profiles add -n ABS -a packaging/author_test.p12 -p author_test -d packaging/tizen-distributor-partner-manufacturer-signer.p12 -dp tizenpkcs12passfordsigner\r
+\r
+#Release mode\r
+tizen build-native -C Release -a arm -c gcc -- ./src/plusplayer-core\r
+tizen build-native -C Release -a arm -c gcc -- ./src/tracksource\r
+tizen build-native -C Release -a arm -c gcc -- ./src/plusplayer\r
+\r
+tizen cli-config "profiles.path=`eval echo $HOME`/tizen-studio-data/profile/profiles.xml"\r
+tizen security-profiles add -n ABS -a packaging/author_test.p12 -p author_test -d packaging/tizen-distributor-partner-manufacturer-signer.p12 -dp tizenpkcs12passfordsigner\r
+\r
+rm -rf ${BMS_SERVICE_DIR}/plusplayer-api/*\r
+cp -rf ./include/plusplayer ${BMS_SERVICE_DIR}/plusplayer-api\r
+cp -vf ./src/plusplayer-core/Release/libplusplayercore_tvplus.so ${BMS_SERVICE_DIR}/lib/\r
+cp -vf ./src/tracksource/Release/libtracksource_tvplus.so ${BMS_SERVICE_DIR}/lib/ \r
+cp -vf ./src/plusplayer/Release/libplusplayer_tvplus.so ${BMS_SERVICE_DIR}/lib/\r
+cp -vf ./config/tvplus/plusplayer.ini ${BMS_SERVICE_DIR}/res/\r
+\r
+tizen clean -- ./src/plusplayer-core\r
+tizen clean -- ./src/tracksource\r
+tizen clean -- ./src/plusplayer\r
diff --git a/capi-trackrenderer-tv.pc.in b/capi-trackrenderer-tv.pc.in
new file mode 100755 (executable)
index 0000000..be8b623
--- /dev/null
@@ -0,0 +1,10 @@
+\r
+prefix = @PREFIX@\r
+exec_prefix = /usr\r
+libdir = @LIB_INSTALL_DIR@\r
+\r
+Name: @PC_NAME@\r
+Description: @PACKAGE_DESCRYPTION@\r
+Version: @VERSION@\r
+Libs: -L${libdir} @PC_LDFLAGS@\r
+Cflags : @PC_CFLAGS@\r
diff --git a/docs/class_diagram/adapter/bms_avplayer_player_adapter(1).plantuml b/docs/class_diagram/adapter/bms_avplayer_player_adapter(1).plantuml
new file mode 100755 (executable)
index 0000000..b976c76
--- /dev/null
@@ -0,0 +1,62 @@
+@startuml\r
+\r
+note "AS-IS" as PAGE1 #99FF99\r
+\r
+class PCTask {\r
+  # virtual bool t_OnEvent();\r
+  # virtual bool t_Create(void);\r
+  # virtual void t_Destroy(void);\r
+}\r
+\r
+interface IPlayer {\r
+  virtual bool Play()=0;\r
+  virtual bool Stop()=0;\r
+  virtual bool Pause()=0;\r
+  virtual bool Resume()=0;\r
+}\r
+\r
+interface IAVPlayHelper {\r
+  + virtual bool IsShutdown() = 0;\r
+  + virtual bool HandleOnEvent(const TSEvent* pEvent) = 0;     \r
+  + virtual bool GetPlayTime(unsigned long& time) = 0;\r
+  + virtual bool GetCurrentPlayProgram(std::string& outData) = 0;\r
+  + virtual void GetDuration(int& pDuration) = 0;\r
+}\r
+\r
+class TCAVPlayer {\r
+  - IAVPlayHelper* m_pAVCurrentHelper;\r
+\r
+  - IAVPlayHelper* m_pTVPlusAVPlayHelper;\r
+  - IAVPlayHelper* m_pATSC30Helper;\r
+}\r
+note top : "BmsAvPlayer.h"\r
+\r
+IPlayer <|-- TCAVPlayer\r
+PCTask <|-- TCAVPlayer\r
+\r
+TCAVPlayer o-- TvplusAVPlayHelper\r
+TCAVPlayer o-- ATSC3AVPlayHelper\r
+\r
+class TvplusAVPlayHelper {\r
+}\r
+\r
+IAVPlayHelper <|-- TvplusAVPlayHelper\r
+\r
+class ATSC3AVPlayHelper {\r
+}\r
+\r
+IAVPlayHelper <|-- ATSC3AVPlayHelper\r
+\r
+\r
+package "capi-media-player" {\r
+}\r
+\r
+package "libmmplayer" {\r
+}\r
+\r
+TvplusAVPlayHelper --> "capi-media-player"\r
+ATSC3AVPlayHelper --> "capi-media-player"\r
+\r
+"capi-media-player" --> "libmmplayer"\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/adapter/bms_avplayer_player_adapter(1).png b/docs/class_diagram/adapter/bms_avplayer_player_adapter(1).png
new file mode 100755 (executable)
index 0000000..e5504b4
Binary files /dev/null and b/docs/class_diagram/adapter/bms_avplayer_player_adapter(1).png differ
diff --git a/docs/class_diagram/adapter/bms_avplayer_player_adapter(2).plantuml b/docs/class_diagram/adapter/bms_avplayer_player_adapter(2).plantuml
new file mode 100755 (executable)
index 0000000..106b515
--- /dev/null
@@ -0,0 +1,59 @@
+@startuml\r
+\r
+note "TO-BE" as PAGE1 #99FF99\r
+\r
+package "plusplayer" {\r
+}\r
+\r
+package "bms-service" {\r
+\r
+class PCTask {\r
+  # virtual bool t_OnEvent();\r
+  # virtual bool t_Create(void);\r
+  # virtual void t_Destroy(void);\r
+}\r
+\r
+interface IPlayer {\r
+  virtual bool Play()=0;\r
+  virtual bool Stop()=0;\r
+  virtual bool Pause()=0;\r
+  virtual bool Resume()=0;\r
+}\r
+\r
+interface IAVPlayHelper {\r
+  + virtual bool IsShutdown() = 0;\r
+  + virtual bool HandleOnEvent(const TSEvent* pEvent) = 0;     \r
+  + virtual bool GetPlayTime(unsigned long& time) = 0;\r
+  + virtual bool GetCurrentPlayProgram(std::string& outData) = 0;\r
+  + virtual void GetDuration(int& pDuration) = 0;\r
+}\r
+\r
+class TCAVPlayer {\r
+  - IAVPlayHelper* m_pAVCurrentHelper;\r
+\r
+  - IAVPlayHelper* m_pTVPlusAVPlayHelper;\r
+  - IAVPlayHelper* m_pATSC30Helper;\r
+}\r
+note top of TCAVPlayer : "BmsAvPlayer.h"\r
+\r
+IPlayer <|-- TCAVPlayer\r
+PCTask <|-- TCAVPlayer\r
+\r
+TCAVPlayer o-- TvplusPlusplayerHelper\r
+TCAVPlayer o-- ATSC3PlusplayerHelper\r
+\r
+class TvplusPlusplayerHelper {\r
+}\r
+\r
+IAVPlayHelper <|-- TvplusPlusplayerHelper\r
+\r
+class ATSC3PlusplayerHelper {\r
+}\r
+\r
+IAVPlayHelper <|-- ATSC3PlusplayerHelper\r
+\r
+}\r
+\r
+TvplusPlusplayerHelper *--> "plusplayer"\r
+ATSC3PlusplayerHelper *--> "plusplayer"\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/adapter/bms_avplayer_player_adapter(2).png b/docs/class_diagram/adapter/bms_avplayer_player_adapter(2).png
new file mode 100755 (executable)
index 0000000..ebc6e0e
Binary files /dev/null and b/docs/class_diagram/adapter/bms_avplayer_player_adapter(2).png differ
diff --git a/docs/class_diagram/adapter/trackrenderer_adapter.plantuml b/docs/class_diagram/adapter/trackrenderer_adapter.plantuml
new file mode 100755 (executable)
index 0000000..d49a106
--- /dev/null
@@ -0,0 +1,11 @@
+@startuml\r
+\r
+title TrackRenderer Adapter\r
+\r
+DefaultPlayer *-- TrackRendererAdapter\r
+class TrackRendererAdapter\r
+note left : RAII container of Trackrenderer instance.\r
+TrackRendererAdapter --> TrackRendererCapi\r
+TrackRendererCapi --> TrackRenderer\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/adapter/webapi_avplay_player_adapter.plantuml b/docs/class_diagram/adapter/webapi_avplay_player_adapter.plantuml
new file mode 100755 (executable)
index 0000000..9251563
--- /dev/null
@@ -0,0 +1,80 @@
+@startuml\r
+\r
+title AS-IS\r
+\r
+package "capi-media-player" {\r
+}\r
+\r
+package "webapi-plugins-avplay" {\r
+  class AVPlayInstance {\r
+  }\r
+\r
+  class AVPlayerAdapter {\r
+  }\r
+}\r
+\r
+package "webapi-plugins-avplay" {\r
+  class AVPlayInstance {\r
+  }\r
+\r
+  class AVPlayerAdapter {\r
+  }\r
+\r
+  AVPlayInstance *-- AVPlayerAdapter\r
+  AVPlayerAdapter *--> "capi-media-player"\r
+}\r
+\r
+newpage\r
+\r
+title TO-BE\r
+\r
+package "capi-media-player" {\r
+}\r
+\r
+package "webapi-plugins-avplay" {\r
+  class AVPlayInstance {\r
+  }\r
+\r
+  class AVPlayerAdapter {\r
+  }\r
+\r
+  interface AvPlay {\r
+  }\r
+\r
+  AVPlayInstance *-- AvPlay\r
+  AvPlay <|.. AVPlayerAdapter\r
+  AVPlayerAdapter *-- "capi-media-player"\r
+  AvPlay <|.. AvPlusPlayer\r
+  PlusPlayerEventListener --* AvPlusPlayer\r
+}\r
+\r
+package "plusplayer" {\r
+}\r
+\r
+AvPlusPlayer *--> "plusplayer" : use\r
+\r
+@enduml@startuml\r
+\r
+package "webapi-plugins-avplay" {\r
+  class AVPlayInstance {\r
+  }\r
+\r
+  class AVPlayerAdapter {\r
+  }\r
+\r
+  interface AvPlay {\r
+  }\r
+\r
+  AVPlayInstance *-- AvPlay\r
+  AvPlay <|.. AVPlayerAdapter\r
+  AVPlayerAdapter *-- "capi-media-player"\r
+  AvPlay <|.. AvPlusPlayer\r
+  PlusPlayerEventListener --* AvPlusPlayer\r
+}\r
+\r
+package "plusplayer" {\r
+}\r
+\r
+AvPlusPlayer *--> "plusplayer" : use\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/adapter/webapi_avplay_player_adapter.png b/docs/class_diagram/adapter/webapi_avplay_player_adapter.png
new file mode 100755 (executable)
index 0000000..e9a25c6
Binary files /dev/null and b/docs/class_diagram/adapter/webapi_avplay_player_adapter.png differ
diff --git a/docs/class_diagram/adapter/webmedia_mse_eme.plantuml b/docs/class_diagram/adapter/webmedia_mse_eme.plantuml
new file mode 100755 (executable)
index 0000000..5053958
--- /dev/null
@@ -0,0 +1,17 @@
+@startuml\r
+\r
+'HTML5 VideoTag case\r
+package "webmedia" {\r
+  class OriginalMediaPort {\r
+  }\r
+  interface MediaPort {\r
+  }\r
+  class PlusPlayerMediaPort {\r
+    /' Adapter '/\r
+  }\r
+  MediaPort <|.. OriginalMediaPort\r
+  MediaPort <|. PlusPlayerMediaPort\r
+  "capi-media-player" --* OriginalMediaPort\r
+}\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/bmservice_drmmanager_plusplayer.plantuml b/docs/class_diagram/bmservice_drmmanager_plusplayer.plantuml
new file mode 100755 (executable)
index 0000000..581fcad
--- /dev/null
@@ -0,0 +1,31 @@
+@startuml\r
+\r
+class TvplusPlusplayerHelper {\r
+\r
+}\r
+\r
+package "plusplayer" {\r
+class Plusplayer {\r
+}\r
+}\r
+\r
+class CBmsDrmHandler {\r
+\r
+}\r
+\r
+package "DrmManager" {\r
+  class DrmManager {\r
+  }\r
+}\r
+\r
+package "IEME" {\r
+\r
+}\r
+\r
+TvplusPlusplayerHelper *-- Plusplayer\r
+TvplusPlusplayerHelper *-- CBmsDrmHandler\r
+CBmsDrmHandler *-- DrmManager\r
+DrmManager --> IEME\r
+Plusplayer --> IEME\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/details/defaultplayer.plantuml b/docs/class_diagram/details/defaultplayer.plantuml
new file mode 100755 (executable)
index 0000000..512dd28
--- /dev/null
@@ -0,0 +1,23 @@
+@startuml\r
+\r
+title DefaultPlayer\r
+' DefaultPlayer\r
+  interface PlusPlayer {\r
+  }\r
+  interface TrackSource {\r
+  }\r
+  PlusPlayer <|.. DefaultPlayer\r
+  \r
+' DefaultPlayer\r
+  DefaultPlayer "1" *-- "1" StateManager\r
+  DefaultPlayer "1" *-- "1" MsgHandler\r
+  DefaultPlayer "1" *--- "1" Feeder\r
+  DefaultPlayer "1" *--- "1" TypeFinder\r
+  DefaultPlayer "1" *--- "1" TrackSourceCompositor\r
+  TrackSource <|-- TrackSourceCompositor\r
+  DefaultPlayer "1" *--- "1" TrackRenderer\r
+  DefaultPlayer "1" *- "1" TrackSourceEventListener\r
+  DefaultPlayer "1" *- "1" TrackRendererEventListener\r
+  DefaultPlayer ..> Track\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/details/trackrenderer.plantuml b/docs/class_diagram/details/trackrenderer.plantuml
new file mode 100755 (executable)
index 0000000..953cdce
--- /dev/null
@@ -0,0 +1,55 @@
+@startuml\r
+\r
+title TrackRenderer\r
+\r
+class TrackRenderer {\r
+  + bool Open()\r
+  + bool Close()\r
+  + bool Prepare()\r
+  + bool Start()\r
+  + bool Stop()\r
+  + void SetDisplayMode()\r
+  + bool SetDisplay()\r
+  + bool SetDisplayRoi()\r
+  + bool SetVisible()\r
+  + bool SetTrack()\r
+  + bool SubmitPacket(const DecoderInputBufferPtr& data)\r
+  + bool GetPlayingTime()\r
+\r
+  - std::vector<Track> trackinfo_;\r
+  - std::unique_ptr<Pipeline<T>> pipeline_;\r
+  - AvocHandle avoc_id_;\r
+\r
+}\r
+\r
+class Display {\r
+  + void SetDisplayMode()\r
+  + bool SetDisplay()\r
+  + bool SetDisplayRoi()\r
+  + bool SetVisible()\r
+}\r
+\r
+class DecoderInputBuffer {\r
+  - GstBuffer* buffer_\r
+}\r
+\r
+class ResourceManager {\r
+  + bool Alloc()\r
+  + bool Dealloc()\r
+  - static rm_cb_result ResourceConflictCallback_()\r
+}\r
+\r
+  DefaultPlayer "1" *-- "1" TrackRenderer\r
+  TrackRenderer "1" o-- "1" Display\r
+  TrackRenderer *-- ResourceManager\r
+  TrackRenderer *-- Track\r
+  TrackRenderer ..> DecoderInputBuffer\r
+  TrackRenderer *-- Pipeline\r
+\r
+  package Gstreamer {\r
+  }\r
+  Pipeline --> Gstreamer\r
+  package Avoc {\r
+  }\r
+  TrackRenderer --> Avoc\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/details/tracksource_compositor.plantuml b/docs/class_diagram/details/tracksource_compositor.plantuml
new file mode 100755 (executable)
index 0000000..72cd16c
--- /dev/null
@@ -0,0 +1,84 @@
+@startuml\r
+\r
+' TrackSource\r
+title TrackSource & Compositor\r
+\r
+  interface TrackSource {\r
+    + virtual bool AddSource()\r
+    + virtual bool StopSource()\r
+    + virtual bool DeleteSource()\r
+    + virtual bool Open()\r
+    + virtual bool Close()\r
+    + virtual bool Prepare()\r
+    + virtual bool Start()\r
+    + virtual bool Stop()\r
+    + virtual bool Seek()\r
+    + virtual bool SelectTrack()\r
+    + virtual bool Deactivate()\r
+    + virtual bool GetTrackInfo()\r
+    + virtual bool GetDuration()\r
+    + virtual bool SetBufferConfig()\r
+    + virtual bool RegisterListener(DecoderInputBuffer*)\r
+    + virtual bool RegisterEventListener(EventListener*)\r
+\r
+  }\r
+\r
+  class TrackSourceCompositor {\r
+    + bool AddSource()\r
+    + bool StopSource()\r
+    + bool DeleteSource()\r
+  }\r
+\r
+  class HlsTrackSource {\r
+    + bool Open()\r
+    + bool Close()\r
+    + bool Prepare()\r
+    + bool Start()\r
+    + bool Stop()\r
+    + bool Seek()\r
+  }\r
+\r
+  class DashTrackSource {\r
+    + bool Open()\r
+    + bool Close()\r
+    + bool Prepare()\r
+    + bool Start()\r
+    + bool Stop()\r
+    + bool Seek()\r
+  }\r
+\r
+  class HttpTrackSource {\r
+    + bool Open()\r
+    + bool Close()\r
+    + bool Prepare()\r
+    + bool Start()\r
+    + bool Stop()\r
+    + bool Seek()\r
+    - GstElement* pipeline;\r
+  }\r
+\r
+  class ExternalSubtitleSource {\r
+    + bool Open()\r
+    + bool Close()\r
+    + bool Prepare()\r
+    + bool Start()\r
+    + bool Stop()\r
+    + bool Seek()\r
+  }\r
+\r
+  TrackSource <|.. TrackSourceCompositor\r
+  TrackSource <|.. HlsTrackSource\r
+  TrackSource <|.. DashTrackSource\r
+  TrackSource <|.. HttpTrackSource\r
+  TrackSource <|.. ExternalSubtitleSource\r
+  TrackSource --o TrackSourceCompositor\r
+\r
+  package Gstreamer {\r
+  }\r
+\r
+  HlsTrackSource --> Gstreamer\r
+  DashTrackSource --> Gstreamer\r
+  HttpTrackSource --> Gstreamer\r
+  ExternalSubtitleSource --> Gstreamer\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/esplusplayer.plantuml b/docs/class_diagram/esplusplayer.plantuml
new file mode 100755 (executable)
index 0000000..4442ef5
--- /dev/null
@@ -0,0 +1,52 @@
+@startuml\r
+\r
+package "esplusplayer" {\r
+\r
+  interface EsPlusPlayer {\r
+  }\r
+\r
+  EsPlusPlayer <|.. EsPlayer\r
+\r
+  class EsEventListener {\r
+  }\r
+\r
+  class AudioStream {\r
+  }\r
+\r
+  class VideoStream {\r
+  }\r
+\r
+  class EsPacket {\r
+  }\r
+\r
+  class TrackRenderer {\r
+  }\r
+\r
+' EsPlayer\r
+  EsPlayer "1" *-- "1" StateManager\r
+  EsPlayer "1" *-- "1" TrackRenderer\r
+  EsPlayer "1" *-- "1" MsgHandler\r
+  EsPlayer "1" *-- "1" TrackRendererEventListener\r
+  EsPlayer ..> AudioStream\r
+  EsPlayer ..> VideoStream\r
+  EsPlayer ..> EsPacket\r
+  EsPlayer ..> Track\r
+  EsPlayer --- DecoderInputBuffer\r
+  \r
+  AudioStream ..> Track  \r
+  VideoStream ..> Track  \r
+\r
+' TrackRenderer\r
+  TrackRenderer "1" o--- "1" Display\r
+  TrackRenderer *-- ResourceManager\r
+  TrackRenderer *-- Track\r
+  TrackRenderer ...> DecoderInputBuffer\r
+  TrackRenderer *- Pipeline\r
+\r
+  Pipeline --> GstObjectGuard\r
+  \r
+  ResourceManager --> Resource\r
+  ResourceManager *-- Resource\r
+}\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/plusplayer.plantuml b/docs/class_diagram/plusplayer.plantuml
new file mode 100755 (executable)
index 0000000..2f702b2
--- /dev/null
@@ -0,0 +1,64 @@
+@startuml\r
+\r
+package "plusplayer" {\r
+\r
+  interface PlusPlayer {\r
+  }\r
+\r
+  PlusPlayer <|.. DefaultPlayer\r
+\r
+  class TrackRenderer {\r
+  }\r
+\r
+  ResourceManager --> Resource\r
+  ResourceManager *-- Resource\r
+\r
+  class DecoderInputBufferListener {\r
+  }\r
+\r
+  class TrackSourceCompositor {\r
+  }\r
+\r
+  class TypeFinder {\r
+  }\r
+\r
+  TypeFinder *-- SourceType\r
+  DecoderInputBufferListener <|-- Feeder\r
+\r
+' DefaultPlayer\r
+  DefaultPlayer "1" *-- "1" Feeder\r
+  DefaultPlayer "1" *- "1" StateManager\r
+  DefaultPlayer "1" *-- "1" TypeFinder\r
+  DefaultPlayer "1" *-- "1" TrackSourceCompositor\r
+  DefaultPlayer "1" *--- "1" TrackRenderer\r
+  DefaultPlayer "1" *-- "1" MsgHandler\r
+  DefaultPlayer "1" *-- "1" TrackSourceEventListener\r
+  DefaultPlayer "1" *-- "1" TrackRendererEventListener\r
+  DefaultPlayer ..> Track\r
+\r
+' TrackSource\r
+  interface TrackSource {\r
+  }\r
+\r
+  class HlsTrackSource {\r
+  }\r
+  TrackSource <|.. TrackSourceCompositor\r
+  TrackSource <|.. HlsTrackSource\r
+  TrackSource <|.. ExternalSubtitleSource\r
+  TrackSource --o TrackSourceCompositor\r
+  HlsTrackSource *-- Track\r
+  HlsTrackSource --- DecoderInputBuffer\r
+  ExternalSubtitleSource --- DecoderInputBuffer\r
+\r
+  Pipeline --> GstObjectGuard\r
+  HlsTrackSource --> GstObjectGuard\r
+  ExternalSubtitleSource --> GstObjectGuard\r
+\r
+  TrackRenderer "1" o--- "1" Display\r
+  TrackRenderer *-- ResourceManager\r
+  TrackRenderer *-- Track\r
+  TrackRenderer ...> DecoderInputBuffer\r
+  TrackRenderer *- Pipeline\r
+}\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/class_diagram/plusplayer.png b/docs/class_diagram/plusplayer.png
new file mode 100755 (executable)
index 0000000..0690d2e
Binary files /dev/null and b/docs/class_diagram/plusplayer.png differ
diff --git a/docs/class_diagram/plusplayer_simple.plantuml b/docs/class_diagram/plusplayer_simple.plantuml
new file mode 100755 (executable)
index 0000000..c7801f6
--- /dev/null
@@ -0,0 +1,30 @@
+@startuml\r
+\r
+package "plusplayer" {\r
+\r
+  interface PlusPlayer {\r
+  }\r
+\r
+  PlusPlayer <|.. DefaultPlayer\r
+\r
+  class TrackRenderer {\r
+  }\r
+  DefaultPlayer "1" *-- "1" TrackSourceCompositor\r
+  DefaultPlayer "1" *-- "1" TrackRenderer\r
+\r
+  class TrackSourceCompositor {\r
+  }\r
+\r
+' TrackSource\r
+  interface TrackSource {\r
+  }\r
+\r
+  class HlsTrackSource {\r
+  }\r
+  TrackSource <|.. TrackSourceCompositor\r
+  TrackSource <|.. HlsTrackSource\r
+  TrackSource <|.. ExternalSubtitleSource\r
+  TrackSource --o TrackSourceCompositor\r
+}\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/coding_rule.md b/docs/coding_rule.md
new file mode 100755 (executable)
index 0000000..52a8e6e
--- /dev/null
@@ -0,0 +1,55 @@
+## **CODING STYLE** ##\r
+  * All codes follow 'Google C++ Style Guide' \r
+    - [English](https://google.github.io/styleguide/cppguide.html)\r
+  * some major rules are below\r
+\r
+---\r
+\r
+### § Naming ###\r
+  Give as descriptive a name as possible.\r
+  \r
+#### 1. Namespace/File/Variable/Struct Data member ####\r
+  * All lower case(mandatory) + between underscore(optional)\r
+    * e.g) mediaplayer.h , trackrenderer , track_renderer\r
+\r
+#### 2. Class Data Members\r
+  * Private attributes : Variable names + Trailing underscore("_")\r
+    * e.g) tablename_ , tracksource_ , track_source_\r
+  * Public attributes - Not Allowed.\r
+\r
+#### 3. Type Names - Class,Struct,Type Aliases,Enums and type template parameters  ####\r
+  * Names start with a capital letter and have a capital letter for each new word\r
+  * No Underscore\r
+    * e.g) MMPlayer(X) , MmPlayer(O)\r
+    * e.g) class MediaPlayer {} ...\r
+    * e.g) struct PlayerContext {} , enum SourceType {...}\r
+\r
+#### 4. Macro Names ####\r
+  * All capitals + Underscore\r
+\r
+#### 5. Constant / Enumerator ####\r
+  * prefix 'k' + TypeNames  \r
+  * e.g   \r
+      const int kDaysInAWeek = 7;  \r
+      enum UrlTableErrors {  \r
+        kErrorOutOfMemory  \r
+      }  \r
+\r
+### § Formating ###\r
+\r
+#### 1. Indentation ####\r
+  * Default indentation : 2 spaces \r
+  * We use spaces for indentation. Do not use tabs in your code.\r
+\r
+#### 2. Class ####\r
+  * Ordering\r
+    * Sections in public - protected - private order\r
+    * method(public/protected/private) -> attribute order\r
+  * public, protected and private keywords : **1** space indentation\r
+\r
+### § Header Files ###\r
+\r
+#### 1. Order of Includes ####\r
+  * Related header, C library, C++ library, other libraries' .h, your project's .h.\r
+\r
+> plz refer to "Google C++ Style Guide" for the rest of detail guide.\r
diff --git a/docs/dot_graph/plusplayer_renderer_start.png b/docs/dot_graph/plusplayer_renderer_start.png
new file mode 100755 (executable)
index 0000000..ca27b1a
Binary files /dev/null and b/docs/dot_graph/plusplayer_renderer_start.png differ
diff --git a/docs/dot_graph/plusplayer_renderer_stop.png b/docs/dot_graph/plusplayer_renderer_stop.png
new file mode 100755 (executable)
index 0000000..4d92f40
Binary files /dev/null and b/docs/dot_graph/plusplayer_renderer_stop.png differ
diff --git a/docs/dot_graph/plusplayer_src_start.png b/docs/dot_graph/plusplayer_src_start.png
new file mode 100755 (executable)
index 0000000..b73c014
Binary files /dev/null and b/docs/dot_graph/plusplayer_src_start.png differ
diff --git a/docs/dot_graph/plusplayer_src_stop.png b/docs/dot_graph/plusplayer_src_stop.png
new file mode 100755 (executable)
index 0000000..cf2f2e2
Binary files /dev/null and b/docs/dot_graph/plusplayer_src_stop.png differ
diff --git a/docs/downloadable/class_diagram.plantuml b/docs/downloadable/class_diagram.plantuml
new file mode 100755 (executable)
index 0000000..bc57199
--- /dev/null
@@ -0,0 +1,2 @@
+@startuml\r
+@enduml
\ No newline at end of file
diff --git a/docs/downloadable/version_control.plantuml b/docs/downloadable/version_control.plantuml
new file mode 100755 (executable)
index 0000000..c1a06ad
--- /dev/null
@@ -0,0 +1,6 @@
+@startuml\r
+\r
+' to be updated soon\r
+' this is test\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/downloadable/version_control_sequence.plantuml b/docs/downloadable/version_control_sequence.plantuml
new file mode 100755 (executable)
index 0000000..1f3fce1
--- /dev/null
@@ -0,0 +1,80 @@
+@startuml\r
+\r
+/'\r
+skinparam backgroundColor #EEEBDC\r
+skinparam handwritten true\r
+skinparam sequence {\r
+  ArrowColor DeepSkyBlue\r
+  ActorBorderColor DeepSkyBlue\r
+  LifeLineBorderColor blue\r
+  LifeLineBackgroundColor #A9DCDF\r
+  ParticipantBorderColor DeepSkyBlue\r
+  ParticipantBackgroundColor DodgerBlue\r
+  ParticipantFontName Impact\r
+  ParticipantFontSize 17\r
+  ParticipantFontColor #A9DCDF\r
+  ActorBackgroundColor aqua\r
+  ActorFontColor DeepSkyBlue\r
+  ActorFontSize 17\r
+  ActorFontName Aapex\r
+}\r
+'/\r
+\r
+title tvplus case(1) dynamic loading\r
+\r
+participant AppLauncher\r
+participant App\r
+participant BmsService\r
+note over BmsService : daemon\r
+participant Plusplayer\r
+participant PlusplayerLoader\r
+database version_info\r
+\r
+== initialization ==\r
+alt successful case\r
+  AppLauncher -> App : load\r
+  App -> BmsService : play()\r
+  BmsService -> Plusplayer : SetVersion("path")\r
+  Plusplayer -> PlusplayerLoader : SetVersion("path")\r
+  PlusplayerLoader -> version_info : ReadVersion()\r
+  ' 한번에 모두 로딩 or 분할하여.\r
+  PlusplayerLoader -> PlusplayerLoader : LoadProperLibSet_()\r
+  BmsService -> Plusplayer : Create()\r
+else some kind of failure (version mismatch or missing)\r
+end\r
+\r
+newpage tvplus case(2) dynamic linking\r
+\r
+actor PlayerManager\r
+participant ServiceDaemonLauncher\r
+participant App\r
+participant BmsService\r
+note over BmsService : daemon\r
+participant Plusplayer\r
+participant PlusplayerLoader\r
+database version_info\r
+\r
+\r
+== initialization ==\r
+\r
+group compile time\r
+  PlayerManager -> BmsService : update LD_PRELOAD configuration\r
+  note over BmsService : adjust bms.service configuration file\r
+end\r
+\r
+alt successful case\r
+  ServiceDaemonLauncher -> BmsService : load\r
+  note over BmsService : updated libs are dynamically linked\r
+  App -> BmsService : play()\r
+  BmsService -> Plusplayer : SetVersion("path")\r
+  Plusplayer -> PlusplayerLoader : GetVersion("path")\r
+  PlusplayerLoader -> version_info : ReadVersion()\r
+  PlusplayerLoader -> PlusplayerLoader : CheckLibValidation_()\r
+  Plusplayer <-- PlusplayerLoader : success\r
+  BmsService -> Plusplayer : Create()\r
+else some kind of failure (version mismatch or missing)\r
+end\r
+\r
+\r
+\r
+@enduml\r
diff --git a/docs/gtest_guide.md b/docs/gtest_guide.md
new file mode 100755 (executable)
index 0000000..0fa6c9e
--- /dev/null
@@ -0,0 +1,127 @@
+**GTest guide** \r
+===============\r
+  For unit test for plusplayer\r
+\r
+---\r
+### Reference \r
+- <https://github.com/google/googletest>\r
+\r
+## Assertion \r
+* ASSERT_* : 실패시 해당 테스트를 바로 종료 <br>\r
+* EXPECT_* : 실패하여도 테스트 계속 진행 <br>\r
+\r
+#### Basic Assertions ###\r
+\r
+These assertions do basic true/false condition testing.\r
+\r
+| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |\r
+|:--------------------|:-----------------------|:-------------|\r
+| `ASSERT_TRUE(`_condition_`)`;  | `EXPECT_TRUE(`_condition_`)`;   | _condition_ is true |\r
+| `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`;  | _condition_ is false |\r
+\r
+#### Binary Comparison ###\r
+\r
+This section describes assertions that compare two values.\r
+\r
+| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |\r
+|:--------------------|:-----------------------|:-------------|\r
+|`ASSERT_EQ(`_val1_`, `_val2_`);`|`EXPECT_EQ(`_val1_`, `_val2_`);`| _val1_ `==` _val2_ |\r
+|`ASSERT_NE(`_val1_`, `_val2_`);`|`EXPECT_NE(`_val1_`, `_val2_`);`| _val1_ `!=` _val2_ |\r
+|`ASSERT_LT(`_val1_`, `_val2_`);`|`EXPECT_LT(`_val1_`, `_val2_`);`| _val1_ `<` _val2_ |\r
+|`ASSERT_LE(`_val1_`, `_val2_`);`|`EXPECT_LE(`_val1_`, `_val2_`);`| _val1_ `<=` _val2_ |\r
+|`ASSERT_GT(`_val1_`, `_val2_`);`|`EXPECT_GT(`_val1_`, `_val2_`);`| _val1_ `>` _val2_ |\r
+|`ASSERT_GE(`_val1_`, `_val2_`);`|`EXPECT_GE(`_val1_`, `_val2_`);`| _val1_ `>=` _val2_ |\r
+\r
+\r
+#### String Comparison ###\r
+\r
+The assertions in this group compare two **C strings**.<br>\r
+If you want to compare two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead.\r
+\r
+| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |\r
+|:--------------------|:-----------------------|:-------------|\r
+| `ASSERT_STREQ(`_str1_`, `_str2_`);`    | `EXPECT_STREQ(`_str1_`, `_str_2`);`     | the two C strings have the same content |\r
+| `ASSERT_STRNE(`_str1_`, `_str2_`);`    | `EXPECT_STRNE(`_str1_`, `_str2_`);`     | the two C strings have different content |\r
+| `ASSERT_STRCASEEQ(`_str1_`, `_str2_`);`| `EXPECT_STRCASEEQ(`_str1_`, `_str2_`);` | the two C strings have the same content, ignoring case |\r
+| `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case |\r
+\r
+## Text Fixtures : Using the Same Data Configuration for Multiple Tests ##\r
+\r
+사용자가 유사한 data를 사용해서 하나 이상의 test를 작성한다면, test fixture를 사용할 수 있다. 이 test fixture를 사용한다는 것은 여러개의 다양한 test를 작성하는 과정에서 같은 object의 configuration을 재사용한다는 것을 의미한다.\r
+\r
+Fixture를 작성할 때에는 아래의 내용대로 수행하면 된다.\r
+\r
+1. ::testing::Test 로부터 class를 derive한다. Sub-class 에서 fixture member에 접근해야 하기 때문에 protected 혹은 public 으로 작성해야 한다.   \r
+2. Class 내부에서 사용자가 원하는대로 object들을 선언해 사용한다.  \r
+3. 필요하다면, 생성자나 SetUp() function을 작성해둔다.   \r
+4. 생성자나 SetUp() function을 정의해서 사용하고 있다면, 해당 function에서 사용했던 resource를 반환하기 위해 소멸자나 TearDown() function을 작성한다.   \r
+5. Subroutine 들을 작성한다.   \r
+\r
+Fixture를 사용하기 위해서는 TEST() 대신에 TEST_F()를 사용해야만 한다.\r
+TEST()에서는 첫번째 argument가 testcase의 이름이었지만 TEST_F()를 사용할 때는 첫번째 argument로 test fixture class의 이름을 사용해야만 한다.\r
+\r
+**Fixture class 기본 구현 Form**\r
+* 관례에 따라 테스트할 클래스가 Foo라면 이름을 FooTest라고 하는게 좋다.\r
+~~~\r
+class PlusPlayerTest : public ::testing::Test {\r
+public:\r
+  PlusPlayerTest(std::string url)\r
+    : plusplayer_(nullptr), url_(url)\r
+  {\r
+  }\r
+\r
+  void SetUp() override\r
+  {\r
+    plusplayer_ = new PlusPlayer();\r
+    create(url_);\r
+  }\r
+\r
+  void TearDown() override\r
+  {\r
+    destory(plusplayer_);\r
+  }\r
+\r
+private:\r
+  std::string url_;\r
+  PlusPlayer* plusplayer_;\r
+\r
+}\r
+~~~\r
+\r
+**실행 순서**   \r
+1. 모든 구글 테스트 플래그 상태를 저장한다.  \r
+2. 첫 번째 테스트에 대해 테스트 fixture 객체를 생성한다.  \r
+3. 만든 객체를 SetUp()에서 초기화한다.  \r
+4. 픽스처 객체에 대해 테스트를 실행한다.  \r
+5. TearDown()에서 해당 픽스처를 정리한다.  \r
+6. 해당 픽스처를 삭제한다.  \r
+7. 모든 구글 테스트 플래그 상태를 복원한다.  \r
+8. 모든 테스트를 마칠 때까지 다음 테스트에 대해 위 과정을 반복한다.   \r
+\r
+---\r
+\r
+## Arguments \r
+reference\r
+\r
+1. test selection\r
+  * --gtest_list_tests <br>\r
+    > 테스트할 항목을 보여준다. (테스트 실시 X)\r
+  * --gtest_also_run_disabled_tests <br>\r
+    > DISABLED_ 로 막아둔 test case 를 일시적으로 실행\r
+  * --gtest_filter <br>\r
+    > 특정 case 들만 실행 가능<br>\r
+      Ex) --gtest_filter="*.create*" : 모든 TC중에서 create 로 시작하는 모든 TC 실행. <br>\r
+\r
+2. test Execution\r
+  * --gtest_repeat <br>\r
+    > test 반복 가능. -1일 경우 무한히 반복<br>\r
+      --gtest_break_on_failure와 함께 사용하면 실패할 경우 멈춤.\r
+  * --gtest_shuffle <br>\r
+    > 무작위로 실행 가능 (test case 간 dependency 가 없어야 하기 때문이다)<br>\r
+      gtest는 기본적으로 현재시간을 랜덤함수의 시드값으로 사용하나,  --gtest_random_seed로 조절가능하다\r
+  * --gtest_random_seed \r
+    > 1 ~ 99999까지의 값을 --gtest_shuffle에서 사용할 랜덤함수의 시드로 사용.\r
+\r
+---\r
+## Reference\r
+  * Gtest Primer(EN)<br> <https://github.com/google/googletest/blob/master/googletest/docs/Primer.md>\r
diff --git a/docs/module_view/libav-common.plantuml b/docs/module_view/libav-common.plantuml
new file mode 100755 (executable)
index 0000000..09ba0ae
--- /dev/null
@@ -0,0 +1,25 @@
+@startuml\r
+\r
+title reduced downloadable module size by libav-common\n dash/hls/http streaming module 9M to 4.5M 50% decreased\r
+\r
+component "dash gst-plugin" as dash\r
+component "hls gst-plugin" as hls\r
+component "httpdemux gst-plugin" as http\r
+\r
+component "libavformat-dash.so" as dashformat\r
+component "libavformat-hls.so" as hlsformat\r
+component "libavformat-httpdemux.so" as httpformat\r
+\r
+package "libav-common" as libavcommon {\r
+  [libavcodec.so]\r
+  [libavutils.so]\r
+}\r
+\r
+dash --> dashformat : use\r
+http --> httpformat : use\r
+hls --> hlsformat : use\r
+\r
+dashformat --> libavcommon : use\r
+httpformat --> libavcommon : use\r
+hlsformat --> libavcommon : use\r
+@enduml
\ No newline at end of file
diff --git a/docs/module_view/uses_view.plantuml b/docs/module_view/uses_view.plantuml
new file mode 100755 (executable)
index 0000000..bbf7204
--- /dev/null
@@ -0,0 +1,70 @@
+@startuml\r
+\r
+title : module view : uses view\r
+\r
+component [Downloadable module] #Aquamarine\r
+\r
+package "Security" {\r
+  IEME -- [EME]\r
+}\r
+package "System" {\r
+  package "Subsystem" {\r
+    RM -- [ResourceManager]\r
+  }\r
+\r
+  package "Subsystem" {\r
+    AVOC -- [libavoc]\r
+  }\r
+}\r
+\r
+package "EFL" {\r
+  ecore_wayland_api -- [Ecore_Wayland]\r
+}\r
+\r
+package "Gstreamer" {\r
+  [gstreamer] --> [gst-openmax]\r
+  package "gst-plugins-streamingengine" {\r
+    [gst-plugin-dash] #Aquamarine\r
+    [gst-plugin-hls] #Aquamarine\r
+    [gst-plugin-http] #Aquamarine\r
+    [gstreamer] --> [gst-plugin-dash]\r
+    [gstreamer] --> [gst-plugin-hls]\r
+    [gstreamer] --> [gst-plugin-http]\r
+  }\r
+}\r
+\r
+package "Plusplayer" {\r
+  [plusplayer] #Aquamarine\r
+  [tracksource] #Aquamarine\r
+  [plusplayer-core] #Aquamarine\r
+  [plusplayer] --> [tracksource] : use\r
+  [plusplayer] --> [trackrenderer] : use\r
+  [plusplayer] --> [plusplayer-core] : use\r
+  [tracksource] --> [plusplayer-core] : use\r
+  '[tracksource] --> [gstreamer] : use\r
+  [trackrenderer] --> [plusplayer-core] : use\r
+  [trackrenderer] --> RM : use\r
+  '[trackrenderer] --> [gstreamer] : use\r
+  [trackrenderer] --> [ecore_wayland_api] : use\r
+  [trackrenderer] --> [AVOC] : use\r
+  [trackrenderer] --> [IEME] : use\r
+  [plusplayer-core] --> [gstreamer] : use\r
+}\r
+\r
+\r
+package "drmmanager" {\r
+  drmapi -- [DrmManager]\r
+  [DrmManager] --> [IEME] : use\r
+}\r
+\r
+package "webapi-avplay" {\r
+  [avplay] --> [plusplayer]\r
+  [avplay] --> [drmapi]\r
+}\r
+\r
+package "bms-service" {\r
+  [BmsAVPlayer] --> [plusplayer]\r
+  [BmsAVPlayer] --> [drmapi]\r
+}\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/module_view/uses_view.png b/docs/module_view/uses_view.png
new file mode 100755 (executable)
index 0000000..1f12768
Binary files /dev/null and b/docs/module_view/uses_view.png differ
diff --git a/docs/plusplayer_guide.md b/docs/plusplayer_guide.md
new file mode 100755 (executable)
index 0000000..66c6035
--- /dev/null
@@ -0,0 +1,69 @@
+# **PlusPlayer** #\r
+  PlusPlayer is a new multimedia player object-oriented designed.\r
+\r
+## Goals ##\r
+  * Improve maintainability / extensibility / reusability\r
+    - object oriented design\r
+    - separate the modules into high-variation part and low-variation part\r
+    - decoupling between each streaming services\r
+  * Simplification\r
+    - simplified pipeline , creates static pipeline\r
+  * Easy to upgrade\r
+    - support downloadable features (planned)\r
+\r
+## Architecture Design ##\r
+  * PlusPlayer consists of TypeFinder / TrackSource / TrackRenderer / DefaultPlayer objects.\r
+    * TypeFinder\r
+      - Probing source type by inspecting probing data\r
+      - use gstreamer typefinder plugin\r
+    * TrackSource\r
+      - Fetching data from server , demuxing , controling demuxed packet buffers\r
+      - a pipeline consists of `src - typefinder - demuxer - multiqueue - inputselector - fakesink`\r
+        - plz refer to `${plusplayer_workspace}/docs/dot/plusplayer_src_start.png`\r
+    * TrackRenderer\r
+      - maintains a pipeline consists of `appsrc - omx - sink` elements\r
+        - plz refer to `${plusplayer_workspace}/docs/dot/plusplayer_renderer_start.png`\r
+  * Class diagram\r
+    * ${plusplayer_workspace}/docs/class_diagram.plantuml\r
+    * or you can directly download it from [class_diagram.plantuml]\r
+\r
+## Development ##\r
+  * GitHub Project :\r
+    * All the milestones / activities (Codes , CodeReview , Design , Issues , etc) are being uploaded here\r
+  * Codereview on Github\r
+    - Each Developers should fork master branch and work on their own forked project.\r
+    - developer should submit pull-request to apply their changes\r
+      * all developers must sync their forked project with the latest master prior to sumit pull-request. so that we can avoid merge conflicts.\r
+    - everyone can join the codereviews\r
+  * the coding style follows Google C++ coding style guide. refer to [CODING STYLE](### coding-style)\r
+  * Test Driven Development (use gtest - plusplayer_ut -for their implementation and verifications)\r
+\r
+#### GTest guide ####\r
+  * To write Unit test case for PlusPlayer\r
+    * docs/gtest_guide.md\r
+    * Check Reference section of above link for more detailed documents.\r
+    * example\r
+    ```\r
+    sh-3.2# plusplayer_ut --gtest_filter="AvPlusPlayerTest.play"\r
+    ```\r
+#### Coding Rule Check ####\r
+  * check your coding style using **cpplint.py** before uploading your codes\r
+    > e.g) $ **cpplint.py** cpp_style_test.cpp\r
+  * Or check your coding style and fix your codes automatically using **clang-format**\r
+    > e.g) $ **clang-format-3.4** cpp_style_test.cpp -style=google **-i**  \r
+\r
+#### Build ####\r
+  > 1. Clone or Download plusplayer package.\r
+  > 2. $ gbs -c ~/gbsconf/gbs_3_0.conf  build -A armv7l --include-all --clean -B ~/GBS_ROOT_PLUSPLAYER  \r
+\r
+#### Understanding the codes ####\r
+ to understand PlusPlayer concept quickly\r
+ plz refer to \r
+  - ${plusplayer_workspace}/ut/porting/webapi-plugins-avplay/src/avplusplayer.cc/h  \r
+  - ${plusplayer_workspace}/src/player/defaultplayer.cpp/h\r
+  - ${plusplayer_workspace}/docs/class_diagram.txt\r
+\r
+#### CODING STYLE ####\r
+  'Google C++ Style Guide' based coding.  \r
+  > Translated(Korean)\r
+  > Original(English): [https://google.github.io/styleguide/cppguide.html](https://google.github.io/styleguide/cppguide.html)\r
diff --git a/docs/reference/PlantUML_Language_Reference_Guide.pdf b/docs/reference/PlantUML_Language_Reference_Guide.pdf
new file mode 100755 (executable)
index 0000000..2a8c568
Binary files /dev/null and b/docs/reference/PlantUML_Language_Reference_Guide.pdf differ
diff --git a/docs/sequence_activity_diagram/avplusplayer_adapter/avplusplayer_adapter_sequence_diagram.plantuml b/docs/sequence_activity_diagram/avplusplayer_adapter/avplusplayer_adapter_sequence_diagram.plantuml
new file mode 100755 (executable)
index 0000000..b739ae4
--- /dev/null
@@ -0,0 +1,33 @@
+@startuml\r
+\r
+actor App\r
+boundary AvPlayInstance\r
+\r
+App -> AvPlayInstance :  AVPlayOpen(url)\r
+note left : request playback\r
+AvPlayInstance -> AvPlusPlayer : Open(url)\r
+AvPlusPlayer -> Plusplayer : Open(url)\r
+AvPlusPlayer -> Plusplayer : RegisterEventListener()\r
+\r
+App -> AvPlayInstance : AVPlaySetBufferingParam()\r
+AvPlayInstance -> AvPlusPlayer : setBufferingParam()\r
+AvPlusPlayer -> Plusplayer : SetBufferConfig()\r
+App -> AvPlayInstance : AVPlaySetDisplayRect()\r
+AvPlayInstance -> AvPlusPlayer : SetOutputArea()\r
+AvPlusPlayer -> Plusplayer : SetDisplayMode()\r
+AvPlusPlayer -> Plusplayer : SetDisplayRoi()\r
+AvPlusPlayer -> Plusplayer : SetDisplay(Evas_Object*)\r
+App -> AvPlayInstance : AVPlaySetStreamingProperty()\r
+AvPlayInstance -> AvPlusPlayer : SetStreamingProperty()\r
+AvPlusPlayer -> Plusplayer : SetStreamingProperty()\r
+\r
+App -> AvPlayInstance : AVPlayPrepare()\r
+AvPlayInstance -> AvPlusPlayer : prepareAsync()\r
+AvPlusPlayer -> Plusplayer : PrepareAsync()\r
+Plusplayer --> AvPlusPlayer : OnPrepareDone(ret)\r
+AvPlusPlayer --> AvPlayInstance : onAsyncEventComplete()\r
+App -> AvPlayInstance : AVPlayPlay()\r
+AvPlayInstance -> AvPlusPlayer : play()\r
+AvPlusPlayer -> Plusplayer : Start()\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/dash_drm_playback/dash_drm_playback_base_flow_1.plantuml b/docs/sequence_activity_diagram/dash_drm_playback/dash_drm_playback_base_flow_1.plantuml
new file mode 100755 (executable)
index 0000000..83f267b
--- /dev/null
@@ -0,0 +1,53 @@
+@startuml\r
+\r
+title dash_drm_playback_base_flow_1\r
+\r
+BmsAvPlayer -> TvplusPlusplayerAdapter : m_Play()\r
+TvplusPlusplayerAdapter -> CBmsDrmHandler : StoreDrmInfo()\r
+activate CBmsDrmHandler\r
+CBmsDrmHandler -> DrmManager : DMGRCreateDRMSession(DRM_TYPE_EME)\r
+CBmsDrmHandler -> DrmManager : DMGRSetDRMLocalMode()\r
+DrmManager -> IEME : create_session()\r
+IEME --> DrmManager : drm_handle*\r
+DrmManager --> CBmsDrmHandler : return\r
+CBmsDrmHandler --> TvplusPlusplayerAdapter : return\r
+deactivate CBmsDrmHandler\r
+TvplusPlusplayerAdapter -> CBmsDrmHandler : GetDrmHandle()\r
+CBmsDrmHandler --> TvplusPlusplayerAdapter : drm_handle*\r
+TvplusPlusplayerAdapter -> Plusplayer : SetDrm(DrmInfo)\r
+Plusplayer -> TrackRenderer : SetDrmInfo(DrmInfo)\r
+TvplusPlusplayerAdapter -> Plusplayer : PrepareAsync()\r
+Plusplayer -> TrackRenderer : Prepare()\r
+activate TrackRenderer\r
+group CreatePipeline\r
+  TrackRenderer -> Gstreamer : factory_make(appsrc)\r
+  TrackRenderer -> Gstreamer : factory_make(drm_eme)\r
+  TrackRenderer --> DrmEme : g_object_set(DrmInitData_Callback)\r
+  TrackRenderer -> Gstreamer : factory_make(omx_decoder)\r
+  TrackRenderer -> Gstreamer : factory_make(sink)\r
+  TrackRenderer -> Gstreamer : set_state(GST_STATE_PAUSE)(async)\r
+  TrackRenderer -> TrackRenderer : wait state_changed\r
+  activate TrackRenderer #DarkSalmon\r
+  DrmEme --> TrackRenderer : DrmInitData_Callback(init_data)\r
+  TrackRenderer --> Plusplayer : OnDrmInitData(init_data, tracktype)\r
+  Plusplayer --> TvplusPlusplayerAdapter : OnDrmInitData(init_data, tracktype)\r
+  activate TvplusPlusplayerAdapter\r
+  TvplusPlusplayerAdapter -> CBmsDrmHandler : SetDrmInitData(init_data)\r
+  activate CBmsDrmHandler\r
+  CBmsDrmHandler -> DrmManager : DMGRSetDrmInitData(init_data)\r
+  DrmManager --> CBmsDrmHandler : return\r
+  CBmsDrmHandler --> TvplusPlusplayerAdapter : return\r
+  deactivate CBmsDrmHandler\r
+  TvplusPlusplayerAdapter -> Plusplayer : DrmLicenseAcquiredDone(tracktype)\r
+  deactivate TvplusPlusplayerAdapter\r
+  Plusplayer -> TrackRenderer : DrmLicenseAcquiredDone(tractype)\r
+  TrackRenderer -> DrmEme : g_object_set(getrights-complete-return)\r
+  DrmEme --> Gstreamer : state_changed\r
+  Gstreamer --> TrackRenderer : state_changed\r
+  deactivate TrackRenderer\r
+end\r
+TrackRenderer -> Plusplayer : return\r
+deactivate TrackRenderer\r
+Plusplayer --> TvplusPlusplayerAdapter : OnPrepareDone(ret)\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/source_change/source_change_base_flow_1.plantuml b/docs/sequence_activity_diagram/source_change/source_change_base_flow_1.plantuml
new file mode 100755 (executable)
index 0000000..7cfcce8
--- /dev/null
@@ -0,0 +1,49 @@
+@startuml\r
+\r
+ref over BmsAVPlayer, TvplusPlusplayerHelper, Plusplayer\r
+playing previous channel\r
+end ref\r
+\r
+BmsAVPlayer -> TvplusPlusplayerHelper : m_PlayPosition()\r
+note left : request channel change\r
+TvplusPlusplayerHelper -> TvplusPlusplayerHelper : compare codec info\r
+alt if codec info is same\r
+TvplusPlusplayerHelper -> Plusplayer : ChangeSource(url,resume_time)\r
+Plusplayer -> StateManager : ProcessEvent(StopSource)\r
+StateManager -> TrackSourceCompositor : StopSource(type)\r
+TrackSourceCompositor -> HlSTrackSource : Stop()\r
+TrackSourceCompositor --> StateManager : ret\r
+StateManager -> MetaStateMachine : request state to SourceStopped\r
+MetaStateMachine -> StateManager : state changed\r
+StateManager -> TrackSourceCompositor : DeleteSource(type)\r
+TrackSourceCompositor -> HlSTrackSource : <<destroy>>\r
+destroy HlSTrackSource\r
+TrackSourceCompositor --> StateManager : ret\r
+StateManager --> Plusplayer : done\r
+Plusplayer -> ChangeSourceTask : create task\r
+ChangeSourceTask -> StateManager : ProcessEvent(InitializeSource)\r
+StateManager -> TrackSourceCompositor : AddSource(type)\r
+create DashTrackSource\r
+TrackSourceCompositor -> DashTrackSource : <<create>>\r
+StateManager --> ChangeSourceTask : ret\r
+ChangeSourceTask -> StateManager : ProcessEvent(PrepareSource)\r
+StateManager -> TrackSourceCompositor : Prepare()\r
+TrackSourceCompositor -> DashTrackSource : Prepare()\r
+StateManager --> ChangeSourceTask : ret\r
+ChangeSourceTask -> StateManager : ProcessEvent(Start)\r
+StateManager -> TrackSourceCompositor : Start()\r
+TrackSourceCompositor -> DashTrackSource : Start()\r
+StateManager --> ChangeSourceTask : ret\r
+ChangeSourceTask --> Plusplayer : ret\r
+Plusplayer --> TvplusPlusplayerHelper : OnChangeSourceDone(ret)\r
+else if codec is not same\r
+TvplusPlusplayerHelper -> Plusplayer : Stop and Destroy\r
+TvplusPlusplayerHelper -> Plusplayer : PlusPlayer::Create()\r
+TvplusPlusplayerHelper -> Plusplayer : Open(url)\r
+TvplusPlusplayerHelper -> Plusplayer : PrepareAsync(url)\r
+...\r
+Plusplayer --> TvplusPlusplayerHelper : OnPrepareDone(ret)\r
+TvplusPlusplayerHelper -> Plusplayer : Start()\r
+end\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/trackrenderer_adapter/trackrenderer_adapter.plantuml b/docs/sequence_activity_diagram/trackrenderer_adapter/trackrenderer_adapter.plantuml
new file mode 100755 (executable)
index 0000000..2432b66
--- /dev/null
@@ -0,0 +1,13 @@
+@startuml\r
+\r
+title TrackRendererAdapter Sequence Diagram\r
+participant DefaultPlayer\r
+\r
+create TrackRendererAdapter\r
+DefaultPlayer -> TrackRendererAdapter : TrackRendererAdapter::Create()\r
+TrackRendererAdapter -> TrackRendererCapi : trackrenderer_create()\r
+create TrackRenderer\r
+TrackRendererCapi -> TrackRenderer : std::unique_ptr<T>(new TrackRenderer)\r
+TrackRendererCapi --> TrackRendererAdapter : handle\r
+\r
+@enduml\r
diff --git a/docs/sequence_activity_diagram/tracksource/tracksource_alternative_flow_1.plantuml b/docs/sequence_activity_diagram/tracksource/tracksource_alternative_flow_1.plantuml
new file mode 100755 (executable)
index 0000000..c1d70e4
--- /dev/null
@@ -0,0 +1,34 @@
+@startuml\r
+\r
+title tracksource_alternative_flow_1\r
+\r
+actor App\r
+boundary BmsService\r
+\r
+App -> BmsService : request playback\r
+BmsService -> Plusplayer : Open(url)\r
+Plusplayer -> TrackSource : TrackSource::CreateCompositor()\r
+Plusplayer -> TrackSourceCompositor : RegisterEventListener(this)\r
+BmsService -> Plusplayer : RegisterEventListener()\r
+BmsService -> Plusplayer : SetSourceType(sourcetype)\r
+BmsService -> Plusplayer : PrepareAsync()\r
+Plusplayer -> TrackSourceCompositor : AddSource(sourcetype)\r
+activate TrackSourceCompositor\r
+TrackSourceCompositor -> HttpTrackSource : new\r
+HttpTrackSource --> TrackSourceCompositor : object\r
+Plusplayer -> TrackSourceCompositor : Prepare()\r
+TrackSourceCompositor -> HttpTrackSource : Prepare()\r
+group CreatePipeline\r
+HttpTrackSource -> gstreamer : pipeline_new()\r
+HttpTrackSource -> gstreamer : factory_make(src)\r
+HttpTrackSource -> gstreamer : factory_make(http_demuxer)\r
+HttpTrackSource -> gstreamer : factory_make(...)\r
+HttpTrackSource -> gstreamer : set_state(PAUSE)\r
+gstreamer --> HttpTrackSource : state_changed\r
+end\r
+HttpTrackSource --> TrackSourceCompositor : success\r
+TrackSourceCompositor --> Plusplayer : success\r
+deactivate TrackSourceCompositor\r
+Plusplayer --> BmsService : Listener::PrepareDone(success)\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/tracksource/tracksource_base_flow_1.plantuml b/docs/sequence_activity_diagram/tracksource/tracksource_base_flow_1.plantuml
new file mode 100755 (executable)
index 0000000..c210b17
--- /dev/null
@@ -0,0 +1,42 @@
+@startuml\r
+\r
+title tracksource_base_flow_1\r
+\r
+actor App\r
+boundary BmsService\r
+\r
+App -> BmsService : request playback\r
+BmsService -> Plusplayer : Open(url)\r
+Plusplayer -> TrackSource : TrackSource::CreateCompositor()\r
+Plusplayer -> TrackSourceCompositor : RegisterEventListener(this)\r
+BmsService -> Plusplayer : RegisterEventListener()\r
+\r
+BmsService -> Plusplayer : PrepareAsync()\r
+Plusplayer -> TrackSourceCompositor : AddSource(url)\r
+activate TrackSourceCompositor\r
+TrackSourceCompositor -> Typefinder : probe()\r
+group createpipeline\r
+Typefinder -> gstreamer : pipeline_new()\r
+Typefinder -> gstreamer : factory_make(src)\r
+Typefinder -> gstreamer : factory_make(typefinder)\r
+gstreamer --> Typefinder : OnHaveType_(sourcetype)\r
+end\r
+Typefinder --> TrackSourceCompositor : sourcetype\r
+TrackSourceCompositor -> HttpTrackSource : new\r
+\r
+HttpTrackSource --> TrackSourceCompositor : object\r
+\r
+Plusplayer -> TrackSourceCompositor : Prepare()\r
+TrackSourceCompositor -> HttpTrackSource : Prepare()\r
+group CreatePipeline\r
+HttpTrackSource -> gstreamer : factory_make(http_demuxer)\r
+HttpTrackSource -> gstreamer : factory_make(...)\r
+HttpTrackSource -> gstreamer : set_state(PAUSE)\r
+gstreamer --> HttpTrackSource : state_changed\r
+end\r
+HttpTrackSource --> TrackSourceCompositor : success\r
+TrackSourceCompositor --> Plusplayer : success\r
+deactivate TrackSourceCompositor\r
+Plusplayer --> BmsService : Listener::PrepareDone(success)\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_1.plantuml b/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_1.plantuml
new file mode 100755 (executable)
index 0000000..b127340
--- /dev/null
@@ -0,0 +1,29 @@
+@startuml\r
+\r
+title tracksource_exception_flow_1\r
+\r
+actor App\r
+boundary BmsService\r
+\r
+App -> BmsService : request playback\r
+BmsService -> Plusplayer : Open(url)\r
+Plusplayer -> TrackSource : TrackSource::CreateCompositor()\r
+Plusplayer -> TrackSourceCompositor : RegisterEventListener(this)\r
+BmsService -> Plusplayer : RegisterEventListener()\r
+\r
+BmsService -> Plusplayer : PrepareAsync()\r
+Plusplayer -> TrackSourceCompositor : AddSource(url)\r
+activate TrackSourceCompositor\r
+TrackSourceCompositor -> Typefinder : probe()\r
+group createpipeline\r
+Typefinder -> gstreamer : pipeline_new()\r
+Typefinder -> gstreamer : factory_make(src)\r
+Typefinder -> gstreamer : factory_make(typefinder)\r
+gstreamer --> Typefinder : Error()\r
+end\r
+Typefinder --> TrackSourceCompositor : fail\r
+TrackSourceCompositor --> Plusplayer : fail\r
+deactivate TrackSourceCompositor\r
+Plusplayer --> BmsService : Listener::PrepareDone(fail)\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_2.plantuml b/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_2.plantuml
new file mode 100755 (executable)
index 0000000..bb7ec0e
--- /dev/null
@@ -0,0 +1,29 @@
+@startuml\r
+\r
+title tracksource_exception_flow_2\r
+\r
+actor App\r
+boundary BmsService\r
+\r
+App -> BmsService : request playback\r
+BmsService -> Plusplayer : Open(url)\r
+Plusplayer -> TrackSource : TrackSource::CreateCompositor()\r
+Plusplayer -> TrackSourceCompositor : RegisterEventListener(this)\r
+BmsService -> Plusplayer : RegisterEventListener()\r
+\r
+BmsService -> Plusplayer : PrepareAsync()\r
+Plusplayer -> TrackSourceCompositor : AddSource(url)\r
+activate TrackSourceCompositor\r
+TrackSourceCompositor -> Typefinder : probe()\r
+group createpipeline\r
+Typefinder -> gstreamer : pipeline_new()\r
+Typefinder -> gstreamer : factory_make(src)\r
+Typefinder -> gstreamer : factory_make(typefinder)\r
+gstreamer --> Typefinder : Error()\r
+end\r
+Typefinder --> TrackSourceCompositor : fail\r
+TrackSourceCompositor --> Plusplayer : fail\r
+deactivate TrackSourceCompositor\r
+Plusplayer --> BmsService : Listener::PrepareDone(fail)\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_3.plantuml b/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_3.plantuml
new file mode 100755 (executable)
index 0000000..0a5083c
--- /dev/null
@@ -0,0 +1,42 @@
+@startuml\r
+\r
+title tracksource_exception_flow_3\r
+\r
+actor App\r
+boundary BmsService\r
+\r
+App -> BmsService : request playback\r
+BmsService -> Plusplayer : Open(url)\r
+Plusplayer -> TrackSource : TrackSource::CreateCompositor()\r
+Plusplayer -> TrackSourceCompositor : RegisterEventListener(this)\r
+BmsService -> Plusplayer : RegisterEventListener()\r
+\r
+BmsService -> Plusplayer : PrepareAsync()\r
+Plusplayer -> TrackSourceCompositor : AddSource(url)\r
+activate TrackSourceCompositor\r
+TrackSourceCompositor -> Typefinder : probe()\r
+group createpipeline\r
+Typefinder -> gstreamer : pipeline_new()\r
+Typefinder -> gstreamer : factory_make(src)\r
+Typefinder -> gstreamer : factory_make(typefinder)\r
+gstreamer --> Typefinder : OnHaveType_(sourcetype)\r
+end\r
+Typefinder --> TrackSourceCompositor : sourcetype\r
+TrackSourceCompositor -> HttpTrackSource : new\r
+\r
+HttpTrackSource --> TrackSourceCompositor : object\r
+\r
+Plusplayer -> TrackSourceCompositor : Prepare()\r
+TrackSourceCompositor -> HttpTrackSource : Prepare()\r
+group CreatePipeline\r
+HttpTrackSource -> gstreamer : factory_make(http_demuxer)\r
+HttpTrackSource -> gstreamer : factory_make(...)\r
+HttpTrackSource -> gstreamer : set_state(PAUSE)\r
+gstreamer --> HttpTrackSource : SyncMessageHandler(Error)\r
+end\r
+HttpTrackSource --> TrackSourceCompositor : fail\r
+TrackSourceCompositor --> Plusplayer : fail\r
+deactivate TrackSourceCompositor\r
+Plusplayer --> BmsService : Listener::OnPrepareDone(fail)\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/tvplus_update_activity_diagram/risk_management_lib_api_validation.plantuml b/docs/sequence_activity_diagram/tvplus_update_activity_diagram/risk_management_lib_api_validation.plantuml
new file mode 100755 (executable)
index 0000000..19cd0f5
--- /dev/null
@@ -0,0 +1,26 @@
+@startuml\r
+\r
+database VersionInfo\r
+participant BmsService\r
+participant APIWrapper\r
+database Plusplayer.so\r
+\r
+ref over VersionInfo : VersionInfo contains libVersion and apiVersion\r
+ref over BmsService , VersionInfo : Compiled in SDK\r
+ref over BmsService , APIWrapper : downloaded and installed\r
+BmsService -> APIWrapper : Init()\r
+APIWrapper -> Plusplayer.so : GetVersion()\r
+Plusplayer.so --> APIWrapper : VersionInfo\r
+ref over APIWrapper : update current-apiVersion\r
+...\r
+BmsService -> APIWrapper : NewFunction()\r
+APIWrapper -> APIWrapper : check apiVersion\r
+alt current-apiVersion supports NewFuntion\r
+ref over Plusplayer.so : do something\r
+else current-apiVersion not support NewFuntion\r
+APIWrapper --> BmsService : return false\r
+end\r
+' 수정사항의 일부만 이전 모델에 반영 하는 경우....\r
+\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/tvplus_update_activity_diagram/update_procedure.plantuml b/docs/sequence_activity_diagram/tvplus_update_activity_diagram/update_procedure.plantuml
new file mode 100755 (executable)
index 0000000..e89ecf3
--- /dev/null
@@ -0,0 +1,27 @@
+@startuml\r
+\r
+title TVPlus Player update process\r
+\r
+(*) --> "Developing/Fixing Issues"\r
+--> "Make TC"\r
+--> "Devoloper Functional Verification"\r
+if "is there no issues ?" then\r
+--> [fail] "Developing/Fixing Issues"\r
+else\r
+--> [pass] "API Review w/ API reviewer board"\r
+--> "Binary Compatibility Test"\r
+if "is there no issues ?" then\r
+--> [fail] "Developing/Fixing Issues"\r
+else\r
+--> [pass] "Library distribution to Bms Team"\r
+--> "bms-daemon tpk packaing w/ player libraries"\r
+--> Installation & Verification\r
+if "is there no issues ?" then\r
+--> [fail] "Developing/Fixing Issues"\r
+else\r
+--> [pass] "Minor/Patch Version Update"\r
+--> "Request Release to Release Team"\r
+--> "App server registration"\r
+--> [Ending Process] (*)\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/sequence_activity_diagram/tvplusplusplayerhelper/tvplusplusplayerhelper_sequence_diagram.plantuml b/docs/sequence_activity_diagram/tvplusplusplayerhelper/tvplusplusplayerhelper_sequence_diagram.plantuml
new file mode 100755 (executable)
index 0000000..e1d7ed8
--- /dev/null
@@ -0,0 +1,18 @@
+@startuml\r
+\r
+BmsAVPlayer -> TvplusPlusplayerHelper : m_CreatePlayer()\r
+TvplusPlusplayerHelper -> Plusplayer : PlusPlayer::Create()\r
+Plusplayer --> TvplusPlusplayerHelper : object*\r
+BmsAVPlayer -> TvplusPlusplayerHelper : m_OpenStream()\r
+TvplusPlusplayerHelper -> Plusplayer : Open(url)\r
+TvplusPlusplayerHelper -> Plusplayer : SetBufferConfig()\r
+TvplusPlusplayerHelper -> Plusplayer : SetDisplayMode()\r
+TvplusPlusplayerHelper -> Plusplayer : SetDisplayRoi()\r
+TvplusPlusplayerHelper -> Plusplayer : SetDisplay(Evas_Object*)\r
+TvplusPlusplayerHelper -> Plusplayer : SetStreamingProperty()\r
+BmsAVPlayer -> TvplusPlusplayerHelper : m_Play()\r
+TvplusPlusplayerHelper -> Plusplayer : PrepareAsync()\r
+Plusplayer -> TvplusPlusplayerHelper : OnPrepareDone(ret)\r
+TvplusPlusplayerHelper -> Plusplayer : Start()\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/state_diagram/plusplayer_internal_state_diagram.png b/docs/state_diagram/plusplayer_internal_state_diagram.png
new file mode 100755 (executable)
index 0000000..573061b
Binary files /dev/null and b/docs/state_diagram/plusplayer_internal_state_diagram.png differ
diff --git a/docs/state_diagram/state_diagram.plantuml b/docs/state_diagram/state_diagram.plantuml
new file mode 100755 (executable)
index 0000000..4c69a8a
--- /dev/null
@@ -0,0 +1,74 @@
+@startuml\r
+'skinparam backgroundColor LightYellow\r
+\r
+title plusplayer_internal_state_diagram\r
+\r
+state None {\r
+}\r
+state Idle {\r
+}\r
+state IdleInactive {\r
+}\r
+state TypeFinderReady {\r
+}\r
+state TrackSourceReady {\r
+}\r
+state Ready {\r
+}\r
+state ResourceConflicted {\r
+}\r
+\r
+\r
+[*] --> None\r
+None --> Idle : open\r
+None --> None : close\r
+\r
+Idle --> None : close\r
+Idle --> TypeFinderReady : probe\r
+Idle --> TypeFinderReady : pause_or_start_defered\r
+Idle --> IdleInactive : stop\r
+\r
+TypeFinderReady --> TrackSourceReady : prepare_source\r
+TypeFinderReady --> TrackSourceReady : pause_or_start_defered\r
+TypeFinderReady --> IdleInactive : stop\r
+\r
+TrackSourceReady --> Ready : prepare_renderer\r
+TrackSourceReady --> Ready : pause_or_start_defered\r
+TrackSourceReady --> IdleInactive : stop\r
+\r
+Ready --> Playing : start\r
+Ready --> Paused : pause\r
+Ready --> ResourceConflicted : resource_conflict\r
+Ready --> IdleInactive : stop\r
+Ready --> SourceStopped : stop_source\r
+\r
+Playing --> Paused : pause\r
+Playing --> Playing : resume\r
+Playing --> Paused : internal_pause\r
+Playing --> ResourceConflicted : resource_conflict\r
+Playing --> IdleInactive : stop\r
+Playing --> SourceStopped : stop_source\r
+\r
+Paused --> Playing : resume\r
+Paused --> Paused: pause\r
+Paused --> Playing : internal_resume\r
+Paused --> ResourceConflicted : resource_conflict\r
+Paused --> IdleInactive : stop\r
+Paused --> SourceStopped : stop_source\r
+\r
+ResourceConflicted --> Ready : restore\r
+ResourceConflicted --> IdleInactive : stop\r
+\r
+SourceChanged --> Playing : start\r
+SourceChanged --> SourceStopped : stop_source\r
+SourceChanged --> IdleInactive : stop\r
+SourceInitialized --> SourceChanged : prepare_source\r
+SourceInitialized --> SourceStopped : stop_source\r
+SourceInitialized --> IdleInactive : stop\r
+\r
+SourceStopped --> SourceInitialized : initialize_source\r
+SourceStopped --> IdleInactive : stop\r
+\r
+IdleInactive --> None : close\r
+\r
+@enduml
\ No newline at end of file
diff --git a/docs/state_diagram/state_diagram_v2_substatemachine.plantuml b/docs/state_diagram/state_diagram_v2_substatemachine.plantuml
new file mode 100755 (executable)
index 0000000..694fd69
--- /dev/null
@@ -0,0 +1,105 @@
+@startuml\r
+\r
+'skinparam backgroundColor LightYellow\r
+\r
+title plusplayer_internal_state_diagram\r
+\r
+state Statemanager {\r
+\r
+note "Active state" as N1\r
+\r
+state Idle {\r
+  [*] --> IdleZero\r
+  state TypeFinderReady {\r
+  }\r
+  state TrackSourceReady {\r
+  }\r
+  Idle: defer InternalPause\r
+  Idle: defer InternalResume\r
+\r
+  IdleZero --> PseudoExit3 : close\r
+  IdleZero --> TypeFinderReady : probe\r
+  TypeFinderReady --> TrackSourceReady : prepare_source\r
+  TrackSourceReady --> PseudoExit : prepare_renderer\r
+\r
+  IdleZero : defer SelectTrack()\r
+  IdleZero : defer Pause()\r
+  IdleZero : defer Start()\r
+  TypeFinderReady : defer SelectTrack()\r
+  TypeFinderReady : defer Pause()\r
+  TypeFinderReady : defer Start()\r
+  TrackSourceReady : defer Pause()\r
+  TrackSourceReady : defer Start()\r
+  TrackSourceReady --> TrackSourceReady : SelectTrack()\r
+}\r
+\r
+state ChangingSource {\r
+  state SourceStopped {\r
+  }\r
+  state SourceInitialized {\r
+  }\r
+  ChangingSource: defer InternalPause\r
+  ChangingSource: defer InternalResume\r
+\r
+  [*] --> SourceStopped\r
+\r
+  SourceStopped --> SourceInitialized : initialize_source\r
+  SourceStopped --> SourceStopped : stop_source\r
+\r
+  SourceInitialized --> SourceStopped : stop_source\r
+  SourceInitialized --> PseudoExit1 : prepare_source\r
+}\r
+\r
+[*] --> None\r
+None --> Idle : open\r
+None --> None : close\r
+PseudoExit3 --> None : close\r
+PseudoExit --> Ready : prepare_renderer\r
+\r
+Ready --> Playing : start\r
+Ready --> Paused : pause\r
+Ready --> Ready : internal_pause\r
+Ready --> Playing : internal_resume\r
+Paused --> Playing : resume\r
+Paused --> Playing : internal_resume\r
+Paused --> Paused : internal_pause\r
+Paused --> Playing : start\r
+Playing --> Paused : pause\r
+Playing --> Paused : internal_pause\r
+\r
+Paused --> Paused: pause\r
+Playing --> Playing : resume\r
+\r
+ResourceConflicted --> Ready : restore\r
+Ready --> ResourceConflicted : resource_conflict\r
+Playing --> ResourceConflicted : resource_conflict\r
+Paused --> ResourceConflicted : resource_conflict\r
+\r
+Ready --> ChangingSource : stop_source\r
+Paused --> ChangingSource : stop_source\r
+Playing --> ChangingSource : stop_source\r
+\r
+PseudoExit1 --> Ready : prepare_source\r
+\r
+Playing --> Playing : seek\r
+Paused --> Paused : seek\r
+\r
+Ready --> Ready : select_track()\r
+Playing --> Playing : select_track()\r
+Paused --> Paused : select_track()\r
+\r
+--\r
+\r
+note "Inactive state" as N2\r
+[*] --> Active\r
+Active --> Inactive : stop\r
+Inactive --> Inactive : stop\r
+note right of Inactive\r
+Inactive is interrupt state only allowing {stop , close} events.\r
+others will be ignored.\r
+end note\r
+Inactive --> Close : close\r
+\r
+}\r
+\r
+@enduml
\ No newline at end of file
diff --git a/include/trackrenderer_capi/buffer.h b/include/trackrenderer_capi/buffer.h
new file mode 100755 (executable)
index 0000000..45dd724
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * @file
+ * @brief          the buffer for playback.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style buffer related enum.
+ * @see            N/A
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+#ifndef __PLUSPLAYER_TRACKRENDERER_CAPI_BUFFER_H__
+#define __PLUSPLAYER_TRACKRENDERER_CAPI_BUFFER_H__
+
+#include <cstdint>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the buffer status
+ */
+enum TrackRendererBufferStatus {
+  kTrackRendererBufferStatusUnderrun,
+  kTrackRendererBufferStatusOverrun
+};
+
+/**
+ * @brief  Enumerations for video decoded buffer type
+ */
+enum TrackRendererDecodedVideoFrameBufferType {
+  kTrackRendererDecodedVideoFrameBufferNone,
+  kTrackRendererDecodedVideoFrameBufferCopy,
+  kTrackRendererDecodedVideoFrameBufferReference,
+  kTrackRendererDecodedVideoFrameBufferScale
+};
+
+/**
+ * @brief  video decoded buffer struct
+ */
+typedef struct {
+  /**
+   * @description   buffer pts, in millisecond
+   */
+  uint64_t pts;
+  /**
+   *@description   buffer duration, in millisecond
+   */
+  uint64_t duration;
+  /**
+   * @description   surface data
+   */
+  void* surface_data;
+  /**
+   * @description   the scaler index,0 1 ...
+   */
+  void* scaler_index;
+} TrackRendererDecodedVideoPacket;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CAPI_BUFFER_H__
diff --git a/include/trackrenderer_capi/decoderinputbuffer.h b/include/trackrenderer_capi/decoderinputbuffer.h
new file mode 100755 (executable)
index 0000000..69bab44
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * @file           decoderinputbuffer.h
+ * @brief          Managed decoderinputbuffer related data structures and enums
+ *                 used by trackrenderer apis.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style decoderinputbuffer releted data
+ *                 structures and enums.
+ * @see            The decoderinputbuffer related enum values and data
+ *                 structures will be converted by this managed C version types
+ *                 to avoid binary compatibility.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DECODERINPUTBUFFER_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DECODERINPUTBUFFER_H__
+
+#include "gst/gst.h"
+
+#include "trackrenderer_capi/track.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Trackrenderer must not have the gstreamer dependency since Tizen 5.5.
+ * TRACKRENDERER_GST_DEPENDENCY_REMOVAL must be defined since Tizen 5.5
+ * The type of buffer memeber variable has been defined as GstBuffer* in rootstrap of Tizen 5.0.
+ * The variable type should be defined differently because of tvplus-services tpk's compiling issue.
+ */
+#define TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+
+/**
+ * @brief  Enumerations for the decoder input buffer
+ */
+typedef struct _TrackRendererDecoderInputBuffer {
+  /**
+   * @description   track type(audio, video, subtitle)
+   * @remark        default value is kTrackRendererTrackTypeMax
+   */
+  TrackRendererTrackType type;
+
+  /**
+   * @description   buffer index
+   */
+  int index;
+
+  /**
+   * @description   gst buffer
+   * @remark        default value is nullptr
+   */
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  void* buffer;
+#else
+  GstBuffer* buffer;
+#endif
+} TrackRendererDecoderInputBuffer;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DECODERINPUTBUFFER_H__
diff --git a/include/trackrenderer_capi/display.h b/include/trackrenderer_capi/display.h
new file mode 100755 (executable)
index 0000000..2270f29
--- /dev/null
@@ -0,0 +1,160 @@
+/**
+ * @file
+ * @brief          Managed display related data structures and enums used by
+ *                 trackrenderer apis.
+ * @interfacetype  Platform
+ * @platform_porting_interface
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style display releted data structures
+ *                 and enums.
+ * @see            The display related enum values and data structures will be
+ *                 converted by this managed C version types to avoid binary
+ *                 compatibility.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DISPLAY_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DISPLAY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @brief   Region of interest area of display
+ */
+typedef struct _TrackRendererGeometry {
+  /**
+   * @description   x value of display window
+   */
+  int x;
+
+  /**
+   * @description   y value of display window
+   */
+  int y;
+
+  /**
+   * @description   width of display window
+   */
+  int w;
+
+  /**
+   * @description   height of display window
+   */
+  int h;
+} TrackRendererGeometry;
+
+/**
+ * @brief   Region of crop area of display
+ */
+typedef struct _TrackRendererCropArea {
+  /**
+   * @description   scaled x label ratio
+   */
+  double scale_x;
+
+  /**
+   * @description   scaled y label ratio
+   */
+  double scale_y;
+
+  /**
+   * @description   scaled width ratio
+   */
+  double scale_w;
+
+  /**
+   * @description   scaled heigh ratio
+   */
+  double scale_h;
+
+} TrackRendererCropArea;
+
+/**
+ * @brief   Region of render rectangle
+ */
+typedef struct _TrackRendererRenderRect {
+  /**
+   * @description   x value of render rectangle
+   */
+  int x;
+
+  /**
+   * @description   y value of render rectangle
+   */
+  int y;
+
+  /**
+   * @description   width of render rectangle
+   */
+  int w;
+
+  /**
+   * @description   height of render rectangle
+   */
+  int h;
+} TrackRendererRenderRect;
+
+/**
+ * @brief  Enumerations for the display type
+ */
+enum TrackRendererDisplayType {
+  kTrackRendererDisplayTypeNone,
+  kTrackRendererDisplayTypeOverlay,
+  kTrackRendererDisplayTypeEvas
+};
+
+/**
+ * @brief  Enumerations for the display mode
+ */
+enum TrackRendererDisplayMode {
+  kTrackRendererDisplayModeLetterBox,
+  kTrackRendererDisplayModeOriginSize,
+  kTrackRendererDisplayModeFullScreen,
+  kTrackRendererDisplayModeCroppedFull,
+  kTrackRendererDisplayModeOriginOrLetter,
+  kTrackRendererDisplayModeDstRoi,
+  kTrackRendererDisplayModeAutoAspectRatio,
+  kTrackRendererDisplayModeDisplayMax
+};
+
+/**
+ * @brief  Enumerations for the display rotate angle
+ */
+enum TrackRendererDisplayRotate {
+  kTrackRendererDisplayRotateNone,
+  kTrackRendererDisplayRotate90,
+  kTrackRendererDisplayRotate180,
+  kTrackRendererDisplayRotate270
+};
+
+/**
+ * @brief  Enumerations for the still mode
+ */
+enum TrackRendererStillMode {
+  kTrackRendererStillModeNone,
+  kTrackRendererStillModeOff,
+  kTrackRendererStillModeOn
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DISPLAY_H__
diff --git a/include/trackrenderer_capi/drm.h b/include/trackrenderer_capi/drm.h
new file mode 100755 (executable)
index 0000000..c6f6a1f
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * @file           
+ * @brief          Managed drm related data structures and enums used by
+ *                 trackrenderer apis.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style drm releted data structures and
+ *                 enums.
+ * @see            Drm releated event listeners, enum classes, etc.. are
+ *                 converted to this.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DRM_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DRM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the drm type
+ */
+enum TrackRendererDrmType {
+  kTrackRendererDrmTypeNone,
+  kTrackRendererDrmTypePlayready,
+  kTrackRendererDrmTypeMarlin,
+  kTrackRendererDrmTypeVerimatrix,
+  kTrackRendererDrmTypeWidevineClassic,
+  kTrackRendererDrmTypeSecuremedia,
+  kTrackRendererDrmTypeSdrm,
+  kTrackRendererDrmTypeWidevineCdm,
+  kTrackRendererDrmTypeDrmMax
+};
+
+/**
+ * @brief   Drm properties
+ */
+typedef struct _TrackRendererDrmProperty {
+  /**
+   * @description   Drm type
+   */
+  TrackRendererDrmType type;
+
+  /**
+   * @description   Drm handle
+   */
+  int handle;
+
+  /**
+   * @description   External Decryption Mode
+   */
+  int external_decryption;
+
+  /**
+   * @description   The cb will be invoked when license was acquired.
+   */
+  void* license_acquired_cb;
+
+  /**
+   * @description   The userdata will be sent by license_acquired_cb
+   */
+  void* license_acquired_userdata;
+} TrackRendererDrmProperty;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_DRM_H__
diff --git a/include/trackrenderer_capi/error.h b/include/trackrenderer_capi/error.h
new file mode 100755 (executable)
index 0000000..457cb75
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * @file           
+ * @brief          managed error related enum used by trackrenderer apis.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style error releted enum.
+ * @see            All error enum values will be converted to this managed error
+ *                 types.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_ERROR_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_ERROR_H__
+
+#include "tizen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PLUSPLAYER_ERROR_CLASS TIZEN_ERROR_PLAYER | 0x20
+
+/* This is for custom defined player error. */
+#define PLUSPLAYER_CUSTOM_ERROR_CLASS TIZEN_ERROR_PLAYER | 0x1000
+
+/**
+ * @brief  Enumerations for the error type
+ */
+enum TrackRendererErrorType {
+  kTrackRendererErrorTypeErrorNone,
+  kTrackRendererErrorTypeOutOfMemory,
+  kTrackRendererErrorTypeInvalidParameter,
+  kTrackRendererErrorTypeNoSuchFile,
+  kTrackRendererErrorTypeInvalidOperation,
+  kTrackRendererErrorTypeFileNoSpaceOnDevice,
+  kTrackRendererErrorTypeFeatureNotSupportedOnDevice,
+  kTrackRendererErrorTypeSeekFailed,
+  kTrackRendererErrorTypeInvalidState,
+  kTrackRendererErrorTypeNotSupportedFile,
+  kTrackRendererErrorTypeInvalidUri,
+  kTrackRendererErrorTypeSoundPolicy,
+  kTrackRendererErrorTypeConnectionFailed,
+  kTrackRendererErrorTypeVideoCaptureFailed,
+  kTrackRendererErrorTypeDrmExpired,
+  kTrackRendererErrorTypeDrmNoLicense,
+  kTrackRendererErrorTypeDrmFutureUse,
+  kTrackRendererErrorTypeDrmNotPermitted,
+  kTrackRendererErrorTypeResourceLimit,
+  kTrackRendererErrorTypePermissionDenied,
+  kTrackRendererErrorTypeServiceDisconnected,
+  kTrackRendererErrorTypeBufferSpace,
+  kTrackRendererErrorTypeNotSupportedAudioCodec,
+  kTrackRendererErrorTypeNotSupportedVideoCodec,
+  kTrackRendererErrorTypeNotSupportedSubtitle,
+  kTrackRendererErrorTypeDrmInfo,
+  kTrackRendererErrorTypeNotSupportedFormat,
+  kTrackRendererErrorTypeStreamingPlayer,
+  kTrackRendererErrorTypeDtcpFsk,
+  kTrackRendererErrorTypePreLoadingTimeOut,
+  kTrackRendererErrorTypeNetworkError,
+  kTrackRendererErrorTypeChannelSurfingFailed,
+  kTrackRendererErrorTypeUnknown
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_API_DRM_H__
diff --git a/include/trackrenderer_capi/event.h b/include/trackrenderer_capi/event.h
new file mode 100755 (executable)
index 0000000..8c78038
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * @file
+ * @brief          The event for playback.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style event related enum and structure.
+ * @see            N/A
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__
+#define __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__
+
+#include <cstdint>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CAPI_EVENT_H__
diff --git a/include/trackrenderer_capi/iniproperty.h b/include/trackrenderer_capi/iniproperty.h
new file mode 100755 (executable)
index 0000000..4a20654
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * @file           iniproperty.h
+ * @brief          structure for iniproperty map converting.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style iniproperty releted enum.
+ * @see            Iniproperty map converting structure
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_INIPROPERTY_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_INIPROPERTY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Plusplayer ini property map pair.
+ */
+typedef struct _TrackRendererIniProperty {
+  /**
+   * @description   ini property.
+   */
+  const char* key;
+
+  /**
+   * @description   ini property value.
+   */
+  int value;
+} TrackRendererIniProperty;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_INIPROPERTY_H__
\ No newline at end of file
diff --git a/include/trackrenderer_capi/latency.h b/include/trackrenderer_capi/latency.h
new file mode 100755 (executable)
index 0000000..5db88cb
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * @file           
+ * @brief          managed error related enum used by trackrenderer apis.
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        3.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style error releted enum.
+ * @see            All error enum values will be converted to this managed error
+ *                 types.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_LATENCY_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_LATENCY_H__
+
+#include "tizen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @brief  Enumerations for the error type
+ */
+enum TrackRendererCatchUpSpeed {
+  kTrackRendererCatchUpSpeedNone,
+  kTrackRendererCatchUpSpeedSlow,
+  kTrackRendererCatchUpSpeedNormal,
+  kTrackRendererCatchUpSpeedFast
+};
+
+enum TrackRendererLatencyStatus {
+  kTrackRendererLatencyStatusLow,
+  kTrackRendererLatencyStatusMid,
+  kTrackRendererLatencyStatusHigh
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_LATENCY_H__
diff --git a/include/trackrenderer_capi/state.h b/include/trackrenderer_capi/state.h
new file mode 100755 (executable)
index 0000000..415d6fe
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * @brief          structure for converting state enum.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style state related enum.
+ * @see            State enum convertion.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_STATE_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_STATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the trackrenderer state
+ */
+enum TrackRendererState {
+  kTrackRendererStateInit,                // initial state
+  kTrackRendererStateWorking,             // normal working state
+  kTrackRendererStateResourceConflicted,  // resource conflicted state
+  kTrackRendererStateStopped,             // stopped state
+  kTrackRendererStateUnknown
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_STATE_H__
\ No newline at end of file
diff --git a/include/trackrenderer_capi/submitstatus.h b/include/trackrenderer_capi/submitstatus.h
new file mode 100755 (executable)
index 0000000..12b913d
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * @file
+ * @brief          structure for submitstatus enum converting.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style submitstatus related enum.
+ * @see            Submitstatus enum convertion.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_SUBMITSTATUS_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_SUBMITSTATUS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the submit status
+ */
+enum TrackRendererSubmitStatus {
+  kTrackRendererSubmitStatusNotPrepared,  // not prepared to get data
+  kTrackRendererSubmitStatusHold,         // valid data, hold this packet
+  kTrackRendererSubmitStatusFull,         // buffer already full
+  kTrackRendererSubmitStatusSuccess,      // submit succeeded
+  kTrackRendererSubmitStatusDrop,         // invalid data , drop this packet
+  kTrackRendererSubmitStatusFailed
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_SUBMITSTATUS_H__
\ No newline at end of file
diff --git a/include/trackrenderer_capi/track.h b/include/trackrenderer_capi/track.h
new file mode 100755 (executable)
index 0000000..4c94ed3
--- /dev/null
@@ -0,0 +1,364 @@
+/**
+ * @file
+ * @brief          Managed track related data structures and enums used by
+ *                 trackrenderer apis.
+ * @interfacetype  Platform
+ * @platform_porting_interface 
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style track releted data structures and
+ *                 enums.
+ * @see            All track releated types shared_ptr, boost::any, enum
+ *                 classes, std::string, etc.. are converted to this.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACK_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACK_H__
+
+#include <cstdint>
+#include <memory>
+
+#include "display.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Default value of track index.
+ */
+const int kTrackRendererInvalidTrackIndex = -1;
+
+/**
+ * @brief  Enumerations for the track type
+ */
+enum TrackRendererTrackType {
+  kTrackRendererTrackTypeAudio = 0,
+  kTrackRendererTrackTypeVideo,
+  kTrackRendererTrackTypeSubtitle,
+  kTrackRendererTrackTypeMax
+};
+
+/**
+ * @brief   Track info.
+ */
+typedef struct _TrackRendererTrack {
+  /**
+   * @description   Index.
+   */
+  int index;
+
+  /**
+   * @description   Id.
+   */
+  int id;
+
+  /**
+   * @description   Mime type.
+   * @remark  mimetype is declared as char pointer but it is actually
+   *          string type. It must have null at the end of array
+   *          to terminate string.
+   */
+  const char* mimetype;
+
+  /**
+   * @description   Stream type.
+   * @remark  streamtype is declared as char pointer but it is actually
+   *          string type. It must have null at the end of array
+   *          to terminate string.
+   */
+  const char* streamtype;
+
+  /**
+   * @description   Track type.
+   */
+  TrackRendererTrackType type;
+
+  /**
+   * @description   Codec data.
+   */
+  char* codec_data;
+
+  /**
+   * @description   Codec data lenth.
+   */
+  int codec_data_len;
+
+  /**
+   * @description   Width.
+   */
+  int width;
+
+  /**
+   * @description   Height.
+   */
+  int height;
+
+  /**
+   * @description   Max width.
+   */
+  int maxwidth;
+
+  /**
+   * @description   Max height.
+   */
+  int maxheight;
+
+  /**
+   * @description   Framerate numerator.
+   */
+  int framerate_num;
+
+  /**
+   * @description   Framerate denominator.
+   */
+  int framerate_den;
+
+  /**
+   * @description   Sample rate.
+   */
+  int sample_rate;
+
+  /**
+   * @description   Sample format.
+   */
+  int sample_format;
+
+  /**
+   * @description   Channel.
+   */
+  int channels;
+
+  /**
+   * @description   Version.
+   */
+  int version;
+
+  /**
+   * @description  Layer.
+   */
+  int layer;
+
+  /**
+   * @description   Bit per sample.
+   */
+  int bits_per_sample;
+
+  /**
+   * @description   Block alignment.
+   */
+  int block_align;
+
+  /**
+   * @description   Bit rate.
+   */
+  int bitrate;
+
+  /**
+   * @description   Endianness.
+   * @remark        little endian : 1234 \n
+   *                others big endian
+   */
+  int endianness;
+
+  /**
+   * @description   Signed or unsigned.
+   */
+  int is_signed;
+
+  /**
+   * @description   Active track.
+   */
+  int active;
+
+  /**
+   * @description   Use software decoder.
+   */
+  int use_swdecoder;
+
+  /**
+   * @description   Language code.
+   */
+  const char* language_code;
+
+  /**
+   * @description   Subtitle format.
+   */
+  const char* subtitle_format;
+} TrackRendererTrack;
+
+/**
+ * @brief  Enumerations for the subtitle attribute type
+ */
+enum TrackRendererSubtitleAttrType {
+  kTrackRendererSubtitleAttrTypeRegionXPos = 0,      // float type
+  kTrackRendererSubtitleAttrTypeRegionYPos,          // float type
+  kTrackRendererSubtitleAttrTypeRegionWidth,         // float type
+  kTrackRendererSubtitleAttrTypeRegionHeight,        // float type
+  kTrackRendererSubtitleAttrTypeWindowXPadding,      // float type
+  kTrackRendererSubtitleAttrTypeWindowYPadding,      // float type
+  kTrackRendererSubtitleAttrTypeWindowLeftMargin,    // int type
+  kTrackRendererSubtitleAttrTypeWindowRightMargin,   // int type
+  kTrackRendererSubtitleAttrTypeWindowTopMargin,     // int type
+  kTrackRendererSubtitleAttrTypeWindowBottomMargin,  // int type
+  kTrackRendererSubtitleAttrTypeWindowBgColor,       // int type
+  kTrackRendererSubtitleAttrTypeWindowOpacity,       // float type
+  kTrackRendererSubtitleAttrTypeWindowShowBg,  // how to show window background,
+                                               // uint type
+  kTrackRendererSubtitleAttrTypeFontFamily,                 // char* type
+  kTrackRendererSubtitleAttrTypeFontSize,                   // float type
+  kTrackRendererSubtitleAttrTypeFontWeight,                 // int type
+  kTrackRendererSubtitleAttrTypeFontStyle,                  // int type
+  kTrackRendererSubtitleAttrTypeFontColor,                  // int type
+  kTrackRendererSubtitleAttrTypeFontBgColor,                // int type
+  kTrackRendererSubtitleAttrTypeFontOpacity,                // float type
+  kTrackRendererSubtitleAttrTypeFontBgOpacity,              // float type
+  kTrackRendererSubtitleAttrTypeFontTextOutlineColor,       // int type
+  kTrackRendererSubtitleAttrTypeFontTextOutlineThickness,   // int type
+  kTrackRendererSubtitleAttrTypeFontTextOutlineBlurRadius,  // int type
+  kTrackRendererSubtitleAttrTypeFontVerticalAlign,          // int type
+  kTrackRendererSubtitleAttrTypeFontHorizontalAlign,        // int type
+  kTrackRendererSubtitleAttrTypeRawSubtitle,                // char* type
+  kTrackRendererSubtitleAttrTypeWebvttCueLine,              // float type
+  kTrackRendererSubtitleAttrTypeWebvttCueLineNum,           // int type
+  kTrackRendererSubtitleAttrTypeWebvttCueLineAlign,         // int type
+  kTrackRendererSubtitleAttrTypeWebvttCueAlign,             // int type
+  kTrackRendererSubtitleAttrTypeWebvttCueSize,              // float type
+  kTrackRendererSubtitleAttrTypeWebvttCuePosition,          // float type
+  kTrackRendererSubtitleAttrTypeWebvttCuePositionAlign,     // int type
+  kTrackRendererSubtitleAttrTypeWebvttCueVertical,          // int type
+  // TODO(sy0207.ju) : check later.
+  kTrackRendererSubtitleAttrTypeTimestamp,
+  kTrackRendererSubtitleAttrTypeExtsubIndex,  // File index of external subtitle
+  kTrackRendererSubtitleAttrTypeTypeNone
+};
+
+/**
+ * @brief  Enumerations for the subtitle type
+ */
+enum TrackRendererSubtitleType {
+  kTrackRendererSubtitleTypeText,
+  kTrackRendererSubtitleTypePicture,
+  kTrackRendererSubtitleTypeInvalid
+};
+
+/**
+ * @brief   Subtitle attribute data structure
+ */
+typedef struct _TrackRendererSubtitleAttr {
+  /**
+   * @description   Subtitle attribute type.
+   */
+  TrackRendererSubtitleAttrType type;
+
+  /**
+   * @description   Start time.
+   */
+  uint32_t start_time;
+
+  /**
+   * @description   Stop time.
+   */
+  uint32_t stop_time;
+
+  /**
+   * @description   Subtitle attribute value. It can be float, int32, char*,
+   *                unsigned int.
+   */
+  union {
+    /**
+     * @description   Floating type subtitle attribute value.
+     * @remark        kSubAttrRegionXPos \n
+     *                kSubAttrRegionYPos \n
+     *                kSubAttrRegionWidth \n
+     *                kSubAttrRegionHeight \n
+     *                kSubAttrWindowXPadding \n
+     *                kSubAttrWindowYPadding \n
+     *                kSubAttrWindowOpacity \n
+     *                kSubAttrWindowShowBg \n
+     *                kSubAttrFontSize \n
+     *                kSubAttrFontOpacity \n
+     *                kSubAttrFontBgOpacity \n
+     *                kSubAttrWebvttCueLine \n
+     *                kSubAttrWebvttCueSize \n
+     *                kSubAttrWebvttCuePosition \n
+     *                kSubAttrWebvttCueVertical
+     */
+    float f;
+
+    /**
+     * @description   32bit integer type subtitle atribute value.
+     * @remark        kSubAttrWindowLeftMargin \n
+     *                kSubAttrWindowRightMargin \n
+     *                kSubAttrWindowTopMargin \n
+     *                kSubAttrWindowBottomMargin \n
+     *                kSubAttrWindowBgColor \n
+     *                kSubAttrFontWeight \n
+     *                kSubAttrFontStyle \n
+     *                kSubAttrFontColor \n
+     *                kSubAttrFontBgColor \n
+     *                kSubAttrFontTextOutlineColor \n
+     *                kSubAttrFontTextOutlineThickness \n
+     *                kSubAttrFontTextOutlineBlurRadius \n
+     *                kSubAttrFontVerticalAlign \n
+     *                kSubAttrFontHorizontalAlign \n
+     *                kSubAttrWebvttCueLineNum \n
+     *                kSubAttrWebvttCueLineAlign \n
+     *                kSubAttrWebvttCueAlign \n
+     *                kSubAttrWebvttC
+     */
+    int32_t i32;
+
+    /**
+     * @description   String type subtitle atribute value.
+     * @remark        kSubAttrFontFamily \n
+     *                kSubAttrRawSubtitle
+     */
+    const char* str;
+
+    /**
+     * @description   Unsigned 32bit integer type subtitle attribute value.
+     */
+    uint32_t ui32;
+
+    /**
+     * @description   Unsigned 64bit integer type subtitle attribute value.
+     */
+    uint64_t ui64;
+
+    /**
+     * @description   64bit integer type subtitle attribute value.
+     */
+    int64_t i64;
+
+    /**
+     * @description   Double type subtitle attribute value.
+     */
+    double d64;
+  } value;
+
+  /**
+   * @description   Extra subtitle attribute index.
+   */
+  int extsub_index;
+} TrackRendererSubtitleAttr;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACK_H__
diff --git a/include/trackrenderer_capi/track_capi.h b/include/trackrenderer_capi/track_capi.h
new file mode 100755 (executable)
index 0000000..1a19ed9
--- /dev/null
@@ -0,0 +1,528 @@
+/**
+ * @file           track_capi.h
+ * @brief          trackrenderer internally used api c version
+ * @interfacetype  Module
+ * @platform_porting_interface
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        3.0
+ * @SDK_Support    N
+ * @remark         This is track api set for trackrenderer implemented as C
+ *                 style to avoid binary compatibility issues.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACK_CAPI_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACK_CAPI_H__
+
+#include "trackrenderer_capi/track.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for types of track handle
+ */
+typedef void* TrackRendererTrackHandle;
+
+/**
+ * @brief  Enumerations for types of endianness
+ */
+enum TrackRendererTrackEndianness {
+  kTrackRendererTrackEndiannessLittle, /**< Little Endian */
+  kTrackRendererTrackEndiannessBig,    /**< Big Endian */
+};
+
+/**
+ * @brief  Enumerations for types of signedness
+ */
+enum TrackRendererTrackSignedness {
+  kTrackRendererTrackSignednessSigned,   /**< Signed */
+  kTrackRendererTrackSignednessUnsigned, /**< Unsigned */
+};
+
+/**
+ * @brief  Enumerations for types of activation
+ */
+enum TrackRendererTrackActivation {
+  kTrackRendererTrackActivationActive,   /**< Active */
+  kTrackRendererTrackActivationDeactive, /**< Deactive */
+};
+
+/**
+ * @brief  Enumerations for types of decoder
+ */
+enum TrackRendererTrackDecoderType {
+  kTrackRendererTrackDecoderTypeHwOnly, /**< H/W Decoder */
+  kTrackRendererTrackDecoderTypeSwOnly, /**< S/W Decoder */
+};
+
+/**
+ * @brief        [Video/Audio/Subtitle] Create empty track handle.
+ * @param        [out] handle : trackrenderer track handle ptr
+ * @param        [in] type : one of track type for track handle
+ * @param        [in] index : track index
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if track handle is created successfully.
+                 Otherwise -1 if handle is nullptr or memory allocation failure.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ * @see          TrackRendererTrackType
+ */
+int trackrenderer_track_create(TrackRendererTrackHandle* handle,
+                               const TrackRendererTrackType type,
+                               const int index);
+
+/**
+ * @brief        [Video/Audio/Subtitle] Destroy track handle.
+ * @param        [in] handle : trackrenderer track handle ptr to destroy
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if track handle is destroyed successfully.
+                 Otherwise -1 if handle is nullptr.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_destroy(TrackRendererTrackHandle handle);
+
+/**
+ * @brief        [Video/Audio/Subtitle] Set track activated. If application
+ *               doesn't call this api, the track will be deactivated by
+ *               default.
+ * @param        [in] handle : trackrenderer track handle ptr to set activation
+ * @param        [in] activation : activation value
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the activation of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ * @see          TrackRendererTrackActivation
+ */
+int trackrenderer_track_set_activation(
+    TrackRendererTrackHandle handle,
+    const TrackRendererTrackActivation activation);
+
+/**
+ * @brief        [Video/Audio/Subtitle] Set mimetype for track
+ * @param        [in] handle : trackrenderer track handle ptr to set mimetype
+ * @param        [in] mimetype : mimetype with null terminated string
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the mimetype of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_set_mimetype(TrackRendererTrackHandle handle,
+                                     const char* mimetype);
+
+/**
+ * @brief        [Video/Audio/Subtitle] Set streamtype for track
+ * @param        [in] handle : trackrenderer track handle ptr to set streamtype
+ * @param        [in] streamtype : streamtype with null terminated string
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the streamtype of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_set_streamtype(TrackRendererTrackHandle handle,
+                                       const char* streamtype);
+
+/**
+ * @brief        [Video/Audio] Set codec data for track
+ * @param        [in] handle : trackrenderer track handle ptr to set codec data
+ * @param        [in] codec_data : bytes array of codec_data
+ * @param        [in] codec_data_len : size of the codec_data
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the codec data of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr,
+ *               codec_data_len is over 1MB or the type of the track handle is
+ *               different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_set_codec_data(TrackRendererTrackHandle handle,
+                                       const char* codec_data,
+                                       const int codec_data_len);
+
+/**
+ * @brief        [Video/Audio] Set decoder type. default value is
+ *               kTrackRendererTrackDecoderTypeHwOnly
+ * @param        [in] handle : trackrenderer track handle ptr to set decoder
+ *               type
+ * @param        [in] type : type of decoder (h/w or s/w)
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the decoder type of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ * @see          TrackRendererTrackDecoderType
+ */
+int trackrenderer_track_set_decoder_type(
+    TrackRendererTrackHandle handle, const TrackRendererTrackDecoderType type);
+
+/**
+ * @brief        [Video] Set resolution for video track
+ * @param        [in] handle : trackrenderer track handle ptr to set resolution
+ * @param        [in] width : width of video frame
+ * @param        [in] height : height of video frame
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the resolution of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_video_set_resolution(TrackRendererTrackHandle handle,
+                                             const int width, const int height);
+
+/**
+ * @brief        [Video] Set max resolution for video track
+ * @param        [in] handle : trackrenderer track handle ptr to set max
+ *               resolution
+ * @param        [in] width : maximum width of video frame
+ * @param        [in] height : maximum height of video frame
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the max resolution of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_video_set_max_resolution(
+    TrackRendererTrackHandle handle, const int width, const int height);
+
+/**
+ * @brief        [Video] Set framerate for video track
+ * @param        [in] handle : trackrenderer track handle ptr to set framerate
+ * @param        [in] num : numerator of video sequence
+ * @param        [in] den : denominator of video sequence
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the framerate of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_video_set_framerate(TrackRendererTrackHandle handle,
+                                            const int num, const int den);
+
+/**
+ * @brief        [Video] Set video codec tag for video track
+ * @param        [in] handle : trackrenderer track handle ptr to set video codec
+ *               tag
+ * @param        [in] codec_tag : codec tag with null terminated string
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the codec tag of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_video_set_codec_tag(TrackRendererTrackHandle handle,
+                                            const char* codec_tag);
+
+/**
+ * @brief        [Video] Set version for video track
+ * @param        [in] handle : trackrenderer track handle ptr to set version
+ * @param        [in] version : version of video codec
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the version of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_video_set_version(TrackRendererTrackHandle handle,
+                                          const int version);
+
+/**
+ * @brief        [Audio] Set sample rate for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set sample rate
+ * @param        [in] sample_rate : sample rate of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the sample rate of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_sample_rate(TrackRendererTrackHandle handle,
+                                              const int sample_rate);
+
+/**
+ * @brief        [Audio] Set sample format for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set sample
+ *               format
+ * @param        [in] sample_format : sample format of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the sample format of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_sample_format(TrackRendererTrackHandle handle,
+                                                const int sample_format);
+
+/**
+ * @brief        [Audio] Set channels for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set channels
+ * @param        [in] channels : channels of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the channels of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_channels(TrackRendererTrackHandle handle,
+                                           const int channels);
+
+/**
+ * @brief        [Audio] Set version for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set version
+ * @param        [in] version : version of audio codec
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the version of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_version(TrackRendererTrackHandle handle,
+                                          const int version);
+
+/**
+ * @brief        [Audio] Set layer for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set layer
+ * @param        [in] layer : layer of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the layer of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_layer(TrackRendererTrackHandle handle,
+                                        const int layer);
+
+/**
+ * @brief        [Audio] Set bits per sample (bps) for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set bps
+ * @param        [in] bits_per_sample : bits per sample of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the bits per sample of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_bits_per_sample(
+    TrackRendererTrackHandle handle, const int bits_per_sample);
+
+/**
+ * @brief        [Audio] Set block align for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set block align
+ * @param        [in] block_align : block align of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the block align of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_block_align(TrackRendererTrackHandle handle,
+                                              const int block_align);
+
+/**
+ * @brief        [Audio] Set bitrate for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set bitrate
+ * @param        [in] bitrate : bitrate of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the bitrate of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_bitrate(TrackRendererTrackHandle handle,
+                                          const int bitrate);
+
+/**
+ * @brief        [Audio] Set layout for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set layout
+ * @param        [in] layout : layout of audio stream with null terminated
+ *               string
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the layout of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_layout(TrackRendererTrackHandle handle,
+                                         const char* layout);
+
+/**
+ * @brief        [Audio] Set flavor for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set flavor
+ * @param        [in] flavor : flavor of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the flavor of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_flavor(TrackRendererTrackHandle handle,
+                                         const int flavor);
+
+/**
+ * @brief        [Audio] Set endianness for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set endianness
+ * @param        [in] endianness : endianness of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the endianness of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ * @see          TrackRendererTrackEndianness
+ */
+int trackrenderer_track_audio_set_endianness(
+    TrackRendererTrackHandle handle,
+    const TrackRendererTrackEndianness endianness);
+
+/**
+ * @brief        [Audio] Set signedness for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set signedness
+ * @param        [in] signedness : signedness of audio stream
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the signedness of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_signedness(
+    TrackRendererTrackHandle handle,
+    const TrackRendererTrackSignedness signedness);
+
+/**
+ * @brief        [Audio] Set codec tag for audio track
+ * @param        [in] handle : trackrenderer track handle ptr to set codec tag
+ * @param        [in] codec_tag : codec tag with null terminated string
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the codec tag of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_audio_set_codec_tag(TrackRendererTrackHandle handle,
+                                            const char* codec_tag);
+
+/**
+ * @brief        [Subtitle] Set language code for subtitle track
+ * @param        [in] handle : trackrenderer track handle ptr to set language
+ *               code
+ * @param        [in] language_code : language code with null terminated string
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the language code of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_subtitle_set_language_code(
+    TrackRendererTrackHandle handle, const char* language_code);
+
+/**
+ * @brief        [Subtitle] Set subtitle format for subtitle track
+ * @param        [in] handle : trackrenderer track handle ptr to set subtitle
+ *               format
+ * @param        [in] subtitle_format : subtitle format with null terminated
+ *               string
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @return       Returns 0 if the subtitle format of the track handle is set
+ *               successfully. Otherwise -1 if handle is nullptr or the type of
+ *               the track handle is different.
+ * @retval       0 on success
+ * @retval       -1 on failure
+ */
+int trackrenderer_track_subtitle_set_subtitle_format(
+    TrackRendererTrackHandle handle, const char* subtitle_format);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_TRACK_CAPI_H__
\ No newline at end of file
diff --git a/include/trackrenderer_capi/trackrenderer_capi.h b/include/trackrenderer_capi/trackrenderer_capi.h
new file mode 100755 (executable)
index 0000000..4dc7953
--- /dev/null
@@ -0,0 +1,2957 @@
+/**
+ * @file           trackrenderer_capi.h
+ * @brief          Plusplayer trackrenderer api c version.
+ * @interfacetype  Platform
+ * @platform_porting_interface
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is trackrenderer api header implemented as C style to
+ *                 avoid binary compatibility issues.
+ * @see            trackrenderer api header will be exposed to rootstrap and the
+ *                 apis are managed.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_CAPI_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_CAPI_H__
+
+#include "trackrenderer_capi/buffer.h"
+#include "trackrenderer_capi/decoderinputbuffer.h"
+#include "trackrenderer_capi/display.h"
+#include "trackrenderer_capi/drm.h"
+#include "trackrenderer_capi/error.h"
+//#include "trackrenderer_capi/event.h"
+#include "trackrenderer_capi/iniproperty.h"
+#include "trackrenderer_capi/latency.h"
+#include "trackrenderer_capi/state.h"
+#include "trackrenderer_capi/submitstatus.h"
+#include "trackrenderer_capi/track.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Player app id, version, type information
+ */
+typedef struct {
+  /**
+   * @description   App id for controlling resource.
+   */
+  char* id;
+  /**
+   * @description   When there is playback market issue, KPI logger will
+   *                send the version.
+   */
+  char* version;
+  /**
+   * @description   RunningApps.InformationTicker will use this type to show
+   *                stream information. ex) "MSE", "HTML5", etc..
+   */
+  char* type;
+} TrackRendererAppInfo;
+
+/**
+ * @brief Event message
+ */
+typedef struct {
+  /**
+   * @description event message data
+   *           eg) kTrackRendererEventTypeResolutionChanged : "1920x1080"
+   */
+  char* data;
+  /**
+   * @description the length of event message data
+   */
+  uint64_t len;
+} TrackrendererEventMsg;
+
+/**
+ * @brief  Enumerations for the audio easing type
+ * @version      3.0
+ */
+enum TrackRendererAudioEasingType {
+  /**
+   * @description audio easing function type is linear
+   */
+  kTrackRendererAudioEasingLinear = 0,
+  /**
+   * @description audio easing function type is incubic
+   */
+  kTrackRendererAudioEasingIncubic,
+  /**
+   * @description audio easing function type is outcubic
+   */
+  kTrackRendererAudioEasingOutcubic,
+  /**
+   * @description audio easing function type is none
+   */
+  kTrackRendererAudioEasingNone
+};
+
+/**
+ * @brief  audio easing information struct
+ * @version      3.0
+ */
+typedef struct _TrackRendererAudioEasingInfo {
+  /**
+   * @description   audio easing target volume
+   */
+  uint32_t target_volume;
+  /**
+   * @description   audio easing duration, in millisecond
+   */
+  uint32_t duration;
+  /**
+   * @description   audio easing type
+   */
+  TrackRendererAudioEasingType type;
+} TrackRendererAudioEasingInfo;
+
+/**
+ * @brief Enumerations for the resource types
+ * @version      3.0
+ */
+enum TrackRendererRscType {
+  kTrackRendererRscTypeVideoRenderer,
+};
+
+/**
+ * @brief Enumerations for event message types
+ */
+enum TrackRendererEventType {
+  kTrackRendererEventTypeNone,
+  kTrackRendererEventTypeResolutionChanged,
+};
+
+/**
+ * @brief Enumerations for advanced picture quality types
+ */
+enum TrackRendererAdvPictureQualityType {
+  kTrackRendererAdvPictureQualityTypeVideoCall,
+  kTrackRendererAdvPictureQualityTypeUsbCamera,
+};
+
+/**
+ * @brief Enumerations for resource allocate policy
+ */
+enum TrackRendererRscAllocPolicy {
+  kTrackRendererRscAllocExclusive,
+  kTrackRendererRscAllocConditional,
+};
+
+/**
+ * @brief   the numerator/denominator  value
+ * @version      3.2
+ */
+typedef struct _TrackRendererRational {
+  int num;
+  int den;
+} TrackRendererRational;
+
+typedef void* TrackRendererHandle;
+/**
+ * @description  If there is an error, this function will post
+ *               error message with error code.
+ * @param        [in] error_code : enum TrackRendererErrorType\n
+ * @param        [in] userdata : userdata of trackrenderer_error_cb
+ *               callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_error_cb in advance.
+ * @post         User will handle the posted error according to error code.
+ * @see          trackrenderer_set_error_cb()
+ * @see          trackrenderer_error_msg_cb() if a detailed error message is
+ *               required
+ */
+typedef void (*trackrenderer_error_cb)(const TrackRendererErrorType error_code,
+                                       void* userdata);
+
+/**
+ * @description  If there is an error, this function will post
+ *               error message with error code and detailed infomation.
+ * @param        [in] error_code : enum TrackRendererErrorType\n
+ * @param        [in] error_msg : detailed error message including info related
+ *               to codec,demuxer,network status, etc.
+ * @param        [in] userdata : userdata of trackrenderer_error_cb
+ *               callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_error_msg_cb in advance.
+ * @post         User will handle the posted error according to error code.
+ * @see          trackrenderer_set_error_msg_cb()
+ * @see          trackrenderer_error_cb() if only simple error code is required
+ */
+typedef void (*trackrenderer_error_msg_cb)(
+    const TrackRendererErrorType error_code, char* error_msg, void* userdata);
+
+/**
+ * @description  If there is a resource conflict, this function will notice
+ *               that there is resource conflict. Then trackrenderer can
+ *               release the current TV decoder and display resources. Data
+ *               feeding also need to be stoped as well.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_resource_conflicted_cb callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_resourceconflict_cb in advance.
+ * @post         User will control trackrenderer resources.
+ * @see          trackrenderer_set_resourceconflict_cb()
+ */
+typedef void (*trackrenderer_resource_conflicted_cb)(void* userdata);
+
+/**
+ * @description  When seek operation is done, this function will be called.
+ * @param        [in] userdata : userdata of trackrenderer_seekdone_cb callback
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_seekdone_cb, in advance.
+ * @post         User can decide the next operation after seek is done.
+ * @see          trackrenderer_set_seekdone_cb()
+ */
+typedef void (*trackrenderer_seekdone_cb)(void* userdata);
+
+/**
+ * @description  When flush operation is done, this function will be called.
+ * @param        [in] userdata : userdata of trackrenderer_flushdone_cb callback
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_flushdone_cb, in advance.
+ * @post         User can decide the next operation after flush is done.
+ * @see          trackrenderer_set_flushdone_cb()
+ */
+typedef void (*trackrenderer_flushdone_cb)(void* userdata);
+
+/**
+ * @description  When data stream meet the eos signal, this function will be
+ *               called to notify that the contents end.
+ * @param        [in] userdata : userdata of trackrenderer_eos_cb callback
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_eos_cb, in advance.
+ * @post         User have to stop playback and release the TV resources.
+ * @see          trackrenderer_set_eos_cb()
+ */
+typedef void (*trackrenderer_eos_cb)(void* userdata);
+
+/**
+ * @description  When a specific event occurs, this function will be called to
+ *               notify it.
+ * @param        [in] event_type : event type that occured
+ * @param        [in] msg_data : event information
+ * @param        [in] userdata : userdata of trackrenderer_event_cb callback
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_event_cb, in advance.
+ * @post         User can get the information of the event that occured
+ * @see          trackrenderer_set_event_cb()
+ */
+typedef void (*trackrenderer_event_cb)(const TrackRendererEventType event_type,
+                                       const TrackrendererEventMsg msg_data,
+                                       void* userdata);
+/**
+ * @description  When there is subtitle to display, this function is called to
+ *               give subtitle data. If user want to display the subtitle,
+ *               should get subtitle informations from raw data.
+ * @param        [in] buf : buffer including subtitle information \n
+ * @param        [in] type : subtitle type (text or picture) \n
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_subtitle_rawdata_cb callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_subtitle_rawdata_cb, in advance.
+ * @post         User have to get subtitle informations from data to display
+ *               subtitle.
+ * @see          trackrenderer_set_subtitle_rawdata_cb()
+ */
+typedef void (*trackrenderer_subtitle_rawdata_cb)(
+    TrackRendererDecoderInputBuffer* buf, const TrackRendererSubtitleType type,
+    void* userdata);
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+/**
+ * @description  (deprecated) When there is subtitle to display, this function
+ *               is called to give subtitle data. User can use the shared
+ *               informations to display subtitle.
+ * @param        [in] data : subtitle data \n
+ * @param        [in] size : subtitle data length \n
+ * @param        [in] type : subtitle type (text or picture) \n
+ * @param        [in] duration : subtitle duration (ms) \n
+ * @param        [in] attr_list : list of subtitle attribute \n
+ * @param        [in] attr_list_size : length of subtite attribute \n
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_subtitledata_cb callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_subtitledata_cb, in advance.
+ * @post         User can display the subtitle using shared subtitle data.
+ * @see          trackrenderer_set_subtitledata_cb()
+ */
+typedef void (*trackrenderer_subtitledata_cb)(
+    const char* data, const int size, const TrackRendererSubtitleType type,
+    const unsigned long long duration, TrackRendererSubtitleAttr* attr_list,
+    int attr_list_size, void* userdata);
+#endif
+
+/**
+ * @description  When there is closed caption to display, this function
+ *               is called to give closed caption data.
+ * @param        [in] data : closedcaption data \n
+ * @param        [in] size : length of closedcaption data \n
+ * @param        [in] userdata : userdata of trackrenderer_closedcaption_cb
+ *               callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_closedcaption_cb, in advance.
+ * @post         User can display the closed caption using shared data.
+ * @see          trackrenderer_set_closedcaption_cb()
+ */
+typedef void (*trackrenderer_closedcaption_cb)(const char* data, const int size,
+                                               void* userdata);
+
+/**
+ * @description  When trackrenderer detected any informations which need to
+ *               initiate drm, this function is called to share the drm
+ *               informations for decryption.
+ * @param        [in] drmhandle : drm handle \n
+ * @param        [in] len : pssh data length \n
+ * @param        [in] psshdata : pssh data \n
+ * @param        [in] type : track type \n
+ * @param        [in] userdata : userdata of trackrenderer_drminitdata_cb
+ *               callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_drminitdata_cb, in advance.
+ * @post         User can use the shared drm informations for initializing drm.
+ * @see          trackrenderer_set_drminitdata_cb()
+ */
+typedef void (*trackrenderer_drminitdata_cb)(int* drmhandle, unsigned int len,
+                                             unsigned char* psshdata,
+                                             TrackRendererTrackType type,
+                                             void* userdata);
+
+/**
+ * @description  When trackrenderer detected that there is not enough data or
+ *               full at trackrenderer buffer, call this function to let user
+ *               know current buffer status.
+ * @param        [in] type : track type \n
+ * @param        [in] status : trackrenderer buffer status \n
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_bufferstatus_cb, in advance.
+ * @post         User can control data feeding speed with this change
+ *               callback.
+ * @see          trackrenderer_set_bufferstatus_cb()
+ */
+typedef void (*trackrenderer_bufferstatus_cb)(
+    const TrackRendererTrackType type, const TrackRendererBufferStatus status,
+    void* userdata);
+
+/**
+ * @description  When trackrenderer finish to flush the currently buffered data
+ *               and trackrenderer is ready to get new seeked position segment,
+ *               this is called. User can know the time to push the new segment
+ *               data.
+ * @param        [in] type : track type \n
+ *               [in] offset : the new seeked position \n
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_seekdata_cb, in advance.
+ * @post         User can control feeding time during seek operation.
+ * @see          trackrenderer_set_seekdata_cb()
+ */
+typedef void (*trackrenderer_seekdata_cb)(const TrackRendererTrackType type,
+                                          const uint64_t offset,
+                                          void* userdata);
+
+/**
+ * @description  When trackrenderer finish to decode video buffer,
+ *              this is called want to get an useful tbm point form the tbm
+ * list.
+ * @param        [in] ptr : pointer set to get tbm address \n
+ *               [in] is_scale_change : param indicate whether scale resolution
+ * changed \n
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_media_packet_video_tbmptr_cb, in advance.
+ * @post         User can get an useful tbm surface ptr
+ * @version        3.2
+ * @see          trackrenderer_set_media_packet_video_tbmptr_cb()
+ */
+typedef void (*trackrenderer_media_packet_video_tbmptr_cb)(void** ptr,
+                                                           bool is_scale_change,
+                                                           void* userdata);
+
+/**
+ * @description  When trackrenderer finish to decode video buffer,
+ *               this is called, then user can get the decoded video buffer
+ * @param        [in] packet : decoded video packet \n
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_media_packet_video_decoded_cb, in advance.
+ * @post         User can use the decoded buffer to render.
+ * @see          trackrenderer_set_media_packet_video_decoded_cb()
+ */
+typedef void (*trackrenderer_media_packet_video_decoded_cb)(
+    const TrackRendererDecodedVideoPacket* packet, void* userdata);
+
+/**
+ * @description  If the latency status of the video stream changes, this
+ *               function will be called.
+ * @param        [in] latency_status : the video latency status \n
+ *               [in] userdata : userdata of trackrenderer_latency_status_cb
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_video_latency_status_cb, in advance.
+ * @post         User can decide the next operation after the latency status
+ * changes.
+ * @see          trackrenderer_set_video_latency_status_cb()
+ */
+typedef void (*trackrenderer_video_latency_status_cb)(
+    const TrackRendererLatencyStatus video_latency_status, void* userdata);
+
+/**
+ * @description  If the latency status of the audio stream changes, this
+ *               function will be called.
+ * @param        [in] latency_status : the audio latency status \n
+ *               [in] userdata : userdata of trackrenderer_latency_status_cb
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_audio_latency_status_cb, in advance.
+ * @post         User can decide the next operation after the latency status
+ * changes.
+ * @see          trackrenderer_set_audio_latency_status_cb()
+ */
+typedef void (*trackrenderer_audio_latency_status_cb)(
+    const TrackRendererLatencyStatus audio_latency_status, void* userdata);
+
+/**
+ * @description  If high latency occurs, this function will be called.
+ * @param        [in] userdata : userdata of trackrenderer_video_high_latency_cb
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_video_high_latency_cb, in advance.
+ * @post         User can decide the next operation after video high latency
+ * occurs.
+ * @see          trackrenderer_set_video_high_latency_cb()
+ */
+typedef void (*trackrenderer_video_high_latency_cb)(void* userdata);
+
+/**
+ * @description  If high latency occurs, this function will be called.
+ * @param        [in] userdata : userdata of trackrenderer_audio_high_latency_cb
+ *               function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_audio_high_latency_cb, in advance.
+ * @post         User can decide the next operation after audio high latency
+ * occurs.
+ * @see          trackrenderer_set_audio_high_latency_cb()
+ */
+typedef void (*trackrenderer_audio_high_latency_cb)(void* userdata);
+
+/**
+ * @description  If ResourceCenter sends video start request to a player when
+ * it's required, this function will be called.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_multiview_start_video_cb callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_multiview_start_video_cb in advance.
+ * @post         User will activate video stream.
+ * @see          trackrenderer_set_multiview_start_video_cb()
+ */
+typedef void (*trackrenderer_multiview_start_video_cb)(void* userdata);
+
+/**
+ * @description  If ResourceCenter sends video stop request to a player when
+ * it's required, this function will be called.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_multiview_stop_video_cb callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_multiview_stop_video_cb in advance.
+ * @post         User will deactivate video stream.
+ * @see          trackrenderer_set_multiview_stop_video_cb()
+ */
+typedef void (*trackrenderer_multiview_stop_video_cb)(void* userdata);
+
+/**
+ * @brief        return libtrackrenderer.so lib version as string
+ * @param        None
+ * @return       version info - major.minor.micro - as string
+ * @code
+ *               //your logic
+ *               const char* version;
+ *               version =  trackrenderer_get_version();
+ *               //your logic
+ * @endcode
+ * @pre          None
+ * @post         None
+ * @exception    None
+ */
+const char* trackrenderer_get_version(void);
+
+/**
+ * @brief        return libtrackrenderer.so lib version as constant int.
+ * @param        None
+ * @return       version info - major.minor.micro - as unsigned int
+ * @code
+ *               //your logic
+ *               uint32_t version = 0;
+ *               version =  trackrenderer_get_version_int();
+ *               //your logic
+ * @endcode
+ * @pre          None
+ * @post         None
+ * @exception    None
+ */
+uint32_t trackrenderer_get_version_int(void);
+
+/**
+ * @brief        Create trackrenderer instance.
+ * @description  Create trackrenderer object and handle for accessing
+ *               trackrenderer object. Trackrenderer is in charge of rendering
+ *               related job ex) display setting, decoding, rendering, etc..
+ * @param        [out] handle : Get trackrenderer handle ptr.
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               TrackRendererHandle handle = nullptr;
+ *               trackrenderer_create(&handle);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          None
+ * @post         None
+ * @exception    None
+ */
+int trackrenderer_create(TrackRendererHandle* handle);
+
+/**
+ * @brief        Remove trackrenderer object
+ * @description  Remove and dealloc trackrenderer object and handle.
+ * @param        [in] handle : trackrenderer handle
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               refer to the sample code of trackrenderer_create()
+ * @endcode
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_destroy(TrackRendererHandle handle);
+
+/**
+ * @brief        Trackrenderer start to play media contents.
+ * @description  In this function, trackrenderer start to display the delivered
+ *               media contents.
+ * @param        [in] handle : trackrenderer handle
+ * @return       Return 0 if no problem.
+ *               Otherewise -1 if the trackrenderer is not even set up.
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         The contents is playing.
+ * @exception    None
+ * @code
+ *               //prepare trackrenderer hanle
+ *               trackrenderer_start(handle);
+ *               //your logic
+ *               trackrenderer_pause(handle);
+ *               //your logic
+ *               trackrenderer_resume(handle);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_start(TrackRendererHandle handle);
+
+/**
+ * @brief        Trackrenderer stop to play the media contents.
+ * @description  In this function trackrenderer release the resources. When user
+ *               command stop to play or got callback such as
+ *               trackrenderer_error_cb or trackrenderer_resource_conflicted_cb,
+ *               this is called.
+ * @param        [in] handle : trackrenderer handle
+ * @return       Return 0 if the trackrenderer is not even setup or release the
+ *               resource successfully.
+ *               Otherwise -1.
+ * @code
+ *               refer to the sample code of trackrenderer_start()
+ * @endcode
+ * @pre          After trackrenderer object is created, this can be called.
+ * @post         Trackrenderer release the decoder and display resource.
+ * @exception    None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_start()
+ */
+int trackrenderer_stop(TrackRendererHandle handle);
+
+/**
+ * @brief        Trackrenderer set up properties and prepare playback.
+ * @description  In this function trackrenderer prepare video/audio decoder,
+ *               sink, drm info, etc.. and set up several properties for
+ *               video/audio decoding and rendering.
+ * @param        [in] handle : trackrenderer handle
+ * @return       Return 0 if all valid tracks playback is successfully prepared,
+ *               succeed to update display 1 decoded frame media contents.
+ *               Otherwise -1.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               //set tracks if needed
+ *               trackrenderer_prepare(handle);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          Active tracks informations for playing need to be set up.
+ *               The media contents data must be delivered as mush as
+ *               trackrenderer can parse data type.
+ * @post         1 decoded frame media contents is displayed. The necessary TV
+ *               resource is prepared to use.
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_track()
+ */
+int trackrenderer_prepare(TrackRendererHandle handle);
+
+/**
+ * @brief        Trackrenderer pause displaying media contents
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @return       Return 0 if trakrenderer is successfully paused.
+ *               Oterwise return -1 if trackrenderer already release the
+ *               resource.
+ * @code
+ *               refer to the sample code of trackrenderer_start()
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         The trackrenderer pause playback and displaying 1 decoded frame
+ *               data.
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_start()
+ */
+int trackrenderer_pause(TrackRendererHandle handle);
+
+/**
+ * @brief        Trackrenderer resume displaying media contents
+ * @description  In this function trackrenderer resume media contents from
+ *               paused position.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @return       Returen 0 if trackrenderer is successfully resume media
+ *               contents.
+ *               Otherwise -1.
+ * @code
+ *               refer to the sample code of trackrenderer_start()
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         The contents is playing.
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_start() \n
+ *               trackrenderer_pause()
+ */
+int trackrenderer_resume(TrackRendererHandle handle);
+
+/**
+ * @brief        Set active track info to set up trackrenderer properties.
+ * @description  In this fuction, trackrenderer set track info which is
+ *               necessary for media contents playback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] track : Active tracks for playing media contents.
+ * @param        [in] size : Number of tracks. The maximum number of tracks
+ *               is 3.(audio, video, subtitle)
+ * @return       Return 0 if there are any active tracks among audio, video,
+ *               subtitle and successcully set the track info to trackrenderer.
+ *               Otherwise -1 if there is not any active tracks or already set
+ *               tracks info.
+ * @code
+ *               TrackRendererHandle handle = nullptr;
+ *               trackrenderer_create(&handle)
+ *               TrackRendererTrack tracks[] = {videotrack, audiotrack};
+ *               int tracksize = 2;
+ *               trackrenderer_set_track(handle, tracks, tracksize);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          Get active tracks list for playing.
+ * @post         Set up left of other properties to trackrenderer with using
+ *               trackrenderer_prepare().
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_track(TrackRendererHandle handle,
+                            const TrackRendererTrack* track, const int size);
+
+/**
+ * @brief        Set properties to trackrenderer.
+ * @description  Parsing informations from loaded property file and set values
+ *               to trackrenderer.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] properties : Setting properties got from property file.
+ * @param        [in] property_size : Number of properties for parsing.
+ * @code
+ *               trackrenderer_create(&handle)
+ *               TrackRendererIniProperty properties[2];
+ *               properties[0].key = "use_new_hls_mpegts_demuxer";
+ *               properties[0].value = true;
+ *               properties[1].key = "use_new_dash_tiny_demuxer";
+ *               properties[1].value = false;
+ *               trackrenderer_set_ini_property(handle, properties, 2)
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          Load property file and get informations.
+ * @post         Trackrenderer set the parsed properties.
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+void trackrenderer_set_ini_property(TrackRendererHandle handle,
+                                    TrackRendererIniProperty* properties,
+                                    int property_size);
+
+/**
+ * @brief        Seek trackrenderer playback position, asynchronously.
+ * @description  In this function, trackrenderer seek playback position to
+ *               specific position and can set playback rate.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] time_millisecond : the absolute position(playingtime) of
+ *               the stream in milliseconds
+ * @param        [in] playback_rate : For trick play playback rate.
+ * @return       Return 0 if he trackrenderer can seek the position or set
+ *               playback rate successfully. Playback rate 0 is not accecptable
+ *               eventhough return value is 0.
+ *               Otherwise -1 if the trackrenderer is not even setup,
+ *               trackrenderer fail to seek playback position or fail to set
+ *               playback rate.
+ * @code
+ *               static void SeekDoneCb(UserData userdata) {
+ *                  //do something you want when seek done
+ *               }
+ *               static void SeekDataCb(const TrackRendererTrackType type,
+ *                  const unsigned long long offset, UserData userdata) {
+ *                 //do something you want when trackrenderer is ready
+ *                  to get new seeked position segment data
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_seekdone_cb(handle, SeekDoneCb, nullptr);
+ *               trackrenderer_set_seekdata_cb(handle, SeekDataCb, nullptr);
+ *               trackrenderer_prepare(handle);
+ *               trackrenderer_start(handle);
+ *               //your logic
+ *               trackrenderer_seek(handle,10,1.0);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         Release the buffered data and start buffering seeked position
+ *               segment data.
+ * @exception    None
+ * @remark       Seek is asynchronous operation. trackrenderer_seekdone_cb() is
+ *               called when seek operation is finished.
+ *               The accecptable playback rate is different for each streaming
+ *               source type.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_start() \n
+ *               trackrenderer_set_seekdone_cb()
+ */
+int trackrenderer_seek(TrackRendererHandle handle,
+                       unsigned long long time_millisecond,
+                       double playback_rate);
+/**
+ * @brief        Seek trackrenderer playback position, asynchronously.
+ * @description  In this function, trackrenderer seek playback position to
+ *               specific position and can set playback rate with audio mute
+ *               on/off.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] time_millisecond : the absolute position(playingtime) of
+ *               the stream in milliseconds
+ * @param        [in] playback_rate : For trick play playback rate.
+ * @param        [in] audio_mute : audio is mute on/off when seek to target
+ *               position.
+ * @return       Return 0 if he trackrenderer can seek the position or set
+ *               playback rate successfully. Playback rate 0 is not accecptable
+ *               eventhough return value is 0.
+ *               Otherwise -1 if the trackrenderer is not even setup,
+ *               trackrenderer fail to seek playback position or fail to set
+ *               playback rate.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               trackrenderer_start(handle);
+ *               //your logic
+ *               trackrenderer_seek2(handle,10,1.0,true);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         Release the buffered data and start buffering seeked position
+ *               segment data.
+ * @exception    None
+ * @version      2.0
+ * @remark       Seek is asynchronous operation. trackrenderer_seekdone_cb() is
+ *               called when seek operation is finished.
+ *               The accecptable playback rate is different for each streaming
+ *               source type.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_start()
+ */
+int trackrenderer_seek2(TrackRendererHandle handle,
+                        unsigned long long time_millisecond,
+                        double playback_rate, bool audio_mute);
+
+/**
+ * @brief        Set trackrenderer playback rate, asynchronously.
+ * @description  In this function, trackrenderer set playback rate and audio
+ *               mute on/off.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] playback_rate : For trick play playback rate.
+ * @param        [in] audio_mute : For trick play audio mute on/off, true: mute
+ *               on, false: mute off.
+ * @return       Return 0 if he trackrenderer can  set  playback rate
+ *               successfully. Playback rate 0 is not accecptable
+ *               eventhough return value is 0.
+ *               Otherwise -1 if the trackrenderer is not even setup,
+ *               trackrenderer fail to set playback rate.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               trackrenderer_set_playback_rate(handle, 2.0, true);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         Release the buffered data and start buffering current playing
+ * position
+ * @exception    None
+ * @version      2.0
+ * @remark       Setting playback rate is asynchronous operation.
+ *               The accecptable playback rate is different for each streaming
+ *               source type.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_set_playback_rate(TrackRendererHandle handle,
+                                    double playback_rate, bool audio_mute);
+
+/**
+ * @brief        Get current trackrenderer playing time
+ * @description  In this function trackrenderer get currently rendering
+ *               contents position. This is used when change playback rate from
+ *               current position.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] time_millisecond : current playing time in milliseconds
+ * @return       Return 0 if trackrenderer successfully get currently rendering
+ *               contents position.
+ *               Otherwise -1.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               uint64_t time_millisecond = 0;
+ *               trackrenderer_get_playing_time(handle, &time_millisecond));
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None.
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_get_playing_time(TrackRendererHandle handle,
+                                   unsigned long long* time_millisecond);
+/**
+ * @brief        Get dropped frame counts in videosink
+ * @description  In this function trackrenderer get currently dropped frames in
+ *               sink.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] counts : dropped counts
+ * @return       Return 0 if trackrenderer successfully get frame counts.
+ *               Otherwise -1.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               uint64_t count = 0;
+ *               trackrenderer_get_dropped_frames(handle,static_cast<void*>(&count)));
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None.
+ * @version      2.0
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_get_dropped_frames(TrackRendererHandle handle, void* counts);
+
+/**
+ * @brief        Get dropped frame counts for catchup in video/audio sink
+ * @description  In this function trackrenderer get dropped frames for catchup
+ *               in sink.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : the type of the track
+ * @param        [out] counts : dropped counts
+ * @return       Return 0 if trackrenderer successfully get frame counts.
+ *               Otherwise -1.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               uint64_t dropped_video_frames = 0;
+ *               trackrenderer_get_dropped_frames_for_catchup(handle,
+ *                   TrackRendererTrackType::kTrackRendererTrackTypeVideo,
+ *                   static_cast<void*>(&dropped_video_frames)));
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None.
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_get_dropped_frames_for_catchup(TrackRendererHandle handle,
+                                                 TrackRendererTrackType type,
+                                                 void* counts);
+
+/**
+ * @brief        Flush buffers for a trackrenderer.
+ * @description  In this function trackrenderer will flush data in
+ *               appsrc,decoder,sink.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : type of track which need to be flush.
+ * @return       Return 0 if flushing buffer for a track successfully.
+ *               Otherwise -1.
+ * @code
+ *               static void FlushDoneCb(UserData userdata) {
+ *                   //do something you want to do when flush done
+ *               }
+
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_flushdone_cb(handle, FlushDoneCb, nullptr);
+ *               trackrenderer_prepare(handle);
+ *               //your logic
+ *               trackrenderer_flush(handle, kTrackRendererTrackTypeAudio);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None.
+ * @version      2.0
+ * @remark       trackrenderer_flushdone_cb() is called when flush operation is
+ *               fininshed
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_flushdone_cb()
+ */
+int trackrenderer_flush(TrackRendererHandle handle,
+                        TrackRendererTrackType type);
+
+/**
+ * @brief        Trackrenderer flush the buffered data and release the TV
+ *               rendering resources.
+ * @description  In this function flush the currently inserted data for
+ *               rendering to get new data stream. Release current audio decoder
+ *               and display resource for getting new data and decoder as well.
+ *               The deactivatable track is audio and subtitle only.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : track type.
+ * @return       Return 0 if successfully flush the inserted data and release
+ *               the TV resources.
+ *               Otherwise -1 if the trackrenderer is not even set up or fail to
+ *               release the resources.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               trackrenderer_deactivate(handle, kTrackRendererTrackTypeVideo)
+ *               //your logic
+ *               trackrenderer_activate(handle,
+ *                   kTrackRendererTrackTypeVideo,nullptr));
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         trackrenderer_activate() should be called if new data stream
+ *               need to be inserted and get new TV resource for decoding and
+ *               rendering.
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_deactivate(TrackRendererHandle handle,
+                             TrackRendererTrackType type);
+
+/**
+ * @brief        Trackrenderer set new tracks and set up the new data stream
+ *               properties.
+ * @description  In this function rebuild the trackrenderer properties for the
+ *               newly changed data stream and get TV resources for playback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : track type(audio, video, subtitle)
+ * @param        [in] track : a track that need to be rebuilded.
+ * @return       Return 0 if trackrenderer is successfully rebuilt with using
+ *               new data stream. Otherwise -1 if the trackrenderer is not even
+ *               set up or fail to get resources.
+ * @code
+ *               refer to the sample code of trackrenderer_deactivate()
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_deactivate()
+ */
+int trackrenderer_activate(TrackRendererHandle handle,
+                           TrackRendererTrackType type,
+                           TrackRendererTrack* track);
+
+/**
+ * @brief        The shared data will be pushed to the queue.
+ * @description  In this function push the buffer to trackrenderer queue of
+ *               buffer. When the buffer is full, the queue is blocked until
+ *               free space becomes available in queue. With parameter, user can
+ *               know the submition result and can handle for it. This should be
+ *               called repeatedly during playback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] data : the data user want to add to the trackrenderer
+                 buffer
+ * @param        [out] retval : the result of submition.
+ * @return       Return 0 if trackrenderer successfully add the buffer to queue
+ *               or the EOS data.
+ *               Otherwise -1 if the trackrenderer is not even set up, queue is
+ *               already full or the data is unusable.
+ * @code
+ *               static void BufferStatusCb(const TrackRendererTrackType type,
+ *                   const TrackRendererBufferStatus status,UserData userdata) {
+ *                   if (type == kTrackRendererTrackTypeAudio) {
+ *                       if (status == kTrackRendererBufferStatusUnderrun)
+ *                           // do something when feed Audio is possible
+ *                       else
+ *                           //do something when feed Audio is impossible
+ *                   } else if(type == kTrackRendererTrackTypeVideo) {
+ *                       if (status == kTrackRendererBufferStatusUnderrun)
+ *                           //do something when feed Video is possible
+ *                       else
+ *                           //do something when feed Video is impossible
+ *                   } else if(type == kTrackRendererTrackTypeSubtitle) {
+ *                       if (status == kTrackRendererBufferStatusUnderrun)
+ *                           //do something when feed Subtitle is possible
+ *                       else
+ *                           //do something when feed Subtitle is impossible
+ *                   }
+ *               }
+ *               void FeedPacket(const TrackRendererHandle& handle,
+ *                   const TrackRendererDecoderInputBufferPtr& buffer,...) {
+ *                   //your logic
+ *                   SubmitStatus status=kTrackRendererSubmitStatusNotPrepared;
+ *                   trackrenderer_submit_packet(handle, buffer.get(),&status);
+ *                   //your logic
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_bufferstatus_cb(handle,BufferStatusCb,nullptr);
+ *               trackrenderer_prepare(handle);
+ *               //your logic
+ *               //execute FeedPacket() when feed is possible.
+ *               (call a new thread to do this)
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         If EOS is submitted to buffer, trackrenderer_eos_cb will be
+ *               called.
+ * @exception    None
+ * @remark       The buffered tracksource data is submitted to trackrenderer by
+ *               feeder.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_set_bufferstatus_cb()
+ */
+int trackrenderer_submit_packet(TrackRendererHandle handle,
+                                TrackRendererDecoderInputBuffer* data,
+                                TrackRendererSubmitStatus* retval);
+
+/**
+ * @brief        The shared data will be pushed to the queue.
+ * @description  In this function push the buffer to trackrenderer queue of
+ *               buffer. When the buffer is full, the queue is blocked until
+ *               free space becomes available in queue. With parameter, user can
+ *               know the submition result and can handle for it. This should be
+ *               called repeatedly during playback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] data : the data user want to add to the trackrenderer
+ *               buffer
+ * @param        [out] retval : the result of submition.
+ * @code
+                 refer to the sample code of trackrenderer_submit_packet()
+ * @endcode
+ * @return       Return 0 if trackrenderer successfully add the buffer to queue
+ *               or the EOS data.
+ *               Otherwise -1 if the trackrenderer is not even set up, queue is
+ *               already full or the data is unusable.
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         If EOS is submitted to buffer, trackrenderer_eos_cb will be
+ *               called.
+ * @exception    None
+ * @remark       The buffered tracksource data is submitted to trackrenderer by
+ *               feeder.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_set_bufferstatus_cb()
+ */
+int trackrenderer_submit_packet2(TrackRendererHandle handle,
+                                 TrackRendererDecoderInputBuffer* data,
+                                 TrackRendererSubmitStatus* retval);
+
+/**
+ * @brief        Set drm property.
+ * @description  Set drm property for decription. The properties will be used
+ *               for drm licensing just in case trackrender does security
+ *               process itself.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] drm_property : drm property
+ * @code
+ *               trackrenderer_create(&handle);
+ *               TrackRendererDrmProperty trackrenderer_drm_property{
+ *                      kTrackRendererDrmTypePlayready,
+ *                                      0, 1, nullptr, nullptr};
+ *               trackrenderer_set_drm(handle,&trackrenderer_drm_property);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       Set drm property directly
+ * @see          trackrenderer_create()
+ */
+void trackrenderer_set_drm(TrackRendererHandle handle,
+                           TrackRendererDrmProperty* drm_property);
+
+/**
+ * @brief        Notify drm licensing is done.
+ * @description  In this function let user know that trackrenderer getright is
+ *               finished successfully. This is used when trackrenderer does drm
+ *               process itself.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : which type of track drm license was acquired
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               trackrenderer_drm_license_acquired_done(handle,
+ *                   kTrackRendererTrackTypeMax);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+void trackrenderer_drm_license_acquired_done(TrackRendererHandle handle,
+                                             TrackRendererTrackType type);
+
+/**
+ * @brief        Set the video display mode.
+ * @description  In this function set how display shows. If the
+ *               trackrenderer is not prepared to update the display yet, the
+ *               trackrenderer stored the mode and update display after
+ *               trackrenderer is ready to update display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] mode : display mode
+ * @return       Return 0 if rendering mode is successfully applied or stored
+ *               for future displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_display_mode(
+ *                   handle, kTrackRendererDisplayModeOriginSize));
+ *               //your logic
+ *               TrackRendererDisplayMode display_mode =
+ *                   static_cast<TrackRendererDisplayMode>(-1);
+ *               trackrenderer_get_display_mode(handle, &display_mode);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_display_mode(TrackRendererHandle handle,
+                                   TrackRendererDisplayMode mode);
+
+/**
+ * @brief        Set the video display rotate angle.
+ * @description  In this function will set the video display rotate. If the
+ *               trackrenderer is not prepared to update the display rotate yet,
+ *               the trackrenderer stored the rotate and update it after
+ *               trackrenderer is ready to update display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] rotate : display rotate angle
+ * @return       Return 0 if rendering mode is successfully applied or stored
+ *               for future displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_display_rotate(handle,kTrackRendererDisplayRotate90);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @version      2.0
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_display_rotate(TrackRendererHandle handle,
+                                     TrackRendererDisplayRotate rotate);
+
+/**
+ * @brief        Get the video display rotate angle.
+ * @description  In this function will get the video display rotate.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] rotate : store the display rotate angle
+ * @return       Return 0 if get rotate value success.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               //your logic
+ *               TrackRendererDisplayRotate gtype =
+ *                   kTrackRendererDisplayRotateNone;
+ *               rackrenderer_get_display_rotate(handle, &gtype);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @version      2.0
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_get_display_rotate(TrackRendererHandle handle,
+                                     TrackRendererDisplayRotate* rotate);
+
+/**
+ * @brief        Set the video display properties.
+ * @description  In this function set rendering properties and rendering
+ *               locations. If the trackrenderer is not prepared to update the
+ *               display yet, the trackrenderer store the mode and update
+ *               display after trackrenderer is ready to update display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : display type
+ * @param        [in] surface_id : resource id of window.
+ * @param        [in] x : x param of display window
+ * @param        [in] y : y param of display window
+ * @param        [in] w : width of display window
+ * @param        [in] h : height of display window
+ * @return       Return 0 if rendering properties are successfully applied for
+ *               displaying contents or stored for future displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_display_surface(handle,
+ *                   kTrackRendererDisplayTypeOverlay, 3, 100, 100, 100, 100);
+ *               //your logic
+ *               TrackRendererDisplayType type = kTrackRendererDisplayTypeNone;
+ *               TrackRendererGeometry area = {-1, -1, -1, -1};
+ *               trackrenderer_get_display(handle, &type, &area);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_display_surface(TrackRendererHandle handle,
+                                      TrackRendererDisplayType type,
+                                      unsigned int surface_id, long x, long y,
+                                      long w, long h);
+
+/**
+ * @brief        Set the video rendering object.
+ * @description  In this function set rendering object. If the trackrenderer is
+ *               not prepared to update the display yet, the trackrenderer
+ *               stored the rendering object and update display after
+ *               trackrenderer is ready to update display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : trackrenderer display type.
+ * @param        [in] obj : the handle to display window.
+ * @return       Return 0 if rendering object is successfully applied for
+ *               displaying contents or stored for future displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               Environment* env = new Environment();
+ *               TrackRendererDisplayType type =
+ *                   kTrackRendererDisplayTypeOverlay;
+ *               trackrenderer_set_display(handle,type,env->Window());
+ *               //your logic
+ *               delete env;
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_display(TrackRendererHandle handle,
+                              TrackRendererDisplayType type, void* obj);
+
+/**
+ * @brief        Set the video display properties.
+ * @description  In this function set rendering object and rendering
+ *               locations. If the trackrenderer is not prepared to update the
+ *               display yet, the trackrenderer stored the rendering object
+ *               properties and update display after trackrenderer is ready to
+ *               update display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : display type
+ * @param        [in] ecore_wl2_window : ecore wayland handle to display window.
+ * @param        [in] x : x param of display window
+ * @param        [in] y : y param of display window
+ * @param        [in] w : width of display window
+ * @param        [in] h : height of display window
+ * @return       Return 0 if rendering oejct and properties are successfully
+ *               applied for displaying contents or stored for future
+ *               displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_display_ecore_wl2_window(
+ *                   handle,kTrackRendererDisplayTypeOverlay,NULL,
+ *                   0,0,1920,1080));
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_display_ecore_wl2_window(TrackRendererHandle handle,
+                                               TrackRendererDisplayType type,
+                                               void* ecore_wl2_window, int x,
+                                               int y, int w, int h);
+/**
+ * @brief        Set the video display properties.
+ * @description  In this function set rendering object and rendering
+ *               locations. If the trackrenderer is not prepared to update the
+ *               display yet, the trackrenderer stored the rendering object
+ *               properties and update display after trackrenderer is ready to
+ *               update display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : display type
+ * @param        [in] ecore_wl2_subsurface : ecore wl subsurface handle to
+ *               display window.
+ * @param        [in] x : x param of display window
+ * @param        [in] y : y param of display window
+ * @param        [in] w : width of display window
+ * @param        [in] h : height of display window
+ * @return       Return 0 if rendering oejct and properties are successfully
+ *               applied for displaying contents or stored for future
+ *               displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @version      3.1
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_display_ecore_wl2_subsurface(
+    TrackRendererHandle handle, TrackRendererDisplayType type,
+    void* ecore_wl2_subsurface, int x, int y, int w, int h);
+
+/**
+ * @brief        Set the ROI(Region Of Interest) area of display
+ * @description  In this function set contents rendering range.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] roi : Roi Geometry
+ * @return       Return 0 if rendering range is successfully set or
+ *               rendering range is stored for future displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_display_mode(
+ *                   handle, kTrackRendererDisplayModeDstRoi));
+ *               TrackRendererGeometry roi = {0, 0, 1920, 1080};
+ *               trackrenderer_set_display_roi(handle, &roi);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ *               The display mode should be set to
+ *               kTrackRendererDisplayModeDstRoi.
+ * @post         None
+ * @exception    None
+ * @remark       The minimum value of width and height are 1.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_display_mode()
+ */
+int trackrenderer_set_display_roi(TrackRendererHandle handle,
+                                  TrackRendererGeometry* roi);
+
+/**
+ * @brief        Set the Crop Area(Region Of Src ratio) area of display.
+ * @param        [in] handle : esplusplayer handle.
+ * @param        [in] crop: x y label , height, width crop ratio in src video area.
+ * @return       @c true on success, otherwise @c false.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_display_mode(
+ *                   handle, kTrackRendererDisplayModeDstRoi));
+ *               TrackRendererCropArea roi = {0.2, 0.2, 0.5, 0.5};
+ *               trackrenderer_set_video_roi(handle, &roi));
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and
+ *               The player state can be all of #esplusplayer_state except
+ *               #ESPLUSPLAYER_STATE_NONE.
+ * @post         None
+ * @exception    None
+ * @version      2.0
+ * @remark       The minimum value of input are 0,maximun value is 1.
+ * @see          trackrenderer_create() \n
+ *               esplusplayer_set_display() \n
+ *               esplusplayer_set_display_visible()
+ */
+int trackrenderer_set_video_roi(TrackRendererHandle handle,
+                                TrackRendererCropArea* crop);
+
+/**
+ * @brief     Resize the render rectangle(the max region that video can be
+ * displayed).
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] rect: render rectangle.
+ * @return    @c true on success, otherwise @c false.
+ * @pre       This should be called after trackrenderer_set_display() \n
+ *            trackrenderer_set_display_surface() \n
+ *            trackrenderer_set_display_ecore_wl2_window() \n
+ *            trackrenderer_set_display_ecore_wl2_subsurface
+ * @post      None
+ * @exception   None
+ * @version        3.2
+ * @remark    The minimum value of width and height are 1.
+ * @see       esplusplayer_set_display() \n
+ *            trackrenderer_set_display_surface() \n
+ *            trackrenderer_set_display_ecore_wl2_window() \n
+ *            trackrenderer_set_display_ecore_wl2_subsurface
+ */
+int trackrenderer_resize_render_rect(TrackRendererHandle handle,
+                                     TrackRendererRenderRect* rect);
+
+/**
+ * @brief        Set on off the video display.
+ * @description  In this function trackrenderer can set contents display
+ *               visibility for some reasons.
+ *               trackrenderer_set_display_visible() toggle works.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] is_visible : The visibility of the display \n
+ *               (@c true = visible, @c false = non-visible)
+ * @return       Return 0 if visibility is updated or stored for future
+ *               displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_display_visible(handle, true);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @see          This is similar to trackrenderer_set_audio_mute() for audio
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_display_visible(TrackRendererHandle handle,
+                                      bool is_visible);
+
+/**
+ * @brief        Get the ROI(Region Of Interest) area of display and display
+ *               type
+ * @description  In this function get contents rendering range and display
+ *               type.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] type : display type
+ * @param        [out] area : Roi Geometry
+ * @code
+ *               please refer to the sample code of
+ *               trackrenderer_set_display_surface
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_display_surface()
+ */
+void trackrenderer_get_display(TrackRendererHandle handle,
+                               TrackRendererDisplayType* type,
+                               TrackRendererGeometry* area);
+
+/**
+ * @brief        Get trackrenderer video display mode.
+ * @description  In this function get what mode trackrenderer displaying
+ *               contents.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] mode : display mode
+ * @code
+ *               please refer to the sample code of
+ *               trackrenderer_set_display_mode
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_display_mode()
+ */
+void trackrenderer_get_display_mode(TrackRendererHandle handle,
+                                    TrackRendererDisplayMode* mode);
+
+/**
+ * @brief        Set app id to resource manager
+ * @description  In this fuction trackrenderer set app id to resource
+ *               manager. In future resource manager will control the
+ *               rendering resources using this app id.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] app_id : application id
+ * @code
+ *               trackrenderer_create(&handle);
+ *               std::string app_id = "plusplayer-mapi";
+ *               trackrenderer_set_app_id(handle, app_id.c_str());
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create()
+ */
+void trackrenderer_set_app_id(TrackRendererHandle handle, const char* app_id);
+
+/**
+ * @brief        Set App id to player for resource manager
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] app_info : application id, version, type.
+ * @return       @c true on success, otherwise @c false.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               TrackRendererAppInfo app_info;
+ *               app_info.id = "plusplayer-mapi";
+ *               app_info.version = "";
+ *               app_info.type = "";
+ *               trackrenderer_set_app_info(handle, &app_info);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @version      2.0
+ * @see          trackrenderer_create()
+ */
+void trackrenderer_set_app_info(TrackRendererHandle handle,
+                                const TrackRendererAppInfo* app_info);
+
+/**
+ * @brief        Set mute on off the audio sound.
+ * @description  In this function trackrenderer can set audio sound on off
+ *               for some reasons.
+ *               trackrenderer_set_audio_mute() toggle works.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] is_mute : On mute of the sound \n
+ *               (@c true = mute, @c false = non-mute)
+ * @return       Return 0 if audio mute successfully turn into or stored for
+ *               future playing.
+ *               Otherwise -1 failed if the trackrenderer not even set up.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_audio_mute(handle, true);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_audio_mute(TrackRendererHandle handle, bool is_mute);
+
+/**
+ * @brief        Set trackrenderer video still mode
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : trackrenderer still mode on, off or non
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_video_still_mode(handle,
+ *                   kTrackRendererStillModeOn);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create()
+ */
+void trackrenderer_set_video_still_mode(TrackRendererHandle handle,
+                                        TrackRendererStillMode type);
+
+/**
+ * @brief        Get trackrenderer current state
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @return       Returns TrackRendererState.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               //your logic
+ *               TrackRendererState state = trackrenderer_get_state(handle);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create()
+ */
+TrackRendererState trackrenderer_get_state(TrackRendererHandle handle);
+
+/**
+ * @brief        Set attribute and value for trackrenderer.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] attr_name : name of first property to set.
+ * @param        [in] ... : value for the first property, followed optionally by
+ *               more name/value pairs, followed by NULL.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               unsigned long long video_queue_size = 2 * 1024 * 1024; // 2MB
+ *               unsigned long long audio_queue_size = 100 * 1024; // 100KB
+ *               trackrenderer_set_attribute(handle,
+ *                   "video-queue-max-byte", video_queue_byte,
+ *                   "audio-queue-max-byte", audio_queue_byte,
+ *                   NULL);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       a name of attribute and a type of value must be paired. \n
+ *               if you set wrong type of attribute, unknown error can be
+ *               occured.\n if trackrenderer can't parse attr_name, assertion
+ *               will be failed.
+ * @see          trackrenderer_create() \n
+ *               If you want to know what kinds of attribute are there, please
+ *               refer this link: \n
+ */
+void trackrenderer_set_attribute(TrackRendererHandle handle,
+                                 const char* attr_name, ...);
+
+/**
+ * @brief        Get attribute and value for trackrenderer.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] attr_name : name of first property to set.
+ * @param        [in] ... : value for the first property, followed optionally by
+ *               more name/value pairs, followed by NULL.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               unsigned long long video_current_byte;
+ *               unsigned long long audio_current_byte;
+ *               trackrenderer_get_attribute(handle,
+ *                   "video-current-level-byte", &video_current_byte,
+ *                   "audio-current-level-byte", &audio_current_byte,
+ *                   NULL);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          None
+ * @post         None
+ * @exception    None
+ * @version      2.0
+ * @remark       a name of attribute and a type of value must be paired. \n
+ *               if you set wrong type of attribute, unknown error can be
+ *               occured.\n if trackrenderer can't parse attr_name, assertion
+ *               will be failed.
+ * @see          trackrenderer_create() \n
+ *               If you want to know what kinds of attribute are there, please
+ *               refer this link: \n
+ */
+void trackrenderer_get_attribute(TrackRendererHandle handle,
+                                 const char* attr_name, ...);
+
+/**
+ * @brief        Set matroska color info to trackrenderer as string
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] color_info : matroska color info
+ * @return       Return 0 if no problem.
+ *               Otherewise -1 if the trackrenderer is not even set up.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               std::string color = "red";
+ *               trackrenderer_set_matroska_color_info(handle, color.c_str());
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_set_matroska_color_info(TrackRendererHandle handle,
+                                          const char* color_info);
+
+/**
+ * @brief        Set decoded video frame buffer type.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : one of the video decoded buffer type to set .
+ * @pre          The trackrenderer must be at least created, but before prepare
+ *               if type is not equal to be
+ * kTrackRendererDecodedVideoFrameBufferScale.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_video_frame_buffer_type(handle,
+ *                   kTrackRendererDecodedVideoFrameBufferReference);
+ *               //your logic
+ *               trackrenderer_prepare(handle);
+ *               //your logic
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None
+ * @version      2.0
+ * @see          trackrenderer_create()
+ */
+void trackrenderer_set_video_frame_buffer_type(
+    TrackRendererHandle handle, TrackRendererDecodedVideoFrameBufferType type);
+
+/**
+ * @brief        Set the target scale resolution when decoded video frame buffer
+ * type is scale
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] target_width : scale target width of video frame buffer.
+ * @param        [in] target_width : scale target height of video frame buffer.
+ * @return       Return 0 if no problem.
+ *               Otherewise -1 if the trackrenderer is not created.
+ * @pre          The trackrenderer must be at least created but before prepare.
+ *               trackrenderer_create()
+ * @post         None
+ * @version       3.1
+ * @exception    None
+ */
+int trackrenderer_set_video_frame_buffer_scale_resolution(
+    TrackRendererHandle handle, uint32_t target_width, uint32_t target_height);
+
+/**
+ * @brief        Set the request frame rate of decoded video
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] request_framerate : the request frame rate of returned decoded video frame
+ *                The value of track_framerate and request_framerate should be one of the following sets:
+ *                track_framerate indicate the frame rate of input video stream
+ *                 1.A/(A-B) = X ,X means drop 1 frame every X frame
+ *                 2.Special cases,such as 24000/1000 -> 15000/1000
+ *                when request_framerate.num = 0, return none decoded video frame.
+ *                when request_framerate.num/request_framerate.den =
+ *                  track_framerate.num/track_framerate.den, return all decoded 
+ *                  video frame.
+ *                when request_framerate.num/request_framerate.den <
+ *                  track_framerate.num/track_framerate.den, drop some decoded 
+ *                  video frame.
+ * @return       Return 0 if no problem.
+ *                Otherewise -1 if the trackrenderer is not created or the value
+ *                of request_framerate is invalid .
+ * @pre          The trackrenderer must be at least created.
+ *                trackrenderer_create()
+ * @post         None
+ * @version      3.3
+ * @exception    None
+ * @remark       Only works when decoded video frame buffer type is scale
+ */
+int trackrenderer_set_decoded_video_frame_rate(
+    TrackRendererHandle handle, TrackRendererRational request_framerate);
+
+/**
+ * @brief        Set volume to trackrenderer
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] volume : volume level(0 ~ 100)
+ * @return       Return 0 if no problem.
+ *               Otherewise -1 if the trackrenderer is not created.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               int volume = 65;
+ *               trackrenderer_set_volume(handle, volume));
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @version      2.0
+ * @exception    None
+ * @see          trackrenderer_create()
+ */
+
+int trackrenderer_set_volume(TrackRendererHandle handle, const int volume);
+
+/**
+ * @brief        Get volume from trackrenderer
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] volume : volume ptr
+ * @return       Return 0 if no problem.
+ *               Otherewise -1 if the trackrenderer is not created.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               //your logic
+ *               int volume = 0;
+ *               trackrenderer_get_volume(handle, &volume));
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @version      2.0
+ * @exception    None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_get_volume(TrackRendererHandle handle, int* volume);
+
+/**
+ * @brief        Provided api for rendering a video frame which is holded by
+ *               video frame peek mode.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @return       Return 0 if no problem.
+ * @code
+ *               //prepare trackrenderer hanle
+ *               //your logic
+ *               trackrenderer_render_video_frame(handle);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ *               trackrenderer_create()
+ *               trackrenderer_prepare() or after trackrenderer_seekdone_cb() is
+ *               called.
+ * @post         None
+ * @version      2.0
+ * @exception    None
+ * @remark       esplusplayer_set_video_frame_peek_mode().
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_render_video_frame(TrackRendererHandle handle);
+/**
+ * @brief        Set catch up speed.
+ * @description  Set catch up speed for catch up. The properties will
+ *               be used to catch up with latency
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] level : catch up speed level.
+ * @return       Return 0 if there is no problem.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_catch_up_speed(handle,
+ *                   kTrackRendererCatchUpSpeedSlow);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         None
+ * @exception    None
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_catch_up_speed(TrackRendererHandle handle,
+                                     const TrackRendererCatchUpSpeed level);
+/**
+ * @brief        Get current video latency status
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] status : current latency status.
+ * @return       Return 0 if there is no problem.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               //your logic
+ *               TrackRendererLatencyStatus status;
+ *               trackrenderer_get_video_latency_status(handle, &status)
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+
+ */
+int trackrenderer_get_video_latency_status(TrackRendererHandle handle,
+                                           TrackRendererLatencyStatus* status);
+/**
+ * @brief        Get current audio latency status
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] status : current latency status.
+ * @return       Return 0 if there is no problem.
+ * @code
+ *               refer to the sample code of
+ *               trackrenderer_get_video_latency_status()
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_get_video_latency_status()
+ */
+int trackrenderer_get_audio_latency_status(TrackRendererHandle handle,
+                                           TrackRendererLatencyStatus* status);
+
+/**
+ * @brief        Provided api for add an aifiter to the video pipeline.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] aifilter : aifilter plugin.
+ * @return       Return 0 if no problem.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               GstElement* aifilter =
+ *               gst_element_factory_make("aifilter_autozoom","auto_zoom");
+ *               if (aifilter != nullptr) {
+ *                   g_object_set(G_OBJECT(aifilter),"detection-type",2,NULL);
+ *                   g_object_set(G_OBJECT(aifilter),"is-enabled",TRUE,NULL);
+ *               }
+ *               trackrenderer_set_aifilter(handle,aifilter);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @version      3.0
+ * @exception    None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_aifilter(TrackRendererHandle handle, void* aifilter);
+
+/**
+ * @brief        Set mid latency threshold to trackrenderer
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] threshold : the threshold(number) of the video frames for
+ *               mid latency
+ * @code
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_audio_mid_latency_threshold(handle, 2);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @return       Return 0 if there is no problem.
+ * @pre          The trackrenderer must be at least created
+ *               TrackRendererState should be kTrackRendererStateInit or
+ *               kTrackRendererStateWorking.
+ * @post         None
+ * @exception    None
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_set_video_mid_latency_threshold(TrackRendererHandle handle,
+                                                  const unsigned int threshold);
+
+/**
+ * @brief        Set mid latency threshold to trackrenderer
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] threshold : the threshold(number) of the audio frames for
+ *               mid latency
+ * @code
+ *               refer the sample code of
+ *               trackrenderer_set_video_mid_latency_threshold()
+ * @endcode
+ * @return       Return 0 if there is no problem.
+ * @pre          The trackrenderer must be at least created
+ *               trackrenderer_create()
+ *               TrackRendererState should be kTrackRendererStateInit or
+ *               kTrackRendererStateWorking.
+ * @post         None
+ * @exception    None
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_video_mid_latency_threshold()
+ */
+int trackrenderer_set_audio_mid_latency_threshold(TrackRendererHandle handle,
+                                                  const unsigned int threshold);
+
+/**
+ * @brief        Set high latency threshold to trackrenderer
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] threshold : the threshold(number) of the video frames for
+ *               high latency
+ * @return       Return 0 if there is no problem.
+ * @code
+ *               refer the sample code of
+ *               trackrenderer_set_video_mid_latency_threshold()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ *               trackrenderer_create()
+ *               TrackRendererState should be kTrackRendererStateInit or
+ *               kTrackRendererStateWorking.
+ * @post         None
+ * @exception    None
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_video_mid_latency_threshold()
+ */
+int trackrenderer_set_video_high_latency_threshold(
+    TrackRendererHandle handle, const unsigned int threshold);
+
+/**
+ * @brief        Set high latency threshold to trackrenderer
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] threshold : the threshold(number) of the audio frames for
+ *               high latency
+ * @return       Return 0 if there is no problem.
+ * @code
+ *               refer the sample code of
+ *               trackrenderer_set_video_mid_latency_threshold()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ *               TrackRendererState should be kTrackRendererStateInit or
+ *               kTrackRendererStateWorking.
+ * @post         None
+ * @exception    None
+ * @version      3.0
+ * @remark       None
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_video_mid_latency_threshold()
+ */
+int trackrenderer_set_audio_high_latency_threshold(
+    TrackRendererHandle handle, const unsigned int threshold);
+
+/* CALL back*/
+
+/**
+ * @brief        Set error callback function.
+ * @description  If there is an error, the trackrenderer_error_cb will post
+ *               error message with error code.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_error_cb function
+ * @param        [in] userdata : userdata of trackrenderer_error_cb callback
+ *               function.
+ * @code
+ *               static void ErrorCb(const TrackRendererErrorType error_code,
+ *                   UserData userdata) {
+ *                   //Something you want to do when Receive error
+ *                   printf("Receive error\n");
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_error_cb(handle, ErrorCb, nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When there is error event, trackrenderer_error_cb() is called.
+ * @exception    None
+ * @remark       trackrenderer_error_cb \n
+ *               [in] error_code : enum TrackRendererErrorType\n
+ *               [in] userdata : userdata of trackrenderer_error_cb
+ *               callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_error_cb
+ */
+void trackrenderer_set_error_cb(TrackRendererHandle handle,
+                                trackrenderer_error_cb callback,
+                                void* userdata);
+
+/**
+ * @brief        Set error msg callback function.
+ * @description  If there is an error, the trackrenderer_error_cb will post
+ *               error message with error code and detailed infomation.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_error_msg_cb function
+ * @param        [in] userdata : userdata of trackrenderer_error_msg_cb callback
+ *               function.
+ * @code
+ *               static void ErrorMsgCb(const TrackRendererErrorType error_code,
+ *                   char* error_msg,UserData userdata) {
+ *                   //Something you want to do when Receive error
+ *                   printf("Receive error message: %s\n", error_msg);
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_error_msg_cb(handle, ErrorMsgCb, nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When there is error event, trackrenderer_error_msg_cb() is
+ *               called.
+ * @exception    None
+ * @version      3.0
+ * @remark       trackrenderer_error_msg_cb \n
+ *               [in] error_code : enum TrackRendererErrorType\n
+ *               [in] error_msg : detailed error message including info related
+ *               to codec,demuxer,network status, etc.
+ *               [in] userdata : userdata of trackrenderer_error_msg_cb
+ *               callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_error_msg_cb
+ */
+void trackrenderer_set_error_msg_cb(TrackRendererHandle handle,
+                                    trackrenderer_error_msg_cb callback,
+                                    void* userdata);
+
+/**
+ * @brief        Set resource conflict callback funciton
+ * @description  If there is resource conflict error, trackrender must release
+ *               the current TV decoder and display resource and data feeding
+ *               need to be stop as well.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_resource_conflicted_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_resource_conflicted_cb callback function.
+ * @code
+ *               static void ResourceConflictCb(UserData userdata) {
+ *                   //Something you want to do when Resource Conflict
+ *                   printf("Receive Resource Conflict message\n");
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_resourceconflict_cb(handle,
+ *                   ResourceConflictCb, nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When there is resource conflict, the
+ *               trackrenderer_resource_conflicted_cb will notify the resource
+ *               conflict message to manage the resource.
+ * @exception    None
+ * @remark       trackrenderer_resource_conflicted_cb \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_resource_conflicted_cb callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_resource_conflicted_cb
+ */
+void trackrenderer_set_resourceconflict_cb(
+    TrackRendererHandle handle, trackrenderer_resource_conflicted_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set video latency status callback function
+ * @description  If the latency status of the video stream changes, track
+ *               renderer must send the callback
+ *               to notify the application of the latency status.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_video_latency_status_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_video_latency_status_cb callback function.
+ * @code
+ *               static void static void VideoLatencyStatusCb(
+ *                   const TrackRendererLatencyStatus latency_status,
+ *                   UserData userdata) {
+ *                   //Something you want to do when VideoLatency Status change
+ *                   printf("Receive VideoLatency Status change message\n");
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_video_latency_status_cb(handle,
+ *                   VideoLatencyStatusCb, nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When the latency status of the video stream changes,
+ *               trackrenderer_video_latency_status_cb will be sent.
+ * @exception    None
+ * @version      3.0
+ * @remark       trackrenderer_video_latency_stuats_cb \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_video_latency_status_cb callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_video_latency_stuats_cb
+ */
+void trackrenderer_set_video_latency_status_cb(
+    TrackRendererHandle handle, trackrenderer_video_latency_status_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set audio latency status callback function
+ * @description  If the latency status of the audio stream changes, track
+ *               renderer must send the callback
+ *               to notify the application of the latency status.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_audio_latency_status_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_audio_latency_status_cb callback function.
+ * @code
+ *               refer to the sample code of
+ *               trackrenderer_set_video_latency_status_cb()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When the latency status of the audio stream
+ *               changes,trackrenderer_audio_latency_status_cb will besent.
+ * @exception    None
+ * @version      3.0
+ * @remark       trackrenderer_audio_latency_stuats_cb \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_audio_latency_status_cb
+ *               callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_audio_latency_stuats_cb
+ */
+void trackrenderer_set_audio_latency_status_cb(
+    TrackRendererHandle handle, trackrenderer_audio_latency_status_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set video high latency callback function
+ * @description  If video high latency occurs, track renderer must send the
+ * callback
+ *               to notify the application of the player buffer status.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_video_high_latency_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_high_latency_cb callback function.
+ * @code
+ *               static void VideoHighLatencyCb(UserData userdata) {
+ *                   //Something you want to do when high latency occurs *
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_video_high_latency_cb(handle,
+ *                   VideoHighLatencyCb, nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When video high latency occurs,
+ *               trackrenderer_video_high_latency_cb will be sent.
+ * @exception    None
+ * @version      3.0
+ * @remark       trackrenderer_video_high_latency_cb \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_video_high_latency_cb callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_video_high_latency_cb
+ */
+void trackrenderer_set_video_high_latency_cb(
+    TrackRendererHandle handle, trackrenderer_video_high_latency_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set audio high latency callback function
+ * @description  If audio high latency occurs, track renderer must send the
+ *               callback
+ *               to notify the application of the player buffer status.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_audio_high_latency_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_audio_high_latency_cb callback function.
+ * @code
+ *               refer to the sample code of
+ *               trackrenderer_set_video_high_latency_cb()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When audio high latency occurs,
+ *               trackrenderer_audio_high_latency_cb will be
+ * sent.
+ * @exception    None
+ * @version      3.0
+ * @remark       trackrenderer_audio_high_latency_cb \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_audio_high_latency_cb callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_audio_high_latency_cb
+ */
+void trackrenderer_set_audio_high_latency_cb(
+    TrackRendererHandle handle, trackrenderer_audio_high_latency_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set seek done callback funciton.
+ * @description  If seek operation is finished, the trackrenderer_seekdone_cb
+ *               will be called to notify seek status to help to decide next
+ *               operation during or after seek.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_seekdone_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_seekdone_cb callback
+ *               function.
+ * @code
+ *               refer to the sample code of trackrenderer_seek()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When seek done, app will handle the trackrenderer_seekdone_cb
+ *               to decide next operation.
+ * @exception    None
+ * @remark       trackrenderer_seekdone_cb \n
+ *               [in] userdata : userdata of trackrenderer_seekdone_cb callback
+ *               function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_seekdone_cb
+ */
+void trackrenderer_set_seekdone_cb(TrackRendererHandle handle,
+                                   trackrenderer_seekdone_cb callback,
+                                   void* userdata);
+
+/**
+ * @brief        Set flush done callback funciton.
+ * @description  If flush operation is finished, the trackrenderer_flushdone_cb
+ *               will be called to notify flush status to help to decide next
+ *               operation after flush.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_flushdone_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_flushdone_cb callback
+ *               function.
+ * @code
+ *               refer to the sample code of trackrenderer_flush()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When flush done, app will handle the trackrenderer_flushdone_cb
+ *               to decide next operation.
+ * @exception    None
+ * @version      2.0
+ * @remark       trackrenderer_flushdone_cb \n
+ *               [in] userdata : userdata of trackrenderer_flushdone_cb callback
+ *               function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_flushdone_cb
+ */
+void trackrenderer_set_flushdone_cb(TrackRendererHandle handle,
+                                    trackrenderer_flushdone_cb callback,
+                                    void* userdata);
+/**
+ * @brief        Set event callback function
+ * @description  In this function set event callback to get event information.
+ *               If a specific event occurs, trackrenderer_event_cb will be
+ *               called to notify it with event information.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_event_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_event_cb
+ *               callback function.
+ * @code
+ *               static void OnEventCb(const TrackRendererEventType event_type,
+ *                   const TrackrendererEventMsg msg_data,UserData userdata) {
+ *                   //Something you want to do when the event occurs
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_event_cb(handle,OnEventCb, nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         App can get the information of the event that occured.
+ * @version      2.0
+ * @exception    None
+ * @remark       trackrenderer_event_cb
+ *               [in] event_type : event type that occured.
+ *               [in] msg_data : event message data.
+ *               [in] userdata : userdata of trackrenderer_event_cb callback
+ *               function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_event_cb
+ */
+void trackrenderer_set_event_cb(TrackRendererHandle handle,
+                                trackrenderer_event_cb callback,
+                                void* userdata);
+/**
+ * @brief        Set subtitle callback function
+ * @description  In this function set subtitle callback to handle the subtitle.
+ *               If there is subtitle to display trackrenderer_subtitle_rawdata_cb
+ *               will be called to notify there is subtitle to display.
+ *               The subtitle whole raw data will be shared. If user get this
+ *               callback and want to display the subtitle, user should get
+ *               subtitle informations from shared raw data.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_subtitle_rawdata_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_subtitle_rawdata_cb callback function.
+ * @code
+ *               static void SubtitleRawDataCb(TrackRendererDecoderInputBuffer* buf,
+ *                   const TrackRendererSubtitleType type,
+ *                   UserData userdata) {
+ *                   //Something you want to do when there is subtitle data
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_subtitle_rawdata_cb(handle,SubtitleRawDataCb,nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When there is subtitledata, call
+ *               trackrenderer_subtitle_rawdata_cb to notice that there is
+ *               subtitle needed to be displayed.
+ * @exception    None
+ * @remark       trackrenderer_subtitle_rawdata_cb \n
+ *               [in] buf : buffer including subtitle information \n
+ *               [in] type : subtitle type (text or picture) \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_subtitle_rawdata_cb callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_subtitle_rawdata_cb
+ */
+void trackrenderer_set_subtitle_rawdata_cb(
+    TrackRendererHandle handle, trackrenderer_subtitle_rawdata_cb callback,
+    void* userdata);
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+/**
+ * @brief        Set subtitle callback function (deprecated)
+ * @description  (deprecated) In this function set subtitle callback to handle
+ *               the subtitle. If there is subtitle to display
+ *               trackrenderer_subtitledata_cb will be called to notify there
+ *               is subtitle to display. If user get this callback and want to display the
+ *               subtitle, user can use the shared subtitle informations.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_subtitledata_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_subtitledata_cb
+ *               callback function.
+ * @code
+ *               static void SubtitleDataCb(const char* data, const int size,
+ *                   const TrackRendererSubtitleType type,
+ *                   const unsigned long long duration,
+ *                   TrackRendererSubtitleAttr* attr_list,
+ *                   int attr_list_size, UserData userdata) {
+ *                   //Something you want to do when  there is subtitle data
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_subtitledata_cb(handle,SubtitleDataCb,nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When there is subtitledata, call
+ *               trackrenderer_subtitledata_cb to notice that there is subtitle needed to be
+ *               displayed.
+ * @exception    None
+ * @remark       trackrenderer_subtitledata_cb \n
+ *               [in] data : subtitle data \n
+ *               [in] size : subtitle data length \n
+ *               [in] type : subtitle type (text or picture) \n
+ *               [in] duration : subtitle duration (ms) \n
+ *               [in] attr_list : list of subtitle attribute \n
+ *               [in] attr_list_size : length of subtite attribute \n
+ *               [in] userdata : userdata of trackrenderer_subtitledata_cb
+ *               callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_subtitledata_cb
+ */
+void trackrenderer_set_subtitledata_cb(TrackRendererHandle handle,
+                                       trackrenderer_subtitledata_cb callback,
+                                       void* userdata);
+#endif
+
+/**
+ * @brief        Set EOS callback function
+ * @description  In this function set EOS callback to handle EOS. If the
+ *               playing contents meet EOS, trackrenderer_eos_cb will be called 
+ *               to notify the contents end.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_eos_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_eos_cb callback
+ *               function.
+ * @code
+ *               static void EosCb(UserData userdata) {
+ *                   //Something you want to do when contents meet EOS
+ *                   printf("EOS received\n");
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_eos_cb(handle,EosCb,nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When contents meet EOS, the trackrenderer_eos_cb will be
+ *               called
+ * @exception    None
+ * @remark       trackrenderer_eos_cb \n
+ *               [in] userdata : userdata of trackrenderer_eos_cb callback
+ *               function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_eos_cb
+ */
+void trackrenderer_set_eos_cb(TrackRendererHandle handle,
+                              trackrenderer_eos_cb callback, void* userdata);
+
+/**
+ * @brief        Set closed caption callback function.
+ * @description  In this function set closed caption callback to handle the
+ *               closed caption. If there is close caption to display,
+ *               trackrenderer_closedcaption_cb will be called to notify there
+ *               is closed caption to display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_closedcaption_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_closedcaption_cb
+ *               callback function.
+ * @code
+ *               static void ClosedCaptionDataCb(const char* data,
+ *                   const int size, UserData userdata) {
+ *                   //Something you want to do when there is closed
+ *                   caption needed to be displayed
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_closedcaption_cb(handle,ClosedCaptionDataCb,nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When there is closed caption data, call
+ *               trackrenderer_closedcaption_cb to nofity that there is closed
+ *               caption needed to be displayed.
+ * @exception    None
+ * @remark       trackrenderer_closedcaption_cb \n
+ *               [in] data : closedcaption data \n
+ *               [in] size : length of closedcaption data \n
+ *               [in] userdata : userdata of trackrenderer_closedcaption_cb
+ *               callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_closedcaption_cb
+ */
+void trackrenderer_set_closedcaption_cb(TrackRendererHandle handle,
+                                        trackrenderer_closedcaption_cb callback,
+                                        void* userdata);
+
+/**
+ * @brief        Set drm initialize data callback function.
+ * @description  In this function set drm initialize data callback. If
+ *               trackrenderer detected any informations which need to
+ *               initiate drm, the trackrenderer_drminitdata_cb is called to
+ *               share the drm informations for dectyption.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_drminitdata_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_drminitdata_cb
+ *               callback function.
+ * @code
+ *               static void DrmInitDataCb(int* drmhandle,unsigned int len,
+ *                   unsigned char* psshdata, TrackRendererTrackType type,
+ *                   UserData userdata) {
+ *                   //Something you want to do when detect any drm data
+ *                   printf("drm data received\n");
+ *               }
+ *               trackrenderer_create(&handle);
+ *               trackrenderer_set_drminitdata_cb(handle,DrmInitDataCb,nullptr);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When the trackrenderer detect any drm data, call
+ *               trackrenderer_drminitdata_cb function to share the init data.
+ * @exception    The trackrenderer must be at least created
+ * @remark       trackrenderer_drminitdata_cb \n
+ *               [in] drmhandle : drm handle \n
+ *               [in] len : pssh data length \n
+ *               [in] psshdata : pssh data \n
+ *               [in] type : track type \n
+ *               [in] userdata : userdata of trackrenderer_drminitdata_cb
+ *               callback function.
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_set_drminitdata_cb
+ */
+void trackrenderer_set_drminitdata_cb(TrackRendererHandle handle,
+                                      trackrenderer_drminitdata_cb callback,
+                                      void* userdata);
+
+/**
+ * @brief        Set current buffer status call back function
+ * @description  In this function set buffer status callback function. If
+ *               trackrenderer detected that there is not enough data or full
+ *               at trackrenderer buffer, call trackrenderer_bufferstatus_cb
+ *               to let user know what current buffer status is.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_bufferstatus_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_bufferstatus_cb
+ *               callback function.
+ * @code
+ *               refer to the sample code of trackrenderer_submit_packet()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When trackrenderer buffer status has changed to not enough or
+ *               full, call trackrenderer_bufferstatus_cb()
+ * @exception    None
+ * @remark       trackrenderer_bufferstatus_cb \n
+ *               [in] type : track type \n
+ *               [in] status : trackrenderer buffer status \n
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_bufferstatus_cb
+ */
+void trackrenderer_set_bufferstatus_cb(TrackRendererHandle handle,
+                                       trackrenderer_bufferstatus_cb callback,
+                                       void* userdata);
+
+/**
+ * @brief        Set seek data callback function
+ * @description  In this function set seek data callback function. After
+ *               flushing currently buffered data and trackrenderer is ready
+ *               to get new seeked position segment data, the
+ *               trackrenderer_seekdata_cb is called. If get this callback,
+ *               user can know the time to push new segment data.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_seekdata_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_seekdata_cb
+ *               callback function.
+ * @code
+ *               please refer to the sample code of trackrenderer_seek()
+ * @endcode
+ * @pre          The trackrenderer must be at least created
+ * @post         When trackrenderer finish to flush the buffered data for seek
+ *               operation, call trackrenderer_seekdata_cb .
+ * @exception    None
+ * @remark       trackrenderer_seekdata_cb \n
+ *               [in] type : track type \n
+ *               [in] offset : the new seeked position \n
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_seekdata_cb
+ */
+void trackrenderer_set_seekdata_cb(TrackRendererHandle handle,
+                                   trackrenderer_seekdata_cb callback,
+                                   void* userdata);
+
+/**
+ * @brief        Set tbm surface get callback function
+ * @description  In this function set bm surface get  callback function.
+ *               After setting, user can get the useful tbm surface by
+ *               callback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback :
+ * trackrenderer_media_packet_video_tbmptr_cb ptr.
+ * @param        [in] userdata : userdata of callback function.
+ * @pre          None
+ * @version        3.2
+ * @post         When trackrenderer would send decoded video buffer, call
+ * trackrenderer_media_packet_video_tbmptr_cb .
+ * @exception    None
+ * @remark       trackrenderer_media_packet_video_tbmptr_cb \n
+ *                  [in] ptr : pointer set to get the tbm surface data  \n
+ */
+void trackrenderer_set_media_packet_video_tbmptr_cb(
+    TrackRendererHandle handle,
+    trackrenderer_media_packet_video_tbmptr_cb callback, void* userdata);
+
+/**
+ * @brief        Set video decoded buffer callback function
+ * @description  In this function set video decoded buffer callback function.
+ *               After setting, user can get the video decoded buffers by
+ *               callback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] media_packet_video_decoded_cb :
+ *               trackrenderer_media_packet_video_decoded_cb ptr.
+ * @param        [in] userdata : userdata of media_packet_video_decoded_cb
+ *               callback function.
+ * @pre          The trackrenderer must be at least created
+ * @version      2.0
+ * @post         When trackrenderer decoded video buffer, call
+ *               trackrenderer_media_packet_video_decoded_cb .
+ * @exception    None
+ * @remark       trackrenderer_media_packet_video_decoded_cb \n
+ *               [in] packet : packet including decoded buffer  \n
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_media_packet_video_decoded_cb
+ */
+void trackrenderer_set_media_packet_video_decoded_cb(
+    TrackRendererHandle handle,
+    trackrenderer_media_packet_video_decoded_cb media_packet_video_decoded_cb,
+    void* userdata);
+
+/**
+ * @brief        Set multiview start video callback function
+ * @description  Entering mulview mode, if ResourceCenter sends
+ * video start request to a player when it's required, the callback function
+ * will be invoked. User must activate new stream by trackrenderer_activate()
+ * before callback returns, and seek to current playing position.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_multiview_start_video_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_multiview_start_video_cb callback function.
+ * @pre          The trackrenderer must be created but before
+ * trackrenderer_prepare()
+ * @post         When ResourceCenter sends video start request to a player,
+ * trackrenderer_multiview_start_video_cb will be sent.
+ * @exception    None
+ * @version      3.1
+ * @remark       trackrenderer_multiview_start_video_cb \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_multiview_start_video_cb callback function.
+ * @see          trackrenderer_activate() \n
+ *               trackrenderer_seek() \n
+ *               trackrenderer_seek2() \n
+ */
+void trackrenderer_set_multiview_start_video_cb(
+    TrackRendererHandle handle, trackrenderer_multiview_start_video_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set multiview stop video callback function
+ * @description  Entering mulview mode, if ResourceCenter sends
+ * video stop request to a player when it's required, the callback function will
+ * be invoked. User must stop video packet feeding, and deactivate video stream
+ * by trackrenderer_deactivate() before callback returns.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_multiview_stop_video_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_multiview_stop_video_cb callback function.
+ * @pre          The trackrenderer must be created but before
+ * trackrenderer_prepare()
+ * @post         When ResourceCenter sends video start request to a player,
+ * trackrenderer_multiview_stop_video_cb will be sent.
+ * @exception    None
+ * @version      3.1
+ * @remark       trackrenderer_multiview_stop_video_cb \n
+ *               [in] userdata : userdata of
+ *               trackrenderer_multiview_stop_video_cb callback function.
+ * @see          trackrenderer_deactivate() \n
+ */
+void trackrenderer_set_multiview_stop_video_cb(
+    TrackRendererHandle handle, trackrenderer_multiview_stop_video_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Initialize easing info to trackrenderer.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] init_volume : initial easing volume (0 ~ 100).
+ * @param        [in] init_elapsed_time : initial elapsed time (millisecond).
+ * @param        [in] easing_info : target volume, duration, type.
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               const TrackRendererAudioEasingInfo init_info =
+ *                   {0,1000,kTrackRendererAudioEasingLinear};
+ *               trackrenderer_init_audio_easing_info(handle, 100, 0,
+ *                   &init_info);
+ *               //your logic
+ *               const TrackRendererAudioEasingInfo update_info =
+ *                   {100,1000,kTrackRendererAudioEasingLinear};
+ *               trackrenderer_update_audio_easing_info(handle, &update_info));
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.0
+ * @see          trackrenderer_create()
+ */
+int trackrenderer_init_audio_easing_info(
+    TrackRendererHandle handle, const uint32_t init_volume,
+    const uint32_t init_elapsed_time,
+    const TrackRendererAudioEasingInfo* easing_info);
+
+/**
+ * @brief        Update easing info to trackrenderer.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] easing_info : target volume, duration, type.
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               refer to the sample code of
+ *               trackrenderer_init_audio_easing_info()
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ *               This api should be called after
+ *               trackrenderer_init_audio_easing_info() is called
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.0
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_init_audio_easing_info()
+ */
+int trackrenderer_update_audio_easing_info(
+    TrackRendererHandle handle,
+    const TrackRendererAudioEasingInfo* easing_info);
+
+/**
+ * @brief        Get easing info currently in easing operation from
+ *               trackrenderer
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [out] current_volume : current volume (0 ~ 100).
+ * @param        [out] elapsed_time : elapsed time (millisecond).
+ * @param        [out] easing_info : target volume, duration, type.
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               const TrackRendererAudioEasingInfo init_info =
+ *                   {0,1000,kTrackRendererAudioEasingLinear};
+ *               trackrenderer_init_audio_easing_info(handle, 100, 0,
+ *                   &init_info);
+ *               //your logic
+ *               uint32_t cur_volume = 0;
+ *               uint32_t elapsed_time = 0;
+ *               TrackRendererAudioEasingInfo get_info;
+ *               trackrenderer_get_audio_easing_info(handle, &cur_volume,
+ *                   &elapsed_time, &get_info);
+ *               //your logic
+ *               trackrenderer_destroy(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ *               This api should be called after
+ *               trackrenderer_init_audio_easing_info() is called
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.0
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_init_audio_easing_info()
+ */
+int trackrenderer_get_audio_easing_info(
+    TrackRendererHandle handle, uint32_t* current_volume,
+    uint32_t* elapsed_time, TrackRendererAudioEasingInfo* easing_info);
+
+/**
+ * @brief        Start audio easing using a registered audio easing info
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               trackrenderer_create(&handle);
+ *               const TrackRendererAudioEasingInfo init_info =
+ *                   {0,1000,kTrackRendererAudioEasingLinear};
+ *               trackrenderer_init_audio_easing_info(handle, 100, 0,
+ *                   &init_info);
+ *               trackrenderer_prepare(handle);
+ *               trackrenderer_start_audio_easing(handle);
+ *               //your logic
+ *               trackrenderer_stop_audio_easing(handle);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ *               This api should be called after
+ *               trackrenderer_init_audio_easing_info() is called
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.0
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_init_audio_easing_info()
+ */
+int trackrenderer_start_audio_easing(TrackRendererHandle handle);
+
+/**
+ * @brief        Stop audio easing
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               refer to the sample code of trackrenderer_start_audio_easing()
+ * @endcode
+ * @pre          The trackrenderer must be at least created.
+ *               This api should be called after
+ *               trackrenderer_init_audio_easing_info() is called
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.0
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare() \n
+ *               trackrenderer_start_audio_easing() \n
+ *               trackrenderer_init_audio_easing_info()
+ */
+int trackrenderer_stop_audio_easing(TrackRendererHandle handle);
+
+/**
+ * @brief        Get virtual resource id
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : the resource type of virtual id.
+ * @param        [out] virtual_id : Stored virtual resource id value.
+ * @return       0 on success, otherwise -1 failed.
+ * @code
+ *               //prepare trackrenderer hanle *
+ *               //your logic
+ *               int virtual_id = -1;
+ *               trackrenderer_get_virtual_rsc_id(
+ *               handle, kTrackRendererRscTypeVideoRenderer, &virtual_id);
+ *               //your logic
+ *               trackrenderer_stop(handle);
+ * @endcode
+ * @pre          The trackrenderer must be at least created and set up.
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.0
+ * @see          trackrenderer_create() \n
+ *               trackrenderer_prepare()
+ */
+int trackrenderer_get_virtual_rsc_id(TrackRendererHandle handle,
+                                     TrackRendererRscType type,
+                                     int* virtual_id);
+
+/**
+ * @brief        Set advanced picture quality type
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : the advanced picture quality type.
+ * @return       0 on success, otherwise -1 failed.
+ * @pre          The trackrenderer must be at least created.
+ *               trackrenderer_create()
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.1
+ */
+int trackrenderer_set_advanced_picture_quality_type(
+    TrackRendererHandle handle, TrackRendererAdvPictureQualityType type);
+
+/**
+ * @brief        Set resource allocate policy
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] policy : the resource allocate policy.
+ * @return       0 on success, otherwise -1 failed.
+ * @pre          The trackrenderer must be at least created.
+ *               trackrenderer_create()
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.2
+ */
+int trackrenderer_set_resource_allocate_policy(
+    TrackRendererHandle handle, TrackRendererRscAllocPolicy policy);
+
+/**
+ * @brief        Set video's par(pixel aspect ratio) and dar(display aspect
+ * ratio)
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] time_millisecond : timestamp when par and dar will
+ * changed.
+ * @param        [in] par_num : par_num : numerator of par.
+ * @param        [in] par_den : par_den : denominator of par.
+ * @param        [in] dar_num : dar_num : numerator of dar.
+ * @param        [in] dar_den : dar_den : denominator of dar.
+ * @return       0 on success, otherwise -1 failed.
+ * @pre          The trackrenderer must be at least created.
+ *               trackrenderer_create()
+ * @post         None
+ * @exception    None
+ * @remark       None
+ * @version      3.3
+ */
+int trackrenderer_set_video_par_dar(TrackRendererHandle handle,
+                                    uint64_t time_millisecond, uint32_t par_num,
+                                    uint32_t par_den, uint32_t dar_num,
+                                    uint32_t dar_den);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_CAPI_H__
diff --git a/include/trackrenderer_capi/trackrenderer_internal.h b/include/trackrenderer_capi/trackrenderer_internal.h
new file mode 100755 (executable)
index 0000000..f55a3ca
--- /dev/null
@@ -0,0 +1,289 @@
+/**
+ * @file           trackrenderer_internal.h
+ * @brief          trackrenderer internally used api c version
+ * @interfacetype  Module
+ * @platform_porting_interface
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is trackrenderer api header implemented as C style to
+ *                 avoid binary compatibility issues.
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_INTERNAL_H__
+#define __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_INTERNAL_H__
+
+#include "trackrenderer_capi/display.h"
+#include "trackrenderer_capi/track_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  video decoded buffer struct (raw mode)
+ */
+typedef struct {
+  /**
+   * @description   buffer pts, in millisecond
+   */
+  uint64_t pts;
+  /**
+   * @description   width
+   */
+  uint32_t width;
+  /**
+   * @description   height
+   */
+  uint32_t height;
+  /**
+   * @description   internal data
+   */
+  void* internal_data;
+} TrackRendererDecodedVideoRawModePacket;
+
+/**
+ * @brief  Enumerations for types of video decoded buffer (raw mode)
+ */
+enum TrackRendererDecodedVideoType {
+  kTrackRendererDecodedVideoPhysicalAddressType,
+  kTrackRendererDecodedVideoTizenBufferType,
+};
+
+/**
+ * @brief  Enumerations for video decoded buffer type
+ */
+enum TrackRendererDecodedVideoFrameBufferTypeExt {
+  kTrackRendererDecodedVideoFrameBufferExtNone,
+  kTrackRendererDecodedVideoFrameBufferExtRaw
+};
+
+/**
+ * @brief  Enumerations for video renderer type
+ */
+enum TrackRendererVideoRendererType {
+  TrackRendererVideoRendererTypeMain,
+  TrackRendererVideoRendererTypeSub,
+  TrackRendererVideoRendererTypeSub2,
+  TrackRendererVideoRendererTypeSub3,
+};
+
+typedef void* TrackRendererHandle;
+typedef void (*trackrenderer_first_decoding_done_cb)(void* userdata);
+
+/**
+ * @description  When trackrenderer detected that there is not enough data at
+ *               decoder output buffer, call this function to let user know
+ *               current buffer status.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_decoder_underrun_cb callback function.
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_decoder_underrun_cb, in advance.
+ * @post         User can control data feeding speed with this change callback.
+ * @see          trackrenderer_set_decoder_underrun_cb()
+ */
+typedef void (*trackrenderer_decoder_underrun_cb)(void* userdata);
+
+/**
+ * @description  When trackrenderer finish to decode video buffer,
+ *               this is called, then user can get the decoded video buffer
+ * @param        [in] packet : decoded video packet \n
+ *               [in] type : the type of decoded video packet.
+ *                           (tbm_key or h/w decoded) \n
+ * @pre          The callback function should be set by
+ *               trackrenderer_set_media_packet_video_raw_decoded_cb,
+ *               in advance.
+ * @post         User can use the decoded buffer to render.
+ * @see          trackrenderer_set_media_packet_video_raw_decoded_cb()
+ */
+typedef void (*trackrenderer_media_packet_video_raw_decoded_cb)(
+    const TrackRendererDecodedVideoRawModePacket* packet,
+    TrackRendererDecodedVideoType type, void* userdata);
+
+/**
+ * @brief        Set the video display properties.
+ * @description  In this function set rendering object and rendering
+ *               locations. If the trackrenderer is not prepared to update the
+ *               display yet, the trackrenderer stored the rendering object
+ *               properties and update display after trackrenderer is ready to
+ *               update display.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : display type
+ * @param        [in] ecore_wl2_window : ecore wayland handle to display window.
+ * @param        [in] x : x param of display window
+ * @param        [in] y : y param of display window
+ * @param        [in] w : width of display window
+ * @param        [in] h : height of display window
+ * @return       Return 0 if rendering oejct and properties are successfully
+ *               applied for displaying contents or stored for future
+ *               displaying.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @pre          The trackrenderer must be at least created.
+ *               trackrenderer_create()
+ * @post         None
+ * @exception    None
+ * @remark       None
+ */
+int trackrenderer_set_display_ecore_wl2_window(TrackRendererHandle handle,
+                                               TrackRendererDisplayType type,
+                                               void* ecore_wl2_window, int x,
+                                               int y, int w, int h);
+/**
+ * @brief        Set first decoding done call back function
+ * @description  in this function set first decoding done callback function.
+ *               It wil be invoked when the first video frame is decoded.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_first_decoding_done_cb ptr.
+ * @param        [in] userdata : userdata of
+ *               trackrenderer_first_decoding_done_cb callback function.
+ * @pre          "video-frame-peek-mode" attribute of
+ *               trackrenderer_set_attribute() have to be set.
+ * @post         When the first video frame is decoded, call
+ *               trackrenderer_first_decoding_done_cb()
+ * @exception    None
+ * @remark       trackrenderer_first_decoding_done_cb \n
+ */
+void trackrenderer_set_first_decoding_done_cb(
+    TrackRendererHandle handle, trackrenderer_first_decoding_done_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set video decoder underrun status call back function
+ * @description  In this function set buffer status callback function. If
+ *               trackrenderer detected that not enough data at decoder output
+ *               buffer, call trackrenderer_decoder_underrun_cb to let user
+ *               know current buffer status.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] callback : trackrenderer_decoder_underrun_cb ptr.
+ * @param        [in] userdata : userdata of trackrenderer_decoder_underrun_cb
+ *               callback function.
+ * @pre          None
+ * @post         When video decoder buffer status has changed to not enough,
+ *               call trackrenderer_decoder_underrun_cb()
+ * @exception    None
+ * @remark       trackrenderer_decoder_underrun_cb \n
+ */
+void trackrenderer_set_video_decoder_underrun_cb(
+    TrackRendererHandle handle, trackrenderer_decoder_underrun_cb callback,
+    void* userdata);
+
+/**
+ * @brief        Set active track info to set up trackrenderer properties.
+ * @description  In this fuction, trackrenderer set track info which is
+ *               necessary for media contents playback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] handles_array : Active track handles for playing media
+ *               contents.
+ * @param        [in] array_size : Number of tracks. The maximum number of
+ *               tracks is 3.(audio, video, subtitle)
+ * @return       Return 0 if there are any active tracks among audio, video,
+ *               subtitle and successcully set the track info to trackrenderer.
+ *               Otherwise -1 if there is not any active tracks or already set
+ *               tracks info.
+ * @pre          This api should never be called before.
+ * @post         TrackRenderer sets factories to create pipeline using tracks
+ *               passed.
+ * @exception    None
+ * @remark       None
+ * @see          trackrenderer_track_create()\n
+ *               trackrenderer_track_destroy()
+ */
+int trackrenderer_set_track_handle(
+    TrackRendererHandle handle, const TrackRendererTrackHandle* handles_array,
+    const int array_size);
+
+/**
+ * @brief        Provided api for setting alternative audio resource(sub decoder
+ *               and sub out)
+ * @description  In this fuction, trackrenderer select the main or sub among the
+ *               HW resources.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] rsc_type : set alternative audio resource
+ *               (@c 0 = default audio resource(main), @c 1 = audio sub
+ *               resource)
+ * @return       Return 0 if set the audio resource type.
+ *               Otherwise -1 if the trackrenderer is not even setup.
+ * @pre          The trackrenderer must be at least created.
+ *               trackrenderer_create()
+ * @post         None
+ * @exception    None
+ * @remark       None
+ */
+
+int trackrenderer_set_alternative_audio_resource(TrackRendererHandle handle,
+                                                 unsigned int rsc_type);
+
+/**
+ * @brief        Set decoded video frame buffer extended type.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : one of the video decoded buffer type to set .
+ * @pre          The trackrenderer must be at least created but before prepare.
+ *               trackrenderer_create()
+ * @post         None
+ * @exception    None
+ */
+void trackrenderer_set_video_frame_buffer_type_ext(
+    TrackRendererHandle handle,
+    TrackRendererDecodedVideoFrameBufferTypeExt type);
+
+/**
+ * @brief        Set video decoded raw buffer callback function
+ * @description  In this function set video decoded buffer callback function.
+ *               After setting, user can get the video decoded buffers by
+ *               callback.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] media_packet_video_decoded_cb :
+ *               trackrenderer_media_packet_video_raw_decoded_cb ptr.
+ * @param        [in] userdata : userdata of media_packet_video_decoded_cb
+ *               callback function.
+ * @pre          None
+ * @post         When trackrenderer decoded video buffer, call
+ *               trackrenderer_media_packet_video_raw_decoded_cb.
+ * @exception    None
+ * @remark       trackrenderer_media_packet_video_decoded_cb \n
+ *               [in] packet : packet including decoded buffer  \n
+ *               [in] type : the type of decoded video packet.
+ *                           (tbm_key or h/w decoded) \n
+ */
+void trackrenderer_set_media_packet_video_raw_decoded_cb(
+    TrackRendererHandle handle,
+    trackrenderer_media_packet_video_raw_decoded_cb
+        media_packet_video_decoded_cb,
+    void* userdata);
+
+/**
+ * @brief        Set video renderer type. It overrides the scaler type from
+ *               trackrenderer_set_attribute(handle,
+ *               "alternative-video-resource", type, nullptr)
+ *               It also depends on target which support multi video renderer.
+ * @param        [in] handle : trackrenderer handle ptr.
+ * @param        [in] type : video renderer type
+ * @return       Return 0 if set the video renderer type.
+ *               Otherwise -1 if the video renderer type is not even setup.
+ * @pre          None
+ * @post         None
+ * @see          TrackRendererVideoRendererType
+ */
+int trackrenderer_set_video_renderer_type(
+    TrackRendererHandle handle, TrackRendererVideoRendererType renderer_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __CAPI_TRACKRENDERER_TV_TRACKRENDERER_CAPI_TRACKRENDERER_INTERNAL_H__
diff --git a/out/docs/class_diagram/adapter/bms_avplayer_player_adapter(1)/bms_avplayer_player_adapter(1).png b/out/docs/class_diagram/adapter/bms_avplayer_player_adapter(1)/bms_avplayer_player_adapter(1).png
new file mode 100755 (executable)
index 0000000..e5504b4
Binary files /dev/null and b/out/docs/class_diagram/adapter/bms_avplayer_player_adapter(1)/bms_avplayer_player_adapter(1).png differ
diff --git a/out/docs/class_diagram/adapter/bms_avplayer_player_adapter(2)/bms_avplayer_player_adapter(2).png b/out/docs/class_diagram/adapter/bms_avplayer_player_adapter(2)/bms_avplayer_player_adapter(2).png
new file mode 100755 (executable)
index 0000000..8a0d3bf
Binary files /dev/null and b/out/docs/class_diagram/adapter/bms_avplayer_player_adapter(2)/bms_avplayer_player_adapter(2).png differ
diff --git a/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 1.png b/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 1.png
new file mode 100755 (executable)
index 0000000..207bdf9
Binary files /dev/null and b/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 1.png differ
diff --git a/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 2.png b/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 2.png
new file mode 100755 (executable)
index 0000000..a0c1341
Binary files /dev/null and b/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter-TO-BE page 2.png differ
diff --git a/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter.png b/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter.png
new file mode 100755 (executable)
index 0000000..0022fc6
Binary files /dev/null and b/out/docs/class_diagram/adapter/webapi_avplay_player_adapter/webapi_avplay_player_adapter.png differ
diff --git a/out/docs/class_diagram/bmservice_drmmanager_plusplayer/bmservice_drmmanager_plusplayer.png b/out/docs/class_diagram/bmservice_drmmanager_plusplayer/bmservice_drmmanager_plusplayer.png
new file mode 100755 (executable)
index 0000000..64fc589
Binary files /dev/null and b/out/docs/class_diagram/bmservice_drmmanager_plusplayer/bmservice_drmmanager_plusplayer.png differ
diff --git a/out/docs/class_diagram/details/defaultplayer/DefaultPlayer.png b/out/docs/class_diagram/details/defaultplayer/DefaultPlayer.png
new file mode 100755 (executable)
index 0000000..ca9fd33
Binary files /dev/null and b/out/docs/class_diagram/details/defaultplayer/DefaultPlayer.png differ
diff --git a/out/docs/class_diagram/details/trackrenderer/TrackRenderer.png b/out/docs/class_diagram/details/trackrenderer/TrackRenderer.png
new file mode 100755 (executable)
index 0000000..0eb2615
Binary files /dev/null and b/out/docs/class_diagram/details/trackrenderer/TrackRenderer.png differ
diff --git a/out/docs/class_diagram/details/tracksource_compositor/TrackSource & Compositor.png b/out/docs/class_diagram/details/tracksource_compositor/TrackSource & Compositor.png
new file mode 100755 (executable)
index 0000000..281653e
Binary files /dev/null and b/out/docs/class_diagram/details/tracksource_compositor/TrackSource & Compositor.png differ
diff --git a/out/docs/class_diagram/esplusplayer/esplusplayer.png b/out/docs/class_diagram/esplusplayer/esplusplayer.png
new file mode 100755 (executable)
index 0000000..3e5a9e1
Binary files /dev/null and b/out/docs/class_diagram/esplusplayer/esplusplayer.png differ
diff --git a/out/docs/class_diagram/plusplayer/plusplayer.png b/out/docs/class_diagram/plusplayer/plusplayer.png
new file mode 100755 (executable)
index 0000000..1d13d0e
Binary files /dev/null and b/out/docs/class_diagram/plusplayer/plusplayer.png differ
diff --git a/out/docs/class_diagram/plusplayer_simple/plusplayer_simple.png b/out/docs/class_diagram/plusplayer_simple/plusplayer_simple.png
new file mode 100755 (executable)
index 0000000..0a787ea
Binary files /dev/null and b/out/docs/class_diagram/plusplayer_simple/plusplayer_simple.png differ
diff --git a/out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 1.png b/out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 1.png
new file mode 100755 (executable)
index 0000000..f11efbb
Binary files /dev/null and b/out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 1.png differ
diff --git a/out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 2.png b/out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 2.png
new file mode 100755 (executable)
index 0000000..0230148
Binary files /dev/null and b/out/docs/downloadable/version_control_sequence/tvplus case(1) dynamic loading page 2.png differ
diff --git a/out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 1.png b/out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 1.png
new file mode 100755 (executable)
index 0000000..9ae0fc9
Binary files /dev/null and b/out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 1.png differ
diff --git a/out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 2.png b/out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 2.png
new file mode 100755 (executable)
index 0000000..84c65fe
Binary files /dev/null and b/out/docs/downloadable/version_control_sequence/tvplus case1) dynamic loading page 2.png differ
diff --git a/out/docs/module_view/libav-common/reduced downloadable module size by libav-common dash hls http streaming module.png b/out/docs/module_view/libav-common/reduced downloadable module size by libav-common dash hls http streaming module.png
new file mode 100755 (executable)
index 0000000..0c8c978
Binary files /dev/null and b/out/docs/module_view/libav-common/reduced downloadable module size by libav-common dash hls http streaming module.png differ
diff --git a/out/docs/module_view/uses_view/module view uses view.png b/out/docs/module_view/uses_view/module view uses view.png
new file mode 100755 (executable)
index 0000000..da737ff
Binary files /dev/null and b/out/docs/module_view/uses_view/module view uses view.png differ
diff --git a/out/docs/sequence_activity_diagram/source_change/source_change_base_flow_1/source_change_base_flow_1.png b/out/docs/sequence_activity_diagram/source_change/source_change_base_flow_1/source_change_base_flow_1.png
new file mode 100755 (executable)
index 0000000..0378d7b
Binary files /dev/null and b/out/docs/sequence_activity_diagram/source_change/source_change_base_flow_1/source_change_base_flow_1.png differ
diff --git a/out/docs/sequence_activity_diagram/tracksource/tracksource_alternative_flow_1/tracksource_alternative_flow_1.png b/out/docs/sequence_activity_diagram/tracksource/tracksource_alternative_flow_1/tracksource_alternative_flow_1.png
new file mode 100755 (executable)
index 0000000..ffe67ee
Binary files /dev/null and b/out/docs/sequence_activity_diagram/tracksource/tracksource_alternative_flow_1/tracksource_alternative_flow_1.png differ
diff --git a/out/docs/sequence_activity_diagram/tracksource/tracksource_base_flow_1/tracksource_base_flow_1.png b/out/docs/sequence_activity_diagram/tracksource/tracksource_base_flow_1/tracksource_base_flow_1.png
new file mode 100755 (executable)
index 0000000..6e6208f
Binary files /dev/null and b/out/docs/sequence_activity_diagram/tracksource/tracksource_base_flow_1/tracksource_base_flow_1.png differ
diff --git a/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_1/tracksource_exception_flow_1.png b/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_1/tracksource_exception_flow_1.png
new file mode 100755 (executable)
index 0000000..fde5983
Binary files /dev/null and b/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_1/tracksource_exception_flow_1.png differ
diff --git a/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_2/tracksource_exception_flow_2.png b/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_2/tracksource_exception_flow_2.png
new file mode 100755 (executable)
index 0000000..dd0b012
Binary files /dev/null and b/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_2/tracksource_exception_flow_2.png differ
diff --git a/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_3/tracksource_exception_flow_3.png b/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_3/tracksource_exception_flow_3.png
new file mode 100755 (executable)
index 0000000..d7b36d9
Binary files /dev/null and b/out/docs/sequence_activity_diagram/tracksource/tracksource_exception_flow_3/tracksource_exception_flow_3.png differ
diff --git a/out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/risk_management_lib_api_validation/risk_management_lib_api_validation.png b/out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/risk_management_lib_api_validation/risk_management_lib_api_validation.png
new file mode 100755 (executable)
index 0000000..81bd0e0
Binary files /dev/null and b/out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/risk_management_lib_api_validation/risk_management_lib_api_validation.png differ
diff --git a/out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/update_procedure/TVPlus Player update process.png b/out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/update_procedure/TVPlus Player update process.png
new file mode 100755 (executable)
index 0000000..9e7da9e
Binary files /dev/null and b/out/docs/sequence_activity_diagram/tvplus_update_activity_diagram/update_procedure/TVPlus Player update process.png differ
diff --git a/out/docs/state_diagram/state_diagram/plusplayer_internal_state_diagram.png b/out/docs/state_diagram/state_diagram/plusplayer_internal_state_diagram.png
new file mode 100755 (executable)
index 0000000..76736f5
Binary files /dev/null and b/out/docs/state_diagram/state_diagram/plusplayer_internal_state_diagram.png differ
diff --git a/out/docs/state_diagram/state_diagram_v2_substatemachine/plusplayer_internal_state_diagram.png b/out/docs/state_diagram/state_diagram_v2_substatemachine/plusplayer_internal_state_diagram.png
new file mode 100755 (executable)
index 0000000..938863a
Binary files /dev/null and b/out/docs/state_diagram/state_diagram_v2_substatemachine/plusplayer_internal_state_diagram.png differ
diff --git a/packaging/capi-trackrenderer-tv.manifest b/packaging/capi-trackrenderer-tv.manifest
new file mode 100755 (executable)
index 0000000..f3090b0
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>\r
+       <request>\r
+               <domain name="_" />\r
+       </request>\r
+</manifest>
\ No newline at end of file
diff --git a/packaging/capi-trackrenderer-tv.spec b/packaging/capi-trackrenderer-tv.spec
new file mode 100755 (executable)
index 0000000..9df8d64
--- /dev/null
@@ -0,0 +1,208 @@
+# %bcond_with : disable TRACKRENDERER_CAPI_UT by default, %bcond_without : enable TRACKRENDERER_CAPI_UT
+%bcond_without TRACKRENDERER_CAPI_UT
+Name:       capi-trackrenderer-tv
+Summary:    new multimedia streaming player capi-trackrenderer-tv
+Version:    0.0.1
+Release:    0
+Group:      Multimedia/Libraries
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Source1001: capi-trackrenderer-tv.manifest
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(capi-base-common)
+BuildRequires:  pkgconfig(gstreamer-1.0)
+BuildRequires:  pkgconfig(gstreamer-plugins-base-1.0)
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(boost)
+BuildRequires:  pkgconfig(elementary)
+BuildRequires:  pkgconfig(ecore)
+BuildRequires:  pkgconfig(evas)
+BuildRequires:  pkgconfig(ecore-wl2)
+BuildRequires:  pkgconfig(wayland-client)
+BuildRequires:  pkgconfig(tizen-extension-client)
+BuildRequires:  pkgconfig(tv-resource-manager)
+BuildRequires:  pkgconfig(tv-resource-information)
+BuildRequires:  pkgconfig(resource-center-api)
+BuildRequires:  pkgconfig(audio-control)
+BuildRequires:  pkgconfig(libtzplatform-config)
+BuildRequires:  pkgconfig(jsoncpp)
+BuildRequires:  pkgconfig(gstreamer-ffsubtitle-1.0)
+BuildRequires:  pkgconfig(icu-i18n)
+BuildRequires:  pkgconfig(drmdecrypt)
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(logger)
+BuildRequires:  pkgconfig(gio-2.0)
+BuildRequires:  pkgconfig(factory-api)
+BuildRequires:  pkgconfig(libtbm)
+BuildRequires:  pkgconfig(lwipc)
+BuildRequires:  pkgconfig(capi-screensaver)
+BuildRequires:  pkgconfig(context-aware-api)
+BuildRequires:  pkgconfig(vd-win-util)
+BuildRequires:  pkgconfig(iniparser)
+
+%if ("%{_vd_cfg_product_type}" == "AUDIO")
+BuildRequires:  pkgconfig(libavoc-av)
+%else
+BuildRequires:  pkgconfig(libavoc)
+BuildRequires:  pkgconfig(graphics-control)
+%endif
+
+%if ("%{_vd_cfg_licensing}" == "n")
+# for ut
+BuildRequires:  pkgconfig(capi-media-player)
+BuildRequires:  pkgconfig(gtest_gmock)
+BuildRequires:  pkgconfig(appcore-efl)
+BuildRequires:  pkgconfig(libresourced)
+%endif
+
+%define _packagedir /usr
+%define _bindir %{_packagedir}/bin
+%define _libdir %{_packagedir}/lib
+%define _includedir %{_packagedir}/include
+%define _pkgconfigdir %{_libdir}/pkgconfig
+%define _unpackaged_files_terminate_build 0
+%define _missing_doc_files_terminate_build 0
+
+%description
+new multimedia player, object-oriented model
+
+%package devel
+Summary:    Developement for multimedia player
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%package config
+Summary:    Configuration for multimedia player
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+%devel_desc
+
+%description config
+
+#################################################
+# gcov
+#################################################
+%if 0%{?vd_gcov:1}
+%package gcov
+Summary: gcov enabled package
+Group: gcov package
+
+%description gcov
+This package is gcov package for coverage measurement.
+%endif
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%if ("%{_vd_cfg_licensing}" == "n")
+
+%{?!TOMATO: %define TOMATO n}
+
+%define _tomatoname trackrenderer_capi
+%define _tomatodir  /opt/usr/apps/tomato/testcase/%{name}
+%define _tomatobin /opt/usr/apps/tomato/testcase/%{name}/bin
+
+%package ut-component-tomato
+Summary: Test package with TOMATO
+BuildRequires:  pkgconfig(tomato)
+BuildRequires:         pkgconfig(gtest_gmock)
+Requires: %{name} = %{version}-%{release}
+
+%description ut-component-tomato
+This package is for test
+
+%files ut-component-tomato
+%defattr(-,root,root,-)
+%{_bindir}/capi-trackrenderer-tv_ut
+%{_tomatodir}/*
+
+%endif
+
+%build
+export CFLAGS+=" -Wno-deprecated-declarations"
+export CXXFLAGS+=" -Wno-deprecated-declarations"
+
+%if ("%{_vd_cfg_product_type}" == "AV")
+export CFLAGS+=" -DIS_AV_PRODUCT"
+export CXXFLAGS+=" -DIS_AV_PRODUCT"
+%endif
+
+export CFLAGS+=" -DPLUS_PLAYER_AI_DATA_COLLECTION"
+export CXXFLAGS+=" -DPLUS_PLAYER_AI_DATA_COLLECTION"
+
+%if ("%{_vd_cfg_product_type}" == "AUDIO")
+export CFLAGS+=" -DSOUNDBAR_PRODUCT"
+export CXXFLAGS+=" -DSOUNDBAR_PRODUCT"
+%define _support_soundbar -DSUPPORT_SOUNDBAR=ON
+%endif
+
+%if ("%{_vd_cfg_licensing}" == "n")
+%if %{with TRACKRENDERER_CAPI_UT}
+%define _trackrenderer_capi_ut -DTRACKRENDERER_BUILD_UT=ON
+%endif
+%endif
+
+%if 0%{?vd_gcov:1}
+export CFLAGS+=" -fprofile-arcs -ftest-coverage"
+export CXXFLAGS+=" -fprofile-arcs -ftest-coverage"
+export FFLAGS+=" -fprofile-arcs -ftest-coverage"
+export LDFLAGS+=" -lgcov"
+%endif
+
+%cmake \
+    %{?_trackrenderer_capi_ut:%_trackrenderer_capi_ut} \
+    %{?_support_soundbar:%_support_soundbar}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+%if ("%{_vd_cfg_licensing}" == "n")
+mkdir -p %{buildroot}%{_tomatodir}
+mkdir -p %{buildroot}%{_tomatodir}/log
+mkdir -p %{buildroot}%{_tomatodir}/result
+mkdir -p %{buildroot}%{_tomatodir}/tc
+cp -rf tomato/tc/* %{buildroot}%{_tomatodir}/tc
+%endif
+
+%make_install
+
+%if 0%{?vd_gcov:1}
+mkdir -p %{buildroot}%{_datadir}/gcov/obj
+find . \( -name '*.gcno' -o -name '*.cpp' -o -name '*.c' -o -name '*.hpp' -o -name '*.h' \) ! -path "./ut/*" ! -path "./test/*" ! -path "*/CompilerIdCXX/*" -exec cp --parents -r '{}' %{buildroot}%{_datadir}/gcov/obj ';'
+%endif
+
+%files
+%defattr(-,root,root,-)
+%manifest capi-trackrenderer-tv.manifest
+%license LICENSE.APLv2
+%{_libdir}/libtrackrenderer.so
+
+%if ("%{_vd_cfg_licensing}" == "n")
+%if %{with TRACKRENDERER_CAPI_UT}
+%{_bindir}/capi-trackrenderer-tv_ut
+%defattr(-,root,root,-)
+%{_tomatodir}/*
+%endif
+%endif
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/trackrenderer_capi/*.h
+%{_pkgconfigdir}/capi-trackrenderer-tv.pc
+
+%files config
+%defattr(-,root,root,-)
+%manifest capi-trackrenderer-tv.manifest
+%license LICENSE.APLv2
+
+%if 0%{?vd_gcov:1}
+%files gcov
+%{_datadir}/gcov/*
+%endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..3abacd7
--- /dev/null
@@ -0,0 +1,94 @@
+PROJECT(trackrenderer)
+
+SET(fw_name "${PROJECT_NAME}")
+SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+SET(${fw_name}_LDFLAGS)
+
+SET(ADD_LIBS
+  "gstvideo-1.0"
+  "gstapp-1.0"
+)
+
+SET(${fw_name}_CXXFLAGS "-Wall -Werror -std=c++11 -fPIC -Wl,-z,relro -fstack-protector -DEFL_BETA_API_SUPPORT")
+
+SET(dependents "gstreamer-1.0 gstreamer-ffsubtitle-1.0"
+               "boost"
+               "vconf"
+               "tv-resource-manager"
+               "elementary ecore ecore-wl2"
+               "audio-control"
+               "libtbm"
+               "capi-screensaver"
+               "lwipc"
+               "vd-win-util"
+               "jsoncpp"
+               "capi-system-info"
+               "iniparser"
+               "drmdecrypt"
+               "resource-center-api")
+
+IF(SUPPORT_SOUNDBAR)
+SET(dependents ${dependents} "libavoc-av")
+ELSE(SUPPORT_SOUNDBAR)
+SET(dependents ${dependents} "libavoc" "graphics-control")
+ENDIF(SUPPORT_SOUNDBAR)
+
+INCLUDE(FindPkgConfig)
+
+IF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+pkg_check_modules(${fw_name} REQUIRED ${dependents})
+ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+pkg_check_modules(${fw_name} REQUIRED ${dependents})
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSDK_ENABLED_FEATURE")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSDK_ENABLED_FEATURE")
+ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+
+FOREACH(flag ${${fw_name}_CFLAGS})
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
+ENDFOREACH(flag)
+
+FOREACH(flag ${${fw_name}_CXXFLAGS})
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} ${flag}")
+ENDFOREACH(flag)
+
+GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_SOURCE_DIR} DIRECTORY)
+INCLUDE_DIRECTORIES(
+  ${PROJECT_SOURCE_DIR}/include_internal
+)
+
+SET(CC_SRCS
+  ${PROJECT_SOURCE_DIR}/caps_recipes.cpp
+  ${PROJECT_SOURCE_DIR}/display.cpp
+  ${PROJECT_SOURCE_DIR}/error.cpp
+  ${PROJECT_SOURCE_DIR}/latency_manager.cpp
+  ${PROJECT_SOURCE_DIR}/trackrenderer.cpp
+  ${PROJECT_SOURCE_DIR}/trackrenderer_attr.cpp
+  ${PROJECT_SOURCE_DIR}/trackrenderer_capi.cpp
+  ${PROJECT_SOURCE_DIR}/resourcemanager.cpp
+  ${PROJECT_SOURCE_DIR}/trackrenderer_capi_utils.cpp
+  ${PROJECT_SOURCE_DIR}/trackrenderer_debug.cpp
+  ${PROJECT_SOURCE_DIR}/gstcaps_builder.cpp
+  ${PROJECT_SOURCE_DIR}/pipeline.cpp
+  ${PROJECT_SOURCE_DIR}/decoderinputbuffer.cpp
+  ${PROJECT_SOURCE_DIR}/gst_utils.cpp
+  ${PROJECT_SOURCE_DIR}/gstobject_guard.cpp
+  ${PROJECT_SOURCE_DIR}/gstsignal_holder.cpp
+  ${PROJECT_SOURCE_DIR}/track_util.cpp
+  ${PROJECT_SOURCE_DIR}/screen_saver.cpp
+  ${PROJECT_SOURCE_DIR}/track_capi.cpp
+  ${PROJECT_SOURCE_DIR}/trackrenderer_vconf.cpp
+  # temporary, this will be remove when trackrenderer/subtitle_attr_parser deprecation.
+  ${PROJECT_SOURCE_DIR}/subtitle_attr_parser.cpp
+  ${PROJECT_SOURCE_DIR}/audio_easing_controller.cpp
+  ${PROJECT_SOURCE_DIR}/vr360.cpp
+)
+
+ADD_LIBRARY(${fw_name} SHARED ${CC_SRCS})
+
+SET_TARGET_PROPERTIES(${fw_name} PROPERTIES LINKER_LANGUAGE CXX)
+TARGET_LINK_LIBRARIES(${fw_name} ${CMAKE_THREAD_LIBS_INIT} ${${fw_name}_LDFLAGS} ${ADD_LIBS})
+
+INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR})
+INSTALL(
+        DIRECTORY ${INC_DIR}/ DESTINATION include/
+)
diff --git a/src/audio_easing_controller.cpp b/src/audio_easing_controller.cpp
new file mode 100755 (executable)
index 0000000..44acdce
--- /dev/null
@@ -0,0 +1,447 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/audio_controller/audio_easing_controller.h"
+
+#include <algorithm>
+#include <chrono>
+#include <unordered_map>
+
+#include "trackrenderer/core/gstobject_guard.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+namespace internal {
+
+bool IsValidVolume(const uint32_t volume) {
+  constexpr uint32_t kVolumeMax = 100;
+  if (volume > kVolumeMax) {
+    TRACKRENDERER_ERROR("volume: %d", volume);
+    return false;
+  }
+  return true;
+}
+
+void UpdateInfo(AudioEasingInfo* dest, const AudioEasingInfo* src) {
+  TRACKRENDERER_ERROR(
+      "target vol [%u - %u] / duration [%u - %u] / type [%d - %d]",
+      dest->target_volume, src->target_volume, dest->duration, src->duration,
+      static_cast<int>(dest->type), static_cast<int>(src->type));
+
+  *dest = *src;
+}
+
+uint32_t GetMicroSecStepInterval(uint32_t duration_us) {
+  constexpr uint32_t kDefaultEaseSteps = 400;
+  constexpr uint32_t kDefaultInterval = 10000;
+
+  uint32_t interval = duration_us / kDefaultEaseSteps;
+  return std::max(interval, kDefaultInterval);
+}
+
+using SystemClockType = std::chrono::system_clock::time_point;
+uint32_t GetMicroSecElapsedEasingTime(SystemClockType begin) {
+  auto end = std::chrono::system_clock::now();
+  auto real_elapsed_time =
+      std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
+
+  return real_elapsed_time.count();
+}
+
+void WaitGap(uint32_t end, uint32_t begin) {
+  if (begin > end) return;
+
+  auto wait = end - begin;
+  if (wait > 0) {
+    std::this_thread::sleep_for(std::chrono::microseconds(wait));
+  }
+}
+
+constexpr int kTimeFactor = 1000;
+uint32_t ConvertMsToMicroSec(uint32_t ms) {
+  uint32_t us = ms * kTimeFactor;
+  return us;
+}
+uint32_t ConvertMicroSecToMs(uint32_t us) {
+  uint32_t ms = us / kTimeFactor;
+  return ms;
+}
+
+}  // namespace internal
+
+constexpr int kMaxVolumeIndex = 101;
+const int kVolumeToGainIndexTable[kMaxVolumeIndex] = {
+    0,  7,  12, 17, 20, 24, 28, 32, 34, 37,  // 9
+    39, 42, 43, 46, 47, 48, 49, 51, 52, 53,  // 19
+    54, 56, 57, 57, 58, 59, 61, 61, 62, 62,  // 29
+    63, 64, 64, 66, 66, 67, 67, 68, 68, 69,  // 39
+    69, 71, 71, 71, 72, 72, 73, 73, 73, 74,  // 49
+    74, 74, 76, 76, 76, 77, 77, 77, 78, 78,  // 59
+    78, 78, 79, 79, 79, 81, 81, 81, 81, 82,  // 69
+    82, 82, 82, 83, 83, 83, 83, 83, 84, 84,  // 79
+    84, 84, 86, 86, 86, 86, 86, 87, 87, 87,  // 89
+    87, 87, 88, 88, 88, 88, 88, 88, 89, 89,  // 99
+    89};
+
+AudioEasingController::AudioEasingController(uint32_t init_volume,
+                                             uint32_t init_elapsed_time,
+                                             const AudioEasingInfo& init_info) {
+  TRACKRENDERER_ENTER;
+  is_stopped_.store(true);
+  AudioEasingController::SetInfo(init_info);
+  volume_.store(init_volume);
+  initial_volume_.store(init_volume);
+  elapsed_time_ms_.store(init_elapsed_time);  // have the dependency of sequence
+  TRACKRENDERER_LEAVE;
+}
+
+AudioEasingController::~AudioEasingController() {
+  TRACKRENDERER_ENTER;
+  if (easing_task_.joinable()) {
+    TRACKRENDERER_ERROR("join before");
+    easing_task_.join();
+    TRACKRENDERER_ERROR("join after");
+  }
+}
+
+int AudioEasingController::GetGainFromVolume(uint32_t volume) {
+  TRACKRENDERER_ENTER;
+  if (volume > kMaxVolumeIndex) return -1;
+  return kVolumeToGainIndexTable[volume];
+}
+
+bool AudioEasingController::GetInfo(uint32_t* current_volume,
+                                    uint32_t* elapsed_time,
+                                    AudioEasingInfo* info) {
+  TRACKRENDERER_ENTER;
+  if (current_volume == nullptr || elapsed_time == nullptr || info == nullptr) {
+    TRACKRENDERER_ERROR("input param is nullptr");
+    return false;
+  }
+
+  *current_volume = volume_.load();
+  *elapsed_time = elapsed_time_ms_.load();
+  TRACKRENDERER_ERROR("%u - %u / %u - %u", *current_volume, volume_.load(),
+                      *elapsed_time, elapsed_time_ms_.load());
+
+  std::lock_guard<std::mutex> info_lock(current_info_m_);
+  internal::UpdateInfo(info, &easing_info_);
+  TRACKRENDERER_LEAVE;
+  return true;
+}  // namespace trackrenderer
+
+bool AudioEasingController::SetInfo(const AudioEasingInfo& info) {
+  TRACKRENDERER_ENTER;
+  if (!internal::IsValidVolume(info.target_volume)) return false;
+
+  std::lock_guard<std::mutex> pending_lock(pending_info_m_);
+  internal::UpdateInfo(&pending_info_, &info);
+  need_reset_ = true;
+
+  if (pending_info_.duration == 0) {
+    InterruptEasingThread_();
+    volume_.store(pending_info_.target_volume);
+  }
+
+  if (is_stopped_.load() == true) {
+    std::lock_guard<std::mutex> info_lock(current_info_m_);
+    internal::UpdateInfo(&easing_info_, &pending_info_);
+    elapsed_time_ms_.store(0);
+    initial_volume_.store(volume_.load());
+    need_reset_ = false;
+    TRACKRENDERER_ERROR("elapsed time %u, initial volume %u",
+                        elapsed_time_ms_.load(), initial_volume_.load());
+  }
+  TRACKRENDERER_LEAVE;
+  return true;
+}
+
+void AudioEasingController::AudioEasingStop() {
+  TRACKRENDERER_ENTER;
+  if (is_stopped_.load() == true) {
+    TRACKRENDERER_ERROR("Stop : already paused");
+  }
+
+  InterruptEasingThread_();
+  std::lock_guard<std::mutex> pending_lock(pending_info_m_);
+  TRACKRENDERER_ERROR("before info lock");
+  std::lock_guard<std::mutex> info_lock(current_info_m_);
+  TRACKRENDERER_ERROR("after info lock");
+  internal::UpdateInfo(&pending_info_, &easing_info_);
+
+  TRACKRENDERER_LEAVE;
+}
+
+bool AudioEasingController::AudioEasingStart(GstElement* audiosink) {
+  TRACKRENDERER_ENTER;
+  if (audiosink == nullptr) {
+    TRACKRENDERER_ERROR("audiosink is nullptr");
+    return false;
+  }
+
+  bool need_lock_delay = NeedToWaitLockDelay_();
+  InterruptEasingThread_();
+
+  SetAudioGain_(audiosink, volume_.load());
+
+  std::lock_guard<std::mutex> pending_lock(pending_info_m_);
+  TRACKRENDERER_ERROR("before info lock");
+  std::lock_guard<std::mutex> info_lock(current_info_m_);
+  TRACKRENDERER_ERROR("after info lock");
+  internal::UpdateInfo(&easing_info_, &pending_info_);
+  auto volume = volume_.load();
+  if (need_reset_) {
+    elapsed_time_ms_.store(0);
+    initial_volume_.store(volume);
+    need_reset_ = false;
+    TRACKRENDERER_ERROR("elapsed time %u, initial volume %u",
+                        elapsed_time_ms_.load(), initial_volume_.load());
+  }
+
+  if (easing_info_.target_volume == volume) return true;
+
+  if (easing_info_.duration == 0) {
+    SetAudioGain_(audiosink, easing_info_.target_volume);
+  } else {
+    easing_task_ = std::thread(&AudioEasingController::SetVolumeWithFade_, this,
+                               audiosink, need_lock_delay);
+  }
+  TRACKRENDERER_LEAVE;
+  return true;
+}
+
+void AudioEasingController::SetVolumeWithFade_(GstElement* audiosink,
+                                               bool need_lock_delay) {
+  TRACKRENDERER_ENTER;
+  if (audiosink == nullptr) return;
+  is_stopped_.store(false);
+
+  if (need_lock_delay) {
+    TRACKRENDERER_ERROR("wait lock delay : %d", lock_delay_ms_);
+    std::this_thread::sleep_for(std::chrono::microseconds(lock_delay_ms_));
+  }
+
+  TRACKRENDERER_ERROR("before info lock");
+  std::unique_lock<std::mutex> info_lock(current_info_m_);
+  TRACKRENDERER_ERROR("after info lock");
+  const uint32_t target_volume = easing_info_.target_volume;
+  const uint32_t duration_ms = easing_info_.duration;
+  const AudioEasingType type = easing_info_.type;
+  info_lock.unlock();
+
+  float start_volume = static_cast<float>(initial_volume_.load());
+  float delta = static_cast<float>(target_volume) - start_volume;
+  uint32_t duration_us = internal::ConvertMsToMicroSec(duration_ms);
+  const uint32_t interval = internal::GetMicroSecStepInterval(duration_us);
+
+  if (type == AudioEasingType::kAudioEasingLinear) {
+    delta = AdjustLinearTypeVolumeDelta_(delta, start_volume, target_volume);
+    duration_us -= interval;
+  }
+
+  float set_volume = start_volume;
+  auto elapsed_time_us = internal::ConvertMsToMicroSec(elapsed_time_ms_.load());
+  const uint32_t init_elapsed_time_us = elapsed_time_us;
+  TRACKRENDERER_ERROR("start_volume %f / cur volume %u, elapsed us time %u",
+                      set_volume, volume_.load(), elapsed_time_us);
+
+  TRACKRENDERER_ERROR(
+      "Ease Duration(%u us), Ease Volume Delta(%f), Ease Step Interval(%u us), "
+      "Ease Type(%d)",
+      duration_us, delta, interval, static_cast<int>(type));
+  auto begin = std::chrono::system_clock::now();
+
+  const AudioEasingInfo setup_info = {target_volume, duration_ms, type};
+  SetEasingStartProperty_(audiosink, setup_info);
+
+  while (duration_us) {
+    if (is_ease_interrupt_) {
+      TRACKRENDERER_ERROR("interrupt break");
+      SetEasingStopProperty_(audiosink);
+      is_stopped_.store(true);
+      return;
+    }
+
+    set_volume =
+        CalculateVolume_(static_cast<float>(elapsed_time_us), start_volume,
+                         delta, static_cast<float>(duration_us), type);
+
+    SetAudioGain_(audiosink, static_cast<uint32_t>(set_volume));
+    auto real_elapsed_time =
+        internal::GetMicroSecElapsedEasingTime(begin) + init_elapsed_time_us;
+
+    if (elapsed_time_us >= duration_us) {
+      break;
+    }
+    elapsed_time_us += interval;
+    elapsed_time_ms_.store(internal::ConvertMicroSecToMs(elapsed_time_us));
+
+    internal::WaitGap(elapsed_time_us, real_elapsed_time);
+  }
+
+  if (static_cast<uint32_t>(set_volume) != target_volume) {
+    TRACKRENDERER_ERROR("diff set volume & target volume");
+    auto real_elapsed_time =
+        internal::GetMicroSecElapsedEasingTime(begin) + init_elapsed_time_us;
+
+    elapsed_time_us += interval;
+    elapsed_time_ms_.store(internal::ConvertMicroSecToMs(elapsed_time_us));
+
+    internal::WaitGap(internal::ConvertMsToMicroSec(duration_ms),
+                      real_elapsed_time);
+
+    SetAudioGain_(audiosink, target_volume);
+  }
+  SetEasingStopProperty_(audiosink);
+  is_stopped_.store(true);
+
+  auto final_elapsed_time =
+      internal::GetMicroSecElapsedEasingTime(begin) + init_elapsed_time_us;
+
+  TRACKRENDERER_ERROR(
+      "Final target volume [%d], start volume [%f], elapsedTime[%d ms /%d ms], "
+      "final_elapsed_time [%d us]",
+      target_volume, start_volume, elapsed_time_ms_.load(), duration_ms,
+      final_elapsed_time);
+
+  TRACKRENDERER_LEAVE;
+  return;
+}
+
+bool AudioEasingController::NeedToWaitLockDelay_() {
+  return easing_task_.joinable() ? FALSE : TRUE;
+}
+
+void AudioEasingController::InterruptEasingThread_() {
+  TRACKRENDERER_ENTER;
+
+  std::lock_guard<std::mutex> lock(easing_m_);
+
+  is_ease_interrupt_ = true;
+  if (easing_task_.joinable()) {
+    TRACKRENDERER_ERROR("join before");
+    easing_task_.join();
+    TRACKRENDERER_ERROR("join after");
+  }
+
+  is_ease_interrupt_ = false;
+  TRACKRENDERER_LEAVE;
+}
+
+float AudioEasingController::AdjustLinearTypeVolumeDelta_(float delta,
+                                                          float start,
+                                                          int target) {
+  int i;
+  int volume = target;
+  int last_gain = kVolumeToGainIndexTable[volume];
+
+  if (delta >= 0) {
+    for (i = volume - 1; i >= 0; i--) {
+      if (kVolumeToGainIndexTable[i] != last_gain) {
+        break;
+      }
+    }
+  } else {
+    for (i = volume + 1; i < kMaxVolumeIndex; i++) {
+      if (kVolumeToGainIndexTable[i] != last_gain) {
+        break;
+      }
+    }
+  }
+
+  volume = i;
+  delta = static_cast<float>(volume) - start;
+
+  return delta;
+}
+
+float AudioEasingController::CalculateVolume_(float t, float b, float delta,
+                                              float d, AudioEasingType type) {
+  float volume;
+  switch (type) {
+    case AudioEasingType::kAudioEasingIncubic: {
+      TRACKRENDERER_INFO("INCUBIC Ease");
+      t /= d;
+      volume = delta * t * t * t + b;
+    } break;
+    case AudioEasingType::kAudioEasingOutcubic: {
+      TRACKRENDERER_INFO("OUTCUBIC Ease");
+      t = t / d - 1.0f;
+      volume = delta * (t * t * t + 1.0f) + b;
+    } break;
+    case AudioEasingType::kAudioEasingLinear:
+    default: {
+      TRACKRENDERER_INFO("LINEAR Ease");
+      volume = (delta * t) / d + b;
+    } break;
+  }
+
+  if (delta > 0) {
+    volume += 0.5;
+  }
+
+  return volume;
+}
+
+bool AudioEasingController::SetAudioGain_(GstElement* audiosink,
+                                          uint32_t volume) {
+  TRACKRENDERER_ENTER;
+  if (audiosink == nullptr) return false;
+  if (volume > kMaxVolumeIndex) return false;
+
+  int gain = kVolumeToGainIndexTable[volume];
+  g_object_set(G_OBJECT(audiosink), "device-volume", gain, NULL);
+
+  volume_.store(volume);
+  TRACKRENDERER_INFO("gain : %d / volume : %u", gain, volume);
+  TRACKRENDERER_LEAVE;
+  return true;
+}
+
+void AudioEasingController::SetEasingStartProperty_(
+    GstElement* audiosink, const AudioEasingInfo& setup_info) {
+  TRACKRENDERER_ENTER;
+  if (audiosink == nullptr) return;
+
+  const uint32_t target_volume =
+      kVolumeToGainIndexTable[setup_info.target_volume];
+  const uint32_t duration = setup_info.duration - elapsed_time_ms_.load();
+
+  const AudioEasingInfo start_info = {target_volume, duration, setup_info.type};
+  SetEasingInfoProperty_(audiosink, start_info);
+
+  TRACKRENDERER_LEAVE;
+  return;
+}
+
+void AudioEasingController::SetEasingStopProperty_(GstElement* audiosink) {
+  TRACKRENDERER_ENTER;
+  if (audiosink == nullptr) return;
+
+  const uint32_t target_volume = kVolumeToGainIndexTable[volume_.load()];
+  const AudioEasingInfo stop_info = {target_volume, static_cast<uint32_t>(-1),
+                                     AudioEasingType::kAudioEasingLinear};
+  SetEasingInfoProperty_(audiosink, stop_info);
+
+  TRACKRENDERER_LEAVE;
+  return;
+}
+
+void AudioEasingController::SetEasingInfoProperty_(
+    GstElement* audiosink, const AudioEasingInfo& info) {
+  if (audiosink == nullptr) return;
+
+  auto easing_info = gstguard::make_guard(gst_structure_new(
+      "easing-info", "volume", G_TYPE_UINT, info.target_volume, "duration",
+      G_TYPE_INT, info.duration, "type", G_TYPE_UINT,
+      static_cast<uint32_t>(info.type), NULL));
+  g_object_set(G_OBJECT(audiosink), "audio-easing-info", easing_info.get(),
+               NULL);
+  return;
+}
+
+}  // namespace trackrenderer
+}  // namespace plusplayer
diff --git a/src/caps_recipes.cpp b/src/caps_recipes.cpp
new file mode 100755 (executable)
index 0000000..721f045
--- /dev/null
@@ -0,0 +1,514 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/caps_recipes.h"
+
+#include <cassert>
+
+#include "trackrenderer/trackrenderer.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace track {
+const int kLittleEndian = 1234;
+
+namespace audio {
+void FillDefault(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("channels", G_TYPE_INT, track.channels);
+  caps.SetValue("rate", G_TYPE_INT, track.sample_rate);
+}
+
+/* =========================================
+ * audio/mpeg
+ * =========================================
+ */
+bool CheckMpeg1(const Track& track) { return track.version == 1; }
+void FillMpeg1(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("mpegversion", G_TYPE_INT, track.version);
+  caps.SetValue("layer", G_TYPE_INT, track.layer);
+  caps.SetValue("parsed", G_TYPE_BOOLEAN, true);
+}
+
+bool CheckAac(const Track& track) {
+  return (track.version == 2 || track.version == 4) && track.layer == 0;
+}
+void FillAac(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("mpegversion", G_TYPE_INT, track.version);
+  caps.SetValue("framed", G_TYPE_BOOLEAN, true);
+  caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
+  caps.SetValue("stream-format", G_TYPE_STRING, "raw");
+}
+
+bool CheckAacWithAdtsHeader(const Track& track) {
+  return (track.version == 2 || track.version == 4) && track.layer == 1;
+}
+void FillAacWithAdtsHeader(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("mpegversion", G_TYPE_INT, track.version);
+  caps.SetValue("framed", G_TYPE_BOOLEAN, true);
+  caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
+  caps.SetValue("stream-format", G_TYPE_STRING, "adts");
+}
+
+bool CheckAacWithAdifHeader(const Track& track) {
+  return (track.version == 2 || track.version == 4) && track.layer == 2;
+}
+void FillAacWithAdifHeader(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("mpegversion", G_TYPE_INT, track.version);
+  caps.SetValue("framed", G_TYPE_BOOLEAN, true);
+  caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
+  caps.SetValue("stream-format", G_TYPE_STRING, "adif");
+}
+
+/* =========================================
+ * audio/x-raw
+ * =========================================
+ */
+bool CheckPcmS32Le(const Track& track) {
+  return track.is_signed && track.sample_format == 32 &&
+         track.endianness == kLittleEndian;
+}
+void FillPcmS32Le(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "S32LE");
+  caps.SetValue("bpp", G_TYPE_INT, 32);
+  caps.SetValue("endianness", G_TYPE_INT, 1234);
+  caps.SetValue("signed", G_TYPE_BOOLEAN, true);
+}
+
+bool CheckPcmS32Be(const Track& track) {
+  return track.is_signed && track.sample_format == 32 &&
+         track.endianness != kLittleEndian;
+}
+void FillPcmS32Be(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "S32BE");
+  caps.SetValue("bpp", G_TYPE_INT, 32);
+  caps.SetValue("signed", G_TYPE_BOOLEAN, true);
+}
+
+bool CheckPcmU32Le(const Track& track) {
+  return !track.is_signed && track.sample_format == 32 &&
+         track.endianness == kLittleEndian;
+}
+void FillPcmU32Le(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "U32LE");
+  caps.SetValue("bpp", G_TYPE_INT, 32);
+  caps.SetValue("endianness", G_TYPE_INT, 1234);
+}
+
+bool CheckPcmU32Be(const Track& track) {
+  return !track.is_signed && track.sample_format == 32 &&
+         track.endianness != kLittleEndian;
+}
+void FillPcmU32Be(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "U32BE");
+  caps.SetValue("bpp", G_TYPE_INT, 32);
+}
+
+bool CheckPcmS24Le(const Track& track) {
+  return track.is_signed && track.sample_format == 24 &&
+         track.endianness == kLittleEndian;
+}
+void FillPcmS24Le(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "S24LE");
+  caps.SetValue("bpp", G_TYPE_INT, 24);
+  caps.SetValue("endianness", G_TYPE_INT, 1234);
+  caps.SetValue("signed", G_TYPE_BOOLEAN, true);
+}
+
+bool CheckPcmS24Be(const Track& track) {
+  return track.is_signed && track.sample_format == 24 &&
+         track.endianness != kLittleEndian;
+}
+void FillPcmS24Be(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "S24BE");
+  caps.SetValue("bpp", G_TYPE_INT, 24);
+  caps.SetValue("signed", G_TYPE_BOOLEAN, true);
+}
+
+bool CheckPcmU24Le(const Track& track) {
+  return !track.is_signed && track.sample_format == 24 &&
+         track.endianness == kLittleEndian;
+}
+void FillPcmU24Le(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "U24LE");
+  caps.SetValue("bpp", G_TYPE_INT, 24);
+  caps.SetValue("endianness", G_TYPE_INT, 1234);
+}
+
+bool CheckPcmU24Be(const Track& track) {
+  return !track.is_signed && track.sample_format == 24 &&
+         track.endianness != kLittleEndian;
+}
+void FillPcmU24Be(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "U24BE");
+  caps.SetValue("bpp", G_TYPE_INT, 24);
+}
+
+bool CheckPcmS16Le(const Track& track) {
+  return ((track.is_signed && track.sample_format == 16 &&
+           track.endianness == kLittleEndian) ||
+          (track.codec_tag == "S16LE"));
+}
+void FillPcmS16Le(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "S16LE");
+  caps.SetValue("bpp", G_TYPE_INT, 16);
+  caps.SetValue("endianness", G_TYPE_INT, 1234);
+  caps.SetValue("signed", G_TYPE_BOOLEAN, true);
+  caps.SetValue("block_align", G_TYPE_INT, track.block_align);
+}
+
+bool CheckPcmS16Be(const Track& track) {
+  return track.is_signed && track.sample_format == 16 &&
+         track.endianness != kLittleEndian;
+}
+void FillPcmS16Be(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "S16BE");
+  caps.SetValue("bpp", G_TYPE_INT, 16);
+  caps.SetValue("signed", G_TYPE_BOOLEAN, true);
+}
+
+bool CheckPcmU16Le(const Track& track) {
+  return !track.is_signed && track.sample_format == 16 &&
+         track.endianness == kLittleEndian;
+}
+void FillPcmU16Le(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "U16LE");
+  caps.SetValue("bpp", G_TYPE_INT, 16);
+  caps.SetValue("endianness", G_TYPE_INT, 1234);
+}
+
+bool CheckPcmU16Be(const Track& track) {
+  return !track.is_signed && track.sample_format == 16 &&
+         track.endianness != kLittleEndian;
+}
+void FillPcmU16Be(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "U16BE");
+  caps.SetValue("bpp", G_TYPE_INT, 16);
+}
+
+bool CheckPcmS8(const Track& track) {
+  return track.is_signed && track.sample_format == 8;
+}
+void FillPcmS8(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "S8");
+  caps.SetValue("bpp", G_TYPE_INT, 8);
+  caps.SetValue("signed", G_TYPE_BOOLEAN, true);
+}
+
+bool CheckPcmU8(const Track& track) {
+  return !track.is_signed && track.sample_format == 8;
+}
+void FillPcmU8(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("layout", G_TYPE_STRING, "interleaved");
+  caps.SetValue("format", G_TYPE_STRING, "U8");
+  caps.SetValue("bpp", G_TYPE_INT, 8);
+}
+
+/* =========================================
+ * audio/x-eac3
+ * audio/x-dts
+ * audio/x-ac3
+ * =========================================
+ */
+void FillDolby(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("framed", G_TYPE_BOOLEAN, true);
+  caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
+  caps.SetValue("bpp", G_TYPE_INT, track.bits_per_sample);
+}
+
+/* =========================================
+ * audio/x-adpcm
+ * =========================================
+ */
+void FillAdpcm(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("block_align", G_TYPE_INT, track.block_align);
+  caps.SetValue("layout", G_TYPE_STRING, track.layout.c_str());
+}
+/* =========================================
+ * audio/x-wma
+ * =========================================
+ */
+void FillWma(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("block_align", G_TYPE_INT, track.block_align);
+  caps.SetValue("wmaversion", G_TYPE_INT, track.version);
+  caps.SetValue("bpp", G_TYPE_INT, track.bits_per_sample);
+  if (!track.codec_tag.empty())
+    caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
+  else
+    caps.SetValue("format", G_TYPE_STRING,
+                  (track.version == 1) ? "0160" : "0161");
+
+  caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
+}
+/* =========================================
+ * audio/x-pn-realaudio
+ * =========================================
+ */
+void FillRealAudio(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("flavor", G_TYPE_INT, track.flavor);
+  caps.SetValue("leaf_size", G_TYPE_INT, track.block_align);
+  caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
+}
+
+/* =========================================
+ * audio/x-vorbis
+ * =========================================
+ */
+void FillVorbis(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("block_align", G_TYPE_INT, track.block_align);
+  caps.SetValue("bpp", G_TYPE_INT, track.bits_per_sample);
+  caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
+  caps.SetValue("bitrate", G_TYPE_INT, track.bitrate);
+}
+
+}  // namespace audio
+namespace video {
+void FillDefault(const GstCapsWrapper& caps, const Track& track) {
+  int max_width = track.maxwidth ? track.maxwidth : track.width;
+  int max_height = track.maxheight ? track.maxheight : track.height;
+  caps.SetValue("width", G_TYPE_INT, track.width);
+  caps.SetValue("height", G_TYPE_INT, track.height);
+  caps.SetValue("maxwidth", G_TYPE_INT, max_width);
+  caps.SetValue("maxheight", G_TYPE_INT, max_height);
+  caps.SetValue("framerate", GST_TYPE_FRACTION, track.framerate_num,
+                track.framerate_den);
+}
+
+// LCOV_EXCL_START
+/* =========================================
+ * video/mpeg
+ * =========================================
+ */
+void FillMpeg(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("mpegversion", G_TYPE_INT, track.version);
+  caps.SetValue("systemstream", G_TYPE_BOOLEAN, false);
+  if (!track.codec_tag.empty())
+    caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
+}
+
+/* =========================================
+ * video/x-h263
+ * =========================================
+ */
+void FillH263(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("variant", G_TYPE_STRING, "itu");
+}
+
+/* =========================================
+ * video/x-wmv
+ * =========================================
+ */
+void FillWmv(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("wmvversion", G_TYPE_INT, track.version);
+  if (!track.codec_tag.empty())
+    caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
+  else
+    switch (track.version) {
+      case 1:
+        caps.SetValue("format", G_TYPE_STRING, "WMV1");
+        break;
+      case 2:
+        caps.SetValue("format", G_TYPE_STRING, "WMV2");
+        break;
+      case 3:
+        caps.SetValue("format", G_TYPE_STRING, "WMV3");
+        break;
+    }
+}
+
+/* =========================================
+ * video/x-pn-realvideo
+ * =========================================
+ */
+bool CheckRealVideo3(const Track& track) { return track.version == 3; }
+void FillRealVideo3(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("rmversion", G_TYPE_INT, track.version);
+  caps.SetValue("format", G_TYPE_STRING, "RV30");
+}
+
+bool CheckRealVideo4(const Track& track) { return track.version == 4; }
+void FillRealVideo4(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("rmversion", G_TYPE_INT, track.version);
+  caps.SetValue("format", G_TYPE_STRING, "RV40");
+}
+
+/* =========================================
+ * video/x-msmpeg
+ * =========================================
+ */
+void FillMsMpeg(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("format", G_TYPE_STRING, "DIV3");
+}
+
+/* =========================================
+ * video/x-vp9
+ * =========================================
+ */
+void FillVP9(const GstCapsWrapper& caps, const Track& track) {
+  // WHY?
+  // gst_wayland_sink_set_matroska_color_info()
+  // mdcv_structure->max_fall = sink->isVP9;
+  // SW Qualty didn't use the maxFALL parameter, and they need the new parameter
+  // to check current is VP9 or not.
+  caps.SetValue("VP9", G_TYPE_INT, 1);
+}
+/* =========================================
+ * video/x-raw
+ * =========================================
+ */
+void FillVideoRaw(const GstCapsWrapper& caps, const Track& track) {
+  caps.SetValue("format", G_TYPE_STRING, "STV1");
+}
+/* =========================================
+ * video/x-vp6
+ * =========================================
+ */
+void FillVP6(const GstCapsWrapper& caps, const Track& track) {
+  if (!track.codec_tag.empty())
+    caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
+}
+/* =========================================
+ * video/x-jpeg
+ * =========================================
+ */
+void FillJpeg(const GstCapsWrapper& caps, const Track& track) {
+  if (!track.codec_tag.empty())
+    caps.SetValue("format", G_TYPE_STRING, track.codec_tag.c_str());
+}
+// LCOV_EXCL_STOP
+}  // namespace video
+
+bool AlwaysPass(const Track& track) { return true; }
+
+void FillDefaultValue(const GstCapsWrapper& caps, const Track& track) {
+  switch (track.type) {
+    case kTrackTypeAudio:
+      track::audio::FillDefault(caps, track);
+      break;
+    case kTrackTypeVideo:
+      track::video::FillDefault(caps, track);
+      break;
+    default:
+      assert(false && "unsupport TrackType");
+      break;
+  }
+}
+}  // namespace track
+
+const GstCapsBuilder::Recipes TrackRenderer::kCapsRecipes_ = {
+    {kDefaultRecipe, {{track::AlwaysPass, track::FillDefaultValue}}},
+    {"audio/mpeg",
+     {
+         {track::audio::CheckMpeg1, track::audio::FillMpeg1},
+         {track::audio::CheckAac, track::audio::FillAac},
+         {track::audio::CheckAacWithAdtsHeader,
+          track::audio::FillAacWithAdtsHeader},
+         {track::audio::CheckAacWithAdifHeader,
+          track::audio::FillAacWithAdifHeader},
+     }},
+    {"audio/x-raw",
+     {
+         {track::audio::CheckPcmS32Le, track::audio::FillPcmS32Le},
+         {track::audio::CheckPcmS32Be, track::audio::FillPcmS32Be},
+         {track::audio::CheckPcmU32Le, track::audio::FillPcmU32Le},
+         {track::audio::CheckPcmU32Be, track::audio::FillPcmU32Be},
+         {track::audio::CheckPcmS24Le, track::audio::FillPcmS24Le},
+         {track::audio::CheckPcmS24Be, track::audio::FillPcmS24Be},
+         {track::audio::CheckPcmU24Le, track::audio::FillPcmU24Le},
+         {track::audio::CheckPcmU24Be, track::audio::FillPcmU24Be},
+         {track::audio::CheckPcmS16Le, track::audio::FillPcmS16Le},
+         {track::audio::CheckPcmS16Be, track::audio::FillPcmS16Be},
+         {track::audio::CheckPcmU16Le, track::audio::FillPcmU16Le},
+         {track::audio::CheckPcmU16Be, track::audio::FillPcmU16Be},
+         {track::audio::CheckPcmS8, track::audio::FillPcmS8},
+         {track::audio::CheckPcmU8, track::audio::FillPcmU8},
+     }},
+    {"audio/x-eac3",
+     {
+         {track::AlwaysPass, track::audio::FillDolby},
+     }},
+    {"audio/x-dts",
+     {
+         {track::AlwaysPass, track::audio::FillDolby},
+     }},
+    {"audio/x-ac3",
+     {
+         {track::AlwaysPass, track::audio::FillDolby},
+     }},
+    {"audio/x-ac4",
+     {
+         {track::AlwaysPass, track::audio::FillDolby},
+     }},
+    {"audio/x-adpcm",
+     {
+         {track::AlwaysPass, track::audio::FillAdpcm},
+     }},
+    {"audio/x-wma",
+     {
+         {track::AlwaysPass, track::audio::FillWma},
+     }},
+    {"audio/x-pn-realaudio",
+     {
+         {track::AlwaysPass, track::audio::FillRealAudio},
+     }},
+    {"audio/x-vorbis",
+     {
+         {track::AlwaysPass, track::audio::FillVorbis},
+     }},
+    {"video/mpeg",
+     {
+         {track::AlwaysPass, track::video::FillMpeg},
+     }},
+    {"video/x-h263",
+     {
+         {track::AlwaysPass, track::video::FillH263},
+     }},
+    {"video/x-wmv",
+     {
+         {track::AlwaysPass, track::video::FillWmv},
+     }},
+    {"video/x-pn-realvideo",
+     {
+         {track::video::CheckRealVideo3, track::video::FillRealVideo3},
+         {track::video::CheckRealVideo4, track::video::FillRealVideo4},
+     }},
+    {"video/x-msmpeg",
+     {
+         {track::AlwaysPass, track::video::FillMsMpeg},
+     }},
+    {"video/x-vp9",
+     {
+         {track::AlwaysPass, track::video::FillVP9},
+     }},
+    {"video/x-raw",
+     {
+         {track::AlwaysPass, track::video::FillVideoRaw},
+     }},
+    {"video/x-vp6",
+     {
+         {track::AlwaysPass, track::video::FillVP6},
+     }},
+    {"video/x-jpeg",
+     {
+         {track::AlwaysPass, track::video::FillJpeg},
+     }},
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/decoderinputbuffer.cpp b/src/decoderinputbuffer.cpp
new file mode 100755 (executable)
index 0000000..ff51adc
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/decoderinputbuffer.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace decoderinputbuffer_util {
+
+bool FlushQueue(std::queue<DecoderInputBufferPtr>& queue) {
+  while (!queue.empty()) {
+    queue.pop();
+  }
+  return true;
+}
+
+}  // namespace decoderinputbuffer_util
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/display.cpp b/src/display.cpp
new file mode 100755 (executable)
index 0000000..1678cb4
--- /dev/null
@@ -0,0 +1,555 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/display.h"
+
+#include <boost/scope_exit.hpp>
+#include <cassert>
+#include <string>
+#include <utility>
+
+#include "Ecore.h"
+#include "Elementary.h"
+#include "glib-object.h"
+#include "tizen-extension-client-protocol.h"
+#include "trackrenderer/core/gstobject_guard.h"
+#include "trackrenderer/core/utils/log.h"
+#include "wayland-client.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+constexpr static uint32_t kInvalidSurfaceId = 0;
+
+namespace internal {
+
+struct WaylandClient {
+  wl_display* display = nullptr;
+  wl_registry* registry = nullptr;
+  tizen_surface* surface = nullptr;
+  tizen_resource* resource = nullptr;
+};
+
+void HandleResourceId(void* userdata, tizen_resource* resource,
+                      unsigned int id) {
+  unsigned int* wl_surface_id = static_cast<unsigned int*>(userdata);
+  *wl_surface_id = id;
+  TRACKRENDERER_INFO("[CLIENT] got wl_surface_id(%d) from server\n", id);
+}
+
+static const tizen_resource_listener tizen_resource_listener = {
+    HandleResourceId,
+};
+
+static void GlobalHandle(void* userdata, wl_registry* registry,
+                         unsigned int name, const char* interface,
+                         unsigned int version) {
+  if (!userdata) {
+    TRACKRENDERER_ERROR("userdata is null!");
+    return;
+  }
+  WaylandClient* wlclient = static_cast<WaylandClient*>(userdata);
+
+  if (strcmp(interface, "tizen_surface") == 0) {
+    TRACKRENDERER_DEBUG("binding tizen_surface");
+    wlclient->surface = static_cast<tizen_surface*>(
+        wl_registry_bind(registry, name, &tizen_surface_interface, version));
+    if (!wlclient->surface) {
+      TRACKRENDERER_ERROR("wlclient->tizen_surface is null!");
+      return;
+    }
+  }
+}
+
+static const wl_registry_listener registry_listener = {
+    GlobalHandle, NULL
+};
+
+bool GetWindowGeometry(Evas_Object* obj, int* x, int* y, int* width,
+                       int* height) {
+  evas_object_geometry_get(obj, x, y, width, height);
+  Evas* evas = evas_object_evas_get(obj);
+  if (!evas) {
+    TRACKRENDERER_ERROR("fail to get evas");
+    return false;
+  }
+  Ecore_Evas* ecore_evas = ecore_evas_ecore_evas_get(evas);
+  if (!ecore_evas) {
+    return false;
+  }
+
+  int rotation = ecore_evas_rotation_get(ecore_evas);
+  if (rotation == 270 || rotation == 90) {
+    std::swap(*width, *height);
+  }
+
+  TRACKRENDERER_DEBUG(
+      "window geometroy : x(%d) y(%d) width(%d) height(%d) rotation(%d)", *x,
+      *y, *width, *height, rotation);
+
+  return true;
+}
+
+uint32_t GetSurfaceId(wl_surface* surface, wl_display* display) {
+  if (!surface || !display) {
+    TRACKRENDERER_ERROR("input is nullptr!!");
+    return kInvalidSurfaceId;
+  }
+
+  WaylandClient wlclient;
+  wl_display* display_wrapper = nullptr;
+  wl_event_queue* queue = nullptr;
+  BOOST_SCOPE_EXIT(&queue, &display_wrapper, &wlclient) {
+    if (queue) wl_event_queue_destroy(queue);
+    if (display_wrapper) wl_proxy_wrapper_destroy(display_wrapper);
+    if (wlclient.registry) wl_registry_destroy(wlclient.registry);
+    if (wlclient.surface) tizen_surface_destroy(wlclient.surface);
+    if (wlclient.resource) tizen_resource_destroy(wlclient.resource);
+  }
+  BOOST_SCOPE_EXIT_END
+
+  wlclient.display = display;
+  queue = wl_display_create_queue(wlclient.display);
+  if (!queue) {
+    return kInvalidSurfaceId;
+  }
+
+  display_wrapper =
+      reinterpret_cast<wl_display*>(wl_proxy_create_wrapper(wlclient.display));
+  if (!display_wrapper) {
+    return kInvalidSurfaceId;
+  }
+
+  wl_proxy_set_queue(reinterpret_cast<wl_proxy*>(display_wrapper), queue);
+  wlclient.registry = wl_display_get_registry(display_wrapper);
+  if (!wlclient.registry) {
+    return kInvalidSurfaceId;
+  }
+
+  wl_registry_add_listener(wlclient.registry, &registry_listener, &wlclient);
+  TRACKRENDERER_INFO("wl_display_roundtrip_queue()");
+  wl_display_roundtrip_queue(wlclient.display, queue);
+  if (!wlclient.surface) {
+    return kInvalidSurfaceId;
+  }
+
+  TRACKRENDERER_INFO("tizen_surface_get_tizen_resource()");
+  wlclient.resource =
+      tizen_surface_get_tizen_resource(wlclient.surface, surface);
+  if (!wlclient.resource) {
+    return kInvalidSurfaceId;
+  }
+
+  TRACKRENDERER_INFO("tizen_resource_add_listener()");
+  unsigned int surface_id = kInvalidSurfaceId;
+  tizen_resource_add_listener(wlclient.resource, &tizen_resource_listener,
+                              &surface_id);
+  TRACKRENDERER_INFO("wl_display_roundtrip_queue()");
+  wl_display_roundtrip_queue(wlclient.display, queue);
+  if (surface_id <= 0) {
+    return kInvalidSurfaceId;
+  }
+
+  TRACKRENDERER_INFO("Surfaceid = %d", surface_id);
+  return surface_id;
+}
+
+// TODO(sy0207.ju) :
+// this is temparary solution.
+// defined in player.h , player_display_mode_e
+typedef enum {
+  PLAYER_DISPLAY_MODE_LETTER_BOX = 0,      /**< Letter box */
+  PLAYER_DISPLAY_MODE_ORIGIN_SIZE,         /**< Origin size */
+  PLAYER_DISPLAY_MODE_FULL_SCREEN,         /**< Full-screen */
+  PLAYER_DISPLAY_MODE_CROPPED_FULL,        /**< Cropped full-screen */
+  PLAYER_DISPLAY_MODE_ORIGIN_OR_LETTER,    /**< Origin size (if surface size is
+                                              larger than video size(width/height))
+                                              or Letter box (if video
+                                              size(width/height) is larger than
+                                              surface size) */
+  PLAYER_DISPLAY_MODE_DST_ROI,             /**< Dst ROI mode */
+                                           // #ifdef USE_PRODUCT_FEATURE
+  PLAYER_DISPLAY_MODE_ZOOM_HALF,           /*zoom half */
+  PLAYER_DISPLAY_MODE_ZOOM_THREE_QUARTERS, /*zoom three quarters */
+  PLAYER_DISPLAY_MODE_ZOOM_16_9,           /**16*9*/
+  PLAYER_DISPLAY_MODE_ZOOM,                /**< WZOOM*/
+  PLAYER_DISPLAY_MODE_ZOOM_CUSTOM,         /**< ZOOM CUSTOM*/
+  PLAYER_DISPLAY_MODE_ZOOM_NETFLIX_16X9,   /**< zoom to 16x9, only for netflix*/
+  PLAYER_DISPLAY_MODE_ZOOM_NETFLIX_4X3,    /**< zoom to 4x3, only for netflix*/
+  PLAYER_DISPLAY_MODE_DPS,
+  PLAYER_DISPLAY_MODE_ZOOM__9,
+  PLAYER_DISPLAY_MODE_AUTO,
+  PLAYER_DISPLAY_MODE_CAPTION,
+  PLAYER_DISPLAY_MODE_AUTO_ASPECT_RATIO, /**< use the dar/par from video info to
+                                            show video*/
+                                         // #endif
+  PLAYER_DISPLAY_MODE_NUM
+} player_display_mode_e;
+
+int ConvertDisplayModeValue(const DisplayMode& mode) {
+  switch (mode) {
+    case DisplayMode::kLetterBox: {
+      return PLAYER_DISPLAY_MODE_LETTER_BOX;
+    }
+    case DisplayMode::kOriginSize: {
+      return PLAYER_DISPLAY_MODE_ORIGIN_SIZE;
+    }
+    case DisplayMode::kFullScreen: {
+      return PLAYER_DISPLAY_MODE_FULL_SCREEN;
+    }
+    case DisplayMode::kCroppedFull: {
+      return PLAYER_DISPLAY_MODE_CROPPED_FULL;
+    }
+    case DisplayMode::kOriginOrLetter: {
+      return PLAYER_DISPLAY_MODE_ORIGIN_OR_LETTER;
+    }
+    case DisplayMode::kDstRoi: {
+      return PLAYER_DISPLAY_MODE_DST_ROI;
+    }
+    case DisplayMode::kAutoAspectRatio: {
+      return PLAYER_DISPLAY_MODE_AUTO_ASPECT_RATIO;
+    }
+    default:
+      assert(0 && "unknown displaymode");
+      return PLAYER_DISPLAY_MODE_FULL_SCREEN;
+  }
+}
+
+}  // namespace internal
+
+Display::~Display() {}
+
+bool Display::SetDisplay(const DisplayType& type, Evas_Object* obj) {
+  assert(obj && "obj should not be null");
+
+  TRACKRENDERER_ENTER_P(this);
+  if (type == DisplayType::kNone) {
+    unsigned int surface_id = 0;
+    long x = 0, y = 0, w = 0, h = 0;
+    SetDisplay(type, surface_id, x, y, w, h);
+    return false;
+  }
+
+  ecore_thread_main_loop_begin();
+
+  BOOST_SCOPE_EXIT(&obj) { ecore_thread_main_loop_end(); }
+  BOOST_SCOPE_EXIT_END
+
+  const std::string obj_type(evas_object_type_get(obj));
+  if (!obj_type.c_str()) {
+    assert(0 && "object type is null");
+    TRACKRENDERER_ERROR_P(this, "object type is null");
+    return false;
+  }
+
+  if (type == DisplayType::kOverlay && obj_type == "elm_win") {
+    int x, y, w, h;
+    bool ret = internal::GetWindowGeometry(obj, &x, &y, &w, &h);
+    if (!ret) {
+      TRACKRENDERER_ERROR_P(this, "Fail GetWindowGeometry");
+      return false;
+    }
+    Ecore_Evas* ee = ecore_evas_ecore_evas_get(evas_object_evas_get(obj));
+
+    Ecore_Wl2_Window* wl_window = ecore_evas_wayland2_window_get(ee);
+    if (!wl_window) {
+      TRACKRENDERER_ERROR_P(this, "elm_win_wl_window_get() failed");
+      return false;
+    }
+    wl_surface* surface = GetWlSurface_(wl_window);
+    return SetDisplay_(type, surface, x, y, w, h);
+  } else {
+    // TODO(js4716.chun) :
+    // else if (type == PLAYER_DISPLAY_TYPE_EVAS &&
+    // !strcmp(object_type, "image"))
+    assert(obj && "not support yet!");
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+wl_surface* Display::GetWlSurface_(Ecore_Wl2_Window* ecore_wl2_window) {
+  /*
+   app have to call ecore_wl2_window_video_surface_create() for sync issue
+   between video and graphic. then player can get surface id from
+   ecore_wl2_window_video_surface_get().
+  */
+  wl_surface* surface =
+      (wl_surface*)ecore_wl2_window_video_surface_get(ecore_wl2_window);
+  if (surface) {
+    TRACKRENDERER_INFO_P(this,
+                         "sync support: get surface id from "
+                         "ecore_wl2_windoe_video_surface_get()");
+    has_parent_surface_ = true;
+  } else {
+    // EAPI struct wl_surface *
+    // ecore_wl2_window_surface_get(Ecore_Wl2_Window * win)
+    surface = ecore_wl2_window_surface_get(ecore_wl2_window);
+  }
+  return surface;
+}
+
+// LCOV_EXCL_START
+bool Display::SetDisplay(const DisplayType& type,
+                         Ecore_Wl2_Window* ecore_wl2_window, const int x,
+                         const int y, const int w, const int h) {
+  assert(ecore_wl2_window && "ecore_wl2_window should not be null");
+  assert((type == DisplayType::kOverlay) && "not support yet!");
+
+  TRACKRENDERER_ENTER_P(this);
+  if (type == DisplayType::kNone) {
+    unsigned int surface_id = 0;
+    int x_ = 0, y_ = 0, w_ = 0, h_ = 0;
+    SetDisplay(type, surface_id, x_, y_, w_, h_);
+    return false;
+  }
+
+  ecore_thread_main_loop_begin();
+
+  BOOST_SCOPE_EXIT(void) { ecore_thread_main_loop_end(); }
+  BOOST_SCOPE_EXIT_END
+
+  wl_surface* surface = GetWlSurface_(ecore_wl2_window);
+  return SetDisplay_(type, surface, x, y, w, h);
+}
+// LCOV_EXCL_STOP
+
+bool Display::SetDisplaySubsurface(const DisplayType& type,
+                                   Ecore_Wl2_Subsurface* ecore_wl2_subsurface,
+                                   const int x, const int y, const int w,
+                                   const int h) {
+  assert(ecore_wl2_subsurface && "ecore_wl2_subsurface should not be null");
+  assert((type == DisplayType::kOverlay) && "not support yet!");
+
+  TRACKRENDERER_ENTER_P(this);
+  if (type == DisplayType::kNone) {
+    unsigned int surface_id = 0;
+    int x_ = 0, y_ = 0, w_ = 0, h_ = 0;
+    SetDisplay(type, surface_id, x_, y_, w_, h_);
+    return false;
+  }
+
+  ecore_thread_main_loop_begin();
+
+  BOOST_SCOPE_EXIT(void) { ecore_thread_main_loop_end(); }
+  BOOST_SCOPE_EXIT_END
+
+  wl_surface* surface = (wl_surface*)ecore_wl2_subsurface_native_surface_get(
+      ecore_wl2_subsurface);
+  has_parent_surface_ = true;
+  return SetDisplay_(type, surface, x, y, w, h);
+}
+
+bool Display::SetDisplay_(const DisplayType& type, wl_surface* surface,
+                          const int x, const int y, const int w, const int h) {
+  if (!surface) {
+    TRACKRENDERER_ERROR_P(this, "ecore_wl_window_surface_get() failed");
+    return false;
+  }
+
+  Ecore_Wl2_Display* wl2_display = ecore_wl2_connected_display_get(NULL);
+  wl_display* display = ecore_wl2_display_get(wl2_display);
+  if (!display) {
+    TRACKRENDERER_ERROR_P(this, "ecore_wl_display_get() failed");
+    return false;
+  }
+
+  unsigned int surfaceid = internal::GetSurfaceId(surface, display);
+  if (surfaceid == kInvalidSurfaceId) {
+    TRACKRENDERER_ERROR_P(this, "Can't get surface id!");
+    return false;
+  }
+
+  // TODO(euna7.ko) what is mean??
+  // wl_window is based on app window(param display).
+  // App window already move, so do not need to move wl_window
+  // x = 0;
+  // y = 0;
+
+  TRACKRENDERER_LEAVE_P(this);
+  return SetDisplay(type, surfaceid, x, y, w, h);
+}
+
+bool Display::SetDisplay(const DisplayType& type, const uint32_t surface_id,
+                         const int x, const int y, const int w, const int h) {
+  TRACKRENDERER_ENTER_P(this);
+  // TODO(euna7.ko) State should not be idle.
+  // unsigned int pre_surface_id = surface_id_;   // for backup previouse info.
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+  TRACKRENDERER_INFO_P(this,
+                       "type: %d, surface_id: %d, x(%d) y(%d) w(%d) h(%d)",
+                       static_cast<int>(type), surface_id, x, y, w, h);
+
+  if (type == DisplayType::kNone) { /* Null serface */
+    surface_id_ = 0;
+  } else if (type == DisplayType::kOverlay) {
+    surface_id_ = surface_id;
+  } else {  // plusplayer don't handle of Evas case.
+    TRACKRENDERER_ERROR_P(this, "Not Support Surface type");
+    return false;
+  }
+
+  if (type_ == DisplayType::kNone ||
+      type_ == type) {  // first time or same type
+    type_ = type;
+    window_.x = x;
+    window_.y = y;
+    window_.w = w;
+    window_.h = h;
+  } else {
+    // TODO(euna7.ko)
+    // changing surface case
+    // ret = mm_player_change_videosink(handle->mm_handle, mmType, set_handle);
+    // if( ret != true) {
+    //   type = DisplayType::kNone;
+    //   surface_id_ = pre_surface_id;
+    //   return false;
+    // }
+  }
+
+  // TODO(euna7.ko) if We need to change window, how can we update it??
+  // display_->Update(pipeline_->video_sink);
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool Display::SetDisplayRoi(const Geometry& roi) {
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+  if (mode_ != DisplayMode::kDstRoi) {
+    TRACKRENDERER_ERROR_P(this, "DisplayMode is not Roi!");
+    return false;
+  }
+  roi_ = roi;
+  return true;
+}
+
+bool Display::SetDisplayCropArea(const CropArea& area) {
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+  scale_ = area;
+  return true;
+}
+
+bool Display::ResizeRenderRect(const RenderRect& rect) {
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+  //x,y should be set with 0 to avoid double calculation at TDM side
+  window_.x = 0;
+  window_.y = 0;
+  window_.w = rect.w;
+  window_.h = rect.h;
+  return true;
+}
+
+void Display::GetDisplayCropArea(CropArea* area) {
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+  *area = scale_;
+}
+
+bool Display::Update(GstElement* videosink) {
+  TRACKRENDERER_ENTER_P(this);
+  if (videosink == nullptr) {
+    assert(0);
+    return false;
+  }
+
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+  //   - typedef unsigned long guintptr;
+  //   - gst_video_overlay_set_window_handle (GstVideoOverlay * overlay
+  //      , guintptr handle)
+  if (type_ == DisplayType::kOverlay && surface_id_ != 0) {  // waylandsink
+    if (has_parent_surface_)
+      g_object_set(G_OBJECT(videosink), "has-parent-surface", true, NULL);
+    TRACKRENDERER_DEBUG_P(this, "serfaceid: %d, x: %d, y: %d, w: %d, h: %d",
+                          surface_id_, window_.x, window_.y, window_.w,
+                          window_.h);
+    gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(videosink),
+                                        surface_id_);
+    gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(videosink),
+                                           window_.x, window_.y, window_.w,
+                                           window_.h);
+    TRACKRENDERER_DEBUG_P(this, "mode: %d, visible: %d, rotate: %d",
+                          static_cast<int>(mode_), visible_,
+                          static_cast<int>(rotate_));
+    g_object_set(G_OBJECT(videosink), "seamless-resolution-change", true, NULL);
+    int mode_value = internal::ConvertDisplayModeValue(mode_);
+    int rotate_value = static_cast<int>(rotate_);
+    g_object_set(G_OBJECT(videosink), "display-geometry-method", mode_value,
+                 "visible", visible_, "rotate", rotate_value, nullptr);
+    g_object_set(G_OBJECT(videosink), "display-src-x-ratio", scale_.scale_x,
+                 "display-src-y-ratio", scale_.scale_y, "display-src-w-ratio",
+                 scale_.scale_w, "display-src-h-ratio", scale_.scale_h,
+                 nullptr);
+    g_object_set(G_OBJECT(videosink), "video-quality-mode", qualitymode_,
+                 nullptr);
+
+    if (video_quality_info_caps_.get() != nullptr) {
+      g_object_set(G_OBJECT(videosink), "video-quality-info",
+                   video_quality_info_caps_.get(), NULL);
+      video_quality_info_caps_.reset();
+    }
+
+    if (mode_ == DisplayMode::kDstRoi) {
+      if (roi_.w != 0 && roi_.h != 0) {
+        TRACKRENDERER_ERROR_P(this, "Roi > x[%d] y[%d] w[%d] h[%d]", roi_.x,
+                              roi_.y, roi_.w, roi_.h);
+        g_object_set(G_OBJECT(videosink), "dst-roi-x", roi_.x, "dst-roi-y",
+                     roi_.y, "dst-roi-w", roi_.w, "dst-roi-h", roi_.h, nullptr);
+      }
+    }
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool Display::UpdateVisible(GstElement* videosink) {
+  TRACKRENDERER_ENTER_P(this);
+  if (videosink == nullptr) {
+    assert(0);
+    return false;
+  }
+
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+
+  if (type_ == DisplayType::kOverlay && surface_id_ != 0) {  // waylandsink
+    TRACKRENDERER_DEBUG_P(this, "visible: %d", visible_);
+    g_object_set(G_OBJECT(videosink), "visible", visible_, nullptr);
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+void Display::SetDisplayQualityInfo(const GstCaps* video_quality_info_caps) {
+  video_quality_info_caps_ =
+      gstguard::make_guard(gst_caps_copy(video_quality_info_caps));
+}
+
+bool Display::UpdateCropArea(GstElement* videosink) {
+  TRACKRENDERER_ENTER_P(this);
+  if (videosink == nullptr) {
+    assert(0);
+    return false;
+  }
+
+  std::lock_guard<std::mutex> lock(settings_mutex_);
+
+  if (type_ == DisplayType::kOverlay && surface_id_ != 0) {  // waylandsink
+    g_object_set(G_OBJECT(videosink), "display-src-x-ratio", scale_.scale_x,
+                 "display-src-y-ratio", scale_.scale_y, "display-src-w-ratio",
+                 scale_.scale_w, "display-src-h-ratio", scale_.scale_h,
+                 nullptr);
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+void Display::SetDisplayMode(const DisplayMode& mode) { mode_ = mode; }
+
+void Display::SetDisplayRotate(const DisplayRotation& rotate) {
+  rotate_ = rotate;
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/error.cpp b/src/error.cpp
new file mode 100755 (executable)
index 0000000..6803b7f
--- /dev/null
@@ -0,0 +1,209 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/error.h"
+
+#include "trackrenderer/core/gst_utils.h"
+#include "trackrenderer/core/gstobject_guard.h"
+#include "trackrenderer/core/utils/log.h"
+// LCOV_EXCL_START
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace internal {
+
+ErrorType HandleOmxError(const GstMessage* message, const GError* error,
+                         const bool is_music_content) {
+  if (!g_strrstr(gst_util::GetElementName(message), "omx"))
+    return ErrorType::kUnknown;
+
+  if (error->code == GST_STREAM_ERROR_FAILED) {
+    if (g_strrstr(gst_util::GetKlass(message), "Audio")) {
+      if (is_music_content)
+        return ErrorType::kNotSupportedFormat;
+      else
+        return ErrorType::kNotSupportedAudioCodec;
+    }
+  }
+  return ErrorType::kUnknown;
+}
+
+ErrorType ConvertGstCoreError(const int error_code) {
+  ErrorType type = ErrorType::kNone;
+  switch (error_code) {
+    case GST_CORE_ERROR_MISSING_PLUGIN:
+      return ErrorType::kNotSupportedFormat;
+    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:
+      type = ErrorType::kInvalidOperation;
+      break;
+  }
+  return type;
+}
+
+ErrorType ConvertGstLibraryError(const int error_code) {
+  ErrorType type = ErrorType::kNone;
+  switch (error_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:
+      type = ErrorType::kInvalidOperation;
+      break;
+  }
+
+  return type;
+}
+
+ErrorType ConvertGstResourceError(const int error_code) {
+  ErrorType type = ErrorType::kNone;
+  switch (error_code) {
+    case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
+      type = ErrorType::kFileNoSpaceOnDevice;
+      break;
+    case GST_RESOURCE_ERROR_NOT_FOUND:
+    case GST_RESOURCE_ERROR_OPEN_READ:
+    case GST_RESOURCE_ERROR_BUSY:
+      type = ErrorType::kConnectionFailed;
+      break;
+    case GST_RESOURCE_ERROR_READ:
+      type = ErrorType::kInvalidOperation;
+      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_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:
+      type = ErrorType::kInvalidOperation;
+      break;
+  }
+  return type;
+}
+
+ErrorType ConvertGstStreamError(const GError* error) {
+  ErrorType type = ErrorType::kNone;
+  if (!error) return ErrorType::kInvalidParameter;
+
+  switch (error->code) {
+    case GST_STREAM_ERROR_DECODE:
+      return ErrorType::kInvalidOperation;
+    case GST_STREAM_ERROR_CODEC_NOT_FOUND:
+    case GST_STREAM_ERROR_TYPE_NOT_FOUND:
+    case GST_STREAM_ERROR_WRONG_TYPE:
+      return ErrorType::kNotSupportedFile;
+    case GST_STREAM_ERROR_FAILED:
+      return ErrorType::kNotSupportedFormat;
+    case GST_STREAM_ERROR_DECRYPT:
+      return ErrorType::kDrmInfo;
+    case GST_STREAM_ERROR_DECRYPT_NOKEY: {
+      TRACKRENDERER_INFO("decryption error, reason : [%s]\n", error->message);
+      if (strstr(error->message, "rights expired")) {
+        return ErrorType::kDrmExpired;
+      } else if (strstr(error->message, "no rights")) {
+        return ErrorType::kDrmNoLicense;
+      } else if (strstr(error->message, "has future rights")) {
+        return ErrorType::kDrmFutureUse;
+      } else if (strstr(error->message, "opl violation")) {
+        return ErrorType::kDrmNotPermitted;
+      }
+      return ErrorType::kDrmInfo;
+    }
+    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:
+      type = ErrorType::kInvalidOperation;
+      break;
+  }
+  return type;
+}
+
+ErrorType HandleGstError(const GError* error) {
+  ErrorType ret = ErrorType::kNone;
+
+  if (error == nullptr) return ret;
+
+  if (error->domain == GST_CORE_ERROR) {
+    ret = internal::ConvertGstCoreError(error->code);
+  } else if (error->domain == GST_LIBRARY_ERROR) {
+    ret = internal::ConvertGstLibraryError(error->code);
+  } else if (error->domain == GST_RESOURCE_ERROR) {
+    ret = internal::ConvertGstResourceError(error->code);
+  } else if (error->domain == GST_STREAM_ERROR) {
+    ret = internal::ConvertGstStreamError(error);
+  } else {
+    TRACKRENDERER_INFO("This error domain is not defined.\n");
+    // we treat system error as an internal error
+    ret = ErrorType::kInvalidOperation;
+  }
+  return ret;
+}
+
+}  // namespace internal
+
+ErrorType HandleError(GstMessage* message, const bool is_music_content) {
+  if (message == nullptr) return ErrorType::kNone;
+
+  GError* p_error = nullptr;
+  gchar* p_debug = nullptr;
+  gst_message_parse_error(message, &p_error, &p_debug);
+  auto error = gstguard::make_guard(p_error);
+  auto debug = gstguard::make_guard(p_debug);
+  if (error == nullptr) return ErrorType::kNone;
+
+  TRACKRENDERER_DEBUG("ERROR is posting. from %s / %s \n>> %s",
+                      gst_util::GetKlass(message),
+                      gst_util::GetElementName(message), error->message);
+
+  ErrorType ret =
+      internal::HandleOmxError(message, error.get(), is_music_content);
+  if (ret != ErrorType::kUnknown) return ret;
+
+  return internal::HandleGstError(error.get());
+}
+
+void HandleErrorMsg(GstMessage* message, gchar** error_msg) {
+  if (message == nullptr) return;
+
+  GError* p_error = nullptr;
+  gst_message_parse_error(message, &p_error, error_msg);
+  auto error = gstguard::make_guard(p_error);
+  if (error == nullptr || *error_msg == nullptr) return;
+
+  TRACKRENDERER_DEBUG("ERROR is posting. from %s / %s \n>> %s \n>> %s",
+                      gst_util::GetKlass(message),
+                      gst_util::GetElementName(message), error->message, *error_msg);
+  return;
+}
+
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+// LCOV_EXCL_STOP
+
diff --git a/src/gst_utils.cpp b/src/gst_utils.cpp
new file mode 100755 (executable)
index 0000000..b9d932d
--- /dev/null
@@ -0,0 +1,85 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include "trackrenderer/core/gst_utils.h"
+
+#include <cassert>
+#include <thread>
+
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace gst_util {
+
+void ShowStateChangedMsg(GstMessage* msg, void* id) {
+  GstState old_state = GST_STATE_VOID_PENDING;
+  GstState new_state = GST_STATE_VOID_PENDING;
+  GstState pending_state = GST_STATE_VOID_PENDING;
+  gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state);
+  TRACKRENDERER_ERROR_P(id,
+      "thread[%p] msg[%p], old[%8s], new[%8s], pending[%8s] src[%s]",
+      g_thread_self(), msg, gst_element_state_get_name(old_state),
+      gst_element_state_get_name(new_state),
+      gst_element_state_get_name(pending_state), GST_MESSAGE_SRC_NAME(msg));
+}
+
+void SetGstStateToNull(GstElement* pipeline, void* id) {
+  if (!pipeline) return;
+  GstStateChangeReturn ret;
+  ret = gst_element_set_state(pipeline, GST_STATE_NULL);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    TRACKRENDERER_ERROR_P(id, "Set State to NULL failed");
+  }
+}
+
+// LCOV_EXCL_START
+const gchar* GetElementName(const GstMessage* msg) {
+  GstElement* src_element = GST_ELEMENT_CAST(msg->src);
+  if (!src_element) return nullptr;
+
+  return GST_ELEMENT_NAME(src_element);
+}
+
+const gchar* GetKlass(const GstMessage* msg) {
+  GstElement* src_element = GST_ELEMENT_CAST(msg->src);
+  if (!src_element) return nullptr;
+
+  GstElementFactory* factory = gst_element_get_factory(src_element);
+  if (!factory) return nullptr;
+
+  return gst_element_factory_get_klass(factory);
+}
+
+void GstInit() { gst_init(NULL, NULL); }
+
+void GstInit(const Json::Value& root) {
+  int argc = 1;
+  char* argv[6]{
+      nullptr,
+  };
+  std::string gstparam1 = root.get("gstparam1", "").asString();
+  argv[argc++] = const_cast<char*>(gstparam1.c_str());
+  std::string gstparam2 = root.get("gstparam2", "").asString();
+  argv[argc++] = const_cast<char*>(gstparam2.c_str());
+  std::string gstparam3 = root.get("gstparam3", "").asString();
+  argv[argc++] = const_cast<char*>(gstparam3.c_str());
+  std::string gstparam4 = root.get("gstparam4", "").asString();
+  argv[argc++] = const_cast<char*>(gstparam4.c_str());
+  std::string gstparam5 = root.get("gstparam5", "").asString();
+  argv[argc++] = const_cast<char*>(gstparam5.c_str());
+
+  for (int i = 1; i < argc; ++i) {
+    TRACKRENDERER_INFO(" %s", argv[i]);
+  }
+  char** pargv = argv;
+  gst_init(&argc, &pargv);
+}
+// LCOV_EXCL_STOP
+}  // namespace gst_util
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/gstcaps_builder.cpp b/src/gstcaps_builder.cpp
new file mode 100755 (executable)
index 0000000..24d6ec7
--- /dev/null
@@ -0,0 +1,189 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/gstcaps_builder.h"
+
+#include <string>
+#include <algorithm>
+
+#include "trackrenderer/core/caps_recipes.h"
+#include "trackrenderer/core/pipeline.hpp"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace internal {
+
+constexpr guint kMaxAudioChannels = 64;
+
+static GstBuffer* MakeGstBufferWithCodecData(const std::shared_ptr<char>& data,
+                                             int len) {
+  constexpr int kMaxLen = 1024 * 1024;
+  if (len <= 0 || len > kMaxLen) {
+    TRACKRENDERER_WARN("There are not any codec_data length [%d]", len);
+    return nullptr;
+  }
+  GstBuffer* codec_data = gst_buffer_new_and_alloc(len);
+  GstMapInfo codec_data_info;
+  if (!gst_buffer_map(codec_data, &codec_data_info, GST_MAP_WRITE)) {
+    TRACKRENDERER_WARN("gst_buffer_map fail");
+    gst_buffer_unref(codec_data);
+    return nullptr;
+  }
+  for (int i = 0; i < len; i++) {
+    codec_data_info.data[i] = (data.get())[i];
+  }
+  TRACKRENDERER_DEBUG("codec extra data size : %d", len);
+  gst_buffer_unmap(codec_data, &codec_data_info);
+  return codec_data;
+}
+
+static const std::string GetMediaType(const Track& track) {
+  std::string media_type =
+      track.streamtype.empty() ? track.mimetype : track.streamtype;
+  if (media_type.find("_tz") != std::string::npos) {
+    media_type = media_type.substr(0, media_type.size() - 3);
+  }
+  return media_type;
+}
+
+static const std::string GetCapsName(const std::string media_type,
+                                     bool is_drm) {
+  if (is_drm) {
+    return "drm/eme";
+  } else {
+    return media_type;
+  }
+}
+
+static void FillStreamType(const GstCapsWrapper& caps, const Track& track) {
+  if (track.streamtype.empty()) return;
+  caps.SetValue("stream-type", G_TYPE_STRING, track.streamtype.c_str());
+}
+
+static void FillCodecData(const GstCapsWrapper& caps, const Track& track) {
+  GstBuffer* codec_data =
+      MakeGstBufferWithCodecData(track.codec_data, track.codec_data_len);
+  if (codec_data == nullptr) return;
+  caps.SetValue("codec_data", GST_TYPE_BUFFER, codec_data);
+}
+
+static void FillSecureField(const GstCapsWrapper& caps, const Track& track) {
+  if (track.mimetype.find("_tz") == std::string::npos) return;
+  caps.SetValue("secure", G_TYPE_BOOLEAN, TRUE);
+}
+
+static void FillChannelMaskField(const GstCapsWrapper& caps,
+                                 const Track& track) {
+  GstAudioChannelPosition position[kMaxAudioChannels];
+  guint64 channel_mask = 0;
+  guint nchannels = std::min(static_cast<guint>(track.channels),
+                             kMaxAudioChannels);
+  if (nchannels <= 2) return;
+  if (nchannels == 4) {
+    position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+    position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+    position[2] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
+    position[3] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
+  } else if (nchannels == 6) {
+    position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+    position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+    position[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+    position[3] = GST_AUDIO_CHANNEL_POSITION_LFE1;
+    position[4] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
+    position[5] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
+  } else if (nchannels == 8) {
+    position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+    position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+    position[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+    position[3] = GST_AUDIO_CHANNEL_POSITION_LFE1;
+    position[4] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
+    position[5] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
+    position[6] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT;
+    position[7] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT;
+  } else {
+    guint i;
+    for (i = 0; i < nchannels; i++) {
+      position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+    }
+  }
+  guint j;
+  for (j = 0; j < nchannels; j++) {
+    channel_mask |= (G_GUINT64_CONSTANT(1) << position[j]);
+  }
+  caps.SetValue("channel-mask", GST_TYPE_BITMASK, channel_mask);
+}
+}  // namespace internal
+
+GstCapsWrapper::GstCapsWrapper(const std::string& caps_name) {
+  caps_ = gst_caps_new_empty_simple(caps_name.c_str());
+}
+
+GstCapsWrapper::GstCapsWrapper(GstCapsWrapper&& caps_wrapper) {
+  caps_ = caps_wrapper.caps_;
+  caps_wrapper.caps_ = nullptr;
+}
+
+GstCapsWrapper::~GstCapsWrapper() {
+  if (caps_ == nullptr) return;
+  gst_caps_unref(caps_);
+  caps_ = nullptr;
+}
+
+void GstCapsWrapper::PrintCapsString() {
+  if (caps_ == nullptr) return;
+  auto caps_str = gstguard::make_guard(gst_caps_to_string(caps_));
+  TRACKRENDERER_DEBUG("caps : %s", caps_str.get());
+}
+
+GstCapsBuilder::GstCapsBuilder(const Recipes& recipes) : kRecipes_(recipes) {}
+
+GstCapsWrapper GstCapsBuilder::Build(const Track& track, bool is_drm) {
+  const std::string media_type = internal::GetMediaType(track);
+  const std::string caps_name = internal::GetCapsName(track.mimetype, is_drm);
+
+  TRACKRENDERER_DEBUG("media_type[%s] caps_name[%s]", media_type.c_str(),
+            caps_name.c_str());
+
+  GstCapsWrapper caps(caps_name);
+
+  auto filler = FindCapsFiller_(track, media_type);
+  if (filler != nullptr) filler(caps, track);
+
+  FillDefaultValue_(caps, track);
+  internal::FillStreamType(caps, track);
+  internal::FillCodecData(caps, track);
+  internal::FillSecureField(caps, track);
+  internal::FillChannelMaskField(caps, track);
+
+  caps.PrintCapsString();
+
+  return caps;
+}
+
+GstCapsBuilder::Recipe::CapsFiller GstCapsBuilder::FindCapsFiller_(
+    const Track& track, const std::string& media_type) {
+  if (kRecipes_.count(media_type) == 0) return nullptr;
+  const auto& recipes = kRecipes_.at(media_type);
+  for (auto& recipe : recipes) {
+    if (recipe.type_checker(track) == false) continue;
+    return recipe.caps_filler;
+  }
+  return nullptr;
+}
+
+void GstCapsBuilder::FillDefaultValue_(const GstCapsWrapper& caps,
+                                       const Track& track) {
+  if (kRecipes_.count(kDefaultRecipe)) {
+    const auto recipes = kRecipes_.at(kDefaultRecipe);
+    for (auto& recipe : recipes) {
+      recipe.caps_filler(caps, track);
+    }
+  }
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/gstobject_guard.cpp b/src/gstobject_guard.cpp
new file mode 100755 (executable)
index 0000000..1b949e2
--- /dev/null
@@ -0,0 +1,52 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include "glib.h"
+
+#include "trackrenderer/core/gstobject_guard.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace gstguard {
+
+void CustomDeleter(GstCaps* obj) { gst_caps_unref(obj); }
+
+void CustomDeleter(GstObject* obj) { gst_object_unref(obj); }
+
+void CustomDeleter(GstPad* obj) { gst_object_unref(obj); }
+
+void CustomDeleter(GstBuffer* obj) { gst_buffer_unref(obj); }
+
+void CustomDeleter(GstElement* obj) { gst_object_unref(obj); }
+
+void CustomDeleter(GstQuery* obj) { gst_query_unref(obj); }
+
+void CustomDeleter(GstEvent* obj) { gst_event_unref(obj); }
+
+void CustomDeleter(GstMessage* obj) { gst_message_unref(obj); }
+
+void CustomDeleter(GstPluginFeature* obj) { gst_object_unref(obj); }
+
+void CustomDeleter(GstElementFactory* obj) { gst_object_unref(obj); }
+
+void CustomDeleter(GstBus* obj) { gst_object_unref(GST_OBJECT(obj)); }
+
+void CustomDeleter(gchar* obj) { g_free(obj); }
+
+void CustomDeleter(GError* obj) { g_error_free(obj); }
+
+void CustomDeleter(GstStructure* obj) { gst_structure_free(obj); }
+
+void CustomDeleter(GValue* obj) { g_value_unset(obj); }
+
+void CustomDeleter(GstIterator* obj) { gst_iterator_free(obj); }
+
+void CustomDeleter(GBytes* obj) { g_bytes_unref(obj); }
+
+}  // namespace gstguard
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/gstsignal_holder.cpp b/src/gstsignal_holder.cpp
new file mode 100755 (executable)
index 0000000..8c3f6b0
--- /dev/null
@@ -0,0 +1,93 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/gstsignal_holder.h"
+
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class GstSignalHolder::GstSignalItem {
+ public:
+  GstSignalItem(GObject* obj, const char* signal_name, GCallback handler,
+                gpointer data)
+      : obj_(obj) {
+    gst_object_ref(obj_);
+    sig_ = g_signal_connect(obj_, signal_name, handler, data);
+    if (sig_ == 0)
+      TRACKRENDERER_INFO("g_signal_connect return error. object[ %s ]",
+               GST_OBJECT_NAME(obj_));
+  }
+  ~GstSignalItem() {
+    if (g_signal_handler_is_connected(obj_, sig_))
+      g_signal_handler_disconnect(obj_, sig_);
+    TRACKRENDERER_INFO("Disconnect signal [%lu]", sig_);
+    gst_object_unref(obj_);
+  }
+
+ private:
+  GstSignalItem() = default;
+  GObject* obj_ = nullptr;
+  gulong sig_ = 0;
+};
+
+namespace internal {
+
+void DisconnectSignal(const GValue* item, gpointer user_data);
+
+}  // namespace internal
+
+GstSignalHolder::GstSignalHolder() {}
+GstSignalHolder::~GstSignalHolder() {
+  std::lock_guard<std::mutex> guard(item_lock_);
+  signal_list_.clear();
+}
+
+void GstSignalHolder::Add(GObject* obj, const char* signal_name,
+                          GCallback handler, gpointer data) {
+  std::lock_guard<std::mutex> guard(item_lock_);
+  std::unique_ptr<GstSignalItem> item(
+      new GstSignalItem(obj, signal_name, handler, data));
+  signal_list_.insert(std::pair<GObject*, std::unique_ptr<GstSignalItem>>(
+      obj, std::move(item)));
+}
+
+void GstSignalHolder::Delete(GObject* obj) {
+  if (!obj || !GST_IS_ELEMENT(obj)) {
+    TRACKRENDERER_ERROR("object null or object is not gst element");
+    return;
+  }
+
+  std::lock_guard<std::mutex> guard(item_lock_);
+  if (GST_IS_BIN(obj)) {
+    GstIterator* it = gst_bin_iterate_elements(GST_BIN_CAST(obj));
+    gst_iterator_foreach(it,
+                         (GstIteratorForeachFunction)internal::DisconnectSignal,
+                         (gpointer) this);
+    gst_iterator_free(it);
+  }
+  signal_list_.erase(obj);
+}
+
+void GstSignalHolder::DeleteAll() {
+  std::lock_guard<std::mutex> guard(item_lock_);
+  TRACKRENDERER_INFO("num of signals[ %d ]", signal_list_.size());
+  signal_list_.clear();
+}
+
+namespace internal {
+
+void DisconnectSignal(const GValue* item, gpointer user_data) {
+  GstSignalHolder* pthis = static_cast<GstSignalHolder*>(user_data);
+  GstElement* element = GST_ELEMENT_CAST(g_value_get_object(item));
+  pthis->Delete(G_OBJECT(element));
+}
+
+}  // namespace internal
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/include_internal/trackrenderer/audio_controller/audio_easing_controller.h b/src/include_internal/trackrenderer/audio_controller/audio_easing_controller.h
new file mode 100755 (executable)
index 0000000..8006f9f
--- /dev/null
@@ -0,0 +1,72 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIOEASING_CONTROLLER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIOEASING_CONTROLLER_H__
+
+#include <gst/gstelement.h>
+
+#include <atomic>
+#include <boost/core/noncopyable.hpp>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "trackrenderer/core/audioeasinginfo.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class AudioEasingController : private boost::noncopyable {
+ public:
+  explicit AudioEasingController(uint32_t init_volume,
+                                 uint32_t init_elapsed_time,
+                                 const AudioEasingInfo& init_info);
+  ~AudioEasingController();
+  bool AudioEasingStart(GstElement* audiosink);
+  void AudioEasingStop();
+  bool SetInfo(const AudioEasingInfo& info);
+  bool GetInfo(uint32_t* current_volume, uint32_t* elapsed_time,
+               AudioEasingInfo* info);
+  int GetGainFromVolume(uint32_t volume);
+
+ private:
+  bool SetAudioGain_(GstElement* audiosink, uint32_t volume);
+  float CalculateVolume_(float t, float b, float delta, float d,
+                         AudioEasingType type);
+  float AdjustLinearTypeVolumeDelta_(float delta, float start, int target);
+  void InterruptEasingThread_();
+  void SetVolumeWithFade_(GstElement* audiosink, bool need_lock_delay);
+  void SetEasingStartProperty_(GstElement* audiosink,
+                               const AudioEasingInfo& setup_info);
+  void SetEasingStopProperty_(GstElement* audiosink);
+  void SetEasingInfoProperty_(GstElement* audiosink,
+                              const AudioEasingInfo& info);
+  bool NeedToWaitLockDelay_();
+
+ private:
+  bool is_ease_interrupt_ = false;
+  bool need_reset_ = false;
+  // temporary fixed value. lock delay have dependency with chipset.
+  uint32_t lock_delay_ms_ = 150000;
+  std::atomic<uint32_t> initial_volume_;
+  std::atomic<uint32_t> volume_;
+  std::atomic<uint32_t> elapsed_time_ms_;
+  std::atomic<bool> is_stopped_;
+  AudioEasingInfo easing_info_ = {100, 0, AudioEasingType::kAudioEasingNone};
+  AudioEasingInfo pending_info_ = {100, 0, AudioEasingType::kAudioEasingNone};
+  std::thread easing_task_;
+
+  std::mutex pending_info_m_;
+  std::mutex current_info_m_;
+  std::mutex easing_m_;
+  std::mutex state_m_;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIOEASING_CONTROLLER_H__
diff --git a/src/include_internal/trackrenderer/audio_controller/resyncaudio/default_policy.hpp b/src/include_internal/trackrenderer/audio_controller/resyncaudio/default_policy.hpp
new file mode 100755 (executable)
index 0000000..eceed31
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DEFAULT_POLICY_HPP__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DEFAULT_POLICY_HPP__
+
+#include "trackrenderer/audio_controller/resyncaudio_policy.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+namespace trackrenderer {
+namespace resync_audio {
+class DefaultPolicy : public ResyncAudioPolicy {
+ public:
+  DefaultPolicy() = default;
+  virtual ~DefaultPolicy() = default;
+
+ public:
+  virtual bool Resync(PipelinePtr& pipeline) override {
+    TRACKRENDERER_ENTER
+    return pipeline->SetProperty(Elements::kSinkAudio, "audio-swap", TRUE);
+  }
+};
+}  // namespace resync_audio
+}  // namespace trackrenderer
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DEFAULT_POLICY_HPP__
diff --git a/src/include_internal/trackrenderer/audio_controller/resyncaudio/dummy_policy.hpp b/src/include_internal/trackrenderer/audio_controller/resyncaudio/dummy_policy.hpp
new file mode 100755 (executable)
index 0000000..d5d9ed0
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DUMMY_POLICY_HPP__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DUMMY_POLICY_HPP__
+
+#include "trackrenderer/audio_controller/resyncaudio_policy.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+namespace trackrenderer {
+namespace resync_audio {
+class DummyPolicy : public ResyncAudioPolicy {
+ public:
+  DummyPolicy() = default;
+  virtual ~DummyPolicy() = default;
+
+ public:
+  virtual bool Resync(PipelinePtr& pipeline) override {
+    TRACKRENDERER_ENTER
+    return true;
+  }
+};
+}  // namespace resync_audio
+}  // namespace trackrenderer
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_DUMMY_POLICY_HPP__
diff --git a/src/include_internal/trackrenderer/audio_controller/resyncaudio/policies.h b/src/include_internal/trackrenderer/audio_controller/resyncaudio/policies.h
new file mode 100755 (executable)
index 0000000..11296ec
--- /dev/null
@@ -0,0 +1,12 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_POLICIES_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_POLICIES_H__
+
+#include "trackrenderer/audio_controller/resyncaudio/default_policy.hpp"
+#include "trackrenderer/audio_controller/resyncaudio/dummy_policy.hpp"
+#include "trackrenderer/audio_controller/resyncaudio/swdecoder_policy.hpp"
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_POLICIES_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/audio_controller/resyncaudio/swdecoder_policy.hpp b/src/include_internal/trackrenderer/audio_controller/resyncaudio/swdecoder_policy.hpp
new file mode 100755 (executable)
index 0000000..b02e668
--- /dev/null
@@ -0,0 +1,92 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+// LCOV_EXCL_START
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_SWDECODER_POLICY_HPP__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_SWDECODER_POLICY_HPP__
+
+#include <boost/scope_exit.hpp>
+#include <mutex>
+#include <string>
+
+#include "trackrenderer/audio_controller/resyncaudio_policy.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+namespace trackrenderer {
+namespace resync_audio {
+class SwDecoderPolicy : public ResyncAudioPolicy {
+ public:
+  explicit SwDecoderPolicy(const std::uint64_t& rstarttime,
+                           const double& playback_rate)
+      : rendering_start_time_(rstarttime), playback_rate_(playback_rate) {}
+  virtual ~SwDecoderPolicy() = default;
+
+ public:
+  virtual bool Resync(PipelinePtr& pipeline) override {
+    TRACKRENDERER_ENTER
+
+    Pipeline<Elements>::Pad padprobe;
+    pipeline->PeerPadAddProbe(
+        Elements::kSinkAudio, kPadBlockProbeId_.c_str(), "sink", kPadProbeType_,
+        GstSrcPadProbeIdleAndBlockCb_, &padprobe, nullptr);
+
+    BOOST_SCOPE_EXIT(&pipeline, &kPadBlockProbeId_) {
+      if (pipeline->PadRemoveProbe(kPadBlockProbeId_.c_str()) == false) {
+        TRACKRENDERER_WARN("[WARNING] PadRemoveProbe failed");
+      }
+    }
+    BOOST_SCOPE_EXIT_END
+
+    TRACKRENDERER_INFO("Wait for Pad Idle!");
+    {
+      std::unique_lock<std::mutex> lk(padprobe.m);
+      padprobe.cv.wait(lk, [&padprobe]() { return padprobe.is_idle; });
+    }
+    TRACKRENDERER_INFO("Wait for Pad Idle! [done]");
+
+    bool ret = true;
+    ret &= pipeline->SetProperty(Elements::kSinkAudio, "audio-swap", TRUE);
+    ret &= pipeline->DirectPadFlushStartDownStream(Elements::kSinkAudio);
+    ret &= pipeline->DirectPadFlushStopDownStream(Elements::kSinkAudio, false);
+    ret &= pipeline->DirectSendSegmentEvent(
+        Elements::kSinkAudio, rendering_start_time_, playback_rate_);
+
+    TRACKRENDERER_LEAVE
+    return ret;
+  }
+
+ private:
+  static GstPadProbeReturn GstSrcPadProbeIdleAndBlockCb_(GstPad* pad,
+                                                         GstPadProbeInfo* info,
+                                                         gpointer userdata) {
+    if (info->type & GST_PAD_PROBE_TYPE_BLOCK) {
+      TRACKRENDERER_INFO("Pad Blocked!");
+    }
+    if (info->type & GST_PAD_PROBE_TYPE_IDLE) {
+      TRACKRENDERER_INFO("Pad Idle!");
+      Pipeline<Elements>::Pad* padprobe =
+          static_cast<Pipeline<Elements>::Pad*>(userdata);
+      std::unique_lock<std::mutex> lk(padprobe->m);
+      padprobe->is_idle = true;
+      TRACKRENDERER_INFO("Pad Idle notify_all()!");
+      padprobe->cv.notify_all();
+    }
+    return GST_PAD_PROBE_OK;
+  }
+
+ private:
+  const std::string kPadBlockProbeId_ =
+      "RESYNC_AUDIO_SINK_PAD_IDLE_AND_BLOCK_PROBE";
+  const GstPadProbeType kPadProbeType_ = static_cast<GstPadProbeType>(
+      GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM | GST_PAD_PROBE_TYPE_IDLE);
+
+  const std::uint64_t& rendering_start_time_;
+  const double& playback_rate_;
+};
+}  // namespace resync_audio
+}  // namespace trackrenderer
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_AUDIO_CONTROLLER_RESYNC_AUDIO_SWDECODER_POLICY_HPP__
+// LCOV_EXCL_STOP
diff --git a/src/include_internal/trackrenderer/audio_controller/resyncaudio_policy.h b/src/include_internal/trackrenderer/audio_controller/resyncaudio_policy.h
new file mode 100755 (executable)
index 0000000..fd0e20b
--- /dev/null
@@ -0,0 +1,25 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_RESYNC_AUDIO_POLICY_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_RESYNC_AUDIO_POLICY_H__
+
+#include <memory>
+
+#include "trackrenderer/core/elements.h"
+#include "trackrenderer/core/pipeline.hpp"
+
+namespace plusplayer {
+namespace trackrenderer {
+struct ResyncAudioPolicy {
+  using PipelinePtr = std::unique_ptr<Pipeline<Elements>>;
+  virtual ~ResyncAudioPolicy() = default;
+  virtual bool Resync(PipelinePtr& pipeline) = 0;
+};
+
+using ResyncAudioPolicyPtr = std::unique_ptr<ResyncAudioPolicy>;
+}  // namespace trackrenderer
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_RESYNC_AUDIO_POLICY_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/appinfo.h b/src/include_internal/trackrenderer/core/appinfo.h
new file mode 100755 (executable)
index 0000000..50229ea
--- /dev/null
@@ -0,0 +1,25 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_APPINFO_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_APPINFO_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+/**
+* @brief Player app information.
+*/
+struct PlayerAppInfo {
+  std::string id;      /**< App id */
+  std::string version; /**< App version */
+  std::string type;    /**< App type. ex)"MSE", "HTML5", etc.. */
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_APPINFO_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/attribute.hpp b/src/include_internal/trackrenderer/core/attribute.hpp
new file mode 100755 (executable)
index 0000000..10dd48b
--- /dev/null
@@ -0,0 +1,87 @@
+//\r
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_ATTRIBUTE_HPP__\r
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_ATTRIBUTE_HPP__\r
+\r
+#include <boost/any.hpp>\r
+#include <boost/core/noncopyable.hpp>\r
+#include <memory>\r
+#include <typeinfo>\r
+\r
+#include "trackrenderer/core/pipeline.hpp"\r
+\r
+namespace plusplayer {\r
+\r
+namespace trackrenderer {\r
+\r
+template <typename ElementType>\r
+class AttributeSetter;\r
+\r
+template <typename ElementType>\r
+using AttributeChangedHandler = std::function<bool(\r
+    AttributeSetter<ElementType>&, const boost::any&, const boost::any&)>;\r
+\r
+template <typename ElementType>\r
+class AttributeGetter;\r
+\r
+template <typename ElementType>\r
+using AttributeGottenHandler =\r
+    std::function<bool(AttributeGetter<ElementType>&, boost::any*)>;\r
+\r
+template <typename ElementType>\r
+struct AttributeBinder {\r
+  const ElementType element;\r
+  const std::type_info& value_type;\r
+  const std::string property;\r
+  const bool need_to_init;\r
+  const boost::any default_value;\r
+  AttributeChangedHandler<ElementType> on_attribute_set;\r
+  AttributeGottenHandler<ElementType> on_attribute_get;\r
+};\r
+\r
+template <typename ElementType>\r
+class AttributeSetter : private boost::noncopyable {\r
+ public:\r
+  explicit AttributeSetter(std::unique_ptr<Pipeline<ElementType>>& pipeline,\r
+                           const AttributeBinder<ElementType>& binder)\r
+      : pipeline_(pipeline), binder_(binder) {}\r
+\r
+  template <typename ValueType>\r
+  void Set(ValueType value) {\r
+    if (pipeline_ == nullptr) return;\r
+    pipeline_->SetProperty(binder_.element, binder_.property.c_str(), value);\r
+  }\r
+\r
+ private:\r
+  std::unique_ptr<Pipeline<ElementType>>& pipeline_;\r
+  const AttributeBinder<ElementType>& binder_;\r
+};\r
+\r
+template <typename ElementType>\r
+class AttributeGetter : private boost::noncopyable {\r
+ public:\r
+  explicit AttributeGetter(std::unique_ptr<Pipeline<ElementType>>& pipeline,\r
+                           const AttributeBinder<ElementType>& binder)\r
+      : pipeline_(pipeline), binder_(binder) {}\r
+\r
+  template <typename ValueType>\r
+  bool Get(boost::any* get_value) {\r
+    ValueType value;\r
+    if (pipeline_ == nullptr) return false;\r
+    pipeline_->GetProperty(binder_.element, binder_.property.c_str(), &value);\r
+    *get_value = value;\r
+    return true;\r
+  }\r
+\r
+ private:\r
+  std::unique_ptr<Pipeline<ElementType>>& pipeline_;\r
+  const AttributeBinder<ElementType>& binder_;\r
+};\r
+\r
+}  // namespace trackrenderer\r
+\r
+}  // namespace plusplayer\r
+\r
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_ATTRIBUTE_HPP__\r
diff --git a/src/include_internal/trackrenderer/core/audioeasinginfo.h b/src/include_internal/trackrenderer/core/audioeasinginfo.h
new file mode 100755 (executable)
index 0000000..3c5a2e7
--- /dev/null
@@ -0,0 +1,32 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_AUDIOEASINGINFO_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_AUDIOEASINGINFO_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+enum class AudioEasingType {
+  kAudioEasingLinear = 0,
+  kAudioEasingIncubic,
+  kAudioEasingOutcubic,
+  kAudioEasingNone
+};
+
+/**
+ * @brief  audio easing information struct
+ */
+struct AudioEasingInfo {
+  uint32_t target_volume; /**< Audio easing target volume */
+  uint32_t duration;      /**< Audio easing duration, in millisecond */
+  AudioEasingType type;   /**< Audio easing type */
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_AUDIOEASINGINFO_H__
diff --git a/src/include_internal/trackrenderer/core/buffer.h b/src/include_internal/trackrenderer/core/buffer.h
new file mode 100755 (executable)
index 0000000..6071a29
--- /dev/null
@@ -0,0 +1,94 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_BUFFER_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_BUFFER_H__
+
+#include <cstdint>
+
+#include "tbm_surface.h"
+#include "tbm_surface_internal.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+/**
+ * @brief  Enumerations for the buffer status
+ */
+enum class BufferStatus {
+  kUnderrun,  // buffer underrun
+  kOverrun    // buffer everrun
+};
+
+enum class DecodedVideoFrameBufferType { kNone, kCopy, kReference, kRaw, kScale };
+
+struct DecodedVideoPacket {
+  uint64_t pts = 0;
+  uint64_t duration = 0;
+  void* surface_data = nullptr;  // tbm_surface
+  void* scaler_index = nullptr;
+};
+
+enum class DecodedVideoRawModePacketType { kPhysicalAddress, kTizenBuffer };
+
+struct DecodedVideoRawModePacket {
+  DecodedVideoRawModePacketType type =
+      DecodedVideoRawModePacketType::kPhysicalAddress;
+  uint64_t pts = 0;
+  uint32_t width = 0;
+  uint32_t height = 0;
+  union {
+    struct {
+      int y_phyaddr = 0;
+      int y_viraddr = 0;
+      int y_linesize = 0;
+      int uv_phyaddr = 0;
+      int uv_viraddr = 0;
+      int uv_linesize = 0;
+    } raw;
+    struct {
+      tbm_key key;
+    } tbm;
+  } data = {.tbm = {0}};
+};
+
+static constexpr int kHandoffFrameBufferNum = 2;
+static constexpr int kScalerY = 0;
+static constexpr int kScalerU = 1;
+
+class TbmBufferManager {
+ public:
+  explicit TbmBufferManager() { bufmgr = tbm_bufmgr_init(-1); };
+  ~TbmBufferManager() {
+    tbm_bufmgr_deinit(bufmgr);
+    for (int i = 0; i < kHandoffFrameBufferNum; i++) {
+      if (tbm_surface[i]) {
+        tbm_surface_destroy(tbm_surface[i]);
+        tbm_surface[i] = nullptr;
+      }
+    }
+  };
+
+  bool TbmBufferAllocate(int width, int height) {
+    for (int i = 0; i < kHandoffFrameBufferNum; i++) {
+      tbm_surface[i] = tbm_surface_create(width, height, TBM_FORMAT_NV12);
+      if (!tbm_surface[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+ public:
+  tbm_bufmgr bufmgr = nullptr;
+  tbm_surface_h tbm_surface[kHandoffFrameBufferNum] = {nullptr};
+  int scaler_index = 0;
+};  // class TbmBufferManager
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_BUFFER_H__
diff --git a/src/include_internal/trackrenderer/core/caps_recipes.h b/src/include_internal/trackrenderer/core/caps_recipes.h
new file mode 100755 (executable)
index 0000000..226ff49
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_CAPS_RECIPES_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_CAPS_RECIPES_H__
+
+#include <string>
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+static const std::string kDefaultRecipe {"*"};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_CAPS_RECIPES_H__
diff --git a/src/include_internal/trackrenderer/core/decoderinputbuffer.h b/src/include_internal/trackrenderer/core/decoderinputbuffer.h
new file mode 100755 (executable)
index 0000000..a8b94ed
--- /dev/null
@@ -0,0 +1,139 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_DECODERINPUTBUFFER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_DECODERINPUTBUFFER_H__
+
+#include <atomic>
+#include <boost/core/noncopyable.hpp>
+#include <memory>
+#include <queue>
+
+#include "gst/gst.h"
+#include <drmdecrypt/drmdecrypt_api.h>
+
+#include "trackrenderer/core/track.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class DecoderInputBuffer : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<DecoderInputBuffer>;
+
+  static Ptr Create(const TrackType type = kTrackTypeMax,
+                    const int index = kInvalidTrackIndex,
+                    GstBuffer* buffer = nullptr, bool incref = true) {
+    return Ptr(new DecoderInputBuffer(buffer, type, index, incref));
+  }
+
+  DecoderInputBuffer() = delete;
+
+  ~DecoderInputBuffer() {
+    while (std::atomic_flag_test_and_set_explicit(&buffer_lock_,
+                                                  std::memory_order_acquire))
+      ;  // spin until the lock is acquired
+    if (buffer_ && incref_) {
+      ReleaseTZHandle_(buffer_);
+      gst_buffer_unref(buffer_);
+    }
+    std::atomic_flag_clear_explicit(&buffer_lock_, std::memory_order_release);
+  }
+
+  const TrackType GetType() const { return type_; }
+  const int GetIndex() const { return index_; }
+
+  const uint64_t GetDuration() const { return duration_; }
+
+  const uint32_t GetSize() const { return buffer_size_; }
+
+  const uint8_t* GetRawData() const { return raw_data_; }
+
+  const bool IsEos() const { return is_eos_; }
+
+  GstBuffer* Release() {
+    while (std::atomic_flag_test_and_set_explicit(&buffer_lock_,
+                                                  std::memory_order_acquire))
+      ;  // spin until the lock is acquired
+    GstBuffer* tmp = buffer_;
+    buffer_ = nullptr;
+    std::atomic_flag_clear_explicit(&buffer_lock_, std::memory_order_release);
+    return tmp;
+  }
+
+  const GstBuffer* Get() const { return buffer_; }
+
+ private:
+  explicit DecoderInputBuffer(GstBuffer* buffer, const TrackType type,
+                              const int index, bool incref)
+      : type_(type), index_(index), incref_(incref) {
+    if (buffer) {
+      buffer_ = incref_ ? gst_buffer_ref(buffer) : buffer;
+      duration_ = GST_TIME_AS_MSECONDS(GST_BUFFER_DURATION(buffer_));
+      if (type == kTrackTypeSubtitle) {
+        GstMapInfo info;
+        gst_buffer_map(buffer_, &info, GST_MAP_READ);
+        raw_data_ = info.data;
+        buffer_size_ = info.size;
+        gst_buffer_unmap(buffer_, &info);
+      }
+    } else {
+      is_eos_ = true;
+    }
+  }
+
+  void ReleaseTZHandle_(GstBuffer* buffer) {
+    GstStructure* tzqdata = GST_STRUCTURE(gst_mini_object_get_qdata(
+        GST_MINI_OBJECT(buffer),
+        g_quark_from_static_string("GstTzHandleData")));
+
+    if (tzqdata) {
+      gboolean ret = FALSE;
+      guint packet_handle = 0;
+      guint packet_size = 0;
+      handle_and_size_s ret_Handle;
+      memset(&ret_Handle, 0, sizeof(ret_Handle));
+
+      ret = gst_structure_get_uint(tzqdata, "packet_handle", &packet_handle);
+      if (FALSE == ret) {
+        return;
+      }
+
+      ret = gst_structure_get_uint(tzqdata, "packet_size", &packet_size);
+      if (FALSE == ret) {
+        return;
+      }
+
+      ret_Handle.handle = packet_handle;
+      ret_Handle.size = packet_size;
+      release_handle(&ret_Handle);
+    }
+  }
+
+ private:
+  std::atomic_flag buffer_lock_ = ATOMIC_FLAG_INIT;
+  const TrackType type_ = kTrackTypeMax;
+  const int index_ = kInvalidTrackIndex;
+  bool incref_ = true;
+  bool is_eos_ = false;
+  GstBuffer* buffer_ = nullptr;
+  uint32_t buffer_size_ = 0;
+  uint64_t duration_ = 0;
+  const uint8_t* raw_data_ = nullptr;
+};
+
+using DecoderInputBufferPtr = DecoderInputBuffer::Ptr;
+
+namespace decoderinputbuffer_util {
+
+bool FlushQueue(std::queue<DecoderInputBufferPtr>& queue);
+
+}  // namespace decoderinputbuffer_util
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_DECODERINPUTBUFFER_H__
diff --git a/src/include_internal/trackrenderer/core/display.h b/src/include_internal/trackrenderer/core/display.h
new file mode 100755 (executable)
index 0000000..1bb4f47
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_DISPLAY_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_DISPLAY_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+enum class DisplayType { kNone, kOverlay, kEvas };
+
+enum class DisplayMode {
+  kLetterBox,
+  kOriginSize,
+  kFullScreen,
+  kCroppedFull,
+  kOriginOrLetter,
+  kDstRoi,
+  kAutoAspectRatio,
+  kMax
+};
+
+enum class DisplayRotation { kNone, kRotate90, kRotate180, kRotate270 };
+
+struct Geometry {
+  int x = 0, y = 0;
+  int w = 1920, h = 1080;
+};
+
+struct CropArea {
+  double scale_x = 0.0;
+  double scale_y = 0.0;
+  double scale_w = 1.0;
+  double scale_h = 1.0;
+};
+
+struct RenderRect {
+  int x = 0, y = 0;
+  int w = 1920, h = 1080;
+};
+
+struct ParDarInfo {
+  uint64_t time_millisecond = 0;
+  uint32_t par_num = 0;
+  uint32_t par_den = 1;
+  uint32_t dar_num = 0;
+  uint32_t dar_den = 1;
+};
+
+enum class StillMode { kNone, kOff, kOn };
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_DISPLAY_H__
diff --git a/src/include_internal/trackrenderer/core/drm.h b/src/include_internal/trackrenderer/core/drm.h
new file mode 100755 (executable)
index 0000000..b279f12
--- /dev/null
@@ -0,0 +1,46 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_DRM_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_DRM_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace drm {
+
+using LicenseAcquiredCb = void*;
+using UserData = void*;
+using DrmHandle = int;
+
+enum class Type {
+  kNone = 0,
+  kPlayready,
+  kMarlin,
+  kVerimatrix,
+  kWidevineClassic,
+  kSecuremedia,
+  kSdrm,
+  kWidevineCdm = 8,
+  kMax
+};
+
+// post from hlsdemux for getright
+
+struct Property {
+  Type type = Type::kNone; // Drm type
+  DrmHandle handle = 0; // Drm handle
+  bool external_decryption = false; // External Decryption Mode
+  LicenseAcquiredCb license_acquired_cb = nullptr; // The cb will be invoked when license was acquired.
+  UserData license_acquired_userdata = nullptr; // The userdata will be sent by license_acquired_cb
+};
+  
+}  // namespace drm
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_DRM_H__
diff --git a/src/include_internal/trackrenderer/core/elements.h b/src/include_internal/trackrenderer/core/elements.h
new file mode 100755 (executable)
index 0000000..c72cfdb
--- /dev/null
@@ -0,0 +1,42 @@
+//\r
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_ELEMENTS_H__\r
+#define __PLUSPLAYER_TRACKRENDERER_CORE_ELEMENTS_H__\r
+\r
+namespace plusplayer {\r
+\r
+namespace trackrenderer {\r
+\r
+enum class Elements {\r
+  kPipeline,  // must be the first\r
+  kAppSrcVideo,\r
+  kAppSrcAudio,\r
+  kAppSrcSubtitle,\r
+  kDrmVideo,\r
+  kDrmAudio,\r
+  kDecVideo,\r
+  kDecAudio,\r
+  kSinkVideo,\r
+  kAudioConvert,\r
+  kCapsFillterDefault,\r
+  kCapsFillter2,\r
+  kAudioResample,\r
+  kScaleTempo,\r
+  kSinkAudio,\r
+  kSinkSubtitle,\r
+  kBinVideo,\r
+  kBinAudio,\r
+  kBinSubtitle,\r
+  kSinkCaption,\r
+  kQueueCaption,\r
+  kAiFilter,\r
+  kMaxElements  // must be the last\r
+};\r
+\r
+}  // namespace trackrenderer\r
+\r
+}  // namespace plusplayer\r
+\r
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_ELEMENTS_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/error.h b/src/include_internal/trackrenderer/core/error.h
new file mode 100755 (executable)
index 0000000..ee4d641
--- /dev/null
@@ -0,0 +1,62 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_ERROR_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_ERROR_H__
+
+#include "tizen.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+#define TRACKRENDERER_ERROR_CLASS          TIZEN_ERROR_PLAYER | 0x20
+
+/* This is for custom defined player error. */
+#define TRACKRENDERER_CUSTOM_ERROR_CLASS   TIZEN_ERROR_PLAYER | 0x1000
+
+
+enum class ErrorType {
+  kNone   = TIZEN_ERROR_NONE,                                 /**< Successful */
+  kOutOfMemory  = TIZEN_ERROR_OUT_OF_MEMORY,                /**< Out of memory */
+  kInvalidParameter  = TIZEN_ERROR_INVALID_PARAMETER,        /**< Invalid parameter */
+  kNoSuchFile   = TIZEN_ERROR_NO_SUCH_FILE,                 /**< No such file or directory */
+  kInvalidOperation  = TIZEN_ERROR_INVALID_OPERATION,        /**< Invalid operation */
+  kFileNoSpaceOnDevice    = TIZEN_ERROR_FILE_NO_SPACE_ON_DEVICE,  /**< No space left on the device */
+  kFeatureNotSupportedOnDevice    = TIZEN_ERROR_NOT_SUPPORTED,    /**< Not supported */
+  kSeekFailed    = TRACKRENDERER_ERROR_CLASS | 0x01,                /**< Seek operation failure */
+  kInvalidState  = TRACKRENDERER_ERROR_CLASS | 0x02,                /**< Invalid state */
+  kNotSupportedFile = TRACKRENDERER_ERROR_CLASS | 0x03,            /**< File format not supported */
+  kInvalidUri    = TRACKRENDERER_ERROR_CLASS | 0x04,                /**< Invalid URI */
+  kSoundPolicy   = TRACKRENDERER_ERROR_CLASS | 0x05,                /**< Sound policy error */
+  kConnectionFailed  = TRACKRENDERER_ERROR_CLASS | 0x06,            /**< Streaming connection failed */
+  kVideoCaptureFailed   = TRACKRENDERER_ERROR_CLASS | 0x07,        /**< Video capture failed */
+  kDrmExpired    = TRACKRENDERER_ERROR_CLASS | 0x08,                /**< Expired license */
+  kDrmNoLicense         = TRACKRENDERER_ERROR_CLASS | 0x09,            /**< No license */
+  kDrmFutureUse         = TRACKRENDERER_ERROR_CLASS | 0x0a,            /**< License for future use */
+  kDrmNotPermitted  = TRACKRENDERER_ERROR_CLASS | 0x0b,            /**< Format not permitted */
+  kResourceLimit     = TRACKRENDERER_ERROR_CLASS | 0x0c,            /**< Resource limit */
+  kPermissionDenied  = TIZEN_ERROR_PERMISSION_DENIED,        /**< Permission denied */
+  kServiceDisconnected = TRACKRENDERER_ERROR_CLASS | 0x0d,          /**< Socket connection lost (Since 3.0) */
+  kBufferSpace         = TIZEN_ERROR_BUFFER_SPACE,           /**< No buffer space available (Since 3.0)*/
+  kNotSupportedAudioCodec = TRACKRENDERER_ERROR_CLASS | 0x0e, /**< Not supported audio codec but video can be played (Since 4.0) */
+  kNotSupportedVideoCodec = TRACKRENDERER_ERROR_CLASS | 0x0f, /**< Not supported video codec but audio can be played (Since 4.0) */
+  kNotSupportedSubtitle = TRACKRENDERER_ERROR_CLASS | 0x10, /**< Not supported subtitle format (Since 4.0) */
+    
+  kDrmInfo = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x05,              /**< playready drm error info */
+  kNotSupportedFormat = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x08,
+  kStreamingPlayer = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x09,
+  kDtcpFsk = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x0a,
+  kPreLoadingTimeOut =TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x0b, /**< can't finish preloading in time*/
+  kNetworkError = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x0c,     /**< for network error */
+  kChannelSurfingFailed = TRACKRENDERER_CUSTOM_ERROR_CLASS | 0x0d, /**< for channel surfing error */
+
+  kUnknown
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_ERROR_H__
diff --git a/src/include_internal/trackrenderer/core/event.h b/src/include_internal/trackrenderer/core/event.h
new file mode 100755 (executable)
index 0000000..012c6c6
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * @file
+ * @brief          The event for playback.
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style event related enum and structure.
+ * @see            N/A
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+ * PROPRIETARY/CONFIDENTIAL
+ * This software is the confidential and proprietary
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+ * not disclose such Confidential Information and shall use it only in
+ * accordance with the terms of the license agreement you entered into with
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+ * suitability of the software, either express or implied, including but not
+ * limited to the implied warranties of merchantability, fitness for a
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+ * damages suffered by licensee as a result of using, modifying or distributing
+ * this software or its derivatives.
+ */
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+/**
+ * @brief
+ */
+typedef struct {
+  /**
+   * @description
+   */
+  std::string data;
+  /**
+   * @description
+   */
+  uint64_t len;
+} EventMsg;
+
+/**
+ * @brief
+ */
+enum class EventType {
+  kNone,
+  kResolutionChanged,
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_EVENT_H__
diff --git a/src/include_internal/trackrenderer/core/gst_utils.h b/src/include_internal/trackrenderer/core/gst_utils.h
new file mode 100755 (executable)
index 0000000..8792944
--- /dev/null
@@ -0,0 +1,30 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GST_UTILS_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GST_UTILS_H__
+
+#include "gst/gst.h"
+#include "json/json.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace gst_util {
+
+void GstInit();
+void GstInit(const Json::Value& root);
+void ShowStateChangedMsg(GstMessage* msg, void* id = nullptr);
+void SetGstStateToNull(GstElement* pipeline, void* id = nullptr);
+const gchar* GetElementName(const GstMessage* msg);
+const gchar* GetKlass(const GstMessage* msg);
+
+}  // namespace gst_util
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GST_UTILS_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/gstcaps_builder.h b/src/include_internal/trackrenderer/core/gstcaps_builder.h
new file mode 100755 (executable)
index 0000000..69723db
--- /dev/null
@@ -0,0 +1,81 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTCAPS_BUILDER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTCAPS_BUILDER_H__
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+
+#include <cassert>
+#include <functional>
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "trackrenderer/core/track.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class GstCapsWrapper {
+ public:
+  template <typename T>
+  friend class Pipeline;
+
+ public:
+  explicit GstCapsWrapper(const std::string&);
+  GstCapsWrapper(const GstCapsWrapper&) = delete;
+  GstCapsWrapper(GstCapsWrapper&&);
+  virtual ~GstCapsWrapper();
+
+ public:
+  template <typename... Args>
+  void SetValue(const std::string& name, Args... args) const {
+    assert(caps_ != nullptr);
+    gst_caps_set_simple(caps_, name.c_str(), args..., nullptr);
+  }
+  void PrintCapsString();
+
+ private:
+  GstCaps* GetCaps_() const { return caps_; }
+
+ private:
+  GstCaps* caps_;
+};
+
+class GstCapsBuilder {
+ public:
+  struct Recipe {
+    using TypeChecker = std::function<bool(const Track&)>;
+    using CapsFiller =
+        std::function<void(const GstCapsWrapper& caps, const Track&)>;
+    TypeChecker type_checker;
+    CapsFiller caps_filler;
+  };
+
+  using Recipes = std::map<const std::string, const std::list<Recipe>>;
+
+ public:
+  explicit GstCapsBuilder(const Recipes&);
+  GstCapsBuilder(const GstCapsBuilder&) = delete;
+  GstCapsBuilder(GstCapsBuilder&&) = delete;
+
+  GstCapsWrapper Build(const Track& track, bool is_drm);
+
+ private:
+  Recipe::CapsFiller FindCapsFiller_(const Track&, const std::string&);
+  void FillDefaultValue_(const GstCapsWrapper&, const Track&);
+
+ private:
+  const Recipes& kRecipes_;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTCAPS_BUILDER_H__
diff --git a/src/include_internal/trackrenderer/core/gstobject_guard.h b/src/include_internal/trackrenderer/core/gstobject_guard.h
new file mode 100755 (executable)
index 0000000..3fa3cb7
--- /dev/null
@@ -0,0 +1,71 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTOBJECT_GUARD_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTOBJECT_GUARD_H__
+
+#include <memory>
+
+#include "gst/gst.h"
+#include <functional>
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+// <Usage Example>
+//
+//   bool CreatePipeline() {
+//     // Old Way
+//     // GstCaps* caps = gst_pad_get_currnet_caps();
+//     // ... do somthing ...
+//     // gst_caps_unref(caps);
+//
+//     // New way.
+//     auto caps_unique_ptr = utils::make_guard(gst_pad_get_current_caps());
+//     GstCaps* caps = caps_unique_ptr.get();
+//     // .. do somthing ..
+//     // you don't need to call "gst_caps_unref()"
+//     return true;
+//   }
+
+namespace gstguard {
+
+template <typename T>
+using GstGuardPtr = std::unique_ptr<T, std::function<void(T*)>>;
+//
+// Register CustomDeleter Here (start)
+//
+void CustomDeleter(GstCaps* obj);
+void CustomDeleter(GstObject* obj);
+void CustomDeleter(GstPad* obj);
+void CustomDeleter(GstBuffer* obj);
+void CustomDeleter(GstElement* obj);
+void CustomDeleter(GstQuery* obj);
+void CustomDeleter(GstEvent* obj);
+void CustomDeleter(GstMessage* obj);
+void CustomDeleter(GstPluginFeature* obj);
+void CustomDeleter(GstElementFactory* obj);
+void CustomDeleter(GstBus* obj);
+void CustomDeleter(gchar* obj);
+void CustomDeleter(GError* obj);
+void CustomDeleter(GstStructure* obj);
+void CustomDeleter(GValue* obj);
+void CustomDeleter(GstIterator* obj);
+void CustomDeleter(GBytes* obj);
+//
+// Register CustomDeleter Here (end)
+//
+template <typename T>
+GstGuardPtr<T> make_guard(T* obj) {
+  return GstGuardPtr<T>(obj, [](T* _obj) { CustomDeleter(_obj); });
+}
+
+}  // namespace gstguard
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTOBJECT_GUARD_H__
diff --git a/src/include_internal/trackrenderer/core/gstsignal_holder.h b/src/include_internal/trackrenderer/core/gstsignal_holder.h
new file mode 100755 (executable)
index 0000000..b394cda
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTSIGNAL_HOLDER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTSIGNAL_HOLDER_H__
+
+#include <boost/core/noncopyable.hpp>
+#include <map>
+#include <memory>
+#include <mutex>
+
+#include "glib-object.h"
+#include "gst/gst.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class GstSignalHolder : private boost::noncopyable {
+ public:
+  GstSignalHolder();
+  ~GstSignalHolder();
+  void Add(GObject* obj, const char* signal_name, GCallback handler,
+           gpointer data);
+  void Delete(GObject* obj);  // If the obj is BIN, delete not only its signal
+                              // but also its children's.
+  void DeleteAll();
+
+ private:
+  std::mutex item_lock_;
+  class GstSignalItem;
+  std::multimap<GObject*, std::unique_ptr<GstSignalItem>> signal_list_;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  //  __PLUSPLAYER_SRC_TRACKRENDERER_CORE_GSTSIGNAL_HOLDER_H__
diff --git a/src/include_internal/trackrenderer/core/latency.h b/src/include_internal/trackrenderer/core/latency.h
new file mode 100755 (executable)
index 0000000..bf64390
--- /dev/null
@@ -0,0 +1,29 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_LATENCY_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_LATENCY_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+enum class CatchUpSpeed {
+  kNone,
+  kSlow,
+  kMid,
+  kFast
+};
+
+enum class LatencyStatus {
+  kLow,
+  kMid,
+  kHigh
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_LATENCY_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/picturequality.h b/src/include_internal/trackrenderer/core/picturequality.h
new file mode 100755 (executable)
index 0000000..2a81389
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// @ Copyright [2021] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_PICTUREQUALITY_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_PICTUREQUALITY_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+/**
+* @brief Advanced Picture Quality Type.
+*/
+enum class AdvPictureQualityType {
+  kVideoCall,
+  kUsbCamera
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_PICTUREQUALITY_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/pipeline.hpp b/src/include_internal/trackrenderer/core/pipeline.hpp
new file mode 100755 (executable)
index 0000000..11f4f93
--- /dev/null
@@ -0,0 +1,660 @@
+//\r
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+// Gstreamer facade\r
+//\r
+\r
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__\r
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__\r
+\r
+#include <malloc.h>\r
+\r
+#include <boost/core/noncopyable.hpp>\r
+#include <cassert>\r
+#include <condition_variable>\r
+#include <functional>\r
+#include <map>\r
+#include <memory>\r
+#include <mutex>\r
+#include <unordered_map>\r
+\r
+#include "glib-object.h"\r
+#include "gst/app/gstappsrc.h"\r
+#include "gst/gst.h"\r
+#include "trackrenderer/core/gst_utils.h"\r
+#include "trackrenderer/core/gstcaps_builder.h"\r
+#include "trackrenderer/core/gstobject_guard.h"\r
+#include "trackrenderer/core/gstsignal_holder.h"\r
+#include "trackrenderer/core/utils/log.h"\r
+\r
+namespace plusplayer {\r
+\r
+namespace trackrenderer {\r
+\r
+namespace trustzone {\r
+\r
+bool InitTzAppsrc();\r
+bool GstAppsrcPushBuffer(GstElement* appsrc, GstBuffer* buffer);\r
+\r
+}  // namespace trustzone\r
+\r
+namespace pipeline_internal {\r
+\r
+inline GstElement* GetLastObj(GstElement* bin) {\r
+  GValue data;\r
+  memset(&data, 0, sizeof(data));\r
+  auto data_guard = gstguard::make_guard(&data);\r
+  GstIterator* it = gst_bin_iterate_elements(GST_BIN_CAST(bin));\r
+  auto it_guard = gstguard::make_guard(it);\r
+  GstIteratorResult ret = gst_iterator_next(it, &data);\r
+  if (ret != GST_ITERATOR_OK) {\r
+    return nullptr;\r
+  }\r
+  return static_cast<GstElement*>(g_value_get_object(&data));\r
+}\r
+\r
+}  // namespace pipeline_internal\r
+\r
+template <typename T>\r
+class Pipeline : private boost::noncopyable {\r
+ public:\r
+  using Operator = std::function<bool(GstElement* element)>;\r
+  struct Pad {\r
+    std::mutex m;\r
+    std::condition_variable cv;\r
+    gulong probe_id = 0;\r
+    bool is_idle = false;\r
+  };\r
+\r
+ public:\r
+  using Ptr = std::unique_ptr<Pipeline<T>>;\r
+  static Ptr Create(const char* name) {\r
+    return Ptr(new Pipeline<T>(gst_pipeline_new(name)));\r
+  }\r
+\r
+  ~Pipeline() noexcept {\r
+    std::lock_guard<std::mutex> lock(execute_mutex_);\r
+    signals_.reset();\r
+    TRACKRENDERER_DEBUG("[%p]", mainbin_[static_cast<int>(T::kPipeline)]);\r
+    gst_object_unref(mainbin_[static_cast<int>(T::kPipeline)]);\r
+    malloc_trim(0);\r
+    for (int element_idx = static_cast<int>(T::kPipeline);\r
+         element_idx < static_cast<int>(T::kMaxElements); element_idx++)\r
+      mainbin_[element_idx] = nullptr;\r
+  }\r
+\r
+  // Purose of Execute\r
+  //  - serialization of gstreamer commands\r
+  bool Execute(T type, Operator op) {\r
+    std::lock_guard<std::mutex> lock(execute_mutex_);\r
+    if (!mainbin_[static_cast<int>(type)]) return false;\r
+    return op(mainbin_[static_cast<int>(type)]);\r
+  }\r
+\r
+  ////////////////                      /////////////////\r
+  //////////////// Utilities (Entering) /////////////////\r
+  ////////////////                      /////////////////\r
+  bool FactoryMake(const T element, const char* name, const char* nickname) {\r
+    if (!name) {\r
+      TRACKRENDERER_ERROR("invalid element_name[null]");\r
+      return false;\r
+    }\r
+    GstElement* obj = gst_element_factory_make(name, nickname);\r
+\r
+    if (strstr(name, "tzappsrc")) {\r
+      is_trustzone_element_[static_cast<int>(element)] = true;\r
+      if (!InitTzAppsrc_()) return false;\r
+    }\r
+\r
+    if (!obj) {\r
+      TRACKRENDERER_ERROR("Fail to create element[%s][%s]",\r
+                          name ? name : "(EMPTY)",\r
+                          nickname ? nickname : "(EMPTY)");\r
+      return false;\r
+    }\r
+    return Set_(element, obj);\r
+  }\r
+\r
+  bool ElementAdd(const T element, void* obj) {\r
+    if (!obj) {\r
+      return false;\r
+    }\r
+    return Set_(element, static_cast<GstElement*>(gst_object_ref(obj)));\r
+  }\r
+\r
+  bool CreateBin(T element, const char* name) {\r
+    GstElement* obj = gst_bin_new(name);\r
+    return Set_(element, obj);\r
+  }\r
+\r
+  bool SignalConnect(T type, const char* name, GCallback handler,\r
+                     gpointer data) {\r
+    std::lock_guard<std::mutex> lock(execute_mutex_);\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    signals_->Add(G_OBJECT(obj), name, handler, data);\r
+    return true;\r
+  }\r
+\r
+  bool SetSyncHandler(GstBusSyncHandler func, gpointer user_data,\r
+                      GDestroyNotify notify) {\r
+    GstElement* obj = mainbin_[static_cast<int>(T::kPipeline)];\r
+    if (!obj) return false;\r
+    auto bus =\r
+        gstguard::make_guard<GstBus>(gst_pipeline_get_bus(GST_PIPELINE(obj)));\r
+    if (bus) gst_bus_set_sync_handler(bus.get(), func, user_data, notify);\r
+    return true;\r
+  }\r
+\r
+  template <typename... Args>\r
+  bool SetProperty(T type, const char* name, Args... args) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    g_object_set(G_OBJECT(obj), name, args..., NULL);\r
+    return true;\r
+  }\r
+\r
+  template <typename... Args>\r
+  bool GetProperty(T type, const char* name, Args... args) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    g_object_get(G_OBJECT(obj), name, args..., NULL);\r
+    return true;\r
+  }\r
+\r
+  //\r
+  // BinRemove\r
+  // description : remove each elements from bin\r
+  //\r
+  void BinRemove(T bin, T last) {\r
+    GstElement* obj = mainbin_[static_cast<int>(last)];\r
+    GstElement* bin_element = mainbin_[static_cast<int>(bin)];\r
+    auto sink_pad =\r
+        gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
+    gst_pad_unlink(GST_PAD_PEER(sink_pad.get()), sink_pad.get());\r
+\r
+    auto src_pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
+    if (src_pad) {\r
+      // gst_pad_unlink(src_pad.get(), GST_PAD_PEER(src_pad.get()));\r
+      assert(0 && "not support this feature");\r
+    }\r
+    gst_util::SetGstStateToNull(obj);\r
+    gst_bin_remove_many(GST_BIN(bin_element), obj, nullptr);\r
+    Unset_(last);\r
+  }\r
+\r
+  template <typename... Args>\r
+  void BinRemove(T bin, T element, Args... args) {\r
+    GstElement* obj = mainbin_[static_cast<int>(element)];\r
+    GstElement* bin_element = mainbin_[static_cast<int>(bin)];\r
+    if (obj) {\r
+      auto sink_pad =\r
+          gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
+      gst_pad_unlink(GST_PAD_PEER(sink_pad.get()), sink_pad.get());\r
+      gst_util::SetGstStateToNull(obj);\r
+      gst_bin_remove_many(GST_BIN(bin_element), obj, nullptr);\r
+      Unset_(element);\r
+    }\r
+    BinRemove(bin, args...);\r
+  }\r
+\r
+  //\r
+  // BinAdd\r
+  // description : add each elements to Bin , and link each elements\r
+  //\r
+  void BinAdd(T bin, T last) {\r
+    GstElement* bin_obj = mainbin_[static_cast<int>(bin)];\r
+    GstElement* obj = mainbin_[static_cast<int>(last)];\r
+    assert(bin_obj && obj);\r
+    GstElement* last_obj = pipeline_internal::GetLastObj(bin_obj);\r
+    gst_bin_add(GST_BIN(bin_obj), obj);\r
+    if (last_obj) {\r
+      if (!gst_element_link(last_obj, obj)) {\r
+        TRACKRENDERER_ERROR("elements link error");\r
+        gst_bin_remove(GST_BIN(bin_obj), obj);\r
+        return;\r
+      }\r
+    }\r
+    if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {\r
+      TRACKRENDERER_ERROR("sync state with parent error");\r
+      gst_bin_remove(GST_BIN(bin_obj), obj);\r
+      return;\r
+    }\r
+  }\r
+\r
+  template <typename... Args>\r
+  void BinAdd(T bin, T element, Args... args) {\r
+    GstElement* bin_obj = mainbin_[static_cast<int>(bin)];\r
+    GstElement* obj = mainbin_[static_cast<int>(element)];\r
+    assert(bin_obj);\r
+    if (!obj) {\r
+      BinAdd(bin, args...);\r
+      return;\r
+    }\r
+    GstElement* last_obj = pipeline_internal::GetLastObj(bin_obj);\r
+    gst_bin_add(GST_BIN(bin_obj), obj);\r
+    if (last_obj) {\r
+      // TRACKRENDERER_DEBUG("[%p] is linked to [%p]", obj, last_obj);\r
+      if (!gst_element_link(last_obj, obj)) {\r
+        TRACKRENDERER_ERROR("elements link error");\r
+        gst_bin_remove(GST_BIN(bin_obj), obj);\r
+        return;\r
+      }\r
+    }\r
+    if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {\r
+      TRACKRENDERER_ERROR("sync state with parent error");\r
+      gst_bin_remove(GST_BIN(bin_obj), obj);\r
+      return;\r
+    }\r
+    BinAdd(bin, args...);\r
+  }\r
+\r
+  //\r
+  // ElementLink\r
+  // description : link elements\r
+  //\r
+  void ElementLink(T src, T dest) {\r
+    GstElement* src_obj = mainbin_[static_cast<int>(src)];\r
+    GstElement* dest_obj = mainbin_[static_cast<int>(dest)];\r
+    assert(src_obj && dest_obj);\r
+    if (!gst_element_link(src_obj, dest_obj)) {\r
+      TRACKRENDERER_ERROR("elements link error");\r
+      return;\r
+    }\r
+    if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(dest_obj))) {\r
+      TRACKRENDERER_ERROR("sync state with parent error");\r
+      gst_bin_remove(GST_BIN(gst_element_get_parent(dest_obj)), dest_obj);\r
+      return;\r
+    }\r
+  }\r
+\r
+  bool BinAddSimple(T dst, T src) {\r
+    GstElement* bin = mainbin_[static_cast<int>(dst)];\r
+    GstElement* obj = mainbin_[static_cast<int>(src)];\r
+    if (!bin || !obj) {\r
+      return false;\r
+    }\r
+    gst_bin_add(GST_BIN(bin), obj);\r
+    if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(obj))) {\r
+      TRACKRENDERER_ERROR("sync state with parent error");\r
+      gst_bin_remove(GST_BIN(bin), obj);\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+  //\r
+  // SetState\r
+  //\r
+  bool SetState(T element, GstState state) {\r
+    GstElement* obj = mainbin_[static_cast<int>(element)];\r
+    if (!obj) return false;\r
+    if (state == GST_STATE_NULL) {\r
+      gst_util::SetGstStateToNull(obj);\r
+      return true;\r
+    }\r
+    GstStateChangeReturn ret = gst_element_set_state(obj, state);\r
+    if (ret == GST_STATE_CHANGE_FAILURE) {\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  bool GetState(T element, GstState* cur_state, GstState* pending_state,\r
+                GstClockTime timeout) {\r
+    GstElement* obj = mainbin_[static_cast<int>(element)];\r
+    if (!obj) return false;\r
+    GstStateChangeReturn ret =\r
+        gst_element_get_state(obj, cur_state, pending_state, timeout);\r
+    if (ret == GST_STATE_CHANGE_FAILURE) {\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  bool GenerateDot(const gchar* file_name) {\r
+    GstElement* pipeline = mainbin_[static_cast<int>(T::kPipeline)];\r
+    if (!pipeline) return false;\r
+    GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL,\r
+                              file_name);\r
+    return true;\r
+  }\r
+\r
+  bool Seek(gdouble rate, GstFormat format, GstSeekFlags flags,\r
+            GstSeekType start_type, gint64 start, GstSeekType stop_type,\r
+            gint64 stop) {\r
+    GstElement* obj = mainbin_[static_cast<int>(T::kPipeline)];\r
+    if (!obj) return false;\r
+    if (!gst_element_seek(obj, rate, format, flags, start_type, start,\r
+                          stop_type, stop)) {\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  bool AppSrcPushBuffer(T type, GstBuffer* buffer) {\r
+    int index = static_cast<int>(type);\r
+    GstElement* obj = mainbin_[index];\r
+    if (!obj) return false;\r
+    if (is_trustzone_element_[index]) {\r
+      trustzone::GstAppsrcPushBuffer(obj, buffer);\r
+    } else {\r
+      gst_app_src_push_buffer(GST_APP_SRC(obj), buffer);\r
+    }\r
+\r
+    return true;\r
+  }\r
+\r
+  bool SetAppSrcCaps(T type, const GstCapsWrapper& caps) {\r
+    return SetProperty(type, "caps", caps.GetCaps_());\r
+  }\r
+\r
+  bool SetPadCaps(T type, const char* mime_type) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
+    auto gstcaps = gstguard::make_guard(gst_caps_new_empty_simple(mime_type));\r
+    if (!gst_pad_set_caps(pad.get(), gstcaps.get())) {\r
+      TRACKRENDERER_ERROR("gst_pad_set_caps error");\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  template <typename... Args>\r
+  bool SetPadCaps(T type, const char* mime_type, Args... caps) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
+    auto gstcaps =\r
+        gstguard::make_guard(gst_caps_new_simple(mime_type, caps..., nullptr));\r
+    if (!gst_pad_set_caps(pad.get(), gstcaps.get())) {\r
+      TRACKRENDERER_ERROR("gst_pad_set_caps error");\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  GstCaps* GetSinkPadCaps(T type) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return nullptr;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
+    auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad.get()));\r
+    return gst_caps_copy(caps.get());\r
+  }\r
+\r
+  bool Flush(T type) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    bool ret = true;\r
+    if (!gst_element_send_event(GST_ELEMENT_CAST(obj),\r
+                                gst_event_new_flush_start())) {\r
+      TRACKRENDERER_ERROR("Fail to send flush start");\r
+      ret = false;\r
+    }\r
+    if (!gst_element_send_event(GST_ELEMENT_CAST(obj),\r
+                                gst_event_new_flush_stop(FALSE))) {\r
+      TRACKRENDERER_ERROR("Fail to send flush stop");\r
+      ret = false;\r
+    }\r
+    return ret;\r
+  }\r
+\r
+  bool FlushDownStream(T type, gboolean reset_time) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
+    auto peer_pad = GST_PAD_PEER(pad.get());\r
+    if (!gst_pad_send_event(peer_pad, gst_event_new_flush_start())) {\r
+      TRACKRENDERER_ERROR("Fail to send flush start");\r
+      return false;\r
+    }\r
+    if (!gst_pad_send_event(peer_pad, gst_event_new_flush_stop(reset_time))) {\r
+      TRACKRENDERER_ERROR("Fail to send flush stop");\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  // LCOV_EXCL_START\r
+  bool DirectPadFlushStartDownStream(T type) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
+    if (!gst_pad_send_event(pad.get(), gst_event_new_flush_start())) {\r
+      TRACKRENDERER_ERROR("Fail to send flush start");\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  bool DirectPadFlushStopDownStream(T type, bool reset_time) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
+    if (!gst_pad_send_event(pad.get(), gst_event_new_flush_stop(reset_time))) {\r
+      TRACKRENDERER_ERROR("Fail to send flush stop");\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+  // LCOV_EXCL_STOP\r
+\r
+  bool PushSegmentEvent(T type, uint64_t position, gdouble rate) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "src"));\r
+    auto peer_pad = GST_PAD_PEER(pad.get());\r
+    GstSegment segment;\r
+    gst_segment_init(&segment, GST_FORMAT_TIME);\r
+    segment.rate = rate;\r
+    segment.start = position;\r
+    segment.position = position;\r
+    segment.time = position;\r
+    GstEvent* seg_event = gst_event_new_segment(&segment);\r
+    if (!gst_pad_send_event(peer_pad, seg_event)) {\r
+      TRACKRENDERER_ERROR("Fail to send segment event");\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  // LCOV_EXCL_START\r
+  bool DirectSendSegmentEvent(T type, uint64_t position, gdouble rate) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
+    GstSegment segment;\r
+    gst_segment_init(&segment, GST_FORMAT_TIME);\r
+    segment.rate = rate;\r
+    segment.start = position;\r
+    segment.position = position;\r
+    segment.time = position;\r
+    if (!gst_pad_send_event(pad.get(), gst_event_new_segment(&segment))) {\r
+      TRACKRENDERER_ERROR("Fail to send segment event");\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+  // LCOV_EXCL_STOP\r
+\r
+  gulong GetPadProbeId(const char* key) {\r
+    auto find = [](const PadProbeMap& map, const char* _key) -> bool {\r
+      auto look = map.find(_key);\r
+      if (look == map.end()) return false;\r
+      return true;\r
+    };\r
+    if (!find(padprobe_id_, key)) return 0;\r
+    return padprobe_id_[key].first;\r
+  }\r
+\r
+  bool PadAddProbe(T type, const char* key, const char* padname,\r
+                   GstPadProbeType mask, GstPadProbeCallback callback,\r
+                   gpointer user_data, GDestroyNotify destroy_data) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));\r
+    assert(pad);\r
+    gulong id =\r
+        gst_pad_add_probe(pad.get(), mask, callback, user_data, destroy_data);\r
+    if (key) padprobe_id_[key] = {id, pad.get()};\r
+    return true;\r
+  }\r
+\r
+  // LCOV_EXCL_START\r
+  bool PeerPadAddProbe(T type, const char* key, const char* padname,\r
+                       GstPadProbeType mask, GstPadProbeCallback callback,\r
+                       gpointer user_data, GDestroyNotify destroy_data) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));\r
+    assert(pad);\r
+    auto peerpad = gstguard::make_guard(gst_pad_get_peer(pad.get()));\r
+    assert(peerpad);\r
+    gulong id = gst_pad_add_probe(peerpad.get(), mask, callback, user_data,\r
+                                  destroy_data);\r
+    if (key) padprobe_id_[key] = {id, peerpad.get()};\r
+    return true;\r
+  }\r
+  // LCOV_EXCL_STOP\r
+\r
+  bool PadRemoveProbe(T type, const char* padname, const gulong id) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, padname));\r
+    gst_pad_remove_probe(pad.get(), id);\r
+    return true;\r
+  }\r
+\r
+  bool PadRemoveProbe(const char* key) {\r
+    auto find = [](const PadProbeMap& map, const char* _key) -> bool {\r
+      auto look = map.find(_key);\r
+      if (look == map.end()) return false;\r
+      return true;\r
+    };\r
+    if (!find(padprobe_id_, key)) return false;\r
+    gst_pad_remove_probe(padprobe_id_[key].second, padprobe_id_[key].first);\r
+    return true;\r
+  }\r
+\r
+  bool SignalEmitByName(T type, const char* name) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    GstFlowReturn ret;\r
+    g_signal_emit_by_name(gpointer(obj), name, &ret);\r
+    TRACKRENDERER_DEBUG("g emit signal [%s] ret[%d]", name, ret);\r
+    return true;\r
+  }\r
+\r
+  bool QueryPosition(T type, GstFormat format, int64_t* position) {\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    return gst_element_query_position(obj, format, position);\r
+  }\r
+\r
+  bool QuerySegment(T type, GstSegment* segment) {\r
+    if (segment == nullptr) return false;\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+\r
+    auto query = gstguard::make_guard(gst_query_new_segment(GST_FORMAT_TIME));\r
+    if (gst_element_query(obj, query.get()) == false) {\r
+      TRACKRENDERER_ERROR("Fail to query segment");\r
+      return false;\r
+    }\r
+\r
+    gdouble rate;\r
+    GstFormat format;\r
+    gint64 starttime, stoptime;\r
+    gst_query_parse_segment(query.get(), &rate, &format, &starttime, &stoptime);\r
+    TRACKRENDERER_DEBUG(\r
+        "Segment : format(%d), rate(parsed:%lf), starttime(%lld), "\r
+        "stoptime(%lld)",\r
+        format, rate, starttime, stoptime);\r
+\r
+    gst_segment_init(segment, format);\r
+    segment->rate = rate;\r
+    segment->start = starttime;\r
+    segment->stop = stoptime;\r
+    return true;\r
+  }\r
+\r
+  void SetGstElementCreatedCbHandler(std::function<void(T)> handler) {\r
+    on_gstelement_created_cb_handler_ = handler;\r
+  }\r
+\r
+  bool SetParDar(T type, uint64_t timestamp, uint32_t VParN, uint32_t VParD,\r
+                 uint32_t VDarN, uint32_t VDarD) {\r
+    TRACKRENDERER_ERROR("SetParDar enter");\r
+    GstElement* obj = mainbin_[static_cast<int>(type)];\r
+    if (!obj) return false;\r
+    auto pad = gstguard::make_guard(gst_element_get_static_pad(obj, "sink"));\r
+    bool ret = true;\r
+    timestamp *= G_GINT64_CONSTANT(1000000);  // ms->ns\r
+    GstStructure* pardar_structure = gst_structure_new(\r
+        "GstPARDAR_Changed", "pkt_timestamp", G_TYPE_UINT64, timestamp, "vParN",\r
+        G_TYPE_UINT, VParN, "vParD", G_TYPE_UINT, VParD, "vDarN", G_TYPE_UINT,\r
+        VDarN, "vDarD", G_TYPE_UINT, VDarD, NULL);\r
+    GstEvent* pardar_event = gst_event_new_custom(\r
+        GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, pardar_structure);\r
+    if (!gst_pad_send_event(pad.get(), pardar_event)) {\r
+      TRACKRENDERER_ERROR("Fail to send par and dar");\r
+      ret = false;\r
+    }\r
+    TRACKRENDERER_ERROR("send par and dar to video decoder successfully");\r
+    return ret;\r
+  }\r
+\r
+  ////////////////                     /////////////////\r
+  //////////////// Utilities (Leaving) /////////////////\r
+  ////////////////                     /////////////////\r
+\r
+ private:\r
+  explicit Pipeline(GstElement* pipeline) noexcept {\r
+    assert(pipeline && "pipeline is null");\r
+    mainbin_[static_cast<int>(T::kPipeline)] = pipeline;\r
+  }\r
+\r
+  bool Set_(T type, GstElement* element) {\r
+    std::lock_guard<std::mutex> lock(execute_mutex_);\r
+    assert(element && (type < T::kMaxElements));\r
+    assert(mainbin_[static_cast<int>(type)] == nullptr);\r
+    TRACKRENDERER_DEBUG("TYPE[%d] ELEMENT[%p]", static_cast<int>(type),\r
+                        element);\r
+    mainbin_[static_cast<int>(type)] = element;\r
+    if (on_gstelement_created_cb_handler_ != nullptr)\r
+      on_gstelement_created_cb_handler_(type);\r
+    return true;\r
+  }\r
+\r
+  bool Unset_(T type) {\r
+    assert(type < T::kMaxElements);\r
+    assert(mainbin_[static_cast<int>(type)] != nullptr);\r
+    TRACKRENDERER_DEBUG("TYPE[%d]", static_cast<int>(type));\r
+    mainbin_[static_cast<int>(type)] = nullptr;\r
+    return true;\r
+  }\r
+\r
+  bool InitTzAppsrc_() { return trustzone::InitTzAppsrc(); }\r
+\r
+ private:\r
+  using PadProbeMap =\r
+      std::unordered_map<std::string, std::pair<gulong, GstPad*>>;\r
+\r
+ private:\r
+  std::mutex execute_mutex_;\r
+  GstElement* mainbin_[static_cast<int>(T::kMaxElements)]{\r
+      nullptr,\r
+  };\r
+  std::unique_ptr<GstSignalHolder> signals_{new GstSignalHolder};\r
+  PadProbeMap padprobe_id_;\r
+  std::function<void(T)> on_gstelement_created_cb_handler_;\r
+  bool is_trustzone_element_[static_cast<int>(T::kMaxElements)]{\r
+      false,\r
+  };\r
+};  // struct TrackRenderer::Pipeline\r
+\r
+}  // namespace trackrenderer\r
+\r
+}  // namespace plusplayer\r
+\r
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_PIPELINE_H__\r
diff --git a/src/include_internal/trackrenderer/core/screen_saver.h b/src/include_internal/trackrenderer/core/screen_saver.h
new file mode 100755 (executable)
index 0000000..918e44f
--- /dev/null
@@ -0,0 +1,33 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SCREENSAVER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SCREENSAVER_H__
+
+#include <boost/core/noncopyable.hpp>
+
+#include "glib.h"
+#include "screensaver.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class ScreenSaver : private boost::noncopyable {
+ public:
+  ~ScreenSaver();
+  static void StartTimeout();
+  static void StopTimeout();
+
+ private:
+  static gboolean ResetTimeout(gpointer data);
+
+ private:
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SCREENSAVER_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/stream.h b/src/include_internal/trackrenderer/core/stream.h
new file mode 100755 (executable)
index 0000000..ba75238
--- /dev/null
@@ -0,0 +1,21 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_STREAM_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_STREAM_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+/**
+ * @brief  Enumerations for the stream type
+ */
+enum class StreamType { kAudio = 0, kVideo, kMax };
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_STREAM_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/subtitle_attr.h b/src/include_internal/trackrenderer/core/subtitle_attr.h
new file mode 100755 (executable)
index 0000000..8fb10e4
--- /dev/null
@@ -0,0 +1,79 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_SUBTITLE_ATTR_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_SUBTITLE_ATTR_H__
+
+#include <boost/any.hpp>
+#include <cstdint>
+#include <limits>
+#include <list>
+#include <memory>
+
+namespace plusplayer {
+namespace trackrenderer {
+enum SubtitleAttrType {
+  kSubAttrRegionXPos = 0,            // float type
+  kSubAttrRegionYPos,                // float type
+  kSubAttrRegionWidth,               // float type
+  kSubAttrRegionHeight,              // float type
+  kSubAttrWindowXPadding,            // float type
+  kSubAttrWindowYPadding,            // float type
+  kSubAttrWindowLeftMargin,          // int type
+  kSubAttrWindowRightMargin,         // int type
+  kSubAttrWindowTopMargin,           // int type
+  kSubAttrWindowBottomMargin,        // int type
+  kSubAttrWindowBgColor,             // int type
+  kSubAttrWindowOpacity,             // float type
+  kSubAttrWindowShowBg,              // how to show window background, uint type
+  kSubAttrFontFamily,                // char* type
+  kSubAttrFontSize,                  // float type
+  kSubAttrFontWeight,                // int type
+  kSubAttrFontStyle,                 // int type
+  kSubAttrFontColor,                 // int type
+  kSubAttrFontBgColor,               // int type
+  kSubAttrFontOpacity,               // float type
+  kSubAttrFontBgOpacity,             // float type
+  kSubAttrFontTextOutlineColor,      // int type
+  kSubAttrFontTextOutlineThickness,  // int type
+  kSubAttrFontTextOutlineBlurRadius,  // int type
+  kSubAttrFontVerticalAlign,          // int type
+  kSubAttrFontHorizontalAlign,        // int type
+  kSubAttrRawSubtitle,                // char* type
+  kSubAttrWebvttCueLine,              // float type
+  kSubAttrWebvttCueLineNum,           // int type
+  kSubAttrWebvttCueLineAlign,         // int type
+  kSubAttrWebvttCueAlign,             // int type
+  kSubAttrWebvttCueSize,              // float type
+  kSubAttrWebvttCuePosition,          // float type
+  kSubAttrWebvttCuePositionAlign,     // int type
+  kSubAttrWebvttCueVertical,          // int type
+  kSubAttrTimestamp,
+  kSubAttrExtsubIndex,  // File index of external subtitle
+  kSubAttrTypeNone
+};
+
+enum class SubtitleType { kText, kPicture, kInvalid };
+
+struct SubtitleAttr {
+  explicit SubtitleAttr(const SubtitleAttrType _type,
+                        const uint32_t _start_time, const uint32_t _stop_time,
+                        const boost::any _value, const int _extsub_index)
+      : type(_type),
+        start_time(_start_time),
+        stop_time(_stop_time),
+        value(_value),
+        extsub_index(_extsub_index) {}
+  const SubtitleAttrType type = kSubAttrTypeNone;
+  const uint32_t start_time = std::numeric_limits<uint32_t>::max();
+  const uint32_t stop_time = std::numeric_limits<uint32_t>::max();
+  const boost::any value;
+  const int extsub_index = -1;
+};
+using SubtitleAttrList = std::list<SubtitleAttr>;
+using SubtitleAttrListPtr = std::unique_ptr<SubtitleAttrList>;
+}  // namespace trackrenderer
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_SUBTITLE_ATTR_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/track.h b/src/include_internal/trackrenderer/core/track.h
new file mode 100755 (executable)
index 0000000..a8002c4
--- /dev/null
@@ -0,0 +1,66 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_TRACKRENDERER_CORE_TRACK_H__
+#define __PLUSPLAYER_TRACKRENDERER_CORE_TRACK_H__
+
+#include <memory>
+#include <string>
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+const int kInvalidTrackIndex = -1;
+
+enum TrackType {
+  kTrackTypeAudio = 0,
+  kTrackTypeVideo,
+  kTrackTypeSubtitle,
+  kTrackTypeMax
+};
+
+struct Track {
+  int index = kInvalidTrackIndex;
+  int id = 0;
+  std::string mimetype;
+  std::string streamtype;
+  TrackType type = kTrackTypeMax;
+  std::shared_ptr<char> codec_data;
+  int codec_data_len = 0;
+  int width = 0;
+  int height = 0;
+  int maxwidth = 0;
+  int maxheight = 0;
+  int framerate_num = 0;
+  int framerate_den = 0;
+  int sample_rate = 0;
+  int sample_format = 0;
+  int channels = 0;
+  int version = 0;
+  int layer = 0;
+  int bits_per_sample = 0;
+  int block_align = 0;
+  int bitrate = 0;
+  int endianness = 1234;  // little endian : 1234 others big endian
+  bool is_signed = false;
+  bool active = false;
+  bool use_swdecoder = false;
+  std::string language_code;
+  std::string subtitle_format;
+  std::string layout;
+  std::string codec_tag;
+  int flavor = 0;
+};
+
+struct Rational {
+  int num = 0;     // the numerator value
+  int den = 0;     // the denominator value
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACKRENDERER_CORE_TRACK_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/core/track_util.h b/src/include_internal/trackrenderer/core/track_util.h
new file mode 100755 (executable)
index 0000000..8e00586
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_TRACK_UTIL_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_TRACK_UTIL_H__
+
+#include <vector>
+
+#include "gst/gst.h"
+
+#include "trackrenderer/core/track.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace track_util {
+
+bool GetActiveTrack(const std::vector<Track>& track_list, TrackType type,
+                    Track* track);
+bool GetActiveTrackList(const std::vector<Track>& tracklist,
+                        std::vector<Track>& active_track);
+
+void ShowTrackInfo(const std::vector<Track>& trackinfo);
+void ShowTrackInfo(const Track& track);
+uint64_t GetPositionWithinBoundary(const uint64_t duration,
+                                   const uint64_t position,
+                                   const uint64_t threshold);
+bool IsValidCodecDataSize(int size);
+void FillCodecDataIntoTrack(const GValue* codec_data, Track* track);
+const std::string& GetTrackTypeString(const TrackType& type);
+}  // namespace track_util
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_TRACK_UTIL_H__
diff --git a/src/include_internal/trackrenderer/core/utils/log.h b/src/include_internal/trackrenderer/core/utils/log.h
new file mode 100755 (executable)
index 0000000..e8a2345
--- /dev/null
@@ -0,0 +1,145 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_LOG_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_LOG_H__
+
+#include <dlog.h>
+#include <string.h>
+
+#undef LOG_TAG
+#define LOG_TAG "PLUSPLAYER"
+
+#ifndef __MODULE__
+#define __MODULE__ \
+  (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+#endif
+
+#define TRACKRENDERER_DEBUG(fmt, arg...) \
+  ({                                     \
+    do {                                 \
+      LOGI(fmt, ##arg);                  \
+    } while (0);                         \
+  })
+
+#define TRACKRENDERER_DEBUG_P(id, fmt, arg...) \
+  ({                                           \
+    do {                                       \
+      LOGI("[%p] > " #fmt, id, ##arg);         \
+    } while (0);                               \
+  })
+
+#define TRACKRENDERER_INFO(fmt, arg...) \
+  ({                                    \
+    do {                                \
+      LOGI(fmt, ##arg);                 \
+    } while (0);                        \
+  })
+
+#define TRACKRENDERER_INFO_P(id, fmt, arg...) \
+  ({                                          \
+    do {                                      \
+      LOGI("[%p] > " #fmt, id, ##arg);        \
+    } while (0);                              \
+  })
+
+#define TRACKRENDERER_WARN(fmt, arg...) \
+  ({                                    \
+    do {                                \
+      LOGW(fmt, ##arg);                 \
+    } while (0);                        \
+  })
+
+#define TRACKRENDERER_WARN_P(id, fmt, arg...) \
+  ({                                          \
+    do {                                      \
+      LOGW("[%p] > " #fmt, id, ##arg);        \
+    } while (0);                              \
+  })
+
+#define TRACKRENDERER_ERROR(fmt, arg...) \
+  ({                                     \
+    do {                                 \
+      LOGE(fmt, ##arg);                  \
+    } while (0);                         \
+  })
+
+#define TRACKRENDERER_ERROR_P(id, fmt, arg...) \
+  ({                                           \
+    do {                                       \
+      LOGE("[%p] > " #fmt, id, ##arg);         \
+    } while (0);                               \
+  })
+
+#define TRACKRENDERER_FATAL(fmt, arg...) \
+  ({                                     \
+    do {                                 \
+      LOGF(fmt, ##arg);                  \
+    } while (0);                         \
+  })
+
+#define TRACKRENDERER_FATAL_P(id, fmt, arg...) \
+  ({                                           \
+    do {                                       \
+      LOGF("[%p] > " #fmt, id, ##arg);         \
+    } while (0);                               \
+  })
+
+#define TRACKRENDERER_ENTER \
+  {                         \
+    do {                    \
+      LOGI("ENTER");        \
+    } while (0);            \
+  }
+
+#define TRACKRENDERER_ENTER_P(id) \
+  {                               \
+    do {                          \
+      LOGI("[%p] > ENTER", id);   \
+    } while (0);                  \
+  }
+
+#define TRACKRENDERER_LEAVE \
+  {                         \
+    do {                    \
+      LOGI("LEAVE");        \
+    } while (0);            \
+  }
+
+#define TRACKRENDERER_LEAVE_P(id) \
+  {                               \
+    do {                          \
+      LOGI("[%p] > LEAVE", id);   \
+    } while (0);                  \
+  }
+
+#define TRACKRENDERER_ENTER_E \
+  {                           \
+    do {                      \
+      LOGE("ENTER");          \
+    } while (0);              \
+  }
+
+#define TRACKRENDERER_ENTER_E_P(id) \
+  {                                 \
+    do {                            \
+      LOGE("[%p] > ENTER", id);     \
+    } while (0);                    \
+  }
+
+#define TRACKRENDERER_LEAVE_E \
+  {                           \
+    do {                      \
+      LOGE("LEAVE");          \
+    } while (0);              \
+  }
+
+#define TRACKRENDERER_LEAVE_E_P(id) \
+  {                                 \
+    do {                            \
+      LOGE("[%p] > LEAVE", id);     \
+    } while (0);                    \
+  }
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_LOG_H__
diff --git a/src/include_internal/trackrenderer/core/utils/product_cfg.h b/src/include_internal/trackrenderer/core/utils/product_cfg.h
new file mode 100755 (executable)
index 0000000..5cf60f8
--- /dev/null
@@ -0,0 +1,31 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_PRODUCT_CFG_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_PRODUCT_CFG_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+enum class ProductType { kTv, kAv };
+// enum class ChipType { kKantM };
+
+namespace product_cfg {
+
+constexpr ProductType GetProductType() {
+#ifdef IS_AV_PRODUCT
+  return ProductType::kAv;
+#else
+  return ProductType::kTv;
+#endif
+}
+
+}  // namespace product_cfg
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_CORE_UTILS_PRODUCT_CFG_H__
diff --git a/src/include_internal/trackrenderer/display.h b/src/include_internal/trackrenderer/display.h
new file mode 100755 (executable)
index 0000000..a78acda
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_DISPLAY_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_DISPLAY_H__
+
+#include <boost/core/noncopyable.hpp>
+#include <mutex>
+
+#include "Ecore_Wl2.h"
+#include "Evas.h"
+#include "gst/video/videooverlay.h"
+#include "trackrenderer/core/display.h"
+#include "trackrenderer/core/gstobject_guard.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class Display : private boost::noncopyable {
+ public:
+  ~Display();
+  uint32_t GetSurfaceId() const { return surface_id_; }
+  void SetDisplayQualityInfo(const GstCaps* video_appsrc);
+  void SetDisplayMode(const DisplayMode& mode);
+  void SetDisplayRotate(const DisplayRotation& rotate);
+  bool SetDisplay(const DisplayType& type, Evas_Object* obj);
+  bool SetDisplay(const DisplayType& type, Ecore_Wl2_Window* ecore_wl2_window,
+                  const int x, const int y, const int w, const int h);
+  bool SetDisplay(const DisplayType& type, const uint32_t surface_id,
+                  const int x, const int y, const int w, const int h);
+  bool SetDisplaySubsurface(const DisplayType& type,
+                            Ecore_Wl2_Subsurface* ecore_wl2_subsurface,
+                            const int x, const int y, const int w, const int h);
+  bool SetDisplayRoi(const Geometry& roi);
+  bool SetDisplayCropArea(const CropArea& area);
+  bool ResizeRenderRect(const RenderRect& rect);
+  void SetVisible(bool is_visible) { visible_ = is_visible; }
+  bool Update(GstElement* videosink);
+  bool UpdateVisible(GstElement* videosink);
+  bool UpdateCropArea(GstElement* videosink);
+  void GetDisplayCropArea(CropArea* area);
+  void GetDisplay(DisplayType* type, Geometry* area) {
+    *type = type_;
+    *area = window_;
+  }
+  void GetDisplayMode(DisplayMode* mode) { *mode = mode_; }
+  void GetDisplayRotate(DisplayRotation* rotate) { *rotate = rotate_; }
+  void SetVideoQualityMode(const uint32_t mode) { qualitymode_ = mode; }
+
+ private:
+  bool SetDisplay_(const DisplayType& type, wl_surface* wl_surface, const int x,
+                   const int y, const int w, const int h);
+  wl_surface* GetWlSurface_(Ecore_Wl2_Window* ecore_wl2_window);
+
+ private:
+  uint32_t surface_id_ = 0;
+  Geometry window_;
+  Geometry roi_;
+  CropArea scale_;
+  DisplayType type_ = DisplayType::kNone;
+  DisplayMode mode_ = DisplayMode::kFullScreen;
+  DisplayRotation rotate_ = DisplayRotation::kNone;
+  uint32_t qualitymode_ = 0;
+  bool visible_ = true;
+  std::mutex settings_mutex_;
+  gstguard::GstGuardPtr<GstCaps> video_quality_info_caps_;
+  bool has_parent_surface_ = false;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_DISPLAY_H__
diff --git a/src/include_internal/trackrenderer/error.h b/src/include_internal/trackrenderer/error.h
new file mode 100755 (executable)
index 0000000..4d09c84
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_ERROR_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_ERROR_H__
+
+#include "gst/gst.h"
+
+#include "trackrenderer/core/error.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+ErrorType HandleError(GstMessage* message, const bool is_music_content);
+
+void HandleErrorMsg(GstMessage* message, gchar** error_msg);
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_ERROR_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/latency_manager.h b/src/include_internal/trackrenderer/latency_manager.h
new file mode 100755 (executable)
index 0000000..2e7af72
--- /dev/null
@@ -0,0 +1,82 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_MANAGER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_MANAGER_H__
+
+#include <stdint.h>
+
+#include <bitset>
+#include <future>
+#include <mutex>
+
+#include "trackrenderer/core/latency.h"
+#include "trackrenderer/core/pipeline.hpp"
+#include "trackrenderer/core/track.h"
+#include "trackrenderer/latency_status_listener.h"
+#include "trackrenderer/core/elements.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class LatencyManager {
+
+ public:
+  explicit LatencyManager(LatencyStatusListener* listener);
+  ~LatencyManager();
+
+  enum class UpdatePacketStatus {
+    kSubmit,
+    kFlush,
+    kMax
+  };
+
+  void SetVideoMidLatencyThreshold(const unsigned int threshold);
+  void SetAudioMidLatencyThreshold(const unsigned int threshold);
+  void SetVideoHighLatencyThreshold(const unsigned int threshold);
+  void SetAudioHighLatencyThreshold(const unsigned int threshold);
+  void SetCatchUpSpeed(const CatchUpSpeed& level);
+  void SetPipeline(Pipeline<Elements>* pipeline);
+  void UnsetPipeline();
+  void GetVideoLatencyStatus(LatencyStatus* status);
+  void GetAudioLatencyStatus(LatencyStatus* status);
+  void UpdateVideoFrameStatus(UpdatePacketStatus status);
+
+ private:
+  int CalculateDropRate_();
+  LatencyStatus GetVideoLatencyStatus_(const unsigned int latency);
+  LatencyStatus GetAudioLatencyStatus_(const unsigned int latency);
+  void LatencyCheckerTask_();
+  void HandleVideoLatency_(const unsigned int video_latency);
+  void HandleAudioLatency_(const unsigned int audio_latency);
+  void StartLatencyChecker_();
+
+ private:
+  enum class CheckerPrecondition {
+    kSetThreshold = 0,
+    kSetPipeline,
+    kMax
+  };
+
+  unsigned int video_mid_latency_threshold_ = UINT32_MAX;
+  unsigned int audio_mid_latency_threshold_ = UINT32_MAX;
+  unsigned int video_high_latency_threshold_ = UINT32_MAX;
+  unsigned int audio_high_latency_threshold_ = UINT32_MAX;
+  unsigned int submitted_video_frames_ = 0;
+  CatchUpSpeed speed_level_ = CatchUpSpeed::kNone;
+  LatencyStatus video_latency_status_ = LatencyStatus::kLow;
+  LatencyStatus audio_latency_status_ = LatencyStatus::kLow;
+  LatencyStatusListener* event_listener_ = nullptr;
+  std::future<void> latency_checker_task_;
+  std::bitset<static_cast<int>(CheckerPrecondition::kMax)>
+      checker_precondition_;
+  bool is_stopped_ = false;
+  std::mutex pipeline_m_;
+  Pipeline<Elements>* pipeline_ = nullptr;
+};
+}  // namespace trackrenderer
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_MANAGER_H__
diff --git a/src/include_internal/trackrenderer/latency_status_listener.h b/src/include_internal/trackrenderer/latency_status_listener.h
new file mode 100755 (executable)
index 0000000..88f163f
--- /dev/null
@@ -0,0 +1,27 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_STATUS_LISTENER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_STATUS_LISTENER_H__
+
+#include "trackrenderer/core/track.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class LatencyStatusListener {
+ public:
+  virtual ~LatencyStatusListener() {}
+  virtual void OnVideoLatencyStatus(const LatencyStatus& latency_status) = 0;
+  virtual void OnAudioLatencyStatus(const LatencyStatus& latency_status) = 0;
+  virtual void OnVideoHighLatency() = 0;
+  virtual void OnAudioHighLatency() = 0;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_LATENCY_STATUS_LISTENER_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/resource.h b/src/include_internal/trackrenderer/resource.h
new file mode 100755 (executable)
index 0000000..2ff7a80
--- /dev/null
@@ -0,0 +1,82 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_H__
+
+#include <string>
+
+#include "trackrenderer/core/track.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+enum class RscType { kVideoRenderer };
+
+enum class ResourceCategory {
+  kVideoDecoder,
+  kVideoDecoderSub,
+  kVideoRenderer,
+  kVideoRendererSub,
+  kVideoRendererSub2,
+  kVideoRendererSub3,
+  kAudioDecoder,
+  kAudioDecoderSub,
+  kAudioRenderer,
+  kAudioRendererSub
+};
+
+enum class AllocatedState { kFailed, kSuccess, kSkipped };
+
+enum class RscAllocPolicy {
+  kRscAllocExclusive,
+  kRscAllocConditional,
+};
+
+struct ResourceProperty {
+  ResourceCategory category = ResourceCategory::kVideoDecoder;
+  Track track;
+  bool use_sw = false;
+  bool is_vr360 = false;
+  bool is_dual_sound = false;
+  bool is_multiview = false;
+  bool is_ndecoding = false;
+  RscAllocPolicy rsc_alloc_policy = RscAllocPolicy::kRscAllocExclusive;
+};
+
+constexpr char kSwDecoderComponentName[] = "FFMPEG.SW.Decoder";
+constexpr char kPulseSinkComponentName[] = "Pulse.Audio.Out";
+constexpr char kSkippedResource[] = "SKIP";
+
+class Resource {
+ public:
+  Resource(const ResourceProperty& property, const std::string& componentname)
+      : property_(property), componentname_(componentname) {}
+  Resource(const ResourceProperty& property, int deviceid,
+           const std::string& componentname)
+      : property_(property),
+        deviceid_(deviceid),
+        componentname_(componentname) {}
+  Resource(const ResourceProperty& property, AllocatedState state)
+      : property_(property), state_(state) {}
+  const ResourceCategory& GetResourceCategory() const {
+    return property_.category;
+  }
+  const int& GetDeviceId() const { return deviceid_; }
+  const std::string& GetComponentName() const { return componentname_; }
+  const AllocatedState& GetAllocatedState() const { return state_; }
+
+ private:
+  const ResourceProperty property_;
+  const int deviceid_ = 0;
+  const std::string componentname_;
+  const AllocatedState state_ = AllocatedState::kSuccess;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_H__
diff --git a/src/include_internal/trackrenderer/resource_conflict_listener.h b/src/include_internal/trackrenderer/resource_conflict_listener.h
new file mode 100755 (executable)
index 0000000..2c17d59
--- /dev/null
@@ -0,0 +1,22 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_CONFLICT_LISTENER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_CONFLICT_LISTENER_H__
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class ResourceConflictListener {
+ public:
+  virtual ~ResourceConflictListener() {}
+  virtual void OnResourceConflicted() = 0;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCE_CONFLICT_LISTENER_H__
diff --git a/src/include_internal/trackrenderer/resourcemanager.h b/src/include_internal/trackrenderer/resourcemanager.h
new file mode 100755 (executable)
index 0000000..8c692a9
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCEMANAGER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCEMANAGER_H__
+
+#include <list>
+#include <mutex>
+#include <string>
+
+#include "rm_api.h"
+#include "trackrenderer/core/track.h"
+#include "trackrenderer/resource.h"
+#include "trackrenderer/resource_conflict_listener.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+using ResourceManagerHandle = int;
+
+constexpr int kMaxUhd8kWidth = 7680;
+constexpr int kMaxUhd8kHeight = 4320;
+constexpr int kMaxUhdWidth = 4096;
+constexpr int kMaxUhdHeight = 2160;
+constexpr int kMaxFhdWidth = 1920;
+constexpr int kMaxFhdHeight = 1080;
+
+class ResourceManager {
+ public:
+  explicit ResourceManager(ResourceConflictListener* listener);
+  ~ResourceManager();
+
+  void SetAppId(const std::string& appid);
+  bool Alloc(const std::list<ResourceProperty>& properties);
+  bool Dealloc();
+  bool Dealloc(const ResourceCategory type);
+  std::string GetComponentName(const ResourceCategory type);
+  int GetRawHandle();
+  AllocatedState GetAllocatedState(const ResourceCategory type);
+  bool IsMainDevice(const ResourceCategory& type);
+  int GetDeviceId(const ResourceCategory& type);
+  bool NeedPulseResource(const ResourceProperty& property);
+  bool IsAudioFocused();
+
+ private:
+  bool Alloc_(const ResourceProperty& property);
+  bool AllocPulseResource_(const ResourceProperty& property);
+  bool AllocSwDecoderResource_(const ResourceProperty& property);
+  bool AllocHWResource_(const ResourceProperty& property);
+  bool TryAllocHWResource_(const ResourceProperty& property,
+                           const rm_category_request_s& req);
+  int GetCategoryOption_(const rm_rsc_category_e& category_id,
+                         const ResourceProperty& property);
+  AllocatedState MakeCategoryRequest_(const ResourceProperty& property,
+                                      rm_category_request_s* req);
+
+ private:
+  static rm_cb_result ResourceConflictCallback_(ResourceManagerHandle rmhandle,
+                                                rm_callback_type eventtype,
+                                                rm_device_request_s* info,
+                                                void* userdata);
+
+ private:
+  ResourceManagerHandle resourcemanager_handle_ = 0;
+  std::list<Resource> resourcelist_;
+  std::mutex control_lock_;
+  ResourceConflictListener* resourceconflict_listener_ = nullptr;
+  std::string app_id_ = "";
+};  // class ResourceManager
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_RESOURCEMANAGER_H__
diff --git a/src/include_internal/trackrenderer/subtitle_attr_parser.h b/src/include_internal/trackrenderer/subtitle_attr_parser.h
new file mode 100755 (executable)
index 0000000..3599c9e
--- /dev/null
@@ -0,0 +1,31 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SUBTITLE_ATTR_PARSER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_CORE_SUBTITLE_ATTR_PARSER_H__
+
+#include <gst/gst.h>
+
+#include <boost/core/noncopyable.hpp>
+
+#include "trackrenderer/core/subtitle_attr.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class SubtitleAttrParser : private boost::noncopyable {
+ public:
+  explicit SubtitleAttrParser(GstBuffer* buf) : gstbuf_(buf) {}
+  SubtitleAttrListPtr Parse();
+
+ private:
+  GstBuffer* gstbuf_ = nullptr;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  //__PLUSPLAYER_SRC_TRACKRENDERER_CORE_SUBTITLE_ATTR_PARSER_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/trackrenderer.h b/src/include_internal/trackrenderer/trackrenderer.h
new file mode 100755 (executable)
index 0000000..1cf6d42
--- /dev/null
@@ -0,0 +1,532 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_H__
+
+#include <gst/gst.h>
+#include <gst/video/video-info.h>
+
+#include <boost/core/noncopyable.hpp>
+#include <condition_variable>  // std::condition_variable
+#include <functional>
+#include <memory>
+#include <mutex>  // std::mutex , std::unique_lock
+#include <string>
+#include <vector>
+
+#ifndef SOUNDBAR_PRODUCT
+#include "avoc.h"
+#endif
+
+#include "trackrenderer/audio_controller/audio_easing_controller.h"
+#include "trackrenderer/audio_controller/resyncaudio_policy.h"
+#include "trackrenderer/core/attribute.hpp"
+#include "trackrenderer/core/buffer.h"
+#include "trackrenderer/core/decoderinputbuffer.h"
+#include "trackrenderer/core/display.h"
+#include "trackrenderer/core/drm.h"
+#include "trackrenderer/core/elements.h"
+#include "trackrenderer/core/error.h"
+#include "trackrenderer/core/event.h"
+#include "trackrenderer/core/gstcaps_builder.h"
+#include "trackrenderer/core/latency.h"
+#include "trackrenderer/core/picturequality.h"
+#include "trackrenderer/core/pipeline.hpp"
+#include "trackrenderer/core/screen_saver.h"
+#include "trackrenderer/core/stream.h"
+#include "trackrenderer/core/subtitle_attr.h"
+#include "trackrenderer/core/track.h"
+#include "trackrenderer/latency_manager.h"
+#include "trackrenderer/latency_status_listener.h"
+#include "trackrenderer/resource.h"
+#include "trackrenderer/resource_conflict_listener.h"
+#include "trackrenderer/trackrenderer_attr.h"
+#include "trackrenderer/trackrenderer_debug.h"
+#include "trackrenderer/vr360.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+class ResourceManager;
+class Display;
+class ScreenSaver;
+
+enum class SubmitStatus {
+  kNotPrepared,  // not prepared to get data
+  kHold,         // valid data, hold this packet
+  kFull,         // buffer already full
+  kSuccess,      // submit succeeded
+  kDrop,         // invalid data , drop this packet
+};
+
+static const double kDefaultPlaybackRate = 1.0;
+
+class TrackRenderer : public ResourceConflictListener,
+                      LatencyStatusListener,
+                      private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<TrackRenderer>;
+  ~TrackRenderer();
+  static Ptr Create() { return Ptr(new TrackRenderer); }
+
+ public:  // Types
+  using AudioStartCbHandle = std::uint32_t;
+  using AudioStopCbHandle = std::uint32_t;
+  using AudioResyncCbHandle = std::uint32_t;
+  using VideoStartCbHandle = std::uint32_t;
+  using VideoStopCbHandle = std::uint32_t;
+  // LCOV_EXCL_START
+  class EventListener {
+   public:
+    virtual ~EventListener() {}
+    virtual void OnError(const ErrorType& err_code) {}
+    virtual void OnErrorMsg(const ErrorType& error_code, char* error_msg){};
+    virtual void OnResourceConflicted() {}
+    virtual void OnSeekDone() {}
+    virtual void OnFlushDone() {}
+    virtual void OnEos() {}
+    virtual void OnFirstDecodingDone() {}
+    virtual void OnEvent(const EventType& event, const EventMsg& msg_data) {}
+    virtual void OnSubtitleData(const DecoderInputBufferPtr& buf,
+                                const SubtitleType& type) {}
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+    virtual void OnSubtitleData(const char* data, const int size,
+                                const SubtitleType& type,
+                                const uint64_t duration,
+                                SubtitleAttrListPtr attr_list) {}
+#endif
+    virtual void OnClosedCaptionData(const char* data, const int size) {}
+    virtual void OnDrmInitData(int* drmhandle, unsigned int len,
+                               unsigned char* psshdata, TrackType type) {}
+    virtual void OnBufferStatus(const TrackType& type,
+                                const BufferStatus& status) {}
+    virtual void OnSeekData(const TrackType& type, const uint64_t offset) {}
+    virtual void OnMediaPacketGetTbmBufPtr(void** tbm_ptr,
+                                           bool is_scale_change) {}
+    virtual void OnMediaPacketVideoDecoded(const DecodedVideoPacket& packet) {}
+    virtual void OnMediaRawPacketVideoDecoded(
+        DecodedVideoRawModePacket& packet) {}
+    virtual void OnVideoDecoderUnderrun() {}
+    virtual void OnVideoLatencyStatus(const LatencyStatus& latency_status) {}
+    virtual void OnAudioLatencyStatus(const LatencyStatus& latency_status) {}
+    virtual void OnVideoHighLatency() {}
+    virtual void OnAudioHighLatency() {}
+    virtual void OnMultiviewStartVideo() {}
+    virtual void OnMultiviewStopVideo() {}
+  };
+  // LCOV_EXCL_STOP
+
+  enum class State { kInit, kWorking, kResourceConflicted, kStopped };
+
+ public:  // Methods
+  bool Start();
+  bool Stop();
+  bool Prepare();
+  bool Pause();
+  bool Resume();
+  bool SetTrack(const std::vector<Track>& trackinfo);
+  void SetIniProperty(const std::map<std::string, bool>& Properties);
+  bool Seek(uint64_t time_millisecond, double playback_rate);
+  bool Seek(uint64_t time_millisecond, double playback_rate, bool audio_mute);
+  bool SetPlaybackRate(double playback_rate, bool audio_mute);
+  bool GetPlayingTime(uint64_t* curtime_in_msec);
+  bool GetDroppedFrames(void* frame_counts);
+  bool GetDroppedFramesForCatchup(TrackType type, void* frame_counts);
+  bool Deactivate(TrackType type);
+  bool Activate(TrackType type, const Track& track);
+  bool SubmitPacket(const DecoderInputBufferPtr& data,
+                    SubmitStatus* retval = nullptr);
+  void SetDrm(const drm::Property& drm_property) {
+    drm_property_ = drm_property;
+  }
+  bool SetMatroskaColorInfo(const std::string& color_info);
+  void DrmLicenseAcquiredDone(TrackType type);
+  bool SetDisplayMode(const DisplayMode& mode);
+  bool SetDisplayRotate(const DisplayRotation& rotate);
+  void GetDisplayRotate(DisplayRotation* rotation);
+  bool SetDisplay(const DisplayType& type, uint32_t surface_id, long x, long y,
+                  long w, long h);
+  bool SetDisplay(const DisplayType& type, void* obj);
+  bool SetDisplay(const DisplayType& type, void* ecore_wl2_window, int x, int y,
+                  int w, int h);
+  bool SetDisplaySubsurface(const DisplayType& type, void* ecore_wl2_subsurface,
+                            int x, int y, int w, int h);
+  bool SetDisplayRoi(const Geometry& roi);
+  bool SetVideoRoi(const CropArea& area);
+  bool ResizeRenderRect(const RenderRect& rect);
+  bool SetDisplayVisible(bool is_visible);
+  void GetDisplay(DisplayType* type, Geometry* area);
+  void GetDisplayMode(DisplayMode* mode);
+  bool SetAudioMute(bool is_mute);
+  bool SetVolume(const int& volume);
+  bool GetVolume(int* volume);
+  void OnResourceConflicted() override;
+  void OnVideoLatencyStatus(const LatencyStatus& latency_status) override;
+  void OnAudioLatencyStatus(const LatencyStatus& latency_status) override;
+  void OnVideoHighLatency() override;
+  void OnAudioHighLatency() override;
+  void RegisterListener(EventListener* listener);
+  void SetVideoStillMode(const StillMode& type) { still_mode_type_ = type; }
+  void SetAttribute(const Attribute& attr, const boost::any& value);
+  void GetAttribute(const Attribute& attr, boost::any* value);
+  void SetConfig(const std::string, const boost::any& value);
+  State GetState() { return state_; }
+  void SetAppId(const std::string& app_id);
+  void SetAppInfo(const PlayerAppInfo& app_info);
+  void FlushAppsrc(TrackType type, bool setbyuser);
+  void SetVideoFrameBufferType(DecodedVideoFrameBufferType type);
+  void SetVideoFrameBufferScaleResolution(const uint32_t& target_width,
+                                          const uint32_t& target_height);
+  bool SetDecodedVideoFrameRate(const Rational& request_framerate);
+  bool RenderVideoFrame();
+  bool SetAiFilter(void* aifilter);
+  void SetAlternativeAudioResource(const boost::any& value);
+  void SetCatchUpSpeed(const CatchUpSpeed& level);
+  void GetVideoLatencyStatus(LatencyStatus* status);
+  void GetAudioLatencyStatus(LatencyStatus* status);
+  void SetVideoMidLatencyThreshold(const unsigned int threshold);
+  void SetAudioMidLatencyThreshold(const unsigned int threshold);
+  void SetVideoHighLatencyThreshold(const unsigned int threshold);
+  void SetAudioHighLatencyThreshold(const unsigned int threshold);
+  bool InitAudioEasingInfo(const uint32_t& init_volume,
+                           const uint32_t& init_elapsed_time,
+                           const AudioEasingInfo& info);
+  bool UpdateAudioEasingInfo(const AudioEasingInfo& info);
+  bool GetAudioEasingInfo(uint32_t* current_volume, uint32_t* elapsed_time,
+                          AudioEasingInfo* info);
+  bool StartAudioEasing();
+  bool StopAudioEasing();
+  bool GetVirtualRscId(const RscType type, int* virtual_id);
+  bool SetAdvancedPictureQualityType(const AdvPictureQualityType type);
+  bool SetResourceAllocatePolicy(const RscAllocPolicy policy);
+  bool SetVideoRendererType(const ResourceCategory video_renderer_type);
+  void SetVideoParDar(uint64_t time_millisecond, uint32_t par_n, uint32_t par_d,
+                      uint32_t dar_n, uint32_t dar_d);
+
+ private:
+  enum VolumeLevel {
+    kVolumeNone = -1,
+    kVolumeMin = 0,
+    kVolumeMax = 100,
+  };
+
+  enum LowLatencyMode {
+    kLowLatencyModeNone = 0x0000,
+    kLowLatencyModeAudio = 0x0001,
+    kLowLatencyModeVideo = 0x0010,
+    kLowLatencyModeVideoDistortionConcealment = kLowLatencyModeVideo | 0x0020,
+    kLowLatencyModeDisableAVSync = 0x0100,
+    kLowLatencyModeDisablePreroll = 0x0200,
+    kLowLatencyModeDisableVideoQuality = 0x1000
+  };
+
+  enum class DropMode {
+    kDropModeNone = 0,
+    kDropModeAccordingToRate,
+    kDropModeAccordingToTable,
+  };
+
+  enum class SubState {
+    kUnknown,
+    kPaused,
+    kPlaying,
+  };
+
+  struct TrackContext {
+    int index = kInvalidTrackIndex;
+    bool is_enough_data = false;
+    bool need_update_segment = true;
+    std::function<bool(const Track*)> create_pipeline;
+    Track* track = nullptr;
+  };
+
+  struct AttributeValue {
+    boost::any value;
+    bool value_assigned = false;
+  };
+
+  struct RenderingStartTime {
+    bool is_set = false;
+    uint64_t time = 0;
+  };
+
+  struct DropContext {
+    std::mutex drop_mutex;
+    Rational track_fps;
+    Rational request_fps;
+    bool fps_changed = false;
+    DropMode drop_mode = DropMode::kDropModeNone;
+    uint32_t drop_rate = 0;
+    uint32_t base_num = 0;
+  };
+
+ public:
+  using TrackRendererAttributeSetter = AttributeSetter<Elements>;
+  using TrackRendererAttributeGetter = AttributeGetter<Elements>;
+
+ private:
+  using TrackRendererAttributeBinder = AttributeBinder<Elements>;
+  using Attributes =
+      std::map<trackrenderer::Attribute, TrackRendererAttributeBinder>;
+  using AttributesByElement =
+      std::map<Elements, std::vector<trackrenderer::Attribute>>;
+  using Config_Setter = std::function<bool(const boost::any&)>;
+
+ private:
+  TrackRenderer() noexcept;
+
+  static GstBusSyncReply GstBusSyncHandlerCb_(GstBus* bus, GstMessage* message,
+                                              gpointer data);
+  static GstPadProbeReturn GstPadProbeIdleCb_(GstPad* pad,
+                                              GstPadProbeInfo* info,
+                                              gpointer userdata);
+  static GstPadProbeReturn GstPadProbeBlockCb_(GstPad* pad,
+                                               GstPadProbeInfo* info,
+                                               gpointer userdata);
+  static void GstSubtitleDataHandOffCb_(GstElement* object, GstBuffer* buf,
+                                        GstPad* pad, gpointer userdata);
+  static void GstClosedCaptionHandOffCb_(GstElement* object, GstBuffer* buf,
+                                         GstPad* pad, gpointer userdata);
+  static void GstClosedCaptionPadAddedCb_(GstElement* element, GstPad* srcpad,
+                                          gpointer userdata);
+
+  static void GstAudioNeedDataCb_(GstElement* element, guint size,
+                                  gpointer userdata);
+  static void GstVideoNeedDataCb_(GstElement* element, guint size,
+                                  gpointer userdata);
+  static void GstSubtitleNeedDataCb_(GstElement* element, guint size,
+                                     gpointer userdata);
+  static void GstAudioEnoughDataCb_(GstElement* element, gpointer userdata);
+  static void GstVideoEnoughDataCb_(GstElement* element, gpointer userdata);
+  static void GstSubtitleEnoughDataCb_(GstElement* element, gpointer userdata);
+  static gboolean GstAudioSeekDataCb_(GstElement* element, guint64 offset,
+                                      gpointer user_data);
+  static gboolean GstVideoSeekDataCb_(GstElement* element, guint64 offset,
+                                      gpointer user_data);
+  static gboolean GstSubtitleSeekDataCb_(GstElement* element, guint64 offset,
+                                         gpointer user_data);
+  static gboolean GstVideoDrmInitDataCb_(int* drmhandle, unsigned int len,
+                                         unsigned char* psshdata,
+                                         void* userdata);
+  static gboolean GstAudioDrmInitDataCb_(int* drmhandle, unsigned int len,
+                                         unsigned char* psshdata,
+                                         void* userdata);
+  static void GstDecodedVideoReferenceBufferCb_(GstElement* element,
+                                                GstBuffer* buffer, GstPad* pad,
+                                                void* userdata);
+  static void GstDecodedVideoCopyBufferCb_(GstElement* element,
+                                           GstBuffer* buffer, GstPad* pad,
+                                           void* userdata);
+  static void GstDecodedVideoRawBufferCb_(GstElement* element,
+                                          GstBuffer* buffer, GstPad* pad,
+                                          void* userdata);
+  static void GstDecodedVideoScaleBufferCb_(GstElement* element,
+                                            GstBuffer* buffer, GstPad* pad,
+                                            void* userdata);
+  static void GstAiFilterResultCb_(GstElement* element, GstStructure* structure,
+                                   void* userdata);
+  static AttributesByElement InitAttributeByElementType_();
+  static void MultiviewStartAudioCb_(int player_id, void* data);
+  static void MultiviewStopAudioCb_(int player_id, void* data);
+  static void MultiviewResyncAudioCb_(int player_id, void* data);
+  static void MultiviewStartVideoCb_(int player_id, void* data);
+  static void MultiviewStopVideoCb_(int player_id, void* data);
+  static void VconfCb_(const std::string& name, const std::string& value,
+                       void* userdata);
+  static GstPadProbeReturn GstSrcPadProbeBlockCb_(GstPad* pad,
+                                                  GstPadProbeInfo* info,
+                                                  gpointer userdata);
+  static GstPadProbeReturn GstSrcPadProbeIdleCb_(GstPad* pad,
+                                                 GstPadProbeInfo* info,
+                                                 gpointer userdata);
+  static GstPadProbeReturn GstPadProbeVideoPeekBlockCb_(GstPad* pad,
+                                                        GstPadProbeInfo* info,
+                                                        gpointer userdata);
+  static GstPadProbeReturn GstPadProbeVideoDecodedCb_(GstPad* pad,
+                                                      GstPadProbeInfo* info,
+                                                      gpointer userdata);
+  static GstPadProbeReturn GstPadProbeVideoDecInputCb_(GstPad* pad,
+                                                       GstPadProbeInfo* info,
+                                                       gpointer userdata);
+
+  bool GetResource_(const TrackType& type);
+  bool CreatePipeline_();
+  void CreateAppSrc_(TrackType type, const std::string& mimetype);
+  void CreateDrmElement_(const Track& track);
+  const char* GetAudioSinkPluginName_(bool swdecoder,
+                                      const std::string& mimetype);
+  void CreateAudioSink_(const std::string& sink_name);
+  void CreateVideoDecoder_(const char* dec_name);
+  bool CreateVideoSink_();
+  void SetPropertyForAiFilter_();
+  void SetPropertyForDecodedVideoBufferWithDisplay_();
+  void SetPropertyForDecodedVideoBufferWithoutDisplay_();
+  void SetPropertyForDecodedVideoBuffer_();
+  bool CreateVideoPipeline_(const Track* track);
+  bool CreateAudioPipeline_(const Track* track);
+  bool CreateSwAudioPipeline_(const Track* track);
+  bool CreateRawAudioPipeline_(const Track* track);
+  bool CreateSubtitlePipeline_(const Track* track);
+  bool NeedAvocPlayerRegister_();
+  bool AvocPlayerRegister_();
+  bool AvocPlayRequest_();
+  bool AvocPlayerUnRegister_();
+  bool AddAiFilter_(void* aifilter);
+  void RemoveAiFilter_();
+  bool ReleaseResource_();
+  bool ControlDropRate_(uint64_t packet_pts, SubmitStatus* status);
+  bool RemoveDownstreamOfAppsrc_(TrackType type);
+  const char* GetDecoderPluginName_(TrackType type,
+                                    const std::string& mimetype);
+  void UpdateStartSegment_(GstClockTime start_time, const TrackType& type);
+  SubtitleType GetSubtitleType_(const GstBuffer* buffer);
+  void GstElementCreatedCb_(Elements element);
+  void SetDefaultAttributeValue_();
+  void SetAttribute_(const TrackRendererAttributeBinder& binder,
+                     const boost::any& original_value,
+                     const boost::any& new_value);
+  bool GetPlayingTime_(uint64_t* curtime_in_msec);
+  void UpdatePlaybackInfo_(bool is_updating);
+  void SetVolume_();
+  bool ActivateAudio_();
+  bool DeactivateAudio_();
+  void FlushDownStream_(Elements element, const char* key, gboolean reset_time);
+  void InitConfigSetterTable_();
+  bool SetAccurateSeekMode_(const boost::any& value);
+  bool SetLowLatencyMode_(const boost::any& value);
+  bool SetWindowStandAloneMode_(const boost::any& value);
+  bool SetVideoFramePeekMode_(const boost::any& value);
+  void GstElementLowLatency_(const TrackType& type);
+  void CreateTbmBufferManager_();
+  void SetVr360GpuModeSecure_(bool set);
+  void SetSequentialMode_();
+  void SetDirectCrop_(const std::string& app_id);
+  void GetResolutionInfo_(EventMsg* event_msg);
+  bool SetUnlimitedMaxBufferMode_(const boost::any& value);
+  bool SetVideoPreDisplayMode_(const boost::any& value);
+  bool SetStartRenderingTime_(const boost::any& value);
+  bool SetFmmMode_(const boost::any& value);
+  bool SetAlternativeVideoResource_(const boost::any& value);
+  bool SetVideoDecodingMode_(const boost::any& value);
+  bool SetLateVideoFrameDropMode_(const boost::any& value);
+  void SetVideoQualityInfo_();
+  void CompleteSeeking_(void);
+  bool IsSegmentUpdated_() const;
+  bool HasSubtitleOnly_() const;
+  void SetDefaultAppSrcSignals_(const TrackType& type);
+  bool SetResourceCenterCallback_();
+  bool UnsetResourceCenterCallback_();
+  void SetVconfCb_();
+  void UnsetVconfCb_();
+  bool StopAudioEasing_();
+  bool NeedSyncPause_();
+  bool ResyncAudio_();
+  void SetAudioOut_();
+  void UpdateTrackFrameRate_(const int& framerate_num,
+                             const int& framerate_den);
+  void UpdateDecodedDropContext_();
+  bool NeedDropThisDecodedVideoBuffer_();
+
+ private:
+  EventListener* eventlistener_ = nullptr;  // eventlistener is Defaultplayer
+  std::mutex resource_m_;
+  std::mutex internal_audio_m_;
+  std::condition_variable resource_cv_;
+
+  std::unique_ptr<ResourceManager> resource_manager_;
+  std::unique_ptr<Display> display_;
+  std::unique_ptr<ScreenSaver> screen_saver_;
+  std::unique_ptr<AudioEasingController> audio_easing_controller_;
+  ResourceCategory video_decoder_id_ = ResourceCategory::kVideoDecoder;
+  ResourceCategory video_renderer_id_ = ResourceCategory::kVideoRenderer;
+  ResourceCategory audio_out_id_ = ResourceCategory::kAudioRenderer;
+  ResourceCategory audio_decoder_id_ = ResourceCategory::kAudioDecoder;
+  RscAllocPolicy rsc_alloc_policy_ = RscAllocPolicy::kRscAllocExclusive;
+  AudioStartCbHandle audio_start_cb_id_ = 0;
+  AudioStopCbHandle audio_stop_cb_id_ = 0;
+  AudioResyncCbHandle audio_resync_cb_id_ = 0;
+  VideoStartCbHandle video_start_cb_id_ = 0;
+  VideoStopCbHandle video_stop_cb_id_ = 0;
+  int avoc_id_ = -1;
+  bool need_avoc_register = false;
+
+  GstCapsBuilder caps_builder_;
+  std::map<std::string, bool> properties_;
+  std::vector<Track> trackinfo_;
+  TrackContext trackctx_[kTrackTypeMax];
+  bool is_seeking_ = false;
+  bool is_flushing_ = false;
+  gboolean is_sound_mute_ = FALSE;
+  bool is_accurate_seek_ = false;
+  bool is_async_done_ = false;
+  gboolean window_stand_alone_mode_ = FALSE;
+  bool is_video_frame_peek_ = false;
+  std::uint32_t low_latency_mode_ = 0;
+  bool unlimited_max_buffer_mode_ = 0;
+  bool video_pre_display_mode_ = false;
+  gint fmm_mode_ = 0;
+  std::uint32_t video_decoding_mode_ = 0x02;  // seamless mode
+  RenderingStartTime rendering_start_time_;
+  int volume_ = kVolumeNone;
+  uint64_t last_position_ = 0;
+  std::unique_ptr<Pipeline<Elements>> pipeline_;
+  StillMode still_mode_type_ = StillMode::kNone;
+  drm::Property drm_property_;
+  std::map<trackrenderer::Attribute, AttributeValue> set_attribute_values_;
+  bool is_stopped_ = false;
+  State state_ = State::kInit;
+  std::unique_ptr<debug::PlayinfoSetter> playback_info_;
+  DecodedVideoFrameBufferType decoded_buffer_type_ =
+      DecodedVideoFrameBufferType::kNone;
+  bool is_audioactivated_ = true;
+  bool is_videoactivated_ = true;
+  bool is_multiscreen_ = false;
+  std::unique_ptr<TbmBufferManager> tbm_buffer_manager_;
+  int use_seq_mode_ = 0;
+  void* aifilter_ = nullptr;
+  bool enable_direct_crop_ = false;
+  double playback_rate_ = kDefaultPlaybackRate;
+
+  SubState target_substate_ = SubState::kUnknown;
+
+  std::map<std::string, Config_Setter> config_setter_table_;
+  bool enable_audio_track_change_ = false;
+  gboolean support_audio_codec_change_ = FALSE;
+  bool support_videodec_underflow_pause_ = false;
+  bool need_avoc_sub_source_ = false;
+#ifndef SOUNDBAR_PRODUCT
+  avoc_sub_source_e avoc_sub_source_ = AVOC_SUB_SOURCE_NONE;
+#endif
+  std::unique_ptr<LatencyManager> latency_manager_;
+  int virtual_scaler_id_ = -1;
+  bool is_error_posted_ = false;
+
+  std::unique_ptr<ResyncAudioPolicy> resync_audio_policy_;
+  DisplayType display_type_ = DisplayType::kNone;
+  uint32_t scale_target_width_ = 960;
+  uint32_t scale_target_height_ = 540;
+  bool is_scale_size_changed_ = false;
+  std::mutex tbmmgr_m_;
+  DropContext decoded_drop_ctx_;
+  std::mutex scale_target_m_;
+
+  std::unique_ptr<Vr360> vr360_;
+
+  bool drop_all_late_video_ = false;
+  ParDarInfo par_dar_;
+  bool is_pardar_updated_ = false;
+
+ private:
+  static const Attributes kAttributes_;
+  static const AttributesByElement kAttributesByElem_;
+  static const GstCapsBuilder::Recipes kCapsRecipes_;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_H__
diff --git a/src/include_internal/trackrenderer/trackrenderer_attr.h b/src/include_internal/trackrenderer/trackrenderer_attr.h
new file mode 100755 (executable)
index 0000000..96d999e
--- /dev/null
@@ -0,0 +1,130 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_ATTR_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_ATTR_H__
+
+/*
+ * NOTICE
+ * If there is new attribute, please write details in below documents.
+ * 
+ *
+ */
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+enum class Attribute {
+  kVideoQueueMaxByte,           // std::uint64_t
+  kAudioQueueMaxByte,           // std::uint64_t
+  kVideoQueueCurrentLevelByte,  // std::uint64_t
+  kAudioQueueCurrentLevelByte,  // std::uint64_t
+  kVideoMinByteThreshold,       // std::uint32_t
+  kAudioMinByteThreshold,       // std::uint32_t
+  kVideoQueueMaxTime,           // std::uint64_t
+  kAudioQueueMaxTime,           // std::uint64_t
+  kVideoQueueCurrentLevelTime,  // std::uint64_t
+  kAudioQueueCurrentLevelTime,  // std::uint64_t
+  kVideoMinTimeThreshold,       // std::uint32_t
+  kAudioMinTimeThreshold,       // std::uint32_t
+  kVideoSupportRotation,        // std::uint32_t
+  kVideoRenderTimeOffset,       // std::int64_t
+  kAudioRenderTimeOffset,       // std::int64_t
+  kMax,
+};
+
+enum class ValueType {
+  kUnknown,
+  kInt32,
+  kUInt32,
+  kInt64,
+  kUInt64,
+  kMax,
+};
+
+// Trackrenderer configure names
+constexpr char ConfigNameAccurateSeekMode[] = "accurate-seek-mode";
+constexpr char ConfigNameLowLatencyMode[] = "low-latency-mode";
+constexpr char ConfigNameWindowStandAloneMode[] = "window-stand-alone-mode";
+constexpr char ConfigNameVideoFramePeekMode[] = "video-frame-peek-mode";
+constexpr char ConfigNameUnlimitedMaxBufferMode[] = "unlimited-max-buffer-mode";
+constexpr char ConfigNameVideoPreDisplayMode[] = "video-pre-display-mode";
+constexpr char ConfigNameStartRenderingTime[] = "start-rendering-time";
+constexpr char ConfigNameFmmMode[] = "fmm-mode";
+constexpr char ConfigNameAlternativeVideoResource[] =
+    "alternative-video-resource";
+constexpr char ConfigNameVideoDecodingMode[] = "video-decoding-mode";
+constexpr char ConfigNameLateVideoFrameDropMode[] = "late-video-frame-drop-mode";
+
+struct TrackRendererAttrInfo {
+  const ValueType value_type;
+  const plusplayer::trackrenderer::Attribute attr_enum;
+};
+static const std::map<std::string, TrackRendererAttrInfo>
+    kPluginPropertyInfoTable = {
+        {"video-queue-max-byte",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kVideoQueueMaxByte}},
+        {"audio-queue-max-byte",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kAudioQueueMaxByte}},
+        {"video-current-level-byte",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kVideoQueueCurrentLevelByte}},
+        {"audio-current-level-byte",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kAudioQueueCurrentLevelByte}},
+        {"video-min-byte-percent",
+         {ValueType::kUInt32,
+          plusplayer::trackrenderer::Attribute::kVideoMinByteThreshold}},
+        {"audio-min-byte-percent",
+         {ValueType::kUInt32,
+          plusplayer::trackrenderer::Attribute::kAudioMinByteThreshold}},
+        {"video-queue-max-time",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kVideoQueueMaxTime}},
+        {"audio-queue-max-time",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kAudioQueueMaxTime}},
+        {"video-current-level-time",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kVideoQueueCurrentLevelTime}},
+        {"audio-current-level-time",
+         {ValueType::kUInt64,
+          plusplayer::trackrenderer::Attribute::kAudioQueueCurrentLevelTime}},
+        {"video-min-time-percent",
+         {ValueType::kUInt32,
+          plusplayer::trackrenderer::Attribute::kVideoMinTimeThreshold}},
+        {"audio-min-time-percent",
+         {ValueType::kUInt32,
+          plusplayer::trackrenderer::Attribute::kAudioMinTimeThreshold}},
+        {"video-support-rotation",
+         {ValueType::kUInt32,
+          plusplayer::trackrenderer::Attribute::kVideoSupportRotation}},
+        {"video-render-time-offset",
+         {ValueType::kInt64,
+          plusplayer::trackrenderer::Attribute::kVideoRenderTimeOffset}},
+        {"audio-render-time-offset",
+         {ValueType::kInt64,
+          plusplayer::trackrenderer::Attribute::kAudioRenderTimeOffset}}};
+
+static const std::map<std::string, ValueType> kConfigInfoTable = {
+    {ConfigNameAccurateSeekMode, ValueType::kUInt32},
+    {ConfigNameLowLatencyMode, ValueType::kUInt32},
+    {ConfigNameWindowStandAloneMode, ValueType::kUInt32},
+    {ConfigNameVideoFramePeekMode, ValueType::kUInt32},
+    {ConfigNameUnlimitedMaxBufferMode, ValueType::kUInt32},
+    {ConfigNameVideoPreDisplayMode, ValueType::kUInt32},
+    {ConfigNameStartRenderingTime, ValueType::kUInt64},
+    {ConfigNameFmmMode, ValueType::kUInt32},
+    {ConfigNameAlternativeVideoResource, ValueType::kUInt32},
+    {ConfigNameVideoDecodingMode, ValueType::kUInt32},
+    {ConfigNameLateVideoFrameDropMode, ValueType::kUInt32}};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_ATTR_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/trackrenderer_capi_utils.h b/src/include_internal/trackrenderer/trackrenderer_capi_utils.h
new file mode 100755 (executable)
index 0000000..8ad276d
--- /dev/null
@@ -0,0 +1,126 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERERAPI_UTILS_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERERAPI_UTILS_H__
+
+#include <cassert>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "trackrenderer/core/appinfo.h"
+#include "trackrenderer/core/audioeasinginfo.h"
+#include "trackrenderer/core/buffer.h"
+#include "trackrenderer/core/display.h"
+#include "trackrenderer/core/drm.h"
+#include "trackrenderer/core/error.h"
+#include "trackrenderer/core/event.h"
+#include "trackrenderer/core/latency.h"
+#include "trackrenderer/core/picturequality.h"
+#include "trackrenderer/core/subtitle_attr.h"
+#include "trackrenderer/core/track.h"
+#include "trackrenderer/resource.h"
+#include "trackrenderer_capi/buffer.h"
+#include "trackrenderer_capi/decoderinputbuffer.h"
+#include "trackrenderer_capi/display.h"
+#include "trackrenderer_capi/drm.h"
+#include "trackrenderer_capi/error.h"
+#include "trackrenderer_capi/iniproperty.h"
+#include "trackrenderer_capi/latency.h"
+#include "trackrenderer_capi/track.h"
+#include "trackrenderer_capi/trackrenderer_capi.h"
+#include "trackrenderer_capi/trackrenderer_internal.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace capi_utils {
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+TrackRendererSubtitleAttr InitSubtitleAttr();
+#endif
+void MakeDrmProperty(drm::Property* drm_property,
+                     const TrackRendererDrmProperty& properties);
+void MakeGeometry(Geometry* output, const TrackRendererGeometry& input);
+void MakeCropArea(CropArea* output, const TrackRendererCropArea& input);
+void MakeRenderRect(RenderRect* output, const TrackRendererRenderRect& input);
+std::map<std::string, bool> MakeIniProperty(
+    TrackRendererIniProperty* properties, int size);
+std::vector<Track> MakeTrack(const TrackRendererTrack* trackrenderertrack,
+                             const int size);
+std::vector<Track> MakeTrackFromTrackHandle(
+    const TrackRendererTrackHandle* track_handle, const int size);
+void MakeTrackRendererGeometry(TrackRendererGeometry* geometry,
+                               const Geometry& roi);
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+void MakeTrackRendererSubtitleAttr(TrackRendererSubtitleAttr* attr,
+                                   const SubtitleAttr& input_attr);
+#endif
+void MakePlayerAppInfo(const TrackRendererAppInfo* app_attr,
+                       PlayerAppInfo& app_info);
+
+DisplayMode ConvertToDisplayMode(TrackRendererDisplayMode typevalue);
+DisplayRotation ConvertToDisplayRotate(TrackRendererDisplayRotate rotate);
+DisplayType ConvertToDisplayType(const TrackRendererDisplayType typevalue);
+drm::Type ConvertToDrmType(TrackRendererDrmType typevalue);
+StillMode ConvertToStillMode(TrackRendererStillMode typevalue);
+TrackType ConvertToTrackType(const TrackRendererTrackType typevalue);
+
+TrackRendererDisplayMode ConvertToTrackRendererDisplayMode(
+    const DisplayMode& mode);
+TrackRendererDisplayRotate ConvertToTrackRendererDisplayRotate(
+    const DisplayRotation& rotate);
+TrackRendererDisplayType ConvertToTrackRendererDisplayType(
+    const DisplayType& type);
+TrackRendererErrorType ConvertToTrackRendererErrorType(ErrorType type);
+TrackRendererEventType ConvertToTrackRendererEventType(const EventType& event);
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+TrackRendererSubtitleAttrType ConvertToTrackRendererSubtitleAttrType(
+    const SubtitleAttrType& type);
+#endif
+TrackRendererSubtitleType ConvertToTrackRendererSubtitleType(
+    const SubtitleType typevalue);
+TrackRendererTrackType ConvertToTrackRendererTrackType(const TrackType& type);
+
+TrackRendererBufferStatus ConvertToTrackRendererBufferStatus(
+    const BufferStatus& status);
+TrackRendererDecodedVideoPacket ConvertToDecodedVideoPacket(
+    const DecodedVideoPacket& packet);
+DecodedVideoFrameBufferType ConvertToVideoFrameBufferType(
+    const TrackRendererDecodedVideoFrameBufferType& type);
+DecodedVideoFrameBufferType ConvertToVideoFrameBufferTypeExt(
+    const TrackRendererDecodedVideoFrameBufferTypeExt& type);
+
+CatchUpSpeed ConvertToCatchUpSpeed(const TrackRendererCatchUpSpeed& level);
+TrackRendererLatencyStatus ConvertToTrackrendererLatencyStatus(
+    const LatencyStatus& status);
+
+AudioEasingType ConvertToAudioEasingType(
+    const TrackRendererAudioEasingType& type);
+TrackRendererAudioEasingType ConvertToTrackRendererAudioEasingType(
+    const AudioEasingType& type);
+void MakeAudioEasingInfo(AudioEasingInfo* easing_info,
+                         const TrackRendererAudioEasingInfo* easing_attr);
+void MakeTrackRendererAudioEasingInfo(TrackRendererAudioEasingInfo* easing_attr,
+                                      const AudioEasingInfo& easing_info);
+bool ConvertToRscType(const TrackRendererRscType& typevalue, RscType* type);
+bool ConvertToAdvPictureQualityType(
+    const TrackRendererAdvPictureQualityType& typevalue,
+    AdvPictureQualityType* type);
+void MakeRational(Rational* rational_info,
+                  const TrackRendererRational& rational_attr);
+bool ConvertToRscAllocPolicy(const TrackRendererRscAllocPolicy& policyvalue,
+                             RscAllocPolicy* policy);
+bool ConvertToVideoRendererType(
+    const TrackRendererVideoRendererType& renderer_type,
+    ResourceCategory* rsc_category);
+}  // namespace capi_utils
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERERAPI_UTILS_H__
\ No newline at end of file
diff --git a/src/include_internal/trackrenderer/trackrenderer_debug.h b/src/include_internal/trackrenderer/trackrenderer_debug.h
new file mode 100755 (executable)
index 0000000..305c592
--- /dev/null
@@ -0,0 +1,68 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_DEBUG_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_DEBUG_H__
+
+#include <boost/core/noncopyable.hpp>
+
+#include <string>
+#include <vector>
+
+#include "gst/gst.h"
+
+#include "trackrenderer/core/drm.h"
+#include "trackrenderer/core/track.h"
+#include "trackrenderer/core/appinfo.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+/*
+ * Debugging class to display stream information during playback through
+ * InformationTicker(RunningApps) application. ( InformationTicker : display any
+ * information by Wintok to help easier debugging ) How to execute : mute + 1 +
+ * 1 + 4 + mute
+ */
+namespace debug {
+
+struct StreamInfo {
+  const char* v_codec = nullptr;
+  const char* a_codec = nullptr;
+  int v_width = 0;
+  int v_height = 0;
+  int bitrate = 0;
+  drm::Type drm_type = drm::Type::kNone;
+  float fps = 0;
+};
+
+class PlayinfoSetter : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<PlayinfoSetter>;
+  static Ptr Create();
+
+ public:
+  virtual ~PlayinfoSetter() {}
+
+  virtual void SetAppInfo(const PlayerAppInfo& app_info) = 0;
+  virtual bool SetStreamInfo(GstCaps* v_sink_caps, GstCaps* v_decoder_caps,
+                             GstCaps* a_decoder_caps,
+                             const std::vector<Track>& tracks,
+                             drm::Type drm_type) = 0;
+  virtual void VconfSetMsgShow() = 0;
+  virtual void VconfSetMsgUpdate() = 0;
+  virtual void VconfSetMsgHide() = 0;
+
+ protected:
+  PlayinfoSetter() noexcept {}
+};
+
+}  // namespace debug
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_TRACKRENDERER_DEBUG_H__
diff --git a/src/include_internal/trackrenderer/trackrenderer_vconf.h b/src/include_internal/trackrenderer/trackrenderer_vconf.h
new file mode 100755 (executable)
index 0000000..ef0ae23
--- /dev/null
@@ -0,0 +1,72 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_VCONF_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_VCONF_H__
+
+#include <boost/core/noncopyable.hpp>
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+#include <mutex>
+#include <vector>
+
+#include "vconf.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+constexpr char kMultiscreenInfoVconf[] = "memory/multiscreen/info";
+constexpr char kPowerAnimationVconf[] = "memory/welcome_mode/power_animation";
+constexpr char kTV2MobileStateVconf[] =
+    "memory/menu/network/screenmirroring/smsrc_status";
+
+typedef void (*vconf_cb)(const std::string& name, const std::string& value,
+                         void* userdata);
+
+class Vconf : private boost::noncopyable {
+ public:
+  using VconfPair = std::pair<vconf_cb, void*>;
+  using VconfCbList = std::list<VconfPair>;
+  using VconfMap = std::map<std::string, VconfCbList>;
+
+  Vconf(Vconf const&) = delete;
+  Vconf(Vconf&&) = delete;
+  Vconf& operator=(Vconf const&) = delete;
+  Vconf& operator=(Vconf&&) = delete;
+
+  static Vconf& Instance() {
+    static Vconf instance;
+    return instance;
+  }
+
+  bool IsMultiscreenMode();
+  void SetVconfsCb(const std::vector<std::string>& names,
+                   vconf_cb callback, void* userdata);
+  void UnsetVconfsCb(const std::vector<std::string>& names,
+                     vconf_cb callback, void* userdata);
+
+ private:
+  Vconf();
+  ~Vconf();
+  void SetVconfCb_(const std::string& name, vconf_cb callback,
+                   void* userdata);
+  void UnsetVconfCb_(const std::string& name, vconf_cb callback,
+                     void* userdata);
+  static void VconfCb_(keynode_t* key, void* userdata);
+  void Notify_(const std::string& name, const std::string& value);
+  bool ParseMlsVconf_(const char* json);
+
+ private:
+  std::mutex vconf_m_;
+  VconfMap vconf_map_;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_VCONF_H__
diff --git a/src/include_internal/trackrenderer/version.h b/src/include_internal/trackrenderer/version.h
new file mode 100755 (executable)
index 0000000..1b80e65
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_VERSION_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_VERSION_H__
+
+#define TRACKRENDERER_VERSION_INT(a, b, c) ((a) << 16 | (b) << 8 | (c))
+#define TRACKRENDERER_VERSION_DOT(a, b, c) a ##.## b ##.## c
+#define TRACKRENDERER_VERSION(a, b, c) TRACKRENDERER_VERSION_DOT(a, b, c)
+
+/**
+ * @brief  Get version components from the full ::TRACKRENDERER_VERSION_INT int
+ */
+#define TRACKRENDERER_GET_VERSION_MAJOR(a) ((a) >> 16)
+#define TRACKRENDERER_GET_VERSION_MINOR(a) (((a)&0x00FF00) >> 8)
+#define TRACKRENDERER_GET_VERSION_MICRO(a) ((a)&0xFF)
+
+#define LIB_TRACKRENDERER_VERSION_MAJOR 0
+#define LIB_TRACKRENDERER_VERSION_MINOR 0
+#define LIB_TRACKRENDERER_VERSION_MICRO 2
+
+#define LIB_TRACKRENDERER_VERSION_INT                        \
+  TRACKRENDERER_VERSION_INT(LIB_TRACKRENDERER_VERSION_MAJOR, \
+                            LIB_TRACKRENDERER_VERSION_MINOR, \
+                            LIB_TRACKRENDERER_VERSION_MICRO)
+
+#define LIB_TRACKRENDERER_VERSION                        \
+  TRACKRENDERER_VERSION(LIB_TRACKRENDERER_VERSION_MAJOR, \
+                        LIB_TRACKRENDERER_VERSION_MINOR, \
+                        LIB_TRACKRENDERER_VERSION_MICRO)
+
+#define TRACKRENDERER_STRINGIFY(s) TRACKRENDERER_TOSTRING(s)
+#define TRACKRENDERER_TOSTRING(s) #s
+
+#endif  //  __PLUSPLAYER_SRC_TRACKRENDERER_VERSION_H__
diff --git a/src/include_internal/trackrenderer/vr360.h b/src/include_internal/trackrenderer/vr360.h
new file mode 100755 (executable)
index 0000000..6de8958
--- /dev/null
@@ -0,0 +1,41 @@
+//
+// @ Copyright [2021] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKRENDERER_VR360_POLICY_H__
+#define __PLUSPLAYER_SRC_TRACKRENDERER_VR360_POLICY_H__
+
+#include <boost/core/noncopyable.hpp>
+#include <string>
+#include <utility>
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+using Vr360TzHandle = void *;
+using Vr360Initialize = int (*)(Vr360TzHandle *handle);
+using Vr360Finalize = int (*)(Vr360TzHandle handle);
+using Vr360SetGpuMode = int (*)(Vr360TzHandle handle, int mode);
+
+class Vr360 : private boost::noncopyable {
+ public:
+  enum class GpuMode {
+    kVr360GpuModeSecure = 0x301, /**< Give GPU secure property */
+    kVr360GpuModeNonSecure,      /**< Take secure property from GPU */
+  };
+
+  explicit Vr360();
+  ~Vr360();
+
+  void Vr360TzSetGpuMode(bool set);
+
+ private:
+  Vr360TzHandle vr360_tz_handle_ = nullptr;
+};
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKRENDERER_VR360_POLICY_H__
\ No newline at end of file
diff --git a/src/latency_manager.cpp b/src/latency_manager.cpp
new file mode 100755 (executable)
index 0000000..6d94732
--- /dev/null
@@ -0,0 +1,295 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <cassert>
+
+#include "trackrenderer/core/utils/log.h"
+#include "trackrenderer/latency_manager.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+LatencyManager::LatencyManager(LatencyStatusListener* listener)
+    : event_listener_(listener) {
+  assert(listener && "listener is nullptr!!");
+}
+
+LatencyManager::~LatencyManager() {
+  if (latency_checker_task_.valid()) {
+    is_stopped_ = true;
+    latency_checker_task_.wait();
+  }
+  TRACKRENDERER_INFO("Bye~");
+}
+
+void LatencyManager::SetVideoMidLatencyThreshold(const unsigned int threshold) {
+  video_mid_latency_threshold_ = threshold;
+  TRACKRENDERER_INFO("Video MidLatencyThreshold : %d",
+                     video_mid_latency_threshold_);
+  checker_precondition_.set(
+      static_cast<int>(CheckerPrecondition::kSetThreshold));
+  StartLatencyChecker_();
+}
+
+void LatencyManager::SetAudioMidLatencyThreshold(const unsigned int threshold) {
+  audio_mid_latency_threshold_ = threshold;
+  TRACKRENDERER_INFO("Audio MidLatencyThreshold : %d",
+                     audio_mid_latency_threshold_);
+  checker_precondition_.set(
+      static_cast<int>(CheckerPrecondition::kSetThreshold));
+  StartLatencyChecker_();
+}
+
+void LatencyManager::SetVideoHighLatencyThreshold(
+    const unsigned int threshold) {
+  video_high_latency_threshold_ = threshold;
+  TRACKRENDERER_INFO("Video HighLatencyThreshold : %d",
+                     video_high_latency_threshold_);
+  checker_precondition_.set(
+      static_cast<int>(CheckerPrecondition::kSetThreshold));
+  StartLatencyChecker_();
+}
+
+void LatencyManager::SetAudioHighLatencyThreshold(
+    const unsigned int threshold) {
+  audio_high_latency_threshold_ = threshold;
+  TRACKRENDERER_INFO("Audio HighLatencyThreshold : %d",
+                     audio_high_latency_threshold_);
+  checker_precondition_.set(
+      static_cast<int>(CheckerPrecondition::kSetThreshold));
+  StartLatencyChecker_();
+}
+
+void LatencyManager::SetCatchUpSpeed(const CatchUpSpeed& level) {
+  speed_level_ = level;
+
+  if (pipeline_) {
+    if (speed_level_ != CatchUpSpeed::kNone) {
+      int drop_rate = CalculateDropRate_();
+      pipeline_->SetProperty(Elements::kSinkVideo, "frame-drop-rate",
+                             drop_rate);
+      pipeline_->SetProperty(Elements::kSinkAudio, "frame-drop-rate",
+                             drop_rate);
+    }
+  }
+}
+
+void LatencyManager::GetVideoLatencyStatus(LatencyStatus* status) {
+  *status = video_latency_status_;
+  TRACKRENDERER_INFO("LatencyStatus is %d", static_cast<int>(*status));
+}
+
+void LatencyManager::GetAudioLatencyStatus(LatencyStatus* status) {
+  *status = audio_latency_status_;
+  TRACKRENDERER_INFO("LatencyStatus is %d", static_cast<int>(*status));
+}
+
+void LatencyManager::SetPipeline(Pipeline<Elements>* pipeline) {
+  if (pipeline_) {
+    assert(0 && "pipeline already exist");
+  }
+  pipeline_ = pipeline;
+  checker_precondition_.set(
+      static_cast<int>(CheckerPrecondition::kSetPipeline));
+  StartLatencyChecker_();
+}
+
+void LatencyManager::UnsetPipeline() {
+  TRACKRENDERER_ENTER;
+  is_stopped_ = true;
+  checker_precondition_.reset(
+      static_cast<int>(CheckerPrecondition::kSetPipeline));
+  std::lock_guard<std::mutex> mutex(pipeline_m_);
+  pipeline_ = nullptr;
+  TRACKRENDERER_LEAVE;
+}
+
+void LatencyManager::UpdateVideoFrameStatus(
+    LatencyManager::UpdatePacketStatus status) {
+  switch (status) {
+    case LatencyManager::UpdatePacketStatus::kFlush:
+      TRACKRENDERER_INFO("Flush, reset the value!");
+      submitted_video_frames_ = 0;
+      return;
+    case LatencyManager::UpdatePacketStatus::kSubmit:
+      ++submitted_video_frames_;
+      return;
+    default:
+      TRACKRENDERER_ERROR("Wrong status:%d", static_cast<int>(status));
+  }
+}
+
+void LatencyManager::StartLatencyChecker_() {
+  TRACKRENDERER_ENTER;
+  std::bitset<static_cast<int>(CheckerPrecondition::kMax)> precondition;
+  precondition.set();
+
+  if (precondition != checker_precondition_) {
+    TRACKRENDERER_INFO("Can't make checker thread, precondition = %s",
+                       checker_precondition_.to_string().c_str());
+    return;
+  }
+
+  if (latency_checker_task_.valid()) {
+    TRACKRENDERER_INFO("checker task is already valid");
+    return;
+  }
+
+  pipeline_->SetProperty(Elements::kAppSrcAudio, "noqueue", FALSE);
+  pipeline_->SetProperty(Elements::kAppSrcAudio, "max-bytes", 0);
+
+  if (speed_level_ != CatchUpSpeed::kNone) {
+    int drop_rate = CalculateDropRate_();
+    pipeline_->SetProperty(Elements::kSinkVideo, "frame-drop-rate", drop_rate);
+    pipeline_->SetProperty(Elements::kSinkAudio, "frame-drop-rate", drop_rate);
+  }
+
+  latency_checker_task_ = std::async(
+      std::launch::async, &LatencyManager::LatencyCheckerTask_, this);
+  if (!latency_checker_task_.valid()) {
+    TRACKRENDERER_ERROR("checker task is Not valid");
+    return;
+  }
+  TRACKRENDERER_LEAVE;
+}
+
+void LatencyManager::LatencyCheckerTask_() {
+  TRACKRENDERER_ENTER;
+  while (!is_stopped_) {
+    std::unique_lock<std::mutex> mutex(pipeline_m_);
+    if (pipeline_ == nullptr) return;
+
+    uint consumed_frames = 0;
+    bool ret = pipeline_->GetProperty(Elements::kSinkVideo, "consumed-frames",
+                                      &consumed_frames);
+    int video_latency = submitted_video_frames_ - consumed_frames;
+    if (video_latency < 0) {
+      TRACKRENDERER_ERROR(
+          "ERROR!! consumed_frames = %u, submitted_video_frames_ = %u",
+          consumed_frames, submitted_video_frames_);
+      video_latency = 0;
+    }
+    if (ret == true) HandleVideoLatency_(video_latency);
+
+    uint audio_latency = 0;
+    ret = pipeline_->GetProperty(Elements::kAppSrcAudio, "frame-count",
+                                 &audio_latency);
+    if (ret == true) HandleAudioLatency_(audio_latency);
+    mutex.unlock();
+
+    // TODO: How to set the sleep time.
+    std::this_thread::sleep_for(std::chrono::milliseconds(50));
+  }
+  TRACKRENDERER_LEAVE;
+}
+
+void LatencyManager::HandleVideoLatency_(const unsigned int video_latency) {
+  if (is_stopped_) return;
+
+  LatencyStatus prev_video_latency_status_ = video_latency_status_;
+  video_latency_status_ = GetVideoLatencyStatus_(video_latency);
+  bool is_status_changed =
+      video_latency_status_ != prev_video_latency_status_ ? true : false;
+
+  if (is_status_changed) {
+    event_listener_->OnVideoLatencyStatus(video_latency_status_);
+    if (video_latency_status_ == LatencyStatus::kHigh)  // To be deleted. later.
+      event_listener_->OnVideoHighLatency();
+
+    if (prev_video_latency_status_ == LatencyStatus::kLow) {
+      pipeline_->SetProperty(Elements::kSinkVideo, "is-catchup-mode", TRUE);
+    } else if (video_latency_status_ == LatencyStatus::kLow) {
+      pipeline_->SetProperty(Elements::kSinkVideo, "is-catchup-mode", FALSE);
+    }
+  }
+}
+
+void LatencyManager::HandleAudioLatency_(const unsigned int audio_latency) {
+  if (is_stopped_) return;
+
+  LatencyStatus prev_audio_latency_status_ = audio_latency_status_;
+  audio_latency_status_ = GetAudioLatencyStatus_(audio_latency);
+  bool is_status_changed =
+      audio_latency_status_ != prev_audio_latency_status_ ? true : false;
+
+  if (is_status_changed) {
+    event_listener_->OnAudioLatencyStatus(audio_latency_status_);
+    if (audio_latency_status_ == LatencyStatus::kHigh)  // To be deleted. later.
+      event_listener_->OnAudioHighLatency();
+
+    if (prev_audio_latency_status_ == LatencyStatus::kLow) {
+      pipeline_->SetProperty(Elements::kSinkAudio, "is-catchup-mode", TRUE);
+    } else if (audio_latency_status_ == LatencyStatus::kLow) {
+      pipeline_->SetProperty(Elements::kSinkAudio, "is-catchup-mode", FALSE);
+    }
+  }
+}
+
+int LatencyManager::CalculateDropRate_() {
+  int ret = 0;
+  if (speed_level_ == CatchUpSpeed::kSlow) {
+    // TODO
+    ret = 4;
+  } else if (speed_level_ == CatchUpSpeed::kMid) {
+    // TODO
+    ret = 3;
+  } else {
+    // TODO
+    ret = 2;
+  }
+  return ret;
+}
+
+LatencyStatus LatencyManager::GetVideoLatencyStatus_(
+    const unsigned int latency) {
+  TRACKRENDERER_DEBUG(
+      "Latency : %d, video_mid_latency_threshold : %d, "
+      "video_high_latency_threshold : %d",
+      latency, video_mid_latency_threshold_, video_high_latency_threshold_);
+
+  if (video_mid_latency_threshold_ == UINT32_MAX) {
+    if (latency < video_high_latency_threshold_) {
+      return LatencyStatus::kLow;
+    } else {
+      return LatencyStatus::kHigh;
+    }
+  }
+
+  if (latency < video_mid_latency_threshold_) {
+    return LatencyStatus::kLow;
+  } else if (latency >= video_high_latency_threshold_) {
+    return LatencyStatus::kHigh;
+  } else {
+    return LatencyStatus::kMid;
+  }
+}
+
+LatencyStatus LatencyManager::GetAudioLatencyStatus_(
+    const unsigned int latency) {
+  TRACKRENDERER_DEBUG(
+      "Latency : %d, audio_mid_latency_threshold : %d, "
+      "audio_high_latency_threshold : %d",
+      latency, audio_mid_latency_threshold_, audio_high_latency_threshold_);
+
+  if (audio_mid_latency_threshold_ == UINT32_MAX) {
+    if (latency < audio_high_latency_threshold_) {
+      return LatencyStatus::kLow;
+    } else {
+      return LatencyStatus::kHigh;
+    }
+  }
+
+  if (latency < audio_mid_latency_threshold_) {
+    return LatencyStatus::kLow;
+  } else if (latency >= audio_high_latency_threshold_) {
+    return LatencyStatus::kHigh;
+  } else {
+    return LatencyStatus::kMid;
+  }
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/pipeline.cpp b/src/pipeline.cpp
new file mode 100755 (executable)
index 0000000..8bffef6
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/pipeline.hpp"
+
+#include <dlfcn.h>
+
+#include <cassert>
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace trustzone {
+
+#define GSTREAMER_PLUGIN_LIB(NAME) "/usr/lib/gstreamer-1.0/" #NAME
+
+static std::once_flag lib_loaded;
+static void* tzappsrc_lib = nullptr;
+using TzAppsrcPushBuffer = int(*)(void* appsrc, void* buffer);
+static TzAppsrcPushBuffer tz_appsrc_push_buffer;
+
+bool InitTzAppsrc() {
+  bool retval = true;
+  auto loadlib = [](bool& ret) {
+    tzappsrc_lib = dlopen(GSTREAMER_PLUGIN_LIB(libgsttzappsrc.so), RTLD_LAZY);
+    if (!tzappsrc_lib) {
+      TRACKRENDERER_ERROR("libgsttzappsrc.so open failed: %s", dlerror());
+      assert(0);
+      ret = false;
+      return;
+    }
+    tz_appsrc_push_buffer =
+        (TzAppsrcPushBuffer)dlsym(tzappsrc_lib, "gst_tz_app_src_push_buffer");
+    if (!tz_appsrc_push_buffer) {
+      TRACKRENDERER_ERROR("Failed to import gst_tz_app_src_push_buffer");
+      assert(0);
+      ret = false;
+      return;
+    }
+  };
+  std::call_once(lib_loaded, loadlib, retval);
+  return retval;
+}
+
+bool GstAppsrcPushBuffer(GstElement* appsrc, GstBuffer* buffer) {
+  if(tz_appsrc_push_buffer(appsrc,buffer) != GST_FLOW_OK) {
+    return false;
+  }
+  return true;
+}
+
+} // namespace trustzone
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/resourcemanager.cpp b/src/resourcemanager.cpp
new file mode 100755 (executable)
index 0000000..38853a5
--- /dev/null
@@ -0,0 +1,715 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/resourcemanager.h"
+
+#include <stdlib.h>  //  free
+
+#include <algorithm>  // std::min
+#include <boost/scope_exit.hpp>
+#include <cassert>  //  assert()
+#include <chrono>   // std::chrono
+#include <functional>
+#include <map>        // std::map
+#include <stdexcept>  // std::out_of_range
+#include <thread>     // std::this_thread::sleep_for
+#include <unordered_map>
+
+#include "resource_center.h"
+#include "ri-api.h"
+#include "ri-module-api.h"
+#include "rm_module_api.h"
+#include "trackrenderer/core/utils/log.h"
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace internal {
+
+constexpr int kMaxFrameRate = 60;
+constexpr int kDefaultColorDepth = 8;
+constexpr int kDefaultSamplingFormat = 1;
+
+// clang-format off
+const std::map<std::string, std::string> MimeTypetoCodecNameConverter = {
+    {"video/x-h264", "H264"},       {"video/x-h265", "HEVC"},
+    {"video/mpeg1", "MPEG1"},       {"video/mpeg2", "MPEG2"},
+    {"video/mpeg4", "MPEG4"},       {"video/x-msmpeg", "MPEG4"},
+    {"video/x-wmv", "WMV"},         {"video/x-h263", "H263"},
+    {"video/x-pn-realvideo", "RV"}, {"video/x-vp8", "VP8"},
+    {"video/x-vp9", "VP9"},         {"video/x-divx", "MPEG4"},
+    {"video/x-xvid", "MPEG4"},      {"video/x-3ivx", "MPEG4"},
+    {"video/x-avs", "AVS"},         {"video/x-avs+", "AVS+"},
+    {"video/x-jpeg", "MJPEG"},      {"video/x-av1", "AV1"},
+    {"video/x-h264_tz", "H264"},
+    {"video/x-h265_tz", "HEVC"},    {"video/mpeg1_tz", "MPEG1"},
+    {"video/mpeg2_tz", "MPEG2"},    {"video/mpeg4_tz", "MPEG4"},
+    {"video/x-msmpeg_tz", "MPEG4"}, {"video/x-wmv_tz", "WMV"},
+    {"video/x-h263_tz", "H263"},    {"video/x-pn-realvideo_tz", "RV"},
+    {"video/x-vp8_tz", "VP8"},      {"video/x-vp9_tz", "VP9"},
+    {"video/x-divx_tz", "MPEG4"},   {"video/x-xvid_tz", "MPEG4"},
+    {"video/x-3ivx_tz", "MPEG4"},   {"video/x-avs_tz", "AVS"},
+    {"video/x-avs+_tz", "AVS+"},    {"video/x-jpeg_tz", "MJPEG"},
+    {"video/x-av1_tz", "AV1"},
+
+    {"audio/mpeg", "MPEG"},         {"audio/x-aac", "AAC"},
+    {"audio/x-true-hd", "TrueHD"},  {"audio/x-ac3", "AC3"},
+    {"audio/x-eac3", "E-AC3"},      {"audio/ac3", "AC3"},
+    {"audio/x-ac4", "AC4"},         {"audio/x-adpcm", "ADPCM"},
+    {"audio/x-wma", "WMA"},         {"audio/x-vorbis", "Vorbis"},
+    {"audio/x-gst-fourcc-mha1", "MPEG-H"},{"audio/x-pn-realaudio", "G2Cook"},
+    {"audio/x-gst-fourcc-mhm1", "MPEG-H"},{"audio/x-opus", "OPUS"},
+    {"audio/x-alaw", "ALAW"},      {"audio/x-mulaw", "MULAW"},
+    {"audio/mpeg_tz", "MPEG"},      {"audio/x-aac_tz", "AAC"},
+    {"audio/x-ac3_tz", "AC3"},      {"audio/x-eac3_tz", "E-AC3"},
+    {"audio/ac3_tz", "AC3"},        {"audio/x-ac4_tz", "AC4"},
+    {"audio/x-adpcm_tz", "ADPCM"},  {"audio/x-wma_tz", "WMA"},
+    {"audio/x-vorbis_tz", "Vorbis"},{"audio/x-pn-realaudio_tz", "G2Cook"},
+    {"audio/x-gst-fourcc-mha1_tz", "MPEG-H"},{"audio/x-raw_tz", "PCM"},
+    {"audio/x-gst-fourcc-mhm1_tz", "MPEG-H"},{"audio/x-opus_tz", "OPUS"},
+    {"audio/x-alaw_tz", "ALAW"},      {"audio/x-mulaw_tz", "MULAW"},
+};
+// clang-format on
+
+const std::map<ResourceCategory, rm_rsc_category_e> TypeToCategoryConverter = {
+    {ResourceCategory::kVideoDecoder, RM_CATEGORY_VIDEO_DECODER},
+    {ResourceCategory::kVideoDecoderSub, RM_CATEGORY_VIDEO_DECODER_SUB},
+    {ResourceCategory::kVideoRenderer, RM_CATEGORY_SCALER},
+    {ResourceCategory::kVideoRendererSub, RM_CATEGORY_SCALER_SUB},
+    {ResourceCategory::kVideoRendererSub2, RM_CATEGORY_SCALER_SUB2},
+    {ResourceCategory::kVideoRendererSub3, RM_CATEGORY_SCALER_SUB3},
+    {ResourceCategory::kAudioDecoder, RM_CATEGORY_AUDIO_DECODER},
+    {ResourceCategory::kAudioDecoderSub, RM_CATEGORY_AUDIO_DECODER_SUB},
+    {ResourceCategory::kAudioRenderer, RM_CATEGORY_AUDIO_MAIN_OUT},
+    {ResourceCategory::kAudioRendererSub, RM_CATEGORY_AUDIO_SUB_OUT}};
+
+const std::map<ResourceCategory, rm_rsc_category_e>
+    MultiviewTypeToCategoryConverter = {
+        {ResourceCategory::kVideoDecoder, RM_CATEGORY_VIDEO_DECODER},
+        {ResourceCategory::kVideoDecoderSub, RM_CATEGORY_VIDEO_DECODER},
+        {ResourceCategory::kVideoRenderer, RM_CATEGORY_SCALER},
+        {ResourceCategory::kVideoRendererSub, RM_CATEGORY_SCALER},
+        {ResourceCategory::kVideoRendererSub2, RM_CATEGORY_SCALER},
+        {ResourceCategory::kVideoRendererSub3, RM_CATEGORY_SCALER},
+        {ResourceCategory::kAudioDecoder, RM_CATEGORY_AUDIO_DECODER},
+        {ResourceCategory::kAudioDecoderSub, RM_CATEGORY_AUDIO_DECODER},
+        {ResourceCategory::kAudioRenderer, RM_CATEGORY_AUDIO_MAIN_OUT},
+        {ResourceCategory::kAudioRendererSub, RM_CATEGORY_AUDIO_MAIN_OUT}};
+
+const std::map<RscAllocPolicy, rm_requests_resource_state_e>
+    TypeToResourceStateConverter = {
+        {RscAllocPolicy::kRscAllocExclusive, RM_STATE_EXCLUSIVE},
+        {RscAllocPolicy::kRscAllocConditional, RM_STATE_EXCLUSIVE_CONDITIONAL}};
+
+const std::string GetVideoCodecName(const ResourceProperty& property) {
+  try {
+    std::string mime_type = property.track.mimetype;
+    const std::string video_mpeg = "video/mpeg";
+    if (mime_type.find(video_mpeg) != std::string::npos)
+      mime_type.insert(video_mpeg.size(),
+                       std::to_string(property.track.version));
+    std::string codec_name = MimeTypetoCodecNameConverter.at(mime_type);
+    if (property.is_vr360) {
+      codec_name.append("_VR360");
+    }
+    return codec_name;
+  } catch (const std::out_of_range& oor) {
+    TRACKRENDERER_ERROR(" Unknown mimetype [%s] ",
+                        property.track.mimetype.c_str());
+    return "";
+  }
+}
+
+const std::string GetAudioCodecName(const ResourceProperty& property) {
+  try {
+    std::string mime_type = property.track.mimetype;
+    std::string codec_name = MimeTypetoCodecNameConverter.at(mime_type);
+    if (property.track.version > 1) {
+      codec_name = "AAC";
+      // TODO: Need to check "stream-format" info according to mmplayer logic.
+      // codec_name should be changed to "HE-AAC" if "stream-format" is "loas".
+    }
+    return codec_name;
+  } catch (const std::out_of_range& oor) {
+    TRACKRENDERER_ERROR(" Unknown mimetype [%s] ",
+                        property.track.mimetype.c_str());
+    return "";
+  }
+}
+
+double GetFramerate(const int& framerate_num, const int& framerate_den) {
+  int framerate = 0;
+  if (framerate_num > 0 && framerate_den > 0) {
+    framerate = framerate_num / framerate_den;
+  } else {
+    framerate = kMaxFrameRate;
+    return framerate;
+  }
+
+  framerate = std::min(framerate, kMaxFrameRate);
+  return framerate;
+}
+
+int GetWidth(const Track& trackinfo) {
+  return trackinfo.maxwidth ? trackinfo.maxwidth : trackinfo.width;
+  // TODO(euna7.ko) should i check if value is 0 ?
+  // mm get the value from caps. if value is 0, mm set the valeu to HD
+  // resolution.
+}
+
+int GetHeight(const Track& trackinfo) {
+  return trackinfo.maxheight ? trackinfo.maxheight : trackinfo.height;
+}
+
+inline bool OverFHD(const int width, const int height) {
+  return (width > kMaxFhdWidth || height > kMaxFhdHeight) ? true : false;
+}
+
+int GetExplicitDecoderOption(const ResourceProperty& property) {
+  constexpr int kAuto = 0;
+  if (property.is_multiview) return kAuto;
+  if (property.category == ResourceCategory::kVideoDecoder ||
+      property.category == ResourceCategory::kAudioDecoder)
+    return RM_DEVICE_OPT_MAIN;
+  else if (property.category == ResourceCategory::kVideoDecoderSub ||
+           property.category == ResourceCategory::kAudioDecoderSub)
+    return RM_DEVICE_OPT_SUB;
+
+  return kAuto;
+}
+
+int GetVideoDecCategoryOption(const ResourceProperty& property) {
+  int category_option = RM_CATEGORY_NONE;
+  int width = internal::GetWidth(property.track);
+  int height = internal::GetHeight(property.track);
+
+  ri_video_category_option_request_s opt;
+  memset(&opt, 0, sizeof(ri_video_category_option_request_s));
+  std::string codecname = GetVideoCodecName(property);
+  if (codecname.empty()) return RI_ERROR;
+  opt.codec_name = codecname.c_str();
+  opt.color_depth = kDefaultColorDepth;
+  opt.h_size = width;
+  opt.v_size = height;
+  opt.framerate = (int)GetFramerate(property.track.framerate_num,
+                                    property.track.framerate_den);
+  opt.sampling_format = kDefaultSamplingFormat;
+  if (property.is_ndecoding) {
+    category_option = (ri_get_n_decoder_category_id(&opt));
+    TRACKRENDERER_INFO(
+        " request n decoder codec_name %s, with : %d, height : %d  category "
+        "option %d",
+        opt.codec_name, opt.h_size, opt.v_size, category_option);
+  } else {
+    category_option = ri_get_capable_video_category_id(&opt);
+  }
+  if (OverFHD(width, height) || property.is_ndecoding) return category_option;
+  int explicit_device = GetExplicitDecoderOption(property);
+  category_option |= explicit_device;
+  return category_option;
+}
+
+// LCOV_EXCL_START
+int GetVideoJpegDecCategoryOption(const ResourceProperty& property) {
+  std::string codecname = GetVideoCodecName(property);
+  if (codecname.empty()) return RI_ERROR;
+  int width = internal::GetWidth(property.track);
+  int height = internal::GetHeight(property.track);
+  int category_option = ri_get_jpeg_category_id(codecname.c_str(), width);
+  if (OverFHD(width, height)) return category_option;
+
+  int explicit_device = GetExplicitDecoderOption(property);
+  category_option |= explicit_device;
+  return category_option;
+}
+// LCOV_EXCL_STOP
+
+int GetAudioDecCategoryOption(const ResourceProperty& property) {
+  ri_audio_category_option_request_s opt;
+  memset(&opt, 0, sizeof(ri_audio_category_option_request_s));
+  std::string codecname = GetAudioCodecName(property);
+  if (codecname.empty()) return RI_ERROR;
+  opt.codec_name = codecname.c_str();
+  if (property.is_dual_sound) opt.mixing_mode = RI_MIXING_MODE_MULTIVIEW;
+
+  int explicit_device = GetExplicitDecoderOption(property);
+  int category_option =
+      (ri_get_capable_audio_category_id(&opt) | explicit_device);
+  return category_option;
+}
+
+int GetScalerCategoryOption(const ResourceProperty& property) {
+  constexpr int kAutoScaler = RM_CATEGORY_SCALER;
+  int explicit_device = internal::TypeToCategoryConverter.at(property.category);
+  int category_option = property.is_multiview ? kAutoScaler : explicit_device;
+  return category_option;
+}
+
+int GetAudioOutCategoryOption(const ResourceProperty& property) {
+  constexpr int kAutoAudioOut = RM_CATEGORY_AUDIO_MAIN_OUT;
+  int explicit_device = internal::TypeToCategoryConverter.at(property.category);
+  int category_option = property.is_multiview ? kAutoAudioOut : explicit_device;
+  return category_option;
+}
+
+rm_rsc_category_e GetCategoryID(const ResourceProperty& property) {
+  rm_rsc_category_e category_id;
+  if (property.is_multiview)
+    category_id =
+        internal::MultiviewTypeToCategoryConverter.at(property.category);
+  else
+    category_id = internal::TypeToCategoryConverter.at(property.category);
+
+  if (property.track.type == kTrackTypeVideo) {
+    if (GetVideoCodecName(property) == "MJPEG") {
+      return RM_CATEGORY_MJPEG_DECODER;
+    }
+  }
+  return category_id;
+}
+
+bool TryAlloc(ResourceManagerHandle rmhandle, const rm_category_request_s& req,
+              rm_device_return_s* devices) {
+  int try_count = 5;
+  bool ret = false;
+  while (try_count--) {
+    int rm_ret = rm_allocate_resources(rmhandle, &req, devices);
+    if (rm_ret == RM_ERROR) {
+      TRACKRENDERER_ERROR("rm_allocate_resources fail[RM_ERROR]");
+      break;
+    } else if (rm_ret == RM_OK) {
+      ret = true;
+      break;
+    }
+    TRACKRENDERER_ERROR("rm_allocate_resources failed rm_ret[%d]", rm_ret);
+    TRACKRENDERER_ERROR("retry_count[%d]", try_count);
+    std::this_thread::sleep_for(std::chrono::milliseconds(15));
+  }
+  if (devices->device_id[0] == 0 || devices->omx_comp_name[0] == nullptr) {
+    TRACKRENDERER_ERROR("device id or comp name error");
+    ret = false;
+  }
+  return ret;
+}
+
+bool NeedSwDecoderResource(const ResourceProperty& property) {
+  if (property.category != ResourceCategory::kVideoDecoder &&
+      property.category != ResourceCategory::kVideoDecoderSub &&
+      property.category != ResourceCategory::kAudioDecoder &&
+      property.category != ResourceCategory::kAudioDecoderSub)
+    return false;
+  if (property.use_sw) return true;
+  return false;
+}
+
+/*
+ * ResourceManager handle will be saved in rsc_list after
+ * ResourceManager created which will be removed before
+ * the handle released in ~ResourceManager(). rsc_lock is to
+ * protect that ResourceManager handle is valid if resource
+ * conflict happens before trackrenderer handle released.
+ */
+static std::mutex rsc_lock;
+static std::list<ResourceManager*> rsc_list;
+
+void AddRMHandle(ResourceManager* handle) {
+  TRACKRENDERER_INFO("Resource manager handle[%p]", handle);
+  std::lock_guard<std::mutex> lock(rsc_lock);
+  rsc_list.push_back(handle);
+}
+
+void RemoveRMHandle(ResourceManager* handle) {
+  TRACKRENDERER_INFO("Resource manager handle[%p]", handle);
+  std::lock_guard<std::mutex> lock(rsc_lock);
+  auto iter = find(rsc_list.begin(), rsc_list.end(), handle);
+  if (iter != rsc_list.end()) {
+    rsc_list.erase(iter);
+  } else {
+    TRACKRENDERER_ERROR("Invalid handle[%p]", handle);
+  }
+}
+
+using CategoryOption = std::function<int(const ResourceProperty& property)>;
+static std::unordered_map<rm_rsc_category_e, CategoryOption> CategoryOptionMap =
+    {{RM_CATEGORY_VIDEO_DECODER, internal::GetVideoDecCategoryOption},
+     {RM_CATEGORY_VIDEO_DECODER_SUB, internal::GetVideoDecCategoryOption},
+     {RM_CATEGORY_MJPEG_DECODER, internal::GetVideoJpegDecCategoryOption},
+     {RM_CATEGORY_SCALER, internal::GetScalerCategoryOption},
+     {RM_CATEGORY_SCALER_SUB, internal::GetScalerCategoryOption},
+     {RM_CATEGORY_SCALER_SUB2, internal::GetScalerCategoryOption},
+     {RM_CATEGORY_SCALER_SUB3, internal::GetScalerCategoryOption},
+     {RM_CATEGORY_AUDIO_DECODER, internal::GetAudioDecCategoryOption},
+     {RM_CATEGORY_AUDIO_DECODER_SUB, internal::GetAudioDecCategoryOption},
+     {RM_CATEGORY_AUDIO_MAIN_OUT, internal::GetAudioOutCategoryOption},
+     {RM_CATEGORY_AUDIO_SUB_OUT, internal::GetAudioOutCategoryOption}};
+
+}  // namespace internal
+
+ResourceManager::ResourceManager(ResourceConflictListener* listener)
+    : resourceconflict_listener_(listener) {
+  assert(listener && "listener is nullptr!!");
+
+  internal::AddRMHandle(this);
+  // TODO(js4716.chun) :
+  // Add Exception - Assert
+  // rm_register(&handle_, ResourceConflictCallback , ...);
+  int ret = rm_register((rm_resource_cb)ResourceConflictCallback_, (void*)this,
+                        &resourcemanager_handle_, NULL);
+  assert(ret == RM_OK && "rm_register() is failed");
+  TRACKRENDERER_INFO_P(resourceconflict_listener_,
+                       "resource manager handle = %d, Listener = %p, this = %p",
+                       resourcemanager_handle_, listener, this);
+}
+
+ResourceManager::~ResourceManager() {
+  if (resourcemanager_handle_ != -1) {
+    int ret = rm_unregister(resourcemanager_handle_);
+    assert(ret == RM_OK && "rm_unregister() is failed");
+    TRACKRENDERER_ERROR_P(resourceconflict_listener_,
+                          "rm_unregister() was done");
+  }
+
+  internal::RemoveRMHandle(this);
+}
+
+// LCOV_EXCL_START
+rm_cb_result ResourceManager::ResourceConflictCallback_(
+    ResourceManagerHandle rmhandle, rm_callback_type eventtype,
+    rm_device_request_s* info, void* userdata) {
+  TRACKRENDERER_DEBUG(
+      "ResourceManagerHandle[%d], cb_type[%d], conflicted num[%d], "
+      "device_id[%d]",
+      rmhandle, eventtype, info->request_num, info->device_id[0]);
+
+  ResourceManager* resourcemanager = static_cast<ResourceManager*>(userdata);
+  /* Do not access non-static variables except callback input parameters
+     before checking whether ResourceManager handle is valid.*/
+  std::lock_guard<std::mutex> lock(internal::rsc_lock);
+  auto iter = find(internal::rsc_list.begin(), internal::rsc_list.end(),
+                   resourcemanager);
+  if (iter == internal::rsc_list.end()) {
+    TRACKRENDERER_WARN("ResourceManager[%p] is released", resourcemanager);
+    return RM_CB_RESULT_OK;
+  }
+
+  {
+    std::lock_guard<std::mutex> lock2(resourcemanager->control_lock_);
+    if (resourcemanager->resourcelist_.empty()) {
+      TRACKRENDERER_ERROR_P(resourcemanager->resourceconflict_listener_,
+                            "resourcelist is empty! return.");
+      return RM_CB_RESULT_OK;
+    }
+  }
+
+  if (!resourcemanager->resourceconflict_listener_) {
+    TRACKRENDERER_ERROR("confilict listener is nullptr. ERROR!");
+    assert(0 && "resourceconflict_listener_ is nullptr");
+    return RM_CB_RESULT_ERROR;
+  }
+
+  resourcemanager->resourceconflict_listener_->OnResourceConflicted();
+  TRACKRENDERER_LEAVE_P(resourcemanager->resourceconflict_listener_);
+  return RM_CB_RESULT_OK;
+}
+// LCOV_EXCL_STOP
+
+void ResourceManager::SetAppId(const std::string& appid) {
+  if (appid.empty()) return;
+  rm_set_app_id(resourcemanager_handle_, const_cast<char*>(appid.c_str()));
+  app_id_ = appid;
+}
+
+bool ResourceManager::NeedPulseResource(const ResourceProperty& property) {
+  if (property.category != ResourceCategory::kAudioRenderer || !property.use_sw)
+    return false;
+  rm_resource_list_h list;
+
+  BOOST_SCOPE_EXIT(&list) { rm_free_resource_list(list); }
+  BOOST_SCOPE_EXIT_END
+
+  rm_get_resource_list(RM_CATEGORY_AUDIO_MAIN_OUT, &list);
+  rm_resource_h rsc = rm_resource_list_get_first(list);
+  while (rsc) {
+    if (rm_resource_get_state(rsc) != RM_RSC_STATE_FREE) {
+      bool is_main_device = ri_is_main_device(rm_resource_get_id(rsc));
+      if (is_main_device) {
+        const char* app_id = rm_resource_get_app_id(rsc);
+        if (!strcmp(app_id_.c_str(), app_id)) {
+          TRACKRENDERER_INFO_P(
+              resourceconflict_listener_,
+              "need pulsesink current app id [%s] allocated app id[%s]",
+              app_id_.c_str(), app_id);
+          return true;
+        }
+      }
+    }
+    rsc = rm_resource_list_get_next(list);
+  }
+  return false;
+}
+
+bool ResourceManager::AllocPulseResource_(const ResourceProperty& property) {
+  resourcelist_.emplace_back(property, kPulseSinkComponentName);
+  return true;
+}
+
+bool ResourceManager::AllocSwDecoderResource_(
+    const ResourceProperty& property) {
+  resourcelist_.emplace_back(property, kSwDecoderComponentName);
+  return true;
+}
+
+bool ResourceManager::AllocHWResource_(const ResourceProperty& property) {
+  rm_category_request_s req;
+  memset(&req, 0, sizeof(rm_category_request_s));
+  AllocatedState avail_state = MakeCategoryRequest_(property, &req);
+  TRACKRENDERER_ERROR_P(resourceconflict_listener_, "available state[%d]",
+                        static_cast<int>(avail_state));
+
+  if (avail_state == AllocatedState::kFailed) return false;
+  if (avail_state == AllocatedState::kSkipped) {
+    resourcelist_.emplace_back(property, avail_state);
+    return true;
+  }
+  return TryAllocHWResource_(property, req);
+}
+
+bool ResourceManager::TryAllocHWResource_(const ResourceProperty& property,
+                                          const rm_category_request_s& req) {
+  rm_device_return_s devices;
+  memset(&devices, 0, sizeof(rm_device_return_s));
+  if (internal::TryAlloc(resourcemanager_handle_, req, &devices) == false) {
+    TRACKRENDERER_ERROR_P(resourceconflict_listener_,
+                          "rm_allocate_resources FAIL.");
+    return false;
+  }
+
+  TRACKRENDERER_INFO_P(resourceconflict_listener_,
+                       "resource Type[%d], device id[%d], comp_name[%s]",
+                       static_cast<int>(property.category),
+                       devices.device_id[0], devices.omx_comp_name[0]);
+
+  resourcelist_.emplace_back(property, devices.device_id[0],
+                             devices.omx_comp_name[0]);
+
+  if (devices.device_node[0]) {
+    free(devices.device_node[0]);
+  }
+  if (devices.omx_comp_name[0]) {
+    free(devices.omx_comp_name[0]);
+  }
+  return true;
+}
+
+int ResourceManager::GetCategoryOption_(const rm_rsc_category_e& category_id,
+                                        const ResourceProperty& property) {
+  auto& mapper = internal::CategoryOptionMap.at(category_id);
+  int capable_category = mapper(property);
+  TRACKRENDERER_INFO_P(resourceconflict_listener_,
+                       "capable_category_option : %d", capable_category);
+  int category_option = rc_get_capable_category_id(
+      resourcemanager_handle_, app_id_.c_str(), capable_category);
+  TRACKRENDERER_INFO_P(resourceconflict_listener_, "capable_category_id : %d",
+                       category_option);
+  return category_option;
+}
+
+AllocatedState ResourceManager::MakeCategoryRequest_(
+    const ResourceProperty& property, rm_category_request_s* req) {
+  req->request_num = 1;
+  req->state[0] =
+      internal::TypeToResourceStateConverter.at(property.rsc_alloc_policy);
+  req->category_id[0] = internal::GetCategoryID(property);
+  req->category_option[0] = GetCategoryOption_(req->category_id[0], property);
+  if (req->category_option[0] == RI_ERROR)
+    return AllocatedState::kFailed;
+  else if (req->category_option[0] == RI_CATEGORY_NOT_PERMITTED)
+    return AllocatedState::kSkipped;
+
+  return AllocatedState::kSuccess;
+}
+
+bool ResourceManager::Alloc_(const ResourceProperty& property) {
+  if (internal::NeedSwDecoderResource(property)) {
+    return AllocSwDecoderResource_(property);
+  } else if (NeedPulseResource(property)) {
+    return AllocPulseResource_(property);
+  } else {
+    return AllocHWResource_(property);
+  }
+}
+
+bool ResourceManager::Alloc(const std::list<ResourceProperty>& properties) {
+  for (const auto& property : properties) {
+    TRACKRENDERER_INFO_P(resourceconflict_listener_,
+                         "Resource Type[%d], use_sw[%d]",
+                         static_cast<int>(property.category), property.use_sw);
+    if (Alloc_(property) == false) return false;
+  }
+  return true;
+}
+
+bool ResourceManager::Dealloc() {
+  TRACKRENDERER_ENTER_P(resourceconflict_listener_);
+
+  if (resourcelist_.empty()) return true;
+
+  rm_device_request_s devices;
+  memset(&devices, 0, sizeof(rm_device_request_s));
+
+  if (resourcelist_.size() == 0) return true;  // There is no resource.
+
+  unsigned int device_num = 0;
+  std::for_each(resourcelist_.begin(), resourcelist_.end(),
+                [&devices, &device_num](const Resource& resource) {
+                  if (resource.GetDeviceId() != 0) {
+                    devices.device_id[device_num++] = resource.GetDeviceId();
+                  }
+                });
+  if (device_num > 0) {
+    devices.request_num = device_num;
+    int rm_err = rm_deallocate_resources(resourcemanager_handle_, &devices);
+    if (rm_err != RM_OK) {
+      TRACKRENDERER_ERROR_P(resourceconflict_listener_,
+                            "rm_deallocate_resources failed, rm_err[%d]",
+                            rm_err);
+      return false;
+    }
+  } else {
+    TRACKRENDERER_INFO_P(resourceconflict_listener_,
+                         "therer are no resource to dealloc");
+    return true;
+  }
+
+  {
+    std::lock_guard<std::mutex> lock(control_lock_);
+    resourcelist_.clear();
+  }
+  TRACKRENDERER_LEAVE_P(resourceconflict_listener_);
+  return true;
+}
+
+bool ResourceManager::Dealloc(const ResourceCategory type) {
+  TRACKRENDERER_ENTER_P(resourceconflict_listener_);
+  if (resourcelist_.empty()) return true;
+  rm_device_request_s devices;
+  memset(&devices, 0, sizeof(rm_device_request_s));
+  devices.request_num = 1;
+
+  auto compare = [type](Resource& item) noexcept -> bool {
+    return item.GetResourceCategory() == type;
+  };
+  auto target =
+      std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
+
+  // There is no resource.
+  if (target == resourcelist_.end()) return true;
+  if (target->GetDeviceId() == 0) {
+    std::lock_guard<std::mutex> lock(control_lock_);
+    resourcelist_.erase(target);
+    TRACKRENDERER_DEBUG_P(resourceconflict_listener_,
+                          "resourcelist_.size() = %d", resourcelist_.size());
+    return true;
+  }
+
+  devices.device_id[0] = target->GetDeviceId();
+
+  int rm_err = rm_deallocate_resources(resourcemanager_handle_, &devices);
+  if (rm_err != RM_OK) {
+    TRACKRENDERER_ERROR_P(resourceconflict_listener_,
+                          "rm_deallocate_resources failed, rm_err[%d]", rm_err);
+    return false;
+  }
+
+  {
+    std::lock_guard<std::mutex> lock(control_lock_);
+    resourcelist_.erase(target);
+    TRACKRENDERER_DEBUG_P(resourceconflict_listener_,
+                          "resourcelist_.size() = %d", resourcelist_.size());
+  }
+  TRACKRENDERER_LEAVE_P(resourceconflict_listener_);
+  return true;
+}
+
+std::string ResourceManager::GetComponentName(const ResourceCategory type) {
+  auto compare = [type](const Resource& item) noexcept -> bool {
+    return item.GetResourceCategory() == type;
+  };
+  auto target =
+      std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
+  if (target == resourcelist_.end()) return {};
+
+  TRACKRENDERER_INFO_P(resourceconflict_listener_, "Comp name : %s",
+                       (target->GetComponentName()).c_str());
+  return target->GetComponentName();
+}
+
+int ResourceManager::GetRawHandle() { return resourcemanager_handle_; }
+
+AllocatedState ResourceManager::GetAllocatedState(const ResourceCategory type) {
+  auto compare = [type](const Resource& item) noexcept -> bool {
+    return item.GetResourceCategory() == type;
+  };
+  auto target =
+      std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
+  if (target == resourcelist_.end()) return AllocatedState::kFailed;
+
+  TRACKRENDERER_INFO_P(resourceconflict_listener_, "Allocated State : %d",
+                       static_cast<int>(target->GetAllocatedState()));
+  return target->GetAllocatedState();
+}
+
+bool ResourceManager::IsMainDevice(const ResourceCategory& type) {
+  TRACKRENDERER_ENTER_P(resourceconflict_listener_);
+  auto compare = [type](const Resource& item) noexcept -> bool {
+    return item.GetResourceCategory() == type;
+  };
+  auto target =
+      std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
+  if (target == resourcelist_.end()) {
+    TRACKRENDERER_WARN_P(resourceconflict_listener_,
+                         "This resource[%d] is not allocated.",
+                         static_cast<int>(type));
+    return true;
+  }
+
+  int device_id = target->GetDeviceId();
+  if (type == ResourceCategory::kVideoRenderer ||
+      type == ResourceCategory::kVideoRendererSub ||
+      type == ResourceCategory::kVideoRendererSub2 ||
+      type == ResourceCategory::kVideoRendererSub3) {
+    device_id = rm_find_device_id(device_id);
+  }
+  bool is_main = ri_is_main_device(device_id);
+  TRACKRENDERER_INFO_P(resourceconflict_listener_,
+                       "This resrouce[%d] is [%s] device",
+                       static_cast<int>(type), is_main ? "main" : "sub");
+  return is_main;
+}
+
+int ResourceManager::GetDeviceId(const ResourceCategory& type) {
+  TRACKRENDERER_ENTER_P(resourceconflict_listener_);
+  auto compare = [type](const Resource& item) noexcept -> bool {
+    return item.GetResourceCategory() == type;
+  };
+  auto target =
+      std::find_if(resourcelist_.begin(), resourcelist_.end(), compare);
+  if (target == resourcelist_.end()) {
+    TRACKRENDERER_ERROR_P(resourceconflict_listener_,
+                          "This resource[%d] is not allocated ",
+                          static_cast<int>(type));
+    return -1;  // invalid device id
+  }
+  return target->GetDeviceId();
+}
+
+bool ResourceManager::IsAudioFocused() {
+  bool is_audio_focused = rc_is_audio_focused(app_id_.c_str());
+  TRACKRENDERER_INFO("is audio focused [%d]", is_audio_focused);
+  return is_audio_focused;
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/screen_saver.cpp b/src/screen_saver.cpp
new file mode 100755 (executable)
index 0000000..866e9c7
--- /dev/null
@@ -0,0 +1,44 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/screen_saver.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+static int timeout_timer_id_ = 0;
+#define ResetTimeoutValue 30  // timeout second
+
+ScreenSaver::~ScreenSaver() {}
+
+void ScreenSaver::StartTimeout() {
+  if (timeout_timer_id_ == 0) {
+    int ret = screensaver_reset_timeout();
+    TRACKRENDERER_DEBUG("screensaver_reset_timeout start : ret = %d", ret);
+    timeout_timer_id_ =
+        g_timeout_add_seconds(ResetTimeoutValue, ResetTimeout, NULL);
+    TRACKRENDERER_DEBUG("timer_id = %d", timeout_timer_id_);
+  }
+}
+
+void ScreenSaver::StopTimeout() {
+  if (timeout_timer_id_ != 0) {
+    TRACKRENDERER_DEBUG("timer_id = %d", timeout_timer_id_);
+    g_source_remove(timeout_timer_id_);
+    timeout_timer_id_ = 0;
+  }
+  TRACKRENDERER_DEBUG("remove screensaver reset timer");
+}
+
+gboolean ScreenSaver::ResetTimeout(gpointer data) {
+  int ret = screensaver_reset_timeout();
+  TRACKRENDERER_DEBUG("screensaver_reset_timeout resume: ret = %d", ret);
+  return true;
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/subtitle_attr_parser.cpp b/src/subtitle_attr_parser.cpp
new file mode 100755 (executable)
index 0000000..a0d9e9b
--- /dev/null
@@ -0,0 +1,550 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/subtitle_attr_parser.h"
+
+#include <algorithm>
+#include <cassert>
+
+#include "gst/ffsubtitle/gstsubattributes.h"
+
+#include "trackrenderer/core/utils/log.h"
+// LCOV_EXCL_START
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace internal {
+void AddSubtitleAttribute(std::list<SubtitleAttr>* list,
+                          const SubtitleAttrType type, const boost::any& value,
+                          const unsigned int start_pos,
+                          const unsigned int stop_pos) {
+  list->emplace_back(type, start_pos, stop_pos, value, -1);
+}
+
+bool ComparingStartTime(const SubtitleAttr& a, const SubtitleAttr& b) {
+  return (a.start_time < b.start_time);
+}
+
+constexpr int kAttrInvalidIntVal = -1;
+constexpr unsigned int kAttrInvalidUintVal =
+    std::numeric_limits<unsigned int>::max();
+constexpr float kAttrInvalidFloatVal = 0.0;
+
+void ParseSubtitleRegionAttr(GstStructure* attribute,
+                             std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_ENTER;
+  while (attribute) {
+    gfloat x_pos = kAttrInvalidIntVal, y_pos = kAttrInvalidFloatVal,
+           width = kAttrInvalidFloatVal, height = kAttrInvalidFloatVal;
+    attribute = gst_sub_attribute_region_parse(attribute, &x_pos, &y_pos,
+                                               &width, &height);
+    TRACKRENDERER_DEBUG(
+        "parsed new region attribute: x(%f), y(%f), width(%f), "
+        "height(%f)",
+        x_pos, y_pos, width, height);
+    if (x_pos != kAttrInvalidFloatVal) {
+      boost::any value = x_pos;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrRegionXPos, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (y_pos != kAttrInvalidFloatVal) {
+      boost::any value = y_pos;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrRegionYPos, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (width != kAttrInvalidFloatVal) {
+      boost::any value = width;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrRegionWidth, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (height != kAttrInvalidFloatVal) {
+      boost::any value = height;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrRegionHeight, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+  }
+}
+
+void ParseSubtitleWindowAttr(GstStructure* attribute,
+                             std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_ENTER;
+  while (attribute) {
+    gfloat x_padding = kAttrInvalidFloatVal, y_padding = kAttrInvalidFloatVal;
+    gint l_margin = kAttrInvalidIntVal, r_margin = kAttrInvalidIntVal,
+         t_margin = kAttrInvalidIntVal, b_margin = kAttrInvalidIntVal;
+    guint bg_color = kAttrInvalidUintVal;
+    gfloat opacity = kAttrInvalidFloatVal;
+    guint show_bg = kAttrInvalidUintVal;
+    attribute = gst_sub_attribute_window_parse(
+        attribute, &x_padding, &y_padding, &l_margin, &r_margin, &t_margin,
+        &b_margin, &bg_color, &opacity, &show_bg);
+    TRACKRENDERER_DEBUG(
+        "parsed new window attribute: x_padding(%f), y_padding(%f), "
+        "l_margin(%d), r_margin(%d), t_margin(%d), b_margin(%d), "
+        "bg_color(%u), opacity(%f), show_bg(%u)",
+        x_padding, y_padding, l_margin, r_margin, t_margin, b_margin, bg_color,
+        opacity, show_bg);
+    if (x_padding != kAttrInvalidFloatVal) {
+      boost::any value = x_padding;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowXPadding, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (y_padding != kAttrInvalidFloatVal) {
+      boost::any value = y_padding;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowYPadding, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (l_margin != kAttrInvalidIntVal) {
+      boost::any value = l_margin;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowLeftMargin, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (r_margin != kAttrInvalidIntVal) {
+      boost::any value = r_margin;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowRightMargin,
+                                     value, kAttrInvalidUintVal,
+                                     kAttrInvalidUintVal);
+    }
+    if (t_margin != kAttrInvalidIntVal) {
+      boost::any value = t_margin;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowTopMargin, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (b_margin != kAttrInvalidIntVal) {
+      boost::any value = b_margin;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowBottomMargin,
+                                     value, kAttrInvalidUintVal,
+                                     kAttrInvalidUintVal);
+    }
+    if (bg_color != kAttrInvalidUintVal) {
+      boost::any value = bg_color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowBgColor, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (opacity != kAttrInvalidFloatVal) {
+      boost::any value = opacity;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowOpacity, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+    if (show_bg != kAttrInvalidUintVal) {
+      boost::any value = show_bg;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWindowShowBg, value,
+                                     kAttrInvalidUintVal, kAttrInvalidUintVal);
+    }
+  }
+}
+
+void ParseSubtitleFontAttr(GstStructure* attribute,
+                           std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute font!");
+  while (attribute) {
+    GstSubAttributeScope scope;
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gchar* family = nullptr;
+    gfloat size = kAttrInvalidFloatVal;
+    gint weight = kAttrInvalidIntVal, style = kAttrInvalidIntVal;
+    guint color = kAttrInvalidUintVal, bg_color = kAttrInvalidUintVal;
+    gfloat opacity = kAttrInvalidFloatVal, bg_opacity = kAttrInvalidFloatVal;
+    guint text_outline_color = kAttrInvalidUintVal,
+          text_outline_tn = kAttrInvalidUintVal;
+    gint text_outline_br = kAttrInvalidIntVal, v_align = kAttrInvalidIntVal,
+         h_align = kAttrInvalidIntVal;
+    attribute = gst_sub_attribute_font_parse(
+        attribute, &scope, &start_index, &stop_index, &family, &size, &weight,
+        &style, &color, &bg_color, &opacity, &bg_opacity, &text_outline_color,
+        &text_outline_tn, &text_outline_br, &v_align, &h_align);
+    TRACKRENDERER_DEBUG(
+        "passed a font attribute: scope(%u), start_index(%u), "
+        "stop_index(%u), family(%s), size(%f),"
+        "weight(%d), style(%d), color(%u), bg_color(%u), opacity(%f), "
+        "bg_opacity(%f), text_outline_color(%u),"
+        "text_outline_tn(%u),text_outline_br(%d), v_align(%d), "
+        "h_align(%d)",
+        scope, start_index, stop_index, family, size, weight, style, color,
+        bg_color, opacity, bg_opacity, text_outline_color, text_outline_tn,
+        text_outline_br, v_align, h_align);
+    if (family != nullptr) {
+      boost::any value = std::string(family);
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontFamily, value,
+                                     start_index, stop_index);
+    }
+    if (size != kAttrInvalidFloatVal) {
+      boost::any value = size;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontSize, value,
+                                     start_index, stop_index);
+    }
+    if (weight != kAttrInvalidIntVal) {
+      boost::any value = weight;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontWeight, value,
+                                     start_index, stop_index);
+    }
+    if (style != kAttrInvalidIntVal) {
+      boost::any value = style;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontStyle, value,
+                                     start_index, stop_index);
+    }
+    if (color != kAttrInvalidUintVal) {
+      boost::any value = color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
+                                     start_index, stop_index);
+    }
+    if (bg_color != kAttrInvalidUintVal) {
+      boost::any value = bg_color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgColor, value,
+                                     start_index, stop_index);
+    }
+    if (opacity != kAttrInvalidFloatVal) {
+      boost::any value = opacity;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontOpacity, value,
+                                     start_index, stop_index);
+    }
+    if (bg_opacity != kAttrInvalidFloatVal) {
+      boost::any value = bg_opacity;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgOpacity, value,
+                                     start_index, stop_index);
+    }
+    if (text_outline_color != kAttrInvalidUintVal) {
+      boost::any value = text_outline_color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontTextOutlineColor,
+                                     value, start_index, stop_index);
+    }
+    if (text_outline_tn != kAttrInvalidUintVal) {
+      boost::any value = text_outline_tn;
+      internal::AddSubtitleAttribute(attr_list,
+                                     kSubAttrFontTextOutlineThickness, value,
+                                     start_index, stop_index);
+    }
+    if (text_outline_br != kAttrInvalidIntVal) {
+      boost::any value = text_outline_br;
+      internal::AddSubtitleAttribute(attr_list,
+                                     kSubAttrFontTextOutlineBlurRadius, value,
+                                     start_index, stop_index);
+    }
+    if (v_align != kAttrInvalidIntVal) {
+      boost::any value = v_align;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontVerticalAlign,
+                                     value, start_index, stop_index);
+    }
+    if (h_align != kAttrInvalidIntVal) {
+      boost::any value = h_align;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontHorizontalAlign,
+                                     value, start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleFontSizeWeightStyleClolr(GstStructure* attribute,
+                                           std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute font shortcut SIZE_WEIGHT_STYLE_COLOR!");
+  while (attribute) {
+    GstSubAttributeScope scope;
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gfloat size = kAttrInvalidFloatVal;
+    gint weight = kAttrInvalidIntVal, style = kAttrInvalidIntVal;
+    guint color = kAttrInvalidUintVal;
+    attribute = gst_sub_attribute_font_sc_size_weight_style_color_parse(
+        attribute, &scope, &start_index, &stop_index, &size, &weight, &style,
+        &color);
+    TRACKRENDERER_DEBUG(
+        "passed a font attribute: scope(%u), start_index(%u), "
+        "stop_index(%u), size(%f),"
+        "weight(%d), style(%d), color(%u)",
+        scope, start_index, stop_index, size, weight, style, color);
+    if (size != kAttrInvalidFloatVal) {
+      boost::any value = size;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontSize, value,
+                                     start_index, stop_index);
+    }
+    if (weight != kAttrInvalidIntVal) {
+      boost::any value = weight;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontWeight, value,
+                                     start_index, stop_index);
+    }
+    if (style != kAttrInvalidIntVal) {
+      boost::any value = style;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontStyle, value,
+                                     start_index, stop_index);
+    }
+    if (color != kAttrInvalidUintVal) {
+      boost::any value = color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
+                                     start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleFontColorOpacities(GstStructure* attribute,
+                                     std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute font shortcut SIZE_COLORS_AND_OPACITIES!");
+  while (attribute) {
+    GstSubAttributeScope scope;
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal,
+          color = kAttrInvalidUintVal, bg_color = kAttrInvalidUintVal;
+    gfloat opacity = kAttrInvalidFloatVal, bg_opacity = kAttrInvalidFloatVal;
+    guint text_outline_color = kAttrInvalidUintVal;
+    attribute = gst_sub_attribute_font_sc_colors_and_opacities_parse(
+        attribute, &scope, &start_index, &stop_index, &color, &bg_color,
+        &opacity, &bg_opacity, &text_outline_color);
+    TRACKRENDERER_DEBUG(
+        "passed a font attribute: scope(%u), start_index(%u), "
+        "stop_index(%u),"
+        "color(%u), bg_color(%u), opacity(%f), bg_opacity(%f), "
+        "text_outline_color(%u)",
+        scope, start_index, stop_index, color, bg_color, opacity, bg_opacity,
+        text_outline_color);
+    if (color != kAttrInvalidUintVal) {
+      boost::any value = color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
+                                     start_index, stop_index);
+    }
+    if (bg_color != kAttrInvalidUintVal) {
+      boost::any value = bg_color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgColor, value,
+                                     start_index, stop_index);
+    }
+    if (opacity != kAttrInvalidFloatVal) {
+      boost::any value = opacity;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontOpacity, value,
+                                     start_index, stop_index);
+    }
+    if (bg_opacity != kAttrInvalidFloatVal) {
+      boost::any value = bg_opacity;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontBgOpacity, value,
+                                     start_index, stop_index);
+    }
+    if (text_outline_color != kAttrInvalidUintVal) {
+      boost::any value = text_outline_color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontTextOutlineColor,
+                                     value, start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleFontSize(GstStructure* attribute,
+                           std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute font shortcut SIZE!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gfloat size = kAttrInvalidFloatVal;
+    attribute = gst_sub_attribute_font_sc_size_parse(attribute, &start_index,
+                                                     &stop_index, &size);
+    TRACKRENDERER_DEBUG(
+        "passed a font attribute: start_index(%u), stop_index(%u), "
+        "size(%f)",
+        start_index, stop_index, size);
+    if (size != kAttrInvalidFloatVal) {
+      boost::any value = size;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontSize, value,
+                                     start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleFontWeight(GstStructure* attribute,
+                             std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute font shortcut WEIGHT!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gint weight = kAttrInvalidIntVal;
+    attribute = gst_sub_attribute_font_sc_weight_parse(attribute, &start_index,
+                                                       &stop_index, &weight);
+    TRACKRENDERER_DEBUG(
+        "passed a font attribute: start_index(%u), stop_index(%u), "
+        "weight(%d)",
+        start_index, stop_index, weight);
+    if (weight != kAttrInvalidIntVal) {
+      boost::any value = weight;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontWeight, value,
+                                     start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleFontStyle(GstStructure* attribute,
+                            std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute font shortcut STYLE!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gint style = kAttrInvalidIntVal;
+    attribute = gst_sub_attribute_font_sc_style_parse(attribute, &start_index,
+                                                      &stop_index, &style);
+    TRACKRENDERER_DEBUG(
+        "passed a font attribute: start_index(%u), stop_index(%u), "
+        "style(%d)",
+        start_index, stop_index, style);
+    if (style != kAttrInvalidIntVal) {
+      boost::any value = style;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontStyle, value,
+                                     start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleFontColor(GstStructure* attribute,
+                            std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute font shortcut COLOR!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    guint color = kAttrInvalidUintVal;
+    attribute = gst_sub_attribute_font_sc_color_parse(attribute, &start_index,
+                                                      &stop_index, &color);
+    TRACKRENDERER_DEBUG(
+        "passed a font attribute: start_index(%u), stop_index(%u), "
+        "color(%u)",
+        start_index, stop_index, color);
+    if (color != kAttrInvalidUintVal) {
+      boost::any value = color;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrFontColor, value,
+                                     start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleRaw(GstStructure* attribute,
+                      std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute raw!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gchar* raw_subtitle = nullptr;
+    attribute = gst_sub_attribute_raw_data(attribute, &raw_subtitle);
+    TRACKRENDERER_DEBUG("passed a raw attribute: raw_subtitle(%s)", raw_subtitle);
+    if (raw_subtitle != nullptr) {
+      boost::any value = std::string(raw_subtitle);
+      internal::AddSubtitleAttribute(attr_list, kSubAttrRawSubtitle, value,
+                                     start_index, stop_index);
+    }
+  }
+}
+void ParseSubtitleWebvttCue(GstStructure* attribute,
+                            std::list<SubtitleAttr>* attr_list) {
+  TRACKRENDERER_DEBUG("Now parse attribute of webvtt cue!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gint line_num = kAttrInvalidIntVal, line_align = kAttrInvalidIntVal,
+         pos_align = kAttrInvalidIntVal, align = kAttrInvalidIntVal,
+         vertical = kAttrInvalidIntVal;
+    gfloat line = kAttrInvalidFloatVal, size = kAttrInvalidFloatVal,
+           position = kAttrInvalidFloatVal;
+    attribute = gst_sub_attribute_webvttcue_parse(
+        attribute, &line, &line_num, &line_align, &align, &size, &position,
+        &pos_align, &vertical);
+    TRACKRENDERER_DEBUG(
+        "passed webvttcue attributes: line(%f), line_num(%d), line_align(%d), "
+        "align(%d), size(%f), position(%f), pos_align(%d), vertical(%d)",
+        line, line_num, line_align, align, size, position, pos_align, vertical);
+    if (line != kAttrInvalidFloatVal) {
+      boost::any value = line;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueLine, value,
+                                     start_index, stop_index);
+    }
+    if (line_num != kAttrInvalidIntVal) {
+      boost::any value = line_num;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueLineNum, value,
+                                     start_index, stop_index);
+    }
+    if (line_align != kAttrInvalidIntVal) {
+      boost::any value = line_align;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueLineAlign,
+                                     value, start_index, stop_index);
+    }
+    if (align != kAttrInvalidIntVal) {
+      boost::any value = align;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueAlign, value,
+                                     start_index, stop_index);
+    }
+    if (size != kAttrInvalidFloatVal) {
+      boost::any value = size;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueSize, value,
+                                     start_index, stop_index);
+    }
+    if (position != kAttrInvalidFloatVal) {
+      boost::any value = position;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCuePosition,
+                                     value, start_index, stop_index);
+    }
+    if (pos_align != kAttrInvalidIntVal) {
+      boost::any value = pos_align;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCuePositionAlign,
+                                     value, start_index, stop_index);
+    }
+    if (vertical != kAttrInvalidIntVal) {
+      boost::any value = vertical;
+      internal::AddSubtitleAttribute(attr_list, kSubAttrWebvttCueVertical,
+                                     value, start_index, stop_index);
+    }
+  }
+}
+
+}  // namespace internal
+
+SubtitleAttrListPtr SubtitleAttrParser::Parse() {
+  SubtitleAttrListPtr attr_list{new SubtitleAttrList};
+  for (int attr_type = GST_SUB_ATTRI_TYPE_REGION;
+       attr_type < GST_SUB_ATTRI_TYPE_UNKNOWN; ++attr_type) {
+    const gchar* type_name =
+        gst_sub_attribute_type_to_name((GstSubAttributeType)attr_type);
+    GQuark attri_quark =
+        gst_sub_attribute_type_to_quark((GstSubAttributeType)attr_type);
+    if (!attri_quark) {
+      TRACKRENDERER_DEBUG("We don't have quark of this attribute type(%s)!", type_name);
+      continue;
+    }
+
+    GstStructure* attribute = GST_STRUCTURE_CAST(
+        gst_mini_object_get_qdata(GST_MINI_OBJECT(gstbuf_), attri_quark));
+
+    if (!attribute) continue;
+    TRACKRENDERER_DEBUG("attribute type(%s) from gstbuffer!", type_name);
+
+    switch (attr_type) {
+      case GST_SUB_ATTRI_TYPE_REGION:
+        internal::ParseSubtitleRegionAttr(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_WINDOW:
+        internal::ParseSubtitleWindowAttr(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_FONT:
+        internal::ParseSubtitleFontAttr(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_FONT_SC_SIZE_WEIGHT_STYLE_COLOR:
+        internal::ParseSubtitleFontSizeWeightStyleClolr(attribute,
+                                                        attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_FONT_SC_COLORS_AND_OPACITIES:
+        internal::ParseSubtitleFontColorOpacities(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_FONT_SC_SIZE:
+        internal::ParseSubtitleFontSize(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_FONT_SC_WEIGHT:
+        internal::ParseSubtitleFontWeight(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_FONT_SC_STYLE:
+        internal::ParseSubtitleFontStyle(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_FONT_SC_COLOR:
+        internal::ParseSubtitleFontColor(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_RAW:
+        internal::ParseSubtitleRaw(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_TYPE_WEBVTT_CUE:
+        internal::ParseSubtitleWebvttCue(attribute, attr_list.get());
+        break;
+      default:
+        TRACKRENDERER_ERROR("UNKNOWN ATTR TYPE");
+        return nullptr;
+    }
+  }
+
+  (attr_list.get())->sort(internal::ComparingStartTime);
+  boost::any value = 0;
+  GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
+  duration = GST_TIME_AS_MSECONDS(GST_BUFFER_DURATION(gstbuf_));
+  timestamp = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(gstbuf_));
+  TRACKRENDERER_DEBUG("pts[%llu] duration[%llu]", timestamp, duration);
+  internal::AddSubtitleAttribute(attr_list.get(), kSubAttrTimestamp, value,
+                                 timestamp, timestamp + duration);
+
+  return attr_list;
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
+// LCOV_EXCL_STOP
diff --git a/src/track_capi.cpp b/src/track_capi.cpp
new file mode 100755 (executable)
index 0000000..eeda99c
--- /dev/null
@@ -0,0 +1,311 @@
+// LCOV_EXCL_START
+#include "trackrenderer_capi/track_capi.h"
+
+#include <cstring>
+#include <memory>
+
+#include "trackrenderer/core/track.h"
+#include "trackrenderer/core/track_util.h"
+#include "trackrenderer/trackrenderer_capi_utils.h"
+
+namespace tr = plusplayer::trackrenderer;
+
+namespace {
+tr::Track* cast_(TrackRendererTrackHandle handle) {
+  return static_cast<tr::Track*>(handle);
+}
+
+int FillCodecData(tr::Track* track, const char* codec_data,
+                  const int codec_data_len) {
+  auto* codec_data_ptr = new char[codec_data_len];
+  if (codec_data_ptr == nullptr) return -1;
+  std::memcpy(codec_data_ptr, codec_data, codec_data_len);
+  track->codec_data =
+      std::shared_ptr<char>(codec_data_ptr, std::default_delete<char[]>());
+  track->codec_data_len = codec_data_len;
+  return 0;
+}
+
+bool IsAudioTrackType(const tr::Track* track) {
+  return track->type == tr::kTrackTypeAudio;
+}
+bool IsVideoTrackType(const tr::Track* track) {
+  return track->type == tr::kTrackTypeVideo;
+}
+bool IsSubtitleTrackType(const tr::Track* track) {
+  return track->type == tr::kTrackTypeSubtitle;
+}
+}  // namespace
+
+int trackrenderer_track_create(TrackRendererTrackHandle* handle,
+                               const TrackRendererTrackType type,
+                               const int index) {
+  if (handle == nullptr) return -1;
+  *handle = nullptr;
+  tr::Track* track = new tr::Track;
+  if (track == nullptr) return -1;
+  track->type = tr::capi_utils::ConvertToTrackType(type);
+  track->index = index;
+  *handle = static_cast<TrackRendererTrackHandle>(track);
+  return 0;
+}
+
+int trackrenderer_track_destroy(TrackRendererTrackHandle handle) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  delete track;
+  return 0;
+}
+
+int trackrenderer_track_set_activation(
+    TrackRendererTrackHandle handle,
+    const TrackRendererTrackActivation activation) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  track->active =
+      activation == kTrackRendererTrackActivationActive ? true : false;
+  return 0;
+}
+
+int trackrenderer_track_set_mimetype(TrackRendererTrackHandle handle,
+                                     const char* mimetype) {
+  if (handle == nullptr) return -1;
+  if (mimetype == nullptr) return -1;
+  auto* track = cast_(handle);
+  track->mimetype = mimetype;
+  return 0;
+}
+
+int trackrenderer_track_set_streamtype(TrackRendererTrackHandle handle,
+                                       const char* streamtype) {
+  if (handle == nullptr) return -1;
+  if (streamtype == nullptr) return -1;
+  auto* track = cast_(handle);
+  track->streamtype = streamtype;
+  return 0;
+}
+
+int trackrenderer_track_set_codec_data(TrackRendererTrackHandle handle,
+                                       const char* codec_data,
+                                       const int codec_data_len) {
+  if (handle == nullptr) return -1;
+  if (codec_data == nullptr) return -1;
+  if (tr::track_util::IsValidCodecDataSize(codec_data_len) == false) return -1;
+  auto* track = cast_(handle);
+  if (IsSubtitleTrackType(track)) return -1;
+  return FillCodecData(track, codec_data, codec_data_len);
+}
+
+int trackrenderer_track_set_decoder_type(
+    TrackRendererTrackHandle handle, const TrackRendererTrackDecoderType type) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsSubtitleTrackType(track)) return -1;
+  auto ret = 0;
+  switch (type) {
+    case kTrackRendererTrackDecoderTypeHwOnly:
+      track->use_swdecoder = false;
+      break;
+    case kTrackRendererTrackDecoderTypeSwOnly:
+      track->use_swdecoder = true;
+      break;
+    default:
+      ret = -1;
+      break;
+  }
+  return ret;
+}
+
+int trackrenderer_track_video_set_resolution(TrackRendererTrackHandle handle,
+                                             const int width,
+                                             const int height) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsVideoTrackType(track) == false) return -1;
+  track->width = width;
+  track->height = height;
+  return 0;
+}
+
+int trackrenderer_track_video_set_max_resolution(
+    TrackRendererTrackHandle handle, const int width, const int height) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsVideoTrackType(track) == false) return -1;
+  track->maxwidth = width;
+  track->maxheight = height;
+  return 0;
+}
+
+int trackrenderer_track_video_set_framerate(TrackRendererTrackHandle handle,
+                                            const int num, const int den) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsVideoTrackType(track) == false) return -1;
+  track->framerate_num = num;
+  track->framerate_den = den;
+  return 0;
+}
+
+int trackrenderer_track_video_set_codec_tag(TrackRendererTrackHandle handle,
+                                            const char* codec_tag) {
+  if (handle == nullptr) return -1;
+  if (codec_tag == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsVideoTrackType(track) == false) return -1;
+  track->codec_tag = codec_tag;
+  return 0;
+}
+
+int trackrenderer_track_video_set_version(TrackRendererTrackHandle handle,
+                                          const int version) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsVideoTrackType(track) == false) return -1;
+  track->version = version;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_sample_rate(TrackRendererTrackHandle handle,
+                                              const int sample_rate) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->sample_rate = sample_rate;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_sample_format(TrackRendererTrackHandle handle,
+                                                const int sample_format) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->sample_format = sample_format;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_channels(TrackRendererTrackHandle handle,
+                                           const int channels) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->channels = channels;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_version(TrackRendererTrackHandle handle,
+                                          const int version) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->version = version;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_layer(TrackRendererTrackHandle handle,
+                                        const int layer) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->layer = layer;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_bits_per_sample(
+    TrackRendererTrackHandle handle, const int bits_per_sample) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->bits_per_sample = bits_per_sample;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_block_align(TrackRendererTrackHandle handle,
+                                              const int block_align) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->block_align = block_align;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_bitrate(TrackRendererTrackHandle handle,
+                                          const int bitrate) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->bitrate = bitrate;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_layout(TrackRendererTrackHandle handle,
+                                         const char* layout) {
+  if (handle == nullptr) return -1;
+  if (layout == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->layout = layout;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_flavor(TrackRendererTrackHandle handle,
+                                         const int flavor) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->flavor = flavor;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_endianness(
+    TrackRendererTrackHandle handle,
+    const TrackRendererTrackEndianness endianness) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->endianness =
+      endianness == kTrackRendererTrackEndiannessLittle ? 1234 : 4321;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_signedness(
+    TrackRendererTrackHandle handle,
+    const TrackRendererTrackSignedness signedness) {
+  if (handle == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->is_signed =
+      signedness == kTrackRendererTrackSignednessSigned ? true : false;
+  return 0;
+}
+
+int trackrenderer_track_audio_set_codec_tag(TrackRendererTrackHandle handle,
+                                            const char* codec_tag) {
+  if (handle == nullptr) return -1;
+  if (codec_tag == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsAudioTrackType(track) == false) return -1;
+  track->codec_tag = codec_tag;
+  return 0;
+}
+
+int trackrenderer_track_subtitle_set_language_code(
+    TrackRendererTrackHandle handle, const char* language_code) {
+  if (handle == nullptr) return -1;
+  if (language_code == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsSubtitleTrackType(track) == false) return -1;
+  track->language_code = language_code;
+  return 0;
+}
+
+int trackrenderer_track_subtitle_set_subtitle_format(
+    TrackRendererTrackHandle handle, const char* subtitle_format) {
+  if (handle == nullptr) return -1;
+  if (subtitle_format == nullptr) return -1;
+  auto* track = cast_(handle);
+  if (IsSubtitleTrackType(track) == false) return -1;
+  track->subtitle_format = subtitle_format;
+  return 0;
+}
+// LCOV_EXCL_STOP
diff --git a/src/track_util.cpp b/src/track_util.cpp
new file mode 100755 (executable)
index 0000000..4ed8502
--- /dev/null
@@ -0,0 +1,165 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/track_util.h"
+
+#include <algorithm>
+#include <string>
+#include <unordered_map>
+
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace track_util {
+
+bool GetActiveTrack(const std::vector<Track>& track_list, const TrackType type,
+                    Track* track) {
+  if (!track) return false;
+  auto find_target = [type](const Track& item) -> bool {
+    if (item.type == type && item.active) {
+      return true;
+    } else {
+      return false;
+    }
+  };
+  auto target = std::find_if(track_list.begin(), track_list.end(), find_target);
+  if (target == track_list.end()) return false;  // There is no target.
+  *track = *target;
+  // TRACKRENDERER_INFO("tracktype : %d, index : %d", track->type,
+  // track->index);
+  return true;
+}
+
+bool GetActiveTrackList(const std::vector<Track>& tracklist,
+                        std::vector<Track>& active_track) {
+  unsigned int video = 0, audio = 0, text = 0;
+  for (const auto& track : tracklist) {
+    if (track.active == true) {
+      active_track.push_back(track);
+      if (track.type == kTrackTypeAudio)
+        audio++;
+      else if (track.type == kTrackTypeVideo)
+        video++;
+      else if (track.type == kTrackTypeSubtitle)
+        text++;
+    }
+  }
+  if (active_track.empty()) {
+    TRACKRENDERER_ERROR("no active track found");
+    return false;
+  }
+  if (video > 1 || audio > 1 || text > 1) {
+    TRACKRENDERER_ERROR(
+        "actived tracks are too much: video(%d), audio(%d), text(%d)", video,
+        audio, text);
+    return false;
+  }
+  return true;
+}
+
+void ShowTrackInfo(const std::vector<Track>& trackinfo) {
+  std::vector<Track> info = trackinfo;
+  TRACKRENDERER_INFO("### Track List ###");
+  for (const Track& item : info) {
+    ShowTrackInfo(item);
+  }
+  TRACKRENDERER_INFO("### ~Track List ###");
+}
+
+void ShowTrackInfo(const Track& track) {
+  TRACKRENDERER_INFO("### TrackInfo ###");
+  TRACKRENDERER_INFO("index : %d   id : %d ,", track.index, track.id);
+  TRACKRENDERER_INFO("mimetype: %s", track.mimetype.c_str());
+  TRACKRENDERER_INFO("streamtype: %s", track.streamtype.c_str());
+  TRACKRENDERER_INFO("tracktype : %d", track.type);
+  TRACKRENDERER_INFO("width: %d  height : %d", track.width, track.height);
+  TRACKRENDERER_INFO("maxwidth: %d  maxheight : %d", track.maxwidth,
+                     track.maxheight);
+  TRACKRENDERER_INFO("framerate(num : %d  den : %d)", track.framerate_num,
+                     track.framerate_den);
+  TRACKRENDERER_INFO("framerate(codec_data : %p )", track.codec_data.get());
+  TRACKRENDERER_INFO("framerate(codec_data_len : %d )", track.codec_data_len);
+  TRACKRENDERER_INFO(
+      "sample_rate %d  sample_format : %d  channel : %d  version : %d  layer : "
+      "%d",
+      track.sample_rate, track.sample_format, track.channels, track.version,
+      track.layer);
+  TRACKRENDERER_INFO(
+      "bits_per_sample %d  block_align : %d  bitrate : %d  endianness : %d  "
+      "is_signed : %d",
+      track.bits_per_sample, track.block_align, track.bitrate, track.endianness,
+      track.is_signed);
+  TRACKRENDERER_INFO("active %d  subtitle_format : %s ", track.active,
+                     track.subtitle_format.c_str());
+  TRACKRENDERER_INFO("use_swdecoder : %d", track.use_swdecoder);
+  TRACKRENDERER_INFO("language_code: %s", track.language_code.c_str());
+}
+
+uint64_t GetPositionWithinBoundary(const uint64_t duration,
+                                   const uint64_t position,
+                                   const uint64_t threshold) {
+  TRACKRENDERER_DEBUG("duration[%llu] position[%llu] threshold[%llu]", duration,
+                      position, threshold);
+  if (duration < threshold) return position;
+  uint64_t safe_pos = position;
+  uint64_t boundary = duration - threshold;
+  if (position > boundary) {
+    safe_pos = boundary;
+  }
+  return safe_pos;
+}
+
+bool IsValidCodecDataSize(int size) {
+  constexpr int kMaxSize = 1024 * 1024;  // 1MB
+  if (size > 0 && size < kMaxSize) return true;
+  return false;
+}
+
+void FillCodecDataIntoTrack(const GValue* codec_data, Track* track) {
+  GstBuffer* buffer = gst_value_get_buffer(codec_data);
+  GstMapInfo codec_data_info;
+  if (gst_buffer_map(buffer, &codec_data_info, GST_MAP_READ)) {
+    TRACKRENDERER_DEBUG("codec extra data [ %s ]", codec_data_info.data);
+    TRACKRENDERER_DEBUG("codec extra data size[ %d ]", codec_data_info.size);
+    if (IsValidCodecDataSize(codec_data_info.size)) {
+      std::shared_ptr<char> data(new char[codec_data_info.size],
+                                 std::default_delete<char[]>());
+      memcpy(data.get(), codec_data_info.data, codec_data_info.size);
+      track->codec_data = data;
+      track->codec_data_len = codec_data_info.size;
+    } else {
+      TRACKRENDERER_WARN("Warning invalid codec extra data size [%d]",
+                         codec_data_info.size);
+    }
+    gst_buffer_unmap(buffer, &codec_data_info);
+  } else {
+    TRACKRENDERER_DEBUG("Fail to gst_buffer_map for codec data");
+  }
+}
+
+const std::string& GetTrackTypeString(const TrackType& type) {
+  static const std::unordered_map<TrackType, std::string> kTrackTypeStringMap =
+      {
+          {kTrackTypeAudio, "AudioTrackType"},
+          {kTrackTypeVideo, "VideoTrackType"},
+          {kTrackTypeSubtitle, "SubtitleTrackType"},
+      };
+  static const std::string kInvalidTrackTypeString = "InvalidTrackType";
+
+  const auto got = kTrackTypeStringMap.find(type);
+  if (got == kTrackTypeStringMap.end()) {
+    return std::move(kInvalidTrackTypeString);
+  } else {
+    return std::move(got->second);
+  }
+}
+
+}  // namespace track_util
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/trackrenderer.cpp b/src/trackrenderer.cpp
new file mode 100755 (executable)
index 0000000..f5abbab
--- /dev/null
@@ -0,0 +1,5336 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/trackrenderer.h"
+
+#include <sys/prctl.h>
+
+#include <boost/scope_exit.hpp>
+#include <chrono>
+#include <limits>
+#include <list>
+#include <map>
+#include <thread>
+#include <utility>
+
+#ifdef SOUNDBAR_PRODUCT
+#include "avoc_av_audio.h"
+#else
+#include "avoc.h"
+#include "avoc_callback.h"
+#include "avoc_mls.h"
+#endif
+#include "iaudio-control.hpp"
+#include "iniparser.h"
+#include "lwipc.h"
+#include "resource_center.h"
+#include "system_info.h"
+
+// performance logs in popup log file
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+// end
+
+#ifndef SOUNDBAR_PRODUCT
+#include <capi-graphics-control.h>
+#endif
+
+#include "trackrenderer/audio_controller/resyncaudio/policies.h"
+#include "trackrenderer/core/gst_utils.h"
+#include "trackrenderer/core/gstobject_guard.h"
+#include "trackrenderer/core/track_util.h"
+#include "trackrenderer/core/utils/log.h"
+#include "trackrenderer/core/utils/product_cfg.h"
+#include "trackrenderer/display.h"
+#include "trackrenderer/error.h"
+#include "trackrenderer/resourcemanager.h"
+#include "trackrenderer/trackrenderer_vconf.h"
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+#include "trackrenderer/subtitle_attr_parser.h"
+#endif
+
+namespace {
+
+constexpr char kTrackRendererPipelineName[] = "TrackRenderer";
+
+constexpr guint64 kMaxByteOfSubtitleSrcQueue = 1024;  // 1KB
+
+const char kPadProbeAudioIdle[] = "AUDIO_IDLE_DOWNSTREAM";
+const char kPadProbeAudioBlock[] = "AUDIO_BLOCK_DOWNSTREAM";
+const char kPadProbeVideoBlock[] = "VIDEO_BLOCK_DOWNSTREAM";
+const char kPadProbeSubtitleBlock[] = "SUBTITLE_BLOCK_DOWNSTREAM";
+const char kPadProbeVideoPeekBlock[] = "VIDEO_PEEK_BLOCK_DOWNSTREAM";
+const char kPadProbeVideoDecoded[] = "VIDEO_DECODED_DOWNSTREAM";
+const char kPadProbeVideoDecInputBlock[] = "VIDEO_DECODER_INPUT_DOWNSTREAM";
+
+constexpr char kDecoderPluginConfPath[] = "/etc/multimedia/gst-openmax.conf";
+constexpr char kTzDecoderPluginConfPath[] =
+    "/etc/multimedia/gst-tz-openmax.conf";
+constexpr char kPlayerIniPath[] = "/etc/multimedia/mmfw_player.ini";
+
+using ComponentWithCodec = std::pair<std::string, std::string>;
+
+static std::once_flag plugin_loaded;
+static std::map<ComponentWithCodec, std::string> PluginTable;  // loadable table
+static bool IsDualSoundMode = false;
+
+enum class DeviceSinkElementType {
+  kVideoSink,
+  kAudioSink,
+  kPcmAudiosink,
+};
+static std::map<DeviceSinkElementType, std::string> SinkPluginTable;
+
+enum class PluginType {
+  kHw,
+  kSw,
+};
+static std::map<std::string, PluginType> PluginTypeTable;
+
+enum class VideoColorFormat {
+  kColorFormatI420,
+  kColorFormatNV12,
+  kColorFormatYUY2,
+  kColorFormatUYVY,
+  kColorFormatI422,
+  kColorFormatNV16,
+  kColorFormatST12,
+  kColorFormatSN12
+};
+
+#if 0
+const std::map<ComponentWithCodec, std::string> kPluginMap = {
+    // rank = 260
+    // "omx_mpeg4dec" also can handle x-h264 --> version is different.
+    {{"OMX.SDP.video_decoder.mfc0", "video/mpeg"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-h264"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-h263"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-wmv"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-vp8"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-pn-realvideo"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-avs"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-avs+"}, "omx_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-msmpeg"}, "omx_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-xvid"}, "omx_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-3ivx"}, "omx_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.vr360dec", "video/x-vp9"},
+     "omx_uhd_videodec_vr360"},
+    {{"OMX.SDP.video_decoder.vr360dec", "video/x-h264"},
+     "omx_uhd_videodec_vr360"},
+    {{"OMX.SDP.video_decoder.vr360dec", "video/x-av1"},
+     "omx_uhd_videodec_vr360"},
+    // rank = 259
+    // "omx_mpeg4dec_1" also can handle x-h264 --> version is different.
+    {{"OMX.SDP.video_decoder.mfc1", "video/mpeg"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-h264"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-h263"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-wmv"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-vp8"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-pn-realvideo"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-avs"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-avs+"}, "omx_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-msmpeg"}, "omx_mpeg4dec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-xvid"}, "omx_mpeg4dec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-3ivx"}, "omx_mpeg4dec_1"},
+    // rank = 258
+    {{"OMX.SDP.video_decoder.mfc2", "video/x-h264"}, "omx_videodec_2"},
+    // rank = 257
+    {{"OMX.SDP.video_decoder.mfc3", "video/x-h264"}, "omx_videodec_3"},
+    // rank = 256
+    {{"OMX.SDP.video_decoder.mfc4", "video/x-h264"}, "omx_videodec_4"},
+    // rank = 258
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-h264"}, "omx_uhd_videodec"},
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-vp9"}, "omx_uhd_videodec"},
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-h265"}, "omx_uhd_videodec"},
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-av1"}, "omx_uhd_videodec"},
+    {{"OMX.SDP.video_decoder.hevc8k", "video/x-h265"}, "omx_uhd8k_videodec"},
+    {{"OMX.SDP.video_decoder.hevc8k", "video/x-av1"}, "omx_uhd8k_videodec"},
+    // TODO: add switch 4K 8K logic
+    // rank = 257
+    {{"OMX.SDP.video_decoder.dvde1", "video/x-vp9"}, "omx_videodec_5"},
+    {{"OMX.SDP.video_decoder.dvde1", "video/x-h265"}, "omx_videodec_5"},
+    // rank = 260
+    // "omx_uhd_mjpegdec"  also can handle x-h265 --> resolution is different.
+    {{"OMX.SDP.video_decoder.mjpeg", "video/x-jpeg"}, "omx_mjpegdec"},
+    // rand = 259
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/mpeg"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-aac"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-true-hd"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac3"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-eac3"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/ac3"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac4"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-adpcm"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-wma"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-vorbis"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-pn-realaudio"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mha1"},
+     "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mhm1"},
+     "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-alaw"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-mulaw"}, "omx_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-opus"}, "omx_audiodec"},
+
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/mpeg"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-aac"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-true-hd"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac3"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-eac3"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/ac3"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac4"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-adpcm"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-wma"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-vorbis"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-pn-realaudio"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mha1"},
+     "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mhm1"},
+     "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-alaw"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-mulaw"}, "omx_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-opus"}, "omx_audiodec_1"},
+    // rand = 258
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/mpeg"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-aac"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-true-hd"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac3"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-eac3"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/ac3"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac4"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-adpcm"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-wma"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-vorbis"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-pn-realaudio"},
+     "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mha1"},
+     "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mhm1"},
+     "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-alaw"}, "omx_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-mulaw"}, "omx_mmaudiodec"},
+    // tz case
+    {{"OMX.SDP.video_decoder.mfc0", "video/mpeg_tz"}, "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-h264_tz"}, "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-h263_tz"}, "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-wmv_tz"}, "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-vp8_tz"}, "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-pn-realvideo_tz"},
+     "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-avs_tz"}, "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-avs+_tz"}, "omx_tz_videodec_0"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-msmpeg_tz"}, "omx_tz_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-xvid_tz"}, "omx_tz_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/x-3ivx_tz"}, "omx_tz_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/mpeg_tz"}, "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-h264_tz"}, "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-h263_tz"}, "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-wmv_tz"}, "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-vp8_tz"}, "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-pn-realvideo_tz"},
+     "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-avs_tz"}, "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/x-avs+_tz"}, "omx_tz_videodec_1"},
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-h264_tz"}, "omx_tz_uhd_videodec"},
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-vp9_tz"}, "omx_tz_uhd_videodec"},
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-h265_tz"}, "omx_tz_uhd_h265dec"},
+    {{"OMX.SDP.video_decoder.dvde0", "video/x-av1_tz"}, "omx_tz_uhd_videodec"},
+    {{"OMX.SDP.video_decoder.hevc8k", "video/x-h265_tz"},
+     "omx_tz_uhd8k_videodec"},
+    {{"OMX.SDP.video_decoder.hevc8k", "video/x-av1_tz"},
+     "omx_tz_uhd8k_videodec"},
+    {{"OMX.SDP.video_decoder.dvde1", "video/x-vp9_tz"}, "omx_tz_videodec_5"},
+    {{"OMX.SDP.video_decoder.dvde1", "video/x-h265_tz"}, "omx_tz_videodec_5"},
+    {{"OMX.SDP.video_decoder.mjpeg", "video/x-jpeg_tz"}, "omx_tz_mjpegdec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/mpeg_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-aac_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac3_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-eac3_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/ac3_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-ac4_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-adpcm_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-wma_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-vorbis_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-alaw_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-mulaw_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mha1_tz"},
+     "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-gst-fourcc-mhm1_tz"},
+     "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-opus_tz"}, "omx_tz_audiodec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST0", "audio/x-raw_tz"}, "omx_tz_lpcmdec"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/mpeg_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-aac_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac3_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-eac3_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/ac3_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-ac4_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-adpcm_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-wma_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-vorbis_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-alaw_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-mulaw_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mha1_tz"},
+     "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-gst-fourcc-mhm1_tz"},
+     "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-opus_tz"}, "omx_tz_audiodec_1"},
+    {{"OMX.SDP.AUDIO.DECODER.INST1", "audio/x-raw_tz"}, "omx_tz_lpcmdec_1"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/mpeg_tz"}, "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-aac_tz"}, "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac3_tz"}, "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-eac3_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/ac3_tz"}, "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-ac4_tz"}, "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-adpcm_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-wma_tz"}, "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-vorbis_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-pn-realaudio_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mha1_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-gst-fourcc-mhm1_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-alaw_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-mulaw_tz"},
+     "omx_tz_mmaudiodec"},
+    {{"OMX.SDP.AUDANY_PRIMARY.Decoder", "audio/x-raw_tz"}, "omx_tz_mmaudiodec"},
+    // SW decoder
+    {{"FFMPEG.SW.Decoder", "video/audio"}, "ffdec_xxx"}, };
+#endif
+
+using ComponentWithSwCodec = std::pair<std::string, int>;  // mime,version
+const std::map<ComponentWithSwCodec, std::string> kSwPluginMap = {
+    {{"video/mpeg", 1}, "ffdec_mpeg1video"},
+    {{"video/mpeg", 2}, "ffdec_mpeg2video"},
+    {{"video/mpeg", 4}, "ffdec_mpeg4"},
+    {{"video/x-h264", 0}, "ffdec_h264"},
+    {{"video/x-vp9", 0}, "ffdec_vp9"},
+    {{"video/x-vp8", 0}, "ffdec_vp8"},
+    {{"video/x-vp6", 0}, "ffdec_vp6"},
+    {{"video/x-h265", 0}, "ffdec_hevc"},
+    {{"video/x-msmpeg", 41}, "ffdec_msmpeg4v1"},
+    {{"video/x-msmpeg", 42}, "ffdec_msmpeg4v2"},
+    {{"video/x-msmpeg", 43}, "ffdec_msmpeg4"},
+    {{"video/x-wmv", 1}, "ffdec_wmv1"},
+    {{"video/x-wmv", 2}, "ffdec_wmv2"},
+    {{"video/x-wmv", 3}, "ffdec_wmv3"},
+    {{"audio/mpeg", 1}, "ffdec_mp3"},
+    {{"audio/x-opus", 0}, "ffdec_opus"},
+    {{"audio/mpeg", 2}, "ffdec_aac"},
+    {{"audio/mpeg", 4}, "ffdec_aac"},
+    {{"audio/x-ac3", 0}, "ffdec_ac3"},
+    {{"audio/x-eac3", 0}, "ffdec_eac3"},
+    {{"audio/x-wma", 1}, "ffdec_wmav1"},
+    {{"audio/x-wma", 2}, "ffdec_wmav2"},
+    {{"audio/x-mulaw", 0}, "ffdec_pcm_mulaw"},
+};
+
+using ComponentWithMpeg4VideoCodec = std::pair<std::string, std::string>;
+using Mpeg4VidoePluginMapType =
+    std::map<ComponentWithMpeg4VideoCodec, std::string>;
+
+const Mpeg4VidoePluginMapType kMpeg4VidoePluginMap = {
+    {{"OMX.SDP.video_decoder.mfc0", "video/mpeg"}, "omx_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/mpeg"}, "omx_mpeg4dec_1"},
+    {{"OMX.SDP.video_decoder.mfc0", "video/mpeg_tz"}, "omx_tz_mpeg4dec"},
+    {{"OMX.SDP.video_decoder.mfc1", "video/mpeg_tz"}, "omx_tz_mpeg4dec_1"},
+};
+
+// Hw clock
+#ifndef PR_TASK_PERF_USER_TRACE
+#define PR_TASK_PERF_USER_TRACE 666
+#endif
+
+constexpr int kBufSize = 256;
+inline void PerfUsrTrace(const char* arg = nullptr) {
+  char buf[kBufSize]{
+      0,
+  };
+  const char* prefix_str = "[PERF][MMPLAYER]";
+  bool use_arg{false};
+  if (arg) {
+    if (strlen(arg) < (kBufSize - strlen(prefix_str))) {
+      use_arg = true;
+    }
+  }
+  snprintf(buf, kBufSize, "%s %s", prefix_str, (use_arg ? arg : ""));
+  prctl(PR_TASK_PERF_USER_TRACE, buf, strlen(buf));
+}
+
+}  // namespace
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace internal {
+
+enum class TrackEncryptionUnit { kNone, kTs, kEs };
+// LCOV_EXCL_START
+void TvplusPerformanceLogs() {
+  FILE* fp = NULL;
+  const char* TVPLUS_POPUP_LOG_FILE_NAME = "/tmp/play_log.txt";
+  TRACKRENDERER_DEBUG("~~~~~~~~~~~~~ [PROFILING LOG ON] ~~~~~~~~~~~~~~~~");
+  if ((fp = fopen(TVPLUS_POPUP_LOG_FILE_NAME, "a+")) != NULL) {
+    struct timespec tp;
+    char unmute[30];
+    clock_gettime(CLOCK_MONOTONIC, &tp);
+    snprintf(unmute, 30, "[um:%d.%d]", (int)tp.tv_sec,
+             (int)tp.tv_nsec / 10000000);
+    fprintf(fp, "%s", unmute);
+    chmod(TVPLUS_POPUP_LOG_FILE_NAME, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    fclose(fp);
+    TRACKRENDERER_DEBUG("~~~~~~~~~~~~~ file write passed ~~~~~~~~~~~~~~~");
+  } else {
+    TRACKRENDERER_DEBUG("~~~~~~~~~~~~~ file write failed ~~~~~~~~~~~~~~~~");
+  }
+}
+// LCOV_EXCL_STOP
+
+bool IsSdkEnabledFeature() {
+#ifdef SDK_ENABLED_FEATURE
+  return true;
+#endif
+  return false;
+}
+
+void GetSoundMode() {
+  int ret = system_info_get_custom_bool(
+      "com.samsung/featureconf/multiview.dualsound", &IsDualSoundMode);
+  if (SYSTEM_INFO_ERROR_NONE != ret) {
+    TRACKRENDERER_ERROR("system_info_get_custom_bool() return error[%d]", ret);
+  }
+}
+
+inline bool IsHwPlugin(const char* plugin_name) {
+  if (PluginTypeTable.count(plugin_name) > 0) {
+    if (PluginTypeTable[plugin_name] == ::PluginType::kHw) return true;
+  }
+  return false;
+}
+
+inline bool IsPcmMimeType(const std::string& mimetype) {
+  return (mimetype == "audio/x-raw");
+}
+
+void GetIniValue(const std::map<std::string, bool>& properties,
+                 const std::string& key, bool* value) {
+  auto look = properties.find(key);
+  if (look == properties.end()) {
+    return;
+  }
+  *value = look->second;
+  return;
+}
+
+TrackEncryptionUnit GetTrackEncryptionUnit(drm::Type type) {
+  if (type == drm::Type::kPlayready) return TrackEncryptionUnit::kEs;
+  if (type == drm::Type::kWidevineCdm) return TrackEncryptionUnit::kEs;
+  if (type == drm::Type::kVerimatrix) return TrackEncryptionUnit::kTs;
+  return TrackEncryptionUnit::kNone;
+}
+
+inline bool IsFhdOrLowerResolution(int width, int height, int max_w,
+                                   int max_h) {
+  int w = max_w ? max_w : width;
+  int h = max_h ? max_h : height;
+  if ((w <= kMaxFhdWidth && h <= kMaxFhdHeight) ||
+      (w <= kMaxFhdHeight && h <= kMaxFhdWidth))
+    return true;
+  TRACKRENDERER_ERROR("w:%d, h:%d, mw:%d, mh:%d!", width, height, max_w, max_h);
+  return false;
+}
+
+inline bool IsUhdResolution(int w, int h) {
+  return ((w > kMaxFhdWidth || h > kMaxFhdHeight) &&
+          (w <= kMaxUhdWidth && h <= kMaxUhdHeight));
+}
+
+inline bool IsUhd8kResolution(int w, int h) {
+  return (w > kMaxUhdWidth || h > kMaxUhdHeight);
+}
+
+inline bool IsAacCodec(const Track& track) {
+  return (track.mimetype.find("audio/mpeg") != std::string::npos &&
+          track.version == 2);
+}
+
+inline bool IsEac3Codec(const std::string& mimetype) {
+  return mimetype.find("audio/x-eac3") != std::string::npos;
+}
+
+inline bool IsAc3Codec(const std::string& mimetype) {
+  return mimetype.find("audio/x-ac3") != std::string::npos;
+}
+
+inline bool IsTzMimeType(const std::string& mimetype) {  // useful when external
+                                                         // audio is present in
+  // verimatrix case as trustzone is not used in this case
+  return (mimetype.find("_tz") != std::string::npos);
+}
+
+inline bool IsVideoRawMimeType(const std::string& mimetype) {
+  return (mimetype.find("video/x-raw") != std::string::npos);
+}
+
+inline bool IsExternalDecryptionCase(const drm::Property& property) {
+  return property.external_decryption;
+}
+
+inline bool IsTzAppSrcElementNecessary(const drm::Property& property,
+                                       const std::string& mimetype) {
+  return IsTzMimeType(mimetype);
+}
+
+inline bool IsDrmEmeElementNecessary(const drm::Property& property,
+                                     const std::string& mimetype) {
+  // Some Apps call setDrm even for plain content (mostly trailers),
+  // but main contents are Drm protected. So we need to check drm_type
+  // as well as mime_type for plain/drm content. (Example app: Stan/Chili)
+  return (GetTrackEncryptionUnit(property.type) == TrackEncryptionUnit::kEs &&
+          IsTzMimeType(mimetype));
+}
+
+inline bool IsTzDecoderElementNecessary(const drm::Property& property,
+                                        const std::string& mimetype) {
+  return IsTzMimeType(mimetype);
+}
+
+inline bool IsDecoderElementNecessary(const std::string& mimetype) {
+  return !IsPcmMimeType(mimetype) && !IsVideoRawMimeType(mimetype);
+}
+
+inline bool IsDecodedVideoBufferNeeded(DecodedVideoFrameBufferType& type) {
+  return (type != DecodedVideoFrameBufferType::kNone);
+}
+
+inline bool IsDisplayNeeded(DisplayType& type) {
+  return (type != DisplayType::kNone);
+}
+
+inline bool IsAvailableCodecChange(const Track& track) {
+  if (internal::IsAacCodec(track) || internal::IsAc3Codec(track.mimetype) ||
+      internal::IsEac3Codec(track.mimetype))
+    return true;
+  return false;
+}
+
+constexpr int kVideoBufferPlaneMax = 4;
+struct VideoStreamDataType {
+  tbm_format format = TBM_FORMAT_NV12;          //< image format
+  Geometry crop_area;                           //< crop info of video buffer
+  int width = 0;                                //< width of video buffer
+  int height = 0;                               //< height of video buffer
+  tbm_bo bo[kVideoBufferPlaneMax] = {nullptr};  //< TBM buffer object
+  void* internal_buffer = nullptr;              //< Internal buffer pointer
+  int stride[kVideoBufferPlaneMax] = {0};       //< stride of plane
+  int elevation[kVideoBufferPlaneMax] = {0};    //< elevation of plane
+};
+
+void SetGeometry(Geometry* geom, const int& x, const int& y, const int& w,
+                 const int& h) {
+  geom->x = x;
+  geom->y = y;
+  geom->w = w;
+  geom->h = h;
+  return;
+}
+
+bool CopySwCodec(GstBuffer* decodedBuffer, const VideoStreamDataType& stream) {
+  tbm_bo bo_Y = stream.bo[GST_VIDEO_COMP_Y];
+  tbm_bo bo_C = stream.bo[GST_VIDEO_COMP_U];
+
+  tbm_bo_handle ap_bo_handle = {
+      nullptr,
+  };
+
+  GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
+      GST_MINI_OBJECT(decodedBuffer), g_quark_from_static_string("tbm_bo")));
+  if (s) {
+    if (!gst_structure_get(s, "tbm_bo_hnd", G_TYPE_POINTER, &ap_bo_handle,
+                           NULL)) {
+      TRACKRENDERER_ERROR("Buffer don't have tbm_bo_hnd structure");
+      return false;
+    }
+  } else {
+    TRACKRENDERER_ERROR("Buffer don't have tbm_bo structure");
+    return false;
+  }
+
+  tbm_bo_handle bo_handle_Y =
+      tbm_bo_map(bo_Y, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+  if (!bo_handle_Y.ptr) {
+    TRACKRENDERER_ERROR("TBM get error : bo_handle_Y.ptr is NULL");
+    return false;
+  }
+  for (int i = 0; i < stream.height; i++) {
+    memcpy((unsigned char*)(bo_handle_Y.ptr) +
+               (i * stream.stride[GST_VIDEO_COMP_Y]),
+           (unsigned char*)(ap_bo_handle.ptr) + (i * stream.width),
+           stream.width);
+  }
+  tbm_bo_unmap(bo_Y);
+
+  tbm_bo_handle bo_handle_C =
+      tbm_bo_map(bo_C, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+  if (!bo_handle_C.ptr) {
+    TRACKRENDERER_ERROR("TBM get error : bo_handle_C.ptr is NULL");
+    return false;
+  }
+  int data_size = stream.width * stream.height;
+  for (int i = 0; i < stream.height / 2; i++) {
+    memcpy((unsigned char*)(bo_handle_C.ptr) +
+               (i * stream.stride[GST_VIDEO_COMP_U]),
+           (unsigned char*)(ap_bo_handle.ptr) + data_size + (i * stream.width),
+           stream.width);
+  }
+  tbm_bo_unmap(bo_C);
+
+  return true;
+}
+
+bool CopyHwCodec(const VideoStreamDataType& stream, int y_viraddr,
+                 int c_viraddr, int y_linesize, int c_linesize,
+                 VideoColorFormat color_format) {
+  tbm_bo bo_Y = stream.bo[GST_VIDEO_COMP_Y];
+  tbm_bo bo_C = stream.bo[GST_VIDEO_COMP_U];
+  tbm_bo_handle bo_handle_Y =
+      tbm_bo_map(bo_Y, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+  if (!bo_handle_Y.ptr) {
+    TRACKRENDERER_ERROR("TBM get error : bo_handle_Y.ptr is NULL");
+    return false;
+  }
+
+  for (int i = 0; i < stream.height; i++) {
+    memcpy((unsigned char*)(bo_handle_Y.ptr) +
+               (i * stream.stride[GST_VIDEO_COMP_Y]),
+           (unsigned char*)y_viraddr, stream.width);
+    y_viraddr += y_linesize;
+  }
+  tbm_bo_unmap(bo_Y);
+
+  tbm_bo_handle bo_handle_C =
+      tbm_bo_map(bo_C, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+  if (!bo_handle_C.ptr) {
+    TRACKRENDERER_ERROR("TBM get error : bo_handle_C.ptr is NULL");
+    return false;
+  }
+  if (color_format ==
+      VideoColorFormat::kColorFormatNV16) {  // NV16, convert to NV12
+    for (int i = 0; i < stream.height / 2; i++) {
+      memcpy((unsigned char*)(bo_handle_C.ptr) +
+                 (i * stream.stride[GST_VIDEO_COMP_U]),
+             (unsigned char*)c_viraddr, stream.width);
+      c_viraddr += c_linesize * 2;
+    }
+  } else if (color_format == VideoColorFormat::kColorFormatNV12) {  // NV12
+    for (int i = 0; i < stream.height / 2; i++) {
+      memcpy((unsigned char*)(bo_handle_C.ptr) +
+                 (i * stream.stride[GST_VIDEO_COMP_U]),
+             (unsigned char*)c_viraddr, stream.width);
+      c_viraddr += c_linesize;
+    }
+  }
+  tbm_bo_unmap(bo_C);
+  return true;
+}
+
+tbm_surface_h CreateTbmSurfaceWithBos(VideoStreamDataType& stream) {
+  unsigned int bo_num = 0;
+  for (int i = 0; i < internal::kVideoBufferPlaneMax; i++) {
+    if (stream.bo[i]) bo_num++;
+  }
+  tbm_surface_info_s surface_info;
+  memset(&surface_info, 0, sizeof(surface_info));
+  surface_info.width = stream.width;
+  surface_info.height = stream.height;
+  surface_info.format = TBM_FORMAT_NV12;
+  surface_info.bpp = tbm_surface_internal_get_bpp(surface_info.format);
+  surface_info.num_planes =
+      tbm_surface_internal_get_num_planes(surface_info.format);
+  for (unsigned int i = 0; i < surface_info.num_planes; i++) {
+    surface_info.planes[i].stride = stream.stride[i];
+    surface_info.planes[i].size = stream.stride[i] * stream.elevation[i];
+    if (i < bo_num) {
+      surface_info.planes[i].offset = 0;
+    } else {
+      surface_info.planes[i].offset =
+          surface_info.planes[i - 1].offset + surface_info.planes[i - 1].size;
+    }
+    surface_info.size += surface_info.planes[i].size;
+  }
+  tbm_surface_h tbm_surf =
+      tbm_surface_internal_create_with_bos(&surface_info, stream.bo, bo_num);
+  if (!tbm_surf) {
+    TRACKRENDERER_ERROR("failed to create tbm surface");
+    return nullptr;
+  }
+  return tbm_surf;
+}
+
+#ifdef SOUNDBAR_PRODUCT
+bool ScaleHwCodecWithGa(tbm_bufmgr bufmgr, const VideoStreamDataType& stream,
+                        int y_phyaddr, int c_phyaddr, int y_linesize,
+                        int c_linesize, VideoColorFormat color_format) {
+  return false;
+}
+#else
+bool TbmScale(tbm_bufmgr bufmgr, Graphics_ColorFormat_k colorMode,
+              std::uint32_t src_handle, const Geometry& src_rect,
+              int src_linesize, std::uint32_t dst_handle,
+              const Geometry& dst_rect, int dst_linesize) {
+  GraphicsGAScaleInfo ga_info;
+  memset(&ga_info, 0, sizeof(GraphicsGAScaleInfo));
+
+  ga_info.ga_mode = GRAPHICS_GA_SCALE_MODE;
+  ga_info.rop_mode = GRAPHICS_GA_ROP_COPY;
+  ga_info.ga_op_type = GRAPHICS_GA_SCALE;
+  ga_info.pre_alphamode = 0;
+  ga_info.ca_value = 0;
+  ga_info.rop_on_off = 0;
+  ga_info.color_format = colorMode;
+
+  ga_info.src_handle = src_handle;
+  ga_info.src_hbytesize = src_linesize;
+  ga_info.src_rect.x = src_rect.x;
+  ga_info.src_rect.y = src_rect.y;
+  ga_info.src_rect.w = src_rect.w;
+  ga_info.src_rect.h = src_rect.h;
+
+  ga_info.dst_handle = dst_handle;
+  ga_info.dst_hbytesize = dst_linesize;
+  ga_info.dst_rect.x = dst_rect.x;
+  ga_info.dst_rect.y = dst_rect.y;
+  ga_info.dst_rect.w = dst_rect.w;
+  ga_info.dst_rect.h = dst_rect.h;
+
+  if (Gfx_GA_Scale(bufmgr, &ga_info) < 0) {
+    TRACKRENDERER_ERROR("Gfx_GA_Scale fail");
+    return false;
+  }
+  return true;
+}
+
+bool ScaleHwCodecWithGa(tbm_bufmgr bufmgr, const VideoStreamDataType& stream,
+                        int y_phyaddr, int c_phyaddr, int y_linesize,
+                        int c_linesize, VideoColorFormat color_format) {
+  Geometry src_rect, dst_rect;
+
+  tbm_bo bo_Y = stream.bo[GST_VIDEO_COMP_Y];
+  tbm_bo bo_C = stream.bo[GST_VIDEO_COMP_U];
+  tbm_bo_handle bo_handle_Y = tbm_bo_get_handle(bo_Y, TBM_DEVICE_2D);
+  if (!bo_handle_Y.u32) {
+    TRACKRENDERER_ERROR("TBM get error : bo_handle_Y.u32 is NULL");
+    return false;
+  }
+
+  tbm_bo_handle bo_handle_C = tbm_bo_get_handle(bo_C, TBM_DEVICE_2D);
+  if (!bo_handle_C.u32) {
+    TRACKRENDERER_ERROR("TBM get error : bo_handle_C.u32 is NULL");
+    return false;
+  }
+
+  SetGeometry(&src_rect, stream.crop_area.x, stream.crop_area.y,
+              stream.crop_area.w, stream.crop_area.h);
+  SetGeometry(&dst_rect, 0, 0, stream.width, stream.height);
+  if (!TbmScale(bufmgr, GRAPHICS_GA_FORMAT_8BPP, y_phyaddr, src_rect,
+                y_linesize, bo_handle_Y.u32, dst_rect,
+                stream.stride[GST_VIDEO_COMP_Y])) {
+    TRACKRENDERER_ERROR("Y data Ga copy fail");
+    return false;
+  }
+
+  if (color_format == VideoColorFormat::kColorFormatNV16) {  // NV16
+    SetGeometry(&src_rect, stream.crop_area.x / 2, stream.crop_area.y,
+                stream.crop_area.w / 2, stream.crop_area.h);
+    SetGeometry(&dst_rect, 0, 0, stream.width / 2, stream.height / 2);
+  } else if (color_format == VideoColorFormat::kColorFormatNV12) {  // NV12
+    SetGeometry(&src_rect, stream.crop_area.x / 2, stream.crop_area.y / 2,
+                stream.crop_area.w / 2, stream.crop_area.h / 2);
+    SetGeometry(&dst_rect, 0, 0, stream.width / 2, stream.height / 2);
+  }
+  if (!TbmScale(bufmgr, GRAPHICS_GA_FORMAT_16BPP, c_phyaddr, src_rect,
+                c_linesize, bo_handle_C.u32, dst_rect,
+                stream.stride[GST_VIDEO_COMP_U])) {
+    TRACKRENDERER_ERROR("UV data Ga copy fail");
+    return false;
+  }
+  return true;
+}
+#endif
+
+int ToBufferTypeForSink(const DecodedVideoFrameBufferType& type) {
+  // 0:copy, 1:reference, -1:none  (refer to gstwaylnadsink)
+  constexpr int kCopy = 0;
+  constexpr int kReference = 1;
+  constexpr int kNone = -1;
+
+  switch (type) {
+    case DecodedVideoFrameBufferType::kCopy:
+      return kCopy;
+    case DecodedVideoFrameBufferType::kReference:
+      return kReference;
+    default:
+      return kNone;
+  }
+  return kNone;
+}
+
+inline bool IsLowLatencyModeDisableAVSync(std::uint32_t low_latency_mode) {
+  constexpr std::uint32_t kAVSync = 0x0100;
+  return (low_latency_mode & kAVSync) ? true : false;
+}
+inline bool IsLowLatencyModeDisablePreroll(std::uint32_t low_latency_mode) {
+  constexpr std::uint32_t kPreroll = 0x0200;
+  return (low_latency_mode & kPreroll) ? true : false;
+}
+
+// LCOV_EXCL_START
+int GetVideoWidth(const GstCaps* caps) {
+  GstStructure* structure = gst_caps_get_structure(caps, 0);
+  if (!structure) return 0;
+
+  int width = 0;
+  if (!gst_structure_get_int(structure, "width", &width)) return 0;
+
+  return width;
+}
+
+int GetVideoHeight(const GstCaps* caps) {
+  GstStructure* structure = gst_caps_get_structure(caps, 0);
+  if (!structure) return 0;
+
+  int height = 0;
+  if (!gst_structure_get_int(structure, "height", &height)) return 0;
+
+  return height;
+}
+// LCOV_EXCL_STOP
+
+void LoadDecoderPluginTable_(const char* path) {
+  gchar* config = nullptr;
+  if (!g_file_get_contents(path, &config, nullptr, nullptr)) {
+    TRACKRENDERER_ERROR("could not find config file!");
+    return;
+  }
+
+  GstStructure* element_table =
+      gst_structure_new_empty("element_table");  // leak caution
+  GstStructure* element = nullptr;
+  gchar* start = config;
+
+  while ((element = gst_structure_from_string(start, &start))) {
+    const gchar* element_name = gst_structure_get_name(element);
+    gst_structure_set(element_table, element_name, GST_TYPE_STRUCTURE, element,
+                      nullptr);
+  }
+
+  unsigned int cnt = gst_structure_n_fields(element_table);
+  for (unsigned int i = 0; i < cnt; i++) {
+    const gchar* element_name = gst_structure_nth_field_name(element_table, i);
+    gst_structure_get(element_table, element_name, GST_TYPE_STRUCTURE, &element,
+                      nullptr);
+    const gchar* component_name =
+        gst_structure_get_string(element, "component-name");
+    const gchar* sink_caps = gst_structure_get_string(element, "sink");
+    // TRACKRENDERER_ERROR("plugin name [%s] comp-name [%s]", element_name,
+    //                    component_name);
+    ::PluginTypeTable.emplace(element_name, PluginType::kHw);
+
+    std::string caps_str(sink_caps);
+    std::size_t offset = 0;
+    while (1) {
+      // TRACKRENDERER_ERROR("offset %d", offset);
+      std::size_t start_pos = caps_str.find("video/", offset);
+      if (start_pos == std::string::npos) {
+        start_pos = caps_str.find("audio/", offset);
+        if (start_pos == std::string::npos) break;
+      }
+
+      std::string mimetype;
+      std::size_t end_pos = caps_str.find(';', start_pos);
+      if (end_pos == std::string::npos) {
+        end_pos = caps_str.find(',', start_pos);
+        if (end_pos == std::string::npos) {
+          mimetype = caps_str.substr(start_pos);
+        } else {
+          mimetype = caps_str.substr(start_pos, end_pos - start_pos);
+        }
+        // TRACKRENDERER_ERROR("parsed mimetype :: %s", mimetype.c_str());
+        ::PluginTable.emplace(
+            std::pair<std::string, std::string>(component_name, mimetype),
+            element_name);
+        break;  // last item or only one item.
+      } else {
+        // gen sub string video/ or audio/ ~ ';'
+        std::string sub_caps_str =
+            caps_str.substr(start_pos, end_pos - start_pos);
+        //        TRACKRENDERER_ERROR("sub str :: %s   >>> start pos[%d]  end
+        //        pos [%d]", sub_caps_str.c_str(), start_pos, end_pos);
+        std::size_t sub_end_pos = sub_caps_str.find(',');
+        if (sub_end_pos == std::string::npos) {
+          mimetype = sub_caps_str;
+        } else {
+          mimetype = sub_caps_str.substr(0, sub_end_pos);
+        }
+        ::PluginTable.emplace(
+            std::pair<std::string, std::string>(component_name, mimetype),
+            element_name);
+      }
+      offset = end_pos;
+      //      TRACKRENDERER_ERROR("start pos [%d],  end pos [%d]", start_pos,
+      //      end_pos);
+      // TRACKRENDERER_ERROR("parsed mimetype :: %s", mimetype.c_str());
+    }
+  }
+  gst_structure_free(element_table);
+}
+
+std::string GetIniString(dictionary* dict, const char* key, char* default_val) {
+  const gchar* value = iniparser_getstring(dict, key, default_val);
+  constexpr int kMaxIniStrLen = 100;
+  if (value && strlen(value) > 0 && strlen(value) < kMaxIniStrLen) {
+    return value;
+  } else {
+    return {};
+  }
+}
+
+void LoadSinkPluginTable() {
+  dictionary* dict = nullptr;
+  dict = iniparser_load(kPlayerIniPath);
+  if (!dict) {
+    TRACKRENDERER_ERROR("Fail to load ini file");
+    return;
+  }
+
+  char default_video_sink_name[] = "directvideosink";
+  SinkPluginTable.emplace(
+      DeviceSinkElementType::kVideoSink,
+      GetIniString(dict, "general:videosink element overlay",
+                   default_video_sink_name));
+
+  char default_audio_sink_name[] = "mmaudiosink";
+  SinkPluginTable.emplace(
+      DeviceSinkElementType::kAudioSink,
+      GetIniString(dict, "general:audiosink element", default_audio_sink_name));
+
+  SinkPluginTable.emplace(DeviceSinkElementType::kPcmAudiosink,
+                          GetIniString(dict, "general:pcmaudiosink element",
+                                       default_audio_sink_name));
+}
+
+void LoadPluginTable() {
+  LoadDecoderPluginTable_(kDecoderPluginConfPath);
+  LoadDecoderPluginTable_(kTzDecoderPluginConfPath);
+  LoadSinkPluginTable();
+  GetSoundMode();
+
+  /*
+    for (auto& item : ::PluginTable) {
+      TRACKRENDERER_ERROR(" PluginTable :: [%s][%s][%s]",
+                          (item.first).first.c_str(),
+    (item.first).second.c_str(), item.second.c_str());
+    }
+
+    for (auto& item : ::PluginTypeTable) {
+      TRACKRENDERER_ERROR(" PluginTypeTable :: [%s][%d]", (item.first).c_str(),
+                          static_cast<int>(item.second));
+    }
+  */
+  for (auto& item : ::SinkPluginTable) {
+    TRACKRENDERER_ERROR(" SinkPluginTable :: [%d][%s]",
+                        static_cast<int>(item.first), (item.second).c_str());
+  }
+}
+
+bool CheckMpeg4Video(const std::string& mime_type, const int version) {
+  const std::string video_mpeg = "video/mpeg";
+  return ((mime_type.find(video_mpeg) != std::string::npos) && version == 4);
+}
+
+int GetAvocSourceType(bool is_main_device, bool swdecoder,
+                      const std::string& mimetype) {
+  if (swdecoder || internal::IsPcmMimeType(mimetype)) return AUDIO_MM;
+  int sec_ctl_source =
+      is_main_device ? AUDIO_MULTIMEDIA_DEC0 : AUDIO_MULTIMEDIA_DEC1;
+  return sec_ctl_source;
+}
+
+int GetAudioOut(bool is_main_device) {
+  constexpr int kAudioMainOut = 0;
+  constexpr int kAudioSubOut = 1;
+  int audio_out = (is_main_device) ? kAudioMainOut : kAudioSubOut;
+  return audio_out;
+}
+
+bool FillVideoStreamDataAndTbmSurface(internal::VideoStreamDataType* stream,
+                                      tbm_surface_h* tbm_surf_t,
+                                      const int width, const int height) {
+  if (stream == nullptr || tbm_surf_t == nullptr) {
+    TRACKRENDERER_ERROR("stream[%p] or tbm_surf_t[%p] is nullptr", stream,
+                        tbm_surf_t);
+    return false;
+  }
+
+  stream->format = TBM_FORMAT_NV12;
+  stream->width = width;
+  stream->height = height;
+  stream->elevation[GST_VIDEO_COMP_Y] = height;
+  stream->elevation[GST_VIDEO_COMP_U] = height / 2;
+
+  *tbm_surf_t =
+      tbm_surface_create(stream->width, stream->height, TBM_FORMAT_NV12);
+
+  tbm_surface_internal_get_plane_data(
+      *tbm_surf_t, GST_VIDEO_COMP_Y, NULL, NULL,
+      (uint32_t*)&stream->stride[GST_VIDEO_COMP_Y]);
+  tbm_surface_internal_get_plane_data(
+      *tbm_surf_t, GST_VIDEO_COMP_U, NULL, NULL,
+      (uint32_t*)&stream->stride[GST_VIDEO_COMP_U]);
+
+  stream->bo[GST_VIDEO_COMP_Y] =
+      tbm_surface_internal_get_bo(*tbm_surf_t, GST_VIDEO_COMP_Y);
+  if (!stream->bo[GST_VIDEO_COMP_Y]) {
+    TRACKRENDERER_ERROR("[bo Y] tbm_surface_internal_get_bo failed");
+    return false;
+  }
+
+  stream->bo[GST_VIDEO_COMP_U] =
+      tbm_surface_internal_get_bo(*tbm_surf_t, GST_VIDEO_COMP_U);
+  if (!stream->bo[GST_VIDEO_COMP_U]) {
+    TRACKRENDERER_ERROR("[bo C] tbm_surface_internal_get_bo failed");
+    return false;
+  }
+  return true;
+}
+
+}  // namespace internal
+
+TrackRenderer::TrackRenderer() noexcept : caps_builder_(kCapsRecipes_) {
+  resource_manager_.reset(new ResourceManager(this));
+  display_.reset(new Display);
+  TRACKRENDERER_DEBUG_P(this, "Display instance > %p", display_.get());
+  screen_saver_.reset(new ScreenSaver);
+  latency_manager_.reset(new LatencyManager(this));
+  resync_audio_policy_.reset(new resync_audio::DummyPolicy());
+  playback_info_ = debug::PlayinfoSetter::Create();
+  SetDefaultAttributeValue_();
+  InitConfigSetterTable_();
+  std::call_once(::plugin_loaded, [this]() { internal::LoadPluginTable(); });
+}
+
+TrackRenderer::~TrackRenderer() {
+  TRACKRENDERER_ENTER_P(this);
+  resource_manager_.reset();
+  latency_manager_.reset();
+  UnsetVconfCb_();
+  TRACKRENDERER_LEAVE_P(this);
+}
+
+bool TrackRenderer::Start() {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (state_ == State::kResourceConflicted) return true;
+  if (!pipeline_) {
+    return false;
+  }
+  /*
+    if(still_mode_type_ == StillMode::kOff) {
+      pipeline_->SetProperty(Elements::kSinkVideo, "still-mode", FALSE);
+    }
+  */
+  pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
+  pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
+  if (state_ < State::kWorking) return false;
+  target_substate_ = SubState::kPlaying;
+  pipeline_->SetState(Elements::kPipeline, GST_STATE_PLAYING);
+#if 0
+  internal::TvplusPerformanceLogs();
+#endif
+  bool value = false;
+  internal::GetIniValue(properties_, "generate_dot", &value);
+  if (value) pipeline_->GenerateDot("plusplayer_trackrenderer_start");
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::Stop() {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  resource_cv_.notify_one();
+  if (state_ == State::kStopped) {
+    TRACKRENDERER_LEAVE_P(this);
+    return true;
+  }
+  if (state_ != State::kResourceConflicted) state_ = State::kStopped;
+  if (!pipeline_) {
+    TRACKRENDERER_LEAVE_P(this);
+    return true;
+  }
+  /*
+    if(still_mode_type_ == StillMode::kOn) {
+      pipeline_->SetProperty(Elements::kSinkVideo, "still-mode", TRUE);
+    }
+  */
+  TRACKRENDERER_INFO_P(this, "Set pipeline state to GST_STATE_NULL.");
+  UnsetResourceCenterCallback_();
+  StopAudioEasing_();
+  pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
+  pipeline_->PadRemoveProbe(kPadProbeVideoDecoded);
+  pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
+  pipeline_->SetState(Elements::kPipeline, GST_STATE_NULL);
+  SetVr360GpuModeSecure_(false);
+  ReleaseResource_();
+  playback_info_->VconfSetMsgHide();
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+void TrackRenderer::SetVideoQualityInfo_() {
+  GstCaps* video_caps = nullptr;
+  pipeline_->GetProperty(Elements::kAppSrcVideo, "caps", &video_caps);
+
+  if (video_caps == nullptr) return;
+  auto video_caps_guard = gstguard::make_guard(video_caps);
+  auto new_caps_guard = gstguard::make_guard(gst_caps_copy(video_caps));
+
+  GstStructure* structure = gst_caps_get_structure(new_caps_guard.get(), 0);
+  const gchar* stream_type = gst_structure_get_string(structure, "stream-type");
+  if (stream_type) gst_structure_set_name(structure, stream_type);
+
+  int max_w = 0, max_h = 0;
+  if (!gst_structure_get_int(structure, "maxwidth", &max_w))
+    gst_structure_get_int(structure, "width", &max_w);
+  if (!gst_structure_get_int(structure, "maxheight", &max_h))
+    gst_structure_get_int(structure, "height", &max_h);
+
+  if (internal::IsUhd8kResolution(max_w, max_h)) {
+    max_w = kMaxUhd8kWidth;
+    max_h = kMaxUhd8kHeight;
+  } else if (internal::IsUhdResolution(max_w, max_h)) {
+    max_w = kMaxUhdWidth;
+    max_h = kMaxUhdHeight;
+  } else {
+    max_w = kMaxFhdWidth;
+    max_h = kMaxFhdHeight;
+  }
+  gst_caps_set_simple(new_caps_guard.get(), "maxwidth", G_TYPE_INT, max_w,
+                      "maxheight", G_TYPE_INT, max_h, NULL);
+
+  TRACKRENDERER_INFO_P(this, "max widh [%d], max height [%d]", max_w, max_h);
+  display_->SetDisplayQualityInfo(new_caps_guard.get());
+}
+
+bool TrackRenderer::Prepare() {
+  TRACKRENDERER_ENTER_E_P(this);
+  std::unique_lock<std::mutex> lock(resource_m_);
+  std::unique_lock<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) {
+    TRACKRENDERER_ERROR_P(this, "already stopped");
+    return false;
+  }
+  SetVconfCb_();
+
+  if (AvocPlayerRegister_() == false) {
+    TRACKRENDERER_ERROR_P(this, "AvocPlayerRegister_() failed");
+    return false;
+  }
+  SetResourceCenterCallback_();
+
+  ::PerfUsrTrace("Prepare GetResource");
+  if (GetResource_(kTrackTypeMax) == false) {
+    TRACKRENDERER_ERROR_P(this, "resource acquire failed.");
+    ReleaseResource_();
+    return false;
+  }
+  SetVr360GpuModeSecure_(true);
+  ::PerfUsrTrace("Prepare CreatePipeline");
+  if (CreatePipeline_() == false) {
+    TRACKRENDERER_ERROR_P(this, "renderer pipeline creation failed");
+    return false;
+  }
+
+  latency_manager_->SetPipeline(pipeline_.get());
+  if (!AvocPlayRequest_()) {
+    TRACKRENDERER_ERROR_P(this, "AvocPlayRequest_() failed");
+    return false;
+  }
+  ::PerfUsrTrace("Prepare InitAvoc end");
+
+  SetAudioOut_();
+
+  int max_width = 0;
+  int max_height = 0;
+  for (const Track& track : trackinfo_) {
+    if (track.type == kTrackTypeVideo) {
+      max_width = track.maxwidth;
+      max_height = track.maxheight;
+      break;
+    }
+  }
+
+  if (internal::IsUhd8kResolution(max_width, max_height)) {
+    constexpr uint32_t kAdaptiveStreaming8kMode =
+        0x80;  // refer to waylandsink properity value.
+    TRACKRENDERER_INFO_P(this, "Set 8K Video quality mode : 0x80");
+    display_->SetVideoQualityMode(kAdaptiveStreaming8kMode);
+  }
+  ::PerfUsrTrace("Prepare SetVideoQualityInfo_ begin");
+  SetVideoQualityInfo_();
+  ::PerfUsrTrace("Prepare SetVideoQualityInfo_ end");
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  auto audio_delay_info = gstguard::make_guard(gst_structure_new(
+      "audio-delay-info", "video-max-width", G_TYPE_UINT, max_width,
+      "video-max-height", G_TYPE_UINT, max_height, NULL));
+  TRACKRENDERER_INFO_P(this, "Set AudioDelayInformation v_res [%d x %d]",
+                       max_width, max_height);
+  pipeline_->SetProperty(Elements::kSinkAudio, "audio-delay-info-for-avsync",
+                         audio_delay_info.get());
+  if (!pipeline_->SetState(Elements::kPipeline, GST_STATE_PAUSED)) {
+    TRACKRENDERER_ERROR_P(this, "Set State to PAUSED failed");
+    return false;
+  }
+  if (is_pardar_updated_) {
+    TRACKRENDERER_INFO_P(this, "is_pardar_updated_ is true");
+    pipeline_->SetParDar(Elements::kDecVideo, par_dar_.time_millisecond,
+                         par_dar_.par_num, par_dar_.par_den, par_dar_.dar_num,
+                         par_dar_.dar_den);
+  }
+  audio_lk.unlock();
+
+  if (!HasSubtitleOnly_() &&
+      !internal::IsLowLatencyModeDisableAVSync(low_latency_mode_) &&
+      !internal::IsLowLatencyModeDisablePreroll(low_latency_mode_))
+    resource_cv_.wait(lock);
+  if (pipeline_) {
+    pipeline_->PadRemoveProbe(kPadProbeVideoDecoded);
+  }
+  if (state_ != State::kWorking) {
+    TRACKRENDERER_ERROR_P(
+        this,
+        "Prepare fail, aborted by eos, error message, resource conflict or "
+        "stop called");
+    return false;
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::Pause() {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (state_ == State::kResourceConflicted) return true;
+  if (!pipeline_) {
+    return false;
+  }
+  target_substate_ = SubState::kPaused;
+  if (!NeedSyncPause_())
+    pipeline_->SetState(Elements::kPipeline, GST_STATE_PAUSED);
+
+  /*In ChangeSource_ situation, video and audio will in pause status since flush
+   event But subtitle can't in pause status since the "async" property is
+   false, so need to set to pause alone*/
+  GstState cur_state = GST_STATE_NULL;
+  bool ret = false;
+
+  ret = pipeline_->GetState(Elements::kBinSubtitle, &cur_state, NULL,
+                            50 * GST_MSECOND);
+  if ((true == ret) && (GST_STATE_PLAYING == cur_state)) {
+    TRACKRENDERER_DEBUG_P(
+        this, "kBinSubtitle paused failed, try to pause kBinSubtitle alone");
+    pipeline_->SetState(Elements::kBinSubtitle, GST_STATE_PAUSED);
+  }
+
+  ret = pipeline_->GetState(Elements::kSinkCaption, &cur_state, NULL,
+                            50 * GST_MSECOND);
+  if ((true == ret) && (GST_STATE_PLAYING == cur_state)) {
+    TRACKRENDERER_DEBUG_P(
+        this, "kSinkCaption paused failed, try to pause kSinkCaption alone");
+    pipeline_->SetState(Elements::kSinkCaption, GST_STATE_PAUSED);
+  }
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::Resume() {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (state_ == State::kResourceConflicted) return true;
+  if (!pipeline_) {
+    return false;
+  }
+
+  if (is_video_frame_peek_) {
+    pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
+  }
+  if (support_videodec_underflow_pause_) {
+    pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
+  }
+
+  target_substate_ = SubState::kPlaying;
+  pipeline_->SetState(Elements::kPipeline, GST_STATE_PLAYING);
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::SetTrack(const std::vector<Track>& trackinfo) {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (enable_audio_track_change_ && state_ == State::kWorking) {
+    enable_audio_track_change_ = false;
+
+    if (!internal::IsAvailableCodecChange(*(trackctx_[kTrackTypeAudio].track)))
+      return false;
+    auto is_audio_track = [](const Track& item) noexcept->bool {
+      return item.type == kTrackTypeAudio;
+    };
+    auto new_track =
+        find_if(trackinfo.begin(), trackinfo.end(), is_audio_track);
+    if (new_track == trackinfo.end()) return false;
+    if (!internal::IsAvailableCodecChange(*new_track)) return false;
+
+    auto old_track =
+        find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+    if (old_track != trackinfo_.end()) {
+      trackinfo_.erase(old_track);
+    }
+    trackinfo_.push_back(*new_track);
+    track_util::ShowTrackInfo(trackinfo_);
+    for (auto& track : trackinfo_) {
+      if (track.type == kTrackTypeAudio) {
+        trackctx_[kTrackTypeAudio].index = track.index;
+        trackctx_[kTrackTypeAudio].track = &track;
+        auto caps = caps_builder_.Build(
+            track,
+            internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype));
+        pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
+        TRACKRENDERER_INFO_P(this, "change audio track after flush");
+      }
+    }
+    return true;
+  }
+
+  if (!trackinfo_.empty()) {
+    TRACKRENDERER_ERROR_P(
+        this, "trackinfo_ already was set. DO NOT CALL SetTrack()!!");
+    return false;
+  }
+  trackinfo_ = trackinfo;
+  for (auto& track : trackinfo_) {
+    if (track.type >= kTrackTypeMax) return false;
+    trackctx_[track.type].index = track.index;
+    trackctx_[track.type].track = &track;
+    if (track.type == kTrackTypeVideo) {
+      trackctx_[track.type].create_pipeline = std::bind(
+          &TrackRenderer::CreateVideoPipeline_, this, std::placeholders::_1);
+      UpdateTrackFrameRate_(track.framerate_num, track.framerate_den);
+    } else if (track.type == kTrackTypeAudio) {
+      if (track.use_swdecoder || internal::IsSdkEnabledFeature()) {
+        trackctx_[track.type].create_pipeline =
+            std::bind(&TrackRenderer::CreateSwAudioPipeline_, this,
+                      std::placeholders::_1);
+      } else {
+        if (internal::IsDecoderElementNecessary(track.mimetype)) {
+          trackctx_[track.type].create_pipeline =
+              std::bind(&TrackRenderer::CreateAudioPipeline_, this,
+                        std::placeholders::_1);
+        } else {
+          trackctx_[track.type].create_pipeline =
+              std::bind(&TrackRenderer::CreateRawAudioPipeline_, this,
+                        std::placeholders::_1);
+        }
+      }
+    }
+  }
+  trackctx_[kTrackTypeSubtitle].create_pipeline = std::bind(
+      &TrackRenderer::CreateSubtitlePipeline_, this, std::placeholders::_1);
+  return true;
+}
+
+void TrackRenderer::SetIniProperty(
+    const std::map<std::string, bool>& properties) {
+  auto find = [](const std::map<std::string, bool>& property,
+                 const std::string& key, bool& value) -> bool {
+    auto look = property.find(key);
+    if (look == property.end()) {
+      return false;
+    }
+    value = look->second;
+    return true;
+  };
+  std::string key = "generate_dot";
+  bool value = false;
+  if (find(properties, key, value)) {
+    properties_[key] = value;
+  }
+}
+
+bool TrackRenderer::Seek(unsigned long long time_millisecond,
+                         double playback_rate) {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) {
+    return false;
+  }
+  // mute off/on values are defined in mmaudiosink element
+  static const gint mute_off = 2;
+  static const gint mute_on = 3;
+
+  gint mute_flag = mute_off;
+  gboolean async = TRUE;
+  if (playback_rate != kDefaultPlaybackRate) {
+    mute_flag = mute_on;
+    async = FALSE;
+  }
+
+  TRACKRENDERER_INFO_P(this, "Set async property as [%d]", async);
+  auto is_audio_track = [](const Track& item) noexcept->bool {
+    return item.mimetype.find("audio") != std::string::npos;
+  };
+  auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+  if (target != trackinfo_.end()) {
+    if (target->use_swdecoder || internal::IsSdkEnabledFeature())
+      pipeline_->SetProperty(Elements::kSinkAudio, "mute", mute_flag % 2,
+                             "async", async);
+    else {
+      pipeline_->SetProperty(Elements::kSinkAudio, "mute-mask", mute_flag,
+                             "async", async);
+    }
+  }
+
+  TRACKRENDERER_INFO_P(this, " target %llu ms  rate [%lf]", time_millisecond,
+                       playback_rate);
+  gint64 start = time_millisecond * GST_MSECOND, stop = GST_CLOCK_TIME_NONE;
+  if (playback_rate < 0) {
+    stop = start;
+    start = 0;
+  }
+  if (!pipeline_->Seek(playback_rate, GST_FORMAT_TIME,
+                       (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET,
+                       start, GST_SEEK_TYPE_SET, stop)) {
+    TRACKRENDERER_ERROR_P(this, "Fail to seek to [%llu] ms", time_millisecond);
+  }
+  is_seeking_ = true;
+  if (playback_rate != kDefaultPlaybackRate) {
+    TRACKRENDERER_INFO_P(this,
+                         "sequential mode should be off during trickplay");
+    pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", TRUE);
+  } else
+    pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", FALSE);
+
+  if (is_video_frame_peek_) {
+    pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
+    pipeline_->PadAddProbe(Elements::kSinkVideo, kPadProbeVideoPeekBlock,
+                           "sink", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+                           GstPadProbeVideoPeekBlockCb_, this, nullptr);
+  }
+  rendering_start_time_.time = start;
+  if (playback_rate > 0) {
+    for (int i = 0; i < kTrackTypeMax; ++i) {
+      trackctx_[i].is_enough_data = false;
+      trackctx_[i].need_update_segment = true;
+    }
+
+    if (is_accurate_seek_) {
+      UpdateStartSegment_(time_millisecond * GST_MSECOND, kTrackTypeMax);
+    }
+  }
+  playback_rate_ = playback_rate;
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::Seek(unsigned long long time_millisecond,
+                         double playback_rate, bool audio_mute) {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) {
+    return false;
+  }
+  // mute off/on values are defined in mmaudiosink element
+  static const gint mute_off = 2;
+  static const gint mute_on = 3;
+
+  gint mute_flag = audio_mute ? mute_on : mute_off;
+
+  auto is_audio_track = [](const Track& item) noexcept->bool {
+    return item.mimetype.find("audio") != std::string::npos;
+  };
+  auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+  if (target != trackinfo_.end()) {
+    if (target->use_swdecoder || internal::IsSdkEnabledFeature()) {
+      pipeline_->SetProperty(Elements::kSinkAudio, "mute", mute_flag % 2);
+    } else {
+      pipeline_->SetProperty(Elements::kSinkAudio, "mute-mask", mute_flag);
+    }
+  }
+
+  TRACKRENDERER_INFO_P(this, " target %llu ms  rate [%lf]  mute [%d]",
+                       time_millisecond, playback_rate, audio_mute);
+  if (!pipeline_->Seek(playback_rate, GST_FORMAT_TIME,
+                       (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET,
+                       time_millisecond * GST_MSECOND, GST_SEEK_TYPE_NONE,
+                       GST_CLOCK_TIME_NONE)) {
+    TRACKRENDERER_ERROR_P(this, "Fail to seek to [%llu] ms", time_millisecond);
+  }
+  is_seeking_ = true;
+  if (playback_rate != kDefaultPlaybackRate) {
+    TRACKRENDERER_INFO_P(this,
+                         "sequential mode should be off during trickplay");
+    pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", TRUE);
+  } else
+    pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", FALSE);
+
+  if (is_video_frame_peek_) {
+    pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
+    pipeline_->PadAddProbe(Elements::kSinkVideo, kPadProbeVideoPeekBlock,
+                           "sink", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+                           GstPadProbeVideoPeekBlockCb_, this, nullptr);
+  }
+  if (support_videodec_underflow_pause_) {
+    pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
+  }
+
+  rendering_start_time_.time = time_millisecond * GST_MSECOND;
+  for (int i = 0; i < kTrackTypeMax; ++i) {
+    trackctx_[i].is_enough_data = false;
+    trackctx_[i].need_update_segment = true;
+  }
+
+  if (is_accurate_seek_) {
+    UpdateStartSegment_(time_millisecond * GST_MSECOND, kTrackTypeMax);
+  }
+  playback_rate_ = playback_rate;
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::SetPlaybackRate(double playback_rate, bool audio_mute) {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) {
+    return false;
+  }
+  // mute off/on values are defined in mmaudiosink element
+  static const gint mute_off = 2;
+  static const gint mute_on = 3;
+  uint64_t curtime_in_msec = 0;
+  gint mute_flag = audio_mute ? mute_on : mute_off;
+  GetPlayingTime_(&curtime_in_msec);
+
+  TRACKRENDERER_INFO_P(this, "Set mute-mask property as [%d] ,rate [%lf]",
+                       mute_flag, playback_rate);
+  auto is_audio_track = [](const Track& item) noexcept->bool {
+    return item.mimetype.find("audio") != std::string::npos;
+  };
+  auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+  if (target != trackinfo_.end()) {
+    if (target->use_swdecoder || internal::IsSdkEnabledFeature()) {
+      pipeline_->SetProperty(Elements::kSinkAudio, "mute", mute_flag % 2);
+    } else {
+      pipeline_->SetProperty(Elements::kSinkAudio, "mute-mask", mute_flag);
+      pipeline_->SetProperty(Elements::kDecAudio, "audio-playback-rate",
+                             gint(playback_rate * 100));
+      pipeline_->SetProperty(Elements::kSinkAudio, "playback-rate",
+                             gint(playback_rate * 100));
+    }
+  }
+
+  Elements audio_probe_element = Elements::kDecAudio;
+  Elements video_probe_element = Elements::kDecVideo;
+  Elements subtitle_probe_element = Elements::kAppSrcSubtitle;
+  Elements close_caption_probe_element = Elements::kQueueCaption;
+  for (const Track& track : trackinfo_) {
+    if (internal::IsPcmMimeType(track.mimetype)) {
+      audio_probe_element = Elements::kAppSrcAudio;
+    } else if (internal::IsVideoRawMimeType(track.mimetype)) {
+      video_probe_element = Elements::kAppSrcVideo;
+    }
+  }
+  std::map<Elements, std::pair<std::string, std::string>> probe_map = {
+      {audio_probe_element,
+       {"AUDIO_RATE_IDLE_PROBE", "AUDIO_RATE_BLOCK_PROBE"}},
+      {video_probe_element,
+       {"VIDEO_RATE_IDLE_PROBE", "VIDEO_RATE_BLOCK_PROBE"}},
+      {subtitle_probe_element,
+       {"SUBTITLE_RATE_IDLE_PROBE", "SUBTITLE_RATE_BLOCK_PROBE"}},
+      {close_caption_probe_element,
+       {"CLOSE_CAPTION_RATE_IDLE_PROBE", "CLOSE_CAPTION_RATE_BLOCK_PROBE"}}};
+
+  std::map<Elements, Elements> probe_sink_map = {
+      {audio_probe_element, Elements::kSinkAudio},
+      {video_probe_element, Elements::kSinkVideo},
+      {subtitle_probe_element, Elements::kSinkSubtitle},
+      {close_caption_probe_element, Elements::kSinkCaption}};
+
+  for (auto& kv : probe_map) {
+    const Elements& element = kv.first;
+    std::pair<std::string, std::string>& probe = kv.second;
+    pipeline_->PadAddProbe(element, (probe.second).c_str(), "src",
+                           GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, nullptr,
+                           nullptr, nullptr);
+    gboolean is_sync = FALSE;
+    pipeline_->GetProperty(probe_sink_map[element], "sync", &is_sync);
+    pipeline_->SetProperty(probe_sink_map[element], "sync", FALSE);
+    FlushDownStream_(element, (probe.first).c_str(), TRUE);
+    if (is_sync) pipeline_->SetProperty(probe_sink_map[element], "sync", TRUE);
+  }
+
+  if (playback_rate != kDefaultPlaybackRate) {
+    TRACKRENDERER_INFO_P(this,
+                         "sequential mode should be off during trickplay");
+    pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", TRUE);
+  } else
+    pipeline_->SetProperty(Elements::kSinkVideo, "is-trickplay", FALSE);
+
+  for (auto& kv : probe_map) {
+    const Elements& element = kv.first;
+    std::pair<std::string, std::string>& probe = kv.second;
+    pipeline_->PushSegmentEvent(element, curtime_in_msec * GST_MSECOND,
+                                playback_rate);
+    pipeline_->PadRemoveProbe((probe.second).c_str());
+  }
+  rendering_start_time_.time = curtime_in_msec * GST_MSECOND;
+  playback_rate_ = playback_rate;
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::ControlDropRate_(uint64_t packet_pts,
+                                     SubmitStatus* status) {
+  uint64_t current_time = 0;
+  GetPlayingTime_(&current_time);
+  const auto islate = [](uint64_t cur_time, uint64_t pts) {
+    if (pts <= cur_time) {
+      return true;
+    } else {
+      return false;
+    }
+  };
+  if (islate(current_time, packet_pts)) {
+    *status = SubmitStatus::kDrop;
+    return true;
+  }
+  *status = SubmitStatus::kHold;
+  return false;
+}
+
+bool TrackRenderer::IsSegmentUpdated_() const {
+  for (int i = 0; i < kTrackTypeMax; i++) {
+    if (trackctx_[i].need_update_segment == false) return true;
+  }
+  return false;
+}
+
+bool TrackRenderer::HasSubtitleOnly_() const {
+  return trackctx_[kTrackTypeAudio].index == kInvalidTrackIndex &&
+         trackctx_[kTrackTypeVideo].index == kInvalidTrackIndex &&
+         trackctx_[kTrackTypeSubtitle].index != kInvalidTrackIndex;
+}
+// LCOV_EXCL_STOP
+
+bool TrackRenderer::SubmitPacket(const DecoderInputBufferPtr& data,
+                                 SubmitStatus* status) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  SubmitStatus submitstate = SubmitStatus::kSuccess;
+  BOOST_SCOPE_EXIT(&submitstate, &status) {
+    if (status) *status = submitstate;
+  }
+  BOOST_SCOPE_EXIT_END
+  if (state_ == State::kStopped) {
+    submitstate = SubmitStatus::kNotPrepared;
+    return false;
+  }
+  if (!pipeline_) {
+    // TRACKRENDERER_DEBUG_P(this, "pipeline is nullptr , wait prepared");
+    submitstate = SubmitStatus::kNotPrepared;
+    return false;
+  }
+
+  const TrackType type = data->GetType();
+  Elements element = Elements::kAppSrcAudio;
+  if (type == kTrackTypeVideo) {
+    element = Elements::kAppSrcVideo;
+  } else if (type == kTrackTypeSubtitle) {
+    element = Elements::kAppSrcSubtitle;
+  }
+
+  if (data->IsEos()) {
+    pipeline_->SignalEmitByName(element, "end-of-stream");
+    submitstate = SubmitStatus::kSuccess;
+    return true;
+  }
+
+  // TRACKRENDERER_DEBUG_P(this,
+  //    "TYPE[%d] PKT INDEX[%d] TIMESTAMP[%lld]ms SIZE[%d] EOS[%d]", type,
+  //    data->GetIndex(), GST_BUFFER_TIMESTAMP(data->Get()) / 1000000,
+  //    gst_buffer_get_size(const_cast<GstBuffer*>(data->Get())),
+  //    data->IsEos());
+
+  if (type >= kTrackTypeMax) return false;
+  if (trackctx_[type].index == kInvalidTrackIndex) {
+    // TRACKRENDERER_ERROR_P(this, "data is not activated track. type:%d,
+    // input:acti %d:%d", type, data->GetIndex(), trackctx_[type].index);
+    return ControlDropRate_(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(data->Get())),
+                            &submitstate);
+  }
+
+  if (!unlimited_max_buffer_mode_ && trackctx_[type].is_enough_data) {
+    submitstate = SubmitStatus::kFull;
+    return false;
+  }
+
+  const bool is_segment_updated = IsSegmentUpdated_();
+  const bool request_to_hold_subtitle = (type == kTrackTypeSubtitle) &&
+                                        (is_segment_updated == false) &&
+                                        (HasSubtitleOnly_() == false);
+
+  if (request_to_hold_subtitle) {
+    TRACKRENDERER_INFO_P(this, "subtitle should be submitted after a/v packet");
+    submitstate = SubmitStatus::kHold;
+    return false;
+  }
+
+  GstBuffer* buffer = data->Release();
+
+  if (is_segment_updated == false) {
+    UpdateStartSegment_(GST_BUFFER_TIMESTAMP(buffer), type);
+  }
+
+  pipeline_->AppSrcPushBuffer(element, buffer);
+
+  if (type == kTrackTypeVideo) {
+    latency_manager_->UpdateVideoFrameStatus(
+        LatencyManager::UpdatePacketStatus::kSubmit);
+  }
+
+  submitstate = SubmitStatus::kSuccess;
+  return true;
+}
+
+bool TrackRenderer::SetMatroskaColorInfo(const std::string& color_info) {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  if (pipeline_ == nullptr) return false;
+  GstCaps* old_caps = nullptr;
+  pipeline_->GetProperty(Elements::kAppSrcVideo, "caps", &old_caps);
+  if (old_caps == nullptr) return false;
+  auto old_caps_guard = gstguard::make_guard(old_caps);
+  auto new_caps_guard = gstguard::make_guard(gst_caps_copy(old_caps));
+  gst_caps_set_simple(new_caps_guard.get(), "matroska_color_info",
+                      G_TYPE_STRING, color_info.c_str(), nullptr);
+  pipeline_->SetProperty(Elements::kSinkVideo, "video-color-info",
+                         new_caps_guard.get());
+  pipeline_->SetProperty(Elements::kAppSrcVideo, "caps", new_caps_guard.get());
+  return true;
+}
+
+void TrackRenderer::UpdateStartSegment_(GstClockTime start_time,
+                                        const TrackType& type) {
+  if (type == kTrackTypeMax) {
+    TRACKRENDERER_INFO_P(
+        this, "update src segment with start time [%llu ms] for all tracks",
+        start_time / 1000000);
+    for (int i = 0; i < kTrackTypeMax; ++i) {
+      trackctx_[i].need_update_segment = false;
+    }
+  } else {
+    const auto& track_type_str = track_util::GetTrackTypeString(type);
+    TRACKRENDERER_ERROR_P(
+        this, "update src segment with first pts [%llu ms] by %s stream",
+        start_time / 1000000, track_type_str.c_str());
+    trackctx_[type].need_update_segment = false;
+  }
+
+  if (rendering_start_time_.is_set) {
+    start_time = rendering_start_time_.time;
+    rendering_start_time_.is_set = false;
+    TRACKRENDERER_ERROR_P(
+        this,
+        "update src segment with first pts [%llu ms] by start-rendering-time",
+        start_time / 1000000);
+  }
+
+  pipeline_->SetProperty(Elements::kAppSrcVideo, "update-segment", start_time);
+  pipeline_->SetProperty(Elements::kAppSrcAudio, "update-segment", start_time);
+  pipeline_->SetProperty(Elements::kAppSrcSubtitle, "update-segment",
+                         start_time);
+  rendering_start_time_.time = start_time;
+}
+
+void TrackRenderer::CreateAppSrc_(TrackType type, const std::string& mimetype) {
+  if (internal::IsTzAppSrcElementNecessary(drm_property_, mimetype)) {
+    if (type == kTrackTypeVideo) {
+      pipeline_->FactoryMake(Elements::kAppSrcVideo, "tzappsrc",
+                             "tz_video_appsrc");
+    } else {
+      pipeline_->FactoryMake(Elements::kAppSrcAudio, "tzappsrc",
+                             "tz_audio_appsrc");
+    }
+  } else {
+    if (type == kTrackTypeVideo) {
+      pipeline_->FactoryMake(Elements::kAppSrcVideo, "appsrc", "video_appsrc");
+    } else {
+      pipeline_->FactoryMake(Elements::kAppSrcAudio, "appsrc", "audio_appsrc");
+    }
+  }
+  SetDefaultAppSrcSignals_(type);
+
+  Elements element = Elements::kAppSrcAudio;
+  if (type == kTrackTypeVideo) element = Elements::kAppSrcVideo;
+
+  pipeline_->SetProperty(element, "format", GST_FORMAT_TIME);
+  pipeline_->SetProperty(element, "stream-type", GST_APP_STREAM_TYPE_SEEKABLE);
+}
+
+void TrackRenderer::SetDefaultAppSrcSignals_(const TrackType& type) {
+  if (type == kTrackTypeVideo) {
+    pipeline_->SignalConnect(Elements::kAppSrcVideo, "need-data",
+                             G_CALLBACK(GstVideoNeedDataCb_), this);
+    pipeline_->SignalConnect(Elements::kAppSrcVideo, "enough-data",
+                             G_CALLBACK(GstVideoEnoughDataCb_), this);
+    pipeline_->SignalConnect(Elements::kAppSrcVideo, "seek-data",
+                             G_CALLBACK(GstVideoSeekDataCb_), this);
+  } else if (type == kTrackTypeAudio) {
+    pipeline_->SignalConnect(Elements::kAppSrcAudio, "need-data",
+                             G_CALLBACK(GstAudioNeedDataCb_), this);
+    pipeline_->SignalConnect(Elements::kAppSrcAudio, "enough-data",
+                             G_CALLBACK(GstAudioEnoughDataCb_), this);
+    pipeline_->SignalConnect(Elements::kAppSrcAudio, "seek-data",
+                             G_CALLBACK(GstAudioSeekDataCb_), this);
+  } else if (type == kTrackTypeSubtitle) {
+    pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "need-data",
+                             G_CALLBACK(GstSubtitleNeedDataCb_), this);
+    pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "enough-data",
+                             G_CALLBACK(GstSubtitleEnoughDataCb_), this);
+    pipeline_->SignalConnect(Elements::kAppSrcSubtitle, "seek-data",
+                             G_CALLBACK(GstSubtitleSeekDataCb_), this);
+  }
+}
+
+void TrackRenderer::CreateDrmElement_(const Track& track) {
+  if (!internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype))
+    return;
+
+  if (track.type == kTrackTypeAudio) {
+    pipeline_->FactoryMake(Elements::kDrmAudio, "drm_eme", "audio_drm");
+    pipeline_->SetProperty(Elements::kDrmAudio, "plus-player-eme", TRUE);
+    if (internal::IsExternalDecryptionCase(drm_property_) == false) {
+      pipeline_->SetProperty(Elements::kDrmAudio, "getrights-complete-cb",
+                             GstAudioDrmInitDataCb_);
+      pipeline_->SetProperty(Elements::kDrmAudio, "getrights-complete-cb-data",
+                             this);
+    }
+  } else if (track.type == kTrackTypeVideo) {
+    pipeline_->FactoryMake(Elements::kDrmVideo, "drm_eme", "video_drm");
+    pipeline_->SetProperty(Elements::kDrmVideo, "plus-player-eme", TRUE);
+    if (!internal::IsExternalDecryptionCase(drm_property_)) {
+      pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb",
+                             GstVideoDrmInitDataCb_);
+      pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-cb-data",
+                             this);
+    }
+  }
+}
+
+const char* TrackRenderer::GetAudioSinkPluginName_(
+    bool swdecoder, const std::string& mimetype) {
+  if (internal::IsSdkEnabledFeature()) return "pulsesink";
+  if (product_cfg::GetProductType() == ProductType::kAv) {
+    return "mmaudiosink2";
+  }
+  if (swdecoder || internal::IsPcmMimeType(mimetype)) {
+    const std::string comp_name =
+        resource_manager_->GetComponentName(audio_out_id_);
+    if (comp_name == kPulseSinkComponentName) return "pulsesink";
+    return ::SinkPluginTable.count(::DeviceSinkElementType::kPcmAudiosink) > 0
+               ? ::SinkPluginTable.at(::DeviceSinkElementType::kPcmAudiosink)
+                     .c_str()
+               : nullptr;
+  }
+  return ::SinkPluginTable.count(::DeviceSinkElementType::kAudioSink) > 0
+             ? ::SinkPluginTable.at(::DeviceSinkElementType::kAudioSink).c_str()
+             : nullptr;
+}
+
+void TrackRenderer::CreateAudioSink_(const std::string& sink_name) {
+  if (sink_name.find("alsasink") != std::string::npos ||
+      sink_name.find("pulsesink") != std::string::npos) {
+    pipeline_->FactoryMake(Elements::kAudioConvert, "audioconvert", nullptr);
+    pipeline_->FactoryMake(Elements::kCapsFillterDefault, "capsfilter",
+                           nullptr);
+    auto caps1 = gstguard::make_guard(
+        gst_caps_from_string("audio/x-raw, "
+                             "format = (string) S16LE, "
+                             "layout = (string) interleaved, "
+                             "channels = (int) 2"));
+    pipeline_->SetProperty(Elements::kCapsFillterDefault, "caps", caps1.get());
+    pipeline_->FactoryMake(Elements::kAudioResample, "audioresample", nullptr);
+    pipeline_->FactoryMake(Elements::kCapsFillter2, "capsfilter", nullptr);
+    auto caps2 =
+        gstguard::make_guard(gst_caps_from_string("audio/x-raw, "
+                                                  "rate = (int) 48000"));
+    pipeline_->SetProperty(Elements::kCapsFillter2, "caps", caps2.get());
+    pipeline_->FactoryMake(Elements::kScaleTempo, "scaletempo", nullptr);
+
+    pipeline_->FactoryMake(Elements::kSinkAudio, sink_name.c_str(), NULL);
+    if (sink_name.find("pulsesink") == std::string::npos) {
+      pipeline_->SetProperty(Elements::kSinkAudio, "device", "hw:0,0");
+    }
+    pipeline_->SetProperty(Elements::kSinkAudio, "drift-tolerance",
+                           ((200 * GST_MSECOND) / GST_USECOND));
+    pipeline_->SetProperty(Elements::kSinkAudio, "provide-clock", FALSE);
+    pipeline_->SetProperty(Elements::kSinkAudio, "sync", TRUE);
+    pipeline_->SetProperty(Elements::kSinkAudio, "force-render", FALSE);
+    pipeline_->SetProperty(Elements::kSinkAudio, "multiview-window-id",
+                           static_cast<int>(display_->GetSurfaceId()));
+
+    if (sink_name.find("pulsesink") == std::string::npos) {
+      resync_audio_policy_.reset(new resync_audio::DummyPolicy());
+    } else {
+      resync_audio_policy_.reset(new resync_audio::SwDecoderPolicy(
+          rendering_start_time_.time, playback_rate_));
+    }
+  } else if (sink_name.find("fakesink") != std::string::npos) {
+    TRACKRENDERER_ERROR_P(this, "fake");
+    pipeline_->FactoryMake(Elements::kSinkAudio, sink_name.c_str(), NULL);
+    pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE, NULL);
+    pipeline_->SetProperty(Elements::kSinkAudio, "sync", TRUE, NULL);
+    pipeline_->SetProperty(Elements::kSinkAudio, "max-lateness",
+                           static_cast<gint64>(-1), NULL);
+    pipeline_->SetProperty(Elements::kSinkAudio, "no-drop", TRUE, NULL);
+    resync_audio_policy_.reset(new resync_audio::DummyPolicy());
+  } else {
+    pipeline_->FactoryMake(Elements::kSinkAudio, sink_name.c_str(), NULL);
+    pipeline_->SetProperty(Elements::kSinkAudio,           //
+                           "sync", TRUE,                   //
+                           "async", TRUE,                  //
+                           "fast-rendering", 200000000LL,  //
+                           "force-render", FALSE);
+    pipeline_->SetProperty(Elements::kSinkAudio, "multiview-window-id",
+                           static_cast<int>(display_->GetSurfaceId()));
+    int is_audio_decoder_sub =
+        resource_manager_->IsMainDevice(audio_decoder_id_) ? 0 : 1;
+    pipeline_->SetProperty(Elements::kSinkAudio, "device-audio-decoder",
+                           is_audio_decoder_sub, NULL);
+    resync_audio_policy_.reset(new resync_audio::DefaultPolicy());
+  }
+  pipeline_->SetProperty(Elements::kSinkAudio, "mls-player-id", avoc_id_);
+}
+
+void TrackRenderer::CreateVideoDecoder_(const char* dec_name) {
+  pipeline_->FactoryMake(Elements::kDecVideo, dec_name, NULL);
+
+  pipeline_->SetProperty(Elements::kDecVideo, "extradata_flag", TRUE);
+  pipeline_->SetProperty(Elements::kDecVideo, "decoding-type",
+                         static_cast<gint>(video_decoding_mode_));
+  pipeline_->SignalConnect(Elements::kDecVideo, "pad-added",
+                           G_CALLBACK(GstClosedCaptionPadAddedCb_), this);
+}
+
+bool TrackRenderer::CreateVideoSink_() {
+  if (internal::IsDisplayNeeded(display_type_) == false)
+    pipeline_->FactoryMake(Elements::kSinkVideo, "fakesink", "fakesink");
+  else
+    pipeline_->FactoryMake(Elements::kSinkVideo, "directvideosink",
+                           "directvideosink");
+
+  // gstbasesink property
+  pipeline_->SetProperty(Elements::kSinkVideo, "sync", TRUE, "async", TRUE,
+                         "max-lateness", static_cast<gint64>(0));
+  if (video_pre_display_mode_)
+    pipeline_->SetProperty(Elements::kSinkVideo, "accurate-resume", TRUE);
+  if (drop_all_late_video_)
+    pipeline_->SetProperty(Elements::kSinkVideo, "force-render", FALSE);
+
+  if (internal::IsDisplayNeeded(display_type_) == false) return true;
+
+  // gstwaylandsink property
+  pipeline_->SetProperty(Elements::kSinkVideo, "subsurface-stand-alone",
+                         window_stand_alone_mode_);
+  SetSequentialMode_();
+  pipeline_->SetProperty(Elements::kSinkVideo, "use-seq-mode", use_seq_mode_);
+  virtual_scaler_id_ = resource_manager_->GetDeviceId(video_renderer_id_);
+  if (virtual_scaler_id_ == -1) {
+    return false;
+  }
+  pipeline_->SetProperty(Elements::kSinkVideo, "device-scaler",
+                         virtual_scaler_id_);
+
+  if (fmm_mode_)
+    pipeline_->SetProperty(Elements::kSinkVideo, "fmm-mode", fmm_mode_);
+  if (enable_direct_crop_)
+    pipeline_->SetProperty(Elements::kSinkVideo, "enable-direct-crop", TRUE);
+#ifndef SOUNDBAR_PRODUCT
+  if (avoc_sub_source_ != AVOC_SUB_SOURCE_NONE)
+    pipeline_->SetProperty(Elements::kSinkVideo, "avoc-sub-source",
+                           static_cast<gint>(avoc_sub_source_));
+#endif
+  return true;
+}
+
+void TrackRenderer::SetPropertyForAiFilter_() {
+  if (aifilter_ == nullptr) return;
+  pipeline_->ElementAdd(Elements::kAiFilter, aifilter_);
+  pipeline_->SetProperty(Elements::kAiFilter, "scaler-id", virtual_scaler_id_);
+  pipeline_->SignalConnect(Elements::kAiFilter, "return-result",
+                           G_CALLBACK(GstAiFilterResultCb_), this);
+  return;
+}
+
+void TrackRenderer::SetPropertyForDecodedVideoBufferWithDisplay_() {
+  if (pipeline_ == nullptr) return;
+  if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kScale) {
+    pipeline_->SignalConnect(Elements::kDecVideo, "get-buffer",
+                             G_CALLBACK(GstDecodedVideoScaleBufferCb_), this);
+    pipeline_->SetProperty(Elements::kDecVideo, "signal-outbuffer", TRUE);
+  }
+  return;
+}
+
+void TrackRenderer::SetPropertyForDecodedVideoBufferWithoutDisplay_() {
+  /*in case of omx seamless mode,if not render omx data directly,like copy
+   * omxdata to DP buffer case,need set bNoVideoOut= True .*/
+  if (pipeline_ == nullptr) return;
+
+  pipeline_->SetProperty(Elements::kDecVideo, "display-omxdata-direct", FALSE);
+  TRACKRENDERER_INFO_P(
+      this,
+      "set [ %d ] to 'display-omxdata-direct' property of omx seamless "
+      "videodec",
+      FALSE);
+  pipeline_->SetProperty(Elements::kSinkVideo, "signal-handoffs", TRUE);
+
+  if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kCopy) {
+    constexpr int kTbmBoType =
+        1;  // 1:tbm bo, 0:CMA  (refer to gstffmpegdec element, currently for
+            // this feature use only sw decoder(ffmpegdec) and tbm_bo)
+    pipeline_->SetProperty(Elements::kDecVideo, "tbm-buffer-type", kTbmBoType);
+    pipeline_->SignalConnect(Elements::kSinkVideo, "handoff",
+                             G_CALLBACK(GstDecodedVideoCopyBufferCb_), this);
+  } else if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kReference) {
+    constexpr int kModeYoutube360 =
+        1;  // 1:youtube 360, 0:usb 360, -1:normal  (refer to gstomxvideo)
+    pipeline_->SetProperty(Elements::kDecVideo, "vr360-mode", kModeYoutube360);
+    pipeline_->SignalConnect(Elements::kSinkVideo, "handoff",
+                             G_CALLBACK(GstDecodedVideoReferenceBufferCb_),
+                             this);
+  } else if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kRaw) {
+    constexpr int kTbmBoType =
+        0;  // 1:tbm bo, 0:CMA  (refer to gstffmpegdec element, currently for
+            // this feature use only sw decoder(ffmpegdec) and tbm_bo)
+    pipeline_->SetProperty(Elements::kDecVideo, "tbm-buffer-type", kTbmBoType);
+    pipeline_->SignalConnect(Elements::kSinkVideo, "handoff",
+                             G_CALLBACK(GstDecodedVideoRawBufferCb_), this);
+  } else if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kScale) {
+    pipeline_->SignalConnect(Elements::kDecVideo, "get-buffer",
+                             G_CALLBACK(GstDecodedVideoScaleBufferCb_), this);
+    pipeline_->SetProperty(Elements::kDecVideo, "signal-outbuffer", TRUE);
+    pipeline_->SetProperty(Elements::kSinkVideo, "signal-handoffs", FALSE);
+  }
+  return;
+}
+
+void TrackRenderer::SetPropertyForDecodedVideoBuffer_() {
+  if (internal::IsDecodedVideoBufferNeeded(decoded_buffer_type_) == false)
+    return;
+
+  CreateTbmBufferManager_();
+
+  if (internal::IsDisplayNeeded(display_type_))
+    SetPropertyForDecodedVideoBufferWithDisplay_();
+  else
+    SetPropertyForDecodedVideoBufferWithoutDisplay_();
+  return;
+}
+
+bool TrackRenderer::CreateVideoPipeline_(const Track* track) {
+  const char* kDecoderPluginName =
+      GetDecoderPluginName_(kTrackTypeVideo, track->mimetype);
+  if (kDecoderPluginName == nullptr &&
+      internal::IsDecoderElementNecessary(track->mimetype)) {
+    const ErrorType err = ErrorType::kNotSupportedVideoCodec;
+    eventlistener_->OnError(err);
+    eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
+    return false;
+  }
+  if (kDecoderPluginName &&
+      (strcmp(kDecoderPluginName, kSkippedResource) == 0)) {
+    const ErrorType err = ErrorType::kResourceLimit;
+    eventlistener_->OnError(err);
+    eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
+    return false;
+  }
+  CreateAppSrc_(kTrackTypeVideo, track->mimetype);
+
+  CreateDrmElement_(*track);
+
+  CreateVideoDecoder_(kDecoderPluginName);
+
+  if (CreateVideoSink_() == false) return false;
+
+  GstElementLowLatency_(kTrackTypeVideo);
+
+  SetPropertyForAiFilter_();
+
+  pipeline_->CreateBin(Elements::kBinVideo, "videobin");
+
+  pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo,
+                    Elements::kDrmVideo, Elements::kDecVideo,
+                    Elements::kAiFilter, Elements::kSinkVideo);
+
+  pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinVideo);
+
+  auto caps = caps_builder_.Build(*track, internal::IsDrmEmeElementNecessary(
+                                              drm_property_, track->mimetype));
+  pipeline_->SetAppSrcCaps(Elements::kAppSrcVideo, caps);
+
+  if (is_video_frame_peek_) {
+    pipeline_->PadAddProbe(Elements::kSinkVideo, kPadProbeVideoDecoded, "sink",
+                           GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
+                           GstPadProbeVideoDecodedCb_, this, nullptr);
+  }
+  SetPropertyForDecodedVideoBuffer_();
+  return true;
+}
+
+bool TrackRenderer::CreateAudioPipeline_(const Track* track) {
+  const char* kDecoderPluginName =
+      GetDecoderPluginName_(kTrackTypeAudio, track->mimetype);
+  if (kDecoderPluginName == nullptr) {
+    const ErrorType err = ErrorType::kNotSupportedAudioCodec;
+    eventlistener_->OnError(err);
+    eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
+    return false;
+  }
+  pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+
+  CreateAppSrc_(kTrackTypeAudio, track->mimetype);
+  auto caps = caps_builder_.Build(*track, internal::IsDrmEmeElementNecessary(
+                                              drm_property_, track->mimetype));
+  pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
+
+  CreateDrmElement_(*track);
+
+  if (strcmp(kDecoderPluginName, kSkippedResource) != 0) {
+    pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, NULL);
+    pipeline_->SetProperty(Elements::kDecAudio, "support-codec-change",
+                           support_audio_codec_change_);
+    if (low_latency_mode_ ==
+        static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone)) {
+      constexpr int kPtsManipulationThreshold = 99000;  // 99ms
+      pipeline_->SetProperty(Elements::kDecAudio, "set-usr-cal-timestamp",
+                             kPtsManipulationThreshold);
+    }
+    std::string audiosink_name =
+        GetAudioSinkPluginName_(track->use_swdecoder, track->mimetype);
+    CreateAudioSink_(audiosink_name);
+    is_audioactivated_ = true;
+
+  } else {  // fake sink
+    std::string sink_name("fakesink");
+    if (internal::IsTzMimeType(track->mimetype)) {
+      sink_name = "tzfakesink";
+    }
+    CreateAudioSink_(sink_name);
+    is_audioactivated_ = false;
+  }
+
+  GstElementLowLatency_(kTrackTypeAudio);
+  pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio,
+                    Elements::kDrmAudio, Elements::kDecAudio,
+                    Elements::kSinkAudio);
+  pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
+  return true;
+}
+
+bool TrackRenderer::CreateSwAudioPipeline_(const Track* track) {
+  const char* kDecoderPluginName =
+      GetDecoderPluginName_(kTrackTypeAudio, track->mimetype);
+  if (kDecoderPluginName == nullptr) {
+    const ErrorType err = ErrorType::kNotSupportedAudioCodec;
+    eventlistener_->OnError(err);
+    eventlistener_->OnErrorMsg(err, const_cast<char*>(track->mimetype.c_str()));
+    return false;
+  }
+  pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+
+  std::string appsrc_mimetype = track->mimetype;
+  CreateAppSrc_(kTrackTypeAudio, appsrc_mimetype);
+  auto caps = caps_builder_.Build(*track, false);
+  pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
+
+  if (strcmp(kDecoderPluginName, kSkippedResource) != 0) {
+    pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, NULL);
+
+    std::string audiosink_name =
+        GetAudioSinkPluginName_(track->use_swdecoder, track->mimetype);
+    CreateAudioSink_(audiosink_name);
+    is_audioactivated_ = true;
+
+  } else {  // fake sink
+    CreateAudioSink_("fakesink");
+    is_audioactivated_ = false;
+  }
+
+  GstElementLowLatency_(kTrackTypeAudio);
+  pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio,
+                    Elements::kDecAudio, Elements::kAudioConvert,
+                    Elements::kCapsFillterDefault, Elements::kAudioResample,
+                    Elements::kCapsFillter2, Elements::kScaleTempo,
+                    Elements::kSinkAudio);
+  pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
+  return true;
+}
+
+bool TrackRenderer::CreateRawAudioPipeline_(const Track* track) {
+  pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+
+  CreateAppSrc_(kTrackTypeAudio, track->mimetype);
+  auto caps = caps_builder_.Build(*track, false);
+  pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
+
+  AllocatedState state = resource_manager_->GetAllocatedState(audio_out_id_);
+  if (state == AllocatedState::kSuccess) {
+    std::string audiosink_name =
+        GetAudioSinkPluginName_(track->use_swdecoder, track->mimetype);
+    CreateAudioSink_(audiosink_name);
+    is_audioactivated_ = true;
+
+  } else if (state == AllocatedState::kSkipped) {  // fake sink
+    resource_manager_->Dealloc(audio_out_id_);
+
+    CreateAudioSink_("fakesink");
+    is_audioactivated_ = false;
+
+  } else {  // AllocatedState::kFailed
+    TRACKRENDERER_ERROR_P(this, "Fail to create raw audio pipeline!");
+    return false;
+  }
+
+  GstElementLowLatency_(kTrackTypeAudio);
+  pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio,
+                    Elements::kAudioConvert, Elements::kCapsFillterDefault,
+                    Elements::kAudioResample, Elements::kCapsFillter2,
+                    Elements::kScaleTempo, Elements::kSinkAudio);
+  pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
+  return true;
+}
+
+bool TrackRenderer::CreateSubtitlePipeline_(const Track* track) {
+  pipeline_->FactoryMake(Elements::kAppSrcSubtitle, "appsrc",
+                         "subtitle_appsrc");
+  SetDefaultAppSrcSignals_(kTrackTypeSubtitle);
+  pipeline_->FactoryMake(Elements::kSinkSubtitle, "fakesink", "subtitle_sink");
+  pipeline_->CreateBin(Elements::kBinSubtitle, "subtitlebin");
+  pipeline_->SetProperty(Elements::kAppSrcSubtitle, "format", GST_FORMAT_TIME);
+  pipeline_->BinAdd(Elements::kBinSubtitle, Elements::kAppSrcSubtitle,
+                    Elements::kSinkSubtitle);
+  pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinSubtitle);
+
+  std::string mimetype = (track == nullptr) ? "" : track->mimetype;
+  auto caps = gstguard::make_guard(gst_caps_new_empty_simple(mimetype.c_str()));
+  pipeline_->SetProperty(Elements::kAppSrcSubtitle, "stream-type",
+                         GST_APP_STREAM_TYPE_SEEKABLE, "max-bytes",
+                         ::kMaxByteOfSubtitleSrcQueue, "caps", caps.get());
+  pipeline_->SetProperty(Elements::kSinkSubtitle, "sync", TRUE, "async", FALSE,
+                         "signal-handoffs", TRUE);
+  GstElementLowLatency_(kTrackTypeSubtitle);
+  pipeline_->SignalConnect(Elements::kSinkSubtitle, "handoff",
+                           G_CALLBACK(GstSubtitleDataHandOffCb_), this);
+  return true;
+}
+
+bool TrackRenderer::CreatePipeline_() {
+  TRACKRENDERER_ENTER_P(this);
+  pipeline_ = Pipeline<Elements>::Create(::kTrackRendererPipelineName);
+
+  constexpr int kPrimeNumForFamilyId = 97;
+  int gst_family_id =
+      reinterpret_cast<std::uint32_t>(this) % kPrimeNumForFamilyId;
+  TRACKRENDERER_ERROR_P(this, "gst family-id : %d", gst_family_id);
+  pipeline_->SetProperty(Elements::kPipeline, "family-id", gst_family_id);
+
+  pipeline_->SetGstElementCreatedCbHandler(std::bind(
+      &TrackRenderer::GstElementCreatedCb_, this, std::placeholders::_1));
+  for (const auto& trackctx : trackctx_) {
+    if (trackctx.index != kInvalidTrackIndex) {
+      if (!trackctx.create_pipeline(trackctx.track)) {
+        TRACKRENDERER_ERROR_P(this, "fail to create pipeline!");
+        // TODO(js4716.chun)
+        // - check if no leak.
+        return false;
+      }
+    }
+  }
+  if (trackctx_[kTrackTypeSubtitle].index == kInvalidTrackIndex) {
+    if (!trackctx_[kTrackTypeSubtitle].create_pipeline(nullptr)) {
+      TRACKRENDERER_ERROR_P(this, "fail to create pipeline!");
+      return false;
+    }
+  }
+  pipeline_->SetSyncHandler(GstBusSyncHandlerCb_, this, nullptr);
+  if (!pipeline_->SetState(Elements::kPipeline, GST_STATE_READY)) {
+    TRACKRENDERER_ERROR_P(this, "Set State to READY failed");
+    return false;
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+void TrackRenderer::SetDirectCrop_(const std::string& app_id) {
+  if (strstr(app_id.c_str(), "UsbCamApp") ||
+      strstr(app_id.c_str(), "GoogleDuoWeb")) {
+    enable_direct_crop_ = true;
+  }
+}
+
+void TrackRenderer::SetSequentialMode_() {
+  bool is_supporting_seq_mode = false;
+  int ret = system_info_get_custom_bool(
+      "com.samsung/featureconf/media.support_seq_mode",
+      &is_supporting_seq_mode);
+  if (SYSTEM_INFO_ERROR_NONE != ret) {
+    TRACKRENDERER_ERROR_P(
+        this, "system_info_get_custom_bool() return error [%d]", ret);
+    return;
+  }
+  if (!is_supporting_seq_mode) {
+    TRACKRENDERER_ERROR_P(this, "is_supporting_seq_mode [%d]",
+                          is_supporting_seq_mode);
+    return;
+  }
+  if (!internal::IsDecoderElementNecessary(
+          trackctx_[kTrackTypeVideo].track->mimetype)) {
+    TRACKRENDERER_ERROR_P(this, "raw video pipeline");
+    return;
+  }
+  constexpr std::uint32_t not_need_seq =
+      kLowLatencyModeVideoDistortionConcealment | kLowLatencyModeDisableAVSync |
+      kLowLatencyModeDisablePreroll | kLowLatencyModeDisableVideoQuality;
+  /* sequential mode can cause other issue because these modes can't ensure
+   * sync by pts */
+  if (low_latency_mode_ & not_need_seq) return;
+
+  use_seq_mode_ = 1;
+}
+
+void TrackRenderer::SetAppId(const std::string& app_id) {
+  PlayerAppInfo app_info;
+  app_info.id = app_id;
+  SetAppInfo(app_info);
+}
+
+void TrackRenderer::SetAppInfo(const PlayerAppInfo& app_info) {
+  if (strstr(app_info.id.c_str(), "netflix")) {
+    support_audio_codec_change_ = TRUE;
+    support_videodec_underflow_pause_ = true;
+  }
+#ifndef SOUNDBAR_PRODUCT
+  else if (strcmp(app_info.id.c_str(), "org.tizen.tv-viewer") == 0) {
+    avoc_sub_source_ = AVOC_SUB_SOURCE_UNIPLAYER_TVPLUS;
+  }
+#endif
+  SetDirectCrop_(app_info.id);
+  resource_manager_->SetAppId(app_info.id);
+  playback_info_->SetAppInfo(app_info);
+}
+
+bool TrackRenderer::GetResource_(const TrackType& type) {
+  assert(!trackinfo_.empty());
+  std::list<ResourceProperty> properties;
+  bool need_video_rsc =
+      (type == kTrackTypeMax || type == kTrackTypeVideo) ? true : false;
+  bool need_audio_rsc =
+      (type == kTrackTypeMax || type == kTrackTypeAudio) ? true : false;
+
+  TRACKRENDERER_INFO_P(this, "Is dual sound mode[%d]", IsDualSoundMode);
+  for (const Track& track : trackinfo_) {
+    if (track.active == false) continue;
+
+    if (track.type == kTrackTypeVideo && need_video_rsc) {
+      bool need_renderer_resource = true;
+      if (internal::IsDecoderElementNecessary(track.mimetype)) {
+        ResourceProperty videodecproperty;
+        videodecproperty.category = video_decoder_id_;
+        videodecproperty.track = track;
+        videodecproperty.is_multiview = is_multiscreen_;
+        videodecproperty.rsc_alloc_policy = rsc_alloc_policy_;
+
+        if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kReference) {
+          videodecproperty.is_vr360 = true;
+        } else if (internal::IsDisplayNeeded(display_type_) == false) {
+          need_renderer_resource = false;
+        }
+
+        if (internal::IsSdkEnabledFeature()) {
+          videodecproperty.use_sw = true;
+        } else {
+          videodecproperty.use_sw = track.use_swdecoder;
+        }
+        constexpr uint32_t kNdecodingMode = 0x04;
+        if (video_decoding_mode_ == kNdecodingMode) {
+          videodecproperty.is_ndecoding = true;
+        }
+        properties.push_back(videodecproperty);
+      }
+      if (need_renderer_resource) {
+        ResourceProperty videorenderproperty;
+        videorenderproperty.category = video_renderer_id_;
+        videorenderproperty.is_multiview = is_multiscreen_;
+        videorenderproperty.rsc_alloc_policy = rsc_alloc_policy_;
+        properties.push_back(videorenderproperty);
+      }
+    }
+    if (track.type == kTrackTypeAudio && need_audio_rsc) {
+      bool need_renderer_resource = true;
+      if (internal::IsDecoderElementNecessary(track.mimetype)) {
+        ResourceProperty audiodecproperty;
+        audiodecproperty.track = track;
+        if (internal::IsSdkEnabledFeature()) {
+          need_renderer_resource = false;
+          audiodecproperty.use_sw = true;
+        } else
+          audiodecproperty.use_sw = track.use_swdecoder;
+        audiodecproperty.category = audio_decoder_id_;
+        audiodecproperty.is_dual_sound = IsDualSoundMode;
+        audiodecproperty.is_multiview = is_multiscreen_;
+        audiodecproperty.rsc_alloc_policy = rsc_alloc_policy_;
+        properties.push_back(audiodecproperty);
+      }
+      if (need_renderer_resource) {
+        ResourceProperty audiorenderproperty;
+        audiorenderproperty.category = audio_out_id_;
+        audiorenderproperty.is_dual_sound = IsDualSoundMode;
+        audiorenderproperty.is_multiview = is_multiscreen_;
+        audiorenderproperty.rsc_alloc_policy = rsc_alloc_policy_;
+        audiorenderproperty.use_sw = track.use_swdecoder;
+        properties.push_back(audiorenderproperty);
+      }
+    }
+  }
+  bool ret = resource_manager_->Alloc(properties);
+  if (!ret) {
+    TRACKRENDERER_ERROR_P(this, "GetResource_ Fail");
+  }
+  return ret;
+}
+
+void TrackRenderer::SetDefaultAttributeValue_() {
+  for (auto& kv : kAttributes_) {
+    const Attribute& attr = kv.first;
+    const TrackRendererAttributeBinder& binder = kv.second;
+    set_attribute_values_[attr].value = binder.default_value;
+    set_attribute_values_[attr].value_assigned = false;
+  }
+}
+
+bool TrackRenderer::NeedAvocPlayerRegister_() {
+  TRACKRENDERER_ENTER_P(this);
+  if (internal::IsSdkEnabledFeature()) {
+    TRACKRENDERER_INFO_P(this, "SDK feature, don't need avoc register");
+    return false;
+  }
+
+  auto is_audio_track = [](const Track& item) noexcept->bool {
+    return item.mimetype.find("audio") != std::string::npos;
+  };
+  auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+  if (target == trackinfo_.end()) {
+    TRACKRENDERER_INFO_P(this, "Not found audio track");
+    return false;
+  }
+
+  ResourceProperty audiorenderproperty;
+  audiorenderproperty.category = audio_out_id_;
+  audiorenderproperty.use_sw = target->use_swdecoder;
+  if (resource_manager_->NeedPulseResource(audiorenderproperty)) {
+    TRACKRENDERER_INFO_P(this,
+                         "sw decoder + pulsesink, don't need avoc register");
+    return false;
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::AvocPlayerRegister_() {
+  TRACKRENDERER_ENTER_P(this);
+  avoc_id_ = resource_manager_->GetRawHandle();
+  if (!NeedAvocPlayerRegister_()) return true;
+
+  /* avoc does not care about player's audio out value, in fact avoc will check
+     audio out value from RC. so we can set them with default value to
+     avoc_av_player_register_m */
+  need_avoc_register = true;
+  int default_source_id = AVOC_AUDIO_SOURCE_MULTIMEDIA_DEC0;
+  int default_audio_out = 0;
+  ::PerfUsrTrace("avoc(_av)_player_register_m");
+
+#ifdef SOUNDBAR_PRODUCT
+  avoc_error_e ret = avoc_av_player_register_m(
+      static_cast<int>(display_->GetSurfaceId()), default_source_id,
+      default_audio_out, &avoc_id_);
+#else
+  avoc_error_e ret =
+      avoc_player_register_m(static_cast<int>(display_->GetSurfaceId()),
+                             default_source_id, default_audio_out, avoc_id_);
+#endif
+
+  if (ret != AVOC_EXIT_SUCCESS) {
+    TRACKRENDERER_ERROR_P(this, "avoc(_av)_player_register_m failed, ret[ %d ]",
+                          ret);
+    return false;
+  }
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::AvocPlayRequest_() {
+  TRACKRENDERER_ENTER_P(this);
+  if (resource_manager_->GetComponentName(audio_out_id_) ==
+      kPulseSinkComponentName) {
+    TRACKRENDERER_INFO_P(this,
+                         "sw decoder + pulsesink, don't need avoc request");
+    return true;
+  }
+  auto is_audio_track = [](const Track& item) noexcept->bool {
+    return item.mimetype.find("audio") != std::string::npos;
+  };
+  auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+  if (target == trackinfo_.end()) {
+    TRACKRENDERER_INFO_P(this, "Not found audio track");
+    return true;
+  }
+
+  if (resource_manager_->GetAllocatedState(audio_out_id_) !=
+      AllocatedState::kSuccess) {
+    TRACKRENDERER_INFO_P(
+        this, "AllocatedState: %d",
+        static_cast<int>(resource_manager_->GetAllocatedState(audio_out_id_)));
+    return true;
+  }
+
+  int sec_ctl_source = internal::GetAvocSourceType(
+      resource_manager_->IsMainDevice(audio_decoder_id_), target->use_swdecoder,
+      target->mimetype);
+  // AVOC uses the audio_out given by resource-center instead of player setting
+  // value. if resource-center return error, AVOC use this value in 4K model.
+  int audio_out =
+      internal::GetAudioOut(resource_manager_->IsMainDevice(audio_out_id_));
+
+  ::PerfUsrTrace("avoc(_av)_play_request_m");
+#ifdef SOUNDBAR_PRODUCT
+  avoc_error_e avoc_ret =
+      avoc_av_play_request_m(avoc_id_, sec_ctl_source, audio_out);
+#else
+  avoc_error_e avoc_ret =
+      avoc_play_request_m(avoc_id_, sec_ctl_source, audio_out);
+#endif
+
+  if (avoc_ret != AVOC_EXIT_SUCCESS) {
+    TRACKRENDERER_ERROR_P(this, "avoc(_av)_play_request_m failed, ret[ %d ]",
+                          avoc_ret);
+    return false;
+  }
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::AvocPlayerUnRegister_() {
+  TRACKRENDERER_ENTER_P(this);
+  if (avoc_id_ < 0) {
+    TRACKRENDERER_INFO_P(this, "Avoc has been deinitialized");
+    return true;
+  }
+  if (!need_avoc_register) return true;
+  avoc_error_e ret = AVOC_EXIT_SUCCESS;
+#ifdef SOUNDBAR_PRODUCT
+  ret = avoc_av_player_unregister(avoc_id_);
+#else
+  ret = avoc_player_unregister(avoc_id_);
+#endif
+  if (ret != AVOC_EXIT_SUCCESS) {
+    TRACKRENDERER_ERROR_P(this, "avoc(_av)_player_unregister() is failed");
+    return false;
+  }
+
+  avoc_id_ = -1;
+  need_avoc_register = false;
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::AddAiFilter_(void* aifilter) {
+  TRACKRENDERER_ENTER_P(this);
+  if (aifilter == nullptr) return false;
+  RemoveAiFilter_();
+  aifilter_ = gst_object_ref(aifilter);
+  return true;
+}
+
+void TrackRenderer::RemoveAiFilter_() {
+  TRACKRENDERER_ENTER_P(this);
+  if (aifilter_ == nullptr) return;
+  gst_object_unref(aifilter_);
+  aifilter_ = nullptr;
+  return;
+}
+
+bool TrackRenderer::ReleaseResource_() {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->UnsetPipeline();
+  pipeline_.reset();
+  AvocPlayerUnRegister_();
+  RemoveAiFilter_();
+
+  if (!resource_manager_->Dealloc()) {
+    TRACKRENDERER_ERROR_P(this, "resource manager dealloc fail!");
+  }
+
+  for (int i = 0; i < kTrackTypeMax; ++i) {
+    trackctx_[i].index = kInvalidTrackIndex;
+    trackctx_[i].is_enough_data = false;
+    trackctx_[i].need_update_segment = true;
+  }
+  trackinfo_.clear();
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+// LCOV_EXCL_START
+void TrackRenderer::OnResourceConflicted() {
+  TRACKRENDERER_ENTER_E_P(this);
+  resource_cv_.notify_one();
+  state_ = State::kResourceConflicted;
+  eventlistener_->OnResourceConflicted();
+}
+
+void TrackRenderer::OnVideoLatencyStatus(const LatencyStatus& latency_status) {
+  TRACKRENDERER_ENTER_E_P(this);
+  eventlistener_->OnVideoLatencyStatus(latency_status);
+}
+
+void TrackRenderer::OnAudioLatencyStatus(const LatencyStatus& latency_status) {
+  TRACKRENDERER_ENTER_E_P(this);
+  eventlistener_->OnAudioLatencyStatus(latency_status);
+}
+
+void TrackRenderer::OnVideoHighLatency() {
+  TRACKRENDERER_ENTER_E_P(this);
+  eventlistener_->OnVideoHighLatency();
+}
+
+void TrackRenderer::OnAudioHighLatency() {
+  TRACKRENDERER_ENTER_E_P(this);
+  eventlistener_->OnAudioHighLatency();
+}
+
+SubtitleType TrackRenderer::GetSubtitleType_(const GstBuffer* buf) {
+  auto is_subtitle_track = [](const Track& track) noexcept->bool {
+    return ((track.type == kTrackTypeSubtitle) && (track.active));
+  };
+
+  auto subtitle_track =
+      std::find_if(trackinfo_.begin(), trackinfo_.end(), is_subtitle_track);
+  if (subtitle_track == trackinfo_.end()) {
+    TRACKRENDERER_ERROR_P(this, "Not found subtitle track info");
+    return SubtitleType::kInvalid;
+  }
+
+  TRACKRENDERER_DEBUG_P(this, "subtitle_track->mimetype = [%s]",
+                        (subtitle_track->mimetype).c_str());
+
+  if ((subtitle_track->mimetype).find("x-xsub") != std::string::npos ||
+      (subtitle_track->mimetype).find("x-smpte-png") != std::string::npos ||
+      (subtitle_track->mimetype).find("video/x-raw") != std::string::npos) {
+    TRACKRENDERER_DEBUG_P(this, "It is Picture type subtitle");
+    return SubtitleType::kPicture;
+  }
+
+  if (((subtitle_track->mimetype).find("x-smpte-text") != std::string::npos) ||
+      ((subtitle_track->mimetype).find("stpp") != std::string::npos)) {
+    TRACKRENDERER_DEBUG_P(this, "Find the x-smpte-text");
+    gint* picture_flag = (gint*)gst_mini_object_get_qdata(
+        GST_MINI_OBJECT(buf), g_quark_from_static_string("picture_flag"));
+    TRACKRENDERER_DEBUG_P(this, "picture_flag = [%p]", picture_flag);
+    if (picture_flag && (1 == *picture_flag)) {
+      TRACKRENDERER_DEBUG_P(this,
+                            "It is Picture type subtitle for x-smpte-text");
+      return SubtitleType::kPicture;
+    }
+  }
+
+  TRACKRENDERER_DEBUG_P(this, "It is TEXT type subtitle");
+  return SubtitleType::kText;
+}
+
+void TrackRenderer::GstSubtitleDataHandOffCb_(GstElement* object,
+                                              GstBuffer* buf, GstPad* pad,
+                                              gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (trackrenderer == nullptr) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "trackrenderer == nullptr");
+    return;
+  }
+  TRACKRENDERER_DEBUG("Subtitle Buffer :Timestamp:[%" GST_TIME_FORMAT "]",
+                      GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)));
+  const SubtitleType type = trackrenderer->GetSubtitleType_(buf);
+  if (type == SubtitleType::kInvalid) return;
+  auto inbuffer = DecoderInputBuffer::Create(kTrackTypeSubtitle, 0, buf);
+  trackrenderer->eventlistener_->OnSubtitleData(std::move(inbuffer), type);
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+  SubtitleAttrParser sub_attr_parser(buf);
+  auto attr_list = sub_attr_parser.Parse();
+  if (!attr_list && gst_buffer_get_size(buf) > 0) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "attr_list is NULL");
+    return;
+  }
+  GstMapInfo info;
+  gst_buffer_map(buf, &info, GST_MAP_READ);
+  char* buffer = reinterpret_cast<char*>(info.data);
+  GstClockTime duration = GST_CLOCK_TIME_NONE;
+  duration = GST_TIME_AS_MSECONDS(GST_BUFFER_DURATION(buf));
+
+  trackrenderer->eventlistener_->OnSubtitleData(buffer, info.size, type,
+                                                duration, std::move(attr_list));
+  gst_buffer_unmap(buf, &info);
+#endif
+}
+
+void TrackRenderer::GstClosedCaptionHandOffCb_(GstElement* object,
+                                               GstBuffer* buf, GstPad* pad,
+                                               gpointer userdata) {
+  // need mutex for event listener
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  GstMapInfo info;
+  gst_buffer_map(buf, &info, GST_MAP_READ);
+  // TRACKRENDERER_DEBUG_P(trackrenderer, "data[%p], size[%d]", info.data,
+  // info.size);
+
+  char* buffer = reinterpret_cast<char*>(info.data);
+  trackrenderer->eventlistener_->OnClosedCaptionData(buffer, info.size);
+  gst_buffer_unmap(buf, &info);
+}
+
+void TrackRenderer::GstClosedCaptionPadAddedCb_(GstElement* element,
+                                                GstPad* pad,
+                                                gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  TRACKRENDERER_ENTER_P(trackrenderer);
+  if (!element || !pad) {
+    assert(element);
+    assert(pad);
+    TRACKRENDERER_ERROR_P(trackrenderer, "NULL object element[%p] pad[%p]",
+                          element, pad);
+    return;
+  }
+  auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
+  if (!caps.get()) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
+    return;
+  }
+  GstStructure* gststr = gst_caps_get_structure(caps.get(), 0);
+  if (!gststr) {
+    assert(gststr);
+    TRACKRENDERER_ERROR_P(trackrenderer, "GstStructure is NULL");
+    return;
+  }
+  std::string name = gst_structure_get_name(gststr);
+  if (name != "text/dtv-closed-caption") {
+    TRACKRENDERER_ERROR_P(trackrenderer, "NOT closed caption");
+    return;
+  }
+  assert(trackrenderer);
+  assert(trackrenderer->pipeline_.get());
+  if (!trackrenderer->pipeline_->FactoryMake(Elements::kQueueCaption, "queue",
+                                             "caption_queue")) {
+    assert(0);
+    return;
+  }
+
+  /*Not limit the time and buffer size of caption queue*/
+  trackrenderer->pipeline_->SetProperty(Elements::kQueueCaption,
+                                        "max-size-time", (guint64)0,
+                                        "max-size-buffers", (guint)0);
+
+  if (!trackrenderer->pipeline_->FactoryMake(Elements::kSinkCaption, "fakesink",
+                                             "caption_sink")) {
+    assert(0);
+    return;
+  }
+  trackrenderer->pipeline_->SetProperty(Elements::kSinkCaption, "sync", TRUE,
+                                        "async", FALSE, "signal-handoffs", TRUE,
+                                        "is-subtitle", TRUE);
+  trackrenderer->GstElementLowLatency_(kTrackTypeSubtitle);
+  trackrenderer->pipeline_->SignalConnect(
+      Elements::kSinkCaption, "handoff", G_CALLBACK(GstClosedCaptionHandOffCb_),
+      userdata);
+  trackrenderer->pipeline_->BinAddSimple(Elements::kBinVideo,
+                                         Elements::kQueueCaption);
+  trackrenderer->pipeline_->ElementLink(Elements::kDecVideo,
+                                        Elements::kQueueCaption);
+  trackrenderer->pipeline_->BinAdd(Elements::kBinVideo, Elements::kSinkCaption);
+  TRACKRENDERER_LEAVE_P(trackrenderer);
+}
+// LCOV_EXCL_STOP
+
+void TrackRenderer::CompleteSeeking_() {
+  if (!is_async_done_ || !is_seeking_) return;
+  TRACKRENDERER_ERROR_P(this, "Seeking has been completed SubState[%d]",
+                        static_cast<int>(target_substate_));
+  eventlistener_->OnSeekDone();
+  is_seeking_ = false;
+  is_async_done_ = false;
+}
+
+GstBusSyncReply TrackRenderer::GstBusSyncHandlerCb_(GstBus* bus,
+                                                    GstMessage* message,
+                                                    gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  assert(trackrenderer);
+
+  switch (GST_MESSAGE_TYPE(message)) {
+    case GST_MESSAGE_UNKNOWN:
+      TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_UNKNOWN");
+      break;
+    case GST_MESSAGE_EOS: {
+      TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_EOS");
+      trackrenderer->eventlistener_->OnEos();
+      break;
+    }
+    case GST_MESSAGE_STATE_CHANGED: {
+      GstState old_state = GST_STATE_VOID_PENDING;
+      GstState new_state = GST_STATE_VOID_PENDING;
+      GstState pending_state = GST_STATE_VOID_PENDING;
+      gst_message_parse_state_changed(message, &old_state, &new_state,
+                                      &pending_state);
+      std::string message_src_name(GST_MESSAGE_SRC_NAME(message));
+      gst_util::ShowStateChangedMsg(message, trackrenderer);
+      if (message_src_name == ::kTrackRendererPipelineName) {
+        if (old_state == GST_STATE_NULL && new_state == GST_STATE_READY &&
+            pending_state == GST_STATE_VOID_PENDING) {
+          TRACKRENDERER_ERROR_P(trackrenderer,
+                                "PIPELINE STATE CHANGED FROM NULL to READY");
+        } else if (old_state == GST_STATE_READY &&
+                   new_state == GST_STATE_PAUSED) {
+          trackrenderer->state_ = State::kWorking;
+          trackrenderer->resource_cv_.notify_one();
+
+          trackrenderer->UpdatePlaybackInfo_(false);
+
+          TRACKRENDERER_ERROR_P(trackrenderer,
+                                "PIPELINE STATE CHANGED FROM READY to PAUSED");
+        } else if (old_state == GST_STATE_PAUSED &&
+                   new_state == GST_STATE_PLAYING &&
+                   pending_state == GST_STATE_VOID_PENDING) {
+          trackrenderer->screen_saver_->StartTimeout();
+          TRACKRENDERER_ERROR_P(
+              trackrenderer, "PIPELINE STATE CHANGED FROM PAUSED to PLAYING");
+          trackrenderer->CompleteSeeking_();
+        } else if (old_state == GST_STATE_PLAYING &&
+                   new_state == GST_STATE_PAUSED) {
+          trackrenderer->screen_saver_->StopTimeout();
+        } else if (new_state == GST_STATE_NULL &&
+                   pending_state == GST_STATE_VOID_PENDING) {
+          trackrenderer->screen_saver_->StopTimeout();
+        }
+      }
+      break;
+    }  // case GST_MESSAGE_STATE_CHANGED
+    case GST_MESSAGE_ELEMENT: {
+      TRACKRENDERER_INFO_P(trackrenderer, "GST_MESSAGE_ELEMENT");
+      const gchar* struct_name =
+          gst_structure_get_name(gst_message_get_structure(message));
+      if (!strcmp(struct_name, "resolution_is_changed")) {
+        int is_changed = 0;
+        gst_structure_get_int(gst_message_get_structure(message),
+                              "Resolution_changed", &is_changed);
+        TRACKRENDERER_ERROR_P(trackrenderer, "resolution is changed - [%d]",
+                              is_changed);
+        if (1 == is_changed) {
+          trackrenderer->UpdatePlaybackInfo_(true);
+          EventMsg event_msg;
+          trackrenderer->GetResolutionInfo_(&event_msg);
+          trackrenderer->eventlistener_->OnEvent(EventType::kResolutionChanged,
+                                                 event_msg);
+        }
+      } else if (!strcmp(struct_name, "omx_vdec_underflow")) {
+        GstState element_state = GST_STATE_VOID_PENDING;
+        trackrenderer->pipeline_->GetState(Elements::kPipeline, &element_state,
+                                           NULL, 10 * GST_MSECOND);
+        TRACKRENDERER_WARN_P(
+            trackrenderer,
+            "omx_vdec_underflow will be posted, current state[%s]",
+            gst_element_state_get_name(element_state));
+        if (element_state == GST_STATE_PLAYING) {
+          trackrenderer->eventlistener_->OnVideoDecoderUnderrun();
+        }
+      }
+      break;
+    }  // case GST_MESSAGE_ELEMENT
+    case GST_MESSAGE_ASYNC_DONE: {
+      TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_ASYNC_DONE");
+      trackrenderer->is_async_done_ = true;
+      if (trackrenderer->target_substate_ != SubState::kPlaying) {
+        trackrenderer->CompleteSeeking_();
+      }
+      if (trackrenderer->is_flushing_) {
+        trackrenderer->eventlistener_->OnFlushDone();
+        trackrenderer->is_flushing_ = false;
+        trackrenderer->enable_audio_track_change_ = false;
+      }
+      break;
+    }
+    // LCOV_EXCL_START
+    case GST_MESSAGE_ERROR: {
+      TRACKRENDERER_ERROR_P(trackrenderer, "GST_MESSAGE_ERROR");
+      trackrenderer->resource_cv_.notify_one();
+      bool is_music_content =
+          trackrenderer->trackctx_[kTrackTypeVideo].index != kInvalidTrackIndex
+              ? false
+              : true;
+      const ErrorType err = HandleError(message, is_music_content);
+      if (trackrenderer->is_error_posted_) {
+        TRACKRENDERER_INFO_P(trackrenderer, "error is already posted");
+        break;
+      }
+      trackrenderer->eventlistener_->OnError(err);
+      gchar* error_msg = nullptr;
+      HandleErrorMsg(message, &error_msg);
+      auto debug = gstguard::make_guard(error_msg);
+      if (debug != nullptr) {
+        trackrenderer->eventlistener_->OnErrorMsg(err, debug.get());
+      }
+      trackrenderer->is_error_posted_ = true;
+      break;
+    }  // case GST_MESSAGE_ERROR
+    // LCOV_EXCL_STOP
+    default: {
+      TRACKRENDERER_INFO_P(
+          trackrenderer, "thread[ %p ], msg[ %p / %s ] src[ %s ]",
+          g_thread_self(), message, GST_MESSAGE_TYPE_NAME(message),
+          GST_MESSAGE_SRC_NAME(message));
+    }
+  }
+  gst_message_unref(message);
+  return GST_BUS_DROP;
+}
+
+GstPadProbeReturn TrackRenderer::GstPadProbeIdleCb_(GstPad* pad,
+                                                    GstPadProbeInfo* info,
+                                                    gpointer userdata) {
+  TRACKRENDERER_ENTER;
+  auto gstpad = static_cast<Pipeline<Elements>::Pad*>(userdata);
+  std::unique_lock<std::mutex> pad_block_locker(gstpad->m);
+  gstpad->is_idle = true;
+  gstpad->cv.notify_one();
+  return GST_PAD_PROBE_REMOVE;
+}
+
+void TrackRenderer::GstAudioNeedDataCb_(GstElement* element, guint size,
+                                        gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  trackrenderer->trackctx_[kTrackTypeAudio].is_enough_data = false;
+  trackrenderer->eventlistener_->OnBufferStatus(kTrackTypeAudio,
+                                                BufferStatus::kUnderrun);
+}
+
+void TrackRenderer::GstVideoNeedDataCb_(GstElement* element, guint size,
+                                        gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  trackrenderer->trackctx_[kTrackTypeVideo].is_enough_data = false;
+  trackrenderer->eventlistener_->OnBufferStatus(kTrackTypeVideo,
+                                                BufferStatus::kUnderrun);
+}
+
+void TrackRenderer::GstSubtitleNeedDataCb_(GstElement* element, guint size,
+                                           gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (trackrenderer->trackctx_[kTrackTypeSubtitle].index == kInvalidTrackIndex)
+    return;
+  trackrenderer->trackctx_[kTrackTypeSubtitle].is_enough_data = false;
+}
+
+void TrackRenderer::GstAudioEnoughDataCb_(GstElement* element,
+                                          gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  trackrenderer->trackctx_[kTrackTypeAudio].is_enough_data = true;
+  trackrenderer->eventlistener_->OnBufferStatus(kTrackTypeAudio,
+                                                BufferStatus::kOverrun);
+}
+
+void TrackRenderer::GstVideoEnoughDataCb_(GstElement* element,
+                                          gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  trackrenderer->trackctx_[kTrackTypeVideo].is_enough_data = true;
+  trackrenderer->eventlistener_->OnBufferStatus(kTrackTypeVideo,
+                                                BufferStatus::kOverrun);
+}
+
+void TrackRenderer::GstSubtitleEnoughDataCb_(GstElement* element,
+                                             gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (trackrenderer->trackctx_[kTrackTypeSubtitle].index == kInvalidTrackIndex)
+    return;
+  trackrenderer->trackctx_[kTrackTypeSubtitle].is_enough_data = true;
+}
+
+gboolean TrackRenderer::GstAudioSeekDataCb_(GstElement* element, guint64 offset,
+                                            gpointer user_data) {
+  auto trackrenderer = static_cast<TrackRenderer*>(user_data);
+  TRACKRENDERER_INFO_P(trackrenderer, "offset : %llu", offset);
+  trackrenderer->eventlistener_->OnSeekData(kTrackTypeAudio,
+                                            offset / GST_MSECOND);
+  return true;
+}
+
+gboolean TrackRenderer::GstVideoSeekDataCb_(GstElement* element, guint64 offset,
+                                            gpointer user_data) {
+  auto trackrenderer = static_cast<TrackRenderer*>(user_data);
+  TRACKRENDERER_INFO_P(trackrenderer, "offset : %llu", offset);
+  trackrenderer->eventlistener_->OnSeekData(kTrackTypeVideo,
+                                            offset / GST_MSECOND);
+  return true;
+}
+
+gboolean TrackRenderer::GstSubtitleSeekDataCb_(GstElement* element,
+                                               guint64 offset,
+                                               gpointer user_data) {
+  auto trackrenderer = static_cast<TrackRenderer*>(user_data);
+  TRACKRENDERER_INFO_P(trackrenderer, "offset : %llu", offset);
+  return true;
+}
+
+// LCOV_EXCL_START
+gboolean TrackRenderer::GstAudioDrmInitDataCb_(int* drmhandle, unsigned int len,
+                                               unsigned char* psshdata,
+                                               void* userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  TRACKRENDERER_ENTER_P(trackrenderer);
+  trackrenderer->eventlistener_->OnDrmInitData(drmhandle, len, psshdata,
+                                               kTrackTypeAudio);
+  TRACKRENDERER_LEAVE_P(trackrenderer);
+  return TRUE;
+}
+
+gboolean TrackRenderer::GstVideoDrmInitDataCb_(int* drmhandle, unsigned int len,
+                                               unsigned char* psshdata,
+                                               void* userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  TRACKRENDERER_ENTER_P(trackrenderer);
+  trackrenderer->eventlistener_->OnDrmInitData(drmhandle, len, psshdata,
+                                               kTrackTypeVideo);
+  TRACKRENDERER_LEAVE_P(trackrenderer);
+  return TRUE;
+}
+// LCOV_EXCL_STOP
+
+void TrackRenderer::GstElementCreatedCb_(Elements element) {
+  auto it = kAttributesByElem_.find(element);
+  if (it == kAttributesByElem_.end()) return;
+  const std::vector<Attribute>& attrs = it->second;
+  for (const auto& attr : attrs) {
+    const auto& binder = kAttributes_.at(attr);
+    const AttributeValue& attr_value = set_attribute_values_[attr];
+    if (binder.need_to_init == false && attr_value.value_assigned == false)
+      continue;
+    const boost::any empty;
+    SetAttribute_(binder, empty, attr_value.value);
+  }
+}
+
+void TrackRenderer::GstDecodedVideoReferenceBufferCb_(GstElement* element,
+                                                      GstBuffer* buffer,
+                                                      GstPad* pad,
+                                                      void* userdata) {
+  GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
+      GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (!s) {
+    TRACKRENDERER_ERROR_P(trackrenderer,
+                          "scaler buffer don't have v4l2_info structure");
+    return;
+  }
+  int width, height, y_linesize, c_linesize, y_fd, c_fd, plane_num;
+  gst_structure_get_int(s, "width", &width);
+  gst_structure_get_int(s, "height", &height);
+  gst_structure_get_int(s, "y_linesize", &y_linesize);
+  gst_structure_get_int(s, "u_linesize", &c_linesize);
+  gst_structure_get_int(s, "y_phyaddr", &y_fd);
+  gst_structure_get_int(s, "u_phyaddr", &c_fd);
+  gst_structure_get_int(s, "plane_num", &plane_num);
+
+  tbm_bo bo_Y =
+      tbm_bo_import_fd(trackrenderer->tbm_buffer_manager_->bufmgr, y_fd);
+  if (bo_Y == nullptr) {
+    TRACKRENDERER_ERROR_P(trackrenderer,
+                          "[Weak Ref] tbm_bo_import_fd() error : Y bo is NULL");
+    return;
+  }
+  BOOST_SCOPE_EXIT(&bo_Y) {
+    if (bo_Y) {
+      tbm_bo_unref(bo_Y);
+      bo_Y = nullptr;
+    }
+  }
+  BOOST_SCOPE_EXIT_END
+
+  tbm_bo bo_C =
+      tbm_bo_import_fd(trackrenderer->tbm_buffer_manager_->bufmgr, c_fd);
+  if (bo_C == nullptr) {
+    TRACKRENDERER_ERROR_P(trackrenderer,
+                          "[Weak Ref] tbm_bo_import_fd() error : C bo is NULL");
+    return;
+  }
+  BOOST_SCOPE_EXIT(&bo_C) {
+    if (bo_C) {
+      tbm_bo_unref(bo_C);
+      bo_C = nullptr;
+    }
+  }
+  BOOST_SCOPE_EXIT_END
+
+  tbm_bo bo[internal::kVideoBufferPlaneMax] = {nullptr};
+  bo[GST_VIDEO_COMP_Y] = bo_Y;
+  bo[GST_VIDEO_COMP_U] = bo_C;
+
+  tbm_surface_info_s info;
+  memset(&info, 0, sizeof(info));
+  info.width = width;
+  info.height = height;
+  info.format = TBM_FORMAT_NV12;
+
+  info.bpp = tbm_surface_internal_get_bpp(info.format);
+  info.num_planes = tbm_surface_internal_get_num_planes(info.format);
+
+  info.planes[GST_VIDEO_COMP_Y].stride = y_linesize;
+  info.planes[GST_VIDEO_COMP_Y].size = y_linesize * c_linesize;
+  info.size += info.planes[GST_VIDEO_COMP_Y].size;
+  info.planes[GST_VIDEO_COMP_U].stride = c_linesize;
+  info.planes[GST_VIDEO_COMP_U].size = c_linesize * c_linesize / 2;
+  info.size += info.planes[GST_VIDEO_COMP_U].size;
+
+  tbm_surface_h tbm_surf =
+      tbm_surface_internal_create_with_bos(&info, bo, info.num_planes);
+  if (!tbm_surf) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "failed to create tbm surface");
+    return;
+  }
+
+  DecodedVideoPacket packet;
+  packet.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));  // ns -> ms
+  packet.surface_data = tbm_surf;
+  packet.scaler_index = reinterpret_cast<void*>(plane_num);
+
+  trackrenderer->eventlistener_->OnMediaPacketVideoDecoded(packet);
+  return;
+}
+
+void TrackRenderer::GstDecodedVideoCopyBufferCb_(GstElement* element,
+                                                 GstBuffer* buffer, GstPad* pad,
+                                                 void* userdata) {
+  auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (!caps.get()) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
+    return;
+  }
+  GstVideoInfo info;
+  if (!gst_video_info_from_caps(&info, caps.get())) {
+    TRACKRENDERER_ERROR_P(trackrenderer,
+                          "fail to get gst_video_info_from_caps()");
+    return;
+  }
+  VideoColorFormat colorformat = VideoColorFormat::kColorFormatNV12;
+  GstStructure* structure = gst_caps_get_structure(caps.get(), 0);
+  const gchar* color_format =
+      gst_structure_get_string(structure, "color-format");
+  if (color_format && strstr(color_format, "NV16"))
+    colorformat = VideoColorFormat::kColorFormatNV16;
+
+  tbm_surface_h tbm_surf_t = nullptr;
+  internal::VideoStreamDataType stream = {};
+
+  BOOST_SCOPE_EXIT(&tbm_surf_t) {
+    if (tbm_surf_t) {
+      tbm_surface_destroy(tbm_surf_t);
+      tbm_surf_t = nullptr;
+    }
+  }
+  BOOST_SCOPE_EXIT_END
+
+  if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV0) {
+    GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
+        GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
+    if (!s) {
+      TRACKRENDERER_ERROR_P(trackrenderer,
+                            "scaler buffer don't have v4l2_info structure");
+      return;
+    }
+    int y_linesize, c_linesize, y_viraddr, c_viraddr, plane_num = 0;
+    int width = 0, height = 0;
+    gst_structure_get_int(s, "width", &width);
+    gst_structure_get_int(s, "height", &height);
+    gst_structure_get_int(s, "y_viraddr", &y_viraddr);
+    gst_structure_get_int(s, "u_viraddr", &c_viraddr);
+    gst_structure_get_int(s, "y_linesize", &y_linesize);
+    gst_structure_get_int(s, "u_linesize", &c_linesize);
+    gst_structure_get_int(s, "plane_num", &plane_num);
+
+    if (internal::FillVideoStreamDataAndTbmSurface(&stream, &tbm_surf_t, width,
+                                                   height) == false) {
+      TRACKRENDERER_ERROR_P(trackrenderer,
+                            "FillVideoStreamDataAndTbmSurface fail");
+      return;
+    }
+
+    if (!internal::CopyHwCodec(stream, y_viraddr, c_viraddr, y_linesize,
+                               c_linesize, colorformat)) {
+      TRACKRENDERER_ERROR_P(trackrenderer, "data copy fail");
+      return;
+    }
+  } else if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV1) {
+    if (internal::FillVideoStreamDataAndTbmSurface(
+            &stream, &tbm_surf_t, info.width, info.height) == false) {
+      TRACKRENDERER_ERROR_P(trackrenderer,
+                            "FillVideoStreamDataAndTbmSurface fail");
+      return;
+    }
+
+    if (!internal::CopySwCodec(buffer, stream)) {
+      TRACKRENDERER_ERROR_P(trackrenderer, "data copy fail");
+      return;
+    }
+  }
+  tbm_surface_h tbm_surf = internal::CreateTbmSurfaceWithBos(stream);
+
+  DecodedVideoPacket packet;
+  packet.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));  // ns -> ms
+  packet.surface_data = tbm_surf;
+
+  trackrenderer->eventlistener_->OnMediaPacketVideoDecoded(packet);
+  return;
+}
+
+// LCOV_EXCL_START
+void TrackRenderer::GstDecodedVideoRawBufferCb_(GstElement* element,
+                                                GstBuffer* buffer, GstPad* pad,
+                                                void* userdata) {
+  auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (!caps.get()) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
+    return;
+  }
+  GstVideoInfo info;
+  if (!gst_video_info_from_caps(&info, caps.get())) {
+    TRACKRENDERER_ERROR_P(trackrenderer,
+                          "fail to get gst_video_info_from_caps()");
+    return;
+  }
+
+  DecodedVideoRawModePacket packet;
+
+  int width = 0, height = 0;
+  if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV0) {
+    GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
+        GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
+    if (!s) {
+      TRACKRENDERER_ERROR_P(trackrenderer,
+                            "scaler buffer doesn't have v4l2_info structure");
+      return;
+    }
+    packet.type = DecodedVideoRawModePacketType::kPhysicalAddress;
+    gst_structure_get_int(s, "width", &width);
+    gst_structure_get_int(s, "height", &height);
+    gst_structure_get_int(s, "y_phyaddr", &packet.data.raw.y_phyaddr);
+    gst_structure_get_int(s, "u_phyaddr", &packet.data.raw.uv_phyaddr);
+    gst_structure_get_int(s, "y_viraddr", &packet.data.raw.y_viraddr);
+    gst_structure_get_int(s, "u_viraddr", &packet.data.raw.uv_viraddr);
+    gst_structure_get_int(s, "y_linesize", &packet.data.raw.y_linesize);
+    gst_structure_get_int(s, "u_linesize", &packet.data.raw.uv_linesize);
+  } else if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV1) {
+    GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
+        GST_MINI_OBJECT(buffer), g_quark_from_static_string("tbm_bo")));
+    width = info.width;
+    height = info.height;
+    if (s) {
+      packet.type = DecodedVideoRawModePacketType::kTizenBuffer;
+      if (!gst_structure_get(s, "tbm_bo_key", G_TYPE_UINT, &packet.data.tbm.key,
+                             NULL)) {
+        TRACKRENDERER_ERROR_P(trackrenderer,
+                              "Buffer doesn't have tbm_bo_hnd structure");
+        return;
+      }
+    } else {
+      TRACKRENDERER_ERROR_P(trackrenderer,
+                            "Buffer doesn't have tbm_bo structure");
+      return;
+    }
+  }
+
+  packet.width = width;
+  packet.height = height;
+  packet.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));  // ns -> ms
+
+  trackrenderer->eventlistener_->OnMediaRawPacketVideoDecoded(packet);
+  return;
+}
+
+void TrackRenderer::GstDecodedVideoScaleBufferCb_(GstElement* element,
+                                                  GstBuffer* buffer,
+                                                  GstPad* pad, void* userdata) {
+  auto caps = gstguard::make_guard(gst_pad_get_current_caps(pad));
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (!caps.get()) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "caps is NULL");
+    return;
+  }
+  GstVideoInfo info;
+  if (!gst_video_info_from_caps(&info, caps.get())) {
+    TRACKRENDERER_ERROR_P(trackrenderer,
+                          "fail to get gst_video_info_from_caps()");
+    return;
+  }
+  if (trackrenderer->NeedDropThisDecodedVideoBuffer_()) {
+    return;
+  }
+  std::lock_guard<std::mutex> lk(trackrenderer->scale_target_m_);
+  internal::VideoStreamDataType stream = {};
+  stream.format = TBM_FORMAT_NV12;
+  stream.width = trackrenderer->scale_target_width_;
+  stream.height = trackrenderer->scale_target_height_;
+  stream.elevation[GST_VIDEO_COMP_Y] = trackrenderer->scale_target_height_;
+  stream.elevation[GST_VIDEO_COMP_U] = trackrenderer->scale_target_height_ / 2;
+  VideoColorFormat colorformat = VideoColorFormat::kColorFormatNV12;
+  GstStructure* structure = gst_caps_get_structure(caps.get(), 0);
+  const gchar* color_format =
+      gst_structure_get_string(structure, "color-format");
+  if (color_format && strstr(color_format, "NV16"))
+    colorformat = VideoColorFormat::kColorFormatNV16;
+  // using cb to get the free tbm ptr, if not find then new one, else, using it
+  tbm_surface_h tbm_surf_t = nullptr;
+  void* tbm_surf = nullptr;
+  bool exception_flag = true;
+  DecodedVideoPacket packet;
+
+  BOOST_SCOPE_EXIT(&tbm_surf_t, &tbm_surf, &exception_flag) {
+    if (!tbm_surf && tbm_surf_t && exception_flag == true) {
+      tbm_surface_destroy(tbm_surf_t);
+      tbm_surf_t = nullptr;
+    }
+  }
+  BOOST_SCOPE_EXIT_END
+
+  if (GST_VIDEO_INFO_FORMAT(&info) == GST_VIDEO_FORMAT_STV0) {
+    GstStructure* s = GST_STRUCTURE_CAST(gst_mini_object_get_qdata(
+        GST_MINI_OBJECT(buffer), g_quark_from_static_string("v4l2_info")));
+    if (!s) {
+      TRACKRENDERER_ERROR_P(trackrenderer,
+                            "scaler buffer don't have v4l2_info structure");
+      return;
+    }
+    int y_linesize, c_linesize, y_phyaddr, u_phyaddr, plane_num = 0;
+    int width = 0, height = 0;
+    CropArea crop_info;
+    int x, y, w, h = 0;
+    gst_structure_get_int(s, "width", &width);
+    gst_structure_get_int(s, "height", &height);
+    gst_structure_get_int(s, "y_phyaddr", &y_phyaddr);
+    gst_structure_get_int(s, "u_phyaddr", &u_phyaddr);
+    gst_structure_get_int(s, "y_linesize", &y_linesize);
+    gst_structure_get_int(s, "u_linesize", &c_linesize);
+    gst_structure_get_int(s, "plane_num", &plane_num);
+    if (!y_phyaddr || !u_phyaddr) {
+      TRACKRENDERER_ERROR_P(trackrenderer, "invalid y_phyaddr or u_phyaddr");
+      return;
+    }
+    if (!width || !height) {
+      TRACKRENDERER_WARN_P(
+          trackrenderer,
+          "invalid width or height, using width&&height of caps_info");
+      width = info.width;
+      height = info.height;
+    }
+
+    tbm_surface_info_s surface_info;
+    trackrenderer->eventlistener_->OnMediaPacketGetTbmBufPtr(
+        &tbm_surf, trackrenderer->is_scale_size_changed_);
+    trackrenderer->is_scale_size_changed_ = false;
+    if (tbm_surf == nullptr) {
+      tbm_surf_t = tbm_surface_internal_create_with_flags(
+          stream.width, stream.height, TBM_FORMAT_NV12,
+          (1 << 17 | TBM_BO_SCANOUT));
+      TRACKRENDERER_ERROR_P(trackrenderer, "create new tbm %p", tbm_surf_t);
+    } else {
+      tbm_surf_t = static_cast<tbm_surface_h>(tbm_surf);
+    }
+    stream.bo[GST_VIDEO_COMP_Y] = tbm_surface_internal_get_bo(tbm_surf_t, 0);
+    if (!stream.bo[GST_VIDEO_COMP_Y]) {
+      TRACKRENDERER_ERROR_P(trackrenderer, "[bo Y] tbm_bo_alloc failed");
+      return;
+    }
+    stream.bo[GST_VIDEO_COMP_U] = tbm_surface_internal_get_bo(tbm_surf_t, 1);
+    if (!stream.bo[GST_VIDEO_COMP_U]) {
+      TRACKRENDERER_ERROR_P(trackrenderer, "[bo U] tbm_bo_alloc failed");
+      return;
+    }
+    if (TBM_SURFACE_ERROR_NONE !=
+        tbm_surface_get_info(tbm_surf_t, &surface_info)) {
+      TRACKRENDERER_ERROR_P(trackrenderer, "tbm_surface_get_info failed");
+      return;
+    }
+    stream.stride[GST_VIDEO_COMP_Y] = surface_info.planes[0].stride;
+    stream.stride[GST_VIDEO_COMP_U] = surface_info.planes[1].stride;
+
+    trackrenderer->display_->GetDisplayCropArea(&crop_info);
+    x = width * crop_info.scale_x;
+    y = height * crop_info.scale_y;
+    w = width * crop_info.scale_w;
+    h = height * crop_info.scale_h;
+    internal::SetGeometry(&stream.crop_area, x & 0xFFFFFFFE, y & 0xFFFFFFFE, w,
+                          h);
+    if (!internal::ScaleHwCodecWithGa(
+            trackrenderer->tbm_buffer_manager_->bufmgr, stream, y_phyaddr,
+            u_phyaddr, y_linesize, c_linesize, colorformat)) {
+      TRACKRENDERER_ERROR_P(trackrenderer, "data copy fail");
+      return;
+    }
+  } else {
+    TRACKRENDERER_ERROR_P(trackrenderer, "SW decoder type, not support now");
+    return;
+  }
+  packet.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));  // ns -> ms
+  packet.surface_data = tbm_surf_t;
+  trackrenderer->eventlistener_->OnMediaPacketVideoDecoded(packet);
+  exception_flag = false;
+  return;
+}
+
+void TrackRenderer::GstAiFilterResultCb_(GstElement* element,
+                                         GstStructure* structure,
+                                         void* userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  const gchar* struct_name = gst_structure_get_name(structure);
+  if (!strcmp(struct_name, "auto_zoom_crop")) {
+    CropArea roi_area;
+    gfloat x_ratio, y_ratio = 0.0f;
+    gfloat width_ratio, height_ratio = 1.0f;
+
+    gst_structure_get(structure, "x_ratio", G_TYPE_FLOAT, &x_ratio, "y_ratio",
+                      G_TYPE_FLOAT, &y_ratio, "width_ratio", G_TYPE_FLOAT,
+                      &width_ratio, "height_ratio", G_TYPE_FLOAT, &height_ratio,
+                      NULL);
+    TRACKRENDERER_DEBUG_P(
+        trackrenderer, "x_ratio %f y_ratio %f width_ratio %f height_ratio %f",
+        x_ratio, y_ratio, width_ratio, height_ratio);
+
+    roi_area.scale_x = (double)x_ratio;
+    roi_area.scale_y = (double)y_ratio;
+    roi_area.scale_w = (double)width_ratio;
+    roi_area.scale_h = (double)height_ratio;
+    trackrenderer->display_->SetDisplayCropArea(roi_area);
+    if (!trackrenderer->pipeline_) return;
+    trackrenderer->pipeline_->Execute(
+        Elements::kSinkVideo, [trackrenderer](GstElement * obj) noexcept {
+          return trackrenderer->display_->UpdateCropArea(obj);
+        });
+  }
+  return;
+}
+// LCOV_EXCL_STOP
+
+void TrackRenderer::FlushAppsrc(TrackType type, bool setbyuser) {
+  TRACKRENDERER_ENTER_P(this);
+  if (!pipeline_) return;
+  if (type >= kTrackTypeMax) {
+    TRACKRENDERER_ERROR_P(
+        this,
+        "Support only audio and subtitle and video pipeline flush for now");
+    return;
+  }
+  Track track;
+  if (!track_util::GetActiveTrack(trackinfo_, type, &track)) {
+    TRACKRENDERER_ERROR_P(this, "There is no %s track",
+                          track_util::GetTrackTypeString(type).c_str());
+    return;
+  }
+  if (setbyuser && type == kTrackTypeAudio) enable_audio_track_change_ = true;
+
+  Elements element = Elements::kAppSrcSubtitle;
+  if (type == kTrackTypeAudio) {
+    element = Elements::kAppSrcAudio;
+  } else if (type == kTrackTypeVideo) {
+    if (support_videodec_underflow_pause_) {
+      pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
+    }
+    element = Elements::kAppSrcVideo;
+    latency_manager_->UpdateVideoFrameStatus(
+        LatencyManager::UpdatePacketStatus::kFlush);
+  }
+  pipeline_->Flush(element);
+  if (setbyuser) is_flushing_ = true;
+
+  // TODO: external flush api seems not to need to check pad idle status. it is
+  // necessary to check whether to remove this code.
+  Pipeline<Elements>::Pad pad;
+  pipeline_->PadAddProbe(element, nullptr, "src", GST_PAD_PROBE_TYPE_IDLE,
+                         GstPadProbeIdleCb_, &pad, nullptr);
+
+  {
+    std::unique_lock<std::mutex> pad_block_locker(pad.m);
+    if (!pad.is_idle) {
+      pad.cv.wait(pad_block_locker);
+      TRACKRENDERER_INFO_P(this, "pad block wait end");
+    }
+  }
+  TRACKRENDERER_LEAVE_P(this);
+}
+
+void TrackRenderer::SetVideoFrameBufferType(DecodedVideoFrameBufferType type) {
+  TRACKRENDERER_ENTER_E_P(this);
+  decoded_buffer_type_ = type;
+  if (type == DecodedVideoFrameBufferType::kScale) {
+    CreateTbmBufferManager_();
+    SetPropertyForDecodedVideoBufferWithDisplay_();
+  }
+  if (type == DecodedVideoFrameBufferType::kReference) {
+    if (vr360_ == nullptr) {
+      vr360_.reset(new Vr360);
+    }
+  }
+}
+
+void TrackRenderer::SetVideoFrameBufferScaleResolution(
+    const uint32_t& target_width, const uint32_t& target_height) {
+  TRACKRENDERER_ENTER;
+  std::lock_guard<std::mutex> lk(scale_target_m_);
+  scale_target_width_ = target_width;
+  scale_target_height_ = target_height;
+  is_scale_size_changed_ = true;
+}
+
+bool TrackRenderer::SetDecodedVideoFrameRate(
+    const Rational& request_framerate) {
+  TRACKRENDERER_ENTER;
+  std::lock_guard<std::mutex> lk(decoded_drop_ctx_.drop_mutex);
+
+  if (request_framerate.num && !request_framerate.den) {
+    TRACKRENDERER_ERROR("invalid request frame rate: %d/%d",
+                        request_framerate.num, request_framerate.den);
+    return false;
+  }
+  decoded_drop_ctx_.request_fps = request_framerate;
+  decoded_drop_ctx_.fps_changed = true;
+  return true;
+}
+
+void TrackRenderer::RegisterListener(EventListener* listener) {
+  assert(listener);
+  assert(!eventlistener_);
+  eventlistener_ = listener;
+}
+
+bool TrackRenderer::RemoveDownstreamOfAppsrc_(TrackType type) {
+  TRACKRENDERER_ENTER_P(this);
+  if (type == kTrackTypeVideo) {
+    pipeline_->BinRemove(Elements::kBinVideo, Elements::kDrmVideo,
+                         Elements::kDecVideo, Elements::kQueueCaption,
+                         Elements::kSinkCaption, Elements::kAiFilter,
+                         Elements::kSinkVideo);
+  } else if (type == kTrackTypeAudio) {
+    pipeline_->BinRemove(Elements::kBinAudio, Elements::kDrmAudio,
+                         Elements::kDecAudio, Elements::kAudioConvert,
+                         Elements::kCapsFillterDefault,
+                         Elements::kAudioResample, Elements::kCapsFillter2,
+                         Elements::kScaleTempo, Elements::kSinkAudio);
+  }
+
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+// LCOV_EXCL_START
+GstPadProbeReturn TrackRenderer::GstPadProbeBlockCb_(GstPad* pad,
+                                                     GstPadProbeInfo* info,
+                                                     gpointer userdata) {
+  TRACKRENDERER_ENTER_P(userdata);
+  if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
+    GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info);
+
+    if (!GST_EVENT_IS_SERIALIZED(event)) {
+      TRACKRENDERER_DEBUG_P(userdata, "pass non-serialized event");
+      return GST_PAD_PROBE_PASS;
+    }
+
+    if (GST_EVENT_IS_STICKY(event) && GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
+      TRACKRENDERER_DEBUG_P(userdata, "pass sticky event");
+      return GST_PAD_PROBE_PASS;
+    }
+  }
+
+  if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_BUFFER) {
+    TRACKRENDERER_DEBUG_P(userdata, "drop buffer as pad is not re-activated");
+    return GST_PAD_PROBE_DROP;
+  }
+  return GST_PAD_PROBE_OK;
+}
+// LCOV_EXCL_STOP
+
+GstPadProbeReturn TrackRenderer::GstPadProbeVideoPeekBlockCb_(
+    GstPad* pad, GstPadProbeInfo* info, gpointer userdata) {
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  TRACKRENDERER_ENTER_P(trackrenderer);
+  if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
+    GstEvent* event = GST_PAD_PROBE_INFO_EVENT(info);
+
+    if (!GST_EVENT_IS_SERIALIZED(event)) {
+      TRACKRENDERER_DEBUG_P(trackrenderer, "pass non-serialized event");
+      return GST_PAD_PROBE_PASS;
+    }
+
+    if (GST_EVENT_IS_STICKY(event) && GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
+      TRACKRENDERER_DEBUG_P(trackrenderer, "pass sticky event");
+      return GST_PAD_PROBE_PASS;
+    }
+  }
+
+  GstBuffer* buffer = gst_pad_probe_info_get_buffer(info);
+  if (!buffer) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "buffer is null maybe EOS event");
+    return GST_PAD_PROBE_PASS;
+  }
+  trackrenderer->last_position_ = GST_BUFFER_PTS(buffer) / GST_MSECOND;
+  TRACKRENDERER_ERROR_P(trackrenderer,
+                        "Update last position for playing time [%lld ms]",
+                        trackrenderer->last_position_);
+
+  if (trackrenderer->is_seeking_ && trackrenderer->state_ == State::kWorking) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "Seek Done");
+    trackrenderer->eventlistener_->OnSeekDone();
+    trackrenderer->is_seeking_ = false;
+    return GST_PAD_PROBE_OK;
+  }
+  return GST_PAD_PROBE_OK;
+}
+
+GstPadProbeReturn TrackRenderer::GstPadProbeVideoDecodedCb_(
+    GstPad* pad, GstPadProbeInfo* info, gpointer userdata) {
+  GstBuffer* buffer = gst_pad_probe_info_get_buffer(info);
+  auto trackrenderer = static_cast<TrackRenderer*>(userdata);
+  if (trackrenderer->state_ < State::kWorking && buffer) {
+    TRACKRENDERER_ERROR_P(trackrenderer, "First Decoding Done");
+    trackrenderer->eventlistener_->OnFirstDecodingDone();
+  }
+  return GST_PAD_PROBE_OK;
+}
+
+GstPadProbeReturn TrackRenderer::GstPadProbeVideoDecInputCb_(
+    GstPad* pad, GstPadProbeInfo* info, gpointer userdata) {
+  TRACKRENDERER_ENTER_P(userdata);
+  if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_BUFFER) {
+    TRACKRENDERER_ERROR_P(
+        userdata, "block first video input buffer when do underflow pause");
+    return GST_PAD_PROBE_OK;
+  } else
+    return GST_PAD_PROBE_PASS;
+}
+
+bool TrackRenderer::Deactivate(TrackType type) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) return false;
+  TRACKRENDERER_ENTER_P(this);
+
+  Track track;
+  if (!track_util::GetActiveTrack(trackinfo_, type, &track)) {
+    TRACKRENDERER_ERROR_P(this, "There is no track to deactivate");
+    return false;
+  }
+  if (type >= kTrackTypeMax) return false;
+  trackctx_[type].index = kInvalidTrackIndex;
+  if (type == kTrackTypeVideo) {
+    pipeline_->PadAddProbe(Elements::kAppSrcVideo, kPadProbeVideoBlock, "src",
+                           GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+                           GstPadProbeBlockCb_, nullptr, nullptr);
+    pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
+    FlushAppsrc(type, false);
+    RemoveDownstreamOfAppsrc_(type);
+    auto is_video_track = [](const Track& item) -> bool {
+      return item.type == kTrackTypeVideo;
+    };
+    auto target =
+        std::find_if(trackinfo_.begin(), trackinfo_.end(), is_video_track);
+    if (target != trackinfo_.end()) {
+      trackinfo_.erase(target);
+    }
+    resource_manager_->Dealloc(video_decoder_id_);
+    resource_manager_->Dealloc(video_renderer_id_);
+  } else if (type == kTrackTypeAudio) {
+    pipeline_->PadAddProbe(Elements::kAppSrcAudio, kPadProbeAudioBlock, "src",
+                           GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+                           GstPadProbeBlockCb_, nullptr, nullptr);
+    pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+    FlushAppsrc(type, false);
+    RemoveDownstreamOfAppsrc_(type);
+
+    auto is_audio_track = [](const Track& item) -> bool {
+      return item.type == kTrackTypeAudio;
+    };
+    auto target =
+        std::find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+    if (target != trackinfo_.end()) {
+      trackinfo_.erase(target);
+    }
+    resource_manager_->Dealloc(audio_decoder_id_);
+    resource_manager_->Dealloc(audio_out_id_);
+    if (!AvocPlayerUnRegister_()) return false;
+  } else {
+    pipeline_->PadAddProbe(Elements::kAppSrcSubtitle, kPadProbeSubtitleBlock,
+                           "src", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, nullptr,
+                           nullptr, nullptr);
+    FlushAppsrc(type, false);
+
+    auto is_subtitle_track = [](const Track& item) -> bool {
+      return item.type == kTrackTypeSubtitle;
+    };
+    auto target =
+        std::find_if(trackinfo_.begin(), trackinfo_.end(), is_subtitle_track);
+    if (target != trackinfo_.end()) {
+      trackinfo_.erase(target);
+    }
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::Activate(TrackType type, const Track& track) {
+  // construct pipeline
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) return false;
+
+  Track active_track;
+  if (type >= kTrackTypeMax) return false;
+  if (trackctx_[type].track &&
+      track_util::GetActiveTrack(trackinfo_, type, &active_track)) {
+    TRACKRENDERER_ERROR_P(this,
+                          "Valid and activated track, can not be activated.");
+    return false;
+  }
+  if (!trackctx_[type].track) {
+    TRACKRENDERER_INFO_P(this, "Add a new stream.");
+    if (type == kTrackTypeAudio) {
+      CreateAppSrc_(kTrackTypeAudio, track.mimetype);
+      pipeline_->SetProperty(Elements::kAppSrcAudio, "update-segment",
+                             rendering_start_time_.time);
+      pipeline_->CreateBin(Elements::kBinAudio, "audiobin");
+      pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinAudio);
+      pipeline_->BinAdd(Elements::kBinAudio, Elements::kAppSrcAudio);
+    } else if (type == kTrackTypeVideo) {
+      CreateAppSrc_(kTrackTypeVideo, track.mimetype);
+      pipeline_->SetProperty(Elements::kAppSrcVideo, "update-segment",
+                             rendering_start_time_.time);
+      pipeline_->CreateBin(Elements::kBinVideo, "videobin");
+      pipeline_->BinAddSimple(Elements::kPipeline, Elements::kBinVideo);
+      pipeline_->BinAdd(Elements::kBinVideo, Elements::kAppSrcVideo);
+    } else if (type == kTrackTypeSubtitle) {
+      TRACKRENDERER_INFO_P(this,
+                           "set subtitle track information in track renderer");
+      trackctx_[type].index = track.index;
+      trackinfo_.push_back(track);
+      trackctx_[track.type].track = &(trackinfo_.back());
+      return true;
+    }
+  }
+
+  trackctx_[type].index = track.index;
+  trackinfo_.push_back(track);
+  trackctx_[track.type].track = &(trackinfo_.back());
+
+  if (type == kTrackTypeAudio) {
+    if (!AvocPlayerRegister_()) {
+      TRACKRENDERER_ERROR_P(this, "AvocPlayerRegister_() fail.");
+      return false;
+    }
+  }
+  if (!GetResource_(track.type)) {
+    TRACKRENDERER_ERROR_P(this,
+                          "[%s] resource allocation fail! ChangeTrack fail.",
+                          track_util::GetTrackTypeString(track.type).c_str());
+    return false;
+  }
+  if (type == kTrackTypeVideo) {
+    // the element name should be changed
+    CreateDrmElement_(track);
+
+    const char* kDecoderPluginName =
+        GetDecoderPluginName_(kTrackTypeVideo, track.mimetype);
+    if (kDecoderPluginName &&
+        (strcmp(kDecoderPluginName, kSkippedResource) == 0)) {
+      const ErrorType err = ErrorType::kResourceLimit;
+      eventlistener_->OnError(err);
+      eventlistener_->OnErrorMsg(err,
+                                 const_cast<char*>(track.mimetype.c_str()));
+      return false;
+    }
+    CreateVideoDecoder_(kDecoderPluginName);
+
+    if (CreateVideoSink_() == false) return false;
+
+    GstElementLowLatency_(kTrackTypeVideo);
+
+    SetPropertyForAiFilter_();
+
+    if (internal::IsDisplayNeeded(display_type_)) {
+      pipeline_->Execute(
+          Elements::kSinkVideo,
+          [this](GstElement * obj) noexcept { return display_->Update(obj); });
+    }
+    gboolean is_async = FALSE;
+    pipeline_->GetProperty(Elements::kSinkVideo, "async", &is_async);
+    if (is_async) pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
+
+    pipeline_->BinAdd(Elements::kBinVideo, Elements::kDrmVideo,
+                      Elements::kDecVideo, Elements::kAiFilter,
+                      Elements::kSinkVideo);
+
+    if (is_async) pipeline_->SetProperty(Elements::kSinkVideo, "async", TRUE);
+
+    auto caps = caps_builder_.Build(track, internal::IsDrmEmeElementNecessary(
+                                               drm_property_, track.mimetype));
+    pipeline_->SetAppSrcCaps(Elements::kAppSrcVideo, caps);
+    SetPropertyForDecodedVideoBuffer_();
+    pipeline_->PadRemoveProbe(kPadProbeVideoBlock);
+    UpdatePlaybackInfo_(true);
+    UpdateTrackFrameRate_(track.framerate_num, track.framerate_den);
+  } else if (type == kTrackTypeAudio) {
+    // the element name should be changed
+    CreateDrmElement_(track);
+    if (internal::IsDecoderElementNecessary(track.mimetype)) {
+      const char* kDecoderPluginName =
+          GetDecoderPluginName_(kTrackTypeAudio, track.mimetype);
+      pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, nullptr);
+      if (internal::IsHwPlugin(kDecoderPluginName)) {
+        if (low_latency_mode_ ==
+            static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone)) {
+          constexpr int kPtsManipulationThreshold = 99000;  // 99ms
+          pipeline_->SetProperty(Elements::kDecAudio, "set-usr-cal-timestamp",
+                                 kPtsManipulationThreshold);
+        }
+        pipeline_->SetProperty(Elements::kDecAudio, "support-codec-change",
+                               support_audio_codec_change_);
+      }
+    }
+    std::string audiosink_name =
+        GetAudioSinkPluginName_(track.use_swdecoder, track.mimetype);
+    CreateAudioSink_(audiosink_name);
+
+    AvocPlayRequest_();
+    SetAudioOut_();
+    GstElementLowLatency_(kTrackTypeAudio);
+
+    gboolean is_async = FALSE;
+    pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async);
+    if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+
+    pipeline_->BinAdd(Elements::kBinAudio, Elements::kDrmAudio,
+                      Elements::kDecAudio, Elements::kAudioConvert,
+                      Elements::kCapsFillterDefault, Elements::kAudioResample,
+                      Elements::kCapsFillter2, Elements::kScaleTempo,
+                      Elements::kSinkAudio);
+    if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
+
+    auto caps = caps_builder_.Build(track, internal::IsDrmEmeElementNecessary(
+                                               drm_property_, track.mimetype));
+    pipeline_->SetAppSrcCaps(Elements::kAppSrcAudio, caps);
+    pipeline_->PadRemoveProbe(kPadProbeAudioBlock);
+    UpdatePlaybackInfo_(true);
+  } else {
+    auto caps =
+        gstguard::make_guard(gst_caps_new_empty_simple(track.mimetype.c_str()));
+    pipeline_->SetProperty(Elements::kAppSrcSubtitle, "caps", caps.get());
+    pipeline_->PadRemoveProbe(kPadProbeSubtitleBlock);
+  }
+  TRACKRENDERER_LEAVE_P(this);
+  return true;
+}
+
+bool TrackRenderer::GetPlayingTime(uint64_t* curtime_in_msec) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  if (state_ == State::kResourceConflicted) {
+    *curtime_in_msec = last_position_;
+    return true;
+  }
+  if (!pipeline_) return false;
+  GetPlayingTime_(curtime_in_msec);
+  return true;
+}
+
+bool TrackRenderer::GetPlayingTime_(uint64_t* curtime_in_msec) {
+  int64_t pos_video = 0, pos_audio = 0;
+  bool ret_video = pipeline_->QueryPosition(Elements::kSinkVideo,
+                                            GST_FORMAT_TIME, &pos_video);
+  bool ret_audio = pipeline_->QueryPosition(Elements::kSinkAudio,
+                                            GST_FORMAT_TIME, &pos_audio);
+  if (ret_video || ret_audio)
+    last_position_ = *curtime_in_msec = pos_audio > pos_video
+                                            ? (pos_audio / GST_MSECOND)
+                                            : (pos_video / GST_MSECOND);
+  else
+    *curtime_in_msec = last_position_;
+  // TRACKRENDERER_INFO_P(this, "playing time [%llu ms]", *curtime_in_msec);
+  return true;
+}
+
+bool TrackRenderer::GetDroppedFrames(void* frame_counts) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) return false;
+  int64_t drop_count = 0;
+  Elements element = Elements::kSinkVideo;
+  bool ret = false;
+  if (playback_rate_ == kDefaultPlaybackRate && use_seq_mode_)
+    ret = pipeline_->GetProperty(element, "dropped-frames-count", &drop_count);
+  else
+    ret = pipeline_->GetProperty(element, "dropped-frames", &drop_count);
+  if (ret) {
+    *(int64_t*)frame_counts = drop_count;
+    return true;
+  }
+  return false;
+}
+
+bool TrackRenderer::GetDroppedFramesForCatchup(TrackType type,
+                                               void* frame_counts) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) return false;
+  uint64_t drop_count = 0;
+  Elements video_element = Elements::kSinkVideo;
+  Elements audio_element = Elements::kSinkAudio;
+  bool ret = false;
+
+  if (type == kTrackTypeAudio) {
+    ret = pipeline_->GetProperty(audio_element, "dropped-frames-for-catchup",
+                                 &drop_count);
+  } else if (type == kTrackTypeVideo) {
+    ret = pipeline_->GetProperty(video_element, "dropped-frames-for-catchup",
+                                 &drop_count);
+  }
+
+  if (ret) {
+    *(int64_t*)frame_counts = drop_count;
+    return true;
+  }
+
+  return false;
+}
+
+bool TrackRenderer::SetDisplayMode(const DisplayMode& mode) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_->SetDisplayMode(mode);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::SetDisplayRotate(const DisplayRotation& rotate) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_->SetDisplayRotate(rotate);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::SetDisplay(const DisplayType& type, void* obj) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_type_ = type;
+  if (type == DisplayType::kNone) {
+    TRACKRENDERER_WARN_P(this, "Just Reset Display type as None");
+    return true;
+  }
+  display_->SetDisplay(type, static_cast<Evas_Object*>(obj));
+
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * _obj) noexcept {
+    return display_->Update(_obj);
+  });
+  return true;
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::SetDisplay(const DisplayType& type, void* ecore_wl2_window,
+                               int x, int y, int w, int h) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_type_ = type;
+  display_->SetDisplay(type, static_cast<Ecore_Wl2_Window*>(ecore_wl2_window),
+                       x, y, w, h);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  return true;
+}
+// LCOV_EXCL_STOP
+
+bool TrackRenderer::SetDisplaySubsurface(const DisplayType& type,
+                                         void* ecore_wl2_subsurface, int x,
+                                         int y, int w, int h) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_type_ = type;
+  display_->SetDisplaySubsurface(
+      type, static_cast<Ecore_Wl2_Subsurface*>(ecore_wl2_subsurface), x, y, w,
+      h);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  return true;
+}
+
+void TrackRenderer::DrmLicenseAcquiredDone(TrackType type) {
+  TRACKRENDERER_ENTER_P(this);
+  if (type == kTrackTypeAudio) {
+    pipeline_->SetProperty(Elements::kDrmAudio, "getrights-complete-return",
+                           TRUE);
+  } else if (type == kTrackTypeVideo) {
+    pipeline_->SetProperty(Elements::kDrmVideo, "getrights-complete-return",
+                           TRUE);
+  } else {
+    TRACKRENDERER_ERROR_P(this, "Invalid Track Type !!");
+  }
+  TRACKRENDERER_LEAVE_P(this);
+}
+
+bool TrackRenderer::SetDisplay(const DisplayType& type, unsigned int surface_id,
+                               long x, long y, long w, long h) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_type_ = type;
+  display_->SetDisplay(type, surface_id, x, y, w, h);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::SetDisplayRoi(const Geometry& roi) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_->SetDisplayRoi(roi);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::SetVideoRoi(const CropArea& area) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_->SetDisplayCropArea(area);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->UpdateCropArea(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::ResizeRenderRect(const RenderRect& rect) {
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_->ResizeRenderRect(rect);
+  if (!pipeline_) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->Update(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::SetDisplayVisible(bool is_visible) {
+  TRACKRENDERER_DEBUG_P(this, "visible: %d", is_visible);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  if (state_ == State::kStopped) return false;
+  display_->SetVisible(is_visible);
+  if (pipeline_ == nullptr) return true;
+  pipeline_->Execute(Elements::kSinkVideo, [this](GstElement * obj) noexcept {
+    return display_->UpdateVisible(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::SetAudioMute(bool is_mute) {
+  TRACKRENDERER_DEBUG_P(this, "mute: %d", is_mute);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  is_sound_mute_ = is_mute ? TRUE : FALSE;
+  if (!pipeline_) return true;
+  pipeline_->SetProperty(Elements::kSinkAudio, "mute", is_sound_mute_);
+  return true;
+}
+
+bool TrackRenderer::SetVolume(const int& volume) {
+  TRACKRENDERER_DEBUG_P(this, "volume: %d", volume);
+  if (volume < kVolumeMin || volume > kVolumeMax) {
+    TRACKRENDERER_ERROR_P(this, "volume: %d", volume);
+    return false;
+  }
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  volume_ = volume;
+  if (!pipeline_) return true;
+  SetVolume_();
+  return true;
+}
+
+void TrackRenderer::SetVolume_() {
+  const gchar* sink_name = nullptr;
+  pipeline_->GetProperty(Elements::kSinkAudio, "name", &sink_name);
+  if (sink_name == nullptr) {
+    TRACKRENDERER_WARN_P(this, "no audio sink");
+    return;
+  }
+  if (strstr(sink_name, "mmaudiosink")) {  // mmaudiosink or mmaudiosink2
+    pipeline_->SetProperty(Elements::kSinkAudio, "device-volume", volume_);
+  } else if (strstr(sink_name, "alsasink")) {
+    pipeline_->SetProperty(Elements::kSinkAudio, "alsa-volume", volume_);
+  } else if (strstr(sink_name, "pulsesink")) {
+    TRACKRENDERER_DEBUG_P(this, "pulsesink, not set volume");
+  } else {
+    TRACKRENDERER_WARN_P(this, "unknow audio sink name: %s", sink_name);
+  }
+}
+
+void TrackRenderer::CreateTbmBufferManager_() {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(tbmmgr_m_);
+  if (tbm_buffer_manager_ == nullptr) {
+    tbm_buffer_manager_.reset(new TbmBufferManager);
+  }
+}
+
+void TrackRenderer::SetVr360GpuModeSecure_(bool set) {
+  // Fix:: This is adding for Youtube 360 playback, at the beginning playback,
+  // need to set GPU secure mode, when playback is finished, need to set
+  // GPU non secure mode ,kReference only be set for Youtube 360 feature.
+  if (decoded_buffer_type_ == DecodedVideoFrameBufferType::kReference) {
+    TRACKRENDERER_INFO_P(this, "gpu mode: [%s]", set ? "secure" : "non-secure");
+    vr360_->Vr360TzSetGpuMode(set);
+  }
+}
+
+bool TrackRenderer::GetVolume(int* volume) {
+  if (!volume) return false;
+  *volume = volume_;
+  return true;
+}
+
+const char* TrackRenderer::GetDecoderPluginName_(TrackType type,
+                                                 const std::string& mimetype) {
+  if (type == kTrackTypeAudio) {
+    if (resource_manager_->GetAllocatedState(audio_decoder_id_) ==
+            AllocatedState::kSkipped ||
+        resource_manager_->GetAllocatedState(audio_out_id_) ==
+            AllocatedState::kSkipped) {
+      resource_manager_->Dealloc(audio_decoder_id_);
+      resource_manager_->Dealloc(audio_out_id_);
+      return kSkippedResource;
+    }
+    if (product_cfg::GetProductType() == ProductType::kAv) {
+      if (internal::IsTzDecoderElementNecessary(drm_property_, mimetype))
+        return "omx_tz_mmaudiodec";
+      return "omx_mmaudiodec";
+    }
+    const std::string comp_name =
+        resource_manager_->GetComponentName(audio_decoder_id_);
+    if (comp_name.empty()) {
+      TRACKRENDERER_ERROR_P(this, "Not found component name");
+      return nullptr;
+    }
+    auto is_audio_track = [](const Track& item) noexcept->bool {
+      return item.mimetype.find("audio") != std::string::npos;
+    };
+    auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_audio_track);
+    if (target == trackinfo_.end()) {
+      TRACKRENDERER_ERROR_P(this, "Not found audio track");
+      return nullptr;
+    }
+    TRACKRENDERER_INFO_P(this, "mime type : %s", (target->mimetype).c_str());
+    if (comp_name == kSwDecoderComponentName) {
+      return ::kSwPluginMap.count({target->mimetype, target->version}) > 0
+                 ? ::kSwPluginMap.at({target->mimetype, target->version})
+                       .c_str()
+                 : nullptr;
+    } else {
+      return ::PluginTable.count({comp_name, target->mimetype}) > 0
+                 ? ::PluginTable.at({comp_name, target->mimetype}).c_str()
+                 : nullptr;
+    }
+
+  } else if (type == kTrackTypeVideo) {
+    if (resource_manager_->GetAllocatedState(video_decoder_id_) ==
+            AllocatedState::kSkipped ||
+        resource_manager_->GetAllocatedState(video_renderer_id_) ==
+            AllocatedState::kSkipped) {
+      resource_manager_->Dealloc(video_decoder_id_);
+      resource_manager_->Dealloc(video_renderer_id_);
+      return kSkippedResource;
+    }
+    const std::string comp_name =
+        resource_manager_->GetComponentName(video_decoder_id_);
+    if (comp_name.empty()) {
+      TRACKRENDERER_ERROR_P(this, "Not found component name");
+      return nullptr;
+    }
+    auto is_video_track = [](const Track& item) noexcept->bool {
+      return item.mimetype.find("video") != std::string::npos;
+    };
+    auto target = find_if(trackinfo_.begin(), trackinfo_.end(), is_video_track);
+    if (target == trackinfo_.end()) {
+      TRACKRENDERER_ERROR_P(this, "Not found video track");
+      return nullptr;
+    }
+    TRACKRENDERER_INFO_P(this, "mime type : %s", (target->mimetype).c_str());
+    if (internal::CheckMpeg4Video(target->mimetype, target->version)) {
+      return ::kMpeg4VidoePluginMap.at({comp_name, target->mimetype}).c_str();
+    }
+    if (comp_name == kSwDecoderComponentName) {
+      return ::kSwPluginMap.count({target->mimetype, target->version}) > 0
+                 ? ::kSwPluginMap.at({target->mimetype, target->version})
+                       .c_str()
+                 : nullptr;
+    } else {
+      return ::PluginTable.count({comp_name, target->mimetype}) > 0
+                 ? ::PluginTable.at({comp_name, target->mimetype}).c_str()
+                 : nullptr;
+    }
+  }
+
+  return nullptr;
+}
+
+void TrackRenderer::GetDisplay(DisplayType* type, Geometry* area) {
+  display_->GetDisplay(type, area);
+}
+
+void TrackRenderer::GetDisplayMode(DisplayMode* mode) {
+  display_->GetDisplayMode(mode);
+}
+
+void TrackRenderer::GetDisplayRotate(DisplayRotation* rotation) {
+  display_->GetDisplayRotate(rotation);
+}
+
+bool TrackRenderer::RenderVideoFrame() {
+  TRACKRENDERER_ENTER_P(this);
+  if (!is_video_frame_peek_) return false;
+  pipeline_->PadRemoveProbe(kPadProbeVideoPeekBlock);
+  return true;
+}
+
+bool TrackRenderer::SetAiFilter(void* aifilter) {
+  TRACKRENDERER_ENTER_P(this);
+  return AddAiFilter_(aifilter);
+}
+
+void TrackRenderer::SetVideoMidLatencyThreshold(const unsigned int threshold) {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->SetVideoMidLatencyThreshold(threshold);
+}
+
+void TrackRenderer::SetAudioMidLatencyThreshold(const unsigned int threshold) {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->SetAudioMidLatencyThreshold(threshold);
+}
+
+void TrackRenderer::SetVideoHighLatencyThreshold(const unsigned int threshold) {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->SetVideoHighLatencyThreshold(threshold);
+}
+
+void TrackRenderer::SetAudioHighLatencyThreshold(const unsigned int threshold) {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->SetAudioHighLatencyThreshold(threshold);
+}
+
+void TrackRenderer::SetCatchUpSpeed(const CatchUpSpeed& level) {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->SetCatchUpSpeed(level);
+}
+
+void TrackRenderer::GetVideoLatencyStatus(LatencyStatus* status) {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->GetVideoLatencyStatus(status);
+}
+
+void TrackRenderer::GetAudioLatencyStatus(LatencyStatus* status) {
+  TRACKRENDERER_ENTER_P(this);
+  latency_manager_->GetAudioLatencyStatus(status);
+}
+
+void TrackRenderer::SetAttribute_(const TrackRendererAttributeBinder& binder,
+                                  const boost::any& original_value,
+                                  const boost::any& new_value) {
+  TrackRendererAttributeSetter commiiter(pipeline_, binder);
+  bool is_set = binder.on_attribute_set(commiiter, original_value, new_value);
+  TRACKRENDERER_DEBUG_P(this, "a property(prop[%s] of elem[%d]) is_set[%d]",
+                        binder.property.c_str(),
+                        static_cast<int>(binder.element), is_set);
+}
+
+void TrackRenderer::SetAttribute(const Attribute& attr,
+                                 const boost::any& value) {
+  const TrackRendererAttributeBinder& binder = kAttributes_.at(attr);
+  if (binder.value_type != value.type()) {
+    TRACKRENDERER_ERROR_P(this,
+                          "a property(prop[%s] of elem[%d]) type mismatched! "
+                          "it wasn't able to be applied.",
+                          binder.property.c_str(),
+                          static_cast<int>(binder.element));
+    return;
+  }
+  SetAttribute_(binder, set_attribute_values_[attr], value);
+  set_attribute_values_[attr].value = value;
+  set_attribute_values_[attr].value_assigned = true;
+}
+
+void TrackRenderer::GetAttribute(const Attribute& attr, boost::any* value) {
+  if (state_ > State::kWorking) {
+    return;
+  }
+  const TrackRendererAttributeBinder& binder = kAttributes_.at(attr);
+  TrackRendererAttributeGetter commiiter(pipeline_, binder);
+  bool is_get = binder.on_attribute_get(commiiter, value);
+  if (!is_get)
+    TRACKRENDERER_ERROR_P(this, "property(prop[%s] of elem[%d]) get failed!!!",
+                          binder.property.c_str(),
+                          static_cast<int>(binder.element));
+}
+
+void TrackRenderer::SetConfig(const std::string name, const boost::any& value) {
+  if (config_setter_table_.count(name) > 0) {
+    Config_Setter setter = config_setter_table_.at(name);
+    setter(value);
+  } else {
+    TRACKRENDERER_ERROR_P(this,
+                          "No name of setter [%s], if needed, assign setter in "
+                          "config_setter_table & init",
+                          name.c_str());
+  }
+}
+
+void TrackRenderer::InitConfigSetterTable_() {
+  config_setter_table_[ConfigNameAccurateSeekMode] = std::bind(
+      &TrackRenderer::SetAccurateSeekMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameLowLatencyMode] = std::bind(
+      &TrackRenderer::SetLowLatencyMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameWindowStandAloneMode] = std::bind(
+      &TrackRenderer::SetWindowStandAloneMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameVideoFramePeekMode] = std::bind(
+      &TrackRenderer::SetVideoFramePeekMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameUnlimitedMaxBufferMode] = std::bind(
+      &TrackRenderer::SetUnlimitedMaxBufferMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameVideoPreDisplayMode] = std::bind(
+      &TrackRenderer::SetVideoPreDisplayMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameStartRenderingTime] = std::bind(
+      &TrackRenderer::SetStartRenderingTime_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameFmmMode] =
+      std::bind(&TrackRenderer::SetFmmMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameAlternativeVideoResource] =
+      std::bind(&TrackRenderer::SetAlternativeVideoResource_, this,
+                std::placeholders::_1);
+  config_setter_table_[ConfigNameVideoDecodingMode] = std::bind(
+      &TrackRenderer::SetVideoDecodingMode_, this, std::placeholders::_1);
+  config_setter_table_[ConfigNameLateVideoFrameDropMode] = std::bind(
+      &TrackRenderer::SetLateVideoFrameDropMode_, this, std::placeholders::_1);
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::SetAccurateSeekMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+  is_accurate_seek_ = (val != 0) ? true : false;
+  return true;
+}
+// LCOV_EXCL_STOP
+
+bool TrackRenderer::SetLowLatencyMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Mode [%d]", val);
+  low_latency_mode_ = val;
+  if (low_latency_mode_ & kLowLatencyModeDisableAVSync)
+    unlimited_max_buffer_mode_ = true;
+  return true;
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::SetWindowStandAloneMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+  window_stand_alone_mode_ = (val != 0) ? TRUE : FALSE;
+  return true;
+}
+// LCOV_EXCL_STOP
+
+bool TrackRenderer::SetVideoFramePeekMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+  is_video_frame_peek_ = (val != 0) ? true : false;
+  return true;
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::SetUnlimitedMaxBufferMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+  unlimited_max_buffer_mode_ = (val != 0) ? true : false;
+  return true;
+}
+
+bool TrackRenderer::SetVideoPreDisplayMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+  video_pre_display_mode_ = (val != 0) ? true : false;
+  return true;
+}
+// LCOV_EXCL_STOP
+
+bool TrackRenderer::SetStartRenderingTime_(const boost::any& value) {
+  std::uint64_t val = boost::any_cast<std::uint64_t>(value);
+  TRACKRENDERER_ERROR_P(this, "time [%llu ms]", val);
+  rendering_start_time_.is_set = true;
+  rendering_start_time_.time = val * GST_MSECOND;
+  return true;
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::SetFmmMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Mode [%s]", (val != 0) ? "TRUE" : "FALSE");
+  fmm_mode_ = (val != 0) ? 1 : 0;
+  return true;
+}
+
+bool TrackRenderer::SetAlternativeVideoResource_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Alternative video resource [%d]", val);
+  if (val == 0) {
+    video_decoder_id_ = ResourceCategory::kVideoDecoder;
+    video_renderer_id_ = ResourceCategory::kVideoRenderer;
+  } else if (val == 1) {
+    video_decoder_id_ = ResourceCategory::kVideoDecoderSub;
+    video_renderer_id_ = ResourceCategory::kVideoRendererSub;
+  } else if (val == 2) {
+    video_decoder_id_ = ResourceCategory::kVideoDecoderSub;
+    video_renderer_id_ = ResourceCategory::kVideoRenderer;
+  } else if (val == 3) {
+    video_decoder_id_ = ResourceCategory::kVideoDecoder;
+    video_renderer_id_ = ResourceCategory::kVideoRendererSub;
+  } else
+    return false;
+  return true;
+}
+
+bool TrackRenderer::SetVideoDecodingMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, "Video decoding mode [%u]", val);
+  video_decoding_mode_ = val;
+  return true;
+}
+
+bool TrackRenderer::SetLateVideoFrameDropMode_(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " LateVideoFrameDropMode [%s]",
+                        (val != 0) ? "TRUE" : "FALSE");
+  drop_all_late_video_ = (val != 0) ? true : false;
+  return true;
+}
+// LCOV_EXCL_STOP
+
+void TrackRenderer::GstElementLowLatency_(const TrackType& type) {
+  if (low_latency_mode_ ==
+      static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone))
+    return;
+
+  switch (type) {
+    case kTrackTypeAudio:
+      if (low_latency_mode_ & kLowLatencyModeAudio) {
+        constexpr gint kDecodingType = 0x01;
+        constexpr gint kDeviceLatency = 0;
+        pipeline_->SetProperty(Elements::kDecAudio, "decoding-type",
+                               kDecodingType);
+        pipeline_->SetProperty(Elements::kSinkAudio, "device-latency",
+                               kDeviceLatency);
+      }
+      if (low_latency_mode_ & kLowLatencyModeDisableAVSync) {
+        constexpr guint64 kLowLatencyMaxBytes = 200;
+        constexpr guint64 kFastRendering = 0;
+        pipeline_->SetProperty(Elements::kAppSrcAudio, "max-bytes",
+                               kLowLatencyMaxBytes, "noqueue", TRUE);
+        pipeline_->SetProperty(Elements::kSinkAudio, "sync", FALSE, "async",
+                               FALSE);
+        pipeline_->SetProperty(Elements::kSinkAudio, "fast-rendering",
+                               kFastRendering);
+        pipeline_->SetProperty(Elements::kSinkAudio, "game-mode", TRUE);
+        pipeline_->SetProperty(Elements::kSinkAudio, "free-run", TRUE);
+      }
+      if (low_latency_mode_ & kLowLatencyModeDisablePreroll) {
+        pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+      }
+      break;
+    case kTrackTypeVideo:
+      if (low_latency_mode_ & kLowLatencyModeVideo) {
+        constexpr gint kDecodingType = 0x01;
+        pipeline_->SetProperty(Elements::kDecVideo, "decoding-type",
+                               kDecodingType);
+
+        if ((low_latency_mode_ & kLowLatencyModeVideoDistortionConcealment) ==
+            kLowLatencyModeVideoDistortionConcealment)
+          pipeline_->SetProperty(Elements::kDecVideo, "error-concealment",
+                                 TRUE);
+      }
+      if (low_latency_mode_ & kLowLatencyModeDisableAVSync) {
+        pipeline_->SetProperty(Elements::kSinkVideo, "sync", FALSE, "async",
+                               FALSE);
+      }
+      if (low_latency_mode_ & kLowLatencyModeDisableVideoQuality) {
+        constexpr uint32_t kDisableVideoQuality = 0x04;
+        display_->SetVideoQualityMode(kDisableVideoQuality);
+      }
+      if (low_latency_mode_ & kLowLatencyModeDisablePreroll) {
+        pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
+      }
+      break;
+    case kTrackTypeSubtitle:
+      if (low_latency_mode_ & kLowLatencyModeDisableAVSync) {
+        pipeline_->SetProperty(Elements::kSinkCaption, "sync", FALSE, "async",
+                               FALSE);
+        pipeline_->SetProperty(Elements::kSinkSubtitle, "sync", FALSE, "async",
+                               FALSE);
+      }
+      if (low_latency_mode_ & kLowLatencyModeDisablePreroll) {
+        pipeline_->SetProperty(Elements::kSinkSubtitle, "async", FALSE);
+      }
+      break;
+    default:
+      TRACKRENDERER_ERROR_P(this, "wrong track type");
+  }
+}
+
+// LCOV_EXCL_START
+void TrackRenderer::GetResolutionInfo_(EventMsg* event_msg) {
+  if (!pipeline_) return;
+  auto video_sink_caps =
+      gstguard::make_guard(pipeline_->GetSinkPadCaps(Elements::kSinkVideo));
+
+  std::string info;
+  int width = internal::GetVideoWidth(video_sink_caps.get());
+  int height = internal::GetVideoHeight(video_sink_caps.get());
+
+  if (width > 0 && height > 0) {
+    info = std::to_string(width) + "x" + std::to_string(height);
+  }
+  event_msg->data = info;
+  event_msg->len = event_msg->data.length();
+}
+// LCOV_EXCL_STOP
+
+void TrackRenderer::UpdatePlaybackInfo_(bool is_updating) {
+  if (!pipeline_ || !playback_info_) return;
+  auto video_sink_caps =
+      gstguard::make_guard(pipeline_->GetSinkPadCaps(Elements::kSinkVideo));
+  auto video_decoder_caps =
+      gstguard::make_guard(pipeline_->GetSinkPadCaps(Elements::kDecVideo));
+  auto audio_decoder_caps =
+      gstguard::make_guard(pipeline_->GetSinkPadCaps(Elements::kDecAudio));
+  if (!playback_info_->SetStreamInfo(
+          video_sink_caps.get(), video_decoder_caps.get(),
+          audio_decoder_caps.get(), trackinfo_, drm_property_.type))
+    return;
+  if (is_updating)
+    playback_info_->VconfSetMsgUpdate();
+  else
+    playback_info_->VconfSetMsgShow();
+}
+
+// LCOV_EXCL_START
+GstPadProbeReturn TrackRenderer::GstSrcPadProbeBlockCb_(GstPad* pad,
+                                                        GstPadProbeInfo* info,
+                                                        gpointer userdata) {
+  TRACKRENDERER_ENTER_P(userdata);
+
+  return GST_PAD_PROBE_OK;
+}
+// LCOV_EXCL_STOP
+
+GstPadProbeReturn TrackRenderer::GstSrcPadProbeIdleCb_(GstPad* pad,
+                                                       GstPadProbeInfo* info,
+                                                       gpointer userdata) {
+  TRACKRENDERER_ENTER_P(userdata);
+  auto gstpad = static_cast<Pipeline<Elements>::Pad*>(userdata);
+  std::unique_lock<std::mutex> pad_block_locker(gstpad->m);
+  gstpad->is_idle = true;
+  gstpad->cv.notify_one();
+  TRACKRENDERER_LEAVE_P(userdata)
+  return GST_PAD_PROBE_DROP;
+}
+
+void TrackRenderer::FlushDownStream_(Elements element, const char* key,
+                                     gboolean reset_time) {
+  TRACKRENDERER_ENTER_P(this);
+  if (!pipeline_) return;
+
+  Pipeline<Elements>::Pad pad;
+
+  pipeline_->PadAddProbe(element, key, "src", GST_PAD_PROBE_TYPE_IDLE,
+                         GstSrcPadProbeIdleCb_, &pad, nullptr);
+
+  if (pipeline_->FlushDownStream(element, reset_time)) {
+    std::unique_lock<std::mutex> pad_block_locker(pad.m);
+    if (!pad.is_idle) {
+      pad.cv.wait(pad_block_locker);
+      TRACKRENDERER_INFO_P(this, "pad block wait end");
+    }
+  }
+  pipeline_->PadRemoveProbe(key);
+  TRACKRENDERER_LEAVE_P(this);
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::ActivateAudio_() {
+  TRACKRENDERER_ENTER_P(this)
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (state_ == State::kResourceConflicted) {
+    TRACKRENDERER_WARN_P(this, "Resource conflict!");
+    return false;
+  }
+  if (!pipeline_) return false;
+  if (is_audioactivated_) {
+    TRACKRENDERER_WARN_P(this, "Audio has been activated!");
+    return false;
+  }
+
+  Track track;
+  if (!track_util::GetActiveTrack(trackinfo_, kTrackTypeAudio, &track)) {
+    TRACKRENDERER_ERROR_P(this, "Failed to find active audio track.");
+    return false;
+  }
+
+  if (!GetResource_(kTrackTypeAudio)) {
+    TRACKRENDERER_ERROR_P(this,
+                          "Audio resource allocation fail! ChangeTrack fail.");
+    return false;
+  }
+
+  const char* kDecoderPluginName = nullptr;
+  if (internal::IsDecoderElementNecessary(track.mimetype)) {
+    kDecoderPluginName = GetDecoderPluginName_(kTrackTypeAudio, track.mimetype);
+    if (nullptr == kDecoderPluginName) {
+      TRACKRENDERER_ERROR_P(this, "Audio decoder plugin name is nullptr");
+      return false;
+    } else if (strcmp(kDecoderPluginName, kSkippedResource) == 0) {
+      TRACKRENDERER_ERROR_P(this, "The audio resource is NOT_PERMITTED.");
+      return false;
+    }
+  }
+
+  Elements element = Elements::kAppSrcAudio;
+  if (internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype)) {
+    element = Elements::kDrmAudio;
+  }
+
+  pipeline_->PadAddProbe(element, kPadProbeAudioBlock, "src",
+                         GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+                         GstSrcPadProbeBlockCb_, nullptr, nullptr);
+  pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+  FlushDownStream_(element, kPadProbeAudioIdle, FALSE);
+  pipeline_->BinRemove(Elements::kBinAudio, Elements::kSinkAudio);
+
+  if (internal::IsDecoderElementNecessary(track.mimetype)) {
+    pipeline_->FactoryMake(Elements::kDecAudio, kDecoderPluginName, NULL);
+    pipeline_->SetProperty(Elements::kDecAudio, "support-codec-change",
+                           support_audio_codec_change_);
+    if (low_latency_mode_ ==
+        static_cast<std::uint32_t>(LowLatencyMode::kLowLatencyModeNone)) {
+      constexpr int kPtsManipulationThreshold = 99000;  // 99ms
+      pipeline_->SetProperty(Elements::kDecAudio, "set-usr-cal-timestamp",
+                             kPtsManipulationThreshold);
+    }
+  }
+  std::string audiosink_name =
+      GetAudioSinkPluginName_(track.use_swdecoder, track.mimetype);
+  CreateAudioSink_(audiosink_name);
+  GstElementLowLatency_(kTrackTypeAudio);
+
+  gboolean is_async = FALSE;
+  pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async);
+  if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+  pipeline_->BinAdd(Elements::kBinAudio, Elements::kDecAudio,
+                    Elements::kAudioConvert, Elements::kCapsFillterDefault,
+                    Elements::kAudioResample, Elements::kCapsFillter2,
+                    Elements::kScaleTempo, Elements::kSinkAudio);
+  if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
+  pipeline_->PadRemoveProbe(kPadProbeAudioBlock);
+
+  AvocPlayRequest_();
+  SetAudioOut_();
+
+  is_audioactivated_ = true;
+  TRACKRENDERER_LEAVE_P(this)
+  return true;
+}
+
+bool TrackRenderer::DeactivateAudio_() {
+  TRACKRENDERER_ENTER_P(this)
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (state_ == State::kResourceConflicted) {
+    TRACKRENDERER_WARN_P(this, "Resource conflict!");
+    return false;
+  }
+  if (!pipeline_) return false;
+  if (!is_audioactivated_) {
+    TRACKRENDERER_WARN_P(this, "Audio has been deactivated!");
+    return false;
+  }
+
+#ifndef SOUNDBAR_PRODUCT
+  int result = avoc_player_disconnect(avoc_id_);
+  TRACKRENDERER_INFO_P(this, "avoc_player_disconnect() return value[%d]",
+                       result);
+#endif
+
+  Track track;
+  if (!track_util::GetActiveTrack(trackinfo_, kTrackTypeAudio, &track)) {
+    TRACKRENDERER_ERROR_P(this, "Failed to find active audio track.");
+    return false;
+  }
+  Elements element = Elements::kAppSrcAudio;
+  if (internal::IsDrmEmeElementNecessary(drm_property_, track.mimetype)) {
+    element = Elements::kDrmAudio;
+  }
+  pipeline_->PadAddProbe(element, kPadProbeAudioBlock, "src",
+                         GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+                         GstSrcPadProbeBlockCb_, nullptr, nullptr);
+  pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+  FlushDownStream_(element, kPadProbeAudioIdle, FALSE);
+  pipeline_->BinRemove(Elements::kBinAudio, Elements::kDecAudio,
+                       Elements::kAudioConvert, Elements::kCapsFillterDefault,
+                       Elements::kAudioResample, Elements::kCapsFillter2,
+                       Elements::kScaleTempo, Elements::kSinkAudio);
+
+  std::string sink_name("fakesink");
+  if (internal::IsTzMimeType(track.mimetype)) {
+    sink_name = "tzfakesink";
+  }
+  CreateAudioSink_(sink_name);
+  GstElementLowLatency_(kTrackTypeAudio);
+
+  gboolean is_async = FALSE;
+  pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async);
+  if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+  pipeline_->BinAdd(Elements::kBinAudio, Elements::kSinkAudio);
+  if (is_async) pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
+  pipeline_->PadRemoveProbe(kPadProbeAudioBlock);
+
+  resource_manager_->Dealloc(audio_decoder_id_);
+  resource_manager_->Dealloc(audio_out_id_);
+  is_audioactivated_ = false;
+  TRACKRENDERER_LEAVE_P(this)
+  return true;
+}
+
+void TrackRenderer::MultiviewStartAudioCb_(int player_id, void* data) {
+  TRACKRENDERER_ENTER;
+  if (data == nullptr) return;
+  auto tr = static_cast<TrackRenderer*>(data);
+  TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
+                       tr->avoc_id_);
+  if (player_id == tr->avoc_id_) {
+    tr->is_multiscreen_ = Vconf::Instance().IsMultiscreenMode();
+    tr->ActivateAudio_();
+    TRACKRENDERER_INFO_P(tr, "Send audio pipeline start done event!");
+    rc_player_audio_start_done(player_id);
+  }
+  TRACKRENDERER_LEAVE_P(tr)
+}
+
+void TrackRenderer::MultiviewStopAudioCb_(int player_id, void* data) {
+  TRACKRENDERER_ENTER
+  if (data == nullptr) return;
+  auto tr = static_cast<TrackRenderer*>(data);
+  TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
+                       tr->avoc_id_);
+  if (player_id == tr->avoc_id_) {
+    tr->DeactivateAudio_();
+    rc_player_audio_stop_done(player_id);
+    TRACKRENDERER_INFO_P(tr, "Send audio pipeline stop done event!");
+  }
+  TRACKRENDERER_LEAVE_P(tr)
+}
+
+void TrackRenderer::MultiviewResyncAudioCb_(int player_id, void* data) {
+  TRACKRENDERER_ENTER
+  if (data == nullptr) return;
+  auto tr = static_cast<TrackRenderer*>(data);
+  TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
+                       tr->avoc_id_);
+  if (player_id != tr->avoc_id_) return;
+  tr->ResyncAudio_();
+  TRACKRENDERER_LEAVE_P(tr)
+}
+
+bool TrackRenderer::ResyncAudio_() {
+  TRACKRENDERER_ENTER_P(this)
+  // internal_audio_m_ is needed to prevent state-change, audio pipeline
+  // manipulation, set volume and audio mute in progress of ResyncAudio_()
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return false;
+  if (state_ == State::kResourceConflicted) {
+    TRACKRENDERER_ERROR_P(this, "Resource conflict!");
+    return false;
+  }
+  if (!pipeline_) return false;
+  AvocPlayRequest_();
+  resync_audio_policy_->Resync(pipeline_);
+#ifdef SOUNDBAR_PRODUCT
+  if (!is_sound_mute_) avoc_av_audio_mute(avoc_id_, AVOC_SETTING_OFF);
+#else
+  if (!is_sound_mute_) avoc_audio_mute(avoc_id_, AVOC_SETTING_OFF);
+#endif
+  return true;
+}  // namespace trackrenderer
+
+void TrackRenderer::MultiviewStartVideoCb_(int player_id, void* data) {
+  TRACKRENDERER_ENTER;
+  if (data == nullptr) return;
+  auto tr = static_cast<TrackRenderer*>(data);
+  TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
+                       tr->avoc_id_);
+  if (player_id != tr->avoc_id_) return;
+  BOOST_SCOPE_EXIT(&player_id) { rc_player_video_start_done(player_id); }
+  BOOST_SCOPE_EXIT_END
+  if (tr->state_ == State::kStopped ||
+      tr->state_ == State::kResourceConflicted) {
+    TRACKRENDERER_WARN_P(tr, "player state: %d", static_cast<int>(tr->state_));
+    return;
+  }
+  if (!tr->pipeline_ || tr->is_videoactivated_) {
+    TRACKRENDERER_WARN_P(tr, "is_videoactivated_: %d", tr->is_videoactivated_);
+    return;
+  }
+  tr->is_multiscreen_ = Vconf::Instance().IsMultiscreenMode();
+  tr->eventlistener_->OnMultiviewStartVideo();
+  tr->is_videoactivated_ = true;
+  TRACKRENDERER_LEAVE_P(tr)
+}
+
+void TrackRenderer::MultiviewStopVideoCb_(int player_id, void* data) {
+  TRACKRENDERER_ENTER
+  if (data == nullptr) return;
+  auto tr = static_cast<TrackRenderer*>(data);
+  TRACKRENDERER_INFO_P(tr, "player_id: %d, avoc id: %d", player_id,
+                       tr->avoc_id_);
+  if (player_id != tr->avoc_id_) return;
+  BOOST_SCOPE_EXIT(&player_id) { rc_player_video_stop_done(player_id); }
+  BOOST_SCOPE_EXIT_END
+  if (tr->state_ == State::kStopped ||
+      tr->state_ == State::kResourceConflicted) {
+    TRACKRENDERER_WARN_P(tr, "player state: %d", static_cast<int>(tr->state_));
+    return;
+  }
+  if (!tr->pipeline_ || !tr->is_videoactivated_) {
+    TRACKRENDERER_WARN_P(tr, "is_videoactivated_: %d", tr->is_videoactivated_);
+    return;
+  }
+  tr->eventlistener_->OnMultiviewStopVideo();
+  tr->is_videoactivated_ = false;
+  TRACKRENDERER_LEAVE_P(tr)
+}
+// LCOV_EXCL_STOP
+
+void TrackRenderer::SetVconfCb_() {
+  TRACKRENDERER_ENTER_P(this)
+  std::vector<std::string> names;
+  names.push_back(kPowerAnimationVconf);
+
+  Vconf::Instance().SetVconfsCb(names, TrackRenderer::VconfCb_, this);
+  is_multiscreen_ = Vconf::Instance().IsMultiscreenMode();
+  TRACKRENDERER_LEAVE_P(this)
+}
+
+void TrackRenderer::UnsetVconfCb_() {
+  TRACKRENDERER_ENTER_P(this)
+  std::vector<std::string> names;
+  names.push_back(kPowerAnimationVconf);
+
+  Vconf::Instance().UnsetVconfsCb(names, TrackRenderer::VconfCb_, this);
+  TRACKRENDERER_LEAVE_P(this)
+}
+
+// LCOV_EXCL_START
+void TrackRenderer::VconfCb_(const std::string& name, const std::string& value,
+                             void* userdata) {
+  TRACKRENDERER_ENTER
+  if (userdata == nullptr) return;
+  auto tr = static_cast<TrackRenderer*>(userdata);
+  if (name == kPowerAnimationVconf) {
+    std::lock_guard<std::mutex> lk(tr->resource_m_);
+    if (tr->state_ == State::kStopped) return;
+    if (tr->state_ == State::kResourceConflicted) {
+      TRACKRENDERER_WARN_P(tr, "Resource conflict!");
+      return;
+    }
+    if (!tr->pipeline_) return;
+    gboolean is_mute = (value == "true") ? TRUE : FALSE;
+    tr->pipeline_->SetProperty(Elements::kSinkAudio, "mute", is_mute);
+    TRACKRENDERER_WARN_P(tr, "[%s] audio!", is_mute ? "Mute" : "Unmute");
+  } else {
+    TRACKRENDERER_ERROR_P(tr, "Unknow vconf name: %s", name.c_str());
+  }
+
+  TRACKRENDERER_LEAVE_P(tr)
+}
+// LCOV_EXCL_STOP
+
+bool TrackRenderer::SetResourceCenterCallback_() {
+  TRACKRENDERER_ENTER_P(this)
+
+  audio_start_cb_id_ = rc_register_player_audio_start_request_callback(
+      MultiviewStartAudioCb_, this);
+  audio_stop_cb_id_ = rc_register_player_audio_stop_request_callback(
+      MultiviewStopAudioCb_, this);
+  audio_resync_cb_id_ = rc_register_player_audio_resync_request_callback(
+      MultiviewResyncAudioCb_, this);
+
+  video_start_cb_id_ = rc_register_player_video_start_request_callback(
+      MultiviewStartVideoCb_, this);
+  video_stop_cb_id_ = rc_register_player_video_stop_request_callback(
+      MultiviewStopVideoCb_, this);
+
+  bool ret = true;
+  if (audio_start_cb_id_ == 0 || audio_stop_cb_id_ == 0 ||
+      audio_resync_cb_id_ == 0) {
+    TRACKRENDERER_ERROR_P(
+        this, "register audio request callback failed: %d, %d, %d",
+        audio_start_cb_id_, audio_stop_cb_id_, audio_resync_cb_id_);
+    ret = false;
+  }
+  if (video_start_cb_id_ == 0 || video_stop_cb_id_ == 0) {
+    TRACKRENDERER_ERROR_P(this,
+                          "register video request callback failed: %d, %d",
+                          video_start_cb_id_, video_stop_cb_id_);
+    ret = false;
+  }
+  TRACKRENDERER_LEAVE_P(this)
+  return ret;
+}
+
+bool TrackRenderer::UnsetResourceCenterCallback_() {
+  TRACKRENDERER_ENTER_P(this)
+
+  auto audio_start_cb_ret =
+      rc_unregister_player_audio_start_request_callback(audio_start_cb_id_);
+  auto audio_stop_cb_ret =
+      rc_unregister_player_audio_stop_request_callback(audio_stop_cb_id_);
+  auto audio_resync_cb_ret =
+      rc_unregister_player_audio_resync_request_callback(audio_resync_cb_id_);
+
+  auto video_start_cb_ret =
+      rc_unregister_player_video_start_request_callback(video_start_cb_id_);
+  auto video_stop_cb_ret =
+      rc_unregister_player_video_stop_request_callback(video_stop_cb_id_);
+
+  bool ret = true;
+  if (audio_start_cb_ret != 0 || audio_stop_cb_ret != 0 ||
+      audio_resync_cb_ret != 0) {
+    TRACKRENDERER_ERROR_P(
+        this, "unregister audio request callback failed: %d, %d, %d",
+        audio_start_cb_ret, audio_stop_cb_ret, audio_resync_cb_ret);
+    ret = false;
+  }
+  if (video_start_cb_ret != 0 || video_stop_cb_ret != 0) {
+    TRACKRENDERER_ERROR_P(this,
+                          "unregister video request callback failed: %d, %d",
+                          video_start_cb_ret, video_stop_cb_ret);
+    ret = false;
+  }
+  return ret;
+  TRACKRENDERER_LEAVE_P(this)
+}
+
+// LCOV_EXCL_START
+void TrackRenderer::SetAlternativeAudioResource(const boost::any& value) {
+  std::uint32_t val = boost::any_cast<std::uint32_t>(value);
+  TRACKRENDERER_ERROR_P(this, " Alternative audio resource [%s]",
+                        (val != 0) ? "TRUE" : "FALSE");
+  if (val != 0) {
+    audio_decoder_id_ = ResourceCategory::kAudioDecoderSub;
+    audio_out_id_ = ResourceCategory::kAudioRendererSub;
+  } else {
+    audio_decoder_id_ = ResourceCategory::kAudioDecoder;
+    audio_out_id_ = ResourceCategory::kAudioRenderer;
+  }
+}
+// LCOV_EXCL_STOP
+
+bool TrackRenderer::InitAudioEasingInfo(const uint32_t& init_volume,
+                                        const uint32_t& init_elapsed_time,
+                                        const AudioEasingInfo& info) {
+  TRACKRENDERER_ENTER_P(this)
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (audio_easing_controller_) {
+    TRACKRENDERER_ERROR_P(this,
+                          "audio easing controller is already Initialized");
+    return false;
+  }
+
+  if (init_volume > kVolumeMax || info.target_volume > kVolumeMax) {
+    TRACKRENDERER_ERROR_P(this, "volume: %d", info.target_volume);
+    return false;
+  }
+  audio_easing_controller_.reset(
+      new AudioEasingController(init_volume, init_elapsed_time, info));
+
+  if (info.duration == 0)
+    volume_ = audio_easing_controller_->GetGainFromVolume(info.target_volume);
+  else
+    volume_ = audio_easing_controller_->GetGainFromVolume(init_volume);
+  if (pipeline_) SetVolume_();
+
+  TRACKRENDERER_LEAVE_P(this)
+  return true;
+}
+
+bool TrackRenderer::UpdateAudioEasingInfo(const AudioEasingInfo& info) {
+  TRACKRENDERER_ENTER_P(this)
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (!audio_easing_controller_) {
+    TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
+    return false;
+  }
+  if (info.target_volume > kVolumeMax) {
+    TRACKRENDERER_ERROR_P(this, "volume: %d", info.target_volume);
+    return false;
+  }
+  auto ret = audio_easing_controller_->SetInfo(info);
+  if (!ret) return false;
+
+  if (info.duration == 0) {
+    volume_ = audio_easing_controller_->GetGainFromVolume(info.target_volume);
+    if (pipeline_) SetVolume_();
+  }
+  TRACKRENDERER_LEAVE_P(this)
+  return true;
+}
+
+bool TrackRenderer::GetAudioEasingInfo(uint32_t* current_volume,
+                                       uint32_t* elapsed_time,
+                                       AudioEasingInfo* info) {
+  TRACKRENDERER_ENTER_P(this)
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (!audio_easing_controller_) {
+    TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
+    return false;
+  }
+  auto ret =
+      audio_easing_controller_->GetInfo(current_volume, elapsed_time, info);
+  TRACKRENDERER_LEAVE_P(this)
+  return ret;
+}
+
+bool TrackRenderer::StartAudioEasing() {
+  TRACKRENDERER_ENTER_P(this)
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (!audio_easing_controller_) {
+    TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
+    return false;
+  }
+  if (state_ == State::kStopped) return false;
+  if (!pipeline_) return false;
+
+  pipeline_->Execute(Elements::kSinkAudio, [this](GstElement * obj) noexcept {
+    return audio_easing_controller_->AudioEasingStart(obj);
+  });
+  return true;
+}
+
+bool TrackRenderer::StopAudioEasing() {
+  TRACKRENDERER_ENTER_P(this)
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  return StopAudioEasing_();
+}
+
+bool TrackRenderer::StopAudioEasing_() {
+  TRACKRENDERER_ENTER_P(this)
+  if (!audio_easing_controller_) {
+    TRACKRENDERER_ERROR_P(this, "audio easing controller is not exist");
+    return false;
+  }
+  audio_easing_controller_->AudioEasingStop();
+  return true;
+}
+
+bool TrackRenderer::GetVirtualRscId(const RscType type, int* virtual_id) {
+  if (virtual_id == nullptr) return false;
+  if (type != RscType::kVideoRenderer || virtual_scaler_id_ == -1) {
+    *virtual_id = -1;
+    return false;
+  }
+  *virtual_id = virtual_scaler_id_;
+  return true;
+}
+
+// LCOV_EXCL_START
+bool TrackRenderer::NeedSyncPause_() {
+  if (!support_videodec_underflow_pause_) {
+    return false;
+  }
+  TRACKRENDERER_WARN_P(this, "sync pause");
+  pipeline_->PadRemoveProbe(kPadProbeVideoDecInputBlock);
+  pipeline_->PadAddProbe(Elements::kDecVideo, kPadProbeVideoDecInputBlock,
+                         "sink", GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+                         GstPadProbeVideoDecInputCb_, this, nullptr);
+
+  gboolean is_async_video = FALSE, is_async_audio = FALSE;
+  pipeline_->GetProperty(Elements::kSinkVideo, "async", &is_async_video);
+  if (is_async_video)
+    pipeline_->SetProperty(Elements::kSinkVideo, "async", FALSE);
+  pipeline_->GetProperty(Elements::kSinkAudio, "async", &is_async_audio);
+  if (is_async_audio)
+    pipeline_->SetProperty(Elements::kSinkAudio, "async", FALSE);
+  pipeline_->SetState(Elements::kPipeline, GST_STATE_PAUSED);
+  if (is_async_video)
+    pipeline_->SetProperty(Elements::kSinkVideo, "async", TRUE);
+  if (is_async_audio)
+    pipeline_->SetProperty(Elements::kSinkAudio, "async", TRUE);
+  return true;
+}
+// LCOV_EXCL_STOP
+
+void TrackRenderer::SetAudioOut_() {
+  TRACKRENDERER_ENTER_P(this)
+  if (!pipeline_) return;
+
+  /* need to call this api after avoc_play_request_m() */
+  rc_player_audio_out_e audio_out;
+  rc_get_player_audio_out(avoc_id_, &audio_out);
+  TRACKRENDERER_INFO_P(this, "avoc_id_ : %d , rc_audio_out [%d]", avoc_id_,
+                       audio_out);
+
+  int is_audio_sub_out_path = (audio_out == RC_PLAYER_AUDIO_OUT_SUB) ? 1 : 0;
+  pipeline_->SetProperty(Elements::kSinkAudio, "device-audio-out",
+                         is_audio_sub_out_path, NULL);
+  pipeline_->SetProperty(Elements::kSinkAudio, "mute", is_sound_mute_, NULL);
+  if (volume_ != kVolumeNone) {
+    SetVolume_();
+  }
+  return;
+}
+bool TrackRenderer::SetAdvancedPictureQualityType(
+    const AdvPictureQualityType type) {
+  TRACKRENDERER_ENTER_P(this)
+#ifndef SOUNDBAR_PRODUCT
+  switch (type) {
+    case AdvPictureQualityType::kVideoCall:
+      avoc_sub_source_ = AVOC_SUB_SOURCE_UNIPLAYER_VIDEOCALL;
+      break;
+    case AdvPictureQualityType::kUsbCamera:
+      avoc_sub_source_ = AVOC_SUB_SOURCE_UNIPLAYER_CAMERA;
+      break;
+    default:
+      return false;
+  }
+#endif
+  return true;
+}
+
+bool TrackRenderer::SetResourceAllocatePolicy(const RscAllocPolicy policy) {
+  TRACKRENDERER_ENTER_P(this)
+  rsc_alloc_policy_ = policy;
+  return true;
+}
+
+void TrackRenderer::UpdateTrackFrameRate_(const int& framerate_num,
+                                          const int& framerate_den) {
+  std::lock_guard<std::mutex> lk(decoded_drop_ctx_.drop_mutex);
+  decoded_drop_ctx_.track_fps.num = framerate_num;
+  decoded_drop_ctx_.track_fps.den = framerate_den;
+  decoded_drop_ctx_.fps_changed = true;
+}
+
+void TrackRenderer::UpdateDecodedDropContext_() {
+  std::lock_guard<std::mutex> lk(decoded_drop_ctx_.drop_mutex);
+
+  BOOST_SCOPE_EXIT(&decoded_drop_ctx_) {
+    decoded_drop_ctx_.fps_changed = false;
+  }
+  BOOST_SCOPE_EXIT_END
+
+  if (decoded_drop_ctx_.fps_changed) {
+    Rational track_framerate = decoded_drop_ctx_.track_fps;
+    Rational request_framerate = decoded_drop_ctx_.request_fps;
+    if (!track_framerate.num || !track_framerate.den ||
+        !request_framerate.den) {
+      TRACKRENDERER_ERROR("invalid track or request frame rate: %d/%d",
+                          track_framerate.num, track_framerate.den);
+      return;
+    }
+    if (!request_framerate.num) {
+      decoded_drop_ctx_.drop_mode = DropMode::kDropModeAccordingToRate;
+      decoded_drop_ctx_.drop_rate = 1;
+      decoded_drop_ctx_.base_num = 0;
+      return;
+    }
+    const int64_t tmp1 = track_framerate.num * (int64_t)request_framerate.den;
+    const int64_t tmp2 =
+        tmp1 - request_framerate.num * (int64_t)track_framerate.den;
+    if (tmp2 < 0) {
+      TRACKRENDERER_ERROR(
+          "request frame rate(%d/%d) can not be larger than track frame "
+          "rate(%d/%d)",
+          request_framerate.num, request_framerate.den, track_framerate.num,
+          track_framerate.den);
+      return;
+    } else if (!tmp2) {
+      decoded_drop_ctx_.drop_mode = DropMode::kDropModeNone;
+    } else {
+      if (tmp1 % tmp2 == 0) {
+        decoded_drop_ctx_.drop_mode = DropMode::kDropModeAccordingToRate;
+        decoded_drop_ctx_.drop_rate = static_cast<uint32_t>(tmp1 / tmp2);
+        decoded_drop_ctx_.base_num = 0;
+      } else if (track_framerate.num == 24 * track_framerate.den &&
+                 request_framerate.num == 15 * request_framerate.den) {
+        decoded_drop_ctx_.drop_mode = DropMode::kDropModeAccordingToTable;
+        decoded_drop_ctx_.base_num = 0;
+      } else {
+        TRACKRENDERER_ERROR(
+            "not support case: request frame rate(%d/%d)  track frame "
+            "rate(%d/%d)",
+            request_framerate.num, request_framerate.den, track_framerate.num,
+            track_framerate.den);
+        return;
+      }
+    }
+  }
+  return;
+}
+
+bool TrackRenderer::NeedDropThisDecodedVideoBuffer_() {
+  bool ret = false;
+
+  UpdateDecodedDropContext_();
+  if (decoded_drop_ctx_.drop_mode == DropMode::kDropModeAccordingToRate &&
+      decoded_drop_ctx_.drop_rate) {
+    uint32_t drop_rate = decoded_drop_ctx_.drop_rate;
+    constexpr uint32_t kDropAll = 1;
+    decoded_drop_ctx_.base_num++;
+    if (drop_rate == kDropAll ||
+        (decoded_drop_ctx_.base_num % drop_rate == 0)) {
+      decoded_drop_ctx_.base_num = 0;
+      ret = true;
+    }
+  } else if (decoded_drop_ctx_.drop_mode ==
+             DropMode::kDropModeAccordingToTable) {
+    constexpr uint32_t kDropTable[8] = {0, 0, 1, 0, 0, 1, 0, 1};
+
+    decoded_drop_ctx_.base_num = decoded_drop_ctx_.base_num & 0x7;
+    if (kDropTable[decoded_drop_ctx_.base_num]) {
+      ret = true;
+    }
+    decoded_drop_ctx_.base_num++;
+  }
+  return ret;
+}
+
+bool TrackRenderer::SetVideoRendererType(
+    const ResourceCategory video_renderer_type) {
+  if (video_renderer_type < ResourceCategory::kVideoRenderer) return false;
+  if (video_renderer_type > ResourceCategory::kVideoRendererSub3) return false;
+  video_renderer_id_ = video_renderer_type;
+  return true;
+}
+
+void TrackRenderer::SetVideoParDar(uint64_t time_millisecond, uint32_t par_num,
+                                   uint32_t par_den, uint32_t dar_num,
+                                   uint32_t dar_den) {
+  TRACKRENDERER_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(resource_m_);
+  std::lock_guard<std::mutex> audio_lk(internal_audio_m_);
+  if (state_ == State::kStopped) return;
+  if (state_ == State::kResourceConflicted) return;
+
+  if (!pipeline_) {
+    par_dar_.time_millisecond = time_millisecond;
+    par_dar_.par_num = par_num;
+    par_dar_.par_den = par_den;
+    par_dar_.dar_num = dar_num;
+    par_dar_.dar_den = dar_den;
+    is_pardar_updated_ = true;
+  } else {
+    pipeline_->SetParDar(Elements::kDecVideo, time_millisecond, par_num,
+                         par_den, dar_num, dar_den);
+  }
+  TRACKRENDERER_LEAVE_P(this);
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/trackrenderer_attr.cpp b/src/trackrenderer_attr.cpp
new file mode 100755 (executable)
index 0000000..64ca3d2
--- /dev/null
@@ -0,0 +1,182 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/trackrenderer.h"
+#include "trackrenderer/core/elements.h"
+
+#define MAKE_ATTRIBUTE(attr, elem, type, name, init, value)                   \
+  {                                                                           \
+    trackrenderer::Attribute::attr, {                                         \
+      trackrenderer::Elements::elem, typeid(type), name, init, value, \
+          &::OnAttributeSetWithCasting<type>,                         \
+          &::OnAttributeGetWithCasting<type>                                  \
+    }                                                                         \
+  }
+#define ELEMENT(elem) elem
+#define VALUE_TYPE(type) type
+#define PROPERTY(name) name
+#define WITHOUT_INIT false
+#define WITH_INIT true
+#define DEFAULT_VALUE(value) value
+
+namespace {
+constexpr std::uint64_t kMaxByteOfVideoSrcQueue = 1024 * 1024;  // 1MB
+constexpr std::uint64_t kMaxByteOfAudioSrcQueue = 1024;         // 1KB
+constexpr std::uint64_t kCurrentLevelByteOfVideo = 0;           // 0KB
+constexpr std::uint64_t kCurrentLevelByteOfAudio = 0;           // 0KB
+constexpr std::uint32_t kMinByteThresholdOfVideo = 0;           // 0%
+constexpr std::uint32_t kMinByteThresholdOfAudio = 0;           // 0%
+constexpr std::uint64_t kMaxTimeOfVideoSrcQueue = 0;            // 0ns
+constexpr std::uint64_t kMaxTimeOfAudioSrcQueue = 0;            // 0ns
+constexpr std::uint64_t kCurrentLevelTimeOfVideo = 0;           // 0ns
+constexpr std::uint64_t kCurrentLevelTimeOfAudio = 0;           // 0ns
+constexpr std::uint32_t kMinTimeThresholdOfVideo = 0;           // 0%
+constexpr std::uint32_t kMinTimeThresholdOfAudio = 0;           // 0%
+constexpr std::int32_t kInvalidExternalDrmHandle = -1;
+constexpr std::int32_t kIsSupportRotate = 0;
+constexpr std::int64_t kDefaultRenderTimeOffset = 0;
+
+template <typename ValueType>
+bool IsSameValue(const boost::any& v1, const boost::any& v2) {
+  if (v1.type() != v2.type()) return false;
+  return (boost::any_cast<ValueType>(v1) == boost::any_cast<ValueType>(v2));
+}
+
+template <typename ValueType>
+static bool OnAttributeSetWithCasting(
+    plusplayer::trackrenderer::TrackRenderer::TrackRendererAttributeSetter&
+        setter,
+    const boost::any& original_value, const boost::any& new_value) {
+  if (original_value.empty() == false &&
+      IsSameValue<ValueType>(original_value, new_value))
+    return false;
+  setter.Set(boost::any_cast<ValueType>(new_value));
+  return true;
+}
+
+template <typename ValueType>
+static bool OnAttributeGetWithCasting(
+    plusplayer::trackrenderer::TrackRenderer::TrackRendererAttributeGetter&
+        getter,
+    boost::any* get_value) {
+  getter.Get<ValueType>(get_value);
+  return true;
+}
+}  // namespace
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+TrackRenderer::AttributesByElement
+TrackRenderer::InitAttributeByElementType_() {
+  assert(kAttributes_.size() != 0);
+  TrackRenderer::AttributesByElement attirbutes_by_elem;
+  for (auto& kv : kAttributes_) {
+    const trackrenderer::Attribute& attr = kv.first;
+    const TrackRendererAttributeBinder& binder = kv.second;
+    attirbutes_by_elem[binder.element].push_back(attr);
+  }
+  return attirbutes_by_elem;
+}
+
+const TrackRenderer::Attributes TrackRenderer::kAttributes_ = {
+    MAKE_ATTRIBUTE(kVideoQueueMaxByte,                          //
+                   ELEMENT(kAppSrcVideo),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("max-bytes"),                       //
+                   WITH_INIT,                                   //
+                   DEFAULT_VALUE(::kMaxByteOfVideoSrcQueue)),   //
+    MAKE_ATTRIBUTE(kAudioQueueMaxByte,                          //
+                   ELEMENT(kAppSrcAudio),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("max-bytes"),                       //
+                   WITH_INIT,                                   //
+                   DEFAULT_VALUE(::kMaxByteOfAudioSrcQueue)),   //
+    MAKE_ATTRIBUTE(kVideoQueueCurrentLevelByte,                 //
+                   ELEMENT(kAppSrcVideo),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("current-level-bytes"),             //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kCurrentLevelByteOfVideo)),  //
+    MAKE_ATTRIBUTE(kAudioQueueCurrentLevelByte,                 //
+                   ELEMENT(kAppSrcAudio),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("current-level-bytes"),             //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kCurrentLevelByteOfAudio)),  //
+    MAKE_ATTRIBUTE(kVideoMinByteThreshold,                      //
+                   ELEMENT(kAppSrcVideo),                       //
+                   VALUE_TYPE(std::uint32_t),                   //
+                   PROPERTY("min-percent"),                     //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kMinByteThresholdOfVideo)),  //
+    MAKE_ATTRIBUTE(kAudioMinByteThreshold,                      //
+                   ELEMENT(kAppSrcAudio),                       //
+                   VALUE_TYPE(std::uint32_t),                   //
+                   PROPERTY("min-percent"),                     //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kMinByteThresholdOfAudio)),  //
+    MAKE_ATTRIBUTE(kVideoQueueMaxTime,                          //
+                   ELEMENT(kAppSrcVideo),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("max-time"),                        //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kMaxTimeOfVideoSrcQueue)),   //
+    MAKE_ATTRIBUTE(kAudioQueueMaxTime,                          //
+                   ELEMENT(kAppSrcAudio),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("max-time"),                        //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kMaxTimeOfAudioSrcQueue)),   //
+    MAKE_ATTRIBUTE(kVideoQueueCurrentLevelTime,                 //
+                   ELEMENT(kAppSrcVideo),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("current-level-time"),              //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kCurrentLevelTimeOfVideo)),  //
+    MAKE_ATTRIBUTE(kAudioQueueCurrentLevelTime,                 //
+                   ELEMENT(kAppSrcAudio),                       //
+                   VALUE_TYPE(std::uint64_t),                   //
+                   PROPERTY("current-level-time"),              //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kCurrentLevelTimeOfAudio)),  //
+    MAKE_ATTRIBUTE(kVideoMinTimeThreshold,                      //
+                   ELEMENT(kAppSrcVideo),                       //
+                   VALUE_TYPE(std::uint32_t),                   //
+                   PROPERTY("min-time-percent"),                //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kMinTimeThresholdOfVideo)),  //
+    MAKE_ATTRIBUTE(kAudioMinTimeThreshold,                      //
+                   ELEMENT(kAppSrcAudio),                       //
+                   VALUE_TYPE(std::uint32_t),                   //
+                   PROPERTY("min-time-percent"),                //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kMinTimeThresholdOfAudio)),  //
+    MAKE_ATTRIBUTE(kVideoSupportRotation,                       //
+                   ELEMENT(kSinkVideo),                         //
+                   VALUE_TYPE(std::uint32_t),                   //
+                   PROPERTY("support-rotation"),                //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kIsSupportRotate)),          //
+    MAKE_ATTRIBUTE(kVideoRenderTimeOffset,                      //
+                   ELEMENT(kSinkVideo),                         //
+                   VALUE_TYPE(std::int64_t),                    //
+                   PROPERTY("ts-offset"),                       //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kDefaultRenderTimeOffset)),  //
+    MAKE_ATTRIBUTE(kAudioRenderTimeOffset,                      //
+                   ELEMENT(kSinkAudio),                         //
+                   VALUE_TYPE(std::int64_t),                    //
+                   PROPERTY("ts-offset"),                       //
+                   WITHOUT_INIT,                                //
+                   DEFAULT_VALUE(::kDefaultRenderTimeOffset)),  //
+};
+
+const TrackRenderer::AttributesByElement TrackRenderer::kAttributesByElem_ =
+    TrackRenderer::InitAttributeByElementType_();
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/trackrenderer_capi.cpp b/src/trackrenderer_capi.cpp
new file mode 100755 (executable)
index 0000000..598b623
--- /dev/null
@@ -0,0 +1,1704 @@
+#include "trackrenderer_capi/trackrenderer_capi.h"
+
+#include <cassert>
+#include <cstdarg>
+#include <map>
+#include <memory>
+#include <string>
+#include <typeinfo>
+
+#include "trackrenderer/core/display.h"
+#include "trackrenderer/core/track.h"
+#include "trackrenderer/trackrenderer.h"
+#include "trackrenderer/trackrenderer_capi_utils.h"
+#include "trackrenderer/version.h"
+#include "trackrenderer_capi/trackrenderer_internal.h"
+
+//#define DUMP_SUBTITLE_PICTURE
+#ifdef DUMP_SUBTITLE_PICTURE
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#pragma pack(1)
+typedef struct tagBITMAPFILEHEADER {
+  short bfType;
+  int bfSize;
+  short bfReserved1;
+  short bfReserved2;
+  int bfOffBits;
+} BITMAPFILEHEADER;
+
+typedef struct tagBITMAPINFOHEADER {
+  int biSize;
+  int biWidth;
+  int biHeight;
+  short biPlanes;
+  short biBitCount;
+  int biCompression;
+  int biSizeImage;
+  int biXPelsPerMeter;
+  int biYPelsPerMeter;
+  int biClrUsed;
+  int biClrImportant;
+} BITMAPINFOHEADER;
+#pragma pack()
+
+static int CreateWindowsBMP(unsigned char* outARGBadd, int width, int height,
+                            int file_index) {
+  TRACKRENDERER_DEBUG("==CreateWindowsBMP==");
+
+  BITMAPFILEHEADER bFileHeader;
+  BITMAPINFOHEADER bInfoHeader;
+
+  /*file header*/
+  bFileHeader.bfType = 0x4d42;
+  bFileHeader.bfReserved1 = 0;
+  bFileHeader.bfReserved2 = 0;
+  bFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+
+  /*info header*/
+  bInfoHeader.biSize = 40;
+  bInfoHeader.biWidth = width;
+  bInfoHeader.biHeight = height;
+  bInfoHeader.biPlanes = 1;
+  bInfoHeader.biCompression = 0;
+  bInfoHeader.biXPelsPerMeter = 0;
+  bInfoHeader.biYPelsPerMeter = 0;
+  bInfoHeader.biClrUsed = 0;
+  bInfoHeader.biClrImportant = 0;
+
+  unsigned char* outARGBadd_bmp = NULL;
+  int height_count;
+
+  FILE* fp = NULL;
+  struct stat ls;
+  char path[256] = {
+      0,
+  };
+  snprintf(path, 256, "/media/USBDriveA1/subtitle_picture_plusplayer_%d.bmp",
+           file_index);
+
+  /*Check the soft symbol, refer to
+   * */
+  /*File information is obtained by using lstat function.*/
+  if (lstat(path, &ls) == -1) {
+    if (errno != ENOENT) {
+      TRACKRENDERER_DEBUG("lstat error");
+      return -1;
+    }
+  } else {
+    /*In case of existing file, checking symbolic link*/
+    if (S_ISLNK(ls.st_mode)) {
+      TRACKRENDERER_DEBUG("symbolic link is detected");
+      return -1;
+    }
+  }
+
+  if ((fp = fopen(path, "wb")) == NULL) {
+    TRACKRENDERER_DEBUG("Error in opening file");
+    return 1;
+  }
+
+  bInfoHeader.biBitCount = 32;
+  bInfoHeader.biSizeImage = width * height * 4;
+  bFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
+                       (4 * (width * height));
+  outARGBadd_bmp = (unsigned char*)malloc(width * height * 4);
+  if (!outARGBadd_bmp) return -1;
+  for (height_count = 0; height_count < height; ++height_count) {
+    memcpy(outARGBadd_bmp + (height - height_count - 1) * width * 4,
+           outARGBadd + height_count * width * 4, width * 4);
+  }
+  fwrite(&bFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
+  fwrite(&bInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
+  fwrite(outARGBadd_bmp, height * width * 4, 1, fp);
+
+  TRACKRENDERER_DEBUG("==Create pictuer over!==");
+  free(outARGBadd_bmp);
+  fclose(fp);
+  fp = NULL;
+  return 1;
+}
+#endif
+
+const char* trackrenderer_get_version(void) {
+  TRACKRENDERER_ERROR("libtrackrenderer.so version [%s]",
+                      TRACKRENDERER_STRINGIFY(LIB_TRACKRENDERER_VERSION));
+  return TRACKRENDERER_STRINGIFY(LIB_TRACKRENDERER_VERSION);
+}
+
+uint32_t trackrenderer_get_version_int(void) {
+  TRACKRENDERER_ERROR("libtrackrenderer.so version [%u]",
+                      LIB_TRACKRENDERER_VERSION_INT);
+  return LIB_TRACKRENDERER_VERSION_INT;
+}
+
+struct TrackRendererPriv;
+
+class TrackRendererEventListener
+    : public plusplayer::trackrenderer::TrackRenderer::EventListener {
+ public:
+  explicit TrackRendererEventListener(TrackRendererPriv* handler)
+      : handler_(handler) {}
+  void OnError(const plusplayer::trackrenderer::ErrorType& error_code) override;
+  void OnErrorMsg(const plusplayer::trackrenderer::ErrorType& error_code,
+                  char* error_msg) override;
+  void OnResourceConflicted() override;
+  void OnSeekDone() override;
+  void OnFlushDone() override;
+  void OnEos() override;
+  void OnEvent(const plusplayer::trackrenderer::EventType& event,
+               const plusplayer::trackrenderer::EventMsg& msg_data) override;
+  void OnFirstDecodingDone() override;
+  void OnSubtitleData(
+      const plusplayer::trackrenderer::DecoderInputBufferPtr& buf,
+      const plusplayer::trackrenderer::SubtitleType& type) override;
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+  void OnSubtitleData(
+      const char* data, const int size,
+      const plusplayer::trackrenderer::SubtitleType& type,
+      const uint64_t duration,
+      plusplayer::trackrenderer::SubtitleAttrListPtr attr_list) override;
+#endif
+  void OnClosedCaptionData(const char* data, const int size) override;
+  void OnDrmInitData(int* drmhandle, unsigned int len, unsigned char* psshdata,
+                     plusplayer::trackrenderer::TrackType type) override;
+  void OnBufferStatus(
+      const plusplayer::trackrenderer::TrackType& type,
+      const plusplayer::trackrenderer::BufferStatus& status) override;
+  void OnSeekData(const plusplayer::trackrenderer::TrackType& type,
+                  const uint64_t offset) override;
+  void OnMediaPacketGetTbmBufPtr(void** ptr, bool is_scale_change) override;
+  void OnMediaPacketVideoDecoded(
+      const plusplayer::trackrenderer::DecodedVideoPacket& packet) override;
+  void OnMediaRawPacketVideoDecoded(
+      plusplayer::trackrenderer::DecodedVideoRawModePacket& packet) override;
+  void OnVideoDecoderUnderrun() override;
+  void OnVideoLatencyStatus(
+      const plusplayer::trackrenderer::LatencyStatus& latency_status) override;
+  void OnAudioLatencyStatus(
+      const plusplayer::trackrenderer::LatencyStatus& latency_status) override;
+  void OnVideoHighLatency() override;
+  void OnAudioHighLatency() override;
+  void OnMultiviewStartVideo() override;
+  void OnMultiviewStopVideo() override;
+
+ private:
+  TrackRendererPriv* handler_ = nullptr;
+};  // class TrackRendererEventListener
+
+struct TrackRendererPriv {
+  std::unique_ptr<plusplayer::trackrenderer::TrackRenderer> renderer;
+
+  trackrenderer_error_cb error_cb = nullptr;
+  void* error_cb_userdata = nullptr;
+
+  trackrenderer_error_msg_cb error_msg_cb = nullptr;
+  void* error_msg_cb_userdata = nullptr;
+
+  trackrenderer_resource_conflicted_cb resourceconflict_cb = nullptr;
+  void* resourceconflict_cb_userdata = nullptr;
+
+  trackrenderer_seekdone_cb seekdone_cb = nullptr;
+  void* seekdone_cb_userdata = nullptr;
+
+  trackrenderer_flushdone_cb flushdone_cb = nullptr;
+  void* flushdone_cb_userdata = nullptr;
+
+  trackrenderer_eos_cb eos_cb = nullptr;
+  void* eos_cb_userdata = nullptr;
+
+  trackrenderer_event_cb event_cb = nullptr;
+  void* event_cb_userdata = nullptr;
+
+  trackrenderer_first_decoding_done_cb first_decoding_done_cb = nullptr;
+  void* first_decoding_done_cb_userdata = nullptr;
+
+  trackrenderer_subtitle_rawdata_cb subtitle_rawdata_cb = nullptr;
+  void* subtitle_rawdata_cb_userdata = nullptr;
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+  trackrenderer_subtitledata_cb subtitledata_cb = nullptr;
+  void* subtitledata_cb_userdata = nullptr;
+#endif
+
+  trackrenderer_closedcaption_cb closedcaption_cb = nullptr;
+  void* closedcaption_cb_userdata = nullptr;
+
+  trackrenderer_drminitdata_cb drminitdata_cb = nullptr;
+  void* drminitdata_cb_userdata = nullptr;
+
+  trackrenderer_bufferstatus_cb bufferstatus_cb = nullptr;
+  void* bufferstatus_cb_userdata = nullptr;
+
+  trackrenderer_seekdata_cb seekdata_cb = nullptr;
+  void* seekdata_cb_userdata = nullptr;
+
+  trackrenderer_media_packet_video_tbmptr_cb video_tbmptr_cb = nullptr;
+  void* video_tbmptr_cb_userdata = nullptr;
+
+  trackrenderer_media_packet_video_decoded_cb video_decoded_cb = nullptr;
+  void* video_decoded_cb_userdata = nullptr;
+
+  trackrenderer_media_packet_video_raw_decoded_cb video_raw_decoded_cb =
+      nullptr;
+  void* video_raw_decoded_cb_userdata = nullptr;
+
+  trackrenderer_decoder_underrun_cb video_decoder_underrun_cb = nullptr;
+  void* video_decoder_underrun_cb_userdata = nullptr;
+
+  trackrenderer_video_latency_status_cb video_latency_status_cb = nullptr;
+  trackrenderer_audio_latency_status_cb audio_latency_status_cb = nullptr;
+  void* video_latency_status_cb_userdata = nullptr;
+  void* audio_latency_status_cb_userdata = nullptr;
+  trackrenderer_video_high_latency_cb video_high_latency_cb = nullptr;
+  trackrenderer_audio_high_latency_cb audio_high_latency_cb = nullptr;
+  void* video_high_latency_cb_userdata = nullptr;
+  void* audio_high_latency_cb_userdata = nullptr;
+
+  trackrenderer_multiview_start_video_cb multiview_start_video_cb = nullptr;
+  trackrenderer_multiview_stop_video_cb multiview_stop_video_cb = nullptr;
+  void* multiview_start_video_cb_userdata = nullptr;
+  void* multiview_stop_video_cb_userdata = nullptr;
+
+  std::unique_ptr<TrackRendererEventListener> eventlistener{
+      new TrackRendererEventListener(this)};
+
+  using Ptr = TrackRendererPriv*;
+  friend Ptr Create();
+  friend void Destroy(Ptr& instance);
+
+ private:
+  TrackRendererPriv() {}
+  ~TrackRendererPriv() {}
+};
+
+void TrackRendererEventListener::OnError(
+    const plusplayer::trackrenderer::ErrorType& error_code) {
+  if (handler_->error_cb == nullptr) return;
+  handler_->error_cb(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererErrorType(
+          error_code),
+      handler_->error_cb_userdata);
+}
+
+void TrackRendererEventListener::OnErrorMsg(
+    const plusplayer::trackrenderer::ErrorType& error_code, char* error_msg) {
+  if (handler_->error_msg_cb == nullptr) return;
+  handler_->error_msg_cb(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererErrorType(
+          error_code),
+      error_msg, handler_->error_cb_userdata);
+}
+
+void TrackRendererEventListener::OnResourceConflicted() {
+  if (handler_->resourceconflict_cb == nullptr) return;
+  handler_->resourceconflict_cb(handler_->resourceconflict_cb_userdata);
+}
+void TrackRendererEventListener::OnSeekDone() {
+  if (handler_->seekdone_cb == nullptr) return;
+  handler_->seekdone_cb(handler_->seekdone_cb_userdata);
+}
+
+void TrackRendererEventListener::OnFlushDone() {
+  if (handler_->flushdone_cb == nullptr) return;
+  handler_->flushdone_cb(handler_->flushdone_cb_userdata);
+}
+
+void TrackRendererEventListener::OnEos() {
+  if (handler_->eos_cb == nullptr) return;
+  handler_->eos_cb(handler_->eos_cb_userdata);
+}
+
+void TrackRendererEventListener::OnEvent(
+    const plusplayer::trackrenderer::EventType& event,
+    const plusplayer::trackrenderer::EventMsg& msg_data) {
+  if (handler_->event_cb == nullptr) return;
+  TrackrendererEventMsg event_msg;
+  event_msg.data = const_cast<char*>(msg_data.data.c_str());
+  event_msg.len = msg_data.len;
+  handler_->event_cb(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererEventType(
+          event),
+      event_msg, handler_->event_cb_userdata);
+}
+
+void TrackRendererEventListener::OnFirstDecodingDone() {
+  if (handler_->first_decoding_done_cb == nullptr) return;
+  handler_->first_decoding_done_cb(handler_->first_decoding_done_cb_userdata);
+}
+
+void TrackRendererEventListener::OnSubtitleData(
+    const plusplayer::trackrenderer::DecoderInputBufferPtr& buf,
+    const plusplayer::trackrenderer::SubtitleType& type) {
+  if (handler_->subtitle_rawdata_cb == nullptr) return;
+  if (!buf) return;
+
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  TrackRendererDecoderInputBuffer buffer{
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererTrackType(
+          buf->GetType()),
+      0, static_cast<void*>(const_cast<GstBuffer*>(buf->Get()))};
+#else
+  TrackRendererDecoderInputBuffer buffer{
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererTrackType(
+          buf->GetType()),
+      0, const_cast<GstBuffer*>(buf->Get())};
+#endif
+  handler_->subtitle_rawdata_cb(
+      &buffer,
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererSubtitleType(
+          type),
+      handler_->subtitle_rawdata_cb_userdata);
+}
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+void TrackRendererEventListener::OnSubtitleData(
+    const char* data, const int size,
+    const plusplayer::trackrenderer::SubtitleType& type,
+    const uint64_t duration,
+    plusplayer::trackrenderer::SubtitleAttrListPtr attr_list) {
+  if (plusplayer::trackrenderer::SubtitleType::kPicture == type && size > 0) {
+    gfloat width = 0, height = 0;
+
+    for (plusplayer::trackrenderer::SubtitleAttrList::iterator it =
+             attr_list->begin();
+         it != attr_list->end(); ++it) {
+      TRACKRENDERER_DEBUG("it->type = [%d]", (int)(it->type));
+      switch (it->type) {
+        case plusplayer::trackrenderer::kSubAttrRegionWidth:
+          width = boost::any_cast<gfloat>(it->value);
+          break;
+        case plusplayer::trackrenderer::kSubAttrRegionHeight:
+          height = boost::any_cast<gfloat>(it->value);
+          break;
+        default:
+          break;
+      }
+      if (width && height) {
+        break;
+      }
+    }
+    TRACKRENDERER_DEBUG("Picture subtitle >> width [%f],height [%f]", width,
+                        height);
+#ifdef DUMP_SUBTITLE_PICTURE
+    static unsigned int picture_index = 0;
+    CreateWindowsBMP((unsigned char*)data, (int)width, (int)height,
+                     picture_index++);
+#endif
+  } else if (plusplayer::trackrenderer::SubtitleType::kText == type &&
+             size > 0) {
+    TRACKRENDERER_DEBUG("Text subtitle >>  %s", data);
+  }
+
+  if (handler_->subtitledata_cb == nullptr) return;
+  int attr_list_size = attr_list->size();
+  if (attr_list_size <= 0 && size > 0) {
+    return;
+  }
+  TrackRendererSubtitleAttr subtitle_attr_list[attr_list_size];
+  int index = 0;
+  for (index = 0; index < attr_list_size; index++) {
+    subtitle_attr_list[index] =
+        plusplayer::trackrenderer::capi_utils::InitSubtitleAttr();
+  }
+  index = 0;
+  for (const auto& attr : *attr_list) {
+    plusplayer::trackrenderer::capi_utils::MakeTrackRendererSubtitleAttr(
+        &subtitle_attr_list[index], attr);
+    index++;
+  }
+  handler_->subtitledata_cb(
+      const_cast<char*>(data), size,
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererSubtitleType(
+          type),
+      duration, subtitle_attr_list, attr_list_size,
+      handler_->subtitledata_cb_userdata);
+}
+#endif
+
+void TrackRendererEventListener::OnClosedCaptionData(const char* data,
+                                                     const int size) {
+  if (handler_->closedcaption_cb == nullptr) return;
+  handler_->closedcaption_cb(const_cast<char*>(data), size,
+                             handler_->closedcaption_cb_userdata);
+}
+void TrackRendererEventListener::OnDrmInitData(
+    int* drmhandle, unsigned int len, unsigned char* psshdata,
+    plusplayer::trackrenderer::TrackType type) {
+  if (handler_->drminitdata_cb == nullptr) return;
+  handler_->drminitdata_cb(
+      drmhandle, len, psshdata,
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererTrackType(
+          type),
+      handler_->drminitdata_cb_userdata);
+}
+
+void TrackRendererEventListener::OnBufferStatus(
+    const plusplayer::trackrenderer::TrackType& type,
+    const plusplayer::trackrenderer::BufferStatus& status) {
+  if (handler_->bufferstatus_cb == nullptr) return;
+  handler_->bufferstatus_cb(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererTrackType(
+          type),
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererBufferStatus(
+          status),
+      handler_->bufferstatus_cb_userdata);
+}
+
+void TrackRendererEventListener::OnSeekData(
+    const plusplayer::trackrenderer::TrackType& type, const uint64_t offset) {
+  if (handler_->seekdata_cb == nullptr) return;
+  handler_->seekdata_cb(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererTrackType(
+          type),
+      offset, handler_->seekdata_cb_userdata);
+}
+
+void TrackRendererEventListener::OnMediaPacketGetTbmBufPtr(
+    void** ptr, bool is_scale_change) {
+  if (handler_->video_tbmptr_cb == nullptr) return;
+  handler_->video_tbmptr_cb(ptr, is_scale_change,
+                            handler_->video_tbmptr_cb_userdata);
+}
+
+void TrackRendererEventListener::OnMediaPacketVideoDecoded(
+    const plusplayer::trackrenderer::DecodedVideoPacket& packet) {
+  if (handler_->video_decoded_cb == nullptr) return;
+  TrackRendererDecodedVideoPacket _packet =
+      plusplayer::trackrenderer::capi_utils::ConvertToDecodedVideoPacket(
+          packet);
+  handler_->video_decoded_cb(&_packet, handler_->video_decoded_cb_userdata);
+}
+
+void TrackRendererEventListener::OnMediaRawPacketVideoDecoded(
+    plusplayer::trackrenderer::DecodedVideoRawModePacket& packet) {
+  if (handler_->video_raw_decoded_cb == nullptr) return;
+  TrackRendererDecodedVideoRawModePacket _packet;
+  _packet.pts = packet.pts;
+  _packet.width = packet.width;
+  _packet.height = packet.height;
+  _packet.internal_data = static_cast<void*>(&packet.data);
+  handler_->video_raw_decoded_cb(
+      &_packet, static_cast<TrackRendererDecodedVideoType>(packet.type),
+      handler_->video_raw_decoded_cb_userdata);
+}
+
+void TrackRendererEventListener::OnVideoDecoderUnderrun() {
+  if (handler_->video_decoder_underrun_cb == nullptr) return;
+  handler_->video_decoder_underrun_cb(
+      handler_->video_decoder_underrun_cb_userdata);
+}
+
+void TrackRendererEventListener::OnVideoLatencyStatus(
+    const plusplayer::trackrenderer::LatencyStatus& latency_status) {
+  if (handler_->video_latency_status_cb == nullptr) return;
+  handler_->video_latency_status_cb(
+      plusplayer::trackrenderer::capi_utils::
+          ConvertToTrackrendererLatencyStatus(latency_status),
+      handler_->video_latency_status_cb_userdata);
+}
+
+void TrackRendererEventListener::OnAudioLatencyStatus(
+    const plusplayer::trackrenderer::LatencyStatus& latency_status) {
+  if (handler_->audio_latency_status_cb == nullptr) return;
+  handler_->audio_latency_status_cb(
+      plusplayer::trackrenderer::capi_utils::
+          ConvertToTrackrendererLatencyStatus(latency_status),
+      handler_->audio_latency_status_cb_userdata);
+}
+
+void TrackRendererEventListener::OnVideoHighLatency() {
+  if (handler_->video_high_latency_cb == nullptr) return;
+  handler_->video_high_latency_cb(handler_->video_high_latency_cb_userdata);
+}
+
+void TrackRendererEventListener::OnAudioHighLatency() {
+  if (handler_->audio_high_latency_cb == nullptr) return;
+  handler_->audio_high_latency_cb(handler_->audio_high_latency_cb_userdata);
+}
+
+void TrackRendererEventListener::OnMultiviewStartVideo() {
+  if (handler_->multiview_start_video_cb == nullptr) return;
+  handler_->multiview_start_video_cb(
+      handler_->multiview_start_video_cb_userdata);
+}
+
+void TrackRendererEventListener::OnMultiviewStopVideo() {
+  if (handler_->multiview_stop_video_cb == nullptr) return;
+  handler_->multiview_stop_video_cb(handler_->multiview_stop_video_cb_userdata);
+}
+
+using TrackRendererPrivPtr = TrackRendererPriv::Ptr;
+
+TrackRendererPrivPtr Create() {
+  auto instance = new TrackRendererPriv;
+  instance->renderer = plusplayer::trackrenderer::TrackRenderer::Create();
+  instance->renderer->RegisterListener(instance->eventlistener.get());
+  return instance;
+}
+
+void Destroy(TrackRendererPrivPtr& instance) {
+  if (instance) delete instance;
+  instance = nullptr;
+}
+
+constexpr int kSuccess = 0;
+constexpr int kFailed = -1;
+
+int trackrenderer_create(TrackRendererHandle* handle) {
+  *handle = static_cast<void*>(Create());
+  return kSuccess;
+}
+
+int trackrenderer_destroy(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  Destroy(priv);
+  return kSuccess;
+}
+
+int trackrenderer_start(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->Start() == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_stop(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  priv->renderer->Stop();
+  return kSuccess;
+}
+
+int trackrenderer_prepare(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->Prepare() == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_pause(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->Pause() == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_resume(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->Resume() == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+constexpr int kTrackRendererMaxStreamNumber = 3;
+int trackrenderer_set_track(TrackRendererHandle handle,
+                            const TrackRendererTrack* track, const int size) {
+  if (size <= 0 || size > kTrackRendererMaxStreamNumber) return kFailed;
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  auto trackinfo =
+      plusplayer::trackrenderer::capi_utils::MakeTrack(track, size);
+  priv->renderer->SetTrack(trackinfo);
+  return kSuccess;
+}
+
+int trackrenderer_set_track_handle(
+    TrackRendererHandle handle, const TrackRendererTrackHandle* handles_array,
+    const int array_size) {
+  if (array_size <= 0 || array_size > kTrackRendererMaxStreamNumber)
+    return kFailed;
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  auto trackinfo =
+      plusplayer::trackrenderer::capi_utils::MakeTrackFromTrackHandle(
+          handles_array, array_size);
+  return priv->renderer->SetTrack(trackinfo) ? kSuccess : kFailed;
+}
+
+void trackrenderer_set_ini_property(TrackRendererHandle handle,
+                                    TrackRendererIniProperty* properties,
+                                    int property_size) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  std::map<std::string, bool> iniproperty =
+      plusplayer::trackrenderer::capi_utils::MakeIniProperty(properties,
+                                                             property_size);
+  priv->renderer->SetIniProperty(iniproperty);
+}
+
+int trackrenderer_seek(TrackRendererHandle handle,
+                       unsigned long long time_millisecond,
+                       double playback_rate) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->Seek(time_millisecond, playback_rate) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_seek2(TrackRendererHandle handle,
+                        unsigned long long time_millisecond,
+                        double playback_rate, bool audio_mute) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->Seek(time_millisecond, playback_rate, audio_mute) ==
+      false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_playback_rate(TrackRendererHandle handle,
+                                    double playback_rate, bool audio_mute) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetPlaybackRate(playback_rate, audio_mute) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_get_playing_time(TrackRendererHandle handle,
+                                   unsigned long long* time_millisecond) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->GetPlayingTime(time_millisecond) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_get_dropped_frames(TrackRendererHandle handle, void* counts) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->GetDroppedFrames(counts) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_get_dropped_frames_for_catchup(TrackRendererHandle handle,
+                                                 TrackRendererTrackType type,
+                                                 void* counts) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->GetDroppedFramesForCatchup(
+          plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type),
+          counts) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_deactivate(TrackRendererHandle handle,
+                             TrackRendererTrackType type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->Deactivate(
+          plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type)) ==
+      false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_activate(TrackRendererHandle handle,
+                           TrackRendererTrackType type,
+                           TrackRendererTrack* trackinfo) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  // TODO(sy0207.ju):MakeTrack return vector. use magic number.
+  auto tracks = plusplayer::trackrenderer::capi_utils::MakeTrack(trackinfo, 1);
+
+  if (priv->renderer->Activate(
+          plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type),
+          tracks.front()) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+using SubmitStatus = plusplayer::trackrenderer::SubmitStatus;
+
+TrackRendererSubmitStatus ConvertToTrackRendererSubmitStatus(
+    SubmitStatus status) {
+  switch (status) {
+    case SubmitStatus::kNotPrepared: {
+      return TrackRendererSubmitStatus::kTrackRendererSubmitStatusNotPrepared;
+    }
+    case SubmitStatus::kHold: {
+      return TrackRendererSubmitStatus::kTrackRendererSubmitStatusHold;
+    }
+    case SubmitStatus::kFull: {
+      return TrackRendererSubmitStatus::kTrackRendererSubmitStatusFull;
+    }
+    case SubmitStatus::kSuccess: {
+      return TrackRendererSubmitStatus::kTrackRendererSubmitStatusSuccess;
+    }
+    case SubmitStatus::kDrop: {
+      return TrackRendererSubmitStatus::kTrackRendererSubmitStatusDrop;
+    }
+    default:
+      assert(0 && "unknown submitstatus");
+      return TrackRendererSubmitStatus::kTrackRendererSubmitStatusFailed;
+  }
+}
+
+int trackrenderer_submit_packet(TrackRendererHandle handle,
+                                TrackRendererDecoderInputBuffer* data,
+                                TrackRendererSubmitStatus* retval) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
+      data->index, static_cast<GstBuffer*>(data->buffer));
+#else
+  auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
+      data->index, data->buffer);
+#endif
+
+  SubmitStatus status;
+  if (priv->renderer->SubmitPacket(std::move(inputbuffer), &status) == false) {
+    return kFailed;
+  }
+  if (retval) {
+    *retval = ConvertToTrackRendererSubmitStatus(status);
+  }
+
+  return kSuccess;
+}
+
+int trackrenderer_submit_packet2(TrackRendererHandle handle,
+                                 TrackRendererDecoderInputBuffer* data,
+                                 TrackRendererSubmitStatus* retval) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
+      data->index, static_cast<GstBuffer*>(data->buffer), false);
+#else
+  auto inputbuffer = plusplayer::trackrenderer::DecoderInputBuffer::Create(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackType(data->type),
+      data->index, data->buffer, false);
+#endif
+
+  SubmitStatus status;
+  if (priv->renderer->SubmitPacket(std::move(inputbuffer), &status) == false) {
+    if (retval) {
+      *retval = ConvertToTrackRendererSubmitStatus(status);
+    }
+    return kFailed;
+  }
+  if (retval) {
+    *retval = ConvertToTrackRendererSubmitStatus(status);
+  }
+
+  return kSuccess;
+}
+
+using State = plusplayer::trackrenderer::TrackRenderer::State;
+
+TrackRendererState ConvertToTrackRendererState(State state) {
+  switch (state) {
+    case State::kInit: {
+      return kTrackRendererStateInit;
+    }
+    case State::kWorking: {
+      return kTrackRendererStateWorking;
+    }
+    case State::kResourceConflicted: {
+      return kTrackRendererStateResourceConflicted;
+    }
+    case State::kStopped: {
+      return kTrackRendererStateStopped;
+    }
+    default:
+      assert(0 && "unknown state");
+      return kTrackRendererStateUnknown;
+  }
+}
+
+TrackRendererState trackrenderer_get_state(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kTrackRendererStateUnknown;
+  return ConvertToTrackRendererState(priv->renderer->GetState());
+}
+
+void trackrenderer_set_drm(TrackRendererHandle handle,
+                           TrackRendererDrmProperty* properties) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  plusplayer::trackrenderer::drm::Property drm_property;
+  plusplayer::trackrenderer::capi_utils::MakeDrmProperty(&drm_property,
+                                                         *properties);
+  priv->renderer->SetDrm(drm_property);
+}
+
+void trackrenderer_drm_license_acquired_done(TrackRendererHandle handle,
+                                             TrackRendererTrackType type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->renderer->DrmLicenseAcquiredDone(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type));
+}
+
+int trackrenderer_set_display_mode(TrackRendererHandle handle,
+                                   TrackRendererDisplayMode mode) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetDisplayMode(
+          plusplayer::trackrenderer::capi_utils::ConvertToDisplayMode(mode)) ==
+      false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_display_rotate(TrackRendererHandle handle,
+                                     TrackRendererDisplayRotate rotate) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetDisplayRotate(
+          plusplayer::trackrenderer::capi_utils::ConvertToDisplayRotate(
+              rotate)) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_get_display_rotate(TrackRendererHandle handle,
+                                     TrackRendererDisplayRotate* rotate) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::DisplayRotation display_rotate;
+  priv->renderer->GetDisplayRotate(&display_rotate);
+  *rotate = plusplayer::trackrenderer::capi_utils::
+      ConvertToTrackRendererDisplayRotate(display_rotate);
+  return kSuccess;
+}
+
+int trackrenderer_set_display_surface(TrackRendererHandle handle,
+                                      TrackRendererDisplayType type,
+                                      unsigned int surface_id, long x, long y,
+                                      long w, long h) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetDisplay(
+          plusplayer::trackrenderer::capi_utils::ConvertToDisplayType(type),
+          surface_id, x, y, w, h) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_display(TrackRendererHandle handle,
+                              TrackRendererDisplayType type, void* obj) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetDisplay(
+          plusplayer::trackrenderer::capi_utils::ConvertToDisplayType(type),
+          obj) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_display_ecore_wl2_window(TrackRendererHandle handle,
+                                               TrackRendererDisplayType type,
+                                               void* ecore_wl2_window, int x,
+                                               int y, int w, int h) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetDisplay(
+          plusplayer::trackrenderer::capi_utils::ConvertToDisplayType(type),
+          ecore_wl2_window, x, y, w, h) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_display_ecore_wl2_subsurface(
+    TrackRendererHandle handle, TrackRendererDisplayType type,
+    void* ecore_wl2_subsurface, int x, int y, int w, int h) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (!ecore_wl2_subsurface) return kFailed;
+  if (priv->renderer->SetDisplaySubsurface(
+          plusplayer::trackrenderer::capi_utils::ConvertToDisplayType(type),
+          ecore_wl2_subsurface, x, y, w, h) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_display_roi(TrackRendererHandle handle,
+                                  TrackRendererGeometry* geometry) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::Geometry result;
+  plusplayer::trackrenderer::capi_utils::MakeGeometry(&result, *geometry);
+  if (!priv->renderer->SetDisplayRoi(result)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_video_roi(TrackRendererHandle handle,
+                                TrackRendererCropArea* crop) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::CropArea result;
+  plusplayer::trackrenderer::capi_utils::MakeCropArea(&result, *crop);
+  if (!priv->renderer->SetVideoRoi(result)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_resize_render_rect(TrackRendererHandle handle,
+                                     TrackRendererRenderRect* rect) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::RenderRect result;
+  plusplayer::trackrenderer::capi_utils::MakeRenderRect(&result, *rect);
+  if (!priv->renderer->ResizeRenderRect(result)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+void trackrenderer_get_display(TrackRendererHandle handle,
+                               TrackRendererDisplayType* type,
+                               TrackRendererGeometry* area) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  plusplayer::trackrenderer::Geometry geometry;
+  plusplayer::trackrenderer::DisplayType display_type;
+
+  priv->renderer->GetDisplay(&display_type, &geometry);
+  plusplayer::trackrenderer::capi_utils::MakeTrackRendererGeometry(area,
+                                                                   geometry);
+  *type =
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererDisplayType(
+          display_type);
+}
+
+void trackrenderer_get_display_mode(TrackRendererHandle handle,
+                                    TrackRendererDisplayMode* mode) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+
+  plusplayer::trackrenderer::DisplayMode display_mode;
+  priv->renderer->GetDisplayMode(&display_mode);
+  *mode =
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackRendererDisplayMode(
+          display_mode);
+}
+
+int trackrenderer_set_display_visible(TrackRendererHandle handle,
+                                      bool is_visible) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetDisplayVisible(is_visible) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+void trackrenderer_set_app_id(TrackRendererHandle handle, const char* app_id) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  std::string appid{app_id};
+  priv->renderer->SetAppId(appid);
+}
+
+void trackrenderer_set_app_info(TrackRendererHandle handle,
+                                const TrackRendererAppInfo* app_info) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  plusplayer::trackrenderer::PlayerAppInfo info;
+  plusplayer::trackrenderer::capi_utils::MakePlayerAppInfo(app_info, info);
+  priv->renderer->SetAppInfo(info);
+}
+
+int trackrenderer_set_audio_mute(TrackRendererHandle handle, bool is_mute) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (priv->renderer->SetAudioMute(is_mute) == false) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+void trackrenderer_set_video_still_mode(TrackRendererHandle handle,
+                                        TrackRendererStillMode type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+
+  plusplayer::trackrenderer::StillMode still_mode =
+      plusplayer::trackrenderer::capi_utils::ConvertToStillMode(type);
+  priv->renderer->SetVideoStillMode(still_mode);
+}
+
+void trackrenderer_set_attribute(TrackRendererHandle handle,
+                                 const char* attr_name, ...) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  va_list arg_ptr;
+
+  va_start(arg_ptr, attr_name);
+  const char* attr = attr_name;
+  while (attr != nullptr) {
+    if (plusplayer::trackrenderer::kPluginPropertyInfoTable.count(attr) > 0) {
+      const plusplayer::trackrenderer::TrackRendererAttrInfo& attr_info =
+          plusplayer::trackrenderer::kPluginPropertyInfoTable.at(attr);
+
+      switch (attr_info.value_type) {
+        case plusplayer::trackrenderer::ValueType::kInt32: {
+          std::int32_t value = va_arg(arg_ptr, std::int32_t);
+          priv->renderer->SetAttribute(attr_info.attr_enum, value);
+        } break;
+        case plusplayer::trackrenderer::ValueType::kUInt32: {
+          std::uint32_t value = va_arg(arg_ptr, std::uint32_t);
+          priv->renderer->SetAttribute(attr_info.attr_enum, value);
+        } break;
+        case plusplayer::trackrenderer::ValueType::kInt64: {
+          std::int64_t value = va_arg(arg_ptr, std::int64_t);
+          priv->renderer->SetAttribute(attr_info.attr_enum, value);
+        } break;
+        case plusplayer::trackrenderer::ValueType::kUInt64: {
+          std::uint64_t value = va_arg(arg_ptr, std::uint64_t);
+          priv->renderer->SetAttribute(attr_info.attr_enum, value);
+        } break;
+        default:
+          assert(0 && "Unsupported Value Type");
+          break;
+      }
+    } else if (plusplayer::trackrenderer::kConfigInfoTable.count(attr) > 0) {
+      plusplayer::trackrenderer::ValueType value_type =
+          plusplayer::trackrenderer::kConfigInfoTable.at(attr);
+      switch (value_type) {
+        case plusplayer::trackrenderer::ValueType::kUInt32: {
+          std::uint32_t value = va_arg(arg_ptr, std::uint32_t);
+          priv->renderer->SetConfig(attr, value);
+        } break;
+        case plusplayer::trackrenderer::ValueType::kUInt64: {
+          std::uint64_t value = va_arg(arg_ptr, std::uint64_t);
+          priv->renderer->SetConfig(attr, value);
+        } break;
+        default:
+          assert(0 && "Unsupported Value Type");
+          break;
+      }
+    } else {
+      TRACKRENDERER_ERROR("Unsupported attribute name");
+      break;
+    }
+    attr = va_arg(arg_ptr, const char*);
+  }
+  va_end(arg_ptr);
+  return;
+}
+
+void trackrenderer_get_attribute(TrackRendererHandle handle,
+                                 const char* attr_name, ...) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  va_list arg_ptr;
+
+  va_start(arg_ptr, attr_name);
+  const char* attr = attr_name;
+  while (attr != nullptr) {
+    if (plusplayer::trackrenderer::kPluginPropertyInfoTable.count(attr) == 0) {
+      TRACKRENDERER_ERROR("Unknown Attribute [%s]", attr);
+      break;
+    }
+    const plusplayer::trackrenderer::TrackRendererAttrInfo& attr_info =
+        plusplayer::trackrenderer::kPluginPropertyInfoTable.at(attr);
+
+    switch (attr_info.value_type) {
+      case plusplayer::trackrenderer::ValueType::kInt32: {
+        std::int32_t* value = va_arg(arg_ptr, std::int32_t*);
+        boost::any _value = std::int32_t(0);
+        priv->renderer->GetAttribute(attr_info.attr_enum, &_value);
+        *value = boost::any_cast<std::int32_t>(_value);
+      } break;
+      case plusplayer::trackrenderer::ValueType::kUInt32: {
+        std::uint32_t* value = va_arg(arg_ptr, std::uint32_t*);
+        boost::any _value = std::uint32_t(0);
+        priv->renderer->GetAttribute(attr_info.attr_enum, &_value);
+        *value = boost::any_cast<std::uint32_t>(_value);
+      } break;
+      case plusplayer::trackrenderer::ValueType::kInt64: {
+        std::int64_t* value = va_arg(arg_ptr, std::int64_t*);
+        boost::any _value = std::int64_t(0);
+        priv->renderer->GetAttribute(attr_info.attr_enum, &_value);
+        *value = boost::any_cast<std::int64_t>(_value);
+      } break;
+      case plusplayer::trackrenderer::ValueType::kUInt64: {
+        std::uint64_t* value = va_arg(arg_ptr, std::uint64_t*);
+        boost::any _value = std::uint64_t(0);
+        priv->renderer->GetAttribute(attr_info.attr_enum, &_value);
+        *value = boost::any_cast<std::uint64_t>(_value);
+      } break;
+      default:
+        assert(0 && "Unsupported Value Type");
+        break;
+    }
+    attr = va_arg(arg_ptr, const char*);
+  }
+  va_end(arg_ptr);
+  return;
+}
+
+int trackrenderer_set_matroska_color_info(TrackRendererHandle handle,
+                                          const char* color_info) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (!priv->renderer->SetMatroskaColorInfo(color_info)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_volume(TrackRendererHandle handle, const int volume) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (!priv->renderer->SetVolume(volume)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_get_volume(TrackRendererHandle handle, int* volume) {
+  if (!volume) return kFailed;
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (!priv->renderer->GetVolume(volume)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+void trackrenderer_set_video_frame_buffer_type(
+    TrackRendererHandle handle, TrackRendererDecodedVideoFrameBufferType type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->renderer->SetVideoFrameBufferType(
+      plusplayer::trackrenderer::capi_utils::ConvertToVideoFrameBufferType(
+          type));
+}
+
+void trackrenderer_set_video_frame_buffer_type_ext(
+    TrackRendererHandle handle,
+    TrackRendererDecodedVideoFrameBufferTypeExt type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->renderer->SetVideoFrameBufferType(
+      plusplayer::trackrenderer::capi_utils::ConvertToVideoFrameBufferTypeExt(
+          type));
+}
+
+int trackrenderer_set_video_frame_buffer_scale_resolution(
+    TrackRendererHandle handle, uint32_t target_width, uint32_t target_height) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (!target_width || !target_height) return kFailed;
+  priv->renderer->SetVideoFrameBufferScaleResolution(target_width,
+                                                     target_height);
+  return kSuccess;
+}
+
+int trackrenderer_set_decoded_video_frame_rate(
+    TrackRendererHandle handle, TrackRendererRational request_framerate) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::Rational request_fps;
+  plusplayer::trackrenderer::capi_utils::MakeRational(&request_fps,
+                                                      request_framerate);
+  if (!priv->renderer->SetDecodedVideoFrameRate(request_fps)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_flush(TrackRendererHandle handle,
+                        TrackRendererTrackType type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  priv->renderer->FlushAppsrc(
+      plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type), true);
+  return kSuccess;
+}
+
+int trackrenderer_render_video_frame(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (!priv->renderer->RenderVideoFrame()) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_aifilter(TrackRendererHandle handle, void* aifilter) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  if (!priv->renderer->SetAiFilter(aifilter)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_catch_up_speed(TrackRendererHandle handle,
+                                     const TrackRendererCatchUpSpeed level) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  priv->renderer->SetCatchUpSpeed(
+      plusplayer::trackrenderer::capi_utils::ConvertToCatchUpSpeed(level));
+  return kSuccess;
+}
+
+int trackrenderer_get_video_latency_status(TrackRendererHandle handle,
+                                           TrackRendererLatencyStatus* status) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  plusplayer::trackrenderer::LatencyStatus current =
+      plusplayer::trackrenderer::LatencyStatus::kLow;
+  priv->renderer->GetVideoLatencyStatus(&current);
+  *status = plusplayer::trackrenderer::capi_utils::
+      ConvertToTrackrendererLatencyStatus(current);
+  return kSuccess;
+}
+
+int trackrenderer_get_audio_latency_status(TrackRendererHandle handle,
+                                           TrackRendererLatencyStatus* status) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  plusplayer::trackrenderer::LatencyStatus current =
+      plusplayer::trackrenderer::LatencyStatus::kLow;
+  priv->renderer->GetAudioLatencyStatus(&current);
+  *status = plusplayer::trackrenderer::capi_utils::
+      ConvertToTrackrendererLatencyStatus(current);
+  return kSuccess;
+}
+
+int trackrenderer_set_video_mid_latency_threshold(
+    TrackRendererHandle handle, const unsigned int threshold) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  priv->renderer->SetVideoMidLatencyThreshold(threshold);
+  return kSuccess;
+}
+
+int trackrenderer_set_audio_mid_latency_threshold(
+    TrackRendererHandle handle, const unsigned int threshold) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  priv->renderer->SetAudioMidLatencyThreshold(threshold);
+  return kSuccess;
+}
+
+int trackrenderer_set_video_high_latency_threshold(
+    TrackRendererHandle handle, const unsigned int threshold) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  priv->renderer->SetVideoHighLatencyThreshold(threshold);
+  return kSuccess;
+}
+
+int trackrenderer_set_audio_high_latency_threshold(
+    TrackRendererHandle handle, const unsigned int threshold) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  priv->renderer->SetAudioHighLatencyThreshold(threshold);
+  return kSuccess;
+}
+
+/* CALL back*/
+void trackrenderer_set_error_cb(TrackRendererHandle handle,
+                                trackrenderer_error_cb callback,
+                                void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->error_cb = callback;
+  priv->error_cb_userdata = userdata;
+}
+
+void trackrenderer_set_error_msg_cb(TrackRendererHandle handle,
+                                    trackrenderer_error_msg_cb callback,
+                                    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->error_msg_cb = callback;
+  priv->error_msg_cb_userdata = userdata;
+}
+
+void trackrenderer_set_resourceconflict_cb(
+    TrackRendererHandle handle, trackrenderer_resource_conflicted_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->resourceconflict_cb = callback;
+  priv->resourceconflict_cb_userdata = userdata;
+}
+
+void trackrenderer_set_seekdone_cb(TrackRendererHandle handle,
+                                   trackrenderer_seekdone_cb callback,
+                                   void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->seekdone_cb = callback;
+  priv->seekdone_cb_userdata = userdata;
+}
+
+void trackrenderer_set_flushdone_cb(TrackRendererHandle handle,
+                                    trackrenderer_flushdone_cb callback,
+                                    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->flushdone_cb = callback;
+  priv->flushdone_cb_userdata = userdata;
+}
+
+void trackrenderer_set_eos_cb(TrackRendererHandle handle,
+                              trackrenderer_eos_cb callback, void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->eos_cb = callback;
+  priv->eos_cb_userdata = userdata;
+}
+
+void trackrenderer_set_event_cb(TrackRendererHandle handle,
+                                trackrenderer_event_cb callback,
+                                void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->event_cb = callback;
+  priv->event_cb_userdata = userdata;
+}
+
+void trackrenderer_set_first_decoding_done_cb(
+    TrackRendererHandle handle, trackrenderer_first_decoding_done_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->first_decoding_done_cb = callback;
+  priv->first_decoding_done_cb_userdata = userdata;
+}
+
+void trackrenderer_set_subtitle_rawdata_cb(
+    TrackRendererHandle handle, trackrenderer_subtitle_rawdata_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->subtitle_rawdata_cb = callback;
+  priv->subtitle_rawdata_cb_userdata = userdata;
+}
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+void trackrenderer_set_subtitledata_cb(TrackRendererHandle handle,
+                                       trackrenderer_subtitledata_cb callback,
+                                       void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->subtitledata_cb = callback;
+  priv->subtitledata_cb_userdata = userdata;
+}
+#endif
+
+void trackrenderer_set_closedcaption_cb(TrackRendererHandle handle,
+                                        trackrenderer_closedcaption_cb callback,
+                                        void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->closedcaption_cb = callback;
+  priv->closedcaption_cb_userdata = userdata;
+}
+
+void trackrenderer_set_drminitdata_cb(TrackRendererHandle handle,
+                                      trackrenderer_drminitdata_cb callback,
+                                      void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->drminitdata_cb = callback;
+  priv->drminitdata_cb_userdata = userdata;
+}
+
+void trackrenderer_set_bufferstatus_cb(TrackRendererHandle handle,
+                                       trackrenderer_bufferstatus_cb callback,
+                                       void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->bufferstatus_cb = callback;
+  priv->bufferstatus_cb_userdata = userdata;
+}
+
+void trackrenderer_set_seekdata_cb(TrackRendererHandle handle,
+                                   trackrenderer_seekdata_cb callback,
+                                   void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->seekdata_cb = callback;
+  priv->seekdata_cb_userdata = userdata;
+}
+
+void trackrenderer_set_media_packet_video_tbmptr_cb(
+    TrackRendererHandle handle,
+    trackrenderer_media_packet_video_tbmptr_cb callback, void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->video_tbmptr_cb = callback;
+  priv->video_tbmptr_cb_userdata = userdata;
+}
+
+void trackrenderer_set_media_packet_video_decoded_cb(
+    TrackRendererHandle handle,
+    trackrenderer_media_packet_video_decoded_cb callback, void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->video_decoded_cb = callback;
+  priv->video_decoded_cb_userdata = userdata;
+}
+
+void trackrenderer_set_media_packet_video_raw_decoded_cb(
+    TrackRendererHandle handle,
+    trackrenderer_media_packet_video_raw_decoded_cb callback, void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->video_raw_decoded_cb = callback;
+  priv->video_raw_decoded_cb_userdata = userdata;
+}
+
+void trackrenderer_set_video_decoder_underrun_cb(
+    TrackRendererHandle handle, trackrenderer_decoder_underrun_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->video_decoder_underrun_cb = callback;
+  priv->video_decoder_underrun_cb_userdata = userdata;
+}
+
+int trackrenderer_set_alternative_audio_resource(TrackRendererHandle handle,
+                                                 unsigned int rsc_type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  priv->renderer->SetAlternativeAudioResource(rsc_type);
+  return kSuccess;
+}
+
+void trackrenderer_set_video_latency_status_cb(
+    TrackRendererHandle handle, trackrenderer_video_latency_status_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->video_latency_status_cb = callback;
+  priv->video_latency_status_cb_userdata = userdata;
+}
+
+void trackrenderer_set_audio_latency_status_cb(
+    TrackRendererHandle handle, trackrenderer_audio_latency_status_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->audio_latency_status_cb = callback;
+  priv->audio_latency_status_cb_userdata = userdata;
+}
+
+void trackrenderer_set_video_high_latency_cb(
+    TrackRendererHandle handle, trackrenderer_video_high_latency_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->video_high_latency_cb = callback;
+  priv->video_high_latency_cb_userdata = userdata;
+}
+
+void trackrenderer_set_audio_high_latency_cb(
+    TrackRendererHandle handle, trackrenderer_audio_high_latency_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->audio_high_latency_cb = callback;
+  priv->audio_high_latency_cb_userdata = userdata;
+}
+
+void trackrenderer_set_multiview_start_video_cb(
+    TrackRendererHandle handle, trackrenderer_multiview_start_video_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->multiview_start_video_cb = callback;
+  priv->multiview_start_video_cb_userdata = userdata;
+}
+
+void trackrenderer_set_multiview_stop_video_cb(
+    TrackRendererHandle handle, trackrenderer_multiview_stop_video_cb callback,
+    void* userdata) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return;
+  priv->multiview_stop_video_cb = callback;
+  priv->multiview_stop_video_cb_userdata = userdata;
+}
+
+int trackrenderer_init_audio_easing_info(
+    TrackRendererHandle handle, const uint32_t init_volume,
+    const uint32_t init_elapsed_time,
+    const TrackRendererAudioEasingInfo* easing_info) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  plusplayer::trackrenderer::AudioEasingInfo info;
+  plusplayer::trackrenderer::capi_utils::MakeAudioEasingInfo(&info,
+                                                             easing_info);
+  if (!priv->renderer->InitAudioEasingInfo(init_volume, init_elapsed_time,
+                                           info)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_update_audio_easing_info(
+    TrackRendererHandle handle,
+    const TrackRendererAudioEasingInfo* easing_info) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::AudioEasingInfo info;
+  plusplayer::trackrenderer::capi_utils::MakeAudioEasingInfo(&info,
+                                                             easing_info);
+  if (!priv->renderer->UpdateAudioEasingInfo(info)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_get_audio_easing_info(
+    TrackRendererHandle handle, uint32_t* current_volume,
+    uint32_t* elapsed_time, TrackRendererAudioEasingInfo* easing_info) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::AudioEasingInfo info;
+  if (!priv->renderer->GetAudioEasingInfo(current_volume, elapsed_time,
+                                          &info)) {
+    return kFailed;
+  }
+  plusplayer::trackrenderer::capi_utils::MakeTrackRendererAudioEasingInfo(
+      easing_info, info);
+  return kSuccess;
+}
+
+int trackrenderer_start_audio_easing(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  if (!priv->renderer->StartAudioEasing()) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_stop_audio_easing(TrackRendererHandle handle) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+
+  if (!priv->renderer->StopAudioEasing()) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_get_virtual_rsc_id(TrackRendererHandle handle,
+                                     TrackRendererRscType type,
+                                     int* virtual_id) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::RscType converted_type =
+      plusplayer::trackrenderer::RscType::kVideoRenderer;
+  if (!plusplayer::trackrenderer::capi_utils::ConvertToRscType(type,
+                                                               &converted_type))
+    return kFailed;
+  if (!priv->renderer->GetVirtualRscId(converted_type, virtual_id)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_advanced_picture_quality_type(
+    TrackRendererHandle handle, TrackRendererAdvPictureQualityType type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::AdvPictureQualityType converted_type =
+      plusplayer::trackrenderer::AdvPictureQualityType::kVideoCall;
+  if (!plusplayer::trackrenderer::capi_utils::ConvertToAdvPictureQualityType(
+          type, &converted_type))
+    return kFailed;
+  if (!priv->renderer->SetAdvancedPictureQualityType(converted_type)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_resource_allocate_policy(
+    TrackRendererHandle handle, TrackRendererRscAllocPolicy policy) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::RscAllocPolicy converted_policy =
+      plusplayer::trackrenderer::RscAllocPolicy::kRscAllocExclusive;
+  if (!plusplayer::trackrenderer::capi_utils::ConvertToRscAllocPolicy(
+          policy, &converted_policy))
+    return kFailed;
+  if (!priv->renderer->SetResourceAllocatePolicy(converted_policy)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_video_renderer_type(
+    TrackRendererHandle handle, TrackRendererVideoRendererType renderer_type) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  plusplayer::trackrenderer::ResourceCategory converted_renderer_type;
+  if (!plusplayer::trackrenderer::capi_utils::ConvertToVideoRendererType(
+          renderer_type, &converted_renderer_type))
+    return kFailed;
+  if (!priv->renderer->SetVideoRendererType(converted_renderer_type)) {
+    return kFailed;
+  }
+  return kSuccess;
+}
+
+int trackrenderer_set_video_par_dar(TrackRendererHandle handle,
+                                    uint64_t time_millisecond, uint32_t par_num,
+                                    uint32_t par_den, uint32_t dar_num,
+                                    uint32_t dar_den) {
+  auto priv = static_cast<TrackRendererPrivPtr>(handle);
+  if (!priv) return kFailed;
+  priv->renderer->SetVideoParDar(time_millisecond, par_num, par_den, dar_num,
+                                 dar_den);
+  return kSuccess;
+}
diff --git a/src/trackrenderer_capi_utils.cpp b/src/trackrenderer_capi_utils.cpp
new file mode 100755 (executable)
index 0000000..5a225a3
--- /dev/null
@@ -0,0 +1,923 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/trackrenderer_capi_utils.h"
+
+#include "trackrenderer/core/track_util.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace capi_utils {
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+TrackRendererSubtitleAttr InitSubtitleAttr() {
+  TrackRendererSubtitleAttr subtitle_attr{
+      .type = kTrackRendererSubtitleAttrTypeTypeNone,
+      .start_time = std::numeric_limits<uint32_t>::max(),
+      .stop_time = std::numeric_limits<uint32_t>::max(),
+      {.f = 0},
+      .extsub_index = -1};
+
+  return subtitle_attr;
+}
+#endif
+
+void MakeDrmProperty(drm::Property* drm_property,
+                     const TrackRendererDrmProperty& properties) {
+  drm_property->type = ConvertToDrmType(properties.type);
+  drm_property->handle = properties.handle;
+  drm_property->external_decryption = properties.external_decryption;
+  drm_property->license_acquired_cb = properties.license_acquired_cb;
+  drm_property->license_acquired_userdata =
+      properties.license_acquired_userdata;
+}
+
+void MakeGeometry(Geometry* output, const TrackRendererGeometry& input) {
+  output->x = input.x;
+  output->y = input.y;
+  output->w = input.w;
+  output->h = input.h;
+}
+
+void MakeCropArea(CropArea* output, const TrackRendererCropArea& input) {
+  output->scale_x = input.scale_x;
+  output->scale_y = input.scale_y;
+  output->scale_w = input.scale_w;
+  output->scale_h = input.scale_h;
+}
+
+void MakeRenderRect(RenderRect* output, const TrackRendererRenderRect& input) {
+  output->x = input.x;
+  output->y = input.y;
+  output->w = input.w;
+  output->h = input.h;
+}
+
+std::map<std::string, bool> MakeIniProperty(
+    TrackRendererIniProperty* properties, int size) {
+  std::map<std::string, bool> iniproperty;
+  for (int index = 0; index < size; index++) {
+    iniproperty.insert(std::pair<std::string, bool>(properties[index].key,
+                                                    properties[index].value));
+  }
+  return iniproperty;
+}
+
+std::vector<Track> MakeTrack(const TrackRendererTrack* trackrenderertrack,
+                             const int size) {
+  std::vector<Track> trackvector;
+  for (int index = 0; index < size; index++) {
+    Track track;
+    track.index = trackrenderertrack[index].index;
+    track.id = trackrenderertrack[index].id;
+    track.mimetype = trackrenderertrack[index].mimetype
+                         ? trackrenderertrack[index].mimetype
+                         : "";
+    track.streamtype = trackrenderertrack[index].streamtype
+                           ? trackrenderertrack[index].streamtype
+                           : "";
+    track.type = ConvertToTrackType(trackrenderertrack[index].type);
+    if (track_util::IsValidCodecDataSize(
+            trackrenderertrack[index].codec_data_len)) {
+      track.codec_data = std::shared_ptr<char>(
+          new char[trackrenderertrack[index].codec_data_len],
+          std::default_delete<char[]>());
+      memcpy(track.codec_data.get(), trackrenderertrack[index].codec_data,
+             trackrenderertrack[index].codec_data_len);
+      track.codec_data_len = trackrenderertrack[index].codec_data_len;
+    }
+    track.width = trackrenderertrack[index].width;
+    track.height = trackrenderertrack[index].height;
+    track.maxwidth = trackrenderertrack[index].maxwidth;
+    track.maxheight = trackrenderertrack[index].maxheight;
+    track.framerate_num = trackrenderertrack[index].framerate_num;
+    track.framerate_den = trackrenderertrack[index].framerate_den;
+    track.sample_rate = trackrenderertrack[index].sample_rate;
+    track.sample_format = trackrenderertrack[index].sample_format;
+    track.channels = trackrenderertrack[index].channels;
+    track.version = trackrenderertrack[index].version;
+    track.layer = trackrenderertrack[index].layer;
+    track.bits_per_sample = trackrenderertrack[index].bits_per_sample;
+    track.block_align = trackrenderertrack[index].block_align;
+    track.bitrate = trackrenderertrack[index].bitrate;
+    track.endianness = trackrenderertrack[index].endianness;
+    track.is_signed = trackrenderertrack[index].is_signed;
+    track.active = trackrenderertrack[index].active;
+    track.use_swdecoder = trackrenderertrack[index].use_swdecoder;
+    track.language_code = trackrenderertrack[index].language_code
+                              ? trackrenderertrack[index].language_code
+                              : "";
+    track.subtitle_format = trackrenderertrack[index].subtitle_format
+                                ? trackrenderertrack[index].subtitle_format
+                                : "";
+    trackvector.push_back(std::move(track));
+  }
+  return trackvector;
+}
+
+std::vector<Track> MakeTrackFromTrackHandle(
+    const TrackRendererTrackHandle* track_handle, const int size) {
+  std::vector<Track> trackvector;
+  for (int index = 0; index < size; index++) {
+    trackvector.push_back(*static_cast<Track*>(track_handle[index]));
+  }
+  return trackvector;
+}
+
+void MakeTrackRendererGeometry(TrackRendererGeometry* geometry,
+                               const Geometry& roi) {
+  geometry->x = roi.x;
+  geometry->y = roi.y;
+  geometry->w = roi.w;
+  geometry->h = roi.h;
+}
+
+// LCOV_EXCL_START
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+void MakeTrackRendererSubtitleAttr(TrackRendererSubtitleAttr* attr,
+                                   const SubtitleAttr& input_attr) {
+  attr->type = ConvertToTrackRendererSubtitleAttrType(input_attr.type);
+  attr->start_time = input_attr.start_time;
+  attr->stop_time = input_attr.stop_time;
+  attr->extsub_index = input_attr.extsub_index;
+
+  switch (input_attr.type) {
+    case kSubAttrRegionXPos:         // fall through
+    case kSubAttrRegionYPos:         // fall through
+    case kSubAttrRegionWidth:        // fall through
+    case kSubAttrRegionHeight:       // fall through
+    case kSubAttrWindowXPadding:     // fall through
+    case kSubAttrWindowYPadding:     // fall through
+    case kSubAttrWindowOpacity:      // fall through
+    case kSubAttrWindowShowBg:       // fall through
+    case kSubAttrFontSize:           // fall through
+    case kSubAttrFontOpacity:        // fall through
+    case kSubAttrFontBgOpacity:      // fall through
+    case kSubAttrWebvttCueLine:      // fall through
+    case kSubAttrWebvttCueSize:      // fall through
+    case kSubAttrWebvttCuePosition:  // fall through
+    case kSubAttrWebvttCueVertical: {
+      const float* value = boost::any_cast<float>(&input_attr.value);
+      if (value) attr->value.f = *value;
+      break;
+    }
+    case kSubAttrWindowLeftMargin:           // fall through
+    case kSubAttrWindowRightMargin:          // fall through
+    case kSubAttrWindowTopMargin:            // fall through
+    case kSubAttrWindowBottomMargin:         // fall through
+    case kSubAttrWindowBgColor:              // fall through
+    case kSubAttrFontWeight:                 // fall through
+    case kSubAttrFontStyle:                  // fall through
+    case kSubAttrFontColor:                  // fall through
+    case kSubAttrFontBgColor:                // fall through
+    case kSubAttrFontTextOutlineColor:       // fall through
+    case kSubAttrFontTextOutlineThickness:   // fall through
+    case kSubAttrFontTextOutlineBlurRadius:  // fall through
+    case kSubAttrFontVerticalAlign:          // fall through
+    case kSubAttrFontHorizontalAlign:        // fall through
+    case kSubAttrWebvttCueLineNum:           // fall through
+    case kSubAttrWebvttCueLineAlign:         // fall through
+    case kSubAttrWebvttCueAlign:             // fall through
+    case kSubAttrWebvttCuePositionAlign: {
+      const int32_t* value = boost::any_cast<int32_t>(&input_attr.value);
+      if (value) attr->value.i32 = *value;
+      break;
+    }
+    case kSubAttrFontFamily:  // fall through
+    case kSubAttrRawSubtitle: {
+      const std::string* value =
+          boost::any_cast<std::string>(&input_attr.value);
+      if (!value->empty()) attr->value.str = (*value).c_str();
+      break;
+    }
+    case kSubAttrTimestamp:
+    case kSubAttrExtsubIndex:
+      break;
+    default:
+      TRACKRENDERER_ERROR("Unknown subtitle attr type");
+  }
+}
+#endif
+// LCOV_EXCL_STOP
+
+void MakePlayerAppInfo(const TrackRendererAppInfo* app_attr,
+                       PlayerAppInfo& app_info) {
+  if (app_attr->id) app_info.id = app_attr->id;
+  if (app_attr->version) app_info.version = app_attr->version;
+  if (app_attr->type) app_info.type = app_attr->type;
+}
+
+DisplayMode ConvertToDisplayMode(TrackRendererDisplayMode typevalue) {
+  switch (typevalue) {
+    case kTrackRendererDisplayModeLetterBox: {
+      return DisplayMode::kLetterBox;
+    }
+    case kTrackRendererDisplayModeOriginSize: {
+      return DisplayMode::kOriginSize;
+    }
+    case kTrackRendererDisplayModeFullScreen: {
+      return DisplayMode::kFullScreen;
+    }
+    case kTrackRendererDisplayModeCroppedFull: {
+      return DisplayMode::kCroppedFull;
+    }
+    case kTrackRendererDisplayModeOriginOrLetter: {
+      return DisplayMode::kOriginOrLetter;
+    }
+    case kTrackRendererDisplayModeDstRoi: {
+      return DisplayMode::kDstRoi;
+    }
+    case kTrackRendererDisplayModeAutoAspectRatio: {
+      return DisplayMode::kAutoAspectRatio;
+    }
+    case kTrackRendererDisplayModeDisplayMax: {
+      return DisplayMode::kMax;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown DisplayMode");
+      return DisplayMode::kFullScreen;
+  }
+}
+
+DisplayRotation ConvertToDisplayRotate(TrackRendererDisplayRotate rotate) {
+  switch (rotate) {
+    case kTrackRendererDisplayRotateNone: {
+      return DisplayRotation::kNone;
+    }
+    case kTrackRendererDisplayRotate90: {
+      return DisplayRotation::kRotate90;
+    }
+    case kTrackRendererDisplayRotate180: {
+      return DisplayRotation::kRotate180;
+    }
+    case kTrackRendererDisplayRotate270: {
+      return DisplayRotation::kRotate270;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown DisplayRotation");
+      return DisplayRotation::kNone;
+  }
+}
+
+DisplayType ConvertToDisplayType(const TrackRendererDisplayType typevalue) {
+  switch (typevalue) {
+    case kTrackRendererDisplayTypeNone: {
+      return DisplayType::kNone;
+    }
+    case kTrackRendererDisplayTypeOverlay: {
+      return DisplayType::kOverlay;
+    }
+    case kTrackRendererDisplayTypeEvas: {
+      return DisplayType::kEvas;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown DisplayType");
+      return DisplayType::kNone;
+  }
+}
+
+drm::Type ConvertToDrmType(TrackRendererDrmType typevalue) {
+  switch (typevalue) {
+    case kTrackRendererDrmTypeNone: {
+      return drm::Type::kNone;
+    }
+    case kTrackRendererDrmTypePlayready: {
+      return drm::Type::kPlayready;
+    }
+    case kTrackRendererDrmTypeMarlin: {
+      return drm::Type::kMarlin;
+    }
+    case kTrackRendererDrmTypeVerimatrix: {
+      return drm::Type::kVerimatrix;
+    }
+    case kTrackRendererDrmTypeWidevineClassic: {
+      return drm::Type::kWidevineClassic;
+    }
+    case kTrackRendererDrmTypeSecuremedia: {
+      return drm::Type::kSecuremedia;
+    }
+    case kTrackRendererDrmTypeSdrm: {
+      return drm::Type::kSdrm;
+    }
+    case kTrackRendererDrmTypeWidevineCdm: {
+      return drm::Type::kWidevineCdm;
+    }
+    case kTrackRendererDrmTypeDrmMax: {
+      return drm::Type::kMax;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown drm type");
+      return drm::Type::kNone;
+  }
+}
+
+StillMode ConvertToStillMode(TrackRendererStillMode typevalue) {
+  switch (typevalue) {
+    case kTrackRendererStillModeNone: {
+      return StillMode::kNone;
+    }
+    case kTrackRendererStillModeOff: {
+      return StillMode::kOff;
+    }
+    case kTrackRendererStillModeOn: {
+      return StillMode::kOn;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown StillMode");
+      return StillMode::kNone;
+  }
+}
+
+TrackType ConvertToTrackType(TrackRendererTrackType typevalue) {
+  switch (typevalue) {
+    case kTrackRendererTrackTypeAudio: {
+      return TrackType::kTrackTypeAudio;
+    }
+    case kTrackRendererTrackTypeVideo: {
+      return TrackType::kTrackTypeVideo;
+    }
+    case kTrackRendererTrackTypeSubtitle: {
+      return TrackType::kTrackTypeSubtitle;
+    }
+    case kTrackRendererTrackTypeMax: {
+      return TrackType::kTrackTypeMax;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown tracktype");
+      return TrackType::kTrackTypeMax;
+  }
+}
+
+TrackRendererDisplayMode ConvertToTrackRendererDisplayMode(
+    const DisplayMode& mode) {
+  switch (mode) {
+    case DisplayMode::kLetterBox: {
+      return kTrackRendererDisplayModeLetterBox;
+    }
+    case DisplayMode::kOriginSize: {
+      return kTrackRendererDisplayModeOriginSize;
+    }
+    case DisplayMode::kFullScreen: {
+      return kTrackRendererDisplayModeFullScreen;
+    }
+    case DisplayMode::kCroppedFull: {
+      return kTrackRendererDisplayModeCroppedFull;
+    }
+    case DisplayMode::kOriginOrLetter: {
+      return kTrackRendererDisplayModeOriginOrLetter;
+    }
+    case DisplayMode::kDstRoi: {
+      return kTrackRendererDisplayModeDstRoi;
+    }
+    case DisplayMode::kAutoAspectRatio: {
+      return kTrackRendererDisplayModeAutoAspectRatio;
+    }
+    case DisplayMode::kMax: {
+      return kTrackRendererDisplayModeDisplayMax;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown displaymode");
+      return kTrackRendererDisplayModeFullScreen;
+  }
+}
+
+TrackRendererDisplayRotate ConvertToTrackRendererDisplayRotate(
+    const DisplayRotation& rotate) {
+  switch (rotate) {
+    case DisplayRotation::kNone: {
+      return kTrackRendererDisplayRotateNone;
+    }
+    case DisplayRotation::kRotate90: {
+      return kTrackRendererDisplayRotate90;
+    }
+    case DisplayRotation::kRotate180: {
+      return kTrackRendererDisplayRotate180;
+    }
+    case DisplayRotation::kRotate270: {
+      return kTrackRendererDisplayRotate270;
+    }
+    default:
+      return kTrackRendererDisplayRotateNone;
+  }
+}
+TrackRendererDisplayType ConvertToTrackRendererDisplayType(
+    const DisplayType& type) {
+  switch (type) {
+    case DisplayType::kNone: {
+      return kTrackRendererDisplayTypeNone;
+    }
+    case DisplayType::kOverlay: {
+      return kTrackRendererDisplayTypeOverlay;
+    }
+    case DisplayType::kEvas: {
+      return kTrackRendererDisplayTypeEvas;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown displaytype");
+      return kTrackRendererDisplayTypeNone;
+  }
+}
+
+// LCOV_EXCL_START
+TrackRendererErrorType ConvertToTrackRendererErrorType(ErrorType type) {
+  switch (type) {
+    case ErrorType::kNone: {
+      return kTrackRendererErrorTypeErrorNone;
+    }
+    case ErrorType::kOutOfMemory: {
+      return kTrackRendererErrorTypeOutOfMemory;
+    }
+    case ErrorType::kInvalidParameter: {
+      return kTrackRendererErrorTypeInvalidParameter;
+    }
+    case ErrorType::kNoSuchFile: {
+      return kTrackRendererErrorTypeNoSuchFile;
+    }
+    case ErrorType::kInvalidOperation: {
+      return kTrackRendererErrorTypeInvalidOperation;
+    }
+    case ErrorType::kFileNoSpaceOnDevice: {
+      return kTrackRendererErrorTypeFileNoSpaceOnDevice;
+    }
+    case ErrorType::kFeatureNotSupportedOnDevice: {
+      return kTrackRendererErrorTypeFeatureNotSupportedOnDevice;
+    }
+    case ErrorType::kSeekFailed: {
+      return kTrackRendererErrorTypeSeekFailed;
+    }
+    case ErrorType::kInvalidState: {
+      return kTrackRendererErrorTypeInvalidState;
+    }
+    case ErrorType::kNotSupportedFile: {
+      return kTrackRendererErrorTypeNotSupportedFile;
+    }
+    case ErrorType::kInvalidUri: {
+      return kTrackRendererErrorTypeInvalidUri;
+    }
+    case ErrorType::kSoundPolicy: {
+      return kTrackRendererErrorTypeSoundPolicy;
+    }
+    case ErrorType::kConnectionFailed: {
+      return kTrackRendererErrorTypeConnectionFailed;
+    }
+    case ErrorType::kVideoCaptureFailed: {
+      return kTrackRendererErrorTypeVideoCaptureFailed;
+    }
+    case ErrorType::kDrmExpired: {
+      return kTrackRendererErrorTypeDrmExpired;
+    }
+    case ErrorType::kDrmNoLicense: {
+      return kTrackRendererErrorTypeDrmNoLicense;
+    }
+    case ErrorType::kDrmFutureUse: {
+      return kTrackRendererErrorTypeDrmFutureUse;
+    }
+    case ErrorType::kDrmNotPermitted: {
+      return kTrackRendererErrorTypeDrmNotPermitted;
+    }
+    case ErrorType::kResourceLimit: {
+      return kTrackRendererErrorTypeResourceLimit;
+    }
+    case ErrorType::kPermissionDenied: {
+      return kTrackRendererErrorTypePermissionDenied;
+    }
+    case ErrorType::kServiceDisconnected: {
+      return kTrackRendererErrorTypeServiceDisconnected;
+    }
+    case ErrorType::kBufferSpace: {
+      return kTrackRendererErrorTypeBufferSpace;
+    }
+    case ErrorType::kNotSupportedAudioCodec: {
+      return kTrackRendererErrorTypeNotSupportedAudioCodec;
+    }
+    case ErrorType::kNotSupportedVideoCodec: {
+      return kTrackRendererErrorTypeNotSupportedVideoCodec;
+    }
+    case ErrorType::kNotSupportedSubtitle: {
+      return kTrackRendererErrorTypeNotSupportedSubtitle;
+    }
+    case ErrorType::kDrmInfo: {
+      return kTrackRendererErrorTypeDrmInfo;
+    }
+    case ErrorType::kNotSupportedFormat: {
+      return kTrackRendererErrorTypeNotSupportedFormat;
+    }
+    case ErrorType::kStreamingPlayer: {
+      return kTrackRendererErrorTypeStreamingPlayer;
+    }
+    case ErrorType::kDtcpFsk: {
+      return kTrackRendererErrorTypeDtcpFsk;
+    }
+    case ErrorType::kPreLoadingTimeOut: {
+      return kTrackRendererErrorTypePreLoadingTimeOut;
+    }
+    case ErrorType::kNetworkError: {
+      return kTrackRendererErrorTypeNetworkError;
+    }
+    case ErrorType::kChannelSurfingFailed: {
+      return kTrackRendererErrorTypeChannelSurfingFailed;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown error type");
+      return kTrackRendererErrorTypeUnknown;
+  }
+}
+
+TrackRendererEventType ConvertToTrackRendererEventType(const EventType& event) {
+  switch (event) {
+    case EventType::kNone: {
+      return kTrackRendererEventTypeNone;
+    }
+    case EventType::kResolutionChanged: {
+      return kTrackRendererEventTypeResolutionChanged;
+    }
+    default:
+      return kTrackRendererEventTypeNone;
+  }
+}
+// LCOV_EXCL_STOP
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+TrackRendererSubtitleAttrType ConvertToTrackRendererSubtitleAttrType(
+    const SubtitleAttrType& type) {
+  switch (type) {
+    case SubtitleAttrType::kSubAttrRegionXPos: {
+      return kTrackRendererSubtitleAttrTypeRegionXPos;
+    }
+    case SubtitleAttrType::kSubAttrRegionYPos: {
+      return kTrackRendererSubtitleAttrTypeRegionYPos;
+    }
+    case SubtitleAttrType::kSubAttrRegionWidth: {
+      return kTrackRendererSubtitleAttrTypeRegionWidth;
+    }
+    case SubtitleAttrType::kSubAttrRegionHeight: {
+      return kTrackRendererSubtitleAttrTypeRegionHeight;
+    }
+    case SubtitleAttrType::kSubAttrWindowXPadding: {
+      return kTrackRendererSubtitleAttrTypeWindowXPadding;
+    }
+    case SubtitleAttrType::kSubAttrWindowYPadding: {
+      return kTrackRendererSubtitleAttrTypeWindowYPadding;
+    }
+    case SubtitleAttrType::kSubAttrWindowLeftMargin: {
+      return kTrackRendererSubtitleAttrTypeWindowLeftMargin;
+    }
+    case SubtitleAttrType::kSubAttrWindowRightMargin: {
+      return kTrackRendererSubtitleAttrTypeWindowRightMargin;
+    }
+    case SubtitleAttrType::kSubAttrWindowTopMargin: {
+      return kTrackRendererSubtitleAttrTypeWindowTopMargin;
+    }
+    case SubtitleAttrType::kSubAttrWindowBottomMargin: {
+      return kTrackRendererSubtitleAttrTypeWindowBottomMargin;
+    }
+    case SubtitleAttrType::kSubAttrWindowBgColor: {
+      return kTrackRendererSubtitleAttrTypeWindowBgColor;
+    }
+    case SubtitleAttrType::kSubAttrWindowOpacity: {
+      return kTrackRendererSubtitleAttrTypeWindowOpacity;
+    }
+    case SubtitleAttrType::kSubAttrWindowShowBg: {
+      return kTrackRendererSubtitleAttrTypeWindowShowBg;
+    }
+    case SubtitleAttrType::kSubAttrFontFamily: {
+      return kTrackRendererSubtitleAttrTypeFontFamily;
+    }
+    case SubtitleAttrType::kSubAttrFontSize: {
+      return kTrackRendererSubtitleAttrTypeFontSize;
+    }
+    case SubtitleAttrType::kSubAttrFontWeight: {
+      return kTrackRendererSubtitleAttrTypeFontWeight;
+    }
+    case SubtitleAttrType::kSubAttrFontStyle: {
+      return kTrackRendererSubtitleAttrTypeFontStyle;
+    }
+    case SubtitleAttrType::kSubAttrFontColor: {
+      return kTrackRendererSubtitleAttrTypeFontColor;
+    }
+    case SubtitleAttrType::kSubAttrFontBgColor: {
+      return kTrackRendererSubtitleAttrTypeFontBgColor;
+    }
+    case SubtitleAttrType::kSubAttrFontOpacity: {
+      return kTrackRendererSubtitleAttrTypeFontOpacity;
+    }
+    case SubtitleAttrType::kSubAttrFontBgOpacity: {
+      return kTrackRendererSubtitleAttrTypeFontBgOpacity;
+    }
+    case SubtitleAttrType::kSubAttrFontTextOutlineColor: {
+      return kTrackRendererSubtitleAttrTypeFontTextOutlineColor;
+    }
+    case SubtitleAttrType::kSubAttrFontTextOutlineThickness: {
+      return kTrackRendererSubtitleAttrTypeFontTextOutlineThickness;
+    }
+    case SubtitleAttrType::kSubAttrFontTextOutlineBlurRadius: {
+      return kTrackRendererSubtitleAttrTypeFontTextOutlineBlurRadius;
+    }
+    case SubtitleAttrType::kSubAttrFontVerticalAlign: {
+      return kTrackRendererSubtitleAttrTypeFontVerticalAlign;
+    }
+    case SubtitleAttrType::kSubAttrFontHorizontalAlign: {
+      return kTrackRendererSubtitleAttrTypeFontHorizontalAlign;
+    }
+    case SubtitleAttrType::kSubAttrRawSubtitle: {
+      return kTrackRendererSubtitleAttrTypeRawSubtitle;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCueLine: {
+      return kTrackRendererSubtitleAttrTypeWebvttCueLine;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCueLineNum: {
+      return kTrackRendererSubtitleAttrTypeWebvttCueLineNum;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCueLineAlign: {
+      return kTrackRendererSubtitleAttrTypeWebvttCueLineAlign;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCueAlign: {
+      return kTrackRendererSubtitleAttrTypeWebvttCueAlign;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCueSize: {
+      return kTrackRendererSubtitleAttrTypeWebvttCueSize;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCuePosition: {
+      return kTrackRendererSubtitleAttrTypeWebvttCuePosition;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCuePositionAlign: {
+      return kTrackRendererSubtitleAttrTypeWebvttCuePositionAlign;
+    }
+    case SubtitleAttrType::kSubAttrWebvttCueVertical: {
+      return kTrackRendererSubtitleAttrTypeWebvttCueVertical;
+    }
+    case SubtitleAttrType::kSubAttrTimestamp: {
+      return kTrackRendererSubtitleAttrTypeTimestamp;
+    }
+    case SubtitleAttrType::kSubAttrExtsubIndex: {
+      return kTrackRendererSubtitleAttrTypeExtsubIndex;
+    }
+    case SubtitleAttrType::kSubAttrTypeNone: {
+      return kTrackRendererSubtitleAttrTypeTypeNone;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown subtitle attr type");
+      return kTrackRendererSubtitleAttrTypeTypeNone;
+  }
+}
+#endif
+
+TrackRendererSubtitleType ConvertToTrackRendererSubtitleType(
+    SubtitleType typevalue) {
+  switch (typevalue) {
+    case SubtitleType::kText: {
+      return kTrackRendererSubtitleTypeText;
+    }
+    case SubtitleType::kPicture: {
+      return kTrackRendererSubtitleTypePicture;
+    }
+    case SubtitleType::kInvalid: {
+      return kTrackRendererSubtitleTypeInvalid;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown subtitle type");
+      return kTrackRendererSubtitleTypeInvalid;
+  }
+}
+
+TrackRendererTrackType ConvertToTrackRendererTrackType(const TrackType& type) {
+  switch (type) {
+    case TrackType::kTrackTypeAudio: {
+      return kTrackRendererTrackTypeAudio;
+    }
+    case TrackType::kTrackTypeVideo: {
+      return kTrackRendererTrackTypeVideo;
+    }
+    case TrackType::kTrackTypeSubtitle: {
+      return kTrackRendererTrackTypeSubtitle;
+    }
+    case TrackType::kTrackTypeMax: {
+      return kTrackRendererTrackTypeMax;
+    }
+    default:
+      TRACKRENDERER_ERROR("unknown tracktype");
+      return kTrackRendererTrackTypeMax;
+  }
+}
+
+TrackRendererBufferStatus ConvertToTrackRendererBufferStatus(
+    const BufferStatus& status) {
+  switch (status) {
+    case BufferStatus::kUnderrun: {
+      return kTrackRendererBufferStatusUnderrun;
+    }
+    case BufferStatus::kOverrun: {
+      return kTrackRendererBufferStatusOverrun;
+    }
+  }
+  TRACKRENDERER_ERROR("Unknown buffern status");
+  return kTrackRendererBufferStatusUnderrun;
+}
+TrackRendererDecodedVideoPacket ConvertToDecodedVideoPacket(
+    const DecodedVideoPacket& packet) {
+  TrackRendererDecodedVideoPacket _packet;
+  _packet.pts = packet.pts;
+  _packet.duration = packet.duration;
+  _packet.surface_data = static_cast<void*>(packet.surface_data);
+  _packet.scaler_index = packet.scaler_index;
+  return _packet;
+}
+DecodedVideoFrameBufferType ConvertToVideoFrameBufferType(
+    const TrackRendererDecodedVideoFrameBufferType& type) {
+  switch (type) {
+    case kTrackRendererDecodedVideoFrameBufferCopy: {
+      return DecodedVideoFrameBufferType::kCopy;
+    }
+    case kTrackRendererDecodedVideoFrameBufferReference: {
+      return DecodedVideoFrameBufferType::kReference;
+    }
+    case kTrackRendererDecodedVideoFrameBufferScale: {
+      return DecodedVideoFrameBufferType::kScale;
+    }
+    case kTrackRendererDecodedVideoFrameBufferNone: {
+      return DecodedVideoFrameBufferType::kNone;
+    }
+    default:
+      TRACKRENDERER_ERROR("wrong buffer type");
+      return DecodedVideoFrameBufferType::kNone;
+  }
+}
+DecodedVideoFrameBufferType ConvertToVideoFrameBufferTypeExt(
+    const TrackRendererDecodedVideoFrameBufferTypeExt& type) {
+  switch (type) {
+    case kTrackRendererDecodedVideoFrameBufferExtNone: {
+      return DecodedVideoFrameBufferType::kNone;
+    }
+    case kTrackRendererDecodedVideoFrameBufferExtRaw: {
+      return DecodedVideoFrameBufferType::kRaw;
+    }
+    default:
+      TRACKRENDERER_ERROR("wrong buffer type");
+      return DecodedVideoFrameBufferType::kNone;
+  }
+}
+
+CatchUpSpeed ConvertToCatchUpSpeed(const TrackRendererCatchUpSpeed& level) {
+  switch (level) {
+    case kTrackRendererCatchUpSpeedNone: {
+      return CatchUpSpeed::kNone;
+    }
+    case kTrackRendererCatchUpSpeedSlow: {
+      return CatchUpSpeed::kSlow;
+    }
+    case kTrackRendererCatchUpSpeedNormal: {
+      return CatchUpSpeed::kMid;
+    }
+    case kTrackRendererCatchUpSpeedFast: {
+      return CatchUpSpeed::kFast;
+    }
+  }
+  TRACKRENDERER_ERROR("Unknown catch up speed");
+  return CatchUpSpeed::kNone;
+}
+
+TrackRendererLatencyStatus ConvertToTrackrendererLatencyStatus(
+    const LatencyStatus& status) {
+  switch (status) {
+    case LatencyStatus::kLow: {
+      return kTrackRendererLatencyStatusLow;
+    }
+    case LatencyStatus::kMid: {
+      return kTrackRendererLatencyStatusMid;
+    }
+    case LatencyStatus::kHigh: {
+      return kTrackRendererLatencyStatusHigh;
+    }
+    default:
+      TRACKRENDERER_ERROR("Unknown latency status");
+      return kTrackRendererLatencyStatusLow;
+  }
+}
+
+AudioEasingType ConvertToAudioEasingType(
+    const TrackRendererAudioEasingType& type) {
+  switch (type) {
+    case kTrackRendererAudioEasingLinear: {
+      return AudioEasingType::kAudioEasingLinear;
+    }
+    case kTrackRendererAudioEasingIncubic: {
+      return AudioEasingType::kAudioEasingIncubic;
+    }
+    case kTrackRendererAudioEasingOutcubic: {
+      return AudioEasingType::kAudioEasingOutcubic;
+    }
+    default:
+      TRACKRENDERER_ERROR("wrong audio easing type");
+      return AudioEasingType::kAudioEasingNone;
+  }
+}
+
+TrackRendererAudioEasingType ConvertToTrackRendererAudioEasingType(
+    const AudioEasingType& type) {
+  switch (type) {
+    case AudioEasingType::kAudioEasingLinear: {
+      return kTrackRendererAudioEasingLinear;
+    }
+    case AudioEasingType::kAudioEasingIncubic: {
+      return kTrackRendererAudioEasingIncubic;
+    }
+    case AudioEasingType::kAudioEasingOutcubic: {
+      return kTrackRendererAudioEasingOutcubic;
+    }
+    default:
+      TRACKRENDERER_ERROR("wrong audio easing type");
+      return kTrackRendererAudioEasingNone;
+  }
+}
+
+void MakeAudioEasingInfo(AudioEasingInfo* easing_info,
+                         const TrackRendererAudioEasingInfo* easing_attr) {
+  easing_info->target_volume = easing_attr->target_volume;
+  easing_info->duration = easing_attr->duration;
+  easing_info->type = ConvertToAudioEasingType(easing_attr->type);
+}
+
+void MakeTrackRendererAudioEasingInfo(TrackRendererAudioEasingInfo* easing_attr,
+                                      const AudioEasingInfo& easing_info) {
+  easing_attr->target_volume = easing_info.target_volume;
+  easing_attr->duration = easing_info.duration;
+  easing_attr->type = ConvertToTrackRendererAudioEasingType(easing_info.type);
+}
+
+bool ConvertToRscType(const TrackRendererRscType& typevalue, RscType* type) {
+  switch (typevalue) {
+    case kTrackRendererRscTypeVideoRenderer:
+      *type = RscType::kVideoRenderer;
+      return true;
+    default:
+      TRACKRENDERER_ERROR("unknown resource type");
+      return false;
+  }
+}
+
+bool ConvertToAdvPictureQualityType(
+    const TrackRendererAdvPictureQualityType& typevalue,
+    AdvPictureQualityType* type) {
+  switch (typevalue) {
+    case kTrackRendererAdvPictureQualityTypeVideoCall:
+      *type = AdvPictureQualityType::kVideoCall;
+      return true;
+    case kTrackRendererAdvPictureQualityTypeUsbCamera:
+      *type = AdvPictureQualityType::kUsbCamera;
+      return true;
+    default:
+      TRACKRENDERER_ERROR("unknown resource type");
+      return false;
+  }
+}
+
+bool ConvertToRscAllocPolicy(const TrackRendererRscAllocPolicy& policyvalue,
+                             RscAllocPolicy* policy) {
+  switch (policyvalue) {
+    case kTrackRendererRscAllocExclusive:
+      *policy = RscAllocPolicy::kRscAllocExclusive;
+      return true;
+    case kTrackRendererRscAllocConditional:
+      *policy = RscAllocPolicy::kRscAllocConditional;
+      return true;
+    default:
+      TRACKRENDERER_ERROR("unknown policy");
+      return false;
+  }
+}
+
+void MakeRational(Rational* rational_info,
+                  const TrackRendererRational& rational_attr) {
+  if (!rational_info) return;
+  rational_info->num = rational_attr.num;
+  rational_info->den = rational_attr.den;
+}
+
+bool ConvertToVideoRendererType(
+    const TrackRendererVideoRendererType& renderer_type,
+    ResourceCategory* rsc_category) {
+  if (rsc_category == nullptr) return false;
+  bool ret = true;
+  if (renderer_type == TrackRendererVideoRendererTypeMain) {
+    *rsc_category = ResourceCategory::kVideoRenderer;
+  } else if (renderer_type == TrackRendererVideoRendererTypeSub) {
+    *rsc_category = ResourceCategory::kVideoRendererSub;
+  } else if (renderer_type == TrackRendererVideoRendererTypeSub2) {
+    *rsc_category = ResourceCategory::kVideoRendererSub2;
+  } else if (renderer_type == TrackRendererVideoRendererTypeSub3) {
+    *rsc_category = ResourceCategory::kVideoRendererSub3;
+  } else {
+    ret = false;
+  }
+  return ret;
+}
+
+}  // namespace capi_utils
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/trackrenderer_debug.cpp b/src/trackrenderer_debug.cpp
new file mode 100755 (executable)
index 0000000..878890c
--- /dev/null
@@ -0,0 +1,314 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/trackrenderer_debug.h"
+
+#include <vconf.h>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "trackrenderer/core/pipeline.hpp"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+namespace debug {
+
+class ConcretePlayinfoSetter : public PlayinfoSetter {
+ public:
+  ConcretePlayinfoSetter() noexcept {}
+  ~ConcretePlayinfoSetter() {}
+
+  void SetAppInfo(const PlayerAppInfo& app_info) override;
+  bool SetStreamInfo(GstCaps* v_sink_caps, GstCaps* v_decoder_caps,
+                     GstCaps* a_decoder_caps, const std::vector<Track>& tracks,
+                     drm::Type drm_type) override;
+  void VconfSetMsgShow() override;
+  void VconfSetMsgUpdate() override;
+  void VconfSetMsgHide() override;
+
+ private:
+  bool is_shown_ = false;
+  StreamInfo stream_info_;
+  PlayerAppInfo app_info_;
+};
+
+static const char* VCONF_KEY_FOR_PLAYBACK_INFO = "memory/mm/playinfo";
+
+static gboolean SendMessage(gpointer data) {
+  std::stringstream* msg = (std::stringstream*)data;
+  // TRACKRENDERER_INFO("%s", msg->str().c_str());
+  vconf_set_str(VCONF_KEY_FOR_PLAYBACK_INFO, msg->str().c_str());
+  return false;
+}
+
+static void MessageDestructor(gpointer data) {
+  std::stringstream* msg = (std::stringstream*)data;
+  // TRACKRENDERER_INFO("%s", msg->str().c_str());
+  delete msg;
+  return;
+}
+
+std::string toString(drm::Type type) {
+  const char* drm_type = NULL;
+  switch (type) {
+    case drm::Type::kNone:
+      drm_type = "NONE";
+      break;
+    case drm::Type::kPlayready:
+      drm_type = "PLAYREADY";
+      break;
+    case drm::Type::kMarlin:
+      drm_type = "MARLIN";
+      break;
+    case drm::Type::kVerimatrix:
+      drm_type = "VERIMATRIX";
+      break;
+    case drm::Type::kWidevineClassic:
+      drm_type = "WIDEVINE CLASSIC";
+      break;
+    case drm::Type::kSecuremedia:
+      drm_type = "SECUREMEDIA";
+      break;
+    case drm::Type::kSdrm:
+      drm_type = "SDRM";
+      break;
+    case drm::Type::kWidevineCdm:
+      drm_type = "WIDEVINE CDM";
+      break;
+    default:
+      drm_type = "";
+      break;
+  }
+  return std::string(drm_type);
+}
+
+const char* GetAudioCodec(const GstCaps* caps) {
+  GstStructure* structure = gst_caps_get_structure(caps, 0);
+  if (!structure) return NULL;
+
+  const char* codec = gst_structure_get_name(structure);
+  if (g_strrstr(codec, "drm/")) {
+    codec = gst_structure_get_string(structure, "stream-type");
+  }
+
+  if (g_strrstr(codec, "audio/mpeg")) {
+    static char modifiedCodec[100] = {
+        0,
+    };
+    int version = 0;
+    int layer = 0;
+    gst_structure_get_int(structure, "mpegversion", &version);
+    gst_structure_get_int(structure, "mpeglayer", &layer);
+    snprintf(modifiedCodec, 100, "%s_v%d_layer%d", codec, version, layer);
+    codec = modifiedCodec;
+  }
+  return codec;
+}
+
+const char* GetVideoCodec(const GstCaps* caps) {
+  GstStructure* structure = gst_caps_get_structure(caps, 0);
+  if (!structure) return NULL;
+
+  const char* codec = gst_structure_get_name(structure);
+  if (g_strrstr(codec, "drm/")) {
+    codec = gst_structure_get_string(structure, "stream-type");
+  }
+  return codec;
+}
+
+int GetVideoWidth(const GstCaps* caps) {
+  GstStructure* structure = gst_caps_get_structure(caps, 0);
+  if (!structure) return 0;
+
+  int width = 0;
+  if (!gst_structure_get_int(structure, "width", &width)) return 0;
+
+  return width;
+}
+
+int GetVideoHeight(const GstCaps* caps) {
+  GstStructure* structure = gst_caps_get_structure(caps, 0);
+  if (!structure) return 0;
+
+  int height = 0;
+  if (!gst_structure_get_int(structure, "height", &height)) return 0;
+
+  return height;
+}
+
+float GetVideoFrameRate(const GstCaps* caps) {
+  GstStructure* structure = gst_caps_get_structure(caps, 0);
+  if (!structure) return 0;
+
+  int num = 0, den = 0;
+  if (!gst_structure_get_fraction(structure, "framerate", &num, &den)) return 0;
+
+  if (den <= 0 || num <= 0) return 0;
+
+  return ((float)num) / den;
+}
+
+void SetVideoInfoFromSink(GstCaps* caps, StreamInfo& out_info) {
+  if (!caps) return;
+
+  out_info.v_width = GetVideoWidth(caps);
+  out_info.v_height = GetVideoHeight(caps);
+  out_info.fps = GetVideoFrameRate(caps);
+  return;
+}
+
+void SetVideoInfoFromDecoder(GstCaps* caps, StreamInfo& out_info) {
+  if (!caps) return;
+
+  out_info.v_codec = GetVideoCodec(caps);
+  return;
+}
+
+void SetVideoInfoFromDemuxer(const std::vector<Track>& tracks,
+                             StreamInfo& out_info) {
+  for (const Track& track : tracks) {
+    if (track.type == kTrackTypeVideo) {
+      out_info.bitrate = track.bitrate;
+    }
+  }
+  return;
+}
+
+void SetAudioInfoFromDecoder(GstCaps* caps, StreamInfo& out_info) {
+  if (!caps) return;
+
+  out_info.a_codec = GetAudioCodec(caps);
+  return;
+}
+
+void FillMsgWithAppInfo(const PlayerAppInfo& app_info,
+                        std::stringstream* out_message) {
+  if (app_info.id.empty())
+    *out_message << "appid="
+                 << "_";
+  else
+    *out_message << "appid=" << app_info.id.c_str();
+
+  if (app_info.version.empty())
+    *out_message << "&app_version="
+                 << "_";
+  else
+    *out_message << "&app_version=" << app_info.version.c_str();
+
+  if (app_info.type.empty())
+    *out_message << "&app_type="
+                 << "_";
+  else
+    *out_message << "&app_type=" << app_info.type.c_str();
+
+  return;
+}
+
+void FillMsgWithStreamInfo(const StreamInfo& in_info,
+                           std::stringstream* out_message) {
+  // InformationTicker will parse the keys by this delimeter '&'
+  if (in_info.a_codec) {
+    *out_message << "&a_codec=" << in_info.a_codec;
+  }
+
+  if (in_info.v_codec) {
+    *out_message << "&v_codec=" << in_info.v_codec;
+  }
+
+  if (in_info.v_width > 0 && in_info.v_height > 0) {
+    *out_message << "&v_resolution=" << in_info.v_width << "x"
+                 << in_info.v_height;
+  }
+
+  if (in_info.fps > 0.0) {
+    *out_message << "&v_framerate=" << std::fixed << std::setprecision(2)
+                 << in_info.fps << "fps";
+  }
+
+  if (in_info.drm_type > drm::Type::kNone) {
+    *out_message << "&drm_type=" << toString((drm::Type)in_info.drm_type);
+  }
+
+  if (in_info.bitrate > 0) {
+    *out_message << "&bitrate=" << in_info.bitrate << "bps";
+  }
+  return;
+}
+
+PlayinfoSetter::Ptr PlayinfoSetter::Create() {
+  return PlayinfoSetter::Ptr(new ConcretePlayinfoSetter);
+}
+
+void ConcretePlayinfoSetter::SetAppInfo(const PlayerAppInfo& app_info) {
+  app_info_ = app_info;
+}
+
+bool ConcretePlayinfoSetter::SetStreamInfo(GstCaps* v_sink_caps,
+                                           GstCaps* v_decoder_caps,
+                                           GstCaps* a_decoder_caps,
+                                           const std::vector<Track>& tracks,
+                                           drm::Type drm_type) {
+  StreamInfo info;
+  SetVideoInfoFromSink(v_sink_caps, info);
+  SetVideoInfoFromDecoder(v_decoder_caps, info);
+  SetAudioInfoFromDecoder(a_decoder_caps, info);
+  SetVideoInfoFromDemuxer(tracks, info);
+  info.drm_type = drm_type;
+
+  stream_info_ = info;
+  return true;
+}
+
+void ConcretePlayinfoSetter::VconfSetMsgShow() {
+  auto message = std::unique_ptr<std::stringstream>(new std::stringstream);
+  FillMsgWithAppInfo(app_info_, message.get());
+  *message.get() << "&display_mode=show";
+  FillMsgWithStreamInfo(stream_info_, message.get());
+
+  TRACKRENDERER_INFO("display : %s", message.get()->str().c_str());
+  g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)SendMessage,
+                  (gpointer)message.release(), MessageDestructor);
+  is_shown_ = true;
+  return;
+}
+
+void ConcretePlayinfoSetter::VconfSetMsgUpdate() {
+  if (!is_shown_) return;
+
+  auto message = std::unique_ptr<std::stringstream>(new std::stringstream);
+  FillMsgWithAppInfo(app_info_, message.get());
+  *message.get() << "&display_mode=update";
+  FillMsgWithStreamInfo(stream_info_, message.get());
+
+  TRACKRENDERER_INFO("display : %s", message.get()->str().c_str());
+  g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)SendMessage,
+                  (gpointer)message.release(), MessageDestructor);
+  return;
+}
+
+void ConcretePlayinfoSetter::VconfSetMsgHide() {
+  if (!is_shown_) return;
+  auto message = std::unique_ptr<std::stringstream>(new std::stringstream);
+  FillMsgWithAppInfo(app_info_, message.get());
+  *message.get() << "&display_mode=hide";
+
+  TRACKRENDERER_INFO("display : %s", message.get()->str().c_str());
+  g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)SendMessage,
+                  (gpointer)message.release(), MessageDestructor);
+  is_shown_ = false;
+  return;
+}
+
+}  // namespace debug
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/trackrenderer_vconf.cpp b/src/trackrenderer_vconf.cpp
new file mode 100755 (executable)
index 0000000..7932801
--- /dev/null
@@ -0,0 +1,186 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/trackrenderer_vconf.h"
+
+#include <algorithm>
+
+#include "json/json.h"
+#include "trackrenderer/core/utils/log.h"
+
+namespace plusplayer {
+
+namespace trackrenderer {
+
+Vconf::Vconf() {
+  VconfCbList vconf_cb_list;
+  vconf_map_[kPowerAnimationVconf] = vconf_cb_list;
+}
+
+Vconf::~Vconf() {
+  vconf_map_[kPowerAnimationVconf].clear();
+  vconf_map_.clear();
+}
+
+bool Vconf::IsMultiscreenMode() {
+  TRACKRENDERER_ENTER
+  char* mls_json_info = vconf_get_str(kMultiscreenInfoVconf);
+  if (NULL == mls_json_info) {
+    TRACKRENDERER_ERROR("Fail to get memory/multiscreen/info vconf info.");
+    return false;
+  }
+  bool ret = ParseMlsVconf_(mls_json_info);
+  free(mls_json_info);
+
+  return ret;
+}
+
+void Vconf::SetVconfsCb(const std::vector<std::string>& names,
+                        vconf_cb callback, void* userdata) {
+  TRACKRENDERER_ENTER
+  if (names.empty() || nullptr == callback || nullptr == userdata) return;
+
+  std::lock_guard<std::mutex> lk(vconf_m_);
+  for (auto& name : names) {
+    SetVconfCb_(name, callback, userdata);
+  }
+  TRACKRENDERER_LEAVE
+}
+
+void Vconf::UnsetVconfsCb(const std::vector<std::string>& names,
+                          vconf_cb callback, void* userdata) {
+  if (names.empty() || nullptr == callback || nullptr == userdata) return;
+
+  std::lock_guard<std::mutex> lk(vconf_m_);
+  for (auto& name : names) {
+    UnsetVconfCb_(name, callback, userdata);
+  }
+}
+
+void Vconf::VconfCb_(keynode_t* key, void* userdata) {
+  TRACKRENDERER_ENTER
+  Vconf* vf = static_cast<Vconf*>(userdata);
+  if (nullptr == vf) return;
+  char* name = vconf_keynode_get_name(key);
+  if (nullptr == name) {
+    TRACKRENDERER_ERROR("vconf name is NULL!");
+    return;
+  }
+
+  TRACKRENDERER_INFO("vconf name[%s]", name);
+  std::string vf_name(name);
+  std::string value;
+  if (vf_name == kPowerAnimationVconf) {
+    int vf_value = vconf_keynode_get_int(key);
+    TRACKRENDERER_INFO("vconf memory/welcome_mode/power_animation, value[%d]",
+                       vf_value);
+    if (vf_value > 1 || vf_value < 0) {
+      TRACKRENDERER_WARN("Skip power_animation vconf value[%d]", vf_value);
+      return;
+    }
+    int smsrc_status = 0;
+    if (vconf_get_int(kTV2MobileStateVconf, &smsrc_status)) {
+      TRACKRENDERER_ERROR("Fail to get[%s] value!", kTV2MobileStateVconf);
+      return;
+    }
+    if (smsrc_status) {
+      TRACKRENDERER_WARN("Skip TV2Mobile state[%d]", smsrc_status);
+      return;
+    }
+
+    value = (vf_value == 1) ? "true" : "false";
+  } else {
+    TRACKRENDERER_ERROR("Unknow vconf name: %s", name);
+    return;
+  }
+
+  vf->Notify_(vf_name, value);
+  TRACKRENDERER_LEAVE
+}
+
+void Vconf::Notify_(const std::string& name, const std::string& value) {
+  TRACKRENDERER_ENTER
+  std::lock_guard<std::mutex> lk(vconf_m_);
+  TRACKRENDERER_INFO("name[%s], value[%s]", name.c_str(), value.c_str());
+  for (auto& item : vconf_map_[name]) {
+    if (item.first) {
+      item.first(name, value, item.second);
+      TRACKRENDERER_INFO("Notify user[%p]", item.second);
+    }
+  }
+  TRACKRENDERER_LEAVE
+}
+
+void Vconf::SetVconfCb_(const std::string& name, vconf_cb callback,
+                        void* userdata) {
+  TRACKRENDERER_INFO("name[%s], callback[%p], userdata[%p]", name.c_str(),
+                     callback, userdata);
+  if (vconf_map_.count(name) == 0) {
+    TRACKRENDERER_ERROR("Not support vconf[%s]", name.c_str());
+    return;
+  }
+  if (vconf_map_[name].empty()) {
+    int ret = vconf_notify_key_changed(name.c_str(), Vconf::VconfCb_, this);
+    if (ret < 0) {
+      TRACKRENDERER_ERROR("vconf_notify_key_changed() return error[%d]", ret);
+      return;
+    }
+    TRACKRENDERER_INFO("Register vconf[%s] successfully", name.c_str());
+  }
+
+  auto is_exist = [callback, userdata](const VconfPair& item) {
+    return (callback == item.first) && (userdata == item.second);
+  };
+  auto target =
+      std::find_if(vconf_map_[name].begin(), vconf_map_[name].end(), is_exist);
+  if (target != vconf_map_[name].end()) {
+    TRACKRENDERER_ERROR("User[%p] has existed!", userdata);
+    return;
+  }
+  vconf_map_[name].push_back(std::make_pair(callback, userdata));
+}
+
+void Vconf::UnsetVconfCb_(const std::string& name, vconf_cb callback,
+                          void* userdata) {
+  TRACKRENDERER_INFO("name[%s], callback[%p], userdata[%p]", name.c_str(),
+                     callback, userdata);
+  if (vconf_map_.count(name) == 0) {
+    TRACKRENDERER_ERROR("Not support vconf[%s]", name.c_str());
+    return;
+  }
+  if (vconf_map_[name].empty()) return;
+
+  auto is_exist = [callback, userdata](const VconfPair& item) {
+    return (callback == item.first) && (userdata == item.second);
+  };
+  vconf_map_[name].remove_if(is_exist);
+
+  if (vconf_map_[name].empty()) {
+    int ret = vconf_ignore_key_changed(name.c_str(), Vconf::VconfCb_);
+    if (ret < 0) {
+      TRACKRENDERER_ERROR("vconf_ignore_key_changed() return error[%d]", ret);
+    } else {
+      TRACKRENDERER_INFO("Unregister vconf[%s] successfully.", name.c_str());
+    }
+  }
+}
+
+bool Vconf::ParseMlsVconf_(const char* json) {
+  TRACKRENDERER_INFO("memory/multiscreen/info: %s", json);
+  Json::Value root;
+  Json::Reader reader;
+  if (!reader.parse(json, root)) {
+    TRACKRENDERER_ERROR(
+        "Fail to parse memory/multiscreen/info content info[%s], error[%s]",
+        json, (reader.getFormatedErrorMessages()).c_str());
+    return false;
+  }
+  std::string mode = root["mode"].asString();
+  TRACKRENDERER_INFO("Multiscreen mode[%s]", mode.c_str());
+  return (mode == "on") ? true : false;
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/src/vr360.cpp b/src/vr360.cpp
new file mode 100755 (executable)
index 0000000..636b0d4
--- /dev/null
@@ -0,0 +1,74 @@
+//
+// @ Copyright [2021] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "trackrenderer/core/utils/log.h"
+#include "trackrenderer/vr360.h"
+
+#include <dlfcn.h>
+#include <mutex>
+namespace plusplayer {
+
+namespace trackrenderer {
+
+#define VR360_LIB_PATH "/usr/lib/libvr360.so"
+
+static std::once_flag lib_loaded;
+static void* vr360_lib = nullptr;
+
+static Vr360Initialize vr360_tz_initialize = nullptr;
+static Vr360Finalize vr360_tz_finalize = nullptr;
+static Vr360SetGpuMode vr360_tz_set_gpu_mode = nullptr;
+
+Vr360::Vr360() {
+  auto loadlib = []() {
+    TRACKRENDERER_ENTER
+    vr360_lib = dlopen(VR360_LIB_PATH, RTLD_LAZY);
+    if (!vr360_lib) {
+      TRACKRENDERER_ERROR("libvr360.so open failed: %s", dlerror());
+      return;
+    }
+    vr360_tz_initialize =
+        (Vr360Initialize)dlsym(vr360_lib, "vr360_tz_initialize");
+    if (!vr360_tz_initialize) {
+      TRACKRENDERER_ERROR("Failed to import vr360_tz_initialize");
+      return;
+    }
+    vr360_tz_finalize = (Vr360Finalize)dlsym(vr360_lib, "vr360_tz_finalize");
+    if (!vr360_tz_finalize) {
+      TRACKRENDERER_ERROR("Failed to import vr360_tz_finalize");
+      return;
+    }
+    vr360_tz_set_gpu_mode =
+        (Vr360SetGpuMode)dlsym(vr360_lib, "vr360_tz_set_gpu_mode");
+    if (!vr360_tz_set_gpu_mode) {
+      TRACKRENDERER_ERROR("Failed to import vr360_tz_set_gpu_mode");
+      return;
+    }
+  };
+  std::call_once(lib_loaded, loadlib);
+}
+
+Vr360::~Vr360() {}
+
+void Vr360::Vr360TzSetGpuMode(bool set) {
+  TRACKRENDERER_ENTER
+  if (vr360_tz_initialize == nullptr || vr360_tz_finalize == nullptr ||
+      vr360_tz_set_gpu_mode == nullptr)
+    return;
+  vr360_tz_initialize(&vr360_tz_handle_);
+  if (set) {
+    vr360_tz_set_gpu_mode(vr360_tz_handle_,
+                          static_cast<int>(GpuMode::kVr360GpuModeSecure));
+  } else {
+    vr360_tz_set_gpu_mode(vr360_tz_handle_,
+                          static_cast<int>(GpuMode::kVr360GpuModeNonSecure));
+  }
+  vr360_tz_finalize(vr360_tz_handle_);
+  vr360_tz_handle_ = nullptr;
+  TRACKRENDERER_LEAVE
+}
+
+}  // namespace trackrenderer
+
+}  // namespace plusplayer
diff --git a/tomato/tc/TCList.dat b/tomato/tc/TCList.dat
new file mode 100755 (executable)
index 0000000..c621586
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_all.xml
\ No newline at end of file
diff --git a/tomato/tc/TCList_test_1.dat b/tomato/tc/TCList_test_1.dat
new file mode 100755 (executable)
index 0000000..ec50b2c
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_1.xml
\ No newline at end of file
diff --git a/tomato/tc/TCList_test_2.dat b/tomato/tc/TCList_test_2.dat
new file mode 100755 (executable)
index 0000000..aa23a3c
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_2.xml
\ No newline at end of file
diff --git a/tomato/tc/TCList_test_3.dat b/tomato/tc/TCList_test_3.dat
new file mode 100755 (executable)
index 0000000..66c190a
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_3.xml
\ No newline at end of file
diff --git a/tomato/tc/TCList_test_4.dat b/tomato/tc/TCList_test_4.dat
new file mode 100755 (executable)
index 0000000..2011546
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_4.xml
\ No newline at end of file
diff --git a/tomato/tc/TCList_test_5.dat b/tomato/tc/TCList_test_5.dat
new file mode 100755 (executable)
index 0000000..75aeb25
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_5.xml
\ No newline at end of file
diff --git a/tomato/tc/TCList_test_6.dat b/tomato/tc/TCList_test_6.dat
new file mode 100755 (executable)
index 0000000..bdd39cd
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_6.xml
\ No newline at end of file
diff --git a/tomato/tc/TCList_test_7.dat b/tomato/tc/TCList_test_7.dat
new file mode 100755 (executable)
index 0000000..2a29684
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_plusplayer_7.xml
\ No newline at end of file
diff --git a/tomato/tc/testfarm_script.xml b/tomato/tc/testfarm_script.xml
new file mode 100755 (executable)
index 0000000..b24a284
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestFarm>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_1.dat"/>
+       </Target>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_2.dat"/>
+       </Target>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_3.dat"/>
+       </Target>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_4.dat"/>
+       </Target>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_5.dat"/>
+       </Target>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_6.dat"/>
+       </Target>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="plusplayer" RpmName="plusplayer-ut-component-tomato" DatFile="TCList_test_7.dat"/>
+       </Target>
+</TestFarm>
\ No newline at end of file
diff --git a/tomato/tc/unit_test/ut_plusplayer_1.xml b/tomato/tc/unit_test/ut_plusplayer_1.xml
new file mode 100755 (executable)
index 0000000..be805df
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test - 1/7">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test - step : 1" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=0;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_1.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_1.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/tomato/tc/unit_test/ut_plusplayer_2.xml b/tomato/tc/unit_test/ut_plusplayer_2.xml
new file mode 100755 (executable)
index 0000000..51082c7
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test - 2/7">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test - step : 2" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=1;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_2.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_2.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/tomato/tc/unit_test/ut_plusplayer_3.xml b/tomato/tc/unit_test/ut_plusplayer_3.xml
new file mode 100755 (executable)
index 0000000..7aa8441
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test - 3/7">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test - step : 3" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=2;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_3.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_3.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/tomato/tc/unit_test/ut_plusplayer_4.xml b/tomato/tc/unit_test/ut_plusplayer_4.xml
new file mode 100755 (executable)
index 0000000..a19bee8
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test - 4/7">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test - step : 4" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=3;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_4.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_4.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/tomato/tc/unit_test/ut_plusplayer_5.xml b/tomato/tc/unit_test/ut_plusplayer_5.xml
new file mode 100755 (executable)
index 0000000..3e876eb
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test - 5/7">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test - step : 5" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=4;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_5.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_5.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/tomato/tc/unit_test/ut_plusplayer_6.xml b/tomato/tc/unit_test/ut_plusplayer_6.xml
new file mode 100755 (executable)
index 0000000..9461a7f
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test - 6/7">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test - step : 6" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=5;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_6.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_6.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/tomato/tc/unit_test/ut_plusplayer_7.xml b/tomato/tc/unit_test/ut_plusplayer_7.xml
new file mode 100755 (executable)
index 0000000..6ab947f
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test - 7/7">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test - step : 7" Type="EXT_TEST_PACKAGE" Command="export GTEST_TOTAL_SHARDS=7 GTEST_SHARD_INDEX=6;/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result_7.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result_7.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/tomato/tc/unit_test/ut_plusplayer_all.xml b/tomato/tc/unit_test/ut_plusplayer_all.xml
new file mode 100755 (executable)
index 0000000..f7e85db
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="Plusplayer API Test" Description="Plusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="Plusplayer unit test">
+               <Step Name="Plusplayer prepare test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/player-ut --gtest_filter=*PlusplayerTest_Prepare* --gtest_output=xml:/usr/etc/plusplayer_prepare_tests_result.xml"  Permission="ROOT">
+                       <Input Expirytime="600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_prepare_tests_result.xml"/>
+               </Step>
+
+               <Step Name="Plusplayer unit test" Type="EXT_TEST_PACKAGE" Command="/usr/bin/plusplayer_ut --gtest_output=xml:/usr/etc/plusplayer_tests_result.xml" Permission="ROOT">
+                       <Input Expirytime="3600"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/plusplayer_tests_result.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/ut/CMakeLists.txt b/ut/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..42a2e83
--- /dev/null
@@ -0,0 +1,102 @@
+SET(fw_name "${PROJECT_NAME}_ut")
+
+SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+
+SET(${fw_name}_CXXFLAGS "-Wall -Werror -std=c++11 -pthread -fPIE -Wl,-z,relro -fstack-protector -fno-delete-null-pointer-checks -DEFL_BETA_API_SUPPORT")
+
+SET(${fw_name}_LDFLAGS)
+
+SET(ADD_LIBS
+  "trackrenderer"
+  "gstvideo-1.0"
+)
+
+SET(dependents "gstreamer-1.0 glib-2.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 dlog gtest_gmock"
+               "boost"
+               "tv-resource-information tv-resource-manager libresourced appcore-efl elementary ecore evas ecore-wl2 audio-control"
+               "capi-media-player"
+               )
+IF(SUPPORT_SOUNDBAR)
+SET(dependents ${dependents} "libavoc-av")
+ELSE(SUPPORT_SOUNDBAR)
+SET(dependents ${dependents} "libavoc")
+ENDIF(SUPPORT_SOUNDBAR)
+
+INCLUDE(FindPkgConfig)
+IF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+pkg_check_modules(${fw_name} REQUIRED ${dependents})
+ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+pkg_check_modules(${fw_name} REQUIRED ${dependents})
+ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+
+FOREACH(flag ${${fw_name}_CFLAGS})
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+FOREACH(flag ${${fw_name}_CXXFLAGS})
+SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS}")
+
+INCLUDE_DIRECTORIES(
+  ${PROJECT_SOURCE_DIR}/src
+  ${PROJECT_SOURCE_DIR}/include
+  ${PROJECT_SOURCE_DIR}
+  ${PROJECT_SOURCE_DIR}/src/plusplayer-core/include_internal
+  ${PROJECT_SOURCE_DIR}/src/plusplayer/include_internal
+  ${PROJECT_SOURCE_DIR}/src/esplusplayer/include_internal
+  ${PROJECT_SOURCE_DIR}/src/tracksource/include_internal
+  ${PROJECT_SOURCE_DIR}/src/trackrenderer/include_internal
+)
+
+SET(UT_SRC
+  # src/ut_defaultplayer.cpp
+  # src/ut_espacket.cpp
+  # src/ut_esplayer.cpp
+  # src/ut_esplayer2.cpp
+  # src/ut_esplayer_trackrenderer.cpp
+  # src/ut_dashplayback.cpp
+  # src/ut_display.cpp
+  # src/ut_gst.cpp
+  # src/ut_gstdashtracksource.cpp
+  # src/ut_gsthlstracksource.cpp
+  # src/ut_gsttrackrenderer.cpp
+  # src/ut_gsttypefinder.cpp
+  # src/ut_hlstracksource.cpp
+  # src/ut_tracksource.cpp
+  # src/ut_external_subtitle.cpp
+  src/ut_main.cpp
+  # src/ut_miscellaneous.cpp
+  # src/ut_pipeline.cpp
+  # src/ut_resource_manager.cpp
+  # src/ut_serializer.cpp
+  # src/ut_streamreader.cpp
+  # src/ut_typefinder.cpp
+  # src/ut_statemanager.cpp
+  # src/ut_external_subtitle.cpp
+  # src/ut_example.cpp
+  # temporarily disabled - invalid tc , build errors : improve it or delete it
+  # src/ut_trackrendereradapter.cpp
+  # src/ut_trackrenderer.cpp
+  # src/ut_trackrenderer_capi.cpp
+  #src/esplusplayer/ut_basic.cpp
+  #src/esplusplayer/ut_display.cpp
+)
+
+ADD_EXECUTABLE(${fw_name} ${UT_SRC})
+
+LINK_DIRECTORIES(${LIB_INSTALL_DIR})
+
+TARGET_LINK_LIBRARIES(${fw_name}
+       ${CMAKE_THREAD_LIBS_INIT}
+  ${ADD_LIBS}
+  ${${fw_name}_LDFLAGS}
+  "-pie"
+)
+
+INSTALL(
+       TARGETS ${fw_name}
+       DESTINATION bin
+)
diff --git a/ut/README.md b/ut/README.md
new file mode 100755 (executable)
index 0000000..0fa6c9e
--- /dev/null
@@ -0,0 +1,127 @@
+**GTest guide** \r
+===============\r
+  For unit test for plusplayer\r
+\r
+---\r
+### Reference \r
+- <https://github.com/google/googletest>\r
+\r
+## Assertion \r
+* ASSERT_* : 실패시 해당 테스트를 바로 종료 <br>\r
+* EXPECT_* : 실패하여도 테스트 계속 진행 <br>\r
+\r
+#### Basic Assertions ###\r
+\r
+These assertions do basic true/false condition testing.\r
+\r
+| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |\r
+|:--------------------|:-----------------------|:-------------|\r
+| `ASSERT_TRUE(`_condition_`)`;  | `EXPECT_TRUE(`_condition_`)`;   | _condition_ is true |\r
+| `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`;  | _condition_ is false |\r
+\r
+#### Binary Comparison ###\r
+\r
+This section describes assertions that compare two values.\r
+\r
+| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |\r
+|:--------------------|:-----------------------|:-------------|\r
+|`ASSERT_EQ(`_val1_`, `_val2_`);`|`EXPECT_EQ(`_val1_`, `_val2_`);`| _val1_ `==` _val2_ |\r
+|`ASSERT_NE(`_val1_`, `_val2_`);`|`EXPECT_NE(`_val1_`, `_val2_`);`| _val1_ `!=` _val2_ |\r
+|`ASSERT_LT(`_val1_`, `_val2_`);`|`EXPECT_LT(`_val1_`, `_val2_`);`| _val1_ `<` _val2_ |\r
+|`ASSERT_LE(`_val1_`, `_val2_`);`|`EXPECT_LE(`_val1_`, `_val2_`);`| _val1_ `<=` _val2_ |\r
+|`ASSERT_GT(`_val1_`, `_val2_`);`|`EXPECT_GT(`_val1_`, `_val2_`);`| _val1_ `>` _val2_ |\r
+|`ASSERT_GE(`_val1_`, `_val2_`);`|`EXPECT_GE(`_val1_`, `_val2_`);`| _val1_ `>=` _val2_ |\r
+\r
+\r
+#### String Comparison ###\r
+\r
+The assertions in this group compare two **C strings**.<br>\r
+If you want to compare two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead.\r
+\r
+| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |\r
+|:--------------------|:-----------------------|:-------------|\r
+| `ASSERT_STREQ(`_str1_`, `_str2_`);`    | `EXPECT_STREQ(`_str1_`, `_str_2`);`     | the two C strings have the same content |\r
+| `ASSERT_STRNE(`_str1_`, `_str2_`);`    | `EXPECT_STRNE(`_str1_`, `_str2_`);`     | the two C strings have different content |\r
+| `ASSERT_STRCASEEQ(`_str1_`, `_str2_`);`| `EXPECT_STRCASEEQ(`_str1_`, `_str2_`);` | the two C strings have the same content, ignoring case |\r
+| `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case |\r
+\r
+## Text Fixtures : Using the Same Data Configuration for Multiple Tests ##\r
+\r
+사용자가 유사한 data를 사용해서 하나 이상의 test를 작성한다면, test fixture를 사용할 수 있다. 이 test fixture를 사용한다는 것은 여러개의 다양한 test를 작성하는 과정에서 같은 object의 configuration을 재사용한다는 것을 의미한다.\r
+\r
+Fixture를 작성할 때에는 아래의 내용대로 수행하면 된다.\r
+\r
+1. ::testing::Test 로부터 class를 derive한다. Sub-class 에서 fixture member에 접근해야 하기 때문에 protected 혹은 public 으로 작성해야 한다.   \r
+2. Class 내부에서 사용자가 원하는대로 object들을 선언해 사용한다.  \r
+3. 필요하다면, 생성자나 SetUp() function을 작성해둔다.   \r
+4. 생성자나 SetUp() function을 정의해서 사용하고 있다면, 해당 function에서 사용했던 resource를 반환하기 위해 소멸자나 TearDown() function을 작성한다.   \r
+5. Subroutine 들을 작성한다.   \r
+\r
+Fixture를 사용하기 위해서는 TEST() 대신에 TEST_F()를 사용해야만 한다.\r
+TEST()에서는 첫번째 argument가 testcase의 이름이었지만 TEST_F()를 사용할 때는 첫번째 argument로 test fixture class의 이름을 사용해야만 한다.\r
+\r
+**Fixture class 기본 구현 Form**\r
+* 관례에 따라 테스트할 클래스가 Foo라면 이름을 FooTest라고 하는게 좋다.\r
+~~~\r
+class PlusPlayerTest : public ::testing::Test {\r
+public:\r
+  PlusPlayerTest(std::string url)\r
+    : plusplayer_(nullptr), url_(url)\r
+  {\r
+  }\r
+\r
+  void SetUp() override\r
+  {\r
+    plusplayer_ = new PlusPlayer();\r
+    create(url_);\r
+  }\r
+\r
+  void TearDown() override\r
+  {\r
+    destory(plusplayer_);\r
+  }\r
+\r
+private:\r
+  std::string url_;\r
+  PlusPlayer* plusplayer_;\r
+\r
+}\r
+~~~\r
+\r
+**실행 순서**   \r
+1. 모든 구글 테스트 플래그 상태를 저장한다.  \r
+2. 첫 번째 테스트에 대해 테스트 fixture 객체를 생성한다.  \r
+3. 만든 객체를 SetUp()에서 초기화한다.  \r
+4. 픽스처 객체에 대해 테스트를 실행한다.  \r
+5. TearDown()에서 해당 픽스처를 정리한다.  \r
+6. 해당 픽스처를 삭제한다.  \r
+7. 모든 구글 테스트 플래그 상태를 복원한다.  \r
+8. 모든 테스트를 마칠 때까지 다음 테스트에 대해 위 과정을 반복한다.   \r
+\r
+---\r
+\r
+## Arguments \r
+reference\r
+\r
+1. test selection\r
+  * --gtest_list_tests <br>\r
+    > 테스트할 항목을 보여준다. (테스트 실시 X)\r
+  * --gtest_also_run_disabled_tests <br>\r
+    > DISABLED_ 로 막아둔 test case 를 일시적으로 실행\r
+  * --gtest_filter <br>\r
+    > 특정 case 들만 실행 가능<br>\r
+      Ex) --gtest_filter="*.create*" : 모든 TC중에서 create 로 시작하는 모든 TC 실행. <br>\r
+\r
+2. test Execution\r
+  * --gtest_repeat <br>\r
+    > test 반복 가능. -1일 경우 무한히 반복<br>\r
+      --gtest_break_on_failure와 함께 사용하면 실패할 경우 멈춤.\r
+  * --gtest_shuffle <br>\r
+    > 무작위로 실행 가능 (test case 간 dependency 가 없어야 하기 때문이다)<br>\r
+      gtest는 기본적으로 현재시간을 랜덤함수의 시드값으로 사용하나,  --gtest_random_seed로 조절가능하다\r
+  * --gtest_random_seed \r
+    > 1 ~ 99999까지의 값을 --gtest_shuffle에서 사용할 랜덤함수의 시드로 사용.\r
+\r
+---\r
+## Reference\r
+  * Gtest Primer(EN)<br> <https://github.com/google/googletest/blob/master/googletest/docs/Primer.md>\r
diff --git a/ut/cpplint.py b/ut/cpplint.py
new file mode 100755 (executable)
index 0000000..4b9d830
--- /dev/null
@@ -0,0 +1,6123 @@
+#!/usr/bin/env python\r
+#\r
+# Copyright (c) 2009 Google Inc. All rights reserved.\r
+#\r
+# Redistribution and use in source and binary forms, with or without\r
+# modification, are permitted provided that the following conditions are\r
+# met:\r
+#\r
+#    * Redistributions of source code must retain the above copyright\r
+# notice, this list of conditions and the following disclaimer.\r
+#    * Redistributions in binary form must reproduce the above\r
+# copyright notice, this list of conditions and the following disclaimer\r
+# in the documentation and/or other materials provided with the\r
+# distribution.\r
+#    * Neither the name of Google Inc. nor the names of its\r
+# contributors may be used to endorse or promote products derived from\r
+# this software without specific prior written permission.\r
+#\r
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+\r
+"""Does google-lint on c++ files.\r
+\r
+The goal of this script is to identify places in the code that *may*\r
+be in non-compliance with google style.  It does not attempt to fix\r
+up these problems -- the point is to educate.  It does also not\r
+attempt to find all problems, or to ensure that everything it does\r
+find is legitimately a problem.\r
+\r
+In particular, we can get very confused by /* and // inside strings!\r
+We do a small hack, which is to ignore //'s with "'s after them on the\r
+same line, but it is far from perfect (in either direction).\r
+"""\r
+\r
+import codecs\r
+import copy\r
+import getopt\r
+import math  # for log\r
+import os\r
+import re\r
+import sre_compile\r
+import string\r
+import sys\r
+import unicodedata\r
+\r
+\r
+_USAGE = """\r
+Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]\r
+                   [--counting=total|toplevel|detailed] [--root=subdir]\r
+                   [--linelength=digits] [--headers=x,y,...]\r
+        <file> [file] ...\r
+\r
+  The style guidelines this tries to follow are those in\r
+    https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml\r
+\r
+  Every problem is given a confidence score from 1-5, with 5 meaning we are\r
+  certain of the problem, and 1 meaning it could be a legitimate construct.\r
+  This will miss some errors, and is not a substitute for a code review.\r
+\r
+  To suppress false-positive errors of a certain category, add a\r
+  'NOLINT(category)' comment to the line.  NOLINT or NOLINT(*)\r
+  suppresses errors of all categories on that line.\r
+\r
+  The files passed in will be linted; at least one file must be provided.\r
+  Default linted extensions are .cc, .cpp, .cu, .cuh and .h.  Change the\r
+  extensions with the --extensions flag.\r
+\r
+  Flags:\r
+\r
+    output=vs7\r
+      By default, the output is formatted to ease emacs parsing.  Visual Studio\r
+      compatible output (vs7) may also be used.  Other formats are unsupported.\r
+\r
+    verbose=#\r
+      Specify a number 0-5 to restrict errors to certain verbosity levels.\r
+\r
+    filter=-x,+y,...\r
+      Specify a comma-separated list of category-filters to apply: only\r
+      error messages whose category names pass the filters will be printed.\r
+      (Category names are printed with the message and look like\r
+      "[whitespace/indent]".)  Filters are evaluated left to right.\r
+      "-FOO" and "FOO" means "do not print categories that start with FOO".\r
+      "+FOO" means "do print categories that start with FOO".\r
+\r
+      Examples: --filter=-whitespace,+whitespace/braces\r
+                --filter=whitespace,runtime/printf,+runtime/printf_format\r
+                --filter=-,+build/include_what_you_use\r
+\r
+      To see a list of all the categories used in cpplint, pass no arg:\r
+         --filter=\r
+\r
+    counting=total|toplevel|detailed\r
+      The total number of errors found is always printed. If\r
+      'toplevel' is provided, then the count of errors in each of\r
+      the top-level categories like 'build' and 'whitespace' will\r
+      also be printed. If 'detailed' is provided, then a count\r
+      is provided for each category like 'build/class'.\r
+\r
+    root=subdir\r
+      The root directory used for deriving header guard CPP variable.\r
+      By default, the header guard CPP variable is calculated as the relative\r
+      path to the directory that contains .git, .hg, or .svn.  When this flag\r
+      is specified, the relative path is calculated from the specified\r
+      directory. If the specified directory does not exist, this flag is\r
+      ignored.\r
+\r
+      Examples:\r
+        Assuming that src/.git exists, the header guard CPP variables for\r
+        src/chrome/browser/ui/browser.h are:\r
+\r
+        No flag => CHROME_BROWSER_UI_BROWSER_H_\r
+        --root=chrome => BROWSER_UI_BROWSER_H_\r
+        --root=chrome/browser => UI_BROWSER_H_\r
+\r
+    linelength=digits\r
+      This is the allowed line length for the project. The default value is\r
+      80 characters.\r
+\r
+      Examples:\r
+        --linelength=120\r
+\r
+    extensions=extension,extension,...\r
+      The allowed file extensions that cpplint will check\r
+\r
+      Examples:\r
+        --extensions=hpp,cpp\r
+\r
+    headers=x,y,...\r
+      The header extensions that cpplint will treat as .h in checks. Values are\r
+      automatically added to --extensions list.\r
+\r
+      Examples:\r
+        --headers=hpp,hxx\r
+        --headers=hpp\r
+\r
+    cpplint.py supports per-directory configurations specified in CPPLINT.cfg\r
+    files. CPPLINT.cfg file can contain a number of key=value pairs.\r
+    Currently the following options are supported:\r
+\r
+      set noparent\r
+      filter=+filter1,-filter2,...\r
+      exclude_files=regex\r
+      linelength=80\r
+      root=subdir\r
+      headers=x,y,...\r
+\r
+    "set noparent" option prevents cpplint from traversing directory tree\r
+    upwards looking for more .cfg files in parent directories. This option\r
+    is usually placed in the top-level project directory.\r
+\r
+    The "filter" option is similar in function to --filter flag. It specifies\r
+    message filters in addition to the |_DEFAULT_FILTERS| and those specified\r
+    through --filter command-line flag.\r
+\r
+    "exclude_files" allows to specify a regular expression to be matched against\r
+    a file name. If the expression matches, the file is skipped and not run\r
+    through liner.\r
+\r
+    "linelength" allows to specify the allowed line length for the project.\r
+\r
+    The "root" option is similar in function to the --root flag (see example\r
+    above).\r
+    \r
+    The "headers" option is similar in function to the --headers flag \r
+    (see example above).\r
+\r
+    CPPLINT.cfg has an effect on files in the same directory and all\r
+    sub-directories, unless overridden by a nested configuration file.\r
+\r
+      Example file:\r
+        filter=-build/include_order,+build/include_alpha\r
+        exclude_files=.*\.cc\r
+\r
+    The above example disables build/include_order warning and enables\r
+    build/include_alpha as well as excludes all .cc from being\r
+    processed by linter, in the current directory (where the .cfg\r
+    file is located) and all sub-directories.\r
+"""\r
+\r
+# We categorize each error message we print.  Here are the categories.\r
+# We want an explicit list so we can list them all in cpplint --filter=.\r
+# If you add a new error message with a new category, add it to the list\r
+# here!  cpplint_unittest.py should tell you if you forget to do this.\r
+_ERROR_CATEGORIES = [\r
+    'build/class',\r
+    'build/c++11',\r
+    'build/c++14',\r
+    'build/c++tr1',\r
+    'build/deprecated',\r
+    'build/endif_comment',\r
+    'build/explicit_make_pair',\r
+    'build/forward_decl',\r
+    'build/header_guard',\r
+    'build/include',\r
+    'build/include_alpha',\r
+    'build/include_order',\r
+    'build/include_what_you_use',\r
+    'build/namespaces',\r
+    'build/printf_format',\r
+    'build/storage_class',\r
+    'legal/copyright',\r
+    'readability/alt_tokens',\r
+    'readability/braces',\r
+    'readability/casting',\r
+    'readability/check',\r
+    'readability/constructors',\r
+    'readability/fn_size',\r
+    'readability/inheritance',\r
+    'readability/multiline_comment',\r
+    'readability/multiline_string',\r
+    'readability/namespace',\r
+    'readability/nolint',\r
+    'readability/nul',\r
+    'readability/strings',\r
+    'readability/todo',\r
+    'readability/utf8',\r
+    'runtime/arrays',\r
+    'runtime/casting',\r
+    'runtime/explicit',\r
+    'runtime/int',\r
+    'runtime/init',\r
+    'runtime/invalid_increment',\r
+    'runtime/member_string_references',\r
+    'runtime/memset',\r
+    'runtime/indentation_namespace',\r
+    'runtime/operator',\r
+    'runtime/printf',\r
+    'runtime/printf_format',\r
+    'runtime/references',\r
+    'runtime/string',\r
+    'runtime/threadsafe_fn',\r
+    'runtime/vlog',\r
+    'whitespace/blank_line',\r
+    'whitespace/braces',\r
+    'whitespace/comma',\r
+    'whitespace/comments',\r
+    'whitespace/empty_conditional_body',\r
+    'whitespace/empty_if_body',\r
+    'whitespace/empty_loop_body',\r
+    'whitespace/end_of_line',\r
+    'whitespace/ending_newline',\r
+    'whitespace/forcolon',\r
+    'whitespace/indent',\r
+    'whitespace/line_length',\r
+    'whitespace/newline',\r
+    'whitespace/operators',\r
+    'whitespace/parens',\r
+    'whitespace/semicolon',\r
+    'whitespace/tab',\r
+    'whitespace/todo',\r
+    ]\r
+\r
+# These error categories are no longer enforced by cpplint, but for backwards-\r
+# compatibility they may still appear in NOLINT comments.\r
+_LEGACY_ERROR_CATEGORIES = [\r
+    'readability/streams',\r
+    'readability/function',\r
+    ]\r
+\r
+# The default state of the category filter. This is overridden by the --filter=\r
+# flag. By default all errors are on, so only add here categories that should be\r
+# off by default (i.e., categories that must be enabled by the --filter= flags).\r
+# All entries here should start with a '-' or '+', as in the --filter= flag.\r
+_DEFAULT_FILTERS = ['-build/include_alpha']\r
+\r
+# The default list of categories suppressed for C (not C++) files.\r
+_DEFAULT_C_SUPPRESSED_CATEGORIES = [\r
+    'readability/casting',\r
+    ]\r
+\r
+# The default list of categories suppressed for Linux Kernel files.\r
+_DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [\r
+    'whitespace/tab',\r
+    ]\r
+\r
+# We used to check for high-bit characters, but after much discussion we\r
+# decided those were OK, as long as they were in UTF-8 and didn't represent\r
+# hard-coded international strings, which belong in a separate i18n file.\r
+\r
+# C++ headers\r
+_CPP_HEADERS = frozenset([\r
+    # Legacy\r
+    'algobase.h',\r
+    'algo.h',\r
+    'alloc.h',\r
+    'builtinbuf.h',\r
+    'bvector.h',\r
+    'complex.h',\r
+    'defalloc.h',\r
+    'deque.h',\r
+    'editbuf.h',\r
+    'fstream.h',\r
+    'function.h',\r
+    'hash_map',\r
+    'hash_map.h',\r
+    'hash_set',\r
+    'hash_set.h',\r
+    'hashtable.h',\r
+    'heap.h',\r
+    'indstream.h',\r
+    'iomanip.h',\r
+    'iostream.h',\r
+    'istream.h',\r
+    'iterator.h',\r
+    'list.h',\r
+    'map.h',\r
+    'multimap.h',\r
+    'multiset.h',\r
+    'ostream.h',\r
+    'pair.h',\r
+    'parsestream.h',\r
+    'pfstream.h',\r
+    'procbuf.h',\r
+    'pthread_alloc',\r
+    'pthread_alloc.h',\r
+    'rope',\r
+    'rope.h',\r
+    'ropeimpl.h',\r
+    'set.h',\r
+    'slist',\r
+    'slist.h',\r
+    'stack.h',\r
+    'stdiostream.h',\r
+    'stl_alloc.h',\r
+    'stl_relops.h',\r
+    'streambuf.h',\r
+    'stream.h',\r
+    'strfile.h',\r
+    'strstream.h',\r
+    'tempbuf.h',\r
+    'tree.h',\r
+    'type_traits.h',\r
+    'vector.h',\r
+    # 17.6.1.2 C++ library headers\r
+    'algorithm',\r
+    'array',\r
+    'atomic',\r
+    'bitset',\r
+    'chrono',\r
+    'codecvt',\r
+    'complex',\r
+    'condition_variable',\r
+    'deque',\r
+    'exception',\r
+    'forward_list',\r
+    'fstream',\r
+    'functional',\r
+    'future',\r
+    'initializer_list',\r
+    'iomanip',\r
+    'ios',\r
+    'iosfwd',\r
+    'iostream',\r
+    'istream',\r
+    'iterator',\r
+    'limits',\r
+    'list',\r
+    'locale',\r
+    'map',\r
+    'memory',\r
+    'mutex',\r
+    'new',\r
+    'numeric',\r
+    'ostream',\r
+    'queue',\r
+    'random',\r
+    'ratio',\r
+    'regex',\r
+    'scoped_allocator',\r
+    'set',\r
+    'sstream',\r
+    'stack',\r
+    'stdexcept',\r
+    'streambuf',\r
+    'string',\r
+    'strstream',\r
+    'system_error',\r
+    'thread',\r
+    'tuple',\r
+    'typeindex',\r
+    'typeinfo',\r
+    'type_traits',\r
+    'unordered_map',\r
+    'unordered_set',\r
+    'utility',\r
+    'valarray',\r
+    'vector',\r
+    # 17.6.1.2 C++ headers for C library facilities\r
+    'cassert',\r
+    'ccomplex',\r
+    'cctype',\r
+    'cerrno',\r
+    'cfenv',\r
+    'cfloat',\r
+    'cinttypes',\r
+    'ciso646',\r
+    'climits',\r
+    'clocale',\r
+    'cmath',\r
+    'csetjmp',\r
+    'csignal',\r
+    'cstdalign',\r
+    'cstdarg',\r
+    'cstdbool',\r
+    'cstddef',\r
+    'cstdint',\r
+    'cstdio',\r
+    'cstdlib',\r
+    'cstring',\r
+    'ctgmath',\r
+    'ctime',\r
+    'cuchar',\r
+    'cwchar',\r
+    'cwctype',\r
+    ])\r
+\r
+# Type names\r
+_TYPES = re.compile(\r
+    r'^(?:'\r
+    # [dcl.type.simple]\r
+    r'(char(16_t|32_t)?)|wchar_t|'\r
+    r'bool|short|int|long|signed|unsigned|float|double|'\r
+    # [support.types]\r
+    r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|'\r
+    # [cstdint.syn]\r
+    r'(u?int(_fast|_least)?(8|16|32|64)_t)|'\r
+    r'(u?int(max|ptr)_t)|'\r
+    r')$')\r
+\r
+\r
+# These headers are excluded from [build/include] and [build/include_order]\r
+# checks:\r
+# - Anything not following google file name conventions (containing an\r
+#   uppercase character, such as Python.h or nsStringAPI.h, for example).\r
+# - Lua headers.\r
+_THIRD_PARTY_HEADERS_PATTERN = re.compile(\r
+    r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')\r
+\r
+# Pattern for matching FileInfo.BaseName() against test file name\r
+_TEST_FILE_SUFFIX = r'(_test|_unittest|_regtest)$'\r
+\r
+# Pattern that matches only complete whitespace, possibly across multiple lines.\r
+_EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL)\r
+\r
+# Assertion macros.  These are defined in base/logging.h and\r
+# testing/base/public/gunit.h.\r
+_CHECK_MACROS = [\r
+    'DCHECK', 'CHECK',\r
+    'EXPECT_TRUE', 'ASSERT_TRUE',\r
+    'EXPECT_FALSE', 'ASSERT_FALSE',\r
+    ]\r
+\r
+# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE\r
+_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])\r
+\r
+for op, replacement in [('==', 'EQ'), ('!=', 'NE'),\r
+                        ('>=', 'GE'), ('>', 'GT'),\r
+                        ('<=', 'LE'), ('<', 'LT')]:\r
+  _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement\r
+  _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement\r
+  _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement\r
+  _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement\r
+\r
+for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),\r
+                            ('>=', 'LT'), ('>', 'LE'),\r
+                            ('<=', 'GT'), ('<', 'GE')]:\r
+  _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement\r
+  _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement\r
+\r
+# Alternative tokens and their replacements.  For full list, see section 2.5\r
+# Alternative tokens [lex.digraph] in the C++ standard.\r
+#\r
+# Digraphs (such as '%:') are not included here since it's a mess to\r
+# match those on a word boundary.\r
+_ALT_TOKEN_REPLACEMENT = {\r
+    'and': '&&',\r
+    'bitor': '|',\r
+    'or': '||',\r
+    'xor': '^',\r
+    'compl': '~',\r
+    'bitand': '&',\r
+    'and_eq': '&=',\r
+    'or_eq': '|=',\r
+    'xor_eq': '^=',\r
+    'not': '!',\r
+    'not_eq': '!='\r
+    }\r
+\r
+# Compile regular expression that matches all the above keywords.  The "[ =()]"\r
+# bit is meant to avoid matching these keywords outside of boolean expressions.\r
+#\r
+# False positives include C-style multi-line comments and multi-line strings\r
+# but those have always been troublesome for cpplint.\r
+_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(\r
+    r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')\r
+\r
+\r
+# These constants define types of headers for use with\r
+# _IncludeState.CheckNextIncludeOrder().\r
+_C_SYS_HEADER = 1\r
+_CPP_SYS_HEADER = 2\r
+_LIKELY_MY_HEADER = 3\r
+_POSSIBLE_MY_HEADER = 4\r
+_OTHER_HEADER = 5\r
+\r
+# These constants define the current inline assembly state\r
+_NO_ASM = 0       # Outside of inline assembly block\r
+_INSIDE_ASM = 1   # Inside inline assembly block\r
+_END_ASM = 2      # Last line of inline assembly block\r
+_BLOCK_ASM = 3    # The whole block is an inline assembly block\r
+\r
+# Match start of assembly blocks\r
+_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'\r
+                        r'(?:\s+(volatile|__volatile__))?'\r
+                        r'\s*[{(]')\r
+\r
+# Match strings that indicate we're working on a C (not C++) file.\r
+_SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|'\r
+                            r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))')\r
+\r
+# Match string that indicates we're working on a Linux Kernel file.\r
+_SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)')\r
+\r
+_regexp_compile_cache = {}\r
+\r
+# {str, set(int)}: a map from error categories to sets of linenumbers\r
+# on which those errors are expected and should be suppressed.\r
+_error_suppressions = {}\r
+\r
+# The root directory used for deriving header guard CPP variable.\r
+# This is set by --root flag.\r
+_root = None\r
+\r
+# The allowed line length of files.\r
+# This is set by --linelength flag.\r
+_line_length = 80\r
+\r
+# The allowed extensions for file names\r
+# This is set by --extensions flag.\r
+_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])\r
+\r
+# Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc.\r
+# This is set by --headers flag.\r
+_hpp_headers = set(['h'])\r
+\r
+# {str, bool}: a map from error categories to booleans which indicate if the\r
+# category should be suppressed for every line.\r
+_global_error_suppressions = {}\r
+\r
+def ProcessHppHeadersOption(val):\r
+  global _hpp_headers\r
+  try:\r
+    _hpp_headers = set(val.split(','))\r
+    # Automatically append to extensions list so it does not have to be set 2 times\r
+    _valid_extensions.update(_hpp_headers)\r
+  except ValueError:\r
+    PrintUsage('Header extensions must be comma seperated list.')\r
+\r
+def IsHeaderExtension(file_extension):\r
+  return file_extension in _hpp_headers\r
+\r
+def ParseNolintSuppressions(filename, raw_line, linenum, error):\r
+  """Updates the global list of line error-suppressions.\r
+\r
+  Parses any NOLINT comments on the current line, updating the global\r
+  error_suppressions store.  Reports an error if the NOLINT comment\r
+  was malformed.\r
+\r
+  Args:\r
+    filename: str, the name of the input file.\r
+    raw_line: str, the line of input text, with comments.\r
+    linenum: int, the number of the current line.\r
+    error: function, an error handler.\r
+  """\r
+  matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)\r
+  if matched:\r
+    if matched.group(1):\r
+      suppressed_line = linenum + 1\r
+    else:\r
+      suppressed_line = linenum\r
+    category = matched.group(2)\r
+    if category in (None, '(*)'):  # => "suppress all"\r
+      _error_suppressions.setdefault(None, set()).add(suppressed_line)\r
+    else:\r
+      if category.startswith('(') and category.endswith(')'):\r
+        category = category[1:-1]\r
+        if category in _ERROR_CATEGORIES:\r
+          _error_suppressions.setdefault(category, set()).add(suppressed_line)\r
+        elif category not in _LEGACY_ERROR_CATEGORIES:\r
+          error(filename, linenum, 'readability/nolint', 5,\r
+                'Unknown NOLINT error category: %s' % category)\r
+\r
+\r
+def ProcessGlobalSuppresions(lines):\r
+  """Updates the list of global error suppressions.\r
+\r
+  Parses any lint directives in the file that have global effect.\r
+\r
+  Args:\r
+    lines: An array of strings, each representing a line of the file, with the\r
+           last element being empty if the file is terminated with a newline.\r
+  """\r
+  for line in lines:\r
+    if _SEARCH_C_FILE.search(line):\r
+      for category in _DEFAULT_C_SUPPRESSED_CATEGORIES:\r
+        _global_error_suppressions[category] = True\r
+    if _SEARCH_KERNEL_FILE.search(line):\r
+      for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES:\r
+        _global_error_suppressions[category] = True\r
+\r
+\r
+def ResetNolintSuppressions():\r
+  """Resets the set of NOLINT suppressions to empty."""\r
+  _error_suppressions.clear()\r
+  _global_error_suppressions.clear()\r
+\r
+\r
+def IsErrorSuppressedByNolint(category, linenum):\r
+  """Returns true if the specified error category is suppressed on this line.\r
+\r
+  Consults the global error_suppressions map populated by\r
+  ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions.\r
+\r
+  Args:\r
+    category: str, the category of the error.\r
+    linenum: int, the current line number.\r
+  Returns:\r
+    bool, True iff the error should be suppressed due to a NOLINT comment or\r
+    global suppression.\r
+  """\r
+  return (_global_error_suppressions.get(category, False) or\r
+          linenum in _error_suppressions.get(category, set()) or\r
+          linenum in _error_suppressions.get(None, set()))\r
+\r
+\r
+def Match(pattern, s):\r
+  """Matches the string with the pattern, caching the compiled regexp."""\r
+  # The regexp compilation caching is inlined in both Match and Search for\r
+  # performance reasons; factoring it out into a separate function turns out\r
+  # to be noticeably expensive.\r
+  if pattern not in _regexp_compile_cache:\r
+    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)\r
+  return _regexp_compile_cache[pattern].match(s)\r
+\r
+\r
+def ReplaceAll(pattern, rep, s):\r
+  """Replaces instances of pattern in a string with a replacement.\r
+\r
+  The compiled regex is kept in a cache shared by Match and Search.\r
+\r
+  Args:\r
+    pattern: regex pattern\r
+    rep: replacement text\r
+    s: search string\r
+\r
+  Returns:\r
+    string with replacements made (or original string if no replacements)\r
+  """\r
+  if pattern not in _regexp_compile_cache:\r
+    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)\r
+  return _regexp_compile_cache[pattern].sub(rep, s)\r
+\r
+\r
+def Search(pattern, s):\r
+  """Searches the string for the pattern, caching the compiled regexp."""\r
+  if pattern not in _regexp_compile_cache:\r
+    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)\r
+  return _regexp_compile_cache[pattern].search(s)\r
+\r
+\r
+def _IsSourceExtension(s):\r
+  """File extension (excluding dot) matches a source file extension."""\r
+  return s in ('c', 'cc', 'cpp', 'cxx')\r
+\r
+\r
+class _IncludeState(object):\r
+  """Tracks line numbers for includes, and the order in which includes appear.\r
+\r
+  include_list contains list of lists of (header, line number) pairs.\r
+  It's a lists of lists rather than just one flat list to make it\r
+  easier to update across preprocessor boundaries.\r
+\r
+  Call CheckNextIncludeOrder() once for each header in the file, passing\r
+  in the type constants defined above. Calls in an illegal order will\r
+  raise an _IncludeError with an appropriate error message.\r
+\r
+  """\r
+  # self._section will move monotonically through this set. If it ever\r
+  # needs to move backwards, CheckNextIncludeOrder will raise an error.\r
+  _INITIAL_SECTION = 0\r
+  _MY_H_SECTION = 1\r
+  _C_SECTION = 2\r
+  _CPP_SECTION = 3\r
+  _OTHER_H_SECTION = 4\r
+\r
+  _TYPE_NAMES = {\r
+      _C_SYS_HEADER: 'C system header',\r
+      _CPP_SYS_HEADER: 'C++ system header',\r
+      _LIKELY_MY_HEADER: 'header this file implements',\r
+      _POSSIBLE_MY_HEADER: 'header this file may implement',\r
+      _OTHER_HEADER: 'other header',\r
+      }\r
+  _SECTION_NAMES = {\r
+      _INITIAL_SECTION: "... nothing. (This can't be an error.)",\r
+      _MY_H_SECTION: 'a header this file implements',\r
+      _C_SECTION: 'C system header',\r
+      _CPP_SECTION: 'C++ system header',\r
+      _OTHER_H_SECTION: 'other header',\r
+      }\r
+\r
+  def __init__(self):\r
+    self.include_list = [[]]\r
+    self.ResetSection('')\r
+\r
+  def FindHeader(self, header):\r
+    """Check if a header has already been included.\r
+\r
+    Args:\r
+      header: header to check.\r
+    Returns:\r
+      Line number of previous occurrence, or -1 if the header has not\r
+      been seen before.\r
+    """\r
+    for section_list in self.include_list:\r
+      for f in section_list:\r
+        if f[0] == header:\r
+          return f[1]\r
+    return -1\r
+\r
+  def ResetSection(self, directive):\r
+    """Reset section checking for preprocessor directive.\r
+\r
+    Args:\r
+      directive: preprocessor directive (e.g. "if", "else").\r
+    """\r
+    # The name of the current section.\r
+    self._section = self._INITIAL_SECTION\r
+    # The path of last found header.\r
+    self._last_header = ''\r
+\r
+    # Update list of includes.  Note that we never pop from the\r
+    # include list.\r
+    if directive in ('if', 'ifdef', 'ifndef'):\r
+      self.include_list.append([])\r
+    elif directive in ('else', 'elif'):\r
+      self.include_list[-1] = []\r
+\r
+  def SetLastHeader(self, header_path):\r
+    self._last_header = header_path\r
+\r
+  def CanonicalizeAlphabeticalOrder(self, header_path):\r
+    """Returns a path canonicalized for alphabetical comparison.\r
+\r
+    - replaces "-" with "_" so they both cmp the same.\r
+    - removes '-inl' since we don't require them to be after the main header.\r
+    - lowercase everything, just in case.\r
+\r
+    Args:\r
+      header_path: Path to be canonicalized.\r
+\r
+    Returns:\r
+      Canonicalized path.\r
+    """\r
+    return header_path.replace('-inl.h', '.h').replace('-', '_').lower()\r
+\r
+  def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path):\r
+    """Check if a header is in alphabetical order with the previous header.\r
+\r
+    Args:\r
+      clean_lines: A CleansedLines instance containing the file.\r
+      linenum: The number of the line to check.\r
+      header_path: Canonicalized header to be checked.\r
+\r
+    Returns:\r
+      Returns true if the header is in alphabetical order.\r
+    """\r
+    # If previous section is different from current section, _last_header will\r
+    # be reset to empty string, so it's always less than current header.\r
+    #\r
+    # If previous line was a blank line, assume that the headers are\r
+    # intentionally sorted the way they are.\r
+    if (self._last_header > header_path and\r
+        Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])):\r
+      return False\r
+    return True\r
+\r
+  def CheckNextIncludeOrder(self, header_type):\r
+    """Returns a non-empty error message if the next header is out of order.\r
+\r
+    This function also updates the internal state to be ready to check\r
+    the next include.\r
+\r
+    Args:\r
+      header_type: One of the _XXX_HEADER constants defined above.\r
+\r
+    Returns:\r
+      The empty string if the header is in the right order, or an\r
+      error message describing what's wrong.\r
+\r
+    """\r
+    error_message = ('Found %s after %s' %\r
+                     (self._TYPE_NAMES[header_type],\r
+                      self._SECTION_NAMES[self._section]))\r
+\r
+    last_section = self._section\r
+\r
+    if header_type == _C_SYS_HEADER:\r
+      if self._section <= self._C_SECTION:\r
+        self._section = self._C_SECTION\r
+      else:\r
+        self._last_header = ''\r
+        return error_message\r
+    elif header_type == _CPP_SYS_HEADER:\r
+      if self._section <= self._CPP_SECTION:\r
+        self._section = self._CPP_SECTION\r
+      else:\r
+        self._last_header = ''\r
+        return error_message\r
+    elif header_type == _LIKELY_MY_HEADER:\r
+      if self._section <= self._MY_H_SECTION:\r
+        self._section = self._MY_H_SECTION\r
+      else:\r
+        self._section = self._OTHER_H_SECTION\r
+    elif header_type == _POSSIBLE_MY_HEADER:\r
+      if self._section <= self._MY_H_SECTION:\r
+        self._section = self._MY_H_SECTION\r
+      else:\r
+        # This will always be the fallback because we're not sure\r
+        # enough that the header is associated with this file.\r
+        self._section = self._OTHER_H_SECTION\r
+    else:\r
+      assert header_type == _OTHER_HEADER\r
+      self._section = self._OTHER_H_SECTION\r
+\r
+    if last_section != self._section:\r
+      self._last_header = ''\r
+\r
+    return ''\r
+\r
+\r
+class _CppLintState(object):\r
+  """Maintains module-wide state.."""\r
+\r
+  def __init__(self):\r
+    self.verbose_level = 1  # global setting.\r
+    self.error_count = 0    # global count of reported errors\r
+    # filters to apply when emitting error messages\r
+    self.filters = _DEFAULT_FILTERS[:]\r
+    # backup of filter list. Used to restore the state after each file.\r
+    self._filters_backup = self.filters[:]\r
+    self.counting = 'total'  # In what way are we counting errors?\r
+    self.errors_by_category = {}  # string to int dict storing error counts\r
+\r
+    # output format:\r
+    # "emacs" - format that emacs can parse (default)\r
+    # "vs7" - format that Microsoft Visual Studio 7 can parse\r
+    self.output_format = 'emacs'\r
+\r
+  def SetOutputFormat(self, output_format):\r
+    """Sets the output format for errors."""\r
+    self.output_format = output_format\r
+\r
+  def SetVerboseLevel(self, level):\r
+    """Sets the module's verbosity, and returns the previous setting."""\r
+    last_verbose_level = self.verbose_level\r
+    self.verbose_level = level\r
+    return last_verbose_level\r
+\r
+  def SetCountingStyle(self, counting_style):\r
+    """Sets the module's counting options."""\r
+    self.counting = counting_style\r
+\r
+  def SetFilters(self, filters):\r
+    """Sets the error-message filters.\r
+\r
+    These filters are applied when deciding whether to emit a given\r
+    error message.\r
+\r
+    Args:\r
+      filters: A string of comma-separated filters (eg "+whitespace/indent").\r
+               Each filter should start with + or -; else we die.\r
+\r
+    Raises:\r
+      ValueError: The comma-separated filters did not all start with '+' or '-'.\r
+                  E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"\r
+    """\r
+    # Default filters always have less priority than the flag ones.\r
+    self.filters = _DEFAULT_FILTERS[:]\r
+    self.AddFilters(filters)\r
+\r
+  def AddFilters(self, filters):\r
+    """ Adds more filters to the existing list of error-message filters. """\r
+    for filt in filters.split(','):\r
+      clean_filt = filt.strip()\r
+      if clean_filt:\r
+        self.filters.append(clean_filt)\r
+    for filt in self.filters:\r
+      if not (filt.startswith('+') or filt.startswith('-')):\r
+        raise ValueError('Every filter in --filters must start with + or -'\r
+                         ' (%s does not)' % filt)\r
+\r
+  def BackupFilters(self):\r
+    """ Saves the current filter list to backup storage."""\r
+    self._filters_backup = self.filters[:]\r
+\r
+  def RestoreFilters(self):\r
+    """ Restores filters previously backed up."""\r
+    self.filters = self._filters_backup[:]\r
+\r
+  def ResetErrorCounts(self):\r
+    """Sets the module's error statistic back to zero."""\r
+    self.error_count = 0\r
+    self.errors_by_category = {}\r
+\r
+  def IncrementErrorCount(self, category):\r
+    """Bumps the module's error statistic."""\r
+    self.error_count += 1\r
+    if self.counting in ('toplevel', 'detailed'):\r
+      if self.counting != 'detailed':\r
+        category = category.split('/')[0]\r
+      if category not in self.errors_by_category:\r
+        self.errors_by_category[category] = 0\r
+      self.errors_by_category[category] += 1\r
+\r
+  def PrintErrorCounts(self):\r
+    """Print a summary of errors by category, and the total."""\r
+    for category, count in self.errors_by_category.iteritems():\r
+      sys.stderr.write('Category \'%s\' errors found: %d\n' %\r
+                       (category, count))\r
+    sys.stdout.write('Total errors found: %d\n' % self.error_count)\r
+\r
+_cpplint_state = _CppLintState()\r
+\r
+\r
+def _OutputFormat():\r
+  """Gets the module's output format."""\r
+  return _cpplint_state.output_format\r
+\r
+\r
+def _SetOutputFormat(output_format):\r
+  """Sets the module's output format."""\r
+  _cpplint_state.SetOutputFormat(output_format)\r
+\r
+\r
+def _VerboseLevel():\r
+  """Returns the module's verbosity setting."""\r
+  return _cpplint_state.verbose_level\r
+\r
+\r
+def _SetVerboseLevel(level):\r
+  """Sets the module's verbosity, and returns the previous setting."""\r
+  return _cpplint_state.SetVerboseLevel(level)\r
+\r
+\r
+def _SetCountingStyle(level):\r
+  """Sets the module's counting options."""\r
+  _cpplint_state.SetCountingStyle(level)\r
+\r
+\r
+def _Filters():\r
+  """Returns the module's list of output filters, as a list."""\r
+  return _cpplint_state.filters\r
+\r
+\r
+def _SetFilters(filters):\r
+  """Sets the module's error-message filters.\r
+\r
+  These filters are applied when deciding whether to emit a given\r
+  error message.\r
+\r
+  Args:\r
+    filters: A string of comma-separated filters (eg "whitespace/indent").\r
+             Each filter should start with + or -; else we die.\r
+  """\r
+  _cpplint_state.SetFilters(filters)\r
+\r
+def _AddFilters(filters):\r
+  """Adds more filter overrides.\r
+\r
+  Unlike _SetFilters, this function does not reset the current list of filters\r
+  available.\r
+\r
+  Args:\r
+    filters: A string of comma-separated filters (eg "whitespace/indent").\r
+             Each filter should start with + or -; else we die.\r
+  """\r
+  _cpplint_state.AddFilters(filters)\r
+\r
+def _BackupFilters():\r
+  """ Saves the current filter list to backup storage."""\r
+  _cpplint_state.BackupFilters()\r
+\r
+def _RestoreFilters():\r
+  """ Restores filters previously backed up."""\r
+  _cpplint_state.RestoreFilters()\r
+\r
+class _FunctionState(object):\r
+  """Tracks current function name and the number of lines in its body."""\r
+\r
+  _NORMAL_TRIGGER = 250  # for --v=0, 500 for --v=1, etc.\r
+  _TEST_TRIGGER = 400    # about 50% more than _NORMAL_TRIGGER.\r
+\r
+  def __init__(self):\r
+    self.in_a_function = False\r
+    self.lines_in_function = 0\r
+    self.current_function = ''\r
+\r
+  def Begin(self, function_name):\r
+    """Start analyzing function body.\r
+\r
+    Args:\r
+      function_name: The name of the function being tracked.\r
+    """\r
+    self.in_a_function = True\r
+    self.lines_in_function = 0\r
+    self.current_function = function_name\r
+\r
+  def Count(self):\r
+    """Count line in current function body."""\r
+    if self.in_a_function:\r
+      self.lines_in_function += 1\r
+\r
+  def Check(self, error, filename, linenum):\r
+    """Report if too many lines in function body.\r
+\r
+    Args:\r
+      error: The function to call with any errors found.\r
+      filename: The name of the current file.\r
+      linenum: The number of the line to check.\r
+    """\r
+    if not self.in_a_function:\r
+      return\r
+\r
+    if Match(r'T(EST|est)', self.current_function):\r
+      base_trigger = self._TEST_TRIGGER\r
+    else:\r
+      base_trigger = self._NORMAL_TRIGGER\r
+    trigger = base_trigger * 2**_VerboseLevel()\r
+\r
+    if self.lines_in_function > trigger:\r
+      error_level = int(math.log(self.lines_in_function / base_trigger, 2))\r
+      # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...\r
+      if error_level > 5:\r
+        error_level = 5\r
+      error(filename, linenum, 'readability/fn_size', error_level,\r
+            'Small and focused functions are preferred:'\r
+            ' %s has %d non-comment lines'\r
+            ' (error triggered by exceeding %d lines).'  % (\r
+                self.current_function, self.lines_in_function, trigger))\r
+\r
+  def End(self):\r
+    """Stop analyzing function body."""\r
+    self.in_a_function = False\r
+\r
+\r
+class _IncludeError(Exception):\r
+  """Indicates a problem with the include order in a file."""\r
+  pass\r
+\r
+\r
+class FileInfo(object):\r
+  """Provides utility functions for filenames.\r
+\r
+  FileInfo provides easy access to the components of a file's path\r
+  relative to the project root.\r
+  """\r
+\r
+  def __init__(self, filename):\r
+    self._filename = filename\r
+\r
+  def FullName(self):\r
+    """Make Windows paths like Unix."""\r
+    return os.path.abspath(self._filename).replace('\\', '/')\r
+\r
+  def RepositoryName(self):\r
+    """FullName after removing the local path to the repository.\r
+\r
+    If we have a real absolute path name here we can try to do something smart:\r
+    detecting the root of the checkout and truncating /path/to/checkout from\r
+    the name so that we get header guards that don't include things like\r
+    "C:\Documents and Settings\..." or "/home/username/..." in them and thus\r
+    people on different computers who have checked the source out to different\r
+    locations won't see bogus errors.\r
+    """\r
+    fullname = self.FullName()\r
+\r
+    if os.path.exists(fullname):\r
+      project_dir = os.path.dirname(fullname)\r
+\r
+      if os.path.exists(os.path.join(project_dir, ".svn")):\r
+        # If there's a .svn file in the current directory, we recursively look\r
+        # up the directory tree for the top of the SVN checkout\r
+        root_dir = project_dir\r
+        one_up_dir = os.path.dirname(root_dir)\r
+        while os.path.exists(os.path.join(one_up_dir, ".svn")):\r
+          root_dir = os.path.dirname(root_dir)\r
+          one_up_dir = os.path.dirname(one_up_dir)\r
+\r
+        prefix = os.path.commonprefix([root_dir, project_dir])\r
+        return fullname[len(prefix) + 1:]\r
+\r
+      # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by\r
+      # searching up from the current path.\r
+      root_dir = current_dir = os.path.dirname(fullname)\r
+      while current_dir != os.path.dirname(current_dir):\r
+        if (os.path.exists(os.path.join(current_dir, ".git")) or\r
+            os.path.exists(os.path.join(current_dir, ".hg")) or\r
+            os.path.exists(os.path.join(current_dir, ".svn"))):\r
+          root_dir = current_dir\r
+        current_dir = os.path.dirname(current_dir)\r
+\r
+      if (os.path.exists(os.path.join(root_dir, ".git")) or\r
+          os.path.exists(os.path.join(root_dir, ".hg")) or\r
+          os.path.exists(os.path.join(root_dir, ".svn"))):\r
+        prefix = os.path.commonprefix([root_dir, project_dir])\r
+        return fullname[len(prefix) + 1:]\r
+\r
+    # Don't know what to do; header guard warnings may be wrong...\r
+    return fullname\r
+\r
+  def Split(self):\r
+    """Splits the file into the directory, basename, and extension.\r
+\r
+    For 'chrome/browser/browser.cc', Split() would\r
+    return ('chrome/browser', 'browser', '.cc')\r
+\r
+    Returns:\r
+      A tuple of (directory, basename, extension).\r
+    """\r
+\r
+    googlename = self.RepositoryName()\r
+    project, rest = os.path.split(googlename)\r
+    return (project,) + os.path.splitext(rest)\r
+\r
+  def BaseName(self):\r
+    """File base name - text after the final slash, before the final period."""\r
+    return self.Split()[1]\r
+\r
+  def Extension(self):\r
+    """File extension - text following the final period."""\r
+    return self.Split()[2]\r
+\r
+  def NoExtension(self):\r
+    """File has no source file extension."""\r
+    return '/'.join(self.Split()[0:2])\r
+\r
+  def IsSource(self):\r
+    """File has a source file extension."""\r
+    return _IsSourceExtension(self.Extension()[1:])\r
+\r
+\r
+def _ShouldPrintError(category, confidence, linenum):\r
+  """If confidence >= verbose, category passes filter and is not suppressed."""\r
+\r
+  # There are three ways we might decide not to print an error message:\r
+  # a "NOLINT(category)" comment appears in the source,\r
+  # the verbosity level isn't high enough, or the filters filter it out.\r
+  if IsErrorSuppressedByNolint(category, linenum):\r
+    return False\r
+\r
+  if confidence < _cpplint_state.verbose_level:\r
+    return False\r
+\r
+  is_filtered = False\r
+  for one_filter in _Filters():\r
+    if one_filter.startswith('-'):\r
+      if category.startswith(one_filter[1:]):\r
+        is_filtered = True\r
+    elif one_filter.startswith('+'):\r
+      if category.startswith(one_filter[1:]):\r
+        is_filtered = False\r
+    else:\r
+      assert False  # should have been checked for in SetFilter.\r
+  if is_filtered:\r
+    return False\r
+\r
+  return True\r
+\r
+\r
+def Error(filename, linenum, category, confidence, message):\r
+  """Logs the fact we've found a lint error.\r
+\r
+  We log where the error was found, and also our confidence in the error,\r
+  that is, how certain we are this is a legitimate style regression, and\r
+  not a misidentification or a use that's sometimes justified.\r
+\r
+  False positives can be suppressed by the use of\r
+  "cpplint(category)"  comments on the offending line.  These are\r
+  parsed into _error_suppressions.\r
+\r
+  Args:\r
+    filename: The name of the file containing the error.\r
+    linenum: The number of the line containing the error.\r
+    category: A string used to describe the "category" this bug\r
+      falls under: "whitespace", say, or "runtime".  Categories\r
+      may have a hierarchy separated by slashes: "whitespace/indent".\r
+    confidence: A number from 1-5 representing a confidence score for\r
+      the error, with 5 meaning that we are certain of the problem,\r
+      and 1 meaning that it could be a legitimate construct.\r
+    message: The error message.\r
+  """\r
+  if _ShouldPrintError(category, confidence, linenum):\r
+    _cpplint_state.IncrementErrorCount(category)\r
+    if _cpplint_state.output_format == 'vs7':\r
+      sys.stderr.write('%s(%s): error cpplint: [%s] %s [%d]\n' % (\r
+          filename, linenum, category, message, confidence))\r
+    elif _cpplint_state.output_format == 'eclipse':\r
+      sys.stderr.write('%s:%s: warning: %s  [%s] [%d]\n' % (\r
+          filename, linenum, message, category, confidence))\r
+    else:\r
+      sys.stderr.write('%s:%s:  %s  [%s] [%d]\n' % (\r
+          filename, linenum, message, category, confidence))\r
+\r
+\r
+# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard.\r
+_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(\r
+    r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')\r
+# Match a single C style comment on the same line.\r
+_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/'\r
+# Matches multi-line C style comments.\r
+# This RE is a little bit more complicated than one might expect, because we\r
+# have to take care of space removals tools so we can handle comments inside\r
+# statements better.\r
+# The current rule is: We only clear spaces from both sides when we're at the\r
+# end of the line. Otherwise, we try to remove spaces from the right side,\r
+# if this doesn't work we try on left side but only if there's a non-character\r
+# on the right.\r
+_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(\r
+    r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' +\r
+    _RE_PATTERN_C_COMMENTS + r'\s+|' +\r
+    r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' +\r
+    _RE_PATTERN_C_COMMENTS + r')')\r
+\r
+\r
+def IsCppString(line):\r
+  """Does line terminate so, that the next symbol is in string constant.\r
+\r
+  This function does not consider single-line nor multi-line comments.\r
+\r
+  Args:\r
+    line: is a partial line of code starting from the 0..n.\r
+\r
+  Returns:\r
+    True, if next character appended to 'line' is inside a\r
+    string constant.\r
+  """\r
+\r
+  line = line.replace(r'\\', 'XX')  # after this, \\" does not match to \"\r
+  return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1\r
+\r
+\r
+def CleanseRawStrings(raw_lines):\r
+  """Removes C++11 raw strings from lines.\r
+\r
+    Before:\r
+      static const char kData[] = R"(\r
+          multi-line string\r
+          )";\r
+\r
+    After:\r
+      static const char kData[] = ""\r
+          (replaced by blank line)\r
+          "";\r
+\r
+  Args:\r
+    raw_lines: list of raw lines.\r
+\r
+  Returns:\r
+    list of lines with C++11 raw strings replaced by empty strings.\r
+  """\r
+\r
+  delimiter = None\r
+  lines_without_raw_strings = []\r
+  for line in raw_lines:\r
+    if delimiter:\r
+      # Inside a raw string, look for the end\r
+      end = line.find(delimiter)\r
+      if end >= 0:\r
+        # Found the end of the string, match leading space for this\r
+        # line and resume copying the original lines, and also insert\r
+        # a "" on the last line.\r
+        leading_space = Match(r'^(\s*)\S', line)\r
+        line = leading_space.group(1) + '""' + line[end + len(delimiter):]\r
+        delimiter = None\r
+      else:\r
+        # Haven't found the end yet, append a blank line.\r
+        line = '""'\r
+\r
+    # Look for beginning of a raw string, and replace them with\r
+    # empty strings.  This is done in a loop to handle multiple raw\r
+    # strings on the same line.\r
+    while delimiter is None:\r
+      # Look for beginning of a raw string.\r
+      # See 2.14.15 [lex.string] for syntax.\r
+      #\r
+      # Once we have matched a raw string, we check the prefix of the\r
+      # line to make sure that the line is not part of a single line\r
+      # comment.  It's done this way because we remove raw strings\r
+      # before removing comments as opposed to removing comments\r
+      # before removing raw strings.  This is because there are some\r
+      # cpplint checks that requires the comments to be preserved, but\r
+      # we don't want to check comments that are inside raw strings.\r
+      matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line)\r
+      if (matched and\r
+          not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//',\r
+                    matched.group(1))):\r
+        delimiter = ')' + matched.group(2) + '"'\r
+\r
+        end = matched.group(3).find(delimiter)\r
+        if end >= 0:\r
+          # Raw string ended on same line\r
+          line = (matched.group(1) + '""' +\r
+                  matched.group(3)[end + len(delimiter):])\r
+          delimiter = None\r
+        else:\r
+          # Start of a multi-line raw string\r
+          line = matched.group(1) + '""'\r
+      else:\r
+        break\r
+\r
+    lines_without_raw_strings.append(line)\r
+\r
+  # TODO(unknown): if delimiter is not None here, we might want to\r
+  # emit a warning for unterminated string.\r
+  return lines_without_raw_strings\r
+\r
+\r
+def FindNextMultiLineCommentStart(lines, lineix):\r
+  """Find the beginning marker for a multiline comment."""\r
+  while lineix < len(lines):\r
+    if lines[lineix].strip().startswith('/*'):\r
+      # Only return this marker if the comment goes beyond this line\r
+      if lines[lineix].strip().find('*/', 2) < 0:\r
+        return lineix\r
+    lineix += 1\r
+  return len(lines)\r
+\r
+\r
+def FindNextMultiLineCommentEnd(lines, lineix):\r
+  """We are inside a comment, find the end marker."""\r
+  while lineix < len(lines):\r
+    if lines[lineix].strip().endswith('*/'):\r
+      return lineix\r
+    lineix += 1\r
+  return len(lines)\r
+\r
+\r
+def RemoveMultiLineCommentsFromRange(lines, begin, end):\r
+  """Clears a range of lines for multi-line comments."""\r
+  # Having // dummy comments makes the lines non-empty, so we will not get\r
+  # unnecessary blank line warnings later in the code.\r
+  for i in range(begin, end):\r
+    lines[i] = '/**/'\r
+\r
+\r
+def RemoveMultiLineComments(filename, lines, error):\r
+  """Removes multiline (c-style) comments from lines."""\r
+  lineix = 0\r
+  while lineix < len(lines):\r
+    lineix_begin = FindNextMultiLineCommentStart(lines, lineix)\r
+    if lineix_begin >= len(lines):\r
+      return\r
+    lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)\r
+    if lineix_end >= len(lines):\r
+      error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,\r
+            'Could not find end of multi-line comment')\r
+      return\r
+    RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)\r
+    lineix = lineix_end + 1\r
+\r
+\r
+def CleanseComments(line):\r
+  """Removes //-comments and single-line C-style /* */ comments.\r
+\r
+  Args:\r
+    line: A line of C++ source.\r
+\r
+  Returns:\r
+    The line with single-line comments removed.\r
+  """\r
+  commentpos = line.find('//')\r
+  if commentpos != -1 and not IsCppString(line[:commentpos]):\r
+    line = line[:commentpos].rstrip()\r
+  # get rid of /* ... */\r
+  return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)\r
+\r
+\r
+class CleansedLines(object):\r
+  """Holds 4 copies of all lines with different preprocessing applied to them.\r
+\r
+  1) elided member contains lines without strings and comments.\r
+  2) lines member contains lines without comments.\r
+  3) raw_lines member contains all the lines without processing.\r
+  4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw\r
+     strings removed.\r
+  All these members are of <type 'list'>, and of the same length.\r
+  """\r
+\r
+  def __init__(self, lines):\r
+    self.elided = []\r
+    self.lines = []\r
+    self.raw_lines = lines\r
+    self.num_lines = len(lines)\r
+    self.lines_without_raw_strings = CleanseRawStrings(lines)\r
+    for linenum in range(len(self.lines_without_raw_strings)):\r
+      self.lines.append(CleanseComments(\r
+          self.lines_without_raw_strings[linenum]))\r
+      elided = self._CollapseStrings(self.lines_without_raw_strings[linenum])\r
+      self.elided.append(CleanseComments(elided))\r
+\r
+  def NumLines(self):\r
+    """Returns the number of lines represented."""\r
+    return self.num_lines\r
+\r
+  @staticmethod\r
+  def _CollapseStrings(elided):\r
+    """Collapses strings and chars on a line to simple "" or '' blocks.\r
+\r
+    We nix strings first so we're not fooled by text like '"http://"'\r
+\r
+    Args:\r
+      elided: The line being processed.\r
+\r
+    Returns:\r
+      The line with collapsed strings.\r
+    """\r
+    if _RE_PATTERN_INCLUDE.match(elided):\r
+      return elided\r
+\r
+    # Remove escaped characters first to make quote/single quote collapsing\r
+    # basic.  Things that look like escaped characters shouldn't occur\r
+    # outside of strings and chars.\r
+    elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)\r
+\r
+    # Replace quoted strings and digit separators.  Both single quotes\r
+    # and double quotes are processed in the same loop, otherwise\r
+    # nested quotes wouldn't work.\r
+    collapsed = ''\r
+    while True:\r
+      # Find the first quote character\r
+      match = Match(r'^([^\'"]*)([\'"])(.*)$', elided)\r
+      if not match:\r
+        collapsed += elided\r
+        break\r
+      head, quote, tail = match.groups()\r
+\r
+      if quote == '"':\r
+        # Collapse double quoted strings\r
+        second_quote = tail.find('"')\r
+        if second_quote >= 0:\r
+          collapsed += head + '""'\r
+          elided = tail[second_quote + 1:]\r
+        else:\r
+          # Unmatched double quote, don't bother processing the rest\r
+          # of the line since this is probably a multiline string.\r
+          collapsed += elided\r
+          break\r
+      else:\r
+        # Found single quote, check nearby text to eliminate digit separators.\r
+        #\r
+        # There is no special handling for floating point here, because\r
+        # the integer/fractional/exponent parts would all be parsed\r
+        # correctly as long as there are digits on both sides of the\r
+        # separator.  So we are fine as long as we don't see something\r
+        # like "0.'3" (gcc 4.9.0 will not allow this literal).\r
+        if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head):\r
+          match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail)\r
+          collapsed += head + match_literal.group(1).replace("'", '')\r
+          elided = match_literal.group(2)\r
+        else:\r
+          second_quote = tail.find('\'')\r
+          if second_quote >= 0:\r
+            collapsed += head + "''"\r
+            elided = tail[second_quote + 1:]\r
+          else:\r
+            # Unmatched single quote\r
+            collapsed += elided\r
+            break\r
+\r
+    return collapsed\r
+\r
+\r
+def FindEndOfExpressionInLine(line, startpos, stack):\r
+  """Find the position just after the end of current parenthesized expression.\r
+\r
+  Args:\r
+    line: a CleansedLines line.\r
+    startpos: start searching at this position.\r
+    stack: nesting stack at startpos.\r
+\r
+  Returns:\r
+    On finding matching end: (index just after matching end, None)\r
+    On finding an unclosed expression: (-1, None)\r
+    Otherwise: (-1, new stack at end of this line)\r
+  """\r
+  for i in xrange(startpos, len(line)):\r
+    char = line[i]\r
+    if char in '([{':\r
+      # Found start of parenthesized expression, push to expression stack\r
+      stack.append(char)\r
+    elif char == '<':\r
+      # Found potential start of template argument list\r
+      if i > 0 and line[i - 1] == '<':\r
+        # Left shift operator\r
+        if stack and stack[-1] == '<':\r
+          stack.pop()\r
+          if not stack:\r
+            return (-1, None)\r
+      elif i > 0 and Search(r'\boperator\s*$', line[0:i]):\r
+        # operator<, don't add to stack\r
+        continue\r
+      else:\r
+        # Tentative start of template argument list\r
+        stack.append('<')\r
+    elif char in ')]}':\r
+      # Found end of parenthesized expression.\r
+      #\r
+      # If we are currently expecting a matching '>', the pending '<'\r
+      # must have been an operator.  Remove them from expression stack.\r
+      while stack and stack[-1] == '<':\r
+        stack.pop()\r
+      if not stack:\r
+        return (-1, None)\r
+      if ((stack[-1] == '(' and char == ')') or\r
+          (stack[-1] == '[' and char == ']') or\r
+          (stack[-1] == '{' and char == '}')):\r
+        stack.pop()\r
+        if not stack:\r
+          return (i + 1, None)\r
+      else:\r
+        # Mismatched parentheses\r
+        return (-1, None)\r
+    elif char == '>':\r
+      # Found potential end of template argument list.\r
+\r
+      # Ignore "->" and operator functions\r
+      if (i > 0 and\r
+          (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))):\r
+        continue\r
+\r
+      # Pop the stack if there is a matching '<'.  Otherwise, ignore\r
+      # this '>' since it must be an operator.\r
+      if stack:\r
+        if stack[-1] == '<':\r
+          stack.pop()\r
+          if not stack:\r
+            return (i + 1, None)\r
+    elif char == ';':\r
+      # Found something that look like end of statements.  If we are currently\r
+      # expecting a '>', the matching '<' must have been an operator, since\r
+      # template argument list should not contain statements.\r
+      while stack and stack[-1] == '<':\r
+        stack.pop()\r
+      if not stack:\r
+        return (-1, None)\r
+\r
+  # Did not find end of expression or unbalanced parentheses on this line\r
+  return (-1, stack)\r
+\r
+\r
+def CloseExpression(clean_lines, linenum, pos):\r
+  """If input points to ( or { or [ or <, finds the position that closes it.\r
+\r
+  If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the\r
+  linenum/pos that correspond to the closing of the expression.\r
+\r
+  TODO(unknown): cpplint spends a fair bit of time matching parentheses.\r
+  Ideally we would want to index all opening and closing parentheses once\r
+  and have CloseExpression be just a simple lookup, but due to preprocessor\r
+  tricks, this is not so easy.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    pos: A position on the line.\r
+\r
+  Returns:\r
+    A tuple (line, linenum, pos) pointer *past* the closing brace, or\r
+    (line, len(lines), -1) if we never find a close.  Note we ignore\r
+    strings and comments when matching; and the line we return is the\r
+    'cleansed' line at linenum.\r
+  """\r
+\r
+  line = clean_lines.elided[linenum]\r
+  if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]):\r
+    return (line, clean_lines.NumLines(), -1)\r
+\r
+  # Check first line\r
+  (end_pos, stack) = FindEndOfExpressionInLine(line, pos, [])\r
+  if end_pos > -1:\r
+    return (line, linenum, end_pos)\r
+\r
+  # Continue scanning forward\r
+  while stack and linenum < clean_lines.NumLines() - 1:\r
+    linenum += 1\r
+    line = clean_lines.elided[linenum]\r
+    (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack)\r
+    if end_pos > -1:\r
+      return (line, linenum, end_pos)\r
+\r
+  # Did not find end of expression before end of file, give up\r
+  return (line, clean_lines.NumLines(), -1)\r
+\r
+\r
+def FindStartOfExpressionInLine(line, endpos, stack):\r
+  """Find position at the matching start of current expression.\r
+\r
+  This is almost the reverse of FindEndOfExpressionInLine, but note\r
+  that the input position and returned position differs by 1.\r
+\r
+  Args:\r
+    line: a CleansedLines line.\r
+    endpos: start searching at this position.\r
+    stack: nesting stack at endpos.\r
+\r
+  Returns:\r
+    On finding matching start: (index at matching start, None)\r
+    On finding an unclosed expression: (-1, None)\r
+    Otherwise: (-1, new stack at beginning of this line)\r
+  """\r
+  i = endpos\r
+  while i >= 0:\r
+    char = line[i]\r
+    if char in ')]}':\r
+      # Found end of expression, push to expression stack\r
+      stack.append(char)\r
+    elif char == '>':\r
+      # Found potential end of template argument list.\r
+      #\r
+      # Ignore it if it's a "->" or ">=" or "operator>"\r
+      if (i > 0 and\r
+          (line[i - 1] == '-' or\r
+           Match(r'\s>=\s', line[i - 1:]) or\r
+           Search(r'\boperator\s*$', line[0:i]))):\r
+        i -= 1\r
+      else:\r
+        stack.append('>')\r
+    elif char == '<':\r
+      # Found potential start of template argument list\r
+      if i > 0 and line[i - 1] == '<':\r
+        # Left shift operator\r
+        i -= 1\r
+      else:\r
+        # If there is a matching '>', we can pop the expression stack.\r
+        # Otherwise, ignore this '<' since it must be an operator.\r
+        if stack and stack[-1] == '>':\r
+          stack.pop()\r
+          if not stack:\r
+            return (i, None)\r
+    elif char in '([{':\r
+      # Found start of expression.\r
+      #\r
+      # If there are any unmatched '>' on the stack, they must be\r
+      # operators.  Remove those.\r
+      while stack and stack[-1] == '>':\r
+        stack.pop()\r
+      if not stack:\r
+        return (-1, None)\r
+      if ((char == '(' and stack[-1] == ')') or\r
+          (char == '[' and stack[-1] == ']') or\r
+          (char == '{' and stack[-1] == '}')):\r
+        stack.pop()\r
+        if not stack:\r
+          return (i, None)\r
+      else:\r
+        # Mismatched parentheses\r
+        return (-1, None)\r
+    elif char == ';':\r
+      # Found something that look like end of statements.  If we are currently\r
+      # expecting a '<', the matching '>' must have been an operator, since\r
+      # template argument list should not contain statements.\r
+      while stack and stack[-1] == '>':\r
+        stack.pop()\r
+      if not stack:\r
+        return (-1, None)\r
+\r
+    i -= 1\r
+\r
+  return (-1, stack)\r
+\r
+\r
+def ReverseCloseExpression(clean_lines, linenum, pos):\r
+  """If input points to ) or } or ] or >, finds the position that opens it.\r
+\r
+  If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the\r
+  linenum/pos that correspond to the opening of the expression.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    pos: A position on the line.\r
+\r
+  Returns:\r
+    A tuple (line, linenum, pos) pointer *at* the opening brace, or\r
+    (line, 0, -1) if we never find the matching opening brace.  Note\r
+    we ignore strings and comments when matching; and the line we\r
+    return is the 'cleansed' line at linenum.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+  if line[pos] not in ')}]>':\r
+    return (line, 0, -1)\r
+\r
+  # Check last line\r
+  (start_pos, stack) = FindStartOfExpressionInLine(line, pos, [])\r
+  if start_pos > -1:\r
+    return (line, linenum, start_pos)\r
+\r
+  # Continue scanning backward\r
+  while stack and linenum > 0:\r
+    linenum -= 1\r
+    line = clean_lines.elided[linenum]\r
+    (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack)\r
+    if start_pos > -1:\r
+      return (line, linenum, start_pos)\r
+\r
+  # Did not find start of expression before beginning of file, give up\r
+  return (line, 0, -1)\r
+\r
+\r
+def CheckForCopyright(filename, lines, error):\r
+  """Logs an error if no Copyright message appears at the top of the file."""\r
+\r
+  # We'll say it should occur by line 10. Don't forget there's a\r
+  # dummy line at the front.\r
+  for line in xrange(1, min(len(lines), 11)):\r
+    if re.search(r'Copyright', lines[line], re.I): break\r
+  else:                       # means no copyright line was found\r
+    error(filename, 0, 'legal/copyright', 5,\r
+          'No copyright message found.  '\r
+          'You should have a line: "Copyright [year] <Copyright Owner>"')\r
+\r
+\r
+def GetIndentLevel(line):\r
+  """Return the number of leading spaces in line.\r
+\r
+  Args:\r
+    line: A string to check.\r
+\r
+  Returns:\r
+    An integer count of leading spaces, possibly zero.\r
+  """\r
+  indent = Match(r'^( *)\S', line)\r
+  if indent:\r
+    return len(indent.group(1))\r
+  else:\r
+    return 0\r
+\r
+\r
+def GetHeaderGuardCPPVariable(filename):\r
+  """Returns the CPP variable that should be used as a header guard.\r
+\r
+  Args:\r
+    filename: The name of a C++ header file.\r
+\r
+  Returns:\r
+    The CPP variable that should be used as a header guard in the\r
+    named file.\r
+\r
+  """\r
+\r
+  # Restores original filename in case that cpplint is invoked from Emacs's\r
+  # flymake.\r
+  filename = re.sub(r'_flymake\.h$', '.h', filename)\r
+  filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)\r
+  # Replace 'c++' with 'cpp'.\r
+  filename = filename.replace('C++', 'cpp').replace('c++', 'cpp')\r
+\r
+  fileinfo = FileInfo(filename)\r
+  file_path_from_root = fileinfo.RepositoryName()\r
+  if _root:\r
+    suffix = os.sep\r
+    # On Windows using directory separator will leave us with\r
+    # "bogus escape error" unless we properly escape regex.\r
+    if suffix == '\\':\r
+      suffix += '\\'\r
+    file_path_from_root = re.sub('^' + _root + suffix, '', file_path_from_root)\r
+  return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'\r
+\r
+\r
+def CheckForHeaderGuard(filename, clean_lines, error):\r
+  """Checks that the file contains a header guard.\r
+\r
+  Logs an error if no #ifndef header guard is present.  For other\r
+  headers, checks that the full pathname is used.\r
+\r
+  Args:\r
+    filename: The name of the C++ header file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  # Don't check for header guards if there are error suppression\r
+  # comments somewhere in this file.\r
+  #\r
+  # Because this is silencing a warning for a nonexistent line, we\r
+  # only support the very specific NOLINT(build/header_guard) syntax,\r
+  # and not the general NOLINT or NOLINT(*) syntax.\r
+  raw_lines = clean_lines.lines_without_raw_strings\r
+  for i in raw_lines:\r
+    if Search(r'//\s*NOLINT\(build/header_guard\)', i):\r
+      return\r
+\r
+  cppvar = GetHeaderGuardCPPVariable(filename)\r
+\r
+  ifndef = ''\r
+  ifndef_linenum = 0\r
+  define = ''\r
+  endif = ''\r
+  endif_linenum = 0\r
+  for linenum, line in enumerate(raw_lines):\r
+    linesplit = line.split()\r
+    if len(linesplit) >= 2:\r
+      # find the first occurrence of #ifndef and #define, save arg\r
+      if not ifndef and linesplit[0] == '#ifndef':\r
+        # set ifndef to the header guard presented on the #ifndef line.\r
+        ifndef = linesplit[1]\r
+        ifndef_linenum = linenum\r
+      if not define and linesplit[0] == '#define':\r
+        define = linesplit[1]\r
+    # find the last occurrence of #endif, save entire line\r
+    if line.startswith('#endif'):\r
+      endif = line\r
+      endif_linenum = linenum\r
+\r
+  if not ifndef or not define or ifndef != define:\r
+    error(filename, 0, 'build/header_guard', 5,\r
+          'No #ifndef header guard found, suggested CPP variable is: %s' %\r
+          cppvar)\r
+    return\r
+\r
+  # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__\r
+  # for backward compatibility.\r
+  if ifndef != cppvar:\r
+    error_level = 0\r
+    if ifndef != cppvar + '_':\r
+      error_level = 5\r
+\r
+    ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum,\r
+                            error)\r
+    error(filename, ifndef_linenum, 'build/header_guard', error_level,\r
+          '#ifndef header guard has wrong style, please use: %s' % cppvar)\r
+\r
+  # Check for "//" comments on endif line.\r
+  ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum,\r
+                          error)\r
+  match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif)\r
+  if match:\r
+    if match.group(1) == '_':\r
+      # Issue low severity warning for deprecated double trailing underscore\r
+      error(filename, endif_linenum, 'build/header_guard', 0,\r
+            '#endif line should be "#endif  // %s"' % cppvar)\r
+    return\r
+\r
+  # Didn't find the corresponding "//" comment.  If this file does not\r
+  # contain any "//" comments at all, it could be that the compiler\r
+  # only wants "/**/" comments, look for those instead.\r
+  no_single_line_comments = True\r
+  for i in xrange(1, len(raw_lines) - 1):\r
+    line = raw_lines[i]\r
+    if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line):\r
+      no_single_line_comments = False\r
+      break\r
+\r
+  if no_single_line_comments:\r
+    match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif)\r
+    if match:\r
+      if match.group(1) == '_':\r
+        # Low severity warning for double trailing underscore\r
+        error(filename, endif_linenum, 'build/header_guard', 0,\r
+              '#endif line should be "#endif  /* %s */"' % cppvar)\r
+      return\r
+\r
+  # Didn't find anything\r
+  error(filename, endif_linenum, 'build/header_guard', 5,\r
+        '#endif line should be "#endif  // %s"' % cppvar)\r
+\r
+\r
+def CheckHeaderFileIncluded(filename, include_state, error):\r
+  """Logs an error if a .cc file does not include its header."""\r
+\r
+  # Do not check test files\r
+  fileinfo = FileInfo(filename)\r
+  if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()):\r
+    return\r
+\r
+  headerfile = filename[0:len(filename) - len(fileinfo.Extension())] + '.h'\r
+  if not os.path.exists(headerfile):\r
+    return\r
+  headername = FileInfo(headerfile).RepositoryName()\r
+  first_include = 0\r
+  for section_list in include_state.include_list:\r
+    for f in section_list:\r
+      if headername in f[0] or f[0] in headername:\r
+        return\r
+      if not first_include:\r
+        first_include = f[1]\r
+\r
+  error(filename, first_include, 'build/include', 5,\r
+        '%s should include its header file %s' % (fileinfo.RepositoryName(),\r
+                                                  headername))\r
+\r
+\r
+def CheckForBadCharacters(filename, lines, error):\r
+  """Logs an error for each line containing bad characters.\r
+\r
+  Two kinds of bad characters:\r
+\r
+  1. Unicode replacement characters: These indicate that either the file\r
+  contained invalid UTF-8 (likely) or Unicode replacement characters (which\r
+  it shouldn't).  Note that it's possible for this to throw off line\r
+  numbering if the invalid UTF-8 occurred adjacent to a newline.\r
+\r
+  2. NUL bytes.  These are problematic for some tools.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    lines: An array of strings, each representing a line of the file.\r
+    error: The function to call with any errors found.\r
+  """\r
+  for linenum, line in enumerate(lines):\r
+    if u'\ufffd' in line:\r
+      error(filename, linenum, 'readability/utf8', 5,\r
+            'Line contains invalid UTF-8 (or Unicode replacement character).')\r
+    if '\0' in line:\r
+      error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.')\r
+\r
+\r
+def CheckForNewlineAtEOF(filename, lines, error):\r
+  """Logs an error if there is no newline char at the end of the file.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    lines: An array of strings, each representing a line of the file.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  # The array lines() was created by adding two newlines to the\r
+  # original file (go figure), then splitting on \n.\r
+  # To verify that the file ends in \n, we just have to make sure the\r
+  # last-but-two element of lines() exists and is empty.\r
+  if len(lines) < 3 or lines[-2]:\r
+    error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,\r
+          'Could not find a newline character at the end of the file.')\r
+\r
+\r
+def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):\r
+  """Logs an error if we see /* ... */ or "..." that extend past one line.\r
+\r
+  /* ... */ comments are legit inside macros, for one line.\r
+  Otherwise, we prefer // comments, so it's ok to warn about the\r
+  other.  Likewise, it's ok for strings to extend across multiple\r
+  lines, as long as a line continuation character (backslash)\r
+  terminates each line. Although not currently prohibited by the C++\r
+  style guide, it's ugly and unnecessary. We don't do well with either\r
+  in this lint program, so we warn about both.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Remove all \\ (escaped backslashes) from the line. They are OK, and the\r
+  # second (escaped) slash may trigger later \" detection erroneously.\r
+  line = line.replace('\\\\', '')\r
+\r
+  if line.count('/*') > line.count('*/'):\r
+    error(filename, linenum, 'readability/multiline_comment', 5,\r
+          'Complex multi-line /*...*/-style comment found. '\r
+          'Lint may give bogus warnings.  '\r
+          'Consider replacing these with //-style comments, '\r
+          'with #if 0...#endif, '\r
+          'or with more clearly structured multi-line comments.')\r
+\r
+  if (line.count('"') - line.count('\\"')) % 2:\r
+    error(filename, linenum, 'readability/multiline_string', 5,\r
+          'Multi-line string ("...") found.  This lint script doesn\'t '\r
+          'do well with such strings, and may give bogus warnings.  '\r
+          'Use C++11 raw strings or concatenation instead.')\r
+\r
+\r
+# (non-threadsafe name, thread-safe alternative, validation pattern)\r
+#\r
+# The validation pattern is used to eliminate false positives such as:\r
+#  _rand();               // false positive due to substring match.\r
+#  ->rand();              // some member function rand().\r
+#  ACMRandom rand(seed);  // some variable named rand.\r
+#  ISAACRandom rand();    // another variable named rand.\r
+#\r
+# Basically we require the return value of these functions to be used\r
+# in some expression context on the same line by matching on some\r
+# operator before the function name.  This eliminates constructors and\r
+# member function calls.\r
+_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)'\r
+_THREADING_LIST = (\r
+    ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'),\r
+    ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'),\r
+    ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'),\r
+    ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'),\r
+    ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'),\r
+    ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'),\r
+    ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'),\r
+    ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'),\r
+    ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'),\r
+    ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'),\r
+    ('strtok(', 'strtok_r(',\r
+     _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'),\r
+    ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'),\r
+    )\r
+\r
+\r
+def CheckPosixThreading(filename, clean_lines, linenum, error):\r
+  """Checks for calls to thread-unsafe functions.\r
+\r
+  Much code has been originally written without consideration of\r
+  multi-threading. Also, engineers are relying on their old experience;\r
+  they have learned posix before threading extensions were added. These\r
+  tests guide the engineers to use thread-safe functions (when using\r
+  posix directly).\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+  for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST:\r
+    # Additional pattern matching check to confirm that this is the\r
+    # function we are looking for\r
+    if Search(pattern, line):\r
+      error(filename, linenum, 'runtime/threadsafe_fn', 2,\r
+            'Consider using ' + multithread_safe_func +\r
+            '...) instead of ' + single_thread_func +\r
+            '...) for improved thread safety.')\r
+\r
+\r
+def CheckVlogArguments(filename, clean_lines, linenum, error):\r
+  """Checks that VLOG() is only used for defining a logging level.\r
+\r
+  For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and\r
+  VLOG(FATAL) are not.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+  if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line):\r
+    error(filename, linenum, 'runtime/vlog', 5,\r
+          'VLOG() should be used with numeric verbosity level.  '\r
+          'Use LOG() if you want symbolic severity levels.')\r
+\r
+# Matches invalid increment: *count++, which moves pointer instead of\r
+# incrementing a value.\r
+_RE_PATTERN_INVALID_INCREMENT = re.compile(\r
+    r'^\s*\*\w+(\+\+|--);')\r
+\r
+\r
+def CheckInvalidIncrement(filename, clean_lines, linenum, error):\r
+  """Checks for invalid increment *count++.\r
+\r
+  For example following function:\r
+  void increment_counter(int* count) {\r
+    *count++;\r
+  }\r
+  is invalid, because it effectively does count++, moving pointer, and should\r
+  be replaced with ++*count, (*count)++ or *count += 1.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+  if _RE_PATTERN_INVALID_INCREMENT.match(line):\r
+    error(filename, linenum, 'runtime/invalid_increment', 5,\r
+          'Changing pointer instead of value (or unused value of operator*).')\r
+\r
+\r
+def IsMacroDefinition(clean_lines, linenum):\r
+  if Search(r'^#define', clean_lines[linenum]):\r
+    return True\r
+\r
+  if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]):\r
+    return True\r
+\r
+  return False\r
+\r
+\r
+def IsForwardClassDeclaration(clean_lines, linenum):\r
+  return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum])\r
+\r
+\r
+class _BlockInfo(object):\r
+  """Stores information about a generic block of code."""\r
+\r
+  def __init__(self, linenum, seen_open_brace):\r
+    self.starting_linenum = linenum\r
+    self.seen_open_brace = seen_open_brace\r
+    self.open_parentheses = 0\r
+    self.inline_asm = _NO_ASM\r
+    self.check_namespace_indentation = False\r
+\r
+  def CheckBegin(self, filename, clean_lines, linenum, error):\r
+    """Run checks that applies to text up to the opening brace.\r
+\r
+    This is mostly for checking the text after the class identifier\r
+    and the "{", usually where the base class is specified.  For other\r
+    blocks, there isn't much to check, so we always pass.\r
+\r
+    Args:\r
+      filename: The name of the current file.\r
+      clean_lines: A CleansedLines instance containing the file.\r
+      linenum: The number of the line to check.\r
+      error: The function to call with any errors found.\r
+    """\r
+    pass\r
+\r
+  def CheckEnd(self, filename, clean_lines, linenum, error):\r
+    """Run checks that applies to text after the closing brace.\r
+\r
+    This is mostly used for checking end of namespace comments.\r
+\r
+    Args:\r
+      filename: The name of the current file.\r
+      clean_lines: A CleansedLines instance containing the file.\r
+      linenum: The number of the line to check.\r
+      error: The function to call with any errors found.\r
+    """\r
+    pass\r
+\r
+  def IsBlockInfo(self):\r
+    """Returns true if this block is a _BlockInfo.\r
+\r
+    This is convenient for verifying that an object is an instance of\r
+    a _BlockInfo, but not an instance of any of the derived classes.\r
+\r
+    Returns:\r
+      True for this class, False for derived classes.\r
+    """\r
+    return self.__class__ == _BlockInfo\r
+\r
+\r
+class _ExternCInfo(_BlockInfo):\r
+  """Stores information about an 'extern "C"' block."""\r
+\r
+  def __init__(self, linenum):\r
+    _BlockInfo.__init__(self, linenum, True)\r
+\r
+\r
+class _ClassInfo(_BlockInfo):\r
+  """Stores information about a class."""\r
+\r
+  def __init__(self, name, class_or_struct, clean_lines, linenum):\r
+    _BlockInfo.__init__(self, linenum, False)\r
+    self.name = name\r
+    self.is_derived = False\r
+    self.check_namespace_indentation = True\r
+    if class_or_struct == 'struct':\r
+      self.access = 'public'\r
+      self.is_struct = True\r
+    else:\r
+      self.access = 'private'\r
+      self.is_struct = False\r
+\r
+    # Remember initial indentation level for this class.  Using raw_lines here\r
+    # instead of elided to account for leading comments.\r
+    self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum])\r
+\r
+    # Try to find the end of the class.  This will be confused by things like:\r
+    #   class A {\r
+    #   } *x = { ...\r
+    #\r
+    # But it's still good enough for CheckSectionSpacing.\r
+    self.last_line = 0\r
+    depth = 0\r
+    for i in range(linenum, clean_lines.NumLines()):\r
+      line = clean_lines.elided[i]\r
+      depth += line.count('{') - line.count('}')\r
+      if not depth:\r
+        self.last_line = i\r
+        break\r
+\r
+  def CheckBegin(self, filename, clean_lines, linenum, error):\r
+    # Look for a bare ':'\r
+    if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):\r
+      self.is_derived = True\r
+\r
+  def CheckEnd(self, filename, clean_lines, linenum, error):\r
+    # If there is a DISALLOW macro, it should appear near the end of\r
+    # the class.\r
+    seen_last_thing_in_class = False\r
+    for i in xrange(linenum - 1, self.starting_linenum, -1):\r
+      match = Search(\r
+          r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' +\r
+          self.name + r'\)',\r
+          clean_lines.elided[i])\r
+      if match:\r
+        if seen_last_thing_in_class:\r
+          error(filename, i, 'readability/constructors', 3,\r
+                match.group(1) + ' should be the last thing in the class')\r
+        break\r
+\r
+      if not Match(r'^\s*$', clean_lines.elided[i]):\r
+        seen_last_thing_in_class = True\r
+\r
+    # Check that closing brace is aligned with beginning of the class.\r
+    # Only do this if the closing brace is indented by only whitespaces.\r
+    # This means we will not check single-line class definitions.\r
+    indent = Match(r'^( *)\}', clean_lines.elided[linenum])\r
+    if indent and len(indent.group(1)) != self.class_indent:\r
+      if self.is_struct:\r
+        parent = 'struct ' + self.name\r
+      else:\r
+        parent = 'class ' + self.name\r
+      error(filename, linenum, 'whitespace/indent', 3,\r
+            'Closing brace should be aligned with beginning of %s' % parent)\r
+\r
+\r
+class _NamespaceInfo(_BlockInfo):\r
+  """Stores information about a namespace."""\r
+\r
+  def __init__(self, name, linenum):\r
+    _BlockInfo.__init__(self, linenum, False)\r
+    self.name = name or ''\r
+    self.check_namespace_indentation = True\r
+\r
+  def CheckEnd(self, filename, clean_lines, linenum, error):\r
+    """Check end of namespace comments."""\r
+    line = clean_lines.raw_lines[linenum]\r
+\r
+    # Check how many lines is enclosed in this namespace.  Don't issue\r
+    # warning for missing namespace comments if there aren't enough\r
+    # lines.  However, do apply checks if there is already an end of\r
+    # namespace comment and it's incorrect.\r
+    #\r
+    # TODO(unknown): We always want to check end of namespace comments\r
+    # if a namespace is large, but sometimes we also want to apply the\r
+    # check if a short namespace contained nontrivial things (something\r
+    # other than forward declarations).  There is currently no logic on\r
+    # deciding what these nontrivial things are, so this check is\r
+    # triggered by namespace size only, which works most of the time.\r
+    if (linenum - self.starting_linenum < 10\r
+        and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)):\r
+      return\r
+\r
+    # Look for matching comment at end of namespace.\r
+    #\r
+    # Note that we accept C style "/* */" comments for terminating\r
+    # namespaces, so that code that terminate namespaces inside\r
+    # preprocessor macros can be cpplint clean.\r
+    #\r
+    # We also accept stuff like "// end of namespace <name>." with the\r
+    # period at the end.\r
+    #\r
+    # Besides these, we don't accept anything else, otherwise we might\r
+    # get false negatives when existing comment is a substring of the\r
+    # expected namespace.\r
+    if self.name:\r
+      # Named namespace\r
+      if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' +\r
+                    re.escape(self.name) + r'[\*/\.\\\s]*$'),\r
+                   line):\r
+        error(filename, linenum, 'readability/namespace', 5,\r
+              'Namespace should be terminated with "// namespace %s"' %\r
+              self.name)\r
+    else:\r
+      # Anonymous namespace\r
+      if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):\r
+        # If "// namespace anonymous" or "// anonymous namespace (more text)",\r
+        # mention "// anonymous namespace" as an acceptable form\r
+        if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line):\r
+          error(filename, linenum, 'readability/namespace', 5,\r
+                'Anonymous namespace should be terminated with "// namespace"'\r
+                ' or "// anonymous namespace"')\r
+        else:\r
+          error(filename, linenum, 'readability/namespace', 5,\r
+                'Anonymous namespace should be terminated with "// namespace"')\r
+\r
+\r
+class _PreprocessorInfo(object):\r
+  """Stores checkpoints of nesting stacks when #if/#else is seen."""\r
+\r
+  def __init__(self, stack_before_if):\r
+    # The entire nesting stack before #if\r
+    self.stack_before_if = stack_before_if\r
+\r
+    # The entire nesting stack up to #else\r
+    self.stack_before_else = []\r
+\r
+    # Whether we have already seen #else or #elif\r
+    self.seen_else = False\r
+\r
+\r
+class NestingState(object):\r
+  """Holds states related to parsing braces."""\r
+\r
+  def __init__(self):\r
+    # Stack for tracking all braces.  An object is pushed whenever we\r
+    # see a "{", and popped when we see a "}".  Only 3 types of\r
+    # objects are possible:\r
+    # - _ClassInfo: a class or struct.\r
+    # - _NamespaceInfo: a namespace.\r
+    # - _BlockInfo: some other type of block.\r
+    self.stack = []\r
+\r
+    # Top of the previous stack before each Update().\r
+    #\r
+    # Because the nesting_stack is updated at the end of each line, we\r
+    # had to do some convoluted checks to find out what is the current\r
+    # scope at the beginning of the line.  This check is simplified by\r
+    # saving the previous top of nesting stack.\r
+    #\r
+    # We could save the full stack, but we only need the top.  Copying\r
+    # the full nesting stack would slow down cpplint by ~10%.\r
+    self.previous_stack_top = []\r
+\r
+    # Stack of _PreprocessorInfo objects.\r
+    self.pp_stack = []\r
+\r
+  def SeenOpenBrace(self):\r
+    """Check if we have seen the opening brace for the innermost block.\r
+\r
+    Returns:\r
+      True if we have seen the opening brace, False if the innermost\r
+      block is still expecting an opening brace.\r
+    """\r
+    return (not self.stack) or self.stack[-1].seen_open_brace\r
+\r
+  def InNamespaceBody(self):\r
+    """Check if we are currently one level inside a namespace body.\r
+\r
+    Returns:\r
+      True if top of the stack is a namespace block, False otherwise.\r
+    """\r
+    return self.stack and isinstance(self.stack[-1], _NamespaceInfo)\r
+\r
+  def InExternC(self):\r
+    """Check if we are currently one level inside an 'extern "C"' block.\r
+\r
+    Returns:\r
+      True if top of the stack is an extern block, False otherwise.\r
+    """\r
+    return self.stack and isinstance(self.stack[-1], _ExternCInfo)\r
+\r
+  def InClassDeclaration(self):\r
+    """Check if we are currently one level inside a class or struct declaration.\r
+\r
+    Returns:\r
+      True if top of the stack is a class/struct, False otherwise.\r
+    """\r
+    return self.stack and isinstance(self.stack[-1], _ClassInfo)\r
+\r
+  def InAsmBlock(self):\r
+    """Check if we are currently one level inside an inline ASM block.\r
+\r
+    Returns:\r
+      True if the top of the stack is a block containing inline ASM.\r
+    """\r
+    return self.stack and self.stack[-1].inline_asm != _NO_ASM\r
+\r
+  def InTemplateArgumentList(self, clean_lines, linenum, pos):\r
+    """Check if current position is inside template argument list.\r
+\r
+    Args:\r
+      clean_lines: A CleansedLines instance containing the file.\r
+      linenum: The number of the line to check.\r
+      pos: position just after the suspected template argument.\r
+    Returns:\r
+      True if (linenum, pos) is inside template arguments.\r
+    """\r
+    while linenum < clean_lines.NumLines():\r
+      # Find the earliest character that might indicate a template argument\r
+      line = clean_lines.elided[linenum]\r
+      match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:])\r
+      if not match:\r
+        linenum += 1\r
+        pos = 0\r
+        continue\r
+      token = match.group(1)\r
+      pos += len(match.group(0))\r
+\r
+      # These things do not look like template argument list:\r
+      #   class Suspect {\r
+      #   class Suspect x; }\r
+      if token in ('{', '}', ';'): return False\r
+\r
+      # These things look like template argument list:\r
+      #   template <class Suspect>\r
+      #   template <class Suspect = default_value>\r
+      #   template <class Suspect[]>\r
+      #   template <class Suspect...>\r
+      if token in ('>', '=', '[', ']', '.'): return True\r
+\r
+      # Check if token is an unmatched '<'.\r
+      # If not, move on to the next character.\r
+      if token != '<':\r
+        pos += 1\r
+        if pos >= len(line):\r
+          linenum += 1\r
+          pos = 0\r
+        continue\r
+\r
+      # We can't be sure if we just find a single '<', and need to\r
+      # find the matching '>'.\r
+      (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1)\r
+      if end_pos < 0:\r
+        # Not sure if template argument list or syntax error in file\r
+        return False\r
+      linenum = end_line\r
+      pos = end_pos\r
+    return False\r
+\r
+  def UpdatePreprocessor(self, line):\r
+    """Update preprocessor stack.\r
+\r
+    We need to handle preprocessors due to classes like this:\r
+      #ifdef SWIG\r
+      struct ResultDetailsPageElementExtensionPoint {\r
+      #else\r
+      struct ResultDetailsPageElementExtensionPoint : public Extension {\r
+      #endif\r
+\r
+    We make the following assumptions (good enough for most files):\r
+    - Preprocessor condition evaluates to true from #if up to first\r
+      #else/#elif/#endif.\r
+\r
+    - Preprocessor condition evaluates to false from #else/#elif up\r
+      to #endif.  We still perform lint checks on these lines, but\r
+      these do not affect nesting stack.\r
+\r
+    Args:\r
+      line: current line to check.\r
+    """\r
+    if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):\r
+      # Beginning of #if block, save the nesting stack here.  The saved\r
+      # stack will allow us to restore the parsing state in the #else case.\r
+      self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))\r
+    elif Match(r'^\s*#\s*(else|elif)\b', line):\r
+      # Beginning of #else block\r
+      if self.pp_stack:\r
+        if not self.pp_stack[-1].seen_else:\r
+          # This is the first #else or #elif block.  Remember the\r
+          # whole nesting stack up to this point.  This is what we\r
+          # keep after the #endif.\r
+          self.pp_stack[-1].seen_else = True\r
+          self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)\r
+\r
+        # Restore the stack to how it was before the #if\r
+        self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)\r
+      else:\r
+        # TODO(unknown): unexpected #else, issue warning?\r
+        pass\r
+    elif Match(r'^\s*#\s*endif\b', line):\r
+      # End of #if or #else blocks.\r
+      if self.pp_stack:\r
+        # If we saw an #else, we will need to restore the nesting\r
+        # stack to its former state before the #else, otherwise we\r
+        # will just continue from where we left off.\r
+        if self.pp_stack[-1].seen_else:\r
+          # Here we can just use a shallow copy since we are the last\r
+          # reference to it.\r
+          self.stack = self.pp_stack[-1].stack_before_else\r
+        # Drop the corresponding #if\r
+        self.pp_stack.pop()\r
+      else:\r
+        # TODO(unknown): unexpected #endif, issue warning?\r
+        pass\r
+\r
+  # TODO(unknown): Update() is too long, but we will refactor later.\r
+  def Update(self, filename, clean_lines, linenum, error):\r
+    """Update nesting state with current line.\r
+\r
+    Args:\r
+      filename: The name of the current file.\r
+      clean_lines: A CleansedLines instance containing the file.\r
+      linenum: The number of the line to check.\r
+      error: The function to call with any errors found.\r
+    """\r
+    line = clean_lines.elided[linenum]\r
+\r
+    # Remember top of the previous nesting stack.\r
+    #\r
+    # The stack is always pushed/popped and not modified in place, so\r
+    # we can just do a shallow copy instead of copy.deepcopy.  Using\r
+    # deepcopy would slow down cpplint by ~28%.\r
+    if self.stack:\r
+      self.previous_stack_top = self.stack[-1]\r
+    else:\r
+      self.previous_stack_top = None\r
+\r
+    # Update pp_stack\r
+    self.UpdatePreprocessor(line)\r
+\r
+    # Count parentheses.  This is to avoid adding struct arguments to\r
+    # the nesting stack.\r
+    if self.stack:\r
+      inner_block = self.stack[-1]\r
+      depth_change = line.count('(') - line.count(')')\r
+      inner_block.open_parentheses += depth_change\r
+\r
+      # Also check if we are starting or ending an inline assembly block.\r
+      if inner_block.inline_asm in (_NO_ASM, _END_ASM):\r
+        if (depth_change != 0 and\r
+            inner_block.open_parentheses == 1 and\r
+            _MATCH_ASM.match(line)):\r
+          # Enter assembly block\r
+          inner_block.inline_asm = _INSIDE_ASM\r
+        else:\r
+          # Not entering assembly block.  If previous line was _END_ASM,\r
+          # we will now shift to _NO_ASM state.\r
+          inner_block.inline_asm = _NO_ASM\r
+      elif (inner_block.inline_asm == _INSIDE_ASM and\r
+            inner_block.open_parentheses == 0):\r
+        # Exit assembly block\r
+        inner_block.inline_asm = _END_ASM\r
+\r
+    # Consume namespace declaration at the beginning of the line.  Do\r
+    # this in a loop so that we catch same line declarations like this:\r
+    #   namespace proto2 { namespace bridge { class MessageSet; } }\r
+    while True:\r
+      # Match start of namespace.  The "\b\s*" below catches namespace\r
+      # declarations even if it weren't followed by a whitespace, this\r
+      # is so that we don't confuse our namespace checker.  The\r
+      # missing spaces will be flagged by CheckSpacing.\r
+      namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)\r
+      if not namespace_decl_match:\r
+        break\r
+\r
+      new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)\r
+      self.stack.append(new_namespace)\r
+\r
+      line = namespace_decl_match.group(2)\r
+      if line.find('{') != -1:\r
+        new_namespace.seen_open_brace = True\r
+        line = line[line.find('{') + 1:]\r
+\r
+    # Look for a class declaration in whatever is left of the line\r
+    # after parsing namespaces.  The regexp accounts for decorated classes\r
+    # such as in:\r
+    #   class LOCKABLE API Object {\r
+    #   };\r
+    class_decl_match = Match(\r
+        r'^(\s*(?:template\s*<[\w\s<>,:]*>\s*)?'\r
+        r'(class|struct)\s+(?:[A-Z_]+\s+)*(\w+(?:::\w+)*))'\r
+        r'(.*)$', line)\r
+    if (class_decl_match and\r
+        (not self.stack or self.stack[-1].open_parentheses == 0)):\r
+      # We do not want to accept classes that are actually template arguments:\r
+      #   template <class Ignore1,\r
+      #             class Ignore2 = Default<Args>,\r
+      #             template <Args> class Ignore3>\r
+      #   void Function() {};\r
+      #\r
+      # To avoid template argument cases, we scan forward and look for\r
+      # an unmatched '>'.  If we see one, assume we are inside a\r
+      # template argument list.\r
+      end_declaration = len(class_decl_match.group(1))\r
+      if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration):\r
+        self.stack.append(_ClassInfo(\r
+            class_decl_match.group(3), class_decl_match.group(2),\r
+            clean_lines, linenum))\r
+        line = class_decl_match.group(4)\r
+\r
+    # If we have not yet seen the opening brace for the innermost block,\r
+    # run checks here.\r
+    if not self.SeenOpenBrace():\r
+      self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)\r
+\r
+    # Update access control if we are inside a class/struct\r
+    if self.stack and isinstance(self.stack[-1], _ClassInfo):\r
+      classinfo = self.stack[-1]\r
+      access_match = Match(\r
+          r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?'\r
+          r':(?:[^:]|$)',\r
+          line)\r
+      if access_match:\r
+        classinfo.access = access_match.group(2)\r
+\r
+        # Check that access keywords are indented +1 space.  Skip this\r
+        # check if the keywords are not preceded by whitespaces.\r
+        indent = access_match.group(1)\r
+        if (len(indent) != classinfo.class_indent + 1 and\r
+            Match(r'^\s*$', indent)):\r
+          if classinfo.is_struct:\r
+            parent = 'struct ' + classinfo.name\r
+          else:\r
+            parent = 'class ' + classinfo.name\r
+          slots = ''\r
+          if access_match.group(3):\r
+            slots = access_match.group(3)\r
+          error(filename, linenum, 'whitespace/indent', 3,\r
+                '%s%s: should be indented +1 space inside %s' % (\r
+                    access_match.group(2), slots, parent))\r
+\r
+    # Consume braces or semicolons from what's left of the line\r
+    while True:\r
+      # Match first brace, semicolon, or closed parenthesis.\r
+      matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)\r
+      if not matched:\r
+        break\r
+\r
+      token = matched.group(1)\r
+      if token == '{':\r
+        # If namespace or class hasn't seen a opening brace yet, mark\r
+        # namespace/class head as complete.  Push a new block onto the\r
+        # stack otherwise.\r
+        if not self.SeenOpenBrace():\r
+          self.stack[-1].seen_open_brace = True\r
+        elif Match(r'^extern\s*"[^"]*"\s*\{', line):\r
+          self.stack.append(_ExternCInfo(linenum))\r
+        else:\r
+          self.stack.append(_BlockInfo(linenum, True))\r
+          if _MATCH_ASM.match(line):\r
+            self.stack[-1].inline_asm = _BLOCK_ASM\r
+\r
+      elif token == ';' or token == ')':\r
+        # If we haven't seen an opening brace yet, but we already saw\r
+        # a semicolon, this is probably a forward declaration.  Pop\r
+        # the stack for these.\r
+        #\r
+        # Similarly, if we haven't seen an opening brace yet, but we\r
+        # already saw a closing parenthesis, then these are probably\r
+        # function arguments with extra "class" or "struct" keywords.\r
+        # Also pop these stack for these.\r
+        if not self.SeenOpenBrace():\r
+          self.stack.pop()\r
+      else:  # token == '}'\r
+        # Perform end of block checks and pop the stack.\r
+        if self.stack:\r
+          self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)\r
+          self.stack.pop()\r
+      line = matched.group(2)\r
+\r
+  def InnermostClass(self):\r
+    """Get class info on the top of the stack.\r
+\r
+    Returns:\r
+      A _ClassInfo object if we are inside a class, or None otherwise.\r
+    """\r
+    for i in range(len(self.stack), 0, -1):\r
+      classinfo = self.stack[i - 1]\r
+      if isinstance(classinfo, _ClassInfo):\r
+        return classinfo\r
+    return None\r
+\r
+  def CheckCompletedBlocks(self, filename, error):\r
+    """Checks that all classes and namespaces have been completely parsed.\r
+\r
+    Call this when all lines in a file have been processed.\r
+    Args:\r
+      filename: The name of the current file.\r
+      error: The function to call with any errors found.\r
+    """\r
+    # Note: This test can result in false positives if #ifdef constructs\r
+    # get in the way of brace matching. See the testBuildClass test in\r
+    # cpplint_unittest.py for an example of this.\r
+    for obj in self.stack:\r
+      if isinstance(obj, _ClassInfo):\r
+        error(filename, obj.starting_linenum, 'build/class', 5,\r
+              'Failed to find complete declaration of class %s' %\r
+              obj.name)\r
+      elif isinstance(obj, _NamespaceInfo):\r
+        error(filename, obj.starting_linenum, 'build/namespaces', 5,\r
+              'Failed to find complete declaration of namespace %s' %\r
+              obj.name)\r
+\r
+\r
+def CheckForNonStandardConstructs(filename, clean_lines, linenum,\r
+                                  nesting_state, error):\r
+  r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.\r
+\r
+  Complain about several constructs which gcc-2 accepts, but which are\r
+  not standard C++.  Warning about these in lint is one way to ease the\r
+  transition to new compilers.\r
+  - put storage class first (e.g. "static const" instead of "const static").\r
+  - "%lld" instead of %qd" in printf-type functions.\r
+  - "%1$d" is non-standard in printf-type functions.\r
+  - "\%" is an undefined character escape sequence.\r
+  - text after #endif is not allowed.\r
+  - invalid inner-style forward declaration.\r
+  - >? and <? operators, and their >?= and <?= cousins.\r
+\r
+  Additionally, check for constructor/destructor style violations and reference\r
+  members, as it is very convenient to do so while checking for\r
+  gcc-2 compliance.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    error: A callable to which errors are reported, which takes 4 arguments:\r
+           filename, line number, error level, and message\r
+  """\r
+\r
+  # Remove comments from the line, but leave in strings for now.\r
+  line = clean_lines.lines[linenum]\r
+\r
+  if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):\r
+    error(filename, linenum, 'runtime/printf_format', 3,\r
+          '%q in format strings is deprecated.  Use %ll instead.')\r
+\r
+  if Search(r'printf\s*\(.*".*%\d+\$', line):\r
+    error(filename, linenum, 'runtime/printf_format', 2,\r
+          '%N$ formats are unconventional.  Try rewriting to avoid them.')\r
+\r
+  # Remove escaped backslashes before looking for undefined escapes.\r
+  line = line.replace('\\\\', '')\r
+\r
+  if Search(r'("|\').*\\(%|\[|\(|{)', line):\r
+    error(filename, linenum, 'build/printf_format', 3,\r
+          '%, [, (, and { are undefined character escapes.  Unescape them.')\r
+\r
+  # For the rest, work with both comments and strings removed.\r
+  line = clean_lines.elided[linenum]\r
+\r
+  if Search(r'\b(const|volatile|void|char|short|int|long'\r
+            r'|float|double|signed|unsigned'\r
+            r'|schar|u?int8|u?int16|u?int32|u?int64)'\r
+            r'\s+(register|static|extern|typedef)\b',\r
+            line):\r
+    error(filename, linenum, 'build/storage_class', 5,\r
+          'Storage-class specifier (static, extern, typedef, etc) should be '\r
+          'at the beginning of the declaration.')\r
+\r
+  if Match(r'\s*#\s*endif\s*[^/\s]+', line):\r
+    error(filename, linenum, 'build/endif_comment', 5,\r
+          'Uncommented text after #endif is non-standard.  Use a comment.')\r
+\r
+  if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):\r
+    error(filename, linenum, 'build/forward_decl', 5,\r
+          'Inner-style forward declarations are invalid.  Remove this line.')\r
+\r
+  if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',\r
+            line):\r
+    error(filename, linenum, 'build/deprecated', 3,\r
+          '>? and <? (max and min) operators are non-standard and deprecated.')\r
+\r
+  if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):\r
+    # TODO(unknown): Could it be expanded safely to arbitrary references,\r
+    # without triggering too many false positives? The first\r
+    # attempt triggered 5 warnings for mostly benign code in the regtest, hence\r
+    # the restriction.\r
+    # Here's the original regexp, for the reference:\r
+    # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'\r
+    # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'\r
+    error(filename, linenum, 'runtime/member_string_references', 2,\r
+          'const string& members are dangerous. It is much better to use '\r
+          'alternatives, such as pointers or simple constants.')\r
+\r
+  # Everything else in this function operates on class declarations.\r
+  # Return early if the top of the nesting stack is not a class, or if\r
+  # the class head is not completed yet.\r
+  classinfo = nesting_state.InnermostClass()\r
+  if not classinfo or not classinfo.seen_open_brace:\r
+    return\r
+\r
+  # The class may have been declared with namespace or classname qualifiers.\r
+  # The constructor and destructor will not have those qualifiers.\r
+  base_classname = classinfo.name.split('::')[-1]\r
+\r
+  # Look for single-argument constructors that aren't marked explicit.\r
+  # Technically a valid construct, but against style.\r
+  explicit_constructor_match = Match(\r
+      r'\s+(?:(?:inline|constexpr)\s+)*(explicit\s+)?'\r
+      r'(?:(?:inline|constexpr)\s+)*%s\s*'\r
+      r'\(((?:[^()]|\([^()]*\))*)\)'\r
+      % re.escape(base_classname),\r
+      line)\r
+\r
+  if explicit_constructor_match:\r
+    is_marked_explicit = explicit_constructor_match.group(1)\r
+\r
+    if not explicit_constructor_match.group(2):\r
+      constructor_args = []\r
+    else:\r
+      constructor_args = explicit_constructor_match.group(2).split(',')\r
+\r
+    # collapse arguments so that commas in template parameter lists and function\r
+    # argument parameter lists don't split arguments in two\r
+    i = 0\r
+    while i < len(constructor_args):\r
+      constructor_arg = constructor_args[i]\r
+      while (constructor_arg.count('<') > constructor_arg.count('>') or\r
+             constructor_arg.count('(') > constructor_arg.count(')')):\r
+        constructor_arg += ',' + constructor_args[i + 1]\r
+        del constructor_args[i + 1]\r
+      constructor_args[i] = constructor_arg\r
+      i += 1\r
+\r
+    defaulted_args = [arg for arg in constructor_args if '=' in arg]\r
+    noarg_constructor = (not constructor_args or  # empty arg list\r
+                         # 'void' arg specifier\r
+                         (len(constructor_args) == 1 and\r
+                          constructor_args[0].strip() == 'void'))\r
+    onearg_constructor = ((len(constructor_args) == 1 and  # exactly one arg\r
+                           not noarg_constructor) or\r
+                          # all but at most one arg defaulted\r
+                          (len(constructor_args) >= 1 and\r
+                           not noarg_constructor and\r
+                           len(defaulted_args) >= len(constructor_args) - 1))\r
+    initializer_list_constructor = bool(\r
+        onearg_constructor and\r
+        Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))\r
+    copy_constructor = bool(\r
+        onearg_constructor and\r
+        Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'\r
+              % re.escape(base_classname), constructor_args[0].strip()))\r
+\r
+    if (not is_marked_explicit and\r
+        onearg_constructor and\r
+        not initializer_list_constructor and\r
+        not copy_constructor):\r
+      if defaulted_args:\r
+        error(filename, linenum, 'runtime/explicit', 5,\r
+              'Constructors callable with one argument '\r
+              'should be marked explicit.')\r
+      else:\r
+        error(filename, linenum, 'runtime/explicit', 5,\r
+              'Single-parameter constructors should be marked explicit.')\r
+    elif is_marked_explicit and not onearg_constructor:\r
+      if noarg_constructor:\r
+        error(filename, linenum, 'runtime/explicit', 5,\r
+              'Zero-parameter constructors should not be marked explicit.')\r
+\r
+\r
+def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):\r
+  """Checks for the correctness of various spacing around function calls.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Since function calls often occur inside if/for/while/switch\r
+  # expressions - which have their own, more liberal conventions - we\r
+  # first see if we should be looking inside such an expression for a\r
+  # function call, to which we can apply more strict standards.\r
+  fncall = line    # if there's no control flow construct, look at whole line\r
+  for pattern in (r'\bif\s*\((.*)\)\s*{',\r
+                  r'\bfor\s*\((.*)\)\s*{',\r
+                  r'\bwhile\s*\((.*)\)\s*[{;]',\r
+                  r'\bswitch\s*\((.*)\)\s*{'):\r
+    match = Search(pattern, line)\r
+    if match:\r
+      fncall = match.group(1)    # look inside the parens for function calls\r
+      break\r
+\r
+  # Except in if/for/while/switch, there should never be space\r
+  # immediately inside parens (eg "f( 3, 4 )").  We make an exception\r
+  # for nested parens ( (a+b) + c ).  Likewise, there should never be\r
+  # a space before a ( when it's a function argument.  I assume it's a\r
+  # function argument when the char before the whitespace is legal in\r
+  # a function name (alnum + _) and we're not starting a macro. Also ignore\r
+  # pointers and references to arrays and functions coz they're too tricky:\r
+  # we use a very simple way to recognize these:\r
+  # " (something)(maybe-something)" or\r
+  # " (something)(maybe-something," or\r
+  # " (something)[something]"\r
+  # Note that we assume the contents of [] to be short enough that\r
+  # they'll never need to wrap.\r
+  if (  # Ignore control structures.\r
+      not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b',\r
+                 fncall) and\r
+      # Ignore pointers/references to functions.\r
+      not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and\r
+      # Ignore pointers/references to arrays.\r
+      not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):\r
+    if Search(r'\w\s*\(\s(?!\s*\\$)', fncall):      # a ( used for a fn call\r
+      error(filename, linenum, 'whitespace/parens', 4,\r
+            'Extra space after ( in function call')\r
+    elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):\r
+      error(filename, linenum, 'whitespace/parens', 2,\r
+            'Extra space after (')\r
+    if (Search(r'\w\s+\(', fncall) and\r
+        not Search(r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall) and\r
+        not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and\r
+        not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and\r
+        not Search(r'\bcase\s+\(', fncall)):\r
+      # TODO(unknown): Space after an operator function seem to be a common\r
+      # error, silence those for now by restricting them to highest verbosity.\r
+      if Search(r'\boperator_*\b', line):\r
+        error(filename, linenum, 'whitespace/parens', 0,\r
+              'Extra space before ( in function call')\r
+      else:\r
+        error(filename, linenum, 'whitespace/parens', 4,\r
+              'Extra space before ( in function call')\r
+    # If the ) is followed only by a newline or a { + newline, assume it's\r
+    # part of a control statement (if/while/etc), and don't complain\r
+    if Search(r'[^)]\s+\)\s*[^{\s]', fncall):\r
+      # If the closing parenthesis is preceded by only whitespaces,\r
+      # try to give a more descriptive error message.\r
+      if Search(r'^\s+\)', fncall):\r
+        error(filename, linenum, 'whitespace/parens', 2,\r
+              'Closing ) should be moved to the previous line')\r
+      else:\r
+        error(filename, linenum, 'whitespace/parens', 2,\r
+              'Extra space before )')\r
+\r
+\r
+def IsBlankLine(line):\r
+  """Returns true if the given line is blank.\r
+\r
+  We consider a line to be blank if the line is empty or consists of\r
+  only white spaces.\r
+\r
+  Args:\r
+    line: A line of a string.\r
+\r
+  Returns:\r
+    True, if the given line is blank.\r
+  """\r
+  return not line or line.isspace()\r
+\r
+\r
+def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,\r
+                                 error):\r
+  is_namespace_indent_item = (\r
+      len(nesting_state.stack) > 1 and\r
+      nesting_state.stack[-1].check_namespace_indentation and\r
+      isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and\r
+      nesting_state.previous_stack_top == nesting_state.stack[-2])\r
+\r
+  if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,\r
+                                     clean_lines.elided, line):\r
+    CheckItemIndentationInNamespace(filename, clean_lines.elided,\r
+                                    line, error)\r
+\r
+\r
+def CheckForFunctionLengths(filename, clean_lines, linenum,\r
+                            function_state, error):\r
+  """Reports for long function bodies.\r
+\r
+  For an overview why this is done, see:\r
+  https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions\r
+\r
+  Uses a simplistic algorithm assuming other style guidelines\r
+  (especially spacing) are followed.\r
+  Only checks unindented functions, so class members are unchecked.\r
+  Trivial bodies are unchecked, so constructors with huge initializer lists\r
+  may be missed.\r
+  Blank/comment lines are not counted so as to avoid encouraging the removal\r
+  of vertical space and comments just to get through a lint check.\r
+  NOLINT *on the last line of a function* disables this check.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    function_state: Current function name and lines in body so far.\r
+    error: The function to call with any errors found.\r
+  """\r
+  lines = clean_lines.lines\r
+  line = lines[linenum]\r
+  joined_line = ''\r
+\r
+  starting_func = False\r
+  regexp = r'(\w(\w|::|\*|\&|\s)*)\('  # decls * & space::name( ...\r
+  match_result = Match(regexp, line)\r
+  if match_result:\r
+    # If the name is all caps and underscores, figure it's a macro and\r
+    # ignore it, unless it's TEST or TEST_F.\r
+    function_name = match_result.group(1).split()[-1]\r
+    if function_name == 'TEST' or function_name == 'TEST_F' or (\r
+        not Match(r'[A-Z_]+$', function_name)):\r
+      starting_func = True\r
+\r
+  if starting_func:\r
+    body_found = False\r
+    for start_linenum in xrange(linenum, clean_lines.NumLines()):\r
+      start_line = lines[start_linenum]\r
+      joined_line += ' ' + start_line.lstrip()\r
+      if Search(r'(;|})', start_line):  # Declarations and trivial functions\r
+        body_found = True\r
+        break                              # ... ignore\r
+      elif Search(r'{', start_line):\r
+        body_found = True\r
+        function = Search(r'((\w|:)*)\(', line).group(1)\r
+        if Match(r'TEST', function):    # Handle TEST... macros\r
+          parameter_regexp = Search(r'(\(.*\))', joined_line)\r
+          if parameter_regexp:             # Ignore bad syntax\r
+            function += parameter_regexp.group(1)\r
+        else:\r
+          function += '()'\r
+        function_state.Begin(function)\r
+        break\r
+    if not body_found:\r
+      # No body for the function (or evidence of a non-function) was found.\r
+      error(filename, linenum, 'readability/fn_size', 5,\r
+            'Lint failed to find start of function body.')\r
+  elif Match(r'^\}\s*$', line):  # function end\r
+    function_state.Check(error, filename, linenum)\r
+    function_state.End()\r
+  elif not Match(r'^\s*$', line):\r
+    function_state.Count()  # Count non-blank/non-comment lines.\r
+\r
+\r
+_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')\r
+\r
+\r
+def CheckComment(line, filename, linenum, next_line_start, error):\r
+  """Checks for common mistakes in comments.\r
+\r
+  Args:\r
+    line: The line in question.\r
+    filename: The name of the current file.\r
+    linenum: The number of the line to check.\r
+    next_line_start: The first non-whitespace column of the next line.\r
+    error: The function to call with any errors found.\r
+  """\r
+  commentpos = line.find('//')\r
+  if commentpos != -1:\r
+    # Check if the // may be in quotes.  If so, ignore it\r
+    if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0:\r
+      # Allow one space for new scopes, two spaces otherwise:\r
+      if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and\r
+          ((commentpos >= 1 and\r
+            line[commentpos-1] not in string.whitespace) or\r
+           (commentpos >= 2 and\r
+            line[commentpos-2] not in string.whitespace))):\r
+        error(filename, linenum, 'whitespace/comments', 2,\r
+              'At least two spaces is best between code and comments')\r
+\r
+      # Checks for common mistakes in TODO comments.\r
+      comment = line[commentpos:]\r
+      match = _RE_PATTERN_TODO.match(comment)\r
+      if match:\r
+        # One whitespace is correct; zero whitespace is handled elsewhere.\r
+        leading_whitespace = match.group(1)\r
+        if len(leading_whitespace) > 1:\r
+          error(filename, linenum, 'whitespace/todo', 2,\r
+                'Too many spaces before TODO')\r
+\r
+        username = match.group(2)\r
+        if not username:\r
+          error(filename, linenum, 'readability/todo', 2,\r
+                'Missing username in TODO; it should look like '\r
+                '"// TODO(my_username): Stuff."')\r
+\r
+        middle_whitespace = match.group(3)\r
+        # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison\r
+        if middle_whitespace != ' ' and middle_whitespace != '':\r
+          error(filename, linenum, 'whitespace/todo', 2,\r
+                'TODO(my_username) should be followed by a space')\r
+\r
+      # If the comment contains an alphanumeric character, there\r
+      # should be a space somewhere between it and the // unless\r
+      # it's a /// or //! Doxygen comment.\r
+      if (Match(r'//[^ ]*\w', comment) and\r
+          not Match(r'(///|//\!)(\s+|$)', comment)):\r
+        error(filename, linenum, 'whitespace/comments', 4,\r
+              'Should have a space between // and comment')\r
+\r
+\r
+def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):\r
+  """Checks for the correctness of various spacing issues in the code.\r
+\r
+  Things we check for: spaces around operators, spaces after\r
+  if/for/while/switch, no spaces around parens in function calls, two\r
+  spaces between code and comment, don't start a block with a blank\r
+  line, don't end a function with a blank line, don't add a blank line\r
+  after public/protected/private, don't have too many blank lines in a row.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  # Don't use "elided" lines here, otherwise we can't check commented lines.\r
+  # Don't want to use "raw" either, because we don't want to check inside C++11\r
+  # raw strings,\r
+  raw = clean_lines.lines_without_raw_strings\r
+  line = raw[linenum]\r
+\r
+  # Before nixing comments, check if the line is blank for no good\r
+  # reason.  This includes the first line after a block is opened, and\r
+  # blank lines at the end of a function (ie, right before a line like '}'\r
+  #\r
+  # Skip all the blank line checks if we are immediately inside a\r
+  # namespace body.  In other words, don't issue blank line warnings\r
+  # for this block:\r
+  #   namespace {\r
+  #\r
+  #   }\r
+  #\r
+  # A warning about missing end of namespace comments will be issued instead.\r
+  #\r
+  # Also skip blank line checks for 'extern "C"' blocks, which are formatted\r
+  # like namespaces.\r
+  if (IsBlankLine(line) and\r
+      not nesting_state.InNamespaceBody() and\r
+      not nesting_state.InExternC()):\r
+    elided = clean_lines.elided\r
+    prev_line = elided[linenum - 1]\r
+    prevbrace = prev_line.rfind('{')\r
+    # TODO(unknown): Don't complain if line before blank line, and line after,\r
+    #                both start with alnums and are indented the same amount.\r
+    #                This ignores whitespace at the start of a namespace block\r
+    #                because those are not usually indented.\r
+    if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:\r
+      # OK, we have a blank line at the start of a code block.  Before we\r
+      # complain, we check if it is an exception to the rule: The previous\r
+      # non-empty line has the parameters of a function header that are indented\r
+      # 4 spaces (because they did not fit in a 80 column line when placed on\r
+      # the same line as the function name).  We also check for the case where\r
+      # the previous line is indented 6 spaces, which may happen when the\r
+      # initializers of a constructor do not fit into a 80 column line.\r
+      exception = False\r
+      if Match(r' {6}\w', prev_line):  # Initializer list?\r
+        # We are looking for the opening column of initializer list, which\r
+        # should be indented 4 spaces to cause 6 space indentation afterwards.\r
+        search_position = linenum-2\r
+        while (search_position >= 0\r
+               and Match(r' {6}\w', elided[search_position])):\r
+          search_position -= 1\r
+        exception = (search_position >= 0\r
+                     and elided[search_position][:5] == '    :')\r
+      else:\r
+        # Search for the function arguments or an initializer list.  We use a\r
+        # simple heuristic here: If the line is indented 4 spaces; and we have a\r
+        # closing paren, without the opening paren, followed by an opening brace\r
+        # or colon (for initializer lists) we assume that it is the last line of\r
+        # a function header.  If we have a colon indented 4 spaces, it is an\r
+        # initializer list.\r
+        exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',\r
+                           prev_line)\r
+                     or Match(r' {4}:', prev_line))\r
+\r
+      if not exception:\r
+        error(filename, linenum, 'whitespace/blank_line', 2,\r
+              'Redundant blank line at the start of a code block '\r
+              'should be deleted.')\r
+    # Ignore blank lines at the end of a block in a long if-else\r
+    # chain, like this:\r
+    #   if (condition1) {\r
+    #     // Something followed by a blank line\r
+    #\r
+    #   } else if (condition2) {\r
+    #     // Something else\r
+    #   }\r
+    if linenum + 1 < clean_lines.NumLines():\r
+      next_line = raw[linenum + 1]\r
+      if (next_line\r
+          and Match(r'\s*}', next_line)\r
+          and next_line.find('} else ') == -1):\r
+        error(filename, linenum, 'whitespace/blank_line', 3,\r
+              'Redundant blank line at the end of a code block '\r
+              'should be deleted.')\r
+\r
+    matched = Match(r'\s*(public|protected|private):', prev_line)\r
+    if matched:\r
+      error(filename, linenum, 'whitespace/blank_line', 3,\r
+            'Do not leave a blank line after "%s:"' % matched.group(1))\r
+\r
+  # Next, check comments\r
+  next_line_start = 0\r
+  if linenum + 1 < clean_lines.NumLines():\r
+    next_line = raw[linenum + 1]\r
+    next_line_start = len(next_line) - len(next_line.lstrip())\r
+  CheckComment(line, filename, linenum, next_line_start, error)\r
+\r
+  # get rid of comments and strings\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # You shouldn't have spaces before your brackets, except maybe after\r
+  # 'delete []' or 'return []() {};'\r
+  if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):\r
+    error(filename, linenum, 'whitespace/braces', 5,\r
+          'Extra space before [')\r
+\r
+  # In range-based for, we wanted spaces before and after the colon, but\r
+  # not around "::" tokens that might appear.\r
+  if (Search(r'for *\(.*[^:]:[^: ]', line) or\r
+      Search(r'for *\(.*[^: ]:[^:]', line)):\r
+    error(filename, linenum, 'whitespace/forcolon', 2,\r
+          'Missing space around colon in range-based for loop')\r
+\r
+\r
+def CheckOperatorSpacing(filename, clean_lines, linenum, error):\r
+  """Checks for horizontal spacing around operators.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Don't try to do spacing checks for operator methods.  Do this by\r
+  # replacing the troublesome characters with something else,\r
+  # preserving column position for all other characters.\r
+  #\r
+  # The replacement is done repeatedly to avoid false positives from\r
+  # operators that call operators.\r
+  while True:\r
+    match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line)\r
+    if match:\r
+      line = match.group(1) + ('_' * len(match.group(2))) + match.group(3)\r
+    else:\r
+      break\r
+\r
+  # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".\r
+  # Otherwise not.  Note we only check for non-spaces on *both* sides;\r
+  # sometimes people put non-spaces on one side when aligning ='s among\r
+  # many lines (not that this is behavior that I approve of...)\r
+  if ((Search(r'[\w.]=', line) or\r
+       Search(r'=[\w.]', line))\r
+      and not Search(r'\b(if|while|for) ', line)\r
+      # Operators taken from [lex.operators] in C++11 standard.\r
+      and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line)\r
+      and not Search(r'operator=', line)):\r
+    error(filename, linenum, 'whitespace/operators', 4,\r
+          'Missing spaces around =')\r
+\r
+  # It's ok not to have spaces around binary operators like + - * /, but if\r
+  # there's too little whitespace, we get concerned.  It's hard to tell,\r
+  # though, so we punt on this one for now.  TODO.\r
+\r
+  # You should always have whitespace around binary operators.\r
+  #\r
+  # Check <= and >= first to avoid false positives with < and >, then\r
+  # check non-include lines for spacing around < and >.\r
+  #\r
+  # If the operator is followed by a comma, assume it's be used in a\r
+  # macro context and don't do any checks.  This avoids false\r
+  # positives.\r
+  #\r
+  # Note that && is not included here.  This is because there are too\r
+  # many false positives due to RValue references.\r
+  match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line)\r
+  if match:\r
+    error(filename, linenum, 'whitespace/operators', 3,\r
+          'Missing spaces around %s' % match.group(1))\r
+  elif not Match(r'#.*include', line):\r
+    # Look for < that is not surrounded by spaces.  This is only\r
+    # triggered if both sides are missing spaces, even though\r
+    # technically should should flag if at least one side is missing a\r
+    # space.  This is done to avoid some false positives with shifts.\r
+    match = Match(r'^(.*[^\s<])<[^\s=<,]', line)\r
+    if match:\r
+      (_, _, end_pos) = CloseExpression(\r
+          clean_lines, linenum, len(match.group(1)))\r
+      if end_pos <= -1:\r
+        error(filename, linenum, 'whitespace/operators', 3,\r
+              'Missing spaces around <')\r
+\r
+    # Look for > that is not surrounded by spaces.  Similar to the\r
+    # above, we only trigger if both sides are missing spaces to avoid\r
+    # false positives with shifts.\r
+    match = Match(r'^(.*[^-\s>])>[^\s=>,]', line)\r
+    if match:\r
+      (_, _, start_pos) = ReverseCloseExpression(\r
+          clean_lines, linenum, len(match.group(1)))\r
+      if start_pos <= -1:\r
+        error(filename, linenum, 'whitespace/operators', 3,\r
+              'Missing spaces around >')\r
+\r
+  # We allow no-spaces around << when used like this: 10<<20, but\r
+  # not otherwise (particularly, not when used as streams)\r
+  #\r
+  # We also allow operators following an opening parenthesis, since\r
+  # those tend to be macros that deal with operators.\r
+  match = Search(r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line)\r
+  if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and\r
+      not (match.group(1) == 'operator' and match.group(2) == ';')):\r
+    error(filename, linenum, 'whitespace/operators', 3,\r
+          'Missing spaces around <<')\r
+\r
+  # We allow no-spaces around >> for almost anything.  This is because\r
+  # C++11 allows ">>" to close nested templates, which accounts for\r
+  # most cases when ">>" is not followed by a space.\r
+  #\r
+  # We still warn on ">>" followed by alpha character, because that is\r
+  # likely due to ">>" being used for right shifts, e.g.:\r
+  #   value >> alpha\r
+  #\r
+  # When ">>" is used to close templates, the alphanumeric letter that\r
+  # follows would be part of an identifier, and there should still be\r
+  # a space separating the template type and the identifier.\r
+  #   type<type<type>> alpha\r
+  match = Search(r'>>[a-zA-Z_]', line)\r
+  if match:\r
+    error(filename, linenum, 'whitespace/operators', 3,\r
+          'Missing spaces around >>')\r
+\r
+  # There shouldn't be space around unary operators\r
+  match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)\r
+  if match:\r
+    error(filename, linenum, 'whitespace/operators', 4,\r
+          'Extra space for operator %s' % match.group(1))\r
+\r
+\r
+def CheckParenthesisSpacing(filename, clean_lines, linenum, error):\r
+  """Checks for horizontal spacing around parentheses.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # No spaces after an if, while, switch, or for\r
+  match = Search(r' (if\(|for\(|while\(|switch\()', line)\r
+  if match:\r
+    error(filename, linenum, 'whitespace/parens', 5,\r
+          'Missing space before ( in %s' % match.group(1))\r
+\r
+  # For if/for/while/switch, the left and right parens should be\r
+  # consistent about how many spaces are inside the parens, and\r
+  # there should either be zero or one spaces inside the parens.\r
+  # We don't want: "if ( foo)" or "if ( foo   )".\r
+  # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.\r
+  match = Search(r'\b(if|for|while|switch)\s*'\r
+                 r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',\r
+                 line)\r
+  if match:\r
+    if len(match.group(2)) != len(match.group(4)):\r
+      if not (match.group(3) == ';' and\r
+              len(match.group(2)) == 1 + len(match.group(4)) or\r
+              not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):\r
+        error(filename, linenum, 'whitespace/parens', 5,\r
+              'Mismatching spaces inside () in %s' % match.group(1))\r
+    if len(match.group(2)) not in [0, 1]:\r
+      error(filename, linenum, 'whitespace/parens', 5,\r
+            'Should have zero or one spaces inside ( and ) in %s' %\r
+            match.group(1))\r
+\r
+\r
+def CheckCommaSpacing(filename, clean_lines, linenum, error):\r
+  """Checks for horizontal spacing near commas and semicolons.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  raw = clean_lines.lines_without_raw_strings\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # You should always have a space after a comma (either as fn arg or operator)\r
+  #\r
+  # This does not apply when the non-space character following the\r
+  # comma is another comma, since the only time when that happens is\r
+  # for empty macro arguments.\r
+  #\r
+  # We run this check in two passes: first pass on elided lines to\r
+  # verify that lines contain missing whitespaces, second pass on raw\r
+  # lines to confirm that those missing whitespaces are not due to\r
+  # elided comments.\r
+  if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and\r
+      Search(r',[^,\s]', raw[linenum])):\r
+    error(filename, linenum, 'whitespace/comma', 3,\r
+          'Missing space after ,')\r
+\r
+  # You should always have a space after a semicolon\r
+  # except for few corner cases\r
+  # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more\r
+  # space after ;\r
+  if Search(r';[^\s};\\)/]', line):\r
+    error(filename, linenum, 'whitespace/semicolon', 3,\r
+          'Missing space after ;')\r
+\r
+\r
+def _IsType(clean_lines, nesting_state, expr):\r
+  """Check if expression looks like a type name, returns true if so.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    expr: The expression to check.\r
+  Returns:\r
+    True, if token looks like a type.\r
+  """\r
+  # Keep only the last token in the expression\r
+  last_word = Match(r'^.*(\b\S+)$', expr)\r
+  if last_word:\r
+    token = last_word.group(1)\r
+  else:\r
+    token = expr\r
+\r
+  # Match native types and stdint types\r
+  if _TYPES.match(token):\r
+    return True\r
+\r
+  # Try a bit harder to match templated types.  Walk up the nesting\r
+  # stack until we find something that resembles a typename\r
+  # declaration for what we are looking for.\r
+  typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) +\r
+                      r'\b')\r
+  block_index = len(nesting_state.stack) - 1\r
+  while block_index >= 0:\r
+    if isinstance(nesting_state.stack[block_index], _NamespaceInfo):\r
+      return False\r
+\r
+    # Found where the opening brace is.  We want to scan from this\r
+    # line up to the beginning of the function, minus a few lines.\r
+    #   template <typename Type1,  // stop scanning here\r
+    #             ...>\r
+    #   class C\r
+    #     : public ... {  // start scanning here\r
+    last_line = nesting_state.stack[block_index].starting_linenum\r
+\r
+    next_block_start = 0\r
+    if block_index > 0:\r
+      next_block_start = nesting_state.stack[block_index - 1].starting_linenum\r
+    first_line = last_line\r
+    while first_line >= next_block_start:\r
+      if clean_lines.elided[first_line].find('template') >= 0:\r
+        break\r
+      first_line -= 1\r
+    if first_line < next_block_start:\r
+      # Didn't find any "template" keyword before reaching the next block,\r
+      # there are probably no template things to check for this block\r
+      block_index -= 1\r
+      continue\r
+\r
+    # Look for typename in the specified range\r
+    for i in xrange(first_line, last_line + 1, 1):\r
+      if Search(typename_pattern, clean_lines.elided[i]):\r
+        return True\r
+    block_index -= 1\r
+\r
+  return False\r
+\r
+\r
+def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error):\r
+  """Checks for horizontal spacing near commas.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Except after an opening paren, or after another opening brace (in case of\r
+  # an initializer list, for instance), you should have spaces before your\r
+  # braces when they are delimiting blocks, classes, namespaces etc.\r
+  # And since you should never have braces at the beginning of a line,\r
+  # this is an easy test.  Except that braces used for initialization don't\r
+  # follow the same rule; we often don't want spaces before those.\r
+  match = Match(r'^(.*[^ ({>]){', line)\r
+\r
+  if match:\r
+    # Try a bit harder to check for brace initialization.  This\r
+    # happens in one of the following forms:\r
+    #   Constructor() : initializer_list_{} { ... }\r
+    #   Constructor{}.MemberFunction()\r
+    #   Type variable{};\r
+    #   FunctionCall(type{}, ...);\r
+    #   LastArgument(..., type{});\r
+    #   LOG(INFO) << type{} << " ...";\r
+    #   map_of_type[{...}] = ...;\r
+    #   ternary = expr ? new type{} : nullptr;\r
+    #   OuterTemplate<InnerTemplateConstructor<Type>{}>\r
+    #\r
+    # We check for the character following the closing brace, and\r
+    # silence the warning if it's one of those listed above, i.e.\r
+    # "{.;,)<>]:".\r
+    #\r
+    # To account for nested initializer list, we allow any number of\r
+    # closing braces up to "{;,)<".  We can't simply silence the\r
+    # warning on first sight of closing brace, because that would\r
+    # cause false negatives for things that are not initializer lists.\r
+    #   Silence this:         But not this:\r
+    #     Outer{                if (...) {\r
+    #       Inner{...}            if (...){  // Missing space before {\r
+    #     };                    }\r
+    #\r
+    # There is a false negative with this approach if people inserted\r
+    # spurious semicolons, e.g. "if (cond){};", but we will catch the\r
+    # spurious semicolon with a separate check.\r
+    leading_text = match.group(1)\r
+    (endline, endlinenum, endpos) = CloseExpression(\r
+        clean_lines, linenum, len(match.group(1)))\r
+    trailing_text = ''\r
+    if endpos > -1:\r
+      trailing_text = endline[endpos:]\r
+    for offset in xrange(endlinenum + 1,\r
+                         min(endlinenum + 3, clean_lines.NumLines() - 1)):\r
+      trailing_text += clean_lines.elided[offset]\r
+    # We also suppress warnings for `uint64_t{expression}` etc., as the style\r
+    # guide recommends brace initialization for integral types to avoid\r
+    # overflow/truncation.\r
+    if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text)\r
+        and not _IsType(clean_lines, nesting_state, leading_text)):\r
+      error(filename, linenum, 'whitespace/braces', 5,\r
+            'Missing space before {')\r
+\r
+  # Make sure '} else {' has spaces.\r
+  if Search(r'}else', line):\r
+    error(filename, linenum, 'whitespace/braces', 5,\r
+          'Missing space before else')\r
+\r
+  # You shouldn't have a space before a semicolon at the end of the line.\r
+  # There's a special case for "for" since the style guide allows space before\r
+  # the semicolon there.\r
+  if Search(r':\s*;\s*$', line):\r
+    error(filename, linenum, 'whitespace/semicolon', 5,\r
+          'Semicolon defining empty statement. Use {} instead.')\r
+  elif Search(r'^\s*;\s*$', line):\r
+    error(filename, linenum, 'whitespace/semicolon', 5,\r
+          'Line contains only semicolon. If this should be an empty statement, '\r
+          'use {} instead.')\r
+  elif (Search(r'\s+;\s*$', line) and\r
+        not Search(r'\bfor\b', line)):\r
+    error(filename, linenum, 'whitespace/semicolon', 5,\r
+          'Extra space before last semicolon. If this should be an empty '\r
+          'statement, use {} instead.')\r
+\r
+\r
+def IsDecltype(clean_lines, linenum, column):\r
+  """Check if the token ending on (linenum, column) is decltype().\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: the number of the line to check.\r
+    column: end column of the token to check.\r
+  Returns:\r
+    True if this token is decltype() expression, False otherwise.\r
+  """\r
+  (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column)\r
+  if start_col < 0:\r
+    return False\r
+  if Search(r'\bdecltype\s*$', text[0:start_col]):\r
+    return True\r
+  return False\r
+\r
+\r
+def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):\r
+  """Checks for additional blank line issues related to sections.\r
+\r
+  Currently the only thing checked here is blank line before protected/private.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    class_info: A _ClassInfo objects.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  # Skip checks if the class is small, where small means 25 lines or less.\r
+  # 25 lines seems like a good cutoff since that's the usual height of\r
+  # terminals, and any class that can't fit in one screen can't really\r
+  # be considered "small".\r
+  #\r
+  # Also skip checks if we are on the first line.  This accounts for\r
+  # classes that look like\r
+  #   class Foo { public: ... };\r
+  #\r
+  # If we didn't find the end of the class, last_line would be zero,\r
+  # and the check will be skipped by the first condition.\r
+  if (class_info.last_line - class_info.starting_linenum <= 24 or\r
+      linenum <= class_info.starting_linenum):\r
+    return\r
+\r
+  matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])\r
+  if matched:\r
+    # Issue warning if the line before public/protected/private was\r
+    # not a blank line, but don't do this if the previous line contains\r
+    # "class" or "struct".  This can happen two ways:\r
+    #  - We are at the beginning of the class.\r
+    #  - We are forward-declaring an inner class that is semantically\r
+    #    private, but needed to be public for implementation reasons.\r
+    # Also ignores cases where the previous line ends with a backslash as can be\r
+    # common when defining classes in C macros.\r
+    prev_line = clean_lines.lines[linenum - 1]\r
+    if (not IsBlankLine(prev_line) and\r
+        not Search(r'\b(class|struct)\b', prev_line) and\r
+        not Search(r'\\$', prev_line)):\r
+      # Try a bit harder to find the beginning of the class.  This is to\r
+      # account for multi-line base-specifier lists, e.g.:\r
+      #   class Derived\r
+      #       : public Base {\r
+      end_class_head = class_info.starting_linenum\r
+      for i in range(class_info.starting_linenum, linenum):\r
+        if Search(r'\{\s*$', clean_lines.lines[i]):\r
+          end_class_head = i\r
+          break\r
+      if end_class_head < linenum - 1:\r
+        error(filename, linenum, 'whitespace/blank_line', 3,\r
+              '"%s:" should be preceded by a blank line' % matched.group(1))\r
+\r
+\r
+def GetPreviousNonBlankLine(clean_lines, linenum):\r
+  """Return the most recent non-blank line and its line number.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file contents.\r
+    linenum: The number of the line to check.\r
+\r
+  Returns:\r
+    A tuple with two elements.  The first element is the contents of the last\r
+    non-blank line before the current line, or the empty string if this is the\r
+    first non-blank line.  The second is the line number of that line, or -1\r
+    if this is the first non-blank line.\r
+  """\r
+\r
+  prevlinenum = linenum - 1\r
+  while prevlinenum >= 0:\r
+    prevline = clean_lines.elided[prevlinenum]\r
+    if not IsBlankLine(prevline):     # if not a blank line...\r
+      return (prevline, prevlinenum)\r
+    prevlinenum -= 1\r
+  return ('', -1)\r
+\r
+\r
+def CheckBraces(filename, clean_lines, linenum, error):\r
+  """Looks for misplaced braces (e.g. at the end of line).\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  line = clean_lines.elided[linenum]        # get rid of comments and strings\r
+\r
+  if Match(r'\s*{\s*$', line):\r
+    # We allow an open brace to start a line in the case where someone is using\r
+    # braces in a block to explicitly create a new scope, which is commonly used\r
+    # to control the lifetime of stack-allocated variables.  Braces are also\r
+    # used for brace initializers inside function calls.  We don't detect this\r
+    # perfectly: we just don't complain if the last non-whitespace character on\r
+    # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the\r
+    # previous line starts a preprocessor block. We also allow a brace on the\r
+    # following line if it is part of an array initialization and would not fit\r
+    # within the 80 character limit of the preceding line.\r
+    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]\r
+    if (not Search(r'[,;:}{(]\s*$', prevline) and\r
+        not Match(r'\s*#', prevline) and\r
+        not (GetLineWidth(prevline) > _line_length - 2 and '[]' in prevline)):\r
+      error(filename, linenum, 'whitespace/braces', 4,\r
+            '{ should almost always be at the end of the previous line')\r
+\r
+  # An else clause should be on the same line as the preceding closing brace.\r
+  if Match(r'\s*else\b\s*(?:if\b|\{|$)', line):\r
+    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]\r
+    if Match(r'\s*}\s*$', prevline):\r
+      error(filename, linenum, 'whitespace/newline', 4,\r
+            'An else should appear on the same line as the preceding }')\r
+\r
+  # If braces come on one side of an else, they should be on both.\r
+  # However, we have to worry about "else if" that spans multiple lines!\r
+  if Search(r'else if\s*\(', line):       # could be multi-line if\r
+    brace_on_left = bool(Search(r'}\s*else if\s*\(', line))\r
+    # find the ( after the if\r
+    pos = line.find('else if')\r
+    pos = line.find('(', pos)\r
+    if pos > 0:\r
+      (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)\r
+      brace_on_right = endline[endpos:].find('{') != -1\r
+      if brace_on_left != brace_on_right:    # must be brace after if\r
+        error(filename, linenum, 'readability/braces', 5,\r
+              'If an else has a brace on one side, it should have it on both')\r
+  elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):\r
+    error(filename, linenum, 'readability/braces', 5,\r
+          'If an else has a brace on one side, it should have it on both')\r
+\r
+  # Likewise, an else should never have the else clause on the same line\r
+  if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):\r
+    error(filename, linenum, 'whitespace/newline', 4,\r
+          'Else clause should never be on same line as else (use 2 lines)')\r
+\r
+  # In the same way, a do/while should never be on one line\r
+  if Match(r'\s*do [^\s{]', line):\r
+    error(filename, linenum, 'whitespace/newline', 4,\r
+          'do/while clauses should not be on a single line')\r
+\r
+  # Check single-line if/else bodies. The style guide says 'curly braces are not\r
+  # required for single-line statements'. We additionally allow multi-line,\r
+  # single statements, but we reject anything with more than one semicolon in\r
+  # it. This means that the first semicolon after the if should be at the end of\r
+  # its line, and the line after that should have an indent level equal to or\r
+  # lower than the if. We also check for ambiguous if/else nesting without\r
+  # braces.\r
+  if_else_match = Search(r'\b(if\s*\(|else\b)', line)\r
+  if if_else_match and not Match(r'\s*#', line):\r
+    if_indent = GetIndentLevel(line)\r
+    endline, endlinenum, endpos = line, linenum, if_else_match.end()\r
+    if_match = Search(r'\bif\s*\(', line)\r
+    if if_match:\r
+      # This could be a multiline if condition, so find the end first.\r
+      pos = if_match.end() - 1\r
+      (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos)\r
+    # Check for an opening brace, either directly after the if or on the next\r
+    # line. If found, this isn't a single-statement conditional.\r
+    if (not Match(r'\s*{', endline[endpos:])\r
+        and not (Match(r'\s*$', endline[endpos:])\r
+                 and endlinenum < (len(clean_lines.elided) - 1)\r
+                 and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))):\r
+      while (endlinenum < len(clean_lines.elided)\r
+             and ';' not in clean_lines.elided[endlinenum][endpos:]):\r
+        endlinenum += 1\r
+        endpos = 0\r
+      if endlinenum < len(clean_lines.elided):\r
+        endline = clean_lines.elided[endlinenum]\r
+        # We allow a mix of whitespace and closing braces (e.g. for one-liner\r
+        # methods) and a single \ after the semicolon (for macros)\r
+        endpos = endline.find(';')\r
+        if not Match(r';[\s}]*(\\?)$', endline[endpos:]):\r
+          # Semicolon isn't the last character, there's something trailing.\r
+          # Output a warning if the semicolon is not contained inside\r
+          # a lambda expression.\r
+          if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$',\r
+                       endline):\r
+            error(filename, linenum, 'readability/braces', 4,\r
+                  'If/else bodies with multiple statements require braces')\r
+        elif endlinenum < len(clean_lines.elided) - 1:\r
+          # Make sure the next line is dedented\r
+          next_line = clean_lines.elided[endlinenum + 1]\r
+          next_indent = GetIndentLevel(next_line)\r
+          # With ambiguous nested if statements, this will error out on the\r
+          # if that *doesn't* match the else, regardless of whether it's the\r
+          # inner one or outer one.\r
+          if (if_match and Match(r'\s*else\b', next_line)\r
+              and next_indent != if_indent):\r
+            error(filename, linenum, 'readability/braces', 4,\r
+                  'Else clause should be indented at the same level as if. '\r
+                  'Ambiguous nested if/else chains require braces.')\r
+          elif next_indent > if_indent:\r
+            error(filename, linenum, 'readability/braces', 4,\r
+                  'If/else bodies with multiple statements require braces')\r
+\r
+\r
+def CheckTrailingSemicolon(filename, clean_lines, linenum, error):\r
+  """Looks for redundant trailing semicolon.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Block bodies should not be followed by a semicolon.  Due to C++11\r
+  # brace initialization, there are more places where semicolons are\r
+  # required than not, so we use a whitelist approach to check these\r
+  # rather than a blacklist.  These are the places where "};" should\r
+  # be replaced by just "}":\r
+  # 1. Some flavor of block following closing parenthesis:\r
+  #    for (;;) {};\r
+  #    while (...) {};\r
+  #    switch (...) {};\r
+  #    Function(...) {};\r
+  #    if (...) {};\r
+  #    if (...) else if (...) {};\r
+  #\r
+  # 2. else block:\r
+  #    if (...) else {};\r
+  #\r
+  # 3. const member function:\r
+  #    Function(...) const {};\r
+  #\r
+  # 4. Block following some statement:\r
+  #    x = 42;\r
+  #    {};\r
+  #\r
+  # 5. Block at the beginning of a function:\r
+  #    Function(...) {\r
+  #      {};\r
+  #    }\r
+  #\r
+  #    Note that naively checking for the preceding "{" will also match\r
+  #    braces inside multi-dimensional arrays, but this is fine since\r
+  #    that expression will not contain semicolons.\r
+  #\r
+  # 6. Block following another block:\r
+  #    while (true) {}\r
+  #    {};\r
+  #\r
+  # 7. End of namespaces:\r
+  #    namespace {};\r
+  #\r
+  #    These semicolons seems far more common than other kinds of\r
+  #    redundant semicolons, possibly due to people converting classes\r
+  #    to namespaces.  For now we do not warn for this case.\r
+  #\r
+  # Try matching case 1 first.\r
+  match = Match(r'^(.*\)\s*)\{', line)\r
+  if match:\r
+    # Matched closing parenthesis (case 1).  Check the token before the\r
+    # matching opening parenthesis, and don't warn if it looks like a\r
+    # macro.  This avoids these false positives:\r
+    #  - macro that defines a base class\r
+    #  - multi-line macro that defines a base class\r
+    #  - macro that defines the whole class-head\r
+    #\r
+    # But we still issue warnings for macros that we know are safe to\r
+    # warn, specifically:\r
+    #  - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P\r
+    #  - TYPED_TEST\r
+    #  - INTERFACE_DEF\r
+    #  - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:\r
+    #\r
+    # We implement a whitelist of safe macros instead of a blacklist of\r
+    # unsafe macros, even though the latter appears less frequently in\r
+    # google code and would have been easier to implement.  This is because\r
+    # the downside for getting the whitelist wrong means some extra\r
+    # semicolons, while the downside for getting the blacklist wrong\r
+    # would result in compile errors.\r
+    #\r
+    # In addition to macros, we also don't want to warn on\r
+    #  - Compound literals\r
+    #  - Lambdas\r
+    #  - alignas specifier with anonymous structs\r
+    #  - decltype\r
+    closing_brace_pos = match.group(1).rfind(')')\r
+    opening_parenthesis = ReverseCloseExpression(\r
+        clean_lines, linenum, closing_brace_pos)\r
+    if opening_parenthesis[2] > -1:\r
+      line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]\r
+      macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix)\r
+      func = Match(r'^(.*\])\s*$', line_prefix)\r
+      if ((macro and\r
+           macro.group(1) not in (\r
+               'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',\r
+               'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED',\r
+               'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or\r
+          (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or\r
+          Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or\r
+          Search(r'\bdecltype$', line_prefix) or\r
+          Search(r'\s+=\s*$', line_prefix)):\r
+        match = None\r
+    if (match and\r
+        opening_parenthesis[1] > 1 and\r
+        Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])):\r
+      # Multi-line lambda-expression\r
+      match = None\r
+\r
+  else:\r
+    # Try matching cases 2-3.\r
+    match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line)\r
+    if not match:\r
+      # Try matching cases 4-6.  These are always matched on separate lines.\r
+      #\r
+      # Note that we can't simply concatenate the previous line to the\r
+      # current line and do a single match, otherwise we may output\r
+      # duplicate warnings for the blank line case:\r
+      #   if (cond) {\r
+      #     // blank line\r
+      #   }\r
+      prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]\r
+      if prevline and Search(r'[;{}]\s*$', prevline):\r
+        match = Match(r'^(\s*)\{', line)\r
+\r
+  # Check matching closing brace\r
+  if match:\r
+    (endline, endlinenum, endpos) = CloseExpression(\r
+        clean_lines, linenum, len(match.group(1)))\r
+    if endpos > -1 and Match(r'^\s*;', endline[endpos:]):\r
+      # Current {} pair is eligible for semicolon check, and we have found\r
+      # the redundant semicolon, output warning here.\r
+      #\r
+      # Note: because we are scanning forward for opening braces, and\r
+      # outputting warnings for the matching closing brace, if there are\r
+      # nested blocks with trailing semicolons, we will get the error\r
+      # messages in reversed order.\r
+\r
+      # We need to check the line forward for NOLINT\r
+      raw_lines = clean_lines.raw_lines\r
+      ParseNolintSuppressions(filename, raw_lines[endlinenum-1], endlinenum-1,\r
+                              error)\r
+      ParseNolintSuppressions(filename, raw_lines[endlinenum], endlinenum,\r
+                              error)\r
+\r
+      error(filename, endlinenum, 'readability/braces', 4,\r
+            "You don't need a ; after a }")\r
+\r
+\r
+def CheckEmptyBlockBody(filename, clean_lines, linenum, error):\r
+  """Look for empty loop/conditional body with only a single semicolon.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  # Search for loop keywords at the beginning of the line.  Because only\r
+  # whitespaces are allowed before the keywords, this will also ignore most\r
+  # do-while-loops, since those lines should start with closing brace.\r
+  #\r
+  # We also check "if" blocks here, since an empty conditional block\r
+  # is likely an error.\r
+  line = clean_lines.elided[linenum]\r
+  matched = Match(r'\s*(for|while|if)\s*\(', line)\r
+  if matched:\r
+    # Find the end of the conditional expression.\r
+    (end_line, end_linenum, end_pos) = CloseExpression(\r
+        clean_lines, linenum, line.find('('))\r
+\r
+    # Output warning if what follows the condition expression is a semicolon.\r
+    # No warning for all other cases, including whitespace or newline, since we\r
+    # have a separate check for semicolons preceded by whitespace.\r
+    if end_pos >= 0 and Match(r';', end_line[end_pos:]):\r
+      if matched.group(1) == 'if':\r
+        error(filename, end_linenum, 'whitespace/empty_conditional_body', 5,\r
+              'Empty conditional bodies should use {}')\r
+      else:\r
+        error(filename, end_linenum, 'whitespace/empty_loop_body', 5,\r
+              'Empty loop bodies should use {} or continue')\r
+\r
+    # Check for if statements that have completely empty bodies (no comments)\r
+    # and no else clauses.\r
+    if end_pos >= 0 and matched.group(1) == 'if':\r
+      # Find the position of the opening { for the if statement.\r
+      # Return without logging an error if it has no brackets.\r
+      opening_linenum = end_linenum\r
+      opening_line_fragment = end_line[end_pos:]\r
+      # Loop until EOF or find anything that's not whitespace or opening {.\r
+      while not Search(r'^\s*\{', opening_line_fragment):\r
+        if Search(r'^(?!\s*$)', opening_line_fragment):\r
+          # Conditional has no brackets.\r
+          return\r
+        opening_linenum += 1\r
+        if opening_linenum == len(clean_lines.elided):\r
+          # Couldn't find conditional's opening { or any code before EOF.\r
+          return\r
+        opening_line_fragment = clean_lines.elided[opening_linenum]\r
+      # Set opening_line (opening_line_fragment may not be entire opening line).\r
+      opening_line = clean_lines.elided[opening_linenum]\r
+\r
+      # Find the position of the closing }.\r
+      opening_pos = opening_line_fragment.find('{')\r
+      if opening_linenum == end_linenum:\r
+        # We need to make opening_pos relative to the start of the entire line.\r
+        opening_pos += end_pos\r
+      (closing_line, closing_linenum, closing_pos) = CloseExpression(\r
+          clean_lines, opening_linenum, opening_pos)\r
+      if closing_pos < 0:\r
+        return\r
+\r
+      # Now construct the body of the conditional. This consists of the portion\r
+      # of the opening line after the {, all lines until the closing line,\r
+      # and the portion of the closing line before the }.\r
+      if (clean_lines.raw_lines[opening_linenum] !=\r
+          CleanseComments(clean_lines.raw_lines[opening_linenum])):\r
+        # Opening line ends with a comment, so conditional isn't empty.\r
+        return\r
+      if closing_linenum > opening_linenum:\r
+        # Opening line after the {. Ignore comments here since we checked above.\r
+        body = list(opening_line[opening_pos+1:])\r
+        # All lines until closing line, excluding closing line, with comments.\r
+        body.extend(clean_lines.raw_lines[opening_linenum+1:closing_linenum])\r
+        # Closing line before the }. Won't (and can't) have comments.\r
+        body.append(clean_lines.elided[closing_linenum][:closing_pos-1])\r
+        body = '\n'.join(body)\r
+      else:\r
+        # If statement has brackets and fits on a single line.\r
+        body = opening_line[opening_pos+1:closing_pos-1]\r
+\r
+      # Check if the body is empty\r
+      if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body):\r
+        return\r
+      # The body is empty. Now make sure there's not an else clause.\r
+      current_linenum = closing_linenum\r
+      current_line_fragment = closing_line[closing_pos:]\r
+      # Loop until EOF or find anything that's not whitespace or else clause.\r
+      while Search(r'^\s*$|^(?=\s*else)', current_line_fragment):\r
+        if Search(r'^(?=\s*else)', current_line_fragment):\r
+          # Found an else clause, so don't log an error.\r
+          return\r
+        current_linenum += 1\r
+        if current_linenum == len(clean_lines.elided):\r
+          break\r
+        current_line_fragment = clean_lines.elided[current_linenum]\r
+\r
+      # The body is empty and there's no else clause until EOF or other code.\r
+      error(filename, end_linenum, 'whitespace/empty_if_body', 4,\r
+            ('If statement had no body and no else clause'))\r
+\r
+\r
+def FindCheckMacro(line):\r
+  """Find a replaceable CHECK-like macro.\r
+\r
+  Args:\r
+    line: line to search on.\r
+  Returns:\r
+    (macro name, start position), or (None, -1) if no replaceable\r
+    macro is found.\r
+  """\r
+  for macro in _CHECK_MACROS:\r
+    i = line.find(macro)\r
+    if i >= 0:\r
+      # Find opening parenthesis.  Do a regular expression match here\r
+      # to make sure that we are matching the expected CHECK macro, as\r
+      # opposed to some other macro that happens to contain the CHECK\r
+      # substring.\r
+      matched = Match(r'^(.*\b' + macro + r'\s*)\(', line)\r
+      if not matched:\r
+        continue\r
+      return (macro, len(matched.group(1)))\r
+  return (None, -1)\r
+\r
+\r
+def CheckCheck(filename, clean_lines, linenum, error):\r
+  """Checks the use of CHECK and EXPECT macros.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  # Decide the set of replacement macros that should be suggested\r
+  lines = clean_lines.elided\r
+  (check_macro, start_pos) = FindCheckMacro(lines[linenum])\r
+  if not check_macro:\r
+    return\r
+\r
+  # Find end of the boolean expression by matching parentheses\r
+  (last_line, end_line, end_pos) = CloseExpression(\r
+      clean_lines, linenum, start_pos)\r
+  if end_pos < 0:\r
+    return\r
+\r
+  # If the check macro is followed by something other than a\r
+  # semicolon, assume users will log their own custom error messages\r
+  # and don't suggest any replacements.\r
+  if not Match(r'\s*;', last_line[end_pos:]):\r
+    return\r
+\r
+  if linenum == end_line:\r
+    expression = lines[linenum][start_pos + 1:end_pos - 1]\r
+  else:\r
+    expression = lines[linenum][start_pos + 1:]\r
+    for i in xrange(linenum + 1, end_line):\r
+      expression += lines[i]\r
+    expression += last_line[0:end_pos - 1]\r
+\r
+  # Parse expression so that we can take parentheses into account.\r
+  # This avoids false positives for inputs like "CHECK((a < 4) == b)",\r
+  # which is not replaceable by CHECK_LE.\r
+  lhs = ''\r
+  rhs = ''\r
+  operator = None\r
+  while expression:\r
+    matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||'\r
+                    r'==|!=|>=|>|<=|<|\()(.*)$', expression)\r
+    if matched:\r
+      token = matched.group(1)\r
+      if token == '(':\r
+        # Parenthesized operand\r
+        expression = matched.group(2)\r
+        (end, _) = FindEndOfExpressionInLine(expression, 0, ['('])\r
+        if end < 0:\r
+          return  # Unmatched parenthesis\r
+        lhs += '(' + expression[0:end]\r
+        expression = expression[end:]\r
+      elif token in ('&&', '||'):\r
+        # Logical and/or operators.  This means the expression\r
+        # contains more than one term, for example:\r
+        #   CHECK(42 < a && a < b);\r
+        #\r
+        # These are not replaceable with CHECK_LE, so bail out early.\r
+        return\r
+      elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'):\r
+        # Non-relational operator\r
+        lhs += token\r
+        expression = matched.group(2)\r
+      else:\r
+        # Relational operator\r
+        operator = token\r
+        rhs = matched.group(2)\r
+        break\r
+    else:\r
+      # Unparenthesized operand.  Instead of appending to lhs one character\r
+      # at a time, we do another regular expression match to consume several\r
+      # characters at once if possible.  Trivial benchmark shows that this\r
+      # is more efficient when the operands are longer than a single\r
+      # character, which is generally the case.\r
+      matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression)\r
+      if not matched:\r
+        matched = Match(r'^(\s*\S)(.*)$', expression)\r
+        if not matched:\r
+          break\r
+      lhs += matched.group(1)\r
+      expression = matched.group(2)\r
+\r
+  # Only apply checks if we got all parts of the boolean expression\r
+  if not (lhs and operator and rhs):\r
+    return\r
+\r
+  # Check that rhs do not contain logical operators.  We already know\r
+  # that lhs is fine since the loop above parses out && and ||.\r
+  if rhs.find('&&') > -1 or rhs.find('||') > -1:\r
+    return\r
+\r
+  # At least one of the operands must be a constant literal.  This is\r
+  # to avoid suggesting replacements for unprintable things like\r
+  # CHECK(variable != iterator)\r
+  #\r
+  # The following pattern matches decimal, hex integers, strings, and\r
+  # characters (in that order).\r
+  lhs = lhs.strip()\r
+  rhs = rhs.strip()\r
+  match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$'\r
+  if Match(match_constant, lhs) or Match(match_constant, rhs):\r
+    # Note: since we know both lhs and rhs, we can provide a more\r
+    # descriptive error message like:\r
+    #   Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42)\r
+    # Instead of:\r
+    #   Consider using CHECK_EQ instead of CHECK(a == b)\r
+    #\r
+    # We are still keeping the less descriptive message because if lhs\r
+    # or rhs gets long, the error message might become unreadable.\r
+    error(filename, linenum, 'readability/check', 2,\r
+          'Consider using %s instead of %s(a %s b)' % (\r
+              _CHECK_REPLACEMENT[check_macro][operator],\r
+              check_macro, operator))\r
+\r
+\r
+def CheckAltTokens(filename, clean_lines, linenum, error):\r
+  """Check alternative keywords being used in boolean expressions.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Avoid preprocessor lines\r
+  if Match(r'^\s*#', line):\r
+    return\r
+\r
+  # Last ditch effort to avoid multi-line comments.  This will not help\r
+  # if the comment started before the current line or ended after the\r
+  # current line, but it catches most of the false positives.  At least,\r
+  # it provides a way to workaround this warning for people who use\r
+  # multi-line comments in preprocessor macros.\r
+  #\r
+  # TODO(unknown): remove this once cpplint has better support for\r
+  # multi-line comments.\r
+  if line.find('/*') >= 0 or line.find('*/') >= 0:\r
+    return\r
+\r
+  for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):\r
+    error(filename, linenum, 'readability/alt_tokens', 2,\r
+          'Use operator %s instead of %s' % (\r
+              _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))\r
+\r
+\r
+def GetLineWidth(line):\r
+  """Determines the width of the line in column positions.\r
+\r
+  Args:\r
+    line: A string, which may be a Unicode string.\r
+\r
+  Returns:\r
+    The width of the line in column positions, accounting for Unicode\r
+    combining characters and wide characters.\r
+  """\r
+  if isinstance(line, unicode):\r
+    width = 0\r
+    for uc in unicodedata.normalize('NFC', line):\r
+      if unicodedata.east_asian_width(uc) in ('W', 'F'):\r
+        width += 2\r
+      elif not unicodedata.combining(uc):\r
+        width += 1\r
+    return width\r
+  else:\r
+    return len(line)\r
+\r
+\r
+def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,\r
+               error):\r
+  """Checks rules from the 'C++ style rules' section of cppguide.html.\r
+\r
+  Most of these rules are hard to test (naming, comment style), but we\r
+  do what we can.  In particular we check for 2-space indents, line lengths,\r
+  tab usage, spaces inside code, etc.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    file_extension: The extension (without the dot) of the filename.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    error: The function to call with any errors found.\r
+  """\r
+\r
+  # Don't use "elided" lines here, otherwise we can't check commented lines.\r
+  # Don't want to use "raw" either, because we don't want to check inside C++11\r
+  # raw strings,\r
+  raw_lines = clean_lines.lines_without_raw_strings\r
+  line = raw_lines[linenum]\r
+  prev = raw_lines[linenum - 1] if linenum > 0 else ''\r
+\r
+  if line.find('\t') != -1:\r
+    error(filename, linenum, 'whitespace/tab', 1,\r
+          'Tab found; better to use spaces')\r
+\r
+  # One or three blank spaces at the beginning of the line is weird; it's\r
+  # hard to reconcile that with 2-space indents.\r
+  # NOTE: here are the conditions rob pike used for his tests.  Mine aren't\r
+  # as sophisticated, but it may be worth becoming so:  RLENGTH==initial_spaces\r
+  # if(RLENGTH > 20) complain = 0;\r
+  # if(match($0, " +(error|private|public|protected):")) complain = 0;\r
+  # if(match(prev, "&& *$")) complain = 0;\r
+  # if(match(prev, "\\|\\| *$")) complain = 0;\r
+  # if(match(prev, "[\",=><] *$")) complain = 0;\r
+  # if(match($0, " <<")) complain = 0;\r
+  # if(match(prev, " +for \\(")) complain = 0;\r
+  # if(prevodd && match(prevprev, " +for \\(")) complain = 0;\r
+  scope_or_label_pattern = r'\s*\w+\s*:\s*\\?$'\r
+  classinfo = nesting_state.InnermostClass()\r
+  initial_spaces = 0\r
+  cleansed_line = clean_lines.elided[linenum]\r
+  while initial_spaces < len(line) and line[initial_spaces] == ' ':\r
+    initial_spaces += 1\r
+  # There are certain situations we allow one space, notably for\r
+  # section labels, and also lines containing multi-line raw strings.\r
+  # We also don't check for lines that look like continuation lines\r
+  # (of lines ending in double quotes, commas, equals, or angle brackets)\r
+  # because the rules for how to indent those are non-trivial.\r
+  if (not Search(r'[",=><] *$', prev) and\r
+      (initial_spaces == 1 or initial_spaces == 3) and\r
+      not Match(scope_or_label_pattern, cleansed_line) and\r
+      not (clean_lines.raw_lines[linenum] != line and\r
+           Match(r'^\s*""', line))):\r
+    error(filename, linenum, 'whitespace/indent', 3,\r
+          'Weird number of spaces at line-start.  '\r
+          'Are you using a 2-space indent?')\r
+\r
+  if line and line[-1].isspace():\r
+    error(filename, linenum, 'whitespace/end_of_line', 4,\r
+          'Line ends in whitespace.  Consider deleting these extra spaces.')\r
+\r
+  # Check if the line is a header guard.\r
+  is_header_guard = False\r
+  if IsHeaderExtension(file_extension):\r
+    cppvar = GetHeaderGuardCPPVariable(filename)\r
+    if (line.startswith('#ifndef %s' % cppvar) or\r
+        line.startswith('#define %s' % cppvar) or\r
+        line.startswith('#endif  // %s' % cppvar)):\r
+      is_header_guard = True\r
+  # #include lines and header guards can be long, since there's no clean way to\r
+  # split them.\r
+  #\r
+  # URLs can be long too.  It's possible to split these, but it makes them\r
+  # harder to cut&paste.\r
+  #\r
+  # The "$Id:...$" comment may also get very long without it being the\r
+  # developers fault.\r
+  if (not line.startswith('#include') and not is_header_guard and\r
+      not Match(r'^\s*//.*http(s?)://\S*$', line) and\r
+      not Match(r'^\s*//\s*[^\s]*$', line) and\r
+      not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):\r
+    line_width = GetLineWidth(line)\r
+    if line_width > _line_length:\r
+      error(filename, linenum, 'whitespace/line_length', 2,\r
+            'Lines should be <= %i characters long' % _line_length)\r
+\r
+  if (cleansed_line.count(';') > 1 and\r
+      # for loops are allowed two ;'s (and may run over two lines).\r
+      cleansed_line.find('for') == -1 and\r
+      (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or\r
+       GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and\r
+      # It's ok to have many commands in a switch case that fits in 1 line\r
+      not ((cleansed_line.find('case ') != -1 or\r
+            cleansed_line.find('default:') != -1) and\r
+           cleansed_line.find('break;') != -1)):\r
+    error(filename, linenum, 'whitespace/newline', 0,\r
+          'More than one command on the same line')\r
+\r
+  # Some more style checks\r
+  CheckBraces(filename, clean_lines, linenum, error)\r
+  CheckTrailingSemicolon(filename, clean_lines, linenum, error)\r
+  CheckEmptyBlockBody(filename, clean_lines, linenum, error)\r
+  CheckSpacing(filename, clean_lines, linenum, nesting_state, error)\r
+  CheckOperatorSpacing(filename, clean_lines, linenum, error)\r
+  CheckParenthesisSpacing(filename, clean_lines, linenum, error)\r
+  CheckCommaSpacing(filename, clean_lines, linenum, error)\r
+  CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error)\r
+  CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)\r
+  CheckCheck(filename, clean_lines, linenum, error)\r
+  CheckAltTokens(filename, clean_lines, linenum, error)\r
+  classinfo = nesting_state.InnermostClass()\r
+  if classinfo:\r
+    CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)\r
+\r
+\r
+_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')\r
+# Matches the first component of a filename delimited by -s and _s. That is:\r
+#  _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'\r
+#  _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'\r
+#  _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'\r
+#  _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'\r
+_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')\r
+\r
+\r
+def _DropCommonSuffixes(filename):\r
+  """Drops common suffixes like _test.cc or -inl.h from filename.\r
+\r
+  For example:\r
+    >>> _DropCommonSuffixes('foo/foo-inl.h')\r
+    'foo/foo'\r
+    >>> _DropCommonSuffixes('foo/bar/foo.cc')\r
+    'foo/bar/foo'\r
+    >>> _DropCommonSuffixes('foo/foo_internal.h')\r
+    'foo/foo'\r
+    >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')\r
+    'foo/foo_unusualinternal'\r
+\r
+  Args:\r
+    filename: The input filename.\r
+\r
+  Returns:\r
+    The filename with the common suffix removed.\r
+  """\r
+  for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',\r
+                 'inl.h', 'impl.h', 'internal.h'):\r
+    if (filename.endswith(suffix) and len(filename) > len(suffix) and\r
+        filename[-len(suffix) - 1] in ('-', '_')):\r
+      return filename[:-len(suffix) - 1]\r
+  return os.path.splitext(filename)[0]\r
+\r
+\r
+def _ClassifyInclude(fileinfo, include, is_system):\r
+  """Figures out what kind of header 'include' is.\r
+\r
+  Args:\r
+    fileinfo: The current file cpplint is running over. A FileInfo instance.\r
+    include: The path to a #included file.\r
+    is_system: True if the #include used <> rather than "".\r
+\r
+  Returns:\r
+    One of the _XXX_HEADER constants.\r
+\r
+  For example:\r
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)\r
+    _C_SYS_HEADER\r
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)\r
+    _CPP_SYS_HEADER\r
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)\r
+    _LIKELY_MY_HEADER\r
+    >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),\r
+    ...                  'bar/foo_other_ext.h', False)\r
+    _POSSIBLE_MY_HEADER\r
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)\r
+    _OTHER_HEADER\r
+  """\r
+  # This is a list of all standard c++ header files, except\r
+  # those already checked for above.\r
+  is_cpp_h = include in _CPP_HEADERS\r
+\r
+  if is_system:\r
+    if is_cpp_h:\r
+      return _CPP_SYS_HEADER\r
+    else:\r
+      return _C_SYS_HEADER\r
+\r
+  # If the target file and the include we're checking share a\r
+  # basename when we drop common extensions, and the include\r
+  # lives in . , then it's likely to be owned by the target file.\r
+  target_dir, target_base = (\r
+      os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))\r
+  include_dir, include_base = os.path.split(_DropCommonSuffixes(include))\r
+  if target_base == include_base and (\r
+      include_dir == target_dir or\r
+      include_dir == os.path.normpath(target_dir + '/../public')):\r
+    return _LIKELY_MY_HEADER\r
+\r
+  # If the target and include share some initial basename\r
+  # component, it's possible the target is implementing the\r
+  # include, so it's allowed to be first, but we'll never\r
+  # complain if it's not there.\r
+  target_first_component = _RE_FIRST_COMPONENT.match(target_base)\r
+  include_first_component = _RE_FIRST_COMPONENT.match(include_base)\r
+  if (target_first_component and include_first_component and\r
+      target_first_component.group(0) ==\r
+      include_first_component.group(0)):\r
+    return _POSSIBLE_MY_HEADER\r
+\r
+  return _OTHER_HEADER\r
+\r
+\r
+\r
+def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):\r
+  """Check rules that are applicable to #include lines.\r
+\r
+  Strings on #include lines are NOT removed from elided line, to make\r
+  certain tasks easier. However, to prevent false positives, checks\r
+  applicable to #include lines in CheckLanguage must be put here.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    include_state: An _IncludeState instance in which the headers are inserted.\r
+    error: The function to call with any errors found.\r
+  """\r
+  fileinfo = FileInfo(filename)\r
+  line = clean_lines.lines[linenum]\r
+\r
+  # "include" should use the new style "foo/bar.h" instead of just "bar.h"\r
+  # Only do this check if the included header follows google naming\r
+  # conventions.  If not, assume that it's a 3rd party API that\r
+  # requires special include conventions.\r
+  #\r
+  # We also make an exception for Lua headers, which follow google\r
+  # naming convention but not the include convention.\r
+  match = Match(r'#include\s*"([^/]+\.h)"', line)\r
+  if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)):\r
+    error(filename, linenum, 'build/include', 4,\r
+          'Include the directory when naming .h files')\r
+\r
+  # we shouldn't include a file more than once. actually, there are a\r
+  # handful of instances where doing so is okay, but in general it's\r
+  # not.\r
+  match = _RE_PATTERN_INCLUDE.search(line)\r
+  if match:\r
+    include = match.group(2)\r
+    is_system = (match.group(1) == '<')\r
+    duplicate_line = include_state.FindHeader(include)\r
+    if duplicate_line >= 0:\r
+      error(filename, linenum, 'build/include', 4,\r
+            '"%s" already included at %s:%s' %\r
+            (include, filename, duplicate_line))\r
+    elif (include.endswith('.cc') and\r
+          os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)):\r
+      error(filename, linenum, 'build/include', 4,\r
+            'Do not include .cc files from other packages')\r
+    elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):\r
+      include_state.include_list[-1].append((include, linenum))\r
+\r
+      # We want to ensure that headers appear in the right order:\r
+      # 1) for foo.cc, foo.h  (preferred location)\r
+      # 2) c system files\r
+      # 3) cpp system files\r
+      # 4) for foo.cc, foo.h  (deprecated location)\r
+      # 5) other google headers\r
+      #\r
+      # We classify each include statement as one of those 5 types\r
+      # using a number of techniques. The include_state object keeps\r
+      # track of the highest type seen, and complains if we see a\r
+      # lower type after that.\r
+      error_message = include_state.CheckNextIncludeOrder(\r
+          _ClassifyInclude(fileinfo, include, is_system))\r
+      if error_message:\r
+        error(filename, linenum, 'build/include_order', 4,\r
+              '%s. Should be: %s.h, c system, c++ system, other.' %\r
+              (error_message, fileinfo.BaseName()))\r
+      canonical_include = include_state.CanonicalizeAlphabeticalOrder(include)\r
+      if not include_state.IsInAlphabeticalOrder(\r
+          clean_lines, linenum, canonical_include):\r
+        error(filename, linenum, 'build/include_alpha', 4,\r
+              'Include "%s" not in alphabetical order' % include)\r
+      include_state.SetLastHeader(canonical_include)\r
+\r
+\r
+\r
+def _GetTextInside(text, start_pattern):\r
+  r"""Retrieves all the text between matching open and close parentheses.\r
+\r
+  Given a string of lines and a regular expression string, retrieve all the text\r
+  following the expression and between opening punctuation symbols like\r
+  (, [, or {, and the matching close-punctuation symbol. This properly nested\r
+  occurrences of the punctuations, so for the text like\r
+    printf(a(), b(c()));\r
+  a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.\r
+  start_pattern must match string having an open punctuation symbol at the end.\r
+\r
+  Args:\r
+    text: The lines to extract text. Its comments and strings must be elided.\r
+           It can be single line and can span multiple lines.\r
+    start_pattern: The regexp string indicating where to start extracting\r
+                   the text.\r
+  Returns:\r
+    The extracted text.\r
+    None if either the opening string or ending punctuation could not be found.\r
+  """\r
+  # TODO(unknown): Audit cpplint.py to see what places could be profitably\r
+  # rewritten to use _GetTextInside (and use inferior regexp matching today).\r
+\r
+  # Give opening punctuations to get the matching close-punctuations.\r
+  matching_punctuation = {'(': ')', '{': '}', '[': ']'}\r
+  closing_punctuation = set(matching_punctuation.itervalues())\r
+\r
+  # Find the position to start extracting text.\r
+  match = re.search(start_pattern, text, re.M)\r
+  if not match:  # start_pattern not found in text.\r
+    return None\r
+  start_position = match.end(0)\r
+\r
+  assert start_position > 0, (\r
+      'start_pattern must ends with an opening punctuation.')\r
+  assert text[start_position - 1] in matching_punctuation, (\r
+      'start_pattern must ends with an opening punctuation.')\r
+  # Stack of closing punctuations we expect to have in text after position.\r
+  punctuation_stack = [matching_punctuation[text[start_position - 1]]]\r
+  position = start_position\r
+  while punctuation_stack and position < len(text):\r
+    if text[position] == punctuation_stack[-1]:\r
+      punctuation_stack.pop()\r
+    elif text[position] in closing_punctuation:\r
+      # A closing punctuation without matching opening punctuations.\r
+      return None\r
+    elif text[position] in matching_punctuation:\r
+      punctuation_stack.append(matching_punctuation[text[position]])\r
+    position += 1\r
+  if punctuation_stack:\r
+    # Opening punctuations left without matching close-punctuations.\r
+    return None\r
+  # punctuations match.\r
+  return text[start_position:position - 1]\r
+\r
+\r
+# Patterns for matching call-by-reference parameters.\r
+#\r
+# Supports nested templates up to 2 levels deep using this messy pattern:\r
+#   < (?: < (?: < [^<>]*\r
+#               >\r
+#           |   [^<>] )*\r
+#         >\r
+#     |   [^<>] )*\r
+#   >\r
+_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*'  # =~ [[:alpha:]][[:alnum:]]*\r
+_RE_PATTERN_TYPE = (\r
+    r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?'\r
+    r'(?:\w|'\r
+    r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|'\r
+    r'::)+')\r
+# A call-by-reference parameter ends with '& identifier'.\r
+_RE_PATTERN_REF_PARAM = re.compile(\r
+    r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*'\r
+    r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]')\r
+# A call-by-const-reference parameter either ends with 'const& identifier'\r
+# or looks like 'const type& identifier' when 'type' is atomic.\r
+_RE_PATTERN_CONST_REF_PARAM = (\r
+    r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT +\r
+    r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')')\r
+# Stream types.\r
+_RE_PATTERN_REF_STREAM_PARAM = (\r
+    r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')')\r
+\r
+\r
+def CheckLanguage(filename, clean_lines, linenum, file_extension,\r
+                  include_state, nesting_state, error):\r
+  """Checks rules from the 'C++ language rules' section of cppguide.html.\r
+\r
+  Some of these rules are hard to test (function overloading, using\r
+  uint32 inappropriately), but we do the best we can.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    file_extension: The extension (without the dot) of the filename.\r
+    include_state: An _IncludeState instance in which the headers are inserted.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    error: The function to call with any errors found.\r
+  """\r
+  # If the line is empty or consists of entirely a comment, no need to\r
+  # check it.\r
+  line = clean_lines.elided[linenum]\r
+  if not line:\r
+    return\r
+\r
+  match = _RE_PATTERN_INCLUDE.search(line)\r
+  if match:\r
+    CheckIncludeLine(filename, clean_lines, linenum, include_state, error)\r
+    return\r
+\r
+  # Reset include state across preprocessor directives.  This is meant\r
+  # to silence warnings for conditional includes.\r
+  match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line)\r
+  if match:\r
+    include_state.ResetSection(match.group(1))\r
+\r
+  # Make Windows paths like Unix.\r
+  fullname = os.path.abspath(filename).replace('\\', '/')\r
+\r
+  # Perform other checks now that we are sure that this is not an include line\r
+  CheckCasts(filename, clean_lines, linenum, error)\r
+  CheckGlobalStatic(filename, clean_lines, linenum, error)\r
+  CheckPrintf(filename, clean_lines, linenum, error)\r
+\r
+  if IsHeaderExtension(file_extension):\r
+    # TODO(unknown): check that 1-arg constructors are explicit.\r
+    #                How to tell it's a constructor?\r
+    #                (handled in CheckForNonStandardConstructs for now)\r
+    # TODO(unknown): check that classes declare or disable copy/assign\r
+    #                (level 1 error)\r
+    pass\r
+\r
+  # Check if people are using the verboten C basic types.  The only exception\r
+  # we regularly allow is "unsigned short port" for port.\r
+  if Search(r'\bshort port\b', line):\r
+    if not Search(r'\bunsigned short port\b', line):\r
+      error(filename, linenum, 'runtime/int', 4,\r
+            'Use "unsigned short" for ports, not "short"')\r
+  else:\r
+    match = Search(r'\b(short|long(?! +double)|long long)\b', line)\r
+    if match:\r
+      error(filename, linenum, 'runtime/int', 4,\r
+            'Use int16/int64/etc, rather than the C type %s' % match.group(1))\r
+\r
+  # Check if some verboten operator overloading is going on\r
+  # TODO(unknown): catch out-of-line unary operator&:\r
+  #   class X {};\r
+  #   int operator&(const X& x) { return 42; }  // unary operator&\r
+  # The trick is it's hard to tell apart from binary operator&:\r
+  #   class Y { int operator&(const Y& x) { return 23; } }; // binary operator&\r
+  if Search(r'\boperator\s*&\s*\(\s*\)', line):\r
+    error(filename, linenum, 'runtime/operator', 4,\r
+          'Unary operator& is dangerous.  Do not use it.')\r
+\r
+  # Check for suspicious usage of "if" like\r
+  # } if (a == b) {\r
+  if Search(r'\}\s*if\s*\(', line):\r
+    error(filename, linenum, 'readability/braces', 4,\r
+          'Did you mean "else if"? If not, start a new line for "if".')\r
+\r
+  # Check for potential format string bugs like printf(foo).\r
+  # We constrain the pattern not to pick things like DocidForPrintf(foo).\r
+  # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())\r
+  # TODO(unknown): Catch the following case. Need to change the calling\r
+  # convention of the whole function to process multiple line to handle it.\r
+  #   printf(\r
+  #       boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);\r
+  printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')\r
+  if printf_args:\r
+    match = Match(r'([\w.\->()]+)$', printf_args)\r
+    if match and match.group(1) != '__VA_ARGS__':\r
+      function_name = re.search(r'\b((?:string)?printf)\s*\(',\r
+                                line, re.I).group(1)\r
+      error(filename, linenum, 'runtime/printf', 4,\r
+            'Potential format string bug. Do %s("%%s", %s) instead.'\r
+            % (function_name, match.group(1)))\r
+\r
+  # Check for potential memset bugs like memset(buf, sizeof(buf), 0).\r
+  match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)\r
+  if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):\r
+    error(filename, linenum, 'runtime/memset', 4,\r
+          'Did you mean "memset(%s, 0, %s)"?'\r
+          % (match.group(1), match.group(2)))\r
+\r
+  if Search(r'\busing namespace\b', line):\r
+    error(filename, linenum, 'build/namespaces', 5,\r
+          'Do not use namespace using-directives.  '\r
+          'Use using-declarations instead.')\r
+\r
+  # Detect variable-length arrays.\r
+  match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)\r
+  if (match and match.group(2) != 'return' and match.group(2) != 'delete' and\r
+      match.group(3).find(']') == -1):\r
+    # Split the size using space and arithmetic operators as delimiters.\r
+    # If any of the resulting tokens are not compile time constants then\r
+    # report the error.\r
+    tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))\r
+    is_const = True\r
+    skip_next = False\r
+    for tok in tokens:\r
+      if skip_next:\r
+        skip_next = False\r
+        continue\r
+\r
+      if Search(r'sizeof\(.+\)', tok): continue\r
+      if Search(r'arraysize\(\w+\)', tok): continue\r
+\r
+      tok = tok.lstrip('(')\r
+      tok = tok.rstrip(')')\r
+      if not tok: continue\r
+      if Match(r'\d+', tok): continue\r
+      if Match(r'0[xX][0-9a-fA-F]+', tok): continue\r
+      if Match(r'k[A-Z0-9]\w*', tok): continue\r
+      if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue\r
+      if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue\r
+      # A catch all for tricky sizeof cases, including 'sizeof expression',\r
+      # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'\r
+      # requires skipping the next token because we split on ' ' and '*'.\r
+      if tok.startswith('sizeof'):\r
+        skip_next = True\r
+        continue\r
+      is_const = False\r
+      break\r
+    if not is_const:\r
+      error(filename, linenum, 'runtime/arrays', 1,\r
+            'Do not use variable-length arrays.  Use an appropriately named '\r
+            "('k' followed by CamelCase) compile-time constant for the size.")\r
+\r
+  # Check for use of unnamed namespaces in header files.  Registration\r
+  # macros are typically OK, so we allow use of "namespace {" on lines\r
+  # that end with backslashes.\r
+  if (IsHeaderExtension(file_extension)\r
+      and Search(r'\bnamespace\s*{', line)\r
+      and line[-1] != '\\'):\r
+    error(filename, linenum, 'build/namespaces', 4,\r
+          'Do not use unnamed namespaces in header files.  See '\r
+          'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'\r
+          ' for more information.')\r
+\r
+\r
+def CheckGlobalStatic(filename, clean_lines, linenum, error):\r
+  """Check for unsafe global or static objects.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Match two lines at a time to support multiline declarations\r
+  if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line):\r
+    line += clean_lines.elided[linenum + 1].strip()\r
+\r
+  # Check for people declaring static/global STL strings at the top level.\r
+  # This is dangerous because the C++ language does not guarantee that\r
+  # globals with constructors are initialized before the first access, and\r
+  # also because globals can be destroyed when some threads are still running.\r
+  # TODO(unknown): Generalize this to also find static unique_ptr instances.\r
+  # TODO(unknown): File bugs for clang-tidy to find these.\r
+  match = Match(\r
+      r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +'\r
+      r'([a-zA-Z0-9_:]+)\b(.*)',\r
+      line)\r
+\r
+  # Remove false positives:\r
+  # - String pointers (as opposed to values).\r
+  #    string *pointer\r
+  #    const string *pointer\r
+  #    string const *pointer\r
+  #    string *const pointer\r
+  #\r
+  # - Functions and template specializations.\r
+  #    string Function<Type>(...\r
+  #    string Class<Type>::Method(...\r
+  #\r
+  # - Operators.  These are matched separately because operator names\r
+  #   cross non-word boundaries, and trying to match both operators\r
+  #   and functions at the same time would decrease accuracy of\r
+  #   matching identifiers.\r
+  #    string Class::operator*()\r
+  if (match and\r
+      not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line) and\r
+      not Search(r'\boperator\W', line) and\r
+      not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))):\r
+    if Search(r'\bconst\b', line):\r
+      error(filename, linenum, 'runtime/string', 4,\r
+            'For a static/global string constant, use a C style string '\r
+            'instead: "%schar%s %s[]".' %\r
+            (match.group(1), match.group(2) or '', match.group(3)))\r
+    else:\r
+      error(filename, linenum, 'runtime/string', 4,\r
+            'Static/global string variables are not permitted.')\r
+\r
+  if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line) or\r
+      Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)):\r
+    error(filename, linenum, 'runtime/init', 4,\r
+          'You seem to be initializing a member variable with itself.')\r
+\r
+\r
+def CheckPrintf(filename, clean_lines, linenum, error):\r
+  """Check for printf related issues.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # When snprintf is used, the second argument shouldn't be a literal.\r
+  match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)\r
+  if match and match.group(2) != '0':\r
+    # If 2nd arg is zero, snprintf is used to calculate size.\r
+    error(filename, linenum, 'runtime/printf', 3,\r
+          'If you can, use sizeof(%s) instead of %s as the 2nd arg '\r
+          'to snprintf.' % (match.group(1), match.group(2)))\r
+\r
+  # Check if some verboten C functions are being used.\r
+  if Search(r'\bsprintf\s*\(', line):\r
+    error(filename, linenum, 'runtime/printf', 5,\r
+          'Never use sprintf. Use snprintf instead.')\r
+  match = Search(r'\b(strcpy|strcat)\s*\(', line)\r
+  if match:\r
+    error(filename, linenum, 'runtime/printf', 4,\r
+          'Almost always, snprintf is better than %s' % match.group(1))\r
+\r
+\r
+def IsDerivedFunction(clean_lines, linenum):\r
+  """Check if current line contains an inherited function.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+  Returns:\r
+    True if current line contains a function with "override"\r
+    virt-specifier.\r
+  """\r
+  # Scan back a few lines for start of current function\r
+  for i in xrange(linenum, max(-1, linenum - 10), -1):\r
+    match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i])\r
+    if match:\r
+      # Look for "override" after the matching closing parenthesis\r
+      line, _, closing_paren = CloseExpression(\r
+          clean_lines, i, len(match.group(1)))\r
+      return (closing_paren >= 0 and\r
+              Search(r'\boverride\b', line[closing_paren:]))\r
+  return False\r
+\r
+\r
+def IsOutOfLineMethodDefinition(clean_lines, linenum):\r
+  """Check if current line contains an out-of-line method definition.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+  Returns:\r
+    True if current line contains an out-of-line method definition.\r
+  """\r
+  # Scan back a few lines for start of current function\r
+  for i in xrange(linenum, max(-1, linenum - 10), -1):\r
+    if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]):\r
+      return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None\r
+  return False\r
+\r
+\r
+def IsInitializerList(clean_lines, linenum):\r
+  """Check if current line is inside constructor initializer list.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+  Returns:\r
+    True if current line appears to be inside constructor initializer\r
+    list, False otherwise.\r
+  """\r
+  for i in xrange(linenum, 1, -1):\r
+    line = clean_lines.elided[i]\r
+    if i == linenum:\r
+      remove_function_body = Match(r'^(.*)\{\s*$', line)\r
+      if remove_function_body:\r
+        line = remove_function_body.group(1)\r
+\r
+    if Search(r'\s:\s*\w+[({]', line):\r
+      # A lone colon tend to indicate the start of a constructor\r
+      # initializer list.  It could also be a ternary operator, which\r
+      # also tend to appear in constructor initializer lists as\r
+      # opposed to parameter lists.\r
+      return True\r
+    if Search(r'\}\s*,\s*$', line):\r
+      # A closing brace followed by a comma is probably the end of a\r
+      # brace-initialized member in constructor initializer list.\r
+      return True\r
+    if Search(r'[{};]\s*$', line):\r
+      # Found one of the following:\r
+      # - A closing brace or semicolon, probably the end of the previous\r
+      #   function.\r
+      # - An opening brace, probably the start of current class or namespace.\r
+      #\r
+      # Current line is probably not inside an initializer list since\r
+      # we saw one of those things without seeing the starting colon.\r
+      return False\r
+\r
+  # Got to the beginning of the file without seeing the start of\r
+  # constructor initializer list.\r
+  return False\r
+\r
+\r
+def CheckForNonConstReference(filename, clean_lines, linenum,\r
+                              nesting_state, error):\r
+  """Check for non-const references.\r
+\r
+  Separate from CheckLanguage since it scans backwards from current\r
+  line, instead of scanning forward.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    error: The function to call with any errors found.\r
+  """\r
+  # Do nothing if there is no '&' on current line.\r
+  line = clean_lines.elided[linenum]\r
+  if '&' not in line:\r
+    return\r
+\r
+  # If a function is inherited, current function doesn't have much of\r
+  # a choice, so any non-const references should not be blamed on\r
+  # derived function.\r
+  if IsDerivedFunction(clean_lines, linenum):\r
+    return\r
+\r
+  # Don't warn on out-of-line method definitions, as we would warn on the\r
+  # in-line declaration, if it isn't marked with 'override'.\r
+  if IsOutOfLineMethodDefinition(clean_lines, linenum):\r
+    return\r
+\r
+  # Long type names may be broken across multiple lines, usually in one\r
+  # of these forms:\r
+  #   LongType\r
+  #       ::LongTypeContinued &identifier\r
+  #   LongType::\r
+  #       LongTypeContinued &identifier\r
+  #   LongType<\r
+  #       ...>::LongTypeContinued &identifier\r
+  #\r
+  # If we detected a type split across two lines, join the previous\r
+  # line to current line so that we can match const references\r
+  # accordingly.\r
+  #\r
+  # Note that this only scans back one line, since scanning back\r
+  # arbitrary number of lines would be expensive.  If you have a type\r
+  # that spans more than 2 lines, please use a typedef.\r
+  if linenum > 1:\r
+    previous = None\r
+    if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line):\r
+      # previous_line\n + ::current_line\r
+      previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$',\r
+                        clean_lines.elided[linenum - 1])\r
+    elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line):\r
+      # previous_line::\n + current_line\r
+      previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$',\r
+                        clean_lines.elided[linenum - 1])\r
+    if previous:\r
+      line = previous.group(1) + line.lstrip()\r
+    else:\r
+      # Check for templated parameter that is split across multiple lines\r
+      endpos = line.rfind('>')\r
+      if endpos > -1:\r
+        (_, startline, startpos) = ReverseCloseExpression(\r
+            clean_lines, linenum, endpos)\r
+        if startpos > -1 and startline < linenum:\r
+          # Found the matching < on an earlier line, collect all\r
+          # pieces up to current line.\r
+          line = ''\r
+          for i in xrange(startline, linenum + 1):\r
+            line += clean_lines.elided[i].strip()\r
+\r
+  # Check for non-const references in function parameters.  A single '&' may\r
+  # found in the following places:\r
+  #   inside expression: binary & for bitwise AND\r
+  #   inside expression: unary & for taking the address of something\r
+  #   inside declarators: reference parameter\r
+  # We will exclude the first two cases by checking that we are not inside a\r
+  # function body, including one that was just introduced by a trailing '{'.\r
+  # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare].\r
+  if (nesting_state.previous_stack_top and\r
+      not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or\r
+           isinstance(nesting_state.previous_stack_top, _NamespaceInfo))):\r
+    # Not at toplevel, not within a class, and not within a namespace\r
+    return\r
+\r
+  # Avoid initializer lists.  We only need to scan back from the\r
+  # current line for something that starts with ':'.\r
+  #\r
+  # We don't need to check the current line, since the '&' would\r
+  # appear inside the second set of parentheses on the current line as\r
+  # opposed to the first set.\r
+  if linenum > 0:\r
+    for i in xrange(linenum - 1, max(0, linenum - 10), -1):\r
+      previous_line = clean_lines.elided[i]\r
+      if not Search(r'[),]\s*$', previous_line):\r
+        break\r
+      if Match(r'^\s*:\s+\S', previous_line):\r
+        return\r
+\r
+  # Avoid preprocessors\r
+  if Search(r'\\\s*$', line):\r
+    return\r
+\r
+  # Avoid constructor initializer lists\r
+  if IsInitializerList(clean_lines, linenum):\r
+    return\r
+\r
+  # We allow non-const references in a few standard places, like functions\r
+  # called "swap()" or iostream operators like "<<" or ">>".  Do not check\r
+  # those function parameters.\r
+  #\r
+  # We also accept & in static_assert, which looks like a function but\r
+  # it's actually a declaration expression.\r
+  whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'\r
+                           r'operator\s*[<>][<>]|'\r
+                           r'static_assert|COMPILE_ASSERT'\r
+                           r')\s*\(')\r
+  if Search(whitelisted_functions, line):\r
+    return\r
+  elif not Search(r'\S+\([^)]*$', line):\r
+    # Don't see a whitelisted function on this line.  Actually we\r
+    # didn't see any function name on this line, so this is likely a\r
+    # multi-line parameter list.  Try a bit harder to catch this case.\r
+    for i in xrange(2):\r
+      if (linenum > i and\r
+          Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):\r
+        return\r
+\r
+  decls = ReplaceAll(r'{[^}]*}', ' ', line)  # exclude function body\r
+  for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):\r
+    if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and\r
+        not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)):\r
+      error(filename, linenum, 'runtime/references', 2,\r
+            'Is this a non-const reference? '\r
+            'If so, make const or use a pointer: ' +\r
+            ReplaceAll(' *<', '<', parameter))\r
+\r
+\r
+def CheckCasts(filename, clean_lines, linenum, error):\r
+  """Various cast related checks.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  # Check to see if they're using an conversion function cast.\r
+  # I just try to capture the most common basic types, though there are more.\r
+  # Parameterless conversion functions, such as bool(), are allowed as they are\r
+  # probably a member operator declaration or default constructor.\r
+  match = Search(\r
+      r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b'\r
+      r'(int|float|double|bool|char|int32|uint32|int64|uint64)'\r
+      r'(\([^)].*)', line)\r
+  expecting_function = ExpectingFunctionArgs(clean_lines, linenum)\r
+  if match and not expecting_function:\r
+    matched_type = match.group(2)\r
+\r
+    # matched_new_or_template is used to silence two false positives:\r
+    # - New operators\r
+    # - Template arguments with function types\r
+    #\r
+    # For template arguments, we match on types immediately following\r
+    # an opening bracket without any spaces.  This is a fast way to\r
+    # silence the common case where the function type is the first\r
+    # template argument.  False negative with less-than comparison is\r
+    # avoided because those operators are usually followed by a space.\r
+    #\r
+    #   function<double(double)>   // bracket + no space = false positive\r
+    #   value < double(42)         // bracket + space = true positive\r
+    matched_new_or_template = match.group(1)\r
+\r
+    # Avoid arrays by looking for brackets that come after the closing\r
+    # parenthesis.\r
+    if Match(r'\([^()]+\)\s*\[', match.group(3)):\r
+      return\r
+\r
+    # Other things to ignore:\r
+    # - Function pointers\r
+    # - Casts to pointer types\r
+    # - Placement new\r
+    # - Alias declarations\r
+    matched_funcptr = match.group(3)\r
+    if (matched_new_or_template is None and\r
+        not (matched_funcptr and\r
+             (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(',\r
+                    matched_funcptr) or\r
+              matched_funcptr.startswith('(*)'))) and\r
+        not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and\r
+        not Search(r'new\(\S+\)\s*' + matched_type, line)):\r
+      error(filename, linenum, 'readability/casting', 4,\r
+            'Using deprecated casting style.  '\r
+            'Use static_cast<%s>(...) instead' %\r
+            matched_type)\r
+\r
+  if not expecting_function:\r
+    CheckCStyleCast(filename, clean_lines, linenum, 'static_cast',\r
+                    r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)\r
+\r
+  # This doesn't catch all cases. Consider (const char * const)"hello".\r
+  #\r
+  # (char *) "foo" should always be a const_cast (reinterpret_cast won't\r
+  # compile).\r
+  if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast',\r
+                     r'\((char\s?\*+\s?)\)\s*"', error):\r
+    pass\r
+  else:\r
+    # Check pointer casts for other than string constants\r
+    CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast',\r
+                    r'\((\w+\s?\*+\s?)\)', error)\r
+\r
+  # In addition, we look for people taking the address of a cast.  This\r
+  # is dangerous -- casts can assign to temporaries, so the pointer doesn't\r
+  # point where you think.\r
+  #\r
+  # Some non-identifier character is required before the '&' for the\r
+  # expression to be recognized as a cast.  These are casts:\r
+  #   expression = &static_cast<int*>(temporary());\r
+  #   function(&(int*)(temporary()));\r
+  #\r
+  # This is not a cast:\r
+  #   reference_type&(int* function_param);\r
+  match = Search(\r
+      r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|'\r
+      r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line)\r
+  if match:\r
+    # Try a better error message when the & is bound to something\r
+    # dereferenced by the casted pointer, as opposed to the casted\r
+    # pointer itself.\r
+    parenthesis_error = False\r
+    match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line)\r
+    if match:\r
+      _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1)))\r
+      if x1 >= 0 and clean_lines.elided[y1][x1] == '(':\r
+        _, y2, x2 = CloseExpression(clean_lines, y1, x1)\r
+        if x2 >= 0:\r
+          extended_line = clean_lines.elided[y2][x2:]\r
+          if y2 < clean_lines.NumLines() - 1:\r
+            extended_line += clean_lines.elided[y2 + 1]\r
+          if Match(r'\s*(?:->|\[)', extended_line):\r
+            parenthesis_error = True\r
+\r
+    if parenthesis_error:\r
+      error(filename, linenum, 'readability/casting', 4,\r
+            ('Are you taking an address of something dereferenced '\r
+             'from a cast?  Wrapping the dereferenced expression in '\r
+             'parentheses will make the binding more obvious'))\r
+    else:\r
+      error(filename, linenum, 'runtime/casting', 4,\r
+            ('Are you taking an address of a cast?  '\r
+             'This is dangerous: could be a temp var.  '\r
+             'Take the address before doing the cast, rather than after'))\r
+\r
+\r
+def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error):\r
+  """Checks for a C-style cast by looking for the pattern.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    cast_type: The string for the C++ cast to recommend.  This is either\r
+      reinterpret_cast, static_cast, or const_cast, depending.\r
+    pattern: The regular expression used to find C-style casts.\r
+    error: The function to call with any errors found.\r
+\r
+  Returns:\r
+    True if an error was emitted.\r
+    False otherwise.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+  match = Search(pattern, line)\r
+  if not match:\r
+    return False\r
+\r
+  # Exclude lines with keywords that tend to look like casts\r
+  context = line[0:match.start(1) - 1]\r
+  if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context):\r
+    return False\r
+\r
+  # Try expanding current context to see if we one level of\r
+  # parentheses inside a macro.\r
+  if linenum > 0:\r
+    for i in xrange(linenum - 1, max(0, linenum - 5), -1):\r
+      context = clean_lines.elided[i] + context\r
+  if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context):\r
+    return False\r
+\r
+  # operator++(int) and operator--(int)\r
+  if context.endswith(' operator++') or context.endswith(' operator--'):\r
+    return False\r
+\r
+  # A single unnamed argument for a function tends to look like old style cast.\r
+  # If we see those, don't issue warnings for deprecated casts.\r
+  remainder = line[match.end(0):]\r
+  if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)',\r
+           remainder):\r
+    return False\r
+\r
+  # At this point, all that should be left is actual casts.\r
+  error(filename, linenum, 'readability/casting', 4,\r
+        'Using C-style cast.  Use %s<%s>(...) instead' %\r
+        (cast_type, match.group(1)))\r
+\r
+  return True\r
+\r
+\r
+def ExpectingFunctionArgs(clean_lines, linenum):\r
+  """Checks whether where function type arguments are expected.\r
+\r
+  Args:\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+\r
+  Returns:\r
+    True if the line at 'linenum' is inside something that expects arguments\r
+    of function types.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+  return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or\r
+          (linenum >= 2 and\r
+           (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$',\r
+                  clean_lines.elided[linenum - 1]) or\r
+            Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$',\r
+                  clean_lines.elided[linenum - 2]) or\r
+            Search(r'\bstd::m?function\s*\<\s*$',\r
+                   clean_lines.elided[linenum - 1]))))\r
+\r
+\r
+_HEADERS_CONTAINING_TEMPLATES = (\r
+    ('<deque>', ('deque',)),\r
+    ('<functional>', ('unary_function', 'binary_function',\r
+                      'plus', 'minus', 'multiplies', 'divides', 'modulus',\r
+                      'negate',\r
+                      'equal_to', 'not_equal_to', 'greater', 'less',\r
+                      'greater_equal', 'less_equal',\r
+                      'logical_and', 'logical_or', 'logical_not',\r
+                      'unary_negate', 'not1', 'binary_negate', 'not2',\r
+                      'bind1st', 'bind2nd',\r
+                      'pointer_to_unary_function',\r
+                      'pointer_to_binary_function',\r
+                      'ptr_fun',\r
+                      'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',\r
+                      'mem_fun_ref_t',\r
+                      'const_mem_fun_t', 'const_mem_fun1_t',\r
+                      'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',\r
+                      'mem_fun_ref',\r
+                     )),\r
+    ('<limits>', ('numeric_limits',)),\r
+    ('<list>', ('list',)),\r
+    ('<map>', ('map', 'multimap',)),\r
+    ('<memory>', ('allocator', 'make_shared', 'make_unique', 'shared_ptr',\r
+                  'unique_ptr', 'weak_ptr')),\r
+    ('<queue>', ('queue', 'priority_queue',)),\r
+    ('<set>', ('set', 'multiset',)),\r
+    ('<stack>', ('stack',)),\r
+    ('<string>', ('char_traits', 'basic_string',)),\r
+    ('<tuple>', ('tuple',)),\r
+    ('<unordered_map>', ('unordered_map', 'unordered_multimap')),\r
+    ('<unordered_set>', ('unordered_set', 'unordered_multiset')),\r
+    ('<utility>', ('pair',)),\r
+    ('<vector>', ('vector',)),\r
+\r
+    # gcc extensions.\r
+    # Note: std::hash is their hash, ::hash is our hash\r
+    ('<hash_map>', ('hash_map', 'hash_multimap',)),\r
+    ('<hash_set>', ('hash_set', 'hash_multiset',)),\r
+    ('<slist>', ('slist',)),\r
+    )\r
+\r
+_HEADERS_MAYBE_TEMPLATES = (\r
+    ('<algorithm>', ('copy', 'max', 'min', 'min_element', 'sort',\r
+                     'transform',\r
+                    )),\r
+    ('<utility>', ('forward', 'make_pair', 'move', 'swap')),\r
+    )\r
+\r
+_RE_PATTERN_STRING = re.compile(r'\bstring\b')\r
+\r
+_re_pattern_headers_maybe_templates = []\r
+for _header, _templates in _HEADERS_MAYBE_TEMPLATES:\r
+  for _template in _templates:\r
+    # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or\r
+    # type::max().\r
+    _re_pattern_headers_maybe_templates.append(\r
+        (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),\r
+            _template,\r
+            _header))\r
+\r
+# Other scripts may reach in and modify this pattern.\r
+_re_pattern_templates = []\r
+for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:\r
+  for _template in _templates:\r
+    _re_pattern_templates.append(\r
+        (re.compile(r'(\<|\b)' + _template + r'\s*\<'),\r
+         _template + '<>',\r
+         _header))\r
+\r
+\r
+def FilesBelongToSameModule(filename_cc, filename_h):\r
+  """Check if these two filenames belong to the same module.\r
+\r
+  The concept of a 'module' here is a as follows:\r
+  foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the\r
+  same 'module' if they are in the same directory.\r
+  some/path/public/xyzzy and some/path/internal/xyzzy are also considered\r
+  to belong to the same module here.\r
+\r
+  If the filename_cc contains a longer path than the filename_h, for example,\r
+  '/absolute/path/to/base/sysinfo.cc', and this file would include\r
+  'base/sysinfo.h', this function also produces the prefix needed to open the\r
+  header. This is used by the caller of this function to more robustly open the\r
+  header file. We don't have access to the real include paths in this context,\r
+  so we need this guesswork here.\r
+\r
+  Known bugs: tools/base/bar.cc and base/bar.h belong to the same module\r
+  according to this implementation. Because of this, this function gives\r
+  some false positives. This should be sufficiently rare in practice.\r
+\r
+  Args:\r
+    filename_cc: is the path for the .cc file\r
+    filename_h: is the path for the header path\r
+\r
+  Returns:\r
+    Tuple with a bool and a string:\r
+    bool: True if filename_cc and filename_h belong to the same module.\r
+    string: the additional prefix needed to open the header file.\r
+  """\r
+\r
+  fileinfo = FileInfo(filename_cc)\r
+  if not fileinfo.IsSource():\r
+    return (False, '')\r
+  filename_cc = filename_cc[:-len(fileinfo.Extension())]\r
+  matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo.BaseName())\r
+  if matched_test_suffix:\r
+    filename_cc = filename_cc[:-len(matched_test_suffix.group(1))]\r
+  filename_cc = filename_cc.replace('/public/', '/')\r
+  filename_cc = filename_cc.replace('/internal/', '/')\r
+\r
+  if not filename_h.endswith('.h'):\r
+    return (False, '')\r
+  filename_h = filename_h[:-len('.h')]\r
+  if filename_h.endswith('-inl'):\r
+    filename_h = filename_h[:-len('-inl')]\r
+  filename_h = filename_h.replace('/public/', '/')\r
+  filename_h = filename_h.replace('/internal/', '/')\r
+\r
+  files_belong_to_same_module = filename_cc.endswith(filename_h)\r
+  common_path = ''\r
+  if files_belong_to_same_module:\r
+    common_path = filename_cc[:-len(filename_h)]\r
+  return files_belong_to_same_module, common_path\r
+\r
+\r
+def UpdateIncludeState(filename, include_dict, io=codecs):\r
+  """Fill up the include_dict with new includes found from the file.\r
+\r
+  Args:\r
+    filename: the name of the header to read.\r
+    include_dict: a dictionary in which the headers are inserted.\r
+    io: The io factory to use to read the file. Provided for testability.\r
+\r
+  Returns:\r
+    True if a header was successfully added. False otherwise.\r
+  """\r
+  headerfile = None\r
+  try:\r
+    headerfile = io.open(filename, 'r', 'utf8', 'replace')\r
+  except IOError:\r
+    return False\r
+  linenum = 0\r
+  for line in headerfile:\r
+    linenum += 1\r
+    clean_line = CleanseComments(line)\r
+    match = _RE_PATTERN_INCLUDE.search(clean_line)\r
+    if match:\r
+      include = match.group(2)\r
+      include_dict.setdefault(include, linenum)\r
+  return True\r
+\r
+\r
+def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,\r
+                              io=codecs):\r
+  """Reports for missing stl includes.\r
+\r
+  This function will output warnings to make sure you are including the headers\r
+  necessary for the stl containers and functions that you use. We only give one\r
+  reason to include a header. For example, if you use both equal_to<> and\r
+  less<> in a .h file, only one (the latter in the file) of these will be\r
+  reported as a reason to include the <functional>.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    include_state: An _IncludeState instance.\r
+    error: The function to call with any errors found.\r
+    io: The IO factory to use to read the header file. Provided for unittest\r
+        injection.\r
+  """\r
+  required = {}  # A map of header name to linenumber and the template entity.\r
+                 # Example of required: { '<functional>': (1219, 'less<>') }\r
+\r
+  for linenum in xrange(clean_lines.NumLines()):\r
+    line = clean_lines.elided[linenum]\r
+    if not line or line[0] == '#':\r
+      continue\r
+\r
+    # String is special -- it is a non-templatized type in STL.\r
+    matched = _RE_PATTERN_STRING.search(line)\r
+    if matched:\r
+      # Don't warn about strings in non-STL namespaces:\r
+      # (We check only the first match per line; good enough.)\r
+      prefix = line[:matched.start()]\r
+      if prefix.endswith('std::') or not prefix.endswith('::'):\r
+        required['<string>'] = (linenum, 'string')\r
+\r
+    for pattern, template, header in _re_pattern_headers_maybe_templates:\r
+      if pattern.search(line):\r
+        required[header] = (linenum, template)\r
+\r
+    # The following function is just a speed up, no semantics are changed.\r
+    if not '<' in line:  # Reduces the cpu time usage by skipping lines.\r
+      continue\r
+\r
+    for pattern, template, header in _re_pattern_templates:\r
+      matched = pattern.search(line)\r
+      if matched:\r
+        # Don't warn about IWYU in non-STL namespaces:\r
+        # (We check only the first match per line; good enough.)\r
+        prefix = line[:matched.start()]\r
+        if prefix.endswith('std::') or not prefix.endswith('::'):\r
+          required[header] = (linenum, template)\r
+\r
+  # The policy is that if you #include something in foo.h you don't need to\r
+  # include it again in foo.cc. Here, we will look at possible includes.\r
+  # Let's flatten the include_state include_list and copy it into a dictionary.\r
+  include_dict = dict([item for sublist in include_state.include_list\r
+                       for item in sublist])\r
+\r
+  # Did we find the header for this file (if any) and successfully load it?\r
+  header_found = False\r
+\r
+  # Use the absolute path so that matching works properly.\r
+  abs_filename = FileInfo(filename).FullName()\r
+\r
+  # For Emacs's flymake.\r
+  # If cpplint is invoked from Emacs's flymake, a temporary file is generated\r
+  # by flymake and that file name might end with '_flymake.cc'. In that case,\r
+  # restore original file name here so that the corresponding header file can be\r
+  # found.\r
+  # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'\r
+  # instead of 'foo_flymake.h'\r
+  abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)\r
+\r
+  # include_dict is modified during iteration, so we iterate over a copy of\r
+  # the keys.\r
+  header_keys = include_dict.keys()\r
+  for header in header_keys:\r
+    (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)\r
+    fullpath = common_path + header\r
+    if same_module and UpdateIncludeState(fullpath, include_dict, io):\r
+      header_found = True\r
+\r
+  # If we can't find the header file for a .cc, assume it's because we don't\r
+  # know where to look. In that case we'll give up as we're not sure they\r
+  # didn't include it in the .h file.\r
+  # TODO(unknown): Do a better job of finding .h files so we are confident that\r
+  # not having the .h file means there isn't one.\r
+  if filename.endswith('.cc') and not header_found:\r
+    return\r
+\r
+  # All the lines have been processed, report the errors found.\r
+  for required_header_unstripped in required:\r
+    template = required[required_header_unstripped][1]\r
+    if required_header_unstripped.strip('<>"') not in include_dict:\r
+      error(filename, required[required_header_unstripped][0],\r
+            'build/include_what_you_use', 4,\r
+            'Add #include ' + required_header_unstripped + ' for ' + template)\r
+\r
+\r
+_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')\r
+\r
+\r
+def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):\r
+  """Check that make_pair's template arguments are deduced.\r
+\r
+  G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are\r
+  specified explicitly, and such use isn't intended in any case.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+  match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)\r
+  if match:\r
+    error(filename, linenum, 'build/explicit_make_pair',\r
+          4,  # 4 = high confidence\r
+          'For C++11-compatibility, omit template arguments from make_pair'\r
+          ' OR use pair directly OR if appropriate, construct a pair directly')\r
+\r
+\r
+def CheckRedundantVirtual(filename, clean_lines, linenum, error):\r
+  """Check if line contains a redundant "virtual" function-specifier.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  # Look for "virtual" on current line.\r
+  line = clean_lines.elided[linenum]\r
+  virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line)\r
+  if not virtual: return\r
+\r
+  # Ignore "virtual" keywords that are near access-specifiers.  These\r
+  # are only used in class base-specifier and do not apply to member\r
+  # functions.\r
+  if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or\r
+      Match(r'^\s+(public|protected|private)\b', virtual.group(3))):\r
+    return\r
+\r
+  # Ignore the "virtual" keyword from virtual base classes.  Usually\r
+  # there is a column on the same line in these cases (virtual base\r
+  # classes are rare in google3 because multiple inheritance is rare).\r
+  if Match(r'^.*[^:]:[^:].*$', line): return\r
+\r
+  # Look for the next opening parenthesis.  This is the start of the\r
+  # parameter list (possibly on the next line shortly after virtual).\r
+  # TODO(unknown): doesn't work if there are virtual functions with\r
+  # decltype() or other things that use parentheses, but csearch suggests\r
+  # that this is rare.\r
+  end_col = -1\r
+  end_line = -1\r
+  start_col = len(virtual.group(2))\r
+  for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())):\r
+    line = clean_lines.elided[start_line][start_col:]\r
+    parameter_list = Match(r'^([^(]*)\(', line)\r
+    if parameter_list:\r
+      # Match parentheses to find the end of the parameter list\r
+      (_, end_line, end_col) = CloseExpression(\r
+          clean_lines, start_line, start_col + len(parameter_list.group(1)))\r
+      break\r
+    start_col = 0\r
+\r
+  if end_col < 0:\r
+    return  # Couldn't find end of parameter list, give up\r
+\r
+  # Look for "override" or "final" after the parameter list\r
+  # (possibly on the next few lines).\r
+  for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())):\r
+    line = clean_lines.elided[i][end_col:]\r
+    match = Search(r'\b(override|final)\b', line)\r
+    if match:\r
+      error(filename, linenum, 'readability/inheritance', 4,\r
+            ('"virtual" is redundant since function is '\r
+             'already declared as "%s"' % match.group(1)))\r
+\r
+    # Set end_col to check whole lines after we are done with the\r
+    # first line.\r
+    end_col = 0\r
+    if Search(r'[^\w]\s*$', line):\r
+      break\r
+\r
+\r
+def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error):\r
+  """Check if line contains a redundant "override" or "final" virt-specifier.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  # Look for closing parenthesis nearby.  We need one to confirm where\r
+  # the declarator ends and where the virt-specifier starts to avoid\r
+  # false positives.\r
+  line = clean_lines.elided[linenum]\r
+  declarator_end = line.rfind(')')\r
+  if declarator_end >= 0:\r
+    fragment = line[declarator_end:]\r
+  else:\r
+    if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0:\r
+      fragment = line\r
+    else:\r
+      return\r
+\r
+  # Check that at most one of "override" or "final" is present, not both\r
+  if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment):\r
+    error(filename, linenum, 'readability/inheritance', 4,\r
+          ('"override" is redundant since function is '\r
+           'already declared as "final"'))\r
+\r
+\r
+\r
+\r
+# Returns true if we are at a new block, and it is directly\r
+# inside of a namespace.\r
+def IsBlockInNameSpace(nesting_state, is_forward_declaration):\r
+  """Checks that the new block is directly in a namespace.\r
+\r
+  Args:\r
+    nesting_state: The _NestingState object that contains info about our state.\r
+    is_forward_declaration: If the class is a forward declared class.\r
+  Returns:\r
+    Whether or not the new block is directly in a namespace.\r
+  """\r
+  if is_forward_declaration:\r
+    if len(nesting_state.stack) >= 1 and (\r
+        isinstance(nesting_state.stack[-1], _NamespaceInfo)):\r
+      return True\r
+    else:\r
+      return False\r
+\r
+  return (len(nesting_state.stack) > 1 and\r
+          nesting_state.stack[-1].check_namespace_indentation and\r
+          isinstance(nesting_state.stack[-2], _NamespaceInfo))\r
+\r
+\r
+def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,\r
+                                    raw_lines_no_comments, linenum):\r
+  """This method determines if we should apply our namespace indentation check.\r
+\r
+  Args:\r
+    nesting_state: The current nesting state.\r
+    is_namespace_indent_item: If we just put a new class on the stack, True.\r
+      If the top of the stack is not a class, or we did not recently\r
+      add the class, False.\r
+    raw_lines_no_comments: The lines without the comments.\r
+    linenum: The current line number we are processing.\r
+\r
+  Returns:\r
+    True if we should apply our namespace indentation check. Currently, it\r
+    only works for classes and namespaces inside of a namespace.\r
+  """\r
+\r
+  is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments,\r
+                                                     linenum)\r
+\r
+  if not (is_namespace_indent_item or is_forward_declaration):\r
+    return False\r
+\r
+  # If we are in a macro, we do not want to check the namespace indentation.\r
+  if IsMacroDefinition(raw_lines_no_comments, linenum):\r
+    return False\r
+\r
+  return IsBlockInNameSpace(nesting_state, is_forward_declaration)\r
+\r
+\r
+# Call this method if the line is directly inside of a namespace.\r
+# If the line above is blank (excluding comments) or the start of\r
+# an inner namespace, it cannot be indented.\r
+def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum,\r
+                                    error):\r
+  line = raw_lines_no_comments[linenum]\r
+  if Match(r'^\s+', line):\r
+    error(filename, linenum, 'runtime/indentation_namespace', 4,\r
+          'Do not indent within a namespace')\r
+\r
+\r
+def ProcessLine(filename, file_extension, clean_lines, line,\r
+                include_state, function_state, nesting_state, error,\r
+                extra_check_functions=[]):\r
+  """Processes a single line in the file.\r
+\r
+  Args:\r
+    filename: Filename of the file that is being processed.\r
+    file_extension: The extension (dot not included) of the file.\r
+    clean_lines: An array of strings, each representing a line of the file,\r
+                 with comments stripped.\r
+    line: Number of line being processed.\r
+    include_state: An _IncludeState instance in which the headers are inserted.\r
+    function_state: A _FunctionState instance which counts function lines, etc.\r
+    nesting_state: A NestingState instance which maintains information about\r
+                   the current stack of nested blocks being parsed.\r
+    error: A callable to which errors are reported, which takes 4 arguments:\r
+           filename, line number, error level, and message\r
+    extra_check_functions: An array of additional check functions that will be\r
+                           run on each source line. Each function takes 4\r
+                           arguments: filename, clean_lines, line, error\r
+  """\r
+  raw_lines = clean_lines.raw_lines\r
+  ParseNolintSuppressions(filename, raw_lines[line], line, error)\r
+  nesting_state.Update(filename, clean_lines, line, error)\r
+  CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,\r
+                               error)\r
+  if nesting_state.InAsmBlock(): return\r
+  CheckForFunctionLengths(filename, clean_lines, line, function_state, error)\r
+  CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)\r
+  CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)\r
+  CheckLanguage(filename, clean_lines, line, file_extension, include_state,\r
+                nesting_state, error)\r
+  CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)\r
+  CheckForNonStandardConstructs(filename, clean_lines, line,\r
+                                nesting_state, error)\r
+  CheckVlogArguments(filename, clean_lines, line, error)\r
+  CheckPosixThreading(filename, clean_lines, line, error)\r
+  CheckInvalidIncrement(filename, clean_lines, line, error)\r
+  CheckMakePairUsesDeduction(filename, clean_lines, line, error)\r
+  CheckRedundantVirtual(filename, clean_lines, line, error)\r
+  CheckRedundantOverrideOrFinal(filename, clean_lines, line, error)\r
+  for check_fn in extra_check_functions:\r
+    check_fn(filename, clean_lines, line, error)\r
+\r
+def FlagCxx11Features(filename, clean_lines, linenum, error):\r
+  """Flag those c++11 features that we only allow in certain places.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)\r
+\r
+  # Flag unapproved C++ TR1 headers.\r
+  if include and include.group(1).startswith('tr1/'):\r
+    error(filename, linenum, 'build/c++tr1', 5,\r
+          ('C++ TR1 headers such as <%s> are unapproved.') % include.group(1))\r
+\r
+  # Flag unapproved C++11 headers.\r
+  if include and include.group(1) in ('cfenv',\r
+                                      'condition_variable',\r
+                                      'fenv.h',\r
+                                      'future',\r
+                                      'mutex',\r
+                                      'thread',\r
+                                      'chrono',\r
+                                      'ratio',\r
+                                      'regex',\r
+                                      'system_error',\r
+                                     ):\r
+    error(filename, linenum, 'build/c++11', 5,\r
+          ('<%s> is an unapproved C++11 header.') % include.group(1))\r
+\r
+  # The only place where we need to worry about C++11 keywords and library\r
+  # features in preprocessor directives is in macro definitions.\r
+  if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return\r
+\r
+  # These are classes and free functions.  The classes are always\r
+  # mentioned as std::*, but we only catch the free functions if\r
+  # they're not found by ADL.  They're alphabetical by header.\r
+  for top_name in (\r
+      # type_traits\r
+      'alignment_of',\r
+      'aligned_union',\r
+      ):\r
+    if Search(r'\bstd::%s\b' % top_name, line):\r
+      error(filename, linenum, 'build/c++11', 5,\r
+            ('std::%s is an unapproved C++11 class or function.  Send c-style '\r
+             'an example of where it would make your code more readable, and '\r
+             'they may let you use it.') % top_name)\r
+\r
+\r
+def FlagCxx14Features(filename, clean_lines, linenum, error):\r
+  """Flag those C++14 features that we restrict.\r
+\r
+  Args:\r
+    filename: The name of the current file.\r
+    clean_lines: A CleansedLines instance containing the file.\r
+    linenum: The number of the line to check.\r
+    error: The function to call with any errors found.\r
+  """\r
+  line = clean_lines.elided[linenum]\r
+\r
+  include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)\r
+\r
+  # Flag unapproved C++14 headers.\r
+  if include and include.group(1) in ('scoped_allocator', 'shared_mutex'):\r
+    error(filename, linenum, 'build/c++14', 5,\r
+          ('<%s> is an unapproved C++14 header.') % include.group(1))\r
+\r
+\r
+def ProcessFileData(filename, file_extension, lines, error,\r
+                    extra_check_functions=[]):\r
+  """Performs lint checks and reports any errors to the given error function.\r
+\r
+  Args:\r
+    filename: Filename of the file that is being processed.\r
+    file_extension: The extension (dot not included) of the file.\r
+    lines: An array of strings, each representing a line of the file, with the\r
+           last element being empty if the file is terminated with a newline.\r
+    error: A callable to which errors are reported, which takes 4 arguments:\r
+           filename, line number, error level, and message\r
+    extra_check_functions: An array of additional check functions that will be\r
+                           run on each source line. Each function takes 4\r
+                           arguments: filename, clean_lines, line, error\r
+  """\r
+  lines = (['// marker so line numbers and indices both start at 1'] + lines +\r
+           ['// marker so line numbers end in a known way'])\r
+\r
+  include_state = _IncludeState()\r
+  function_state = _FunctionState()\r
+  nesting_state = NestingState()\r
+\r
+  ResetNolintSuppressions()\r
+\r
+  CheckForCopyright(filename, lines, error)\r
+  ProcessGlobalSuppresions(lines)\r
+  RemoveMultiLineComments(filename, lines, error)\r
+  clean_lines = CleansedLines(lines)\r
+\r
+  if IsHeaderExtension(file_extension):\r
+    CheckForHeaderGuard(filename, clean_lines, error)\r
+\r
+  for line in xrange(clean_lines.NumLines()):\r
+    ProcessLine(filename, file_extension, clean_lines, line,\r
+                include_state, function_state, nesting_state, error,\r
+                extra_check_functions)\r
+    FlagCxx11Features(filename, clean_lines, line, error)\r
+  nesting_state.CheckCompletedBlocks(filename, error)\r
+\r
+  CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)\r
+\r
+  # Check that the .cc file has included its header if it exists.\r
+  if _IsSourceExtension(file_extension):\r
+    CheckHeaderFileIncluded(filename, include_state, error)\r
+\r
+  # We check here rather than inside ProcessLine so that we see raw\r
+  # lines rather than "cleaned" lines.\r
+  CheckForBadCharacters(filename, lines, error)\r
+\r
+  CheckForNewlineAtEOF(filename, lines, error)\r
+\r
+def ProcessConfigOverrides(filename):\r
+  """ Loads the configuration files and processes the config overrides.\r
+\r
+  Args:\r
+    filename: The name of the file being processed by the linter.\r
+\r
+  Returns:\r
+    False if the current |filename| should not be processed further.\r
+  """\r
+\r
+  abs_filename = os.path.abspath(filename)\r
+  cfg_filters = []\r
+  keep_looking = True\r
+  while keep_looking:\r
+    abs_path, base_name = os.path.split(abs_filename)\r
+    if not base_name:\r
+      break  # Reached the root directory.\r
+\r
+    cfg_file = os.path.join(abs_path, "CPPLINT.cfg")\r
+    abs_filename = abs_path\r
+    if not os.path.isfile(cfg_file):\r
+      continue\r
+\r
+    try:\r
+      with open(cfg_file) as file_handle:\r
+        for line in file_handle:\r
+          line, _, _ = line.partition('#')  # Remove comments.\r
+          if not line.strip():\r
+            continue\r
+\r
+          name, _, val = line.partition('=')\r
+          name = name.strip()\r
+          val = val.strip()\r
+          if name == 'set noparent':\r
+            keep_looking = False\r
+          elif name == 'filter':\r
+            cfg_filters.append(val)\r
+          elif name == 'exclude_files':\r
+            # When matching exclude_files pattern, use the base_name of\r
+            # the current file name or the directory name we are processing.\r
+            # For example, if we are checking for lint errors in /foo/bar/baz.cc\r
+            # and we found the .cfg file at /foo/CPPLINT.cfg, then the config\r
+            # file's "exclude_files" filter is meant to be checked against "bar"\r
+            # and not "baz" nor "bar/baz.cc".\r
+            if base_name:\r
+              pattern = re.compile(val)\r
+              if pattern.match(base_name):\r
+                sys.stderr.write('Ignoring "%s": file excluded by "%s". '\r
+                                 'File path component "%s" matches '\r
+                                 'pattern "%s"\n' %\r
+                                 (filename, cfg_file, base_name, val))\r
+                return False\r
+          elif name == 'linelength':\r
+            global _line_length\r
+            try:\r
+                _line_length = int(val)\r
+            except ValueError:\r
+                sys.stderr.write('Line length must be numeric.')\r
+          elif name == 'root':\r
+            global _root\r
+            _root = val\r
+          elif name == 'headers':\r
+            ProcessHppHeadersOption(val)\r
+          else:\r
+            sys.stderr.write(\r
+                'Invalid configuration option (%s) in file %s\n' %\r
+                (name, cfg_file))\r
+\r
+    except IOError:\r
+      sys.stderr.write(\r
+          "Skipping config file '%s': Can't open for reading\n" % cfg_file)\r
+      keep_looking = False\r
+\r
+  # Apply all the accumulated filters in reverse order (top-level directory\r
+  # config options having the least priority).\r
+  for filter in reversed(cfg_filters):\r
+     _AddFilters(filter)\r
+\r
+  return True\r
+\r
+\r
+def ProcessFile(filename, vlevel, extra_check_functions=[]):\r
+  """Does google-lint on a single file.\r
+\r
+  Args:\r
+    filename: The name of the file to parse.\r
+\r
+    vlevel: The level of errors to report.  Every error of confidence\r
+    >= verbose_level will be reported.  0 is a good default.\r
+\r
+    extra_check_functions: An array of additional check functions that will be\r
+                           run on each source line. Each function takes 4\r
+                           arguments: filename, clean_lines, line, error\r
+  """\r
+\r
+  _SetVerboseLevel(vlevel)\r
+  _BackupFilters()\r
+\r
+  if not ProcessConfigOverrides(filename):\r
+    _RestoreFilters()\r
+    return\r
+\r
+  lf_lines = []\r
+  crlf_lines = []\r
+  try:\r
+    # Support the UNIX convention of using "-" for stdin.  Note that\r
+    # we are not opening the file with universal newline support\r
+    # (which codecs doesn't support anyway), so the resulting lines do\r
+    # contain trailing '\r' characters if we are reading a file that\r
+    # has CRLF endings.\r
+    # If after the split a trailing '\r' is present, it is removed\r
+    # below.\r
+    if filename == '-':\r
+      lines = codecs.StreamReaderWriter(sys.stdin,\r
+                                        codecs.getreader('utf8'),\r
+                                        codecs.getwriter('utf8'),\r
+                                        'replace').read().split('\n')\r
+    else:\r
+      lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')\r
+\r
+    # Remove trailing '\r'.\r
+    # The -1 accounts for the extra trailing blank line we get from split()\r
+    for linenum in range(len(lines) - 1):\r
+      if lines[linenum].endswith('\r'):\r
+        lines[linenum] = lines[linenum].rstrip('\r')\r
+        crlf_lines.append(linenum + 1)\r
+      else:\r
+        lf_lines.append(linenum + 1)\r
+\r
+  except IOError:\r
+    sys.stderr.write(\r
+        "Skipping input '%s': Can't open for reading\n" % filename)\r
+    _RestoreFilters()\r
+    return\r
+\r
+  # Note, if no dot is found, this will give the entire filename as the ext.\r
+  file_extension = filename[filename.rfind('.') + 1:]\r
+\r
+  # When reading from stdin, the extension is unknown, so no cpplint tests\r
+  # should rely on the extension.\r
+  if filename != '-' and file_extension not in _valid_extensions:\r
+    sys.stderr.write('Ignoring %s; not a valid file name '\r
+                     '(%s)\n' % (filename, ', '.join(_valid_extensions)))\r
+  else:\r
+    ProcessFileData(filename, file_extension, lines, Error,\r
+                    extra_check_functions)\r
+\r
+    # If end-of-line sequences are a mix of LF and CR-LF, issue\r
+    # warnings on the lines with CR.\r
+    #\r
+    # Don't issue any warnings if all lines are uniformly LF or CR-LF,\r
+    # since critique can handle these just fine, and the style guide\r
+    # doesn't dictate a particular end of line sequence.\r
+    #\r
+    # We can't depend on os.linesep to determine what the desired\r
+    # end-of-line sequence should be, since that will return the\r
+    # server-side end-of-line sequence.\r
+    if lf_lines and crlf_lines:\r
+      # Warn on every line with CR.  An alternative approach might be to\r
+      # check whether the file is mostly CRLF or just LF, and warn on the\r
+      # minority, we bias toward LF here since most tools prefer LF.\r
+      for linenum in crlf_lines:\r
+        Error(filename, linenum, 'whitespace/newline', 1,\r
+              'Unexpected \\r (^M) found; better to use only \\n')\r
+\r
+  sys.stdout.write('Done processing %s\n' % filename)\r
+  _RestoreFilters()\r
+\r
+\r
+def PrintUsage(message):\r
+  """Prints a brief usage string and exits, optionally with an error message.\r
+\r
+  Args:\r
+    message: The optional error message.\r
+  """\r
+  sys.stderr.write(_USAGE)\r
+  if message:\r
+    sys.exit('\nFATAL ERROR: ' + message)\r
+  else:\r
+    sys.exit(1)\r
+\r
+\r
+def PrintCategories():\r
+  """Prints a list of all the error-categories used by error messages.\r
+\r
+  These are the categories used to filter messages via --filter.\r
+  """\r
+  sys.stderr.write(''.join('  %s\n' % cat for cat in _ERROR_CATEGORIES))\r
+  sys.exit(0)\r
+\r
+\r
+def ParseArguments(args):\r
+  """Parses the command line arguments.\r
+\r
+  This may set the output format and verbosity level as side-effects.\r
+\r
+  Args:\r
+    args: The command line arguments:\r
+\r
+  Returns:\r
+    The list of filenames to lint.\r
+  """\r
+  try:\r
+    (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',\r
+                                                 'counting=',\r
+                                                 'filter=',\r
+                                                 'root=',\r
+                                                 'linelength=',\r
+                                                 'extensions=',\r
+                                                 'headers='])\r
+  except getopt.GetoptError:\r
+    PrintUsage('Invalid arguments.')\r
+\r
+  verbosity = _VerboseLevel()\r
+  output_format = _OutputFormat()\r
+  filters = ''\r
+  counting_style = ''\r
+\r
+  for (opt, val) in opts:\r
+    if opt == '--help':\r
+      PrintUsage(None)\r
+    elif opt == '--output':\r
+      if val not in ('emacs', 'vs7', 'eclipse'):\r
+        PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')\r
+      output_format = val\r
+    elif opt == '--verbose':\r
+      verbosity = int(val)\r
+    elif opt == '--filter':\r
+      filters = val\r
+      if not filters:\r
+        PrintCategories()\r
+    elif opt == '--counting':\r
+      if val not in ('total', 'toplevel', 'detailed'):\r
+        PrintUsage('Valid counting options are total, toplevel, and detailed')\r
+      counting_style = val\r
+    elif opt == '--root':\r
+      global _root\r
+      _root = val\r
+    elif opt == '--linelength':\r
+      global _line_length\r
+      try:\r
+          _line_length = int(val)\r
+      except ValueError:\r
+          PrintUsage('Line length must be digits.')\r
+    elif opt == '--extensions':\r
+      global _valid_extensions\r
+      try:\r
+          _valid_extensions = set(val.split(','))\r
+      except ValueError:\r
+          PrintUsage('Extensions must be comma seperated list.')\r
+    elif opt == '--headers':\r
+      ProcessHppHeadersOption(val)\r
+\r
+  if not filenames:\r
+    PrintUsage('No files were specified.')\r
+\r
+  _SetOutputFormat(output_format)\r
+  _SetVerboseLevel(verbosity)\r
+  _SetFilters(filters)\r
+  _SetCountingStyle(counting_style)\r
+\r
+  return filenames\r
+\r
+\r
+def main():\r
+  filenames = ParseArguments(sys.argv[1:])\r
+\r
+  # Change stderr to write with replacement characters so we don't die\r
+  # if we try to print something containing non-ASCII characters.\r
+  sys.stderr = codecs.StreamReaderWriter(sys.stderr,\r
+                                         codecs.getreader('utf8'),\r
+                                         codecs.getwriter('utf8'),\r
+                                         'replace')\r
+\r
+  _cpplint_state.ResetErrorCounts()\r
+  for filename in filenames:\r
+    ProcessFile(filename, _cpplint_state.verbose_level)\r
+  _cpplint_state.PrintErrorCounts()\r
+\r
+  sys.exit(_cpplint_state.error_count > 0)\r
+\r
+\r
+if __name__ == '__main__':\r
+  main()\r
diff --git a/ut/include/appwindow.h b/ut/include/appwindow.h
new file mode 100755 (executable)
index 0000000..d9c25f9
--- /dev/null
@@ -0,0 +1,95 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_UT_INCLUDE_APPWINDOW_H__
+#define __PLUSPLAYER_UT_INCLUDE_APPWINDOW_H__
+
+#define ECORE_WAYLAND_DISPLAY_TEST 1
+
+#include <chrono>
+#include <thread>
+
+#include "Ecore.h"
+#include "Elementary.h"
+#if ECORE_WAYLAND_DISPLAY_TEST
+#include "Ecore_Wl2.h"
+#endif
+
+namespace plusplayer_ut {
+
+class AppWindow {
+ public:
+  struct Window {
+    Evas_Object* obj = nullptr;
+    int x = 0, y = 0;
+    int w = 0, h = 0;  // width , height
+  };
+
+  AppWindow(int x, int y, int width, int height) : thread_init_done_(false) {
+    window_.x = x, window_.y = y, window_.w = width, window_.h = height;
+    thread_ = std::thread(AppWindow::WindowThread, this);
+    while (!thread_init_done_) {
+      std::this_thread::sleep_for(std::chrono::milliseconds(1));
+    }
+  }
+
+  ~AppWindow() {
+    ecore_thread_main_loop_begin();
+    elm_exit();
+    ecore_thread_main_loop_end();
+    thread_.join();
+  }
+
+  static void WindowThread(AppWindow* appwindow) {
+    elm_init(1, NULL);
+    appwindow->CreateWindow_();
+    appwindow->thread_init_done_ = true;
+    elm_run();
+    elm_shutdown();
+  }
+
+  Window GetWindow() { return window_; }
+
+#if ECORE_WAYLAND_DISPLAY_TEST
+  Ecore_Wl2_Window* GetEcoreWL2Window() {
+    return ecore_wl2_window_;
+  }
+#endif
+
+ private:
+  void CreateWindow_() {
+    ecore_thread_main_loop_begin();
+
+    window_.obj = elm_win_add(NULL, "player", ELM_WIN_BASIC);
+
+    assert(window_.obj && "window is NULL.");
+
+    elm_win_title_set(window_.obj, "Plusplayer");
+
+    elm_win_autodel_set(window_.obj, EINA_TRUE);
+    elm_win_aux_hint_add(window_.obj, "wm.policy.win.user.geometry", "1");
+    evas_object_move(window_.obj, window_.x, window_.y);
+    evas_object_resize(window_.obj, window_.w, window_.h);
+    evas_object_show(window_.obj);
+
+#if ECORE_WAYLAND_DISPLAY_TEST
+    Ecore_Evas *ee =
+             ecore_evas_ecore_evas_get(evas_object_evas_get(window_.obj));
+    ecore_wl2_window_ = ecore_evas_wayland2_window_get(ee);
+#endif
+    ecore_thread_main_loop_end();
+  }
+
+ private:
+  bool thread_init_done_;
+  Window window_;
+#if ECORE_WAYLAND_DISPLAY_TEST
+  Ecore_Wl2_Window* ecore_wl2_window_;
+#endif
+  std::thread thread_;
+};
+
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_UT_INCLUDE_APPWINDOW_H__
diff --git a/ut/include/esplusplayer/eseventlistener.hpp b/ut/include/esplusplayer/eseventlistener.hpp
new file mode 100755 (executable)
index 0000000..5feeb89
--- /dev/null
@@ -0,0 +1,176 @@
+//\r
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_EVENT_LISTENER_H__\r
+#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_EVENT_LISTENER_H__\r
+\r
+#include <string>\r
+#include <thread>\r
+#include <chrono>\r
+\r
+#include "ut/include/esplusplayer/esreader.hpp"\r
+#include "esplusplayer_capi/esplusplayer_capi.h"\r
+\r
+class EsPlayerEventCallback {
+ public:
+  EsPlayerEventCallback(esplusplayer_handle handle,\r
+                        EsStreamReader* video_reader,\r
+                        EsStreamReader* audio_reader)\r
+                        : handle_(handle), video_reader_(video_reader),\r
+                          audio_reader_(audio_reader) {}\r
+  ~EsPlayerEventCallback() {\r
+    if (audio_feeding_task_.joinable())\r
+      audio_feeding_task_.join();\r
+    if (video_feeding_task_.joinable())\r
+      video_feeding_task_.join();\r
+  }\r
+  void SetCallback(void) {
+    esplusplayer_set_error_cb(handle_, OnError, this);
+    esplusplayer_set_buffer_status_cb(handle_, OnBufferStatus, this);
+    esplusplayer_set_resource_conflicted_cb(handle_, OnResourceConflicted,
+                                            this);
+    esplusplayer_set_eos_cb(handle_, OnEos, this);
+    esplusplayer_set_ready_to_prepare_cb(handle_, OnReadyToPrepare, this);
+    esplusplayer_set_prepare_async_done_cb(handle_, OnPrepareDone, this);
+  }
+\r
+  static void DataFeedingTask(EsStreamReader* stream, esplusplayer_handle esplayer) {\r
+    esplusplayer_es_packet pkt;\r
+    while (true) {\r
+      if (!stream->ReadNextPacket(pkt)) break;\r
+      esplusplayer_submit_packet(esplayer, &pkt);\r
+      delete pkt.buffer;\r
+    }\r
+  }\r
+  static void OnError(const esplusplayer_error_type err_code, void* userdata) {
+    std::cout << "OnError" << std::endl;
+  }
+  static void OnResourceConflicted(void* userdata) {
+    std::cout << "OnResourceConflicted" << std::endl;
+  }
+  static void OnSeekDone(void* userdata) {
+    std::cout << "OnSeekDone" << std::endl;
+  }
+  static void OnEos(void* userdata) {
+    EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
+    std::unique_lock<std::mutex> lk(cb->eos_m_);
+    std::cout << "OnEos" << std::endl;
+    cb->eos_ = true;
+    lk.unlock();
+    cb->eos_cv_.notify_all();
+  }
+  static void OnPrepareDone(bool ret, void* userdata) {
+    EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
+    std::unique_lock<std::mutex> lk(cb->prepare_done_m_);
+    std::cout << "OnPrepareDone" << std::endl;
+    cb->prepare_done_ = true;
+    lk.unlock();
+    cb->prepare_done_cv_.notify_all();
+  }
+  static void OnBufferStatus(const esplusplayer_stream_type type,
+                             const esplusplayer_buffer_status status,
+                             void* userdata) {
+    auto buffer_status =
+        status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN ? "underrun" : "overrun";
+    std::cout << "OnBufferStatus " << buffer_status << std::endl;
+  }
+  static void OnReadyToPrepare(const esplusplayer_stream_type type,
+                               void* userdata) {
+    EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
+    std::cout << "OnReadyToPrepare" << std::endl;
+    std::unique_lock<std::mutex> lk(cb->data_m_);
+    if (type == ESPLUSPLAYER_STREAM_TYPE_AUDIO) {
+      cb->ready_audio_data_ = true;\r
+      if (cb->audio_reader_ != nullptr) {\r
+        cb->audio_feeding_task_ = std::thread(DataFeedingTask,\r
+                                              std::ref(cb->audio_reader_),\r
+                                              std::ref(cb->handle_));\r
+      }\r
+      std::cout << "Audio ready to prepare" << std::endl;
+    } else if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {
+      cb->ready_video_data_ = true;\r
+      if (cb->video_reader_ != nullptr) {\r
+        cb->video_feeding_task_ = std::thread(DataFeedingTask,\r
+                                              std::ref(cb->video_reader_),\r
+                                              std::ref(cb->handle_));\r
+      }\r
+      std::cout << "Video ready to prepare" << std::endl;
+    }
+    lk.unlock();
+    cb->data_cv_.notify_all();
+  }
+  static void OnReadyToSeek(const esplusplayer_stream_type type,
+                            const uint64_t offset, void* userdata) {
+    EsPlayerEventCallback* cb = static_cast<EsPlayerEventCallback*>(userdata);
+    std::cout << "OnReadyToSeek" << std::endl;
+    std::unique_lock<std::mutex> lk(cb->data_m_);
+    if (type == ESPLUSPLAYER_STREAM_TYPE_AUDIO)
+      cb->ready_audio_data_ = true;
+    else if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO)
+      cb->ready_video_data_ = true;
+    lk.unlock();
+    cb->data_cv_.notify_all();
+  }
+  void WaitAllStreamData() {
+    std::unique_lock<std::mutex> lk(data_m_);
+    std::cout << "WaitAllStreamData start" << std::endl;
+    data_cv_.wait_for(lk, std::chrono::seconds(1), [this]() -> bool {
+      return ready_audio_data_ && ready_video_data_;
+    });\r
+    std::cout << "WaitAllStreamData stop" << std::endl;
+    lk.unlock();
+  }
+  void WaitAudioStreamData() {
+    std::unique_lock<std::mutex> lk(data_m_);
+    std::cout << "WaitAudioStreamData start" << std::endl;
+    data_cv_.wait_for(lk, std::chrono::seconds(1),
+                      [this]() -> bool { return ready_audio_data_; });
+    std::cout << "WaitAudioStreamData stop" << std::endl;
+    lk.unlock();
+  }
+  void WaitVideoStreamData() {
+    std::unique_lock<std::mutex> lk(data_m_);
+    std::cout << "WaitVideoStreamData start" << std::endl;
+    data_cv_.wait_for(lk, std::chrono::seconds(1),
+                      [this]() -> bool { return ready_audio_data_; });
+    std::cout << "WaitVideoStreamData stop" << std::endl;
+    lk.unlock();
+  }
+  void WaitForEos() {
+    std::cout << "WaitForEos start" << std::endl;
+    std::unique_lock<std::mutex> lk(eos_m_);
+    eos_cv_.wait_for(lk, std::chrono::minutes(1),
+                     [this]() -> bool { return eos_; });\r
+    std::cout << "WaitForEos stop" << std::endl;
+    lk.unlock();
+  }
+  void WaitForPrepareDone() {
+    std::cout << "WaitForPrepareDone start" << std::endl;
+    std::unique_lock<std::mutex> lk(prepare_done_m_);
+    prepare_done_cv_.wait_for(lk, std::chrono::seconds(10),\r
+                              [this]() -> bool { return prepare_done_; });\r
+    std::cout << "WaitForPrepareDone stop" << std::endl;
+    lk.unlock();
+  }
+
+ private:
+  esplusplayer_handle handle_ = nullptr;\r
+  EsStreamReader* video_reader_ = nullptr;\r
+  EsStreamReader* audio_reader_ = nullptr;\r
+  std::thread video_feeding_task_;\r
+  std::thread audio_feeding_task_;\r
+\r
+  bool eos_ = false;
+  std::mutex eos_m_;
+  std::condition_variable eos_cv_;
+  bool ready_audio_data_ = false;
+  bool ready_video_data_ = false;
+  std::mutex data_m_;
+  std::condition_variable data_cv_;
+  bool prepare_done_ = false;
+  std::mutex prepare_done_m_;
+  std::condition_variable prepare_done_cv_;
+};\r
+\r
+#endif  // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_EVENT_LISTENER_H__
\ No newline at end of file
diff --git a/ut/include/esplusplayer/esreader.hpp b/ut/include/esplusplayer/esreader.hpp
new file mode 100755 (executable)
index 0000000..3ca0c2b
--- /dev/null
@@ -0,0 +1,159 @@
+//\r
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_READER_H__\r
+#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_READER_H__\r
+\r
+\r
+#include <string>\r
+#include <fstream>\r
+\r
+#include "esplusplayer_capi/esplusplayer_capi.h"\r
+\r
+static const std::string tc_root_dir = "/tmp/esdata/";\r
+\r
+class EsStreamReader {\r
+ public:\r
+  explicit EsStreamReader(const std::string dirpath,\r
+                          esplusplayer_stream_type type) {\r
+    dir_path_ = tc_root_dir + dirpath;\r
+    es_data_file_ = dir_path_ + "ESP.es";\r
+    es_info_file_ = dir_path_ + "ESP.info";\r
+    extra_codec_file_ = dir_path_ + "ESP.codec_extradata";\r
+    type_ = type;\r
+    std::cout << "ES data file " << es_data_file_ << std::endl;\r
+  }\r
+  ~EsStreamReader() {\r
+    if (stream_.is_open()) {\r
+      stream_.close();\r
+    }\r
+  }\r
+\r
+  bool SetStreamInfo(esplusplayer_handle& esplayer) {\r
+    if (type_ == ESPLUSPLAYER_STREAM_TYPE_AUDIO) {\r
+      esplusplayer_audio_stream_info audio_stream;\r
+      audio_stream.codec_data = nullptr;\r
+      audio_stream.codec_data_length = 0;\r
+      GetExtraData_(audio_stream.codec_data, audio_stream.codec_data_length);\r
+      if (!GetMediaInfo_(audio_stream)) {\r
+        if (audio_stream.codec_data != nullptr)\r
+          delete audio_stream.codec_data;\r
+        return false;\r
+      }\r
+\r
+      esplusplayer_set_audio_stream_info(esplayer, &audio_stream);\r
+      if (audio_stream.codec_data != nullptr)\r
+        delete audio_stream.codec_data;\r
+    } else if (type_ == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {\r
+      esplusplayer_video_stream_info video_stream;\r
+      video_stream.codec_data = nullptr;\r
+      video_stream.codec_data_length = 0;\r
+      GetExtraData_(video_stream.codec_data, video_stream.codec_data_length);\r
+      if (!GetMediaInfo_(video_stream)) {\r
+        if (video_stream.codec_data != nullptr)\r
+          delete video_stream.codec_data;\r
+        return false;\r
+      }\r
+      esplusplayer_set_video_stream_info(esplayer, &video_stream);\r
+      if (video_stream.codec_data != nullptr)\r
+        delete video_stream.codec_data;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  bool ReadNextPacket(esplusplayer_es_packet& pkt) {\r
+    if (!stream_.is_open()) {\r
+      stream_ = std::ifstream(es_data_file_, std::ifstream::binary);\r
+      if (!stream_.is_open()) return false;\r
+    }\r
+    if (stream_.eof() || GetFileLeftSize_() < 24) {\r
+      std::cout << type_ << " stream EOF" << std::endl;\r
+      return false;\r
+    }\r
+    pkt.type = type_;\r
+    std::uint64_t size;\r
+    stream_.read(reinterpret_cast<char*>(&pkt.pts), sizeof(pkt.pts));\r
+    pkt.pts = pkt.pts / 1000000; //ns -> ms\r
+    stream_.read(reinterpret_cast<char*>(&pkt.duration), sizeof(pkt.duration));\r
+    pkt.duration = pkt.duration / 1000000; //ns -> ms\r
+    stream_.read(reinterpret_cast<char*>(&size), sizeof(size));\r
+    pkt.buffer_size = static_cast<uint32_t>(size);\r
+    if (pkt.buffer_size == 0) return false;\r
+    pkt.buffer = new char[pkt.buffer_size];\r
+    stream_.read(reinterpret_cast<char*>(pkt.buffer), pkt.buffer_size);\r
+    pkt.matroska_color_info = nullptr;\r
+    // std::cout << "Read audio/video buffer: " << type_ << std::endl;\r
+    // std::cout << "Type: " << type_ << "Pts: " << pkt.pts << "duration: " <<\r
+    // pkt.duration << "size: " << size << std::endl;\r
+    return true;\r
+  }\r
+\r
+  void ResetReader() {\r
+    stream_.seekg(0,std::ios::beg);\r
+  }\r
+\r
+private:\r
+  int GetFileLeftSize_(void) {\r
+    if (!stream_.is_open()) return 0;\r
+    int cur = stream_.tellg();\r
+    stream_.seekg(0, stream_.end);\r
+    int total = stream_.tellg();\r
+    stream_.seekg(cur);\r
+    return total - cur;\r
+  }\r
+  bool GetExtraData_(char*& data, unsigned int& size) {\r
+    auto stream = std::ifstream(extra_codec_file_, std::ifstream::binary);\r
+    if (!stream.is_open()) return false;\r
+    stream.read(reinterpret_cast<char*>(&size), sizeof(size));\r
+    if (size == 0) return false;\r
+    data = new char[size];\r
+    stream.read(data, size);\r
+    stream.close();\r
+    return true;\r
+  }\r
+\r
+  bool GetMediaInfo_(esplusplayer_video_stream_info& info) {\r
+    auto stream = std::ifstream(es_info_file_, std::ifstream::in);\r
+    if (!stream.is_open()) {\r
+      std::cout << "No video es file: " << es_info_file_ << std::endl;\r
+      return false;\r
+    }\r
+\r
+    uint32_t mime_type;\r
+    stream >> mime_type >> info.width >> info.height >> info.max_width >> info.max_height >>\r
+         info.framerate_num >> info.framerate_den;\r
+    info.mime_type = static_cast<esplusplayer_video_mime_type>(mime_type);\r
+    std::cout << "mime_type: " << info.mime_type << std::endl;\r
+    std::cout << "info.width: " << info.width << std::endl;\r
+    stream.close();\r
+    return true;\r
+  }\r
+\r
+  bool GetMediaInfo_(esplusplayer_audio_stream_info& info) {\r
+    auto stream = std::ifstream(es_info_file_, std::ifstream::in);\r
+    if (!stream.is_open()) {\r
+      std::cout << "No audio es file: " << es_info_file_ << std::endl;\r
+      return false;\r
+    }\r
+    uint32_t mime_type;\r
+    stream >> mime_type >> info.sample_rate >> info.channels;\r
+    info.mime_type = static_cast<esplusplayer_audio_mime_type>(mime_type);\r
+    std::cout << "mime_type: " << info.mime_type << std::endl;\r
+    std::cout << "info.sample_rate: " << info.sample_rate << std::endl;\r
+    stream.close();\r
+    return true;\r
+  }\r
+\r
+\r
+\r
+ private:\r
+  std::string dir_path_;\r
+  std::string es_data_file_;\r
+  std::string es_info_file_;\r
+  std::string extra_codec_file_;\r
+  std::ifstream stream_;\r
+  esplusplayer_stream_type type_;\r
+};\r
+\r
+#endif  // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ES_READER_H__
\ No newline at end of file
diff --git a/ut/include/plusplayer/tclist.h b/ut/include/plusplayer/tclist.h
new file mode 100755 (executable)
index 0000000..2cbf83b
--- /dev/null
@@ -0,0 +1,211 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_TCLIST_H__
+#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_TCLIST_H__
+
+#include <map>
+#include <string>
+#include <tuple>
+#include <vector>
+#include <assert.h>
+namespace tc
+{
+    enum class tc_type {
+        kDefault,
+        kCosmos,
+    };
+
+    enum class stream_state_type {
+        kNormal,
+        k4k,
+        k8k,
+        kVideoOnly,
+        kAudioOnly,
+        kNotSupportStream,
+        k360,
+        kNonSeekable,
+        kDualmono,
+        kNoIFrameListInHls,
+        // add more state
+        kSize,
+    };
+
+    enum class contents_type {
+        kDash,
+        kHls,
+        kHttp,
+        kSize
+    };
+
+    enum class container_type {
+        kMp4,
+        kMp3,
+        kOgg,
+        kAvi,
+        kWebM,
+        kAsf,
+        kWmv,
+        kWma,
+        kMkv,
+        kMka,
+        kMk3d,
+        kMkms,
+        kTs,
+        kDivx,
+        kEs,
+        kMov,
+        // more container
+        kSize
+    };
+
+    enum class drm_type {
+        kClean,
+        kPlayready,
+        kVerimatrix,
+        kWidevineModular,
+        // more drm type
+        kSize
+    };
+
+    enum class video_codec_type {
+        kNone,
+        kH261,
+        kH262,
+        kH263,
+        kH264,  // avc
+        kH265,
+        kHevc,
+        kVc1,
+        kVp9,
+        kMp4_Visual,
+        kMpeg1,
+        kMpeg2,
+        // more codec type
+        kSize
+    };
+
+    enum class audio_codec_type {
+        kNone,
+        kMp3,
+        kAc3,
+        kAac,
+        kE_ac3,
+        kWma,
+        // more codec type
+        kSize
+    };
+
+    enum class audio_track_type {
+        kSingle,
+        kMulti,
+        kSize
+    };
+
+    using url = std::string;
+    using contents_tag = std::tuple<stream_state_type, contents_type, container_type, drm_type, video_codec_type, audio_codec_type, audio_track_type, unsigned int>;
+    using tc_map = std::map<url, contents_tag>;
+    using tc_list = std::vector<url>;
+
+    class TCList {
+    public:
+        static TCList& Instance();
+        static void InitializeTC(tc_type type);
+
+        static void Kill();
+
+        tc_map GetTCMap() const;
+        tc_list GetTCURIList() const;
+        
+        // return uri tag from args
+        static inline contents_tag MakeContentsTag(stream_state_type t0, contents_type t1, container_type t2, drm_type t3, video_codec_type t4, audio_codec_type t5, audio_track_type t6) {
+            return std::make_tuple(t0, t1, t2, t3, t4, t5, t6, 0);
+        }
+        
+        static inline contents_tag MakeUniqueContentsTag(stream_state_type t0, contents_type t1, container_type t2, drm_type t3, video_codec_type t4, audio_codec_type t5, audio_track_type t6, unsigned int unique_id) {
+            assert(unique_id != 0); // because 0 is default id for MakeContentTag()
+            return std::make_tuple(t0, t1, t2, t3, t4, t5, t6, unique_id);
+        }
+        
+        static inline stream_state_type GetStreamStateType(contents_tag tag) { return std::get<0>(tag); }
+        static inline contents_type GetContentsType(contents_tag tag) { return std::get<1>(tag); }
+        static inline container_type GetContainerType(contents_tag tag) { return std::get<2>(tag); }
+        static inline drm_type GetDrmType(contents_tag tag) { return std::get<3>(tag); }
+        static inline video_codec_type GetVideoCodecType(contents_tag tag) { return std::get<4>(tag); }
+        static inline audio_codec_type GetAudioCodecType(contents_tag tag) { return std::get<5>(tag); }
+        static inline audio_track_type GetAudioTrackType(contents_tag tag) { return std::get<6>(tag); }
+
+        virtual ~TCList();
+    private:
+        TCList(tc_type type);
+
+#ifdef VD_UNIT_TEST
+        void MountCIFS();
+        void UnmountCIFS();
+#endif
+
+    private:
+        tc_type type_;
+        tc_map map_;
+        tc_list list_;
+    };
+
+    namespace hls_tc {
+        static const url hls_normal_clean_1 = "";
+        static const url hls_normal_clean_2 = "";
+        static const url hls_normal_clean_3 = "";
+
+        static const url hls_normal_clean_multiaudio_subtitle_1 = "";
+        static const url hls_normal_clean_discontinuity_1 = "";
+    }
+    
+    namespace hls_abnormal_tc {
+        
+    }
+
+    namespace dash_tc {
+        static const url dash_normal_clean_1 = "";
+        static const url dash_normal_clean_2 = "";
+        static const url dash_normal_clean_3 = "";
+
+        static const url dash_normal_clean_uhd_1 = "";
+        static const url dash_normal_clean_uhd_2 = "";
+        
+    }
+
+    namespace http_tc {
+        static const url avc_aac_mp4 = "";
+        static const url avc_mp3_mp4 = "";         
+        static const url hevc_aac_4k_mp4 = "";
+        static const url avc_aac_4k_mp4 = "";
+        static const url hevc_aac_4k_ts = "";
+
+        static const url aac_audioonly_es = "";
+        static const url avc_videoonly_es = "";
+
+        static const url avc_aac_360_mp4 = "";
+        static const url hevc_aac_360_mp4 = "";
+        static const url avc_aac_360_4k_mp4 = "";
+
+        static const url mp3_mp3 = "";
+
+        static const url mpeg2video_ac3_ac3_tp = "";
+    }
+
+    namespace track_tc {
+        static const url http_1video_2audio = http_tc::mpeg2video_ac3_ac3_tp;
+        static const url hls_1video_2audio_4text = "";
+        static const url hls_1video_2audio_3text = hls_tc::hls_normal_clean_multiaudio_subtitle_1;
+        static const url hls_1video_1audio_0text = hls_tc::hls_normal_clean_3;
+        static const url dash_2video_1audio_0text = "";
+        static const url dash_2video_2audio_0text = "";
+        static const url dash_1video_1audio_0text = dash_tc::dash_normal_clean_3;
+        static const url dash_1video_0audio_0text = "";
+        static const url dash_1video_1audio_2text_ttml = "";
+        static const url dash_1video_1audio_2text_xml = "";
+    }
+}
+
+#endif  // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_TCLIST_H__
\ No newline at end of file
diff --git a/ut/include/plusplayer/utility.h b/ut/include/plusplayer/utility.h
new file mode 100755 (executable)
index 0000000..2467d9c
--- /dev/null
@@ -0,0 +1,48 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
+#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
+
+#include <Ecore_Evas.h>
+
+#include "core/utils/plusplayer_log.h"
+#include "plusplayer/plusplayer.h"
+#include "ut/include/appwindow.h"
+
+namespace utils {
+class Utility;
+using evas_h = Evas_Object*;
+
+class Utility {
+ public:
+  static Utility& Instance();
+  static void ThreadSleep(long ms);
+  static void Kill();
+  virtual ~Utility();
+
+  const char* GetCurrentTestName(void);
+
+  plusplayer::PlusPlayer::Ptr GetCreatedPlusPlayer(std::string& uri);
+
+  plusplayer::PlusPlayer::Ptr GetPreparedPlusPlayer(std::string& uri);
+
+  void DestroyPlayer(plusplayer::PlusPlayer::Ptr& player);
+
+  bool IsPaused(plusplayer::PlusPlayer::Ptr& player, int monitoring_time_msec);
+
+  evas_h GetWindow() const;
+
+  Utility(const Utility& rhs) = delete;
+  Utility& operator=(const Utility& rhs) = delete;
+
+ private:
+  explicit Utility();
+
+ private:
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow_;
+};
+
+}  // namespace utils
+
+#endif  // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
\ No newline at end of file
diff --git a/ut/include/streamreader.hpp b/ut/include/streamreader.hpp
new file mode 100755 (executable)
index 0000000..3a89ba0
--- /dev/null
@@ -0,0 +1,235 @@
+//\r
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ESCOMMON_H__\r
+#define __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ESCOMMON_H__\r
+\r
+#include <chrono>\r
+#include <cstdlib>\r
+#include <fstream>\r
+#include <memory>\r
+#include <string>\r
+#include <thread>\r
+#include <vector>\r
+\r
+#include "gtest/gtest.h"\r
+\r
+#include "plusplayer/espacket.h"\r
+#include "trackrenderer/core/decoderinputbuffer.h"\r
+#include "ut/include/appwindow.h"\r
+\r
+namespace pp = plusplayer;\r
+\r
+namespace utils {\r
+inline bool Exists(const std::string &path) {\r
+  std::ifstream ifile(path);\r
+  return static_cast<bool>(ifile);\r
+}\r
+}  // namespace utils\r
+\r
+namespace {\r
+class Environment {\r
+ public:\r
+  Environment() {\r
+    appwindow_.reset(new plusplayer_ut::AppWindow(0, 0, 1920, 1080));\r
+  }\r
+  void *Window() { return appwindow_->GetWindow().obj; }\r
+  void *EcoreWindow() { return appwindow_->GetEcoreWL2Window(); }\r
+\r
+ private:\r
+  std::shared_ptr<plusplayer_ut::AppWindow> appwindow_;\r
+};\r
+\r
+class ESPacketDownloader {\r
+ public:\r
+  static void Init() {\r
+    if (utils::Exists("/tmp/esdata")) {\r
+      return;\r
+    }\r
+    std::cout << "Download ESData via http - path : /tmp/esdata" << std::endl;\r
+    int ret = std::system(\r
+        "/usr/bin/wget "\r
+        "--recursive --directory-prefix=/tmp/esdata --force-directories "\r
+        "--no-host-directories --cut-dirs=2 --no-parent --reject=index.html "\r
+        "");\r
+    assert(ret == 0 && "wget is failed, please retry");\r
+  }\r
+};\r
+}  // namespace\r
+\r
+namespace es {\r
+inline std::uint64_t ConvertNsToMs(std::uint64_t ms) {\r
+  constexpr std::uint64_t ns_unit = 1000000;\r
+  return ms / ns_unit;\r
+}\r
+struct Packet {\r
+  std::uint64_t pts;\r
+  std::uint64_t duration;\r
+  std::uint64_t size;\r
+  std::shared_ptr<char> data;\r
+\r
+  pp::trackrenderer::DecoderInputBufferPtr MakeDecoderInputBuffer(\r
+      pp::trackrenderer::TrackType type) {\r
+    GstMapInfo map;\r
+    auto gstbuffer = gst_buffer_new_and_alloc(size);\r
+    gst_buffer_map(gstbuffer, &map, GST_MAP_WRITE);\r
+    memcpy(map.data, data.get(), size);\r
+    gst_buffer_unmap(gstbuffer, &map);\r
+    GST_BUFFER_PTS(gstbuffer) = pts;\r
+    GST_BUFFER_DURATION(gstbuffer) = duration;\r
+    auto buffer =\r
+        pp::trackrenderer::DecoderInputBuffer::Create(type, 0, gstbuffer);\r
+    gst_buffer_unref(gstbuffer);\r
+    return std::move(buffer);\r
+  }\r
+\r
+  static pp::trackrenderer::DecoderInputBufferPtr MakeEosBuffer(\r
+      pp::trackrenderer::TrackType type) {\r
+    return std::move(pp::trackrenderer::DecoderInputBuffer::Create(type));\r
+  }\r
+\r
+  pp::EsPacketPtr MakeEsPacket(pp::StreamType type) {\r
+    return std::move(\r
+        pp::EsPacket::Create(type, data, static_cast<std::uint32_t>(size),\r
+                             //        pts/1000000,duration/1000000));\r
+                             ConvertNsToMs(pts), ConvertNsToMs(duration)));\r
+  }\r
+\r
+  static pp::EsPacketPtr MakeEosPacket(pp::StreamType type) {\r
+    return std::move(pp::EsPacket::CreateEos(type));\r
+  }\r
+};\r
+\r
+struct CodecExtraData {\r
+  std::uint32_t size;\r
+  std::shared_ptr<char> data;\r
+};\r
+using PacketPtr = std::shared_ptr<Packet>;\r
+using CodecExtraDataPtr = std::shared_ptr<CodecExtraData>;\r
+\r
+template <typename TRACK, typename TRACKTYPE>\r
+struct VideoInfo {\r
+  std::string mimetype;\r
+  int width, height;\r
+  int maxwidth, maxheight;\r
+  int framerate_num, framerate_den;\r
+\r
+  void ExtractMediaInfoFrom(std::ifstream &stream) {\r
+    stream >> mimetype >> width >> height >> maxwidth >> maxheight >>\r
+        framerate_num >> framerate_den;\r
+  }\r
+\r
+  TRACK GetTrack() {\r
+    TRACK t;\r
+    t.active = true;\r
+    t.index = 0;\r
+    t.type = TRACKTYPE::kTrackTypeVideo;\r
+    t.mimetype = mimetype;\r
+    t.width = width;\r
+    t.height = height;\r
+    t.maxwidth = maxwidth;\r
+    t.maxheight = maxheight;\r
+    t.framerate_num = framerate_num;\r
+    t.framerate_den = framerate_den;\r
+    return t;\r
+  }\r
+};\r
+\r
+template <typename TRACK, typename TRACKTYPE>\r
+struct AudioInfo {\r
+  std::string mimetype;\r
+  int samplerate;\r
+  int channels;\r
+  int version;\r
+\r
+  void ExtractMediaInfoFrom(std::ifstream &stream) {\r
+    stream >> mimetype >> samplerate >> channels >> version;\r
+  }\r
+  TRACK GetTrack() {\r
+    TRACK t;\r
+    t.active = true;\r
+    t.index = 0;\r
+    t.type = TRACKTYPE::kTrackTypeAudio;\r
+    t.mimetype = mimetype;\r
+    t.sample_rate = samplerate;\r
+    t.channels = channels;\r
+    t.version = version;\r
+    return t;\r
+  }\r
+};\r
+\r
+template <typename TRACKTYPE>\r
+class StreamReader {\r
+ public:\r
+  using Ptr = std::shared_ptr<StreamReader<TRACKTYPE>>;\r
+  friend Ptr;\r
+  static Ptr Create(const std::string &dirpath, const TRACKTYPE &type) {\r
+    return Ptr(new StreamReader(dirpath, type));\r
+  }\r
+  virtual ~StreamReader() {\r
+    if (stream_.is_open()) {\r
+      stream_.close();\r
+    }\r
+  }\r
+\r
+ private:\r
+  explicit StreamReader(const std::string dirpath, const TRACKTYPE &type)\r
+      : type_(type) {\r
+    dirpath_ = "/tmp/esdata/" + dirpath;\r
+    if (utils::Exists(dirpath_) == false) {\r
+      throw std::runtime_error(dirpath_ + "doesn't exist");\r
+    }\r
+    stream_ = std::ifstream(dirpath_ + "/ESP.es", std::ifstream::binary);\r
+  }\r
+\r
+ public:\r
+  CodecExtraDataPtr GetExtraData() {\r
+    std::string path = dirpath_ + "/ESP.codec_extradata";\r
+    auto stream = std::ifstream(path, std::ifstream::binary);\r
+    auto extradata = CodecExtraDataPtr(new CodecExtraData);\r
+    stream.read(reinterpret_cast<char *>(&extradata->size),\r
+                sizeof extradata->size);\r
+    using DataPtr = std::shared_ptr<char>;\r
+    extradata->data = DataPtr(new char[extradata->size]);\r
+    stream.read(reinterpret_cast<char *>(extradata->data.get()),\r
+                extradata->size);\r
+    stream.close();\r
+    return extradata;\r
+  }\r
+\r
+  PacketPtr ReadNextPacket() {\r
+    if (stream_.eof()) {\r
+      return nullptr;\r
+    }\r
+    auto pkt = PacketPtr(new Packet);\r
+    stream_.read(reinterpret_cast<char *>(&pkt->pts), sizeof pkt->pts);\r
+    stream_.read(reinterpret_cast<char *>(&pkt->duration),\r
+                 sizeof pkt->duration);\r
+    stream_.read(reinterpret_cast<char *>(&pkt->size), sizeof pkt->size);\r
+    using DataPtr = std::unique_ptr<char>;\r
+    pkt->data = DataPtr(new char[pkt->size]);\r
+    stream_.read(reinterpret_cast<char *>(pkt->data.get()), pkt->size);\r
+    return pkt;\r
+  }\r
+\r
+  template <typename T>\r
+  T GetMediaInfo() {\r
+    std::string path = dirpath_ + "/ESP.info";\r
+    T media;\r
+    auto stream = std::ifstream(path, std::ifstream::in);\r
+    media.ExtractMediaInfoFrom(stream);\r
+    stream.close();\r
+    return media;\r
+  }\r
+\r
+  TRACKTYPE GetTrackType() { return type_; }\r
+\r
+ private:\r
+  std::string dirpath_;\r
+  std::ifstream stream_;\r
+  TRACKTYPE type_;\r
+};\r
+\r
+}  // namespace es\r
+#endif  // __CAPI_TRACKRENDERER_TV_UT_INCLUDE_ESCOMMON_H__
\ No newline at end of file
diff --git a/ut/src/tclist.cpp b/ut/src/tclist.cpp
new file mode 100755 (executable)
index 0000000..5acd362
--- /dev/null
@@ -0,0 +1,63 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include "ut/include/plusplayer/tclist.h"
+
+#include <sys/mount.h>
+#include <cassert>
+#include <chrono>
+#include <initializer_list>
+#include <memory>
+
+
+using tclist_ptr = std::unique_ptr<TCList>;
+static tclist_ptr ptr = nullptr;
+
+TCList& TCList::Instance() { return *(ptr.get()); }
+
+void TCList::InitializeTC(tc_type type) {
+  if (ptr.get() == nullptr) ptr.reset(new TCList(type));
+}
+
+void TCList::Kill() { ptr.reset(); }
+
+tc_map TCList::GetTCMap() const { return this->map_; }
+
+tc_list TCList::GetTCURIList() const {
+  std::vector<url> l;
+  for (const auto& p : this->map_) {
+    l.emplace_back(p.first);
+  }
+  return l;
+}
+
+TCList::TCList(tc_type type) : type_(type) {
+  this->map_.insert(http_tc::tc_map_.begin(), http_tc::tc_map_.end());
+  this->map_.insert(hls_tc::tc_map_.begin(), hls_tc::tc_map_.end());
+  this->map_.insert(dash_tc::tc_map_.begin(), dash_tc::tc_map_.end());
+#ifdef VD_UNIT_TEST
+  this->MountCIFS();
+#endif
+}
+
+TCList::~TCList() {
+#ifdef VD_UNIT_TEST
+  this->UnmountCIFS();
+#endif
+}
+
+#ifdef VD_UNIT_TEST
+void TCList::MountCIFS() {
+  LOG_DEBUG("system result : %d",
+            system("/usr/bin/chmod +x /usr/bin/mount-server.sh"));
+  LOG_DEBUG("system result : %d", system("/usr/bin/mount-server.sh"));
+}
+
+void TCList::UnmountCIFS() {
+  LOG_DEBUG(
+      "system result : %d",
+      system("/usr/bin/umount -f -l -a -t cifs"));  // -l : lazy umount for
+                                                    // mount to windows
+}
+#endif
+}  // namespace tc
diff --git a/ut/src/ut_main.cpp b/ut/src/ut_main.cpp
new file mode 100755 (executable)
index 0000000..6c3a61f
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "ut/include/plusplayer/tclist.h"
+
+using tc::tc_type;
+using tc::TCList;
+
+int main(int argc, char *argv[]) {
+  //TCList::InitializeTC(tc_type::kDefault);
+
+  ::testing::InitGoogleTest(&argc, argv);
+  ::testing::InitGoogleMock(&argc, argv);
+
+  auto ret = -1;
+  ret = RUN_ALL_TESTS();
+
+  //TCList::Kill();
+
+  return ret;
+}
diff --git a/ut/src/ut_trackrenderer.cpp b/ut/src/ut_trackrenderer.cpp
new file mode 100755 (executable)
index 0000000..e49ced3
--- /dev/null
@@ -0,0 +1,168 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <chrono>  // std::chrono::seconds()
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>  // std::thread
+
+#include "gst/gst.h"
+#include "gtest/gtest.h"
+
+#include "core/track_util.h"
+#include "player/defaultplayer.h"
+#include "plusplayer/plusplayer.h"
+#include "plusplayer/track.h"
+#include "trackrenderer/display.h"
+#include "trackrenderer/trackrenderer.h"
+#include "tracksource/tracksource.h"
+#include "ut/include/appwindow.h"
+
+class TrackRendererTest : public ::testing::Test {
+ public:
+  TrackRendererTest() {}
+
+  void SetUp() override {
+    gst_init_check(nullptr, nullptr, nullptr);
+
+    // basic , clean stream
+    std::string url = "";
+
+    // multi-track with closed caption data
+    // std::string url =
+    // "http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8";
+
+    // single-track with closed caption data
+    // std::string url =
+    // "http://mediadelivery.mlbcontrol.net/2015/hls_testbeds/ads_302/master_wired_fwv2.m3u8";
+    TypeFinder typefinder(url);
+    typefinder.Probe();
+    StreamingProperty property;
+    tracksource_ = TrackSource::CreateCompositor();
+    tracksource_->AddSource(&typefinder, property);
+    ASSERT_TRUE(tracksource_.get());
+
+    trackrenderer_ = TrackRenderer::Create();
+    ASSERT_TRUE(trackrenderer_.get());
+
+    appwindow_.reset(new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+    ASSERT_TRUE(appwindow_.get());
+
+    trackrenderer_->SetDisplayMode(plusplayer::DisplayMode::kDstRoi);
+    trackrenderer_->SetDisplay(plusplayer::DisplayType::kOverlay,
+                               appwindow_->GetWindow().obj);
+    plusplayer::Geometry roi;
+    roi.x = 600, roi.y = 300, roi.w = 720, roi.h = 480;
+    trackrenderer_->SetDisplayRoi(roi);
+  }
+
+  void TearDown() override {
+    trackrenderer_->Stop();
+    tracksource_->Stop();
+  }
+
+  std::shared_ptr<TrackSource> GetTrackSource() { return tracksource_; }
+  std::shared_ptr<TrackRenderer> GetTrackRenderer() { return trackrenderer_; }
+
+ private:
+  std::shared_ptr<TrackSource> tracksource_;
+  std::shared_ptr<TrackRenderer> trackrenderer_;
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow_;
+};
+
+Track SetVideoInfo(std::string mimetype, int w, int h, int framerate_num,
+                   int framerate_den) {
+  Track trackinfo;
+  trackinfo.mimetype = mimetype;
+  trackinfo.width = w;
+  trackinfo.height = h;
+  trackinfo.framerate_num = framerate_num;
+  trackinfo.framerate_den = framerate_den;
+  trackinfo.active = true;
+
+  return trackinfo;
+}
+
+Track SetAudioInfo(std::string mimetype, int samplerate, int sampleformat,
+                   int channels, int version) {
+  Track trackinfo;
+  trackinfo.mimetype = mimetype;
+  trackinfo.sample_rate = samplerate;
+  trackinfo.sample_format = sampleformat;
+  trackinfo.channels = channels;
+  trackinfo.version = version;
+  trackinfo.active = true;
+  return trackinfo;
+}
+
+TEST_F(TrackRendererTest, DISABLED_Create) {}
+
+TEST_F(TrackRendererTest, DISABLED_Prepare) {  // 기존 Prepare와 합쳐도 됨
+  auto tracksource = GetTrackSource();
+  auto trackrenderer = GetTrackRenderer();
+
+  tracksource->Prepare();  // READY to PAUSE
+  std::vector<Track> track = tracksource->GetTrackInfo();
+
+  // for ut test. will be remove is after tracksource implement GetTrackInfo().
+  Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
+  Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
+  std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
+  bool ret =
+      trackrenderer->SetTrack(track_vector);  // in PlusPlayer or in Wrapper
+  ASSERT_TRUE(ret);
+  // for ut test. will be remove is after tracksource implement GetTrackInfo()
+  // end
+
+  trackrenderer->Prepare();  // NULL to READY
+}
+
+TEST_F(TrackRendererTest, DISABLED_CreateAndSetWindow) {
+  auto tracksource = GetTrackSource();
+  auto trackrenderer = GetTrackRenderer();
+}
+
+TEST_F(TrackRendererTest, DISABLED_Start) {
+  auto tracksource = GetTrackSource();
+  auto trackrenderer = GetTrackRenderer();
+
+  tracksource->Prepare();  // READY to PAUSE , track parsing done
+
+  std::vector<Track> track = tracksource->GetTrackInfo();
+
+  // for ut test. will be remove is after tracksource implement GetTrackInfo().
+  Track vtrack = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
+  Track atrack = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
+  std::vector<Track> selectedtrack = {vtrack, atrack};
+  bool ret = trackrenderer->SetTrack(selectedtrack);
+
+  track_util::ShowTrackInfo(selectedtrack);
+  ASSERT_TRUE(ret);
+  // for ut test. will be remove is after tracksource implement GetTrackInfo()
+  // end
+
+  trackrenderer->Prepare();  // NULL to READY
+
+  trackrenderer->Start();  // READY to PAUSE to PLAYING
+  // PAUSE to PLAYING , Hands-off -> Listener -> SubmitPacket
+  tracksource->Start();
+
+  std::this_thread::sleep_for(std::chrono::seconds(60));
+  std::cout << "wait for 10 secs done ... terminate the test" << std::endl;
+}
+
+TEST_F(TrackRendererTest, DISABLED_SetTrack) {
+  auto tracksource = GetTrackSource();
+  auto trackrenderer = GetTrackRenderer();
+
+  Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
+  Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
+  std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
+  bool ret = trackrenderer->SetTrack(track_vector);
+  ASSERT_TRUE(ret);
+}
+
+TEST_F(TrackRendererTest, DISABLED_ChangeTrack) {
+}
diff --git a/ut/src/ut_trackrenderer2.cpp b/ut/src/ut_trackrenderer2.cpp
new file mode 100755 (executable)
index 0000000..6488134
--- /dev/null
@@ -0,0 +1,241 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <boost/scope_exit.hpp>
+#include <chrono>  // std::chrono::seconds()
+#include <iostream>
+#include <memory>
+#include <queue>
+#include <string>
+#include <thread>  // std::thread
+
+#include "gst/gst.h"
+#include "gtest/gtest.h"
+
+#include "libavformat/avformat.h"
+#include "plusplayer/track.h"
+#include "trackrenderer/core/utils/log.h"
+#include "trackrenderer/display.h"
+#include "trackrenderer/trackrenderer.h"
+#include "tracksource/tracksource.h"
+
+using namespace plusplayer;
+using namespace plusplayer::trackrenderer;
+
+namespace {
+
+class ExternalDemuxer {
+ public:
+  explicit ExternalDemuxer(const std::string& url) : url_(url) { 
+//    Init_();
+  }
+
+ private:
+  struct Context {
+    bool stop = false;
+    std::shared_ptr<TrackRenderer> trackrenderer;
+  };
+
+  bool Init_() {
+    int ret = 0;
+    av_register_all();
+    if(av_open_input_file(&ic_, url_.c_str() , nullptr , 0 , nullptr) < 0) {
+      return false;
+    }
+    ret = av_find_stream_info(ic_);
+    BOOST_SCOPE_EXIT(&ic_, &ret) {
+      if (ic_ && ret < 0) {
+        av_close_input_file(ic_);
+      }
+    } BOOST_SCOPE_EXIT_END;
+
+    if (ret < 0) {
+      return false;
+    }
+
+    ret = av_find_stream_info(ic_);
+    if(ret < 0) {
+      return false;
+    }
+    return true;
+  }
+
+  void InputTask_(Context* ctx) {
+    while (!ctx->stop) {
+      int ret = 0;
+      AVPacket packet;
+      av_init_packet(&packet);
+      if(ctx->stop) break;
+      ret = av_read_frame(ic_, &packet);
+      if(ret < 0) {
+        TRACKRENDERER_ERROR("av_read_frame error!!");
+        break;
+      }
+      MakeGstBuffer_(&packet);
+    }
+  }
+  plusplayer::DecoderInputBuffer* MakeGstBuffer_(AVPacket *packet) {
+    return nullptr;
+  }
+ private:
+  std::string url_;
+  AVFormatContext* ic_ = nullptr;
+  Context ctx;
+};
+#if 0
+  void DecoderInputTask(DataCtx* ctx) {
+    while (!ctx->stop) {
+      char* buf = read_es(frame_cnt, ctx->type, &size);    
+    push_media_data(buf, size, pts, ctx->appsrc, send_segment);
+  }
+ private:
+
+#endif
+}  // end unname space
+
+class TrackRendererTest : public ::testing::Test {
+ public:
+  TrackRendererTest() {}
+
+  void SetUp() override {
+    
+    appwindow_.reset(new AppWindow(0, 0, 1920, 1080));
+    ASSERT_TRUE(appwindow_.get());
+
+    //basic , clean stream
+    std::string url = "/opt/media/USBDriveA1/test.mp4";
+    ::ExternalDemuxer external_demuxer(url);
+    
+    // multi-track with closed caption data
+    // std::string url =
+    // "http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8";
+
+    // single-track with closed caption data
+    // std::string url =
+    // "http://mediadelivery.mlbcontrol.net/2015/hls_testbeds/ads_302/master_wired_fwv2.m3u8";
+    trackrenderer_ = TrackRenderer::Create();
+    ASSERT_TRUE(trackrenderer_.get());
+    
+    trackrenderer_->SetDisplayMode(DisplayMode::kDstRoi);
+    trackrenderer_->SetDisplay(DisplayType::kOverlay,appwindow_->GetWindow().obj);
+    Geometry roi;
+    roi.x = 600, roi.y = 300, roi.w = 720, roi.h = 480;
+    trackrenderer_->SetDisplayRoi(roi);
+  }
+
+  void TearDown() override {
+    trackrenderer_->Stop();
+  }
+
+  std::shared_ptr<TrackRenderer> GetTrackRenderer() { return trackrenderer_; }
+  SourceType& GetSourceType() const { return type_; }
+
+ private:
+  SourceType type_;
+  std::shared_ptr<TrackRenderer> trackrenderer_;  
+  std::unique_ptr<AppWindow> appwindow_;
+};
+
+
+Track SetVideoInfo(std::string mimetype, int w, int h, int framerate_num, int framerate_den) {
+  Track trackinfo;
+  trackinfo.mimetype = mimetype;
+  trackinfo.width = w;
+  trackinfo.height = h;
+  trackinfo.framerate_num = framerate_num;
+  trackinfo.framerate_den = framerate_den;
+  trackinfo.active = true;
+
+  return trackinfo;  
+}
+
+Track SetAudioInfo(std::string mimetype, int samplerate, int sampleformat, int channels, int version) {
+  Track trackinfo;
+  trackinfo.mimetype = mimetype;
+  trackinfo.sample_rate = samplerate;
+  trackinfo.sample_format = sampleformat;
+  trackinfo.channels = channels;
+  trackinfo.version = version;
+  trackinfo.active = true;
+  return trackinfo;  
+}
+
+TEST_F(TrackRendererTest, DISABLED_Create) {}
+
+TEST_F(TrackRendererTest, DISABLED_Prepare) {
+  auto trackrenderer = GetTrackRenderer();
+  
+  Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
+  Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
+  std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
+  bool ret = trackrenderer->SetTrack(track_vector);     // in PlusPlayer or in Wrapper
+  ASSERT_TRUE(ret);
+  trackrenderer->Prepare();  // NULL to READY
+}
+
+TEST_F(TrackRendererTest, DISABLED_SetDisplay) {
+}
+
+TEST_F(TrackRendererTest, DISABLED_Start) {
+  auto trackrenderer = GetTrackRenderer();
+  auto start = logutil::performance::Start();
+
+  Track vtrack = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
+  Track atrack = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
+  std::vector<Track> selectedtrack = {vtrack, atrack};
+  bool ret = trackrenderer->SetTrack(selectedtrack);
+  track_util::ShowTrackInfo(selectedtrack);
+  ASSERT_TRUE(ret);
+
+  trackrenderer->Prepare();  // NULL to READY
+
+  trackrenderer->Start();  // READY to PAUSE to PLAYING
+  // PAUSE to PLAYING , Hands-off -> Listener -> SubmitPacket
+  logutil::performance::End(start, "[TrackRenderer start::]");
+  std::this_thread::sleep_for(std::chrono::seconds(60));
+  std::cout << "wait for 10 secs done ... terminate the test" << std::endl;
+}
+
+TEST_F(TrackRendererTest, DISABLED_SetTrack) {
+  auto trackrenderer = GetTrackRenderer();
+  
+  Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
+  Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
+  std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
+  bool ret = trackrenderer->SetTrack(track_vector);   
+  ASSERT_TRUE(ret);
+}
+
+TEST_F(TrackRendererTest, DISABLED_ChangeTrack) {
+  auto trackrenderer = GetTrackRenderer();
+  Track trackvideoinfo = SetVideoInfo("video/x-h264", 640, 352, 30, 1);
+  Track trackaudioinfo = SetAudioInfo("audio/mpeg", 44100, 0, 2, 4);
+  std::vector<Track> track_vector = {trackvideoinfo, trackaudioinfo};
+  bool ret = trackrenderer->SetTrack(track_vector);     // in PlusPlayer or in Wrapper
+  ASSERT_TRUE(ret);
+
+  trackrenderer->Prepare();  // NULL to READY
+
+  start = logutil::performance::Start();
+  trackrenderer->Start();  // READY to PAUSE to PLAYING
+
+  logutil::performance::End(start, "player start");
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+
+  TRACKRENDERER_DEBUG("Start Track change");
+  Track changed_info;
+  changed_info.channels = 2;
+  changed_info.mimetype = "audio/mpeg";
+  changed_info.sample_rate = 48000;
+  changed_info.sample_format = 2;
+  changed_info.version = 4;
+  changed_info.active = true;
+
+  // push thread for appsrc must be stopped first. otherwisw appsrc block mode
+  // makes deadlock
+  trackrenderer->ChangeTrack(changed_info);
+  TRACKRENDERER_DEBUG("ChangeTrack DONE");
+  std::this_thread::sleep_for(std::chrono::seconds(15));
+  TRACKRENDERER_DEBUG("STOP");
+}
diff --git a/ut/src/ut_trackrenderer_capi.cpp b/ut/src/ut_trackrenderer_capi.cpp
new file mode 100755 (executable)
index 0000000..220b6ac
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+* Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+* PROPRIETARY/CONFIDENTIAL 
+* This software is the confidential and proprietary
+* information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall
+* not disclose such Confidential Information and shall use it only in
+* accordance with the terms of the license agreement you entered into with
+* SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the
+* suitability of the software, either express or implied, including but not
+* limited to the implied warranties of merchantability, fitness for a
+* particular purpose, or non-infringement. SAMSUNG shall not be liable for any
+* damages suffered by licensee as a result of using, modifying or distributing
+* this software or its derivatives.
+*/
+#include "gst/gst.h"
+#include "gtest/gtest.h"
+
+#include "trackrenderer/core/utils/log.h"
+#include "trackrenderer/version.h"
+#include "trackrenderer_capi/trackrenderer_capi.h"
+
+TEST(TrackRendererCapiTest, DISABLED_get_version) {
+  std::string version { TRACKRENDERER_STRINGIFY(LIB_TRACKRENDERER_VERSION)};
+  TRACKRENDERER_INFO("version string[%s]", trackrenderer_get_version());
+  ASSERT_STREQ(version.c_str() , trackrenderer_get_version());
+}
+
+TEST(TrackRendererCapiTest, DISABLED_get_version_int) {
+  uint32_t version = LIB_TRACKRENDERER_VERSION_INT;
+  TRACKRENDERER_INFO("version int[%u]", trackrenderer_get_version_int());
+  ASSERT_EQ(version , trackrenderer_get_version_int());
+}