Initialize the code with P4 FET CL9112401 45/261245/4 tizen_tv_devel
authorchuanji.tang <chuanji.tang@samsung.com>
Wed, 14 Jul 2021 01:14:02 +0000 (09:14 +0800)
committerchuanji.tang <chuanji.tang@samsung.com>
Thu, 15 Jul 2021 08:52:20 +0000 (16:52 +0800)
Change-Id: I22abaca7c3a23d934e1043998c4d047930f83652

294 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]
config/esplusplayer.ini [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]
esplusplayer.pc.in [new file with mode: 0755]
include/esplusplayer_capi/buffer.h [new file with mode: 0755]
include/esplusplayer_capi/display.h [new file with mode: 0755]
include/esplusplayer_capi/drm.h [new file with mode: 0755]
include/esplusplayer_capi/error.h [new file with mode: 0755]
include/esplusplayer_capi/espacket.h [new file with mode: 0755]
include/esplusplayer_capi/esplusplayer_capi.h [new file with mode: 0755]
include/esplusplayer_capi/esplusplayer_internal.h [new file with mode: 0755]
include/esplusplayer_capi/event.h [new file with mode: 0755]
include/esplusplayer_capi/latency.h [new file with mode: 0755]
include/esplusplayer_capi/matroska_color.h [new file with mode: 0755]
include/esplusplayer_capi/state.h [new file with mode: 0755]
include/esplusplayer_capi/stream.h [new file with mode: 0755]
include/esplusplayer_capi/submitdatatype.h [new file with mode: 0755]
include/esplusplayer_capi/submitstatus.h [new file with mode: 0755]
include/mixer/decodedvideoinfo.h [new file with mode: 0755]
include/mixer/mixer.h [new file with mode: 0755]
include/mixer/mixer_eventlistener.h [new file with mode: 0755]
include/mixer/mixerticket.h [new file with mode: 0755]
include/mixer/mixerticket_eventlistener.h [new file with mode: 0755]
include/mixer_capi/display.h [new file with mode: 0755]
include/mixer_capi/error.h [new file with mode: 0755]
include/mixer_capi/mixer_capi.h [new file with mode: 0755]
include/plusplayer/appinfo.h [new file with mode: 0755]
include/plusplayer/attribute.h [new file with mode: 0755]
include/plusplayer/audioeasinginfo.h [new file with mode: 0755]
include/plusplayer/decodedvideopacketex.h [new file with mode: 0755]
include/plusplayer/drm.h [new file with mode: 0755]
include/plusplayer/elementary_stream.h [new file with mode: 0755]
include/plusplayer/es_eventlistener.h [new file with mode: 0755]
include/plusplayer/espacket.h [new file with mode: 0755]
include/plusplayer/esplusplayer.h [new file with mode: 0755]
include/plusplayer/external_drm.h [new file with mode: 0755]
include/plusplayer/track.h [new file with mode: 0755]
include/plusplayer/types/buffer.h [new file with mode: 0755]
include/plusplayer/types/display.h [new file with mode: 0755]
include/plusplayer/types/error.h [new file with mode: 0755]
include/plusplayer/types/event.h [new file with mode: 0755]
include/plusplayer/types/latency.h [new file with mode: 0755]
include/plusplayer/types/picturequality.h [new file with mode: 0755]
include/plusplayer/types/resource.h [new file with mode: 0755]
include/plusplayer/types/source.h [new file with mode: 0755]
include/plusplayer/types/stream.h [new file with mode: 0755]
include/plusplayer/types/streaming_message.h [new file with mode: 0755]
include/plusplayer/types/submitdata.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 9M to 4.5M.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/esplusplayer.manifest [new file with mode: 0755]
packaging/esplusplayer.spec [new file with mode: 0755]
src/CMakeLists.txt [new file with mode: 0755]
src/cpplint.py [new file with mode: 0755]
src/esplusplayer/CMakeLists.txt [new file with mode: 0755]
src/esplusplayer/include_internal/esplayer/decoded_pkt_list.h [new file with mode: 0755]
src/esplusplayer/include_internal/esplayer/espacket_logger.h [new file with mode: 0755]
src/esplusplayer/include_internal/esplayer/esplayer.h [new file with mode: 0755]
src/esplusplayer/include_internal/esplayer/esplayer_drm.h [new file with mode: 0755]
src/esplusplayer/include_internal/esplayer/message.hpp [new file with mode: 0755]
src/esplusplayer/include_internal/esplayer/state_manager.hpp [new file with mode: 0755]
src/esplusplayer/src/elementary_stream.cpp [new file with mode: 0755]
src/esplusplayer/src/espacket.cpp [new file with mode: 0755]
src/esplusplayer/src/espacket_logger.cpp [new file with mode: 0755]
src/esplusplayer/src/esplayer.cpp [new file with mode: 0755]
src/esplusplayer/src/esplayer_drm.cpp [new file with mode: 0755]
src/esplusplayer/src/esplusplayer.cpp [new file with mode: 0755]
src/esplusplayer/src/esplusplayer_capi.cpp [new file with mode: 0755]
src/mixer/CMakeLists.txt [new file with mode: 0755]
src/mixer/include_internal/mixer/abs_videoframe.h [new file with mode: 0755]
src/mixer/include_internal/mixer/defaultmixer.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/accessiblebuffer.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/bufferobject.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/memoryallocator.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/phyaddraccessor.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/renderableobj_factory.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/renderableobject.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/videoplanecollection.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/videoplanecolorfiller.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/videoplanecopier.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/videoplanemanipulable.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/videoplanemanipulator.h [new file with mode: 0755]
src/mixer/include_internal/mixer/interfaces/videoplanescaler.h [new file with mode: 0755]
src/mixer/include_internal/mixer/mixedframe.h [new file with mode: 0755]
src/mixer/include_internal/mixer/renderer.h [new file with mode: 0755]
src/mixer/include_internal/mixer/rendererwithdoublebuf.h [new file with mode: 0755]
src/mixer/include_internal/mixer/sys/tbminterface.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenaccessiblebufferobj.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenbufferkeyvideoframe.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenbuffermgr.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenbufferobj.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenbufferphyaddraccessor.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizendefaultphyaddraccessor.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenhwbufferobj.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenhwvideoframe.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizenrenderableobj_factory.h [new file with mode: 0755]
src/mixer/include_internal/mixer/tizen/tizensurfacevideoframe.h [new file with mode: 0755]
src/mixer/include_internal/mixer/types/buffertype.h [new file with mode: 0755]
src/mixer/include_internal/mixer/types/planecomponent.h [new file with mode: 0755]
src/mixer/include_internal/mixer/types/videoplanemanipinfo.h [new file with mode: 0755]
src/mixer/include_internal/mixer/types/videoplanemoveinfo.h [new file with mode: 0755]
src/mixer/include_internal/mixer/videoplane.h [new file with mode: 0755]
src/mixer/src/abs_videoframe.cpp [new file with mode: 0755]
src/mixer/src/defaultmixer.cpp [new file with mode: 0755]
src/mixer/src/mixedframe.cpp [new file with mode: 0755]
src/mixer/src/mixer.cpp [new file with mode: 0755]
src/mixer/src/mixer_capi.cpp [new file with mode: 0755]
src/mixer/src/renderer.cpp [new file with mode: 0755]
src/mixer/src/sys/tbminterface.cpp [new file with mode: 0755]
src/mixer/src/tizen/tizenaccessiblebufferobj.cpp [new file with mode: 0755]
src/mixer/src/tizen/tizenbufferkeyvideoframe.cpp [new file with mode: 0755]
src/mixer/src/tizen/tizendefaultphyaddraccessor.cpp [new file with mode: 0755]
src/mixer/src/tizen/tizenhwbufferobj.cpp [new file with mode: 0755]
src/mixer/src/tizen/tizenhwvideoframe.cpp [new file with mode: 0755]
src/mixer/src/tizen/tizenrenderableobj_factory.cpp [new file with mode: 0755]
src/mixer/src/tizen/tizensurfacevideoframe.cpp [new file with mode: 0755]
src/mixer/src/videoplane.cpp [new file with mode: 0755]
src/plusplayer-core/Build/appendix.mk [new file with mode: 0755]
src/plusplayer-core/Build/basedef.mk [new file with mode: 0755]
src/plusplayer-core/Build/build_c.mk [new file with mode: 0755]
src/plusplayer-core/Build/build_edc.mk [new file with mode: 0755]
src/plusplayer-core/Build/build_po.mk [new file with mode: 0755]
src/plusplayer-core/Build/flags.mk [new file with mode: 0755]
src/plusplayer-core/Build/funcs.mk [new file with mode: 0755]
src/plusplayer-core/Build/makefile [new file with mode: 0755]
src/plusplayer-core/Build/makefile.mk [new file with mode: 0755]
src/plusplayer-core/Build/platform.mk [new file with mode: 0755]
src/plusplayer-core/Build/tooldef.mk [new file with mode: 0755]
src/plusplayer-core/CMakeLists.txt [new file with mode: 0755]
src/plusplayer-core/build_def.prop [new file with mode: 0755]
src/plusplayer-core/include_internal/core/decodedvideorawmodepacket.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/decoderinputbuffer.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/decoderinputbuffer_listener.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/error.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/gst_utils.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/gstobject_guard.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/gstsignal_holder.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/kpi.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/serializer.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/subtitle_attr_parser.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/track_util.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/trackrendereradapter.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/trackrendereradapter_utils.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/utils/base64.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/utils/caf_logger.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/utils/performance_checker.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/utils/plusplayer_cfg.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/utils/plusplayer_log.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/utils/scope_exit.h [new file with mode: 0755]
src/plusplayer-core/include_internal/core/videoframetypestrategy.h [new file with mode: 0755]
src/plusplayer-core/project_def.prop [new file with mode: 0755]
src/plusplayer-core/src/base64.cpp [new file with mode: 0755]
src/plusplayer-core/src/caf_logger.cpp [new file with mode: 0755]
src/plusplayer-core/src/decodedvideopacketex.cpp [new file with mode: 0755]
src/plusplayer-core/src/decoderinputbuffer.cpp [new file with mode: 0755]
src/plusplayer-core/src/error.cpp [new file with mode: 0755]
src/plusplayer-core/src/gst_utils.cpp [new file with mode: 0755]
src/plusplayer-core/src/gstobject_guard.cpp [new file with mode: 0755]
src/plusplayer-core/src/gstsignal_holder.cpp [new file with mode: 0755]
src/plusplayer-core/src/kpi.cpp [new file with mode: 0755]
src/plusplayer-core/src/plusplayer_cfg.cpp [new file with mode: 0755]
src/plusplayer-core/src/serializer.cpp [new file with mode: 0755]
src/plusplayer-core/src/subtitle_attr_parser.cpp [new file with mode: 0755]
src/plusplayer-core/src/track_util.cpp [new file with mode: 0755]
src/plusplayer-core/src/trackrendereradapter.cpp [new file with mode: 0755]
src/plusplayer-core/src/trackrendereradapter_utils.cpp [new file with mode: 0755]
src/plusplayer-core/src/videoframetypestrategy.cpp [new file with mode: 0755]
tomato/tc/TCList.dat [new file with mode: 0755]
tomato/tc/testfarm_script.xml [new file with mode: 0755]
tomato/tc/unit_test/ut_esplusplayer_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/esplusplayer/tclist.h [new file with mode: 0755]
ut/include/mixer/constant.h [new file with mode: 0755]
ut/include/mixer/matcher.h [new file with mode: 0755]
ut/include/mixer/mock/fakebuffer.h [new file with mode: 0755]
ut/include/mixer/mock/mock_bufferobject.h [new file with mode: 0755]
ut/include/mixer/mock/mock_memallocator.h [new file with mode: 0755]
ut/include/mixer/mock/mock_phyaddraccessor.h [new file with mode: 0755]
ut/include/mixer/mock/mock_renderableobj.h [new file with mode: 0755]
ut/include/mixer/mock/mock_renderableobj_factory.h [new file with mode: 0755]
ut/include/mixer/mock/mock_renderer_evtlistener.h [new file with mode: 0755]
ut/include/mixer/mock/mock_vpcollection.h [new file with mode: 0755]
ut/include/mixer/mock/mock_vpmanipulator.h [new file with mode: 0755]
ut/include/mixer/mock/mock_vpscaler.h [new file with mode: 0755]
ut/include/mixer/mock/movable.h [new file with mode: 0755]
ut/include/mixer/mock/moveobj_wrapper.h [new file with mode: 0755]
ut/include/plusplayer/imagesimilarity.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/esplusplayer/ut_basic.cpp [new file with mode: 0755]
ut/src/esplusplayer/ut_display.cpp [new file with mode: 0755]
ut/src/esplusplayer/ut_setstream.cpp [new file with mode: 0755]
ut/src/mixer/constant.cpp [new file with mode: 0755]
ut/src/mixer/matcher.cpp [new file with mode: 0755]
ut/src/mixer/ut_espp_mixerscenario.cpp [new file with mode: 0755]
ut/src/mixer/ut_mixedframe.cpp [new file with mode: 0755]
ut/src/mixer/ut_mixer.cpp [new file with mode: 0755]
ut/src/mixer/ut_mixer_capi.cpp [new file with mode: 0755]
ut/src/mixer/ut_mixer_espp_capi.cpp [new file with mode: 0755]
ut/src/mixer/ut_mixerscenario.cpp [new file with mode: 0755]
ut/src/mixer/ut_mixerticket.cpp [new file with mode: 0755]
ut/src/mixer/ut_renderer.cpp [new file with mode: 0755]
ut/src/mixer/ut_tizenbuffermgr.cpp [new file with mode: 0755]
ut/src/mixer/ut_tizenbufferobj.cpp [new file with mode: 0755]
ut/src/mixer/ut_videoplane.cpp [new file with mode: 0755]
ut/src/plusplayer/imagesimilarity.cpp [new file with mode: 0755]
ut/src/plusplayer/utility.cpp [new file with mode: 0755]
ut/src/ut_espacket.cpp [new file with mode: 0755]
ut/src/ut_esplayer.cpp [new file with mode: 0755]
ut/src/ut_esplayer2.cpp [new file with mode: 0755]
ut/src/ut_esplayer_trackrenderer.cpp [new file with mode: 0755]
ut/src/ut_main.cpp [new file with mode: 0755]
ut/src/ut_miscellaneous.cpp [new file with mode: 0755]
ut/src/ut_streamreader.cpp [new file with mode: 0755]
ut/src/ut_trackrendereradapter.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..135c035
--- /dev/null
@@ -0,0 +1,61 @@
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+
+PROJECT(esplusplayer)
+SET(description "new multimedia player, object-oriented model")
+SET(PC_NAME "esplusplayer")
+SET(PC_LDFLAGS "-lesplusplayer -lmixer")
+SET(PC_CFLAGS "-I/usr/include/esplusplayer_capi -I/usr/include/mixer")
+
+SET(INC_DIR ${PROJECT_SOURCE_DIR}/include/)
+INCLUDE_DIRECTORIES(${INC_DIR})
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+CONFIGURE_FILE(esplusplayer.pc.in
+  esplusplayer.pc
+  @ONLY
+)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/esplusplayer.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+
+ADD_SUBDIRECTORY(src)
+
+OPTION(ESPLUSPLAYER_BUILD_UT "Build esplusplayer ut codes" OFF)
+IF(ESPLUSPLAYER_BUILD_UT)
+ADD_SUBDIRECTORY(ut)
+ENDIF(ESPLUSPLAYER_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} )
\ No newline at end of file
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..12c8421
--- /dev/null
+++ b/README.md
@@ -0,0 +1,74 @@
+# **PlusPlayer** #\r
+  PlusPlayer is a new multimedia player object-oriented designed.\r
+\r
+## Notice \r
+  * 18_Plusplayer\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): [https://google.github.io/styleguide/cppguide.html](https://google.github.io/styleguide/cppguide.html)\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/config/esplusplayer.ini b/config/esplusplayer.ini
new file mode 100755 (executable)
index 0000000..56f20e5
--- /dev/null
@@ -0,0 +1,12 @@
+{\r
+  "version" : "0.0.4948390.firmware",\r
+  "gstparam1" : "--gst-debug=*:2",\r
+  "gstparam2" : "--gst-disable-segtrap",\r
+  "gstparam3" : "--gst-plugin-load",\r
+  "gstparam4" : "--gst-disable-registry-fork",\r
+  "gstparam5" : "--gst-disable-registry-update",\r
+  "tz_video_es_dump" : false,\r
+  "tz_video_dump_insert_vp9_header" : false,\r
+  "tz_audio_es_dump" : false,\r
+  "generate_dot" : false\r
+}\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..73e4d35
--- /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..838b475
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/esplusplayer.pc.in b/esplusplayer.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/include/esplusplayer_capi/buffer.h b/include/esplusplayer_capi/buffer.h
new file mode 100755 (executable)
index 0000000..f499b25
--- /dev/null
@@ -0,0 +1,103 @@
+/**
+ * @file
+ * @brief          The buffer for playback.
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style buffer related enum.
+ * @see            N/A
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_BUFFER_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_BUFFER_H__
+
+#include <cstdint>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the buffer status
+ */
+enum esplusplayer_buffer_status {
+  ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN,
+  ESPLUSPLAYER_BUFFER_STATUS_OVERRUN
+};
+
+/**
+ * @brief  Enumerations for video decoded buffer type
+ * ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE:
+ * decoded video frame will be croped and scaled, then sent to
+ * user by media_packet_video_decoded_cb, only support hw decoder now
+*/
+enum esplusplayer_decoded_video_frame_buffer_type {
+  ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE,
+  ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY,
+  ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_REFERENCE,
+  ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE
+};
+
+/**
+ * @brief  Enumerations for buffer size option
+ * MAX_TIME_SIZE: The maximum amount of data to esplusplayer internally(in ms)
+ * MIN_TIME_THRESHOLD : Emit under-run when queued bytes drops below this
+ * percent of max-time-size(size%)
+ * MAX_BYTE_SIZE: The maximum number of bytes to esplusplayer internally
+ * MIN_BYTE_THRESHOLD : Emit under-run when queued bytes drops below this
+ * percent of  max-byte-size(size%)
+ */
+enum esplusplayer_buffer_option {
+  ESPLUSPLAYER_BUFFER_AUDIO_MAX_TIME_SIZE,
+  ESPLUSPLAYER_BUFFER_VIDEO_MAX_TIME_SIZE,
+  ESPLUSPLAYER_BUFFER_AUDIO_MIN_TIME_THRESHOLD,
+  ESPLUSPLAYER_BUFFER_VIDEO_MIN_TIME_THRESHOLD,
+  ESPLUSPLAYER_BUFFER_AUDIO_MAX_BYTE_SIZE,
+  ESPLUSPLAYER_BUFFER_VIDEO_MAX_BYTE_SIZE,
+  ESPLUSPLAYER_BUFFER_AUDIO_MIN_BYTE_THRESHOLD,
+  ESPLUSPLAYER_BUFFER_VIDEO_MIN_BYTE_THRESHOLD
+};
+
+/**
+ * @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* private_data;
+} esplusplayer_decoded_video_packet;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_BUFFER_H__
diff --git a/include/esplusplayer_capi/display.h b/include/esplusplayer_capi/display.h
new file mode 100755 (executable)
index 0000000..f3adb95
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * @file
+ * @brief          Display related enums
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.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) 2020 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_ESPLUSPLAYER_CAPI_DISPLAY_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_DISPLAY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the display mode
+ */
+enum esplusplayer_display_mode {
+  ESPLUSPLAYER_DISPLAY_MODE_LETTER_BOX,
+  ESPLUSPLAYER_DISPLAY_MODE_ORIGIN_SIZE,
+  ESPLUSPLAYER_DISPLAY_MODE_FULL_SCREEN,
+  ESPLUSPLAYER_DISPLAY_MODE_CROPPED_FULL,
+  ESPLUSPLAYER_DISPLAY_MODE_ORIGIN_OR_LETTER,
+  ESPLUSPLAYER_DISPLAY_MODE_DST_ROI
+};
+
+/**
+ * @brief  Enumerations for the display type
+ */
+enum esplusplayer_display_type {
+  ESPLUSPLAYER_DISPLAY_TYPE_NONE,
+  ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+  ESPLUSPLAYER_DISPLAY_TYPE_EVAS,
+  ESPLUSPLAYER_DISPLAY_TYPE_MIXER
+};
+
+/**
+ * @brief  Enumerations for the display rotation type
+ */
+enum esplusplayer_display_rotation_type {
+  ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_NONE,
+  ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_90,
+  ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_180,
+  ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_270
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_DISPLAY_H__
diff --git a/include/esplusplayer_capi/drm.h b/include/esplusplayer_capi/drm.h
new file mode 100755 (executable)
index 0000000..dd2babc
--- /dev/null
@@ -0,0 +1,183 @@
+/**
+ * @file
+ * @brief          Drm related enums
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.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) 2020 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_ESPLUSPLAYER_CAPI_DRM_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_DRM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/**
+ * @brief  Enumerations for the drm type
+ */
+enum esplusplayer_drm_type {
+  ESPLUSPLAYER_DRM_TYPE_NONE,
+  ESPLUSPLAYER_DRM_TYPE_PLAYREADY,
+  ESPLUSPLAYER_DRM_TYPE_MARLIN,
+  ESPLUSPLAYER_DRM_TYPE_VERIMATRIX,
+  ESPLUSPLAYER_DRM_TYPE_WV_MODULAR
+};
+
+/**
+ * @brief  Enumerations for the algorithm encrypted
+ */
+enum esplusplayer_drmb_es_cipher_algorithm {
+  ESPLUSPLAYER_DRMB_ES_CIPHER_ALGORITHM_UNKNOWN = -1,
+  ESPLUSPLAYER_DRMB_ES_CIPHER_ALGORITHM_RC4 = 0,
+  ESPLUSPLAYER_DRMB_ES_CIPHER_ALGORITHM_AES128_CTR = 1,
+  ESPLUSPLAYER_DRMB_ES_CIPHER_ALGORITHM_AES128_CBC = 2
+};
+
+/**
+ * @brief  Enumerations for the algorithm encrypted
+ */
+enum esplusplayer_drmb_es_media_format {
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_NONE = 0,
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_FMP4 = 1,
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_TS = 2,
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_ASF = 3,
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_FMP4_AUDIO = 4,
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_FMP4_VIDEO = 5,
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_CLEAN_AUDIO = 6,
+  ESPLUSPLAYER_DRMB_ES_MEDIA_FORMAT_PES = 7
+};
+
+/**
+ * @brief  Enumerations for the phase for cipher
+ */
+enum esplusplayer_drmb_es_cipher_phase {
+  ESPLUSPLAYER_DRMB_ES_CIPHER_PHASE_NONE = 0,
+  ESPLUSPLAYER_DRMB_ES_CIPHER_PHASE_INIT = 1,
+  ESPLUSPLAYER_DRMB_ES_CIPHER_PHASE_UPDATE = 2,
+  ESPLUSPLAYER_DRMB_ES_CIPHER_PHASE_FINAL = 3
+};
+
+/**
+ * @brief  Subsample information structure for encrypted es
+ */
+typedef struct {
+  /**
+   * @description   The bytes of clear data.
+   */
+  uint32_t bytes_of_clear_data;
+  /**
+   * @description   The bytes of encrypted data.
+   */
+  uint32_t bytes_of_encrypted_data;
+} esplusplayer_drmb_es_subsample_info;
+
+/**
+ * @brief  Fragmented MP4 data structure for encrypted es
+ */
+typedef struct {
+  /**
+   * @description   The count of subsample informations
+   */
+  uint32_t subsample_count;
+  /**
+   * @description   The subsample informations
+   */
+  esplusplayer_drmb_es_subsample_info* subsample_infos;
+} esplusplayer_drmb_es_fmp4_data;
+
+/**
+ * @brief  The information to decrypt es packet
+ */
+typedef struct {
+  /**
+   * @description   The handle to decrypt es packet.
+   */
+  int32_t handle;
+  /**
+   * @description   The algorithm encrypted.
+   */
+  esplusplayer_drmb_es_cipher_algorithm algorithm;
+  /**
+   * @description   The es media format.
+   */
+  esplusplayer_drmb_es_media_format format;
+  /**
+   * @description   The phase to decrypt.
+   */
+  esplusplayer_drmb_es_cipher_phase phase;
+  /**
+   * @description   The KID.
+   */
+  unsigned char* kid;
+  /**
+   * @description   The length of KID.
+   */
+  uint32_t kid_length;
+  /**
+   * @description   The vector for initialization.
+   */
+  unsigned char* iv;
+  /**
+   * @description   The length of IV.
+   */
+  uint32_t iv_length;
+  /**
+   * @description   The sub data.
+   * @see           esplusplayer_drmb_es_fmp4_data
+   */
+  void* sub_data;
+  /**
+   * @description   The offset of sample.
+   *                It can be NULL.
+   *                If used, it have to be -1 terminated.
+   *                Max offset is 15.
+   */
+  int* split_offsets;
+  /**
+   * @description   It should be 0 when it must be protected with trustzone.
+   */
+  bool use_out_buffer;
+  /**
+   * @description   If use 'cbcs' pattern scheme, It should be 1. otherwise 0.
+   */
+  bool use_pattern;
+  /**
+   * @description   In case that use_patter is 1,
+   *                count of the encrypted blocks in the protection pattern.
+   */
+  uint32_t crypt_byte_block;
+  /**
+   * @description   In case that use_patter is 1,
+   *                count of the unencrypted blocks in the protection pattern.
+   */
+  uint32_t skip_byte_block;
+} esplusplayer_drm_info;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_DRM_H__
diff --git a/include/esplusplayer_capi/error.h b/include/esplusplayer_capi/error.h
new file mode 100755 (executable)
index 0000000..17f24bd
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * @file
+ * @brief          Error related enums
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.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) 2020 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_ESPLUSPLAYER_CAPI_ERROR_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_ERROR_H__
+
+#include "tizen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ESPLUSPLAYER_ERROR_CLASS TIZEN_ERROR_PLAYER | 0x20
+
+/* This is for custom defined esplusplayer error. */
+#define ESPLUSPLAYER_CUSTOM_ERROR_CLASS TIZEN_ERROR_PLAYER | 0x1000
+
+/**
+ * @brief  Enumerations for the error type
+ */
+enum esplusplayer_error_type {
+  ESPLUSPLAYER_ERROR_TYPE_NONE = TIZEN_ERROR_NONE, /**< Successful */
+  ESPLUSPLAYER_ERROR_TYPE_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+  ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+  ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */
+  ESPLUSPLAYER_ERROR_TYPE_INVALID_STATE  = ESPLUSPLAYER_ERROR_CLASS | 0x02, /**< Invalid state */
+  ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_AUDIO_CODEC = ESPLUSPLAYER_ERROR_CLASS | 0x0e, /**< Not supported audio codec but video can be played (Since 4.0)*/
+  ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_VIDEO_CODEC = ESPLUSPLAYER_ERROR_CLASS | 0x0f, /**< Not supported video codec but audio can be played (Since 4.0)*/
+  ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FILE = ESPLUSPLAYER_ERROR_CLASS | 0x03, /**< File format not supported */
+  ESPLUSPLAYER_ERROR_TYPE_CONNECTION_FAILED = ESPLUSPLAYER_ERROR_CLASS | 0x06, /**< Streaming connection failed */
+  ESPLUSPLAYER_ERROR_TYPE_DRM_EXPIRED = ESPLUSPLAYER_ERROR_CLASS | 0x08, /**< Expired license */
+  ESPLUSPLAYER_ERROR_TYPE_DRM_NO_LICENSE = ESPLUSPLAYER_ERROR_CLASS | 0x09, /**< No license */
+  ESPLUSPLAYER_ERROR_TYPE_DRM_FUTURE_USE = ESPLUSPLAYER_ERROR_CLASS | 0x0a, /**< License for future use */
+  ESPLUSPLAYER_ERROR_TYPE_NOT_PERMITTED = ESPLUSPLAYER_ERROR_CLASS | 0x0b, /**< Format not permitted */
+
+  ESPLUSPLAYER_ERROR_TYPE_DRM_DECRYPTION_FAILED = ESPLUSPLAYER_CUSTOM_ERROR_CLASS | 0x05, /**< drm decryption failed */
+  ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FORMAT = ESPLUSPLAYER_CUSTOM_ERROR_CLASS | 0x08,/**< format not supported */
+  ESPLUSPLAYER_ERROR_TYPE_UNKNOWN
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_ERROR_H__
diff --git a/include/esplusplayer_capi/espacket.h b/include/esplusplayer_capi/espacket.h
new file mode 100755 (executable)
index 0000000..14edd8f
--- /dev/null
@@ -0,0 +1,114 @@
+/**
+ * @file
+ * @brief          The packet for elementary stream
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @see            plusplayer::EsPlusPlayer class
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_ESPACKET_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_ESPACKET_H__
+
+#include <cstdint>
+
+#include "esplusplayer_capi/matroska_color.h"
+#include "esplusplayer_capi/stream.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Es packet structure
+ */
+typedef struct {
+  /**
+   * @description   The stream type.
+   */
+  esplusplayer_stream_type type;
+  /**
+   * @description   The buffer data pointer
+   */
+  char* buffer;
+  /**
+   * @description   The buffer size.
+   */
+  uint32_t buffer_size;
+  /**
+   * @description   The pts value in milisecond.
+   */
+  uint64_t pts;
+  /**
+   * @description   The duration value in milisecond.
+   */
+  uint64_t duration;
+  /**
+   * @description   The matroska color information. this value is only for video
+   * packet. If you set this value on a packet of other type, you can see an
+   * error when you submit the packet.
+   */
+  esplusplayer_matroska_color* matroska_color_info;
+  /**
+   * @description   The hdr10+ metadata size.
+   */
+  uint32_t hdr10p_metadata_size;
+  /**
+   * @description   The hdr10+ metadata.
+   */
+  char* hdr10p_metadata;
+} esplusplayer_es_packet;
+
+/**
+ * @brief   Trust zone es packet structure
+ */
+typedef struct {
+  /**
+   * @description   The Stream type.
+   */
+  esplusplayer_stream_type type;
+  /**
+   * @description   The tz handle.
+   */
+  uint32_t handle;
+  /**
+   * @description   The tz handle size.
+   */
+  uint32_t handle_size;
+  /**
+   * @description   The pts value in milisecond.
+   */
+  uint64_t pts;
+  /**
+   * @description   The duration value in milisecond.
+   */
+  uint64_t duration;
+  /**
+   * @description   The matroska color information. this value is only for video
+   * packet. If you set this value on a packet of other type, you can see an
+   * error when you submit the packet.
+   */
+  esplusplayer_matroska_color* matroska_color_info;
+} esplusplayer_es_tz_packet;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_ESPACKET_H__
diff --git a/include/esplusplayer_capi/esplusplayer_capi.h b/include/esplusplayer_capi/esplusplayer_capi.h
new file mode 100755 (executable)
index 0000000..c7daeed
--- /dev/null
@@ -0,0 +1,2857 @@
+/**
+ * @file           esplusplayer_capi.h
+ * @brief          EsPlusPlayer api c version
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @remark         This is esplusplayer api header implemented as C style to
+ *                 avoid binary compatibility issues.
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_ESPLUSPLAYER_CAPI_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_ESPLUSPLAYER_CAPI_H__
+
+#include "esplusplayer_capi/buffer.h"
+#include "esplusplayer_capi/display.h"
+#include "esplusplayer_capi/drm.h"
+#include "esplusplayer_capi/error.h"
+#include "esplusplayer_capi/espacket.h"
+#include "esplusplayer_capi/event.h"
+#include "esplusplayer_capi/latency.h"
+#include "esplusplayer_capi/state.h"
+#include "esplusplayer_capi/stream.h"
+#include "esplusplayer_capi/submitdatatype.h"
+#include "esplusplayer_capi/submitstatus.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+typedef void (*esplusplayer_error_cb)(const esplusplayer_error_type, void*);
+typedef void (*esplusplayer_buffer_status_cb)(const esplusplayer_stream_type,
+                                              const esplusplayer_buffer_status,
+                                              void*);
+typedef void (*esplusplayer_buffer_byte_status_cb)(
+    const esplusplayer_stream_type, const esplusplayer_buffer_status, uint64_t,
+    void*);
+typedef void (*esplusplayer_buffer_time_status_cb)(
+    const esplusplayer_stream_type, const esplusplayer_buffer_status, uint64_t,
+    void*);
+typedef void (*esplusplayer_resource_conflicted_cb)(void*);
+typedef void (*esplusplayer_eos_cb)(void*);
+typedef void (*esplusplayer_ready_to_prepare_cb)(const esplusplayer_stream_type,
+                                                 void*);
+typedef void (*esplusplayer_prepare_async_done_cb)(bool, void*);
+typedef void (*esplusplayer_seek_done_cb)(void*);
+typedef void (*esplusplayer_ready_to_seek_cb)(const esplusplayer_stream_type,
+                                              const uint64_t, void*);
+typedef void (*esplusplayer_media_packet_video_decoded_cb)(
+    const esplusplayer_decoded_video_packet*, void*);
+typedef void (*esplusplayer_closed_caption_cb)(const char* data, const int size,
+                                               void* userdata);
+typedef void (*esplusplayer_flush_done_cb)(void*);
+typedef void (*esplusplayer_event_cb)(const esplusplayer_event_type,
+                                      const esplusplayer_event_msg, void*);
+typedef void (*esplusplayer_video_latency_status_cb)(
+    const esplusplayer_latency_status latency_status, void*);
+typedef void (*esplusplayer_audio_latency_status_cb)(
+    const esplusplayer_latency_status latency_status, void*);
+typedef void (*esplusplayer_video_high_latency_cb)(void*);
+typedef void (*esplusplayer_audio_high_latency_cb)(void*);
+
+typedef void* esplusplayer_handle;
+
+/**
+ * @brief  Enumerations for the Adaptive info type
+ */
+enum esplusplayer_adaptive_info_type {
+  ESPLUSPLAYER_ADAPT_INFO_TYPE_NONE,
+  ESPLUSPLAYER_ADAPT_INFO_TYPE_DROPPED_FRAMES,
+  ESPLUSPLAYER_ADAPT_INFO_TYPE_DROPPED_VIDEO_FRAMES_FOR_CATCHUP,
+  ESPLUSPLAYER_ADAPT_INFO_TYPE_DROPPED_AUDIO_FRAMES_FOR_CATCHUP,
+};
+
+/**
+ * @brief   Enumerations for low latency mode
+ * @version 3.2
+ */
+enum esplusplayer_low_latency_mode {
+  ESPLUSPLAYER_LOW_LATENCY_MODE_NONE = 0x0000,
+  /**
+   * @description   to support audio fast decoding/rendering
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO = 0x0001,
+  /**
+   * @description   to support video fast decoding/rendering
+   *                Video stream should be composed only of P and I frames.
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO = 0x0010,
+  /**
+   * @description   to support video fast decoding/rendering and video
+   *                distortion concealment.
+   *                Video stream should be composed only of P and I frames.
+   *                For applications using the UDP protocol, packet loss can
+   *                occur. when video distortion by video packet loss is
+   *                detected, it is a function to conceal distortion by showing
+   *                previous vido frame. It is supported only in h.264 codec &
+   *                FHD or lower resolution.
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO_DISTORTION_CONCEALMENT =
+      ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO | 0x0020,
+  /**
+   * @description   to support video fast decoding/rendering and video
+   *                with seamless resolution change.
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_SEAMLESS_RESOLUTION_CHANGE = 0x0040,
+  /**
+   * @description   to disable clock sync and a/v sync when rendering. it
+   *                includes #ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_PREROLL.
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC = 0x0100,
+  /**
+   * @description   to disable preroll which means player doesn't wait for
+   *                first buffer when state is changed to
+   *                #ESPLUSPLAYER_STATE_READY from #ESPLUSPLAYER_STATE_IDLE.
+   *                It changes the state immediately.
+   *                It's usually used for sparse stream. (e.g. video packet
+   *                arrives but audio packet does't yet.)
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_PREROLL = 0x0200,
+  /**
+   * @description   to set lower video quality
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_VIDEO_QUALITY = 0x1000,
+  /**
+   * @description   to set game mode
+   *                It must be used exclusively with ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_VIDEO_QUALITY.
+   *                It must use this value with ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO.
+   *                If use this value, It can expect better latency performance than ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_VIDEO_QUALITY.
+   *                It can use enhanced game_mode.
+   */
+  ESPLUSPLAYER_LOW_LATENCY_MODE_ENABLE_GAME_MODE = 0x2000
+};
+
+/**
+ * @brief   Enumerations for esplusplayer audio codec type
+ */
+enum esplusplayer_audio_codec_type {
+  /**
+   * @description   hardware codec can only be selected, default type
+   */
+  ESPLUSPLAYER_AUDIO_CODEC_TYPE_HW,
+  /**
+   * @description   sorfware codec can only be selected
+   */
+  ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW
+};
+
+/**
+ * @brief   Enumerations for esplusplayer video codec type
+ */
+enum esplusplayer_video_codec_type {
+  /**
+   * @description   hardware codec can only be selected, default type
+   */
+  ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW,
+  /**
+   * @description   software codec can only be selected
+   */
+  ESPLUSPLAYER_VIDEO_CODEC_TYPE_SW,
+  /**
+  * @description   hardware codec using n-decoding mode can only be selected.
+                   It must set display type to mixer type by display setting
+  api.
+                   esplusplayer_set_display()
+  */
+  ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW_N_DECODING
+
+};
+/**
+ * @brief   Enumerations for esplusplayer audio easing type
+ * @version 3.0
+ */
+enum esplusplayer_audio_easing_type {
+  /**
+   * @description audio easing function type is linear
+   */
+  ESPLUSPLAYER_AUDIO_EASING_LINEAR,
+  /**
+   * @description audio easing function type is incubic
+   */
+  ESPLUSPLAYER_AUDIO_EASING_INCUBIC,
+  /**
+   * @description audio easing function type is outcubic
+   */
+  ESPLUSPLAYER_AUDIO_EASING_OUTCUBIC,
+  /**
+   * @description audio easing function type is none
+   */
+  ESPLUSPLAYER_AUDIO_EASING_NONE
+};
+
+/**
+ * @brief   Enumerations for esplusplayer resource type
+ * @version 3.0
+ */
+enum esplusplayer_rsc_type {
+  /**
+   * @description video renderer type
+   */
+  ESPLUSPLAYER_RSC_TYPE_VIDEO_RENDERER
+};
+
+/**
+ * @brief   Enumerations for advanced video quality type
+ * @version 3.1
+ */
+enum esplusplayer_advanced_picture_quality_type {
+  /**
+   * @description advanced picture quality for video call
+   */
+  ESPLUSPLAYER_ADVANCED_PICTURE_QUALITY_VIDEO_CALL,
+  /**
+   * @description advanced picture quality for usb camera
+   */
+  ESPLUSPLAYER_ADVANCED_PICTURE_QUALITY_USB_CAMERA
+};
+
+/**
+ * @brief  ESPlusplayer easing target volume, duration, type information
+ * @version 3.0
+ */
+typedef struct {
+  /**
+   * @description   audio easing target volume (0 ~ 100)
+   */
+  unsigned int volume;
+  /**
+   * @description   audio easing duration, in millisecond
+   */
+  unsigned int duration;
+  /**
+   * @description   audio easing function type
+   */
+  esplusplayer_audio_easing_type type;
+} esplusplayer_target_audio_easing_info;
+
+/**
+ * @brief  ESPlusplayer 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;
+} esplusplayer_app_info;
+
+typedef struct {
+  /**
+   * @description   the minimum frame number in case of mid latency
+   */
+  int mid_latency_threshold;
+  /**
+   * @description   the minimum frame number in case of high latency
+   */
+  int high_latency_threshold;
+} esplusplayer_latency_threshold;
+
+/**
+ * @brief  rational number numerator/denominator
+ */
+typedef struct {
+  /**
+   * @description   the numerator value
+   */
+  int num;
+  /**
+   * @description   the denominator value
+   */
+  int den;
+} esplusplayer_rational;
+
+/**
+ * @brief  resource allocate policy
+ */
+enum esplusplayer_rsc_alloc_policy {
+  /**
+   * @description exclusive policy, RM will return the requested resources,
+   * default policy
+   */
+  ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE = 0,
+  /**
+   * @description conditional policy, when trying to allocate resources and
+   * available resources are not left, RM will return fail.
+   */
+  ESPLUSPLAYER_RSC_ALLOC_EXCLUSIVE_CONDITIONAL
+};
+
+/**
+ * @brief     Create a esplusplayer handle.
+ * @param     None
+ * @return    return esplusplayer handle pointer.
+ * @code
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            // ... your codes ...
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       None
+ * @post      The player state will be #ESPLUSPLAYER_STATE_NONE.
+ * @exception None
+ */
+esplusplayer_handle esplusplayer_create();
+
+/**
+ * @brief     Open esplusplayer handle.
+ * @param     [in] handle : esplusplayer handle
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            esplusplayer_open(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       The player state must be #ESPLUSPLAYER_STATE_NONE.
+ * @post      The player state will be #ESPLUSPLAYER_STATE_IDLE.
+ * @exception None
+ * @see       esplusplayer_close()
+ */
+int esplusplayer_open(esplusplayer_handle handle);
+
+/**
+ * @brief     Release all the player resources and all setting except callback
+ *            functions.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @pre       The player state must be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      The player state will be #ESPLUSPLAYER_STATE_NONE.
+ * @exception None
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_close(esplusplayer_handle handle);
+
+/**
+ * @brief     Release player handle.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_create()
+ * @endcode 
+ * @pre       The player state must be #ESPLUSPLAYER_STATE_NONE
+ * @post      player handle will be removed.
+ * @exception None
+ * @see       esplusplayer_create()
+ */
+int esplusplayer_destroy(esplusplayer_handle handle);
+
+/**
+ * @brief     Flush the specific buffered stream data and release TV resource
+ *            to change stream.
+ * @remark    To activate, the stream must be set again.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : stream type which user want to deactivate.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+              refer to the sample code of esplusplayer_activate()
+ * @endcode 
+ * @pre       The player state must be at least #ESPLUSPLAYER_STATE_READY
+ * @post      The player state is same as before calling
+ *            esplusplayer_deactivate(). The deactivated stream will stop
+ *            rendering and release the decorer, renderer resources.
+ * @exception None
+ * @see       esplusplayer_activate
+ */
+int esplusplayer_deactivate(esplusplayer_handle handle,
+                            esplusplayer_stream_type type);
+
+/**
+ * @brief     Reprepare for the specific stream playback.
+ * @remark    There must be active stream to prepare playback.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : stream type which user want to activate.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_deactivate(esplayer, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+ *            esplusplayer_set_video_stream_info* stream;
+ *            stream->width = 640;
+ *            stream->height = 352;
+ *            stream->mime_type = ESPLUSPLAYER_VIDEO_MIME_TYPE_H264;
+ *            stream->framerate_num = 30;
+ *            stream->framerate_den = 1;
+ *            esplusplayer_set_video_stream_info(esplayer, stream);
+ *            esplusplayer_activate(esplayer, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       The player state must be at least #ESPLUSPLAYER_STATE_READY
+ * @post      The player state is same as before calling
+ *            esplusplayer_activate(). Rebuild pipeline to render the stream.
+ * @exception None
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_activate(esplusplayer_handle handle,
+                          esplusplayer_stream_type type);
+
+/**
+ * @brief     Prepare the player for playback, asynchronously.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            static void OnPrepareDone(bool ret, void* userdata) {
+ *                //Something you want to do when prepare done, but, we strongly
+ *                //recommend DO NOT CALL PLAYER APIs in this callbck
+ *                printf("OnPrepareDone\n");
+ *            }
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            esplusplayer_set_prepare_async_done_cb(esplayer, OnPrepareDone,nullptr);
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_prepare_async(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       The player state must be #ESPLUSPLAYER_STATE_IDLE. \n
+ *            Call at least one of esplusplayer_set_video_stream_info() or
+ *            esplusplayer_set_audio_stream_info(). \n
+ * @post      It invokes esplusplayer_prepare_async_done_cb() when prepare is
+ *            finished. \n
+ *            Prepare result can be succeeded or not at this moment. \n
+ *            If the result is succeeded, the player state will be
+ *            #ESPLUSPLAYER_STATE_READY and one frame will be displayed
+ *            unless esplusplayer_set_display_visible() is set to @c false.
+ * @exception None
+ * @remark    esplusplayer_prepare_async_done_cb() can be invoked only when as
+ *            many es packets as at least one decoded frame is submitted. \n
+ *            The player can receive es packets after
+ *            esplusplayer_ready_to_seek_cb() is called.
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_stop() \n
+ *            esplusplayer_submit_packet() \n
+ *            esplusplayer_ready_to_prepare_cb() \n
+ *            esplusplayer_close()
+ */
+int esplusplayer_prepare_async(esplusplayer_handle handle);
+
+/**
+ * @brief     Start playback.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            esplusplayer_start(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state should be #ESPLUSPLAYER_STATE_READY.
+ * @post      The player state will be #ESPLUSPLAYER_STATE_PLAYING.
+ * @exception None
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_prepare_async() \n
+ *            esplusplayer_stop() \n
+ *            esplusplayer_close()
+ */
+int esplusplayer_start(esplusplayer_handle handle);
+
+/**
+ * @brief     Stop playing media content.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ *             // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      The player state will be #ESPLUSPLAYER_STATE_IDLE.
+ * @exception None
+ * @remark    esplusplayer_close() must be called once after player is stopped
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_prepare_async() \n
+ *            esplusplayer_start() \n
+ *            esplusplayer_pause() \n
+ *            esplusplayer_resume() \n
+ *            esplusplayer_close()
+ */
+int esplusplayer_stop(esplusplayer_handle handle);
+
+/**
+ * @brief     Pause playing media content.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_pause(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_READY or
+ *            #ESPLUSPLAYER_STATE_PAUSED or #ESPLUSPLAYER_STATE_PLAYING.
+ * @post      The player state will be #ESPLUSPLAYER_STATE_PAUSE.
+ * @exception None
+ * @see       esplusplayer_start() \n
+ *            esplusplayer_resume() \n
+ *            esplusplayer_prepare_async()
+ */
+int esplusplayer_pause(esplusplayer_handle handle);
+
+/**
+ * @brief     Resume playing media content.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_pause(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_resume(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_PAUSED or
+ *            #ESPLUSPLAYER_STATE_PLAYING.
+ * @post      The player state will be #ESPLUSPLAYER_STATE_PLAYING.
+ * @exception None
+ * @see       esplusplayer_start() \n
+ *            esplusplayer_pause() \n
+ *            esplusplayer_prepare_async()
+ */
+int esplusplayer_resume(esplusplayer_handle handle);
+
+/**
+ * @brief     Set playback rate.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] playback_rate :  the playback rate from 0.0 to 2.0.
+ * @param     [in] audio_mute :  the audio is mute on/off, true: mute on, false:
+ * mute off.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_set_playback_rate(esplayer,2,true);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_READY or
+ *            #ESPLUSPLAYER_STATE_PAUSED or #ESPLUSPLAYER_STATE_PLAYING. \n
+ *            User has to push the data as fast as playback rate.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_set_playback_rate(esplusplayer_handle handle,
+                                   const double playback_rate,
+                                   const bool audio_mute);
+
+/**
+ * @brief     Seek for playback, asynchronously.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] time_ms : seek time in milliseconds
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            const uint64_t ms_to_seek = 0;
+ *            esplusplayer_seek(esplayer,ms_to_seek);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_READY or
+ *            #ESPLUSPLAYER_STATE_PAUSED or #ESPLUSPLAYER_STATE_PLAYING.
+ *            In ESPLUSPLAYER_STATE_IDLE, this api can be called exceptionally
+ *            between esplusplayer_open() and esplusplayer_prepare_async().
+ *            the start time of plyabak can be set explicitly when starting
+ *            first playback. In this case, esplusplayer_set_seek_done_cb is not
+ *            called.
+ * @post      None
+ * @exception None
+ * @remark    esplusplayer_set_seek_done_cb() will be invoked if seek operation
+ *            is finished. \n
+ *            Seek result can be succeeded or not at this moment. \n
+ *            esplusplayer_set_seek_done_cb() can be invoked only when as many
+ *            es packets as at least one decoded frame is submitted. \n
+ *            The player can receive es packets from seek time after
+ *            esplusplayer_ready_to_seek_cb() is invoked.
+ * @see       esplusplayer_ready_to_seek_cb() \n
+ *            esplusplayer_prepare_async()
+ */
+int esplusplayer_seek(esplusplayer_handle handle, uint64_t time_ms);
+
+/**
+ * @brief     Set App id to esplayer to control resource confliction.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] app_info : application id, version, type.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_app_info appinfo;
+ *            appinfo.id = "youtube";
+ *            appinfo.version = "3.0";
+ *            appinfo.type = "MSE";
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_app_info(esplayer,&appinfo);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_app_info(esplusplayer_handle handle,
+                              const esplusplayer_app_info* app_info);
+
+/**
+ * @brief     Set the video display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : display type.
+ * @param     [in] window : the handle to display window.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_display(esplayer,ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,window);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    Esplusplayer is not supporting changing display. \n
+ *            This API have to be called before calling
+ *            esplusplayer_prepare_async() to reflect the display type.
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_set_display_mode() \n
+ *            esplusplayer_set_display_roi() \n
+ *            esplusplayer_set_display_visible()
+ */
+int esplusplayer_set_display(esplusplayer_handle handle,
+                             esplusplayer_display_type type, void* window);
+/**
+ * @brief     Set the video display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : display type.
+ * @param     [in] subsurface : the ecore wayland subsurface handle.
+ * @param     [in] x : the x coordinate of subsurface.
+ * @param     [in] y : the y coordinate of subsurface.
+ * @param     [in] width : the width of subsurface.
+ * @param     [in] height : the height of subsurface.
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @pre       The player state must be #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception   None
+ * @version   3.1
+ * @see       esplusplayer_set_display_mode() \n
+ *            esplusplayer_set_display_roi() \n
+ *            esplusplayer_set_display_visible()
+ */
+int esplusplayer_set_display_ecore_subsurface(esplusplayer_handle handle,
+                                              esplusplayer_display_type type,
+                                              void* subsurface, int x, int y,
+                                              int width, int height);
+/**
+ * @brief     Set the video display mode.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] mode : display mode.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_display_mode(esplayer,ESPLUSPLAYER_DISPLAY_MODE_DST_ROI);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception None
+ * @remark    If no display is set, no operation is performed.
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_set_display_mode() \n
+ *            esplusplayer_set_display_roi() \n
+ *            esplusplayer_set_display_visible()
+ */
+int esplusplayer_set_display_mode(esplusplayer_handle handle,
+                                  esplusplayer_display_mode mode);
+
+/**
+ * @brief     Set the ROI(Region Of Interest) area of display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] x : var startPointX in src video area.
+ * @param     [in] y : var startPointY in src video area.
+ * @param     [in] width : width of display in src video area.
+ * @param     [in] height : height of display in src video area.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_display(esplayer,ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,window);              
+ *            esplusplayer_set_display_mode(esplayer,ESPLUSPLAYER_DISPLAY_MODE_DST_ROI);
+ *            esplusplayer_set_display_roi(esplayer,0,0,600,500);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE. \n
+ *            Before set display ROI, #ESPLUSPLAYER_DISPLAY_MODE_DST_ROI
+ *            must be set with esplusplayer_set_display_mode().
+ * @post      None
+ * @exception None
+ * @remark    The minimum value of width and height are 1.
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_set_display() \n
+ *            esplusplayer_set_display_mode() \n
+ *            esplusplayer_set_display_visible()
+ */
+int esplusplayer_set_display_roi(esplusplayer_handle handle, int x, int y,
+                                 int width, int height);
+
+/**
+ * @brief     Set the Crop Area(Region Of Src ratio) area of display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] scale_x: x label ratio in src video area.
+ * @param     [in] scale_y: y label ratio in src video area.
+ * @param     [in] scale_w: width ratio in src video area.
+ * @param     [in] scale_h: height ratio in src video area.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_display(esplayer,ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,window);
+ *            esplusplayer_set_video_roi(esplayer,0,0,0.5,0.5);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE. \n
+ * @post      None
+ * @exception None
+ * @remark    The minimum value of input are 0,maximun value is 1.
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_set_display() \n
+ *            esplusplayer_set_display_visible()
+ */
+int esplusplayer_set_video_roi(esplusplayer_handle handle, double scale_x,
+                               double scale_y, double scale_w, double scale_h);
+
+/**
+ * @brief     Resize the render rectangle(the max region that video can be
+ * displayed).
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] x: x coordinate of render rectangle.
+ * @param     [in] y: y coordinate of render rectangle.
+ * @param     [in] width: width  of render rectangle.
+ * @param     [in] height: height  of render rectangle.
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @pre       Should be called after esplusplayer_set_display() \n
+ *            esplusplayer_set_surface_display() \n
+ *            esplusplayer_set_ecore_display() \n
+ *            esplusplayer_set_display_ecore_subsurface
+ * @post      None
+ * @exception   None
+ * @version   3.2
+ * @remark    The minimum value of width and height are 1.
+ * @see       esplusplayer_set_display() \n
+ *            esplusplayer_set_surface_display() \n
+ *            esplusplayer_set_ecore_display() \n
+ *            esplusplayer_set_display_ecore_subsurface
+ */
+int esplusplayer_resize_render_rect(esplusplayer_handle handle, int x, int y,
+                                    int width, int height);
+
+/**
+ * @brief     Set the visibility of the video display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] visible : the visibility of the display.
+ *            (@c true = visible, @c false = non-visible)
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_display(esplayer,ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,window);
+ *            esplusplayer_set_display_visible(esplayer,false);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception   None
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_set_display()
+ */
+int esplusplayer_set_display_visible(esplusplayer_handle handle, bool visible);
+
+/**
+ * @brief     Set the rotate angle of the video display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] rotation : the rotate angle of the display.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_display(esplayer,ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,window);
+ *            esplusplayer_set_display_rotation(esplayer_,ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_90);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      this API worked only when video sink created.
+ * @exception None
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_set_display()
+ */
+int esplusplayer_set_display_rotation(
+    esplusplayer_handle handle, esplusplayer_display_rotation_type rotation);
+
+/**
+ * @brief     Get the rotate angle of the video display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [out] rotation : the rotate angle of the display which want to
+ * get.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_display_rotation(esplayer,ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_90);
+ *            esplusplayer_display_rotation_type rotation_get = ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_NONE;
+ *            // ... your codes ...
+ *            esplusplayer_get_display_rotation(esplayer,&rotation_get);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      this API worked only when video sink created.
+ * @exception None
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_set_display_rotation()
+ */
+int esplusplayer_get_display_rotation(
+    esplusplayer_handle handle, esplusplayer_display_rotation_type* rotation);
+
+/**
+ * @deprecated Deprecated since API V2.0. Use
+ *             esplusplayer_set_submit_data_type() instead.
+ * @brief     Set whether to send decrypted es packets in the trust zone.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] using_tz : whether to use trust zone memory.
+ *            (@c true = if decrypted packets are sent in trust zone, @c false =
+ *            otherwise @c)
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_tz_use(esplayer, true);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    This API have to be called before calling
+ *            esplusplayer_prepare_async(). \n If using_tz is set to true, use
+ *            esplusplayer_submit_trust_zone_packet() to send decrypted packets.
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_submit_trust_zone_packet()
+ */
+int esplusplayer_set_tz_use(esplusplayer_handle handle, bool using_tz);
+
+/**
+ * @brief     Set whether to send decrypted es packets in the trust zone or
+ *            encrypted es packets.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : whether to use trust zone memory or encrypted data
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_submit_data_type(esplayer,ESPLUSPLAYER_SUBMIT_DATA_TYPE_CLEAN_DATA);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    This API have to be called before calling
+ *            esplusplayer_prepare_async(). \n
+ *            If type is ESPLUSPLAYER_SUBMIT_DATA_TYPE_CLEAN_DATA use
+ *            esplusplayer_submit_packet() to send clean packets. \n
+ *            If type is ESPLUSPLAYER_SUBMIT_DATA_TYPE_TRUSTZONE_DATA, use
+ *            esplusplayer_submit_trust_zone_packet() to send decrypted packets
+ *            in trust zone \n
+ *            If type is ESPLUSPLAYER_SUBMIT_DATA_TYPE_ENCRYPTED_DATA, use
+ *            esplusplayer_submit_encrypted_packet() to send encrypted packets.
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_submit_trust_zone_packet() \n
+ *            esplusplayer_submit_encrypted_packet() \n
+ *            esplusplayer_submit_data_type
+ */
+int esplusplayer_set_submit_data_type(esplusplayer_handle handle,
+                                      esplusplayer_submit_data_type type);
+
+/**
+ * @brief     Set on mute of the audio sound.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] mute : on mute of the sound.
+ *            (@c true = mute, @c false = non-mute)
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success, otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_audio_mute(esplayer, true);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_audio_mute(esplusplayer_handle handle, bool mute);
+
+/**
+ * @brief     Get current state of player.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    current #esplusplayer_state of player.
+ * @code
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            // ... your codes ...
+ *            esplusplayer_state ret = esplusplayer_get_state(esplayer);
+ *            // ... your codes ...             
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       None
+ * @post      None
+ * @exception None
+ */
+esplusplayer_state esplusplayer_get_state(esplusplayer_handle handle);
+
+/**
+ * @brief     Submit es packet to decode audio or video.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] packet : es packet pointer.
+ * @return    @c ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS : succeed to submit es
+ *            packet,
+ *            otherwise @c : fail to submit es packet.
+ * @code
+ *            static void OnPrepareDone(bool ret, void* userdata) {
+ *                // ... your codes ...
+ *                printf ("OnPrepareDone\n");
+ *            }
+ *            static void OnReadyToPrepare(const esplusplayer_stream_type type,void* userdata) {
+ *                if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {
+ *                    //Something you want to do when feed es video stream is allowed
+ *                } else {
+ *                    //Something you want to do when feed es audio stream is allowed
+ *                }
+ *                //Something you want to do when OnReadyToPrepare
+ *                printf ("OnReadyToPrepare\n");
+ *            }
+ *            static void OnBufferByteStatus(const esplusplayer_stream_type type,
+ *                                           const esplusplayer_buffer_status status,
+ *                                           uint64_t byte_size, void* userdata) {
+ *                if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {
+ *                    if (status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN) {
+ *                        //Something you want to do when es video buffer is enough
+ *                    } else {
+ *                        //Something you want to do when es video buffer is not enough
+ *                    }
+ *                } else {
+ *                    if (status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN) {
+ *                        //Something you want to do when es audio buffer is enough
+ *                    } else {
+ *                        //Something you want to do when es audio buffer is not enough
+ *                    }
+ *                }
+ *                //Something you want to do when OnBufferByteStatus
+ *                printf ("OnBufferByteStatus\n");
+ *            }
+ *            static void OnBufferTimeStatus(const esplusplayer_stream_type type,
+ *                                           const esplusplayer_buffer_status status,
+ *                                           uint64_t time_size,void* userdata) {
+ *                if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {
+ *                    if (status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN) {
+ *                        //Something you want to do when es video buffer is enough
+ *                    } else {
+ *                        //Something you want to do when es video buffer is not enough
+ *                    }
+ *                } else {
+ *                    if (status == ESPLUSPLAYER_BUFFER_STATUS_UNDERRUN) {
+ *                        //Something you want to do when es audio buffer is enough
+ *                    } else {
+ *                        //Something you want to do when es audio buffer is not enough
+ *                    }
+ *                }
+ *                //Something you want to do when OnBufferTimeStatus
+ *                printf ("OnBufferTimeStatus\n");
+ *            }
+ *            void FeedEsPacket(esplusplayer_handle player,esplusplayer_es_packet pkt) {
+ *               // ... your codes ...
+ *              if(feed is allowed && buffer is enough) {
+ *                   esplusplayer_submit_packet(player, &pkt);
+ *               }
+ *               // ... your codes ...
+ *           )
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            esplusplayer_set_prepare_async_done_cb(esplayer,OnPrepareDone,&esplayer);
+ *            esplusplayer_set_ready_to_prepare_cb(esplayer,OnReadyToPrepare,&esplayer);
+ *            esplusplayer_set_buffer_byte_status_cb(esplayer,OnBufferByteStatus,&esplayer);
+ *            esplusplayer_set_buffer_time_status_cb(esplayer,OnBufferTimeStatus,&esplayer);
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_prepare_async(esplayer);
+ *            // ... your codes ...
+ *            //FeedEsPacket()(call a new thread to do this)
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       User can submit es packets after
+ *            esplusplayer_ready_to_prepare_cb() or
+ *            esplusplayer_ready_to_seek_cb() is called.
+ * @post      None
+ * @exception None
+ * @remark    Amount of packets for at least one decoded frame must be submitted
+ *            after calling esplusplayer_prepare_async() or esplusplayer_seek()
+ *            for invoking esplusplayer_prepare_async_done_cb() or
+ *            esplusplayer_seek_done_cb() \n
+ *            This api must be called from a different thread than other apis.
+ * @see       esplusplayer_set_submit_data_type() \n
+ *            esplusplayer_es_packet \n
+ *            esplusplayer_buffer_status_cb() \n
+ *            esplusplayer_ready_to_prepare_cb() \n
+ *            esplusplayer_ready_to_seek_cb()
+ */
+esplusplayer_submit_status esplusplayer_submit_packet(
+    esplusplayer_handle handle, esplusplayer_es_packet* packet);
+
+/**
+ * @brief     Submit es packet to decode audio or video.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] packet : es packet pointer.
+ * @param     [in] tz_handle : es decrypted tz handle.
+ * @return    @c ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS : succeed to submit es
+ *            packet,
+ *            otherwise @c : fail to submit es packet.
+ * @code
+ *            refer to the sample code of esplusplayer_submit_packet();
+ * @endcode 
+ * @pre       User can submit es packets after
+ *            esplusplayer_ready_to_prepare_cb() or
+ *            esplusplayer_ready_to_seek_cb() is called.
+ * @post      None
+ * @exception None
+ * @remark    Amount of packets for at least one decoded frame must be submitted
+ *            after calling esplusplayer_prepare_async() or esplusplayer_seek()
+ *            for invoking esplusplayer_prepare_async_done_cb() or
+ *            esplusplayer_seek_done_cb(). \n
+ *            To use this api, Must set
+ * ESPLUSPLAYER_SUBMIT_DATA_TYPE_TRUSTZONE_DATA using
+ * esplusplayer_set_submit_data_type() \n This api must be called from a
+ * different thread than other apis.
+ * @see       esplusplayer_es_packet \n
+ *            esplusplayer_buffer_status_cb() \n
+ *            esplusplayer_ready_to_prepare_cb() \n
+ *            esplusplayer_ready_to_seek_cb()
+ */
+esplusplayer_submit_status esplusplayer_submit_trust_zone_packet(
+    esplusplayer_handle handle, esplusplayer_es_packet* packet,
+    uint32_t tz_handle);
+
+/**
+ * @brief     Submit encrypted es packet to decode and decrypt audio or video.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] packet : es packet pointer.
+ * @param     [in] drm_info : information to decrypt es packet.
+ *                            esplusplayer doesn't take ownership. user should
+ *                            free it. if you deliver it as (null), this api
+ *                            works as esplusplayer_submit_packet().
+ * @return    @c ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS : succeed to submit es
+ *            packet,
+ *            otherwise @c : fail to submit es packet.
+ * @code
+ *            refer to the sample code of esplusplayer_submit_packet();
+ * @endcode 
+ * @pre       User can submit es packets after
+ *            esplusplayer_ready_to_prepare_cb() or
+ *            esplusplayer_ready_to_seek_cb() is called.
+ * @post      None
+ * @exception None
+ * @remark    Amount of packets for at least one decoded frame must be submitted
+ *            after calling esplusplayer_prepare_async() or esplusplayer_seek()
+ *            for invoking esplusplayer_prepare_async_done_cb() or
+ *            esplusplayer_seek_done_cb(). \n
+ *            To use this api, Must set
+ * ESPLUSPLAYER_SUBMIT_DATA_TYPE_ENCRYPTED_DATA using
+ * esplusplayer_set_submit_data_type() \n This api must be called from a
+ * different thread than other apis.
+ * @see       esplusplayer_es_packet \n
+ *            esplusplayer_drm_info \n
+ *            esplusplayer_buffer_status_cb() \n
+ *            esplusplayer_ready_to_prepare_cb() \n
+ *            esplusplayer_ready_to_seek_cb() \n
+ *            esplusplayer_submit_packet()
+ */
+esplusplayer_submit_status esplusplayer_submit_encrypted_packet(
+    esplusplayer_handle handle, esplusplayer_es_packet* packet,
+    esplusplayer_drm_info* drm_info);
+
+/**
+ * @brief     Generate EOS(End Of Stream) packet explicitly and submit it to the
+ *            player.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : stream type which reaches eos.
+ * @return    @c ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS : succeed to submit EOS
+ * packet,
+ *            otherwise @c : fail to submit EOS packet.
+ * @code
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            // ... your codes ...
+ *            esplusplayer_submit_eos_packet(esplayer,ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+ *            // ... your codes ...
+ * @endcode
+ * @pre       None
+ * @post      None
+ * @exception None
+ */
+esplusplayer_submit_status esplusplayer_submit_eos_packet(
+    esplusplayer_handle handle, esplusplayer_stream_type type);
+
+/**
+ * @brief     Set audio stream to have contents information.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] stream : audio stream pointer.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_audio_stream_info audio_stream;
+ *            audio_stream.codec_data = nullptr;
+ *            audio_stream.codec_data_length = 0;
+ *            esplusplayer_set_audio_stream_info(esplayer, &audio_stream);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE except
+ *            audio stream is deactivated.
+ * @post      None
+ * @exception None
+ * @remark    This API have to be called before calling the
+ *            esplusplayer_prepare_async().
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_audio_stream_info
+ */
+int esplusplayer_set_audio_stream_info(esplusplayer_handle handle,
+                                       esplusplayer_audio_stream_info* stream);
+
+/**
+ * @brief     Set video stream to have contents information.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] stream : video stream pointer.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE except
+ *            video stream is deactivated.
+ * @post      None
+ * @exception None
+ * @remark    This API have to be called before calling the
+ *            esplusplayer_prepare_async().
+ * @see       esplusplayer_audio_stream_info
+ *            esplusplayer_activate
+ */
+int esplusplayer_set_video_stream_info(esplusplayer_handle handle,
+                                       esplusplayer_video_stream_info* stream);
+
+/**
+ * @brief     Get the current playing time of the associated media.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [out] ms : current playing time in milliseconds.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            esplusplayer_start(esplayer);
+ *            // ... your codes ...
+ *            uint64_t cur_time = 0;
+ *            esplusplayer_get_playing_time(esplayer, &cur_time);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player must be one of #ESPLUSPLAYER_STATE_PAUSE or
+ *            #ESPLUSPLAYER_STATE_PLAYING.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_get_playing_time(esplusplayer_handle handle, uint64_t* ms);
+/**
+ * @brief     Get dropped frame counts in videosink.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [out] padaptive_info : dropped frame counts.
+ * @param     [in] adaptive_type : type of adaptive info which APP want to get.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done 
+ *            // ... your codes ...
+ *            uint64_t count = 0;
+ *            esplusplayer_get_adaptive_info(esplayer,
+ *                static_cast<void*>(&count),ESPLUSPLAYER_ADAPT_INFO_TYPE_DROPPED_FRAMES);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player must be one of #ESPLUSPLAYER_STATE_READY,
+ *                   #ESPLUSPLAYER_STATE_PAUSE or #ESPLUSPLAYER_STATE_PLAYING.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_get_adaptive_info(
+    esplusplayer_handle handle, void* padaptive_info,
+    esplusplayer_adaptive_info_type adaptive_type);
+
+/**
+ * @brief     Set volume to player
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] volume : volume level(0 ~ 100).
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer); 
+ *            int vol = 80;
+ *            esplusplayer_set_volume(esplayer, vol)
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be not #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_volume(esplusplayer_handle handle, const int volume);
+
+/**
+ * @brief     Get volume from player
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [out] volume : volume ptr.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            // ... your codes ...
+ *            int vol = 0;
+ *            esplusplayer_get_volume(esplayer, &vol)
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be not #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_get_volume(esplusplayer_handle handle, int* volume);
+
+/**
+ * @brief     Set decoded video frame buffer type.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : one of the video decoded buffer type to set .
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_video_frame_buffer_type(esplayer,
+ *                ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer); 
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE when type
+              is not equal to be
+ ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE
+              The player state must be not #ESPLUSPLAYER_STATE_NONE when
+              type is equal to be
+ ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE
+ * @post      None
+ * @exception None
+ * @remark    reference can't support sw codec type.
+ *            esplusplayer_set_media_packet_video_decoded_cb()
+ *            esplusplayer_set_video_codec_type()
+ *            when type is SCALE, the target scale resolution can be set by
+ *            esplusplayer_set_video_frame_buffer_scale_resolution()
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_video_frame_buffer_type(
+    esplusplayer_handle handle,
+    esplusplayer_decoded_video_frame_buffer_type type);
+
+/**
+ * @brief     Set the request frame rate of decoded video
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] request_framerate : the request frame rate of returned decoded video frame
+ *                 The value of track_framerate(A) and request_framerate(B) 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    @c one of esplusplayer_error_type values will be returned.
+ * @pre       The player state must be not #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception   None
+ * @version   3.3
+ * @remark    only works when decoded video frame buffer type is scale
+ *            esplusplayer_set_video_frame_buffer_type()
+ *            esplusplayer_set_media_packet_video_decoded_cb()
+ */
+int esplusplayer_set_decoded_video_frame_rate(
+    esplusplayer_handle handle, esplusplayer_rational request_framerate);
+
+/**
+ * @brief     Set the target scale resolution when decoded video frame buffer
+ * type is scale
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] target_width : scale target width of video frame buffer.
+ * @param     [in] target_width : scale target height of video frame buffer.
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception   None
+ * @version   3.1
+ * @remark    esplusplayer_set_video_frame_buffer_type()
+ *            esplusplayer_set_media_packet_video_decoded_cb()
+ *            If user don't call this api to set target_width and target_height,
+ * the default
+ *            target scale resolution is 960x540
+ */
+int esplusplayer_set_video_frame_buffer_scale_resolution(
+    esplusplayer_handle handle, uint32_t target_width, uint32_t target_height);
+
+/**
+ * @brief     Flush buffers for a player.
+ * @param     [in] handle : esplusplayer handle ptr.
+ * @param     [in] type : choose which stream data need to be
+ *            flush,audio/video,if need flush all pipeline can call this API
+ * twice.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_flush(esplayer, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state should greater than #ESPLUSPLAYER_STATE_IDLE
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_flush(esplusplayer_handle handle,
+                       esplusplayer_stream_type type);
+
+/**
+ * @brief     Convert the esplusplayer error type to a string.
+ * @param     [in] type : esplusplayer error type
+ * @return    @c not nullptr  the converted error string otherwise @c failed to
+ *            convert the error.
+ * @code
+ *            // ... your codes ...
+ *            const char* error;
+ *            error = esplusplayer_get_error_string(ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FILE);
+ *            // ... your codes ...
+ * @endcode
+ * @pre       None
+ * @post      None
+ * @exception None
+ */
+const char* esplusplayer_get_error_string(esplusplayer_error_type type);
+
+/**
+ * @brief     Sets a callback function to be invoked when an error occurs.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] error_cb : the error callback function to register.
+ * @param     [in] userdata : userdata of esplusplayer_error_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            static void OnError(const esplusplayer_error_type err_code, void*
+ *                userdata) {
+ *                //Something you want to do when error occur
+ *                printf ("OnError\n");
+ *            }
+ *            esplusplayer_handle esplayer = esplusplayer_create();
+ *            esplusplayer_set_error_cb(esplayer, OnError, nullptr);
+ *            // ... your codes ...
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_error_cb() will be invoked.
+ * @exception None
+ * @remark    esplusplayer_error_cb()
+ *            if error_cb is set to null, esplusplayer_error_cb() will not be
+ *            invoked anymore.
+ */
+int esplusplayer_set_error_cb(esplusplayer_handle handle,
+                              esplusplayer_error_cb error_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when buffer underrun or
+ *            overflow is occurred.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] buffer_status_cb : the buffer status callback function to
+ * register.
+ * @param     [in] userdata : userdata of esplusplayer_buffer_status_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_buffer_status_cb() will be invoked.
+ * @exception None
+ * @remark    esplusplayer_buffer_status_cb()
+ *            if buffer_status_cb is set to null, 
+ *            esplusplayer_buffer_status_cb() will not be invoked anymore.
+ */
+int esplusplayer_set_buffer_status_cb(
+    esplusplayer_handle handle, esplusplayer_buffer_status_cb buffer_status_cb,
+    void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when buffer underrun or
+ *            overflow is occurred and buffer size in byte will be passed.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] buffer_status_cb : the buffer byte status callback function
+ *            to register.
+ * @param     [in] userdata : userdata of esplusplayer_buffer_byte_status_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_submit_packet();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_buffer_byte_status_cb() will be invoked.
+ * @exception None
+ * @remark    esplusplayer_buffer_byte_status_cb()
+ */
+int esplusplayer_set_buffer_byte_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_buffer_byte_status_cb buffer_status_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when buffer underrun or
+ *            overflow is occurred and buffer size in time will be passed.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] buffer_status_cb : the buffer time status callback function
+ *            to register.
+ * @param     [in] userdata : userdata of esplusplayer_buffer_time_status_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+              refer to the sample code of esplusplayer_submit_packet();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_buffer_time_status_cb() will be invoked.
+ * @exception None
+ * @remark    esplusplayer_buffer_time_status_cb(),
+ *            esplusplayer_buffer_time_status_cb() will be invoked only
+ *            when the duration value of espacket is set.
+ *            if buffer_status_cb is set to null, 
+ *            esplusplayer_buffer_time_status_cb() will not be invoked anymore.
+ */
+int esplusplayer_set_buffer_time_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_buffer_time_status_cb buffer_status_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when video latency status
+ *            is changed.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] video_high_latency_status_cb : the video high latency status
+ *            callback function to register.
+ * @param     [in] userdata : userdata of
+ *             esplusplayer_set_video_latency_status_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_video_latency_status_cb() will be invoked.
+ * @exception None
+ * @version   3.0
+ * @remark    esplusplayer_video_latency_status_cb() will be invoked only
+ *            when mid / high latency threshold is set.
+ */
+int esplusplayer_set_video_latency_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_video_latency_status_cb video_high_latency_status_cb,
+    void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when audio latency status
+ * is changed.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] audio_high_latency_status_cb : the audio high latency status
+ *            callback function to register.
+ * @param     [in] userdata : userdata of
+ *            esplusplayer_set_audio_latency_status_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_audio_latency_status_cb() will be invoked.
+ * @exception None
+ * @version   3.0
+ * @remark    esplusplayer_audio_latency_status_cb() will be invoked only
+ *            when mid / high latency threshold is set.
+ */
+int esplusplayer_set_audio_latency_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_audio_latency_status_cb audio_high_latency_status_cb,
+    void* userdata);
+
+/**
+ * @brief     Set buffer size with different option
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] option : the option of buffer size.
+ * @param     [in] size : size of selected buffer option.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_buffer_size(esplayer,ESPLUSPLAYER_BUFFER_AUDIO_MAX_BYTE_SIZE,10240)
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    esplusplayer_buffer_option
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_buffer_size(esplusplayer_handle handle,
+                                 esplusplayer_buffer_option option,
+                                 uint64_t size);
+/**
+ * @brief     Set a callback function to be invoked when resource confliction is
+ * occurred.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] resource_conflicted_cb : the resource conflicted callback
+ *            function to register.
+ * @param     [in] userdata : userdata of resource_conflicted_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_resource_conflicted_cb() will be invoked.
+ * @exception None
+ * @remark    esplusplayer_resource_conflicted_cb()
+ *            if resource_conflicted_cb is set to null, 
+ *            esplusplayer_resource_conflicted_cb() will not be invoked
+ *            anymore.
+ */
+int esplusplayer_set_resource_conflicted_cb(
+    esplusplayer_handle handle,
+    esplusplayer_resource_conflicted_cb resource_conflicted_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when player has reached the
+ *            end of stream.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] eos_cb : the eos callback function to register.
+ * @param     [in] userdata : userdata of esplusplayer_eos_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_eos_cb() will be invoked.
+ * @exception None
+ * @remark    esplusplayer_eos_cb()
+ *            if eos_cb is set to null, esplusplayer_eos_cb() will not be
+ *            invoked anymore.
+ */
+int esplusplayer_set_eos_cb(esplusplayer_handle handle,
+                            esplusplayer_eos_cb eos_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when player is prepared to
+ *            receive es packets after calling esplusplayer_prepare_async().
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] ready_to_prepare_cb : the ready to prepare callback function
+ *            to register.
+ * @param     [in] userdata : userdata of ready_to_prepare_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_submit_packet();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    esplusplayer_prepare_async()
+ *            if ready_to_prepare_cb is set to null, 
+ *            esplusplayer_ready_to_prepare_cb() will not be invoked anymore.
+ */
+int esplusplayer_set_ready_to_prepare_cb(
+    esplusplayer_handle handle,
+    esplusplayer_ready_to_prepare_cb ready_to_prepare_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when player is prepared to
+ *            be started.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] prepare_async_done_cb : the repare async done callback
+ * function to register.
+ * @param     [in] userdata : userdata of prepare_async_done_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of plusplayer_prepare_async();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_prepare_async_done_cb() will be invoked.
+ * @exception It is prohibited to call any player APIs at
+ *            esplusplayer_prepare_async_done_cb callback.
+ * @remark    esplusplayer_prepare_async_done_cb()
+ *            if prepare_async_done_cb is set to null, 
+ *            esplusplayer_prepare_async_done_cb() will not be
+ *            invoked anymore.
+ * @see       plusplayer_prepare_async
+ */
+int esplusplayer_set_prepare_async_done_cb(
+    esplusplayer_handle handle,
+    esplusplayer_prepare_async_done_cb prepare_async_done_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when player is prepared to
+ *            be started.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] seek_done_cb : the seek done callback function to register.
+ * @param     [in] userdata : userdata of esplusplayer_seek_done_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_seek_done_cb() will be invoked.
+ *            if seek_done_cb is set to null, esplusplayer_seek_done_cb() will
+ *            not be invoked anymore.
+ * @exception None
+ */
+int esplusplayer_set_seek_done_cb(esplusplayer_handle handle,
+                                  esplusplayer_seek_done_cb seek_done_cb,
+                                  void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when player is prepared to
+ *            receive es packets after flushing all submitted es packets for
+ *            seek.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] ready_to_seek_cb : the ready to seek callback function to
+ *            register.
+ * @param     [in] userdata : userdata of esplusplayer_ready_to_seek_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    esplusplayer_seek()
+ *            if ready_to_seek_cb is set to null, esplusplayer_ready_to_seek_cb()
+ *            will not be invoked anymore.
+ */
+int esplusplayer_set_ready_to_seek_cb(
+    esplusplayer_handle handle, esplusplayer_ready_to_seek_cb ready_to_seek_cb,
+    void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when player decoded video
+ *            frame. A video frame can be retrieved using a registered callback.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] media_packet_video_decoded_cb : the media packet video
+ * decoded callback function to register.
+ * @param     [in] userdata : userdata of
+ * esplusplayer_set_media_packet_video_decoded_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    esplusplayer_set_video_frame_buffer_type()
+ *            if media_packet_video_decoded_cb is set to null,
+ *            esplusplayer_error_cb() will not be invoked anymore.
+ *            media packets have to be released by calling
+ *            esplusplayer_decoded_buffer_destroy().
+ * @see       esplusplayer_set_video_frame_buffer_scale_resolution
+ */
+int esplusplayer_set_media_packet_video_decoded_cb(
+    esplusplayer_handle handle,
+    esplusplayer_media_packet_video_decoded_cb media_packet_video_decoded_cb,
+    void* userdata);
+
+/**
+ * @brief     Set closed caption callback function.
+ * @description   In this function set closed caption callback to handle the
+ *            closed caption. If there is closed caption to display,
+ *            esplusplayer_closed_caption_cb will be called to notify there
+ *            is closed caption to display.
+ * @param     [in] handle : esplusplayer handle ptr.
+ * @param     [in] closed_caption_cb :  the closed caption callback  function to
+ * register.
+ * @param     [in] userdata : userdata of esplusplayer_closed_caption_cb
+ *            callback function.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      When there is closed caption data, call
+ *            esplusplayer_closed_caption_cb to nofity that there is closed
+ *            caption needed to be displayed.
+ * @exception None
+ * @remark    esplusplayer_closed_caption_cb \n
+ *            [in] data : closed caption data \n
+ *            [in] size : length of closed caption data \n
+ *            [in] userdata : userdata of esplusplayer_closed_caption_cb
+ *            callback function.
+ *            if closed_caption_cb is set to null, esplusplayer_closed_caption_cb()
+ *            will not be invoked anymore.
+ */
+int esplusplayer_set_closed_caption_cb(
+    esplusplayer_handle handle,
+    esplusplayer_closed_caption_cb closed_caption_cb, void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when player is flush
+ *            successed.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] flush_done_cb : the flush done callback function to register.
+ * @param     [in] userdata : userdata of esplusplayer_flush_done_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       This api should be called before esplusplayer_flush() is called
+ * @post      esplusplayer_flush_done_cb() will be invoked.
+ * @exception None
+ * @remark    called before esplusplayer_flush().
+ *            if flush_done_cb is set to null, esplusplayer_error_cb() will
+ *            not be invoked anymore.
+ */
+int esplusplayer_set_flush_done_cb(esplusplayer_handle handle,
+                                   esplusplayer_flush_done_cb flush_done_cb,
+                                   void* userdata);
+/**
+ * @brief     Set a callback function to be invoked when a specific event
+ *            occurs.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] event_cb : the callback function to register.
+ * @param     [in] userdata : userdata of esplusplayer_event_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            refer to the sample code of esplusplayer_set_error_cb();
+ * @endcode 
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE
+ *            or #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_event_cb() will be invoked.
+ * @exception None
+ * @remark    esplusplayer_set_event_cb()
+ *            if event_cb is set to null, esplusplayer_event_cb() will not be
+ *            invoked anymore.
+ */
+int esplusplayer_set_event_cb(esplusplayer_handle handle,
+                              esplusplayer_event_cb event_cb, void* userdata);
+/**
+ * @brief     Provided api for destroying decoded buffer.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] packet : the decoded buffer.
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @pre       The player state can be greater than #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_decoded_buffer_destroy will be invoked for video
+ *            texturing
+ * @exception None
+ * @remark    esplusplayer_decoded_buffer_destroy().
+ */
+int esplusplayer_decoded_buffer_destroy(
+    esplusplayer_handle handle, esplusplayer_decoded_video_packet* packet);
+
+/**
+ * @brief     Provided api for setting low latency mode, multiple modes can be
+ *            set to duplicate.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] mode : one of the low latency mode to set.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_low_latency_mode(esplayer,ESPLUSPLAYER_LOW_LATENCY_MODE_NONE);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer); 
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    esplusplayer_set_low_latency_mode().
+ *            if set ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC:
+ *            1, esplusplayer_buffer_status_cb/
+ *            esplusplayer_buffer_byte_status_cb/
+ *            esplusplayer_buffer_time_status_cb/
+ *            esplusplayer_ready_to_prepare_cb/
+ *            esplusplayer_ready_to_seek_cb/esplusplayer_seek_done_cb
+ *            callbacks are not invoked
+ *            2, If es packets are sent after esplusplayer_start() is called,
+ *            it will be played immediately.
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_low_latency_mode(esplusplayer_handle handle,
+                                      esplusplayer_low_latency_mode mode);
+
+/**
+ * @brief     Provided api for enabling video frame peek mode
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_video_frame_peek_mode(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_render_video_frame().
+ */
+int esplusplayer_set_video_frame_peek_mode(esplusplayer_handle handle);
+
+/**
+ * @brief     Provided api for rendering a video frame which is holded by video
+ *            frame peek mode.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_render_video_frame(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       In order to use this api,
+ *            The player state must be one of #ESPLUSPLAYER_STATE_READY or
+ *            #ESPLUSPLAYER_STATE_PAUSED after esplusplayer_seek_done_cb or
+ *            esplusplayer_prepare_async_done_cb is called \n
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_set_video_frame_peek_mode() \n
+ *            esplusplayer_prepare_async()
+ */
+int esplusplayer_render_video_frame(esplusplayer_handle handle);
+
+/**
+ * @brief     Provided api for setting unlimited max buffer mode, the player
+ *            does not limit es packet transmission although in buffer overrun
+ * status
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_unlimited_max_buffer_mode(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @remark    esplusplayer_set_unlimited_max_buffer_mode().
+ *            esplusplayer_buffer_status_cb() will be invoked in
+ *            overrun/underrun buffer status. but
+ * esplusplayer_submit_packet()/esplusplayer_submit_trust_zone_packet()
+ *            /esplusplayer_submit_encrypted_packet()
+ *            does not return ESPLUSPLAYER_SUBMIT_STATUS_FULL
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_submit_packet() \n
+ *            esplusplayer_submit_trust_zone_packet() \n
+ *            esplusplayer_submit_encrypted_packet()
+ */
+int esplusplayer_set_unlimited_max_buffer_mode(esplusplayer_handle handle);
+/**
+ * @brief     Provided api for enabling film maker mode.
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_fmm_mode(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);              
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_fmm_mode(esplusplayer_handle handle);
+/**
+ * @brief     Provided api for setting audio codec type for playback.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : codec type(hardware/software).
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_audio_codec_type(esplayer,ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+              When the audio stream is not set or deactivated, it can be set
+              in #ESPLUSPLAYER_STATE_READY, #ESPLUSPLAYER_STATE_PAUSED and
+              #ESPLUSPLAYER_STATE_PLAYING. The set codec type will be
+              applied when esplusplayer_activate() is called.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_deactivate() \n
+              esplusplayer_activate() \n
+              esplusplayer_set_audio_stream_info()
+ */
+int esplusplayer_set_audio_codec_type(esplusplayer_handle handle,
+                                      esplusplayer_audio_codec_type type);
+/**
+ * @brief     Provided api for setting video codec type for playback.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : codec type(hardware/software).
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_video_codec_type(esplayer,ESPLUSPLAYER_VIDEO_CODEC_TYPE_SW);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+              When the video stream is not set or deactivated, it can be set
+              in #ESPLUSPLAYER_STATE_READY, #ESPLUSPLAYER_STATE_PAUSED and
+              #ESPLUSPLAYER_STATE_PLAYING. The set codec type will be
+              applied when esplusplayer_activate() is called.
+ * @post      None
+ * @exception None
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_deactivate() \n
+              esplusplayer_activate() \n
+              esplusplayer_set_video_stream_info()
+ */
+int esplusplayer_set_video_codec_type(esplusplayer_handle handle,
+                                      esplusplayer_video_codec_type type);
+/**
+ * @brief     Provided api for setting alternative video resource(sub decoder
+ *            and sub scaler)
+ * @param     [in] handle : esplusplayer handle ptr.
+ * @param     [in] rsc_type : set alternative video resource
+ *            (@c 0 [defualt] = set all video resources(decoder/scaler) to main
+ *                              resources,
+ *             @c 1 = set all video resources(decoder/scaler) to sub resources,
+ *             @c 2 = set only decoder to sub resource,
+ *             @c 3 = set only scaler to sub resource)
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_alternative_video_resource(esplayer,1);
+ *             // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #State except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_alternative_video_resource(esplusplayer_handle handle,
+                                                unsigned int rsc_type);
+
+/**
+ * @brief     Provided api for switching audio stream between the different
+ *            audio codec types on the fly
+ * @param     [in] handle : esplusplayer handle ptr.
+ * @param     [in] stream : audio stream pointer
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_audio_stream_info audio_stream;
+ *            audio_stream.mime_type = ESPLUSPLAYER_AUDIO_MIME_TYPE_AC3;
+ *            audio_stream.sample_rate = 48000;
+ *            audio_stream.channels = 2;
+ *            esplusplayer_switch_audio_stream_onthefly(esplayer,
+ *                &audio_stream);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_READY,
+ *            #ESPLUSPLAYER_STATE_PAUSED or #ESPLUSPLAYER_STATE_PLAYING
+ * @post      None
+ * @exception   None
+ * @remark    Audio codec can be switched between only
+ *            #ESPLUSPLAYER_AUDIO_MIME_TYPE_AAC,
+ *            #ESPLUSPLAYER_AUDIO_MIME_TYPE_EAC3
+ *            and #ESPLUSPLAYER_AUDIO_MIME_TYPE_AC3.
+ *            if other codec is set, this api will return false.
+ * @version   3.0
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_switch_audio_stream_onthefly(
+    esplusplayer_handle handle, esplusplayer_audio_stream_info* stream);
+/**
+ * @brief     Provided api for setting aifilter
+ * @param     [in] handle : esplusplayer handle ptr.
+ * @param     [in] aifilter :  aifilter plugin.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            GstElement* aifilter_ =
+ *                gst_element_factory_make("aifilter_autozoom","auto_zoom");
+ *            g_object_set(G_OBJECT(aifilter_), "az_cb_out_fps", 30, NULL);
+ *            g_object_set(G_OBJECT(aifilter_), "az_inference_fps", 2, NULL);
+ *            g_object_set(G_OBJECT(aifilter_), "az_disp_width", 1920, NULL);
+ *            g_object_set(G_OBJECT(aifilter_), "az_disp_height", 1080, NULL);
+ *            g_object_set(G_OBJECT(aifilter_), "az_detection_type", 2, NULL);
+ *            g_object_set(G_OBJECT(aifilter_), "az_scaler_type", 1, NULL);
+ *            g_object_set(G_OBJECT(aifilter_), "az_target_num", 2, NULL);
+ *            esplusplayer_set_aifilter(esplayer,aifilter_);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_aifilter(esplusplayer_handle handle, void* aifilter);
+
+/**
+ * @brief     Provided api for setting render time offset
+ * @param     [in] handle : esplusplayer handle ptr.
+ * @param     [in] type : stream type
+ * @param     [in] offset : offset (milisecond).
+ *                          G_MININT64 <= offset * 1000000 <= G_MAXINT64
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_low_latency_mode(esplayer,ESPLUSPLAYER_LOW_LATENCY_MODE_NONE);
+ *            prepare esplayer 
+ *            // ... your codes ...
+ *            int64_t set_offset = 10;
+ *            esplusplayer_set_render_time_offset(esplayer,ESPLUSPLAYER_STREAM_TYPE_VIDEO,
+ *                                                set_offset);
+ *            int64_t get_offset = 0;
+ *            esplusplayer_get_render_time_offset(esplayer_,ESPLUSPLAYER_STREAM_TYPE_VIDEO,
+ *                                                &get_offset);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_READY,
+ *            #ESPLUSPLAYER_STATE_PAUSED or #ESPLUSPLAYER_STATE_PLAYING.
+ *            It have to be set to low latency mode. (all mode except
+ *            # ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC)
+ * @remark    esplusplayer_set_low_latency_mode().
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_render_time_offset(esplusplayer_handle handle,
+                                        esplusplayer_stream_type type,
+                                        int64_t offset);
+/**
+ * @brief     Provided api for getting render time offset
+ * @param     [in] handle : esplusplayer handle ptr.
+ * @param     [in] type : stream type
+ * @param     [in] offset : offset ptr (milisecond).
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_READY,
+ *            #ESPLUSPLAYER_STATE_PAUSED or #ESPLUSPLAYER_STATE_PLAYING.
+ *            It have to be set to low latency mode.
+ * @remark    esplusplayer_set_low_latency_mode().
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * see        esplusplayer_set_render_time_offset
+ */
+int esplusplayer_get_render_time_offset(esplusplayer_handle handle,
+                                        esplusplayer_stream_type type,
+                                        int64_t* offset);
+/**
+ * @brief     Provided api for setting catch up speed level in low latency mode
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] level : speed level to catch up
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_low_latency_mode(esplayer,ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO);
+ *            esplusplayer_set_catch_up_speed(esplayer,ESPLUSPLAYER_CATCH_UP_SPEED_MID);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_IDLE,
+ *            #ESPLUSPLAYER_STATE_READY, #ESPLUSPLAYER_STATE_PLAYING
+ *            or #ESPLUSPLAYER_STATE_PAUSED
+ *            esplusplayer_set_low_latency_mode() should be called as below
+ *            before this api is called.
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_VIDEO_QUALITY)
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_set_catch_up_speed(esplusplayer_handle handle,
+                                    esplusplayer_catch_up_speed level);
+
+/**
+ * @brief     Provided api for getting current video latency status
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [out] status : current latency status
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_latency_status current_status =
+ *                ESPLUSPLAYER_LATENCY_LOW;
+ *            esplusplayer_get_video_latency_status(esplayer, &current_status);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_READY,
+ *            #ESPLUSPLAYER_STATE_PLAYING or #ESPLUSPLAYER_STATE_PAUSED
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_get_video_latency_status(esplusplayer_handle handle,
+                                          esplusplayer_latency_status* status);
+
+/**
+ * @brief     Provided api for getting current audio latency status
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [out] status : current latency status
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            esplusplayer_latency_status current_status =
+ *                ESPLUSPLAYER_LATENCY_LOW;
+ *            esplusplayer_get_audio_latency_status(esplayer, &current_status);
+ *            // ... your codes ...
+ *            esplusplayer_stop(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_READY,
+ *            #ESPLUSPLAYER_STATE_PLAYING or #ESPLUSPLAYER_STATE_PAUSED
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_prepare_async()
+ */
+int esplusplayer_get_audio_latency_status(esplusplayer_handle handle,
+                                          esplusplayer_latency_status* status);
+
+/**
+ * @brief     Provided api for setting video mid latency threshold for low
+ * latency
+ * playback
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] threshold: the threshold(number) of the video frames for mid
+ * latency.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_low_latency_mode(esplayer,ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO);
+ *            esplusplayer_set_video_mid_latency_threshold(esplayer,2);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_IDLE,
+ *            #ESPLUSPLAYER_STATE_READY, #ESPLUSPLAYER_STATE_PLAYING
+ *            or #ESPLUSPLAYER_STATE_PAUSED
+ *            esplusplayer_set_low_latency_mode() should be called as below
+ *            before this api is called.
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                  ESPLUSPLAYER_LOW_LATENCY_MODE_ENABLE_GAME_MODE)
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+/// TODO:: set the min/max value of the threshold
+int esplusplayer_set_video_mid_latency_threshold(esplusplayer_handle handle,
+                                                 const unsigned int threshold);
+
+/**
+ * @brief     Provided api for setting audio mid latency threshold for low
+ * latency
+ * playback
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] threshold: the threshold(number) of the audio frames for mid
+ * latency.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_low_latency_mode(esplayer,ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO);
+ *            esplusplayer_set_audio_mid_latency_threshold(esplayer,2);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer); 
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_IDLE,
+ *            #ESPLUSPLAYER_STATE_READY, #ESPLUSPLAYER_STATE_PLAYING
+ *            or #ESPLUSPLAYER_STATE_PAUSED
+ *            esplusplayer_set_low_latency_mode() should be called as below
+ *            before this api is called.
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                  ESPLUSPLAYER_LOW_LATENCY_MODE_ENABLE_GAME_MODE)
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+/// TODO:: set the min/max value of the threshold
+int esplusplayer_set_audio_mid_latency_threshold(esplusplayer_handle handle,
+                                                 const unsigned int threshold);
+
+/**
+ * @brief     Provided api for setting video high latency threshold for low
+ * latency
+ * playback
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] threshold: the threshold(number) of the video frames for high
+ * latency.
+ * @param     [in] video_high_latency_cb : high latency callback function to
+ * register
+ * @param     [in] userdata : userdata of esplusplayer_high_latency_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            static void OnVideoHighLatency(void* userdata) {
+ *                printf ("OnVideoHighLatency\n");
+ *            }
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_low_latency_mode(esplayer,ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO);
+ *            esplusplayer_set_video_high_latency_threshold(esplayer, 2,
+ *                OnVideoHighLatency, nullptr);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_IDLE,
+ *            #ESPLUSPLAYER_STATE_READY, #ESPLUSPLAYER_STATE_PLAYING
+ *            or #ESPLUSPLAYER_STATE_PAUSED
+ *            esplusplayer_set_low_latency_mode() should be called as below
+ *            before this api is called.
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                  ESPLUSPLAYER_LOW_LATENCY_MODE_ENABLE_GAME_MODE)
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+/// TODO:: set the min/max value of the threshold
+int esplusplayer_set_video_high_latency_threshold(
+    esplusplayer_handle handle, const unsigned int threshold,
+    esplusplayer_video_high_latency_cb video_high_latency_cb, void* userdata);
+
+/**
+ * @brief     Provided api for setting audio high latency threshold for low
+ * latency
+ * playback
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] threshold: the threshold(number) of the audio frames for high
+ * latency.
+ * @param     [in] audio_high_latency_cb : high latency callback function to
+ * register
+ * @param     [in] userdata : userdata of esplusplayer_high_latency_cb()
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            static void OnAudioHighLatency(void* userdata) {
+ *                printf ("OnAudioHighLatency\n");
+ *            }
+ *            esplusplayer_open(esplayer);
+ *            esplusplayer_set_low_latency_mode(esplayer,ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO);
+ *            esplusplayer_set_audio_high_latency_threshold(esplayer, 2,
+ *                OnAudioHighLatency, nullptr);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer); 
+ * @endcode
+ * @pre       The player state must be one of #ESPLUSPLAYER_STATE_IDLE,
+ *            #ESPLUSPLAYER_STATE_READY, #ESPLUSPLAYER_STATE_PLAYING
+ *            or #ESPLUSPLAYER_STATE_PAUSED
+ *            esplusplayer_set_low_latency_mode() should be called as below
+ *            before this api is called.
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_AUDIO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_VIDEO),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC),
+ *            esplusplayer_set_low_latency_mode(handle,
+ *                ESPLUSPLAYER_LOW_LATENCY_MODE_ENABLE_GAME_MODE)
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+/// TODO:: set the min/max value of the threshold
+int esplusplayer_set_audio_high_latency_threshold(
+    esplusplayer_handle handle, const unsigned int threshold,
+    esplusplayer_audio_high_latency_cb audio_high_latency_cb, void* userdata);
+
+/**
+ * @brief     Initialize easing info to esplayer.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] init_volume : initial easing volume (0 ~ 100).
+ * @param     [in] elapsed_time : initial elapsed time (millisecond).
+ * @param     [in] easing_info : target volume, duration, type.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            uint32_t volume = 50, elapsed_time = 10000;
+ *            esplusplayer_target_audio_easing_info easing_info;
+ *            easing_info.volume = 30;
+ *            easing_info.duration = 100;
+ *            easing_info.type = ESPLUSPLAYER_AUDIO_EASING_INCUBIC;
+ *            esplusplayer_init_audio_easing_info(esplayer,volume,elapsed_time,&easing_info);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer); 
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_init_audio_easing_info(
+    esplusplayer_handle handle, uint32_t init_volume, uint32_t elapsed_time,
+    const esplusplayer_target_audio_easing_info* easing_info);
+
+/**
+ * @brief     Update easing info to esplayer to update target info.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] easing_info : target volume, duration, type.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_target_audio_easing_info easing_info;
+ *            easing_info.volume = 30;
+ *            easing_info.duration = 100;
+ *            easing_info.type = ESPLUSPLAYER_AUDIO_EASING_INCUBIC;
+ *            esplusplayer_update_audio_easing_info(esplayer,&easing_info);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ *            This api should be called after
+ *            esplusplayer_init_audio_easing_info() is called
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+ */
+int esplusplayer_update_audio_easing_info(
+    esplusplayer_handle handle,
+    const esplusplayer_target_audio_easing_info* easing_info);
+
+/**
+ * @brief     Get easing info currently in easing operation from esplayer
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [out] current_volume : current volume (0 ~ 100).
+ * @param     [out] elapsed_time : elapsed time (millisecond).
+ * @param     [out] easing_info : target volume, duration, type.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            // ... your codes ...
+ *            uint32_t cur_volume = 50, elapsed_time = 0;
+ *            esplusplayer_target_audio_easing_info easing_info;
+ *            esplusplayer_get_audio_easing_info(esplayer,&cur_volume,&elapsed_time,&easing_info);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ *            This api should be called after
+ *            esplusplayer_init_audio_easing_info() is called
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open()
+
+ */
+int esplusplayer_get_audio_easing_info(
+    esplusplayer_handle handle, uint32_t* current_volume,
+    uint32_t* elapsed_time, esplusplayer_target_audio_easing_info* easing_info);
+
+/**
+ * @brief     Start audio easing using a registered audio easing info
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            uint32_t volume = 50, elapsed_time = 10000;
+ *            esplusplayer_target_audio_easing_info easing_info;
+ *            easing_info.volume = 30;
+ *            easing_info.duration = 100;
+ *            easing_info.type = ESPLUSPLAYER_AUDIO_EASING_INCUBIC;
+ *            esplusplayer_init_audio_easing_info(esplayer,volume,elapsed_time,&easing_info);                    
+ *            esplusplayer_start_audio_easing(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state should be at least #ESPLUSPLAYER_STATE_READY.
+ *            This api should be called after
+ *            esplusplayer_init_audio_easing_info() is called
+ * @post      None
+ * @exception None
+ * @version   3.0
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_init_audio_easing_info() \n
+ *            esplusplayer_update_audio_easing_info() \n
+ *            esplusplayer_stop_audio_easing() \n
+ *            esplusplayer_prepare_async()
+ */
+int esplusplayer_start_audio_easing(esplusplayer_handle handle);
+
+/**
+ * @brief     Stop audio easing
+ * @param     [in] handle : esplusplayer handle.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            esplusplayer_open(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_stop_audio_easing(esplayer);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ * @endcode
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ *            This api should be called after
+ *            esplusplayer_init_audio_easing_info() is called
+ * @post      None
+ * @exception   None
+ * @version   3.0
+ * @see       esplusplayer_open() \n
+ *            esplusplayer_start_audio_easing()
+ */
+int esplusplayer_stop_audio_easing(esplusplayer_handle handle);
+
+/**
+ * @brief     Get virtual resource id
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : The resource type of virtual id.
+ * @param     [out] virtual_id : Stored virtual resource id value.
+ * @return    @c ESPLUSPLAYER_ERROR_TYPE_NONE on success,otherwise @c one of esplusplayer_error_type
+ *            values will be returned.
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_NONE Successful
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER Invalid parameter
+ * @retval    #ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION Internal operation failed
+ * @code
+ *            prepare esplayer done
+ *            // ... your codes ...
+ *            int virtual_id;
+ *            esplusplayer_get_virtual_rsc_id(esplayer,ESPLUSPLAYER_RSC_TYPE_VIDEO_RENDERER,&virtual_id);
+ *            // ... your codes ...
+ *            esplusplayer_close(esplayer);
+ *            esplusplayer_destroy(esplayer);
+ * @endcode
+ * @pre       The player state should be #State::kReady, #State::kPlaying or
+ *            #State::kPaused
+ * @post      None
+ * @return    @c True on success, otherwise @c False ("virtual_id" will be -1)
+ * @exception None
+ * @version   3.0
+ * @remark    This function returns virtual resource id which player is
+ *            allocated from resource manager. For example, virtual scaler id is
+ *            required for an application to use capture API directly.
+ * @see       esplusplayer_prepare_async()
+
+ */
+int esplusplayer_get_virtual_rsc_id(esplusplayer_handle handle,
+                                    const esplusplayer_rsc_type type,
+                                    int* virtual_id);
+
+/**
+ * @brief     Set advanced picture quality type.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : The picture quality type.
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @exception  None
+ * @version   3.1
+ */
+int esplusplayer_set_advanced_picture_quality_type(
+    esplusplayer_handle handle,
+    esplusplayer_advanced_picture_quality_type type);
+
+/**
+ * @brief     Set resource allocate policy.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] policy : The resource allocate policy.
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_IDLE.
+ * @post      None
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @exception  None
+ * @version   3.2
+ */
+int esplusplayer_set_resource_allocate_policy(
+    esplusplayer_handle handle, esplusplayer_rsc_alloc_policy policy);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_ESPLUSPLAYER_CAPI_H__
diff --git a/include/esplusplayer_capi/esplusplayer_internal.h b/include/esplusplayer_capi/esplusplayer_internal.h
new file mode 100755 (executable)
index 0000000..a50d4ae
--- /dev/null
@@ -0,0 +1,174 @@
+/**
+ * @file           esplusplayer_internal.h
+ * @brief          EsPlusPlayer internally used api c version
+ * @interfacetype  module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @remark         This is esplusplayer api header implemented as C style to
+ *                 avoid binary compatibility issues.
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_ESPLUSPLAYER_INTERNAL_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_ESPLUSPLAYER_INTERNAL_H__
+
+#include "esplusplayer_capi/display.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+typedef void (*esplusplayer_decoder_underrun_cb)(void* userdata);
+typedef void* esplusplayer_handle;
+typedef void (*esplusplayer_first_video_decoding_done_cb)(void*);
+
+/**
+ * @brief     Set the video display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : display type.
+ * @param     [in] window : the ecore wayland window handle.
+ * @param     [in] x : the x coordinate of window.
+ * @param     [in] y : the ycoordinate of window.
+ * @param     [in] width : the width of window.
+ * @param     [in] height : the height of window.
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception   None
+ * @see       esplusplayer_set_display_mode() \n
+ *            esplusplayer_set_display_roi() \n
+ *            esplusplayer_set_display_visible()
+ */
+int esplusplayer_set_ecore_display(esplusplayer_handle handle,
+                                   esplusplayer_display_type type, void* window,
+                                   int x, int y, int width, int height);
+/**
+ * @brief     Set the video display.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] type : display type.
+ * @param     [in] surface_id : resource id of window.
+ * @param     [in] x : the x coordinate of window.
+ * @param     [in] y : the ycoordinate of window.
+ * @param     [in] width : the width of window.
+ * @param     [in] height : the height of window.
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @pre       The player state can be all of #esplusplayer_state except
+ *            #ESPLUSPLAYER_STATE_NONE.
+ * @post      None
+ * @exception   None
+ * @see       esplusplayer_set_display_mode() \n
+ *            esplusplayer_set_display_roi() \n
+ *            esplusplayer_set_display_visible()
+ */
+int esplusplayer_set_surface_display(esplusplayer_handle handle,
+                                     esplusplayer_display_type type,
+                                     unsigned int surface_id, int x, int y,
+                                     int width, int height);
+
+int esplusplayer_set_first_video_decoding_done_cb(
+    esplusplayer_handle handle,
+    esplusplayer_first_video_decoding_done_cb first_video_decoding_done_cb,
+    void* userdata);
+
+/**
+ * @brief     Set a callback function to be invoked when buffer underrun is
+ *            occurred from a video decoder.
+ * @param     [in] handle : esplusplayer handle.
+ * @param     [in] callback : the callback function to register.
+ * @param     [in] userdata : userdata of esplusplayer_decoder_underrun_cb()
+ * @return    @c one of esplusplayer_error_type values will be returned.
+ * @pre       The player state must be set to #ESPLUSPLAYER_STATE_NONE or
+ *            #ESPLUSPLAYER_STATE_IDLE.
+ * @post      esplusplayer_decoder_underrun_cb() will be invoked.
+ * @exception   None
+ * @remark    esplusplayer_decoder_underrun_cb().
+ *            if video_decoder_underrun_cb is set to null,
+ *            esplusplayer_decoder_underrun_cb() will not be invoked anymore.
+ */
+int esplusplayer_set_video_decoder_underrun_cb(
+    esplusplayer_handle handle,
+    esplusplayer_decoder_underrun_cb video_decoder_underrun_cb, void* userdata);
+
+/**
+ * @brief     Get the size of struct esplusplayer_app_info
+ * @param     None
+ * @return    Total size of struct esplusplayer_app_info
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+int get_size_of_esplusplayer_app_info(void);
+
+/**
+ * @brief     Get the size of struct esplusplayer_es_packet
+ * @param     None
+ * @return    Total size of struct esplusplayer_es_packet
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+int get_size_of_esplusplayer_es_packet(void);
+
+/**
+ * @brief     Get the size of struct esplusplayer_es_tz_packet
+ * @param     None
+ * @return    Total size of struct esplusplayer_es_tz_packet
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+int get_size_of_esplusplayer_es_tz_packet(void);
+
+/**
+ * @brief     Get the size of struct esplusplayer_audio_stream_info
+ * @param     None
+ * @return    Total size of struct esplusplayer_audio_stream_info
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+int get_size_of_esplusplayer_audio_stream_info(void);
+
+/**
+ * @brief     Get the size of struct esplusplayer_video_stream_info
+ * @param     None
+ * @return    Total size of struct esplusplayer_video_stream_info
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+int get_size_of_esplusplayer_video_stream_info(void);
+
+/**
+ * @brief     Get the size of struct esplusplayer_drm_info
+ * @param     None
+ * @return    Total size of struct esplusplayer_drm_info
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+int get_size_of_esplusplayer_drm_info(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_ESPLUSPLAYER_INTERNAL_H__
diff --git a/include/esplusplayer_capi/event.h b/include/esplusplayer_capi/event.h
new file mode 100755 (executable)
index 0000000..3278991
--- /dev/null
@@ -0,0 +1,63 @@
+/**\r
+ * @file\r
+ * @brief          The event for playback.\r
+ * @interfacetype  Platform\r
+ * @privlevel      None-privilege\r
+ * @privilege      None\r
+ * @product        TV, AV, B2B\r
+ * @version        2.0\r
+ * @SDK_Support    N\r
+ * @remark         This is a group of C style event related enum and structure.\r
+ * @see            N/A\r
+ *\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved\r
+ * PROPRIETARY/CONFIDENTIAL\r
+ * This software is the confidential and proprietary\r
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall\r
+ * not disclose such Confidential Information and shall use it only in\r
+ * accordance with the terms of the license agreement you entered into with\r
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the\r
+ * suitability of the software, either express or implied, including but not\r
+ * limited to the implied warranties of merchantability, fitness for a\r
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any\r
+ * damages suffered by licensee as a result of using, modifying or distributing\r
+ * this software or its derivatives.\r
+ */\r
+\r
+#ifndef __PLUSPLAYER_ESPLUSPLAYER_CAPI_EVENT_H__\r
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_EVENT_H__\r
+\r
+#include <cstdint>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * @brief Event message\r
+ */\r
+typedef struct {\r
+  /**\r
+   * @description event message data\r
+   *              eg) ESPLUSPLAYER_EVENT_RESOLUTION_CHANGED : "1920x1080"\r
+   */\r
+  char* data;\r
+  /**\r
+   * @description the length of event message data\r
+   */\r
+  uint64_t len;\r
+} esplusplayer_event_msg;\r
+\r
+/**\r
+ * @brief Enumerations for event message types\r
+ */\r
+enum esplusplayer_event_type {\r
+  ESPLUSPLAYER_EVENT_NONE,\r
+  ESPLUSPLAYER_EVENT_RESOLUTION_CHANGED,\r
+};\r
+\r
+#ifdef __cplusplus\r
+}  // extern "C"\r
+#endif\r
+\r
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_EVENT_H__\r
diff --git a/include/esplusplayer_capi/latency.h b/include/esplusplayer_capi/latency.h
new file mode 100755 (executable)
index 0000000..7548a6f
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * @file
+ * @brief          Latency enum.
+ * @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 state related enum.
+ * @see            State enum convertion.
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_LATENCY_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_LATENCY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @brief   Enumerations for esplusplayer catch up speed 
+ */
+enum esplusplayer_catch_up_speed {
+  ESPLUSPLAYER_CATCH_UP_SPEED_NONE, /**< do not use catch up mode */
+  ESPLUSPLAYER_CATCH_UP_SPEED_SLOW, /**< catch up speed is slow */
+  ESPLUSPLAYER_CATCH_UP_SPEED_MID,  /**< catch up speed is normal */
+  ESPLUSPLAYER_CATCH_UP_SPEED_FAST  /**< catch up speed is fast */
+};
+
+/**
+ * @brief   Enumerations for esplusplayer latency status
+ */
+enum esplusplayer_latency_status {
+  ESPLUSPLAYER_LATENCY_LOW, /**< latency status is low */
+  ESPLUSPLAYER_LATENCY_MID, /**< latency status is middle */
+  ESPLUSPLAYER_LATENCY_HIGH  /**< latency status is high */
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_LATENCY_H__
diff --git a/include/esplusplayer_capi/matroska_color.h b/include/esplusplayer_capi/matroska_color.h
new file mode 100755 (executable)
index 0000000..4b9b828
--- /dev/null
@@ -0,0 +1,170 @@
+/**\r
+ * @file\r
+ * @brief          The matroska color info\r
+ * @interfacetype  Platform\r
+ * @privlevel      None-privilege\r
+ * @privilege      None\r
+ * @product        TV, AV, B2B\r
+ * @version        2.0\r
+ * @SDK_Support    N\r
+ * @see            plusplayer::EsPlusPlayer class\r
+ *\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved\r
+ * PROPRIETARY/CONFIDENTIAL\r
+ * This software is the confidential and proprietary\r
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall\r
+ * not disclose such Confidential Information and shall use it only in\r
+ * accordance with the terms of the license agreement you entered into with\r
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the\r
+ * suitability of the software, either express or implied, including but not\r
+ * limited to the implied warranties of merchantability, fitness for a\r
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any\r
+ * damages suffered by licensee as a result of using, modifying or distributing\r
+ * this software or its derivatives.\r
+ */\r
+\r
+#ifndef __PLUSPLAYER_ESPLUSPLAYER_CAPI_MATROSKA_COLOR_H__\r
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_MATROSKA_COLOR_H__\r
+\r
+#include <cstdint>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * @brief   Structure of matroska matering metadata\r
+ */\r
+typedef struct {\r
+  /**\r
+   * @description    Red X chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double primary_r_chromaticity_x;\r
+  /**\r
+   * @description    Red Y chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double primary_r_chromaticity_y;\r
+  /**\r
+   * @description    Green X chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double primary_g_chromaticity_x;\r
+  /**\r
+   * @description    Green Y chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double primary_g_chromaticity_y;\r
+  /**\r
+   * @description    Blue X chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double primary_b_chromaticity_x;\r
+  /**\r
+   * @description    Blue Y chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double primary_b_chromaticity_y;\r
+  /**\r
+   * @description    White X chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double white_point_chromaticity_x;\r
+  /**\r
+   * @description    White Y chromaticity coordinate as defined by CIE 1931.\r
+   */\r
+  double white_point_chromaticity_y;\r
+  /**\r
+   * @description    Maximum luminance. Represented in candelas per square meter\r
+   * (cd/m²).\r
+   */\r
+  double luminance_max;\r
+  /**\r
+   * @description    Mininum luminance. Represented in candelas per square meter\r
+   * (cd/m²).\r
+   */\r
+  double luminance_min;\r
+} esplusplayer_matroska_mastering_metadata;\r
+\r
+/**\r
+ * @brief   Structure of matroska color information\r
+ */\r
+typedef struct {\r
+  /**\r
+   * @description   The Matrix Coefficients of the video used to derive luma and\r
+   * chroma values from red, green, and blue color primaries. For clarity, the\r
+   * value and meanings for MatrixCoefficients are adopted from Table 4 of\r
+   * ISO/IEC 23001-8:2013/DCOR1.\r
+   */\r
+  uint32_t matrix_coefficients;\r
+  /**\r
+   * @description   Number of decoded bits per channel. A value of 0 indicates\r
+   * that the BitsPerChannel is unspecified.\r
+   */\r
+  uint32_t bits_per_channel;\r
+  /**\r
+   * @description   The amount of pixels to remove in the Cr and Cb channels for\r
+   * every pixel not removed horizontally.\r
+   */\r
+  uint32_t chroma_subsampling_horizontal;\r
+  /**\r
+   * @description   The amount of pixels to remove in the Cr and Cb channels for\r
+   * every pixel not removed vertically.\r
+   */\r
+  uint32_t chroma_subsampling_vertical;\r
+  /**\r
+   * @description    The amount of pixels to remove in the Cb channel for every\r
+   * pixel not removed horizontally. This is additive with\r
+   * chroma_subsampling_horizontal.\r
+   */\r
+  uint32_t cb_subsampling_horizontal;\r
+  /**\r
+   * @description    The amount of pixels to remove in the Cb channel for every\r
+   * pixel not removed vertically. This is additive with\r
+   * chroma_subsampling_vertical.\r
+   */\r
+  uint32_t cb_subsampling_vertical;\r
+  /**\r
+   * @description    How chroma is subsampled horizontally.\r
+   */\r
+  uint32_t chroma_siting_horizontal;\r
+  /**\r
+   * @description    How chroma is subsampled vertically.\r
+   */\r
+  uint32_t chroma_siting_vertical;\r
+  /**\r
+   * @description    Clipping of the color ranges.\r
+   */\r
+  uint32_t range;\r
+  /**\r
+   * @description    The transfer characteristics of the video. For clarity, the\r
+   * value and meanings for transfer_characteristics 1-15 are adopted from Table\r
+   * 3 of ISO/IEC 23001-8:2013/DCOR1. transfer_characteristics 16-18 are\r
+   * proposed values.\r
+   */\r
+  uint32_t transfer_characteristics;\r
+  /**\r
+   * @description    The colour primaries of the video. For clarity, the value\r
+   * and meanings for primaries are adopted from Table 2 of ISO/IEC\r
+   * 23001-8:2013/DCOR1.\r
+   */\r
+  uint32_t primaries;\r
+  /**\r
+   * @description    Maximum brightness of a single pixel (Maximum Content Light\r
+   * Level) in candelas per square meter (cd/m²).\r
+   */\r
+  uint32_t max_cll;\r
+  /**\r
+   * @description    Maximum brightness of a single full frame (Maximum\r
+   * Frame-Average Light Level) in candelas per square meter (cd/m²).\r
+   */\r
+  uint32_t max_fall;\r
+  /**\r
+   * @description    SMPTE 2086 mastering data.\r
+   */\r
+  esplusplayer_matroska_mastering_metadata metadata;\r
+  /**\r
+   * @description    flag to check if this file is hdr10+ (cd/m²).\r
+   */\r
+  uint32_t isHDR10p;\r
+} esplusplayer_matroska_color;\r
+\r
+#ifdef __cplusplus\r
+}  // extern "C"\r
+#endif\r
+\r
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_MATROSKA_COLOR_H__\r
diff --git a/include/esplusplayer_capi/state.h b/include/esplusplayer_capi/state.h
new file mode 100755 (executable)
index 0000000..95048d7
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * @file
+ * @brief          State enum.
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style state related enum.
+ * @see            State enum convertion.
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_STATE_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_STATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for es player state.
+ */
+enum esplusplayer_state {
+  ESPLUSPLAYER_STATE_NONE,  /**<Player is created, but not opened*/
+  ESPLUSPLAYER_STATE_IDLE,  /**<Player is opened, but not prepared or player is
+                               stopped*/
+  ESPLUSPLAYER_STATE_READY, /**<Player is ready to play(start)*/
+  ESPLUSPLAYER_STATE_PLAYING, /**<Player is playing media*/
+  ESPLUSPLAYER_STATE_PAUSED,    /**<Player is playing media*/
+  ESPLUSPLAYER_STATE_MAX
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_STATE_H__
diff --git a/include/esplusplayer_capi/stream.h b/include/esplusplayer_capi/stream.h
new file mode 100755 (executable)
index 0000000..9659811
--- /dev/null
@@ -0,0 +1,166 @@
+/**
+ * @file
+ * @brief          Stream info related data structures and enums
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.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) 2020 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_ESPLUSPLAYER_CAPI_TRACK_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_TRACK_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the stream type
+ */
+enum esplusplayer_stream_type {
+  ESPLUSPLAYER_STREAM_TYPE_AUDIO,
+  ESPLUSPLAYER_STREAM_TYPE_VIDEO,
+  ESPLUSPLAYER_STREAM_TYPE_MAX
+};
+
+/**
+ * @brief   Enumerations for audio mime type
+ */
+enum esplusplayer_audio_mime_type {
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_UNKNOWN,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_AAC,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_MP2,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_MP3,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_AC3,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_EAC3,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_VORBIS,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_OPUS,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_S16LE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_S16BE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_U16LE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_U16BE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_S24LE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_S24BE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_U24LE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_U24BE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_S32LE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_S32BE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_U32LE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_PCM_U32BE,
+  ESPLUSPLAYER_AUDIO_MIME_TYPE_G711_MULAW
+};
+
+/**
+ * @brief   Enumerations for video mime type
+ */
+enum esplusplayer_video_mime_type {
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_UNKNOWN,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_H263,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_H264,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_HEVC,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_MPEG1,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_MPEG2,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_MPEG4,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_VP8,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_VP9,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_WMV3,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_AV1,
+  ESPLUSPLAYER_VIDEO_MIME_TYPE_MJPEG
+};
+
+/**
+ * @brief   Audio stream information structure
+ */
+typedef struct {
+  /**
+   * @description   The audio codec data pointer.
+   */
+  char* codec_data;
+  /**
+   * @description   The audio codec data length.
+   */
+  uint32_t codec_data_length;
+  /**
+   * @description   The audio mime type.
+   */
+  esplusplayer_audio_mime_type mime_type;
+  /**
+   * @description   The audio bitrate value.
+   */
+  uint32_t bitrate;
+  /**
+   * @description   The audio channel number.
+   */
+  uint32_t channels;
+  /**
+   * @description   The audio sample rate value.
+   */
+  uint32_t sample_rate;
+} esplusplayer_audio_stream_info;
+
+/**
+ * @brief   Video stream information structure
+ */
+typedef struct {
+  /**
+   * @description   The video codec data pointer.
+   */
+  char* codec_data;
+  /**
+   * @description   The video codec data length.
+   */
+  uint32_t codec_data_length;
+  /**
+   * @description   The video mime type.
+   */
+  esplusplayer_video_mime_type mime_type;
+  /**
+   * @description   The width value of the video.
+   */
+  uint32_t width;
+  /**
+   * @description   The height value of the video.
+   */
+  uint32_t height;
+  /**
+   * @description   The max width value of the video.
+   */
+  uint32_t max_width;
+  /**
+   * @description   The max height value of the video.
+   */
+  uint32_t max_height;
+  /**
+   * @description   The numerator value of the video frame rate.
+   */
+  uint32_t framerate_num;
+  /**
+   * @description   The denominator value of the video frame rate.
+   */
+  uint32_t framerate_den;
+} esplusplayer_video_stream_info;
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_TRACK_H__
diff --git a/include/esplusplayer_capi/submitdatatype.h b/include/esplusplayer_capi/submitdatatype.h
new file mode 100755 (executable)
index 0000000..1f563e2
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * @file
+ * @brief          For submit data type enum.
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style submitstatus related enum.
+ * @see            SubmitDataType enum conversion.
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_SUBMITDATATYPE_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_SUBMITDATATYPE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the type of buffers submitted
+ */
+enum esplusplayer_submit_data_type {
+  ESPLUSPLAYER_SUBMIT_DATA_TYPE_CLEAN_DATA,
+  ESPLUSPLAYER_SUBMIT_DATA_TYPE_ENCRYPTED_DATA,
+  ESPLUSPLAYER_SUBMIT_DATA_TYPE_TRUSTZONE_DATA,
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_SUBMITDATATYPE_H__
diff --git a/include/esplusplayer_capi/submitstatus.h b/include/esplusplayer_capi/submitstatus.h
new file mode 100755 (executable)
index 0000000..7636f5b
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * @file
+ * @brief          For submitstatus enum.
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        2.0
+ * @SDK_Support    N
+ * @remark         This is a group of C style submitstatus related enum.
+ * @see            Submitstatus enum convertion.
+ *
+ * Copyright (c) 2020 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_ESPLUSPLAYER_CAPI_SUBMITSTATUS_H__
+#define __PLUSPLAYER_ESPLUSPLAYER_CAPI_SUBMITSTATUS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the buffer status
+ */
+enum esplusplayer_submit_status {
+  ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED,
+  ESPLUSPLAYER_SUBMIT_STATUS_INVALID_PACKET,
+  ESPLUSPLAYER_SUBMIT_STATUS_OUT_OF_MEMORY,
+  ESPLUSPLAYER_SUBMIT_STATUS_FULL,
+  ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER_CAPI_SUBMITSTATUS_H__
diff --git a/include/mixer/decodedvideoinfo.h b/include/mixer/decodedvideoinfo.h
new file mode 100755 (executable)
index 0000000..f1a5ab0
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * @file           decodedvideoinfo.h
+ * @brief          Information for decoded video frames
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * Copyright (c) 2020 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_MIXER_DECODED_VIDEO_INFO_H__
+#define __PLUSPLAYER_MIXER_DECODED_VIDEO_INFO_H__
+
+#include <tbm_type_common.h>
+
+#include <cstdint>
+
+namespace plusplayer {
+
+struct DecodedRawPlaneInfo {
+  std::uint32_t phyaddr;
+  std::uint32_t viraddr;
+  std::uint32_t linesize;
+};
+
+struct DecodedRawInfo {
+  std::uint32_t width;
+  std::uint32_t height;
+  DecodedRawPlaneInfo y_info;
+  DecodedRawPlaneInfo uv_info;
+};
+
+struct DecodedVideoKeyTypeInfo {
+  std::uint32_t width;
+  std::uint32_t height;
+  tbm_key key;
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_DECODED_VIDEO_INFO_H__
diff --git a/include/mixer/mixer.h b/include/mixer/mixer.h
new file mode 100755 (executable)
index 0000000..892c78a
--- /dev/null
@@ -0,0 +1,271 @@
+/**
+ * @file           mixer.h
+ * @brief          Mixes raw video frame and rendering mixed frame
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * Copyright (c) 2020 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_MIXER_MIXER__H__
+#define __PLUSPLAYER_MIXER_MIXER__H__
+
+#include <boost/core/noncopyable.hpp>
+#include <memory>
+
+#include "mixer/mixer_eventlistener.h"
+#include "mixer/mixerticket.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+/**
+ * @brief Enumerations for Resource allocation policy
+ */
+enum class RscAllocMode {
+  kDefault,  /**< Main -> Sub -> S/W */
+  kNdecoder, /**< Only N decoder */
+  kDisable   /**< Mixer is NOT involved in resource allocation */
+};
+/**
+ * @brief Class Mixer
+ */
+/**
+ * @brief   Provides methods to control mixer pipeline and modify
+ *          mixed frame.
+ * @remark  It internally manages MixerTicket objects which are
+ *          combined with player objects.
+ * @see     Mixerticket
+ */
+class Mixer : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<Mixer>;
+  /**
+   * @brief      Create a mixer object
+   * @remarks    You must use this to get mixer object
+   * @pre        None
+   * @post       None
+   * @exception  None
+   * @return     mixer object (unique_ptr<Mixer>)
+   */
+  static Ptr Create();
+  /**
+   * @brief Struct for Resolution info of mixed frame.
+   * @brief Default info is 1920x1080, 30fps
+   */
+  struct ResolutionInfo {
+    int width = 1920;       /**< Width of mixed frame */
+    int height = 1080;      /**< Height of mixed frame */
+    int framerate_num = 30; /**< Framerate numerator of mixed frame */
+    int framerate_den = 1;  /**< Framerate denominator of mixed frame */
+  };
+
+ public:
+  /**
+   * @brief     Destructor of Mixer
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   * @see       Mixer::Create()
+   */
+  virtual ~Mixer(){};
+  /**
+   * @brief     Starts Mixer
+   * @pre       None
+   * @post      Black frame or mixed frame will be displayed on the screen
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       Mixer::Stop()
+   */
+  virtual bool Start() { return false; }
+  /**
+   * @brief     Stops Mixer
+   * @pre       Mixer::Start() was called
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       Mixer::Start()
+   */
+  virtual bool Stop() { return false; }
+  /**
+   * @brief     Gets maximal number of players which can be connected to Mixer
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    Non-zero value on success, otherwise zero
+   */
+  virtual int GetMaximumAllowedNumberOfPlayer() { return 0; }
+  /**
+   * @brief     Sets the video display
+   * @remarks   We are not supporting changing display.
+   * @remarks   This API have to be called before calling the
+   *            Mixer::Start() to reflect the display type.
+   * @param     [in] type : display type
+   * @param     [in] obj : The handle to display window
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayType
+   *            Mixer::SetDisplayRoi()
+   */
+  virtual bool SetDisplay(const DisplayType type, void* obj) { return false; }
+  /**
+   * @brief     Sets the video display
+   * @remarks   We are not supporting changing display.
+   * @remarks   This API have to be called before calling the
+   *            Mixer::Start() to reflect the display type.
+   * @param     [in] type : display type
+   * @param     [in] serface_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
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayType
+   *            Mixer::SetDisplayRoi()
+   */
+  virtual bool SetDisplay(const DisplayType type, const uint32_t surface_id, const int x, const int y, const int w, const int h) { return false; }
+  /**
+   * @brief     Set the video display mode
+   * @param     [in] mode : display mode
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayMode
+   * @see       Mixer::SetDisplay()
+   * @see       Mixer::SetDisplayRoi()
+   */
+  virtual bool SetDisplayMode(const DisplayMode& mode) { return false; }
+  /**
+   * @brief     Sets the ROI(Region Of Interest) area of display
+   * @remarks   The minimum value of width and height are 1.
+   * @param     [in] geometry : Roi Geometry
+   * @pre       Before set display ROI, #DisplayMode::kDstRoi must be set
+   *            with Mixer::SetDisplayMode().
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayMode  \n
+   *            Mixer::SetDisplay() \n
+   *            Mixer::SetDisplayMode()
+   */
+  virtual bool SetDisplayRoi(const Geometry& geometry) { return false; }
+   /**
+   * @brief     Set Resource allocation policy.
+   * @param     [in] mode : Resource allocation policy
+   * @pre       This api should be called before setting player's display type to
+   *            mixer type.
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetRscAllocMode(const RscAllocMode& mode) { return false; }
+  /**
+   * @brief     Disable audio focus setting.
+   *            The mixer has no authority to set audio focus and player can
+   *            control audio pipeline's activation/deactivation.
+   * @pre       This api should be called before setting player's display type to
+   *            mixer type.
+   * @post      SetAudioFocus() will return false.
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool DisableAudioFocusSetting() { return false; }
+  /**
+   * @brief     Set the alternative video scaler.
+   *            The mixer change to use the sub video scaler instead of main video
+   *            scaler(default).
+   * @pre       This api should be called before setting player's display type to
+   *            mixer type.
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAlternativeVideoScaler() { return false; }  
+  /**
+   * @brief     Sets audio focus on the specific player object
+   * @param     [in] player_instance : The handle to player instance
+   * @pre       None
+   * @post      The player which gets audio focus will activate its audio
+   *            pipeline.
+   *            By default, players deactivate audio until setting audio focus.
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAudioFocus(const void* player_instance) { return false; }
+  /**
+   * @brief     Applies geometry changes on mixed frame
+   * @pre       SetDisplayRoi() was called for players which are connected to
+   *            Mixer.
+   * @post      All the geometry changes will be applied to mixed frame.
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool Commit() { return false; }
+  /**
+   * @brief     Sets resolution of mixed frame
+   * @remarks   By default, the resolution of mixed frame is 1920x1080.
+   * @param     [in] info : The resolution info of mixed frame
+   * @pre       Mixer has no connected players yet.
+   * @post      The resolution of mixed frame will be changed.
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetResolution(const ResolutionInfo& info) { return false; }
+  /**
+   * @brief     Register eventlistener to Mixer
+   * @param     [in] listener : listener object
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       MixerEventListener
+   */
+  virtual bool RegisterListener(MixerEventListener* listener) { return false; }
+  /**
+   * @brief     Creates MixerTicket object for the specific player
+   * @param     [in] player_instance : The handle to player instance
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    A valid @c MixerTicket object on success, otherwise @c nullptr
+   */
+  virtual MixerTicket* CreateTicket(const void* player_instance) {
+    return nullptr;
+  }
+
+ protected:
+  /**
+   * @brief     Constructor of Mixer
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   * @see       Mixer::Create()
+   */
+  Mixer() noexcept {};
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_MIXER__H__
diff --git a/include/mixer/mixer_eventlistener.h b/include/mixer/mixer_eventlistener.h
new file mode 100755 (executable)
index 0000000..1459b05
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * @file           mixer_eventlistener.h
+ * @brief          Handles various events which comes from Mixer
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * Copyright (c) 2020 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_SRC_MIXER_MIXER_EVENTLISTENER__H__
+#define __PLUSPLAYER_SRC_MIXER_MIXER_EVENTLISTENER__H__
+
+namespace plusplayer {
+/**
+ * @brief Class MixerEventListener
+ */
+/**
+ * @brief   Notifies event that an application needs to handle.
+ * @remark  An application should implement concrete class.
+ * @see     Mixer::RegisterListener
+ */
+class MixerEventListener {
+ public:
+  /**
+   * @brief     Constuctor of MixerEventListener
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  MixerEventListener(){};
+  /**
+   * @brief     Destructor of MixerEventListener
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  virtual ~MixerEventListener(){};
+  /**
+   * @brief     It will be invoked when an error is occured in Mixer object
+   * @remark    OnError means that Mixer can't continue its operation.
+   *            An application may need to terminate Mixer usage.
+   * @pre       MixerEventListener object is registered
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  virtual void OnError() {}
+  /**
+   * @brief     It will be invoked when Mixer's own pipeline is notified
+   *            resource confliction
+   * @remark    OnResourceConflicted means that Mixer can't play anymore.
+   *            An application must terminate Mixer usage.
+   * @pre       MixerEventListener object is registered
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  virtual void OnResourceConflicted() {}
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_MIXER_MIXER_EVENTLISTENER__H__
diff --git a/include/mixer/mixerticket.h b/include/mixer/mixerticket.h
new file mode 100755 (executable)
index 0000000..f490c3b
--- /dev/null
@@ -0,0 +1,178 @@
+/**
+ * @file           mixerticket.h
+ * @brief          Connects player to Mixer and allows it to send raw video
+ *                 frame
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * Copyright (c) 2020 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_SRC_MIXER_MIXERTICKET__H__
+#define __PLUSPLAYER_SRC_MIXER_MIXERTICKET__H__
+
+#include <memory>
+
+#include "mixer/decodedvideoinfo.h"
+#include "mixer/mixerticket_eventlistener.h"
+
+namespace plusplayer {
+/**
+ * @brief Enumerations for Resource category
+ * @brief Each player informs mixer with this category so that
+ *        Mixer can understand which player uses which resources.
+ */
+enum class ResourceCategory {
+  kVideoDecoder, /**< Video decoder category */
+  kAudioDecoder, /**< Audio decoder category */
+  kScaler        /**< Scaler category */
+};
+/**
+ * @brief Enumerations for Resource type
+ * @brief Each player informs mixer with this type so that
+ *        Mixer can understand which player uses main or sub type.
+ */
+enum class ResourceType {
+  kHwMain, /**< H/W Main resource type */
+  kHwSub,  /**< H/W Sub resource type */
+  kSw,     /**< S/W resource type. Only valid for decoder category */
+  kNdecoder,  /**< N decoder resource type */
+  kMax     /**< Size of this enumeration (not used) */
+};
+/**
+ * @brief Class MixerTicket
+ */
+/**
+ * @brief   Provides methods for player to send their raw video
+ *          frame to Mixer.
+ * @remark  It also helps player to request H/W resources without
+ *          causing confliction.
+ * @see     Mixer
+ */
+class MixerTicket {
+ public:
+  /**
+   * @brief     Constuctor of MixerTicket
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  MixerTicket(){};
+  /**
+   * @brief     Destructor of MixerTicket
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  virtual ~MixerTicket(){};
+  /**
+   * @brief     Gets currently available resource type for the player
+   * @param     [in] category : The resource category that player wants to use
+   * @param     [out] type : The resource type that player can allocate
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool GetAvailableResourceType(const ResourceCategory& category,
+                                        ResourceType* type) {
+    return false;
+  }
+  /**
+   * @brief     Informs mixer about resource allocation status
+   * @param     [in] category : The resource category that player is using
+   * @param     [in] type : The resource type that player is using
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool Alloc(const ResourceCategory& category,
+                     const ResourceType& type) {
+    return false;
+  }
+  /**
+   * @brief     Renders decoded video frame into mixed frame in Mixer object
+   * @param     [in] info : The decoded physical address by H/W deocder
+   *            and the resolution of video frame.
+   * @pre       MixerTicket::Prepare() must be performed without error
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool Render(const DecodedRawInfo& info) { return false; }
+  /**
+   * @brief     Renders decoded video frame into mixed frame in Mixer object
+   * @param     [in] info : The information for tbm_key exported and the
+   *            resolution of video frame.
+   * @pre       MixerTicket::Prepare() must be performed without error
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool Render(const DecodedVideoKeyTypeInfo& info) { return false; }
+  /**
+   * @brief     Registers eventlistener to MixerTicket
+   * @param     [in] listener : listener object
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   * @see       MixerTicketEventListener
+   */
+  virtual bool RegisterListener(MixerTicketEventListener* listener) {
+    return false;
+  }
+  /**
+   * @brief     Prepares MixerTicket objects to be ready for use
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool Prepare() { return false; }
+  /**
+   * @brief     Get the status whether the mixer can handle player's audio focus.
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True : The mixer can handle player's audio focus,
+   *            @c False : The mixer can't handle player's audio focus and
+   *                       the attached players will determin whether to activate
+   *                       audio track directly.
+   */
+  virtual bool IsAudioFocusHandler() { return false; }
+  /**
+   * @brief     Get the status whether Mixer can handle player's resource
+   *            allocation.
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    @c True : The mixer will allocate appropriate video decoder
+   *                      resources to the attached players,
+   *            @c False : The attached player sets the video decoder resource to
+   *                       be allocated directly instead of the mixer.
+   */
+  virtual bool IsRscAllocHandler() { return false; }
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_MIXER_MIXERTICKET__H__
\ No newline at end of file
diff --git a/include/mixer/mixerticket_eventlistener.h b/include/mixer/mixerticket_eventlistener.h
new file mode 100755 (executable)
index 0000000..3ec62c8
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * @file           mixerticket_eventlistener.h
+ * @brief          Handles various events which comes from MixerTicket
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * Copyright (c) 2020 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_SRC_MIXER_MIXERTICKET_EVENTLISTENER__H__
+#define __PLUSPLAYER_SRC_MIXER_MIXERTICKET_EVENTLISTENER__H__
+
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+/**
+ * @brief Class MixerTicketEventListener
+ */
+/**
+ * @brief   Notifies event that player needs to handle.
+ * @remark  Player should implement concrete class.
+ * @see     MixerTicket::RegisterListener
+ */
+class MixerTicketEventListener {
+ public:
+  /**
+   * @brief     Constuctor of MixerTicketEventListener
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  MixerTicketEventListener(){};
+  /**
+   * @brief     Destructor of MixerTicketEventListener
+   * @pre       None
+   * @post      None
+   * @exception None
+   * @return    None
+   */
+  virtual ~MixerTicketEventListener(){};
+  /**
+   * @brief     It will be invoked when audio focus is being changed
+   * @param     [in] active : @c True if the player gets focused, otherwise @c
+   *            False.
+   * @pre       MixerTicketEventListener object is registered
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool OnAudioFocusChanged(bool active) { return false; }
+  /**
+   * @brief     It will be invoked when the mixed frame's geometry is being
+   *            changed
+   * @param     [in] cur_info : current display info that Mixer stores for this
+   *            player
+   * @param     [out] new_info : update display info that player needs to
+   *            provide for Mixer
+   * @pre       MixerTicketEventListener object is registered
+   * @post      None
+   * @exception None
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool OnUpdateDisplayInfo(const DisplayInfo& cur_info,
+                                   DisplayInfo* new_info) {
+    return false;
+  }
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_MIXER_MIXERTICKET_EVENTLISTENER__H__
diff --git a/include/mixer_capi/display.h b/include/mixer_capi/display.h
new file mode 100755 (executable)
index 0000000..ba103ca
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * @file
+ * @brief          Display related enums
+ * @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 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) 2020 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_MIXER_CAPI_DISPLAY_H__
+#define __PLUSPLAYER_MIXER_CAPI_DISPLAY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief  Enumerations for the display mode
+ */
+enum mixer_display_mode {
+  MIXER_DISPLAY_MODE_LETTER_BOX,
+  MIXER_DISPLAY_MODE_ORIGIN_SIZE,
+  MIXER_DISPLAY_MODE_FULL_SCREEN,
+  MIXER_DISPLAY_MODE_CROPPED_FULL,
+  MIXER_DISPLAY_MODE_ORIGIN_OR_LETTER,
+  MIXER_DISPLAY_MODE_DST_ROI
+};
+
+/**
+ * @brief  Enumerations for the display type
+ */
+enum mixer_display_type {
+  MIXER_DISPLAY_TYPE_NONE,
+  MIXER_DISPLAY_TYPE_OVERLAY,
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_MIXER_CAPI_DISPLAY_H__
\ No newline at end of file
diff --git a/include/mixer_capi/error.h b/include/mixer_capi/error.h
new file mode 100755 (executable)
index 0000000..903d825
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * @file
+ * @brief          Error related enums
+ * @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) 2020 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_MIXER_CAPI_ERROR_H__
+#define __PLUSPLAYER_MIXER_CAPI_ERROR_H__
+
+#include "tizen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MIXER_ERROR_CLASS TIZEN_ERROR_PLAYER | 0x20
+
+/**
+ * @brief  Enumerations for the error type
+ */
+enum mixer_error_type {
+  MIXER_ERROR_TYPE_NONE = TIZEN_ERROR_NONE, /**< Successful */
+  MIXER_ERROR_TYPE_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+  MIXER_ERROR_TYPE_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // __PLUSPLAYER_MIXER_CAPI_ERROR_H__
\ No newline at end of file
diff --git a/include/mixer_capi/mixer_capi.h b/include/mixer_capi/mixer_capi.h
new file mode 100755 (executable)
index 0000000..b2f39d2
--- /dev/null
@@ -0,0 +1,304 @@
+/**
+ * @file           mixer_capi.h
+ * @brief          Mixer api c version
+ * @interfacetype  Platform
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        3.0
+ * @SDK_Support    N
+ * @remark         This is mixer api header implemented as C style to
+ *                 avoid binary compatibility issues.
+ *
+ * Copyright (c) 2020 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_MIXER_CAPI_MIXER_CAPI_H__
+#define __PLUSPLAYER_MIXER_CAPI_MIXER_CAPI_H__
+
+#include "mixer_capi/error.h"
+#include "mixer_capi/display.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+typedef void (*mixer_resource_conflicted_cb)(void*);
+
+typedef void* mixer_handle;
+typedef void* mixer_ticket_h;
+
+/**
+ * @brief  Enumerations for the resource allocation mode
+ */
+enum mixer_rsc_alloc_mode {
+  MIXER_RSC_ALLOC_MODE_DEFAULT,  /**< Main -> Sub -> S/W */
+  MIXER_RSC_ALLOC_MODE_NDECODER, /**< Only N decoder */
+  MIXER_RSC_ALLOC_MODE_DISABLE /**< Mixer is NOT involved in resource allocation */
+};
+
+/**
+ * @brief     Create a mixer handle
+ * @param     None
+ * @return    return mixer handle pointer
+ * @code
+      // basic api call sequence
+      mixer_handle mixer = mixer_create();
+      mixer_set_display(mixer, MIXER_DISPLAY_TYPE_OVERLAY, window);
+
+      esplusplayer_handle player1 = esplusplayer_create();
+      esplusplayer_open(player1);
+
+      esplusplayer_set_display(player1, ESPLUSPLAYER_DISPLAY_TYPE_MIXER, mixer);
+      eplusplayer_set_display_roi(player1, x, y, w, h);
+
+      mixer_set_audio_focus(mixer, player1);
+
+      esplusplayer_set_video_stream_info(player1, video_info);
+      esplusplayer_set_audio_stream_info(player1, audio_info);
+      esplusplayer_prepare_async(player1);
+
+      mixer_start(mixer);
+      esplusplayer_start(player1);
+
+      mixer_stop(mixer);
+      esplusplayer_close(player1);
+      mixer_destroy(mixer);
+      esplusplayer_destroy(player1);
+ * @endcode
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+mixer_handle mixer_create();
+
+/**
+ * @brief     Release mixer handle
+ * @param     [in] handle : mixer handle
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       None
+ * @post      mixer handle will be removed
+ * @exception   None
+ * @see       mixer_create()
+ */
+int mixer_destroy(mixer_handle handle);
+
+/**
+ * @brief     Starts Mixer.
+ * @param     [in] handle : mixer handle
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       None
+ * @post      Black frame or mixed frame will be displayed on the screen
+ * @exception   None
+ * @see       mixer_stop()
+ */
+int mixer_start(mixer_handle handle);
+
+/**
+ * @brief     Stops Mixer
+ * @param     [in] handle : Mixer handle
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       mixer_start() should be called
+ * @post      None
+ * @exception   None
+ * @see       mixer_start()
+ */
+int mixer_stop(mixer_handle handle);
+
+/**
+ * @brief     Gets maximal number of players which can be connected to Mixer
+ * @param     [in] handle : Mixer handle
+ * @return    Non-zero value on success, otherwise zero
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+int mixer_get_max_allowed_number_of_player(mixer_handle handle);
+
+/**
+ * @brief     Sets the video display
+ * @param     [in] handle : Mixer handle
+ * @param     [in] type : display type
+ * @param     [in] window : The handle to display window
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       This API have to be called before calling the
+ *            mixer_start() to reflect the display type
+ * @post      None
+ * @exception   None
+ * @remarks    We are not supporting changing display
+ * @see       mixer_display_type \n
+ *            mixer_set_display_roi()
+ */
+int mixer_set_display(mixer_handle handle, mixer_display_type type,
+                      void* window);
+
+/**
+ * @brief     Set the video display mode
+ * @param     [in] handle : Mixer handle
+ * @param     [in] mode : display mode
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       None
+ * @post      None
+ * @exception   None
+ * @see       mixer_display_mode
+ * @see       mixer_set_display() \n
+ *            mixer_set_display_roi()
+ */
+int mixer_set_display_mode(mixer_handle handle, mixer_display_mode mode);
+
+/**
+ * @brief     Sets the ROI(Region Of Interest) area of display
+ * @param     [in] handle : Mixer handle
+ * @param     [in] geometry : Roi Geometry
+ * @return    @c one of mixer_error_type values will be returned
+ * @code
+      // The ROI of mixer means display area in tv screen.
+      // The ROI of each player means display area in mixer's ROI.
+      
+      mixer_set_display_mode(mixer, MIXER_DISPLAY_MODE_DST_ROI);      
+      mixer_set_display_roi(mixer, 0, 0, 1920, 1080);
+
+      esplusplayer_set_display_roi(player1, 20, 20, 700, 400);      
+      esplusplayer_set_display_roi(player2, 20, 20, 700, 400);
+      
+      mixer_commit(mixer);
+ * @endcode
+ * @pre       Before set display ROI, #MIXER_DISPLAY_MODE_DST_ROI must be set
+ *            with mixer_set_display_mode()
+ * @post      None
+ * @exception   None
+ * @remarks    The minimum value of width and height are 1.
+ * @see       mixer_display_mode \n
+ *            mixer_set_display() \n
+ *            mixer_set_display_mode()
+ */
+int mixer_set_display_roi(mixer_handle handle, const int x, const int y,
+                          const int width, const int height);
+
+ /**
+  * @brief     Applies geometry changes on mixed frame
+  * @param     [in] handle : Mixer handle
+  * @return    @c one of mixer_error_type values will be returned
+  * @pre       set display roi api was called for players which are connected to
+  *            Mixer.
+  * @post      All the geometry changes will be applied to mixed frame.
+  * @exception   None
+  * @see       mixer_set_display_roi()
+  */
+ int mixer_commit(mixer_handle handle);
+
+ /**
+  * @brief     Set Resource allocation policy
+  * @param     [in] handle : Mixer handle
+  * @param     [in] mode : Resource allocation policy
+  * @return    @c one of mixer_error_type values will be returned
+  * @pre       This api should be called before setting player's display type to
+  *            mixer type.
+  * @post      None
+  * @exception None
+  */
+ int mixer_set_rsc_alloc_mode(mixer_handle handle,
+                              const mixer_rsc_alloc_mode mode);
+
+/**
+ * @brief     Disable audio focus setting.
+ *            The mixer has no authority to set audio focus and player can
+ *            control audio pipeline's activation/deactivation.
+ * @param     [in] handle : Mixer handle
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       This api should be called before setting player's display type to
+ *            mixer type.
+ * @post      mixer_set_audio_focus() will return error.
+ * @exception   None
+ */
+int mixer_disable_audio_focus_setting(mixer_handle handle);
+
+/**
+ * @brief     Set the alternative video scaler.
+ *            The mixer change to use the sub video scaler instead of main video
+ *            scaler(default).
+ * @param     [in] handle : Mixer handle
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       This api should be called before mixer_start().
+ * @post      None
+ * @exception   None
+ */
+int mixer_set_alternative_video_scaler(mixer_handle handle);
+
+/**
+ * @brief     Sets audio focus on the specific player object
+ * @param     [in] handle : Mixer handle
+ * @param     [in] player_instance : The handle to player instance
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       None
+ * @post      The player which gets audio focus will activate its audio
+ *            pipeline. By default, players deactivate audio until setting
+ *            audio focus.
+ * @exception   None
+ */
+int mixer_set_audio_focus(mixer_handle handle, const void* player_instance);
+
+/**
+ * @brief     Sets resolution of mixed frame
+ * @param     [in] handle : Mixer handle
+ * @param     [in] info : The resolution info of mixed frame
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       Mixer has no connected players yet.
+ * @post      The resolution of mixed frame will be changed.
+ * @exception   None
+ * @remarks    By default, the resolution of mixed frame is 1920x1080.
+ */
+int mixer_set_resolution(mixer_handle handle, const int width, const int height,
+                         const int framerate_num, const int framerate_den);
+
+/**
+ * @brief     Creates MixerTicket object for the specific player
+ * @param     [in] handle : Mixer handle
+ * @param     [in] player_instance : The handle to player instance
+ * @return    A valid @c MixerTicket object on success, otherwise @c nullptr
+ * @pre       None
+ * @post      None
+ * @exception   None
+ */
+mixer_ticket_h mixer_create_ticket(mixer_handle handle,
+                                   const void* player_instance);
+
+// callback function
+
+/**
+ * @brief     It will be invoked when Mixer's own pipeline is notified
+ *            resource confliction
+ * @param     [in] handle : Mixer handle
+ * @param     [in] callback : the callback function to register
+ * @param     [in] userdata : userdata of resource_conflicted_cb()
+ * @return    @c one of mixer_error_type values will be returned
+ * @pre       None
+ * @post      resource_conflicted_cb will be invoked when resources are
+ *            conflicted
+ * @exception   None
+ * @remark    resource_conflicted_cb means that Mixer can't play anymore.
+ *            An application must terminate Mixer usage.
+ */
+int mixer_set_resource_conflicted_cb(
+    mixer_handle handle, mixer_resource_conflicted_cb resource_conflicted_cb,
+    void* userdata);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __PLUSPLAYER_MIXER_CAPI_MIXER_CAPI_H__
+
diff --git a/include/plusplayer/appinfo.h b/include/plusplayer/appinfo.h
new file mode 100755 (executable)
index 0000000..2b0106b
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * @file           attribute.h
+ * @interfacetype  module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ *
+ * 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_APPINFO_H__
+#define __PLUSPLAYER_APPINFO_H__
+
+#include <string>
+
+namespace plusplayer {
+
+/**
+* @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 plusplayer
+
+#endif  // __PLUSPLAYER_PLAYER_APPINFO_H__
\ No newline at end of file
diff --git a/include/plusplayer/attribute.h b/include/plusplayer/attribute.h
new file mode 100755 (executable)
index 0000000..d6113d6
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * @file           attribute.h
+ * @interfacetype  module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ *
+ * 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_ATTRIBUTE_H__
+#define __PLUSPLAYER_ATTRIBUTE_H__
+
+namespace plusplayer {
+
+/**
+ * @brief Enumeration for plusplayer attribute
+ *        If there is new attribute, please write details in below documents.
+ */
+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
+  kMax,
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_ATTRIBUTE_H__
\ No newline at end of file
diff --git a/include/plusplayer/audioeasinginfo.h b/include/plusplayer/audioeasinginfo.h
new file mode 100755 (executable)
index 0000000..f6671c8
--- /dev/null
@@ -0,0 +1,45 @@
+/**\r
+ * @file           audioeasinginfo.h\r
+ * @interfacetype  module\r
+ * @privlevel      None-privilege\r
+ * @privilege      None\r
+ * @product        TV, AV, B2B\r
+ * @version        3.0\r
+ * @SDK_Support    N\r
+ *\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved\r
+ * PROPRIETARY/CONFIDENTIAL\r
+ * This software is the confidential and proprietary\r
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall\r
+ * not disclose such Confidential Information and shall use it only in\r
+ * accordance with the terms of the license agreement you entered into with\r
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the\r
+ * suitability of the software, either express or implied, including but not\r
+ * limited to the implied warranties of merchantability, fitness for a\r
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any\r
+ * damages suffered by licensee as a result of using, modifying or distributing\r
+ * this software or its derivatives.\r
+ */\r
+#ifndef __PLUSPLAYER_AUDIOEASINGINFO_H__\r
+#define __PLUSPLAYER_AUDIOEASINGINFO_H__\r
+\r
+namespace plusplayer {\r
+\r
+enum class AudioEasingType {\r
+  kAudioEasingLinear = 0,\r
+  kAudioEasingIncubic,\r
+  kAudioEasingOutcubic,\r
+  kAudioEasingNone\r
+};\r
+\r
+/**\r
+ * @brief  audio easing information struct\r
+ */\r
+struct AudioEasingInfo {\r
+  uint32_t target_volume; /**< Audio easing target volume (0 ~ 100)*/\r
+  uint32_t duration;      /**< Audio easing duration, in millisecond */\r
+  AudioEasingType type;   /**< Audio easing type */\r
+};\r
+}  // namespace plusplayer\r
+\r
+#endif  // __PLUSPLAYER_AUDIOEASINGINFO_H__
\ No newline at end of file
diff --git a/include/plusplayer/decodedvideopacketex.h b/include/plusplayer/decodedvideopacketex.h
new file mode 100755 (executable)
index 0000000..3e36bc9
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * @file
+ * @brief          the decoded video packet for playback
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * Copyright (c) 2020 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_DECODED_VIDEO_PACKET_EX_H__
+#define __PLUSPLAYER_DECODED_VIDEO_PACKET_EX_H__
+
+#include <boost/core/noncopyable.hpp>
+#include <memory>
+#include <utility>
+
+#include "tbm_surface.h"
+#include "tbm_type.h"
+
+namespace plusplayer {
+
+class DecodedVideoPacketEx : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<DecodedVideoPacketEx>;
+
+  static Ptr Create(const uint64_t pts = 0, const uint64_t duration = 0,
+                    tbm_surface_h surface_data = nullptr,
+                    const void* scaler_index = nullptr);
+
+  DecodedVideoPacketEx() = delete;
+
+  virtual ~DecodedVideoPacketEx();
+
+  uint64_t GetPts() const { return pts_; }
+  uint64_t GetDuration() const { return duration_; }
+  const tbm_surface_h GetTbmSurface() const { return surface_data_; }
+  const void* GetScalerIndex() const { return scaler_index_; }
+
+ protected:
+  explicit DecodedVideoPacketEx(const uint64_t pts, const uint64_t duration,
+                                tbm_surface_h surface_data,
+                                const void* scaler_index)
+      : pts_(pts),
+        duration_(duration),
+        surface_data_(surface_data),
+        scaler_index_(scaler_index) {}
+
+ private:
+  const uint64_t pts_ = 0;
+  const uint64_t duration_ = 0;
+  tbm_surface_h surface_data_ = nullptr;  // tbm_surface
+  const void* scaler_index_ = nullptr;
+};
+
+using DecodedVideoPacketExPtr = DecodedVideoPacketEx::Ptr;
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_DECODED_VIDEO_PACKET_EX_H__
diff --git a/include/plusplayer/drm.h b/include/plusplayer/drm.h
new file mode 100755 (executable)
index 0000000..f299eb0
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+* @file           
+* @interfacetype  module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        1.0
+* @SDK_Support    N
+*
+* 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_DRM_H__
+#define __PLUSPLAYER_DRM_H__
+
+namespace plusplayer {
+
+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 plusplayer
+
+#endif  // __PLUSPLAYER_DRM_H__
diff --git a/include/plusplayer/elementary_stream.h b/include/plusplayer/elementary_stream.h
new file mode 100755 (executable)
index 0000000..88b9101
--- /dev/null
@@ -0,0 +1,341 @@
+/**
+ * @file           elementary_stream.h
+ * @brief          the contents information for elementary stream
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ * @remark         You must add contents information of elementary streams for
+ * plusplayer::EsPlusPlayer
+ * @see            plusplayer::EsPlusPlayer class
+ *
+ * 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_ELEMENTARY_STREAM_H_
+#define PLUSPLAYER_ELEMENTARY_STREAM_H_
+
+#include <boost/core/noncopyable.hpp>
+#include <memory>
+
+#include "plusplayer/track.h"
+#include "plusplayer/types/stream.h"
+
+namespace plusplayer {
+
+/**
+ * @brief   Enumerations for audio mime type
+ */
+enum class AudioMimeType {
+  kUnKnown,
+  kAAC,
+  kMP2,
+  kMP3,
+  kAC3,
+  kEAC3,
+  kVORBIS,
+  kOPUS,
+  kPCM_S16LE,
+  kPCM_S16BE,
+  kPCM_U16LE,
+  kPCM_U16BE,
+  kPCM_S24LE,
+  kPCM_S24BE,
+  kPCM_U24LE,
+  kPCM_U24BE,
+  kPCM_S32LE,
+  kPCM_S32BE,
+  kPCM_U32LE,
+  kPCM_U32BE,
+  kG711_MULAW
+};
+/**
+ * @brief   Enumerations for video mime type
+ */
+enum class VideoMimeType {
+  kUnKnown,
+  kH263,
+  kH264,
+  kHEVC,
+  kMPEG1,
+  kMPEG2,
+  kMPEG4,
+  kVP8,
+  kVP9,
+  kWMV3,
+  kAV1,
+  kMJPEG
+};
+
+/**
+ * @brief   the interface of the contents information class for audio stream
+ * @remark  You must add contents information of at least one audio or video
+ * stream
+ */
+class AudioStream : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<AudioStream>;
+  /**
+   * @brief     Create a audio stream object
+   * @remarks   You must use this to get audio stream object
+   * @return    audio stream object (unique_ptr<AudioStream>)
+   */
+  static Ptr Create() { return Ptr(new AudioStream); }
+
+  AudioStream() noexcept;
+
+  ~AudioStream() {}
+  /**
+   * @brief     Set mime type for the associated audio stream
+   * @param     [in] mimetype : the mime type of stream
+   * @return    void
+   * @see       AudioStream::GetMimeType()
+   */
+  void SetMimeType(AudioMimeType mimetype);
+  /**
+   * @brief     Get mime type for the associated audio stream
+   * @return    the mime type of stream (AudioMimeType)
+   * @see       AudioStream::SetMimeType()
+   */
+  AudioMimeType GetMimeType() const { return mimetype_; }
+  /**
+   * @brief     Set samplerate for the associated audio stream
+   * @param     [in] sample_rate : the samplerate of stream
+   * @return    void
+   * @see       AudioStream::GetSamplerate()
+   */
+  void SetSamplerate(uint32_t sample_rate) { track_.sample_rate = sample_rate; }
+  /**
+   * @brief     Get samplerate for the associated audio stream
+   * @return    samplerate : the samplerate of stream
+   * @see       AudioStream::SetSamplerate()
+   */
+  uint32_t GetSamplerate() const { return track_.sample_rate; }
+  /**
+   * @brief     Set channels for the associated audio stream
+   * @param     [in] channels : the channels of stream
+   * @return    void
+   * @see       AudioStream::GetChannels()
+   */
+  void SetChannels(uint32_t channels) { track_.channels = channels; }
+  /**
+   * @brief     Get channels for the associated audio stream
+   * @return    the channels of stream
+   * @see       AudioStream::SetChannels()
+   */
+  uint32_t GetChannels() const { return track_.channels; }
+  /**
+   * @brief     Set bitrate for the associated audio stream
+   * @param     [in] bitrate : the bitrate of stream
+   * @return    void
+   * @see       AudioStream::GetBitrate()
+   */
+  void SetBitrate(uint32_t bitrate) { track_.bitrate = bitrate; }
+  /**
+   * @brief     Get bitrate for the associated audio stream
+   * @return    the bitrate of stream
+   * @see       AudioStream::SetBitrate()
+   */
+  uint32_t GetBitrate() const { return track_.bitrate; }
+  /**
+   * @brief     Set codec data for the associated audio stream
+   * @param     [in] data : the codec data of stream
+   * @param     [in] data_size : the size of codec data
+   * @return    void
+   * @see       AudioStream::GetCodecData(), AudioStream::GetCodecDataSize()
+   */
+  void SetCodecData(std::shared_ptr<char> data, uint32_t data_size) {
+    track_.codec_data = data;
+    track_.codec_data_len = data_size;
+  }
+  /**
+   * @brief     Get codec data for the associated audio stream
+   * @return    std::shared_ptr<char> of codec data
+   * @see       AudioStream::SetCodecData(), AudioStream::GetCodecDataSize()
+   */
+  std::shared_ptr<char> GetCodecData() const { return track_.codec_data; }
+  /**
+   * @brief     Get codec data for the associated audio stream
+   * @return    the size of codec data
+   * @see       AudioStream::SetCodecData(), AudioStream::GetCodecData()
+   */
+  uint32_t GetCodecDataSize() const { return track_.codec_data_len; }
+  /**
+   * @brief     Get whether to use the sw decoder forcibly
+   * @return    @c True if the sw decoder is use, otherwise @c False.
+   */
+  bool GetForceSwDecoderUse()  { return force_swdecoder_use_; }
+
+ private:
+  void SetMimeType_(AudioMimeType mimetype);
+
+  Track GetTrack_() const { return track_; }
+
+  friend class EsPlayer;
+
+ private:
+  Track track_;
+  AudioMimeType mimetype_ = AudioMimeType::kUnKnown;
+  bool force_swdecoder_use_ = false;
+};
+
+using AudioStreamPtr = AudioStream::Ptr;
+
+/**
+ * @brief   the interface of the contents information class for video stream
+ * @remark  You must add contents information of at least one audio or video
+ * stream
+ */
+class VideoStream : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<VideoStream>;
+  /**
+   * @brief     Create a video stream object
+   * @remarks   You must use this to get video stream object
+   * @return    video stream object (unique_ptr<VideoStream>)
+   */
+  static Ptr Create() { return Ptr(new VideoStream); }
+
+  VideoStream() noexcept;
+
+  ~VideoStream() {}
+
+  /**
+   * @brief     Set mime type for the associated video stream
+   * @param     [in] mimetype : the mime type of stream
+   * @return    void
+   * @see       VideoStream::GetMimeType()
+   */
+  void SetMimeType(VideoMimeType mimetype);
+  /**
+   * @brief     Get mime type for the associated video stream
+   * @return    the mime type (VideoMimeType)
+   * @see       VideoStream::SetMimeType()
+   */
+  VideoMimeType GetMimeType() const { return mimetype_; }
+  /**
+   * @brief     Set width for the associated video stream
+   * @param     [in] width : the width of stream
+   * @return    void
+   * @see       VideoStream::GetWidth()
+   */
+  void SetWidth(uint32_t width) { track_.width = width; }
+  /**
+   * @brief     Get width for the associated video stream
+   * @return    the width of stream
+   * @see       VideoStream::SetWidth()
+   */
+  uint32_t GetWidth() const { return track_.width; }
+  /**
+   * @brief     Set height for the associated video stream
+   * @param     [in] height : the height of stream
+   * @return    void
+   * @see       VideoStream::GetHeight()
+   */
+  void SetHeight(uint32_t height) { track_.height = height; }
+  /**
+   * @brief     Get height for the associated video stream
+   * @return    the height of stream
+   * @see       VideoStream::SetHeight()
+   */
+  uint32_t GetHeight() const { return track_.height; }
+  /**
+   * @brief     Set maximum width for the associated video stream
+   * @param     [in] maxwidth : the maximum width of stream
+   * @return    void
+   * @see       VideoStream::GetMaxWidth()
+   */
+  void SetMaxWidth(uint32_t maxwidth) { track_.maxwidth = maxwidth; }
+  /**
+   * @brief     Get maximum width for the associated video stream
+   * @return    the maximum width of stream
+   * @see       VideoStream::SetMaxWidth()
+   */
+  uint32_t GetMaxWidth() const { return track_.maxwidth; }
+  /**
+   * @brief     Set maximum height for the associated video stream
+   * @param     [in] maxheight : the maximum height of stream
+   * @return    void
+   * @see       VideoStream::GetMaxHeight()
+   */
+  void SetMaxHeight(uint32_t maxheight) { track_.maxheight = maxheight; }
+  /**
+   * @brief     Get maximum height for the associated video stream
+   * @return    the maximum height of stream
+   * @see       VideoStream::SetMaxHeight()
+   */
+  uint32_t GetMaxHeight() const { return track_.maxheight; }
+  /**
+   * @brief     Set framerate for the associated video stream
+   * @param     [in] num : the numerator of framerate
+   * @param     [in] den : the denominator of framerate
+   * @return    void
+   * @see       VideoStream::GetFramerate()
+   */
+  void SetFramerate(uint32_t num, uint32_t den) {
+    track_.framerate_num = num;
+    track_.framerate_den = den;
+  }
+  /**
+   * @brief     Get framerate for the associated video stream
+   * @param     [out] num : the numerator of framerate
+   * @param     [out] den : the denominator of framerate
+   * @return    void
+   * @see       VideoStream::SetFramerate()
+   */
+  void GetFramerate(uint32_t* num, uint32_t* den) {
+    *num = track_.framerate_num;
+    *den = track_.framerate_den;
+  }
+  /**
+   * @brief     Set codec data for the associated video stream
+   * @param     [in] data : the codec data of stream
+   * @param     [in] data_size : the size of codec data
+   * @return    void
+   * @see       VideoStream::GetCodecData(), VideoStream::GetCodecDataSize()
+   */
+  void SetCodecData(std::shared_ptr<char> data, uint32_t data_size) {
+    track_.codec_data = data;
+    track_.codec_data_len = data_size;
+  }
+  /**
+   * @brief     Get codec data for the associated video stream
+   * @return    std::shared_ptr<char> of codec data
+   * @see       VideoStream::SetCodecData(), VideoStream::GetCodecDataSize()
+   */
+  std::shared_ptr<char> GetCodecData() const { return track_.codec_data; }
+  /**
+   * @brief     Get codec data for the associated video stream
+   * @return    the size of codec data
+   * @see       VideoStream::SetCodecData(), VideoStream::GetCodecData()
+   */
+  uint32_t GetCodecDataSize() const { return track_.codec_data_len; }
+
+ private:
+  void SetMimeType_(VideoMimeType mimetype);
+  Track GetTrack_() const { return track_; }
+
+  friend class EsPlayer;
+
+ private:
+  Track track_;
+  VideoMimeType mimetype_ = VideoMimeType::kUnKnown;
+};
+
+using VideoStreamPtr = VideoStream::Ptr;
+
+}  // namespace plusplayer
+
+#endif  // PLUSPLAYER_ELEMENTARY_STREAM_H_
diff --git a/include/plusplayer/es_eventlistener.h b/include/plusplayer/es_eventlistener.h
new file mode 100755 (executable)
index 0000000..33e9535
--- /dev/null
@@ -0,0 +1,220 @@
+/**
+ * @file           es_eventlistener.h
+ * @brief          the event listener for plusplayer::EsPlusPlayer
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ * @see            plusplayer::EsPlusPlayer class
+ *
+ * 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_ES_EVENTLISTENER__H__
+#define __PLUSPLAYER_ES_EVENTLISTENER__H__
+
+#include "plusplayer/drm.h"
+#include "plusplayer/types/buffer.h"
+#include "plusplayer/types/error.h"
+#include "plusplayer/types/event.h"
+#include "plusplayer/types/latency.h"
+#include "plusplayer/types/stream.h"
+
+namespace plusplayer {
+
+/**
+ * @brief   the interface of es player EventListener class
+ * @remark  You must implement concrete class and register it to get es player
+ *          events.
+ * @see     EsPlusPlayer::RegisterListener()
+ */
+class EsEventListener {
+ public:
+  EsEventListener() noexcept {}
+  using UserData = void*;
+  virtual ~EsEventListener() {}
+  /**
+   * @brief     It will be invoked when error has happened
+   * @param     [in] error_code : #ErrorType
+   * @param     [in] userdata : user data
+   * @see       #ErrorType
+   * @see       OnErrorMsg() if a detailed error message is required
+   */
+  virtual void OnError(const ErrorType& error_code, UserData userdata) {}
+  /**
+ * @brief     It will be invoked when error has happened
+ * @param     [in] error_code : #ErrorType
+ * @param     [in] error_msg : detailed error message including info related to
+ *                 codec,demuxer,network status, etc.
+ * @see       #ErrorType
+ * @see       OnError() if only simple error code is required
+ */
+  virtual void OnErrorMsg(const ErrorType& error_code, const char* error_msg,
+                          UserData userdata) {}
+  /**
+   * @brief     It will be invoked when buffer overrun or underrun is detected
+   * @param     [in] type : the type of target stream
+   * @param     [in] status : current buffer status
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   */
+  virtual void OnBufferStatus(const StreamType& type,
+                              const BufferStatus& status,
+                              const uint64_t byte_size,
+                              const uint64_t time_size, UserData userdata) {}
+  /**
+   * @brief     It will be invoked when H/W resource is conflicted
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   * @remarks   Player state will be changed to #EsState::kPaused
+   */
+  virtual void OnResourceConflicted(UserData userdata) {}
+  /**
+   * @brief     It will be invoked when player has reached the end of the stream
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   */
+  virtual void OnEos(UserData userdata) {}
+  /**
+   * @brief     It will be invoked when player is prepared to be started
+   * @details   This will be invoked when user calls
+   *            EsPlusPlayer::PrepareAsync()
+   * @param     [in] ret : statue of prepare (@c true = success, @c false =
+   * fail)
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   * @see       EsPlusPlayer::PrepareAsync()
+   */
+  virtual void OnPrepareDone(bool ret, UserData userdata) {}
+  /**
+   * @brief     It will be invoked when ready to receive es packets after
+   * prepare
+   * @details   This will be invoked when user calls
+   *            EsPlusPlayer::PrepareAsync()
+   * @param     [in] type : the stream type
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   * @see       EsPlusPlayer::PrepareAsync() \n
+   * @see       EsPlusPlayer::SubmitPacket()
+   */
+  virtual void OnReadyToPrepare(const StreamType& type, UserData userdata) {}
+  /**
+   * @brief     It will be invoked when the seek operation is completed
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   * @remarks   OnSeekDone() will be called once seek operation is finished
+   * @see       EsPlusPlayer::Seek()
+   */
+  virtual void OnSeekDone(UserData userdata) {}
+  /**
+   * @brief     It will be invoked when ready to receive es packets after seek
+   * @details   This will be invoked when user calls EsPlusPlayer::Seek()
+   * @param     [in] type : the stream type
+   * @param     [in] offset : the new position to seek in milliseconds
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   * @see       EsPlusPlayer::Seek() \n
+   * @see       EsPlusPlayer::SubmitPacket()
+   */
+  virtual void OnReadyToSeek(const StreamType& type, const uint64_t offset,
+                             UserData userdata) {}
+
+  /**
+   * @brief     Set a callback function to be invoked when trackrender side need
+   * to get an useful tbm surface.
+   * @param     [in] ptr : pointer which set to get tbm address.
+   * @param     [in] is_scale_change : parameter which indicate whether the
+   * scale resolution changed.
+   * @remark    SetVideoFrameBufferType()
+   */
+  virtual void OnMediaPacketGetTbmBufPtr(void** ptr, bool is_scale_change) {}
+
+  /**
+   * @brief     Set a callback function to be invoked when player decoded video
+   *            frame. A video frame can be retrieved
+   * @param     [in] packet : decoded video packet
+   * @param     [in] userdata : the user data passed from the event listener
+   * @remark    SetVideoFrameBufferType()
+   */
+  virtual void OnMediaPacketVideoDecoded(const DecodedVideoPacket& packet) {}
+
+  /**
+   * @brief     It will be invoked when player gets closed caption data from
+   *            decoder
+   * @param     [in] data : closed caption data
+   * @param     [in] size : size of closed caption data
+   */
+  virtual void OnClosedCaptionData(std::unique_ptr<char[]> data, const int size,
+                                   UserData userdata) {}
+
+  /**
+   * @brief     It will be invoked when the flush operation is completed
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   * @remarks   OnFlushDone() will be called once flush operation is finished
+   * @see       EsPlusPlayer::Flush()
+   */
+  virtual void OnFlushDone(UserData userdata) {}
+
+  virtual void OnEvent(const EventType& event_type, const EventMsg& msg_data,
+                       UserData userdata) {}
+
+  virtual void OnFirstDecodingDone(UserData userdata) {}
+
+  /**
+   * @brief     It will be invoked when buffer underrun is detected from a video
+   *            decoder.
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   */
+  virtual void OnVideoDecoderUnderrun(UserData userdata) {}
+
+  /**
+   * @brief     It will be invoked when the latency status of the video stream
+   * changes.
+   * @param     [in] latency_status : the latency status
+   *            [in] userdata : the user data passed from the event listener
+   *            registration function
+   */
+  virtual void OnVideoLatencyStatus(const LatencyStatus& latency_status,
+                                    UserData userdata) {}
+
+  /**
+  * @brief     It will be invoked when the latency status of the audio stream
+  * changes.
+  * @param     [in] latency_status : the latency status
+  *            [in] userdata : the user data passed from the event listener
+  *            registration function
+  */
+  virtual void OnAudioLatencyStatus(const LatencyStatus& latency_status,
+                                    UserData userdata) {}
+  /**
+   * @brief     It will be invoked when video high latency occurs.
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   */
+  virtual void OnVideoHighLatency(UserData userdata) {}
+
+  /**
+   * @brief     It will be invoked when audio high latency occurs.
+   * @param     [in] userdata : the user data passed from the event listener
+   *            registration function
+   */
+  virtual void OnAudioHighLatency(UserData userdata) {}
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_ES_EVENTLISTENER__H__
\ No newline at end of file
diff --git a/include/plusplayer/espacket.h b/include/plusplayer/espacket.h
new file mode 100755 (executable)
index 0000000..afea7e2
--- /dev/null
@@ -0,0 +1,188 @@
+/**
+ * @file           espacket.h
+ * @brief          the packet for elementary stream
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ * @see            plusplayer::EsPlusPlayer class
+ *
+ * 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_ESPACKET_H__
+#define __PLUSPLAYER_ESPACKET_H__
+
+#include <boost/core/noncopyable.hpp>
+#include <memory>
+
+#include "plusplayer/types/stream.h"
+
+namespace plusplayer {
+
+/**
+ * @brief   Structure of matroska meta data
+ */
+struct MatroskaMetaData {
+  double primary_r_chromaticity_x;
+  double primary_r_chromaticity_y;
+  double primary_g_chromaticity_x;
+  double primary_g_chromaticity_y;
+  double primary_b_chromaticity_x;
+  double primary_b_chromaticity_y;
+  double white_point_chromaticity_x;
+  double white_point_chromaticity_y;
+  double luminance_max;
+  double luminance_min;
+};
+/**
+ * @brief   Structure of matroska color information
+ */
+struct MatroskaColor {
+  uint32_t matrix_coefficients;
+  uint32_t bits_per_channel;
+  uint32_t chroma_subsampling_horizontal;
+  uint32_t chroma_subsampling_vertical;
+  uint32_t cb_subsampling_horizontal;
+  uint32_t cb_subsampling_vertical;
+  uint32_t chroma_siting_horizontal;
+  uint32_t chroma_siting_vertical;
+  uint32_t range;
+  uint32_t transfer_characteristics;
+  uint32_t primaries;
+  uint32_t max_cll;
+  uint32_t max_fall;
+  MatroskaMetaData metadata;
+  uint32_t is_hdr_10p;
+};
+
+/**
+ * @brief   the interface of the packet class for elementary stream
+ * @see     plusplayer::EsPlusPlayer class
+ */
+class EsPacket : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<EsPacket>;
+  /**
+   * @brief     Create a espacket object
+   * @remarks   You must use this to get espacket object
+   * @return    espacket object (unique_ptr<EsPacket>)
+   */
+  static Ptr Create(const StreamType type = StreamType::kMax,
+                    std::shared_ptr<char> buffer = nullptr,
+                    const uint32_t buffer_size = 0, const uint64_t pts = 0,
+                    const uint64_t duration = 0, const uint32_t hdr10p_size = 0,
+                    std::shared_ptr<char> hdr10p_data = nullptr);
+  /**
+   * @brief     Create an eos espacket object
+   * @remarks   You must use this to get espacket object
+   * @return    espacket object (unique_ptr<EsPacket>)
+   */
+  static Ptr CreateEos(const StreamType type = StreamType::kMax);
+  EsPacket() = delete;
+
+  ~EsPacket() {}
+  /**
+   * @brief     Get the stream type for the associated packet
+   * @return    the stream type to set (StreamType)
+   */
+  StreamType GetType() const { return type_; }
+  /**
+   * @brief     Get the size of the buffer for the associated packet
+   * @return    the size of the buffer to set (StreamType)
+   */
+  uint32_t GetSize() const { return buffer_size_; }
+  /**
+   * @brief     Get the size of the hdr10+ metadata size for the associated
+   * packet
+   * @return    the size of the hdr10+ metadata to set (StreamType)
+   */
+  uint32_t GetHdr10pSize() const { return hdr10p_metadata_size_; }
+  /**
+   * @brief     Get the pts of buffer for the associated packet
+   * @return    the pts to set
+   */
+  uint64_t GetPts() const { return pts_; }
+  /**
+   * @brief     Get the pts of buffer for the associated packet
+   * @return    the duration to set
+   */
+  uint64_t GetDuration() const { return duration_; }
+  /**
+   * @brief     Get the buffer for the associated packet
+   * @return    the buffer to set
+   */
+  std::shared_ptr<char> GetBuffer() const { return buffer_; }
+  /**
+   * @brief     Get the Hdr10p Metadata for the associated packet
+   * @return    the Hdr10p Metadata to set
+   */
+  std::shared_ptr<char> GetHdr10pData() const { return hdr10p_metadata_; }
+  /**
+   * @brief     Set the matroska color information for the associated packet
+   * @return    @c False if the streamtype of this EsPacket isn't
+   * StreamType::kVideo, otherwise @c True
+   * @see       MatroskaColor
+   */
+  bool SetMatroskaColorInfo(const MatroskaColor& color_info) {
+    if (type_ != StreamType::kVideo) return false;
+    matroska_color_info_.reset(new MatroskaColor(color_info));
+    return true;
+  }
+  /**
+   * @brief     Get the matroska color information for the associated packet
+   * @return    the matroska color information to set
+   * @see       MatroskaColor
+   */
+  const MatroskaColor& GetMatroskaColorInfo() const {
+    return *matroska_color_info_.get();
+  }
+  /**
+   * @brief     Inform whether the matroska color information for the associated
+   * packet is set
+   * @return    @c True if matroska color information is set, otherwise @c False
+   * @see       SetMatroskaColorInfo(), GetMatroskaColorInfo()
+   */
+  bool HasMatroskaColorInfo() const { return matroska_color_info_ != nullptr; }
+  /**
+   * @brief     Inform whether this EsPacket is for EndOfStream(EOS)
+   * @return    @c True if this EsPacket is EndOfStream(EOS) Packet, otherwise
+   * @c False
+   * @see       CreateEos()
+   */
+  bool IsEosPacket() const { return buffer_size_ == 0 && buffer_ == nullptr; }
+
+ private:
+  explicit EsPacket(const StreamType type, std::shared_ptr<char> buffer,
+                    const uint32_t buffer_size, const uint64_t pts,
+                    const uint64_t duration, const uint32_t hdr10p_size,
+                    std::shared_ptr<char> hdr10p_data);
+
+ private:
+  const StreamType type_ = StreamType::kMax;
+  std::shared_ptr<char> buffer_ = nullptr;
+  const uint32_t buffer_size_ = 0;
+  const uint64_t pts_ = 0;
+  const uint64_t duration_ = 0;
+  const uint32_t hdr10p_metadata_size_ = 0;
+  std::shared_ptr<char> hdr10p_metadata_ = nullptr;
+  std::unique_ptr<MatroskaColor> matroska_color_info_ = nullptr;
+};
+
+using EsPacketPtr = EsPacket::Ptr;
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_ESPACKET_H__
\ No newline at end of file
diff --git a/include/plusplayer/esplusplayer.h b/include/plusplayer/esplusplayer.h
new file mode 100755 (executable)
index 0000000..890dbda
--- /dev/null
@@ -0,0 +1,1066 @@
+/**
+ * @file           esplusplayer.h
+ * @brief          the playback for elementary stream
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * 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_ESPLUSPLAYER__H__
+#define __PLUSPLAYER_ESPLUSPLAYER__H__
+
+#include <boost/core/noncopyable.hpp>
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#ifndef IS_AUDIO_PRODUCT
+#include "mixer/mixer.h"
+#endif
+
+#include "plusplayer/appinfo.h"
+#include "plusplayer/audioeasinginfo.h"
+#include "plusplayer/drm.h"
+#include "plusplayer/elementary_stream.h"
+#include "plusplayer/es_eventlistener.h"
+#include "plusplayer/espacket.h"
+#include "plusplayer/external_drm.h"
+#include "plusplayer/types/buffer.h"
+#include "plusplayer/types/display.h"
+#include "plusplayer/types/error.h"
+#include "plusplayer/types/latency.h"
+#include "plusplayer/types/picturequality.h"
+#include "plusplayer/types/resource.h"
+#include "plusplayer/types/submitdata.h"
+
+namespace plusplayer {
+
+/**
+ * @brief  Enumerations for es player state.
+ */
+enum class EsState {
+  kNone,     // Player is created, but not opened
+  kIdle,     // Player is opened, but not prepared or player is stopped
+  kReady,    // Player is ready to play(start)
+  kPlaying,  // Player is playing media
+  kPaused,   // Player is paused while playing media
+};
+/**
+ * @brief  Enumerations for espacket submit status.
+ */
+enum class PacketSubmitStatus {
+  kNotPrepared,    // not prepared to get packet
+  kInvalidPacket,  // invalid packet
+  kOutOfMemory,    // out of memory on device
+  kFull,           // buffer already full
+  kSuccess         // submit succeeded
+};
+/**
+ * @brief  Enumerations for adaptive info type.
+ */
+enum class PlayerAdaptiveInfo {
+  kMinType,
+  kVideoDroppedFrames,
+  kDroppedVideoFramesForCatchup,
+  kDroppedAudioFramesForCatchup,
+  kMaxType,
+};
+/**
+ * @brief   Enumerations for low latency mode
+ */
+enum PlayerLowLatencyMode {
+  kLowLatencyModeNone = 0x0000,
+  /**
+   * @description   to support audio fast decoding/rendering
+   */
+  kLowLatencyModeAudio = 0x0001,
+  /**
+   * @description   to support video fast decoding/rendering
+   *                only this value is set, it does not support seamless resolution change.
+   */
+  kLowLatencyModeVideo = 0x0010,
+  /**
+   * @description   to support video fast decoding/rendering and video
+                    distortion concealment.
+                    Video stream should be composed only of P and I frames.
+                    For applications using the UDP protocol, packet loss can
+                    occur. when video distortion by video packet loss is
+                    detected, it is a function to conceal distortion by showing
+                    previous vido frame. It is supported only in h.264 codec &
+                    FHD or lower resolution.
+   */
+  kLowLatencyModeVideoDistortionConcealment = kLowLatencyModeVideo | 0x0020,
+  /**
+   * @description   to support video fast decoding/rendering and video
+   *                with seamless resolution change.
+   */
+  kLowLatencyModeVideoWithSeamlessResolutionChange = 0x0040,  
+  /**
+   * @description   to disable clock sync and a/v sync when rendering. it
+   *                includes #kLowLatencyModeDisablePreroll.
+   */
+  kLowLatencyModeDisableAVSync = 0x0100,
+  /**
+   * @description   to disable preroll which means player doesn't wait for
+   *                first buffer when state is changed to
+   *                #EsState::kReady from #EsState::kIdle.
+   *                It changes the state immediately.
+   *                It's usually used for sparse stream. (e.g. video packet
+   *                arrives but audio packet does't yet.)
+   */
+  kLowLatencyModeDisablePreroll = 0x0200,
+  /**
+   * @description   to set lower video quality
+   */
+  kLowLatencyModeDisableVideoQuality = 0x1000,
+  /**
+   * @description   to set game mode
+   */
+  kLowLatencyModeEnableGameMode = 0x2000
+};
+
+/**
+ * @brief   Enumerations for player audio codec type
+ */
+enum PlayerAudioCodecType {
+  /**
+   * @description   hardware codec can only be selected, default type
+   */
+  kPlayerAudioCodecTypeHW,
+  /**
+   * @description   software codec can only be selected.
+   */
+  kPlayerAudioCodecTypeSW,
+};
+
+/**
+ * @brief   Enumerations for player video codec type
+ */
+enum PlayerVideoCodecType {
+  /**
+   * @description   hardware codec can only be selected, default type
+   */
+  kPlayerVideoCodecTypeHW,
+  /**
+   * @description   software codec can only be selected.
+   */
+  kPlayerVideoCodecTypeSW,
+  /**
+   * @description   hardware codec using n-decoding mode can only be selected.
+                    It must set display type to mixer type by display setting api.
+   */
+  kPlayerVideoCodecTypeHWNdecoding,
+};
+
+/**
+ * @brief  the interface of the playback class for elementary stream
+ */
+class EsPlusPlayer : private boost::noncopyable {
+ public:
+  using Ptr = std::unique_ptr<EsPlusPlayer>;
+  /**
+   * @brief     Create a esplusplayer object
+   * @remarks   You must use this to get esplusplayer object
+   * @return    Player object (unique_ptr<EsPlusPlayer>)
+   */
+  static Ptr Create();
+
+ public:
+  virtual ~EsPlusPlayer() {}
+  /**
+   * @brief     Make player get ready to set playback mode
+   * @remarks   General call sequence to start playback:
+   *            Open() -> SetStream() -> PrepareAsync() -> Start() -> Stop() ->
+   * Close()
+   * @pre       Player state must be kNone
+   * @post      The player state will be EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       Close()
+   */
+  virtual bool Open() { return false; }
+  /**
+   * @brief     Release all the player resources
+   * @pre       The player state must be one of
+   *            EsState::kIdle or EsState::kNone
+   * @post      The player state will be kNone
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::Open()
+   */
+  virtual bool Close() { return false; }
+
+  /**
+   * @brief     Flush the specific buffered stream data and release TV resource
+   *            to change stream.
+   * @remark    To activate, the stream must be set again.
+   * @pre       The player must be set to at least #EsState::kReady
+   * @post       The player state is same as before calling Deactivate().
+   * @return    @c True on success, otherwise @c False.
+   * @see       EsPlusPlayer::Deactivate().
+   */
+  virtual bool Deactivate(const StreamType type) { return false; }
+
+  /**
+   * @brief     Reprepare for the specific stream playback.
+   * @remark    There must be active stream to prepare playback.
+   * @pre       The player must be set to at least #EsState::kReady
+   *            The StreamType must be deactivated in advance.
+   *            Stream should be set in advance.
+   * @return    @c True on success, otherwise @c False
+   * @code
+      PrepareAsync();
+      Deactivate(StreamType::kVideo);
+      VideoStreamPtr video_stream = VideoStream::Create();
+      video_stream->SetMimeType(VideoMimeType::kH264);
+      video_stream->SetWidth(640);
+      video_stream->SetHeight(352);
+      video_stream->SetFramerate(30, 1);
+      SetStream(video_stream);
+      Activate(StreamType::kVideo);
+   * @endcode
+   * @see       EsPlusPlayer::Activate()
+   */
+  virtual bool Activate(const StreamType type) { return false; }
+
+  /**
+   * @brief     Prepare the player for playback, asynchronously.
+   * @remarks   EsEventListener::OnPrepareDone() will be called when prepare is
+   * finished
+   *
+   * @pre       The player state must be set to #EsState::kIdle
+   * @post      The player state will be #EsState::kReady
+   * @return    @c true if async task is correctly started
+   * @see       EsPlusPlayer::Open() \n
+   *            EsPlusPlayer::Stop() \n
+   *            EsPlusPlayer::SubmitPacket()
+   */
+  virtual bool PrepareAsync() { return false; }
+  /**
+   * @brief     Start playback
+   * @pre       The player state should be #EsState::kReady
+   * @post      The player state will be #EsState::kPlaying
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::Open() \n
+   *            EsPlusPlayer::PrepareAsync() \n
+   *            EsPlusPlayer::Stop() \n
+   *            EsPlusPlayer::Close()
+   */
+  virtual bool Start() { return false; }
+  /**
+   * @brief     Stop playing media content
+   * @remarks   EsPlusPlayer::Close() must be called once after player is
+   * stopped
+   * @pre       The player state must be all of #EsState except #EsState::kNone
+   * @post      The player state will be #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::Open() \n
+   *            EsPlusPlayer::PrepareAsync() \n
+   *            EsPlusPlayer::Start() \n
+   *            EsPlusPlayer::Pause() \n
+   *            EsPlusPlayer::Resume() \n
+   *            EsPlusPlayer::Close()
+   */
+  virtual bool Stop() { return false; }
+  /**
+   * @brief     Pause playing media content
+   * @remarks   You can resume playback by using EsPlusPlayer::Resume()
+   * @pre       The player state must be one of #EsState::kReady or
+   * #EsState::kPlaying or #EsState::kPaused
+   * @post      The player state will be #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::Start() \n
+   *            EsPlusPlayer::Resume()
+   */
+  virtual bool Pause() { return false; }
+  /**
+   * @brief     Resume a media content
+   * @pre       The player state must be one of #EsState::kPlaying or
+   * #EsState::kPaused
+   * @post      The player state will be #EsState::kPlaying
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::Start() \n
+   *            EsPlusPlayer::Pause()
+   */
+  virtual bool Resume() { return false; }
+  /**
+   * @brief     SetAppId
+   * @remarks   Set app_id to resource manager. Resource manager check the
+   * priority to control resource.
+   * @param     [in] app_info : application id, version, type
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    None
+   */
+  virtual void SetAppInfo(const PlayerAppInfo& app_info) { return; }
+  /**
+   * @brief     SetPlaybackRate.
+   * @remarks   Set playback rate from 0.0 to 2.0.
+   * @param     [in] rate : The playback rate from 0.0 to 2.0. EsPlayer isn't
+   * support trick play.
+   * @param     [in] audio_mute : The audio is mute on/off,true: mute on, false:
+   * mute off.
+   * @pre       The source and feeder have to push the data as fast as playback
+   * rate.
+   * @return    @c True if set playback rate is finished without any problem
+   * otherwise @c False
+   */
+  virtual bool SetPlaybackRate(const double rate, bool audio_mute) {
+    return false;
+  }
+  /**
+   * @brief     Seek for playback, asynchronously.
+   * @remarks   EsEventListener::OnSeekDone() will be called if seek operation
+   * is finished \n Seek result can be succeeded or not at this moment. \n
+   * @param     [in] time_millisecond : the absolute position(playingtime) of
+   * the stream in milliseconds
+   * @pre       The player state must be one of #EsState::kReady,
+   * #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True if seek operation is started without any problem
+   * otherwise @c False
+   * @see       EsEventListener::OnSeekDone() \n
+   *            EsPlusPlayer::SubmitPacket()
+   */
+  virtual bool Seek(const uint64_t time_millisecond) { return false; }
+  /**
+   * @brief     Set the video display
+   * @remarks   We are not supporting changing display.
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync() to reflect the display type.
+   * @param     [in] type : display type
+   * @param     [in] obj : The handle to display window
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayType \n
+   *            EsPlusPlayer::SetDisplayMode() \n
+   *            EsPlusPlayer::SetDisplayRoi() \n
+   *            EsPlusPlayer::SetDisplayVisible()
+   */
+  virtual bool SetDisplay(const DisplayType& type, void* obj) { return false; }
+#ifndef IS_AUDIO_PRODUCT
+  /**
+   * @brief     Set the video display
+   * @remarks   We are not supporting changing display.
+   * @remarks   This API have to be called before calling the
+   * PlusPlayer::Prepare()
+   *            or PlusPlayer::PrepareAsync() to reflect the display type.
+   * @param     [in] type : display type
+   * @param     [in] handle : The handle of mixer ticket
+   * @pre       The player state must be set to #EsState::kIdle
+   * @post      None
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayType
+   *            PlusPlayer::SetDisplayRoi()
+   *            PlusPlayer::SetDisplayVisible()
+   * @exception  None
+   */
+  virtual bool SetDisplay(const DisplayType& type, MixerTicket* handle) {
+    return false;
+  }
+#endif
+  /**
+   * @brief     Set the video display
+   * @remarks   We are not supporting changing display.
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync() to reflect the display type.
+   * @param     [in] type : display type
+   * @param     [in] ecore_wl2_window : The ecore wayland window handle
+   * @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
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayType \n
+   *            EsPlusPlayer::SetDisplayMode() \n
+   *            EsPlusPlayer::SetDisplayRoi() \n
+   *            EsPlusPlayer::SetDisplayVisible()
+   */
+  virtual bool SetDisplay(const DisplayType& type, void* ecore_wl2_window,
+                          const int x, const int y, const int w, const int h) {
+    return false;
+  }
+  /**
+   * @brief     Set the video display
+   * @remarks   We are not supporting changing display.
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync() to reflect the display type.
+   * @param     [in] type : display type
+   * @param     [in] ecore_wl2_subsurface : The ecore wayland subsurface handle
+   * @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
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayType \n
+   *            EsPlusPlayer::SetDisplayMode() \n
+   *            EsPlusPlayer::SetDisplayRoi() \n
+   *            EsPlusPlayer::SetDisplayVisible()
+   */
+  virtual bool SetDisplaySubsurface(const DisplayType& type,
+                                    void* ecore_wl2_subsurface, const int x,
+                                    const int y, const int w, const int h) {
+    return false;
+  }
+  /**
+   * @brief     Set the video display
+   * @remarks   We are not supporting changing display.
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync() to reflect the display type.
+   * @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
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayType \n
+   *            EsPlusPlayer::SetDisplayMode() \n
+   *            EsPlusPlayer::SetDisplayRoi() \n
+   *            EsPlusPlayer::SetDisplayVisible()
+   */
+  virtual bool SetDisplay(const DisplayType& type, unsigned int surface_id,
+                          const int x, const int y, const int w, const int h) {
+    return false;
+  }
+  /**
+   * @brief     Set the video display mode
+   * @param     [in] mode : display mode
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   * @see       #DisplayMode
+   * @see       EsPlusPlayer::SetDisplay()
+   * @see       EsPlusPlayer::SetDisplayRoi()
+   * @see       EsPlusPlayer::SetDisplayVisible()
+   */
+  virtual bool SetDisplayMode(const DisplayMode& mode) { return false; }
+  /**
+   * @brief     Set the ROI(Region Of Interest) area of display
+   * @remarks   The minimum value of width and height are 1.
+   * @param     [in] roi : Roi Geometry
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * \n Before set display ROI, #DisplayMode::kDstRoi must be set with
+   * EsPlusPlayer::SetDisplayMode().
+   * @return    @c True on success, otherwise @c False
+   * @see       DisplayMode \n
+   *            EsPlusPlayer::SetDisplay() \n
+   *            EsPlusPlayer::SetDisplayMode() \n
+   *            EsPlusPlayer::SetDisplayVisible()
+   */
+  virtual bool SetDisplayRoi(const Geometry& roi) { return false; }
+
+  /**
+   * @brief     Set scaled area ratio of display
+   * @param     [in] area : Crop ratio of src area
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   * @remark    The minimum value of input are 0,maximun is 1.
+   */
+  virtual bool SetVideoRoi(const CropArea& area) { return false; }
+
+  /**
+   * @brief     Resize the render rectangle(the max region that video can be
+   * displayed).
+   * @param     [in] rect : render rectangle.
+   * @pre       Should be called after SetDisplay()
+   * @return    @c True on success, otherwise @c False
+   * @remark    The minimum value of width and height are 1.
+   */
+  virtual bool ResizeRenderRect(const RenderRect& rect) { return false; }
+
+  /**
+   * @brief     Set the rotate angle of display
+   * @remarks   The default value is 0.
+   * @param     [in] rotate : Rotate angle.
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::SetDisplay()
+   */
+  virtual bool SetDisplayRotate(const DisplayRotation& rotate) { return false; }
+
+  /**
+   * @brief     Get the rotate angle of display
+   * @remarks   The default value is 0.
+   * @param     [out] rotate : Stored rotate angle value.
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::SetDisplayRotate()
+   */
+  virtual bool GetDisplayRotate(DisplayRotation* rotate) { return false; }
+
+  /**
+   * @brief     Set the visibility of the video display
+   * @param     [in] is_visible : The visibility of the display
+   *            (@c true = visible, @c false = non-visible)
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::SetDisplay()
+   */
+  virtual bool SetDisplayVisible(bool is_visible) { return false; }
+
+  /**
+   * @deprecated Use SetSubmitDataType instead.
+   * @brief     Set whether to send decrypted es packets in the trust zone
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync() \n If is_using_tz is set to true, use
+   * EsPlusPlayer::SubmitTrustZonePacket() to send decrypted packets \n
+   * @param     [in] is_using_tz : whether to use trust zone memory
+   *            (@c true = if decrypted packets are sent in trust zone, @c false
+   * = otherwise)
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::SubmitTrustZonePacket()
+   */
+  virtual bool SetTrustZoneUse(bool is_using_tz) { return false; }
+  /**
+   * @brief     Set whether to send decrypted es packets in the trust zone or
+   * encrypted es packets
+   * @remarks   This API have to be called before calling the
+   *            EsPlusPlayer::PrepareAsync() \n
+   *            If type is kCleanData, Use SubmitPacket() \n
+   *            If type is kTrustZoneData, Use SubmitTrustZonePacket() \n
+   *            If type is kEncryptedData, Use SubmitEncryptedPacket()
+   * @param     [in] type : whether to use trust zone memory or encrypted data
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       EsPlusPlayer::SubmitPacket() \n
+   *            EsPlusPlayer::SubmitTrustZonePacket() \n
+   *            EsPlusPlayer::SubmitEncryptedPacket() \\n
+   *            SubmitDataType
+   */
+  virtual bool SetSubmitDataType(SubmitDataType type) { return false; }
+  /**
+   * @brief     Set audio stream to have contents information
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync()
+   * @param     [in] stream : audio stream object
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       AudioStream
+   */
+  virtual bool SetStream(const AudioStreamPtr& stream) { return false; }
+  /**
+   * @brief     Set video stream to have contents information
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync()
+   * @param     [in] stream : video stream object
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   * @see       VideoStream
+   */
+  virtual bool SetStream(const VideoStreamPtr& stream) { return false; }
+  /**
+   * @brief     Submit es packet to decode audio or video
+   * @remarks   Amount of packets for at least one decoded frame must be
+   * submitted after EsPlusPlayer::PrepareAsync() or EsPlusPlayer::Seek() for
+   * calling the EsPlusPlayer::OnPrepareDone() or EsPlusPlayer::OnSeekDone() \n
+   *            User can submit es packets when EsPlusPlayer::OnReadyToPrepare()
+   *            or EsPlusPlayer::OnReadyToSeek() is called \n
+   *            To use this api, Must set SubmitDataType::kCleanData using
+   *            SetSubmitDataType() or Don't set any SubmitDataType \n
+   *            This api must be called from a different thread than other apis
+   * @param     [in] packet : es packet object
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c PacketSubmitStatus::kSuccess : succeed to submit es packet
+   *            @c otherwise : fail to submit es packet
+   * @see       SetSubmitDataType() \n
+   *            EsPacket \n
+   *            OnBufferStatus \n
+   *            OnReadyToPrepare \n
+   *            OnReadyToSeek \n
+   *            PacketSubmitStatus
+   */
+  virtual PacketSubmitStatus SubmitPacket(const EsPacketPtr& packet) {
+    return PacketSubmitStatus::kNotPrepared;
+  }
+  /**
+   * @brief     Submit es packet to decode audio or video in the trust zone
+   * @remarks   Amount of decrypted packets for at least one decoded frame must
+   * be submitted after EsPlusPlayer::PrepareAsync() or EsPlusPlayer::Seek() for
+   * calling the EsPlusPlayer::OnPrepareDone() or EsPlusPlayer::OnSeekDone() \n
+   *            User can submit es packets when EsPlusPlayer::OnReadyToPrepare()
+   *            or EsPlusPlayer::OnReadyToSeek() is called \n
+   *            EsPlusPlayer::SetTrustZoneUse() must be set to true \n
+   *            To use this api, Must set SubmitDataType::kTrustZoneData using
+   *            SetSubmitDataType() \n
+   *            This api must be called from a different thread than other apis.
+   * @param     [in] packet : es packet object
+   *            [in] tz_handle : a handle for es packet in the trust zone
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c PacketSubmitStatus::kSuccess : succeed to submit es packet
+   *            @c otherwise : fail to submit es packet
+   * @see       SetSubmitDataType() \n
+   *            EsPacket \n
+   *            OnBufferStatus \n
+   *            OnReadyToPrepare \n
+   *            OnReadyToSeek \n
+   *            PacketSubmitStatus
+   */
+  virtual PacketSubmitStatus SubmitTrustZonePacket(const EsPacketPtr& packet,
+                                                   uint32_t tz_handle = 0) {
+    return PacketSubmitStatus::kNotPrepared;
+  }
+  /**
+   * @brief     Submit encrypted es packet to decode audio or video
+   * @remarks   Amount of encrypted packets for at least one decoded frame must
+   * be submitted after EsPlusPlayer::PrepareAsync() or EsPlusPlayer::Seek() for
+   * calling the EsPlusPlayer::OnPrepareDone() or EsPlusPlayer::OnSeekDone()
+   *            User can submit es packets when EsPlusPlayer::OnReadyToPrepare()
+   *            or EsPlusPlayer::OnReadyToSeek() is called \n
+   *            EsPlusPlayer::SetDrm() must be set to an appropriate drm type \n
+   *            To use this api, Must set SubmitDataType::kEncryptedData using
+   *            SetSubmitDataType() \n
+   *            This api must be called from a different thread than other apis.
+   * @param     [in] packet : encrypted es packet object
+   *            [in] drm_info : information for decryption
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c PacketSubmitStatus::kSuccess : succeed to submit es packet
+   *            @c PacketSubmitStatus::kFull, PacketSubmitStatus::kNotPrepared :
+   * fail to submit es packet
+   * @see       SetSubmitDataType() \n
+   *            EsPacket \n
+   *            OnBufferStatus \n
+   *            OnReadyToPrepare \n
+   *            OnReadyToSeek \n
+   *            PacketSubmitStatus
+   */
+  virtual PacketSubmitStatus SubmitEncryptedPacket(
+      const EsPacketPtr& packet, const drm::EsPlayerEncryptedInfo& drm_info) {
+    return PacketSubmitStatus::kNotPrepared;
+  }
+  /**
+   * @brief     Get current state of player
+   * @return    current #EsState of player
+   */
+  virtual EsState GetState() { return EsState::kNone; }
+  /**
+   * @brief     Get the current playing time of the associated media.
+   * @param     [out] time_in_milliseconds : current playing time in
+   * milliseconds
+   * @pre       The player must be one of #EsState::kPlaying or
+   * #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   *            ("time_in_milliseconds" will be 0)
+   */
+  virtual bool GetPlayingTime(uint64_t* time_in_milliseconds) { return false; }
+  /**
+   * @brief     Get the adaptive info from the plugins
+   * @param     [in] adaptive_type : App wanted get info type
+   * @param     [out] padaptive_info : return value of requested(such as dropped
+   *                   frames)
+   * @pre       The player must be one of #EsState::kPlaying or
+   * #EsState::kPaused or #EsState::kReady
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool GetAdaptiveInfo(void* padaptive_info,
+                               const PlayerAdaptiveInfo& adaptive_type) {
+    return false;
+  }
+  /**
+   * @brief     Set on mute of the audio sound
+   * @param     [in] is_mute : On mute of the sound
+   *            (@c true = mute, @c false = non-mute)
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAudioMute(bool is_mute) { return false; }
+
+  /**
+   * @brief     Set decoded video frame buffer type.
+   * @param     [in] type : A type of decoded video frame buffer.
+   * @pre       The player state must be set to #EsState::kIdle
+   */
+  virtual bool SetVideoFrameBufferType(DecodedVideoFrameBufferType type) {
+    return false;
+  }
+
+  /**
+   * @brief     Set the request frame rate of decoded video
+   * @remarks   Only works when decoded video frame buffer type is scale
+   * @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.
+   * @pre       The player state must be not #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetDecodedVideoFrameRate(const Rational& request_framerate) {
+    return false;
+  }
+
+  /**
+   * @brief     Set the target scale resolution when decoded video frame buffer
+   * type is scale
+   * @param     [in] target_width : target width of scale.
+   * @param     [in] target_height : target height of scale.
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetVideoFrameBufferScaleResolution(
+      const uint32_t& target_width, const uint32_t& target_height) {
+    return false;
+  }
+
+  /**
+   * @brief     Register eventlistener to player
+   * @param     [in] listener : listener object
+   * @param     [in] userdata : listener object's userdata to be returned via
+   *                            notification without any modification
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @see       EsEventListener
+   */
+  virtual void RegisterListener(EsEventListener* listener,
+                                EsEventListener::UserData userdata) {
+    return;
+  }
+  /**
+   * @brief     Set volume to player
+   * @param     [in] volume : volume level
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return       @c True on success, otherwise @c False
+   */
+  virtual bool SetVolume(const int& volume) { return false; }
+  /**
+   * @brief     Get volume to player
+   * @param     [out] volume : volume ptr
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return       @c True on success, otherwise @c False
+   */
+  virtual bool GetVolume(int* volume) { return false; }
+  /**
+   * @brief     Flush the data in pipeline
+   * @param     [in] type : can be kAudio/kVideo
+   * @pre       The player state can greater than #EsState::kIdle
+   * @return       @c True on success, otherwise @c False
+   */
+  virtual bool Flush(const StreamType& type) { return false; }
+  /**
+   * @brief     Set the buffer size
+   * @param     [in] option : A type of Buffer Option
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return       @c True on success, otherwise @c False
+   */
+  virtual void SetBufferSize(const BufferOption& option, uint64_t size) {
+    return;
+  }
+  /**
+   * @brief     Provided api for setting low latency mode
+   * @remarks   This API have to be called before calling the
+   * EsPlusPlayer::PrepareAsync()
+   * @param     [in] mode : one of the low latency mode to set.
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetLowLatencyMode(const PlayerLowLatencyMode& mode) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for enabling video frame peek mode
+   * @pre       The player state must be set to #EsState::kIdle.
+   * @return    @c True on success, otherwise @c False
+   * @see       RenderVideoFrame().
+   */
+  virtual bool SetVideoFramePeekMode() { return false; }
+
+  /**
+   * @brief     Provided api for rendering a video frame which is holded by
+   * video frame peek mode.
+   * @pre       In order to use this api, The player state must be one of
+   * #EsState::kReady or #EsState::kPaused after EsEventListener::OnSeekDone()
+   * or EsEventListener::OnPrepareDone() is called \n
+   * @see       SetVideoFramePeekMode().
+   */
+  virtual bool RenderVideoFrame() { return false; }
+  /**
+   * @brief     Provided api for setting unlimited max buffer mode
+   * @remarks   The player does not limit es packet transmission although in
+   *            buffer overrun status.
+   * @pre       The player state must be set to #EsState::kIdle
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetUnlimitedMaxBufferMode() { return false; }
+  /**
+   * @brief     Provided api for enabling fmm mode
+   * @pre       The player state must be set to #EsState::kIdle.
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetFmmMode() { return false; }
+  /**
+   * @brief     Provided api for setting audio codec type
+   * @pre       The player state must be set to #EsState::kIdle.
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAudioCodecType(const PlayerAudioCodecType& type) {
+    return false;
+  }
+  /**
+   * @brief     Provided api for setting video codec type
+   * @pre       The player state must be set to #EsState::kIdle.
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetVideoCodecType(const PlayerVideoCodecType& type) {
+    return false;
+  }
+  /**
+   * @brief     Provided api for setting alternative video resource(sub decoder
+   *            and sub scaler)
+   * @param     [in] is_set : set alternative video resource
+   *            (@c 0 [defualt] = set all video resources(decoder/scaler) to
+   *                              main resources,
+   *             @c 1 = set all video resources(decoder/scaler) to sub
+   *                    resources,
+   *             @c 2 = set only decoder to sub resource,
+   *             @c 3 = set only scaler to sub resource)
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAlternativeVideoResource(unsigned int rsc_type) {
+    return false;
+  }
+  /**
+   * @brief     Provided api for switching audio stream between the different
+   *            audio codec types on the fly
+   * @param     [in] stream : audio stream object
+   * @remark    Audio stream can be switched between only #AudioMimeType::kAAC,
+   *            #AudioMimeType::kEac3 and #AudioMimeType::kAC3.
+   *            if other codec type is set, this api will return false.
+   * @pre       The player state must be one of #EsState::kReady,
+   *            #EsState::kPlaying, #EsState::kPaused.
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SwitchAudioStreamOnTheFly(const AudioStreamPtr& stream) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for setting aifilter to video pipeline
+   * @pre       The player state must be set to #EsState::kIdle.
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAiFilter(void* aifilter) { return false; }
+  /**
+   * @brief     Provided api for setting render time offset
+   * @param     [in] type : stream type
+   * @param     [in] offset : offset (milisecond).
+   * @pre       The player state must be set to #EsState::kReady,
+   *            #EsState::kPaused or #EsState::kPlaying.
+   *            It have to be set to low latency mode.
+   * @remark    esplusplayer_set_low_latency_mode().
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetRenderTimeOffset(const StreamType type, int64_t offset) {
+    return false;
+  }
+  /**
+   * @brief     Provided api for getting render time offset
+   * @param     [in] type : stream type
+   * @param     [in] offset : offset ptr (milisecond).
+   * @pre       The player state must be set to #EsState::kReady,
+   *            #EsState::kPaused or #EsState::kPlaying.
+   *            It have to be set to low latency mode.
+   * @remark    esplusplayer_set_low_latency_mode().
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool GetRenderTimeOffset(const StreamType type, int64_t* offset) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for setting catch up speed level
+   * @pre       The player state must be set to #EsState::kIdle,
+   *            #EsState::kReady, #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetCatchUpSpeed(const CatchUpSpeed& level) { return false; }
+  /**
+   * @brief     Provided api for getting current video latency status
+   * @pre       The player state must be one of #EsState::kReady,
+   *            #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool GetVideoLatencyStatus(LatencyStatus* status) { return false; }
+  /**
+   * @brief     Provided api for getting current audio latency status
+   * @pre       The player state must be one of #EsState::kReady,
+   *            #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool GetAudioLatencyStatus(LatencyStatus* status) { return false; }
+  /**
+   * @brief     Provided api for setting video mid latency threshold for low
+   * latency playback
+   * @pre       The player state must be set to #EsState::kIdle,
+   *            #EsState::kReady, #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetVideoMidLatencyThreshold(const unsigned int threshold) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for setting audio mid latency threshold for low
+   * latency playback
+   * @pre       The player state must be set to #EsState::kIdle,
+   *            #EsState::kReady, #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAudioMidLatencyThreshold(const unsigned int threshold) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for setting video high latency threshold for low
+   * latency playback
+   * @pre       The player state must be set to #EsState::kIdle,
+   *            #EsState::kReady, #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetVideoHighLatencyThreshold(const unsigned int threshold) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for setting audio high latency threshold for low
+   * latency playback
+   * @pre       The player state must be set to #EsState::kIdle,
+   *            #EsState::kReady, #EsState::kPlaying or #EsState::kPaused
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool SetAudioHighLatencyThreshold(const unsigned int threshold) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for initializing audio easing information
+   * @param     [in] init_volume : initial volume
+   * @param     [in] init_elapsed_time : initail elapsed time (milisecond).
+   * @param     [in] easing_info : target_volume, duration(milisecond), easing
+   * type
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool InitAudioEasingInfo(const uint32_t init_volume,
+                                   const uint32_t init_elapsed_time,
+                                   const AudioEasingInfo& easing_info) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for updating audio easing information
+   * @param     [in] easing_info : target_volume, duration(milisecond), easing
+   * type
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @remarks   This API have to be called after calling the
+   * EsPlusPlayer::InitAudioEasingInfo()
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool UpdateAudioEasingInfo(const AudioEasingInfo& easing_info) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for getting audio easing information
+   * @param     [out] current_volume : current volume
+   * @param     [out] elapsed_time : elapsed time (milisecond).
+   * @param     [out] easing_info : target_volume, duration(milisecond), easing
+   * type
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @remarks   This API have to be called after calling the
+   * EsPlusPlayer::InitAudioEasingInfo()
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool GetAudioEasingInfo(uint32_t* current_volume,
+                                  uint32_t* elapsed_time,
+                                  AudioEasingInfo* easing_info) {
+    return false;
+  }
+
+  /**
+   * @brief     Provided api for starting audio easing
+   * @pre       The player state should be at least #EsState::kReady
+   * @remarks   This API have to be called after calling the
+   * EsPlusPlayer::InitAudioEasingInfo()
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool StartAudioEasing() { return false; }
+
+  /**
+   * @brief     Provided api for stopping audio easing
+   * @pre       The player state can be all of #EsState except #EsState::kNone
+   * @remarks   This API have to be called after calling the
+   * EsPlusPlayer::InitAudioEasingInfo()
+   * @return    @c True on success, otherwise @c False
+   */
+  virtual bool StopAudioEasing() { return false; }
+
+  /**
+   * @brief     Get virtual resource id
+   * @param     [in] type : The resource type of virtual id.
+   * @param     [out] virtual_id : Stored virtual resource id value.
+   * @pre       The player state should be #EsState::kReady, #EsState::kPlaying
+   * or #EsState::kPaused
+   * @post      None
+   * @return    @c True on success, otherwise @c False ("virtual_id" will be -1)
+   * @exception  None
+   */
+  virtual bool GetVirtualRscId(const RscType type, int* virtual_id) {
+    return false;
+  }
+
+  /**
+   * @brief     Set advanced picture quality type.
+   * @param     [in] type : The picture quality type.
+   * @pre       The player state must be set to #EsState::kIdle.
+   * @post      None
+   * @return    @c True on success, otherwise @c False
+   * @exception  None
+   */
+  virtual bool SetAdvancedPictureQualityType(const AdvPictureQualityType type) {
+    return false;
+  }
+
+  /**
+   * @brief     Set resource allocate policy.
+   * @param     [in] policy : The resource allocate policy.
+   * @pre       The player state must be set to #EsState::kIdle.
+   * @post      None
+   * @return    @c True on success, otherwise @c False
+   * @exception  None
+   */
+  virtual bool SetResourceAllocatePolicy(const RscAllocPolicy policy) {
+    return false;
+  }
+
+ protected:
+  EsPlusPlayer() noexcept {};
+};  // class EsPlusPlayer
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_ESPLUSPLAYER__H__
diff --git a/include/plusplayer/external_drm.h b/include/plusplayer/external_drm.h
new file mode 100755 (executable)
index 0000000..226c038
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+ * @file           external_drm.h
+ * @brief          the extrnal drm information for elementary stream
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * 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_EXTERNAL_DRM_H__
+#define __PLUSPLAYER_EXTERNAL_DRM_H__
+
+#include <array>
+#include <string>
+#include <vector>
+
+namespace plusplayer {
+
+namespace drm {
+
+using MetaData = void*;
+/**
+ * @brief  Enumerations for cipher algorithm for drm
+ */
+enum class DrmbEsCipherAlgorithm : int {
+  kUnknown = -1,
+  kRc4 = 0,
+  kAes128Ctr = 1,
+  kAes128Cbc = 2
+};
+/**
+ * @brief  Enumerations for media format for drm
+ */
+enum class DrmbEsMediaFormat : int {
+  kNone = 0,
+  kFragmentedMp4 = 1,
+  kTs = 2,
+  kAsf = 3,
+  kFragmentedMp4Audio = 4,
+  kFragmentedMp4Video = 5,
+  kCleanAudio = 6,  // Clean Audio Data
+  kPes = 7,         // Packetized ES
+};
+/**
+ * @brief  Enumerations for cipher phase for drm
+ */
+enum class DrmbEsCipherPhase : int {
+  kNone = 0,
+  kInit = 1,
+  kUpdate = 2,
+  kFinal = 3
+};
+/**
+ * @brief  Structure of subsample information for drm
+ */
+struct DrmbEsSubSampleInfo {
+  explicit DrmbEsSubSampleInfo(const uint32_t _bytes_of_clear_data,
+                               const uint32_t _bytes_of_encrypted_data)
+      : bytes_of_clear_data(_bytes_of_clear_data),
+        bytes_of_encrypted_data(_bytes_of_encrypted_data) {}
+  uint32_t bytes_of_clear_data;
+  uint32_t bytes_of_encrypted_data;
+};
+/**
+ * @brief  Structure of fragmented mp4 data for drm
+ */
+struct DrmbEsFragmentedMp4Data {
+  std::vector<DrmbEsSubSampleInfo> sub_sample_info_vector;
+};
+/**
+ * @brief  Structure of encrypted information for es playback
+ */
+struct EsPlayerEncryptedInfo {
+  int32_t handle = 0;
+
+  DrmbEsCipherAlgorithm algorithm = DrmbEsCipherAlgorithm::kUnknown;
+  DrmbEsMediaFormat format = DrmbEsMediaFormat::kNone;
+  DrmbEsCipherPhase phase = DrmbEsCipherPhase::kNone;
+
+  std::vector<unsigned char> kid;
+  std::vector<unsigned char> initialization_vector;
+
+  MetaData sub_data = nullptr;
+  std::array<int, 15> split_offsets;
+
+  bool use_out_buffer = false;
+  bool use_pattern = false;
+
+  uint32_t crypt_byte_block = 0;
+  uint32_t skip_byte_block = 0;
+};
+
+}  // namespace drm
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_EXTERNAL_DRM_H__
diff --git a/include/plusplayer/track.h b/include/plusplayer/track.h
new file mode 100755 (executable)
index 0000000..5a13cd9
--- /dev/null
@@ -0,0 +1,161 @@
+/**
+* @file           
+* @interfacetype  module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        1.0
+* @SDK_Support    N
+*
+* 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_TRACK_H__
+#define __PLUSPLAYER_TRACK_H__
+
+#include <boost/any.hpp>
+#include <boost/core/noncopyable.hpp>
+#include <cstdint>
+#include <limits>
+#include <list>
+#include <memory>
+#include <string>
+
+namespace plusplayer {
+
+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;
+  std::string container_type;
+  TrackType type = kTrackTypeMax;
+  std::shared_ptr<char> codec_data;
+  unsigned int codec_tag = 0;
+  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;
+  Track() {};
+  Track(int _index, int _id, std::string _mimetype, std::string _streamtype, std::string _container_type,
+    TrackType _type, std::shared_ptr<char> _codec_data, unsigned int _codec_tag,  int _codec_data_len,
+    int _width, int _height, int _maxwidth, int _maxheight, int _framerate_num, int _framerate_den,
+    int _sample_rate, int _sample_format, int _channels, int _version, int _layer, int _bits_per_sample,
+    int _block_align, int _bitrate, int _endianness, bool _is_signed, bool _active, bool _use_swdecoder,
+    std::string _language_code, std::string _subtitle_format)
+     : index(_index), id(_id), mimetype(_mimetype), streamtype(_streamtype), container_type(_container_type),
+    type(_type), codec_data(_codec_data), codec_tag(_codec_tag),  codec_data_len(_codec_data_len),
+    width(_width), height(_height), maxwidth(_maxwidth), maxheight(_maxheight), framerate_num(_framerate_num), framerate_den(_framerate_den),
+    sample_rate(_sample_rate), sample_format(_sample_format), channels(_channels), version(_version), layer(_layer), bits_per_sample(_bits_per_sample),
+    block_align(_block_align), bitrate(_bitrate), endianness(_endianness), is_signed(_is_signed), active(_active), use_swdecoder(_use_swdecoder),
+    language_code(_language_code), subtitle_format(_subtitle_format) {};
+};
+
+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>;
+struct Rational {
+  int num = 0;     // the numerator value
+  int den = 0;     // the denominator value
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TRACK_H__
\ No newline at end of file
diff --git a/include/plusplayer/types/buffer.h b/include/plusplayer/types/buffer.h
new file mode 100755 (executable)
index 0000000..2dc5737
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * @file
+ * @brief          the buffer for playback
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * 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_TYPES_BUFFER_H__
+#define __PLUSPLAYER_TYPES_BUFFER_H__
+
+#include <cstdint>
+
+#include "tbm_type.h"
+
+namespace plusplayer {
+
+/**
+ * @brief  Enumerations for the buffer status
+ */
+enum class BufferStatus { kUnderrun, kOverrun };
+
+enum class DecodedVideoFrameBufferType { kNone, kCopy, kReference, kScale };
+
+enum class BufferOption {
+  kBufferAudioMaxTimeSize,
+  kBufferVideoMaxTimeSize,
+  kBufferAudioMinTimeThreshold,
+  kBufferVideoMinTimeThreshold,
+  kBufferAudioMaxByteSize,
+  kBufferVideoMaxByteSize,
+  kBufferAudioMinByteThreshold,
+  kBufferVideoMinByteThreshold,
+  kBufferOptionMax
+};
+
+struct DecodedVideoPacket {
+  uint64_t pts = 0;
+  uint64_t duration = 0;
+  tbm_surface_h surface_data = nullptr;  // tbm_surface
+  void* scaler_index = nullptr;
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_BUFFER_H__
diff --git a/include/plusplayer/types/display.h b/include/plusplayer/types/display.h
new file mode 100755 (executable)
index 0000000..c05c738
--- /dev/null
@@ -0,0 +1,82 @@
+/**
+ * @file
+ * @interfacetype  module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        1.0
+ * @SDK_Support    N
+ *
+ * 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_TYPES_DISPLAY_H__
+#define __PLUSPLAYER_TYPES_DISPLAY_H__
+
+namespace plusplayer {
+
+enum class DisplayType { kNone, kOverlay, kEvas, kMixer };
+
+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;
+};
+
+enum class VisibleStatus { kHide, kVisible };
+
+struct DisplayInfo {
+  Geometry geometry;
+  CropArea croparea;
+  VisibleStatus visible_status = VisibleStatus::kVisible;
+};
+
+enum class StillMode { kNone, kOff, kOn };
+
+struct DisplayObject {
+  DisplayType type_;
+  int surface_id_;
+  DisplayMode mode_;
+  Geometry geometry_;
+  void* obj_;
+  bool is_obj_ = false;
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_DISPLAY_H__
diff --git a/include/plusplayer/types/error.h b/include/plusplayer/types/error.h
new file mode 100755 (executable)
index 0000000..d73cc05
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+* @file           
+* @interfacetype  module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        1.0
+* @SDK_Support    N
+*
+* 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_TYPES_ERROR_H__
+#define __PLUSPLAYER_TYPES_ERROR_H__
+
+#include "tizen.h"
+
+namespace plusplayer {
+
+#define PLUSPLAYER_ERROR_CLASS          TIZEN_ERROR_PLAYER | 0x20
+
+/* This is for custom defined player error. */
+#define PLUSPLAYER_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    = PLUSPLAYER_ERROR_CLASS | 0x01,                /**< Seek operation failure */
+  kInvalidState  = PLUSPLAYER_ERROR_CLASS | 0x02,                /**< Invalid state */
+  kNotSupportedFile = PLUSPLAYER_ERROR_CLASS | 0x03,            /**< File format not supported */
+  kInvalidUri    = PLUSPLAYER_ERROR_CLASS | 0x04,                /**< Invalid URI */
+  kSoundPolicy   = PLUSPLAYER_ERROR_CLASS | 0x05,                /**< Sound policy error */
+  kConnectionFailed  = PLUSPLAYER_ERROR_CLASS | 0x06,            /**< Streaming connection failed */
+  kVideoCaptureFailed   = PLUSPLAYER_ERROR_CLASS | 0x07,        /**< Video capture failed */
+  kDrmExpired    = PLUSPLAYER_ERROR_CLASS | 0x08,                /**< Expired license */
+  kDrmNoLicense         = PLUSPLAYER_ERROR_CLASS | 0x09,            /**< No license */
+  kDrmFutureUse         = PLUSPLAYER_ERROR_CLASS | 0x0a,            /**< License for future use */
+  kDrmNotPermitted  = PLUSPLAYER_ERROR_CLASS | 0x0b,            /**< Format not permitted */
+  kResourceLimit     = PLUSPLAYER_ERROR_CLASS | 0x0c,            /**< Resource limit */
+  kPermissionDenied  = TIZEN_ERROR_PERMISSION_DENIED,        /**< Permission denied */
+  kServiceDisconnected = PLUSPLAYER_ERROR_CLASS | 0x0d,          /**< Socket connection lost (Since 3.0) */
+  kBufferSpace         = TIZEN_ERROR_BUFFER_SPACE,           /**< No buffer space available (Since 3.0)*/
+  kNotSupportedAudioCodec = PLUSPLAYER_ERROR_CLASS | 0x0e, /**< Not supported audio codec but video can be played (Since 4.0) */
+  kNotSupportedVideoCodec = PLUSPLAYER_ERROR_CLASS | 0x0f, /**< Not supported video codec but audio can be played (Since 4.0) */
+  kNotSupportedSubtitle = PLUSPLAYER_ERROR_CLASS | 0x10, /**< Not supported subtitle format (Since 4.0) */
+
+  kDrmInfo = PLUSPLAYER_CUSTOM_ERROR_CLASS | 0x05,              /**< playready drm error info */
+  kNotSupportedFormat = PLUSPLAYER_CUSTOM_ERROR_CLASS | 0x08,
+  kStreamingPlayer = PLUSPLAYER_CUSTOM_ERROR_CLASS | 0x09,
+  kDtcpFsk = PLUSPLAYER_CUSTOM_ERROR_CLASS | 0x0a,
+  kPreLoadingTimeOut =PLUSPLAYER_CUSTOM_ERROR_CLASS | 0x0b, /**< can't finish preloading in time*/
+  kNetworkError = PLUSPLAYER_CUSTOM_ERROR_CLASS | 0x0c,     /**< for network error */
+  kChannelSurfingFailed = PLUSPLAYER_CUSTOM_ERROR_CLASS | 0x0d, /**< for channel surfing error */
+
+  kUnknown
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_ERROR_H__
diff --git a/include/plusplayer/types/event.h b/include/plusplayer/types/event.h
new file mode 100755 (executable)
index 0000000..fb6305d
--- /dev/null
@@ -0,0 +1,55 @@
+/**\r
+ * @file\r
+ * @brief          The event for playback.\r
+ * @interfacetype  Module\r
+ * @privlevel      None-privilege\r
+ * @privilege      None\r
+ * @product        TV, AV, B2B\r
+ * @version        1.0\r
+ * @SDK_Support    N\r
+ * @remark         This is a group of C style event related enum and structure.\r
+ * @see            N/A\r
+ *\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved\r
+ * PROPRIETARY/CONFIDENTIAL\r
+ * This software is the confidential and proprietary\r
+ * information of SAMSUNG ELECTRONICS ("Confidential Information"). You shall\r
+ * not disclose such Confidential Information and shall use it only in\r
+ * accordance with the terms of the license agreement you entered into with\r
+ * SAMSUNG ELECTRONICS. SAMSUNG make no representations or warranties about the\r
+ * suitability of the software, either express or implied, including but not\r
+ * limited to the implied warranties of merchantability, fitness for a\r
+ * particular purpose, or non-infringement. SAMSUNG shall not be liable for any\r
+ * damages suffered by licensee as a result of using, modifying or distributing\r
+ * this software or its derivatives.\r
+ */\r
+\r
+#ifndef __PLUSPLAYER_TYPES_EVENT_H__\r
+#define __PLUSPLAYER_TYPES_EVENT_H__\r
+\r
+namespace plusplayer {\r
+/**\r
+ * @brief\r
+ */\r
+typedef struct {\r
+  /**\r
+   * @description\r
+   */\r
+  std::string data;\r
+  /**\r
+   * @description\r
+   */\r
+  uint64_t len;\r
+} EventMsg;\r
+\r
+/**\r
+ * @brief\r
+ */\r
+enum class EventType {\r
+  kNone,\r
+  kResolutionChanged,\r
+};\r
+\r
+}  // namespace plusplayer\r
+\r
+#endif  // __PLUSPLAYER_TYPES_EVENT_H__\r
diff --git a/include/plusplayer/types/latency.h b/include/plusplayer/types/latency.h
new file mode 100755 (executable)
index 0000000..87a8e65
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+* @file           
+* @interfacetype  module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        3.0
+* @SDK_Support    N
+*
+* Copyright (c) 2020 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_TYPES_LATENCY_H__
+#define __PLUSPLAYER_TYPES_LATENCY_H__
+
+namespace plusplayer {
+
+enum class CatchUpSpeed { 
+  kNone,
+  kSlow,
+  kNormal,
+  kFast
+};
+  
+enum class LatencyStatus { 
+  kLow,
+  kMid,
+  kHigh
+};
+  
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_LATENCY_H__
\ No newline at end of file
diff --git a/include/plusplayer/types/picturequality.h b/include/plusplayer/types/picturequality.h
new file mode 100755 (executable)
index 0000000..c4106e8
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+* @file           
+* @interfacetype  module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        1.0
+* @SDK_Support    N
+*
+* 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_PICTUREQUALITY_H__
+#define __PLUSPLAYER_PICTUREQUALITY_H__
+
+namespace plusplayer {
+
+/**
+* @brief Advanced Picture Quality Type.
+*/
+enum class AdvPictureQualityType {
+  kVideoCall,
+  kUsbCamera
+};
+
+}  // namespace plusplayer
+#endif  // __PLUSPLAYER_PICTUREQUALITY_H__
\ No newline at end of file
diff --git a/include/plusplayer/types/resource.h b/include/plusplayer/types/resource.h
new file mode 100755 (executable)
index 0000000..ea7d09b
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * @brief          the stream information for playback
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        3.0
+ * @SDK_Support    N
+ *
+ * Copyright (c) 2020 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_TYPES_RESOURCE_H__
+#define __PLUSPLAYER_TYPES_RESOURCE_H__
+
+namespace plusplayer {
+
+/**
+ * @brief  Enumerations for the resource type
+ */
+enum class RscType { kVideoRenderer };
+
+/**
+ * @brief   Enumerations for resource allocate policy
+ */
+enum class RscAllocPolicy {
+  /**
+   * @description   exclusive policy, default policy
+   */
+  kRscAllocExclusive,
+  /**
+   * @description   conditional policy
+   */
+  kRscAllocConditional,
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_RESOURCE_H__
\ No newline at end of file
diff --git a/include/plusplayer/types/source.h b/include/plusplayer/types/source.h
new file mode 100755 (executable)
index 0000000..3f2502a
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+* @file           source.h
+* @brief          Types related to TrackSource
+* @interfacetype  module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        1.0
+* @SDK_Support    N
+*
+* 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_SRC_TRACKSOURCE_TYPES_H__
+#define __PLUSPLAYER_SRC_TRACKSOURCE_TYPES_H__
+
+namespace plusplayer {
+
+enum class SourceType {
+  kNone,
+  kBase,
+  kHttp,
+  kHls,
+  kDash,
+  kSmooth,
+  kFile,
+  kExternalSubtitle,
+  kNotFound,
+  kMax
+};
+
+enum class ContentFormat {
+  kNone,
+  kMP4Mov,
+  kMpegts,
+  k3GpMov,
+  kAudioMpeg,
+  kAudioMpegAac,
+  kMkv,
+  kAvi,
+  kVideoAsf,
+  kAppXid3,
+  kUnknown
+};
+
+enum class TrickPlayMode {
+  kNone,
+  kDefault,
+  kBySeek
+};
+
+enum class PlayingTimeSupport {
+  kNone,
+  kNeeded
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKSOURCE_TYPES_H__
diff --git a/include/plusplayer/types/stream.h b/include/plusplayer/types/stream.h
new file mode 100755 (executable)
index 0000000..f107592
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * @file
+ * @brief          the stream information for playback
+ * @interfacetype  Module
+ * @privlevel      None-privilege
+ * @privilege      None
+ * @product        TV, AV, B2B
+ * @version        0.0.1
+ * @SDK_Support    N
+ *
+ * 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_TYPES_STREAM_H__
+#define __PLUSPLAYER_TYPES_STREAM_H__
+
+namespace plusplayer {
+
+/**
+ * @brief  Enumerations for the stream type
+ */
+enum class StreamType { kAudio = 0, kVideo, kMax };
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_STREAM_H__
\ No newline at end of file
diff --git a/include/plusplayer/types/streaming_message.h b/include/plusplayer/types/streaming_message.h
new file mode 100755 (executable)
index 0000000..6c5de10
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+* @file           streaming_message.h
+* @interfacetype  module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        1.0
+* @SDK_Support    N
+*
+* 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_TYPES_STREAMING_MESSAGE_H__
+#define __PLUSPLAYER_TYPES_STREAMING_MESSAGE_H__
+
+namespace plusplayer {
+
+enum class StreamingMessageType {
+  kNone = 0,
+  // kResolutionChanged,
+  // kAdEnd,
+  // kAdStart,
+  // kRenderDone,
+  kBitrateChange,
+  // kFragmentInfo,
+  kSparseTrackDetect,
+  // kStreamingEvent,
+  // kDrmChallengeData,
+  kDrmInitData,
+  // kHttpErrorCode,
+  // kDrmRenewSessionData,
+  kStreamEventType,
+  kStreamEventData,
+  kStreamSyncFlush,
+  kStreamMrsUrlChanged,
+  kDrmKeyRotation,
+  kFragmentDownloadInfo,
+  kDvrLiveLag,
+  kSparseTrackData,
+  kConnectionRetry,
+  kConfigLowLatency,
+  kCurlErrorDebugInfo,
+  kParDarChange
+};
+
+struct MessageParam {
+  std::string data;
+  int size = 0;
+  int code = 0;  // Error or warning code
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_STREAMING_MESSAGE_H__
\ No newline at end of file
diff --git a/include/plusplayer/types/submitdata.h b/include/plusplayer/types/submitdata.h
new file mode 100755 (executable)
index 0000000..8ade19f
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+* @file           submitdata.h
+* @brief          the data type to submit
+* @interfacetype  Module
+* @privlevel      None-privilege
+* @privilege      None
+* @product        TV, AV, B2B
+* @version        0.0.1
+* @SDK_Support    N
+*
+* Copyright (c) 2019 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_TYPES_SUBMITDATA_H__
+#define __PLUSPLAYER_TYPES_SUBMITDATA_H__
+
+namespace plusplayer {
+
+/**
+ * @brief Enumerations for the type of espacket submitted
+ */
+enum class SubmitDataType {
+  kCleanData,      // For clean data
+  kEncryptedData,  // For encrypted data
+  kTrustZoneData   // For trustzone data
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_TYPES_SUBMITDATA_H__
\ No newline at end of file
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 9M to 4.5M.png b/out/docs/module_view/libav-common/reduced downloadable module size by libav-common dash hls http streaming module 9M to 4.5M.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 9M to 4.5M.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/esplusplayer.manifest b/packaging/esplusplayer.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/esplusplayer.spec b/packaging/esplusplayer.spec
new file mode 100755 (executable)
index 0000000..6616451
--- /dev/null
@@ -0,0 +1,239 @@
+# %bcond_with : disable ESPLUSPLAYER_UT by default, %bcond_without : enable ESPLUSPLAYER_UT
+%if ("%{_vd_cfg_product_type}" != "AUDIO")
+%bcond_without ESPLUSPLAYER_UT
+%else
+%bcond_with ESPLUSPLAYER_UT
+%endif
+#echo "Product Type: %{_vd_cfg_product_type}"
+Name:       esplusplayer
+Summary:    new multimedia streaming player
+Version:    0.0.1
+Release:    0
+Group:      Multimedia/Libraries
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Source1001: esplusplayer.manifest
+BuildRequires:  cmake
+BuildRequires:  curl
+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(libtzplatform-config)
+BuildRequires:  pkgconfig(jsoncpp)
+BuildRequires:  pkgconfig(gstreamer-ffsubtitle-1.0)
+BuildRequires:  pkgconfig(icu-i18n)
+BuildRequires:  pkgconfig(drmdecrypt)
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(logger)
+BuildRequires:  pkgconfig(gio-2.0)
+BuildRequires:  pkgconfig(libtbm)
+BuildRequires:  pkgconfig(lwipc)
+BuildRequires:  pkgconfig(capi-screensaver)
+BuildRequires:  pkgconfig(context-aware-api)
+BuildRequires:  pkgconfig(capi-trackrenderer-tv)
+BuildRequires:  pkgconfig(libtbm)
+BuildRequires:  pkgconfig(smart-deadlock)
+
+%if ("%{_vd_cfg_product_type}" != "AUDIO")
+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")
+%if ("%{_vd_cfg_product_type}" != "AUDIO")
+%{?!TOMATO: %define TOMATO n}
+
+%define _tomatoname esplusplayer
+%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)
+BuildRequires:  pkgconfig(video-capture)
+BuildRequires:  pkgconfig(audio-control)
+BuildRequires:  libjpeg-turbo-devel
+BuildRequires:  elementary-devel
+BuildRequires:  opencv-devel
+BuildRequires:  pkgconfig(opencv)
+BuildRequires:  pkgconfig(capi-appfw-application)
+Requires: %{name} = %{version}-%{release}
+
+%description ut-component-tomato
+This package is for test
+
+%files ut-component-tomato
+%defattr(-,root,root,-)
+%{_bindir}/esplusplayer_ut
+%{_tomatodir}/*
+
+%endif
+%endif
+
+%build
+export CFLAGS+=" -Wno-deprecated-declarations"
+export CXXFLAGS+=" -Wno-deprecated-declarations"
+
+%if ("%{_vd_cfg_product_type}" == "AUDIO")
+export CFLAGS+=" -DIS_AUDIO_PRODUCT"
+export CXXFLAGS+=" -DIS_AUDIO_PRODUCT"
+%define PRODUCT_TYPE_AUDIO yes
+%else
+%define PRODUCT_TYPE_AUDIO no
+%endif
+
+%if ("%{_vd_cfg_product_type}" == "AV")
+export CFLAGS+=" -DIS_AV_PRODUCT"
+export CXXFLAGS+=" -DIS_AV_PRODUCT"
+%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"
+export CFLAGS+=" -DIS_TOMATO"
+export CXXFLAGS+=" -DIS_TOMATO"
+%endif
+
+export CXXFLAGS+=" -Wno-pessimizing-move"
+
+%if ("%{_vd_cfg_licensing}" == "n")
+%if %{with ESPLUSPLAYER_UT}
+%cmake . -DESPLUSPLAYER_BUILD_UT=ON -DPRODUCT_TYPE_AUDIO=%PRODUCT_TYPE_AUDIO
+%else
+%cmake . -DPRODUCT_TYPE_AUDIO=%PRODUCT_TYPE_AUDIO
+%endif
+%else
+%cmake . -DPRODUCT_TYPE_AUDIO=%PRODUCT_TYPE_AUDIO
+%endif
+
+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
+mkdir -p %{buildroot}%TZ_SYS_RO_ETC/multimedia
+#mkdir -p %{buildroot}%TZ_SYS_RW_APP/multimedia
+#mkdir -p %{buildroot}/opt
+#mkdir -p %{buildroot}/opt/usr
+#mkdir -p %{buildroot}/opt/usr/home
+#mkdir -p %{buildroot}/opt/usr/home/owner
+#mkdir -p %{buildroot}/opt/usr/home/owner/models
+cp -rf config/esplusplayer.ini %{buildroot}%TZ_SYS_RO_ETC/multimedia/esplusplayer.ini
+
+%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 esplusplayer.manifest
+%license LICENSE.APLv2
+%{_libdir}/libespplayer-core.so
+%{_libdir}/libesplusplayer.so
+%if ("%{_vd_cfg_product_type}" != "AUDIO")
+%{_libdir}/libmixer.so
+%endif
+
+%TZ_SYS_RO_ETC/multimedia/esplusplayer.ini
+#%attr(0775, owner,users) %TZ_SYS_RW_APP/multimedia
+
+#remove esplusplayer_ut in esplusplayer package by flash memory issue
+#%if ("%{_vd_cfg_licensing}" == "n")
+#%if %{with ESPLUSPLAYER_UT}
+#%{_bindir}/esplusplayer_ut
+#%defattr(-,root,root,-)
+#%{_tomatodir}/*
+#%endif
+#%endif
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/esplusplayer_capi/*.h
+%{_includedir}/mixer/*.h
+%{_includedir}/mixer_capi/*.h
+%{_pkgconfigdir}/esplusplayer.pc
+
+%files config
+%defattr(-,root,root,-)
+%manifest esplusplayer.manifest
+%license LICENSE.APLv2
+%TZ_SYS_RO_ETC/multimedia/esplusplayer.ini
+%attr(0775, owner,users) %TZ_SYS_RO_ETC/multimedia
+
+%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..82d4cda
--- /dev/null
@@ -0,0 +1,5 @@
+ADD_SUBDIRECTORY(plusplayer-core)
+ADD_SUBDIRECTORY(esplusplayer)
+IF(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+ADD_SUBDIRECTORY(mixer)
+ENDIF(${PRODUCT_TYPE_AUDIO} STREQUAL)
diff --git a/src/cpplint.py b/src/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/src/esplusplayer/CMakeLists.txt b/src/esplusplayer/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..73a51ad
--- /dev/null
@@ -0,0 +1,67 @@
+PROJECT(esplusplayer)
+
+SET(fw_name "${PROJECT_NAME}")
+SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+SET(${fw_name}_LDFLAGS)
+
+IF(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+SET(ADD_LIBS
+  "espplayer-core"
+  "trackrenderer"
+  "mixer"
+)
+ELSE(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+SET(ADD_LIBS
+  "espplayer-core"
+  "trackrenderer"
+)
+ENDIF(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+
+SET(${fw_name}_CXXFLAGS "-Wall -Werror -std=c++11 -fPIC -fno-lto -Wl,-z,relro -fstack-protector -DEFL_BETA_API_SUPPORT")
+
+SET(dependents "gstreamer-1.0 glib-2.0 dlog"
+               "boost"
+               "tv-resource-manager"
+               "elementary ecore ecore-wl2"
+               "jsoncpp")
+
+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(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
+  ${PARENT_DIR}/plusplayer-core/include_internal
+)
+
+SET(CC_SRCS
+  ${PROJECT_SOURCE_DIR}/src/espacket_logger.cpp
+  ${PROJECT_SOURCE_DIR}/src/esplayer_drm.cpp
+  ${PROJECT_SOURCE_DIR}/src/esplusplayer.cpp
+  ${PROJECT_SOURCE_DIR}/src/esplayer.cpp
+  ${PROJECT_SOURCE_DIR}/src/elementary_stream.cpp
+  ${PROJECT_SOURCE_DIR}/src/espacket.cpp
+  ${PROJECT_SOURCE_DIR}/src/esplusplayer_capi.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/esplusplayer/include_internal/esplayer/decoded_pkt_list.h b/src/esplusplayer/include_internal/esplayer/decoded_pkt_list.h
new file mode 100755 (executable)
index 0000000..ab15164
--- /dev/null
@@ -0,0 +1,271 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_ESPLAYER_DECODED_PACKET_LIST_H__
+#define __PLUSPLAYER_SRC_ESPLAYER_DECODED_PACKET_LIST_H__
+
+#include <tbm_surface.h>
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include <memory>
+
+#include "core/utils/plusplayer_log.h"
+#include "plusplayer/types/buffer.h"
+
+namespace {
+void DecodedPacketDeleter(esplusplayer_decoded_video_packet* packet) {
+  if (packet == nullptr || packet->surface_data == nullptr) return;
+  // LOG_DEBUG("packet[%p] deleted", packet);
+  tbm_surface_destroy(static_cast<tbm_surface_h>(packet->surface_data));
+  packet->surface_data = NULL;
+}
+}  // namespace
+
+namespace plusplayer {
+struct DecodedPacketManagerInterface {
+  virtual ~DecodedPacketManagerInterface() = default;
+  virtual bool TryToAdd(esplusplayer_decoded_video_packet* packet) = 0;
+  virtual void Remove(esplusplayer_decoded_video_packet* packet) = 0;
+  virtual void Clear() = 0;
+  virtual void GetFreeTbmSurface(void** ptr, bool is_scale_change) = 0;
+};
+struct CmaBufferInfo {
+  void* tbm_surf = nullptr;
+  bool tbm_is_free = true;
+  bool destroy_flag = false;
+};
+
+class AbstractDecodedPacketList : public DecodedPacketManagerInterface {
+ public:
+  explicit AbstractDecodedPacketList() = default;
+  virtual ~AbstractDecodedPacketList() = default;
+  using DecodedPacketPtr =
+      std::unique_ptr<esplusplayer_decoded_video_packet,
+                      std::function<void(esplusplayer_decoded_video_packet*)>>;
+
+ public:
+  virtual bool TryToAdd(esplusplayer_decoded_video_packet* packet) override {
+    if (packet == nullptr) {
+      LOG_ERROR("packet is nullptr");
+      return false;
+    }
+    std::unique_lock<std::mutex> lk(mtx_);
+    auto pkt_ptr = DecodedPacketPtr(
+        packet, [this](esplusplayer_decoded_video_packet* pkt) {
+          DecodedPacketDeleter(pkt);
+          delete pkt;
+        });
+    if (IsAvailableInternal() == false) {
+      LOG_ERROR("not available to add a packet");
+      return false;
+    }
+    // LOG_DEBUG("packet[%p] added", packet);
+    list_.emplace_back(std::move(pkt_ptr));
+    return true;
+  }
+  virtual void Remove(esplusplayer_decoded_video_packet* packet) override {
+    if (packet == nullptr) return;
+    std::unique_lock<std::mutex> lk(mtx_);
+    list_.remove_if([&packet](const DecodedPacketPtr& cur) {
+      if (cur.get() == packet) return true;
+      return false;
+    });
+  }
+  virtual void Clear() override {
+    std::unique_lock<std::mutex> lk(mtx_);
+    LOG_DEBUG("all packets are cleared");
+    list_.clear();
+  }
+
+  virtual void GetFreeTbmSurface(void** ptr, bool is_scale_change) override {
+    return;
+  }
+
+ protected:
+  const std::list<DecodedPacketPtr>& GetList() { return list_; }
+
+ protected:
+  virtual bool IsAvailableInternal() = 0;
+  virtual void DecodedPacketDeleter(
+      esplusplayer_decoded_video_packet* packet) = 0;
+
+ protected:
+  std::mutex mtx_;
+  std::list<DecodedPacketPtr> list_;
+};
+
+class DecodedReferencePacketList : public AbstractDecodedPacketList {
+ public:
+  explicit DecodedReferencePacketList() { LOG_DEBUG("created"); }
+  virtual ~DecodedReferencePacketList() { LOG_DEBUG("destroyed"); }
+
+ protected:
+  virtual bool IsAvailableInternal() override {
+    if (GetList().size() > kMaxAvailableSize_) return false;
+    return true;
+  }
+  virtual void DecodedPacketDeleter(
+      esplusplayer_decoded_video_packet* packet) override {
+    ::DecodedPacketDeleter(packet);
+  }
+
+ private:
+  const std::uint32_t kMaxAvailableSize_ = 5;
+};
+
+class DecodedCopiedPacketList : public AbstractDecodedPacketList {
+ public:
+  explicit DecodedCopiedPacketList() { LOG_DEBUG("created"); }
+  virtual ~DecodedCopiedPacketList() { LOG_DEBUG("destroyed"); }
+
+ protected:
+  virtual bool IsAvailableInternal() override { return true; }
+  virtual void DecodedPacketDeleter(
+      esplusplayer_decoded_video_packet* packet) override {
+    ::DecodedPacketDeleter(packet);
+  }
+};
+
+class DecodedScaledPacketList : public AbstractDecodedPacketList {
+ public:
+  explicit DecodedScaledPacketList() { LOG_DEBUG("created"); }
+  virtual ~DecodedScaledPacketList() { LOG_DEBUG("destroyed"); }
+  virtual void GetFreeTbmSurface(void** ptr, bool is_scale_change) {
+    std::unique_lock<std::mutex> lk(mtx_);
+    if (is_scale_change) {
+      for (std::vector<CmaBufferInfo>::iterator it = tbm_mgr_.begin();
+           it != tbm_mgr_.end();) {
+        if (it->tbm_is_free == true) {
+          LOG_ERROR("scale size changed, destroy the free tbm %p",
+                    it->tbm_surf);
+          tbm_surface_destroy(static_cast<tbm_surface_h>(it->tbm_surf));
+          it = tbm_mgr_.erase(it);
+        } else {
+          LOG_ERROR("scale size changed, using tbm will be destroy later%p",
+                    it->tbm_surf);
+          it->destroy_flag = true;
+          it++;
+        }
+      }
+      *ptr = nullptr;
+    } else {
+      auto tbm_is_free = [](const CmaBufferInfo& item) -> bool {
+        return item.tbm_is_free == true;
+      };
+      auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), tbm_is_free);
+      if (target != tbm_mgr_.end()) {
+        *ptr = target->tbm_surf;
+      }
+    }
+    return;
+  }
+
+  virtual bool TryToAdd(esplusplayer_decoded_video_packet* packet) override {
+    if (packet == nullptr) {
+      LOG_ERROR("packet is nullptr");
+      return false;
+    }
+    std::unique_lock<std::mutex> lk(mtx_);
+    auto pkt_ptr = DecodedPacketPtr(
+        packet, [this](esplusplayer_decoded_video_packet* pkt) {
+          DecodedPacketDeleter(pkt);
+          delete pkt;
+        });
+    if (IsAvailableInternal() == false) {
+      LOG_ERROR("not available to add a packet");
+      return false;
+    }
+    // traverse tbm_mgr to find the same tbm surf,if find, change that,if not,
+    // new one and add to vector.
+    void* tbm_ptr = packet->surface_data;
+    auto has_tbm = [tbm_ptr](const CmaBufferInfo& item) -> bool {
+      return item.tbm_surf == tbm_ptr;
+    };
+    auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), has_tbm);
+    if (target == tbm_mgr_.end()) {
+      CmaBufferInfo tmp_tbm_buffer;
+      tmp_tbm_buffer.tbm_surf = packet->surface_data;
+      tmp_tbm_buffer.tbm_is_free = false;
+      tmp_tbm_buffer.destroy_flag = false;
+      tbm_mgr_.push_back(tmp_tbm_buffer);
+      LOG_ERROR("add tbm surface %p to list", tmp_tbm_buffer.tbm_surf);
+    } else {
+      target->tbm_is_free = false;
+    }
+    list_.emplace_back(std::move(pkt_ptr));
+    return true;
+  }
+
+  virtual void Remove(esplusplayer_decoded_video_packet* packet) override {
+    if (packet == nullptr) return;
+    std::unique_lock<std::mutex> lk(mtx_);
+    // LOG_ERROR("Remove pkt %p ", packet->surface_data);
+    // before remove packet, set the tbm surf free.
+    void* tbm_ptr = packet->surface_data;
+    auto has_tbm = [tbm_ptr](const CmaBufferInfo& item) -> bool {
+      return item.tbm_surf == tbm_ptr;
+    };
+    auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), has_tbm);
+    if (target != tbm_mgr_.end()) {
+      if (target->destroy_flag == true) {
+        LOG_ERROR("destroy tbm surface %p", target->tbm_surf);
+        tbm_surface_destroy(static_cast<tbm_surface_h>(target->tbm_surf));
+        tbm_mgr_.erase(target);
+      } else {
+        target->tbm_is_free = true;
+      }
+    }
+    list_.remove_if([&packet](const DecodedPacketPtr& cur) {
+      if (cur.get() == packet) return true;
+      return false;
+    });
+  }
+
+  virtual void Clear() override {
+    std::unique_lock<std::mutex> lk(mtx_);
+    LOG_DEBUG("all packets are cleared");
+    list_.clear();
+    for (auto& iter : tbm_mgr_) {
+      LOG_ERROR("destroy tbm buffer in list %p", iter.tbm_surf);
+      tbm_surface_destroy(static_cast<tbm_surface_h>(iter.tbm_surf));
+    }
+    std::vector<CmaBufferInfo> tmp;
+    tbm_mgr_.swap(tmp);
+  }
+
+ protected:
+  virtual bool IsAvailableInternal() override {
+    if (GetList().size() > kMaxAvailableSize_) return false;
+    return true;
+  }
+
+  virtual void DecodedPacketDeleter(
+      esplusplayer_decoded_video_packet* packet) override {
+    // redesign, when pkt list is full, which means new tbm ptr can't add, so
+    // destroy it after create in trackrender.
+    if (GetList().size() > kMaxAvailableSize_) {
+      if (packet == nullptr || packet->surface_data == nullptr) return;
+      // only destroy the tbm surface new created but not added in tbm list
+      void* tbm_ptr = packet->surface_data;
+      auto has_tbm = [tbm_ptr](const CmaBufferInfo& item) -> bool {
+        return item.tbm_surf == tbm_ptr;
+      };
+      auto target = std::find_if(tbm_mgr_.begin(), tbm_mgr_.end(), has_tbm);
+      if (target == tbm_mgr_.end()) {
+        LOG_ERROR("tbm_surface_destroy[%p] deleted", packet->surface_data);
+        tbm_surface_destroy(static_cast<tbm_surface_h>(packet->surface_data));
+        packet->surface_data = NULL;
+      }
+    }
+  }
+
+ private:
+  const std::uint32_t kMaxAvailableSize_ = 5;
+  std::vector<CmaBufferInfo> tbm_mgr_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_ESPLAYER_DECODED_PACKET_LIST_H__
\ No newline at end of file
diff --git a/src/esplusplayer/include_internal/esplayer/espacket_logger.h b/src/esplusplayer/include_internal/esplayer/espacket_logger.h
new file mode 100755 (executable)
index 0000000..8a4678d
--- /dev/null
@@ -0,0 +1,43 @@
+//\r
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __PLUSPLAYER_SRC_ESPLAYER_ESPACEKT_LOGGER__H__\r
+#define __PLUSPLAYER_SRC_ESPLAYER_ESPACEKT_LOGGER__H__\r
+\r
+#include <mutex>\r
+#include <string>\r
+\r
+#include "plusplayer/espacket.h"\r
+\r
+namespace plusplayer {\r
+class EsPacketLogger {\r
+ public:\r
+  EsPacketLogger() = default;\r
+  virtual ~EsPacketLogger() = default;\r
+  EsPacketLogger(const EsPacketLogger&) = delete;\r
+  EsPacketLogger(EsPacketLogger&&) = delete;\r
+\r
+  void StorePacketInfo(const EsPacketPtr& packet);\r
+  void PrintStoredPacketInfo(const StreamType type, bool force = false);\r
+  void ResetLog(const StreamType type);\r
+\r
+ private:\r
+  constexpr static int kStreamTypeMax = static_cast<int>(StreamType::kMax);\r
+  constexpr static int kLogBufferThreshold = 60;\r
+  struct LightWeightEsPacketInfo {\r
+    bool valid = false;\r
+    std::uint32_t size = 0;\r
+    std::uint64_t pts = 0;\r
+    std::uint64_t duration = 0;\r
+    bool is_eos = false;\r
+  };\r
+  std::string GetStringFromLastPacketInfo_(const StreamType type) const;\r
+\r
+  LightWeightEsPacketInfo last_packet_info_[kStreamTypeMax];\r
+  std::uint64_t last_log_packet_count_[kStreamTypeMax] = {0};\r
+  std::mutex mtx_;\r
+};\r
+}  // namespace plusplayer\r
+\r
+#endif
\ No newline at end of file
diff --git a/src/esplusplayer/include_internal/esplayer/esplayer.h b/src/esplusplayer/include_internal/esplayer/esplayer.h
new file mode 100755 (executable)
index 0000000..2ce81cf
--- /dev/null
@@ -0,0 +1,323 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_ESPLAYER_ESPLAYER__H__
+#define __PLUSPLAYER_SRC_ESPLAYER_ESPLAYER__H__
+
+#include <boost/core/noncopyable.hpp>
+#include <future>
+#include <list>
+#include <map>
+#include <memory>
+#include <queue>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "core/decoderinputbuffer.h"
+#include "core/kpi.h"
+#include "core/trackrendereradapter.h"
+#ifndef IS_AUDIO_PRODUCT
+#include "mixer/mixerticket.h"
+#include "mixer/mixerticket_eventlistener.h"
+#endif
+#include "esplayer/espacket_logger.h"
+#include "esplayer/message.hpp"
+#include "esplayer/state_manager.hpp"
+#include "plusplayer/drm.h"
+#include "plusplayer/esplusplayer.h"
+#include "plusplayer/track.h"
+#include "plusplayer/types/buffer.h"
+#include "plusplayer/types/display.h"
+#include "plusplayer/types/error.h"
+#include "plusplayer/types/stream.h"
+
+namespace plusplayer {
+
+enum EosStatus {
+  kNone = 0x0000,
+  kAudioEos = 0x0010,
+  kVideoEos = 0x0100,
+  kAllEos = (kAudioEos | kVideoEos)
+};
+
+static constexpr unsigned long kNeedDataMaskNone = 0x00;
+static constexpr unsigned long kNeedDataMaskBySeek = 0x01;
+static constexpr unsigned long kNeedDataMaskByPrepare = 0x02;
+
+class EsPlayer : public EsPlusPlayer {
+ public:
+  EsPlayer();
+  ~EsPlayer();
+
+  bool Open() override;
+  bool Close() override;
+  bool PrepareAsync() override;
+  bool Deactivate(const StreamType type) override;
+  bool Activate(const StreamType type) override;
+  bool Start() override;
+  bool Stop() override;
+  bool Pause() override;
+  bool Resume() override;
+  bool Seek(const uint64_t time_millisecond) override;
+  void SetAppInfo(const PlayerAppInfo& app_info) override;
+  bool SetPlaybackRate(const double rate, const bool audio_mute) override;
+  bool SetDisplay(const DisplayType& type, void* obj) override;
+#ifndef IS_AUDIO_PRODUCT
+  bool SetDisplay(const DisplayType& type, MixerTicket* handle) override;
+#endif
+  bool SetDisplay(const DisplayType& type, void* ecore_wl2_window, const int x,
+                  const int y, const int w, const int h) override;
+  bool SetDisplaySubsurface(const DisplayType& type, void* ecore_wl2_subsurface,
+                            const int x, const int y, const int w,
+                            const int h) override;
+  bool SetDisplay(const DisplayType& type, unsigned int surface_id, const int x,
+                  const int y, const int w, const int h) override;
+  bool SetDisplayMode(const DisplayMode& mode) override;
+  bool SetDisplayRoi(const Geometry& roi) override;
+  bool SetVideoRoi(const CropArea& area) override;
+  bool ResizeRenderRect(const RenderRect& rect) override;
+  bool SetDisplayRotate(const DisplayRotation& rotate) override;
+  bool GetDisplayRotate(DisplayRotation* rotate) override;
+  bool SetDisplayVisible(bool is_visible) override;
+  bool SetTrustZoneUse(bool is_using_tz) override;
+  bool SetSubmitDataType(SubmitDataType type) override;
+  bool SetStream(const AudioStreamPtr& stream) override;
+  bool SetStream(const VideoStreamPtr& stream) override;
+  PacketSubmitStatus SubmitPacket(const EsPacketPtr& packet) override;
+  PacketSubmitStatus SubmitTrustZonePacket(const EsPacketPtr& packet,
+                                           uint32_t tz_handle = 0) override;
+  PacketSubmitStatus SubmitEncryptedPacket(
+      const EsPacketPtr& packet,
+      const drm::EsPlayerEncryptedInfo& drm_info) override;
+  EsState GetState() override;
+  bool GetPlayingTime(uint64_t* time_in_milliseconds) override;
+  bool SetAudioMute(bool is_mute) override;
+  bool SetVideoFrameBufferType(DecodedVideoFrameBufferType type) override;
+  bool SetVideoFrameBufferScaleResolution(
+      const uint32_t& target_width, const uint32_t& target_height) override;
+  bool SetDecodedVideoFrameRate(const Rational& request_framerate) override;
+  void RegisterListener(EsEventListener* listener,
+                        EsEventListener::UserData userdata) override;
+  bool GetAdaptiveInfo(void* padaptive_info,
+                       const PlayerAdaptiveInfo& adaptive_type) override;
+  bool SetVolume(const int& volume) override;
+  bool GetVolume(int* volume) override;
+  bool Flush(const StreamType& type) override;
+  void SetBufferSize(const BufferOption& option, uint64_t size) override;
+  bool SetLowLatencyMode(const PlayerLowLatencyMode& mode) override;
+  bool SetVideoFramePeekMode() override;
+  bool RenderVideoFrame() override;
+  bool SetUnlimitedMaxBufferMode() override;
+  bool SetFmmMode() override;
+  bool SetAudioCodecType(const PlayerAudioCodecType& type) override;
+  bool SetVideoCodecType(const PlayerVideoCodecType& type) override;
+  bool SetRenderTimeOffset(const StreamType type, int64_t offset) override;
+  bool GetRenderTimeOffset(const StreamType type, int64_t* offset) override;
+  bool SetAlternativeVideoResource(unsigned int rsc_type) override;
+  bool SwitchAudioStreamOnTheFly(const AudioStreamPtr& stream) override;
+  bool SetAiFilter(void* aifilter) override;
+  bool SetCatchUpSpeed(const CatchUpSpeed& level) override;
+  bool GetVideoLatencyStatus(LatencyStatus* status) override;
+  bool GetAudioLatencyStatus(LatencyStatus* status) override;
+  bool SetVideoMidLatencyThreshold(const unsigned int threshold) override;
+  bool SetAudioMidLatencyThreshold(const unsigned int threshold) override;
+  bool SetVideoHighLatencyThreshold(const unsigned int threshold) override;
+  bool SetAudioHighLatencyThreshold(const unsigned int threshold) override;
+  bool InitAudioEasingInfo(const uint32_t init_volume,
+                           const uint32_t init_elapsed_time,
+                           const AudioEasingInfo& easing_info) override;
+  bool UpdateAudioEasingInfo(const AudioEasingInfo& easing_info) override;
+  bool GetAudioEasingInfo(uint32_t* current_volume, uint32_t* elapsed_time,
+                          AudioEasingInfo* easing_info) override;
+  bool StartAudioEasing() override;
+  bool StopAudioEasing() override;
+  bool GetVirtualRscId(const RscType type, int* virtual_id) override;
+  bool SetAdvancedPictureQualityType(const AdvPictureQualityType type) override;
+  bool SetResourceAllocatePolicy(const RscAllocPolicy policy) override;
+
+ private:
+  using SubmitPacketOperator =
+      std::function<PacketSubmitStatus(GstBuffer* buffer)>;
+
+  struct NeedData {
+    std::bitset<2> mask = kNeedDataMaskNone;
+    uint64_t seek_offset = 0;
+  };
+
+  struct ResumeTime {
+    bool is_set = false;
+    uint64_t time = 0;
+  };
+
+  enum class MakeBufferStatus {
+    kEos,          // eos packet
+    kOutOfMemory,  // out of memory
+    kSuccess       // success
+  };
+  struct SrcQueueSize {
+    std::uint64_t kMaxByteOfVideoSrcQueue = 70 * 1024 * 1024;  // 70 MB
+    std::uint64_t kMaxByteOfAudioSrcQueue = 10 * 1024 * 1024;  // 10 MB
+    std::uint32_t kMinByteThresholdOfVideoSrcQueue = 0;
+    std::uint32_t kMinByteThresholdOfAudioSrcQueue = 0;
+
+    std::uint64_t kMaxTimeOfVideoSrcQueue = 0;
+    std::uint64_t kMaxTimeOfAudioSrcQueue = 0;
+    std::uint32_t kMinTimeThresholdOfVideoSrcQueue = 0;
+    std::uint32_t kMinTimeThresholdOfAudioSrcQueue = 0;
+  };
+
+ private:
+  void Init_();
+  void MsgTask_();
+  bool Prepare_();
+  void PrepareTask_();
+  void SetTrackRendererAttributes_();
+  GstBuffer* GetGstBuffer_(const EsPacketPtr& packet, MakeBufferStatus* status);
+  void UnsetTzQdata_(const DecoderInputBufferPtr& buffer);
+  void MakeGstBufferForTzHandle_(GstBuffer* gstbuffer, const TrackType& type,
+                                 const uint32_t& tz_handle,
+                                 const uint32_t& packet_size);
+  void MakeGstBufferForEncryptedPacket_(
+      GstBuffer* gstbuffer, const EsPacketPtr& packet,
+      const drm::EsPlayerEncryptedInfo& drm_info);
+  PacketSubmitStatus SubmitPacketCommon_(const EsPacketPtr& packet,
+                                         SubmitPacketOperator op);
+  PacketSubmitStatus SubmitEosPacket_(const TrackType& type);
+  PacketSubmitStatus SubmitDecoderInputBuffer_(
+      const DecoderInputBufferPtr& buffer);
+  bool SetTrack_(const Track& track);
+  bool ChangeStream_(const Track& track);
+  bool SetStream_(const Track& track);
+  void ResetContextForClose_();
+  void ResetContextForStop_();
+  void GetSrcQueueCurrentSize_(const TrackType& type, uint64_t* byte_size,
+                               uint64_t* time_size);
+  kpi::EsCodecLoggerKeys MakeKpiKeys_();
+#ifndef IS_AUDIO_PRODUCT
+  bool PrepareVideoMixingMode_(std::vector<Track>* tracks);
+#endif
+
+ private:  // private types
+  class TrackRendererEventListener
+      : public TrackRendererAdapter::EventListener {
+   public:
+    explicit TrackRendererEventListener(EsPlayer* handler) : handler_(handler) {
+      assert(handler);
+    }
+    void OnError(const ErrorType& error_code) override;
+    void OnErrorMsg(const ErrorType& error_code, char* error_msg) override;
+    void OnResourceConflicted() override;
+    void OnEos() override;
+    void OnSeekDone() override;
+    void OnBufferStatus(const TrackType& type,
+                        const BufferStatus& status) override;
+    void OnSeekData(const TrackType& type, const uint64_t offset) override;
+    void OnClosedCaptionData(const char* data, const int size) override;
+    void OnFlushDone() override;
+    void OnEvent(const EventType& event_type,
+                 const EventMsg& msg_data) override;
+    void OnFirstDecodingDone() override;
+    void OnVideoDecoderUnderrun() override;
+    void OnVideoLatencyStatus(const LatencyStatus& latency_status) override;
+    void OnAudioLatencyStatus(const LatencyStatus& latency_status) override;
+    void OnVideoHighLatency() override;
+    void OnAudioHighLatency() override;
+#ifndef IS_AUDIO_PRODUCT
+    void OnMediaPacketVideoRawDecoded(
+        const DecodedVideoRawModePacket& packet) override;
+#endif
+
+   private:
+    void ReadyToPrepare_(const TrackType& type);
+    void ReadyToSeek_(const TrackType& type);
+    void BufferStatus_(const TrackType& type, const BufferStatus& status);
+    void OnMediaPacketVideoDecoded(const DecodedVideoPacket& packet);
+    void OnMediaPacketGetTbmBufPtr(void** ptr, bool is_scale_change);
+
+   private:
+    EsPlayer* handler_ = nullptr;
+  };  // class TrackRendererEventListener
+
+#ifndef IS_AUDIO_PRODUCT
+  class MixerListener : public MixerTicketEventListener {
+   public:
+    explicit MixerListener(EsPlayer* handler) : handler_(handler) {
+      assert(handler);
+    }
+    bool OnAudioFocusChanged(bool active) override;
+    bool OnUpdateDisplayInfo(const DisplayInfo& cur_info,
+                             DisplayInfo* new_info) override;
+
+   private:
+    EsPlayer* handler_{nullptr};
+  };
+#endif
+
+ private:
+  std::vector<Track> track_;
+  NeedData need_data_[kTrackTypeMax];
+  int eos_status_ = EosStatus::kAllEos;
+  std::mutex eos_mutex_;
+  EsEventListener* eventlistener_ = nullptr;
+  EsEventListener::UserData eventlistener_userdata_ = nullptr;
+
+  EsStateManager state_manager_;
+
+  SubmitDataType submit_data_type_ = SubmitDataType::kCleanData;
+  drm::Property drm_property_;
+  std::uint32_t low_latency_mode_ = 0;
+  std::uint32_t video_frame_peek_mode_ = 0;
+  std::uint32_t unlimited_max_buffer_mode_ = 0;
+  std::uint32_t accurate_seek_mode_ = 1;
+  std::uint32_t video_pre_display_mode_ = 1;
+  std::uint32_t fmm_mode_ = 0;
+  PlayerAudioCodecType audio_codec_type_ = kPlayerAudioCodecTypeHW;
+  PlayerVideoCodecType video_codec_type_ = kPlayerVideoCodecTypeHW;
+  bool force_audio_swdecoder_use_ = false;
+  std::uint32_t video_decoding_mode_ = 0x02;  // seamless mode
+  std::uint32_t alternaltive_video_resource_ = 0;
+  ResumeTime resume_time_;
+
+  bool is_msg_task_stop_ = false;
+  std::mutex msg_task_mutex_;
+  std::mutex submit_mutex_;
+  std::condition_variable msg_task_cv_;
+  std::queue<es_msg::Base::Ptr> msg_queue_;
+  std::future<void> msg_handler_task_;
+
+  std::unique_ptr<TrackRendererEventListener> trackrenderer_event_listener_{
+      new TrackRendererEventListener(this)};
+#ifndef IS_AUDIO_PRODUCT
+  std::unique_ptr<MixerListener> mixer_event_listener_{new MixerListener(this)};
+#endif
+  std::unique_ptr<TrackRendererAdapter> trackrenderer_;
+  std::future<void> preparetask_;
+  PlayerAppInfo app_info_;
+  double current_playback_rate_ = 1.0;
+  bool current_audio_mute_ = false;
+  bool is_resource_conflicted_ = false;
+  bool is_stopped_ = false;
+  bool is_preparing_ = false;
+  bool is_seek_done_need_drop = false;
+  SrcQueueSize src_queue_size_;
+
+  std::string caf_unique_number;
+#ifndef IS_AUDIO_PRODUCT
+  std::unique_ptr<MixerTicket> mixer_ticket_;
+  bool is_audio_focused_ = true;
+  Geometry mixerticket_roi_;
+  bool is_visible_ = true;
+  std::mutex audio_focus_m_;
+  bool enable_audio_pipeline_handle_ = true;
+  bool enable_rsc_alloc_handle_ = true;
+#endif
+  DecodedVideoFrameBufferType vidoe_frame_buffer_type_ =
+      DecodedVideoFrameBufferType::kNone;
+  // for debugging
+  EsPacketLogger es_packet_logger_;
+};
+
+}  // namespace plusplayer
+#endif  // __PLUSPLAYER_SRC_ESPLAYER_ESPLAYER__H__
diff --git a/src/esplusplayer/include_internal/esplayer/esplayer_drm.h b/src/esplusplayer/include_internal/esplayer/esplayer_drm.h
new file mode 100755 (executable)
index 0000000..78e260e
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_ESPLAYER_ESPLAYER_DRM__H__
+#define __PLUSPLAYER_SRC_ESPLAYER_ESPLAYER_DRM__H__
+
+#include "core/gstobject_guard.h"
+#include "plusplayer/espacket.h"
+#include "plusplayer/external_drm.h"
+
+namespace plusplayer {
+namespace esplayer_drm {
+using GBytesPtr = gstguard::GstGuardPtr<GBytes>;
+GBytesPtr Serialize(const EsPacketPtr &packet,
+                    const drm::EsPlayerEncryptedInfo &drm_info);
+}  // namespace esplayer_drm
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_ESPLAYER_ESPLAYER_DRM__H__
\ No newline at end of file
diff --git a/src/esplusplayer/include_internal/esplayer/message.hpp b/src/esplusplayer/include_internal/esplayer/message.hpp
new file mode 100755 (executable)
index 0000000..bdf19c6
--- /dev/null
@@ -0,0 +1,369 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_ESPLAYER_MESSAGE_H__
+#define __PLUSPLAYER_SRC_ESPLAYER_MESSAGE_H__
+
+#include <boost/core/noncopyable.hpp>
+#include <functional>
+#include <list>
+#include <memory>
+
+#include "core/utils/plusplayer_log.h"
+#include "plusplayer/track.h"
+#include "plusplayer/types/buffer.h"
+#include "plusplayer/types/error.h"
+#include "plusplayer/types/stream.h"
+
+// Restructuring points
+//  - remove listener handler ptr from msg class member
+//  - no RTTI
+//  - no need to know message type in mskTask
+//  - seperate configurations into each messages
+// Check point
+//  - design issues? delivering op breaks encapsulation ?
+//     -> related modules : pipeline , statemanager , msghandler.
+
+namespace plusplayer {
+
+// messages
+namespace es_msg {
+
+struct Base : private boost::noncopyable {
+  using Ptr = std::unique_ptr<Base>;
+  using UserData = void*;
+  virtual ~Base() {}
+  virtual void Execute() = 0;
+
+ protected:
+  Base() = default;
+  Base(const UserData userdata) : userdata_(userdata) {}
+  UserData userdata_ = nullptr;
+};  // class Msg
+
+struct Simple : Base {
+  using Ptr = std::unique_ptr<Simple>;
+  using Operator = std::function<void(Base::UserData)>;
+
+  static Base::Ptr Make(const Operator& _op, const Base::UserData userdata) {
+    return Base::Ptr(new Simple(_op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(userdata_);
+  }
+  const Operator op;
+
+ private:
+  explicit Simple(const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), op(_op) {}
+};
+
+struct Error : Base {
+  using Ptr = std::unique_ptr<Error>;
+  using Operator = std::function<void(const ErrorType&, Base::UserData)>;
+
+  static Base::Ptr Make(const ErrorType& error_type, const Operator& op,
+                        const Base::UserData userdata) {
+    return Base::Ptr(new Error(error_type, op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(type, userdata_);
+  }
+
+  const ErrorType type = ErrorType::kNone;
+  const Operator op;
+
+ private:
+  explicit Error(const ErrorType& _type, const Operator& _op,
+                 const Base::UserData userdata)
+      : Base(userdata), type(_type), op(_op) {}
+};
+
+struct ErrorMsg : Base {
+  using Ptr = std::unique_ptr<ErrorMsg>;
+  using Operator =
+      std::function<void(const ErrorType&, const char*, Base::UserData)>;
+
+  static Base::Ptr Make(const ErrorType& error_type, const char* error_msg,
+                        size_t size, const Operator& op,
+                        const Base::UserData userdata) {
+    return Base::Ptr(new ErrorMsg(error_type, error_msg, size, op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(type, message, userdata_);
+  }
+
+  const ErrorType type = ErrorType::kNone;
+  const char* message = nullptr;
+  const Operator op;
+
+ private:
+  explicit ErrorMsg(const ErrorType& _type, const char* _msg, size_t _size,
+                    const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), type(_type), op(_op) {
+    message = new const char[_size + 1]{0};
+    memcpy((void*)message, _msg, _size);
+  }
+
+  ~ErrorMsg() {
+    delete[] message;
+    message = nullptr;
+  }
+};
+
+struct Bufferstatus : Base {
+  using Ptr = std::unique_ptr<Bufferstatus>;
+  using Operator = std::function<void(StreamType, BufferStatus, uint64_t,
+                                      uint64_t, Base::UserData)>;
+
+  static Base::Ptr Make(const StreamType type, const BufferStatus status,
+                        const uint64_t byte_size, const uint64_t time_size,
+                        const Operator& op, const Base::UserData userdata) {
+    return Base::Ptr(
+        new Bufferstatus(type, status, byte_size, time_size, op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(type, status, byte_size, time_size, userdata_);
+  }
+
+  const StreamType type = StreamType::kMax;
+  const BufferStatus status = BufferStatus::kUnderrun;
+  const uint64_t byte_size;
+  const uint64_t time_size;
+  const Operator op;
+
+ private:
+  explicit Bufferstatus(const StreamType _type, const BufferStatus _status,
+                        const uint64_t _byte_size, const uint64_t _time_size,
+                        const Operator& _op, const Base::UserData userdata)
+      : Base(userdata),
+        type(_type),
+        status(_status),
+        byte_size(_byte_size),
+        time_size(_time_size),
+        op(_op) {}
+};
+
+struct ReadyToPrepare : Base {
+  using Ptr = std::unique_ptr<ReadyToPrepare>;
+  using Operator = std::function<void(StreamType, Base::UserData)>;
+
+  static Base::Ptr Make(const StreamType type, const Operator& op,
+                        const Base::UserData userdata) {
+    return Base::Ptr(new ReadyToPrepare(type, op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(type, userdata_);
+  }
+
+  const StreamType type = StreamType::kMax;
+  const Operator op;
+
+ private:
+  explicit ReadyToPrepare(const StreamType _type, const Operator& _op,
+                          const Base::UserData userdata)
+      : Base(userdata), type(_type), op(_op) {}
+};
+
+struct ReadyToSeek : Base {
+  using Ptr = std::unique_ptr<ReadyToSeek>;
+  using Operator = std::function<void(StreamType, uint64_t, Base::UserData)>;
+
+  static Base::Ptr Make(const StreamType type, const uint64_t offset,
+                        const Operator& op, const Base::UserData userdata) {
+    return Base::Ptr(new ReadyToSeek(type, offset, op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(type, offset, userdata_);
+  }
+
+  const StreamType type = StreamType::kMax;
+  const uint64_t offset = 0;
+  const Operator op;
+
+ private:
+  explicit ReadyToSeek(const StreamType _type, const uint64_t _offset,
+                       const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), type(_type), offset(_offset), op(_op) {}
+};
+
+struct ResourceConflict : Base {
+  using Ptr = std::unique_ptr<ResourceConflict>;
+  using Operator = std::function<void(Base::UserData)>;
+
+  static Base::Ptr Make(const Operator& _op, const Base::UserData userdata) {
+    return Base::Ptr(new ResourceConflict(_op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(userdata_);
+  }
+  const Operator op;
+
+ private:
+  explicit ResourceConflict(const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), op(_op) {}
+};
+
+struct Eos : Base {
+  using Ptr = std::unique_ptr<Eos>;
+  using Operator = std::function<void(Base::UserData)>;
+
+  static Base::Ptr Make(const Operator& _op, const Base::UserData userdata) {
+    return Base::Ptr(new Eos(_op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(userdata_);
+  }
+
+  const Operator op;
+
+ private:
+  explicit Eos(const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), op(_op) {}
+};
+
+struct SeekDone : Base {
+  using Ptr = std::unique_ptr<SeekDone>;
+  using Operator = std::function<void(Base::UserData)>;
+
+  static Base::Ptr Make(const Operator& _op, const Base::UserData userdata) {
+    return Base::Ptr(new SeekDone(_op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(userdata_);
+  }
+
+  const Operator op;
+
+ private:
+  explicit SeekDone(const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), op(_op) {}
+};
+
+struct FlushDone : Base {
+  using Ptr = std::unique_ptr<FlushDone>;
+  using Operator = std::function<void(Base::UserData)>;
+
+  static Base::Ptr Make(const Operator& _op, const Base::UserData userdata) {
+    return Base::Ptr(new FlushDone(_op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(userdata_);
+  }
+
+  const Operator op;
+
+ private:
+  explicit FlushDone(const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), op(_op) {}
+};
+
+struct OnEvent : Base {
+  using Ptr = std::unique_ptr<OnEvent>;
+  using Operator =
+      std::function<void(const EventType&, const EventMsg&, Base::UserData)>;
+
+  static Base::Ptr Make(const EventType& event, const EventMsg& msg_data,
+                        const Operator& op, const Base::UserData userdata) {
+    return Base::Ptr(new OnEvent(event, msg_data, op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(event, msg_data, userdata_);
+  }
+
+  const EventType event = EventType::kNone;
+  EventMsg msg_data;
+  const Operator op;
+
+ private:
+  explicit OnEvent(const EventType& _event, const EventMsg& _msg_data,
+                   const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), event(_event), msg_data(_msg_data), op(_op) {}
+};
+
+struct FirstDecodingDone : Base {
+  using Ptr = std::unique_ptr<FirstDecodingDone>;
+  using Operator = std::function<void(Base::UserData)>;
+
+  static Base::Ptr Make(const Operator& _op, const Base::UserData userdata) {
+    return Base::Ptr(new FirstDecodingDone(_op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(userdata_);
+  }
+
+  const Operator op;
+
+ private:
+  explicit FirstDecodingDone(const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), op(_op) {}
+};
+
+struct ClosedCaption : Base {
+  using Ptr = std::unique_ptr<ClosedCaption>;
+  using Operator =
+      std::function<void(std::unique_ptr<char[]>, int, Base::UserData)>;
+
+  static Base::Ptr Make(const char* _data, const int _size, const Operator& _op,
+                        const Base::UserData userdata) {
+    return Base::Ptr(new ClosedCaption(_data, _size, _op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(std::move(data), size, userdata_);
+  }
+
+  std::unique_ptr<char[]> data;
+  const int size = 0;
+  const Operator op;
+
+ private:
+  explicit ClosedCaption(const char* _data, const int _size,
+                         const Operator& _op, const Base::UserData userdata)
+      : Base(userdata), size(_size), op(_op) {
+    data.reset(new char[size]);
+    memcpy(data.get(), _data, size);
+  }
+};
+
+struct PacketLatencyStatus : Base {
+  using Ptr = std::unique_ptr<PacketLatencyStatus>;
+  using Operator = std::function<void(LatencyStatus, Base::UserData)>;
+
+  static Base::Ptr Make(const LatencyStatus latency_status, const Operator& op,
+                        const Base::UserData userdata) {
+    return Base::Ptr(new PacketLatencyStatus(latency_status, op, userdata));
+  }
+  void Execute() override {
+    if (!op) return;
+    op(latency_status, userdata_);
+  }
+
+  const LatencyStatus latency_status = LatencyStatus::kLow;
+  const Operator op;
+
+ private:
+  explicit PacketLatencyStatus(const LatencyStatus _latency_status,
+                               const Operator& _op,
+                               const Base::UserData userdata)
+      : Base(userdata), latency_status(_latency_status), op(_op) {}
+};
+
+}  // namespace es_msg
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_ESPLAYER_MESSAGE_H__
diff --git a/src/esplusplayer/include_internal/esplayer/state_manager.hpp b/src/esplusplayer/include_internal/esplayer/state_manager.hpp
new file mode 100755 (executable)
index 0000000..90e6f04
--- /dev/null
@@ -0,0 +1,387 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+//
+// StateMachine using boost::msm (meta state machine)
+// <Quick Guide>
+//   * Sequence
+//    1. generate Event (by user)
+//    2. call process_event(Event)
+//    3. check transition_table
+//      3-1. return if no transition defined
+//      3-2. process_event() return if other event is being processed(deferred)
+//    4. check Guard(Event const&)
+//    5. do Action(Event const&) if Guard succeeded
+//    6. Transition updated(to "next")
+//    (4-6) is atomically serialized in boost::msm
+//
+//   * Return value of process_event()
+//    . failed(HANDLED_FALSE=0) if no transition defined in transition_table
+//    . HANDLED_GUARD_REJECT if Guard(Event const&) returned false
+//
+
+#ifndef __PLUSPLAYER_SRC_ESPLAYER_STATE_MANAGER_H__
+#define __PLUSPLAYER_SRC_ESPLAYER_STATE_MANAGER_H__
+
+#include <bitset>
+#include <boost/core/noncopyable.hpp>
+#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+// max lines of transition table
+#define BOOST_MPL_LIMIT_VECTOR_SIZE 50  // or whatever you need
+#define BOOST_MPL_LIMIT_MAP_SIZE 50     // or whatever you need
+// max number of fsm states
+#define FUSION_MAX_VECTOR_SIZE 20                 // or whatever you need
+#include <boost/msm/back/state_machine.hpp>       // back-end
+#include <boost/msm/front/functor_row.hpp>        // functors
+#include <boost/msm/front/state_machine_def.hpp>  // front-end
+#include <mutex>
+#include <vector>
+
+#include "core/utils/plusplayer_log.h"
+#include "plusplayer/esplusplayer.h"
+
+#define DEBUG_STATE_MANAGER
+#ifdef DEBUG_STATE_MANAGER
+#define STATE_TRACE(fmt, arg...) LOG_DEBUG(fmt, ##arg)
+#define STATE_TRACE_P(id, fmt, arg...) LOG_DEBUG_P(id, fmt, ##arg)
+#else
+#define STATE_TRACE(fmt, arg...)
+#endif
+
+namespace plusplayer {
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+// to make transition_table cleaner
+// to use 'Row' 'Defer'
+using namespace msm::front;
+
+namespace es_event {
+
+using Operator = std::function<bool(void)>;
+struct Open {
+  Open() = default;
+  explicit Open(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct Close {
+  Close() = default;
+  explicit Close(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct Start {
+  Start() = default;
+  explicit Start(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct Stop {
+  Stop() = default;
+  explicit Stop(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct SetStream {
+  SetStream() = default;
+  explicit SetStream(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct Prepare {
+  Prepare() = default;
+  explicit Prepare(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct ResConflict {
+  ResConflict() = default;
+  explicit ResConflict(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct Pause {
+  Pause() = default;
+  explicit Pause(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct Resume {
+  Resume() = default;
+  explicit Resume(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct Seek {
+  Seek() = default;
+  explicit Seek(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+struct PlaybackRate {
+  PlaybackRate() = default;
+  explicit PlaybackRate(const Operator _op) : op(_op) {}
+  const Operator op;
+};
+
+}  // namespace es_event
+
+//
+// transition actions
+//
+struct ResetMaskStop {
+  template <class EVT, class FSM, class SourceState, class TargetState>
+  void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&) {
+    STATE_TRACE("entering Action : ResetMaskStop");
+    fsm.event_stop_mask = false;
+  }
+};
+
+using namespace es_event;
+struct EsStateMachine : msm::front::state_machine_def<EsStateMachine> {
+  //
+  // Customizing a state machine / Getting more speed
+  // -http://www.boost.org/doc/libs/1_57_0/libs/msm/doc/HTML/ch03s02.html#d0e1147
+  //
+  typedef int no_exception_thrown;  // no need for exception handling
+  // typedef int no_message_queue;  // no need for message queue
+  // we need this, check ut.
+  typedef int activate_deferred_events;  // manually enable deferred events
+
+  // when a transition is about to be taken, we already update our currently
+  // active state(s)
+  typedef msm::active_state_switch_before_transition active_state_switch_policy;
+
+  template <class Event, class FSM>
+  void on_entry(Event const&, FSM&) {
+    STATE_TRACE("entering: EsPlayer StateMachine");
+  }
+  template <class Event, class FSM>
+  void on_exit(Event const&, FSM&) {
+    STATE_TRACE("leaving: EsPlayer StateMachine");
+  }
+
+  //
+  // The list of FSM states
+  //
+  struct None : public msm::front::state<> {};
+  struct Idle : public msm::front::state<> {};
+  struct StreamReady : public msm::front::state<> {};
+  struct Ready : public msm::front::state<> {};
+  struct Playing : public msm::front::state<> {};
+  struct Paused : public msm::front::state<> {};
+
+  //
+  // guard conditions
+  //
+  struct AlwaysTrue {
+    template <class EVT, class FSM, class SourceState, class TargetState>
+    bool operator()(EVT const& evt, FSM&, SourceState& from, TargetState& to) {
+      return true;
+    }
+  };
+
+  struct CheckOp {
+    template <class EVT, class FSM, class SourceState, class TargetState>
+    bool operator()(EVT const& evt, FSM& fsm, SourceState& from,
+                    TargetState& to) {
+      if (fsm.event_stop_mask) return false;
+      return evt.op ? evt.op() : true;
+    }
+  };
+
+  struct AlwaysRun {
+    template <class EVT, class FSM, class SourceState, class TargetState>
+    bool operator()(EVT const& evt, FSM& fsm, SourceState& from,
+                    TargetState& to) {
+      return evt.op ? evt.op() : true;
+    }
+  };
+
+  //
+  // the initial state of the StateMachine. Must be defined
+  //
+  typedef None initial_state;
+
+  //
+  // Transition table
+  //
+  struct transition_table : mpl::vector<
+  //   Start         Event            Next          Action  Guard
+  //  +------------+----------------+-------------+------+--------+
+  Row< None        , Open           , Idle        , ResetMaskStop, AlwaysRun >,
+  Row< Idle        , Close          , None        , none, AlwaysRun >,
+  //   Start         Event            Next          Action        Guard
+  //  +------------+----------------+-------------+------------+--------+
+  Row< Idle         , SetStream     , StreamReady  , ResetMaskStop, CheckOp >,
+  Row< StreamReady  , SetStream     , StreamReady  , ResetMaskStop, CheckOp >,
+  Row< StreamReady  , Prepare       , Ready       , none, CheckOp >,
+  //   Start         Event            Next         Action    Guard
+  //  +------------+----------------+-------------+-----+--------+
+  Row< Ready       , Start          , Playing     , none, CheckOp >,
+  //   Start         Event           Next          Action    Guard
+  //  +------------+----------------+-------------+-----+---------+
+  Row< Ready       , Pause          , Paused      , none, CheckOp >,
+  Row< Playing     , Pause          , Paused      , none, CheckOp >,
+  Row< Paused      , Resume         , Playing     , none, CheckOp >,
+  //   Start         Event            Next         Action     Guard
+  //  +------------+----------------+-------------+-----+--------+
+  Row< None        , Close          , None        , none, AlwaysTrue >,
+  Row< Paused      , Pause          , Paused      , none, AlwaysTrue >,
+  Row< Playing     , Resume         , Playing     , none, AlwaysTrue >,
+  Row< Idle        , Stop           , Idle        , none, AlwaysTrue >,
+  //   Start         Event            Next          Action    Guard
+  //  +-------------+--------------+--------------+-----+--------+
+  Row< StreamReady    , Stop        , Idle         , none   , none >,
+  Row< Ready          , Stop        , Idle         , none   , none >,
+  Row< Playing        , Stop        , Idle         , none   , none >,
+  Row< Paused         , Stop        , Idle         , none   , none >,
+  //    Start         Event            Next       Action    Guard
+  //  +-------------+----------------+----------+---------+-------+
+  Row< Ready        , Seek           , Ready     , none,    CheckOp >,
+  Row< Playing      , Seek           , Playing   , none,    CheckOp >,
+  Row< Paused       , Seek           , Paused    , none,    CheckOp >,
+  //    Start         Event            Next       Action    Guard
+  //  +-------------+----------------+----------+---------+-------+
+  Row< Ready        , PlaybackRate   , Ready     , none    , CheckOp >,
+  Row< Paused       , PlaybackRate   , Paused    , none    , CheckOp >,
+  Row< Playing      , PlaybackRate   , Playing   , none    , CheckOp >
+  //  +-------------+----------------+--------------+---------+-------+
+  > {};
+
+  // Replaces the default no-transition response.
+  template <class FSM, class Event>
+  void no_transition(Event const& e, FSM& fsm, int state) {
+    LOG_ERROR("no transition on event[%s], check transition_table current[%d]",
+              typeid(e).name(), *fsm.current_state());
+  }
+
+  // Additional data section for customization
+  bool event_stop_mask = false;
+  bool is_preparing = false;
+};  // struct StateMachine
+
+class EsStateManager : private boost::noncopyable {
+ public:
+  EsStateManager() noexcept {}
+  ~EsStateManager() {}
+  void Start() {
+    std::lock_guard<std::mutex> lock(control_m_);
+    msm_.start();
+    stopped_ = false;
+  }
+  void* log_id_ = nullptr;
+
+  void Stop() {
+    // TODO(js4716.chun) :
+    //  - this is for ut_meta_state_machine.cpp MessageQueueTest.
+    //  - find out better solution.
+    while (GetState() != EsState::kNone) {
+      LOG_ERROR_P(this,
+                  "waiting the state to none before stopping state-machine");
+      std::this_thread::sleep_for(std::chrono::milliseconds(1));
+    }
+    {
+      std::lock_guard<std::mutex> lock(control_m_);
+      stopped_ = true;
+      // need to check & wait message queue is empty
+      msm_.stop();
+    }
+  }
+
+  template <typename T>
+  bool ProcessEvent(const T& es_event) {
+    std::lock_guard<std::mutex> lock(control_m_);
+    if (stopped_) return false;
+
+    ProcessEventRet ret = msm::back::HANDLED_FALSE;
+    STATE_TRACE_P(this, "Transition Request, Current[%d]", GetStateEnum());
+    if (!(ret = msm_.process_event(es_event))) {
+      STATE_TRACE_P(this, "process_event failed ret[%d], Current[%d]", ret,
+                    GetStateEnum());
+      return false;
+    }
+    if (ret == msm::back::HANDLED_GUARD_REJECT) {
+      STATE_TRACE_P(this,
+                    "Guard Rejected, probably event.op failed Current[%d]",
+                    GetStateEnum());
+      return false;
+    } else if (ret == msm::back::HANDLED_DEFERRED) {
+      STATE_TRACE_P(this, "Process_event Deffered");
+      // TODO(js4716.chun) : return값을 어떻게 해야하는가.
+      // - deferred된 이후 gaurd fail시 return값이 잘못 될 수 있다.
+      // - 이게 중요한가? 꼭 처리해야 하는가?
+    }
+    STATE_TRACE_P(this, "Process_event done Current[%d],ret[%d]",
+                  GetStateEnum(), ret);
+    return true;
+  }
+
+  bool ProcessEventStop(const es_event::Stop& stop_event) {
+    std::unique_lock<std::mutex> lock(control_m_, std::defer_lock);
+    lock.try_lock();
+    if (stopped_) return false;
+    STATE_TRACE_P(this, "Transition Stop Requested, Current[%d]",
+                  GetStateEnum());
+    msm_.event_stop_mask = true;
+    msm_.is_preparing = false;
+    if (!stop_event.op()) {
+      LOG_ERROR("Stop Operation failed");
+      return false;
+    }
+    ProcessEventRet ret = msm::back::HANDLED_FALSE;
+    STATE_TRACE_P(this, "Transition Request, Current[%d]", GetStateEnum());
+    if (!lock.owns_lock()) lock.lock();
+    if (!(ret = msm_.process_event(stop_event))) {
+      STATE_TRACE_P(this, "process_event_stop failed ret[%d], current[%d]", ret,
+                    GetStateEnum());
+      return false;
+    }
+    STATE_TRACE_P(this, "Process_event done Current[%d],ret[%d]",
+                  GetStateEnum(), ret);
+    return true;
+  }
+
+  EsState GetState() {
+    if (stopped_) return EsState::kNone;
+
+    unsigned int index = *msm_.current_state();
+    if (index >= state_vector_.size()) {
+      assert(0 && "invalid state id returned, something went wrong");
+      return EsState::kNone;
+    }
+    return state_vector_[index];
+  }
+
+  int GetStateEnum() {
+    if (stopped_) return static_cast<int>(EsState::kNone);
+
+    unsigned int index = *msm_.current_state();
+    if (index >= state_vector_.size()) {
+      assert(0 && "invalid state id returned, something went wrong");
+      return static_cast<int>(EsState::kNone);
+    }
+    return static_cast<int>(state_vector_[index]);
+  }
+
+  void SetPreparingState(bool val) { msm_.is_preparing = val; }
+
+  bool GetPreparingState() { return msm_.is_preparing; }
+
+ private:
+  std::mutex control_m_;  // TODO(js4716.chun) : remove this if possible
+  bool stopped_ = true;   // TODO(js4716.chun) : remove this if possible
+
+  // typedef enum {
+  //    HANDLED_FALSE        = 0,
+  //    HANDLED_TRUE         = 1,
+  //    HANDLED_GUARD_REJECT = 2,
+  //    HANDLED_DEFERRED     = 4
+  // } HandledEnum;
+  using ProcessEventRet = msm::back::HandledEnum;
+  // Generating rules of state ids
+  // http://www.boost.org/doc/libs/1_65_1/libs/msm/doc/HTML/ch06s03.html#internals-state-id
+  const std::vector<EsState> state_vector_ = {EsState::kNone,     // None
+                                              EsState::kIdle,     // Idle
+                                              EsState::kIdle,     // StreamReady
+                                              EsState::kReady,    // Ready
+                                              EsState::kPlaying,  // Playing
+                                              EsState::kPaused};  // Paused
+  msm::back::state_machine<EsStateMachine> msm_;
+};  // class StateManager
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_ESPLAYER_STATE_MANAGER_H__
\ No newline at end of file
diff --git a/src/esplusplayer/src/elementary_stream.cpp b/src/esplusplayer/src/elementary_stream.cpp
new file mode 100755 (executable)
index 0000000..9de2d37
--- /dev/null
@@ -0,0 +1,217 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "plusplayer/elementary_stream.h"
+
+namespace {
+
+constexpr int kLittleEdian = 1234;
+constexpr int kBigEdian = 4321;
+
+}  // namespace
+
+namespace plusplayer {
+
+AudioStream::AudioStream() noexcept {
+  track_.type = kTrackTypeAudio;
+  track_.index = 0;
+  track_.active = true;
+}
+
+void AudioStream::SetMimeType(AudioMimeType mimetype) {
+  mimetype_ = mimetype;
+  SetMimeType_(mimetype);
+}
+
+void AudioStream::SetMimeType_(AudioMimeType mimetype) {
+  mimetype_ = mimetype;
+  switch (mimetype) {
+    case AudioMimeType::kAAC: {
+      track_.mimetype = "audio/mpeg";
+      track_.version = 2;
+      break;
+    }
+    case AudioMimeType::kMP2: {
+      track_.mimetype = "audio/mpeg";
+      track_.version = 1;
+      track_.layer = 2;
+      break;
+    }
+    case AudioMimeType::kMP3: {
+      track_.mimetype = "audio/mpeg";
+      track_.version = 1;
+      track_.layer = 3;
+      break;
+    }
+    case AudioMimeType::kAC3: {
+      track_.mimetype = "audio/x-ac3";
+      break;
+    }
+    case AudioMimeType::kEAC3: {
+      track_.mimetype = "audio/x-eac3";
+      break;
+    }
+    case AudioMimeType::kVORBIS: {
+      track_.mimetype = "audio/x-vorbis";
+      break;
+    }
+    case AudioMimeType::kOPUS: {
+      track_.mimetype = "audio/x-opus";
+      break;
+    }
+    case AudioMimeType::kPCM_S16LE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = true;
+      track_.endianness = kLittleEdian;
+      track_.sample_format = 16;
+      break;
+    }
+    case AudioMimeType::kPCM_S16BE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = true;
+      track_.endianness = kBigEdian;
+      track_.sample_format = 16;
+      break;
+    }
+    case AudioMimeType::kPCM_U16LE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = false;
+      track_.endianness = kLittleEdian;
+      track_.sample_format = 16;
+      break;
+    }
+    case AudioMimeType::kPCM_U16BE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = false;
+      track_.endianness = kBigEdian;
+      track_.sample_format = 16;
+      break;
+    }
+    case AudioMimeType::kPCM_S24LE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = true;
+      track_.endianness = kLittleEdian;
+      track_.sample_format = 24;
+      break;
+    }
+    case AudioMimeType::kPCM_S24BE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = true;
+      track_.endianness = kBigEdian;
+      track_.sample_format = 24;
+      break;
+    }
+    case AudioMimeType::kPCM_U24LE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = false;
+      track_.endianness = kLittleEdian;
+      track_.sample_format = 24;
+      break;
+    }
+    case AudioMimeType::kPCM_U24BE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = false;
+      track_.endianness = kBigEdian;
+      track_.sample_format = 24;
+      break;
+    }
+    case AudioMimeType::kPCM_S32LE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = true;
+      track_.endianness = kLittleEdian;
+      track_.sample_format = 32;
+      break;
+    }
+    case AudioMimeType::kPCM_S32BE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = true;
+      track_.endianness = kBigEdian;
+      track_.sample_format = 32;
+      break;
+    }
+    case AudioMimeType::kPCM_U32LE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = false;
+      track_.endianness = kLittleEdian;
+      track_.sample_format = 32;
+      break;
+    }
+    case AudioMimeType::kPCM_U32BE: {
+      track_.mimetype = "audio/x-raw";
+      track_.is_signed = false;
+      track_.endianness = kBigEdian;
+      track_.sample_format = 32;
+      break;
+    }
+    case AudioMimeType::kG711_MULAW: {
+      track_.mimetype = "audio/x-mulaw";
+      force_swdecoder_use_ = true;
+      break;
+    }
+    default:
+      track_.mimetype = "unknown";
+      break;
+  }
+}
+
+VideoStream::VideoStream() noexcept {
+  track_.type = kTrackTypeVideo;
+  track_.index = 0;
+  track_.active = true;
+}
+
+void VideoStream::SetMimeType(VideoMimeType mimetype) {
+  mimetype_ = mimetype;
+  SetMimeType_(mimetype);
+}
+
+void VideoStream::SetMimeType_(VideoMimeType mimetype) {
+  switch (mimetype) {
+    case VideoMimeType::kH263:
+      track_.mimetype = "video/x-h263";
+      break;
+    case VideoMimeType::kH264:
+      track_.mimetype = "video/x-h264";
+      break;
+    case VideoMimeType::kHEVC:
+      track_.mimetype = "video/x-h265";
+      break;
+    case VideoMimeType::kMPEG1: {
+      track_.mimetype = "video/mpeg";
+      track_.version = 1;
+      break;
+    }
+    case VideoMimeType::kMPEG2: {
+      track_.mimetype = "video/mpeg";
+      track_.version = 2;
+      break;
+    }
+    case VideoMimeType::kMPEG4: {
+      track_.mimetype = "video/mpeg";
+      track_.version = 4;
+      break;
+    }
+    case VideoMimeType::kVP8:
+      track_.mimetype = "video/x-vp8";
+      break;
+    case VideoMimeType::kVP9:
+      track_.mimetype = "video/x-vp9";
+      break;
+    case VideoMimeType::kWMV3:
+      track_.mimetype = "video/x-wmv";
+      track_.version = 3;
+      break;
+    case VideoMimeType::kAV1:
+      track_.mimetype = "video/x-av1";
+      break;
+    case VideoMimeType::kMJPEG:
+      track_.mimetype = "video/x-jpeg";
+      break;
+    default:
+      track_.mimetype = "unknown";
+      break;
+  }
+}
+
+}  // namespace plusplayer
diff --git a/src/esplusplayer/src/espacket.cpp b/src/esplusplayer/src/espacket.cpp
new file mode 100755 (executable)
index 0000000..c9bf579
--- /dev/null
@@ -0,0 +1,37 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include "plusplayer/espacket.h"
+
+namespace plusplayer {
+EsPacketPtr EsPacket::Create(const StreamType type,
+                             std::shared_ptr<char> buffer,
+                             const uint32_t buffer_size, const uint64_t pts,
+                             const uint64_t duration,
+                             const uint32_t hdr10p_size,
+                             std::shared_ptr<char> hdr10p_data) {
+  return Ptr(new EsPacket(type, buffer, buffer_size, pts, duration, hdr10p_size,
+                          hdr10p_data));
+}
+
+EsPacketPtr EsPacket::CreateEos(const StreamType type) {
+  return Ptr(new EsPacket(type, nullptr, 0, 0, 0, 0, nullptr));
+}
+
+EsPacket::EsPacket(const StreamType type, std::shared_ptr<char> buffer,
+                   const uint32_t buffer_size, const uint64_t pts,
+                   const uint64_t duration, const uint32_t hdr10p_size,
+                   std::shared_ptr<char> hdr10p_data)
+    : type_(type),
+      buffer_size_(buffer_size),
+      pts_(pts),
+      duration_(duration),
+      hdr10p_metadata_size_(hdr10p_size) {
+  if (buffer) {
+    buffer_ = buffer;
+  }
+  if (hdr10p_data) {
+    hdr10p_metadata_ = hdr10p_data;
+  }
+}
+}  // namespace plusplayer
diff --git a/src/esplusplayer/src/espacket_logger.cpp b/src/esplusplayer/src/espacket_logger.cpp
new file mode 100755 (executable)
index 0000000..19cd11c
--- /dev/null
@@ -0,0 +1,91 @@
+//\r
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#include "esplayer/espacket_logger.h"\r
+\r
+#include <sstream>\r
+#include <thread>\r
+#include <utility>\r
+\r
+#include "core/utils/plusplayer_log.h"\r
+\r
+namespace internal {\r
+enum class TizenBuiltImageType { Unknown, Debug, Release, Perf };\r
+static TizenBuiltImageType GetBuiltImageType() {\r
+  static TizenBuiltImageType image_type;\r
+  if (image_type != TizenBuiltImageType::Unknown) return image_type;\r
+  if (access("/etc/debug", F_OK) == 0) {\r
+    image_type = TizenBuiltImageType::Debug;\r
+    LOG_DEBUG("Debug Image");\r
+  } else if (access("/etc/release", F_OK) == 0) {\r
+    image_type = TizenBuiltImageType::Release;\r
+    LOG_DEBUG("Release Image");\r
+  } else if (access("/etc/perf", F_OK) == 0) {\r
+    image_type = TizenBuiltImageType::Perf;\r
+    LOG_DEBUG("Perf Image");\r
+  }\r
+  return image_type;\r
+}\r
+}  // namespace internal\r
+\r
+namespace plusplayer {\r
+std::string EsPacketLogger::GetStringFromLastPacketInfo_(\r
+    const StreamType type) const {\r
+  const int track_index = static_cast<int>(type);\r
+  const auto& pkt_info = last_packet_info_[track_index];\r
+  std::ostringstream oss;\r
+  oss << "valid? [" << (pkt_info.valid ? 'T' : 'F') << "], ";\r
+  oss << "size [" << (pkt_info.size) << "], ";\r
+  oss << "pts [" << (pkt_info.pts) << "], ";\r
+  oss << "duration [" << (pkt_info.duration) << "], ";\r
+  oss << "is_eos? [" << (pkt_info.is_eos ? 'T' : 'F') << "]";\r
+  return oss.str();\r
+}\r
+\r
+void EsPacketLogger::StorePacketInfo(const EsPacketPtr& packet) {\r
+  if (packet == nullptr) return;\r
+  const int track_index = static_cast<int>(packet->GetType());\r
+  if (track_index >= static_cast<int>(StreamType::kMax)) return;\r
+\r
+  std::lock_guard<std::mutex> lk(mtx_);\r
+\r
+  auto& count = last_log_packet_count_[track_index];\r
+  count++;\r
+\r
+  auto& last_pkt_info = last_packet_info_[track_index];\r
+  last_pkt_info.valid = true;\r
+  last_pkt_info.size = packet->GetSize();\r
+  last_pkt_info.pts = packet->GetPts();\r
+  last_pkt_info.duration = packet->GetDuration();\r
+  last_pkt_info.is_eos = packet->IsEosPacket();\r
+}\r
+\r
+void EsPacketLogger::PrintStoredPacketInfo(const StreamType type, bool force) {\r
+  const bool printable = ((force) || (internal::GetBuiltImageType() ==\r
+                                      internal::TizenBuiltImageType::Debug));\r
+  if (printable == false) return;\r
+\r
+  const int track_index = static_cast<int>(type);\r
+  if (track_index >= static_cast<int>(StreamType::kMax)) return;\r
+\r
+  std::lock_guard<std::mutex> lk(mtx_);\r
+\r
+  const auto& count = last_log_packet_count_[track_index];\r
+  const bool in_timing =\r
+      (force) || (count == 1) || (count % kLogBufferThreshold == 0);\r
+  if (in_timing) {\r
+    const auto logmsg = GetStringFromLastPacketInfo_(type);\r
+    LOG_INFO("<pktinfo - %llu %s> [%s] %s", count, (force ? ": last" : ""),\r
+             (type == StreamType::kAudio ? "AUDIO" : "VIDEO"), logmsg.c_str());\r
+  }\r
+}\r
+\r
+void EsPacketLogger::ResetLog(const StreamType type) {\r
+  std::lock_guard<std::mutex> lk(mtx_);\r
+\r
+  last_packet_info_[static_cast<int>(type)].valid = false;\r
+  last_log_packet_count_[static_cast<int>(type)] = 0;\r
+}\r
+\r
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/esplusplayer/src/esplayer.cpp b/src/esplusplayer/src/esplayer.cpp
new file mode 100755 (executable)
index 0000000..dfecffc
--- /dev/null
@@ -0,0 +1,2580 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+// to manipulate TrackRenderer objects
+// to provide optimized control of TrackRenderer
+
+#include "esplayer/esplayer.h"
+
+#include <boost/scope_exit.hpp>
+#include <cassert>
+#include <chrono>
+#include <fstream>
+#include <functional>
+#include <memory>
+#include <sstream>
+#include <thread>
+
+#include "core/gst_utils.h"
+#include "core/track_util.h"
+#include "core/utils/caf_logger.h"
+#include "core/utils/performance_checker.h"
+#include "core/utils/plusplayer_cfg.h"
+#include "core/utils/plusplayer_log.h"
+#include "core/videoframetypestrategy.h"
+#include "esplayer/esplayer_drm.h"
+#include "json/json.h"
+
+namespace plusplayer {
+
+namespace es_conf {
+
+// get values from /etc/multimedia/esplusplayer.ini
+static std::once_flag loaded;
+static std::map<std::string, bool> ini_property;
+
+bool LoadIniFile();
+void LoadIniProperty(const Json::Value& root);
+
+}  // namespace es_conf
+
+namespace util {
+
+std::uint64_t ConvertMsToNs(std::uint64_t ms) {
+  constexpr std::uint64_t ns_unit = 1000000;
+  if (ms * ns_unit > G_MAXUINT64) return G_MAXUINT64;
+  return ms * ns_unit;
+}
+std::uint64_t ConvertNsToMs(std::uint64_t ns) {
+  constexpr std::uint64_t ms_unit = 1000000;
+  return ns / ms_unit;
+}
+
+std::int64_t ConvertMsToNs(std::int64_t ms) {
+  constexpr std::int64_t ns_unit = 1000000;
+  if (ms * ns_unit > G_MAXINT64) return G_MAXINT64;
+  return ms * ns_unit;
+}
+std::int64_t ConvertNsToMs(std::int64_t ns) {
+  constexpr std::int64_t ms_unit = 1000000;
+  return ns / ms_unit;
+}
+
+std::string GetStringFromMatroskaColor(const MatroskaColor& color_info) {
+  std::ostringstream oss;
+  oss << "matrixCoefficients:" << color_info.matrix_coefficients
+      << " bitsPerChannel:" << color_info.bits_per_channel
+      << " chromaSubsamplingHorz:" << color_info.chroma_subsampling_horizontal
+      << " chromaSubsamplingVert:" << color_info.chroma_subsampling_vertical
+      << " cbSubsamplingHorz:" << color_info.cb_subsampling_horizontal
+      << " cbSubsamplingVert:" << color_info.cb_subsampling_vertical
+      << " chromaSitingHorz:" << color_info.chroma_siting_horizontal
+      << " chromaSitingVert:" << color_info.chroma_siting_vertical
+      << " range:" << color_info.range
+      << " transferCharacteristics:" << color_info.transfer_characteristics
+      << " primaries:" << color_info.primaries
+      << " maxCLL:" << color_info.max_cll << " maxFALL:" << color_info.max_fall
+      << " RX:" << color_info.metadata.primary_r_chromaticity_x
+      << " RY:" << color_info.metadata.primary_r_chromaticity_y
+      << " GX:" << color_info.metadata.primary_g_chromaticity_x
+      << " GY:" << color_info.metadata.primary_g_chromaticity_y
+      << " BX:" << color_info.metadata.primary_b_chromaticity_x
+      << " BY:" << color_info.metadata.primary_b_chromaticity_y
+      << " wX:" << color_info.metadata.white_point_chromaticity_x
+      << " wY:" << color_info.metadata.white_point_chromaticity_y
+      << " luminanceMax:" << color_info.metadata.luminance_max
+      << " luminanceMin:" << color_info.metadata.luminance_min
+      << " isHDR10p:" << color_info.is_hdr_10p;
+  return oss.str();
+}
+
+}  // namespace util
+
+namespace internal {
+// const std::uint64_t kMaxByteOfVideoSrcQueue = 70 * 1024 * 1024;  // 70 MB
+// const std::uint64_t kMaxByteOfAudioSrcQueue = 10 * 1024 * 1024;  // 10 MB
+// const std::uint64_t kMaxTimeOfVideoSrcQueue = 10000000000;       // 10 s
+// const std::uint64_t kMaxTimeOfAudioSrcQueue = 10000000000;       // 10 s
+
+constexpr uint32_t kNdecodingMode = 0x04;
+
+enum VolumeLevel { kVolumeMin = 0, kVolumeMax = 100 };
+constexpr int kMaxFhdWidth = 1920;
+constexpr int kMaxFhdHeight = 1080;
+
+inline bool IsPcmMimeType(const std::string& mimetype) {
+  return (mimetype.find("audio/x-raw") != std::string::npos);
+}
+inline bool IsForcedUnsetTz(const Track& track, const std::string& id) {
+  if ((track.type == kTrackTypeAudio) && strstr(id.c_str(), "netflix")) {
+    return true;
+  }
+  return false;
+}
+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 IsAvailableCodecSwitch(const Track& track) {
+  if (internal::IsAacCodec(track) || internal::IsAc3Codec(track.mimetype) ||
+      internal::IsEac3Codec(track.mimetype))
+    return true;
+  return false;
+}
+
+int ResetEosStatus(const TrackType& type, int eos_status) {
+  if (type == kTrackTypeVideo)
+    eos_status &= ~EosStatus::kVideoEos;
+  else if (type == kTrackTypeAudio)
+    eos_status &= ~EosStatus::kAudioEos;
+  return eos_status;
+}
+
+void MakeTrustZoneTracks(std::vector<Track>& tracks,
+                         const std::string& app_id) {
+  for (auto& track : tracks) {
+    const bool is_already_tz_type =
+        (track.mimetype.find("_tz", track.mimetype.length() - 3) !=
+         std::string::npos);
+    if (is_already_tz_type) {
+      continue;
+    }
+    track.streamtype = track.mimetype;
+    if (track.use_swdecoder || IsPcmMimeType(track.mimetype) ||
+        IsForcedUnsetTz(track, app_id))
+      continue;
+    else
+      track.mimetype = track.mimetype + "_tz";
+  }
+}
+
+void UpdateCodecTypeTracks(std::vector<Track>& tracks,
+                           const PlayerAudioCodecType& audio_codec_type,
+                           const PlayerVideoCodecType& video_codec_type,
+                           bool force_audio_swdecoder_use) {
+  for (auto& track : tracks) {
+    switch (track.type) {
+      case kTrackTypeAudio: {
+        if (audio_codec_type == kPlayerAudioCodecTypeSW ||
+            force_audio_swdecoder_use)
+          track.use_swdecoder = true;
+        else
+          track.use_swdecoder = false;
+        break;
+      }
+      case kTrackTypeVideo: {
+        if (video_codec_type == kPlayerVideoCodecTypeSW)
+          track.use_swdecoder = true;
+        else
+          track.use_swdecoder = false;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+}
+inline bool IsSupportedDrmType(const drm::Type& drm_type) {
+  static const std::map<drm::Type, bool> kSupportedDrmType = {
+      {drm::Type::kPlayready, true},
+  };
+  if (kSupportedDrmType.count(drm_type) == 0) return false;
+  return kSupportedDrmType.at(drm_type);
+}
+inline void ResetDrmProperty(drm::Property& drm_property) {
+  drm_property = drm::Property();
+}
+inline StreamType ConvertToStreamType(TrackType type) {
+  return (type == kTrackTypeAudio) ? StreamType::kAudio : StreamType::kVideo;
+}
+struct AppsrcQueueSizeOption {
+  std::uint64_t current_size = 0;
+  std::uint64_t max_size = 0;
+  std::uint32_t threshold = 0;
+};
+inline bool IsUnderRun(AppsrcQueueSizeOption& byte_based,
+                       AppsrcQueueSizeOption& time_based) {
+  bool need_data_by_byte = false, need_data_by_time = false;
+  need_data_by_byte = (byte_based.max_size > 0) &&
+                      (byte_based.current_size * 100 / byte_based.max_size <=
+                       byte_based.threshold);
+  need_data_by_time = (time_based.max_size > 0) &&
+                      (time_based.current_size * 100 / time_based.max_size <=
+                       time_based.threshold);
+  if (need_data_by_byte || need_data_by_time)
+    return true;
+  else
+    return false;
+}
+inline bool IsLowLatencyModeDisableAVSync(std::uint32_t mode) {
+  constexpr std::uint32_t kAVSync = 0x0100;
+  return (mode & kAVSync) ? true : false;
+}
+inline bool IsLowLatencyModeDisablePreroll(std::uint32_t mode) {
+  constexpr std::uint32_t kPreroll = 0x0200;
+  return (mode & kPreroll) ? true : false;
+}
+inline bool IsLowLatencyMode(std::uint32_t mode) {
+  return (mode != static_cast<std::uint32_t>(kLowLatencyModeNone)) ? true
+                                                                   : false;
+}
+inline bool IsSupportedTsOffset(std::uint32_t mode) {
+  return IsLowLatencyMode(mode) && !IsLowLatencyModeDisableAVSync(mode) ? true
+                                                                        : false;
+}
+inline bool IsSetLowLatencyModeForCatchUp(std::uint32_t low_latency_mode) {
+  std::uint32_t precondition = 0;
+  precondition |= static_cast<std::uint32_t>(kLowLatencyModeAudio);
+  precondition |= static_cast<std::uint32_t>(kLowLatencyModeVideo);
+  precondition |= static_cast<std::uint32_t>(kLowLatencyModeDisableAVSync);
+  precondition |=
+      static_cast<std::uint32_t>(kLowLatencyModeDisableVideoQuality);
+  return (low_latency_mode == precondition) ? true : false;
+}
+
+}  // namespace internal
+
+EsPlayer::EsPlayer() {
+  std::call_once(es_conf::loaded, [this]() { es_conf::LoadIniFile(); });
+  if (CafLogger::Initialize() != true) {
+    LOG_INFO("CAF Dbus not connect.");
+  }
+}
+
+EsPlayer::~EsPlayer() {
+  LOG_ENTER_P(this);
+  Close();
+  LOG_LEAVE_P(this);
+}
+
+bool EsPlayer::Open() {
+  LOG_INFO_P(this, "state manager > %p", &state_manager_);
+  Init_();
+  state_manager_.Start();
+  auto op = [this]() noexcept -> bool {
+    const auto start = performance_checker::Start();
+    if (trackrenderer_) {
+      assert(0 && "trackrenderer already exist");
+    }
+    msg_handler_task_ =
+        std::async(std::launch::async, &EsPlayer::MsgTask_, this);
+    trackrenderer_ = TrackRendererAdapter::Create();
+    assert(trackrenderer_);
+
+    trackrenderer_->RegisterListenerForEsplayer(
+        trackrenderer_event_listener_.get());
+    performance_checker::End(start, "Open");
+    return true;
+  };
+  CafLogger::SetUniqueNumber();
+  caf_unique_number = CafLogger::GetUniqueNumber();
+  CafLogger::LogMessage(CafEventType::kIdle, caf_unique_number);
+
+  es_event::Open event{op};
+  return state_manager_.ProcessEvent(event);
+}
+
+bool EsPlayer::Close() {
+  LOG_ENTER_P(this);
+  std::lock_guard<std::mutex> lk(submit_mutex_);
+  if (state_manager_.GetState() >= EsState::kIdle) {
+    Stop();
+  }
+  auto op = [this]() noexcept {
+    if (is_msg_task_stop_ == false) {
+      is_msg_task_stop_ = true;
+      msg_task_cv_.notify_one();
+      if (msg_handler_task_.valid()) msg_handler_task_.wait();
+    }
+
+    if (trackrenderer_) trackrenderer_.reset();
+    ResetContextForClose_();
+    LOG_LEAVE_P(this);
+    return true;
+  };
+  es_event::Close event{op};
+  state_manager_.ProcessEvent(event);
+  state_manager_.Stop();
+  return true;
+}
+
+bool EsPlayer::Deactivate(const StreamType type) {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (!enable_audio_pipeline_handle_ && type == StreamType::kAudio) {
+    LOG_ERROR_P(
+        this, "can't deactivate audio stream, mixer will control audio stream");
+    return false;
+  }
+#endif
+  if (!trackrenderer_->Deactivate(static_cast<TrackType>(type))) {
+    return false;
+  }
+  {
+    std::lock_guard<std::mutex> lock(eos_mutex_);
+    switch (type) {
+      case StreamType::kAudio:
+        eos_status_ |= EosStatus::kAudioEos;
+        break;
+      case StreamType::kVideo:
+        eos_status_ |= EosStatus::kVideoEos;
+        break;
+      default:
+        break;
+    }
+  }
+  for (auto& track : track_) {
+    if (track.type == static_cast<TrackType>(type)) {
+      track.active = false;
+    }
+  }
+  return true;
+}
+
+bool EsPlayer::Activate(const StreamType type) {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (!enable_audio_pipeline_handle_ && type == StreamType::kAudio) {
+    LOG_ERROR_P(this,
+                "can't activate audio stream, mixer will control audio stream");
+    return false;
+  }
+#endif
+  if (!track_.empty()) {
+    auto has_track = [type](const Track& item) -> bool {
+      return item.type == static_cast<TrackType>(type);
+    };
+    auto target = std::find_if(track_.begin(), track_.end(), has_track);
+    if (target == track_.end()) {
+      LOG_ERROR_P(this, "there is no track to activate");
+      return false;
+    }
+    if (target->active != false) {
+      LOG_ERROR_P(this, "The track should be deactivated in advance.");
+      return false;
+    }
+    target->active = true;
+    internal::UpdateCodecTypeTracks(track_, audio_codec_type_,
+                                    video_codec_type_,
+                                    force_audio_swdecoder_use_);
+    if (drm_property_.external_decryption) {
+      internal::MakeTrustZoneTracks(track_, app_info_.id);
+    }
+    SetTrackRendererAttributes_();
+#ifndef IS_AUDIO_PRODUCT
+    if (type == StreamType::kVideo) {
+      if (mixer_ticket_)
+        trackrenderer_->SetVideoFrameBufferType(
+            VideoFrameTypeStrategyPtr(new RawVideoFrameTypeStrategy()));
+      else
+        trackrenderer_->SetVideoFrameBufferType(VideoFrameTypeStrategyPtr(
+            new DefaultVideoFrameTypeStrategy(vidoe_frame_buffer_type_)));
+    }
+#endif
+    if (!trackrenderer_->Activate(target->type, *target)) {
+      target->active = false;
+      return false;
+    }
+    eos_status_ =
+        internal::ResetEosStatus(static_cast<TrackType>(type), eos_status_);
+    return true;
+  }
+  return false;
+}
+
+bool EsPlayer::Start() {
+  LOG_ENTER_P(this);
+  if (is_stopped_) {
+    LOG_ERROR_P(this, "Stop already, no need to Start,leave...");
+    return false;
+  }
+  auto op = [this]() noexcept {
+    if (!trackrenderer_->Start()) {
+      return false;
+    }
+    return true;
+  };
+
+  CafLogger::LogMessage(CafEventType::kPlaying, caf_unique_number);
+
+  es_event::Start event{op};
+  return state_manager_.ProcessEvent(event);
+}
+
+bool EsPlayer::Stop() {
+  LOG_ENTER_P(this);
+  is_stopped_ = true;
+  auto stop = [this]() noexcept -> bool {
+    const auto start = performance_checker::Start();
+    if (trackrenderer_) trackrenderer_->Stop();
+    ResetContextForStop_();
+#ifndef IS_AUDIO_PRODUCT
+    if (mixer_ticket_) mixer_ticket_.reset();
+#endif
+    performance_checker::End(start, "Stop");
+    return true;
+  };
+  for (const auto& track : track_) {
+    es_packet_logger_.PrintStoredPacketInfo(
+        internal::ConvertToStreamType(track.type), true);
+  }
+  es_event::Stop event{stop};
+  bool res = state_manager_.ProcessEventStop(event);
+
+  if (preparetask_.valid()) {
+    LOG_INFO_P(this, "Stopped , Wait Prepare() finish...");
+    preparetask_.wait();
+    LOG_INFO_P(this, "Wait , Wait Prepare() Done...");
+  }
+
+  CafLogger::LogMessage(CafEventType::kIdle, caf_unique_number);
+  CafLogger::StopLoggingThread();
+
+  return res;
+}
+
+void EsPlayer::SetTrackRendererAttributes_() {
+  if (trackrenderer_ == nullptr) return;
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kVideoQueueMaxByte,
+      src_queue_size_.kMaxByteOfVideoSrcQueue);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kAudioQueueMaxByte,
+      src_queue_size_.kMaxByteOfAudioSrcQueue);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kVideoMinByteThreshold,
+      src_queue_size_.kMinByteThresholdOfVideoSrcQueue);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kAudioMinByteThreshold,
+      src_queue_size_.kMinByteThresholdOfAudioSrcQueue);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kVideoQueueMaxTime,
+      util::ConvertMsToNs(src_queue_size_.kMaxTimeOfVideoSrcQueue));
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kAudioQueueMaxTime,
+      util::ConvertMsToNs(src_queue_size_.kMaxTimeOfAudioSrcQueue));
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kVideoMinTimeThreshold,
+      src_queue_size_.kMinTimeThresholdOfVideoSrcQueue);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kAudioMinTimeThreshold,
+      src_queue_size_.kMinTimeThresholdOfAudioSrcQueue);
+  trackrenderer_->SetAttribute(TrackRendererAdapter::Attribute::kLowLatencyMode,
+                               low_latency_mode_);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kVideoFramePeekMode,
+      video_frame_peek_mode_);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kUnlimitedMaxBufferMode,
+      unlimited_max_buffer_mode_);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kAccurateSeekMode, accurate_seek_mode_);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kVideoPreDisplayMode,
+      video_pre_display_mode_);
+  if (resume_time_.is_set) {
+    trackrenderer_->SetAttribute(
+        TrackRendererAdapter::Attribute::kStartRenderingTime,
+        resume_time_.time);
+    resume_time_.is_set = false;
+  }
+  trackrenderer_->SetAttribute(TrackRendererAdapter::Attribute::kFmmMode,
+                               fmm_mode_);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kAlternativeVideoResource,
+      alternaltive_video_resource_);
+  trackrenderer_->SetAttribute(
+      TrackRendererAdapter::Attribute::kVideoDecodingMode,
+      video_decoding_mode_);
+}
+
+#ifndef IS_AUDIO_PRODUCT
+bool EsPlayer::PrepareVideoMixingMode_(std::vector<Track>* tracks) {
+  LOG_ENTER_P(this);
+  mixer_ticket_->Prepare();
+  if (enable_rsc_alloc_handle_) return true;
+  ResourceType type = ResourceType::kHwMain;
+  if (!mixer_ticket_->GetAvailableResourceType(ResourceCategory::kVideoDecoder,
+                                               &type)) {
+    LOG_ERROR_P(this, "no available resource");
+    return false;
+  }
+  if (!mixer_ticket_->Alloc(ResourceCategory::kVideoDecoder, type)) {
+    LOG_ERROR_P(this, "fail to alloc resource [%d]", static_cast<int>(type));
+    return false;
+  }
+
+  if (type == ResourceType::kHwSub) {
+    alternaltive_video_resource_ = 1;
+  } else if (type == ResourceType::kSw) {
+    for (auto it = tracks->begin(); it != tracks->end(); ++it) {
+      if (it->type == kTrackTypeVideo) {
+        it->use_swdecoder = true;
+        break;
+      }
+    }
+  } else if (type == ResourceType::kNdecoder) {
+    video_decoding_mode_ = internal::kNdecodingMode;
+  }
+  return true;
+}
+#endif
+
+bool EsPlayer::Prepare_() {
+  LOG_ENTER_P(this);
+  if (is_stopped_) {
+    LOG_ERROR_P(this, "Stop already, no need to prepare,leave...");
+    return false;
+  }
+  auto op = [this]() noexcept -> bool {
+    const auto start = performance_checker::Start();
+
+    internal::UpdateCodecTypeTracks(track_, audio_codec_type_,
+                                    video_codec_type_,
+                                    force_audio_swdecoder_use_);
+    if (drm_property_.external_decryption) {
+      internal::MakeTrustZoneTracks(track_, app_info_.id);
+    }
+    std::vector<Track> active_track;
+    if (!track_util::GetActiveTrackList(track_, active_track)) {
+      return false;
+    }
+    trackrenderer_->SetIniProperty(es_conf::ini_property);
+#ifndef IS_AUDIO_PRODUCT
+    if (mixer_ticket_) {
+      trackrenderer_->SetVideoFrameBufferType(
+          VideoFrameTypeStrategyPtr(new RawVideoFrameTypeStrategy()));
+      if (!PrepareVideoMixingMode_(&active_track)) {
+        LOG_ERROR_P(this, "fail to prepare mixing mode");
+        return false;
+      }
+    }
+    std::unique_lock<std::mutex> lock(audio_focus_m_);
+    if (!enable_audio_pipeline_handle_ && !is_audio_focused_) {
+      for (auto it = active_track.begin(); it != active_track.end(); ++it) {
+        if (it->type == kTrackTypeAudio) {
+          active_track.erase(it);
+          LOG_INFO_P(this, "erase audio track is_audio_focused_ [%d]",
+                     is_audio_focused_);
+          break;
+        }
+      }
+    }
+#endif
+    for (const auto& track : active_track) {
+      switch (track.type) {
+        case kTrackTypeAudio: {
+          std::lock_guard<std::mutex> lock2(eos_mutex_);
+          eos_status_ = internal::ResetEosStatus(kTrackTypeAudio, eos_status_);
+          need_data_[track.type].mask |= kNeedDataMaskByPrepare;
+          break;
+        }
+        case kTrackTypeVideo: {
+          std::lock_guard<std::mutex> lock2(eos_mutex_);
+          eos_status_ = internal::ResetEosStatus(kTrackTypeVideo, eos_status_);
+          need_data_[track.type].mask |= kNeedDataMaskByPrepare;
+          break;
+        }
+        default:
+          break;
+      }
+    }
+    trackrenderer_->SetTrack(active_track);
+    SetTrackRendererAttributes_();
+    if (!trackrenderer_->Prepare()) {
+      return false;
+    }
+    performance_checker::End(start, "Prepare");
+    return true;
+  };
+
+  CafLogger::StartLoggingThread();
+  CafLogger::LogMessage(CafEventType::kReady, caf_unique_number);
+
+  es_event::Prepare event{op};
+  if (!state_manager_.ProcessEvent(event)) {
+    return false;
+  }
+  LOG_LEAVE_P(this);
+  return true;
+}
+
+void EsPlayer::PrepareTask_() {
+  bool ret = Prepare_();
+
+  state_manager_.SetPreparingState(false);
+  if (eventlistener_) {
+    LOG_INFO_P(this, "Prepare completely, call OnPrepareDone(%d)", ret);
+    eventlistener_->OnPrepareDone(ret, eventlistener_userdata_);
+  }
+
+  kpi::CodecLogger logger;
+  kpi::EsCodecLoggerKeys event_keys = MakeKpiKeys_();
+  logger.SendKpi(ret, event_keys);
+  LOG_LEAVE_P(this);
+}
+
+bool EsPlayer::PrepareAsync() {
+  LOG_ENTER_P(this);
+  state_manager_.SetPreparingState(true);
+  preparetask_ = std::async(std::launch::async, &EsPlayer::PrepareTask_, this);
+  if (!preparetask_.valid()) {
+    state_manager_.SetPreparingState(false);
+    return false;
+  }
+  return true;
+}
+
+bool EsPlayer::Pause() {
+  LOG_ENTER_P(this);
+  if (is_stopped_) {
+    LOG_ERROR_P(this, "Stop already, no need to pause,leave...");
+    return false;
+  }
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  auto op = [this]() noexcept -> bool {
+    if (!trackrenderer_) return false;
+    if (!trackrenderer_->Pause()) {
+      return false;
+    }
+    return true;
+  };
+  for (const auto& track : track_) {
+    es_packet_logger_.PrintStoredPacketInfo(
+        internal::ConvertToStreamType(track.type), true);
+  }
+
+  CafLogger::LogMessage(CafEventType::kPaused, caf_unique_number);
+
+  es_event::Pause event{op};
+  return state_manager_.ProcessEvent(event);
+}
+
+bool EsPlayer::Resume() {
+  LOG_ENTER_P(this);
+  if (is_stopped_) {
+    LOG_ERROR_P(this, "Stop already, no need to Resume,leave...");
+    return false;
+  }
+  if (state_manager_.GetState() <= EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  if (is_resource_conflicted_) {
+    LOG_ERROR_P(this, "Resuem fail resource conflicted");
+    return false;
+  }
+  auto op = [this]() noexcept -> bool {
+    if (!trackrenderer_) return false;
+    if (!trackrenderer_->Resume()) {
+      return false;
+    }
+    return true;
+  };
+  for (const auto& track : track_) {
+    es_packet_logger_.PrintStoredPacketInfo(
+        internal::ConvertToStreamType(track.type), true);
+  }
+
+  CafLogger::LogMessage(CafEventType::kPlaying, caf_unique_number);
+
+  es_event::Resume event{op};
+  return state_manager_.ProcessEvent(event);
+}
+
+bool EsPlayer::Seek(const uint64_t time_millisecond) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  if (state_manager_.GetState() == EsState::kIdle) {
+    if (state_manager_.GetPreparingState()) {
+      LOG_ERROR_P(this, "Invalid State , during preparing");
+      return false;
+    }
+    LOG_ERROR_P(this, "resume time [%llu ms]", time_millisecond);
+    resume_time_.is_set = true;
+    resume_time_.time = time_millisecond;
+    return true;
+  }
+  is_seek_done_need_drop = true;
+  LOG_DEBUG_P(this, "[ENTER] seek time [%llu ms]", time_millisecond);
+  for (const auto& track : track_) {
+    eos_status_ = internal::ResetEosStatus(track.type, eos_status_);
+    es_packet_logger_.PrintStoredPacketInfo(
+        internal::ConvertToStreamType(track.type), true);
+  }
+  auto op = [this, time_millisecond]() -> bool {
+    if (!trackrenderer_->Seek(time_millisecond, current_playback_rate_,
+                              current_audio_mute_)) {
+      return false;
+    }
+    return true;
+  };
+  es_event::Seek event{op};
+  bool ret = state_manager_.ProcessEvent(event);
+  is_seek_done_need_drop = false;
+
+  if (eventlistener_) {
+    if (internal::IsLowLatencyModeDisableAVSync(low_latency_mode_) ||
+        internal::IsLowLatencyModeDisablePreroll(low_latency_mode_)) {
+      auto listener = std::bind(&plusplayer::EsEventListener::OnSeekDone,
+                                eventlistener_, std::placeholders::_1);
+      auto msg = es_msg::Simple::Make(listener, eventlistener_userdata_);
+      std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);
+      msg_queue_.push(std::move(msg));
+      msg_mutex.unlock();
+      msg_task_cv_.notify_one();
+    }
+  }
+  LOG_DEBUG_P(this, "[LEAVE] seek end [%llu ms]", time_millisecond);
+  return ret;
+}
+
+void EsPlayer::SetAppInfo(const PlayerAppInfo& app_info) {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return;
+  }
+  app_info_ = app_info;
+  trackrenderer_->SetAppInfo(app_info);
+  LOG_INFO("Appid [%s]", app_info.id.c_str());
+  CafLogger::SetAppId(app_info.id);
+}
+
+bool EsPlayer::SetPlaybackRate(const double rate, const bool audio_mute) {
+  LOG_ENTER_P(this);
+
+  if (rate <= 0 || rate > 2.0) {
+    LOG_ERROR_P(this, "Not a valid PlaybackRate");
+    return false;
+  }
+
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  auto op = [this, rate, audio_mute]() -> bool {
+    if (!trackrenderer_->SetPlaybackRate(rate, audio_mute)) {
+      return false;
+    }
+    current_playback_rate_ = rate;
+    current_audio_mute_ = audio_mute;
+    return true;
+  };
+  es_event::PlaybackRate event{op};
+  return state_manager_.ProcessEvent(event);
+
+  LOG_LEAVE_P(this);
+  return true;
+}
+
+bool EsPlayer::SetDisplay(const DisplayType& type, void* obj) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (mixer_ticket_) mixer_ticket_.reset();
+#endif
+  return trackrenderer_->SetDisplay(type, obj);
+}
+
+#ifndef IS_AUDIO_PRODUCT
+bool EsPlayer::SetDisplay(const DisplayType& type, MixerTicket* handle) {
+  if (type == DisplayType::kMixer) {
+    LOG_INFO_P(this, "Create MixerTicket");
+    mixer_ticket_.reset(handle);
+    mixer_ticket_->RegisterListener(mixer_event_listener_.get());
+    if (mixer_ticket_->IsAudioFocusHandler())
+      enable_audio_pipeline_handle_ = false;
+    if (mixer_ticket_->IsRscAllocHandler()) enable_rsc_alloc_handle_ = false;
+    trackrenderer_->SetDisplay(DisplayType::kNone, nullptr);
+  }
+  return true;
+}
+#endif
+
+bool EsPlayer::SetDisplay(const DisplayType& type, void* ecore_wl2_window,
+                          const int x, const int y, const int w, const int h) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (mixer_ticket_) mixer_ticket_.reset();
+#endif
+  return trackrenderer_->SetDisplay(type, ecore_wl2_window, x, y, w, h);
+}
+
+bool EsPlayer::SetDisplaySubsurface(const DisplayType& type,
+                                    void* ecore_wl2_subsurface, const int x,
+                                    const int y, const int w, const int h) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (mixer_ticket_) mixer_ticket_.reset();
+#endif
+  return trackrenderer_->SetDisplaySubsurface(type, ecore_wl2_subsurface, x, y,
+                                              w, h);
+}
+
+bool EsPlayer::SetDisplay(const DisplayType& type, unsigned int surface_id,
+                          const int x, const int y, const int w, const int h) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (mixer_ticket_) mixer_ticket_.reset();
+#endif
+  return trackrenderer_->SetDisplay(type, surface_id, x, y, w, h);
+}
+
+bool EsPlayer::SetDisplayMode(const DisplayMode& mode) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  trackrenderer_->SetDisplayMode(mode);
+  return true;
+}
+
+bool EsPlayer::SetDisplayRoi(const Geometry& roi) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (mixer_ticket_) {
+    LOG_INFO_P(this, "mixed player roi x[%d] y[%d] w[%d] h[%d]", roi.x, roi.y,
+               roi.w, roi.h);
+    mixerticket_roi_ = roi;
+    return true;
+  }
+#endif
+  return trackrenderer_->SetDisplayRoi(roi);
+}
+
+bool EsPlayer::SetVideoRoi(const CropArea& area) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->SetVideoRoi(area);
+}
+
+bool EsPlayer::ResizeRenderRect(const RenderRect& rect) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->ResizeRenderRect(rect);
+}
+
+bool EsPlayer::SetDisplayRotate(const DisplayRotation& rotate) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->SetDisplayRotate(rotate);
+}
+
+bool EsPlayer::GetDisplayRotate(DisplayRotation* rotate) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  if (trackrenderer_->GetDisplayRotate(rotate)) {
+    return true;
+  }
+  return false;
+}
+
+bool EsPlayer::SetDisplayVisible(bool is_visible) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (mixer_ticket_) {
+    LOG_INFO_P(this, "mixed player is_visible [%d] -> [%d]", is_visible_,
+               is_visible);
+    is_visible_ = is_visible;
+    return true;
+  }
+#endif
+  return trackrenderer_->SetDisplayVisible(is_visible);
+}
+
+bool EsPlayer::SetTrustZoneUse(bool is_using_tz) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  if (drm_property_.type != drm::Type::kNone) {
+    LOG_ERROR_P(this, "drm type is already set for sending encrypted packets");
+    return false;
+  }
+  LOG_INFO_P(this, "set trust zone use [%d]", is_using_tz);
+  drm_property_.external_decryption = is_using_tz;
+
+  drm::Property drm_property = drm_property_;
+  drm_property.type = drm::Type::kPlayready;
+  trackrenderer_->SetDrm(drm_property);
+  return true;
+}
+
+bool EsPlayer::SetSubmitDataType(SubmitDataType type) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  LOG_INFO_P(this, "set submit data type [%d]", static_cast<int>(type));
+
+  if (type == SubmitDataType::kCleanData) return true;
+  submit_data_type_ = type;
+  drm_property_.type = drm::Type::kPlayready;
+  // TODO: following SubmitDataType, need to set external_decryption
+  drm_property_.external_decryption = true;
+  drm::Property drm_property = drm_property_;
+  trackrenderer_->SetDrm(drm_property);
+  return true;
+}
+
+bool EsPlayer::SetTrack_(const Track& track) {
+  LOG_ENTER_P(this);
+  track_.push_back(std::move(track));
+  return true;
+}
+
+bool EsPlayer::ChangeStream_(const Track& track) {
+  TrackType type = track.type;
+  if (track_.empty()) return false;
+  auto has_track = [type](const Track& item) -> bool {
+    return item.type == type;
+  };
+  std::lock_guard<std::mutex> lk(submit_mutex_);
+  auto target = std::find_if(track_.begin(), track_.end(), has_track);
+  if (target == track_.end()) {
+    LOG_ERROR_P(this, "Add a new stream.");
+    SetTrack_(track);
+    return true;
+  }
+  if (target->active != false) {
+    LOG_ERROR_P(this, "The track should be deactivated in advance.");
+    return false;
+  }
+  track_.erase(target);
+  LOG_ERROR_P(this, "previously added %s stream is deleted",
+              (type == kTrackTypeAudio) ? "audio" : "video");
+  return SetTrack_(track);
+}
+
+bool EsPlayer::SetStream_(const Track& track) {
+  TrackType type = track.type;
+  if (!track_.empty()) {
+    auto has_track = [type](const Track& item) -> bool {
+      return item.type == type;
+    };
+    auto target = std::find_if(track_.begin(), track_.end(), has_track);
+    if (target != track_.end()) {
+      LOG_ERROR_P(this, "Stream is already exist");
+      return false;
+    }
+  }
+  auto op = [this, track]() noexcept {
+    if (!SetTrack_(track)) {
+      return false;
+    }
+    return true;
+  };
+
+  CafLogger::LogMessage(CafEventType::kStreamReady, caf_unique_number);
+
+  es_event::SetStream event{op};
+  return state_manager_.ProcessEvent(event);
+}
+
+bool EsPlayer::SetStream(const AudioStreamPtr& stream) {
+  LOG_ENTER_P(this);
+  bool ret = false;
+  BOOST_SCOPE_EXIT(&ret, &stream, &force_audio_swdecoder_use_) {
+    if (ret) force_audio_swdecoder_use_ = stream->GetForceSwDecoderUse();
+  }
+  BOOST_SCOPE_EXIT_END
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return ret;
+  }
+  Track track = stream->GetTrack_();
+  if (state_manager_.GetState() >= EsState::kReady) {
+    track.active = false;
+    ret = ChangeStream_(track);
+    return ret;
+  }
+  ret = SetStream_(track);
+  return ret;
+}
+
+bool EsPlayer::SetStream(const VideoStreamPtr& stream) {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  Track track = stream->GetTrack_();
+  if (state_manager_.GetState() >= EsState::kReady) {
+    track.active = false;
+    return ChangeStream_(track);
+  }
+  return SetStream_(track);
+}
+
+bool EsPlayer::SwitchAudioStreamOnTheFly(const AudioStreamPtr& stream) {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  Track track = stream->GetTrack_();
+
+  if (!internal::IsAvailableCodecSwitch(track)) {
+    LOG_ERROR_P(this, "Invalid new mimetype [%s][%d]", track.mimetype.c_str(),
+                track.version);
+    return false;
+  }
+  for (auto& old_track : track_) {
+    if (old_track.type == TrackType::kTrackTypeAudio) {
+      if (!internal::IsAvailableCodecSwitch(old_track)) {
+        LOG_ERROR_P(this, "Invalid previous mimetype [%s][%d]",
+                    old_track.mimetype.c_str(), old_track.version);
+        return false;
+      }
+      if (!Flush(StreamType::kAudio)) return false;
+      old_track.active = false;
+      break;
+    }
+  }
+  if (!ChangeStream_(track)) return false;
+
+  trackrenderer_->SetTrack(track_);
+  return true;
+}
+
+bool EsPlayer::SetAdvancedPictureQualityType(const AdvPictureQualityType type) {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  trackrenderer_->SetAdvancedPictureQualityType(type);
+  return true;
+}
+
+bool EsPlayer::SetResourceAllocatePolicy(const RscAllocPolicy policy) {
+  LOG_ENTER_P(this);
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  trackrenderer_->SetResourceAllocatePolicy(policy);
+  return true;
+}
+
+void EsPlayer::ResetContextForClose_() {
+  internal::ResetDrmProperty(drm_property_);
+  track_.clear();
+  submit_data_type_ = SubmitDataType::kCleanData;
+  low_latency_mode_ = 0;
+  resume_time_.is_set = false;
+  video_frame_peek_mode_ = 0;
+  unlimited_max_buffer_mode_ = 0;
+  fmm_mode_ = 0;
+  audio_codec_type_ = kPlayerAudioCodecTypeHW;
+  video_codec_type_ = kPlayerVideoCodecTypeHW;
+  is_resource_conflicted_ = false;
+  app_info_ = PlayerAppInfo();
+  src_queue_size_ = SrcQueueSize();
+  is_msg_task_stop_ = false;
+}
+
+void EsPlayer::ResetContextForStop_() {
+  for (int i = 0; i < kTrackTypeMax; ++i) {
+    need_data_[i].mask = kNeedDataMaskNone;
+    need_data_[i].seek_offset = 0;
+  }
+  {
+    std::lock_guard<std::mutex> lock(eos_mutex_);
+    eos_status_ = EosStatus::kAllEos;
+  }
+  current_playback_rate_ = 1.0;
+  current_audio_mute_ = false;
+}
+
+void EsPlayer::GetSrcQueueCurrentSize_(const TrackType& type,
+                                       uint64_t* byte_size,
+                                       uint64_t* time_size) {
+  boost::any byte_size_, time_size_;
+  if (type == TrackType::kTrackTypeVideo) {
+    trackrenderer_->GetAttribute(
+        TrackRendererAdapter::Attribute::kVideoQueueCurrentLevelByte,
+        &byte_size_);
+    trackrenderer_->GetAttribute(
+        TrackRendererAdapter::Attribute::kVideoQueueCurrentLevelTime,
+        &time_size_);
+  } else if (type == TrackType::kTrackTypeAudio) {
+    trackrenderer_->GetAttribute(
+        TrackRendererAdapter::Attribute::kAudioQueueCurrentLevelByte,
+        &byte_size_);
+    trackrenderer_->GetAttribute(
+        TrackRendererAdapter::Attribute::kAudioQueueCurrentLevelTime,
+        &time_size_);
+  } else
+    return;
+  *byte_size = boost::any_cast<std::uint64_t>(byte_size_);
+  *time_size = boost::any_cast<std::uint64_t>(time_size_);
+  *time_size = util::ConvertNsToMs(*time_size);
+}
+
+GstBuffer* EsPlayer::GetGstBuffer_(const EsPacketPtr& packet,
+                                   MakeBufferStatus* status) {
+  std::shared_ptr<char> buffer = packet->GetBuffer();
+  uint32_t size = packet->GetSize();
+  if (packet->IsEosPacket()) {
+    *status = MakeBufferStatus::kEos;
+    return nullptr;
+  }
+  GstBuffer* gstbuffer = gst_buffer_new_and_alloc(size);
+  if (!gstbuffer) {
+    *status = MakeBufferStatus::kOutOfMemory;
+    return nullptr;
+  }
+  if (buffer != nullptr) {
+    GstMapInfo map;
+    gst_buffer_map(gstbuffer, &map, GST_MAP_WRITE);
+    memcpy(map.data, buffer.get(), size);
+    gst_buffer_unmap(gstbuffer, &map);
+  }
+
+  uint64_t pts = packet->GetPts();
+  uint64_t duration = packet->GetDuration();
+  /* if pts or duration are -1(=GST_CLOCK_TIME_NONE), some of the elements don't
+   * adjust the buffer. */
+  GST_BUFFER_PTS(gstbuffer) = (pts == GST_CLOCK_TIME_NONE)
+                                  ? GST_CLOCK_TIME_NONE
+                                  : (GstClockTime)util::ConvertMsToNs(pts);
+  GST_BUFFER_DURATION(gstbuffer) =
+      (duration == GST_CLOCK_TIME_NONE)
+          ? GST_CLOCK_TIME_NONE
+          : (GstClockTime)util::ConvertMsToNs(duration);
+  uint32_t hdr10p_size = packet->GetHdr10pSize();
+  std::shared_ptr<char> hdr10p_metadata = packet->GetHdr10pData();
+
+  if (hdr10p_size > 0 && hdr10p_metadata != nullptr) {
+    guint32* blockadditional_size = (guint32*)g_malloc(sizeof(uint32_t));
+    *blockadditional_size = hdr10p_size;
+    gst_mini_object_set_qdata(
+        GST_MINI_OBJECT(gstbuffer),
+        g_quark_from_static_string("matroska_blockadditional_size"),
+        blockadditional_size, g_free);
+
+    /* blockadditiona_data : the data sent to omx, size (4 bytes) + metadata */
+    guint8* blockadditional_data =
+        (guint8*)g_malloc(((*blockadditional_size) + 4) * sizeof(guint8));
+    memcpy(blockadditional_data, blockadditional_size, sizeof(uint32_t));
+    memcpy(blockadditional_data + 4, hdr10p_metadata.get(),
+           (*blockadditional_size));
+    gst_mini_object_set_qdata(
+        GST_MINI_OBJECT(gstbuffer),
+        g_quark_from_static_string("matroska_blockadditional_info"),
+        blockadditional_data, g_free);
+  }
+  *status = MakeBufferStatus::kSuccess;
+  return gstbuffer;
+}
+
+PacketSubmitStatus EsPlayer::SubmitEosPacket_(const TrackType& type) {
+  PacketSubmitStatus submitstate = PacketSubmitStatus::kSuccess;
+  {
+    std::lock_guard<std::mutex> lock(eos_mutex_);
+    switch (type) {
+      case kTrackTypeAudio:
+        eos_status_ |= EosStatus::kAudioEos;
+        break;
+      case kTrackTypeVideo:
+        eos_status_ |= EosStatus::kVideoEos;
+        break;
+      default:
+        break;
+    }
+    if (eos_status_ != EosStatus::kAllEos) {
+      return submitstate;
+    }
+  }
+  for (int tracktype = kTrackTypeAudio; tracktype < kTrackTypeMax;
+       ++tracktype) {
+    auto inbuffer =
+        DecoderInputBuffer::Create(static_cast<TrackType>(tracktype));
+    if (!trackrenderer_->SubmitPacket2(inbuffer, nullptr)) {
+      std::lock_guard<std::mutex> lock(eos_mutex_);
+      eos_status_ = EosStatus::kAllEos;
+      submitstate = PacketSubmitStatus::kNotPrepared;
+      return submitstate;
+    }
+  }
+  return submitstate;
+}
+
+void EsPlayer::UnsetTzQdata_(const DecoderInputBufferPtr& buffer) {
+  const GstBuffer* gstbuf = buffer->Get();
+  if (!gstbuf) return;
+  GstStructure* tzqdata = GST_STRUCTURE(gst_mini_object_steal_qdata(
+      GST_MINI_OBJECT(gstbuf), g_quark_from_static_string("GstTzHandleData")));
+  if (tzqdata) gst_structure_free(tzqdata);
+}
+
+PacketSubmitStatus EsPlayer::SubmitDecoderInputBuffer_(
+    const DecoderInputBufferPtr& buffer) {
+  PacketSubmitStatus status = PacketSubmitStatus::kSuccess;
+  TrackRendererAdapter::SubmitStatus submitstate =
+      TrackRendererAdapter::SubmitStatus::kSuccess;
+  trackrenderer_->SubmitPacket2(buffer, &submitstate);
+
+  switch (submitstate) {
+    case TrackRendererAdapter::SubmitStatus::kSuccess:
+    case TrackRendererAdapter::SubmitStatus::kDrop:
+      status = PacketSubmitStatus::kSuccess;
+      break;
+    case TrackRendererAdapter::SubmitStatus::kFull:
+      UnsetTzQdata_(buffer);
+      trackrenderer_event_listener_->OnBufferStatus(buffer->GetType(),
+                                                    BufferStatus::kOverrun);
+      status = PacketSubmitStatus::kFull;
+      break;
+    default:
+      UnsetTzQdata_(buffer);
+      status = PacketSubmitStatus::kNotPrepared;
+      break;
+  }
+  return status;
+}
+
+void EsPlayer::MakeGstBufferForTzHandle_(GstBuffer* gstbuffer,
+                                         const TrackType& type,
+                                         const uint32_t& tz_handle,
+                                         const uint32_t& packet_size) {
+  GstStructure* gst_tz_handle_data_structure =
+      gst_structure_new("GstTzHandleData", "packet_handle", G_TYPE_UINT,
+                        static_cast<guint32>(tz_handle), "packet_size",
+                        G_TYPE_UINT, static_cast<guint32>(packet_size),
+                        "secure", G_TYPE_BOOLEAN, true, nullptr);
+  gst_mini_object_set_qdata(
+      GST_MINI_OBJECT(gstbuffer), g_quark_from_string("GstTzHandleData"),
+      gst_tz_handle_data_structure, (GDestroyNotify)gst_structure_free);
+
+  if (type == kTrackTypeAudio) {
+    Track audio_track;
+    bool has_active_audio_track =
+        track_util::GetActiveTrack(track_, kTrackTypeAudio, &audio_track);
+    if (has_active_audio_track) {
+      GstStructure* audio_info_structure =
+          gst_structure_new("AudioInfo", "mime_type", G_TYPE_STRING,
+                            audio_track.mimetype.c_str(), nullptr);
+      gst_mini_object_set_qdata(
+          GST_MINI_OBJECT(gstbuffer), g_quark_from_string("AudioInfo"),
+          audio_info_structure, (GDestroyNotify)gst_structure_free);
+    }
+  }
+}
+
+void EsPlayer::MakeGstBufferForEncryptedPacket_(
+    GstBuffer* gstbuffer, const EsPacketPtr& packet,
+    const drm::EsPlayerEncryptedInfo& drm_info) {
+  if (drm_info.handle == 0) return;
+  auto serialized_drm_info_ptr = esplayer_drm::Serialize(packet, drm_info);
+  GstStructure* gst_drm_info_structure =
+      gst_structure_new("drm_info", "drm_specific_info", G_TYPE_BYTES,
+                        serialized_drm_info_ptr.get(), nullptr);
+  if (gst_drm_info_structure) {
+    gst_mini_object_set_qdata(
+        GST_MINI_OBJECT(gstbuffer), g_quark_from_static_string("drm_info"),
+        gst_drm_info_structure, (GDestroyNotify)gst_structure_free);
+  }
+}
+
+PacketSubmitStatus EsPlayer::SubmitPacketCommon_(const EsPacketPtr& packet,
+                                                 SubmitPacketOperator op) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    return PacketSubmitStatus::kNotPrepared;
+  }
+  if (!packet) return PacketSubmitStatus::kInvalidPacket;
+
+  TrackType type = static_cast<TrackType>(packet->GetType());
+  Track activated_track;
+  if (!track_util::GetActiveTrack(track_, type, &activated_track))
+    return PacketSubmitStatus::kInvalidPacket;
+
+  if (state_manager_.GetState() == EsState::kPaused ||
+      state_manager_.GetState() == EsState::kReady) {
+    internal::AppsrcQueueSizeOption byte_based, time_based;
+    switch (type) {
+      case kTrackTypeAudio:
+        byte_based.max_size = src_queue_size_.kMaxByteOfAudioSrcQueue;
+        time_based.max_size = src_queue_size_.kMaxTimeOfAudioSrcQueue;
+        byte_based.threshold = src_queue_size_.kMinByteThresholdOfAudioSrcQueue;
+        time_based.threshold = src_queue_size_.kMinTimeThresholdOfAudioSrcQueue;
+        break;
+      case kTrackTypeVideo:
+        byte_based.max_size = src_queue_size_.kMaxByteOfVideoSrcQueue;
+        time_based.max_size = src_queue_size_.kMaxTimeOfVideoSrcQueue;
+        byte_based.threshold = src_queue_size_.kMinByteThresholdOfVideoSrcQueue;
+        time_based.threshold = src_queue_size_.kMinTimeThresholdOfVideoSrcQueue;
+        break;
+      default:
+        break;
+    }
+    GetSrcQueueCurrentSize_(type, &(byte_based.current_size),
+                            &(time_based.current_size));
+    if (internal::IsUnderRun(byte_based, time_based))
+      trackrenderer_event_listener_->OnBufferStatus(type,
+                                                    BufferStatus::kUnderrun);
+  }
+
+  es_packet_logger_.StorePacketInfo(packet);
+  es_packet_logger_.PrintStoredPacketInfo(packet->GetType());
+
+  MakeBufferStatus make_buffer_status;
+  GstBuffer* gstbuffer = GetGstBuffer_(packet, &make_buffer_status);
+  if (!gstbuffer) {
+    if (make_buffer_status == MakeBufferStatus::kEos)
+      return SubmitEosPacket_(type);
+    else if (make_buffer_status == MakeBufferStatus::kOutOfMemory)
+      return PacketSubmitStatus::kOutOfMemory;
+  }
+  if (op != nullptr) {
+    PacketSubmitStatus op_status = op(gstbuffer);
+    if (op_status != PacketSubmitStatus::kSuccess) {
+      return op_status;
+    }
+  }
+
+  auto inbuffer = DecoderInputBuffer::Create(type, 0, gstbuffer);
+  gst_buffer_unref(gstbuffer);
+
+  if (packet->HasMatroskaColorInfo()) {
+    std::string color_info_str =
+        util::GetStringFromMatroskaColor(packet->GetMatroskaColorInfo());
+    LOG_DEBUG_P(this, "Detected MatroskaColor : %s", color_info_str.c_str());
+    if (trackrenderer_->SetMatroskaColorInfo(color_info_str) == false)
+      return PacketSubmitStatus::kNotPrepared;
+  }
+
+  return SubmitDecoderInputBuffer_(inbuffer);
+}
+
+PacketSubmitStatus EsPlayer::SubmitPacket(const EsPacketPtr& packet) {
+  std::lock_guard<std::mutex> lk(submit_mutex_);
+  return SubmitPacketCommon_(packet, nullptr);
+}
+
+PacketSubmitStatus EsPlayer::SubmitTrustZonePacket(const EsPacketPtr& packet,
+                                                   uint32_t tz_handle) {
+  std::lock_guard<std::mutex> lk(submit_mutex_);
+  if (submit_data_type_ != SubmitDataType::kTrustZoneData)
+    return PacketSubmitStatus::kInvalidPacket;
+  auto submitpacket_op = [this, &tz_handle,
+                          &packet](GstBuffer* gstbuffer) -> PacketSubmitStatus {
+    if (tz_handle > 0) {
+      TrackType type = static_cast<TrackType>(packet->GetType());
+      uint32_t packet_size = packet->GetSize();
+      MakeGstBufferForTzHandle_(gstbuffer, type, tz_handle, packet_size);
+    }
+    return PacketSubmitStatus::kSuccess;
+  };
+  return SubmitPacketCommon_(packet, submitpacket_op);
+}
+
+PacketSubmitStatus EsPlayer::SubmitEncryptedPacket(
+    const EsPacketPtr& packet, const drm::EsPlayerEncryptedInfo& drm_info) {
+  std::lock_guard<std::mutex> lk(submit_mutex_);
+  if (submit_data_type_ != SubmitDataType::kEncryptedData)
+    return PacketSubmitStatus::kInvalidPacket;
+  auto submitpacket_op =
+      [this, &packet, &drm_info](GstBuffer* gstbuffer) -> PacketSubmitStatus {
+    MakeGstBufferForEncryptedPacket_(gstbuffer, packet, drm_info);
+    return PacketSubmitStatus::kSuccess;
+  };
+  return SubmitPacketCommon_(packet, submitpacket_op);
+}
+
+EsState EsPlayer::GetState() { return state_manager_.GetState(); }
+
+bool EsPlayer::GetPlayingTime(uint64_t* time_in_milliseconds) {
+  if (!time_in_milliseconds) return false;
+  if (state_manager_.GetState() <= EsState::kReady) {
+    *time_in_milliseconds = 0;
+    return false;
+  }
+  return trackrenderer_->GetPlayingTime(time_in_milliseconds);
+}
+
+bool EsPlayer::SetAudioMute(bool is_mute) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->SetAudioMute(is_mute);
+}
+
+bool EsPlayer::SetVideoFrameBufferType(DecodedVideoFrameBufferType type) {
+  if ((state_manager_.GetState() != EsState::kIdle &&
+       type != DecodedVideoFrameBufferType::kScale) ||
+      (state_manager_.GetState() < EsState::kIdle &&
+       type == DecodedVideoFrameBufferType::kScale)) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  if (type == DecodedVideoFrameBufferType::kScale &&
+      video_codec_type_ == kPlayerVideoCodecTypeSW) {
+    LOG_ERROR_P(this, "kScale is not supportted when using sw video decoder");
+    return false;
+  }
+  trackrenderer_->SetVideoFrameBufferType(
+      VideoFrameTypeStrategyPtr(new DefaultVideoFrameTypeStrategy(type)));
+  vidoe_frame_buffer_type_ = type;
+  return true;
+}
+
+bool EsPlayer::SetVideoFrameBufferScaleResolution(
+    const uint32_t& target_width, const uint32_t& target_height) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  return trackrenderer_->SetVideoFrameBufferScaleResolution(target_width,
+                                                            target_height);
+}
+
+bool EsPlayer::SetDecodedVideoFrameRate(const Rational& request_framerate) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR("Invalid State , current %d", state_manager_.GetStateEnum());
+    return false;
+  }
+
+  return trackrenderer_->SetDecodedVideoFrameRate(request_framerate);
+}
+
+void EsPlayer::RegisterListener(EsEventListener* listener,
+                                EsEventListener::UserData userdata) {
+  // assert(listener); // allow unregister by setting nullptr
+  assert(!eventlistener_);
+  eventlistener_ = listener;
+  eventlistener_userdata_ = userdata;
+}
+
+bool EsPlayer::GetAdaptiveInfo(void* padaptive_info,
+                               const PlayerAdaptiveInfo& adaptive_type) {
+  if (!padaptive_info || adaptive_type <= PlayerAdaptiveInfo::kMinType ||
+      adaptive_type >= PlayerAdaptiveInfo::kMaxType)
+    return false;
+  switch (adaptive_type) {
+    case PlayerAdaptiveInfo::kVideoDroppedFrames:
+      if (state_manager_.GetState() < EsState::kReady) {
+        LOG_ERROR_P(this, "Wrong state, we aren't started yet");
+        return false;
+      }
+      return trackrenderer_->GetDroppedFrames(padaptive_info);
+    case PlayerAdaptiveInfo::kDroppedVideoFramesForCatchup:
+      if (state_manager_.GetState() < EsState::kReady) {
+        LOG_ERROR_P(this, "Wrong state, we aren't started yet");
+        return false;
+      }
+      return trackrenderer_->GetDroppedFramesForCatchup(kTrackTypeVideo,
+                                                        padaptive_info);
+    case PlayerAdaptiveInfo::kDroppedAudioFramesForCatchup:
+      if (state_manager_.GetState() < EsState::kReady) {
+        LOG_ERROR_P(this, "Wrong state, we aren't started yet");
+        return false;
+      }
+      return trackrenderer_->GetDroppedFramesForCatchup(kTrackTypeAudio,
+                                                        padaptive_info);
+    default:
+      break;
+  }
+  return false;
+}
+
+bool EsPlayer::SetVolume(const int& volume) {
+  if (volume < internal::kVolumeMin || volume > internal::kVolumeMax) {
+    LOG_ERROR_P(this, "Invalid volume level %d", volume);
+    return false;
+  }
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->SetVolume(volume);
+}
+
+bool EsPlayer::GetVolume(int* volume) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->GetVolume(volume);
+}
+
+bool EsPlayer::Flush(const StreamType& type) {
+  if (state_manager_.GetState() <= EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  eos_status_ =
+      internal::ResetEosStatus(static_cast<TrackType>(type), eos_status_);
+  es_packet_logger_.ResetLog(type);
+  return trackrenderer_->Flush(type);
+}
+
+void EsPlayer::SetBufferSize(const BufferOption& option, uint64_t size) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return;
+  }
+  switch (option) {
+    case BufferOption::kBufferAudioMaxByteSize:
+      src_queue_size_.kMaxByteOfAudioSrcQueue = size;
+      break;
+    case BufferOption::kBufferVideoMaxByteSize:
+      src_queue_size_.kMaxByteOfVideoSrcQueue = size;
+      break;
+    case BufferOption::kBufferAudioMinByteThreshold:
+      src_queue_size_.kMinByteThresholdOfAudioSrcQueue =
+          static_cast<uint32_t>(size);
+      break;
+    case BufferOption::kBufferVideoMinByteThreshold:
+      src_queue_size_.kMinByteThresholdOfVideoSrcQueue =
+          static_cast<uint32_t>(size);
+      break;
+    case BufferOption::kBufferAudioMaxTimeSize:
+      src_queue_size_.kMaxTimeOfAudioSrcQueue = size;
+      break;
+    case BufferOption::kBufferVideoMaxTimeSize:
+      src_queue_size_.kMaxTimeOfVideoSrcQueue = size;
+      break;
+    case BufferOption::kBufferAudioMinTimeThreshold:
+      src_queue_size_.kMinTimeThresholdOfAudioSrcQueue =
+          static_cast<uint32_t>(size);
+      break;
+    case BufferOption::kBufferVideoMinTimeThreshold:
+      src_queue_size_.kMinTimeThresholdOfVideoSrcQueue =
+          static_cast<uint32_t>(size);
+      break;
+    default:
+      LOG_ERROR_P(this, "Invalid option!!!");
+      break;
+  }
+}
+
+bool EsPlayer::SetLowLatencyMode(const PlayerLowLatencyMode& mode) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  low_latency_mode_ |= static_cast<std::uint32_t>(mode);
+  return true;
+}
+
+bool EsPlayer::SetRenderTimeOffset(const StreamType type, int64_t offset) {
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  if (!internal::IsSupportedTsOffset(low_latency_mode_)) {
+    LOG_ERROR_P(this,
+                "low latency mode have to be set except disable_sync mode");
+    return false;
+  }
+  constexpr std::int64_t ns_unit = 1000000;
+  if ((offset * ns_unit > G_MAXINT64) || (offset * ns_unit < G_MININT64)) {
+    LOG_ERROR_P(
+        this, "wrong value : G_MAXINT64 < offset[%lld] * 1000000 < G_MAXINT64",
+        offset);
+    return false;
+  }
+  if (type == StreamType::kMax) return false;
+  if (type == StreamType::kAudio)
+    trackrenderer_->SetAttribute(
+        TrackRendererAdapter::Attribute::kAudioRenderTimeOffset,
+        util::ConvertMsToNs(offset));
+  else if (type == StreamType::kVideo)
+    trackrenderer_->SetAttribute(
+        TrackRendererAdapter::Attribute::kVideoRenderTimeOffset,
+        util::ConvertMsToNs(offset));
+  return true;
+}
+
+bool EsPlayer::GetRenderTimeOffset(const StreamType type, int64_t* offset) {
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  if (!internal::IsSupportedTsOffset(low_latency_mode_)) {
+    LOG_ERROR_P(this, "low latency mode have to be set");
+    return false;
+  }
+  if (type == StreamType::kMax) return false;
+  boost::any off_set;
+  if (type == StreamType::kAudio)
+    trackrenderer_->GetAttribute(
+        TrackRendererAdapter::Attribute::kAudioRenderTimeOffset, &off_set);
+  else if (type == StreamType::kVideo)
+    trackrenderer_->GetAttribute(
+        TrackRendererAdapter::Attribute::kVideoRenderTimeOffset, &off_set);
+
+  *offset = boost::any_cast<std::int64_t>(off_set);
+  *offset = util::ConvertNsToMs(*offset);
+  return true;
+}
+
+bool EsPlayer::SetVideoFramePeekMode() {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  constexpr std::uint32_t peek_mode_on = 1;
+  video_frame_peek_mode_ = peek_mode_on;
+  return true;
+}
+
+bool EsPlayer::RenderVideoFrame() {
+  if (!video_frame_peek_mode_) return false;
+  if (state_manager_.GetState() == EsState::kReady ||
+      state_manager_.GetState() == EsState::kPaused) {
+    trackrenderer_->RenderVideoFrame();
+    return true;
+  }
+  LOG_ERROR_P(this, "Invalid State , current %d",
+              state_manager_.GetStateEnum());
+  return false;
+}
+
+bool EsPlayer::SetUnlimitedMaxBufferMode() {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  constexpr std::uint32_t unlimited_max_buffer_mode_on = 1;
+  unlimited_max_buffer_mode_ = unlimited_max_buffer_mode_on;
+  return true;
+}
+
+bool EsPlayer::SetFmmMode() {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  constexpr std::uint32_t fmm_mode_on = 1;
+  fmm_mode_ = fmm_mode_on;
+  return true;
+}
+
+bool EsPlayer::SetAudioCodecType(const PlayerAudioCodecType& type) {
+  Track activated_track;
+  bool is_existed =
+      track_util::GetActiveTrack(track_, kTrackTypeAudio, &activated_track);
+  EsState state = state_manager_.GetState();
+  if ((state < EsState::kIdle) || (state > EsState::kIdle && is_existed)) {
+    LOG_ERROR_P(this,
+                "Invalid State [state:%d] or audio stream already exists[%d],",
+                state_manager_.GetStateEnum(), is_existed);
+    return false;
+  }
+  if (force_audio_swdecoder_use_ && type == kPlayerAudioCodecTypeHW) {
+    LOG_ERROR_P(this, "Not support hw decoder");
+    return false;
+  }
+  LOG_INFO_P(this, "PlayerAudioCodecType [%s]",
+             (type == kPlayerAudioCodecTypeHW) ? "hardware" : "software");
+  audio_codec_type_ = type;
+  return true;
+}
+
+bool EsPlayer::SetVideoCodecType(const PlayerVideoCodecType& type) {
+  Track activated_track;
+  bool is_existed =
+      track_util::GetActiveTrack(track_, kTrackTypeVideo, &activated_track);
+  EsState state = state_manager_.GetState();
+  if ((state < EsState::kIdle) || (state > EsState::kIdle && is_existed)) {
+    LOG_ERROR_P(this,
+                "Invalid State [state:%d] or video stream already exists[%d],",
+                state_manager_.GetStateEnum(), is_existed);
+    return false;
+  }
+  if (type == kPlayerVideoCodecTypeSW &&
+      vidoe_frame_buffer_type_ == DecodedVideoFrameBufferType::kScale) {
+    LOG_ERROR_P(this,
+                "sw video decoder is not supportted when video frame buffer "
+                "type is scale");
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (!enable_rsc_alloc_handle_) {
+    LOG_ERROR_P(this, "player can't control resource type, mixer will do it");
+    return false;
+  }
+  if (type == kPlayerVideoCodecTypeHWNdecoding) {
+    LOG_INFO_P(this, "PlayerVideoCodecType HW N-decoding");
+    video_decoding_mode_ = internal::kNdecodingMode;
+    return true;
+  }
+#endif
+  LOG_INFO_P(this, "PlayerVideoCodecType [%s]",
+             (type == kPlayerVideoCodecTypeHW) ? "hardware" : "software");
+  video_codec_type_ = type;
+  return true;
+}
+
+bool EsPlayer::SetAiFilter(void* aifilter) {
+  if (state_manager_.GetState() != EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  trackrenderer_->SetAiFilter(aifilter);
+  return true;
+}
+
+bool EsPlayer::InitAudioEasingInfo(const uint32_t init_volume,
+                                   const uint32_t init_elapsed_time,
+                                   const AudioEasingInfo& easing_info) {
+  if (init_volume > internal::kVolumeMax ||
+      easing_info.target_volume > internal::kVolumeMax) {
+    LOG_ERROR_P(this, "Invalid volume: init [%d] target [%d]", init_volume,
+                easing_info.target_volume);
+    return false;
+  }
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->InitAudioEasingInfo(init_volume, init_elapsed_time,
+                                             easing_info);
+}
+
+bool EsPlayer::UpdateAudioEasingInfo(const AudioEasingInfo& easing_info) {
+  if (easing_info.target_volume > internal::kVolumeMax) {
+    LOG_ERROR_P(this, "Invalid volume level %d", easing_info.target_volume);
+    return false;
+  }
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->UpdateAudioEasingInfo(easing_info);
+}
+
+bool EsPlayer::GetAudioEasingInfo(uint32_t* current_volume,
+                                  uint32_t* elapsed_time,
+                                  AudioEasingInfo* easing_info) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->GetAudioEasingInfo(current_volume, elapsed_time,
+                                            easing_info);
+}
+
+bool EsPlayer::StartAudioEasing() {
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->StartAudioEasing();
+}
+
+bool EsPlayer::StopAudioEasing() {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+  return trackrenderer_->StopAudioEasing();
+}
+
+bool EsPlayer::SetAlternativeVideoResource(unsigned int rsc_type) {
+  if (state_manager_.GetState() == EsState::kNone) {
+    LOG_ERROR_P(this, "Invalid State");
+    return false;
+  }
+#ifndef IS_AUDIO_PRODUCT
+  if (!enable_rsc_alloc_handle_) {
+    LOG_ERROR_P(this, "player can't control resource type, mixer will do it");
+    return false;
+  }
+#endif
+  alternaltive_video_resource_ = static_cast<std::uint32_t>(rsc_type);
+  return true;
+}
+
+bool EsPlayer::SetCatchUpSpeed(const CatchUpSpeed& level) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  if (false == internal::IsSetLowLatencyModeForCatchUp(low_latency_mode_)) {
+    LOG_ERROR_P(this, "Do not set low latency mode, current[%u]",
+                static_cast<std::uint32_t>(low_latency_mode_));
+    return false;
+  }
+
+  if (trackrenderer_->SetCatchUpSpeed(level)) {
+    return true;
+  }
+  return false;
+}
+
+bool EsPlayer::GetVideoLatencyStatus(LatencyStatus* status) {
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  if (trackrenderer_->GetVideoLatencyStatus(status)) {
+    return true;
+  }
+  return false;
+}
+
+bool EsPlayer::GetAudioLatencyStatus(LatencyStatus* status) {
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  if (trackrenderer_->GetAudioLatencyStatus(status)) {
+    return true;
+  }
+  return false;
+}
+
+bool EsPlayer::SetVideoMidLatencyThreshold(const unsigned int threshold) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  if (false == internal::IsSetLowLatencyModeForCatchUp(low_latency_mode_)) {
+    LOG_ERROR_P(this, "Don't set low latency mode, current[%u]",
+                static_cast<std::uint32_t>(low_latency_mode_));
+    return false;
+  }
+
+  LOG_INFO_P(this, "video_mid_latency_threshold : [%u]", threshold);
+
+  trackrenderer_->SetVideoMidLatencyThreshold(threshold);
+  return true;
+}
+
+bool EsPlayer::SetAudioMidLatencyThreshold(const unsigned int threshold) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  if (false == internal::IsSetLowLatencyModeForCatchUp(low_latency_mode_)) {
+    LOG_ERROR_P(this, "Don't set low latency mode, current[%u]",
+                static_cast<std::uint32_t>(low_latency_mode_));
+    return false;
+  }
+
+  LOG_INFO_P(this, "audio_mid_latency_threshold : [%u]", threshold);
+
+  trackrenderer_->SetAudioMidLatencyThreshold(threshold);
+  return true;
+}
+
+bool EsPlayer::SetVideoHighLatencyThreshold(const unsigned int threshold) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  if (false == internal::IsSetLowLatencyModeForCatchUp(low_latency_mode_)) {
+    LOG_ERROR_P(this, "Don't set low latency mode, current[%u]",
+                static_cast<std::uint32_t>(low_latency_mode_));
+    return false;
+  }
+
+  LOG_INFO_P(this, "video_high_latency_threshold : [%u]", threshold);
+
+  trackrenderer_->SetVideoHighLatencyThreshold(threshold);
+  return true;
+}
+
+bool EsPlayer::SetAudioHighLatencyThreshold(const unsigned int threshold) {
+  if (state_manager_.GetState() < EsState::kIdle) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    return false;
+  }
+
+  if (false == internal::IsSetLowLatencyModeForCatchUp(low_latency_mode_)) {
+    LOG_ERROR_P(this, "Don't set low latency mode, current[%u]",
+                static_cast<std::uint32_t>(low_latency_mode_));
+    return false;
+  }
+
+  LOG_INFO_P(this, "audio_high_latency_threshold : [%u]", threshold);
+
+  trackrenderer_->SetAudioHighLatencyThreshold(threshold);
+  return true;
+}
+
+bool EsPlayer::GetVirtualRscId(const RscType type, int* virtual_id) {
+  if (virtual_id == nullptr) return false;
+  if (state_manager_.GetState() < EsState::kReady) {
+    LOG_ERROR_P(this, "Invalid State , current %d",
+                state_manager_.GetStateEnum());
+    *virtual_id = -1;
+    return false;
+  }
+  return trackrenderer_->GetVirtualRscId(type, virtual_id);
+}
+
+void EsPlayer::Init_() {
+  track_.clear();
+  is_stopped_ = false;
+  LOG_LEAVE_P(this);
+}
+
+void EsPlayer::MsgTask_() {
+  while (!is_msg_task_stop_) {
+    std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);
+    if (msg_queue_.empty()) {
+      msg_task_cv_.wait(msg_mutex);
+    } else {
+      msg_mutex.unlock();
+      msg_queue_.front()->Execute();
+      msg_mutex.lock();
+      msg_queue_.pop();
+    }
+  }
+  while (!msg_queue_.empty()) {
+    std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);
+    msg_queue_.pop();
+  }
+  LOG_INFO_P(this, "Stop MsgTask");
+}
+
+void EsPlayer::TrackRendererEventListener::OnEos() {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+  auto listener = std::bind(&plusplayer::EsEventListener::OnEos,
+                            handler_->eventlistener_, std::placeholders::_1);
+  auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnSeekDone() {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+  if (handler_->is_seek_done_need_drop == true) return;
+  auto listener = std::bind(&plusplayer::EsEventListener::OnSeekDone,
+                            handler_->eventlistener_, std::placeholders::_1);
+  auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnResourceConflicted() {
+  LOG_ENTER_P(handler_);
+  if (handler_->is_stopped_) {
+    LOG_INFO_P(handler_, "LEAVE ~ Stop is called already");
+    return;
+  }
+  LOG_INFO_P(handler_, "Handling resource conflict...");
+  handler_->is_resource_conflicted_ = true;
+  handler_->trackrenderer_->Stop();
+  if (!handler_->eventlistener_ || handler_->is_stopped_) return;
+  auto listener = std::bind(&plusplayer::EsEventListener::OnResourceConflicted,
+                            handler_->eventlistener_, std::placeholders::_1);
+  auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  if (handler_->is_stopped_) {
+    LOG_LEAVE_P(handler_);
+    return;
+  }
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnError(
+    const ErrorType& error_code) {
+  if (!handler_->eventlistener_) return;
+  if (error_code == ErrorType::kResourceLimit) return;
+  auto listener =
+      std::bind(&plusplayer::EsEventListener::OnError, handler_->eventlistener_,
+                std::placeholders::_1, std::placeholders::_2);
+  auto msg = es_msg::Error::Make(error_code, listener,
+                                 handler_->eventlistener_userdata_);
+
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+}
+
+void EsPlayer::TrackRendererEventListener::OnErrorMsg(
+    const ErrorType& error_code, char* error_msg) {
+  if (!handler_->eventlistener_) return;
+  if (error_code == ErrorType::kResourceLimit) return;
+
+  std::vector<Track> activeTracks;
+  track_util::GetActiveTrackList(handler_->track_, activeTracks);
+
+  Json::Value message;
+  message["error_code"] = (int)error_code;
+
+  switch (error_code) {
+    case ErrorType::kNotSupportedVideoCodec:
+      for (const auto& track : activeTracks) {
+        if (track.type == kTrackTypeVideo) {
+          message["codec"] = track.mimetype.c_str();
+          message["demux"] = track.container_type.c_str();
+          char json_string[20] = {0};
+          int nLen = 19;
+          strncat(json_string, std::to_string(track.width).c_str(), nLen);
+          nLen = sizeof(json_string) - strlen(json_string) - 1;
+          if (nLen < 0) nLen = 0;
+          strncat(json_string, "*", nLen);
+          nLen = sizeof(json_string) - strlen(json_string) - 1;
+          if (nLen < 0) nLen = 0;
+          strncat(json_string, std::to_string(track.height).c_str(), nLen);
+          message["resolution"] = json_string;
+          memset(json_string, 0, sizeof(json_string));
+          nLen = 19;
+          strncat(json_string, std::to_string(track.framerate_num).c_str(),
+                  nLen);
+          nLen = sizeof(json_string) - strlen(json_string) - 1;
+          if (nLen < 0) nLen = 0;
+          strncat(json_string, "/", nLen);
+          nLen = sizeof(json_string) - strlen(json_string) - 1;
+          if (nLen < 0) nLen = 0;
+          strncat(json_string, std::to_string(track.framerate_den).c_str(),
+                  nLen);
+          message["fps"] = json_string;
+          message["detail_info"] = error_msg;
+          break;
+        }
+      }
+      break;
+    case ErrorType::kNotSupportedAudioCodec:
+
+      break;
+    default:
+      break;
+  }
+
+  Json::FastWriter writer;
+  std::string str = writer.write(message);
+  LOG_INFO_P(handler_, "error message: %s", str.c_str());
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnErrorMsg,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2, std::placeholders::_3);
+  auto msg =
+      es_msg::ErrorMsg::Make(error_code, str.c_str(), str.size(), listener,
+                             handler_->eventlistener_userdata_);
+
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+}
+
+void EsPlayer::TrackRendererEventListener::ReadyToPrepare_(
+    const TrackType& type) {
+  LOG_INFO_P(handler_, "OnReadyToPrepare [%s]",
+             (type == kTrackTypeAudio) ? "audio" : "video");
+
+  handler_->need_data_[type].mask &= ~kNeedDataMaskByPrepare;
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnReadyToPrepare,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2);
+  StreamType stream_type = internal::ConvertToStreamType(type);
+  auto msg = es_msg::ReadyToPrepare::Make(stream_type, listener,
+                                          handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+}
+
+void EsPlayer::TrackRendererEventListener::ReadyToSeek_(const TrackType& type) {
+  uint64_t offset = handler_->need_data_[type].seek_offset;
+
+  LOG_INFO_P(handler_, "OnReadyToSeek [%s] offset [%llu]ms",
+             (type == kTrackTypeAudio) ? "audio" : "video", offset);
+
+  handler_->need_data_[type].mask &= ~kNeedDataMaskBySeek;
+  handler_->need_data_[type].seek_offset = 0;
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnReadyToSeek,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2, std::placeholders::_3);
+  StreamType stream_type = internal::ConvertToStreamType(type);
+  handler_->es_packet_logger_.ResetLog(stream_type);
+  auto msg = es_msg::ReadyToSeek::Make(stream_type, offset, listener,
+                                       handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+}
+
+void EsPlayer::TrackRendererEventListener::BufferStatus_(
+    const TrackType& type, const BufferStatus& status) {
+  uint64_t byte_size, time_size;
+  // LOG_INFO_P(handler_, "OnBufferStatus [%s] [%s]",
+  //        (type == kTrackTypeAudio) ? "audio" : "video",
+  //        (status == BufferStatus::kUnderrun) ? "underrun" : "overrun");
+  handler_->GetSrcQueueCurrentSize_(type, &byte_size, &time_size);
+  auto listener = std::bind(&plusplayer::EsEventListener::OnBufferStatus,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2, std::placeholders::_3,
+                            std::placeholders::_4, std::placeholders::_5);
+  StreamType stream_type = internal::ConvertToStreamType(type);
+  auto msg =
+      es_msg::Bufferstatus::Make(stream_type, status, byte_size, time_size,
+                                 listener, handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+}
+
+void EsPlayer::TrackRendererEventListener::OnBufferStatus(
+    const TrackType& type, const BufferStatus& status) {
+  if (!handler_->eventlistener_) return;
+  if (internal::IsLowLatencyModeDisableAVSync(handler_->low_latency_mode_))
+    return;
+
+  if (handler_->need_data_[type].mask == kNeedDataMaskByPrepare &&
+      status == BufferStatus::kUnderrun) {
+    ReadyToPrepare_(type);
+  } else if (handler_->need_data_[type].mask == kNeedDataMaskBySeek &&
+             status == BufferStatus::kUnderrun) {
+    ReadyToSeek_(type);
+  } else {
+    BufferStatus_(type, status);
+  }
+}
+
+void EsPlayer::TrackRendererEventListener::OnMediaPacketGetTbmBufPtr(
+    void** tbm_ptr, bool is_scale_change) {
+  if (!handler_->eventlistener_) return;
+
+  handler_->eventlistener_->OnMediaPacketGetTbmBufPtr(tbm_ptr, is_scale_change);
+}
+
+void EsPlayer::TrackRendererEventListener::OnMediaPacketVideoDecoded(
+    const DecodedVideoPacket& packet) {
+  if (!handler_->eventlistener_) return;
+
+  handler_->eventlistener_->OnMediaPacketVideoDecoded(packet);
+}
+
+#ifndef IS_AUDIO_PRODUCT
+void EsPlayer::TrackRendererEventListener::OnMediaPacketVideoRawDecoded(
+    const DecodedVideoRawModePacket& packet) {
+  if (handler_->mixer_ticket_ == nullptr) return;
+  const auto& data = packet.data;
+  if (packet.type == DecodedVideoRawModePacketType::kPhysicalAddress) {
+    DecodedRawInfo info;
+    info.width = packet.width;
+    info.height = packet.height;
+    info.y_info.phyaddr = data.raw.y_phyaddr;
+    info.y_info.viraddr = data.raw.y_viraddr;
+    info.y_info.linesize = data.raw.y_linesize;
+    info.uv_info.phyaddr = data.raw.uv_phyaddr;
+    info.uv_info.viraddr = data.raw.uv_viraddr;
+    info.uv_info.linesize = data.raw.uv_linesize;
+    handler_->mixer_ticket_->Render(info);
+  } else if (packet.type == DecodedVideoRawModePacketType::kTizenBuffer) {
+    DecodedVideoKeyTypeInfo info;
+    info.width = packet.width;
+    info.height = packet.height;
+    info.key = packet.data.tbm.key;
+    handler_->mixer_ticket_->Render(info);
+  }
+}
+
+bool EsPlayer::MixerListener::OnAudioFocusChanged(bool active) {
+  LOG_INFO_P(handler_, "focused [%d]", active);
+  std::unique_lock<std::mutex> lock(handler_->audio_focus_m_);
+  if (handler_->state_manager_.GetState() < EsState::kReady) {
+    handler_->is_audio_focused_ = active;
+    return true;
+  }
+  if (active) {
+    Track activated_track;
+    track_util::GetActiveTrack(handler_->track_, kTrackTypeAudio,
+                               &activated_track);
+    LOG_INFO_P(handler_, "Activate audio track");
+    {
+      std::lock_guard<std::mutex> lock2(handler_->eos_mutex_);
+      handler_->eos_status_ =
+          internal::ResetEosStatus(kTrackTypeAudio, handler_->eos_status_);
+    }
+    return handler_->trackrenderer_->Activate(kTrackTypeAudio, activated_track);
+  }
+  LOG_INFO_P(handler_, "Deactivate audio track");
+  handler_->is_audio_focused_ = false;
+  {
+    std::lock_guard<std::mutex> lock2(handler_->eos_mutex_);
+    handler_->eos_status_ |= EosStatus::kAudioEos;
+  }
+  return handler_->trackrenderer_->Deactivate(kTrackTypeAudio);
+}
+
+bool EsPlayer::MixerListener::OnUpdateDisplayInfo(const DisplayInfo& cur_info,
+                                                  DisplayInfo* new_info) {
+  new_info->geometry = handler_->mixerticket_roi_;
+  new_info->visible_status =
+      handler_->is_visible_ ? VisibleStatus::kVisible : VisibleStatus::kHide;
+  return true;
+}
+#endif
+
+void EsPlayer::TrackRendererEventListener::OnSeekData(const TrackType& type,
+                                                      const uint64_t offset) {
+  if (!handler_->eventlistener_) return;
+
+  if (handler_->need_data_[type].mask != kNeedDataMaskByPrepare) {
+    handler_->need_data_[type].mask |= kNeedDataMaskBySeek;
+    handler_->need_data_[type].seek_offset = offset;
+  }
+}
+
+void EsPlayer::TrackRendererEventListener::OnClosedCaptionData(const char* data,
+                                                               const int size) {
+  if (size <= 0) return;
+  if (!handler_->eventlistener_) return;
+  auto listener = std::bind(&plusplayer::EsEventListener::OnClosedCaptionData,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2, std::placeholders::_3);
+  auto msg = es_msg::ClosedCaption::Make(data, size, listener,
+                                         handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+}
+
+void EsPlayer::TrackRendererEventListener::OnFlushDone() {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnFlushDone,
+                            handler_->eventlistener_, std::placeholders::_1);
+  auto msg =
+      es_msg::FlushDone::Make(listener, handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnEvent(const EventType& event,
+                                                   const EventMsg& msg_data) {
+  if (!handler_->eventlistener_) return;
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnEvent,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2, std::placeholders::_3);
+  auto msg = es_msg::OnEvent::Make(event, msg_data, listener,
+                                   handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnFirstDecodingDone() {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+  auto listener = std::bind(&plusplayer::EsEventListener::OnFirstDecodingDone,
+                            handler_->eventlistener_, std::placeholders::_1);
+  auto msg = es_msg::FirstDecodingDone::Make(listener,
+                                             handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnVideoDecoderUnderrun() {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+
+  if (handler_->state_manager_.GetState() != EsState::kPlaying &&
+      handler_->state_manager_.GetState() != EsState::kPaused) {
+    return;
+  }
+
+  auto listener =
+      std::bind(&plusplayer::EsEventListener::OnVideoDecoderUnderrun,
+                handler_->eventlistener_, std::placeholders::_1);
+  auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnVideoLatencyStatus(
+    const LatencyStatus& latency_status) {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+
+  if (handler_->state_manager_.GetState() != EsState::kPlaying &&
+      handler_->state_manager_.GetState() != EsState::kPaused) {
+    return;
+  }
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnVideoLatencyStatus,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2);
+
+  auto msg = es_msg::PacketLatencyStatus::Make(
+      latency_status, listener, handler_->eventlistener_userdata_);
+
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnAudioLatencyStatus(
+    const LatencyStatus& latency_status) {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+
+  if (handler_->state_manager_.GetState() != EsState::kPlaying &&
+      handler_->state_manager_.GetState() != EsState::kPaused) {
+    return;
+  }
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnAudioLatencyStatus,
+                            handler_->eventlistener_, std::placeholders::_1,
+                            std::placeholders::_2);
+
+  auto msg = es_msg::PacketLatencyStatus::Make(
+      latency_status, listener, handler_->eventlistener_userdata_);
+
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnVideoHighLatency() {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnVideoHighLatency,
+                            handler_->eventlistener_, std::placeholders::_1);
+
+  auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
+
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+void EsPlayer::TrackRendererEventListener::OnAudioHighLatency() {
+  LOG_ENTER_P(handler_);
+  if (!handler_->eventlistener_) return;
+
+  auto listener = std::bind(&plusplayer::EsEventListener::OnAudioHighLatency,
+                            handler_->eventlistener_, std::placeholders::_1);
+
+  auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
+
+  std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
+  handler_->msg_queue_.push(std::move(msg));
+  msg_mutex.unlock();
+  handler_->msg_task_cv_.notify_one();
+  LOG_LEAVE_P(handler_);
+}
+
+kpi::EsCodecLoggerKeys EsPlayer::MakeKpiKeys_() {
+  kpi::EsCodecLoggerKeys event_info;
+  event_info.app_id = app_info_.id;
+  if (submit_data_type_ == SubmitDataType::kCleanData) {
+    event_info.is_clean = true;
+  } else {
+    event_info.is_clean = false;
+  }
+
+  for (const auto& track : track_) {
+    if (track.type == kTrackTypeVideo) {
+      event_info.v_codec = track.mimetype;
+      event_info.v_codec_version = track.version;
+      event_info.width = track.maxwidth;
+      event_info.height = track.maxheight;
+    } else if (track.type == kTrackTypeAudio) {
+      event_info.a_codec = track.mimetype;
+    }
+  }
+  return event_info;
+}
+
+namespace es_conf {
+
+void LoadIniProperty(const Json::Value& root) {
+  gst_util::GstInit(root);
+  std::string key = "generate_dot";
+  es_conf::ini_property[key] = root.get(key, "").asBool();
+  LOG_DEBUG("[%s] : [%d]", key.c_str(), es_conf::ini_property[key]);
+}
+
+bool LoadIniFile() {
+  const char* path = plusplayer_cfg::GetIniPath();
+  LOG_INFO("path : %s", path);
+  std::streampos size;
+  char* buf = nullptr;
+  std::ifstream file(path, std::ios::binary | std::ios::ate);
+  if (file.is_open() == false) {
+    gst_util::GstInit();
+    LOG_ERROR("Can't open file !!");
+    return false;
+  }
+  BOOST_SCOPE_EXIT(&file) { file.close(); }
+  BOOST_SCOPE_EXIT_END
+
+  size = file.tellg();
+  if (size <= 0) {
+    LOG_ERROR("Wrong file size");
+    return false;
+  }
+  size += 1;
+  buf = static_cast<char*>(calloc(size, sizeof(char)));
+  if (buf == nullptr) {
+    LOG_ERROR("Fail to calloc buf");
+    return false;
+  }
+  BOOST_SCOPE_EXIT(&buf) {
+    if (buf) free(buf);
+  }
+  BOOST_SCOPE_EXIT_END
+
+  file.seekg(0, std::ios::beg);
+  file.read(buf, size);
+
+  std::string config = buf;
+  Json::Value root;
+  Json::Reader reader;
+  if (!reader.parse(config, root)) {
+    LOG_ERROR("Fail to parse configuration file %s",
+              (reader.getFormatedErrorMessages()).c_str());
+    return false;
+  }
+
+  es_conf::LoadIniProperty(root);
+  return true;
+}
+
+}  // namespace es_conf
+
+}  // namespace plusplayer
diff --git a/src/esplusplayer/src/esplayer_drm.cpp b/src/esplusplayer/src/esplayer_drm.cpp
new file mode 100755 (executable)
index 0000000..ef576c5
--- /dev/null
@@ -0,0 +1,84 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "esplayer/esplayer_drm.h"
+#include "core/serializer.h"
+
+#include <cstdint>
+#include <cstring>
+#include <sstream>
+#include <type_traits>
+
+namespace plusplayer {
+namespace esplayer_drm {
+GBytesPtr Serialize(const EsPacketPtr &packet,
+                    const drm::EsPlayerEncryptedInfo &drm_info) {
+  Serializer s;
+
+  // box
+  s.Put<uint32_t>(0);                         // box_size : (lazy)
+  s.Put<uint32_t>(true);                      // secure
+  s.Put<int32_t>(drm_info.handle);            // handle
+  s.Put<uint32_t>(0);                         // session_id
+  s.Put<uint32_t>(0);                         // psshinfo_size
+  auto psa_size_offset = s.Put<uint32_t>(0);  // psa_size : (lazy)
+
+  // box.pPSAParam
+  s.Put(drm_info.algorithm);                               // algorithm
+  s.Put(drm_info.format);                                  // format
+  s.Put(drm_info.phase);                                   // phase
+  s.Put<uint32_t>(drm_info.use_out_buffer);                // bUseOutBuf
+  s.Put<uint32_t>(drm_info.kid.size());                    // uKIDLen
+  s.Put(drm_info.kid);                                     // pKID
+  s.Put<uint32_t>(0);                                      // uDataLen
+  s.Put<uint32_t>(0);                                      // uOutBufLen
+  s.Put<uint32_t>(drm_info.initialization_vector.size());  // uIVLen
+  s.Put(drm_info.initialization_vector);                   // pIV
+
+  // box.pPSAParam->pSubData
+  drm::DrmbEsFragmentedMp4Data *sub_data =
+      reinterpret_cast<drm::DrmbEsFragmentedMp4Data *>(drm_info.sub_data);
+  if (sub_data != nullptr && sub_data->sub_sample_info_vector.size() != 0) {
+    uint32_t subdata_size =
+        sizeof(uint32_t) + sub_data->sub_sample_info_vector.size() *
+                               sizeof(drm::DrmbEsSubSampleInfo);
+    s.Put<uint32_t>(subdata_size);                      // subData_size
+    const size_t sub_sample_count = sub_data->sub_sample_info_vector.size();
+    s.Put<uint32_t>(sub_sample_count);                  // uSubSampleCount
+    for (const auto &value : sub_data->sub_sample_info_vector) {
+      s.Put<uint32_t>(value.bytes_of_clear_data);       // uBytesOfClearData
+      s.Put<uint32_t>(value.bytes_of_encrypted_data);   // uBytesOfEncryptedData
+    }
+  } else {
+    s.Put<uint32_t>(0);                                 // subData_size
+  }
+
+  // box.pPSAParam
+  s.Put(
+      reinterpret_cast<const Serializer::Byte *>(drm_info.split_offsets.data()),
+      sizeof(int) * drm_info.split_offsets.max_size());  // split_offsets
+  s.Put<uint8_t>(drm_info.use_pattern);                  // use_pattern
+  s.Put<uint32_t>(drm_info.crypt_byte_block);            // crypt_byte_block
+  s.Put<uint32_t>(drm_info.skip_byte_block);             // skip_byte_block
+
+  // box
+  auto reconfigure_pssh_offset = s.Put<uint32_t>(0);  // reconfigure_pssh
+
+  const auto total_size = s.GetSize();
+  const auto psa_size = reconfigure_pssh_offset - psa_size_offset;
+
+  std::unique_ptr<Serializer::Byte, std::function<void(Serializer::Byte *)>>
+      raw_data_ptr(new Serializer::Byte[total_size],
+                   [](Serializer::Byte *data) { delete[] data; });
+  s.Serialize(raw_data_ptr.get());
+  auto raw_data = raw_data_ptr.get();
+
+  // fill size field
+  Serializer::Put<uint32_t>(raw_data, total_size);                  // box_size
+  Serializer::Put<uint32_t>(raw_data + psa_size_offset, psa_size);  // psa_size
+
+  return gstguard::make_guard(g_bytes_new(raw_data, total_size));
+}
+}  // namespace esplayer_drm
+}  // namespace plusplayer
diff --git a/src/esplusplayer/src/esplusplayer.cpp b/src/esplusplayer/src/esplusplayer.cpp
new file mode 100755 (executable)
index 0000000..1b7038b
--- /dev/null
@@ -0,0 +1,18 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "plusplayer/esplusplayer.h"
+
+#include "core/utils/plusplayer_log.h"
+#include "esplayer/esplayer.h"
+
+namespace plusplayer {
+
+std::unique_ptr<EsPlusPlayer> EsPlusPlayer::Create() {
+  auto instance = std::unique_ptr<EsPlayer>(new EsPlayer);
+  LOG_INFO("Create Es Player [%p]", instance.get());
+  return instance;
+}
+
+}  // namespace plusplayer
diff --git a/src/esplusplayer/src/esplusplayer_capi.cpp b/src/esplusplayer/src/esplusplayer_capi.cpp
new file mode 100755 (executable)
index 0000000..045b444
--- /dev/null
@@ -0,0 +1,1901 @@
+#include "esplusplayer_capi/esplusplayer_capi.h"
+
+#include "plusplayer/esplusplayer.h"
+
+using plusplayer::EsPlusPlayer;
+using plusplayer::Geometry;
+
+#include <inttypes.h>
+#include <tbm_surface.h>
+
+#include <functional>
+#include <iostream>
+#include <mutex>
+#include <unordered_map>
+
+#include "core/utils/plusplayer_log.h"
+#include "esplayer/decoded_pkt_list.h"
+#include "esplusplayer_capi/esplusplayer_internal.h"
+#ifndef IS_TOMATO
+#include "mixer_capi/mixer_capi.h"
+#endif
+#include "plusplayer/appinfo.h"
+#include "plusplayer/audioeasinginfo.h"
+#include "plusplayer/drm.h"
+#include "plusplayer/elementary_stream.h"
+#include "plusplayer/espacket.h"
+#include "plusplayer/esplusplayer.h"
+#include "plusplayer/track.h"
+#include "plusplayer/types/buffer.h"
+#include "plusplayer/types/display.h"
+#include "plusplayer/types/error.h"
+#include "plusplayer/types/latency.h"
+#include "plusplayer/types/picturequality.h"
+#include "plusplayer/types/resource.h"
+#include "plusplayer/types/stream.h"
+
+using plusplayer::AdvPictureQualityType;
+using plusplayer::AudioEasingInfo;
+using plusplayer::AudioEasingType;
+using plusplayer::AudioMimeType;
+using plusplayer::AudioStream;
+using plusplayer::AudioStreamPtr;
+using plusplayer::BufferStatus;
+using plusplayer::CatchUpSpeed;
+using plusplayer::CropArea;
+using plusplayer::DecodedPacketManagerInterface;
+using plusplayer::DisplayMode;
+using plusplayer::DisplayRotation;
+using plusplayer::DisplayType;
+using plusplayer::ErrorType;
+using plusplayer::EsPacket;
+using plusplayer::EsPacketPtr;
+using plusplayer::EsState;
+using plusplayer::LatencyStatus;
+using plusplayer::MatroskaColor;
+using plusplayer::PlayerAdaptiveInfo;
+using plusplayer::PlayerAppInfo;
+using plusplayer::PlayerAudioCodecType;
+using plusplayer::PlayerLowLatencyMode;
+using plusplayer::PlayerVideoCodecType;
+using plusplayer::Rational;
+using plusplayer::RenderRect;
+using plusplayer::RscAllocPolicy;
+using plusplayer::RscType;
+using plusplayer::StreamType;
+using plusplayer::SubmitDataType;
+using plusplayer::Track;
+using plusplayer::TrackType;
+using plusplayer::VideoMimeType;
+using plusplayer::VideoStream;
+using plusplayer::VideoStreamPtr;
+using plusplayer::drm::EsPlayerEncryptedInfo;
+using plusplayer::drm::Type;
+
+namespace util {
+const std::unordered_map<esplusplayer_error_type, std::string> kErrorStringMap =
+    {{ESPLUSPLAYER_ERROR_TYPE_NONE, "ESPLUSPLAYER_ERROR_TYPE_NONE"},
+     {ESPLUSPLAYER_ERROR_TYPE_OUT_OF_MEMORY,
+      "ESPLUSPLAYER_ERROR_TYPE_OUT_OF_MEMORY"},
+     {ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER,
+      "ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER"},
+     {ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION,
+      "ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION"},
+     {ESPLUSPLAYER_ERROR_TYPE_INVALID_STATE,
+      "ESPLUSPLAYER_ERROR_TYPE_INVALID_STATE"},
+     {ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_AUDIO_CODEC,
+      "ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_AUDIO_CODEC"},
+     {ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_VIDEO_CODEC,
+      "ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_VIDEO_CODEC"},
+     {ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FILE,
+      "ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FILE"},
+     {ESPLUSPLAYER_ERROR_TYPE_CONNECTION_FAILED,
+      "ESPLUSPLAYER_ERROR_TYPE_CONNECTION_FAILED"},
+     {ESPLUSPLAYER_ERROR_TYPE_DRM_EXPIRED,
+      "ESPLUSPLAYER_ERROR_TYPE_DRM_EXPIRED"},
+     {ESPLUSPLAYER_ERROR_TYPE_DRM_NO_LICENSE,
+      "ESPLUSPLAYER_ERROR_TYPE_DRM_NO_LICENSE"},
+     {ESPLUSPLAYER_ERROR_TYPE_DRM_FUTURE_USE,
+      "ESPLUSPLAYER_ERROR_TYPE_DRM_FUTURE_USE"},
+     {ESPLUSPLAYER_ERROR_TYPE_NOT_PERMITTED,
+      "ESPLUSPLAYER_ERROR_TYPE_NOT_PERMITTED"},
+     {ESPLUSPLAYER_ERROR_TYPE_DRM_DECRYPTION_FAILED,
+      "ESPLUSPLAYER_ERROR_TYPE_DRM_DECRYPTION_FAILED"},
+     {ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FORMAT,
+      "ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FORMAT"},
+     {ESPLUSPLAYER_ERROR_TYPE_UNKNOWN, "ESPLUSPLAYER_ERROR_TYPE_UNKNOWN"}};
+
+const std::string kUnhandledErrorString = "Unhandled Error Type";
+static const std::string& ConvertErrorTypeToString(
+    esplusplayer_error_type type) {
+  return kErrorStringMap.count(type) > 0 ? kErrorStringMap.at(type)
+                                         : kUnhandledErrorString;
+}
+}  // namespace util
+
+struct EsPlusPlayerPriv;
+
+class listener_bridge : public plusplayer::EsEventListener {
+ public:
+  listener_bridge() { LOG_ENTER }
+  ~listener_bridge() { LOG_ENTER }
+
+  void ResetPacketList() {
+    if (decoded_pkt_mgr_) decoded_pkt_mgr_->Clear();
+  }
+
+  void ResetMultiSeekControl() {
+    std::unique_lock<std::mutex> lock(multi_seek_control.lock);
+    multi_seek_control.is_offset_valid = false;
+    multi_seek_control.offset = 0;
+  }
+
+  void Reset() {
+    LOG_ENTER
+    ResetPacketList();
+    ResetMultiSeekControl();
+    LOG_LEAVE
+  }
+
+  esplusplayer_error_type ConvertErrorCode(const ErrorType& error_code) {
+    esplusplayer_error_type type = ESPLUSPLAYER_ERROR_TYPE_NONE;
+    switch (error_code) {
+      case ErrorType::kOutOfMemory:
+        type = ESPLUSPLAYER_ERROR_TYPE_OUT_OF_MEMORY;
+        break;
+      case ErrorType::kInvalidParameter:
+        type = ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+        break;
+      case ErrorType::kInvalidOperation:
+        type = ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION;
+        break;
+      case ErrorType::kInvalidState:
+        type = ESPLUSPLAYER_ERROR_TYPE_INVALID_STATE;
+        break;
+      case ErrorType::kNotSupportedAudioCodec:
+        type = ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_AUDIO_CODEC;
+        break;
+      case ErrorType::kNotSupportedVideoCodec:
+        type = ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_VIDEO_CODEC;
+        break;
+      case ErrorType::kNotSupportedFile:
+        type = ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FILE;
+        break;
+      case ErrorType::kConnectionFailed:
+        type = ESPLUSPLAYER_ERROR_TYPE_CONNECTION_FAILED;
+        break;
+      case ErrorType::kDrmExpired:
+        type = ESPLUSPLAYER_ERROR_TYPE_DRM_EXPIRED;
+        break;
+      case ErrorType::kDrmNoLicense:
+        type = ESPLUSPLAYER_ERROR_TYPE_DRM_NO_LICENSE;
+        break;
+      case ErrorType::kDrmFutureUse:
+        type = ESPLUSPLAYER_ERROR_TYPE_DRM_FUTURE_USE;
+        break;
+      case ErrorType::kDrmNotPermitted:
+        type = ESPLUSPLAYER_ERROR_TYPE_NOT_PERMITTED;
+        break;
+      case ErrorType::kDrmInfo:
+        type = ESPLUSPLAYER_ERROR_TYPE_DRM_DECRYPTION_FAILED;
+        break;
+      case ErrorType::kNotSupportedFormat:
+        type = ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FORMAT;
+        break;
+      default:
+        LOG_ERROR("not defined error %x", static_cast<int>(error_code));
+        type = ESPLUSPLAYER_ERROR_TYPE_UNKNOWN;
+        break;
+    }
+    return type;
+  }
+
+  virtual void OnError(const ErrorType& error_code, UserData userdata) {
+    LOG_ENTER
+    LOG_INFO("error code : %x", static_cast<int>(error_code));
+    if (this->error_cb_)
+      this->error_cb_(ConvertErrorCode(error_code), error_cb_userdata_);
+  }
+
+  virtual void OnBufferStatus(const StreamType& type,
+                              const BufferStatus& status,
+                              const uint64_t byte_size,
+                              const uint64_t time_size, UserData userdata) {
+    // LOG_ENTER
+    // LOG_INFO("stream type : %d, buffer status : %d", static_cast<int>(type),
+    //          static_cast<int>(status));
+
+    if (this->buffer_status_cb_)
+      this->buffer_status_cb_(static_cast<esplusplayer_stream_type>(type),
+                              static_cast<esplusplayer_buffer_status>(status),
+                              buffer_status_cb_userdata_);
+    if (this->buffer_byte_status_cb_)
+      this->buffer_byte_status_cb_(
+          static_cast<esplusplayer_stream_type>(type),
+          static_cast<esplusplayer_buffer_status>(status), byte_size,
+          buffer_byte_status_cb_userdata_);
+    if (this->buffer_time_status_cb_)
+      this->buffer_time_status_cb_(
+          static_cast<esplusplayer_stream_type>(type),
+          static_cast<esplusplayer_buffer_status>(status), time_size,
+          buffer_time_status_cb_userdata_);
+  }
+
+  virtual void OnResourceConflicted(UserData userdata) {
+    LOG_ENTER
+    this->Reset();
+    if (this->resource_conflicted_cb_)
+      this->resource_conflicted_cb_(resource_conflicted_cb_userdata_);
+  }
+
+  virtual void OnEos(UserData userdata) {
+    LOG_ENTER
+    if (this->eos_cb_) this->eos_cb_(eos_cb_userdata_);
+  }
+
+  virtual void OnPrepareDone(bool result, UserData userdata) {
+    LOG_ENTER
+    LOG_INFO("prepare done. result : %s", result ? "true" : "false");
+    if (this->prepare_async_done_cb_)
+      this->prepare_async_done_cb_(result, prepare_async_done_cb_userdata_);
+  }
+
+  virtual void OnReadyToPrepare(const StreamType& type, UserData userdata) {
+    LOG_ENTER
+    LOG_INFO("stream type : %d", static_cast<int>(type));
+    if (this->ready_to_prepare_cb_)
+      this->ready_to_prepare_cb_(static_cast<esplusplayer_stream_type>(type),
+                                 ready_to_prepare_cb_userdata_);
+  }
+
+  virtual void OnSeekDone(UserData userdata) {
+    LOG_ENTER
+    if (this->seek_done_cb_) this->seek_done_cb_(seek_done_cb_userdata_);
+  }
+
+  virtual void OnReadyToSeek(const StreamType& type, const uint64_t offset,
+                             UserData userdata) {
+    LOG_ENTER
+    LOG_INFO("offset : %llu", offset);
+    std::unique_lock<std::mutex> lock(this->multi_seek_control.lock);
+    if (this->multi_seek_control.is_offset_valid == false ||
+        this->multi_seek_control.offset != offset) {
+      LOG_ERROR("Invalid offset:%llu", this->multi_seek_control.offset);
+      return;
+    }
+    if (this->ready_to_seek_cb_)
+      this->ready_to_seek_cb_(static_cast<esplusplayer_stream_type>(type),
+                              offset, ready_to_seek_cb_userdata_);
+  }
+
+  void SetDecodedPacketManager(
+      std::shared_ptr<DecodedPacketManagerInterface>& mgr) {
+    decoded_pkt_mgr_ = mgr;
+  }
+
+  virtual void OnMediaPacketGetTbmBufPtr(void** ptr, bool is_scale_change) {
+    // get one free point in current tbm list, send to trackrender, if can't
+    // find, set null
+    void* ptr1 = nullptr;
+    if (decoded_pkt_mgr_)
+      decoded_pkt_mgr_->GetFreeTbmSurface(&ptr1, is_scale_change);
+    *ptr = ptr1;
+  }
+
+  virtual void OnMediaPacketVideoDecoded(
+      const plusplayer::DecodedVideoPacket& packet) {
+    if (this->media_packet_video_decoded_cb_ == nullptr) return;
+
+    auto* _pkt = new esplusplayer_decoded_video_packet();
+    _pkt->pts = packet.pts;
+    _pkt->duration = packet.duration;
+    _pkt->surface_data = static_cast<void*>(packet.surface_data);
+    _pkt->private_data = packet.scaler_index;
+    if (decoded_pkt_mgr_ && decoded_pkt_mgr_->TryToAdd(_pkt)) {
+      this->media_packet_video_decoded_cb_(
+          _pkt, media_packet_video_decoded_cb_userdata_);
+    } else {
+      LOG_ERROR("Too many buffers are not released. packet(%p) will be drop.",
+                _pkt);
+    }
+  }
+
+  virtual void OnClosedCaptionData(std::unique_ptr<char[]> data, const int size,
+                                   UserData userdata) {
+    LOG_ENTER
+    if (this->closed_caption_cb_) {
+      this->closed_caption_cb_(data.get(), size, closed_caption_cb_userdata_);
+    }
+  }
+
+  virtual void OnFlushDone(UserData userdata) {
+    LOG_ENTER
+    if (this->flush_done_cb_) this->flush_done_cb_(flush_done_cb_userdata_);
+  }
+
+  virtual void OnEvent(const plusplayer::EventType& event,
+                       const plusplayer::EventMsg& msg_data,
+                       UserData userdata) {
+    LOG_ENTER
+    esplusplayer_event_msg event_msg;
+    event_msg.data = const_cast<char*>(msg_data.data.c_str());
+    event_msg.len = msg_data.len;
+    if (this->event_cb_)
+      this->event_cb_(static_cast<esplusplayer_event_type>(event), event_msg,
+                      event_cb_userdata_);
+  }
+
+  virtual void OnFirstDecodingDone(UserData userdata) {
+    LOG_ENTER
+    if (this->first_video_decoding_done_cb_) {
+      this->first_video_decoding_done_cb_(
+          first_video_decoding_done_cb_userdata_);
+    }
+  }
+
+  virtual void OnVideoDecoderUnderrun(UserData userdata) {
+    LOG_ENTER
+    if (this->video_decoder_underrun_cb_)
+      this->video_decoder_underrun_cb_(video_decoder_underrun_cb_userdata_);
+  }
+
+  virtual void OnVideoLatencyStatus(const LatencyStatus& latency_status,
+                                    UserData userdata) {
+    LOG_ENTER
+    if (this->video_latency_status_cb_)
+      this->video_latency_status_cb_(
+          static_cast<esplusplayer_latency_status>(latency_status),
+          video_latency_status_cb_userdata_);
+  }
+
+  virtual void OnAudioLatencyStatus(const LatencyStatus& latency_status,
+                                    UserData userdata) {
+    LOG_ENTER
+    if (this->audio_latency_status_cb_)
+      this->audio_latency_status_cb_(
+          static_cast<esplusplayer_latency_status>(latency_status),
+          audio_latency_status_cb_userdata_);
+  }
+
+  virtual void OnVideoHighLatency(UserData userdata) {
+    LOG_ENTER
+    if (this->video_high_latency_cb_)
+      this->video_high_latency_cb_(video_high_latency_cb_userdata_);
+  }
+
+  virtual void OnAudioHighLatency(UserData userdata) {
+    LOG_ENTER
+    if (this->audio_high_latency_cb_)
+      this->audio_high_latency_cb_(audio_high_latency_cb_userdata_);
+  }
+
+ private:
+  static void DecodedPacketDeleter(esplusplayer_decoded_video_packet* packet) {
+    if (packet->surface_data != nullptr) {
+      tbm_surface_destroy(static_cast<tbm_surface_h>(packet->surface_data));
+      packet->surface_data = NULL;
+    }
+    delete packet;
+  }
+
+ private:
+  esplusplayer_error_cb error_cb_ = nullptr;
+  void* error_cb_userdata_ = nullptr;
+  esplusplayer_buffer_status_cb buffer_status_cb_ = nullptr;
+  void* buffer_status_cb_userdata_ = nullptr;
+  esplusplayer_buffer_byte_status_cb buffer_byte_status_cb_ = nullptr;
+  void* buffer_byte_status_cb_userdata_ = nullptr;
+  esplusplayer_buffer_time_status_cb buffer_time_status_cb_ = nullptr;
+  void* buffer_time_status_cb_userdata_ = nullptr;
+  esplusplayer_resource_conflicted_cb resource_conflicted_cb_ = nullptr;
+  void* resource_conflicted_cb_userdata_ = nullptr;
+  esplusplayer_eos_cb eos_cb_ = nullptr;
+  void* eos_cb_userdata_ = nullptr;
+  esplusplayer_ready_to_prepare_cb ready_to_prepare_cb_ = nullptr;
+  void* ready_to_prepare_cb_userdata_ = nullptr;
+  esplusplayer_prepare_async_done_cb prepare_async_done_cb_ = nullptr;
+  void* prepare_async_done_cb_userdata_ = nullptr;
+  esplusplayer_seek_done_cb seek_done_cb_ = nullptr;
+  void* seek_done_cb_userdata_ = nullptr;
+  esplusplayer_ready_to_seek_cb ready_to_seek_cb_ = nullptr;
+  void* ready_to_seek_cb_userdata_ = nullptr;
+  esplusplayer_media_packet_video_decoded_cb media_packet_video_decoded_cb_ =
+      nullptr;
+  void* media_packet_video_decoded_cb_userdata_ = nullptr;
+  esplusplayer_closed_caption_cb closed_caption_cb_ = nullptr;
+  void* closed_caption_cb_userdata_ = nullptr;
+  esplusplayer_flush_done_cb flush_done_cb_ = nullptr;
+  void* flush_done_cb_userdata_ = nullptr;
+  esplusplayer_event_cb event_cb_ = nullptr;
+  void* event_cb_userdata_ = nullptr;
+  esplusplayer_first_video_decoding_done_cb first_video_decoding_done_cb_ =
+      nullptr;
+  void* first_video_decoding_done_cb_userdata_ = nullptr;
+  esplusplayer_decoder_underrun_cb video_decoder_underrun_cb_ = nullptr;
+  void* video_decoder_underrun_cb_userdata_ = nullptr;
+  esplusplayer_video_latency_status_cb video_latency_status_cb_ = nullptr;
+  esplusplayer_audio_latency_status_cb audio_latency_status_cb_ = nullptr;
+  void* video_latency_status_cb_userdata_ = nullptr;
+  void* audio_latency_status_cb_userdata_ = nullptr;
+  esplusplayer_video_high_latency_cb video_high_latency_cb_ = nullptr;
+  esplusplayer_audio_high_latency_cb audio_high_latency_cb_ = nullptr;
+  void* video_high_latency_cb_userdata_ = nullptr;
+  void* audio_high_latency_cb_userdata_ = nullptr;
+
+  std::shared_ptr<DecodedPacketManagerInterface> decoded_pkt_mgr_;
+
+  struct MultiSeekControl {
+    std::mutex lock;
+    bool is_offset_valid = false;
+    uint64_t offset = 0;
+  };
+  friend void update_ready_to_seek_callback(
+      esplusplayer_handle pp, esplusplayer_ready_to_seek_cb ready_to_seek_cb,
+      void* userdata);
+  friend void update_ready_to_seek_offset(esplusplayer_handle pp,
+                                          const uint64_t offset);
+  MultiSeekControl multi_seek_control;
+
+  friend int esplusplayer_set_error_cb(esplusplayer_handle pp,
+                                       esplusplayer_error_cb error_cb,
+                                       void* userdata);
+  friend int esplusplayer_set_buffer_status_cb(
+      esplusplayer_handle pp, esplusplayer_buffer_status_cb buffer_status_cb,
+      void* userdata);
+  friend int esplusplayer_set_buffer_byte_status_cb(
+      esplusplayer_handle pp,
+      esplusplayer_buffer_byte_status_cb buffer_status_cb, void* userdata);
+  friend int esplusplayer_set_buffer_time_status_cb(
+      esplusplayer_handle pp,
+      esplusplayer_buffer_time_status_cb buffer_status_cb, void* userdata);
+  friend int esplusplayer_set_resource_conflicted_cb(
+      esplusplayer_handle pp,
+      esplusplayer_resource_conflicted_cb resource_conflicted_cb,
+      void* userdata);
+  friend int esplusplayer_set_eos_cb(esplusplayer_handle pp,
+                                     esplusplayer_eos_cb eos_cb,
+                                     void* userdata);
+  friend int esplusplayer_set_ready_to_prepare_cb(
+      esplusplayer_handle pp,
+      esplusplayer_ready_to_prepare_cb ready_to_prepare_cb, void* userdata);
+  friend int esplusplayer_set_prepare_async_done_cb(
+      esplusplayer_handle pp,
+      esplusplayer_prepare_async_done_cb prepare_async_done_cb, void* userdata);
+  friend int esplusplayer_set_seek_done_cb(
+      esplusplayer_handle pp, esplusplayer_seek_done_cb seek_done_cb,
+      void* userdata);
+  friend int esplusplayer_set_ready_to_seek_cb(
+      esplusplayer_handle pp, esplusplayer_ready_to_seek_cb ready_to_seek_cb,
+      void* userdata);
+  friend int esplusplayer_set_media_packet_video_decoded_cb(
+      esplusplayer_handle pp,
+      esplusplayer_media_packet_video_decoded_cb media_packet_video_decoded_cb,
+      void* userdata);
+  friend int esplusplayer_set_closed_caption_cb(
+      esplusplayer_handle handle,
+      esplusplayer_closed_caption_cb closed_caption_cb, void* userdata);
+  friend int esplusplayer_set_flush_done_cb(
+      esplusplayer_handle pp, esplusplayer_flush_done_cb flush_done_cb,
+      void* userdata);
+  friend int esplusplayer_set_event_cb(esplusplayer_handle pp,
+                                       esplusplayer_event_cb event_cb,
+                                       void* userdata);
+  friend int esplusplayer_set_first_video_decoding_done_cb(
+      esplusplayer_handle handle,
+      esplusplayer_first_video_decoding_done_cb first_video_decoding_done_cb,
+      void* userdata);
+  friend int esplusplayer_set_video_decoder_underrun_cb(
+      esplusplayer_handle handle,
+      esplusplayer_decoder_underrun_cb video_decoder_underrun_cb,
+      void* userdata);
+  friend int esplusplayer_set_video_latency_status_cb(
+      esplusplayer_handle pp,
+      esplusplayer_video_latency_status_cb video_latency_status_cb,
+      void* userdata);
+  friend int esplusplayer_set_audio_latency_status_cb(
+      esplusplayer_handle pp,
+      esplusplayer_audio_latency_status_cb audio_latency_status_cb,
+      void* userdata);
+  friend int esplusplayer_set_video_high_latency_cb(
+      esplusplayer_handle pp,
+      esplusplayer_video_high_latency_cb video_high_latency_cb, void* userdata);
+  friend int esplusplayer_set_audio_high_latency_cb(
+      esplusplayer_handle pp,
+      esplusplayer_audio_high_latency_cb audio_high_latency_cb, void* userdata);
+};
+
+struct EsPlusPlayerPriv {
+  std::unique_ptr<EsPlusPlayer> player;
+  std::unique_ptr<listener_bridge> listener{new listener_bridge()};
+  std::shared_ptr<DecodedPacketManagerInterface> decoded_pkt_mgr;
+
+  friend EsPlusPlayerPriv* EsPrivCreate();
+  friend void EsPrivDestroy(EsPlusPlayerPriv*& instance);
+
+ private:
+  EsPlusPlayerPriv() {}
+  ~EsPlusPlayerPriv() {}
+};
+
+EsPlusPlayerPriv* EsPrivCreate() {
+  EsPlusPlayerPriv* instance = new EsPlusPlayerPriv();
+  instance->player = EsPlusPlayer::Create();
+  instance->player->RegisterListener(instance->listener.get(),
+                                     instance->player.get());
+  return instance;
+}
+
+void EsPrivDestroy(EsPlusPlayerPriv*& instance) {
+  if (instance) delete instance;
+  instance = nullptr;
+}
+
+inline bool is_null_(void* object) { return object == nullptr; }
+
+inline EsPlusPlayer* cast_(esplusplayer_handle pp) {
+  auto priv = static_cast<EsPlusPlayerPriv*>(pp);
+  return priv ? priv->player.get() : nullptr;
+}
+
+inline listener_bridge* listener_cast_(esplusplayer_handle pp) {
+  auto priv = static_cast<EsPlusPlayerPriv*>(pp);
+  return priv->listener.get();
+}
+
+void update_ready_to_seek_callback(
+    esplusplayer_handle handle, esplusplayer_ready_to_seek_cb ready_to_seek_cb,
+    void* userdata) {
+  LOG_ENTER
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return;
+  }
+  std::unique_lock<std::mutex> lock(listener->multi_seek_control.lock);
+  listener->ready_to_seek_cb_ = ready_to_seek_cb;
+  listener->ready_to_seek_cb_userdata_ = userdata;
+  listener->multi_seek_control.is_offset_valid = false;
+}
+void update_ready_to_seek_offset(esplusplayer_handle handle,
+                                 const uint64_t offset) {
+  LOG_ENTER
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return;
+  }
+  std::unique_lock<std::mutex> lock(listener->multi_seek_control.lock);
+  listener->multi_seek_control.offset = offset;
+  listener->multi_seek_control.is_offset_valid = true;
+}
+
+inline void convert_matroska_color_info_(
+    const esplusplayer_matroska_color* from, MatroskaColor* to) {
+  to->matrix_coefficients = from->matrix_coefficients;
+  to->bits_per_channel = from->bits_per_channel;
+  to->chroma_subsampling_horizontal = from->chroma_subsampling_horizontal;
+  to->chroma_subsampling_vertical = from->chroma_subsampling_vertical;
+  to->cb_subsampling_horizontal = from->cb_subsampling_horizontal;
+  to->cb_subsampling_vertical = from->cb_subsampling_vertical;
+  to->chroma_siting_horizontal = from->chroma_siting_horizontal;
+  to->chroma_siting_vertical = from->chroma_siting_vertical;
+  to->range = from->range;
+  to->transfer_characteristics = from->transfer_characteristics;
+  to->primaries = from->primaries;
+  to->max_cll = from->max_cll;
+  to->max_fall = from->max_fall;
+  to->is_hdr_10p = from->isHDR10p;
+  to->metadata.primary_r_chromaticity_x =
+      from->metadata.primary_r_chromaticity_x;
+  to->metadata.primary_r_chromaticity_y =
+      from->metadata.primary_r_chromaticity_y;
+  to->metadata.primary_g_chromaticity_x =
+      from->metadata.primary_g_chromaticity_x;
+  to->metadata.primary_g_chromaticity_y =
+      from->metadata.primary_g_chromaticity_y;
+  to->metadata.primary_b_chromaticity_x =
+      from->metadata.primary_b_chromaticity_x;
+  to->metadata.primary_b_chromaticity_y =
+      from->metadata.primary_b_chromaticity_y;
+  to->metadata.white_point_chromaticity_x =
+      from->metadata.white_point_chromaticity_x;
+  to->metadata.white_point_chromaticity_y =
+      from->metadata.white_point_chromaticity_y;
+  to->metadata.luminance_max = from->metadata.luminance_max;
+  to->metadata.luminance_min = from->metadata.luminance_min;
+}
+
+inline EsPacketPtr convert_espacket_(esplusplayer_es_packet* from) {
+  std::shared_ptr<char> buffer = nullptr;
+  std::shared_ptr<char> hdr10p_metadata = nullptr;
+  if (from->buffer_size != 0 && from->buffer) {
+    buffer = std::shared_ptr<char>(new char[from->buffer_size],
+                                   std::default_delete<char[]>());
+    memcpy(buffer.get(), from->buffer, from->buffer_size);
+  }
+  if (from->hdr10p_metadata_size != 0 && from->hdr10p_metadata) {
+    hdr10p_metadata = std::shared_ptr<char>(
+        new char[from->hdr10p_metadata_size], std::default_delete<char[]>());
+    memcpy(hdr10p_metadata.get(), from->hdr10p_metadata,
+           from->hdr10p_metadata_size);
+  }
+  auto espacket = EsPacket::Create(static_cast<StreamType>(from->type), buffer,
+                                   from->buffer_size, from->pts, from->duration,
+                                   from->hdr10p_metadata_size, hdr10p_metadata);
+
+  if (from->matroska_color_info != nullptr) {
+    MatroskaColor color_info;
+    convert_matroska_color_info_(from->matroska_color_info, &color_info);
+    bool ret = espacket->SetMatroskaColorInfo(color_info);
+    if (ret == false) return nullptr;
+  }
+  return std::move(espacket);
+}
+
+using EncryptedInfoPtr =
+    std::unique_ptr<EsPlayerEncryptedInfo,
+                    std::function<void(EsPlayerEncryptedInfo*)>>;
+inline EncryptedInfoPtr convert_es_drm_info_(esplusplayer_drm_info* from) {
+  auto custom_deleter = [](EsPlayerEncryptedInfo* drm_info) {
+    if (drm_info == nullptr) return;
+    if (drm_info->sub_data != nullptr) {
+      delete reinterpret_cast<plusplayer::drm::DrmbEsFragmentedMp4Data*>(
+          drm_info->sub_data);
+      drm_info->sub_data = nullptr;
+    }
+    delete drm_info;
+  };
+
+  if (from == nullptr) return EncryptedInfoPtr(nullptr, custom_deleter);
+
+  EncryptedInfoPtr drm_info =
+      EncryptedInfoPtr(new EsPlayerEncryptedInfo(), custom_deleter);
+
+  drm_info->handle = from->handle;
+  drm_info->algorithm =
+      static_cast<plusplayer::drm::DrmbEsCipherAlgorithm>(from->algorithm);
+  drm_info->format =
+      static_cast<plusplayer::drm::DrmbEsMediaFormat>(from->format);
+  drm_info->phase =
+      static_cast<plusplayer::drm::DrmbEsCipherPhase>(from->phase);
+
+  // kid
+  if (from->kid && from->kid_length > 0) {
+    drm_info->kid = std::move(
+        std::vector<unsigned char>(from->kid, from->kid + from->kid_length));
+  }
+
+  // initialization_vector
+  if (from->iv && from->iv_length > 0) {
+    drm_info->initialization_vector = std::move(
+        std::vector<unsigned char>(from->iv, from->iv + from->iv_length));
+  }
+
+  // sub_data
+  auto* from_sub_data =
+      reinterpret_cast<esplusplayer_drmb_es_fmp4_data*>(from->sub_data);
+  if (from_sub_data && from_sub_data->subsample_count > 0) {
+    drm_info->sub_data = new plusplayer::drm::DrmbEsFragmentedMp4Data;
+    auto* sub_data =
+        reinterpret_cast<plusplayer::drm::DrmbEsFragmentedMp4Data*>(
+            drm_info->sub_data);
+    for (uint32_t i = 0; i < from_sub_data->subsample_count; i++) {
+      auto& subsample_info = from_sub_data->subsample_infos[i];
+      sub_data->sub_sample_info_vector.emplace_back(
+          subsample_info.bytes_of_clear_data,
+          subsample_info.bytes_of_encrypted_data);
+    }
+  }
+
+  // split_offsets
+  if (from->split_offsets) {
+    const std::size_t kSplitOffsetMaxSize = 15 * sizeof(int);
+    std::memcpy(drm_info->split_offsets.data(), from->split_offsets,
+                kSplitOffsetMaxSize);
+  }
+
+  drm_info->use_out_buffer = from->use_out_buffer;
+  drm_info->use_pattern = from->use_pattern;
+  drm_info->crypt_byte_block = from->crypt_byte_block;
+  drm_info->skip_byte_block = from->skip_byte_block;
+
+  return std::move(drm_info);
+}
+
+inline AudioStreamPtr convert_stream_ptr_(
+    esplusplayer_audio_stream_info* from) {
+  LOG_INFO("mime type : %d", static_cast<int>(from->mime_type));
+  LOG_INFO("from->bitrate : %d", from->bitrate);
+  LOG_INFO("from->channels : %d", from->channels);
+  LOG_INFO("from->sample_rate : %d", from->sample_rate);
+  LOG_INFO("from->codec_data_length : %d", from->codec_data_length);
+
+  auto stream = AudioStream::Create();
+  std::shared_ptr<char> codec_data = nullptr;
+
+  if (from->codec_data_length != 0) {
+    codec_data = std::shared_ptr<char>(new char[from->codec_data_length],
+                                       std::default_delete<char[]>());
+    memcpy(codec_data.get(), from->codec_data, from->codec_data_length);
+  }
+
+  stream->SetCodecData(codec_data, from->codec_data_length);
+  stream->SetMimeType(static_cast<plusplayer::AudioMimeType>(from->mime_type));
+  stream->SetBitrate(from->bitrate);
+  stream->SetChannels(from->channels);
+  stream->SetSamplerate(from->sample_rate);
+
+  return std::move(stream);
+}
+
+inline int convert_return_type_(bool ret) {
+  return ret ? ESPLUSPLAYER_ERROR_TYPE_NONE
+             : ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION;
+}
+
+inline VideoStreamPtr convert_stream_ptr_(
+    esplusplayer_video_stream_info* from) {
+  LOG_INFO("mime type : %u", static_cast<int>(from->mime_type));
+  LOG_INFO("from->width : %u", from->width);
+  LOG_INFO("from->height : %u", from->height);
+  LOG_INFO("from->max_width : %u", from->max_width);
+  LOG_INFO("from->max_height : %u", from->max_height);
+  LOG_INFO("from->framerate_num : %u", from->framerate_num);
+  LOG_INFO("from->framerate_den : %u", from->framerate_den);
+  LOG_INFO("from->codec_data_length : %u", from->codec_data_length);
+
+  auto stream = VideoStream::Create();
+  std::shared_ptr<char> codec_data = nullptr;
+
+  if (from->codec_data_length != 0) {
+    codec_data = std::shared_ptr<char>(new char[from->codec_data_length],
+                                       std::default_delete<char[]>());
+    memcpy(codec_data.get(), from->codec_data, from->codec_data_length);
+  }
+
+  stream->SetCodecData(codec_data, from->codec_data_length);
+  stream->SetMimeType(static_cast<plusplayer::VideoMimeType>(from->mime_type));
+  stream->SetWidth(from->width);
+  stream->SetHeight(from->height);
+  stream->SetMaxWidth(from->max_width);
+  stream->SetMaxHeight(from->max_height);
+  stream->SetFramerate(from->framerate_num, from->framerate_den);
+
+  return std::move(stream);
+}
+
+esplusplayer_handle esplusplayer_create() {
+  esplusplayer_handle player = static_cast<esplusplayer_handle>(EsPrivCreate());
+  LOG_INFO("capi handle > [%p], cpp handle > [%p]", player, cast_(player));
+  return player;
+}
+
+int esplusplayer_open(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  return convert_return_type_(cast_(handle)->Open());
+}
+
+int esplusplayer_close(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  bool ret = cast_(handle)->Close();
+  listener->Reset();
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_destroy(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  if (ESPLUSPLAYER_STATE_NONE != esplusplayer_get_state(handle))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_STATE;
+
+  auto priv = static_cast<EsPlusPlayerPriv*>(handle);
+  EsPrivDestroy(priv);
+
+  return ESPLUSPLAYER_ERROR_TYPE_NONE;
+}
+
+int esplusplayer_deactivate(esplusplayer_handle handle,
+                            esplusplayer_stream_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(
+      cast_(handle)->Deactivate(static_cast<StreamType>(type)));
+}
+
+int esplusplayer_activate(esplusplayer_handle handle,
+                          esplusplayer_stream_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(
+      cast_(handle)->Activate(static_cast<StreamType>(type)));
+}
+
+int esplusplayer_prepare_async(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->PrepareAsync());
+}
+
+int esplusplayer_start(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->Start());
+}
+
+int esplusplayer_stop(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->Stop());
+}
+
+int esplusplayer_pause(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->Pause());
+}
+
+int esplusplayer_resume(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->Resume());
+}
+
+int esplusplayer_set_playback_rate(esplusplayer_handle handle,
+                                   const double playback_rate,
+                                   const bool audio_mute) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "playback rate : %lf, audio mute : %d",
+             playback_rate, audio_mute);
+  return convert_return_type_(
+      cast_(handle)->SetPlaybackRate(playback_rate, audio_mute));
+}
+
+int esplusplayer_seek(esplusplayer_handle handle, uint64_t time_ms) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "time : %llu", time_ms);
+  update_ready_to_seek_offset(handle, time_ms);
+
+  return convert_return_type_(cast_(handle)->Seek(time_ms));
+}
+
+int esplusplayer_set_app_info(esplusplayer_handle handle,
+                              const esplusplayer_app_info* app_info) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  if (app_info == nullptr) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  LOG_INFO_P(cast_(handle), "app id : %s ", app_info->id);
+  LOG_INFO_P(cast_(handle), "app version : %s ", app_info->version);
+  LOG_INFO_P(cast_(handle), "app type : %s", app_info->type);
+
+  PlayerAppInfo info;
+  info.id = app_info->id;
+  info.version = app_info->version;
+  info.type = app_info->type;
+  cast_(handle)->SetAppInfo(info);
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_display(esplusplayer_handle handle,
+                             esplusplayer_display_type type, void* window) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "display type : %d, object : %p",
+             static_cast<int>(type), window);
+
+#if (!IS_AUDIO_PRODUCT) && (!IS_TOMATO)
+  if (type == ESPLUSPLAYER_DISPLAY_TYPE_MIXER) {
+    mixer_handle mixer_h = window;
+    plusplayer::MixerTicket* ticket =
+        (plusplayer::MixerTicket*)mixer_create_ticket(mixer_h, handle);
+    if (is_null_(ticket)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+    return convert_return_type_(
+        cast_(handle)->SetDisplay(static_cast<DisplayType>(type), ticket));
+  }
+#endif
+  return convert_return_type_(
+      cast_(handle)->SetDisplay(static_cast<DisplayType>(type), window));
+}
+
+int esplusplayer_set_ecore_display(esplusplayer_handle handle,
+                                   esplusplayer_display_type type, void* window,
+                                   int x, int y, int width, int height) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "display type : %d, object : %p",
+             static_cast<int>(type), window);
+
+  return convert_return_type_(cast_(handle)->SetDisplay(
+      static_cast<DisplayType>(type), window, x, y, width, height));
+}
+
+int esplusplayer_set_display_ecore_subsurface(esplusplayer_handle handle,
+                                              esplusplayer_display_type type,
+                                              void* subsurface, int x, int y,
+                                              int width, int height) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(subsurface))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "display type : %d, object : %p",
+             static_cast<int>(type), subsurface);
+
+  return convert_return_type_(cast_(handle)->SetDisplaySubsurface(
+      static_cast<DisplayType>(type), subsurface, x, y, width, height));
+}
+
+int esplusplayer_set_surface_display(esplusplayer_handle handle,
+                                     esplusplayer_display_type type,
+                                     unsigned int surface_id, int x, int y,
+                                     int width, int height) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "display type : %d, object : %u",
+             static_cast<int>(type), surface_id);
+
+  return convert_return_type_(cast_(handle)->SetDisplay(
+      static_cast<DisplayType>(type), surface_id, x, y, width, height));
+}
+
+int esplusplayer_set_display_mode(esplusplayer_handle handle,
+                                  esplusplayer_display_mode mode) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "display mode : %d", static_cast<int>(mode));
+
+  return convert_return_type_(
+      cast_(handle)->SetDisplayMode(static_cast<DisplayMode>(mode)));
+}
+
+int esplusplayer_set_display_roi(esplusplayer_handle handle, int x, int y,
+                                 int width, int height) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "x : %d, y: %d, width : %d, height : %d", x, y,
+             width, height);
+
+  Geometry roi;
+  roi.x = x;
+  roi.y = y;
+  roi.w = width;
+  roi.h = height;
+
+  return convert_return_type_(cast_(handle)->SetDisplayRoi(roi));
+}
+
+int esplusplayer_set_video_roi(esplusplayer_handle handle, double scale_x,
+                               double scale_y, double scale_w, double scale_h) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle),
+             "scale-x : %lf, scale-y: %lf, scale-w : %lf, scale-h : %lf",
+             scale_x, scale_y, scale_w, scale_h);
+
+  CropArea rio_area;
+  rio_area.scale_x = scale_x;
+  rio_area.scale_y = scale_y;
+  rio_area.scale_w = scale_w;
+  rio_area.scale_h = scale_h;
+
+  return convert_return_type_(cast_(handle)->SetVideoRoi(rio_area));
+}
+
+int esplusplayer_resize_render_rect(esplusplayer_handle handle, int x, int y,
+                                    int width, int height) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "x : %d, y: %d, width : %d, height : %d", x, y,
+             width, height);
+
+  RenderRect rect;
+  rect.x = x;
+  rect.y = y;
+  rect.w = width;
+  rect.h = height;
+
+  return convert_return_type_(cast_(handle)->ResizeRenderRect(rect));
+}
+
+int esplusplayer_set_display_rotation(
+    esplusplayer_handle handle, esplusplayer_display_rotation_type rotation) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "display rotate angle : %d",
+             static_cast<int>(rotation));
+  return convert_return_type_(
+      cast_(handle)->SetDisplayRotate(static_cast<DisplayRotation>(rotation)));
+}
+
+int esplusplayer_get_display_rotation(
+    esplusplayer_handle handle, esplusplayer_display_rotation_type* rotation) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(rotation))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  return convert_return_type_(cast_(handle)->GetDisplayRotate(
+      reinterpret_cast<DisplayRotation*>(rotation)));
+}
+
+int esplusplayer_set_display_visible(esplusplayer_handle handle, bool visible) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "visible : %s", visible ? "true" : "false");
+  return convert_return_type_(cast_(handle)->SetDisplayVisible(visible));
+}
+
+int esplusplayer_set_tz_use(esplusplayer_handle handle, bool using_tz) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "using_tz : %s", using_tz ? "true" : "false");
+  return convert_return_type_(cast_(handle)->SetTrustZoneUse(using_tz));
+}
+
+int esplusplayer_set_submit_data_type(esplusplayer_handle handle,
+                                      esplusplayer_submit_data_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "type : %d", type);
+  return convert_return_type_(
+      cast_(handle)->SetSubmitDataType(static_cast<SubmitDataType>(type)));
+}
+
+int esplusplayer_set_audio_mute(esplusplayer_handle handle, bool mute) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "mute : %s", mute ? "true" : "false");
+  return convert_return_type_(cast_(handle)->SetAudioMute(mute));
+}
+
+esplusplayer_state esplusplayer_get_state(esplusplayer_handle handle) {
+  // LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return esplusplayer_state::ESPLUSPLAYER_STATE_NONE;
+  auto current_state =
+      static_cast<esplusplayer_state>(cast_(handle)->GetState());
+  // LOG_INFO_P(cast_(handle), "state : %d", static_cast<int>(current_state));
+
+  return current_state;
+}
+
+esplusplayer_submit_status esplusplayer_submit_packet(
+    esplusplayer_handle handle, esplusplayer_es_packet* packet) {
+  if (is_null_(handle)) return ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED;
+  auto packetptr = convert_espacket_(packet);
+  if (packetptr == nullptr) {
+    LOG_ERROR("packet converting failed");
+    return ESPLUSPLAYER_SUBMIT_STATUS_INVALID_PACKET;
+  }
+  auto status = cast_(handle)->SubmitPacket(packetptr);
+  if (status != plusplayer::PacketSubmitStatus::kSuccess) {
+    LOG_ERROR("SubmitPacket status isn't SUCCESS [%d]",
+              static_cast<int>(status));
+  }
+  return static_cast<esplusplayer_submit_status>(status);
+}
+
+esplusplayer_submit_status esplusplayer_submit_trust_zone_packet(
+    esplusplayer_handle handle, esplusplayer_es_packet* packet,
+    uint32_t tz_handle) {
+  if (is_null_(handle)) return ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED;
+  auto packetptr = convert_espacket_(packet);
+  if (packetptr == nullptr) {
+    LOG_ERROR("packet converting failed");
+    return ESPLUSPLAYER_SUBMIT_STATUS_INVALID_PACKET;
+  }
+  auto status = cast_(handle)->SubmitTrustZonePacket(packetptr, tz_handle);
+  if (status != plusplayer::PacketSubmitStatus::kSuccess) {
+    LOG_ERROR("SubmitPacket status isn't SUCCESS [%d]",
+              static_cast<int>(status));
+  }
+  return static_cast<esplusplayer_submit_status>(status);
+}
+
+esplusplayer_submit_status esplusplayer_submit_encrypted_packet(
+    esplusplayer_handle handle, esplusplayer_es_packet* packet,
+    esplusplayer_drm_info* drm_info) {
+  if (is_null_(handle)) return ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED;
+  auto packetptr = convert_espacket_(packet);
+  if (packetptr == nullptr) {
+    LOG_ERROR("packet converting failed");
+    return ESPLUSPLAYER_SUBMIT_STATUS_INVALID_PACKET;
+  }
+  auto status = plusplayer::PacketSubmitStatus::kSuccess;
+  if (drm_info == nullptr) {
+    status = cast_(handle)->SubmitPacket(packetptr);
+  } else {
+    auto encrypted_info = convert_es_drm_info_(drm_info);
+    status = cast_(handle)->SubmitEncryptedPacket(packetptr, *encrypted_info);
+  }
+  if (status != plusplayer::PacketSubmitStatus::kSuccess) {
+    LOG_ERROR("SubmitPacket status isn't SUCCESS [%d]",
+              static_cast<int>(status));
+  }
+  return static_cast<esplusplayer_submit_status>(status);
+}
+
+esplusplayer_submit_status esplusplayer_submit_eos_packet(
+    esplusplayer_handle handle, esplusplayer_stream_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED;
+
+  auto status = cast_(handle)->SubmitPacket(
+      std::move(EsPacket::CreateEos(static_cast<StreamType>(type))));
+  return static_cast<esplusplayer_submit_status>(status);
+}
+
+int esplusplayer_set_audio_stream_info(esplusplayer_handle handle,
+                                       esplusplayer_audio_stream_info* info) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(info))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto stream = convert_stream_ptr_(info);
+  return convert_return_type_(cast_(handle)->SetStream(std::move(stream)));
+}
+
+int esplusplayer_set_video_stream_info(esplusplayer_handle handle,
+                                       esplusplayer_video_stream_info* info) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(info))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto stream = convert_stream_ptr_(info);
+  return convert_return_type_(cast_(handle)->SetStream(std::move(stream)));
+}
+
+int esplusplayer_get_playing_time(esplusplayer_handle handle, uint64_t* ms) {
+  // LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(ms))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret = cast_(handle)->GetPlayingTime(ms);
+  // LOG_INFO_P(cast_(handle), "playing time : %llu", *ms);
+  return convert_return_type_(ret);
+}
+
+namespace {
+std::shared_ptr<DecodedPacketManagerInterface> CreateDecodedPacketManager(
+    esplusplayer_decoded_video_frame_buffer_type type) {
+  std::shared_ptr<DecodedPacketManagerInterface> mgr = nullptr;
+  if (type == ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY)
+    mgr = std::make_shared<plusplayer::DecodedCopiedPacketList>();
+  else if (type == ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_REFERENCE)
+    mgr = std::make_shared<plusplayer::DecodedReferencePacketList>();
+  else if (type == ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_SCALE)
+    mgr = std::make_shared<plusplayer::DecodedScaledPacketList>();
+  return mgr;
+}
+}  // namespace
+
+int esplusplayer_set_video_frame_buffer_type(
+    esplusplayer_handle handle,
+    esplusplayer_decoded_video_frame_buffer_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(listener_cast_(handle)))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto priv = static_cast<EsPlusPlayerPriv*>(handle);
+  priv->decoded_pkt_mgr = ::CreateDecodedPacketManager(type);
+  priv->listener->SetDecodedPacketManager(priv->decoded_pkt_mgr);
+
+  auto ret = cast_(handle)->SetVideoFrameBufferType(
+      static_cast<plusplayer::DecodedVideoFrameBufferType>(type));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_video_frame_buffer_scale_resolution(
+    esplusplayer_handle handle, uint32_t target_width, uint32_t target_height) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || !target_width || !target_height)
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  LOG_INFO_P(cast_(handle), "target_width : %d, target_height: %d",
+             target_width, target_height);
+  return convert_return_type_(cast_(handle)->SetVideoFrameBufferScaleResolution(
+      target_width, target_height));
+}
+
+int esplusplayer_set_decoded_video_frame_rate(
+    esplusplayer_handle handle, esplusplayer_rational request_framerate) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO("request decoded video frame rate : %d/%d", request_framerate.num,
+           request_framerate.den);
+
+  Rational request_fps;
+  request_fps.num = request_framerate.num;
+  request_fps.den = request_framerate.den;
+  return convert_return_type_(
+      cast_(handle)->SetDecodedVideoFrameRate(request_fps));
+}
+
+int esplusplayer_get_adaptive_info(
+    esplusplayer_handle handle, void* padaptive_info,
+    esplusplayer_adaptive_info_type adaptive_type) {
+  // LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(padaptive_info))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret = cast_(handle)->GetAdaptiveInfo(
+      padaptive_info, static_cast<PlayerAdaptiveInfo>(adaptive_type));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_volume(esplusplayer_handle handle, const int volume) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret = cast_(handle)->SetVolume(volume);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_get_volume(esplusplayer_handle handle, int* volume) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(volume))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret = cast_(handle)->GetVolume(volume);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_flush(esplusplayer_handle handle,
+                       esplusplayer_stream_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->Flush(static_cast<StreamType>(type));
+  return convert_return_type_(ret);
+}
+
+const char* esplusplayer_get_error_string(esplusplayer_error_type type) {
+  LOG_ENTER
+  return util::ConvertErrorTypeToString(type).c_str();
+}
+
+int esplusplayer_set_error_cb(esplusplayer_handle handle,
+                              esplusplayer_error_cb error_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->error_cb_ = error_cb;
+  listener->error_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_buffer_status_cb(
+    esplusplayer_handle handle, esplusplayer_buffer_status_cb buffer_status_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->buffer_status_cb_ = buffer_status_cb;
+  listener->buffer_status_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_buffer_byte_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_buffer_byte_status_cb buffer_status_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->buffer_byte_status_cb_ = buffer_status_cb;
+  listener->buffer_byte_status_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_buffer_time_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_buffer_time_status_cb buffer_status_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->buffer_time_status_cb_ = buffer_status_cb;
+  listener->buffer_time_status_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_buffer_size(esplusplayer_handle handle,
+                                 esplusplayer_buffer_option option,
+                                 uint64_t size) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO_P(cast_(handle), "option: %d, size: %lld", static_cast<int>(option),
+             size);
+  cast_(handle)->SetBufferSize(static_cast<plusplayer::BufferOption>(option),
+                               size);
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_resource_conflicted_cb(
+    esplusplayer_handle handle,
+    esplusplayer_resource_conflicted_cb resource_conflicted_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->resource_conflicted_cb_ = resource_conflicted_cb;
+  listener->resource_conflicted_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_eos_cb(esplusplayer_handle handle,
+                            esplusplayer_eos_cb eos_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->eos_cb_ = eos_cb;
+  listener->eos_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_ready_to_prepare_cb(
+    esplusplayer_handle handle,
+    esplusplayer_ready_to_prepare_cb ready_to_prepare_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->ready_to_prepare_cb_ = ready_to_prepare_cb;
+  listener->ready_to_prepare_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_prepare_async_done_cb(
+    esplusplayer_handle handle,
+    esplusplayer_prepare_async_done_cb prepare_async_done_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->prepare_async_done_cb_ = prepare_async_done_cb;
+  listener->prepare_async_done_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_seek_done_cb(esplusplayer_handle handle,
+                                  esplusplayer_seek_done_cb seek_done_cb,
+                                  void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->seek_done_cb_ = seek_done_cb;
+  listener->seek_done_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_ready_to_seek_cb(
+    esplusplayer_handle handle, esplusplayer_ready_to_seek_cb ready_to_seek_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  update_ready_to_seek_callback(handle, ready_to_seek_cb, userdata);
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_media_packet_video_decoded_cb(
+    esplusplayer_handle handle,
+    esplusplayer_media_packet_video_decoded_cb media_packet_video_decoded_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->media_packet_video_decoded_cb_ = media_packet_video_decoded_cb;
+  listener->media_packet_video_decoded_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_closed_caption_cb(
+    esplusplayer_handle handle,
+    esplusplayer_closed_caption_cb closed_caption_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->closed_caption_cb_ = closed_caption_cb;
+  listener->closed_caption_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_flush_done_cb(esplusplayer_handle handle,
+                                   esplusplayer_flush_done_cb flush_done_cb,
+                                   void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->flush_done_cb_ = flush_done_cb;
+  listener->flush_done_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_event_cb(esplusplayer_handle handle,
+                              esplusplayer_event_cb event_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  listener->event_cb_ = event_cb;
+  listener->event_cb_userdata_ = userdata;
+
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_first_video_decoding_done_cb(
+    esplusplayer_handle handle,
+    esplusplayer_first_video_decoding_done_cb first_video_decoding_done_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  listener->first_video_decoding_done_cb_ = first_video_decoding_done_cb;
+  listener->first_video_decoding_done_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_video_decoder_underrun_cb(
+    esplusplayer_handle handle,
+    esplusplayer_decoder_underrun_cb video_decoder_underrun_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  listener->video_decoder_underrun_cb_ = video_decoder_underrun_cb;
+  listener->video_decoder_underrun_cb_userdata_ = userdata;
+
+  return convert_return_type_(true);
+}
+int esplusplayer_set_video_latency_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_video_latency_status_cb video_latency_status_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->video_latency_status_cb_ = video_latency_status_cb;
+  listener->video_latency_status_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_audio_latency_status_cb(
+    esplusplayer_handle handle,
+    esplusplayer_audio_latency_status_cb audio_latency_status_cb,
+    void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->audio_latency_status_cb_ = audio_latency_status_cb;
+  listener->audio_latency_status_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_video_high_latency_cb(
+    esplusplayer_handle handle,
+    esplusplayer_video_high_latency_cb video_high_latency_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->video_high_latency_cb_ = video_high_latency_cb;
+  listener->video_high_latency_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_audio_high_latency_cb(
+    esplusplayer_handle handle,
+    esplusplayer_audio_high_latency_cb audio_high_latency_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("ESPlayer or Listener object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+
+  listener->audio_high_latency_cb_ = audio_high_latency_cb;
+  listener->audio_high_latency_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
+
+int esplusplayer_decoded_buffer_destroy(
+    esplusplayer_handle handle, esplusplayer_decoded_video_packet* packet) {
+  if (is_null_(handle)) {
+    LOG_ERROR("ESPlayer object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  auto priv = static_cast<EsPlusPlayerPriv*>(handle);
+  auto& mgr = priv->decoded_pkt_mgr;
+  if (mgr == nullptr) {
+    LOG_ERROR("DecodedPacketManager object is nil.");
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  mgr->Remove(packet);
+  return convert_return_type_(true);
+}
+
+int esplusplayer_set_low_latency_mode(esplusplayer_handle handle,
+                                      esplusplayer_low_latency_mode mode) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret =
+      cast_(handle)->SetLowLatencyMode(static_cast<PlayerLowLatencyMode>(mode));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_video_frame_peek_mode(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->SetVideoFramePeekMode();
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_render_video_frame(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->RenderVideoFrame();
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_unlimited_max_buffer_mode(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->SetUnlimitedMaxBufferMode();
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_fmm_mode(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->SetFmmMode();
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_audio_codec_type(esplusplayer_handle handle,
+                                      esplusplayer_audio_codec_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret =
+      cast_(handle)->SetAudioCodecType(static_cast<PlayerAudioCodecType>(type));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_aifilter(esplusplayer_handle handle, void* aifilter) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(aifilter))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->SetAiFilter(aifilter);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_video_codec_type(esplusplayer_handle handle,
+                                      esplusplayer_video_codec_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret =
+      cast_(handle)->SetVideoCodecType(static_cast<PlayerVideoCodecType>(type));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_alternative_video_resource(esplusplayer_handle handle,
+                                                unsigned int rsc_type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->SetAlternativeVideoResource(rsc_type);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_render_time_offset(esplusplayer_handle handle,
+                                        esplusplayer_stream_type type,
+                                        int64_t offset) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret =
+      cast_(handle)->SetRenderTimeOffset(static_cast<StreamType>(type), offset);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_get_render_time_offset(esplusplayer_handle handle,
+                                        esplusplayer_stream_type type,
+                                        int64_t* offset) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(offset))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret =
+      cast_(handle)->GetRenderTimeOffset(static_cast<StreamType>(type), offset);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_switch_audio_stream_onthefly(
+    esplusplayer_handle handle, esplusplayer_audio_stream_info* info) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(info))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto stream = convert_stream_ptr_(info);
+  auto ret = cast_(handle)->SwitchAudioStreamOnTheFly(std::move(stream));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_init_audio_easing_info(
+    esplusplayer_handle handle, uint32_t init_volume, uint32_t elapsed_time,
+    const esplusplayer_target_audio_easing_info* easing_info) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  if (easing_info == nullptr) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  AudioEasingInfo info;
+  info.target_volume = easing_info->volume;
+  info.duration = easing_info->duration;
+  info.type = static_cast<AudioEasingType>(easing_info->type);
+  auto ret =
+      cast_(handle)->InitAudioEasingInfo(init_volume, elapsed_time, info);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_update_audio_easing_info(
+    esplusplayer_handle handle,
+    const esplusplayer_target_audio_easing_info* easing_info) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  if (easing_info == nullptr) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  AudioEasingInfo info;
+  info.target_volume = easing_info->volume;
+  info.duration = easing_info->duration;
+  info.type = static_cast<AudioEasingType>(easing_info->type);
+
+  auto ret = cast_(handle)->UpdateAudioEasingInfo(info);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_get_audio_easing_info(
+    esplusplayer_handle handle, uint32_t* current_volume,
+    uint32_t* elapsed_time,
+    esplusplayer_target_audio_easing_info* easing_info) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  if (is_null_(current_volume) || is_null_(elapsed_time) ||
+      is_null_(easing_info))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  AudioEasingInfo info;
+  auto ret =
+      cast_(handle)->GetAudioEasingInfo(current_volume, elapsed_time, &info);
+  easing_info->volume = info.target_volume;
+  easing_info->duration = info.duration;
+  easing_info->type = static_cast<esplusplayer_audio_easing_type>(info.type);
+
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_start_audio_easing(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->StartAudioEasing();
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_stop_audio_easing(esplusplayer_handle handle) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  auto ret = cast_(handle)->StopAudioEasing();
+  return convert_return_type_(ret);
+}
+
+int get_size_of_esplusplayer_app_info(void) {
+  return sizeof(esplusplayer_app_info);
+}
+
+int get_size_of_esplusplayer_es_packet(void) {
+  return sizeof(esplusplayer_es_packet);
+}
+
+int get_size_of_esplusplayer_es_tz_packet(void) {
+  return sizeof(esplusplayer_es_tz_packet);
+}
+
+int get_size_of_esplusplayer_audio_stream_info(void) {
+  return sizeof(esplusplayer_audio_stream_info);
+}
+
+int get_size_of_esplusplayer_video_stream_info(void) {
+  return sizeof(esplusplayer_video_stream_info);
+}
+
+int get_size_of_esplusplayer_drm_info(void) {
+  return sizeof(esplusplayer_drm_info);
+}
+int esplusplayer_set_catch_up_speed(esplusplayer_handle handle,
+                                    esplusplayer_catch_up_speed level) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  if (level < ESPLUSPLAYER_CATCH_UP_SPEED_NONE ||
+      level > ESPLUSPLAYER_CATCH_UP_SPEED_FAST) {
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  auto ret = cast_(handle)->SetCatchUpSpeed(static_cast<CatchUpSpeed>(level));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_get_video_latency_status(esplusplayer_handle handle,
+                                          esplusplayer_latency_status* status) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(status))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  LatencyStatus current_status = LatencyStatus::kLow;
+  auto ret = cast_(handle)->GetVideoLatencyStatus(&current_status);
+  *status = static_cast<esplusplayer_latency_status>(current_status);
+
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_get_audio_latency_status(esplusplayer_handle handle,
+                                          esplusplayer_latency_status* status) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(status))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  LatencyStatus current_status = LatencyStatus::kLow;
+  auto ret = cast_(handle)->GetAudioLatencyStatus(&current_status);
+  *status = static_cast<esplusplayer_latency_status>(current_status);
+
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_video_mid_latency_threshold(esplusplayer_handle handle,
+                                                 const unsigned int threshold) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret = cast_(handle)->SetVideoMidLatencyThreshold(threshold);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_audio_mid_latency_threshold(esplusplayer_handle handle,
+                                                 const unsigned int threshold) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret = cast_(handle)->SetAudioMidLatencyThreshold(threshold);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_video_high_latency_threshold(
+    esplusplayer_handle handle, const unsigned int threshold,
+    esplusplayer_video_high_latency_cb video_high_latency_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  esplusplayer_set_video_high_latency_cb(handle, video_high_latency_cb,
+                                         userdata);
+
+  auto ret = cast_(handle)->SetVideoHighLatencyThreshold(threshold);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_audio_high_latency_threshold(
+    esplusplayer_handle handle, const unsigned int threshold,
+    esplusplayer_audio_high_latency_cb audio_high_latency_cb, void* userdata) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  esplusplayer_set_audio_high_latency_cb(handle, audio_high_latency_cb,
+                                         userdata);
+
+  auto ret = cast_(handle)->SetAudioHighLatencyThreshold(threshold);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_get_virtual_rsc_id(esplusplayer_handle handle,
+                                    const esplusplayer_rsc_type type,
+                                    int* virtual_id) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle) || is_null_(virtual_id))
+    return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret =
+      cast_(handle)->GetVirtualRscId(static_cast<RscType>(type), virtual_id);
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_advanced_picture_quality_type(
+    esplusplayer_handle handle,
+    esplusplayer_advanced_picture_quality_type type) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+
+  auto ret = cast_(handle)->SetAdvancedPictureQualityType(
+      static_cast<AdvPictureQualityType>(type));
+  return convert_return_type_(ret);
+}
+
+int esplusplayer_set_resource_allocate_policy(
+    esplusplayer_handle handle, esplusplayer_rsc_alloc_policy policy) {
+  LOG_ENTER_P(cast_(handle))
+  if (is_null_(handle)) return ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO("policy: %d", static_cast<int>(policy));
+
+  auto ret = cast_(handle)->SetResourceAllocatePolicy(
+      static_cast<RscAllocPolicy>(policy));
+  return convert_return_type_(ret);
+}
diff --git a/src/mixer/CMakeLists.txt b/src/mixer/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..85c8dee
--- /dev/null
@@ -0,0 +1,60 @@
+PROJECT(mixer)
+
+SET(fw_name "${PROJECT_NAME}")
+SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+SET(${fw_name}_LDFLAGS)
+
+SET(${fw_name}_CXXFLAGS "-Wall -Werror -std=c++11 -fPIC -Wl,-z,relro -fstack-protector")
+
+SET(dependents "dlog boost gstreamer-1.0 libtbm graphics-control")
+
+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(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
+  ${PARENT_DIR}/plusplayer-core/include_internal
+)
+
+SET(CC_SRCS
+  ${PROJECT_SOURCE_DIR}/src/mixer_capi.cpp
+  ${PROJECT_SOURCE_DIR}/src/mixer.cpp
+  ${PROJECT_SOURCE_DIR}/src/defaultmixer.cpp
+  ${PROJECT_SOURCE_DIR}/src/sys/tbminterface.cpp
+  ${PROJECT_SOURCE_DIR}/src/tizen/tizenaccessiblebufferobj.cpp
+  ${PROJECT_SOURCE_DIR}/src/tizen/tizenbufferkeyvideoframe.cpp
+  ${PROJECT_SOURCE_DIR}/src/tizen/tizendefaultphyaddraccessor.cpp
+  ${PROJECT_SOURCE_DIR}/src/tizen/tizenhwbufferobj.cpp
+  ${PROJECT_SOURCE_DIR}/src/tizen/tizenhwvideoframe.cpp
+  ${PROJECT_SOURCE_DIR}/src/tizen/tizenrenderableobj_factory.cpp
+  ${PROJECT_SOURCE_DIR}/src/tizen/tizensurfacevideoframe.cpp
+  ${PROJECT_SOURCE_DIR}/src/abs_videoframe.cpp
+  ${PROJECT_SOURCE_DIR}/src/mixedframe.cpp
+  ${PROJECT_SOURCE_DIR}/src/renderer.cpp
+  ${PROJECT_SOURCE_DIR}/src/videoplane.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})
+
+INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR})
+INSTALL(
+        DIRECTORY ${INC_DIR}/ DESTINATION include/
+)
diff --git a/src/mixer/include_internal/mixer/abs_videoframe.h b/src/mixer/include_internal/mixer/abs_videoframe.h
new file mode 100755 (executable)
index 0000000..1cedf89
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __PLUSPLAYER_ABSTRACT_MIXER_VIDEO_FRAME_H__
+#define __PLUSPLAYER_ABSTRACT_MIXER_VIDEO_FRAME_H__
+
+#include <memory>
+
+#include "mixer/interfaces/videoplanecollection.h"
+#include "mixer/interfaces/videoplanemanipulable.h"
+
+namespace plusplayer {
+
+class AbstractVideoFrame : public VideoPlaneCollection {
+ public:
+  using VideoPlaneManipulablePtr = std::unique_ptr<VideoPlaneManipulable>;
+
+ public:
+  explicit AbstractVideoFrame() = default;
+  virtual ~AbstractVideoFrame() = default;
+
+ public:
+  virtual const std::vector<VideoPlaneManipulableInfo> GetVideoPlaneManipInfo()
+      const override;
+
+  bool IsValid() const;
+  bool SetCropArea(const CropArea& croparea);
+  const std::uint32_t GetWidth() const;
+  const std::uint32_t GetHeight() const;
+
+ protected:
+  virtual bool IsValid_() const = 0;
+  virtual const std::uint32_t GetWidth_() const = 0;
+  virtual const std::uint32_t GetHeight_() const = 0;
+
+ protected:
+  void RegisterVideoPlaneManipulablePtr_(VideoPlaneManipulablePtr vpmanip);
+
+ private:
+  std::vector<VideoPlaneManipulablePtr> planes_;
+};
+}  // namespace plusplayer
+
+#endif
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/defaultmixer.h b/src/mixer/include_internal/mixer/defaultmixer.h
new file mode 100755 (executable)
index 0000000..364091d
--- /dev/null
@@ -0,0 +1,146 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_PLAYER_DEFAULTMIXER__H__
+#define __PLUSPLAYER_SRC_PLAYER_DEFAULTMIXER__H__
+
+#include <trackrenderer_capi/trackrenderer_capi.h>
+
+#include <cassert>
+#include <chrono>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/interfaces/videoplanecollection.h"
+#include "mixer/mixer.h"
+#include "mixer/mixerticket.h"
+#include "mixer/renderer.h"
+#include "mixer/tizen/tizenbuffermgr.h"
+
+namespace plusplayer {
+
+class DefaultMixer : public Mixer {
+ public:
+  using RendererPtr = std::unique_ptr<Renderer>;
+
+ public:
+  DefaultMixer();
+  ~DefaultMixer();
+
+  bool Start() override;
+  bool Stop() override;
+  int GetMaximumAllowedNumberOfPlayer() override;
+  bool SetDisplay(const DisplayType type, void* obj) override;
+  bool SetDisplay(const DisplayType type, const uint32_t surface_id,
+                  const int x, const int y, const int w, const int h) override;
+  bool SetDisplayMode(const DisplayMode& mode) override;
+  bool SetDisplayRoi(const Geometry& geometry) override;
+  bool DisableAudioFocusSetting() override;
+  bool SetAlternativeVideoScaler() override;
+  bool SetAudioFocus(const void* player_instance) override;
+  bool SetRscAllocMode(const RscAllocMode& mode) override;
+  bool Commit() override;
+  bool SetResolution(const ResolutionInfo& info) override;
+  bool RegisterListener(MixerEventListener* listener) override;
+  MixerTicket* CreateTicket(const void* player_instance) override;
+
+  class Ticket : public MixerTicket {
+   public:
+    explicit Ticket(DefaultMixer* handler, const void* player_instance)
+        : handler_(handler), player_instance_(player_instance) {
+      assert(handler);
+    }
+    ~Ticket();
+    bool GetAvailableResourceType(const ResourceCategory& category,
+                                  ResourceType* type) override;
+    bool Alloc(const ResourceCategory& category,
+               const ResourceType& type) override;
+    bool Render(const DecodedRawInfo& info) override;
+    bool Render(const DecodedVideoKeyTypeInfo& info) override;
+    bool RegisterListener(MixerTicketEventListener* listener) override;
+    bool Prepare() override;
+    bool IsAudioFocusHandler() override;
+    bool IsRscAllocHandler() override;
+
+    // interface for defaultmixer
+    MixerTicketEventListener* GetListener();
+    bool IsAudioFocused();
+    void SetAudioFocus(bool active);
+    void GetDisplayInfo(DisplayInfo* info);
+    bool HasRenderedBefore();
+    void UpdateDisplayInfo(const DisplayInfo& info);
+    void DeallocResource();
+    void RecordRenderingTime();
+
+   private:
+    DefaultMixer* handler_ = nullptr;
+    const void* player_instance_ = nullptr;
+    MixerTicketEventListener* ticket_listener_ = nullptr;
+    bool is_audio_focus_ = false;
+    DisplayInfo each_display_info_;
+    bool has_rendered_ = false;
+    std::chrono::system_clock::time_point last_rendering_time_;
+  };
+
+ private:
+  struct Resource {
+    ResourceCategory category = ResourceCategory::kVideoDecoder;
+    ResourceType type = ResourceType::kHwMain;
+    const void* assignee = nullptr;
+  };
+
+  class MixerRendererEventListener : public RendererEventListener {
+   public:
+    explicit MixerRendererEventListener(TrackRendererHandle* trhandle_ptr);
+    virtual ~MixerRendererEventListener();
+    virtual bool OnRenderingRelease(const BufferKeyType& key) override;
+
+   private:
+    void* CreateGstBuffer_(const BufferKeyType& key) const;
+    void FillDecoderInputBuffer_(TrackRendererDecoderInputBuffer& buffer,
+                                 const BufferKeyType& key) const;
+
+   private:
+    TrackRendererHandle* trhandle_ptr_;
+  };
+
+ private:
+  bool Detach_(const void* player_instance);
+  bool GetAvailableResourceType_();
+  bool Render_(const void* player_instance,
+               const VideoPlaneCollection& vplanes);
+  bool RegisterListener_();
+  void InitResourceList_();
+  bool IsNeededToSkipRendering_(const DisplayInfo& display_info);
+
+  using UserData = void*;
+  static void ResourceConflictCb_(UserData userdata);
+  static void ErrorCb_(const TrackRendererErrorType error_code,
+                       UserData userdata);
+
+ private:
+  std::map<const void*, Ticket*> player_map_;
+  std::mutex mixer_lock_;
+  std::mutex ticket_lock_;
+  bool is_started_ = false;
+  MixerEventListener* listener_ = nullptr;
+  TrackRendererHandle trackrenderer_handle_ = nullptr;
+  const void* audio_focused_player_ = nullptr;
+  ResolutionInfo whole_resolution_;
+  std::list<Resource> resource_list_;
+  bool enable_audio_focus_setting_ = true;
+  RscAllocMode resource_allocation_mode_ = RscAllocMode::kDefault;
+  bool use_sub_scaler_ = false;
+  RendererPtr renderer_;
+  MixerRendererEventListener renderer_listener_;
+  TizenBufferManager bufmgr_;
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_PLAYER_DEFAULTMIXER__H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/accessiblebuffer.h b/src/mixer/include_internal/mixer/interfaces/accessiblebuffer.h
new file mode 100755 (executable)
index 0000000..aa4a9b8
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_ACCESSIBLE_BUFFER_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_ACCESSIBLE_BUFFER_H__
+
+#include <memory>
+
+#include "mixer/interfaces/bufferobject.h"
+#include "mixer/interfaces/phyaddraccessor.h"
+
+namespace plusplayer {
+struct AccessibleBuffer {
+  using PhyAddrAccessorPtr = std::unique_ptr<PhysicalAddressAccessor>;
+
+  virtual ~AccessibleBuffer() = default;
+  virtual PhyAddrAccessorPtr GetReadableAddress() const = 0;
+  virtual PhyAddrAccessorPtr GetWritableAddress() const = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_ACCESSIBLE_BUFFER_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/bufferobject.h b/src/mixer/include_internal/mixer/interfaces/bufferobject.h
new file mode 100755 (executable)
index 0000000..a08fbda
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_BUFFER_OBJECT_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_BUFFER_OBJECT_H__
+
+#include "mixer/types/buffertype.h"
+
+namespace plusplayer {
+struct BufferObject {
+  virtual ~BufferObject() = default;
+
+  virtual BufferHandleType GetBufferHandle() const = 0;
+  virtual BufferKeyType Export() const = 0;
+  virtual std::uint32_t GetSize() const = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_BUFFER_OBJECT_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/memoryallocator.h b/src/mixer/include_internal/mixer/interfaces/memoryallocator.h
new file mode 100755 (executable)
index 0000000..7446a60
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_MEMORY_OPERATOR_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_MEMORY_OPERATOR_H__
+
+#include <cstdint>
+#include <memory>
+
+#include "mixer/interfaces/bufferobject.h"
+#include "mixer/types/buffertype.h"
+
+namespace plusplayer {
+
+struct MemoryAllocator {
+  virtual ~MemoryAllocator() = default;
+  virtual BufferObject* Allocate(const std::uint32_t& size) const = 0;
+};
+}  // namespace plusplayer
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_MEMORY_OPERATOR_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/phyaddraccessor.h b/src/mixer/include_internal/mixer/interfaces/phyaddraccessor.h
new file mode 100755 (executable)
index 0000000..d50593b
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_PHYSICAL_ADDRESS_ACCESSOR_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_PHYSICAL_ADDRESS_ACCESSOR_H__
+
+#include "mixer/types/buffertype.h"
+
+namespace plusplayer {
+struct PhysicalAddressAccessor {
+  virtual ~PhysicalAddressAccessor() = default;
+  virtual BufferPhysicalAddrType GetAddress() = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_PHYSICAL_ADDRESS_ACCESSOR_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/renderableobj_factory.h b/src/mixer/include_internal/mixer/interfaces/renderableobj_factory.h
new file mode 100755 (executable)
index 0000000..ec7ea9b
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_RENDERABLE_OBJECT_FACTORY_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_RENDERABLE_OBJECT_FACTORY_H__
+
+#include "mixer/interfaces/renderableobject.h"
+
+namespace plusplayer {
+struct RenderableObjectFactory {
+  virtual ~RenderableObjectFactory() = default;
+  virtual RenderableObject* CreateRenderableObject(
+      const std::uint32_t width, const std::uint32_t height) const = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_RENDERABLE_OBJECT_FACTORY_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/renderableobject.h b/src/mixer/include_internal/mixer/interfaces/renderableobject.h
new file mode 100755 (executable)
index 0000000..ccdb598
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_RENDERABLE_OBJECT_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_RENDERABLE_OBJECT_H__
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "mixer/interfaces/videoplanemanipulator.h"
+#include "mixer/types/buffertype.h"
+#include "mixer/types/planecomponent.h"
+#include "mixer/types/videoplanemanipinfo.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+struct RenderableObject {
+  using Ptr = std::unique_ptr<RenderableObject>;
+  virtual ~RenderableObject() = default;
+  virtual bool IsValid() const = 0;
+  virtual std::uint32_t GetWidth() const = 0;
+  virtual std::uint32_t GetHeight() const = 0;
+  virtual std::uint32_t GetSize() const = 0;
+  virtual bool Render(const VideoPlaneManipulator* const vpmanip,
+                      const std::vector<VideoPlaneManipulableInfo>& planes,
+                      const Geometry& geom) = 0;
+  virtual bool Fill(const VideoPlaneColorManipulator* const vpmanip,
+                    const PlaneComponent& comp, const std::uint32_t& color,
+                    const Geometry& geom) = 0;
+  virtual bool Export(BufferKeyType& key) const = 0;
+};
+using RenderableObjectPtr = RenderableObject::Ptr;
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_RENDERABLE_OBJECT_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/videoplanecollection.h b/src/mixer/include_internal/mixer/interfaces/videoplanecollection.h
new file mode 100755 (executable)
index 0000000..e0bb422
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COLLECTION_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COLLECTION_H__
+
+#include <vector>
+
+#include "mixer/types/videoplanemanipinfo.h"
+
+namespace plusplayer {
+struct VideoPlaneCollection {
+  virtual ~VideoPlaneCollection() = default;
+  virtual const std::vector<VideoPlaneManipulableInfo> GetVideoPlaneManipInfo()
+      const = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COLLECTION_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/videoplanecolorfiller.h b/src/mixer/include_internal/mixer/interfaces/videoplanecolorfiller.h
new file mode 100755 (executable)
index 0000000..b35b610
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COLOR_FILLER_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COLOR_FILLER_H__
+
+#include <memory>
+
+#include "mixer/interfaces/videoplanemanipulator.h"
+#include "mixer/types/planecomponent.h"
+
+namespace plusplayer {
+struct VideoPlaneColorFiller {
+  virtual ~VideoPlaneColorFiller() = default;
+  virtual const VideoPlaneColorManipulator* const GetColorFillManipulator()
+      const = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COLOR_FILLER_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/videoplanecopier.h b/src/mixer/include_internal/mixer/interfaces/videoplanecopier.h
new file mode 100755 (executable)
index 0000000..b27dead
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COPIER_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COPIER_H__
+
+#include "mixer/interfaces/videoplanemanipulator.h"
+
+namespace plusplayer {
+struct VideoPlaneCopier {
+  virtual ~VideoPlaneCopier() = default;
+  virtual const VideoPlaneManipulator* const GetCopyManipulator() const = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_COPIER_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/videoplanemanipulable.h b/src/mixer/include_internal/mixer/interfaces/videoplanemanipulable.h
new file mode 100755 (executable)
index 0000000..6bb20f0
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_MANIPULABLE_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_MANIPULABLE_H__
+
+#include "mixer/types/videoplanemanipinfo.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+
+struct VideoPlaneManipulable {
+  virtual ~VideoPlaneManipulable() = default;
+  virtual bool IsValid() const = 0;
+  virtual VideoPlaneManipulableInfo GetVideoPlaneManipulableInfo() const = 0;
+  virtual void SetCropArea(const CropArea& croparea) = 0;
+};
+
+}  // namespace plusplayer
+
+#endif  //__PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_MANIPULABLE_H__
diff --git a/src/mixer/include_internal/mixer/interfaces/videoplanemanipulator.h b/src/mixer/include_internal/mixer/interfaces/videoplanemanipulator.h
new file mode 100755 (executable)
index 0000000..3ddc760
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_MANIPULATOR_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_MANIPULATOR_H__
+
+#include <cstdint>
+
+#include "mixer/types/planecomponent.h"
+#include "mixer/types/videoplanemanipinfo.h"
+
+namespace plusplayer {
+
+template <typename T>
+struct VideoPlaneManipulatorWithType {
+  virtual bool Do(const T&, const VideoPlaneManipulableInfo&) const = 0;
+};
+
+using VideoPlaneManipulator =
+    VideoPlaneManipulatorWithType<VideoPlaneManipulableInfo>;
+
+using VideoPlaneColorManipulator = VideoPlaneManipulatorWithType<std::uint32_t>;
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_MANIPULATOR_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/interfaces/videoplanescaler.h b/src/mixer/include_internal/mixer/interfaces/videoplanescaler.h
new file mode 100755 (executable)
index 0000000..c1aae57
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_SCALER_H__
+#define __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_SCALER_H__
+
+#include "mixer/interfaces/videoplanemanipulator.h"
+
+namespace plusplayer {
+struct VideoPlaneScaler {
+  virtual ~VideoPlaneScaler() = default;
+  virtual const VideoPlaneManipulator* const GetScaleManipulator() const = 0;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_INTERFACES_VIDEO_PLANE_SCALER_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/mixedframe.h b/src/mixer/include_internal/mixer/mixedframe.h
new file mode 100755 (executable)
index 0000000..a2e6c3c
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef __PLUSPLAYER_MIXER_MIXED_FRAME_H__
+#define __PLUSPLAYER_MIXER_MIXED_FRAME_H__
+
+#include <cstdint>
+#include <memory>
+
+#include "mixer/interfaces/memoryallocator.h"
+#include "mixer/interfaces/renderableobject.h"
+#include "mixer/interfaces/videoplanecollection.h"
+#include "mixer/interfaces/videoplanemanipulator.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+class MixedFrame : public VideoPlaneCollection, public RenderableObject {
+ public:
+  using Ptr = std::unique_ptr<MixedFrame>;
+  using BufferObjectPtr = std::unique_ptr<BufferObject>;
+
+ public:
+  static Ptr Create(const MemoryAllocator* const memop,
+                    const std::uint32_t width, const std::uint32_t height);
+
+ public:
+  explicit MixedFrame(const MemoryAllocator* const memop,
+                      const std::uint32_t width, const std::uint32_t height);
+  virtual ~MixedFrame() = default;
+
+ public:
+  virtual const std::vector<VideoPlaneManipulableInfo> GetVideoPlaneManipInfo()
+      const override;
+
+ public:
+  virtual bool IsValid() const override;
+  virtual std::uint32_t GetWidth() const override;
+  virtual std::uint32_t GetHeight() const override;
+  virtual std::uint32_t GetSize() const override;
+  virtual bool Render(const VideoPlaneManipulator* const vpmanip,
+                      const std::vector<VideoPlaneManipulableInfo>& planes,
+                      const Geometry& geom) override;
+  virtual bool Fill(const VideoPlaneColorManipulator* const vpmanip,
+                    const PlaneComponent& comp, const std::uint32_t& color,
+                    const Geometry& geom) override;
+  virtual bool Export(BufferKeyType& key) const override;
+
+ private:
+  std::uint32_t CalculateBufferSize_(const std::uint32_t width,
+                                     const std::uint32_t height);
+  VideoPlaneManipulableInfo GetMixedFrameVideoPlaneManipulableInfo_(
+      const PlaneComponent component, const Geometry& geom);
+  VideoPlaneManipulableInfo GetYComponentVMInfo_(BufferHandleType handle) const;
+  VideoPlaneManipulableInfo GetUVComponentVMInfo_(
+      BufferHandleType handle) const;
+
+ private:
+  const std::uint32_t width_ = 0;
+  const std::uint32_t height_ = 0;
+  mutable std::uint32_t allocated_size_ = 0;
+  BufferObjectPtr buffer_ = nullptr;
+};
+using MixedFramePtr = MixedFrame::Ptr;
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_MIXED_FRAME_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/renderer.h b/src/mixer/include_internal/mixer/renderer.h
new file mode 100755 (executable)
index 0000000..cc326b1
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef __PLUSPLAYER_MIXER_RENDERER_H__
+#define __PLUSPLAYER_MIXER_RENDERER_H__
+
+#include <chrono>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include "mixer/interfaces/renderableobj_factory.h"
+#include "mixer/interfaces/videoplanecollection.h"
+#include "mixer/interfaces/videoplanecolorfiller.h"
+#include "mixer/interfaces/videoplanescaler.h"
+#include "mixer/mixer.h"
+#include "mixer/types/buffertype.h"
+#include "mixer/types/videoplanemoveinfo.h"
+
+namespace plusplayer {
+
+struct RendererEventListener {
+  virtual bool OnRenderingRelease(const BufferKeyType&) = 0;
+};
+
+class Renderer {
+ private:
+  using JitterType = std::chrono::duration<std::int64_t, std::milli>;
+
+ public:
+  explicit Renderer(const RenderableObjectFactory& mf_factory,
+                    const Mixer::ResolutionInfo& rinfo,
+                    RendererEventListener* listener);
+  virtual ~Renderer();
+
+ public:
+  bool IsValid() const;
+  bool Start();
+  bool Stop();
+  bool ChangeResolution(const RenderableObjectFactory& mf_factory,
+                        const std::uint32_t& width,
+                        const std::uint32_t& height);
+  bool ChangeRenderingSpeed(const std::uint32_t framerate_num,
+                            const std::uint32_t framerate_den);
+
+  bool Render(const VideoPlaneScaler* const scaler,
+              const VideoPlaneCollection* const planes, const Geometry& geom);
+  bool Mute(const VideoPlaneColorFiller* const filler, const Geometry& geom);
+  bool Move(const VideoPlaneColorFiller* const filler,
+            const std::vector<VideoPlaneMoveInfo>& moving_planes);
+
+ protected:
+  virtual bool ChangeResolutionInternal_(
+      const RenderableObjectFactory& mf_factory, const std::uint32_t& width,
+      const std::uint32_t& height);
+  virtual bool RenderInternal_(
+      const VideoPlaneManipulator* const vpmanip,
+      const std::vector<VideoPlaneManipulableInfo>& planes,
+      const Geometry& geom);
+  virtual bool MuteInternal_(const VideoPlaneColorManipulator* const filler,
+                             const Geometry& geom);
+  virtual bool MoveInternal_(
+      const VideoPlaneColorManipulator* const filler,
+      const std::vector<VideoPlaneMoveInfo>& moving_planes);
+  virtual bool OnRenderingBefore_(const RenderableObject* const frame);
+  virtual bool IsValid_() const;
+
+  std::uint32_t GetNextRenderingTimeWithJitter_(const JitterType& jitter) const;
+  const Mixer::ResolutionInfo& GetResolutionInfo_() const;
+  RenderableObjectPtr& GetMixedFrame_();
+  void AcquireRenderingLock_();
+  void ReleaseRenderingLock_();
+
+ private:
+  bool RaiseOnRenderingReleaseEvent_(const BufferKeyType& key);
+  void RenderingWorker_();
+
+ protected:
+  static Geometry MakeGeometry_(const std::uint32_t& width,
+                                const std::uint32_t& height);
+  static bool IsSameGeometry_(const Geometry& g1, const Geometry& g2);
+
+ private:
+  Mixer::ResolutionInfo resolution_info_;
+  RendererEventListener* listener_ = nullptr;
+  RenderableObjectPtr frame_ = nullptr;
+
+  bool rendering_flag_ = false;
+  std::mutex rendering_mtx_;
+  std::condition_variable rendering_cv_;
+  std::thread rendering_worker_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_RENDERER_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/rendererwithdoublebuf.h b/src/mixer/include_internal/mixer/rendererwithdoublebuf.h
new file mode 100755 (executable)
index 0000000..b6597ff
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef __PLUSPLAYER_MIXER_RENDERER_WITH_DOUBLE_BUFFERING_H__
+#define __PLUSPLAYER_MIXER_RENDERER_WITH_DOUBLE_BUFFERING_H__
+
+#include <boost/scope_exit.hpp>
+#include <chrono>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/interfaces/videoplanecopier.h"
+#include "mixer/interfaces/videoplanescaler.h"
+#include "mixer/mixedframe.h"
+#include "mixer/renderer.h"
+
+namespace plusplayer {
+
+class RendererWithDoubleBuffer : public Renderer {
+ public:
+  explicit RendererWithDoubleBuffer(const RenderableObjectFactory& mf_factory,
+                                    const VideoPlaneCopier* const vpcopier,
+                                    const VideoPlaneScaler* const vpscaler,
+                                    const Mixer::ResolutionInfo& rinfo,
+                                    RendererEventListener* listener)
+      : Renderer(mf_factory, rinfo, listener),
+        frame_(MixedFramePtr(dynamic_cast<MixedFrame*>(
+            mf_factory.CreateRenderableObject(rinfo.width, rinfo.height)))),
+        vpcopier_(vpcopier),
+        vpscaler_(vpscaler) {}
+  virtual ~RendererWithDoubleBuffer() = default;
+
+ protected:
+  virtual bool OnRenderingBefore_(
+      const RenderableObject* const frame) override {
+    // auto before = std::chrono::system_clock::now();
+    std::unique_lock<std::mutex> lk(rendering_mtx_);
+    if (IsValid() == false) return false;
+    // LOG_INFO("[PERF] OnRenderingBefore_ Lock [%llu]ms",
+    //          std::chrono::duration_cast<std::chrono::milliseconds>(
+    //              std::chrono::system_clock::now() - before)
+    //              .count());
+    const auto& rinfo = GetResolutionInfo_();
+    auto ret = GetMixedFrame_()->Render(
+        vpcopier_->GetCopyManipulator(), frame_->GetVideoPlaneManipInfo(),
+        MakeGeometry_(rinfo.width, rinfo.height));
+    // LOG_INFO("[PERF] Copy [%llu]ms",
+    //          std::chrono::duration_cast<std::chrono::milliseconds>(
+    //              std::chrono::system_clock::now() - before)
+    //              .count());
+    return ret;
+  }
+
+  virtual bool ChangeResolutionInternal_(
+      const RenderableObjectFactory& mf_factory, const std::uint32_t& width,
+      const std::uint32_t& height) override {
+    {
+      std::unique_lock<std::mutex> lk(rendering_mtx_);
+      frame_.reset(nullptr);
+      frame_ = MixedFramePtr(dynamic_cast<MixedFrame*>(
+          mf_factory.CreateRenderableObject(width, height)));
+    }
+    return Renderer::ChangeResolutionInternal_(mf_factory, width, height);
+  }
+
+  virtual bool RenderInternal_(
+      const VideoPlaneManipulator* const scaler,
+      const std::vector<VideoPlaneManipulableInfo>& planes,
+      const Geometry& geom) override {
+    if (scaler == nullptr) return false;
+    auto before = std::chrono::system_clock::now();
+    std::unique_lock<std::mutex> lk(rendering_mtx_);
+    if (IsValid() == false) return false;
+    auto ret = frame_->Render(scaler, planes, geom);
+    LOG_INFO("[PERF] Scale [%llu]ms",
+             std::chrono::duration_cast<std::chrono::milliseconds>(
+                 std::chrono::system_clock::now() - before)
+                 .count());
+    return ret;
+  }
+
+  virtual bool MuteInternal_(const VideoPlaneColorManipulator* const filler,
+                             const Geometry& geom) override {
+    if (filler == nullptr) return false;
+    std::unique_lock<std::mutex> lk(rendering_mtx_);
+    if (IsValid() == false) return false;
+    bool ret = true;
+    LOG_INFO("MUTE REGION (%d, %d, %d x %d)", geom.x, geom.y, geom.w, geom.h);
+    ret &= frame_->Fill(filler, PlaneComponent::kYComponent, 0x00, geom);
+    ret &= frame_->Fill(filler, PlaneComponent::kUVComponent, 0x8080, geom);
+    return ret;
+  }
+
+  virtual bool MoveInternal_(
+      const VideoPlaneColorManipulator* const filler,
+      const std::vector<VideoPlaneMoveInfo>& moving_planes) override {
+    if (filler == nullptr) return false;
+
+    AcquireRenderingLock_();
+    BOOST_SCOPE_EXIT(this_) { this_->ReleaseRenderingLock_(); }
+    BOOST_SCOPE_EXIT_END
+
+    std::unique_lock<std::mutex> lk(rendering_mtx_);
+    if (IsValid() == false) return false;
+
+    auto* mixedframe = dynamic_cast<MixedFrame*>(GetMixedFrame_().get());
+    if (mixedframe == nullptr) return false;
+
+    const auto planes = mixedframe->GetVideoPlaneManipInfo();
+    if (planes.size() != 2) return false;
+
+    const auto& rinfo = GetResolutionInfo_();
+
+    auto fullgeom = MakeGeometry_(rinfo.width, rinfo.height);
+    bool ret = true;
+    ret &= frame_->Fill(filler, PlaneComponent::kYComponent, 0x00, fullgeom);
+    ret &= frame_->Fill(filler, PlaneComponent::kUVComponent, 0x8080, fullgeom);
+    auto* scaler = vpscaler_->GetScaleManipulator();
+    for (const auto& move : moving_planes) {
+      VideoPlaneManipulableInfo y_manipinfo = planes[0];
+      VideoPlaneManipulableInfo uv_manipinfo = planes[1];
+      y_manipinfo.rect = move.cur;
+      uv_manipinfo.rect = move.cur;
+      uv_manipinfo.rect.x /= 2;
+      uv_manipinfo.rect.y /= 2;
+      uv_manipinfo.rect.w /= 2;
+      uv_manipinfo.rect.h /= 2;
+      uv_manipinfo.rect.y += rinfo.height;
+      LOG_INFO("MOVE (%d, %d, %d x %d) -> (%d, %d, %d x %d)", move.cur.x,
+               move.cur.y, move.cur.w, move.cur.h, move.target.x, move.target.y,
+               move.target.w, move.target.h);
+      ret &= frame_->Render(scaler, {y_manipinfo, uv_manipinfo}, move.target);
+    }
+    return true;
+  };
+
+  virtual bool IsValid_() const override {
+    if (frame_ == nullptr) return false;
+    if (frame_->IsValid() == false) return false;
+    if (vpcopier_ == nullptr || vpscaler_ == nullptr) return false;
+    if (vpcopier_->GetCopyManipulator() == nullptr) return false;
+    if (vpscaler_->GetScaleManipulator() == nullptr) return false;
+    return true;
+  }
+
+ private:
+  MixedFramePtr frame_ = nullptr;
+  const VideoPlaneCopier* const vpcopier_ = nullptr;
+  const VideoPlaneScaler* const vpscaler_ = nullptr;
+
+  std::mutex rendering_mtx_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_RENDERER_WITH_DOUBLE_BUFFERING_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/sys/tbminterface.h b/src/mixer/include_internal/mixer/sys/tbminterface.h
new file mode 100755 (executable)
index 0000000..2273a63
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __PLUSPLAYER_MIXER_SYS_TBM_INTERFACE_H__
+#define __PLUSPLAYER_MIXER_SYS_TBM_INTERFACE_H__
+
+#include <capi-graphics-control.h>
+
+#include "mixer/types/buffertype.h"
+
+namespace plusplayer {
+namespace tizen {
+class TBMInterface {
+ public:
+  static BufferDefaultType BoRef(BufferDefaultType bo);
+  static void BoUnRef(BufferDefaultType bo);
+  static int BoSize(BufferDefaultType bo);
+  static BufferUnionHandleType BoGetHandle(BufferDefaultType bo, int device);
+  static BufferUnionHandleType BoMap(BufferDefaultType bo, int device,
+                                     int option);
+  static void BoUnmap(BufferDefaultType bo);
+  static BufferKeyType BoExport(BufferDefaultType bo);
+  static BufferDefaultType BoAlloc(tbm_bufmgr bufmgr, int size, int flag);
+  static BufferDefaultType BoImport(tbm_bufmgr bufmgr, BufferKeyType key);
+  static int GAScale(tbm_bufmgr bufmgr, GraphicsGAScaleInfo* info);
+  static int GACopy(tbm_bufmgr bufmgr, GraphicsGABltRopInfo* info);
+  static int GAFill(tbm_bufmgr bufmgr, GraphicsGAFillRectInfo* info);
+};
+}  // namespace tizen
+}  // namespace plusplayer
+
+#endif  //__PLUSPLAYER_MIXER_SYS_TBM_INTERFACE_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenaccessiblebufferobj.h b/src/mixer/include_internal/mixer/tizen/tizenaccessiblebufferobj.h
new file mode 100755 (executable)
index 0000000..84d9d5d
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_TIZEN_ACCESSIBLE_BUFFER_OBJECT_H__
+#define __PLUSPLAYER_MIXER_TIZEN_TIZEN_ACCESSIBLE_BUFFER_OBJECT_H__
+
+#include "mixer/interfaces/accessiblebuffer.h"
+#include "mixer/tizen/tizenbufferobj.h"
+#include "mixer/tizen/tizenbufferphyaddraccessor.h"
+
+namespace plusplayer {
+class TizenAccessibleBufferObject : public TizenBufferObject,
+                                    public AccessibleBuffer {
+ public:
+  explicit TizenAccessibleBufferObject(BufferDefaultType buffer);
+  virtual ~TizenAccessibleBufferObject() = default;
+  virtual PhyAddrAccessorPtr GetReadableAddress() const override;
+  virtual PhyAddrAccessorPtr GetWritableAddress() const override;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_TIZEN_ACCESSIBLE_BUFFER_OBJECT_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenbufferkeyvideoframe.h b/src/mixer/include_internal/mixer/tizen/tizenbufferkeyvideoframe.h
new file mode 100755 (executable)
index 0000000..f9f5f56
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_BUFFER_KEY_VIDEO_SURFACE_H__
+#define __PLUSPLAYER_MIXER_TIZEN_BUFFER_KEY_VIDEO_SURFACE_H__
+
+#include <memory>
+
+#include "mixer/abs_videoframe.h"
+#include "mixer/interfaces/bufferobject.h"
+#include "mixer/tizen/tizenbuffermgr.h"
+#include "mixer/videoplane.h"
+
+namespace plusplayer {
+
+class TizenBufferKeyVideoFrame : public AbstractVideoFrame {
+ public:
+  using BufferObjectPtr = std::shared_ptr<BufferObject>;
+
+ public:
+  explicit TizenBufferKeyVideoFrame(const TizenBufferManager* const bufmgr,
+                                    const BufferKeyType& key,
+                                    const std::uint32_t& width,
+                                    const std::uint32_t& height);
+  virtual ~TizenBufferKeyVideoFrame() = default;
+
+ protected:
+  virtual bool IsValid_() const override;
+  virtual const std::uint32_t GetWidth_() const override;
+  virtual const std::uint32_t GetHeight_() const override;
+
+ private:
+  const BufferKeyType key_;
+  const std::uint32_t width_;
+  const std::uint32_t height_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_BUFFER_KEY_VIDEO_SURFACE_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenbuffermgr.h b/src/mixer/include_internal/mixer/tizen/tizenbuffermgr.h
new file mode 100755 (executable)
index 0000000..855112c
--- /dev/null
@@ -0,0 +1,289 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_BUFFER_MANAGER_H__
+#define __PLUSPLAYER_MIXER_TIZEN_BUFFER_MANAGER_H__
+
+#include <cstring>
+
+#include "mixer/interfaces/memoryallocator.h"
+#include "mixer/interfaces/videoplanecolorfiller.h"
+#include "mixer/interfaces/videoplanecopier.h"
+#include "mixer/interfaces/videoplanemanipulator.h"
+#include "mixer/interfaces/videoplanescaler.h"
+#include "mixer/sys/tbminterface.h"
+#include "mixer/tizen/tizenaccessiblebufferobj.h"
+#include "mixer/types/videoplanemanipinfo.h"
+
+namespace {
+struct GlobalInstance {
+  tbm_bufmgr bufmgr;
+  GlobalInstance() { bufmgr = tbm_bufmgr_init(-1); }
+  ~GlobalInstance() {
+    if (bufmgr) tbm_bufmgr_deinit(bufmgr);
+  }
+};
+static const GlobalInstance kGlobalInstance;
+}  // namespace
+
+namespace plusplayer {
+template <typename TBM>
+class BufferManagerWithType : public MemoryAllocator,
+                              public VideoPlaneScaler,
+                              public VideoPlaneCopier,
+                              public VideoPlaneColorFiller {
+ public:
+  class Scaler : public VideoPlaneManipulator {
+   public:
+    explicit Scaler(const BufferManagerWithType* const bufmgr);
+    virtual ~Scaler() = default;
+    virtual bool Do(const VideoPlaneManipulableInfo& src,
+                    const VideoPlaneManipulableInfo& dest) const override;
+
+   private:
+    const BufferManagerWithType* const bufmgr_;
+  };
+  class Copier : public VideoPlaneManipulator {
+   public:
+    explicit Copier(const BufferManagerWithType* const bufmgr);
+    virtual ~Copier() = default;
+    virtual bool Do(const VideoPlaneManipulableInfo& src,
+                    const VideoPlaneManipulableInfo& dest) const override;
+
+   private:
+    const BufferManagerWithType* const bufmgr_;
+  };
+  class ColorFiller : public VideoPlaneColorManipulator {
+   public:
+    explicit ColorFiller(const BufferManagerWithType* const bufmgr);
+    virtual ~ColorFiller() = default;
+    virtual bool Do(const std::uint32_t& color,
+                    const VideoPlaneManipulableInfo& dest) const override;
+
+   private:
+    const BufferManagerWithType* const bufmgr_;
+  };
+
+ public:
+  explicit BufferManagerWithType();
+  virtual ~BufferManagerWithType() = default;
+
+ public:
+  virtual BufferObject* Allocate(const std::uint32_t& size) const override;
+  virtual const VideoPlaneManipulator* const GetScaleManipulator()
+      const override;
+  virtual const VideoPlaneManipulator* const GetCopyManipulator()
+      const override;
+  virtual const VideoPlaneColorManipulator* const GetColorFillManipulator()
+      const override;
+  bool IsValid() const;
+  BufferObject* Import(BufferHandleType handle) const;
+
+ protected:
+  bool Copy_(const VideoPlaneManipulableInfo& src,
+             const VideoPlaneManipulableInfo& dst) const;
+  bool Scale_(const VideoPlaneManipulableInfo& src,
+              const VideoPlaneManipulableInfo& dst) const;
+  bool Fill_(const std::uint32_t color,
+             const VideoPlaneManipulableInfo& dst) const;
+
+ private:
+  tbm_bufmgr bufmgr_;
+  Scaler scaler_;
+  Copier copier_;
+  ColorFiller color_filler_;
+};
+
+using TizenBufferManager = BufferManagerWithType<tizen::TBMInterface>;
+
+/******************************************************************************
+ * Body
+ */
+template <typename TBM>
+BufferManagerWithType<TBM>::BufferManagerWithType()
+    : scaler_(this), copier_(this), color_filler_(this) {
+  bufmgr_ = ::kGlobalInstance.bufmgr;
+}
+
+template <typename TBM>
+BufferObject* BufferManagerWithType<TBM>::Allocate(
+    const std::uint32_t& size) const {
+  if (size == 0) return nullptr;
+  if (IsValid() == false) return nullptr;
+  auto buffer = TBM::BoAlloc(bufmgr_, size, TBM_BO_SCANOUT | (1 << 17));
+  if (buffer == nullptr) return nullptr;
+  auto bufferobj = new TizenAccessibleBufferObject(buffer);
+  TBM::BoUnRef(buffer);
+  return bufferobj;
+}
+
+template <typename TBM>
+const VideoPlaneManipulator* const
+BufferManagerWithType<TBM>::GetScaleManipulator() const {
+  return &scaler_;
+}
+
+template <typename TBM>
+const VideoPlaneManipulator* const
+BufferManagerWithType<TBM>::GetCopyManipulator() const {
+  return &copier_;
+}
+
+template <typename TBM>
+const VideoPlaneColorManipulator* const
+BufferManagerWithType<TBM>::GetColorFillManipulator() const {
+  return &color_filler_;
+}
+
+template <typename TBM>
+bool BufferManagerWithType<TBM>::IsValid() const {
+  if (bufmgr_ == nullptr) return false;
+  return true;
+}
+
+template <typename TBM>
+BufferObject* BufferManagerWithType<TBM>::Import(
+    BufferHandleType handle) const {
+  if (IsValid() == false) return nullptr;
+  auto buffer = TBM::BoImport(bufmgr_, handle);
+  if (buffer == nullptr) return nullptr;
+  auto bufferobj = new TizenBufferObject(buffer);
+  TBM::BoUnRef(buffer);
+  return bufferobj;
+}
+
+template <typename TBM>
+bool BufferManagerWithType<TBM>::Copy_(
+    const VideoPlaneManipulableInfo& src,
+    const VideoPlaneManipulableInfo& dst) const {
+  if (src.component != dst.component) return false;
+  if (IsValid() == false) return false;
+  GraphicsGABltRopInfo info;
+  std::memset(&info, 0, sizeof(GraphicsGABltRopInfo));
+  info.ga_mode = GRAPHICS_GA_BITBLT_MODE_NORMAL;
+  info.rop_mode = GRAPHICS_GA_ROP_COPY;
+  info.ga_op_type = GRAPHICS_GA_COPY;
+  info.pre_alphamode = 0;
+  info.ca_value = 0;
+  info.color_format =
+      (src.component == PlaneComponent::kYComponent ? GRAPHICS_GA_FORMAT_8BPP
+                                                    : GRAPHICS_GA_FORMAT_16BPP);
+
+  info.src_handle = src.handle;
+  info.src_hbytesize = src.linesize;
+  info.src_rect.x = src.rect.x;
+  info.src_rect.y = src.rect.y;
+  info.src_rect.w = src.rect.w;
+  info.src_rect.h = src.rect.h;
+
+  info.dst_handle = dst.handle;
+  info.dst_hbytesize = dst.linesize;
+  info.dst_rect.x = dst.rect.x;
+  info.dst_rect.y = dst.rect.y;
+  info.dst_rect.w = dst.rect.w;
+  info.dst_rect.h = dst.rect.h;
+
+  return TBM::GACopy(bufmgr_, &info) > 0;
+}
+
+template <typename TBM>
+bool BufferManagerWithType<TBM>::Scale_(
+    const VideoPlaneManipulableInfo& src,
+    const VideoPlaneManipulableInfo& dst) const {
+  if (src.component != dst.component) return false;
+  if (IsValid() == false) return false;
+  GraphicsGAScaleInfo info;
+  std::memset(&info, 0, sizeof(GraphicsGAScaleInfo));
+  info.ga_mode = GRAPHICS_GA_SCALE_MODE;
+  info.rop_mode = GRAPHICS_GA_ROP_COPY;
+  info.ga_op_type = GRAPHICS_GA_SCALE;
+  info.pre_alphamode = 0;
+  info.ca_value = 0;
+  info.rop_on_off = 0;
+  info.color_format =
+      (src.component == PlaneComponent::kYComponent ? GRAPHICS_GA_FORMAT_8BPP
+                                                    : GRAPHICS_GA_FORMAT_16BPP);
+
+  info.src_handle = src.handle;
+  info.src_hbytesize = src.linesize;
+  info.src_rect.x = src.rect.x;
+  info.src_rect.y = src.rect.y;
+  info.src_rect.w = src.rect.w;
+  info.src_rect.h = src.rect.h;
+
+  info.dst_handle = dst.handle;
+  info.dst_hbytesize = dst.linesize;
+  info.dst_rect.x = dst.rect.x;
+  info.dst_rect.y = dst.rect.y;
+  info.dst_rect.w = dst.rect.w;
+  info.dst_rect.h = dst.rect.h;
+
+  return TBM::GAScale(bufmgr_, &info) > 0;
+}
+
+template <typename TBM>
+bool BufferManagerWithType<TBM>::Fill_(
+    const std::uint32_t color, const VideoPlaneManipulableInfo& dst) const {
+  if (IsValid() == false) return false;
+  GraphicsGAFillRectInfo info;
+  std::memset(&info, 0, sizeof(GraphicsGAFillRectInfo));
+  info.color_format =
+      (dst.component == PlaneComponent::kYComponent ? GRAPHICS_GA_FORMAT_8BPP
+                                                    : GRAPHICS_GA_FORMAT_16BPP);
+  info.ga_op_type = GRAPHICS_GA_SOLID_FILL;
+  info.color = color;
+
+  info.handle = dst.handle;
+  info.hbytesize = dst.linesize;
+  info.rect.x = dst.rect.x;
+  info.rect.y = dst.rect.y;
+  info.rect.w = dst.rect.w;
+  info.rect.h = dst.rect.h;
+
+  return TBM::GAFill(bufmgr_, &info) > 0;
+}
+
+/******************************************************************************
+ * Body for scaler
+ */
+template <typename TBM>
+BufferManagerWithType<TBM>::Scaler::Scaler(
+    const BufferManagerWithType* const bufmgr)
+    : bufmgr_(bufmgr) {}
+
+template <typename TBM>
+bool BufferManagerWithType<TBM>::Scaler::Do(
+    const VideoPlaneManipulableInfo& src,
+    const VideoPlaneManipulableInfo& dest) const {
+  return bufmgr_->Scale_(src, dest);
+}
+
+/******************************************************************************
+ * Body for copier
+ */
+template <typename TBM>
+BufferManagerWithType<TBM>::Copier::Copier(
+    const BufferManagerWithType* const bufmgr)
+    : bufmgr_(bufmgr) {}
+
+template <typename TBM>
+bool BufferManagerWithType<TBM>::Copier::Do(
+    const VideoPlaneManipulableInfo& src,
+    const VideoPlaneManipulableInfo& dest) const {
+  return bufmgr_->Copy_(src, dest);
+}
+
+/******************************************************************************
+ * Body for color filler
+ */
+template <typename TBM>
+BufferManagerWithType<TBM>::ColorFiller::ColorFiller(
+    const BufferManagerWithType* const bufmgr)
+    : bufmgr_(bufmgr) {}
+
+template <typename TBM>
+bool BufferManagerWithType<TBM>::ColorFiller::Do(
+    const std::uint32_t& color, const VideoPlaneManipulableInfo& dest) const {
+  return bufmgr_->Fill_(color, dest);
+}
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_BUFFER_MANAGER_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenbufferobj.h b/src/mixer/include_internal/mixer/tizen/tizenbufferobj.h
new file mode 100755 (executable)
index 0000000..dcd1d3d
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_TIZEN_BUFFER_OBJECT_H__
+#define __PLUSPLAYER_MIXER_TIZEN_TIZEN_BUFFER_OBJECT_H__
+
+#include "mixer/interfaces/bufferobject.h"
+#include "mixer/sys/tbminterface.h"
+
+namespace plusplayer {
+template <typename TBM>
+class BufferObjectWithType : public BufferObject {
+ public:
+  explicit BufferObjectWithType(BufferDefaultType buffer);
+  virtual ~BufferObjectWithType();
+  bool IsValid() const;
+  virtual BufferHandleType GetBufferHandle() const override;
+  virtual BufferKeyType Export() const override;
+  virtual std::uint32_t GetSize() const override;
+
+ protected:
+  const BufferDefaultType& GetBuffer_() const;
+
+ private:
+  BufferDefaultType buffer_ = nullptr;
+};
+
+using TizenBufferObject = BufferObjectWithType<plusplayer::tizen::TBMInterface>;
+
+/******************************************************************************
+ * Body
+ */
+template <typename TBM>
+BufferObjectWithType<TBM>::BufferObjectWithType(BufferDefaultType buffer) {
+  if (buffer == nullptr) return;
+  buffer_ = TBM::BoRef(buffer);
+}
+
+template <typename TBM>
+BufferObjectWithType<TBM>::~BufferObjectWithType() {
+  if (buffer_) TBM::BoUnRef(buffer_);
+}
+
+template <typename TBM>
+bool BufferObjectWithType<TBM>::IsValid() const {
+  if (buffer_ == nullptr) return false;
+  return true;
+}
+
+template <typename TBM>
+BufferHandleType BufferObjectWithType<TBM>::GetBufferHandle() const {
+  if (IsValid() == false) return kInvalidBufferHandle;
+  auto handle = TBM::BoGetHandle(buffer_, TBM_DEVICE_2D);
+  return handle.u32;
+}
+
+template <typename TBM>
+BufferKeyType BufferObjectWithType<TBM>::Export() const {
+  if (IsValid() == false) return kInvalidBufferKey;
+  return TBM::BoExport(buffer_);
+}
+
+template <typename TBM>
+std::uint32_t BufferObjectWithType<TBM>::GetSize() const {
+  if (IsValid() == false) return kInvalidBufferSize;
+  return TBM::BoSize(buffer_);
+}
+
+template <typename TBM>
+const BufferDefaultType& BufferObjectWithType<TBM>::GetBuffer_() const {
+  return buffer_;
+}
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_TIZEN_BUFFER_OBJECT_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenbufferphyaddraccessor.h b/src/mixer/include_internal/mixer/tizen/tizenbufferphyaddraccessor.h
new file mode 100755 (executable)
index 0000000..e16ecfa
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_BUFFER_PHYSICAL_ADDRESS_ACCESOR_H__
+#define __PLUSPLAYER_MIXER_TIZEN_BUFFER_PHYSICAL_ADDRESS_ACCESOR_H__
+
+#include <tbm_bo.h>
+
+#include "mixer/interfaces/phyaddraccessor.h"
+
+namespace plusplayer {
+class AbstractTizenBufferPhyAddrAccessor : public PhysicalAddressAccessor {
+ public:
+  explicit AbstractTizenBufferPhyAddrAccessor(BufferDefaultType buffer) {
+    if (buffer == nullptr) return;
+    buffer_ = tbm_bo_ref(buffer);
+  }
+
+  virtual ~AbstractTizenBufferPhyAddrAccessor() {
+    if (buffer_ == nullptr) return;
+    if (handle_ != nullptr) tbm_bo_unmap(buffer_);
+    tbm_bo_unref(buffer_);
+  }
+
+ public:
+  virtual BufferPhysicalAddrType GetAddress() override {
+    if (handle_ != nullptr) return handle_;
+    handle_ = GetAddress_(buffer_);
+    return handle_;
+  }
+
+ protected:
+  virtual BufferPhysicalAddrType GetAddress_(
+      const BufferDefaultType& buffer) = 0;
+
+ private:
+  BufferDefaultType buffer_;
+  BufferPhysicalAddrType handle_ = nullptr;
+};
+
+class TizenReadableBufferPhyAddrAccessor
+    : public AbstractTizenBufferPhyAddrAccessor {
+ public:
+  explicit TizenReadableBufferPhyAddrAccessor(const BufferDefaultType buffer)
+      : AbstractTizenBufferPhyAddrAccessor(buffer) {}
+  virtual ~TizenReadableBufferPhyAddrAccessor() = default;
+
+ protected:
+  virtual BufferPhysicalAddrType GetAddress_(
+      const BufferDefaultType& buffer) override {
+    auto handle = tbm_bo_map(buffer, TBM_DEVICE_CPU, TBM_OPTION_READ);
+    return handle.ptr;
+  }
+};
+
+class TizenWritableBufferPhyAddrAccessor
+    : public AbstractTizenBufferPhyAddrAccessor {
+ public:
+  explicit TizenWritableBufferPhyAddrAccessor(BufferDefaultType buffer)
+      : AbstractTizenBufferPhyAddrAccessor(buffer) {}
+  virtual ~TizenWritableBufferPhyAddrAccessor() = default;
+
+ protected:
+  virtual BufferPhysicalAddrType GetAddress_(
+      const BufferDefaultType& buffer) override {
+    auto handle = tbm_bo_map(buffer, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+    return handle.ptr;
+  }
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_BUFFER_PHYSICAL_ADDRESS_ACCESOR_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizendefaultphyaddraccessor.h b/src/mixer/include_internal/mixer/tizen/tizendefaultphyaddraccessor.h
new file mode 100755 (executable)
index 0000000..7668790
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_DEFAULT_PHYSICAL_ADDRESS_ACCESOR_H__
+#define __PLUSPLAYER_MIXER_TIZEN_DEFAULT_PHYSICAL_ADDRESS_ACCESOR_H__
+
+#include "mixer/interfaces/phyaddraccessor.h"
+
+namespace plusplayer {
+class TizenDefaultPhyAddrAccessor : public PhysicalAddressAccessor {
+ public:
+  explicit TizenDefaultPhyAddrAccessor(std::uint32_t viraddr);
+  virtual ~TizenDefaultPhyAddrAccessor() = default;
+
+ public:
+  virtual BufferPhysicalAddrType GetAddress() override;
+
+ private:
+  std::uint32_t viraddr_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_DEFAULT_PHYSICAL_ADDRESS_ACCESOR_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenhwbufferobj.h b/src/mixer/include_internal/mixer/tizen/tizenhwbufferobj.h
new file mode 100755 (executable)
index 0000000..9c325f7
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_TIZEN_HW_BUFFER_OBJECT_H__
+#define __PLUSPLAYER_MIXER_TIZEN_TIZEN_HW_BUFFER_OBJECT_H__
+
+#include "mixer/decodedvideoinfo.h"
+#include "mixer/interfaces/bufferobject.h"
+
+namespace plusplayer {
+class TizenHWBufferObject : public BufferObject {
+ public:
+  explicit TizenHWBufferObject(const std::uint32_t& width,
+                               const std::uint32_t& height,
+                               const DecodedRawPlaneInfo& info);
+  virtual ~TizenHWBufferObject() = default;
+
+  bool IsValid() const;
+  virtual BufferHandleType GetBufferHandle() const override;
+  virtual BufferKeyType Export() const override;
+  virtual std::uint32_t GetSize() const override;
+
+ private:
+  std::uint32_t width_;
+  std::uint32_t height_;
+  DecodedRawPlaneInfo info_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_TIZEN_HW_BUFFER_OBJECT_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenhwvideoframe.h b/src/mixer/include_internal/mixer/tizen/tizenhwvideoframe.h
new file mode 100755 (executable)
index 0000000..4374269
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_HW_VIDEO_FRAME_H__
+#define __PLUSPLAYER_MIXER_TIZEN_HW_VIDEO_FRAME_H__
+
+#include <memory>
+
+#include "mixer/abs_videoframe.h"
+#include "mixer/decodedvideoinfo.h"
+#include "mixer/interfaces/bufferobject.h"
+
+namespace plusplayer {
+class TizenHWVideoFrame : public AbstractVideoFrame {
+ public:
+  using BufferObjectPtr = std::unique_ptr<BufferObject>;
+
+ public:
+  explicit TizenHWVideoFrame(const DecodedRawInfo& info);
+  virtual ~TizenHWVideoFrame() = default;
+
+ protected:
+  virtual bool IsValid_() const override;
+  virtual const std::uint32_t GetWidth_() const override;
+  virtual const std::uint32_t GetHeight_() const override;
+
+ private:
+  void PrintDecodedRawInfo() const;
+
+ private:
+  DecodedRawInfo info_;
+};
+}  // namespace plusplayer
+
+#endif  //__PLUSPLAYER_MIXER_TIZEN_HW_VIDEO_FRAME_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizenrenderableobj_factory.h b/src/mixer/include_internal/mixer/tizen/tizenrenderableobj_factory.h
new file mode 100755 (executable)
index 0000000..91401d0
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_RENDERABLE_OBJECT_FACTORY_H__
+#define __PLUSPLAYER_MIXER_TIZEN_RENDERABLE_OBJECT_FACTORY_H__
+
+#include <memory>
+
+#include "mixer/interfaces/memoryallocator.h"
+#include "mixer/interfaces/renderableobj_factory.h"
+
+namespace plusplayer {
+class TizenRenderableObjectFactory : public RenderableObjectFactory {
+ public:
+  explicit TizenRenderableObjectFactory(
+      const MemoryAllocator* const memallocator);
+  virtual ~TizenRenderableObjectFactory() = default;
+
+ public:
+  virtual RenderableObject* CreateRenderableObject(
+      const std::uint32_t width, const std::uint32_t height) const override;
+
+ private:
+  const MemoryAllocator* const memallocator_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TIZEN_RENDERABLE_OBJECT_FACTORY_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/tizen/tizensurfacevideoframe.h b/src/mixer/include_internal/mixer/tizen/tizensurfacevideoframe.h
new file mode 100755 (executable)
index 0000000..eeac31c
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __PLUSPLAYER_MIXER_TIZEN_SURFACE_VIDEO_FRAME_H__
+#define __PLUSPLAYER_MIXER_TIZEN_SURFACE_VIDEO_FRAME_H__
+
+#include <memory>
+
+#include "mixer/abs_videoframe.h"
+#include "mixer/interfaces/bufferobject.h"
+#include "plusplayer/decodedvideopacketex.h"
+
+namespace plusplayer {
+class TizenSurfaceVideoFrame : public AbstractVideoFrame {
+ private:
+  enum ComponentIndex { kYIndex = 0, kUVIndex = 1 };
+
+ public:
+  using BufferObjectPtr = std::unique_ptr<BufferObject>;
+
+ public:
+  explicit TizenSurfaceVideoFrame(DecodedVideoPacketExPtr dvp);
+  virtual ~TizenSurfaceVideoFrame() = default;
+
+ protected:
+  virtual bool IsValid_() const override;
+  virtual const std::uint32_t GetWidth_() const override;
+  virtual const std::uint32_t GetHeight_() const override;
+
+ private:
+  DecodedVideoPacketExPtr dvp_;
+  std::uint32_t width_;
+  std::uint32_t height_;
+};
+}  // namespace plusplayer
+
+#endif  //__PLUSPLAYER_MIXER_TIZEN_SURFACE_VIDEO_FRAME_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/types/buffertype.h b/src/mixer/include_internal/mixer/types/buffertype.h
new file mode 100755 (executable)
index 0000000..d8cfc9e
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __PLUSPLAYER_MIXER_TYPES_BUFFER_TYPE_H__
+#define __PLUSPLAYER_MIXER_TYPES_BUFFER_TYPE_H__
+
+#include <tbm_type_common.h>
+
+#include <cstdint>
+
+namespace plusplayer {
+
+using BufferDefaultType = tbm_bo;
+using BufferUnionHandleType = tbm_bo_handle;
+using BufferHandleType = decltype(BufferUnionHandleType::u32);
+using BufferPhysicalAddrType = decltype(BufferUnionHandleType::ptr);
+using BufferKeyType = tbm_key;
+
+const static BufferHandleType kInvalidBufferHandle = 0;
+const static BufferPhysicalAddrType kInvalidBufferPhysicalAddr = nullptr;
+const static BufferKeyType kInvalidBufferKey = 0;
+const static BufferKeyType kInvalidBufferSize = 0;
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TYPES_BUFFER_TYPE_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/types/planecomponent.h b/src/mixer/include_internal/mixer/types/planecomponent.h
new file mode 100755 (executable)
index 0000000..c16e8cc
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __PLUSPLAYER_MIXER_TYPES_PLANE_COMPONENT_H__
+#define __PLUSPLAYER_MIXER_TYPES_PLANE_COMPONENT_H__
+
+namespace plusplayer {
+
+enum class PlaneComponent {
+  kYComponent,
+  kUVComponent,
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TYPES_PLANE_COMPONENT_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/types/videoplanemanipinfo.h b/src/mixer/include_internal/mixer/types/videoplanemanipinfo.h
new file mode 100755 (executable)
index 0000000..ce09752
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __PLUSPLAYER_MIXER_TYPES_VIDEO_PLANE_MAINIPULABLE_INFO_H__
+#define __PLUSPLAYER_MIXER_TYPES_VIDEO_PLANE_MAINIPULABLE_INFO_H__
+
+#include <cstdint>
+
+#include "mixer/types/buffertype.h"
+#include "mixer/types/planecomponent.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+
+struct VideoPlaneManipulableInfo {
+  BufferHandleType handle;
+  PlaneComponent component;
+  std::uint32_t linesize;
+  Geometry rect;
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TYPES_VIDEO_PLANE_MAINIPULABLE_INFO_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/types/videoplanemoveinfo.h b/src/mixer/include_internal/mixer/types/videoplanemoveinfo.h
new file mode 100755 (executable)
index 0000000..9559f55
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __PLUSPLAYER_MIXER_TYPES_VIDEO_PLANE_MOVE_INFO_H__
+#define __PLUSPLAYER_MIXER_TYPES_VIDEO_PLANE_MOVE_INFO_H__
+
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+
+struct VideoPlaneMoveInfo {
+  explicit VideoPlaneMoveInfo(const Geometry& current_gemetry, const Geometry& target_gemetry)
+      : cur(current_gemetry), target(target_gemetry) {}
+  Geometry cur;
+  Geometry target;
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_TYPES_VIDEO_PLANE_MOVE_INFO_H__
\ No newline at end of file
diff --git a/src/mixer/include_internal/mixer/videoplane.h b/src/mixer/include_internal/mixer/videoplane.h
new file mode 100755 (executable)
index 0000000..969f9b1
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef __PLUSPLAYER_MIXER_VIDEO_PLANE_H__
+#define __PLUSPLAYER_MIXER_VIDEO_PLANE_H__
+
+#include <cstdint>
+#include <memory>
+
+#include "mixer/interfaces/bufferobject.h"
+#include "mixer/interfaces/videoplanemanipulable.h"
+#include "mixer/types/planecomponent.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer {
+class VideoPlane : public VideoPlaneManipulable {
+ public:
+  explicit VideoPlane(PlaneComponent component, const std::uint32_t& width,
+                      const std::uint32_t& height);
+  virtual ~VideoPlane() = default;
+
+ public:
+  virtual bool IsValid() const override;
+  virtual VideoPlaneManipulableInfo GetVideoPlaneManipulableInfo()
+      const override;
+  virtual void SetCropArea(const CropArea& croparea) override;
+
+ protected:
+  virtual const BufferObject* const GetBufferObject_() const = 0;
+  virtual std::uint32_t GetLineSize_() const;
+
+ private:
+  const PlaneComponent component_;
+  const std::uint32_t width_;
+  const std::uint32_t height_;
+  CropArea croparea_;
+};
+
+class YComponentVideoPlane : public VideoPlane {
+ public:
+  using BufferObjectPtr = std::unique_ptr<BufferObject>;
+
+ public:
+  explicit YComponentVideoPlane(BufferObjectPtr buffer,
+                                const std::uint32_t& width,
+                                const std::uint32_t& height);
+  virtual ~YComponentVideoPlane() = default;
+
+ protected:
+  virtual const BufferObject* const GetBufferObject_() const override;
+
+ private:
+  BufferObjectPtr buffer_;
+};
+
+class UVComponentVideoPlane : public VideoPlane {
+ public:
+  using BufferObjectPtr = std::unique_ptr<BufferObject>;
+
+ public:
+  explicit UVComponentVideoPlane(BufferObjectPtr buffer,
+                                 const std::uint32_t& width,
+                                 const std::uint32_t& height);
+  virtual ~UVComponentVideoPlane() = default;
+
+ protected:
+  virtual const BufferObject* const GetBufferObject_() const override;
+
+ private:
+  BufferObjectPtr buffer_;
+};
+
+class YComponentVideoPlaneWithSharedMemory : public VideoPlane {
+ public:
+  using BufferObjectPtr = std::shared_ptr<BufferObject>;
+  using BufferObjectWeakPtr = std::weak_ptr<BufferObject>;
+
+ public:
+  explicit YComponentVideoPlaneWithSharedMemory(BufferObjectWeakPtr buffer,
+                                                const std::uint32_t& width,
+                                                const std::uint32_t& height);
+  virtual ~YComponentVideoPlaneWithSharedMemory() = default;
+
+ protected:
+  virtual std::uint32_t GetLineSize_() const override;
+  virtual const BufferObject* const GetBufferObject_() const override;
+
+ private:
+  BufferObjectPtr buffer_;
+  std::uint32_t width_;
+};
+
+class UVComponentVideoPlaneWithSharedMemory : public VideoPlane {
+ public:
+  using BufferObjectPtr = std::shared_ptr<BufferObject>;
+  using BufferObjectWeakPtr = std::weak_ptr<BufferObject>;
+
+ public:
+  explicit UVComponentVideoPlaneWithSharedMemory(BufferObjectWeakPtr buffer,
+                                                 const std::uint32_t& width,
+                                                 const std::uint32_t& height);
+  virtual ~UVComponentVideoPlaneWithSharedMemory() = default;
+
+ public:
+  virtual VideoPlaneManipulableInfo GetVideoPlaneManipulableInfo()
+      const override;
+
+ protected:
+  virtual std::uint32_t GetLineSize_() const override;
+  virtual const BufferObject* const GetBufferObject_() const override;
+
+ private:
+  BufferObjectPtr buffer_;
+  std::uint32_t width_;
+  std::uint32_t height_;
+};
+}  // namespace plusplayer
+
+#endif  //__PLUSPLAYER_MIXER_VIDEO_PLANE_H__
\ No newline at end of file
diff --git a/src/mixer/src/abs_videoframe.cpp b/src/mixer/src/abs_videoframe.cpp
new file mode 100755 (executable)
index 0000000..3868a4a
--- /dev/null
@@ -0,0 +1,46 @@
+#include "mixer/abs_videoframe.h"
+
+namespace plusplayer {
+
+const std::vector<VideoPlaneManipulableInfo>
+AbstractVideoFrame::GetVideoPlaneManipInfo() const {
+  if (IsValid() == false) return {};
+  std::vector<VideoPlaneManipulableInfo> vector;
+  for (const auto& plane : planes_) {
+    vector.emplace_back(plane->GetVideoPlaneManipulableInfo());
+  }
+  return vector;
+}
+
+bool AbstractVideoFrame::IsValid() const {
+  if (planes_.size() == 0) return false;
+  if (GetWidth_() == 0 || GetHeight_() == 0) return false;
+  if (IsValid_() == false) return false;
+  return true;
+}
+
+bool AbstractVideoFrame::SetCropArea(const CropArea& croparea) {
+  if (IsValid() == false) return false;
+  for (auto& plane : planes_) {
+    plane->SetCropArea(croparea);
+  }
+  return true;
+}
+
+const std::uint32_t AbstractVideoFrame::GetWidth() const {
+  if (IsValid() == false) return 0;
+  return GetWidth_();
+}
+
+const std::uint32_t AbstractVideoFrame::GetHeight() const {
+  if (IsValid() == false) return 0;
+  return GetHeight_();
+}
+
+void AbstractVideoFrame::RegisterVideoPlaneManipulablePtr_(
+    VideoPlaneManipulablePtr vpmanip) {
+  if (vpmanip == nullptr) return;
+  planes_.emplace_back(std::move(vpmanip));
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/defaultmixer.cpp b/src/mixer/src/defaultmixer.cpp
new file mode 100755 (executable)
index 0000000..5fa76a7
--- /dev/null
@@ -0,0 +1,649 @@
+#include "mixer/defaultmixer.h"
+
+#include <gst/gst.h>
+#include <trackrenderer_capi/display.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <fstream>
+#include <vector>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/rendererwithdoublebuf.h"
+#include "mixer/tizen/tizenbufferkeyvideoframe.h"
+#include "mixer/tizen/tizenhwvideoframe.h"
+#include "mixer/tizen/tizenrenderableobj_factory.h"
+#include "mixer/tizen/tizensurfacevideoframe.h"
+#include "mixer/types/videoplanemoveinfo.h"
+
+namespace plusplayer {
+
+namespace internal {
+TrackRendererDisplayMode ConvertToTrackRendererDisplayMode(
+    const DisplayMode& mode);
+
+}  // namespace internal
+DefaultMixer::DefaultMixer() : renderer_listener_(&trackrenderer_handle_) {
+  LOG_ENTER;
+  gst_init(NULL, NULL);
+  trackrenderer_create(&trackrenderer_handle_);
+
+  TizenRenderableObjectFactory factory(&bufmgr_);
+  renderer_ = RendererPtr(new RendererWithDoubleBuffer(
+      factory, &bufmgr_, &bufmgr_, whole_resolution_, &renderer_listener_));
+  // renderer_ = RendererPtr(
+  //     new Renderer(factory, whole_resolution_, &renderer_listener_));
+  InitResourceList_();
+}
+
+DefaultMixer::~DefaultMixer() {
+  LOG_ENTER;
+  trackrenderer_destroy(trackrenderer_handle_);
+  LOG_LEAVE;
+}
+
+bool DefaultMixer::Start() {
+  LOG_ENTER;
+  std::lock_guard<std::mutex> lk(mixer_lock_);
+  if (is_started_ == true) {
+    LOG_ERROR("mixer was already started");
+    return true;
+  }
+
+  if (renderer_->Start() == false) {
+    LOG_ERROR("renderer start failed");
+    return false;
+  }
+
+  TrackRendererTrack track;
+  memset(&track, 0, sizeof(TrackRendererTrack));
+  track.type = kTrackRendererTrackTypeVideo;
+  track.index = 0;
+  track.active = 1;
+  track.mimetype = "video/x-raw";
+  track.width = whole_resolution_.width;
+  track.height = whole_resolution_.height;
+  track.framerate_num = whole_resolution_.framerate_num;
+  track.framerate_den = whole_resolution_.framerate_den;
+
+  if (trackrenderer_set_track(trackrenderer_handle_, &track, 1) != 0) {
+    LOG_ERROR("fail to set track");
+    return false;
+  }
+
+  constexpr std::uint32_t kLowLatencyMode =
+      0x0111;  // video disable avsync & videoquailty
+  trackrenderer_set_attribute(trackrenderer_handle_, "low-latency-mode",
+                              kLowLatencyMode, nullptr);
+  if (use_sub_scaler_) {
+    constexpr std::uint32_t alternative_rsc = 1;
+    trackrenderer_set_attribute(trackrenderer_handle_,
+                                "alternative-video-resource", alternative_rsc,
+                                nullptr);
+  }
+  if (trackrenderer_prepare(trackrenderer_handle_) != 0) {
+    LOG_ERROR("fail to prepare");
+    return false;
+  }
+  if (trackrenderer_start(trackrenderer_handle_) != 0) {
+    LOG_ERROR("fail to start");
+    return false;
+  }
+
+  is_started_ = true;
+  LOG_LEAVE;
+  return true;
+}
+
+bool DefaultMixer::Stop() {
+  LOG_ENTER;
+  std::lock_guard<std::mutex> lk(mixer_lock_);
+  if (is_started_ == false) {
+    LOG_ERROR("mixer was already stopped");
+    return true;
+  }
+
+  if (renderer_->Stop() == false) {
+    LOG_ERROR("renderer stop failed");
+  }
+
+  if (trackrenderer_stop(trackrenderer_handle_) != 0) {
+    LOG_ERROR("fail to stop");
+  }
+
+  is_started_ = false;
+  LOG_LEAVE;
+  return true;
+}
+
+int DefaultMixer::GetMaximumAllowedNumberOfPlayer() {
+  LOG_ENTER;
+  // Fix me if we get policy and detail method (bc_hi.lee)
+  constexpr int kMaximumAllowedNumberOfPlayer = 3;
+  constexpr int kMaximumNumForNdecoder = 4;
+  if (resource_allocation_mode_ == RscAllocMode::kNdecoder)
+    return kMaximumNumForNdecoder;
+  return kMaximumAllowedNumberOfPlayer;
+}
+
+bool DefaultMixer::SetDisplay(const DisplayType type, void* obj) {
+  LOG_ENTER;
+  TrackRendererDisplayType _type = kTrackRendererDisplayTypeNone;
+  switch (type) {
+    case DisplayType::kNone: {
+      _type = kTrackRendererDisplayTypeNone;
+      break;
+    }
+    case DisplayType::kOverlay: {
+      _type = kTrackRendererDisplayTypeOverlay;
+      break;
+    }
+    case DisplayType::kEvas: {
+      _type = kTrackRendererDisplayTypeEvas;
+      break;
+    }
+    default:
+      LOG_ERROR("unknown displaytype");
+      return false;
+  }
+  if (!trackrenderer_set_display(trackrenderer_handle_, _type, obj)) {
+    return true;
+  }
+  return false;
+}
+
+bool DefaultMixer::SetDisplay(const DisplayType type, const uint32_t surface_id,
+                              const int x, const int y, const int w,
+                              const int h) {
+  LOG_ENTER;
+  TrackRendererDisplayType _type = kTrackRendererDisplayTypeNone;
+  switch (type) {
+    case DisplayType::kNone: {
+      _type = kTrackRendererDisplayTypeNone;
+      break;
+    }
+    case DisplayType::kOverlay: {
+      _type = kTrackRendererDisplayTypeOverlay;
+      break;
+    }
+    case DisplayType::kEvas: {
+      _type = kTrackRendererDisplayTypeEvas;
+      break;
+    }
+    default:
+      LOG_ERROR("unknown displaytype");
+      return false;
+  }
+  if (!trackrenderer_set_display_surface(trackrenderer_handle_, _type,
+                                         surface_id, x, y, w, h)) {
+    return true;
+  }
+  return false;
+}
+
+bool DefaultMixer::SetDisplayMode(const DisplayMode& mode) {
+  LOG_ENTER;
+  TrackRendererDisplayMode _mode =
+      internal::ConvertToTrackRendererDisplayMode(mode);
+  if (!trackrenderer_set_display_mode(trackrenderer_handle_, _mode)) {
+    return true;
+  }
+  return false;
+}
+
+bool DefaultMixer::SetDisplayRoi(const Geometry& geometry) {
+  LOG_ENTER;
+  TrackRendererGeometry _geometry;
+  memset(&_geometry, 0, sizeof(TrackRendererGeometry));
+  _geometry.x = geometry.x;
+  _geometry.y = geometry.y;
+  _geometry.w = geometry.w;
+  _geometry.h = geometry.h;
+  if (!trackrenderer_set_display_roi(trackrenderer_handle_, &_geometry)) {
+    return true;
+  }
+  return false;
+}
+
+bool DefaultMixer::SetRscAllocMode(const RscAllocMode& mode) {
+  LOG_ENTER;
+  std::lock_guard<std::mutex> lock(ticket_lock_);
+  if (player_map_.size() != 0) {
+    LOG_ERROR(
+        "it have to be called before setting player's display type to mixer "
+        "type");
+    return false;
+  }
+  resource_allocation_mode_ = mode;
+  return true;
+}
+
+bool DefaultMixer::DisableAudioFocusSetting() {
+  LOG_ENTER;
+  std::lock_guard<std::mutex> lock(ticket_lock_);
+  if (player_map_.size() != 0) {
+    LOG_ERROR(
+        "it have to be called before setting player's display type to mixer "
+        "type");
+    return false;
+  }
+  enable_audio_focus_setting_ = false;
+  if (audio_focused_player_) audio_focused_player_ = nullptr;
+  return true;
+}
+
+bool DefaultMixer::SetAlternativeVideoScaler() {
+  LOG_ENTER;
+  use_sub_scaler_ = true;
+  return true;
+}
+
+bool DefaultMixer::SetAudioFocus(const void* player_instance) {
+  LOG_ENTER;
+  if (!player_instance) return false;
+  std::lock_guard<std::mutex> lock(ticket_lock_);
+
+  if (!enable_audio_focus_setting_) return false;
+
+  if (player_map_.count(player_instance) == 0) {
+    audio_focused_player_ = player_instance;
+    LOG_INFO("audio focus [%p]", audio_focused_player_);
+    return true;
+  }
+
+  LOG_INFO("Active Audio player[%p]", player_instance);
+  auto ticket = player_map_[player_instance];
+  if (ticket->IsAudioFocused()) {
+    LOG_INFO("already focused user");
+    return true;
+  }
+
+  auto target = std::find_if(
+      player_map_.begin(), player_map_.end(),
+      [](const std::pair<const void*, Ticket*>& item) noexcept -> bool {
+        return (item.second)->IsAudioFocused();
+      });
+
+  if (target != player_map_.end()) {
+    if (target->second->GetListener()->OnAudioFocusChanged(false)) {
+      target->second->SetAudioFocus(false);
+    } else {
+      LOG_ERROR("fail to change audio focus");
+      return false;
+    }
+  } else {
+    LOG_INFO("not found audio focused player");
+  }
+
+  if (ticket->GetListener()) {
+    if (ticket->GetListener()->OnAudioFocusChanged(true)) {
+      ticket->SetAudioFocus(true);
+      return true;
+    }
+  }
+  LOG_ERROR("fail to change audio focus");
+  return false;
+}
+
+bool DefaultMixer::Commit() {
+  LOG_ENTER;
+  std::lock_guard<std::mutex> lock(ticket_lock_);
+  std::vector<VideoPlaneMoveInfo> move_list;
+  for (auto it = player_map_.begin(); it != player_map_.end(); ++it) {
+    auto listener = it->second->GetListener();
+    if (!listener) continue;
+    DisplayInfo cur_info, new_info;
+    it->second->GetDisplayInfo(&cur_info);
+    if (listener->OnUpdateDisplayInfo(cur_info, &new_info)) {
+      it->second->UpdateDisplayInfo(new_info);
+      if (it->second->HasRenderedBefore() == true) {
+        move_list.emplace_back(cur_info.geometry, new_info.geometry);
+      }
+    } else {
+      LOG_ERROR("fail to update display info");
+    }
+  }
+  renderer_->Move(&bufmgr_, move_list);
+  return true;
+}
+
+bool DefaultMixer::SetResolution(const ResolutionInfo& info) {
+  whole_resolution_ = info;
+  renderer_->ChangeResolution(TizenRenderableObjectFactory(&bufmgr_),
+                              info.width, info.height);
+  renderer_->ChangeRenderingSpeed(info.framerate_num, info.framerate_den);
+  return true;
+}
+
+bool DefaultMixer::RegisterListener(MixerEventListener* listener) {
+  LOG_ENTER;
+  listener_ = listener;
+  trackrenderer_set_resourceconflict_cb(trackrenderer_handle_,
+                                        ResourceConflictCb_, this);
+  trackrenderer_set_error_cb(trackrenderer_handle_, ErrorCb_, this);
+  return true;
+}
+
+MixerTicket* DefaultMixer::CreateTicket(const void* player_instance) {
+  std::lock_guard<std::mutex> lock(ticket_lock_);
+  LOG_ENTER;
+  auto ticket = new Ticket(this, player_instance);
+  if (audio_focused_player_ == player_instance) {
+    ticket->SetAudioFocus(true);
+    LOG_INFO(" player [%p]", player_instance);
+  }
+  player_map_.emplace(player_instance, ticket);
+  return ticket;
+}
+
+bool DefaultMixer::Detach_(const void* player_instance) {
+  std::lock_guard<std::mutex> lock(ticket_lock_);
+  LOG_ENTER;
+  auto* ticket = player_map_.at(player_instance);
+
+  if (ticket == nullptr) return false;
+  if (ticket->HasRenderedBefore()) {
+    DisplayInfo display_info;
+    ticket->GetDisplayInfo(&display_info);
+    // if this ticket is display visible status, draw black screen
+    if (IsNeededToSkipRendering_(display_info) == false) {
+      LOG_INFO(
+          "player [%p] has been rendered before, so will mute on rendered "
+          "region",
+          player_instance);
+      renderer_->Mute(&bufmgr_, display_info.geometry);
+    }
+  }
+  ticket->DeallocResource();
+  player_map_.erase(player_instance);
+  return true;
+}
+
+bool DefaultMixer::Render_(const void* player_instance,
+                           const VideoPlaneCollection& vplanes) {
+  DisplayInfo display_info;
+  {
+    std::lock_guard<std::mutex> t_lk(ticket_lock_);
+    auto* ticket = player_map_.at(player_instance);
+    if (ticket == nullptr) return false;
+    ticket->GetDisplayInfo(&display_info);
+    ticket->RecordRenderingTime();
+  }
+  if (IsNeededToSkipRendering_(display_info)) {
+    LOG_INFO("Skip Rendering for player [%p]", player_instance);
+    return true;
+  }
+  bool ret = renderer_->Render(&bufmgr_, &vplanes, display_info.geometry);
+  if (ret == false) {
+    LOG_INFO("Rendering Failed for player [%p]", player_instance);
+  }
+  return ret;
+}
+
+bool DefaultMixer::IsNeededToSkipRendering_(const DisplayInfo& display_info) {
+  if (display_info.visible_status == VisibleStatus::kHide) return true;
+  if (display_info.geometry.x == 0 && display_info.geometry.y == 0 &&
+      display_info.geometry.w == 1 && display_info.geometry.h == 1)
+    return true;
+  return false;
+}
+
+void DefaultMixer::ResourceConflictCb_(UserData userdata) {
+  auto mixer = static_cast<DefaultMixer*>(userdata);
+  if (!mixer) return;
+  mixer->listener_->OnResourceConflicted();
+}
+void DefaultMixer::ErrorCb_(const TrackRendererErrorType error_code,
+                            UserData userdata) {
+  auto mixer = static_cast<DefaultMixer*>(userdata);
+  if (!mixer) return;
+  mixer->listener_->OnError();
+}
+
+bool DefaultMixer::Ticket::Render(const DecodedRawInfo& info) {
+  LOG_INFO("player [%p] render frame [%d x %d]", player_instance_, info.width,
+           info.height);
+  TizenHWVideoFrame frame(info);
+  frame.SetCropArea(each_display_info_.croparea);
+  bool ret = handler_->Render_(player_instance_, frame);
+  if (ret == false) {
+    LOG_INFO("player [%p] rendering error", player_instance_);
+  } else {
+    has_rendered_ = true;
+  }
+  return ret;
+}
+
+bool DefaultMixer::Ticket::Render(const DecodedVideoKeyTypeInfo& info) {
+  LOG_INFO("player [%p] render frame [%d x %d]", player_instance_, info.width,
+           info.height);
+  TizenBufferKeyVideoFrame frame(&handler_->bufmgr_, info.key, info.width,
+                                 info.height);
+  frame.SetCropArea(each_display_info_.croparea);
+  bool ret = handler_->Render_(player_instance_, frame);
+  if (ret == false) {
+    LOG_INFO("player [%p] rendering error", player_instance_);
+  } else {
+    has_rendered_ = true;
+  }
+  return ret;
+}
+
+void DefaultMixer::InitResourceList_() {
+  // Must be improved (bc_hi.lee)
+  for (int type = static_cast<int>(ResourceType::kHwMain);
+       type < static_cast<int>(ResourceType::kNdecoder); type++) {
+    Resource resource;
+    resource.category = ResourceCategory::kVideoDecoder;
+    resource.type = static_cast<ResourceType>(type);
+    resource_list_.push_back(std::move(resource));
+  }
+}
+
+bool DefaultMixer::Ticket::GetAvailableResourceType(
+    const ResourceCategory& category, ResourceType* type) {
+  LOG_ENTER;
+  std::lock_guard<std::mutex> lock(handler_->ticket_lock_);
+  if (handler_->resource_allocation_mode_ == RscAllocMode::kDisable) {
+    LOG_ERROR("mixer is no loger involved in resource alloc");
+    return false;
+  }
+
+  if (handler_->resource_allocation_mode_ == RscAllocMode::kNdecoder) {
+    *type = ResourceType::kNdecoder;
+    return true;
+  }
+
+  for (const auto& item : handler_->resource_list_) {
+    if (!item.assignee) {
+      *type = item.type;
+      LOG_INFO("Resource type [%d]", static_cast<int>(*type));
+      return true;
+    }
+  }
+  LOG_ERROR("no available resource type");
+  return false;
+}
+
+bool DefaultMixer::Ticket::IsAudioFocusHandler() {
+  std::lock_guard<std::mutex> lock(handler_->ticket_lock_);
+  return handler_->enable_audio_focus_setting_;
+}
+
+bool DefaultMixer::Ticket::IsRscAllocHandler() {
+  std::lock_guard<std::mutex> lock(handler_->ticket_lock_);
+  return handler_->resource_allocation_mode_ != RscAllocMode::kDisable;
+}
+
+bool DefaultMixer::Ticket::Alloc(const ResourceCategory& category,
+                                 const ResourceType& type) {
+  std::lock_guard<std::mutex> lock(handler_->ticket_lock_);
+  if (handler_->resource_allocation_mode_ == RscAllocMode::kDisable) {
+    LOG_ERROR("mixer is no loger involved in resource alloc");
+    return false;
+  }
+
+  if (type == ResourceType::kNdecoder) {
+    LOG_INFO("Request N decoder");
+    return true;
+  }
+
+  auto compare = [category, type](Resource item) -> bool {
+    if (item.category == category && item.type == type && !item.assignee) {
+      return true;
+    }
+    return false;
+  };
+  auto target = std::find_if(handler_->resource_list_.begin(),
+                             handler_->resource_list_.end(), compare);
+  if (target == handler_->resource_list_.end()) {
+    LOG_ERROR("Resource alloc fail");
+    return false;
+  }
+  LOG_INFO("assignee %p", player_instance_);
+  target->assignee = player_instance_;
+  LOG_LEAVE;
+  return true;
+}
+
+MixerTicketEventListener* DefaultMixer::Ticket::GetListener() {
+  return ticket_listener_;
+}
+
+bool DefaultMixer::Ticket::IsAudioFocused() { return is_audio_focus_; }
+
+void DefaultMixer::Ticket::SetAudioFocus(bool active) {
+  is_audio_focus_ = active;
+}
+
+void DefaultMixer::Ticket::GetDisplayInfo(DisplayInfo* info) {
+  if (info == nullptr) return;
+  *info = each_display_info_;
+}
+
+bool DefaultMixer::Ticket::HasRenderedBefore() { return has_rendered_; }
+
+void DefaultMixer::Ticket::UpdateDisplayInfo(const DisplayInfo& info) {
+  LOG_INFO(
+      "updated display info : geom[%d, %d, %d x %d] crop[%.3lf, %.3lf, %.3lf x "
+      "%.3lf]",
+      info.geometry.x, info.geometry.y, info.geometry.w, info.geometry.h,
+      info.croparea.scale_x, info.croparea.scale_y, info.croparea.scale_w,
+      info.croparea.scale_h);
+  each_display_info_ = info;
+}
+
+void DefaultMixer::Ticket::DeallocResource() {
+  auto compare = [this](Resource item) -> bool {
+    if (item.assignee == player_instance_) {
+      return true;
+    }
+    return false;
+  };
+
+  auto target = std::find_if(handler_->resource_list_.begin(),
+                             handler_->resource_list_.end(), compare);
+  if (target == handler_->resource_list_.end()) {
+    LOG_INFO("not found assignee");
+    return;
+  }
+  target->assignee = nullptr;
+}
+
+void DefaultMixer::Ticket::RecordRenderingTime() {
+  auto now = std::chrono::system_clock::now();
+  LOG_INFO("[PERF] p[%p] render_interval[%llu]ms", player_instance_,
+           std::chrono::duration_cast<std::chrono::milliseconds>(
+               now - last_rendering_time_)
+               .count());
+  last_rendering_time_ = now;
+}
+
+bool DefaultMixer::Ticket::RegisterListener(
+    MixerTicketEventListener* listener) {
+  LOG_ENTER;
+  ticket_listener_ = listener;
+  return true;
+}
+
+bool DefaultMixer::Ticket::Prepare() {
+  LOG_ENTER;
+  DisplayInfo new_info;
+  ticket_listener_->OnUpdateDisplayInfo(each_display_info_, &new_info);
+  UpdateDisplayInfo(new_info);
+  if (!handler_->enable_audio_focus_setting_) return true;
+  LOG_INFO("audio focused [%d]", is_audio_focus_);
+  ticket_listener_->OnAudioFocusChanged(is_audio_focus_);
+  return true;
+}
+
+DefaultMixer::Ticket::~Ticket() {
+  handler_->Detach_(player_instance_);
+  LOG_LEAVE;
+}
+
+DefaultMixer::MixerRendererEventListener::MixerRendererEventListener(
+    TrackRendererHandle* trhandle_ptr)
+    : trhandle_ptr_(trhandle_ptr) {}
+
+DefaultMixer::MixerRendererEventListener::~MixerRendererEventListener() {}
+
+void* DefaultMixer::MixerRendererEventListener::CreateGstBuffer_(
+    const BufferKeyType& key) const {
+  if (key == 0) return nullptr;
+  auto* gstbuffer = gst_buffer_new();
+  auto* gststructure =
+      gst_structure_new("tbm_bo", "tbm_bo_key", G_TYPE_UINT, key, nullptr);
+  gst_mini_object_set_qdata(GST_MINI_OBJECT(gstbuffer),
+                            g_quark_from_static_string("tbm_bo"), gststructure,
+                            (GDestroyNotify)gst_structure_free);
+  return static_cast<void*>(gstbuffer);
+}
+
+void DefaultMixer::MixerRendererEventListener::FillDecoderInputBuffer_(
+    TrackRendererDecoderInputBuffer& buffer, const BufferKeyType& key) const {
+  buffer.type = kTrackRendererTrackTypeVideo;
+  buffer.index = 0;
+  buffer.buffer = CreateGstBuffer_(key);
+}
+
+bool DefaultMixer::MixerRendererEventListener::OnRenderingRelease(
+    const BufferKeyType& key) {
+  if (trhandle_ptr_ == nullptr || *trhandle_ptr_ == nullptr) return false;
+  TrackRendererDecoderInputBuffer buffer;
+  FillDecoderInputBuffer_(buffer, key);
+  TrackRendererSubmitStatus status;
+  int ret = trackrenderer_submit_packet2(*trhandle_ptr_, &buffer, &status);
+  if (ret != 0 && buffer.buffer != nullptr) {
+    gst_buffer_unref(GST_BUFFER(buffer.buffer));
+  }
+  return ret == 0;
+}
+
+namespace internal {
+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;
+    default:
+      return kTrackRendererDisplayModeDisplayMax;
+  }
+}
+
+}  // namespace internal
+
+}  // namespace plusplayer
diff --git a/src/mixer/src/mixedframe.cpp b/src/mixer/src/mixedframe.cpp
new file mode 100755 (executable)
index 0000000..e4e2328
--- /dev/null
@@ -0,0 +1,143 @@
+#include "mixer/mixedframe.h"
+
+#include <cstring>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/interfaces/accessiblebuffer.h"
+
+namespace plusplayer {
+MixedFramePtr MixedFrame::Create(const MemoryAllocator* const memop,
+                                 const std::uint32_t width,
+                                 const std::uint32_t height) {
+  return Ptr(new MixedFrame(memop, width, height));
+}
+
+MixedFrame::MixedFrame(const MemoryAllocator* const memop,
+                       const std::uint32_t width, const std::uint32_t height)
+    : width_(width), height_(height) {
+  if (memop == nullptr) return;
+  const auto size = CalculateBufferSize_(width_, height_);
+  if (size == 0) return;
+  buffer_ = BufferObjectPtr(memop->Allocate(size));
+  if (buffer_ == nullptr) return;
+  allocated_size_ = buffer_->GetSize();
+  if (allocated_size_ == 0) return;
+
+  if (allocated_size_ != size) {
+    LOG_WARN("size mismatched request [%u] allocated [%u]", size,
+             allocated_size_);
+  }
+
+  if (auto* accessible_buffer =
+          dynamic_cast<AccessibleBuffer*>(buffer_.get())) {
+    auto ptr = accessible_buffer->GetWritableAddress();
+    if (ptr == nullptr) return;
+    const auto y_size = width_ * height_;
+    const auto uv_size = y_size >> 1;
+    {
+      std::memset(static_cast<char*>(ptr->GetAddress()), (char)0x00, y_size);
+      std::memset(static_cast<char*>(ptr->GetAddress()) + y_size, (char)0x80,
+                  uv_size);
+    }
+    LOG_DEBUG("MixedFrame UV memset done");
+  }
+}
+
+const std::vector<VideoPlaneManipulableInfo>
+MixedFrame::GetVideoPlaneManipInfo() const {
+  if (IsValid() == false) return {};
+  auto handle = buffer_->GetBufferHandle();
+  return {GetYComponentVMInfo_(handle), GetUVComponentVMInfo_(handle)};
+}
+
+bool MixedFrame::IsValid() const {
+  if (width_ == 0 || height_ == 0) return false;
+  if (allocated_size_ == 0) return false;
+  if (buffer_ == nullptr) return false;
+  return true;
+}
+
+std::uint32_t MixedFrame::GetWidth() const { return width_; }
+
+std::uint32_t MixedFrame::GetHeight() const { return height_; }
+
+std::uint32_t MixedFrame::GetSize() const {
+  if (IsValid() == false) return 0;
+  return allocated_size_;
+}
+
+bool MixedFrame::Render(const VideoPlaneManipulator* const vpmanip,
+                        const std::vector<VideoPlaneManipulableInfo>& planes,
+                        const Geometry& geom) {
+  if (vpmanip == nullptr) return false;
+  if (IsValid() == false) return false;
+  bool ret = true;
+  for (const auto& video_manipinfo : planes) {
+    ret &= vpmanip->Do(video_manipinfo, GetMixedFrameVideoPlaneManipulableInfo_(
+                                            video_manipinfo.component, geom));
+  }
+  return ret;
+}
+
+bool MixedFrame::Fill(const VideoPlaneColorManipulator* const vpmanip,
+                      const PlaneComponent& comp, const std::uint32_t& color,
+                      const Geometry& geom) {
+  VideoPlaneManipulableInfo info =
+      GetMixedFrameVideoPlaneManipulableInfo_(comp, geom);
+  return vpmanip->Do(color, info);
+}
+
+bool MixedFrame::Export(BufferKeyType& key) const {
+  if (IsValid() == false) return false;
+  key = buffer_->Export();
+  return true;
+}
+
+std::uint32_t MixedFrame::CalculateBufferSize_(const std::uint32_t width,
+                                               const std::uint32_t height) {
+  return (width * height * 3) >> 1;
+}
+
+VideoPlaneManipulableInfo MixedFrame::GetMixedFrameVideoPlaneManipulableInfo_(
+    const PlaneComponent component, const Geometry& geom) {
+  VideoPlaneManipulableInfo ret;
+  ret.handle = buffer_->GetBufferHandle();
+  ret.component = component;
+  ret.linesize = GetWidth();
+  if (component == PlaneComponent::kYComponent) {
+    ret.rect = geom;
+  } else {
+    ret.rect.x = geom.x / 2;
+    ret.rect.y = geom.y / 2 + GetHeight();
+    ret.rect.w = geom.w / 2;
+    ret.rect.h = geom.h / 2;
+  }
+  return ret;
+}
+
+VideoPlaneManipulableInfo MixedFrame::GetYComponentVMInfo_(
+    BufferHandleType handle) const {
+  VideoPlaneManipulableInfo info;
+  info.handle = handle;
+  info.linesize = GetWidth();
+  info.rect.x = 0;
+  info.rect.y = 0;
+  info.rect.w = GetWidth();
+  info.rect.h = GetHeight();
+  info.component = PlaneComponent::kYComponent;
+  return info;
+}
+
+VideoPlaneManipulableInfo MixedFrame::GetUVComponentVMInfo_(
+    BufferHandleType handle) const {
+  VideoPlaneManipulableInfo info;
+  info.handle = handle;
+  info.linesize = GetWidth();
+  info.rect.x = 0;
+  info.rect.y = GetHeight();
+  info.rect.w = GetWidth() >> 1;
+  info.rect.h = GetHeight() >> 1;
+  info.component = PlaneComponent::kUVComponent;
+  return info;
+}
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/mixer.cpp b/src/mixer/src/mixer.cpp
new file mode 100755 (executable)
index 0000000..b67e3bc
--- /dev/null
@@ -0,0 +1,14 @@
+#include "mixer/mixer.h"
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/defaultmixer.h"
+
+namespace plusplayer {
+
+std::unique_ptr<Mixer> Mixer::Create() {
+  auto instance = std::unique_ptr<DefaultMixer>(new DefaultMixer);
+  LOG_INFO("Create Mixer [%p]", instance.get());
+  return instance;
+}
+
+}  // namespace plusplayer
diff --git a/src/mixer/src/mixer_capi.cpp b/src/mixer/src/mixer_capi.cpp
new file mode 100755 (executable)
index 0000000..8cfb74c
--- /dev/null
@@ -0,0 +1,206 @@
+#include "mixer_capi/mixer_capi.h"
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/mixer.h"
+#include "mixer/mixer_eventlistener.h"
+#include "plusplayer/types/display.h"
+
+using plusplayer::Mixer;
+
+struct MixerPriv;
+
+class listener_bridge : public plusplayer::MixerEventListener {
+ public:
+  listener_bridge() { LOG_ENTER }
+  ~listener_bridge() { LOG_ENTER }
+
+  virtual void OnResourceConflicted() {
+    LOG_ENTER
+    if (this->resource_conflicted_cb_)
+      this->resource_conflicted_cb_(resource_conflicted_cb_userdata_);
+  }
+
+ private:
+  mixer_resource_conflicted_cb resource_conflicted_cb_ = nullptr;
+  void* resource_conflicted_cb_userdata_ = nullptr;
+
+  friend int mixer_set_resource_conflicted_cb(
+      mixer_handle pp, mixer_resource_conflicted_cb resource_conflicted_cb,
+      void* userdata);
+};
+
+struct MixerPriv {
+  std::unique_ptr<Mixer> mixer;
+  std::unique_ptr<listener_bridge> listener{new listener_bridge()};
+
+  friend MixerPriv* MixerPrivCreate();
+  friend void MixerPrivDestroy(MixerPriv*& instance);
+
+ private:
+  MixerPriv() {}
+  ~MixerPriv() {}
+};
+
+MixerPriv* MixerPrivCreate() {
+  MixerPriv* instance = new MixerPriv();
+  instance->mixer = Mixer::Create();
+  instance->mixer->RegisterListener(instance->listener.get());
+  return instance;
+}
+
+void MixerPrivDestroy(MixerPriv*& instance) {
+  if (instance) delete instance;
+  instance = nullptr;
+}
+
+inline bool is_null_(void* object) { return object == nullptr; }
+
+inline Mixer* cast_(mixer_handle mixer) {
+  auto priv = static_cast<MixerPriv*>(mixer);
+  return priv->mixer.get();
+}
+
+inline listener_bridge* listener_cast_(mixer_handle pp) {
+  auto priv = static_cast<MixerPriv*>(pp);
+  return priv->listener.get();
+}
+
+inline int convert_return_type_(bool ret) {
+  return ret ? MIXER_ERROR_TYPE_NONE : MIXER_ERROR_TYPE_INVALID_OPERATION;
+}
+
+mixer_handle mixer_create() {
+  LOG_ENTER
+  mixer_handle mixer = static_cast<mixer_handle>(MixerPrivCreate());
+  return mixer;
+}
+
+int mixer_destroy(mixer_handle handle) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+    
+  auto priv = static_cast<MixerPriv*>(handle);
+  MixerPrivDestroy(priv);
+  
+  return MIXER_ERROR_TYPE_NONE;
+}
+
+int mixer_start(mixer_handle handle) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->Start());
+}
+
+int mixer_stop(mixer_handle handle) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->Stop());
+}
+
+int mixer_get_max_allowed_number_of_player(mixer_handle handle) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return cast_(handle)->GetMaximumAllowedNumberOfPlayer();
+}
+
+int mixer_set_display(mixer_handle handle, mixer_display_type type,
+                      void* window) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->SetDisplay(
+      static_cast<plusplayer::DisplayType>(type), window));
+}
+
+int mixer_set_display_mode(mixer_handle handle, mixer_display_mode mode) {
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO("display mode : %d", static_cast<int>(mode));
+  return convert_return_type_(cast_(handle)->SetDisplayMode(
+      static_cast<plusplayer::DisplayMode>(mode)));
+}
+
+int mixer_set_display_roi(mixer_handle handle, const int x, const int y,
+                          const int width, const int height) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+  LOG_INFO("x : %d, y: %d, width : %d, height : %d", x, y, width, height);
+  plusplayer::Geometry roi;
+  roi.x = x;
+  roi.y = y;
+  roi.w = width;
+  roi.h = height;
+  return convert_return_type_(cast_(handle)->SetDisplayRoi(roi));
+}
+
+int mixer_set_rsc_alloc_mode(mixer_handle handle,
+                             const mixer_rsc_alloc_mode mode) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->SetRscAllocMode(
+      static_cast<plusplayer::RscAllocMode>(mode)));
+}
+
+int mixer_disable_audio_focus_setting(mixer_handle handle) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->DisableAudioFocusSetting());
+}
+
+int mixer_set_alternative_video_scaler(mixer_handle handle) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->SetAlternativeVideoScaler());
+}
+
+int mixer_set_audio_focus(mixer_handle handle, const void* player_instance) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->SetAudioFocus(player_instance));
+}
+
+int mixer_commit(mixer_handle handle) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+
+  return convert_return_type_(cast_(handle)->Commit());
+}
+
+int mixer_set_resolution(mixer_handle handle, const int width, const int height,
+                         const int framerate_num, const int framerate_den) {
+  LOG_ENTER
+  if (is_null_(handle)) return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+  plusplayer::Mixer::ResolutionInfo info;
+  info.width = width;
+  info.height = height;
+  info.framerate_num = framerate_num;
+  info.framerate_den = framerate_den;
+  return convert_return_type_(cast_(handle)->SetResolution(info));
+}
+
+mixer_ticket_h mixer_create_ticket(mixer_handle handle, const void* player_instance) {
+  LOG_ENTER
+  if (is_null_(handle)) return nullptr;
+
+  return cast_(handle)->CreateTicket(player_instance);
+}
+
+int mixer_set_resource_conflicted_cb(
+    mixer_handle handle, mixer_resource_conflicted_cb resource_conflicted_cb,
+    void* userdata) {
+  LOG_ENTER
+  listener_bridge* listener = nullptr;
+  if (is_null_(handle) || is_null_(listener = listener_cast_(handle))) {
+    LOG_ERROR("Mixer or Listener object is nil.");
+    return MIXER_ERROR_TYPE_INVALID_PARAMETER;
+  }
+  listener->resource_conflicted_cb_ = resource_conflicted_cb;
+  listener->resource_conflicted_cb_userdata_ = userdata;
+  return convert_return_type_(true);
+}
diff --git a/src/mixer/src/renderer.cpp b/src/mixer/src/renderer.cpp
new file mode 100755 (executable)
index 0000000..af48db1
--- /dev/null
@@ -0,0 +1,252 @@
+#include "mixer/renderer.h"
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+using std::chrono::duration_cast;
+using std::chrono::milliseconds;
+using std::chrono::system_clock;
+
+Renderer::Renderer(const RenderableObjectFactory& mf_factory,
+                   const Mixer::ResolutionInfo& rinfo,
+                   RendererEventListener* listener)
+    : resolution_info_(rinfo),
+      listener_(listener),
+      frame_(RenderableObjectPtr(mf_factory.CreateRenderableObject(
+          resolution_info_.width, resolution_info_.height))) {}
+
+Renderer::~Renderer() { Stop(); }
+
+bool Renderer::IsValid() const {
+  if (frame_ == nullptr) return false;
+  if (frame_->IsValid() == false) return false;
+  return IsValid_();
+}
+
+bool Renderer::Start() {
+  std::unique_lock<std::mutex> lk(rendering_mtx_);
+  if (IsValid() == false) return false;
+  if (rendering_worker_.joinable()) return false;
+  rendering_flag_ = true;
+  rendering_worker_ = std::thread(&Renderer::RenderingWorker_, this);
+  return true;
+}
+
+bool Renderer::Stop() {
+  {
+    std::unique_lock<std::mutex> lk(rendering_mtx_);
+    if (rendering_worker_.joinable() == false) return false;
+    rendering_flag_ = false;
+    rendering_cv_.notify_all();
+  }
+  rendering_worker_.join();
+  return true;
+}
+
+bool Renderer::ChangeResolution(const RenderableObjectFactory& mf_factory,
+                                const std::uint32_t& width,
+                                const std::uint32_t& height) {
+  if (width == 0 || height == 0) return false;
+  if (width == static_cast<std::uint32_t>(resolution_info_.width) &&
+      height == static_cast<std::uint32_t>(resolution_info_.height))
+    return false;
+  return ChangeResolutionInternal_(mf_factory, width, height);
+}
+
+bool Renderer::ChangeResolutionInternal_(
+    const RenderableObjectFactory& mf_factory, const std::uint32_t& width,
+    const std::uint32_t& height) {
+  std::unique_lock<std::mutex> lk(rendering_mtx_);
+  resolution_info_.width = width;
+  resolution_info_.height = height;
+  frame_.reset(nullptr);
+  frame_ = RenderableObjectPtr(mf_factory.CreateRenderableObject(
+      resolution_info_.width, resolution_info_.height));
+  return IsValid();
+}
+
+bool Renderer::ChangeRenderingSpeed(const std::uint32_t framerate_num,
+                                    const std::uint32_t framerate_den) {
+  if (framerate_num == 0 || framerate_den == 0) return false;
+  if (framerate_num ==
+          static_cast<std::uint32_t>(resolution_info_.framerate_num) &&
+      framerate_den ==
+          static_cast<std::uint32_t>(resolution_info_.framerate_den))
+    return false;
+  std::unique_lock<std::mutex> lk(rendering_mtx_);
+  if (IsValid() == false) return false;
+  resolution_info_.framerate_num = framerate_num;
+  resolution_info_.framerate_den = framerate_den;
+  return true;
+}
+
+bool Renderer::Render(const VideoPlaneScaler* const scaler,
+                      const VideoPlaneCollection* const planes,
+                      const Geometry& geom) {
+  if (scaler == nullptr) return false;
+  if (planes == nullptr) return false;
+  return RenderInternal_(scaler->GetScaleManipulator(),
+                         planes->GetVideoPlaneManipInfo(), geom);
+}
+
+bool Renderer::RenderInternal_(
+    const VideoPlaneManipulator* const scaler,
+    const std::vector<VideoPlaneManipulableInfo>& planes,
+    const Geometry& geom) {
+  if (scaler == nullptr) return false;
+  const auto before = system_clock::now();
+  std::unique_lock<std::mutex> lk(rendering_mtx_);
+  if (IsValid() == false) return false;
+  LOG_INFO("[PERF] RenderInternal_ Lock [%llu]ms",
+           std::chrono::duration_cast<std::chrono::milliseconds>(
+               system_clock::now() - before)
+               .count());
+  const auto ret = frame_->Render(scaler, planes, geom);
+  LOG_INFO("[PERF] Scale [%llu]ms",
+           std::chrono::duration_cast<std::chrono::milliseconds>(
+               system_clock::now() - before)
+               .count());
+  return ret;
+}
+
+bool Renderer::Mute(const VideoPlaneColorFiller* const filler,
+                    const Geometry& geom) {
+  if (filler == nullptr) return false;
+  return MuteInternal_(filler->GetColorFillManipulator(), geom);
+}
+
+bool Renderer::MuteInternal_(const VideoPlaneColorManipulator* const filler,
+                             const Geometry& geom) {
+  if (filler == nullptr) return false;
+  std::unique_lock<std::mutex> lk(rendering_mtx_);
+  if (IsValid() == false) return false;
+  bool ret = true;
+  ret &= frame_->Fill(filler, PlaneComponent::kYComponent, 0x00, geom);
+  ret &= frame_->Fill(filler, PlaneComponent::kUVComponent, 0x8080, geom);
+  return ret;
+}
+
+bool Renderer::Move(const VideoPlaneColorFiller* const filler,
+                    const std::vector<VideoPlaneMoveInfo>& moving_planes) {
+  if (filler == nullptr) return false;
+  if (moving_planes.size() == 0) return false;
+  return MoveInternal_(filler->GetColorFillManipulator(), moving_planes);
+}
+
+bool Renderer::MoveInternal_(
+    const VideoPlaneColorManipulator* const filler,
+    const std::vector<VideoPlaneMoveInfo>& moving_planes) {
+  if (filler == nullptr) return false;
+  std::unique_lock<std::mutex> lk(rendering_mtx_);
+  if (IsValid() == false) return false;
+  bool ret = true;
+  for (const auto& move : moving_planes) {
+    if (IsSameGeometry_(move.cur, move.target)) continue;
+    ret &= frame_->Fill(filler, PlaneComponent::kYComponent, 0x00, move.cur);
+    ret &= frame_->Fill(filler, PlaneComponent::kUVComponent, 0x8080, move.cur);
+  }
+  return true;
+};
+
+bool Renderer::OnRenderingBefore_(const RenderableObject* const frame) {
+  return true;
+}
+
+bool Renderer::IsValid_() const { return true; }
+
+bool Renderer::RaiseOnRenderingReleaseEvent_(const BufferKeyType& key) {
+  if (listener_ == nullptr) return false;
+  return listener_->OnRenderingRelease(key);
+}
+
+std::uint32_t Renderer::GetNextRenderingTimeWithJitter_(
+    const JitterType& jitter) const {
+  const static std::int64_t kOneSecondInMs = 1000;  // ms
+  auto next = kOneSecondInMs /
+              (resolution_info_.framerate_num / resolution_info_.framerate_den);
+  auto jitter_in_ms = jitter.count();
+  LOG_DEBUG("[PERF] jitter : [%lld]ms / next : [%lld]ms", jitter_in_ms, next);
+  jitter_in_ms %= next;
+  next -= jitter_in_ms;
+  return next < 0 ? 0 : static_cast<std::uint32_t>(next);
+}
+
+void Renderer::RenderingWorker_() {
+  LOG_DEBUG("Start Rendering");
+  JitterType jitter(0);
+  while (1) {
+    LOG_DEBUG("= Start New Frame ===========================================");
+    auto before_1 = system_clock::now();
+    std::unique_lock<std::mutex> lk(rendering_mtx_);
+    if (rendering_flag_ == false) break;
+    if (OnRenderingBefore_(frame_.get()) == false) {
+      LOG_WARN("OnRenderingBefore_ Failed");
+      continue;
+    }
+
+    LOG_DEBUG(
+        "[PERF] before_1 ~ now : [%lld]ms",
+        duration_cast<milliseconds>(system_clock::now() - before_1).count());
+    jitter += duration_cast<milliseconds>(system_clock::now() - before_1);
+
+    std::uint64_t next_in_ms = GetNextRenderingTimeWithJitter_(jitter);
+
+    jitter = JitterType::zero();
+    auto before_2 = system_clock::now();
+    LOG_DEBUG("[PULSE] it will awake after [%llu]ms", next_in_ms);
+    if (next_in_ms > 0) {
+      rendering_cv_.wait_for(lk, milliseconds(next_in_ms),
+                             [this] { return rendering_flag_ == false; });
+      // LOG_DEBUG(
+      //     "[PERF] before_2 ~ after awake : [%lld]ms",
+      //     duration_cast<milliseconds>(system_clock::now() -
+      //     before_2).count());
+      if (rendering_flag_ == false) break;
+    }
+    if (IsValid() == false) continue;
+
+    BufferKeyType key;
+    if (frame_->Export(key) == false) {
+      LOG_ERROR("MixedFrame Export Failed");
+      continue;
+    }
+
+    RaiseOnRenderingReleaseEvent_(key);
+    jitter = duration_cast<milliseconds>(system_clock::now() - before_2 -
+                                         milliseconds(next_in_ms));
+    // LOG_DEBUG(
+    //     "[PERF] before_2 ~ now : [%lld]ms / next_in_ms : [%llu]ms",
+    //     duration_cast<milliseconds>(system_clock::now() - before_2).count(),
+    //     next_in_ms);
+  }
+  std::unique_lock<std::mutex> lk(rendering_mtx_);
+  rendering_flag_ = false;
+  LOG_DEBUG("Rendering Stopped");
+}
+
+const Mixer::ResolutionInfo& Renderer::GetResolutionInfo_() const {
+  return resolution_info_;
+}
+
+RenderableObjectPtr& Renderer::GetMixedFrame_() { return frame_; }
+
+void Renderer::AcquireRenderingLock_() { rendering_mtx_.lock(); }
+
+void Renderer::ReleaseRenderingLock_() { rendering_mtx_.unlock(); }
+
+Geometry Renderer::MakeGeometry_(const std::uint32_t& width,
+                                 const std::uint32_t& height) {
+  Geometry geom;
+  geom.w = width;
+  geom.h = height;
+  return geom;
+}
+
+bool Renderer::IsSameGeometry_(const Geometry& g1, const Geometry& g2) {
+  if (g1.x != g2.x) return false;
+  if (g1.y != g2.y) return false;
+  if (g1.w != g2.w) return false;
+  if (g1.h != g2.h) return false;
+  return true;
+}
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/sys/tbminterface.cpp b/src/mixer/src/sys/tbminterface.cpp
new file mode 100755 (executable)
index 0000000..094a7f3
--- /dev/null
@@ -0,0 +1,50 @@
+#include "mixer/sys/tbminterface.h"
+
+#include <tbm_bo.h>
+#include <tbm_bufmgr.h>
+
+namespace plusplayer {
+namespace tizen {
+BufferDefaultType TBMInterface::BoRef(BufferDefaultType bo) {
+  return tbm_bo_ref(bo);
+}
+void TBMInterface::BoUnRef(BufferDefaultType bo) { tbm_bo_unref(bo); }
+
+int TBMInterface::BoSize(BufferDefaultType bo) { return tbm_bo_size(bo); }
+
+BufferUnionHandleType TBMInterface::BoGetHandle(BufferDefaultType bo,
+                                                int device) {
+  return tbm_bo_get_handle(bo, device);
+}
+
+BufferUnionHandleType TBMInterface::BoMap(BufferDefaultType bo, int device,
+                                          int option) {
+  return tbm_bo_map(bo, device, option);
+}
+
+void TBMInterface::BoUnmap(BufferDefaultType bo) { tbm_bo_unmap(bo); }
+
+BufferKeyType TBMInterface::BoExport(BufferDefaultType bo) {
+  return tbm_bo_export(bo);
+}
+
+BufferDefaultType TBMInterface::BoAlloc(tbm_bufmgr bufmgr, int size, int flag) {
+  return tbm_bo_alloc(bufmgr, size, flag);
+}
+BufferDefaultType TBMInterface::BoImport(tbm_bufmgr bufmgr, BufferKeyType key) {
+  return tbm_bo_import(bufmgr, key);
+}
+
+int TBMInterface::GAScale(tbm_bufmgr bufmgr, GraphicsGAScaleInfo* info) {
+  return Gfx_GA_Scale(bufmgr, info);
+}
+
+int TBMInterface::GACopy(tbm_bufmgr bufmgr, GraphicsGABltRopInfo* info) {
+  return Gfx_GA_BltRop(bufmgr, info);
+}
+
+int TBMInterface::GAFill(tbm_bufmgr bufmgr, GraphicsGAFillRectInfo* info) {
+  return Gfx_GA_FillRect(bufmgr, info);
+}
+}  // namespace tizen
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/tizen/tizenaccessiblebufferobj.cpp b/src/mixer/src/tizen/tizenaccessiblebufferobj.cpp
new file mode 100755 (executable)
index 0000000..49cab1f
--- /dev/null
@@ -0,0 +1,23 @@
+#include "mixer/tizen/tizenaccessiblebufferobj.h"
+
+namespace plusplayer {
+
+TizenAccessibleBufferObject::TizenAccessibleBufferObject(
+    BufferDefaultType buffer)
+    : TizenBufferObject(buffer) {}
+
+TizenAccessibleBufferObject::PhyAddrAccessorPtr
+TizenAccessibleBufferObject::GetReadableAddress() const {
+  if (IsValid() == false) return nullptr;
+  return PhyAddrAccessorPtr(
+      new TizenReadableBufferPhyAddrAccessor(GetBuffer_()));
+}
+
+TizenAccessibleBufferObject::PhyAddrAccessorPtr
+TizenAccessibleBufferObject::GetWritableAddress() const {
+  if (IsValid() == false) return nullptr;
+  return PhyAddrAccessorPtr(
+      new TizenWritableBufferPhyAddrAccessor(GetBuffer_()));
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/tizen/tizenbufferkeyvideoframe.cpp b/src/mixer/src/tizen/tizenbufferkeyvideoframe.cpp
new file mode 100755 (executable)
index 0000000..9d10b5d
--- /dev/null
@@ -0,0 +1,34 @@
+#include "mixer/tizen/tizenbufferkeyvideoframe.h"
+
+namespace plusplayer {
+
+TizenBufferKeyVideoFrame::TizenBufferKeyVideoFrame(
+    const TizenBufferManager* const bufmgr, const BufferKeyType& key,
+    const std::uint32_t& width, const std::uint32_t& height)
+    : key_(key), width_(width), height_(height) {
+  if (bufmgr == nullptr) return;
+  if (key_ == 0) return;
+  if (width_ == 0 || height_ == 0) return;
+
+  auto buffer = BufferObjectPtr(bufmgr->Import(key_));
+  if (buffer == nullptr) return;
+  RegisterVideoPlaneManipulablePtr_(VideoPlaneManipulablePtr(
+      new YComponentVideoPlaneWithSharedMemory(buffer, width_, height_)));
+  RegisterVideoPlaneManipulablePtr_(VideoPlaneManipulablePtr(
+      new UVComponentVideoPlaneWithSharedMemory(buffer, width_, height_)));
+}
+
+bool TizenBufferKeyVideoFrame::IsValid_() const {
+  if (key_ == 0) return false;
+  return true;
+}
+
+const std::uint32_t TizenBufferKeyVideoFrame::GetWidth_() const {
+  return width_;
+}
+
+const std::uint32_t TizenBufferKeyVideoFrame::GetHeight_() const {
+  return height_;
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/tizen/tizendefaultphyaddraccessor.cpp b/src/mixer/src/tizen/tizendefaultphyaddraccessor.cpp
new file mode 100755 (executable)
index 0000000..681c8ae
--- /dev/null
@@ -0,0 +1,12 @@
+#include "mixer/tizen/tizendefaultphyaddraccessor.h"
+
+namespace plusplayer {
+
+TizenDefaultPhyAddrAccessor::TizenDefaultPhyAddrAccessor(std::uint32_t viraddr)
+    : viraddr_(viraddr) {}
+
+BufferPhysicalAddrType TizenDefaultPhyAddrAccessor::GetAddress() {
+  return reinterpret_cast<BufferPhysicalAddrType>(viraddr_);
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/tizen/tizenhwbufferobj.cpp b/src/mixer/src/tizen/tizenhwbufferobj.cpp
new file mode 100755 (executable)
index 0000000..2ca0a4d
--- /dev/null
@@ -0,0 +1,28 @@
+#include "mixer/tizen/tizenhwbufferobj.h"
+
+// #include "mixer/tizen/tizendefaultphyaddraccessor.h"
+
+namespace plusplayer {
+TizenHWBufferObject::TizenHWBufferObject(const std::uint32_t& width,
+                                         const std::uint32_t& height,
+                                         const DecodedRawPlaneInfo& info)
+    : width_(width), height_(height), info_(info) {}
+
+bool TizenHWBufferObject::IsValid() const {
+  if (info_.phyaddr == 0) return false;
+  if (width_ == 0 || height_ == 0 || info_.linesize == 0) return false;
+  return true;
+}
+
+BufferHandleType TizenHWBufferObject::GetBufferHandle() const {
+  if (IsValid() == false) return kInvalidBufferHandle;
+  return static_cast<BufferHandleType>(info_.phyaddr);
+}
+
+BufferKeyType TizenHWBufferObject::Export() const { return kInvalidBufferKey; }
+
+std::uint32_t TizenHWBufferObject::GetSize() const {
+  return height_ * info_.linesize;
+}
+
+}  // namespace plusplayer
diff --git a/src/mixer/src/tizen/tizenhwvideoframe.cpp b/src/mixer/src/tizen/tizenhwvideoframe.cpp
new file mode 100755 (executable)
index 0000000..136d12e
--- /dev/null
@@ -0,0 +1,44 @@
+#include "mixer/tizen/tizenhwvideoframe.h"
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/tizen/tizenhwbufferobj.h"
+#include "mixer/videoplane.h"
+
+namespace plusplayer {
+
+TizenHWVideoFrame::TizenHWVideoFrame(const DecodedRawInfo& info) : info_(info) {
+  if (IsValid_() == false) return;
+
+  RegisterVideoPlaneManipulablePtr_(VideoPlaneManipulablePtr(
+      new YComponentVideoPlane(BufferObjectPtr(new TizenHWBufferObject(
+                                   info_.width, info_.height, info_.y_info)),
+                               info_.width, info_.height)));
+  RegisterVideoPlaneManipulablePtr_(
+      VideoPlaneManipulablePtr(new UVComponentVideoPlane(
+          BufferObjectPtr(new TizenHWBufferObject(
+              info_.width / 2, info_.height / 2, info_.uv_info)),
+          info_.width, info_.height)));
+}
+
+bool TizenHWVideoFrame::IsValid_() const {
+  if (info_.y_info.phyaddr == 0) return false;
+  if (info_.y_info.linesize == 0) return false;
+  if (info_.uv_info.phyaddr == 0) return false;
+  if (info_.uv_info.linesize == 0) return false;
+  return true;
+}
+
+const std::uint32_t TizenHWVideoFrame::GetWidth_() const { return info_.width; }
+
+const std::uint32_t TizenHWVideoFrame::GetHeight_() const {
+  return info_.height;
+}
+
+void TizenHWVideoFrame::PrintDecodedRawInfo() const {
+  LOG_DEBUG("WxH [%ux%u] Y [%u %u %u] / UV [%u %u %u]", info_.width,
+            info_.height, info_.y_info.phyaddr, info_.y_info.viraddr,
+            info_.y_info.linesize, info_.uv_info.phyaddr, info_.uv_info.viraddr,
+            info_.uv_info.linesize);
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/tizen/tizenrenderableobj_factory.cpp b/src/mixer/src/tizen/tizenrenderableobj_factory.cpp
new file mode 100755 (executable)
index 0000000..e678026
--- /dev/null
@@ -0,0 +1,16 @@
+#include "mixer/tizen/tizenrenderableobj_factory.h"
+
+#include "mixer/mixedframe.h"
+
+namespace plusplayer {
+
+TizenRenderableObjectFactory::TizenRenderableObjectFactory(
+    const MemoryAllocator* const memallocator)
+    : memallocator_(memallocator) {}
+
+RenderableObject* TizenRenderableObjectFactory::CreateRenderableObject(
+    const std::uint32_t width, const std::uint32_t height) const {
+  return new MixedFrame(memallocator_, width, height);
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/tizen/tizensurfacevideoframe.cpp b/src/mixer/src/tizen/tizensurfacevideoframe.cpp
new file mode 100755 (executable)
index 0000000..ed6030c
--- /dev/null
@@ -0,0 +1,43 @@
+#include "mixer/tizen/tizensurfacevideoframe.h"
+
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+
+#include "mixer/tizen/tizenbufferobj.h"
+#include "mixer/videoplane.h"
+
+namespace plusplayer {
+
+TizenSurfaceVideoFrame::TizenSurfaceVideoFrame(DecodedVideoPacketExPtr dvp)
+    : dvp_(std::move(dvp)) {
+  auto surface = dvp_->GetTbmSurface();
+  if (surface == nullptr) return;
+
+  width_ = tbm_surface_get_width(surface);
+  height_ = tbm_surface_get_height(surface);
+  if (width_ == 0 || height_ == 0) return;
+
+  auto y_bo = tbm_surface_internal_get_bo(surface, kYIndex);
+  auto uv_bo = tbm_surface_internal_get_bo(surface, kUVIndex);
+  if (y_bo == nullptr || uv_bo == nullptr) return;
+
+  RegisterVideoPlaneManipulablePtr_(
+      VideoPlaneManipulablePtr(new YComponentVideoPlane(
+          BufferObjectPtr(new TizenBufferObject(y_bo)), width_, height_)));
+  RegisterVideoPlaneManipulablePtr_(
+      VideoPlaneManipulablePtr(new UVComponentVideoPlane(
+          BufferObjectPtr(new TizenBufferObject(uv_bo)), width_, height_)));
+}
+
+bool TizenSurfaceVideoFrame::IsValid_() const {
+  if (dvp_ == nullptr) return false;
+  return true;
+}
+
+const std::uint32_t TizenSurfaceVideoFrame::GetWidth_() const { return width_; }
+
+const std::uint32_t TizenSurfaceVideoFrame::GetHeight_() const {
+  return height_;
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/mixer/src/videoplane.cpp b/src/mixer/src/videoplane.cpp
new file mode 100755 (executable)
index 0000000..64ccbc8
--- /dev/null
@@ -0,0 +1,114 @@
+#include "mixer/videoplane.h"
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+/******************************************************************************
+ * VideoPlane
+ */
+VideoPlane::VideoPlane(PlaneComponent component, const std::uint32_t& width,
+                       const std::uint32_t& height)
+    : component_(component), width_(width), height_(height) {}
+
+bool VideoPlane::IsValid() const {
+  if (GetBufferObject_() == nullptr) return false;
+  if (width_ == 0 || height_ == 0 || GetLineSize_() == 0) return false;
+  return true;
+}
+
+VideoPlaneManipulableInfo VideoPlane::GetVideoPlaneManipulableInfo() const {
+  VideoPlaneManipulableInfo info;
+  info.component = component_;
+  info.handle = GetBufferObject_()->GetBufferHandle();
+  info.linesize = GetLineSize_();
+  info.rect.x = width_ * croparea_.scale_x;
+  info.rect.y = height_ * croparea_.scale_y;
+  info.rect.w = width_ * croparea_.scale_w;
+  info.rect.h = height_ * croparea_.scale_h;
+  return info;
+}
+
+void VideoPlane::SetCropArea(const CropArea& croparea) { croparea_ = croparea; }
+
+std::uint32_t VideoPlane::GetLineSize_() const {
+  return GetBufferObject_()->GetSize() / height_;
+}
+
+/******************************************************************************
+ * YComponentVideoPlane
+ */
+
+YComponentVideoPlane::YComponentVideoPlane(BufferObjectPtr buffer,
+                                           const std::uint32_t& width,
+                                           const std::uint32_t& height)
+    : VideoPlane(PlaneComponent::kYComponent, width, height),
+      buffer_(std::move(buffer)) {}
+
+const BufferObject* const YComponentVideoPlane::GetBufferObject_() const {
+  return buffer_.get();
+}
+
+/******************************************************************************
+ * UVComponentVideoPlane
+ */
+
+UVComponentVideoPlane::UVComponentVideoPlane(BufferObjectPtr buffer,
+                                             const std::uint32_t& width,
+                                             const std::uint32_t& height)
+    : VideoPlane(PlaneComponent::kUVComponent, width / 2, height / 2),
+      buffer_(std::move(buffer)) {}
+
+const BufferObject* const UVComponentVideoPlane::GetBufferObject_() const {
+  return buffer_.get();
+}
+
+/******************************************************************************
+ * YComponentVideoPlaneWithSharedMemory
+ */
+
+YComponentVideoPlaneWithSharedMemory::YComponentVideoPlaneWithSharedMemory(
+    BufferObjectWeakPtr buffer, const std::uint32_t& width,
+    const std::uint32_t& height)
+    : VideoPlane(PlaneComponent::kYComponent, width, height),
+      buffer_(buffer),
+      width_(width) {}
+
+std::uint32_t YComponentVideoPlaneWithSharedMemory::GetLineSize_() const {
+  return width_;
+}
+
+const BufferObject* const
+YComponentVideoPlaneWithSharedMemory::GetBufferObject_() const {
+  return buffer_.get();
+}
+
+/******************************************************************************
+ * UVComponentVideoPlaneWithSharedMemory
+ */
+
+UVComponentVideoPlaneWithSharedMemory::UVComponentVideoPlaneWithSharedMemory(
+    BufferObjectWeakPtr buffer, const std::uint32_t& width,
+    const std::uint32_t& height)
+    : VideoPlane(PlaneComponent::kUVComponent, width / 2, height / 2),
+      buffer_(buffer),
+      width_(width),
+      height_(height) {}
+
+VideoPlaneManipulableInfo
+UVComponentVideoPlaneWithSharedMemory::GetVideoPlaneManipulableInfo() const {
+  auto info = VideoPlane::GetVideoPlaneManipulableInfo();
+  info.rect.y += height_;
+  return info;
+}
+
+std::uint32_t UVComponentVideoPlaneWithSharedMemory::GetLineSize_() const {
+  return width_;
+}
+
+const BufferObject* const
+UVComponentVideoPlaneWithSharedMemory::GetBufferObject_() const {
+  return buffer_.get();
+}
+
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/src/plusplayer-core/Build/appendix.mk b/src/plusplayer-core/Build/appendix.mk
new file mode 100755 (executable)
index 0000000..2e06c34
--- /dev/null
@@ -0,0 +1 @@
+# Appendix\r
diff --git a/src/plusplayer-core/Build/basedef.mk b/src/plusplayer-core/Build/basedef.mk
new file mode 100755 (executable)
index 0000000..a7a0869
--- /dev/null
@@ -0,0 +1,34 @@
+# Add inputs and outputs from these tool invocations to the build variables\r
+\r
+\r
+OS_NAME := $(shell $(UNAME))\r
+\r
+\r
+#ifeq ($(origin BUILD_CONFIG), undefined)\r
+BUILD_CONFIG ?= Debug\r
+#endif\r
+\r
+#ifeq ($(origin ARCH), undefined)\r
+ARCH ?= i386\r
+#endif\r
+\r
+#ifeq ($(origin PROJPATH), undefined)\r
+PROJPATH ?= .\r
+#endif\r
+\r
+\r
+#ifeq ($(origin PROJ_PATH), undefined)\r
+PROJ_PATH ?= $(PROJPATH)\r
+#endif\r
+\r
+#ifeq ($(strip $(OUTPUT_DIR)),)\r
+#OUTPUT_DIR ?= $(PROJ_PATH)/$(BUILD_CONFIG)\r
+#endif\r
+\r
+#ifeq ($(strip $(BUILD_ARCH)),)\r
+BUILD_ARCH ?= $(ARCH)\r
+#endif\r
+\r
+#ifeq ($(strip $(ENVENTOR_PATH)),)\r
+ENVENTOR_PATH ?= $(SDK_TOOLPATH)/enventor\r
+#endif\r
diff --git a/src/plusplayer-core/Build/build_c.mk b/src/plusplayer-core/Build/build_c.mk
new file mode 100755 (executable)
index 0000000..4ef9699
--- /dev/null
@@ -0,0 +1,113 @@
+# C/C++ build script\r
+\r
+\r
+_FUNC_EXT2O = $(patsubst %.$(3),$(1)/%.o,$(2))\r
+_FUNC_C2O = $(call _FUNC_EXT2O,$(1),$(2),c)\r
+_FUNC_CPP2O = $(call _FUNC_EXT2O,$(1),$(2),cpp)\r
+\r
+\r
+# parameter :\r
+#  $(1) - C/C++ soruce file\r
+#  $(2) - output path\r
+#  $(3) - .ext\r
+#  $(4) - unique id\r
+CONVERT_ESC_EXT_TO_O = $(addprefix $(2)/,$(notdir $(patsubst %.$(3),%-$(4).o,$(1))))\r
+\r
+#CONVERT_ESC_C_TO_O = $(call CONVERT_ESC_EXT_TO_O,$(1),$(2),c)\r
+#CONVERT_ESC_CPP_TO_O = $(call CONVERT_ESC_EXT_TO_O,$(1),$(2),cpp)\r
+\r
+\r
+# parameter :\r
+#  $(1) - encoded one C/C++ soruce file\r
+#  $(2) - output path\r
+#  $(3) - ext title (C/C++)\r
+#  $(4) - ext (c/cpp)\r
+#  $(5) - compiler ($(CC)/$(CXX))\r
+#  $(6) - build opt\r
+#  $(7) - build opt file\r
+# output :\r
+#  $(8) - output files list\r
+define C_BUILD_PROC_RAW\r
+$(call CONVERT_ESC_EXT_TO_O,$(1),$(2),$(4),$(8)) : $(call DECODE_4MAKE,$(1)) $(7)\r
+       @echo '  Building file: $$<'\r
+       @echo '  Invoking: $(3) Compiler'\r
+       $$(call MAKEDIRS,$$(@D))\r
+       $(5) -c "$$<" -o "$$@" $(6) -Wp,@$(7)\r
+       @echo '  Finished building: $$<'\r
+$(9) += $(call CONVERT_ESC_EXT_TO_O,$(1),$(2),$(4),$(8))\r
+endef\r
+\r
+\r
+# parameter :\r
+#  $(1) - output paths\r
+#  $(2) - src paths\r
+#  $(3) - inc paths\r
+#  $(4) - inc files\r
+#  $(5) - Defs\r
+#  $(6) - UnDefs\r
+#  $(7) - compiler opt\r
+#  $(8) - compiler opt file\r
+#  $(9) - ext title (C/C++)\r
+#  $(10) - ext (c/cpp)\r
+#  $(11) - compiler ($(CC)/$(CXX))\r
+# output :\r
+#  $(12) - OBJS\r
+# return :\r
+#  none\r
+define C_PROC_RAW\r
+\r
+_OUTPUT_DIR := $$(strip $(1))#\r
+_SRCS := $(2)#\r
+_INCS := $(3)#\r
+_INC_FILES := $(4)#\r
+_DEFS := $(5)#\r
+_UNDEFS := $(6)#\r
+\r
+_OPT := $(7)\r
+_OPT_FILE := $(8)\r
+\r
+_EXT_TITLE := $(9)\r
+_EXT := $(10)\r
+_COMPILER := $(11)\r
+\r
+#_OUTPUT_FILES := $(12)\r
+\r
+_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_SRCS))\r
+_ENC_SRCS := $$(filter %.$$(_EXT),$$(_ENC_SRCS))\r
+\r
+ifneq ($$(strip $$(_SRCS)),)\r
+\r
+_NORMAL_SRCS := $$(filter-out %*.$$(_EXT),$$(_ENC_SRCS))\r
+_WIDLCARD_SRCS := $$(filter %*.$$(_EXT),$$(_ENC_SRCS))\r
+\r
+_ALL_SRCS := $$(call DECODE_4MAKE,$$(_NORMAL_SRCS)) \\r
+             $$(foreach var,$$(_WIDLCARD_SRCS),$$(call FIND_FILES_4MAKE,$$(call DECODE_4MAKE,$$(var))))\r
+\r
+ifneq ($$(strip $$(_ALL_SRCS)),)\r
+\r
+_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_ALL_SRCS))\r
+\r
+_CDEFS := $$(CDEFS)\r
+_CDEFS += $$(addprefix -D,$$(_DEFS))\r
+_CDEFS += $$(addprefix -U,$$(_UNDEFS))\r
+\r
+_ENC_C_INCS := $$(call ENCODE_4MAKE,$$(_INCS))\r
+_ENC_C_INCS := $$(addprefix -I,$$(_ENC_C_INCS))\r
+\r
+_ENC_INC_FILES := $$(call ENCODE_4MAKE,$$(_INC_FILES))\r
+_ENC_INC_FILES += $$(addprefix -include,$$(_ENC_INC_FILES))\r
+\r
+_C_INCS := $$(call DECODE_4MAKE,$$(_ENC_C_INCS) $$(_ENC_C_INC_FILES))\r
+\r
+_DEFS := $$(_CDEFS) $$(_C_INCS) -I"pch" $$(_OPT)\r
+\r
+_UNIQUE_ID = $$(firstword $$(shell echo $$(var) | $$(CKSUM)))\r
+\r
+$$(foreach var,$$(_ENC_SRCS),$$(eval $$(call C_BUILD_PROC_RAW,$$(var),$$(_OUTPUT_DIR),$$(_EXT_TITLE),$$(_EXT),$$(_COMPILER),$$(_DEFS),$$(_OPT_FILE),$$(_UNIQUE_ID),$(12))))\r
+\r
+endif  # (_(strip _(_ALL_SRCS)),)\r
+\r
+endif  # (_(strip _(_SRCS)),)\r
+\r
+\r
+endef\r
diff --git a/src/plusplayer-core/Build/build_edc.mk b/src/plusplayer-core/Build/build_edc.mk
new file mode 100755 (executable)
index 0000000..27ee648
--- /dev/null
@@ -0,0 +1,81 @@
+# EDC build script\r
+\r
+\r
+FUNC_EDC2EDJ = $(patsubst %.edc,$(2)/%.edj,$(1))\r
+\r
+# parameter :\r
+#  $(1) - C/C++ soruce file\r
+#  $(2) - output path\r
+CONVERT_ESC_EDC_TO_EDJ = $(call CONVERT_4MAKE_TO_OUT,$(call FUNC_EDC2EDJ,$(1),$(2)))\r
+\r
+\r
+# parameter :\r
+#  $(1) - encoded one C/C++ soruce file\r
+#  $(2) - output path\r
+#  $(3) - build opt\r
+# output :\r
+#  $(4) - output files list\r
+define EDJ_BUILD_PROC_RAW\r
+$(call CONVERT_ESC_EDC_TO_EDJ,$(1),$(2)) : $(call DECODE_4MAKE,$(1))\r
+       @echo '  Building file: $$<'\r
+       @echo '  Invoking: EDC Resource Compiler'\r
+       $$(call MAKEDIRS,$$(@D))\r
+       $$(EDJE_CC) $(3) "$$<" "$$@"\r
+       @echo '  Finished building: $$<'\r
+$(4) += $(call CONVERT_ESC_EDC_TO_EDJ,$(1),$(2))\r
+endef\r
+\r
+\r
+# parameter :\r
+#  $(1) - output paths\r
+#  $(2) - src paths\r
+#  $(3) - image inc paths\r
+#  $(4) - sound inc paths\r
+#  $(5) - font inc paths\r
+# output :\r
+#  $(6) - OBJS \r
+# return :\r
+#  none\r
+define EDJ_PROC_RAW\r
+\r
+_OUTPUT_DIR := $$(strip $(1))#\r
+_SRCS := $(2)# \r
+_IMAGE_DIRS := $(3)# \r
+_SOUND_DIRS := $(4)# \r
+_FONT_DIRS := $(5)# \r
+\r
+ifneq ($$(strip $$(_SRCS)),)\r
+\r
+_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_SRCS)) \r
+\r
+_NORMAL_SRCS := $$(filter-out %*.edc,$$(_ENC_SRCS))\r
+_WIDLCARD_SRCS := $$(filter %*.edc,$$(_ENC_SRCS))\r
+\r
+_ALL_SRCS := $$(call DECODE_4MAKE,$$(_NORMAL_SRCS)) \\r
+             $$(foreach var,$$(_WIDLCARD_SRCS),$$(call FIND_FILES_4MAKE,$$(call DECODE_4MAKE,$$(var))))\r
+\r
+ifneq ($$(strip $$(_ALL_SRCS)),)\r
+\r
+_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_ALL_SRCS)) \r
+\r
+_COMPILER_FLAGS := -id "$$(ENVENTOR_SHARED_RES_PATH)/images"\r
+_COMPILER_FLAGS += -sd "$$(ENVENTOR_SHARED_RES_PATH)/sounds"\r
+_COMPILER_FLAGS += -fd "$$(ENVENTOR_SHARED_RES_PATH)/fonts"\r
+\r
+ifneq ($$(strip $$(_IMAGE_DIRS)),)\r
+_COMPILER_FLAGS += $$(addprefix -id ,$$(_IMAGE_DIRS))\r
+endif\r
+ifneq ($$(strip $$(_SOUND_DIRS)),)\r
+_COMPILER_FLAGS += $$(addprefix -sd ,$$(_SOUND_DIRS))\r
+endif\r
+ifneq ($$(strip $$(_FONT_DIRS)),)\r
+_COMPILER_FLAGS += $$(addprefix -fd ,$$(_FONT_DIRS))\r
+endif\r
+\r
+$$(foreach var,$$(_ENC_SRCS),$$(eval $$(call EDJ_BUILD_PROC_RAW,$$(var),$$(_OUTPUT_DIR),$$(_COMPILER_FLAGS),$(6))))\r
+\r
+endif  # (_(strip _(_ALL_SRCS)),)\r
+\r
+endif  # (_(strip _(_SRCS)),)\r
+\r
+endef\r
diff --git a/src/plusplayer-core/Build/build_po.mk b/src/plusplayer-core/Build/build_po.mk
new file mode 100755 (executable)
index 0000000..3453614
--- /dev/null
@@ -0,0 +1,64 @@
+# PO build script\r
+\r
+\r
+_FUNC_PO2MO = $(patsubst %.po,$(2)/res/locale/%/LC_MESSAGES/$(3).mo,$(notdir $(1)))\r
+\r
+\r
+# parameter :\r
+#  $(1) - C/C++ soruce file\r
+#  $(2) - output path\r
+#  $(3) - app name\r
+CONVERT_ESC_PO_TO_MO = $(call CONVERT_4MAKE_TO_OUT,$(call _FUNC_PO2MO,$(1),$(2),$(3)))\r
+\r
+\r
+# parameter :\r
+#  $(1) - encoded one C/C++ soruce file\r
+#  $(2) - output path\r
+#  $(3) - app name\r
+# output :\r
+#  $(4) - output files list\r
+define MO_BUILD_PROC_RAW\r
+$(call CONVERT_ESC_PO_TO_MO,$(1),$(2),$(3)) : $(call DECODE_4MAKE,$(1))\r
+       @echo '  Building file: $$<'\r
+       @echo '  Invoking: msgfmt String Formatter'\r
+       $$(call MAKEDIRS,$$(@D))\r
+       $$(MSGFMT) -o "$$@" "$$<"\r
+       @echo '  Finished building: $$<'\r
+$(4) += $(call CONVERT_ESC_PO_TO_MO,$(1),$(2),$(3))\r
+endef\r
+\r
\r
+# parameter :\r
+#  $(1) - output dir\r
+#  $(2) - src paths\r
+#  $(3) - app name\r
+# output :\r
+#  $(4) - OBJS \r
+\r
+define MO_PROC_RAW\r
+\r
+_OUTPUT_DIR := $(1)\r
+_SRCS := $(2)\r
+_APPNAME := $(3)\r
+\r
+ifneq ($$(strip $$(_SRCS)),)\r
+\r
+_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_SRCS)) \r
+\r
+_NORMAL_SRCS := $$(filter-out %*.po,$$(_ENC_SRCS))\r
+_WIDLCARD_SRCS := $$(filter %*.po,$$(_ENC_SRCS))\r
+\r
+_ALL_SRCS := $$(call DECODE_4MAKE,$$(_NORMAL_SRCS)) \\r
+             $$(foreach var,$$(_WIDLCARD_SRCS),$$(call FIND_FILES_4MAKE,$$(call DECODE_4MAKE,$$(var))))\r
+\r
+ifneq ($$(strip $$(_ALL_SRCS)),)\r
+\r
+_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_ALL_SRCS)) \r
+\r
+$$(foreach var,$$(_ENC_SRCS),$$(eval $$(call MO_BUILD_PROC_RAW,$$(var),$$(_OUTPUT_DIR),$$(_APPNAME),$(4))))\r
+\r
+endif  # (_(strip _(_ALL_SRCS)),)\r
+\r
+endif  # (_(strip _(_SRCS)),)\r
+\r
+endef\r
diff --git a/src/plusplayer-core/Build/flags.mk b/src/plusplayer-core/Build/flags.mk
new file mode 100755 (executable)
index 0000000..5c0a812
--- /dev/null
@@ -0,0 +1,23 @@
+ifeq ($(strip $(BUILD_CONFIG)),Debug)\r
+DEBUG_OP = -g2\r
+CPP_DEBUG_OP = -g2\r
+\r
+OPTIMIZATION_OP = -O1\r
+CPP_OPTIMIZATION_OP = -O1\r
+else\r
+DEBUG_OP = -g0\r
+CPP_DEBUG_OP = -g0\r
+\r
+OPTIMIZATION_OP = -O2\r
+CPP_OPTIMIZATION_OP = -O2\r
+endif\r
+\r
+COMPILE_FLAGS = $(CFLAGS) $(DEBUG_OP) $(OPTIMIZATION_OP) \r
+\r
+CPP_COMPILE_FLAGS = $(CXXFLAGS) $(CPP_DEBUG_OP) $(CPP_OPTIMIZATION_OP) -Wall -Werror -std=c++11 -w -c -fmessage-length=0 -DPLUPLAYER_DOWNLOADABLE_APP_TVPLUS -fPIC \r
+\r
+LINK_FLAGS = $(CFLAGS) -shared -Wl,-z,relro \r
+\r
+AR_FLAGS = \r
+\r
+EDC_COMPILE_FLAGS = \r
diff --git a/src/plusplayer-core/Build/funcs.mk b/src/plusplayer-core/Build/funcs.mk
new file mode 100755 (executable)
index 0000000..35939a5
--- /dev/null
@@ -0,0 +1,50 @@
+\r
+BSLASH := \\#\r
+NULL_CHAR := #\r
+SPACE := \ #\r
+COLON := :#\r
+DOTDOT := ..#\r
+SPACE_ESC := &sp;#\r
+COLON_ESC := &co;#\r
+SPACE_OUT := ~sp~#\r
+COLON_OUT := ~co~#\r
+DOTDOT_OUT := ~dtdt~#\r
+\r
+BSLASH2SLASH = $(subst $(BSLASH),/,$(1))\r
+\r
+REMOVE_TAIL = $(patsubst %/,%,$(1))\r
+\r
+#LOWER_CASE = $(shell echo translit($(1),[A-Z],[a-z])|$(M4))\r
+LOWER_CASE = $(shell echo $(1)|$(TR) [A-Z] [a-z])\r
+\r
+#ifneq ($(findstring Windows,$(OS)),)\r
+# ...\r
+#endif\r
+\r
+FIND_FILES = $(shell $(FIND) $(1)/$(2) | $(SED) 's/^$(subst /,$(BSLASH)/,$(1))$(BSLASH)///')\r
+FIND_FILES_ESC = $(shell $(FIND) $(1)/$(2) | $(SED) 's/^$(subst /,$(BSLASH)/,$(1))$(BSLASH)///' -e 's/:/$(BSLASH)&co;/g' -e 's/$(BSLASH) /$(BSLASH)&sp;/g')\r
+FIND_FILES_4MAKE = $(shell $(FIND) $(1)/$(2) | $(SED) 's/^$(subst /,$(BSLASH)/,$(1))$(BSLASH)///')\r
+\r
+FIND_FILES_ABS = $(shell $(FIND) $(1))\r
+FIND_FILES_ABS_4MAKE = $(shell $(FIND) $(1) -e 's/$(BSLASH) /$(BSLASH)&sp;/g')\r
+FIND_FILES_ABS_ESC = $(shell $(FIND) $(1) -e 's/:/$(BSLASH)&co;/g' -e 's/$(BSLASH) /$(BSLASH)&sp;/g')\r
+\r
+FIND_FILES_4MAKE = $(shell $(FIND) $(1) | $(SED) 's/ /\\\ /g')\r
+\r
+#ENCODE_ESC = $(shell echo $(1) | $(SED) -e 's/:/$(BSLASH)&co;/g' -e 's/$(BSLASH) /$(BSLASH)&sp;/g')\r
+#DECODE_ESC = $(shell echo $(1) | $(SED) -e 's/$(BSLASH)&co;/:/g' -e 's/$(BSLASH)&sp;/$(BSLASH) / g')\r
+ENCODE_ESC = $(subst $(SPACE),$(SPACE_ESC),$(subst $(COLON),$(COLON_ESC),$(1)))\r
+DECODE_ESC = $(subst $(COLON_ESC),$(COLON),$(subst $(SPACE_ESC),$(SPACE),$(1)))\r
+ENCODE_4MAKE = $(subst $(SPACE),$(SPACE_ESC),$(1))\r
+DECODE_4MAKE = $(subst $(SPACE_ESC),$(SPACE),$(1))\r
+\r
+CONVERT_TO_OUT = $(subst $(DOTDOT),$(DOTDOT_OUT),$(subst $(COLON),$(COLON_OUT),$(subst $(SPACE),$(SPACE_OUT),$(1))))\r
+CONVERT_ESC_TO_OUT = $(subst $(DOTDOT),$(DOTDOT_OUT),$(subst $(COLON_ESC),$(COLON_OUT),$(subst $(SPACE_ESC),$(SPACE_OUT),$(1))))\r
+CONVERT_4MAKE_TO_OUT = $(subst $(DOTDOT),$(DOTDOT_OUT),$(subst $(COLON),$(COLON_OUT),$(subst $(SPACE_ESC),$(SPACE_OUT),$(1))))\r
+\r
+PROC_NO_EXIST = $(if $(wildcard $(1)),,$(call $(2),$(1)))\r
+define MAKEDIRS0\r
+       @echo '  Building directory: $(1)'\r
+       @$(MKDIR) $(MKDIR_OP) $(subst $(BSLASH),/,$(1))\r
+endef\r
+MAKEDIRS = $(call PROC_NO_EXIST,$(1),MAKEDIRS0)\r
diff --git a/src/plusplayer-core/Build/makefile b/src/plusplayer-core/Build/makefile
new file mode 100755 (executable)
index 0000000..95638bb
--- /dev/null
@@ -0,0 +1,34 @@
+# \r
+# Usege : make -f <proj_root>/Build/makefile -C <proj_root> \r
+#\r
\r
+BUILD_SCRIPT_VERSION := 1.1.0\r
+\r
+.PHONY : app_version app_build app_clean build_version\r
+\r
+\r
+all : app_build\r
+\r
+clean : app_clean\r
+\r
+version : build_version\r
+\r
+#PROJ_ROOT = .\r
+#BUILD_ROOT := $(PROJ_PATH)/Build#\r
+\r
+ifeq ($(MAKE_NAME),mingw32-make)\r
+ifneq ($(SHELL),)\r
+OPTIONS += --eval="SHELL=$(SHELL)"\r
+endif\r
+endif\r
+\r
+app_build :\r
+       @echo $(MAKE) -f "$(BUILD_ROOT)/makefile.mk"\r
+       @$(MAKE_BIN) -f "$(BUILD_ROOT)/makefile.mk" -C "$(PROJ_PATH)" $(OPTIONS)\r
+\r
+app_clean :\r
+       @$(MAKE) -f "$(BUILD_ROOT)/makefile.mk" -C "$(PROJ_PATH)" $(OPTIONS) clean\r
+\r
+build_version :\r
+       @echo makefile : $(BUILD_SCRIPT_VERSION)\r
+       @$(MAKE) -f "$(BUILD_ROOT)/makefile.mk" -C "$(PROJ_PATH)" $(OPTIONS) version\r
diff --git a/src/plusplayer-core/Build/makefile.mk b/src/plusplayer-core/Build/makefile.mk
new file mode 100755 (executable)
index 0000000..3a4ad19
--- /dev/null
@@ -0,0 +1,206 @@
+#\r
+# Usege : make -f <proj_root>/Build/makefile -C <proj_root>\r
+#\r
+\r
+BUILD_SCRIPT_VERSION := 1.2.3\r
+\r
+.PHONY : app_version app_clean build_version\r
+\r
+\r
+all : app_build\r
+\r
+clean : app_clean\r
+\r
+version : build_version\r
+\r
+_BLANK :=#\r
+_SPACE := $(_BLANK) $(_BLANK)#\r
+_SPACE_4MAKE := \$(_SPACE)#\r
+\r
+NULL_CHAR :=#\r
+SPACE := $(NULL_CHAR) $(NULL_CHAR)#\r
+\r
+PROJ_ROOT := .\r
+_PROJ_ROOT_4MAKE := $(subst $(_SPACE),$(_SPACE_4MAKE),$(PROJ_ROOT))#\r
+PROJ_ROOT=$(_PROJ_ROOT_4MAKE)\r
+_BUILD_ROOT_4MAKE := $(subst $(_SPACE),$(_SPACE_4MAKE),$(BUILD_ROOT))#\r
+BUILD_ROOT=$(_BUILD_ROOT_4MAKE)\r
+\r
+include $(BUILD_ROOT)/basedef.mk\r
+\r
+include $(PROJ_ROOT)/project_def.prop\r
+-include $(PROJ_ROOT)/build_def.prop\r
+\r
+include $(BUILD_ROOT)/funcs.mk\r
+\r
+-include $(BUILD_ROOT)/tooldef.mk\r
+-include $(BUILD_ROOT)/flags.mk\r
+-include $(BUILD_ROOT)/platform.mk\r
+\r
+\r
+APPTYPE := $(type)\r
+\r
+OUTPUT_DIR := $(PROJ_ROOT)/$(BUILD_CONFIG)\r
+OBJ_OUTPUT := $(OUTPUT_DIR)/objs\r
+\r
+LOWER_APPNAME := $(call LOWER_CASE,$(APPNAME))\r
+APPID2 := $(subst $(basename $(APPID)).,,$(APPID))\r
+\r
+ifeq ($(strip $(APPTYPE)),app)\r
+APPFILE := $(OUTPUT_DIR)/$(LOWER_APPNAME)\r
+endif\r
+ifeq ($(strip $(APPTYPE)),staticLib)\r
+APPFILE := $(OUTPUT_DIR)/lib$(LOWER_APPNAME).a\r
+endif\r
+ifeq ($(strip $(APPTYPE)),sharedLib)\r
+APPFILE := $(OUTPUT_DIR)/lib$(LOWER_APPNAME).so\r
+endif\r
+\r
+ifneq ($(strip $(PLATFORM_INCS)),)\r
+PLATFORM_INCS_FILE := $(OBJ_OUTPUT)/platform_incs_file.inc\r
+endif\r
+\r
+include $(BUILD_ROOT)/build_c.mk\r
+\r
+\r
+ifeq ($(strip $(APPTYPE)),app)\r
+EXT_OP := -fPIE\r
+endif\r
+ifeq ($(strip $(APPTYPE)),staticLib)\r
+EXT_OP := -fPIE\r
+endif\r
+ifeq ($(strip $(APPTYPE)),sharedLib)\r
+EXT_OP := -fPIC\r
+endif\r
+\r
+C_OPT := $(COMPILE_FLAGS) $(TC_COMPILER_MISC) $(RS_COMPILER_MISC) $(EXT_OP) --sysroot="$(SYSROOT)" -Werror-implicit-function-declaration $(M_OPT) $(USER_C_OPTS)\r
+CPP_OPT := $(CPP_COMPILE_FLAGS) $(TC_COMPILER_MISC) $(RS_COMPILER_MISC) $(EXT_OP) --sysroot="$(SYSROOT)" -Werror-implicit-function-declaration $(M_OPT) $(USER_CPP_OPTS)\r
+C_OPT_FILE := $(PLATFORM_INCS_FILE)\r
+\r
+OBJS := #\r
+\r
+# Global C/C++\r
+ifeq ($(strip $(USER_ROOT)),)\r
+USER_ROOT := $(PROJ_ROOT)\r
+endif\r
+$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_SRCS),$(USER_INC_DIRS),$(USER_INC_FILES),$(USER_DEFS),$(USER_UNDEFS),$(C_OPT),$(C_OPT_FILE),C,c,$(CC),OBJS))\r
+$(foreach ext,cpp cxx cc c++ C,$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_SRCS),$(USER_INC_DIRS),$(USER_CPP_INC_FILES),$(USER_CPP_DEFS),$(USER_CPP_UNDEFS),$(CPP_OPT),$(C_OPT_FILE),C++,$(ext),$(CXX),OBJS)))\r
+\r
+# Individual C/C++\r
+ifneq ($(strip $(USER_EXT_C_KEYS)),)\r
+$(foreach var,$(USER_EXT_C_KEYS),$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_EXT_$(var)_SRCS),$(USER_EXT_$(var)_INC_DIRS),$(USER_EXT_$(var)_INC_FILES),$(USER_EXT_$(var)_DEFS),$(USER_EXT_$(var)_UNDEFS),$(C_OPT),$(C_OPT_FILE),C,c,$(CC),OBJS)))\r
+$(foreach ext,cpp cxx cc c++ C,$(foreach var,$(USER_EXT_C_KEYS),$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_EXT_$(var)_SRCS),$(USER_EXT_$(var)_INC_DIRS),$(USER_EXT_$(var)_CPP_INC_FILES),$(USER_EXT_$(var)_CPP_DEFS),$(USER_EXT_$(var)_CPP_UNDEFS),$(CPP_OPT),$(C_OPT_FILE),C++,$(ext),$(CXX),OBJS))))\r
+endif\r
+\r
+\r
+ifneq ($(strip $(USER_LIB_DIRS)),)\r
+_ENC_USER_LIB_DIRS := $(call ENCODE_4MAKE,$(USER_LIB_DIRS))\r
+_ENC_USER_LIB_DIRS := $(addprefix -L,$(_ENC_USER_LIB_DIRS))\r
+LIBPATHS := $(call DECODE_4MAKE,$(_ENC_USER_LIB_DIRS))\r
+endif\r
+\r
+LIBS += $(addprefix -l,$(USER_LIBS))\r
+\r
+UOBJS += $(USER_OBJS)\r
+\r
+M_OPT = -MMD -MP -MF"$(@:%.o=%.d)"\r
+\r
+DEPS := $(OBJS:.o=.d)\r
+\r
+ifneq ($(strip $(DEPS)),)\r
+-include $(PROJ_ROOT)/Build/$(DEPS)\r
+endif\r
+\r
+\r
+ifeq ($(strip $(APPTYPE)),app)\r
+$(APPFILE) : $(OBJS) $(UOBJS)\r
+       @echo '  Building target: $@'\r
+       @echo '  Invoking: C/C++ Linker'\r
+       $(call MAKEDIRS,$(@D))\r
+#      $(CXX) -o $(APPFILE) $(OBJS) $(UOBJS) $(LIBPATHS) -Xlinker --as-needed $(LIBS) $(LINK_FLAGS) $(TC_LINKER_MISC) $(RS_LINKER_MISC) -pie -lpthread --sysroot="$(SYSROOT)" -Xlinker --version-script="$(PROJ_ROOT)/.exportMap" $(RS_LIB_PATHS) $(RS_LIBRARIES) -Xlinker -rpath='$$ORIGIN/../lib' -Werror-implicit-function-declaration $(USER_LINK_OPTS)\r
+       $(CXX) -o $(APPFILE) $(OBJS) $(UOBJS) $(LIBPATHS) -Xlinker $(LIBS) $(LINK_FLAGS) $(TC_LINKER_MISC) $(RS_LINKER_MISC) -pie -lpthread --sysroot="$(SYSROOT)" -Xlinker --version-script="$(PROJ_ROOT)/.exportMap" $(RS_LIB_PATHS) $(RS_LIBRARIES) -Xlinker -rpath='$$ORIGIN/../lib' -Werror-implicit-function-declaration $(USER_LINK_OPTS)\r
+       @echo '  Finished building target: $@'\r
+endif\r
+ifeq ($(strip $(APPTYPE)),staticLib)\r
+$(APPFILE) : $(OBJS) $(UOBJS)\r
+       @echo '  Building target: $@'\r
+       @echo '  Invoking: Archive utility'\r
+       $(call MAKEDIRS,$(@D))\r
+       $(AR) -r $(APPFILE) $(OBJS) $(UOBJS) $(AR_FLAGS) $(USER_LINK_OPTS)\r
+       @echo '  Finished building target: $@'\r
+endif\r
+ifeq ($(strip $(APPTYPE)),sharedLib)\r
+$(APPFILE) : $(OBJS) $(UOBJS)\r
+       @echo '  Building target: $@'\r
+       @echo '  Invoking: C/C++ Linker'\r
+       $(call MAKEDIRS,$(@D))\r
+       $(CXX) -o $(APPFILE) $(OBJS) $(UOBJS) $(LIBPATHS) -Xlinker --as-needed $(LIBS) $(LINK_FLAGS) $(TC_LINKER_MISC) $(RS_LINKER_MISC) -shared -lpthread --sysroot="$(SYSROOT)" $(RS_LIB_PATHS) $(RS_LIBRARIES) $(USER_LINK_OPTS)\r
+       @echo '  Finished building target: $@'\r
+endif\r
+\r
+\r
+$(OBJ_OUTPUT) :\r
+       $(call MAKEDIRS,$@)\r
+\r
+$(OUTPUT_DIR) :\r
+       $(call MAKEDIRS,$@)\r
+\r
+\r
+#ifneq ($(strip $(PLATFORM_INCS)),)\r
+#$(PLATFORM_INCS_FILE) : $(OBJ_OUTPUT)\r
+#      @echo '  Building inc file: $@'\r
+#ifneq ($(findstring Windows,$(OS)),)\r
+#ifneq ($(findstring 3.82,$(MAKE_VERSION)),)\r
+#      $(file > $@,$(PLATFORM_INCS))\r
+#else\r
+#      @echo $(PLATFORM_INCS) > $@\r
+#endif\r
+#else\r
+#      @echo '$(PLATFORM_INCS)' > $@\r
+#endif\r
+#endif\r
+\r
+\r
+include $(BUILD_ROOT)/build_edc.mk\r
+\r
+#ifeq ($(strip $(ENVENTOR_SHARED_RES_PATH)),)\r
+ENVENTOR_SHARED_RES_PATH ?= $(ENVENTOR_PATH)/share/enventor\r
+#endif\r
+\r
+EDJ_FILES :=\r
+\r
+# Global EDCs\r
+ifneq ($(strip $(USER_EDCS)),)\r
+$(eval $(call EDJ_PROC_RAW,$(OUTPUT_DIR),$(USER_EDCS),$(USER_EDCS_IMAGE_DIRS),$(USER_EDCS_SOUND_DIRS),$(USER_EDCS_FONT_DIRS),EDJ_FILES))\r
+endif\r
+\r
+# Individual EDCs\r
+ifneq ($(strip $(USER_EXT_EDC_KEYS)),)\r
+$(foreach var,$(USER_EXT_EDC_KEYS),$(eval $(call EDJ_PROC_RAW,$(OUTPUT_DIR),$(USER_EXT_$(var)_EDCS),$(USER_EXT_$(var)_EDCS_IMAGE_DIRS),$(USER_EXT_$(var)_EDCS_SOUND_DIRS),$(USER_EXT_$(var)_EDCS_FONT_DIRS),EDJ_FILES)))\r
+endif\r
+\r
+\r
+include $(BUILD_ROOT)/build_po.mk\r
+\r
+MO_FILES :=\r
+\r
+# Global POs\r
+ifneq ($(strip $(USER_POS)),)\r
+$(eval $(call MO_PROC_RAW,$(OUTPUT_DIR),$(USER_POS),$(APPID2),MO_FILES))\r
+endif\r
+\r
+\r
+secondary-outputs : $(EDJ_FILES) $(MO_FILES)\r
+\r
+-include appendix.mk\r
+\r
+app_build : $(OUTPUT_DIR) $(APPFILE) secondary-outputs\r
+       @echo ========= done =========\r
+\r
+\r
+app_clean :\r
+       rm -f $(APPFILE)\r
+       rm -rf $(OUTPUT_DIR)\r
+\r
+build_version :\r
+       @echo makefile.mk : $(BUILD_SCRIPT_VERSION)\r
diff --git a/src/plusplayer-core/Build/platform.mk b/src/plusplayer-core/Build/platform.mk
new file mode 100755 (executable)
index 0000000..31248a9
--- /dev/null
@@ -0,0 +1,18 @@
+# Add inputs and outputs from these tool invocations to the build variables\r
+\r
+SYSROOT = $(SBI_SYSROOT)\r
+\r
+#USR_INCS := $(addprefix -I "$(SYSROOT),$(PLATFORM_INCS_EX))\r
+USR_INCS1 := $(addsuffix ",$(PLATFORM_INCS_EX))\r
+USR_INCS := $(addprefix -I "$(SYSROOT),$(USR_INCS1))\r
+\r
+ifeq ($(strip $(PLATFORM_LIB_PATHS)),)\r
+RS_LIB_PATHS := "$(SYSROOT)/usr/lib"\r
+else\r
+RS_LIB_PATHS1 := $(addsuffix ",$(PLATFORM_LIB_PATHS))\r
+RS_LIB_PATHS := $(addprefix -L "$(SYSROOT),$(RS_LIB_PATHS1))\r
+endif\r
+\r
+RS_LIBRARIES := $(addprefix -l,$(RS_LIBRARIES_EX))\r
+\r
+PLATFORM_INCS = $(USR_INCS) -I "$(SDK_PATH)/library"\r
diff --git a/src/plusplayer-core/Build/tooldef.mk b/src/plusplayer-core/Build/tooldef.mk
new file mode 100755 (executable)
index 0000000..7016cd6
--- /dev/null
@@ -0,0 +1,70 @@
+# Add inputs and outputs from these tool invocations to the build variables\r
+\r
+ifneq ($(strip $(SHELL_BIN)),)\r
+SHELL = $(SHELL_BIN)\r
+else\r
+SHELL = sh\r
+endif\r
+\r
+ifneq ($(strip $(MKDIR_BIN)),)\r
+MKDIR = $(MKDIR_BIN)\r
+MKDIR_OP = -p\r
+else\r
+MKDIR = mkdir\r
+MKDIR_OP = -p\r
+endif\r
+\r
+ifneq ($(strip $(UNAME_BIN)),)\r
+UNAME = $(UNAME_BIN)\r
+else\r
+UNAME = uname\r
+endif\r
+\r
+ifneq ($(strip $(M4_BIN)),)\r
+M4 = $(M4_BIN)\r
+else\r
+M4 = m4\r
+endif\r
+\r
+ifneq ($(strip $(TR_BIN)),)\r
+TR = $(TR_BIN)\r
+else\r
+TR = tr\r
+endif\r
+\r
+ifneq ($(strip $(FIND_BIN)),)\r
+FIND = $(FIND_BIN)\r
+else\r
+FIND = find\r
+endif\r
+\r
+ifneq ($(strip $(SED_BIN)),)\r
+SED = $(SED_BIN)\r
+else\r
+SED = sed\r
+endif\r
+\r
+ifneq ($(strip $(GREP_BIN)),)\r
+GREP = $(GREP_BIN)\r
+else\r
+GREP = grep\r
+endif\r
+\r
+ifneq ($(strip $(EDJE_CC_BIN)),)\r
+EDJE_CC = $(EDJE_CC_BIN)\r
+else\r
+EDJE_CC = edje_cc\r
+endif\r
+\r
+ifneq ($(strip $(MSGFMT_BIN)),)\r
+MSGFMT = $(MSGFMT_BIN)\r
+else\r
+MSGFMT = msgfmt\r
+endif\r
+\r
+ifneq ($(strip $(CKSUM_BIN)),)\r
+CKSUM = $(CKSUM_BIN)\r
+else\r
+CKSUM = cksum\r
+endif\r
+\r
diff --git a/src/plusplayer-core/CMakeLists.txt b/src/plusplayer-core/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..95c0912
--- /dev/null
@@ -0,0 +1,71 @@
+PROJECT(plusplayer-core)
+
+SET(fw_name "espplayer-core")
+SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+SET(${fw_name}_LDFLAGS)
+
+SET(ADD_LIBS
+  "gstvideo-1.0"
+  "gstapp-1.0"
+  "trackrenderer"
+)
+
+SET(${fw_name}_CXXFLAGS "-Wall -Werror -std=c++11 -fPIC -Wl,-z,relro -fstack-protector -DEFL_BETA_API_SUPPORT")
+
+SET(dependents "gstreamer-1.0 dlog gstreamer-ffsubtitle-1.0"
+               "boost"               
+               "context-aware-api"
+               "libtzplatform-config"
+               "drmdecrypt"
+               "logger")
+
+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(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}/src/decoderinputbuffer.cpp
+  ${PROJECT_SOURCE_DIR}/src/gstobject_guard.cpp
+  ${PROJECT_SOURCE_DIR}/src/gstsignal_holder.cpp
+  ${PROJECT_SOURCE_DIR}/src/track_util.cpp
+  ${PROJECT_SOURCE_DIR}/src/gst_utils.cpp
+  ${PROJECT_SOURCE_DIR}/src/error.cpp
+  ${PROJECT_SOURCE_DIR}/src/serializer.cpp
+  ${PROJECT_SOURCE_DIR}/src/subtitle_attr_parser.cpp
+  ${PROJECT_SOURCE_DIR}/src/plusplayer_cfg.cpp
+  ${PROJECT_SOURCE_DIR}/src/trackrendereradapter.cpp
+  ${PROJECT_SOURCE_DIR}/src/trackrendereradapter_utils.cpp
+  ${PROJECT_SOURCE_DIR}/src/kpi.cpp
+  ${PROJECT_SOURCE_DIR}/src/decodedvideopacketex.cpp
+  ${PROJECT_SOURCE_DIR}/src/videoframetypestrategy.cpp
+  ${PROJECT_SOURCE_DIR}/src/base64.cpp
+  ${PROJECT_SOURCE_DIR}/src/caf_logger.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/plusplayer-core/build_def.prop b/src/plusplayer-core/build_def.prop
new file mode 100755 (executable)
index 0000000..d164d23
--- /dev/null
@@ -0,0 +1,6 @@
+\r
+# Add pre/post build process\r
+PREBUILD_DESC = \r
+PREBUILD_COMMAND = \r
+POSTBUILD_DESC = \r
+POSTBUILD_COMMAND = 
\ No newline at end of file
diff --git a/src/plusplayer-core/include_internal/core/decodedvideorawmodepacket.h b/src/plusplayer-core/include_internal/core/decodedvideorawmodepacket.h
new file mode 100755 (executable)
index 0000000..bb01d13
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_DECODED_RAW_MODE_PACKET_H__
+#define __PLUSPLAYER_SRC_CORE_DECODED_RAW_MODE_PACKET_H__
+
+#include <tbm_type_common.h>
+
+namespace plusplayer {
+
+enum class DecodedVideoRawModePacketType { kPhysicalAddress, kTizenBuffer };
+
+struct DecodedVideoRawModePacketRawData {
+  int y_phyaddr = 0;
+  int y_viraddr = 0;
+  int y_linesize = 0;
+  int uv_phyaddr = 0;
+  int uv_viraddr = 0;
+  int uv_linesize = 0;
+};
+struct DecodedVideoRawModePacketTBMData {
+  tbm_key key;
+};
+
+struct DecodedVideoRawModePacket {
+  DecodedVideoRawModePacketType type =
+      DecodedVideoRawModePacketType::kPhysicalAddress;
+  uint64_t pts = 0;
+  uint32_t width = 0;
+  uint32_t height = 0;
+  union Data {
+    DecodedVideoRawModePacketRawData raw;
+    DecodedVideoRawModePacketTBMData tbm;
+  } data = {.tbm = {0}};
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_DECODED_RAW_MODE_PACKET_H__
\ No newline at end of file
diff --git a/src/plusplayer-core/include_internal/core/decoderinputbuffer.h b/src/plusplayer-core/include_internal/core/decoderinputbuffer.h
new file mode 100755 (executable)
index 0000000..261857c
--- /dev/null
@@ -0,0 +1,139 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_DECODERINPUTBUFFER_H__
+#define __PLUSPLAYER_SRC_CORE_DECODERINPUTBUFFER_H__
+
+#include <atomic>
+#include <boost/core/noncopyable.hpp>
+#include <memory>
+#include <queue>
+
+#include "gst/gst.h"
+// temporary until drmdecrypt platform interfaces are added into rootstrap
+#ifndef PLUPLAYER_DOWNLOADABLE_APP_TVPLUS
+#include <drmdecrypt/drmdecrypt_api.h>
+#endif
+
+#include "plusplayer/track.h"
+
+namespace plusplayer {
+
+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) {
+    return Ptr(new DecoderInputBuffer(buffer, type, index));
+  }
+
+  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_) {
+      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)
+      : type_(type), index_(index) {
+    if (buffer) {
+      buffer_ = gst_buffer_ref(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) {
+#ifndef PLUPLAYER_DOWNLOADABLE_APP_TVPLUS
+    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);
+    }
+#endif
+  }
+
+ private:
+  std::atomic_flag buffer_lock_ = ATOMIC_FLAG_INIT;
+  const TrackType type_ = kTrackTypeMax;
+  const int index_ = kInvalidTrackIndex;
+  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 plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_DECODERINPUTBUFFER_H__
diff --git a/src/plusplayer-core/include_internal/core/decoderinputbuffer_listener.h b/src/plusplayer-core/include_internal/core/decoderinputbuffer_listener.h
new file mode 100755 (executable)
index 0000000..8363291
--- /dev/null
@@ -0,0 +1,25 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_TRACKSOURCE_DECODERINPUTBUFFER_LISTENER_H__
+#define __PLUSPLAYER_SRC_TRACKSOURCE_DECODERINPUTBUFFER_LISTENER_H__
+
+#include <boost/core/noncopyable.hpp>
+
+#include "core/decoderinputbuffer.h"
+
+namespace plusplayer {
+
+class DecoderInputBufferListener : private boost::noncopyable {
+ public:
+  virtual ~DecoderInputBufferListener() {}
+  virtual void OnRecv(DecoderInputBufferPtr data) {}
+
+ protected:
+  DecoderInputBufferListener() {}
+};
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_TRACKSOURCE_DECODERINPUTBUFFER_LISTENER_H__
diff --git a/src/plusplayer-core/include_internal/core/error.h b/src/plusplayer-core/include_internal/core/error.h
new file mode 100755 (executable)
index 0000000..057ece0
--- /dev/null
@@ -0,0 +1,18 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_ERROR_H__
+#define __PLUSPLAYER_SRC_CORE_ERROR_H__
+
+#include "gst/gst.h"
+
+#include "plusplayer/types/error.h"
+
+namespace plusplayer {
+
+ErrorType HandleGstError(const GError* error);
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_ERROR_H__
diff --git a/src/plusplayer-core/include_internal/core/gst_utils.h b/src/plusplayer-core/include_internal/core/gst_utils.h
new file mode 100755 (executable)
index 0000000..e2adbdd
--- /dev/null
@@ -0,0 +1,26 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_GST_UTILS_H__
+#define __PLUSPLAYER_SRC_CORE_GST_UTILS_H__
+
+#include "gst/gst.h"
+#include "json/json.h"
+
+namespace plusplayer {
+
+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 plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_GST_UTILS_H__
\ No newline at end of file
diff --git a/src/plusplayer-core/include_internal/core/gstobject_guard.h b/src/plusplayer-core/include_internal/core/gstobject_guard.h
new file mode 100755 (executable)
index 0000000..ad8be9e
--- /dev/null
@@ -0,0 +1,66 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_GSTOBJECT_GUARD_H__
+#define __PLUSPLAYER_SRC_CORE_GSTOBJECT_GUARD_H__
+
+#include <memory>
+#include <functional>
+#include "gst/gst.h"
+
+namespace plusplayer {
+
+// <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 plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_GSTOBJECT_GUARD_H__
diff --git a/src/plusplayer-core/include_internal/core/gstsignal_holder.h b/src/plusplayer-core/include_internal/core/gstsignal_holder.h
new file mode 100755 (executable)
index 0000000..5e76daf
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_GSTSIGNAL_HOLDER_H__
+#define __PLUSPLAYER_SRC_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 {
+
+#define GST_SIGNAL_CONNECT(x_holder, x_object, x_signal, x_callback, x_arg) \
+  do {                                                                      \
+    x_holder->Add(G_OBJECT(x_object), x_signal, G_CALLBACK(x_callback),     \
+                 (gpointer)x_arg);                                          \
+  } while (0);
+
+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 plusplayer
+
+#endif  //  __PLUSPLAYER_SRC_CORE_GSTSIGNAL_HOLDER_H__
diff --git a/src/plusplayer-core/include_internal/core/kpi.h b/src/plusplayer-core/include_internal/core/kpi.h
new file mode 100755 (executable)
index 0000000..83e8977
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_KPI_H__
+#define __PLUSPLAYER_SRC_CORE_KPI_H__
+
+#include <string>
+
+#include "plusplayer/drm.h"
+#include "plusplayer/types/source.h"
+
+namespace plusplayer {
+
+namespace kpi {
+
+struct CodecLoggerKeys {
+  SourceType src_type = SourceType::kNone;
+  drm::Type drm_type = drm::Type::kNone;
+  std::string container_type;
+  int v_decoder_type = 0; /**< (0:DEFAULT, 1:HW, 2:SW, 3:DISABLE) */
+  std::string v_codec;
+  unsigned int v_tag = 0;
+  int width = 0;
+  int height = 0;
+  int a_decoder_type = 0; /**< (0:DEFAULT, 1:HW, 2:SW, 3:DISABLE) */
+  std::string a_codec;
+  unsigned int a_tag = 0;
+  std::string app_id;
+};
+
+struct EsCodecLoggerKeys {
+  std::string app_id;
+  bool is_clean = true;  /**< (false:EME, true:MSE) */
+  int width = 0;
+  int height = 0;
+  std::string v_codec;
+  int v_codec_version;
+  std::string a_codec;
+};
+
+
+class CodecLogger {
+ public:
+  CodecLogger() {};
+  ~CodecLogger() {};
+
+  bool SendKpi(bool event_case, const CodecLoggerKeys& keys);
+  bool SendKpi(bool event_case, const EsCodecLoggerKeys& keys);
+ private:
+  bool SendKpi_(bool event_case, const std::stringstream& message);
+};
+
+}  // namespace kpi
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_KPI_H__
\ No newline at end of file
diff --git a/src/plusplayer-core/include_internal/core/serializer.h b/src/plusplayer-core/include_internal/core/serializer.h
new file mode 100755 (executable)
index 0000000..d38a5a8
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_SERIALIZER_H__
+#define __PLUSPLAYER_SRC_CORE_SERIALIZER_H__
+
+#include <cstring>
+#include <sstream>
+#include <type_traits>
+#include <vector>
+
+namespace plusplayer {
+class Serializer {
+ public:
+  using Byte = unsigned char;
+  using Offset = unsigned int;
+
+ public:
+  explicit Serializer() : size_(0) {}
+  Serializer(const Serializer &from) = delete;
+  Serializer(Serializer &&from) = delete;
+  virtual ~Serializer() {}
+
+ public:
+  template <class T>
+  Offset Put(const T data) {
+    static_assert(
+        !std::is_pointer<T>::value || !std::is_same<T, std::string>::value,
+        "this type can't be serialized");
+    Offset offset = size_;
+    constexpr size_t size = sizeof(T);
+    const Byte *data_bytes = reinterpret_cast<const Byte *>(&data);
+    Put_(data_bytes, size);
+    return offset;
+  }
+  Offset Put(const std::vector<unsigned char> &data);
+  Offset Put(const std::string &data);
+  Offset Put(const Byte *data, size_t size);
+  size_t Serialize(Byte *serialized);
+  const size_t GetSize();
+
+  template <class T>
+  static void Put(Byte *bytes, const T value) {
+    constexpr size_t size = sizeof(T);
+    std::memcpy(bytes, reinterpret_cast<const Byte *>(&value), size);
+  }
+
+ private:
+  void Put_(const Byte *data_bytes, const size_t size);
+
+ private:
+  std::basic_stringbuf<Byte> buf_;
+  size_t size_;
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_SERIALIZER_H__
diff --git a/src/plusplayer-core/include_internal/core/subtitle_attr_parser.h b/src/plusplayer-core/include_internal/core/subtitle_attr_parser.h
new file mode 100755 (executable)
index 0000000..564c21a
--- /dev/null
@@ -0,0 +1,28 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_SUBTITLE_ATTR_PARSER_H__
+#define __PLUSPLAYER_SRC_CORE_SUBTITLE_ATTR_PARSER_H__
+
+#include <boost/core/noncopyable.hpp>
+
+#include "gst/gst.h"
+
+#include "plusplayer/track.h"
+
+namespace plusplayer {
+class SubtitleAttrParser : private boost::noncopyable {
+ public:
+  explicit SubtitleAttrParser(GstBuffer* buf) : gstbuf_(buf) {}
+  SubtitleAttrListPtr Parse();
+ ~SubtitleAttrParser() {
+    if(gstbuf_)
+        gst_buffer_unref(gstbuf_);
+  }
+ private:
+  GstBuffer* gstbuf_ = nullptr;
+};
+}  // namespace plusplayer
+
+#endif  //__PLUSPLAYER_SRC_CORE_SUBTITLE_ATTR_PARSER_H__
\ No newline at end of file
diff --git a/src/plusplayer-core/include_internal/core/track_util.h b/src/plusplayer-core/include_internal/core/track_util.h
new file mode 100755 (executable)
index 0000000..eaeb457
--- /dev/null
@@ -0,0 +1,35 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_TRACK_UTIL_H__
+#define __PLUSPLAYER_SRC_CORE_TRACK_UTIL_H__
+
+#include <vector>
+
+#include "gst/gst.h"
+
+#include "plusplayer/track.h"
+
+namespace plusplayer {
+
+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,
+                            plusplayer::Track* track);
+}  // namespace track_util
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_TRACK_UTIL_H__
diff --git a/src/plusplayer-core/include_internal/core/trackrendereradapter.h b/src/plusplayer-core/include_internal/core/trackrendereradapter.h
new file mode 100755 (executable)
index 0000000..f5d2101
--- /dev/null
@@ -0,0 +1,277 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_PLAYER_TRACKRENDERERADAPTER_H__
+#define __PLUSPLAYER_SRC_PLAYER_TRACKRENDERERADAPTER_H__
+
+#include <trackrenderer_capi/trackrenderer_capi.h>
+#include <trackrenderer_capi/trackrenderer_internal.h>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "core/decodedvideorawmodepacket.h"
+#include "core/decoderinputbuffer.h"
+#include "core/videoframetypestrategy.h"
+#include "plusplayer/appinfo.h"
+#include "plusplayer/audioeasinginfo.h"
+#include "plusplayer/drm.h"
+#include "plusplayer/track.h"
+#include "plusplayer/types/buffer.h"
+#include "plusplayer/types/display.h"
+#include "plusplayer/types/error.h"
+#include "plusplayer/types/event.h"
+#include "plusplayer/types/latency.h"
+#include "plusplayer/types/picturequality.h"
+#include "plusplayer/types/resource.h"
+#include "plusplayer/types/stream.h"
+
+namespace plusplayer {
+
+class TrackRendererAdapter {
+ public:
+  enum RetVal { kSuccess = 0, kFailed = -1 };
+  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
+    kFailed,
+  };
+
+  enum class Attribute {
+    /*attributes for gst plugin property*/
+    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::unit32_t
+    kVideoRenderTimeOffset,       // std::int64_t
+    kAudioRenderTimeOffset,       // std::int64_t
+
+    /*attributes for trackrenderer configures*/
+
+    kAccurateSeekMode,          // std::uint32_t
+    kLowLatencyMode,            // std::uint32_t
+    kVideoFramePeekMode,        // std::uint32_t
+    kUnlimitedMaxBufferMode,    // std::uint32_t
+    kVideoPreDisplayMode,       // std::uint32_t
+    kStartRenderingTime,        // std::uint64_t
+    kFmmMode,                   // std::uint32_t
+    kAlternativeVideoResource,  // std::uint32_t
+    kVideoDecodingMode,         // std::uint32_t
+    kLateVideoFrameDropMode,    // std::uint32_t
+
+  };
+
+  // TODO(js4716.chun):CHECK POINTS
+  // - duplicated TrackRenderer::EventListener
+  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 OnEos() {}
+    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 OnMediaPacketVideoRawDecoded(
+        const DecodedVideoRawModePacket& packet) {}
+    virtual void OnFlushDone() {}
+    virtual void OnFirstDecodingDone() {}
+    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() {}
+  };
+
+ public:
+  using Ptr = std::unique_ptr<TrackRendererAdapter>;
+  static Ptr Create();
+
+  ~TrackRendererAdapter();
+
+  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* counts);
+  bool GetDroppedFramesForCatchup(TrackType type, void* counts);
+  bool Deactivate(TrackType type);
+  bool Activate(TrackType type, const Track& track);
+  bool SubmitPacket(const DecoderInputBufferPtr& data);
+  bool SubmitPacket(const DecoderInputBufferPtr& data, SubmitStatus* status);
+  bool SubmitPacket2(const DecoderInputBufferPtr& data, SubmitStatus* status);
+  void SetDrm(const drm::Property& drm_property);
+  void DrmLicenseAcquiredDone(TrackType type);
+  bool SetDisplayMode(const DisplayMode& mode);
+  bool SetDisplayRotate(const DisplayRotation& rotate);
+  bool GetDisplayRotate(DisplayRotation* rotate);
+  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);
+  void SetAppId(const std::string& app_id);
+  void SetAppInfo(const PlayerAppInfo& app_info);
+  bool SetAudioMute(bool is_mute);
+  bool SetVolume(const int& volume);
+  bool GetVolume(int* volume);
+  bool SetCatchUpSpeed(const CatchUpSpeed& level);
+  bool GetVideoLatencyStatus(LatencyStatus* status);
+  bool GetAudioLatencyStatus(LatencyStatus* status);
+
+  void RegisterListener(EventListener* listener);
+  void RegisterListenerForEsplayer(EventListener* listener);
+  void SetVideoStillMode(const StillMode& type);
+  void SetAttribute(const Attribute& attr, const boost::any& value);
+  TrackRendererState GetState();
+  bool SetMatroskaColorInfo(const std::string& color_info);
+  void SetVideoFrameBufferType(VideoFrameTypeStrategyPtr strategy);
+  bool SetVideoFrameBufferScaleResolution(const uint32_t& target_width,
+                                          const uint32_t& target_height);
+  bool SetDecodedVideoFrameRate(const Rational& request_framerate);
+  bool Flush(const StreamType& type);
+  bool Flush(const TrackType& type);
+  void GetAttribute(const Attribute& attr, boost::any* value);
+  bool RenderVideoFrame();
+  bool SetAiFilter(void* aifilter);
+  bool SetVideoMidLatencyThreshold(const unsigned int threshold);
+  bool SetAudioMidLatencyThreshold(const unsigned int threshold);
+  bool SetVideoHighLatencyThreshold(const unsigned int threshold);
+  bool SetAudioHighLatencyThreshold(const unsigned int threshold);
+  bool InitAudioEasingInfo(const uint32_t init_volume,
+                           const uint32_t init_elapsed_time,
+                           const AudioEasingInfo& easing_info);
+  bool UpdateAudioEasingInfo(const AudioEasingInfo& easing_info);
+  bool GetAudioEasingInfo(uint32_t* current_volume, uint32_t* elapsed_time,
+                          AudioEasingInfo* easing_info);
+  bool StartAudioEasing();
+  bool StopAudioEasing();
+  bool GetVirtualRscId(const RscType type, int* virtual_id);
+  bool SetAdvancedPictureQualityType(const AdvPictureQualityType type);
+  bool SetResourceAllocatePolicy(const RscAllocPolicy policy);
+  bool SetVideoParDar(uint64_t time_millisecond, uint32_t par_num,
+                      uint32_t par_den, uint32_t dar_num, uint32_t dar_den);
+
+ private:
+  TrackRendererAdapter();
+  using UserData = void*;
+  static void ErrorCb_(const TrackRendererErrorType error_code,
+                       UserData userdata);
+  static void ErrorMsgCb_(const TrackRendererErrorType error_code,
+                          char* error_msg, UserData userdata);
+  static void ResourceConflictCb_(UserData userdata);
+
+  static void SeekDoneCb_(UserData userdata);
+
+  static void FlushDoneCb_(UserData userdata);
+
+  static void EosCb_(UserData userdata);
+
+  static void EventCb_(const TrackRendererEventType event_type,
+                       const TrackrendererEventMsg msg_data, UserData userdata);
+
+  static void FirstDecodingDoneCb_(UserData userdata);
+
+  static void SubtitleRawDataCb_(TrackRendererDecoderInputBuffer* buf,
+                                 const TrackRendererSubtitleType type,
+                                 UserData userdata);
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+  static void SubtitleDataCb_(const char* data, const int size,
+                              const TrackRendererSubtitleType type,
+                              const uint64_t duration,
+                              TrackRendererSubtitleAttr* attr_list,
+                              int attr_list_size, UserData userdata);
+#endif
+
+  static void ClosedCaptionDataCb_(const char* data, const int size,
+                                   UserData userdata);
+
+  static void DrmInitDataCb_(int* drmhandle, unsigned int len,
+                             unsigned char* psshdata,
+                             TrackRendererTrackType type, UserData userdata);
+
+  static void BufferStatusCb_(const TrackRendererTrackType type,
+                              const TrackRendererBufferStatus status,
+                              UserData userdata);
+
+  static void SeekDataCb_(const TrackRendererTrackType type,
+                          const uint64_t offset, UserData userdata);
+
+  static void MediaPacketGetTbmBufPtrCb_(void** ptr, bool is_scale_change,
+                                         UserData userdata);
+
+  static void MediaPacketVideoDecodedCb_(
+      const TrackRendererDecodedVideoPacket* packet, UserData userdata);
+
+  static void MediaPacketVideoRawDecodedCb_(
+      const TrackRendererDecodedVideoRawModePacket* packet,
+      TrackRendererDecodedVideoType type, UserData userdata);
+
+  static void VideoDecoderUnderrunCb_(UserData userdata);
+  static void VideoLatencyStatusCb_(
+      const TrackRendererLatencyStatus latency_status, UserData userdata);
+  static void AudioLatencyStatusCb_(
+      const TrackRendererLatencyStatus latency_status, UserData userdata);
+  static void VideoHighLatencyCb_(UserData userdata);
+  static void AudioHighLatencyCb_(UserData userdata);
+  static void MultiviewStartVideoCb_(UserData userdata);
+  static void MultiviewStopVideoCb_(UserData userdata);
+
+ private:
+  using TrackRendererHandle = void*;
+  TrackRendererHandle handle_ = nullptr;
+  EventListener* eventlistener_{nullptr};
+};  // class TrackRendererAdapter
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_PLAYER_TRACKRENDERERADAPTER_H__
diff --git a/src/plusplayer-core/include_internal/core/trackrendereradapter_utils.h b/src/plusplayer-core/include_internal/core/trackrendereradapter_utils.h
new file mode 100755 (executable)
index 0000000..7c5ae43
--- /dev/null
@@ -0,0 +1,105 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_PLAYER_TRACKRENDERERADAPTER_UTILS_H__
+#define __PLUSPLAYER_PLAYER_TRACKRENDERERADAPTER_UTILS_H__
+
+#include <cassert>
+
+#include "plusplayer/appinfo.h"
+#include "plusplayer/audioeasinginfo.h"
+#include "plusplayer/drm.h"
+#include "plusplayer/track.h"
+#include "plusplayer/types/buffer.h"
+#include "plusplayer/types/display.h"
+#include "plusplayer/types/error.h"
+#include "plusplayer/types/latency.h"
+#include "plusplayer/types/picturequality.h"
+#include "plusplayer/types/resource.h"
+#include "plusplayer/types/stream.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/latency.h"
+#include "trackrenderer_capi/track.h"
+#include "trackrenderer_capi/trackrenderer_capi.h"
+
+namespace plusplayer {
+
+namespace adapter_utils {
+
+void InitTrack(TrackRendererTrack* track);
+void MakeGeometry(Geometry* roi, const TrackRendererGeometry& geometry);
+void MakeTrackRendererDrmProperty(
+    TrackRendererDrmProperty* trackrenderer_drm_property,
+    const drm::Property& drm_property);
+void MakeTrackRendererGeometry(TrackRendererGeometry* geometry,
+                               const Geometry& roi);
+void MakeTrackRendererCropArea(TrackRendererCropArea* crop,
+                               const CropArea& area);
+void MakeTrackRendererRenderRect(TrackRendererRenderRect* output,
+                                 const RenderRect& input);
+void MakeTrackRendererTrack(TrackRendererTrack* track, const Track& trackinfo);
+void MakeTrackRendererAppInfo(TrackRendererAppInfo* app_attr,
+                              const PlayerAppInfo& app_info);
+void MakeTrackRendererAudioEasingInfo(TrackRendererAudioEasingInfo* easing_attr,
+                                      const AudioEasingInfo& easing_info);
+void MakeAudioEasingInfo(AudioEasingInfo* easing_info,
+                         const TrackRendererAudioEasingInfo& easing_attr);
+void MakeTrackRendererRational(TrackRendererRational* rational_attr,
+                               const Rational& rational_info);
+DisplayMode ConvertToDisplayMode(TrackRendererDisplayMode typevalue);
+DisplayType ConvertToDisplayType(const TrackRendererDisplayType typevalue);
+ErrorType ConvertToErrorType(const TrackRendererErrorType type);
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+SubtitleAttrType ConvertToSubtitleAttrType(
+    const TrackRendererSubtitleAttrType& type);
+#endif
+SubtitleType ConvertToSubtitleType(const TrackRendererSubtitleType& type);
+TrackType ConvertToTrackType(const TrackRendererTrackType typevalue);
+DecodedVideoPacket ConvertToDecodedVideoPacket(
+    const TrackRendererDecodedVideoPacket* packet);
+TrackRendererDecodedVideoFrameBufferType ConvertToVideoFrameBufferType(
+    const DecodedVideoFrameBufferType& type);
+TrackRendererDisplayMode ConvertToTrackRendererDisplayMode(
+    const DisplayMode& mode);
+TrackRendererDisplayRotate ConvertToTrackRendererDisplayRotate(
+    const DisplayRotation& rotate);
+DisplayRotation ConvertToDisplayRotation(
+    const TrackRendererDisplayRotate rotate_value);
+TrackRendererDisplayType ConvertToTrackRendererDisplayType(
+    const DisplayType& type);
+TrackRendererDrmType ConvertToTrackRendererDrmType(const drm::Type& drm_type);
+TrackRendererStillMode ConvertToTrackRendererStillMode(
+    const StillMode& still_mode);
+TrackRendererTrackType ConvertToTrackRendererTrackType(const TrackType& type);
+TrackRendererTrackType ConvertToTrackRendererTrackTypeFromStreamType(
+    const StreamType& type);
+TrackRendererCatchUpSpeed ConvertToTrackRendererCatchUpSpeed(
+    const CatchUpSpeed& level);
+LatencyStatus ConvertToLatencyStatus(const TrackRendererLatencyStatus& status);
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+boost::any SetSubtitleAttrValue(const TrackRendererSubtitleAttr& value);
+#endif
+
+BufferStatus ConvertToBufferStatus(const TrackRendererBufferStatus& status);
+AudioEasingType ConvertToAudioEasingType(
+    const TrackRendererAudioEasingType& type);
+TrackRendererAudioEasingType ConvertToTrackRendererAudioEasingType(
+    const AudioEasingType& type);
+bool ConvertToTrackRendererRscType(const RscType& typevalue,
+                                   TrackRendererRscType* type);
+bool ConvertToTrackRendererAdvPictureQualityType(
+    const AdvPictureQualityType& typevalue,
+    TrackRendererAdvPictureQualityType* type);
+bool ConvertToTrackRendererRscAllocPolicy(const RscAllocPolicy& policyvalue,
+                                          TrackRendererRscAllocPolicy* policy);
+}  // namespace adapter_utils
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_PLAYER_TRACKRENDERERADAPTER_UTILS_H__
diff --git a/src/plusplayer-core/include_internal/core/utils/base64.h b/src/plusplayer-core/include_internal/core/utils/base64.h
new file mode 100755 (executable)
index 0000000..ca76b63
--- /dev/null
@@ -0,0 +1,22 @@
+//\r
+// @ Copyright [2020] <S/W Platform,Visual Display,Samsung Electronics>\r
+//\r
+\r
+#ifndef __PLUSPLAYER_SRC_BASE64_H__\r
+#define __PLUSPLAYER_SRC_BASE64_H__\r
+\r
+#include <iostream>\r
+#include <map>\r
+#include <string>\r
+#include "core/utils/plusplayer_log.h"\r
+\r
+namespace plusplayer {\r
+namespace base64 {\r
+std::string Base64Encode(const char *str, const int size);\r
+\r
+std::string Base64Decode(const std::string str);\r
+}  // namespace base64\r
+\r
+}  // namespace plusplayer\r
+\r
+#endif  // __PLUSPLAYER_SRC_BASE64_H__\r
diff --git a/src/plusplayer-core/include_internal/core/utils/caf_logger.h b/src/plusplayer-core/include_internal/core/utils/caf_logger.h
new file mode 100755 (executable)
index 0000000..33a8218
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef _AVPLAY_CAF_LOGGER_H__\r
+#define _AVPLAY_CAF_LOGGER_H__\r
+\r
+#include <mutex>\r
+#include <queue>\r
+#include <string>\r
+#include <utility>\r
+#include <vector>\r
+#include <future>\r
+#include <map>\r
+#include <boost/core/noncopyable.hpp>\r
+#include <list>\r
+\r
+namespace plusplayer {\r
+\r
+  enum class CafEventType {\r
+    kNone = 0,\r
+    kStart,\r
+    kEnd,\r
+    kBitrate,\r
+    kBuffering,\r
+    kResolution,    \r
+    kStreamReady,\r
+    kIdle,\r
+    kReady,\r
+    kPlaying,\r
+    kPaused,\r
+    kEventMax\r
+  };\r
+\r
+  typedef struct _CafEventData {\r
+    CafEventType event_type;\r
+    std::string event_data;\r
+  }CafEventData;\r
+\r
+  class ContextAware  {\r
+    public:\r
+      ContextAware() {} \r
+      ~ContextAware() {}\r
+      bool InitService();    \r
+      void Write(std::string json_data);\r
+      bool FiniService();\r
+  };\r
+\r
+  class CafLogger {\r
+    private:\r
+      static CafLogger *instance_;\r
+      static std::shared_ptr<ContextAware> context_aware_;\r
+  \r
+      std::mutex object_lock_;\r
+      bool connected_to_dbus_;\r
+      bool msg_thread_stopped_;\r
+      std::queue<CafEventData> msg_queue_;\r
+      std::mutex msg_task_mutex_;\r
+      std::condition_variable msg_task_cv_;    \r
+      std::future<void> msg_handler_task_;\r
+      std::string app_id_;\r
+      int unique_number;\r
+      std::queue<int> using_instance_;\r
+\r
+      CafLogger();\r
+      std::string GetEventStrName_(CafEventType event_type);\r
+      std::string GetEventValueStrName_(CafEventType event_type);\r
+      std::string GetStateValueStrName_(CafEventType event_type);\r
+      void SendData_(CafEventData event);\r
+      void MsgTask_();\r
+      void StartMsgThread_();\r
+      void StopMsgThread_();\r
+      bool PushMessageToQueue_(CafEventType event_type, std::string data);\r
+      bool isConnected_();\r
+      bool Connect_();\r
+      bool Disconnect_();\r
+      void setAppId_(std::string app_id);\r
+      void setUniqueNumber_(int uniqueNumber);\r
+      int getUniqueNumber_();\r
+           \r
+    public:\r
+      static bool Initialize();\r
+      static bool LogMessage(CafEventType event_type, std::string data);\r
+      static void StartLoggingThread();\r
+      static void StopLoggingThread();\r
+      static void SetAppId(std::string app_id);\r
+      static void SetUniqueNumber();\r
+      static std::string GetUniqueNumber();\r
+      static void SetContextAware(std::shared_ptr<ContextAware>&& context_aware);\r
+      ~CafLogger();\r
+  };\r
+\r
+} //plusplayer\r
+\r
+#endif //_AVPLAY_CAF_LOGGER_H__\r
diff --git a/src/plusplayer-core/include_internal/core/utils/performance_checker.h b/src/plusplayer-core/include_internal/core/utils/performance_checker.h
new file mode 100755 (executable)
index 0000000..6308999
--- /dev/null
@@ -0,0 +1,48 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_UTILS_PERFORMANCE_CHECKER_H__
+#define __PLUSPLAYER_SRC_UTILS_PERFORMANCE_CHECKER_H__
+
+#include <sys/prctl.h>
+#include <ctime>
+
+#include "core/utils/plusplayer_log.h"
+
+// Hw clock
+#ifndef PR_TASK_PERF_USER_TRACE
+#define PR_TASK_PERF_USER_TRACE 666
+#endif
+
+namespace plusplayer {
+
+namespace performance_checker {
+
+inline clock_t Start() { return clock(); }
+
+inline void End(const clock_t start,
+                                const char* msg = nullptr) {
+  LOG_DEBUG("[PERF][%s] ELAPSED[%f]SECS", ((msg != nullptr) ? msg : "&"),
+            static_cast<float>(clock() - start) / CLOCKS_PER_SEC);
+}
+
+constexpr int kBufSize = 256;
+inline void PerfUsrTrace(const char* arg = nullptr) {
+  char buf[kBufSize] {0,};
+  const char* prefix_str = "[PERF][PLUSPLAYER]";
+  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 performance_checker
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_UTILS_PERFORMANCE_CHECKER_H__
diff --git a/src/plusplayer-core/include_internal/core/utils/plusplayer_cfg.h b/src/plusplayer-core/include_internal/core/utils/plusplayer_cfg.h
new file mode 100755 (executable)
index 0000000..c520886
--- /dev/null
@@ -0,0 +1,17 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_UTIL_PLUSPLAYER_CFG__
+#define __PLUSPLAYER_SRC_CORE_UTIL_PLUSPLAYER_CFG__
+
+namespace plusplayer {
+
+namespace plusplayer_cfg {
+  
+const char* GetIniPath();
+
+} // namespace plusplayer_cfg
+
+} // namespace plusplayer
+#endif  // __PLUSPLAYER_SRC_CORE_UTIL_PLUSPLAYER_CFG__
\ No newline at end of file
diff --git a/src/plusplayer-core/include_internal/core/utils/plusplayer_log.h b/src/plusplayer-core/include_internal/core/utils/plusplayer_log.h
new file mode 100755 (executable)
index 0000000..b8e2318
--- /dev/null
@@ -0,0 +1,110 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_UTILS_PLUSPLAYER_LOG_H__
+#define __PLUSPLAYER_SRC_UTILS_PLUSPLAYER_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 LOG_DEBUG(fmt, arg...) \
+  ({                           \
+    do {                       \
+      LOGE(fmt, ##arg);        \
+    } while (0);               \
+  })
+
+#define LOG_DEBUG_P(id, fmt, arg...)   \
+  ({                                   \
+    do {                               \
+      LOGE("[%p] > " #fmt, id, ##arg); \
+    } while (0);                       \
+  })
+
+#define LOG_INFO(fmt, arg...) \
+  ({                          \
+    do {                      \
+      LOGE(fmt, ##arg);       \
+    } while (0);              \
+  })
+
+#define LOG_INFO_P(id, fmt, arg...)    \
+  ({                                   \
+    do {                               \
+      LOGE("[%p] > " #fmt, id, ##arg); \
+    } while (0);                       \
+  })
+
+#define LOG_WARN(fmt, arg...) \
+  ({                          \
+    do {                      \
+      LOGE(fmt, ##arg);       \
+    } while (0);              \
+  })
+
+#define LOG_WARN_P(id, fmt, arg...)     \
+  ({                                    \
+    do {                                \
+      LOGE("[ %p] > " #fmt, id, ##arg); \
+    } while (0);                        \
+  })
+
+#define LOG_ERROR(fmt, arg...) \
+  ({                           \
+    do {                       \
+      LOGE(fmt, ##arg);        \
+    } while (0);               \
+  })
+
+#define LOG_ERROR_P(id, fmt, arg...)    \
+  ({                                    \
+    do {                                \
+      LOGE("[ %p] > " #fmt, id, ##arg); \
+    } while (0);                        \
+  })
+
+#define LOG_FATAL(fmt, arg...) \
+  ({                           \
+    do {                       \
+      LOGE(fmt, ##arg);        \
+    } while (0);               \
+  })
+
+#define LOG_ENTER    \
+  {                  \
+    do {             \
+      LOGE("ENTER"); \
+    } while (0);     \
+  }
+
+#define LOG_LEAVE    \
+  {                  \
+    do {             \
+      LOGE("LEAVE"); \
+    } while (0);     \
+  }
+
+#define LOG_ENTER_P(p)         \
+  {                            \
+    do {                       \
+      LOGE("[%p] > ENTER", p); \
+    } while (0);               \
+  }
+
+#define LOG_LEAVE_P(p)         \
+  {                            \
+    do {                       \
+      LOGE("[%p] > LEAVE", p); \
+    } while (0);               \
+  }
+
+#endif  // __PLUSPLAYER_SRC_UTILS_PLUSPLAYER_LOG_H__
diff --git a/src/plusplayer-core/include_internal/core/utils/scope_exit.h b/src/plusplayer-core/include_internal/core/utils/scope_exit.h
new file mode 100755 (executable)
index 0000000..a6295bc
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_UTILS_SCOPE_EXIT_H__
+#define __PLUSPLAYER_SRC_UTILS_SCOPE_EXIT_H__
+
+namespace plusplayer {
+
+namespace utils {
+
+template <typename T>
+class AtScopeExit {
+ public:
+  explicit AtScopeExit(const T& func) : func_(func) {}
+  AtScopeExit(const AtScopeExit&) = delete;
+  AtScopeExit(AtScopeExit&& o) : func_(o.func_) { o.call_ = false; }
+  ~AtScopeExit() {
+    if (call_) func_();
+  }
+
+ private:
+  const T& func_;
+  bool call_ = true;
+};
+
+template <typename T>
+AtScopeExit<T> ScopeExit(const T& func) {
+  return AtScopeExit<T>(func);
+}
+
+}  // namespace utils
+
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_UTILS_SCOPE_EXIT_H__
diff --git a/src/plusplayer-core/include_internal/core/videoframetypestrategy.h b/src/plusplayer-core/include_internal/core/videoframetypestrategy.h
new file mode 100755 (executable)
index 0000000..e8018fd
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_SRC_CORE_VIDEO_FRAME_TYPE_STRATEGY_H__
+#define __PLUSPLAYER_SRC_CORE_VIDEO_FRAME_TYPE_STRATEGY_H__
+
+#include <memory>
+
+#include "plusplayer/types/buffer.h"
+
+namespace plusplayer {
+struct VideoFrameTypeStrategy {
+  using TrackRendererHandle = void*;
+  virtual ~VideoFrameTypeStrategy() = default;
+  virtual void SetType(TrackRendererHandle handle) = 0;
+};
+
+using VideoFrameTypeStrategyPtr = std::unique_ptr<VideoFrameTypeStrategy>;
+
+class DefaultVideoFrameTypeStrategy : public virtual VideoFrameTypeStrategy {
+ public:
+  explicit DefaultVideoFrameTypeStrategy(
+      const DecodedVideoFrameBufferType type);
+  virtual ~DefaultVideoFrameTypeStrategy() = default;
+  virtual void SetType(TrackRendererHandle handle) override;
+
+ private:
+  const DecodedVideoFrameBufferType type_;
+};
+
+class RawVideoFrameTypeStrategy : public virtual VideoFrameTypeStrategy {
+ public:
+  explicit RawVideoFrameTypeStrategy() = default;
+  virtual ~RawVideoFrameTypeStrategy() = default;
+  virtual void SetType(TrackRendererHandle handle);
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_SRC_CORE_VIDEO_FRAME_TYPE_STRATEGY_H__
\ No newline at end of file
diff --git a/src/plusplayer-core/project_def.prop b/src/plusplayer-core/project_def.prop
new file mode 100755 (executable)
index 0000000..95f2f9c
--- /dev/null
@@ -0,0 +1,58 @@
+\r
+# Project Name\r
+APPNAME = plusplayercore_tvplus\r
+\r
+# Project Type\r
+type = sharedLib\r
+\r
+# Project Profile\r
+profile = tv-samsung-5.0\r
+\r
+# C/CPP Sources\r
+USER_SRCS = src/decoderinputbuffer.cpp src/error.cpp src/gstobject_guard.cpp src/gstsignal_holder.cpp src/gst_utils.cpp src/plusplayer_cfg.cpp src/serializer.cpp src/subtitle_attr_parser.cpp src/trackrendereradapter.cpp src/trackrendereradapter_utils.cpp src/track_util.cpp \r
+\r
+# EDC Sources\r
+USER_EDCS =  \r
+\r
+# PO Sources\r
+USER_POS = \r
+\r
+# User Defines\r
+USER_DEFS = \r
+USER_CPP_DEFS = TIZEN_DEPRECATION DEPRECATION_WARNING \r
+\r
+# User Undefines\r
+USER_UNDEFS = \r
+USER_CPP_UNDEFS = \r
+\r
+# User Libraries\r
+USER_LIBS = gstsubtitle_tvplus\r
+\r
+# User Objects\r
+USER_OBJS = \r
+\r
+# User Includes\r
+## C Compiler\r
+USER_C_INC_DIRS = \r
+USER_INC_FILES = \r
+## C++ Compiler\r
+USER_CPP_INC_DIRS = include_internal ../../include ../../../gst-plugins-subtitleparser/subtitle/include_internal\r
+USER_CPP_INC_FILES = \r
+\r
+USER_INC_DIRS = $(USER_C_INC_DIRS) $(USER_CPP_INC_DIRS)\r
+\r
+# User Library Path\r
+USER_LIB_DIRS = ../../../gst-plugins-subtitleparser/subtitle/${BUILD_CONFIG} \r
+\r
+# EDC Resource Path\r
+USER_EDCS_IMAGE_DIRS = ${OUTPUT_DIR} \r
+USER_EDCS_SOUND_DIRS = ${OUTPUT_DIR} \r
+USER_EDCS_FONT_DIRS = ${OUTPUT_DIR} \r
+\r
+# EDC Flags\r
+USER_EXT_EDC_KEYS = \r
+\r
+# Resource Filter\r
+USER_RES_INCLUDE = \r
+USER_RES_EXCLUDE = \r
+\r
diff --git a/src/plusplayer-core/src/base64.cpp b/src/plusplayer-core/src/base64.cpp
new file mode 100755 (executable)
index 0000000..083b8c3
--- /dev/null
@@ -0,0 +1,181 @@
+//\r
+// @ Copyright [2020] <S/W Platform,Visual Display,Samsung Electronics>\r
+//\r
+\r
+#ifndef __PLUSPLAYER_SRC_BASE64_H__\r
+#define __PLUSPLAYER_SRC_BASE64_H__\r
+\r
+#include <iostream>\r
+#include <map>\r
+#include <string>\r
+#include "core/kpi.h"\r
+#include "core/utils/plusplayer_log.h"\r
+\r
+namespace plusplayer {\r
+  namespace base64 {\r
+std::string Base64Encode(const char *str, const int size) {\r
+  LOG_ENTER\r
+  static const std::string sBase64Table =\r
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
+  static const char cFillChar = '=';\r
+  std::string sResult;\r
+\r
+  // Allocate memory for the converted string\r
+  sResult.reserve(size * 8 / 6 + 1);\r
+\r
+  for (int nPos = 0; nPos < size; nPos++) {\r
+    char cCode = (str[nPos] >> 2) & 0x3F;\r
+    // Encode the first 6 bits\r
+    sResult.append(1, sBase64Table[cCode]);\r
+    // Encode the remaining 2 bits with the next 4 bits (if present)\r
+    cCode = (str[nPos] << 4) & 0x3F;\r
+\r
+    if (++nPos < size) {\r
+      cCode |= (str[nPos] >> 4) & 0x0F;\r
+    }\r
+\r
+    sResult.append(1, sBase64Table[cCode]);\r
+\r
+    if (nPos < size) {\r
+      cCode = (str[nPos] << 2) & 0x3F;\r
+\r
+      if (++nPos < size) {\r
+        cCode |= (str[nPos] >> 6) & 0x03;\r
+      }\r
+\r
+      sResult.append(1, sBase64Table[cCode]);\r
+    } else {\r
+      ++nPos;\r
+      sResult.append(1, cFillChar);\r
+    }\r
+\r
+    if (nPos < size) {\r
+      cCode = str[nPos] & 0x3F;\r
+      sResult.append(1, sBase64Table[cCode]);\r
+    } else {\r
+      sResult.append(1, cFillChar);\r
+    }\r
+  }\r
+\r
+  LOG_INFO("Base64Encode output str %s", sResult.c_str());\r
+  LOG_LEAVE\r
+\r
+  return sResult;\r
+}\r
+\r
+std::string Base64Decode(const std::string str) {\r
+  // LOG_ENTER\r
+  std::string destr;\r
+  const int strLen = str.size();\r
+\r
+  static const char arr[] = {// insert from 'A' to 'Z'\r
+                             65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,\r
+                             78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,\r
+                             // insert from 'a' to 'z'\r
+                             97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,\r
+                             108, 109, 110, 111, 112, 113, 114, 115, 116, 117,\r
+                             118, 119, 120, 121, 122,\r
+                             // insert from '0' to '9'\r
+                             48, 49, 50, 51, 52, 53, 54, 55, 56, 57,\r
+                             // insert '+' and '/'\r
+                             43, 47};\r
+  const int size = static_cast<int>(sizeof(arr) / sizeof(char));\r
+  static std::map<char, int> base64EncodeMap;\r
+\r
+  if (base64EncodeMap.size() == 0)\r
+    for (int i = 0; i < size; i++)\r
+      base64EncodeMap.insert(std::pair<char, int>(arr[i], i));\r
+\r
+  LOG_INFO("Base64decode inconming str len %d ", strLen);\r
+\r
+  if (strLen % 4 != 0) {\r
+    // input string size must be multiple of 4\r
+    LOG_INFO("Quit base64decode for strlen error");\r
+    return destr;\r
+  }\r
+\r
+  if (strLen > 0) {\r
+    int pos = 0;\r
+    std::string subStr;\r
+    int encodePrev[4] = {0, 0, 0, 0};\r
+    int encodeEnd[3] = {0, 0, 0};\r
+\r
+    while (pos < strLen) {\r
+      subStr = str.substr(pos, 4);\r
+      int i = 0;\r
+\r
+      for (const auto &c : subStr) encodePrev[i++] = base64EncodeMap[c];\r
+\r
+      encodeEnd[0] = (encodePrev[0] << 2) | (encodePrev[1] >> 4);\r
+      encodeEnd[1] = (encodePrev[1] << 4) | (encodePrev[2] >> 2);\r
+      encodeEnd[2] = (encodePrev[2] << 6) | encodePrev[3];\r
+      destr.push_back(static_cast<char>(encodeEnd[0]));\r
+      destr.push_back(static_cast<char>(encodeEnd[1]));\r
+      destr.push_back(static_cast<char>(encodeEnd[2]));\r
+      pos += 4;\r
+    }\r
+  }\r
+\r
+  // base64 data contain "=" case\r
+  int count = 0;\r
+\r
+  for (int i = str.size() - 1; i >= 0; --i) {\r
+    if (str[i] == '=')\r
+      count++;\r
+    else\r
+      break;\r
+  }\r
+\r
+  LOG_INFO("[*] num of [=] ( %d )", count);\r
+\r
+  if (count > 2) {\r
+    LOG_INFO("[ERROR] num of = should less than two( %d )", count);\r
+    destr.clear();\r
+  } else if (count > 0) {\r
+    destr.erase(destr.size() - count, count);\r
+  }\r
+\r
+  LOG_INFO("Base64Decode output str %d", destr.size());\r
+  LOG_LEAVE\r
+  return destr;\r
+}\r
+  }\r
+\r
+}  // namespace plusplayer\r
+\r
+// base64 rfs ut\r
+// int main()\r
+// {\r
+//   std::cout <<"test"<<std::endl;\r
+//   std::map<std::string,std::string> RFC_test;//RFC 4648  tc\r
+//   RFC_test.insert(std::pair<std::string,std::string>("",""));\r
+//   RFC_test.insert(std::pair<std::string,std::string>("f","Zg=="));\r
+//   RFC_test.insert(std::pair<std::string,std::string>("fo","Zm8="));\r
+//   RFC_test.insert(std::pair<std::string,std::string>("foo","Zm9v"));\r
+//   RFC_test.insert(std::pair<std::string,std::string>("foob","Zm9vYg=="));\r
+//   RFC_test.insert(std::pair<std::string,std::string>("fooba","Zm9vYmE="));\r
+//   RFC_test.insert(std::pair<std::string,std::string>("foobar","Zm9vYmFy"));\r
+//   std::map<std::string,std::string>::iterator iter;\r
+\r
+//   for (iter = RFC_test.begin(); iter != RFC_test.end(); iter++)\r
+//   {\r
+//     std::string encodedstr =\r
+//     Base64Encode(iter->first.c_str(),iter->first.length());\r
+//     if(0!=encodedstr.compare(iter->second))\r
+//     {\r
+//       std::cout << "error encode test tc [" + iter->first +"] user result["+\r
+//       encodedstr + "] refer["+iter->second+"]";\r
+//     }\r
+//   }\r
+//   for (iter = RFC_test.begin(); iter != RFC_test.end(); iter++)\r
+//   {\r
+//     std::string decodedstr = Base64Decode(iter->second );\r
+//     if(0!=decodedstr.compare(iter->first))\r
+//     {\r
+//       std::cout << "error decode test tc [" + iter->second +"] user result["+\r
+//       decodedstr + "] refer["+iter->first+"]";\r
+//     }\r
+//   }\r
+\r
+// }\r
+#endif  // __PLUSPLAYER_SRC_BASE64_H__\r
diff --git a/src/plusplayer-core/src/caf_logger.cpp b/src/plusplayer-core/src/caf_logger.cpp
new file mode 100755 (executable)
index 0000000..62c3195
--- /dev/null
@@ -0,0 +1,303 @@
+#define _TAG "plusplayer"\r
+#include "core/utils/caf_logger.h"\r
+#include "core/utils/plusplayer_log.h"\r
+#include "context-aware-api.h"\r
+#include "ContextData.h"\r
+#include "json/json.h"\r
+#define SUBJECT_RAW_STREAMING_EVENT   "I/Raw/Streaming/Event"\r
+\r
+namespace plusplayer {\r
+\r
+CafLogger* CafLogger::instance_ = NULL;\r
+std::shared_ptr<ContextAware> CafLogger::context_aware_ = NULL;\r
+\r
+std::string EventStrName[] = {"None","Start", "End", "BitRate", "Buffering", "Resolution"};\r
+\r
+bool ContextAware::InitService()  {\r
+   return ContextAware_InitService();\r
+}     \r
+\r
+void ContextAware::Write(std::string json_data) {\r
+  return ContextAware_WriteRawStreamingEvent(json_data.c_str());\r
+}\r
+\r
+bool ContextAware::FiniService() {\r
+   return ContextAware_FiniService();\r
+} \r
+\r
+CafLogger::CafLogger() {\r
+  LOG_ENTER;\r
+  connected_to_dbus_ = false;\r
+  std::lock_guard<std::mutex> guard(object_lock_);\r
+\r
+  if(context_aware_ == NULL) {\r
+     context_aware_ = std::make_shared<ContextAware>();\r
+  }\r
+  \r
+  if(context_aware_ != NULL)\r
+    connected_to_dbus_ = context_aware_->InitService();\r
+  msg_thread_stopped_ = true;\r
+  app_id_ = "Unknown";\r
+  unique_number = -1;\r
+  if(connected_to_dbus_)\r
+    LOG_INFO("CAF initialized successfully.");\r
+  else\r
+    LOG_ERROR("CAF initialization FAILED.");\r
\r
+  LOG_LEAVE;\r
+}\r
+\r
+CafLogger::~CafLogger() {\r
+  LOG_ENTER;\r
+  std::lock_guard<std::mutex> guard(object_lock_);\r
+  StopMsgThread_();\r
+  if(connected_to_dbus_ == true && context_aware_ != NULL)\r
+  {\r
+    connected_to_dbus_ = context_aware_->FiniService();\r
+  }\r
+    \r
+  if(!connected_to_dbus_)\r
+    LOG_INFO("CAF finished successfully.");\r
+  LOG_LEAVE;\r
+}\r
+\r
+std::string CafLogger::GetEventStrName_(CafEventType event_type) {\r
+  if(event_type > CafEventType::kNone && event_type < CafEventType::kEventMax)\r
+    return EventStrName[(int)event_type];\r
+  return "";\r
+}\r
+\r
+std::string CafLogger::GetEventValueStrName_(CafEventType event_type) {\r
+  switch(event_type) {\r
+    case CafEventType::kBitrate: return "BitRateValue";\r
+    case CafEventType::kResolution: return "ResolutionValue";\r
+    case CafEventType::kBuffering: return "BufferingValue";\r
+    default:\r
+        return "";\r
+  }\r
+}\r
+\r
+std::string CafLogger::GetStateValueStrName_(CafEventType event_type) {\r
+  switch(event_type) {\r
+    case CafEventType::kStreamReady: return "StreamReady";\r
+    case CafEventType::kIdle: return "Idle";\r
+    case CafEventType::kReady: return "Ready";\r
+    case CafEventType::kPlaying: return "Playing";\r
+    case CafEventType::kPaused: return "Paused";\r
+    default:\r
+        return "";\r
+  }\r
+}\r
+\r
+void CafLogger::SendData_(CafEventData event) {\r
+  LOG_ENTER;\r
+  ContextData cafData;\r
+  cafData.SetValue("Appid",app_id_);\r
+  switch(event.event_type) {\r
+    case CafEventType::kStart: cafData.SetValue("Event", "Start");break;\r
+    case CafEventType::kEnd: cafData.SetValue("Event", "End");break;\r
+    case CafEventType::kBuffering: /* FALL THROUGH */\r
+    //case CafEventType::kResolution: /* FALL THROUGH */\r
+    case CafEventType::kBitrate: {\r
+      std::string event_name = GetEventStrName_(event.event_type);\r
+      cafData.SetValue("Event", event_name);\r
+      std::string event_value_name = GetEventValueStrName_(event.event_type);\r
+      cafData.SetValue(event_value_name.c_str(), event.event_data);\r
+    }break;\r
+    case CafEventType::kStreamReady: /* FALL THROUGH */\r
+    case CafEventType::kIdle: /* FALL THROUGH */\r
+    case CafEventType::kReady: /* FALL THROUGH */\r
+    case CafEventType::kPlaying: /* FALL THROUGH */\r
+    case CafEventType::kPaused: {\r
+      cafData.SetValue("UniqueId", event.event_data);\r
+      std::string state_value_name = GetStateValueStrName_(event.event_type);\r
+      cafData.SetValue("PlayerState", state_value_name.c_str());\r
+    }break;\r
+    default:\r
+      return;\r
+  }\r
+  LOG_ERROR("all eventdata message [%s]", cafData.MakeStr());\r
+  if(context_aware_ != NULL)  \r
+    context_aware_->Write(cafData.MakeStr());\r
+  LOG_LEAVE;\r
+}\r
+\r
+void CafLogger::MsgTask_() {\r
+LOG_ENTER;\r
+std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);\r
+  do{\r
+    if(msg_queue_.empty())\r
+      msg_task_cv_.wait(msg_mutex);\r
+    if(!msg_queue_.empty()) {\r
+      CafEventData eventData = msg_queue_.front();\r
+      SendData_(eventData);\r
+      msg_queue_.pop();\r
+    }\r
+  } while(!msg_thread_stopped_);\r
+  LOG_LEAVE;\r
+}\r
+\r
+void CafLogger::StartMsgThread_() {\r
+  LOG_ENTER;\r
+  std::lock_guard<std::mutex> guard(object_lock_);\r
+  if(msg_thread_stopped_) {\r
+    using_instance_.push(unique_number);\r
+    msg_thread_stopped_ = false;\r
+    msg_handler_task_ = std::async(std::launch::async, &CafLogger::MsgTask_, this);\r
+  }\r
+  LOG_LEAVE;\r
+}\r
+\r
+void CafLogger::StopMsgThread_() {\r
+  LOG_ENTER;\r
+  \r
+  if(msg_thread_stopped_) return;\r
+\r
+  using_instance_.pop();\r
+\r
+  if(msg_handler_task_.valid() && using_instance_.empty()) {\r
+    std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);\r
+    msg_thread_stopped_ = true;\r
+    msg_task_cv_.notify_one();\r
+    msg_mutex.unlock();\r
+    msg_handler_task_.wait();\r
+  }\r
+  LOG_LEAVE;\r
+}\r
+\r
+bool CafLogger::PushMessageToQueue_(CafEventType event_type, std::string data) {\r
+  LOG_ENTER;\r
+  bool ret = false;\r
+  std::lock_guard<std::mutex> guard(object_lock_);\r
+  if(msg_handler_task_.valid()) {\r
+    CafEventData event;\r
+    event.event_type = event_type;\r
+    event.event_data = data;\r
+    std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);\r
+    msg_queue_.push(event);\r
+    msg_mutex.unlock();\r
+    msg_task_cv_.notify_one();\r
+    ret = true;\r
+  }\r
+  LOG_LEAVE;\r
+  return ret;\r
+}\r
+\r
+bool CafLogger::Connect_() {\r
+  LOG_ENTER;\r
+  std::lock_guard<std::mutex> guard(object_lock_);\r
+  if(!connected_to_dbus_ && context_aware_ != NULL)\r
+    connected_to_dbus_ = context_aware_->InitService();\r
+  LOG_LEAVE;\r
+  return connected_to_dbus_;\r
+}\r
+\r
+bool CafLogger::Disconnect_() {\r
+  LOG_ENTER;\r
+  std::lock_guard<std::mutex> guard(object_lock_);\r
+  /*first stop message thread, then disconnect. */\r
+  \r
+  StopMsgThread_();\r
+  LOG_INFO("Disconnecting to DBus.");\r
+  if(connected_to_dbus_ && context_aware_ != NULL)\r
+    connected_to_dbus_ = context_aware_->FiniService();\r
+  if(!connected_to_dbus_)\r
+    LOG_INFO("Disconnecting to DBus FAILED.");\r
+  connected_to_dbus_ = false;\r
+  LOG_LEAVE;\r
+  return true;\r
+}\r
+\r
+bool CafLogger::isConnected_() {\r
+  return connected_to_dbus_;\r
+}\r
+\r
+void CafLogger::setAppId_(std::string app_id) {\r
+  app_id_ = app_id;\r
+}\r
+\r
+void CafLogger::setUniqueNumber_(int uniqueNumber) {\r
+  unique_number = uniqueNumber;\r
+}\r
+\r
+int CafLogger::getUniqueNumber_() {\r
+  return unique_number;\r
+}\r
+/********   STATIC FUNCTIONS ****************/\r
+\r
+bool CafLogger::Initialize() {\r
+  LOG_ENTER;\r
+\r
+  if(instance_ == NULL) {\r
+     instance_ = new CafLogger();\r
+  }\r
+  LOG_LEAVE;\r
+  return instance_->isConnected_();\r
+}\r
+\r
+bool CafLogger::LogMessage(CafEventType event_type, std::string data) {\r
+  LOG_ENTER;\r
+  bool ret = false;\r
+#ifndef SDK_DISABLED_FEATURE  \r
+  if(instance_ != NULL && instance_->isConnected_()) {\r
+    ret = instance_->PushMessageToQueue_(event_type, data);\r
+  }\r
+#endif\r
+  LOG_LEAVE;\r
+  return ret;\r
+}\r
+\r
+void CafLogger::StartLoggingThread() {\r
+  LOG_ENTER;\r
+  if(instance_ != NULL)\r
+    instance_->StartMsgThread_();\r
+  LOG_LEAVE;\r
+}\r
+\r
+void CafLogger::StopLoggingThread() {\r
+  LOG_ENTER;\r
+  if(instance_ != NULL)\r
+    instance_->StopMsgThread_();\r
+  LOG_LEAVE;\r
+}\r
+\r
+void CafLogger::SetAppId(std::string app_id) {\r
+  LOG_ENTER;\r
+  if(instance_ != NULL)\r
+    instance_->setAppId_(app_id);\r
+  LOG_LEAVE;\r
+}\r
+\r
+void CafLogger::SetUniqueNumber()\r
+{\r
+  LOG_ENTER;\r
+    int id = -1;\r
+    if(instance_ != NULL)\r
+    {\r
+      id = instance_->getUniqueNumber_();\r
+      instance_->setUniqueNumber_(++id);\r
+    }\r
+  LOG_LEAVE;\r
+}\r
+std::string CafLogger::GetUniqueNumber()\r
+{\r
+  LOG_ENTER;\r
+  int id = -1;\r
+  std::string uniqueNumber;\r
+  if(instance_ != NULL)\r
+  {    \r
+    id = instance_->getUniqueNumber_();\r
+    uniqueNumber = std::to_string(getpid()) + "_" + std::to_string(id);\r
+  }\r
+  LOG_LEAVE;\r
+  return uniqueNumber;\r
+}\r
+\r
+void CafLogger::SetContextAware(std::shared_ptr<ContextAware>&& context_aware)\r
+{\r
+  LOG_ENTER;  \r
+  context_aware_ = context_aware;\r
+  LOG_LEAVE;  \r
+} \r
+\r
+} //plusplayer
\ No newline at end of file
diff --git a/src/plusplayer-core/src/decodedvideopacketex.cpp b/src/plusplayer-core/src/decodedvideopacketex.cpp
new file mode 100755 (executable)
index 0000000..68b0f5a
--- /dev/null
@@ -0,0 +1,21 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "plusplayer/decodedvideopacketex.h"
+
+namespace plusplayer {
+
+  DecodedVideoPacketExPtr DecodedVideoPacketEx::Create(const uint64_t pts,
+                      const uint64_t duration, tbm_surface_h surface_data,
+                      const void* scaler_index) {
+    return Ptr(new DecodedVideoPacketEx(pts, duration, surface_data, scaler_index));
+  }
+
+  DecodedVideoPacketEx::~DecodedVideoPacketEx() {
+    if (surface_data_) {
+      tbm_surface_destroy(surface_data_);
+      surface_data_ = nullptr;
+    }
+  }
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/decoderinputbuffer.cpp b/src/plusplayer-core/src/decoderinputbuffer.cpp
new file mode 100755 (executable)
index 0000000..1087462
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/decoderinputbuffer.h"
+
+namespace plusplayer {
+
+namespace decoderinputbuffer_util {
+
+bool FlushQueue(std::queue<DecoderInputBufferPtr>& queue) {
+  while (!queue.empty()) {
+    queue.pop();
+  }
+  return true;
+}
+
+}  // namespace decoderinputbuffer_util
+
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/error.cpp b/src/plusplayer-core/src/error.cpp
new file mode 100755 (executable)
index 0000000..2f8fa14
--- /dev/null
@@ -0,0 +1,159 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/error.h"
+
+#include "core/gstobject_guard.h"
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+namespace internal {
+
+ErrorType ConvertGstCoreError(const int error_code);
+ErrorType ConvertGstLibraryError(const int error_code);
+ErrorType ConvertGstResourceError(const int error_code);
+ErrorType ConvertGstStreamError(const GError* error);
+
+}  // namespace internal
+
+ErrorType HandleGstError(const GError* error) {
+  ErrorType ret = ErrorType::kNone;
+
+  if (error == nullptr) return ret;
+  LOG_ERROR("Entered HandleGstError  error->code[%d] ", error->code);
+  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 {
+    LOG_INFO("This error domain is not defined.\n");
+    // we treat system error as an internal error
+    ret = ErrorType::kInvalidOperation;
+  }
+  return ret;
+}
+
+namespace internal {
+
+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: {
+      LOG_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;
+}
+
+}  // namespace internal
+
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/gst_utils.cpp b/src/plusplayer-core/src/gst_utils.cpp
new file mode 100755 (executable)
index 0000000..6111a46
--- /dev/null
@@ -0,0 +1,83 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include "core/gst_utils.h"
+
+#include <cassert>
+#include <thread>
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+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);
+  LOG_INFO_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) {
+    LOG_ERROR_P(id, "Set State to NULL failed");
+    assert(0 && "Set State to NULL failed");
+  }
+}
+
+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) {
+    LOG_INFO(" %s", argv[i]);
+  }
+  char** pargv = argv;
+  gst_init(&argc, &pargv);
+}
+
+}  // namespace gst_util
+
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/gstobject_guard.cpp b/src/plusplayer-core/src/gstobject_guard.cpp
new file mode 100755 (executable)
index 0000000..3f62e9d
--- /dev/null
@@ -0,0 +1,50 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include "glib.h"
+
+#include "core/gstobject_guard.h"
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+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 plusplayer
diff --git a/src/plusplayer-core/src/gstsignal_holder.cpp b/src/plusplayer-core/src/gstsignal_holder.cpp
new file mode 100755 (executable)
index 0000000..07c68d8
--- /dev/null
@@ -0,0 +1,89 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/gstsignal_holder.h"
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+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)
+      LOG_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_);
+    LOG_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)) {
+    LOG_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_);
+  LOG_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 plusplayer
diff --git a/src/plusplayer-core/src/kpi.cpp b/src/plusplayer-core/src/kpi.cpp
new file mode 100755 (executable)
index 0000000..0b310c7
--- /dev/null
@@ -0,0 +1,199 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/kpi.h"
+
+#include <sstream>
+
+#include "core/utils/plusplayer_log.h"
+
+/* for logger */
+#include "capi-system-info/system_info.h"
+#include "logger/Logger2.h"
+
+using namespace KPILogFramework;
+
+namespace {
+
+const char* GetProductYear(void) {
+  static const char* year = nullptr;
+  if (year) return year;
+
+  int value = -1;
+  int result = system_info_get_custom_int(
+      "com.samsung/featureconf/product.tv_year", &value);
+  if (result != SYSTEM_INFO_ERROR_NONE || value < 0) {
+    LOG_ERROR(
+          "can't get com.samsung/featureconf/product.tv_year, result:%d, "
+          "value:%d",
+          result, value);
+    return "20";
+  }
+
+  static char str_year[3] = {0, };
+  int size = snprintf(str_year, 3, "%d", value);
+  if (size != 2) {
+    LOG_ERROR("size is not 2!! size:%d, year:%d", size, value);
+    return "20";
+  }
+
+  year = str_year;
+  return year;
+}
+}  // unnamed namespace
+
+namespace plusplayer {
+
+namespace internal {
+std::string GetSrcType(SourceType ptype) {
+  switch (ptype) {
+    case SourceType::kHttp:
+      return "HTTP";
+    case SourceType::kHls:
+      return "HLS";
+    case SourceType::kDash:
+      return "DASH";
+    case SourceType::kFile:
+      return "FILE";
+    case SourceType::kNone:
+    case SourceType::kBase:
+    case SourceType::kExternalSubtitle:
+    case SourceType::kMax:
+    default:
+      return "others";
+  }
+}
+
+std::string GetDrmType(drm::Type dtype) {
+  switch (dtype) {
+    case drm::Type::kNone:
+      return "NONE";
+    case drm::Type::kPlayready:
+      return "PLAYREADY";
+    case drm::Type::kMarlin:
+      return "MARLIN";
+    case drm::Type::kVerimatrix:
+      return "VERIMATRIX";
+    case drm::Type::kWidevineClassic:
+      return "WIDEVINE CLASSIC";
+    case drm::Type::kSecuremedia:
+      return "SECUREMEDIA";
+    case drm::Type::kSdrm:
+      return "SDRM";
+    case drm::Type::kWidevineCdm:
+      return "WIDEVINE CDM";
+    case drm::Type::kMax:
+    default:
+      return "others";
+  }
+}
+
+std::string GetDecoderType(int ctype) {  //(0:DEFAULT, 1:HW, 2:SW, 3:DISABLE)
+  if (ctype == 0 || ctype == 1) {
+    return "HW";
+  } else if (ctype == 2) {
+    return "SW";
+  } else {
+    return "DISABLE";
+  }
+}
+}  // namespace internal
+
+namespace kpi {
+bool CodecLogger::SendKpi(bool event_case, const CodecLoggerKeys& keys) {
+  LOG_ENTER;
+
+  std::string ptype = internal::GetSrcType(keys.src_type);
+  std::string drm_type = internal::GetDrmType(keys.drm_type);
+  std::string v_decoder_type = internal::GetDecoderType(keys.v_decoder_type);
+  std::string a_decoder_type = internal::GetDecoderType(keys.a_decoder_type);
+
+  // generate message
+  std::stringstream str;
+  str << "{";
+  str << "ptype=" << ptype;
+  str << ";dtype=" << drm_type;
+  str << ";data_container=" << keys.container_type;
+  str << ";v_decoder_type=" << v_decoder_type;
+  str << ";v_codec=" << keys.v_codec;
+  str << ";v_tag=0x" << std::hex << keys.v_tag;
+  str << ";width=" << std::dec << keys.width;
+  str << ";height=" << std::dec << keys.height;
+  str << ";a_decoder_type=" << a_decoder_type;
+  str << ";a_codec=" << keys.a_codec;
+  str << ";a_tag=0x" << std::hex << keys.a_tag;
+  str << ";app_id=" << keys.app_id;
+  str << "}";
+
+  return SendKpi_(event_case, str);
+}
+
+bool CodecLogger::SendKpi(bool event_case, const EsCodecLoggerKeys& keys) {
+  LOG_ENTER;
+
+  std::string ptype = keys.is_clean ? "MSE" : "EME";
+  std::string drm_type = keys.is_clean ? "NONE" : "EME";
+  std::string v_decoder_type("HW");
+  std::string a_decoder_type("HW");
+  std::string container_type("EsPlusplayer");
+  unsigned int video_tag = 0;
+  unsigned int audio_tag = 0;
+  std::string video_codec = keys.v_codec + "-" +
+                            std::to_string(keys.v_codec_version);
+
+  // generate message
+  std::stringstream str;
+  str << "{";
+  str << "ptype=" << ptype;
+  str << ";dtype=" << drm_type;
+  str << ";data_container=" << container_type;
+  str << ";v_decoder_type=" << v_decoder_type;
+  str << ";v_codec=" << keys.v_codec;
+  str << ";v_tag=0x" << std::hex << video_tag;
+  str << ";width=" << std::dec << keys.width;
+  str << ";height=" << std::dec << keys.height;
+  str << ";a_decoder_type=" << a_decoder_type;
+  str << ";a_codec=" << keys.a_codec;
+  str << ";a_tag=0x" << std::hex << audio_tag;
+  str << ";app_id=" << keys.app_id;
+  str << "}";
+
+  return SendKpi_(event_case, str);
+}
+
+bool CodecLogger::SendKpi_(bool event_case, const std::stringstream& message) {
+  LOG_ENTER;
+  const char* year = ::GetProductYear();
+
+  // send message to KPI logger
+  std::stringstream service_name;
+  service_name << year << "_codec";
+  std::string eventName;
+  std::string category;
+  if (event_case) {
+    eventName = "PLAYBACK";
+    category = "EV001";
+  } else {
+    eventName = "ERRPLAY";
+    category = "EV002";
+  }
+
+  LOG_ERROR("[KPI] service_name: %s, desc_log: %s",
+            service_name.str().c_str(), message.str().c_str());
+
+  CLogger* pLogger = CLogger::GetInstance();
+  LoggerErrorCode result = LOGGER_ERROR_NONE;
+  result = pLogger->AddEventLogSync(service_name.str().c_str(), eventName.c_str(),
+                                    category.c_str(), message.str().c_str());
+  if (result != LOGGER_ERROR_NONE) {
+    LOG_ERROR("Failed to send KPI log for esplayer, result:%d", result);
+    return false;
+  }
+
+  return true;
+}
+
+
+}  // namespace kpi
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/plusplayer_cfg.cpp b/src/plusplayer-core/src/plusplayer_cfg.cpp
new file mode 100755 (executable)
index 0000000..bce0a47
--- /dev/null
@@ -0,0 +1,24 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <cassert>
+
+#ifndef PLUPLAYER_DOWNLOADABLE_APP_TVPLUS
+#include "tzplatform_config.h"
+#endif
+
+namespace plusplayer {
+
+namespace plusplayer_cfg {
+  
+const char* GetIniPath() {
+  const char* path =
+    tzplatform_mkpath(TZ_SYS_RO_ETC, "multimedia/esplusplayer.ini");
+  assert(path);
+  return path;
+}
+
+} // namespace plusplayer_cfg
+
+} // namespace plusplayer
\ No newline at end of file
diff --git a/src/plusplayer-core/src/serializer.cpp b/src/plusplayer-core/src/serializer.cpp
new file mode 100755 (executable)
index 0000000..a31ab75
--- /dev/null
@@ -0,0 +1,47 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/serializer.h"
+
+namespace plusplayer {
+using Offset = Serializer::Offset;
+using Byte = Serializer::Byte;
+
+Offset Serializer::Put(const std::vector<unsigned char> &vector) {
+  Offset offset = size_;
+  if (vector.size() == 0) return offset;
+  const size_t size = vector.size();
+  const Byte *data_bytes = reinterpret_cast<const Byte *>(vector.data());
+  Put_(data_bytes, size);
+  return offset;
+}
+
+Offset Serializer::Put(const std::string &data) {
+  Offset offset = size_;
+  if (data.length() == 0) return offset;
+  const size_t size = data.length();
+  const Byte *data_bytes = reinterpret_cast<const Byte *>(data.c_str());
+  Put_(data_bytes, size);
+  return offset;
+}
+
+Offset Serializer::Put(const Byte *data, size_t size) {
+  Offset offset = size_;
+  if (size == 0) return offset;
+  Put_(data, size);
+  return offset;
+}
+
+size_t Serializer::Serialize(Byte *serialized) {
+  buf_.sgetn(serialized, size_);
+  return size_;
+}
+
+const size_t Serializer::GetSize() { return size_; }
+
+void Serializer::Put_(const Byte *data_bytes, const size_t size) {
+  buf_.sputn(data_bytes, size);
+  size_ += size;
+}
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/subtitle_attr_parser.cpp b/src/plusplayer-core/src/subtitle_attr_parser.cpp
new file mode 100755 (executable)
index 0000000..8daa6f5
--- /dev/null
@@ -0,0 +1,556 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/subtitle_attr_parser.h"
+
+#include <algorithm>
+#include <cassert>
+
+#include "gst/ffsubtitle/gstsubattributes.h"
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+#ifdef PLUPLAYER_DOWNLOADABLE_APP_TVPLUS
+#define GST_SUB_ATTRI_FUNC(name) gst_sub_attributes_##name
+#define GST_SUB_ATTRI_ENUM(name) GST_SUB_ATTRIBUTES_##name
+#define GstSubAttriScope GstSubAttributesScope
+#define GstSubAttriType GstSubAttributesType
+#else
+#define GST_SUB_ATTRI_FUNC(name) gst_sub_attribute_##name
+#define GST_SUB_ATTRI_ENUM(name) GST_SUB_ATTRI_##name
+#define GstSubAttriScope GstSubAttributeScope
+#define GstSubAttriType GstSubAttributeType
+#endif
+
+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) {
+  LOG_ENTER;
+  while (attribute) {
+    gfloat x_pos = kAttrInvalidIntVal, y_pos = kAttrInvalidFloatVal,
+           width = kAttrInvalidFloatVal, height = kAttrInvalidFloatVal;
+    attribute = GST_SUB_ATTRI_FUNC(region_parse)(attribute, &x_pos, &y_pos,
+                                               &width, &height);
+    LOG_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) {
+  LOG_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_ATTRI_FUNC(window_parse)(
+        attribute, &x_padding, &y_padding, &l_margin, &r_margin, &t_margin,
+        &b_margin, &bg_color, &opacity, &show_bg);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute font!");
+  while (attribute) {
+    GstSubAttriScope 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_ATTRI_FUNC(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);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute font shortcut SIZE_WEIGHT_STYLE_COLOR!");
+  while (attribute) {
+    GstSubAttriScope scope;
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gfloat size = kAttrInvalidFloatVal;
+    gint weight = kAttrInvalidIntVal, style = kAttrInvalidIntVal;
+    guint color = kAttrInvalidUintVal;
+    attribute = GST_SUB_ATTRI_FUNC(font_sc_size_weight_style_color_parse)(
+        attribute, &scope, &start_index, &stop_index, &size, &weight, &style,
+        &color);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute font shortcut SIZE_COLORS_AND_OPACITIES!");
+  while (attribute) {
+    GstSubAttriScope 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_ATTRI_FUNC(font_sc_colors_and_opacities_parse)(
+        attribute, &scope, &start_index, &stop_index, &color, &bg_color,
+        &opacity, &bg_opacity, &text_outline_color);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute font shortcut SIZE!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gfloat size = kAttrInvalidFloatVal;
+    attribute = GST_SUB_ATTRI_FUNC(font_sc_size_parse)(attribute, &start_index,
+                                                     &stop_index, &size);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute font shortcut WEIGHT!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gint weight = kAttrInvalidIntVal;
+    attribute = GST_SUB_ATTRI_FUNC(font_sc_weight_parse)(attribute, &start_index,
+                                                       &stop_index, &weight);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute font shortcut STYLE!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gint style = kAttrInvalidIntVal;
+    attribute = GST_SUB_ATTRI_FUNC(font_sc_style_parse)(attribute, &start_index,
+                                                      &stop_index, &style);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute font shortcut COLOR!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    guint color = kAttrInvalidUintVal;
+    attribute = GST_SUB_ATTRI_FUNC(font_sc_color_parse)(attribute, &start_index,
+                                                      &stop_index, &color);
+    LOG_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) {
+  LOG_DEBUG("Now parse attribute raw!");
+  while (attribute) {
+    guint start_index = kAttrInvalidUintVal, stop_index = kAttrInvalidUintVal;
+    gchar* raw_subtitle = nullptr;
+    attribute = GST_SUB_ATTRI_FUNC(raw_data)(attribute, &raw_subtitle);
+    LOG_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) {
+  LOG_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_ATTRI_FUNC(webvttcue_parse)(
+        attribute, &line, &line_num, &line_align, &align, &size, &position,
+        &pos_align, &vertical);
+    LOG_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_ENUM(TYPE_REGION);
+       attr_type < GST_SUB_ATTRI_ENUM(TYPE_UNKNOWN); ++attr_type) {
+    const gchar* type_name =
+        GST_SUB_ATTRI_FUNC(type_to_name)((GstSubAttriType)attr_type);
+    GQuark attri_quark =
+        GST_SUB_ATTRI_FUNC(type_to_quark)((GstSubAttriType)attr_type);
+    if (!attri_quark) {
+      LOG_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;
+    LOG_DEBUG("[core] attribute type(%s) from gstbuffer!", type_name);
+
+    switch (attr_type) {
+      case GST_SUB_ATTRI_ENUM(TYPE_REGION):
+        internal::ParseSubtitleRegionAttr(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_WINDOW):
+        internal::ParseSubtitleWindowAttr(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_FONT):
+        internal::ParseSubtitleFontAttr(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_FONT_SC_SIZE_WEIGHT_STYLE_COLOR):
+        internal::ParseSubtitleFontSizeWeightStyleClolr(attribute,
+                                                        attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_FONT_SC_COLORS_AND_OPACITIES):
+        internal::ParseSubtitleFontColorOpacities(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_FONT_SC_SIZE):
+        internal::ParseSubtitleFontSize(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_FONT_SC_WEIGHT):
+        internal::ParseSubtitleFontWeight(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_FONT_SC_STYLE):
+        internal::ParseSubtitleFontStyle(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_FONT_SC_COLOR):
+        internal::ParseSubtitleFontColor(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_RAW):
+        internal::ParseSubtitleRaw(attribute, attr_list.get());
+        break;
+      case GST_SUB_ATTRI_ENUM(TYPE_WEBVTT_CUE):
+        internal::ParseSubtitleWebvttCue(attribute, attr_list.get());
+        break;
+      default:
+        LOG_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_));
+  LOG_DEBUG("pts[%llu] duration[%llu]", timestamp, duration);
+  internal::AddSubtitleAttribute(attr_list.get(), kSubAttrTimestamp, value,
+                                 timestamp, timestamp + duration);
+
+  return attr_list;
+}
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/track_util.cpp b/src/plusplayer-core/src/track_util.cpp
new file mode 100755 (executable)
index 0000000..df9ceec
--- /dev/null
@@ -0,0 +1,137 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/track_util.h"
+
+#include <string>
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+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;
+  // LOG_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()) {
+    LOG_ERROR("no active track found");
+    return false;
+  }
+  if (video > 1 || audio > 1 || text > 1) {
+    LOG_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;
+  LOG_INFO("### Track List ###");
+  for (const Track& item : info) {
+    ShowTrackInfo(item);
+  }
+  LOG_INFO("### ~Track List ###");
+}
+
+void ShowTrackInfo(const Track& track) {
+  LOG_INFO("### TrackInfo ###");
+  LOG_INFO("index : %d   id : %d ,", track.index, track.id);
+  LOG_INFO("mimetype: %s", track.mimetype.c_str());
+  LOG_INFO("streamtype: %s", track.streamtype.c_str());
+  LOG_INFO("container_type: %s", track.container_type.c_str());
+  LOG_INFO("tracktype : %d", track.type);
+  LOG_INFO("codec tag : %d", track.codec_tag);
+  LOG_INFO("width: %d  height : %d", track.width, track.height);
+  LOG_INFO("maxwidth: %d  maxheight : %d", track.maxwidth, track.maxheight);
+  LOG_INFO("framerate(num : %d  den : %d)", track.framerate_num,
+           track.framerate_den);
+  LOG_INFO("framerate(codec_data : %p )", track.codec_data.get());
+  LOG_INFO("framerate(codec_data_len : %d )", track.codec_data_len);
+  LOG_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);
+  LOG_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);      
+  LOG_INFO("active %d  subtitle_format : %s ", track.active, track.subtitle_format.c_str() );
+  LOG_INFO("use_swdecoder : %d", track.use_swdecoder);
+  LOG_INFO("language_code: %s", track.language_code.c_str());
+}
+
+uint64_t GetPositionWithinBoundary(const uint64_t duration,
+                                   const uint64_t position,
+                                   const uint64_t threshold) {
+  LOG_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,
+                            plusplayer::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)) {
+    LOG_DEBUG("codec extra data [ %s ]", codec_data_info.data);
+    LOG_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 {
+      LOG_WARN("Warning invalid codec extra data size [%d]",
+               codec_data_info.size);
+    }
+    gst_buffer_unmap(buffer, &codec_data_info);
+  } else {
+    LOG_DEBUG("Fail to gst_buffer_map for codec data");
+  }
+}
+
+}  // namespace track_util
+
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/trackrendereradapter.cpp b/src/plusplayer-core/src/trackrendereradapter.cpp
new file mode 100755 (executable)
index 0000000..95d87f6
--- /dev/null
@@ -0,0 +1,1113 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/trackrendereradapter.h"
+
+#include <cstring>
+
+#include "core/trackrendereradapter_utils.h"
+#include "core/utils/plusplayer_log.h"
+#include "trackrenderer_capi/trackrenderer_internal.h"
+
+namespace plusplayer {
+
+TrackRendererAdapter::Ptr TrackRendererAdapter::Create() {
+  LOG_INFO("Trackrenderer adapter is created");
+  return Ptr(new TrackRendererAdapter);
+}
+
+TrackRendererAdapter::TrackRendererAdapter() { trackrenderer_create(&handle_); }
+
+TrackRendererAdapter::~TrackRendererAdapter() {
+  if (handle_) {
+    trackrenderer_destroy(handle_);
+    handle_ = nullptr;
+  }
+}
+
+bool TrackRendererAdapter::Start() {
+  if (trackrenderer_start(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Stop() {
+  if (trackrenderer_stop(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Prepare() {
+  if (trackrenderer_prepare(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Pause() {
+  if (trackrenderer_pause(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Resume() {
+  if (trackrenderer_resume(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+constexpr int kTrackRendererMaxStreamNumber = 3;
+bool TrackRendererAdapter::SetTrack(const std::vector<Track>& trackinfo) {
+  int size = trackinfo.size();
+  if (size <= 0 || size > kTrackRendererMaxStreamNumber) return false;
+
+  TrackRendererTrack tracks[size];
+  int index = 0;
+  for (const auto& track : trackinfo) {
+    adapter_utils::MakeTrackRendererTrack(&tracks[index], track);
+    index++;
+  }
+
+  if (trackrenderer_set_track(handle_, tracks, size) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+void TrackRendererAdapter::SetIniProperty(
+    const std::map<std::string, bool>& properties) {
+  const int size = properties.size();
+  if (size <= 0) return;
+  TrackRendererIniProperty trackrenderer_iniproperty[size];
+  int index = 0;
+  for (const auto& pair : properties) {
+    trackrenderer_iniproperty[index].key = pair.first.c_str();
+    trackrenderer_iniproperty[index].value = pair.second;
+    index++;
+  }
+  trackrenderer_set_ini_property(handle_, trackrenderer_iniproperty, size);
+}
+
+bool TrackRendererAdapter::Seek(uint64_t time_millisecond,
+                                double playback_rate) {
+  if (trackrenderer_seek(handle_, time_millisecond, playback_rate) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Seek(uint64_t time_millisecond, double playback_rate,
+                                bool audio_mute) {
+  if (trackrenderer_seek2(handle_, time_millisecond, playback_rate,
+                          audio_mute) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetPlaybackRate(double playback_rate,
+                                           bool audio_mute) {
+  if (trackrenderer_set_playback_rate(handle_, playback_rate, audio_mute) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetPlayingTime(uint64_t* time_millisecond) {
+  if (trackrenderer_get_playing_time(handle_, time_millisecond) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetDroppedFrames(void* counts) {
+  if (trackrenderer_get_dropped_frames(handle_, counts) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetDroppedFramesForCatchup(TrackType type,
+                                                      void* counts) {
+  if (trackrenderer_get_dropped_frames_for_catchup(
+          handle_, adapter_utils::ConvertToTrackRendererTrackType(type),
+          counts) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Deactivate(TrackType type) {
+  if (trackrenderer_deactivate(
+          handle_, adapter_utils::ConvertToTrackRendererTrackType(type)) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Activate(TrackType type, const Track& trackinfo) {
+  TrackRendererTrack track;
+  adapter_utils::MakeTrackRendererTrack(&track, trackinfo);
+
+  if (trackrenderer_activate(
+          handle_, adapter_utils::ConvertToTrackRendererTrackType(type),
+          &track) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SubmitPacket(const DecoderInputBufferPtr& data) {
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  TrackRendererDecoderInputBuffer decoderinputbuffer{
+      adapter_utils::ConvertToTrackRendererTrackType(data->GetType()),
+      data->GetIndex(),
+      static_cast<void*>(const_cast<GstBuffer*>(data->Get()))};
+#else
+  TrackRendererDecoderInputBuffer decoderinputbuffer{
+      adapter_utils::ConvertToTrackRendererTrackType(data->GetType()),
+      data->GetIndex(), const_cast<GstBuffer*>(data->Get())};
+#endif
+  if (trackrenderer_submit_packet(handle_, &decoderinputbuffer, nullptr) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+namespace adapter_utils {
+
+TrackRendererAdapter::SubmitStatus ConvertToAdapterSubmitStatus(
+    TrackRendererSubmitStatus status) {
+  switch (status) {
+    case kTrackRendererSubmitStatusNotPrepared: {
+      return TrackRendererAdapter::SubmitStatus::kNotPrepared;
+    }
+    case kTrackRendererSubmitStatusHold: {
+      return TrackRendererAdapter::SubmitStatus::kHold;
+    }
+    case kTrackRendererSubmitStatusFull: {
+      return TrackRendererAdapter::SubmitStatus::kFull;
+    }
+    case kTrackRendererSubmitStatusSuccess: {
+      return TrackRendererAdapter::SubmitStatus::kSuccess;
+    }
+    case kTrackRendererSubmitStatusDrop: {
+      return TrackRendererAdapter::SubmitStatus::kDrop;
+    }
+    case kTrackRendererSubmitStatusFailed: {
+      return TrackRendererAdapter::SubmitStatus::kFailed;
+    }
+    default:
+      LOG_ERROR("unknown submitstatus");
+      return TrackRendererAdapter::SubmitStatus::kFailed;
+  }
+}
+
+}  // namespace adapter_utils
+
+bool TrackRendererAdapter::SubmitPacket(const DecoderInputBufferPtr& data,
+                                        SubmitStatus* status) {
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  TrackRendererDecoderInputBuffer decoderinputbuffer{
+      adapter_utils::ConvertToTrackRendererTrackType(data->GetType()),
+      data->GetIndex(),
+      static_cast<void*>(const_cast<GstBuffer*>(data->Get()))};
+#else
+  TrackRendererDecoderInputBuffer decoderinputbuffer{
+      adapter_utils::ConvertToTrackRendererTrackType(data->GetType()),
+      data->GetIndex(), const_cast<GstBuffer*>(data->Get())};
+#endif
+  TrackRendererSubmitStatus submitstatus;
+  if (trackrenderer_submit_packet(handle_, &decoderinputbuffer,
+                                  &submitstatus) == kFailed) {
+    if (status) *status = TrackRendererAdapter::SubmitStatus::kFailed;
+    return false;
+  }
+  if (status)
+    *status = adapter_utils::ConvertToAdapterSubmitStatus(submitstatus);
+  return true;
+}
+
+bool TrackRendererAdapter::SubmitPacket2(const DecoderInputBufferPtr& data,
+                                         SubmitStatus* status) {
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  TrackRendererDecoderInputBuffer decoderinputbuffer{
+      adapter_utils::ConvertToTrackRendererTrackType(data->GetType()),
+      data->GetIndex(),
+      static_cast<void*>(const_cast<GstBuffer*>(data->Get()))};
+#else
+  TrackRendererDecoderInputBuffer decoderinputbuffer{
+      adapter_utils::ConvertToTrackRendererTrackType(data->GetType()),
+      data->GetIndex(), const_cast<GstBuffer*>(data->Get())};
+#endif
+  TrackRendererSubmitStatus submitstatus;
+  if (trackrenderer_submit_packet2(handle_, &decoderinputbuffer,
+                                   &submitstatus) == kFailed) {
+    if (status)
+      *status = adapter_utils::ConvertToAdapterSubmitStatus(submitstatus);
+    return false;
+  }
+
+  if (status)
+    *status = adapter_utils::ConvertToAdapterSubmitStatus(submitstatus);
+
+  if (submitstatus == kTrackRendererSubmitStatusDrop) return true;
+
+  data->Release();
+  return true;
+}
+
+void TrackRendererAdapter::SetDrm(const drm::Property& drm_property) {
+  TrackRendererDrmProperty trackrenderer_drm_property{kTrackRendererDrmTypeNone,
+                                                      0, 0, nullptr, nullptr};
+  adapter_utils::MakeTrackRendererDrmProperty(&trackrenderer_drm_property,
+                                              drm_property);
+  trackrenderer_set_drm(handle_, &trackrenderer_drm_property);
+}
+
+void TrackRendererAdapter::DrmLicenseAcquiredDone(TrackType type) {
+  trackrenderer_drm_license_acquired_done(
+      handle_, adapter_utils::ConvertToTrackRendererTrackType(type));
+}
+
+bool TrackRendererAdapter::SetDisplayMode(const DisplayMode& mode) {
+  if (trackrenderer_set_display_mode(
+          handle_, adapter_utils::ConvertToTrackRendererDisplayMode(mode)) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetDisplay(const DisplayType& type,
+                                      uint32_t surface_id, long x, long y,
+                                      long w, long h) {
+  if (trackrenderer_set_display_surface(
+          handle_, adapter_utils::ConvertToTrackRendererDisplayType(type),
+          surface_id, x, y, w, h) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetDisplay(const DisplayType& type, void* obj) {
+  if (trackrenderer_set_display(
+          handle_, adapter_utils::ConvertToTrackRendererDisplayType(type),
+          obj) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetDisplay(const DisplayType& type,
+                                      void* ecore_wl2_window, int x, int y,
+                                      int w, int h) {
+  if (trackrenderer_set_display_ecore_wl2_window(
+          handle_, adapter_utils::ConvertToTrackRendererDisplayType(type),
+          ecore_wl2_window, x, y, w, h) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetDisplaySubsurface(const DisplayType& type,
+                                                void* ecore_wl2_subsurface,
+                                                int x, int y, int w, int h) {
+  if (trackrenderer_set_display_ecore_wl2_subsurface(
+          handle_, adapter_utils::ConvertToTrackRendererDisplayType(type),
+          ecore_wl2_subsurface, x, y, w, h) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+void TrackRendererAdapter::GetDisplay(DisplayType* type, Geometry* area) {
+  TrackRendererGeometry geometry = {0, 0, 1920, 1080};
+  TrackRendererDisplayType display_type = kTrackRendererDisplayTypeNone;
+  trackrenderer_get_display(handle_, &display_type, &geometry);
+  adapter_utils::MakeGeometry(area, geometry);
+  *type = adapter_utils::ConvertToDisplayType(display_type);
+}
+
+bool TrackRendererAdapter::SetDisplayRoi(const Geometry& roi) {
+  TrackRendererGeometry geometry = {0, 0, 1920, 1080};
+  adapter_utils::MakeTrackRendererGeometry(&geometry, roi);
+  if (trackrenderer_set_display_roi(handle_, &geometry) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetVideoRoi(const CropArea& area) {
+  TrackRendererCropArea croparea = {0.0, 0.0, 1.0, 1.0};
+  adapter_utils::MakeTrackRendererCropArea(&croparea, area);
+  if (trackrenderer_set_video_roi(handle_, &croparea) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::ResizeRenderRect(const RenderRect& rect) {
+  TrackRendererRenderRect result = {0, 0, 1920, 1080};
+  adapter_utils::MakeTrackRendererRenderRect(&result, rect);
+  if (trackrenderer_resize_render_rect(handle_, &result) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetDisplayRotate(const DisplayRotation& rotate) {
+  if (trackrenderer_set_display_rotate(
+          handle_, adapter_utils::ConvertToTrackRendererDisplayRotate(
+                       rotate)) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetDisplayRotate(DisplayRotation* rotate) {
+  TrackRendererDisplayRotate display_rotate = kTrackRendererDisplayRotateNone;
+  if (trackrenderer_get_display_rotate(handle_, &display_rotate) == kFailed) {
+    return false;
+  }
+  *rotate = adapter_utils::ConvertToDisplayRotation(display_rotate);
+  return true;
+}
+
+bool TrackRendererAdapter::SetDisplayVisible(bool is_visible) {
+  if (trackrenderer_set_display_visible(handle_, is_visible) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+void TrackRendererAdapter::GetDisplayMode(DisplayMode* mode) {
+  // TODO: sy0207.ju
+  TrackRendererDisplayMode display_mode = kTrackRendererDisplayModeDisplayMax;
+  trackrenderer_get_display_mode(handle_, &display_mode);
+  *mode = adapter_utils::ConvertToDisplayMode(display_mode);
+}
+
+bool TrackRendererAdapter::SetAudioMute(bool is_mute) {
+  if (trackrenderer_set_audio_mute(handle_, is_mute) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+void TrackRendererAdapter::SetAppId(const std::string& app_id) {
+  trackrenderer_set_app_id(handle_, app_id.c_str());
+}
+
+void TrackRendererAdapter::SetAppInfo(const PlayerAppInfo& app_info) {
+  TrackRendererAppInfo info;
+  adapter_utils::MakeTrackRendererAppInfo(&info, app_info);
+  trackrenderer_set_app_info(handle_, &info);
+}
+
+void TrackRendererAdapter::SetVideoStillMode(const StillMode& type) {
+  trackrenderer_set_video_still_mode(
+      handle_, adapter_utils::ConvertToTrackRendererStillMode(type));
+}
+
+bool TrackRendererAdapter::SetVolume(const int& volume) {
+  if (trackrenderer_set_volume(handle_, volume) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetVolume(int* volume) {
+  if (trackrenderer_get_volume(handle_, volume) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Flush(const StreamType& type) {
+  if (trackrenderer_flush(
+          handle_, adapter_utils::ConvertToTrackRendererTrackTypeFromStreamType(
+                       type)) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::Flush(const TrackType& type) {
+  if (trackrenderer_flush(
+          handle_, adapter_utils::ConvertToTrackRendererTrackType(type)) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+namespace adapter_utils {
+
+enum class ValueType {
+  kUnknown,
+  kInt32,
+  kUInt32,
+  kInt64,
+  kUInt64,
+  kMax,
+};
+struct AttrInfo {
+  const ValueType value_type;
+  const std::string name;
+};
+static const std::map<TrackRendererAdapter::Attribute, AttrInfo>
+    kPluginPropertyInfoTable = {
+        {TrackRendererAdapter::Attribute::kVideoQueueMaxByte,
+         {ValueType::kUInt64, "video-queue-max-byte"}},
+        {TrackRendererAdapter::Attribute::kAudioQueueMaxByte,
+         {ValueType::kUInt64, "audio-queue-max-byte"}},
+        {TrackRendererAdapter::Attribute::kVideoQueueCurrentLevelByte,
+         {ValueType::kUInt64, "video-current-level-byte"}},
+        {TrackRendererAdapter::Attribute::kAudioQueueCurrentLevelByte,
+         {ValueType::kUInt64, "audio-current-level-byte"}},
+        {TrackRendererAdapter::Attribute::kVideoMinByteThreshold,
+         {ValueType::kUInt32, "video-min-byte-percent"}},
+        {TrackRendererAdapter::Attribute::kAudioMinByteThreshold,
+         {ValueType::kUInt32, "audio-min-byte-percent"}},
+        {TrackRendererAdapter::Attribute::kVideoQueueMaxTime,
+         {ValueType::kUInt64, "video-queue-max-time"}},
+        {TrackRendererAdapter::Attribute::kAudioQueueMaxTime,
+         {ValueType::kUInt64, "audio-queue-max-time"}},
+        {TrackRendererAdapter::Attribute::kVideoQueueCurrentLevelTime,
+         {ValueType::kUInt64, "video-current-level-time"}},
+        {TrackRendererAdapter::Attribute::kAudioQueueCurrentLevelTime,
+         {ValueType::kUInt64, "audio-current-level-time"}},
+        {TrackRendererAdapter::Attribute::kVideoMinTimeThreshold,
+         {ValueType::kUInt32, "video-min-time-percent"}},
+        {TrackRendererAdapter::Attribute::kAudioMinTimeThreshold,
+         {ValueType::kUInt32, "audio-min-time-percent"}},
+        {TrackRendererAdapter::Attribute::kVideoSupportRotation,
+         {ValueType::kUInt32, "support-rotation"}},
+        {TrackRendererAdapter::Attribute::kVideoRenderTimeOffset,
+         {ValueType::kInt64, "video-render-time-offset"}},
+        {TrackRendererAdapter::Attribute::kAudioRenderTimeOffset,
+         {ValueType::kInt64, "audio-render-time-offset"}}};
+
+static const std::map<TrackRendererAdapter::Attribute, AttrInfo>
+    kConfigInfoTable = {
+        {TrackRendererAdapter::Attribute::kAccurateSeekMode,
+         {ValueType::kUInt32, "accurate-seek-mode"}},
+        {TrackRendererAdapter::Attribute::kLowLatencyMode,
+         {ValueType::kUInt32, "low-latency-mode"}},
+        {TrackRendererAdapter::Attribute::kVideoFramePeekMode,
+         {ValueType::kUInt32, "video-frame-peek-mode"}},
+        {TrackRendererAdapter::Attribute::kUnlimitedMaxBufferMode,
+         {ValueType::kUInt32, "unlimited-max-buffer-mode"}},
+        {TrackRendererAdapter::Attribute::kVideoPreDisplayMode,
+         {ValueType::kUInt32, "video-pre-display-mode"}},
+        {TrackRendererAdapter::Attribute::kStartRenderingTime,
+         {ValueType::kUInt64, "start-rendering-time"}},
+        {TrackRendererAdapter::Attribute::kFmmMode,
+         {ValueType::kUInt32, "fmm-mode"}},
+        {TrackRendererAdapter::Attribute::kAlternativeVideoResource,
+         {ValueType::kUInt32, "alternative-video-resource"}},
+        {TrackRendererAdapter::Attribute::kVideoDecodingMode,
+         {ValueType::kUInt32, "video-decoding-mode"}},
+        {TrackRendererAdapter::Attribute::kLateVideoFrameDropMode,
+         {ValueType::kUInt32, "late-video-frame-drop-mode"}}};
+}  // namespace adapter_utils
+
+void TrackRendererAdapter::SetAttribute(
+    const TrackRendererAdapter::Attribute& attr, const boost::any& value) {
+  if (adapter_utils::kPluginPropertyInfoTable.count(attr) > 0) {
+    const adapter_utils::AttrInfo& info =
+        adapter_utils::kPluginPropertyInfoTable.at(attr);
+    LOG_DEBUG("attribute [%d] : %s", static_cast<int>(attr), info.name.c_str());
+    switch (info.value_type) {
+      case adapter_utils::ValueType::kInt32: {
+        std::int32_t _value = boost::any_cast<std::int32_t>(value);
+        trackrenderer_set_attribute(handle_, info.name.c_str(), _value,
+                                    nullptr);
+      } break;
+      case adapter_utils::ValueType::kUInt32: {
+        std::uint32_t _value = boost::any_cast<std::uint32_t>(value);
+        trackrenderer_set_attribute(handle_, info.name.c_str(), _value,
+                                    nullptr);
+      } break;
+      case adapter_utils::ValueType::kInt64: {
+        std::int64_t _value = boost::any_cast<std::int64_t>(value);
+        trackrenderer_set_attribute(handle_, info.name.c_str(), _value,
+                                    nullptr);
+      } break;
+      case adapter_utils::ValueType::kUInt64: {
+        std::uint64_t _value = boost::any_cast<std::uint64_t>(value);
+        trackrenderer_set_attribute(handle_, info.name.c_str(), _value,
+                                    nullptr);
+      } break;
+      default:
+        LOG_ERROR("unknown attribute ...");
+        break;
+    }
+    return;
+  } else if (adapter_utils::kConfigInfoTable.count(attr) > 0) {
+    const adapter_utils::AttrInfo& info =
+        adapter_utils::kConfigInfoTable.at(attr);
+    switch (info.value_type) {
+      case adapter_utils::ValueType::kUInt32: {
+        std::uint32_t _value = boost::any_cast<std::uint32_t>(value);
+        trackrenderer_set_attribute(handle_, info.name.c_str(), _value,
+                                    nullptr);
+      } break;
+      case adapter_utils::ValueType::kUInt64: {
+        std::uint64_t _value = boost::any_cast<std::uint64_t>(value);
+        trackrenderer_set_attribute(handle_, info.name.c_str(), _value,
+                                    nullptr);
+      } break;
+      default:
+        LOG_ERROR("unknown attribute ...");
+        break;
+    }
+    return;
+  } else {
+    LOG_ERROR("unknown attribute");
+    return;
+  }
+}
+
+void TrackRendererAdapter::GetAttribute(
+    const TrackRendererAdapter::Attribute& attr, boost::any* value) {
+  if (adapter_utils::kPluginPropertyInfoTable.count(attr) == 0) {
+    LOG_ERROR("unknown attribute");
+    return;
+  }
+  const adapter_utils::AttrInfo& info =
+      adapter_utils::kPluginPropertyInfoTable.at(attr);
+
+  switch (info.value_type) {
+    case adapter_utils::ValueType::kInt32: {
+      std::int32_t _value = 0;
+      trackrenderer_get_attribute(handle_, info.name.c_str(), &_value, nullptr);
+      *value = _value;
+    } break;
+    case adapter_utils::ValueType::kUInt32: {
+      std::uint32_t _value = 0;
+      trackrenderer_get_attribute(handle_, info.name.c_str(), &_value, nullptr);
+      *value = _value;
+    } break;
+    case adapter_utils::ValueType::kInt64: {
+      std::int64_t _value = 0;
+      trackrenderer_get_attribute(handle_, info.name.c_str(), &_value, nullptr);
+      *value = _value;
+    } break;
+    case adapter_utils::ValueType::kUInt64: {
+      std::uint64_t _value = 0;
+      trackrenderer_get_attribute(handle_, info.name.c_str(), &_value, nullptr);
+      *value = _value;
+    } break;
+    default:
+      LOG_ERROR("unknown attribute ...");
+      break;
+  }
+  return;
+}
+
+void TrackRendererAdapter::RegisterListener(EventListener* listener) {
+  eventlistener_ = listener;
+  trackrenderer_set_error_cb(handle_, ErrorCb_, (void*)this);
+  trackrenderer_set_error_msg_cb(handle_, ErrorMsgCb_, (void*)this);
+  trackrenderer_set_resourceconflict_cb(handle_, ResourceConflictCb_,
+                                        (void*)this);
+  trackrenderer_set_seekdone_cb(handle_, SeekDoneCb_, (void*)this);
+  trackrenderer_set_eos_cb(handle_, EosCb_, (void*)this);
+  trackrenderer_set_subtitle_rawdata_cb(handle_, SubtitleRawDataCb_,
+                                        (void*)this);
+  trackrenderer_set_closedcaption_cb(handle_, ClosedCaptionDataCb_,
+                                     (void*)this);
+  trackrenderer_set_drminitdata_cb(handle_, DrmInitDataCb_, (void*)this);
+  trackrenderer_set_media_packet_video_decoded_cb(
+      handle_, MediaPacketVideoDecodedCb_, (void*)this);
+  trackrenderer_set_media_packet_video_raw_decoded_cb(
+      handle_, MediaPacketVideoRawDecodedCb_, (void*)this);
+  trackrenderer_set_multiview_start_video_cb(handle_, MultiviewStartVideoCb_,
+                                             (void*)this);
+  trackrenderer_set_multiview_stop_video_cb(handle_, MultiviewStopVideoCb_,
+                                            (void*)this);
+}
+
+void TrackRendererAdapter::RegisterListenerForEsplayer(
+    EventListener* listener) {
+  eventlistener_ = listener;
+  trackrenderer_set_error_cb(handle_, ErrorCb_, (void*)this);
+  trackrenderer_set_error_msg_cb(handle_, ErrorMsgCb_, (void*)this);
+  trackrenderer_set_resourceconflict_cb(handle_, ResourceConflictCb_,
+                                        (void*)this);
+  trackrenderer_set_seekdone_cb(handle_, SeekDoneCb_, (void*)this);
+  trackrenderer_set_flushdone_cb(handle_, FlushDoneCb_, (void*)this);
+  trackrenderer_set_eos_cb(handle_, EosCb_, (void*)this);
+  trackrenderer_set_event_cb(handle_, EventCb_, (void*)this);
+  trackrenderer_set_bufferstatus_cb(handle_, BufferStatusCb_, (void*)this);
+  trackrenderer_set_seekdata_cb(handle_, SeekDataCb_, (void*)this);
+  trackrenderer_set_closedcaption_cb(handle_, ClosedCaptionDataCb_,
+                                     (void*)this);
+  trackrenderer_set_media_packet_video_tbmptr_cb(
+      handle_, MediaPacketGetTbmBufPtrCb_, (void*)this);
+  trackrenderer_set_media_packet_video_decoded_cb(
+      handle_, MediaPacketVideoDecodedCb_, (void*)this);
+  trackrenderer_set_media_packet_video_raw_decoded_cb(
+      handle_, MediaPacketVideoRawDecodedCb_, (void*)this);
+  trackrenderer_set_first_decoding_done_cb(handle_, FirstDecodingDoneCb_,
+                                           (void*)this);
+  trackrenderer_set_video_decoder_underrun_cb(handle_, VideoDecoderUnderrunCb_,
+                                              (void*)this);
+  trackrenderer_set_video_latency_status_cb(handle_, VideoLatencyStatusCb_,
+                                            (void*)this);
+  trackrenderer_set_audio_latency_status_cb(handle_, AudioLatencyStatusCb_,
+                                            (void*)this);
+}
+
+TrackRendererState TrackRendererAdapter::GetState() {
+  return trackrenderer_get_state(handle_);
+}
+
+bool TrackRendererAdapter::SetMatroskaColorInfo(const std::string& color_info) {
+  if (trackrenderer_set_matroska_color_info(handle_, color_info.c_str()) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+void TrackRendererAdapter::SetVideoFrameBufferType(
+    VideoFrameTypeStrategyPtr strategy) {
+  strategy->SetType(handle_);
+}
+
+bool TrackRendererAdapter::SetVideoFrameBufferScaleResolution(
+    const uint32_t& target_width, const uint32_t& target_height) {
+  if (trackrenderer_set_video_frame_buffer_scale_resolution(
+          handle_, target_width, target_height) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetDecodedVideoFrameRate(
+    const Rational& request_framerate) {
+  TrackRendererRational request_fps;
+  adapter_utils::MakeTrackRendererRational(&request_fps, request_framerate);
+  if (trackrenderer_set_decoded_video_frame_rate(handle_, request_fps) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::RenderVideoFrame() {
+  if (trackrenderer_render_video_frame(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetAiFilter(void* aifilter) {
+  if (trackrenderer_set_aifilter(handle_, aifilter) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetCatchUpSpeed(const CatchUpSpeed& level) {
+  if (trackrenderer_set_catch_up_speed(
+          handle_, adapter_utils::ConvertToTrackRendererCatchUpSpeed(level)) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetVideoLatencyStatus(LatencyStatus* status) {
+  TrackRendererLatencyStatus current_status = kTrackRendererLatencyStatusLow;
+  if (trackrenderer_get_video_latency_status(handle_, &current_status) ==
+      kFailed) {
+    return false;
+  }
+  *status = adapter_utils::ConvertToLatencyStatus(current_status);
+  return true;
+}
+
+bool TrackRendererAdapter::GetAudioLatencyStatus(LatencyStatus* status) {
+  TrackRendererLatencyStatus current_status = kTrackRendererLatencyStatusLow;
+  if (trackrenderer_get_audio_latency_status(handle_, &current_status) ==
+      kFailed) {
+    return false;
+  }
+  *status = adapter_utils::ConvertToLatencyStatus(current_status);
+  return true;
+}
+
+bool TrackRendererAdapter::SetVideoMidLatencyThreshold(
+    const unsigned int threshold) {
+  if (trackrenderer_set_video_mid_latency_threshold(handle_, threshold) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetAudioMidLatencyThreshold(
+    const unsigned int threshold) {
+  if (trackrenderer_set_audio_mid_latency_threshold(handle_, threshold) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetVideoHighLatencyThreshold(
+    const unsigned int threshold) {
+  trackrenderer_set_video_high_latency_cb(handle_, VideoHighLatencyCb_,
+                                          (void*)this);
+
+  if (trackrenderer_set_video_high_latency_threshold(handle_, threshold) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetAudioHighLatencyThreshold(
+    const unsigned int threshold) {
+  trackrenderer_set_audio_high_latency_cb(handle_, AudioHighLatencyCb_,
+                                          (void*)this);
+
+  if (trackrenderer_set_audio_high_latency_threshold(handle_, threshold) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::InitAudioEasingInfo(
+    const uint32_t init_volume, const uint32_t init_elapsed_time,
+    const AudioEasingInfo& easing_info) {
+  TrackRendererAudioEasingInfo info;
+  adapter_utils::MakeTrackRendererAudioEasingInfo(&info, easing_info);
+  if (trackrenderer_init_audio_easing_info(
+          handle_, init_volume, init_elapsed_time, &info) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::UpdateAudioEasingInfo(
+    const AudioEasingInfo& easing_info) {
+  TrackRendererAudioEasingInfo info;
+  adapter_utils::MakeTrackRendererAudioEasingInfo(&info, easing_info);
+  if (trackrenderer_update_audio_easing_info(handle_, &info) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetAudioEasingInfo(uint32_t* current_volume,
+                                              uint32_t* elapsed_time,
+                                              AudioEasingInfo* easing_info) {
+  TrackRendererAudioEasingInfo info;
+  if (trackrenderer_get_audio_easing_info(handle_, current_volume, elapsed_time,
+                                          &info) == kFailed) {
+    return false;
+  }
+  adapter_utils::MakeAudioEasingInfo(easing_info, info);
+  return true;
+}
+
+bool TrackRendererAdapter::StartAudioEasing() {
+  if (trackrenderer_start_audio_easing(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::StopAudioEasing() {
+  if (trackrenderer_stop_audio_easing(handle_) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::GetVirtualRscId(const RscType type,
+                                           int* virtual_id) {
+  TrackRendererRscType converted_type = kTrackRendererRscTypeVideoRenderer;
+  if (!adapter_utils::ConvertToTrackRendererRscType(type, &converted_type))
+    return false;
+  if (trackrenderer_get_virtual_rsc_id(handle_, converted_type, virtual_id) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetAdvancedPictureQualityType(
+    const AdvPictureQualityType type) {
+  TrackRendererAdvPictureQualityType converted_type =
+      kTrackRendererAdvPictureQualityTypeVideoCall;
+  if (!adapter_utils::ConvertToTrackRendererAdvPictureQualityType(
+          type, &converted_type))
+    return false;
+  if (trackrenderer_set_advanced_picture_quality_type(
+          handle_, converted_type) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetResourceAllocatePolicy(
+    const RscAllocPolicy policy) {
+  TrackRendererRscAllocPolicy converted_policy =
+      kTrackRendererRscAllocExclusive;
+  if (!adapter_utils::ConvertToTrackRendererRscAllocPolicy(policy,
+                                                           &converted_policy))
+    return false;
+  if (trackrenderer_set_resource_allocate_policy(handle_, converted_policy) ==
+      kFailed) {
+    return false;
+  }
+  return true;
+}
+
+bool TrackRendererAdapter::SetVideoParDar(uint64_t time_millisecond,
+                                          uint32_t par_num, uint32_t par_den,
+                                          uint32_t dar_num, uint32_t dar_den) {
+  if (trackrenderer_set_video_par_dar(handle_, time_millisecond, par_num,
+                                      par_den, dar_num, dar_den) == kFailed) {
+    return false;
+  }
+  return true;
+}
+
+/////////////////////////////////////////////
+/////////////// Callbacks ///////////////////
+/////////////////////////////////////////////
+void TrackRendererAdapter::ErrorCb_(const TrackRendererErrorType error_code,
+                                    UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnError(
+      adapter_utils::ConvertToErrorType(error_code));
+}
+
+void TrackRendererAdapter::ErrorMsgCb_(const TrackRendererErrorType error_code,
+                                       char* error_msg, UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnErrorMsg(
+      adapter_utils::ConvertToErrorType(error_code), error_msg);
+}
+
+void TrackRendererAdapter::ResourceConflictCb_(UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnResourceConflicted();
+}
+
+void TrackRendererAdapter::SeekDoneCb_(UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnSeekDone();
+}
+
+void TrackRendererAdapter::FlushDoneCb_(UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnFlushDone();
+}
+
+void TrackRendererAdapter::EosCb_(UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnEos();
+}
+
+void TrackRendererAdapter::EventCb_(const TrackRendererEventType event_type,
+                                    const TrackrendererEventMsg msg_data,
+                                    UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  EventMsg event_msg;
+  event_msg.data = msg_data.data;
+  event_msg.len = msg_data.len;
+  adapter->eventlistener_->OnEvent(static_cast<EventType>(event_type),
+                                   event_msg);
+}
+
+void TrackRendererAdapter::FirstDecodingDoneCb_(UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnFirstDecodingDone();
+}
+
+void TrackRendererAdapter::SubtitleRawDataCb_(
+    TrackRendererDecoderInputBuffer* buf, const TrackRendererSubtitleType type,
+    UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter || !buf) return;
+
+#ifdef TRACKRENDERER_GST_DEPENDENCY_REMOVAL
+  auto buffer = DecoderInputBuffer::Create(
+      adapter_utils::ConvertToTrackType(buf->type), buf->index,
+      static_cast<GstBuffer*>(buf->buffer));
+#else
+  auto buffer = DecoderInputBuffer::Create(
+      adapter_utils::ConvertToTrackType(buf->type), buf->index, buf->buffer);
+#endif
+  adapter->eventlistener_->OnSubtitleData(
+      std::move(buffer), adapter_utils::ConvertToSubtitleType(type));
+}
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+void TrackRendererAdapter::SubtitleDataCb_(const char* data, const int size,
+                                           const TrackRendererSubtitleType type,
+                                           const uint64_t duration,
+                                           TrackRendererSubtitleAttr* attr_list,
+                                           int attr_list_size,
+                                           UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+
+  SubtitleAttrList list;
+  int index = 0;
+  for (index = 0; index < attr_list_size; index++) {
+    SubtitleAttr attr{
+        adapter_utils::ConvertToSubtitleAttrType(attr_list[index].type),
+        attr_list[index].start_time, attr_list[index].stop_time,
+        adapter_utils::SetSubtitleAttrValue(attr_list[index]),
+        attr_list[index].extsub_index};
+    list.push_back(std::move(attr));
+  }
+  auto new_list = SubtitleAttrListPtr(new SubtitleAttrList(std::move(list)));
+
+  adapter->eventlistener_->OnSubtitleData(
+      data, size, adapter_utils::ConvertToSubtitleType(type), duration,
+      std::move(new_list));
+}
+#endif
+
+void TrackRendererAdapter::ClosedCaptionDataCb_(const char* data,
+                                                const int size,
+                                                UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnClosedCaptionData(data, size);
+}
+
+void TrackRendererAdapter::DrmInitDataCb_(int* drmhandle, unsigned int len,
+                                          unsigned char* psshdata,
+                                          TrackRendererTrackType type,
+                                          UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnDrmInitData(
+      drmhandle, len, psshdata, adapter_utils::ConvertToTrackType(type));
+}
+
+void TrackRendererAdapter::BufferStatusCb_(
+    const TrackRendererTrackType type, const TrackRendererBufferStatus status,
+    UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnBufferStatus(
+      adapter_utils::ConvertToTrackType(type),
+      adapter_utils::ConvertToBufferStatus(status));
+}
+
+void TrackRendererAdapter::SeekDataCb_(const TrackRendererTrackType type,
+                                       const uint64_t offset,
+                                       UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnSeekData(adapter_utils::ConvertToTrackType(type),
+                                      offset);
+}
+
+void TrackRendererAdapter::MediaPacketGetTbmBufPtrCb_(void** ptr,
+                                                      bool is_scale_change,
+                                                      UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnMediaPacketGetTbmBufPtr(ptr, is_scale_change);
+}
+
+void TrackRendererAdapter::MediaPacketVideoDecodedCb_(
+    const TrackRendererDecodedVideoPacket* packet, UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  DecodedVideoPacket _packet =
+      adapter_utils::ConvertToDecodedVideoPacket(packet);
+  adapter->eventlistener_->OnMediaPacketVideoDecoded(_packet);
+}
+
+void TrackRendererAdapter::MediaPacketVideoRawDecodedCb_(
+    const TrackRendererDecodedVideoRawModePacket* packet,
+    TrackRendererDecodedVideoType type, UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  DecodedVideoRawModePacket _packet;
+  _packet.type = static_cast<DecodedVideoRawModePacketType>(type);
+  _packet.pts = packet->pts;
+  _packet.width = packet->width;
+  _packet.height = packet->height;
+  _packet.data =
+      *static_cast<DecodedVideoRawModePacket::Data*>(packet->internal_data);
+  adapter->eventlistener_->OnMediaPacketVideoRawDecoded(_packet);
+}
+
+void TrackRendererAdapter::VideoDecoderUnderrunCb_(UserData userdata) {
+  auto* adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnVideoDecoderUnderrun();
+}
+
+void TrackRendererAdapter::VideoLatencyStatusCb_(
+    const TrackRendererLatencyStatus video_latency_status, UserData userdata) {
+  auto* adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnVideoLatencyStatus(
+      adapter_utils::ConvertToLatencyStatus(video_latency_status));
+}
+
+void TrackRendererAdapter::AudioLatencyStatusCb_(
+    const TrackRendererLatencyStatus audio_latency_status, UserData userdata) {
+  auto* adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnAudioLatencyStatus(
+      adapter_utils::ConvertToLatencyStatus(audio_latency_status));
+}
+
+void TrackRendererAdapter::VideoHighLatencyCb_(UserData userdata) {
+  auto* adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnVideoHighLatency();
+}
+
+void TrackRendererAdapter::AudioHighLatencyCb_(UserData userdata) {
+  auto* adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnAudioHighLatency();
+}
+
+void TrackRendererAdapter::MultiviewStartVideoCb_(UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnMultiviewStartVideo();
+}
+
+void TrackRendererAdapter::MultiviewStopVideoCb_(UserData userdata) {
+  auto adapter = static_cast<TrackRendererAdapter*>(userdata);
+  if (!adapter) return;
+  adapter->eventlistener_->OnMultiviewStopVideo();
+}
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/trackrendereradapter_utils.cpp b/src/plusplayer-core/src/trackrendereradapter_utils.cpp
new file mode 100755 (executable)
index 0000000..4db154a
--- /dev/null
@@ -0,0 +1,875 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "core/trackrendereradapter_utils.h"
+
+#include <typeinfo>
+
+#include "core/utils/plusplayer_log.h"
+
+namespace plusplayer {
+
+namespace adapter_utils {
+
+void InitTrack(TrackRendererTrack* track) {
+  track->index = kTrackRendererInvalidTrackIndex;  // int index
+  track->id = 0;                                   // int id
+  track->mimetype = nullptr;                       // const char* mimetype
+  track->streamtype = nullptr;                     // const char* streamtype
+  track->type = kTrackRendererTrackTypeMax;        // int type
+  track->codec_data = nullptr;                     // char* codec_data
+  track->codec_data_len = 0;                       // int codec_data_len
+  track->width = 0;                                // int width
+  track->height = 0;                               // int height
+  track->maxwidth = 0;                             // int maxwidth
+  track->maxheight = 0;                            // int maxheight
+  track->framerate_num = 0;                        // int framerate_num
+  track->framerate_den = 0;                        // int framerate_den
+  track->sample_rate = 0;                          // int sample_rate
+  track->sample_format = 0;                        // int sample_format
+  track->channels = 0;                             // int channels
+  track->version = 0;                              // int version
+  track->layer = 0;                                // int layer
+  track->bits_per_sample = 0;                      // int bit_per_sample
+  track->block_align = 0;                          // int block_align
+  track->bitrate = 0;                              // int bitrate
+  track->endianness = 1234;                        // int endianness
+  track->is_signed = 0;                            // int is_signed
+  track->active = 0;                               // int active
+  track->use_swdecoder = 0;                        // int use_swdecoder
+  track->language_code = nullptr;                  // const char* language_code
+  track->subtitle_format = nullptr;  // const char* subtitle_format
+}
+
+void MakeGeometry(Geometry* roi, const TrackRendererGeometry& geometry) {
+  roi->x = geometry.x;
+  roi->y = geometry.y;
+  roi->w = geometry.w;
+  roi->h = geometry.h;
+}
+
+void MakeTrackRendererDrmProperty(
+    TrackRendererDrmProperty* trackrenderer_drm_property,
+    const drm::Property& drm_property) {
+  trackrenderer_drm_property->type =
+      ConvertToTrackRendererDrmType(drm_property.type);
+  trackrenderer_drm_property->handle = static_cast<int>(drm_property.handle);
+  trackrenderer_drm_property->external_decryption =
+      static_cast<bool>(drm_property.external_decryption);
+  trackrenderer_drm_property->license_acquired_cb =
+      static_cast<void*>(drm_property.license_acquired_cb);
+  trackrenderer_drm_property->license_acquired_userdata =
+      static_cast<void*>(drm_property.license_acquired_userdata);
+}
+
+void MakeTrackRendererGeometry(TrackRendererGeometry* geometry,
+                               const Geometry& roi) {
+  geometry->x = roi.x;
+  geometry->y = roi.y;
+  geometry->w = roi.w;
+  geometry->h = roi.h;
+}
+
+void MakeTrackRendererCropArea(TrackRendererCropArea* crop,
+                               const CropArea& area) {
+  crop->scale_x = area.scale_x;
+  crop->scale_y = area.scale_y;
+  crop->scale_w = area.scale_w;
+  crop->scale_h = area.scale_h;
+}
+
+void MakeTrackRendererRenderRect(TrackRendererRenderRect* output,
+                                 const RenderRect& input) {
+  output->x = input.x;
+  output->y = input.y;
+  output->w = input.w;
+  output->h = input.h;
+}
+
+void MakeTrackRendererTrack(TrackRendererTrack* track, const Track& trackinfo) {
+  InitTrack(track);
+  track->index = trackinfo.index;
+  track->id = trackinfo.id;
+  track->mimetype = trackinfo.mimetype.c_str();
+  track->streamtype = trackinfo.streamtype.c_str();
+  track->type = ConvertToTrackRendererTrackType(trackinfo.type);
+  track->codec_data = trackinfo.codec_data.get();
+  track->codec_data_len = trackinfo.codec_data_len;
+  track->width = trackinfo.width;
+  track->height = trackinfo.height;
+  track->maxwidth = trackinfo.maxwidth;
+  track->maxheight = trackinfo.maxheight;
+  track->framerate_num = trackinfo.framerate_num;
+  track->framerate_den = trackinfo.framerate_den;
+  track->sample_rate = trackinfo.sample_rate;
+  track->sample_format = trackinfo.sample_format;
+  track->channels = trackinfo.channels;
+  track->version = trackinfo.version;
+  track->layer = trackinfo.layer;
+  track->bits_per_sample = trackinfo.bits_per_sample;
+  track->block_align = trackinfo.block_align;
+  track->bitrate = trackinfo.bitrate;
+  track->endianness = trackinfo.endianness;
+  track->is_signed = trackinfo.is_signed;
+  track->active = trackinfo.active;
+  track->use_swdecoder = trackinfo.use_swdecoder;
+  track->language_code = trackinfo.language_code.c_str();
+  track->subtitle_format = trackinfo.subtitle_format.c_str();
+}
+
+void MakeTrackRendererAppInfo(TrackRendererAppInfo* app_attr,
+                              const PlayerAppInfo& app_info) {
+  app_attr->id = const_cast<char*>(app_info.id.c_str());
+  app_attr->version = const_cast<char*>(app_info.version.c_str());
+  app_attr->type = const_cast<char*>(app_info.type.c_str());
+}
+
+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);
+}
+
+void MakeTrackRendererRational(TrackRendererRational* rational_attr,
+                               const Rational& rational_info) {
+  if (!rational_attr) return;
+  rational_attr->num = rational_info.num;
+  rational_attr->den = rational_info.den;
+}
+
+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:
+      LOG_ERROR("unknown DisplayMode");
+      return DisplayMode::kFullScreen;
+  }
+}
+DisplayRotation ConvertToDisplayRotation(
+    const TrackRendererDisplayRotate rotate_value) {
+  switch (rotate_value) {
+    case kTrackRendererDisplayRotateNone: {
+      return DisplayRotation::kNone;
+    }
+    case kTrackRendererDisplayRotate90: {
+      return DisplayRotation::kRotate90;
+    }
+    case kTrackRendererDisplayRotate180: {
+      return DisplayRotation::kRotate180;
+    }
+    case kTrackRendererDisplayRotate270: {
+      return DisplayRotation::kRotate270;
+    }
+    default:
+      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:
+      LOG_ERROR("unknown DisplayType");
+      return DisplayType::kNone;
+  }
+}
+
+ErrorType ConvertToErrorType(const TrackRendererErrorType type) {
+  switch (type) {
+    case kTrackRendererErrorTypeErrorNone: {
+      return ErrorType::kNone;
+    }
+    case kTrackRendererErrorTypeOutOfMemory: {
+      return ErrorType::kOutOfMemory;
+    }
+    case kTrackRendererErrorTypeInvalidParameter: {
+      return ErrorType::kInvalidParameter;
+    }
+    case kTrackRendererErrorTypeNoSuchFile: {
+      return ErrorType::kNoSuchFile;
+    }
+    case kTrackRendererErrorTypeInvalidOperation: {
+      return ErrorType::kInvalidOperation;
+    }
+    case kTrackRendererErrorTypeFileNoSpaceOnDevice: {
+      return ErrorType::kFileNoSpaceOnDevice;
+    }
+    case kTrackRendererErrorTypeFeatureNotSupportedOnDevice: {
+      return ErrorType::kFeatureNotSupportedOnDevice;
+    }
+    case kTrackRendererErrorTypeSeekFailed: {
+      return ErrorType::kSeekFailed;
+    }
+    case kTrackRendererErrorTypeInvalidState: {
+      return ErrorType::kInvalidState;
+    }
+    case kTrackRendererErrorTypeNotSupportedFile: {
+      return ErrorType::kNotSupportedFile;
+    }
+    case kTrackRendererErrorTypeInvalidUri: {
+      return ErrorType::kInvalidUri;
+    }
+    case kTrackRendererErrorTypeSoundPolicy: {
+      return ErrorType::kSoundPolicy;
+    }
+    case kTrackRendererErrorTypeConnectionFailed: {
+      return ErrorType::kConnectionFailed;
+    }
+    case kTrackRendererErrorTypeVideoCaptureFailed: {
+      return ErrorType::kVideoCaptureFailed;
+    }
+    case kTrackRendererErrorTypeDrmExpired: {
+      return ErrorType::kDrmExpired;
+    }
+    case kTrackRendererErrorTypeDrmNoLicense: {
+      return ErrorType::kDrmNoLicense;
+    }
+    case kTrackRendererErrorTypeDrmFutureUse: {
+      return ErrorType::kDrmFutureUse;
+    }
+    case kTrackRendererErrorTypeDrmNotPermitted: {
+      return ErrorType::kDrmNotPermitted;
+    }
+    case kTrackRendererErrorTypeResourceLimit: {
+      return ErrorType::kResourceLimit;
+    }
+    case kTrackRendererErrorTypePermissionDenied: {
+      return ErrorType::kPermissionDenied;
+    }
+    case kTrackRendererErrorTypeServiceDisconnected: {
+      return ErrorType::kServiceDisconnected;
+    }
+    case kTrackRendererErrorTypeBufferSpace: {
+      return ErrorType::kBufferSpace;
+    }
+    case kTrackRendererErrorTypeNotSupportedAudioCodec: {
+      return ErrorType::kNotSupportedAudioCodec;
+    }
+    case kTrackRendererErrorTypeNotSupportedVideoCodec: {
+      return ErrorType::kNotSupportedVideoCodec;
+    }
+    case kTrackRendererErrorTypeNotSupportedSubtitle: {
+      return ErrorType::kNotSupportedSubtitle;
+    }
+    case kTrackRendererErrorTypeDrmInfo: {
+      return ErrorType::kDrmInfo;
+    }
+    case kTrackRendererErrorTypeNotSupportedFormat: {
+      return ErrorType::kNotSupportedFormat;
+    }
+    case kTrackRendererErrorTypeStreamingPlayer: {
+      return ErrorType::kStreamingPlayer;
+    }
+    case kTrackRendererErrorTypeDtcpFsk: {
+      return ErrorType::kDtcpFsk;
+    }
+    case kTrackRendererErrorTypePreLoadingTimeOut: {
+      return ErrorType::kPreLoadingTimeOut;
+    }
+    case kTrackRendererErrorTypeNetworkError: {
+      return ErrorType::kNetworkError;
+    }
+    case kTrackRendererErrorTypeChannelSurfingFailed: {
+      return ErrorType::kChannelSurfingFailed;
+    }
+    case kTrackRendererErrorTypeUnknown: {
+      return ErrorType::kUnknown;
+    }
+    default:
+      LOG_ERROR("unknown errortype");
+      return ErrorType::kUnknown;
+  }
+}
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+SubtitleAttrType ConvertToSubtitleAttrType(
+    const TrackRendererSubtitleAttrType& type) {
+  switch (type) {
+    case kTrackRendererSubtitleAttrTypeRegionXPos: {
+      return SubtitleAttrType::kSubAttrRegionXPos;
+    }
+    case kTrackRendererSubtitleAttrTypeRegionYPos: {
+      return SubtitleAttrType::kSubAttrRegionYPos;
+    }
+    case kTrackRendererSubtitleAttrTypeRegionWidth: {
+      return SubtitleAttrType::kSubAttrRegionWidth;
+    }
+    case kTrackRendererSubtitleAttrTypeRegionHeight: {
+      return SubtitleAttrType::kSubAttrRegionHeight;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowXPadding: {
+      return SubtitleAttrType::kSubAttrWindowXPadding;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowYPadding: {
+      return SubtitleAttrType::kSubAttrWindowYPadding;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowLeftMargin: {
+      return SubtitleAttrType::kSubAttrWindowLeftMargin;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowRightMargin: {
+      return SubtitleAttrType::kSubAttrWindowRightMargin;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowTopMargin: {
+      return SubtitleAttrType::kSubAttrWindowTopMargin;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowBottomMargin: {
+      return SubtitleAttrType::kSubAttrWindowBottomMargin;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowBgColor: {
+      return SubtitleAttrType::kSubAttrWindowBgColor;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowOpacity: {
+      return SubtitleAttrType::kSubAttrWindowOpacity;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowShowBg: {
+      return SubtitleAttrType::kSubAttrWindowShowBg;
+    }
+    case kTrackRendererSubtitleAttrTypeFontFamily: {
+      return SubtitleAttrType::kSubAttrFontFamily;
+    }
+    case kTrackRendererSubtitleAttrTypeFontSize: {
+      return SubtitleAttrType::kSubAttrFontSize;
+    }
+    case kTrackRendererSubtitleAttrTypeFontWeight: {
+      return SubtitleAttrType::kSubAttrFontWeight;
+    }
+    case kTrackRendererSubtitleAttrTypeFontStyle: {
+      return SubtitleAttrType::kSubAttrFontStyle;
+    }
+    case kTrackRendererSubtitleAttrTypeFontColor: {
+      return SubtitleAttrType::kSubAttrFontColor;
+    }
+    case kTrackRendererSubtitleAttrTypeFontBgColor: {
+      return SubtitleAttrType::kSubAttrFontBgColor;
+    }
+    case kTrackRendererSubtitleAttrTypeFontOpacity: {
+      return SubtitleAttrType::kSubAttrFontOpacity;
+    }
+    case kTrackRendererSubtitleAttrTypeFontBgOpacity: {
+      return SubtitleAttrType::kSubAttrFontBgOpacity;
+    }
+    case kTrackRendererSubtitleAttrTypeFontTextOutlineColor: {
+      return SubtitleAttrType::kSubAttrFontTextOutlineColor;
+    }
+    case kTrackRendererSubtitleAttrTypeFontTextOutlineThickness: {
+      return SubtitleAttrType::kSubAttrFontTextOutlineThickness;
+    }
+    case kTrackRendererSubtitleAttrTypeFontTextOutlineBlurRadius: {
+      return SubtitleAttrType::kSubAttrFontTextOutlineBlurRadius;
+    }
+    case kTrackRendererSubtitleAttrTypeFontVerticalAlign: {
+      return SubtitleAttrType::kSubAttrFontVerticalAlign;
+    }
+    case kTrackRendererSubtitleAttrTypeFontHorizontalAlign: {
+      return SubtitleAttrType::kSubAttrFontHorizontalAlign;
+    }
+    case kTrackRendererSubtitleAttrTypeRawSubtitle: {
+      return SubtitleAttrType::kSubAttrRawSubtitle;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCueLine: {
+      return SubtitleAttrType::kSubAttrWebvttCueLine;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCueLineNum: {
+      return SubtitleAttrType::kSubAttrWebvttCueLineNum;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCueLineAlign: {
+      return SubtitleAttrType::kSubAttrWebvttCueLineAlign;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCueAlign: {
+      return SubtitleAttrType::kSubAttrWebvttCueAlign;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCueSize: {
+      return SubtitleAttrType::kSubAttrWebvttCueSize;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCuePosition: {
+      return SubtitleAttrType::kSubAttrWebvttCuePosition;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCuePositionAlign: {
+      return SubtitleAttrType::kSubAttrWebvttCuePositionAlign;
+    }
+    case kTrackRendererSubtitleAttrTypeWebvttCueVertical: {
+      return SubtitleAttrType::kSubAttrWebvttCueVertical;
+    }
+    case kTrackRendererSubtitleAttrTypeTimestamp: {
+      return SubtitleAttrType::kSubAttrTimestamp;
+    }
+    case kTrackRendererSubtitleAttrTypeExtsubIndex: {
+      return SubtitleAttrType::kSubAttrExtsubIndex;
+    }
+    case kTrackRendererSubtitleAttrTypeTypeNone: {
+      return SubtitleAttrType::kSubAttrTypeNone;
+    }
+    default:
+      LOG_ERROR("unknown subtitle attr tracktype");
+      return SubtitleAttrType::kSubAttrTypeNone;
+  }
+}
+#endif
+
+SubtitleType ConvertToSubtitleType(const TrackRendererSubtitleType& type) {
+  switch (type) {
+    case kTrackRendererSubtitleTypeText: {
+      return SubtitleType::kText;
+    }
+    case kTrackRendererSubtitleTypePicture: {
+      return SubtitleType::kPicture;
+    }
+    case kTrackRendererSubtitleTypeInvalid: {
+      return SubtitleType::kInvalid;
+    }
+    default:
+      LOG_ERROR("unknown subtitletype");
+      return SubtitleType::kInvalid;
+  }
+}
+
+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:
+      LOG_ERROR("unknown tracktype");
+      return TrackType::kTrackTypeMax;
+  }
+}
+
+DecodedVideoPacket ConvertToDecodedVideoPacket(
+    const TrackRendererDecodedVideoPacket* packet) {
+  DecodedVideoPacket _packet;
+  _packet.pts = packet->pts;
+  _packet.duration = packet->duration;
+  _packet.surface_data = static_cast<tbm_surface_h>(packet->surface_data);
+  _packet.scaler_index = packet->scaler_index;
+  return _packet;
+}
+
+TrackRendererDecodedVideoFrameBufferType ConvertToVideoFrameBufferType(
+    const DecodedVideoFrameBufferType& type) {
+  switch (type) {
+    case DecodedVideoFrameBufferType::kCopy: {
+      return kTrackRendererDecodedVideoFrameBufferCopy;
+    }
+    case DecodedVideoFrameBufferType::kReference: {
+      return kTrackRendererDecodedVideoFrameBufferReference;
+    }
+    case DecodedVideoFrameBufferType::kScale: {
+      return kTrackRendererDecodedVideoFrameBufferScale;
+    }
+    case DecodedVideoFrameBufferType::kNone: {
+      return kTrackRendererDecodedVideoFrameBufferNone;
+    }
+    default:
+      LOG_ERROR("wrong buffer type");
+      return kTrackRendererDecodedVideoFrameBufferNone;
+  }
+}
+
+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:
+      LOG_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:
+      LOG_ERROR("unknown displayrotate");
+      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:
+      LOG_ERROR("unknown displaytype");
+      return kTrackRendererDisplayTypeNone;
+  }
+}
+
+TrackRendererDrmType ConvertToTrackRendererDrmType(const drm::Type& drm_type) {
+  switch (drm_type) {
+    case drm::Type::kNone: {
+      return kTrackRendererDrmTypeNone;
+    }
+    case drm::Type::kPlayready: {
+      return kTrackRendererDrmTypePlayready;
+    }
+    case drm::Type::kMarlin: {
+      return kTrackRendererDrmTypeMarlin;
+    }
+    case drm::Type::kVerimatrix: {
+      return kTrackRendererDrmTypeVerimatrix;
+    }
+    case drm::Type::kWidevineClassic: {
+      return kTrackRendererDrmTypeWidevineClassic;
+    }
+    case drm::Type::kSecuremedia: {
+      return kTrackRendererDrmTypeSecuremedia;
+    }
+    case drm::Type::kSdrm: {
+      return kTrackRendererDrmTypeSdrm;
+    }
+    case drm::Type::kWidevineCdm: {
+      return kTrackRendererDrmTypeWidevineCdm;
+    }
+    case drm::Type::kMax: {
+      return kTrackRendererDrmTypeDrmMax;
+    }
+    default:
+      LOG_ERROR("unknown drmtype");
+      return kTrackRendererDrmTypeNone;
+  }
+}
+
+TrackRendererStillMode ConvertToTrackRendererStillMode(
+    const StillMode& still_mode) {
+  switch (still_mode) {
+    case StillMode::kNone: {
+      return kTrackRendererStillModeNone;
+    }
+    case StillMode::kOff: {
+      return kTrackRendererStillModeOff;
+    }
+    case StillMode::kOn: {
+      return kTrackRendererStillModeOn;
+    }
+    default:
+      LOG_ERROR("unknown stillmode");
+      return kTrackRendererStillModeNone;
+  }
+}
+
+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:
+      LOG_ERROR("unknown tracktype");
+      return kTrackRendererTrackTypeMax;
+  }
+}
+
+TrackRendererTrackType ConvertToTrackRendererTrackTypeFromStreamType(
+    const StreamType& type) {
+  switch (type) {
+    case StreamType::kAudio: {
+      return kTrackRendererTrackTypeAudio;
+    }
+    case StreamType::kVideo: {
+      return kTrackRendererTrackTypeVideo;
+    }
+    case StreamType::kMax: {
+      return kTrackRendererTrackTypeMax;
+    }
+    default:
+      LOG_ERROR("unknown steamtype");
+      return kTrackRendererTrackTypeMax;
+  }
+}
+
+#ifndef TRACKRENDERER_FEATURE_DEPRECATE_SUBTITLE_CB
+boost::any SetSubtitleAttrValue(const TrackRendererSubtitleAttr& attr) {
+  boost::any any_value;
+  switch (attr.type) {
+    case kTrackRendererSubtitleAttrTypeRegionXPos:         // fall through
+    case kTrackRendererSubtitleAttrTypeRegionYPos:         // fall through
+    case kTrackRendererSubtitleAttrTypeRegionWidth:        // fall through
+    case kTrackRendererSubtitleAttrTypeRegionHeight:       // fall through
+    case kTrackRendererSubtitleAttrTypeWindowXPadding:     // fall through
+    case kTrackRendererSubtitleAttrTypeWindowYPadding:     // fall through
+    case kTrackRendererSubtitleAttrTypeWindowOpacity:      // fall through
+    case kTrackRendererSubtitleAttrTypeWindowShowBg:       // fall through
+    case kTrackRendererSubtitleAttrTypeFontSize:           // fall through
+    case kTrackRendererSubtitleAttrTypeFontOpacity:        // fall through
+    case kTrackRendererSubtitleAttrTypeFontBgOpacity:      // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCueLine:      // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCueSize:      // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCuePosition:  // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCueVertical: {
+      if (attr.value.f) any_value = attr.value.f;
+      break;
+    }
+    case kTrackRendererSubtitleAttrTypeWindowLeftMargin:      // fall through
+    case kTrackRendererSubtitleAttrTypeWindowRightMargin:     // fall through
+    case kTrackRendererSubtitleAttrTypeWindowTopMargin:       // fall through
+    case kTrackRendererSubtitleAttrTypeWindowBottomMargin:    // fall through
+    case kTrackRendererSubtitleAttrTypeWindowBgColor:         // fall through
+    case kTrackRendererSubtitleAttrTypeFontWeight:            // fall through
+    case kTrackRendererSubtitleAttrTypeFontStyle:             // fall through
+    case kTrackRendererSubtitleAttrTypeFontColor:             // fall through
+    case kTrackRendererSubtitleAttrTypeFontBgColor:           // fall through
+    case kTrackRendererSubtitleAttrTypeFontTextOutlineColor:  // fall through
+    case kTrackRendererSubtitleAttrTypeFontTextOutlineThickness:   // fall
+                                                                   // through
+    case kTrackRendererSubtitleAttrTypeFontTextOutlineBlurRadius:  // fall
+                                                                   // through
+    case kTrackRendererSubtitleAttrTypeFontVerticalAlign:    // fall through
+    case kTrackRendererSubtitleAttrTypeFontHorizontalAlign:  // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCueLineNum:     // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCueLineAlign:   // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCueAlign:       // fall through
+    case kTrackRendererSubtitleAttrTypeWebvttCuePositionAlign: {
+      if (attr.value.i32) any_value = attr.value.i32;
+      break;
+    }
+    case kTrackRendererSubtitleAttrTypeFontFamily:  // fall through
+    case kTrackRendererSubtitleAttrTypeRawSubtitle: {
+      if (attr.value.str) any_value = std::string(attr.value.str);
+      break;
+    }
+    case kTrackRendererSubtitleAttrTypeTimestamp:
+    case kTrackRendererSubtitleAttrTypeExtsubIndex:
+      break;
+    default:
+      LOG_ERROR("Unknown subtitle attr type");
+  }
+  return any_value;
+}
+#endif
+
+BufferStatus ConvertToBufferStatus(const TrackRendererBufferStatus& status) {
+  switch (status) {
+    case kTrackRendererBufferStatusUnderrun: {
+      return BufferStatus::kUnderrun;
+    }
+    case kTrackRendererBufferStatusOverrun: {
+      return BufferStatus::kOverrun;
+    }
+  }
+  LOG_ERROR("Unknown buffern status");
+  return BufferStatus::kUnderrun;
+}
+
+TrackRendererCatchUpSpeed ConvertToTrackRendererCatchUpSpeed(
+    const CatchUpSpeed& level) {
+  switch (level) {
+    case CatchUpSpeed::kNone: {
+      return kTrackRendererCatchUpSpeedNone;
+    }
+    case CatchUpSpeed::kSlow: {
+      return kTrackRendererCatchUpSpeedSlow;
+    }
+    case CatchUpSpeed::kNormal: {
+      return kTrackRendererCatchUpSpeedNormal;
+    }
+    case CatchUpSpeed::kFast: {
+      return kTrackRendererCatchUpSpeedFast;
+    }
+  }
+  LOG_ERROR("Unknown catch up speed");
+  return kTrackRendererCatchUpSpeedNone;
+}
+
+LatencyStatus ConvertToLatencyStatus(const TrackRendererLatencyStatus& status) {
+  switch (status) {
+    case kTrackRendererLatencyStatusLow: {
+      return LatencyStatus::kLow;
+    }
+    case kTrackRendererLatencyStatusMid: {
+      return LatencyStatus::kMid;
+    }
+    case kTrackRendererLatencyStatusHigh: {
+      return LatencyStatus::kHigh;
+    }
+  }
+  LOG_ERROR("Unknown status");
+  return LatencyStatus::kLow;
+}
+
+AudioEasingType ConvertToAudioEasingType(
+    const TrackRendererAudioEasingType& type) {
+  switch (type) {
+    case TrackRendererAudioEasingType::kTrackRendererAudioEasingLinear: {
+      return AudioEasingType::kAudioEasingLinear;
+    }
+    case TrackRendererAudioEasingType::kTrackRendererAudioEasingIncubic: {
+      return AudioEasingType::kAudioEasingIncubic;
+    }
+    case TrackRendererAudioEasingType::kTrackRendererAudioEasingOutcubic: {
+      return AudioEasingType::kAudioEasingOutcubic;
+    }
+    default:
+      LOG_ERROR("Unknown audio easing type");
+      return AudioEasingType::kAudioEasingNone;
+  }
+}
+
+TrackRendererAudioEasingType ConvertToTrackRendererAudioEasingType(
+    const AudioEasingType& type) {
+  switch (type) {
+    case AudioEasingType::kAudioEasingLinear: {
+      return TrackRendererAudioEasingType::kTrackRendererAudioEasingLinear;
+    }
+    case AudioEasingType::kAudioEasingIncubic: {
+      return TrackRendererAudioEasingType::kTrackRendererAudioEasingIncubic;
+    }
+    case AudioEasingType::kAudioEasingOutcubic: {
+      return TrackRendererAudioEasingType::kTrackRendererAudioEasingOutcubic;
+    }
+    default:
+      LOG_ERROR("Unknown audio easing type");
+      return TrackRendererAudioEasingType::kTrackRendererAudioEasingNone;
+  }
+}
+
+bool ConvertToTrackRendererRscType(const RscType& typevalue,
+                                   TrackRendererRscType* type) {
+  switch (typevalue) {
+    case RscType::kVideoRenderer: {
+      *type = kTrackRendererRscTypeVideoRenderer;
+      return true;
+    }
+    default:
+      LOG_ERROR("unknown resource type");
+      return false;
+  }
+}
+
+bool ConvertToTrackRendererAdvPictureQualityType(
+    const AdvPictureQualityType& typevalue,
+    TrackRendererAdvPictureQualityType* type) {
+  switch (typevalue) {
+    case AdvPictureQualityType::kVideoCall: {
+      *type = kTrackRendererAdvPictureQualityTypeVideoCall;
+      return true;
+    }
+    case AdvPictureQualityType::kUsbCamera: {
+      *type = kTrackRendererAdvPictureQualityTypeUsbCamera;
+      return true;
+    }
+    default:
+      LOG_ERROR("unknown resource type");
+      return false;
+  }
+}
+
+bool ConvertToTrackRendererRscAllocPolicy(const RscAllocPolicy& policyvalue,
+                                          TrackRendererRscAllocPolicy* policy) {
+  switch (policyvalue) {
+    case RscAllocPolicy::kRscAllocExclusive: {
+      *policy = kTrackRendererRscAllocExclusive;
+      return true;
+    }
+    case RscAllocPolicy::kRscAllocConditional: {
+      *policy = kTrackRendererRscAllocConditional;
+      return true;
+    }
+    default:
+      LOG_ERROR("unknown policy");
+      return false;
+  }
+}
+
+}  // namespace adapter_utils
+
+}  // namespace plusplayer
diff --git a/src/plusplayer-core/src/videoframetypestrategy.cpp b/src/plusplayer-core/src/videoframetypestrategy.cpp
new file mode 100755 (executable)
index 0000000..f923ed8
--- /dev/null
@@ -0,0 +1,22 @@
+#include "core/videoframetypestrategy.h"
+
+#include <trackrenderer_capi/trackrenderer_capi.h>
+#include <trackrenderer_capi/trackrenderer_internal.h>
+
+#include "core/trackrendereradapter_utils.h"
+
+namespace plusplayer {
+DefaultVideoFrameTypeStrategy::DefaultVideoFrameTypeStrategy(
+    const DecodedVideoFrameBufferType type)
+    : type_(type) {}
+
+void DefaultVideoFrameTypeStrategy::SetType(TrackRendererHandle handle) {
+  trackrenderer_set_video_frame_buffer_type(
+      handle, adapter_utils::ConvertToVideoFrameBufferType(type_));
+}
+
+void RawVideoFrameTypeStrategy::SetType(TrackRendererHandle handle) {
+  trackrenderer_set_video_frame_buffer_type_ext(
+      handle, kTrackRendererDecodedVideoFrameBufferExtRaw);
+}
+}  // namespace plusplayer
\ No newline at end of file
diff --git a/tomato/tc/TCList.dat b/tomato/tc/TCList.dat
new file mode 100755 (executable)
index 0000000..568f446
--- /dev/null
@@ -0,0 +1 @@
+unit_test/ut_esplusplayer_all.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..517b656
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestFarm>
+       <Target AssignTargets="1"> 
+               <TestPackage Name="esplusplayer" RpmName="esplusplayer-ut-component-tomato" DatFile="TCList.dat"/>      
+</TestFarm>
\ No newline at end of file
diff --git a/tomato/tc/unit_test/ut_esplusplayer_all.xml b/tomato/tc/unit_test/ut_esplusplayer_all.xml
new file mode 100755 (executable)
index 0000000..afcb07f
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TestCase Name="ESPlusplayer API Test" Description="ESPlusplayer APIs unit test" LogFilter="GST_LOG:* TOMATO:* PLUSPLAYER:* STREAMING_ENGINE:*">
+       <Procedure Number="1" Description="ESPlusplayer unit test">
+               <Step Name="ESPlusplayer unit test" Type="EXT_TEST_PACKAGE" Command="GTEST_TOTAL_SHARDS=1 GTEST_SHARD_INDEX=0 /usr/bin/esplusplayer_ut --gtest_output=xml:/usr/etc/esplusplayer_tests_result.xml" Permission="ROOT">
+                       <Input Expirytime="10800"/>
+                       <Output Type="DetectFile" FilePath="/usr/etc/esplusplayer_tests_result.xml"/>
+               </Step>
+       </Procedure>
+</TestCase>
diff --git a/ut/CMakeLists.txt b/ut/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..3bc02dc
--- /dev/null
@@ -0,0 +1,100 @@
+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)
+
+IF(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+SET(ADD_LIBS
+  "espplayer-core"
+  "trackrenderer"
+  "esplusplayer"
+  "mixer"
+  "gstvideo-1.0"
+)
+ELSE(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+SET(ADD_LIBS
+  "espplayer-core"
+  "trackrenderer"
+  "esplusplayer"
+  "gstvideo-1.0"
+)
+ENDIF(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+
+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"
+               "capi-media-player"
+               "video-capture libturbojpeg libjpeg opencv"
+               "audio-control"
+               )
+
+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}/ut/include
+  ${PROJECT_SOURCE_DIR}/src
+  ${PROJECT_SOURCE_DIR}/include
+  ${PROJECT_SOURCE_DIR}
+  ${PROJECT_SOURCE_DIR}/src/plusplayer-core/include_internal
+  ${PROJECT_SOURCE_DIR}/src/esplusplayer/include_internal
+  ${PROJECT_SOURCE_DIR}/src/mixer/include_internal
+)
+
+FILE(GLOB UT_SRC
+  src/plusplayer/*.cpp
+  src/ut_main.cpp
+)
+
+IF(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+SET(UT_MIXER_SRC
+  src/mixer/constant.cpp
+  src/mixer/matcher.cpp
+  src/mixer/ut_mixer_capi.cpp
+  src/mixer/ut_mixer_espp_capi.cpp
+  src/mixer/ut_mixer.cpp
+  src/mixer/ut_mixerticket.cpp
+# src/mixer/ut_mixerscenario.cpp
+  src/mixer/ut_espp_mixerscenario.cpp
+  src/mixer/ut_mixedframe.cpp
+  src/mixer/ut_renderer.cpp
+  src/mixer/ut_tizenbuffermgr.cpp
+  src/mixer/ut_tizenbufferobj.cpp
+  src/mixer/ut_videoplane.cpp
+)
+#ADD_EXECUTABLE(${fw_name} ${UT_SRC} ${UT_MIXER_SRC})
+#ELSE(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+#ADD_EXECUTABLE(${fw_name} ${UT_SRC})
+ENDIF(${PRODUCT_TYPE_AUDIO} STREQUAL "no")
+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..0d17a5b
--- /dev/null
@@ -0,0 +1,97 @@
+//
+// @ 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 <cassert>
+#include <chrono>
+#include <thread>
+
+#include "Ecore.h"
+#include "Ecore_Wayland.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..016a47d
--- /dev/null
@@ -0,0 +1,215 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_UT_INCLUDE_ES_EVENT_LISTENER_H__
+#define __PLUSPLAYER_UT_INCLUDE_ES_EVENT_LISTENER_H__
+
+#include <chrono>
+#include <string>
+#include <thread>
+
+#include "esplusplayer_capi/esplusplayer_capi.h"
+#include "ut/include/esplusplayer/esreader.hpp"
+
+class EsPlayerEventCallback {
+ public:
+  EsPlayerEventCallback(esplusplayer_handle handle,
+                        EsStreamReader* video_reader,
+                        EsStreamReader* audio_reader)
+      : handle_(handle),
+        video_reader_(video_reader),
+        audio_reader_(audio_reader) {}
+  ~EsPlayerEventCallback() {
+    if (audio_feeding_task_.joinable()) audio_feeding_task_.join();
+    if (video_feeding_task_.joinable()) video_feeding_task_.join();
+  }
+  void SetCallback(void) {
+    esplusplayer_set_error_cb(handle_, OnError, this);
+    esplusplayer_set_buffer_status_cb(handle_, OnBufferStatus, this);
+    esplusplayer_set_buffer_byte_status_cb(handle_, OnBufferByteStatus, this);
+    esplusplayer_set_buffer_time_status_cb(handle_, OnBufferTimeStatus, 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);
+    esplusplayer_set_seek_done_cb(handle_, OnSeekDone, this);
+    esplusplayer_set_ready_to_seek_cb(handle_, OnReadyToSeek, this);
+    esplusplayer_set_media_packet_video_decoded_cb(handle_, OnVideoDecoded,
+                                                   this);
+    esplusplayer_set_closed_caption_cb(handle_, OnClosedCaption, this);
+    esplusplayer_set_flush_done_cb(handle_, OnFlushDone, this);
+    esplusplayer_set_event_cb(handle_, OnEvent, this);
+  }
+
+  static void DataFeedingTask(EsStreamReader* stream,
+                              esplusplayer_handle esplayer) {
+    esplusplayer_es_packet pkt;
+    while (true) {
+      memset(&pkt, 0, sizeof(esplusplayer_es_packet));
+      if (!stream->ReadNextPacket(pkt)) break;
+      esplusplayer_submit_packet(esplayer, &pkt);
+      delete []pkt.buffer;
+    }
+  }
+  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 OnBufferByteStatus(const esplusplayer_stream_type,
+                                 const esplusplayer_buffer_status, uint64_t,
+                                 void* userdata) {
+    std::cout << "OnBufferByteStatus" << std::endl;
+  }
+  static void OnBufferTimeStatus(const esplusplayer_stream_type,
+                                 const esplusplayer_buffer_status, uint64_t,
+                                 void* userdata) {
+    std::cout << "OnBufferTimeStatus" << std::endl;
+  }
+  static void OnVideoDecoded(const esplusplayer_decoded_video_packet*,
+                             void* userdata) {
+    std::cout << "OnVideoDecoded" << std::endl;
+  }
+  static void OnClosedCaption(const char* data, const int size,
+                              void* userdata) {
+    std::cout << "OnVideoDecoded" << std::endl;
+  }
+  static void OnFlushDone(void* userdata) {
+    std::cout << "OnFlushDone" << std::endl;
+  }
+  static void OnEvent(const esplusplayer_event_type,
+                      const esplusplayer_event_msg, void*) {
+    std::cout << "OnEvent" << 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;
+    cb->prepare_done_result_ = ret;
+    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;
+      if (cb->audio_reader_ != nullptr) {
+        cb->audio_feeding_task_ =
+            std::thread(DataFeedingTask, std::ref(cb->audio_reader_),
+                        std::ref(cb->handle_));
+      }
+      std::cout << "Audio ready to prepare" << std::endl;
+    } else if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {
+      cb->ready_video_data_ = true;
+      if (cb->video_reader_ != nullptr) {
+        cb->video_feeding_task_ =
+            std::thread(DataFeedingTask, std::ref(cb->video_reader_),
+                        std::ref(cb->handle_));
+      }
+      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_;
+    });
+    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_; });
+    std::cout << "WaitForEos stop" << std::endl;
+    lk.unlock();
+  }
+  bool 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),
+                              [this]() -> bool { return prepare_done_; });
+    std::cout << "WaitForPrepareDone stop" << std::endl;
+    lk.unlock();
+    return prepare_done_result_;
+  }
+
+ private:
+  esplusplayer_handle handle_ = nullptr;
+  EsStreamReader* video_reader_ = nullptr;
+  EsStreamReader* audio_reader_ = nullptr;
+  std::thread video_feeding_task_;
+  std::thread audio_feeding_task_;
+
+  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;
+  bool prepare_done_result_ = false;
+  std::mutex prepare_done_m_;
+  std::condition_variable prepare_done_cv_;
+};
+
+#endif  // __PLUSPLAYER_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..30f9e45
--- /dev/null
@@ -0,0 +1,160 @@
+//\r
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __PLUSPLAYER_UT_INCLUDE_ES_READER_H__\r
+#define __PLUSPLAYER_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
+    if (pkt.pts > 10000) return false; //max buffer 10sec\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  // __PLUSPLAYER_UT_INCLUDE_ES_READER_H__
\ No newline at end of file
diff --git a/ut/include/esplusplayer/tclist.h b/ut/include/esplusplayer/tclist.h
new file mode 100755 (executable)
index 0000000..260353d
--- /dev/null
@@ -0,0 +1,19 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#ifndef __PLUSPLAYER_UT_INCLUDE_ESPLUSPLAYER_TCLIST_H__
+#define __PLUSPLAYER_UT_INCLUDE_ESPLUSPLAYER_TCLIST_H__
+
+namespace es_tc {
+  static const std::string es_h264_aac = "es_h264_aac/";
+  static const std::string es_hevc_ac3 = "es_hevc_ac3/";
+  static const std::string es_vp9_opus = "es_vp9_opus/";
+  std::vector<std::string> tc_list = {
+    es_h264_aac,
+    //es_hevc_ac3,
+    es_vp9_opus,
+  };
+}
+
+#endif  // __PLUSPLAYER_UT_INCLUDE_ESPLUSPLAYER_TCLIST_H__
\ No newline at end of file
diff --git a/ut/include/mixer/constant.h b/ut/include/mixer/constant.h
new file mode 100755 (executable)
index 0000000..5cf3ac4
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __PLUSPLAYER_MIXER_UT_CONSTANT_H__
+#define __PLUSPLAYER_MIXER_UT_CONSTANT_H__
+
+#include <tbm_type.h>
+
+#include <cstdint>
+#include <type_traits>
+
+#include "mixer/mixer.h"
+#include "mixer/types/buffertype.h"
+#include "mixer/types/planecomponent.h"
+#include "mixer/types/videoplanemanipinfo.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer_ut {
+using namespace plusplayer;
+
+VideoPlaneManipulableInfo GetVideoPlaneManipulableInfo(
+    BufferHandleType handle, const PlaneComponent& comp,
+    const std::uint32_t& linesize, const Geometry& geom);
+
+Geometry GetGeometry(const int& x, const int& y, const int& w, const int& h);
+
+CropArea GetCropArea(const double& x, const double& y, const double& w,
+                     const double& h);
+
+Mixer::ResolutionInfo GetResolutionInfo(int width, int height, int fnum,
+                                        int fden);
+
+static const std::uint32_t kDefaultWidth = 1920;
+static const std::uint32_t kDefaultHeight = 1080;
+static const std::uint32_t kSmallWidth = 192;
+static const std::uint32_t kSmallHeight = 108;
+static const std::uint32_t kInvalidWidth = 0;
+static const std::uint32_t kInvalidHeight = 0;
+static const std::uint32_t kExpectedDefaultByteSize =
+    (kDefaultWidth * kDefaultHeight * 3) >> 1;
+
+static const std::uint32_t kDefaultFramerateNum = 30;
+static const std::uint32_t kDefaultFramerateDen = 1;
+static const std::uint32_t kFastFramerateNum = 60;
+static const std::uint32_t kFastFramerateDen = 1;
+static const std::uint32_t kInvalidFramerateNum = 0;
+static const std::uint32_t kInvalidFramerateDen = 0;
+
+static const std::uint32_t kDefaultX = 10;
+static const std::uint32_t kDefaultY = 20;
+static const std::uint32_t kDefaultW = 30;
+static const std::uint32_t kDefaultH = 40;
+
+static const std::uint32_t kDefaultLineSize = kDefaultWidth;
+static const BufferHandleType kDefaultBufferHandle = 1;
+static const BufferHandleType kInvalidBufferHandle = 0;
+static const BufferKeyType kDefaultBufferKey = 1;
+static const BufferKeyType kInvalidBufferKey = 0;
+
+extern BufferDefaultType kDefaultBuffer;
+extern BufferUnionHandleType kDefaultMappedHandle;
+
+static const auto kYComponentSrcVMInfo = GetVideoPlaneManipulableInfo(
+    kDefaultBufferHandle, PlaneComponent::kYComponent, kDefaultLineSize,
+    GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH));
+static const auto kUVComponentSrcVMInfo = GetVideoPlaneManipulableInfo(
+    kDefaultBufferHandle, PlaneComponent::kUVComponent, kDefaultLineSize,
+    GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH));
+
+static const auto kYComponentDestVMInfo = GetVideoPlaneManipulableInfo(
+    kDefaultBufferHandle, PlaneComponent::kYComponent, kDefaultLineSize,
+    GetGeometry(0, 0, kDefaultWidth, kDefaultHeight));
+static const auto kUVComponentDestVMInfo = GetVideoPlaneManipulableInfo(
+    kDefaultBufferHandle, PlaneComponent::kUVComponent, kDefaultLineSize,
+    GetGeometry(0, kDefaultHeight, kDefaultWidth >> 1, kDefaultHeight >> 1));
+
+static const auto kCroppedYComponentDestVMInfo = GetVideoPlaneManipulableInfo(
+    kDefaultBufferHandle, PlaneComponent::kYComponent, kDefaultLineSize,
+    GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH));
+static const auto kCroppedUVComponentDestVMInfo = GetVideoPlaneManipulableInfo(
+    kDefaultBufferHandle, PlaneComponent::kUVComponent, kDefaultLineSize,
+    GetGeometry(kDefaultX >> 1, (kDefaultY >> 1) + kDefaultHeight,
+                kDefaultW >> 1, kDefaultH >> 1));
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_CONSTANT_H__
\ No newline at end of file
diff --git a/ut/include/mixer/matcher.h b/ut/include/mixer/matcher.h
new file mode 100755 (executable)
index 0000000..a44a661
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_MATCHER_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_MATCHER_H__
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+#include "mixer/types/videoplanemanipinfo.h"
+
+namespace plusplayer_ut {
+using namespace plusplayer;
+
+using ::testing::MakeMatcher;
+using ::testing::Matcher;
+using ::testing::MatcherInterface;
+using ::testing::MatchResultListener;
+
+class IsSameVideoPlaneManipulableInfoMatcher
+    : public MatcherInterface<const VideoPlaneManipulableInfo&> {
+ public:
+  explicit IsSameVideoPlaneManipulableInfoMatcher(
+      const VideoPlaneManipulableInfo& comparer)
+      : comparer_(comparer) {}
+  virtual ~IsSameVideoPlaneManipulableInfoMatcher() {}
+  bool MatchAndExplain(const VideoPlaneManipulableInfo& info,
+                       MatchResultListener* listener) const override {
+    if (info.handle != comparer_.handle) {
+      *listener << "handle: " << info.handle << " vs " << comparer_.handle;
+      return false;
+    }
+    if (info.component != comparer_.component) {
+      *listener << "component: " << static_cast<int>(info.component) << " vs "
+                << static_cast<int>(comparer_.component);
+      return false;
+    }
+    if (info.linesize != comparer_.linesize) {
+      *listener << "linesize: " << info.linesize << " vs "
+                << comparer_.linesize;
+      return false;
+    }
+    if (info.rect.x != comparer_.rect.x) {
+      *listener << "rect.x: " << info.rect.x << " vs " << comparer_.rect.x;
+      return false;
+    }
+    if (info.rect.y != comparer_.rect.y) {
+      *listener << "rect.y: " << info.rect.y << " vs " << comparer_.rect.y;
+      return false;
+    }
+    if (info.rect.w != comparer_.rect.w) {
+      *listener << "rect.w: " << info.rect.w << " vs " << comparer_.rect.w;
+      return false;
+    }
+    if (info.rect.h != comparer_.rect.h) {
+      *listener << "rect.h: " << info.rect.h << " vs " << comparer_.rect.h;
+      return false;
+    }
+    return true;
+  }
+
+  void DescribeTo(std::ostream* os) const override {
+    *os << "is same with your param";
+  }
+
+  void DescribeNegationTo(std::ostream* os) const override {
+    *os << "is not same";
+  }
+
+ private:
+  const VideoPlaneManipulableInfo& comparer_;
+};
+
+Matcher<const VideoPlaneManipulableInfo&> IsSameVideoPlaneManipulableInfo(
+    const VideoPlaneManipulableInfo& comparer);
+}  // namespace plusplayer_ut
+
+using ::testing::PrintToString;
+
+template <typename... Args>
+std::string StringFormat(const std::string& format, Args... args) {
+  size_t size = snprintf(nullptr, 0, format.c_str(), args...) +
+                1;  // Extra space for '\0'
+  if (size <= 0) {
+    throw std::runtime_error("Error during formatting.");
+  }
+  std::unique_ptr<char[]> buf(new char[size]);
+  snprintf(buf.get(), size, format.c_str(), args...);
+  return std::string(buf.get(),
+                     buf.get() + size - 1);  // We don't want the '\0' inside
+}
+
+MATCHER_P(IsSameGeometry, geom,
+          StringFormat("%s in (x, y, w, h) [%d, %d, %d, %d]",
+                       negation ? "isn't" : "is", geom.x, geom.y, geom.w,
+                       geom.h)) {
+  if (geom.x != arg.x) return false;
+  if (geom.y != arg.y) return false;
+  if (geom.w != arg.w) return false;
+  if (geom.h != arg.h) return false;
+  return true;
+}
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_MATCHER_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/fakebuffer.h b/ut/include/mixer/mock/fakebuffer.h
new file mode 100755 (executable)
index 0000000..053c8f1
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __PLUSPLAYER_MIXER_UT_FAKE_BUFFER_H__
+#define __PLUSPLAYER_MIXER_UT_FAKE_BUFFER_H__
+
+#include <gmock/gmock.h>
+
+#include <cstdint>
+#include <memory>
+
+using ::testing::MakePolymorphicAction;
+using ::testing::PolymorphicAction;
+
+namespace plusplayer_ut {
+struct FakeBuffer {
+  FakeBuffer(const std::uint32_t& size)
+      : ptr(std::unique_ptr<char[]>(new char[size])), size(size) {}
+  std::unique_ptr<char[]> ptr = nullptr;
+  const std::uint32_t size = 0;
+};
+using FakeBufferPtr = std::unique_ptr<FakeBuffer>;
+
+class CreateFakeBufferAction {
+ public:
+  explicit CreateFakeBufferAction(FakeBufferPtr& buffer) : buffer_(buffer) {}
+  template <typename Result, typename ArgumentTuple>
+  Result Perform(const ArgumentTuple& args) const {
+    auto size = std::get<0>(args);
+    if (size == 0) return;
+    buffer_.reset(new FakeBuffer(size));
+  }
+
+ private:
+  FakeBufferPtr& buffer_;
+};
+
+static PolymorphicAction<CreateFakeBufferAction> CreateFakeBuffer(
+    FakeBufferPtr& buffer) {
+  return MakePolymorphicAction(CreateFakeBufferAction(buffer));
+}
+
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_FAKE_BUFFER_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/mock_bufferobject.h b/ut/include/mixer/mock/mock_bufferobject.h
new file mode 100755 (executable)
index 0000000..958d737
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_BUFFER_OBJECT_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_BUFFER_OBJECT_H__
+
+#include <gmock/gmock.h>
+
+#include "mixer/constant.h"
+#include "mixer/interfaces/accessiblebuffer.h"
+#include "mixer/interfaces/bufferobject.h"
+#include "mixer/mock/movable.h"
+
+namespace plusplayer_ut {
+using namespace plusplayer;
+class MockBufferObject : public BufferObject {
+ public:
+  MOCK_CONST_METHOD0(GetBufferHandle, BufferHandleType());
+  MOCK_CONST_METHOD0(Export, BufferKeyType());
+  MOCK_CONST_METHOD0(GetSize, std::uint32_t());
+};
+
+class MockAccessibleBufferObject : public BufferObject,
+                                   public AccessibleBuffer {
+ public:
+  MOCK_CONST_METHOD0(GetReadableAddress_, Mover<PhyAddrAccessorPtr>());
+  MOCK_CONST_METHOD0(GetWritableAddress_, Mover<PhyAddrAccessorPtr>());
+  MOCK_CONST_METHOD0(GetBufferHandle, BufferHandleType());
+  MOCK_CONST_METHOD0(Export, BufferKeyType());
+  MOCK_CONST_METHOD0(GetSize, std::uint32_t());
+  PhyAddrAccessorPtr GetReadableAddress() const {
+    return std::move(GetReadableAddress_().get());
+  }
+  PhyAddrAccessorPtr GetWritableAddress() const {
+    return std::move(GetWritableAddress_().get());
+  }
+};
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_BUFFER_OBJECT_H__
diff --git a/ut/include/mixer/mock/mock_memallocator.h b/ut/include/mixer/mock/mock_memallocator.h
new file mode 100755 (executable)
index 0000000..cc89f29
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_MEMORY_ALLOCATOR_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_MEMORY_ALLOCATOR_H__
+
+#include <gmock/gmock.h>
+
+#include "mixer/constant.h"
+#include "mixer/interfaces/memoryallocator.h"
+
+namespace plusplayer_ut {
+using namespace plusplayer;
+class MockMemoryAllocator : public MemoryAllocator {
+ public:
+  MOCK_CONST_METHOD1(Allocate, BufferObject*(const std::uint32_t&));
+};
+}  // namespace plusplayer_ut
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_MEMORY_ALLOCATOR_H__
diff --git a/ut/include/mixer/mock/mock_phyaddraccessor.h b/ut/include/mixer/mock/mock_phyaddraccessor.h
new file mode 100755 (executable)
index 0000000..637150f
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_PHYSICAL_ADDRESS_ACCESSOR_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_PHYSICAL_ADDRESS_ACCESSOR_H__
+
+#include <gmock/gmock.h>
+
+#include "mixer/interfaces/phyaddraccessor.h"
+
+namespace plusplayer {
+class MockPhyAddrAccessor : public PhysicalAddressAccessor {
+ public:
+  virtual ~MockPhyAddrAccessor() = default;
+  MOCK_METHOD0(GetAddress, BufferPhysicalAddrType());
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_PHYSICAL_ADDRESS_ACCESSOR_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/mock_renderableobj.h b/ut/include/mixer/mock/mock_renderableobj.h
new file mode 100755 (executable)
index 0000000..c729e53
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_RENDERABLE_OBJECT_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_RENDERABLE_OBJECT_H__
+
+#include <gmock/gmock.h>
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "mixer/constant.h"
+#include "mixer/interfaces/renderableobject.h"
+#include "mixer/interfaces/videoplanemanipulator.h"
+#include "mixer/types/videoplanemanipinfo.h"
+#include "plusplayer/types/display.h"
+
+namespace plusplayer_ut {
+
+class MockRenderableObject : public RenderableObject {
+ public:
+  MOCK_CONST_METHOD0(GetVideoPlaneManipInfo,
+                     const std::vector<VideoPlaneManipulableInfo>());
+  MOCK_CONST_METHOD0(IsValid, bool());
+  MOCK_CONST_METHOD0(GetWidth, std::uint32_t());
+  MOCK_CONST_METHOD0(GetHeight, std::uint32_t());
+  MOCK_CONST_METHOD0(GetSize, std::uint32_t());
+  MOCK_METHOD3(Render, bool(const VideoPlaneManipulator* const,
+                            const std::vector<VideoPlaneManipulableInfo>&,
+                            const Geometry&));
+  MOCK_METHOD4(Fill, bool(const VideoPlaneColorManipulator* const,
+                          const PlaneComponent&, const std::uint32_t&,
+                          const Geometry&));
+  MOCK_CONST_METHOD1(Export, bool(BufferKeyType&));
+};
+
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_RENDERABLE_OBJECT_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/mock_renderableobj_factory.h b/ut/include/mixer/mock/mock_renderableobj_factory.h
new file mode 100755 (executable)
index 0000000..46b022d
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_RENDERABLE_OBJECT_FACTORY_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_RENDERABLE_OBJECT_FACTORY_H__
+
+#include <gmock/gmock.h>
+
+#include <cstdint>
+
+#include "mixer/constant.h"
+#include "mixer/interfaces/renderableobj_factory.h"
+
+namespace plusplayer_ut {
+class MockRenderableObjectFactory : public RenderableObjectFactory {
+ public:
+  MOCK_CONST_METHOD2(CreateRenderableObject,
+                     RenderableObject*(const std::uint32_t width,
+                                       const std::uint32_t height));
+};
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_RENDERABLE_OBJECT_FACTORY_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/mock_renderer_evtlistener.h b/ut/include/mixer/mock/mock_renderer_evtlistener.h
new file mode 100755 (executable)
index 0000000..7b574ed
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_RENDERER_EVENT_LISTENER_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_RENDERER_EVENT_LISTENER_H__
+
+#include <gmock/gmock.h>
+
+#include "mixer/constant.h"
+#include "mixer/renderer.h"
+
+namespace plusplayer_ut {
+class MockRendererEventListener : public RendererEventListener {
+ public:
+  MOCK_METHOD1(OnRenderingRelease, bool(const BufferKeyType&));
+};
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_RENDERER_EVENT_LISTENER_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/mock_vpcollection.h b/ut/include/mixer/mock/mock_vpcollection.h
new file mode 100755 (executable)
index 0000000..60527e4
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_VIDEOPLANECOLLECTION_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_VIDEOPLANECOLLECTION_H__
+
+#include <gmock/gmock.h>
+
+#include "mixer/constant.h"
+#include "mixer/interfaces/videoplanecollection.h"
+
+namespace plusplayer_ut {
+class MockVideoPlaneCollection : public VideoPlaneCollection {
+ public:
+  MOCK_CONST_METHOD0(GetVideoPlaneManipInfo,
+                     const std::vector<VideoPlaneManipulableInfo>());
+};
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_VIDEOPLANECOLLECTION_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/mock_vpmanipulator.h b/ut/include/mixer/mock/mock_vpmanipulator.h
new file mode 100755 (executable)
index 0000000..8b0d0e1
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_VIDEO_PLANE_MANIPULATOR_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_VIDEO_PLANE_MANIPULATOR_H__
+
+#include <cstdint>
+
+#include "mixer/constant.h"
+#include "mixer/interfaces/videoplanemanipulator.h"
+
+namespace plusplayer_ut {
+using namespace plusplayer;
+
+class MockVideoPlaneManipulator : public VideoPlaneManipulator {
+ public:
+  MOCK_CONST_METHOD2(Do, bool(const VideoPlaneManipulableInfo&,
+                              const VideoPlaneManipulableInfo&));
+};
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_VIDEO_PLANE_MANIPULATOR_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/mock_vpscaler.h b/ut/include/mixer/mock/mock_vpscaler.h
new file mode 100755 (executable)
index 0000000..c2c673f
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __PLUSPLAYER_MIXER_MOCK_VIDEO_PLANE_SCALER_H__
+#define __PLUSPLAYER_MIXER_MOCK_VIDEO_PLANE_SCALER_H__
+
+#include <gmock/gmock.h>
+
+#include "mixer/constant.h"
+#include "mixer/interfaces/videoplanescaler.h"
+
+namespace plusplayer {
+class MockVideoPlaneScaler : public VideoPlaneScaler {
+ public:
+  virtual ~MockVideoPlaneScaler() = default;
+  MOCK_CONST_METHOD0(GetScaleManipulator, const VideoPlaneManipulator* const());
+};
+}  // namespace plusplayer
+
+#endif  // __PLUSPLAYER_MIXER_MOCK_VIDEO_PLANE_SCALER_H__
\ No newline at end of file
diff --git a/ut/include/mixer/mock/movable.h b/ut/include/mixer/mock/movable.h
new file mode 100755 (executable)
index 0000000..5f427a6
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_MOVABLE_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_MOVABLE_H__
+
+#include <cassert>
+
+namespace plusplayer_ut {
+
+template <typename T>
+class Mover {
+ public:
+  Mover(T&& object) : object(std::move(object)), valid(true) {}
+
+  Mover(const Mover<T>& other)
+      : object(const_cast<T&&>(other.object)), valid(true) {
+    assert(other.valid);
+    other.valid = false;
+  }
+
+  Mover& operator=(const Mover& other) {
+    assert(other.valid);
+    object = const_cast<T&&>(other.object);
+    other.valid = false;
+    valid = true;
+  }
+
+  T& get() {
+    assert(valid);
+    return object;
+  }
+
+  const T& get() const {
+    assert(valid);
+    return *object;
+  }
+
+ private:
+  T object;
+  mutable bool valid;
+};
+
+template <typename T>
+inline Mover<T> Movable(T&& object) {
+  return Mover<T>(std::move(object));
+}
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_MOVABLE_H__
diff --git a/ut/include/mixer/mock/moveobj_wrapper.h b/ut/include/mixer/mock/moveobj_wrapper.h
new file mode 100755 (executable)
index 0000000..aaabbf3
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __PLUSPLAYER_MIXER_UT_MOCK_MOVE_OBJECT_WRAPPER_H__
+#define __PLUSPLAYER_MIXER_UT_MOCK_MOVE_OBJECT_WRAPPER_H__
+
+#include <iostream>
+
+namespace plusplayer_ut {
+template <typename T>
+class MoveObjectWrapper {
+ public:
+  explicit MoveObjectWrapper(T* obj) : obj_(obj) {}
+  virtual ~MoveObjectWrapper() {
+    if (moved_ == false) {
+      delete obj_;
+      std::cout << "CALLED dtor" << std::endl;
+    }
+  }
+  MoveObjectWrapper<T>& operator=(T* obj) { obj_ = obj; }
+  T& Get() { return *obj_; }
+  T* Move() {
+    moved_ = true;
+    return obj_;
+  }
+
+ private:
+  T* obj_ = nullptr;
+  bool moved_ = false;
+};
+}  // namespace plusplayer_ut
+
+#endif  // __PLUSPLAYER_MIXER_UT_MOCK_MOVE_OBJECT_WRAPPER_H__
\ No newline at end of file
diff --git a/ut/include/plusplayer/imagesimilarity.h b/ut/include/plusplayer/imagesimilarity.h
new file mode 100755 (executable)
index 0000000..7df4535
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __IMAGESIMILARITY_H_
+#define __IMAGESIMILARITY_H_
+
+class ImageSimilarity {
+
+public:
+/**
+ * @brief measuring the similarity of the images using PSNR (Peak Signal-to-Noise Ratio)
+ * @remarks 
+ * @param[in] image1 first image that measures the similarity
+ * @param[in] image2 second image that measures the similarity with image1
+ * @return Normalized Similarity value (0~100) on success, higher is better. 
+ *         otherwise a negative error value           
+ * @pre the image1 and image2 should be properly allocated.
+ * @post None
+ * @exception None
+ */
+       double CompareImagesWithPSNR(char *reference_image, char *comparison_image);
+
+/**
+ * @brief measuring the similarity of tho images using SSIM (Structural Similarity)
+ * @remarks MSSIM (Mean of Structureal Similarity)
+ * @param[in] image1 first image that measures the similarity
+ * @param[in] image2 second image that measures the similarity with image1
+ * @return Normalized Similarity value (0~100) on success, higher is better. 
+ *         otherwise a negative error value
+ * @pre the image1 and image2 should be properly allocated.
+ * @post None
+ * @exception None
+ */
+       double CompareImagesWithMSSIM(char *reference_image, char *comparison_image);
+};
+
+#endif
diff --git a/ut/include/plusplayer/utility.h b/ut/include/plusplayer/utility.h
new file mode 100755 (executable)
index 0000000..e3ca27e
--- /dev/null
@@ -0,0 +1,226 @@
+//
+// @ Copyright [2019] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#ifndef __PLUSPLAYER_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
+#define __PLUSPLAYER_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
+
+#include <Ecore_Evas.h>
+
+#include "gmock/gmock.h"
+
+#include "core/utils/plusplayer_log.h"
+#include "esplusplayer_capi/esplusplayer_capi.h"
+#include "mixer_capi/mixer_capi.h"
+//#include "plusplayer/plusplayer.h"
+#include "plusplayer/types/display.h"
+#include "ut/include/appwindow.h"
+
+#include <condition_variable>
+#include <functional>
+#include <future>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#define DEFAULT_TIMEOUT_FOR_PREPARING (95 * 1000)
+#define DEFAULT_TIMEOUT_FOR_SEEKING (25 * 1000)
+#define EOS_WAIT_TIME 10000
+
+class IAudioControl;
+class DiagnosisAudioControl;
+
+namespace utils {
+class Utility;
+using evas_h = Evas_Object*;
+
+enum EsType {
+  kAudio = 0x01,
+  kVideo = 0x02,
+  kBoth = (kAudio | kVideo)
+};
+
+class Utility {
+ public:
+  static Utility& Instance();
+  static void ThreadSleep(long ms);
+  static void Kill();
+  virtual ~Utility();
+
+  const char* GetCurrentTestName(void);
+
+#ifndef IS_AUDIO_PRODUCT
+
+#if 0
+  plusplayer::PlusPlayer::Ptr GetOpenedMixPlusPlayer(std::string& uri,
+                                                     plusplayer::Mixer* mixer,
+                                                     plusplayer::Geometry& roi);
+
+  plusplayer::PlusPlayer::Ptr GetPreparedMixPlusPlayer(
+      std::string& uri, plusplayer::Mixer* mixer, plusplayer::Geometry& roi);
+
+  plusplayer::PlusPlayer::Ptr GetStartedMixPlusPlayer(
+      std::string& uri, plusplayer::Mixer* mixer, plusplayer::Geometry& roi);
+#endif
+
+  esplusplayer_handle GetOpenedMixESPP(mixer_handle mixer,
+                                       plusplayer::Geometry& roi);
+
+  esplusplayer_handle GetPreparedMixESPP(std::string& uri, mixer_handle mixer,
+                                         plusplayer::Geometry& roi);
+
+  esplusplayer_handle GetStartedMixESPP(std::string& uri, mixer_handle mixer,
+                                        plusplayer::Geometry& roi);
+#endif
+  esplusplayer_handle GetOpenedESPP(plusplayer::Geometry& roi);
+
+  esplusplayer_handle GetPreparedESPP(std::string& uri,
+                                      plusplayer::Geometry& roi);
+
+  esplusplayer_handle GetStartedESPP(std::string& uri, plusplayer::Geometry& roi);
+
+  bool PrepareESPP(esplusplayer_handle player, std::string& uri,
+                   EsType type = EsType::kBoth);
+
+  void FeedingEsPacket(esplusplayer_handle player,
+                       const esplusplayer_stream_type type,
+                       const std::string& uri);
+
+  void DestroyESPP(esplusplayer_handle player);
+
+  evas_h GetWindow() const;
+
+  int CaptureYUV(int capture_width, int capture_height, char* ybuff,
+                 char* cbuff, int ysize, int csize,
+                 std::string result_file_path);
+  
+  int CaptureJPG(const int capture_width, const int capture_height, char* ybuff,
+                 char* cbuff, const int ysize, const int csize,
+                 std::string img_file_path);
+  
+  int CheckYUV(int x, int y);
+  bool IsAudioDisconnected();
+  bool IsAudioConnected() {return !IsAudioDisconnected();}
+  bool IsAudioMute();
+  bool IsAudioUnmute() {return !IsAudioMute();}
+
+  Utility(const Utility& rhs) = delete;
+  Utility& operator=(const Utility& rhs) = delete;
+
+ private:
+  explicit Utility();
+
+ private:
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow_;
+  IAudioControl* audioControl = nullptr;
+  DiagnosisAudioControl* audioDiagnoser = nullptr;
+};
+
+enum class WatcherStatus {
+  kSuccess,
+  kFail
+};
+
+enum PrepareStatus {
+  kReady,
+  kSuccess,
+  kFail
+};
+
+static const int TIMEOUT_10_SEC = 10 * 1000;
+
+template <typename T>
+class Watcher {
+ public:
+  Watcher() = default;
+  ~Watcher() {
+    this->SendSignalToWait();
+    std::unique_lock<std::mutex>(this->destructor_mutex_);
+  }
+
+  explicit Watcher(T&& t) : value_(t) { LOGD("object : 0x%p", this); }
+  Watcher(Watcher<T>&& t) : value_(std::move(std::forward<T>(t))) {
+    LOGD("object&& : 0x%p", this);
+  }
+
+  std::future<WatcherStatus> WaitForChange(T expected, int timeout_ms) {
+    LOG_DEBUG("WaitForChange ::Start ");
+    return std::async(std::launch::async, &Watcher::Evaluate, std::ref(*this),
+                      expected, timeout_ms);
+  }
+
+  void SendSignalToWait() { cv_.notify_one(); }
+
+  T GetValue() { return value_; }
+
+  Watcher& operator=(const T& rhs) {
+    std::unique_lock<std::mutex> locker(this->mutex_);
+    value_ = rhs;
+    this->SendSignalToWait();
+    // LOGD("operator=(const T& rhs)");
+    return *this;
+  }
+
+  Watcher& operator=(const Watcher& rhs) {
+    std::unique_lock<std::mutex> locker(this->mutex_);
+    value_ = rhs.value_;
+    this->SendSignalToWait();
+    // LOGD("operator=(const Watcher& rhs)");
+    return *this;
+  }
+
+  bool operator==(const Watcher& rhs) const {
+    return this->value_ == rhs.value_;
+  }
+
+  bool operator!=(const Watcher& rhs) const { return !(this == rhs); }
+
+  bool operator==(const T& rhs) const { return this->value_ == rhs; }
+
+  bool operator!=(const T& rhs) const { return !(this->value_ == rhs); }
+
+  bool operator<(const T& rhs) const { return this->value_ < rhs; }
+
+  bool operator>(const T& rhs) const { return this->value_ > rhs; }
+
+  bool operator>=(const T& rhs) const { return this->value_ >= rhs; }
+
+  bool operator<=(const T& rhs) const { return this->value_ <= rhs; }
+
+  operator T() { return value_; }
+
+ private:
+  static WatcherStatus Evaluate(Watcher<T>& w, T expected, int timeout_ms) {
+    std::unique_lock<std::mutex>(w.destructor_mutex_);
+    auto until = std::chrono::system_clock::now() +
+                 std::chrono::milliseconds(timeout_ms);
+    std::cv_status status = std::cv_status::timeout;
+
+    while (true) {
+      std::unique_lock<std::mutex> locker(w.mutex_);
+
+      if (w.value_ == expected) {
+        return WatcherStatus::kSuccess;
+      }
+
+      status = w.cv_.wait_until(locker, until);
+
+      if (status == std::cv_status::timeout) {
+        return WatcherStatus::kFail;
+      }
+    }
+
+    return WatcherStatus::kFail;
+  }
+
+ private:
+  T value_;
+  std::mutex mutex_;
+  std::mutex destructor_mutex_;
+  std::condition_variable cv_;
+};
+
+}  // namespace utils
+
+#endif  // __PLUSPLAYER_UT_INCLUDE_PLUSPLAYER_UTILITY_H__
diff --git a/ut/include/streamreader.hpp b/ut/include/streamreader.hpp
new file mode 100755 (executable)
index 0000000..00069cc
--- /dev/null
@@ -0,0 +1,214 @@
+//\r
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>\r
+//\r
+\r
+#ifndef __PLUSPLAYER_UT_INCLUDE_ESCOMMON_H__\r
+#define __PLUSPLAYER_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 "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::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  // __PLUSPLAYER_UT_INCLUDE_ESCOMMON_H__
\ No newline at end of file
diff --git a/ut/src/esplusplayer/ut_basic.cpp b/ut/src/esplusplayer/ut_basic.cpp
new file mode 100755 (executable)
index 0000000..5eea648
--- /dev/null
@@ -0,0 +1,992 @@
+
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <stdio.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <future>
+#include <map>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "esplusplayer_capi/esplusplayer_capi.h"
+#include "gmock/gmock.h"
+#include "gst/gst.h"
+#include "gtest/gtest.h"
+#include "ut/include/appwindow.h"
+#include "ut/include/esplusplayer/eseventlistener.hpp"
+#include "ut/include/esplusplayer/esreader.hpp"
+#include "ut/include/esplusplayer/tclist.h"
+#include "ut/include/streamreader.hpp"
+
+using namespace plusplayer;
+
+class EsTest : public ::testing::Test {
+ public:
+  EsTest() { std::cout << "EsTest()" << std::endl; }
+  ~EsTest() { std::cout << "~EsTest()" << std::endl; }
+
+  virtual void SetUp() override { std::cout << "SetUp()" << std::endl; }
+
+  virtual void TearDown() override { std::cout << "TearDown()" << std::endl; }
+};
+
+class EsBasicTest : public ::testing::TestWithParam<std::string> {
+ public:
+  EsBasicTest() { std::cout << "EsBasicTest()" << std::endl; }
+  ~EsBasicTest() { std::cout << "~EsBasicTest()" << std::endl; }
+
+  static void SetUpTestCase() {
+    gst_init_check(nullptr, nullptr, nullptr);
+    window_ = new Environment();
+    ESPacketDownloader::Init();
+    esplayer_ = esplusplayer_create();
+    ASSERT_NE(nullptr, esplayer_);
+    std::cout << "SetUpTestCase()" << std::endl;
+  }
+  static void TearDownTestCase() {
+    if (window_) {
+      delete window_;
+      window_ = nullptr;
+    }
+    esplusplayer_destroy(esplayer_);
+    esplayer_ = nullptr;
+    std::cout << "TearDownTestCase()" << std::endl;
+  }
+
+  virtual void SetUp() override {
+    uri_ = GetParam();
+    std::cout << "uri_: " << uri_ << std::endl;
+    video_reader_ =
+        new EsStreamReader(uri_ + "video/", ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+    audio_reader_ =
+        new EsStreamReader(uri_ + "audio/", ESPLUSPLAYER_STREAM_TYPE_AUDIO);
+    callback_ =
+        new EsPlayerEventCallback(esplayer_, video_reader_, audio_reader_);
+    callback_->SetCallback();
+
+    std::cout << "SetUp()" << std::endl;
+  }
+
+  virtual void TearDown() override {
+    if (nullptr != esplayer_) {
+      ASSERT_EQ(esplusplayer_close(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+    }
+    delete callback_;
+    delete video_reader_;
+    delete audio_reader_;
+
+    std::cout << "TearDown()" << std::endl;
+  }
+
+ public:
+  std::string uri_;
+  EsStreamReader* video_reader_;
+  EsStreamReader* audio_reader_;
+  static esplusplayer_handle esplayer_;
+  EsPlayerEventCallback* callback_;
+  static Environment* window_;
+};
+Environment* EsBasicTest::window_ = nullptr;
+esplusplayer_handle EsBasicTest::esplayer_ = nullptr;
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_create_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_open_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_close_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_stop_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_stop(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_get_error_string_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  const char* error = new char[100];
+  error =
+      esplusplayer_get_error_string(ESPLUSPLAYER_ERROR_TYPE_NOT_SUPPORTED_FILE);
+  std::cout << "error type" << error << std::endl;
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_set_tz_use_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_tz_use(esplayer, true),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_set_video_frame_buffer_type_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_video_frame_buffer_type(
+                esplayer, ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_NONE),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_set_buffer_size_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_set_buffer_size(esplayer,
+                               ESPLUSPLAYER_BUFFER_AUDIO_MAX_BYTE_SIZE, 10240);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_submit_encrypted_packet_p_1) {
+  esplusplayer_handle esplayer = NULL;
+  ASSERT_EQ(esplusplayer_submit_encrypted_packet(esplayer, NULL, NULL),
+            ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_submit_trust_zone_packet_p_1) {
+  esplusplayer_handle esplayer = NULL;
+  ASSERT_EQ(esplusplayer_submit_trust_zone_packet(esplayer, NULL, 0),
+            ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_submit_eos_packet_p_1) {
+  esplusplayer_handle esplayer = NULL;
+  ASSERT_EQ(
+      esplusplayer_submit_eos_packet(esplayer, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+      ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_decoded_buffer_destroy_p_1) {
+  esplusplayer_handle esplayer = NULL;
+  ASSERT_EQ(esplusplayer_decoded_buffer_destroy(esplayer, NULL),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_set_unlimited_max_buffer_mode_p_1) {
+  esplusplayer_handle esplayer = NULL;
+  ASSERT_EQ(esplusplayer_set_unlimited_max_buffer_mode(esplayer),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_PARAMETER);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_get_state_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::cout << "get state" << std::endl;
+  esplusplayer_state ret = ESPLUSPLAYER_STATE_NONE;
+  ret = esplusplayer_get_state(esplayer);
+  ASSERT_EQ(ret, ESPLUSPLAYER_STATE_IDLE);
+  std::cout << "get state" << ret << std::endl;
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_set_low_latency_mode_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_set_low_latency_mode(esplayer,
+                                    ESPLUSPLAYER_LOW_LATENCY_MODE_NONE);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(EsTest,
+       vdapi_basic_esplusplayer_esplusplayer_set_video_frame_peek_mode_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_set_video_frame_peek_mode(esplayer);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_audio_mute_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_set_audio_mute(esplayer_, true),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+}
+
+TEST_F(EsTest, vdapi_basic_esplusplayer_set_app_info_p_1) {
+  esplusplayer_handle esplayer = esplusplayer_create();
+  ASSERT_NE(nullptr, esplayer);
+  ASSERT_EQ(esplusplayer_open(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  char a[20], appid[] = "youtube";
+  char v[20], version[] = "3.0";
+  char t[20], type[] = "MSE";
+  esplusplayer_app_info appinfo;
+  strncpy(a, appid, sizeof(a)-1);
+  a[sizeof(a)-1] = 0x00;
+  strncpy(v, version, sizeof(v)-1);
+  v[sizeof(v)-1] = 0x00;
+  strncpy(t, type, sizeof(t)-1);
+  t[sizeof(t)-1] = 0x00;
+  appinfo.id = a;
+  appinfo.version = v;
+  appinfo.type = t;
+  ASSERT_EQ(esplusplayer_set_app_info(esplayer, &appinfo),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_close(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_destroy(esplayer), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_close_p_2) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::milliseconds(100));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_prepare_async_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_start_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_pause_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  std::cout << "Pause player" << std::endl;
+  ASSERT_EQ(esplusplayer_pause(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_resume_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  std::cout << "Pause player" << std::endl;
+  ASSERT_EQ(esplusplayer_pause(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  std::cout << "resume player" << std::endl;
+  ASSERT_EQ(esplusplayer_resume(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_deactive_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_deactivate(esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_deactivate(esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_active_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_deactivate(esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_deactivate(esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  video_reader_->ResetReader();
+  audio_reader_->ResetReader();
+  ASSERT_EQ(esplusplayer_activate(esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_activate(esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_get_playing_time_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  uint64_t cur_time1 = 0;
+  uint64_t cur_time2 = 0;
+  ASSERT_EQ(esplusplayer_get_playing_time(esplayer_, &cur_time1),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::cout << "current time is" << cur_time1 << std::endl;
+  ASSERT_EQ(esplusplayer_get_playing_time(esplayer_, &cur_time2),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::cout << "current time is" << cur_time2 << std::endl;
+  ASSERT_LE(cur_time1, cur_time2);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_seek_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_seek(esplayer_, 0), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_playback_rate_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_set_playback_rate(esplayer_, 2.0, true),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_flush_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_flush(esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_flush(esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_resume(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_volume_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  int vol = 80;
+  int vol1 = 0;
+  ASSERT_EQ(esplusplayer_set_volume(esplayer_, vol),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_get_volume(esplayer_, &vol1),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(vol, vol1);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_get_volume_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  int vol = 80;
+  int vol1 = 0;
+  ASSERT_EQ(esplusplayer_set_volume(esplayer_, vol),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_get_volume(esplayer_, &vol1),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(vol, vol1);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_get_adaptive_info_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  uint64_t count = 0;
+  ASSERT_EQ(esplusplayer_get_adaptive_info(
+                esplayer_, static_cast<void*>(&count),
+                ESPLUSPLAYER_ADAPT_INFO_TYPE_DROPPED_FRAMES),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::cout << "count = " << count << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_submit_data_type_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_submit_data_type(
+                esplayer_, ESPLUSPLAYER_SUBMIT_DATA_TYPE_CLEAN_DATA),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_render_video_frame_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_video_frame_peek_mode(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  ASSERT_EQ(esplusplayer_pause(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_seek(esplayer_, 0), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  ASSERT_EQ(esplusplayer_render_video_frame(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(2));
+  ASSERT_EQ(esplusplayer_resume(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_render_time_offset_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_set_low_latency_mode(
+                esplayer_, ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_PREROLL),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  int64_t set_offset = 10;
+  ASSERT_EQ(esplusplayer_set_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, set_offset),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  int64_t get_offset = 0;
+  ASSERT_EQ(esplusplayer_get_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, &get_offset),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(set_offset, get_offset);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_render_time_offset_p_2) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_set_low_latency_mode(
+                esplayer_, ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_PREROLL),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  int64_t set_offset = 10;
+  ASSERT_EQ(esplusplayer_set_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO, set_offset),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  int64_t get_offset = 0;
+  ASSERT_EQ(esplusplayer_get_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO, &get_offset),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(set_offset, get_offset);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_render_time_offset_n_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  int64_t set_offset = 10;
+  ASSERT_EQ(esplusplayer_set_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, set_offset),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  int64_t get_offset = 0;
+  ASSERT_EQ(esplusplayer_get_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, &get_offset),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_render_time_offset_n_2) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_set_low_latency_mode(
+                esplayer_, ESPLUSPLAYER_LOW_LATENCY_MODE_DISABLE_SYNC),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  int64_t set_offset = 10;
+  ASSERT_EQ(esplusplayer_set_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, set_offset),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  int64_t get_offset = 0;
+  ASSERT_EQ(esplusplayer_get_render_time_offset(
+                esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, &get_offset),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_switch_audio_stream_onthefly_p_1) {
+  if (uri_.find("aac") == std::string::npos) return;
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  esplusplayer_audio_stream_info audio_stream;
+  memset(&audio_stream, 0, sizeof(esplusplayer_audio_stream_info));
+  audio_stream.mime_type = ESPLUSPLAYER_AUDIO_MIME_TYPE_AC3;
+  audio_stream.sample_rate = 48000;
+  audio_stream.channels = 2;
+  ASSERT_EQ(esplusplayer_switch_audio_stream_onthefly(esplayer_, &audio_stream),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::cout << "set audio stream info after flush" << std::endl;
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_switch_audio_stream_onthefly_n_1) {
+  if (uri_.find("aac") == std::string::npos) return;
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+
+  esplusplayer_audio_stream_info audio_stream;
+  memset(&audio_stream, 0, sizeof(esplusplayer_audio_stream_info));
+  audio_stream.mime_type = ESPLUSPLAYER_AUDIO_MIME_TYPE_OPUS;
+  audio_stream.sample_rate = 48000;
+  audio_stream.channels = 2;
+  ASSERT_EQ(esplusplayer_switch_audio_stream_onthefly(esplayer_, &audio_stream),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_video_codec_type_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_video_codec_type(esplayer_,
+                                              ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_set_audio_codec_type_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_audio_codec_type(esplayer_,
+                                              ESPLUSPLAYER_AUDIO_CODEC_TYPE_HW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_get_virtual_rsc_id_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+
+  int virtual_id = -1;
+  ASSERT_EQ(esplusplayer_get_virtual_rsc_id(
+                esplayer_, ESPLUSPLAYER_RSC_TYPE_VIDEO_RENDERER, &virtual_id),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(virtual_id != -1);
+  std::cout << "BasicTest, Play, END" << std::endl;
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_init_audio_easing_info_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  const esplusplayer_target_audio_easing_info init_info = {
+      0, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_init_audio_easing_info(esplayer_, 100, 0, &init_info),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_init_audio_easing_info_n_1) {
+  const esplusplayer_target_audio_easing_info init_info = {
+      0, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_init_audio_easing_info(esplayer_, 100, 0, &init_info),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_update_audio_easing_info_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  const esplusplayer_target_audio_easing_info init_info = {
+      0, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_init_audio_easing_info(esplayer_, 100, 0, &init_info),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  const esplusplayer_target_audio_easing_info update_info = {
+      100, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_update_audio_easing_info(esplayer_, &update_info),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_update_audio_easing_info_n_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  const esplusplayer_target_audio_easing_info update_info = {
+      100, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_update_audio_easing_info(esplayer_, &update_info),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_get_audio_easing_info_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  uint32_t init_volume = 100;
+  uint32_t init_elapsed_time = 50;
+  const esplusplayer_target_audio_easing_info info = {
+      50, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_init_audio_easing_info(esplayer_, init_volume,
+                                                init_elapsed_time, &info),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  uint32_t cur_volume = 0;
+  uint32_t elapsed_time = 0;
+  esplusplayer_target_audio_easing_info get_info;
+  ASSERT_EQ(esplusplayer_get_audio_easing_info(esplayer_, &cur_volume,
+                                               &elapsed_time, &get_info),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(init_volume, cur_volume);
+  EXPECT_EQ(init_elapsed_time, elapsed_time);
+  EXPECT_EQ(info.volume, get_info.volume);
+  EXPECT_EQ(info.duration, get_info.duration);
+  EXPECT_EQ(info.type, get_info.type);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_get_audio_easing_info_n_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  uint32_t cur_volume = 0;
+  uint32_t elapsed_time = 0;
+  esplusplayer_target_audio_easing_info get_info;
+  ASSERT_EQ(esplusplayer_get_audio_easing_info(esplayer_, &cur_volume,
+                                               &elapsed_time, &get_info),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_start_audio_easing_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+
+  const esplusplayer_target_audio_easing_info info = {
+      50, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_init_audio_easing_info(esplayer_, 100, 0, &info),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start_audio_easing(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_start_audio_easing_n_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(esplusplayer_start_audio_easing(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_stop_audio_easing_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  callback_->WaitForPrepareDone();
+
+  const esplusplayer_target_audio_easing_info info = {
+      50, 1000, ESPLUSPLAYER_AUDIO_EASING_LINEAR};
+  ASSERT_EQ(esplusplayer_init_audio_easing_info(esplayer_, 100, 0, &info),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start_audio_easing(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+  ASSERT_EQ(esplusplayer_stop_audio_easing(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsBasicTest, vdapi_basic_esplusplayer_stop_audio_easing_n_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  ASSERT_EQ(esplusplayer_stop_audio_easing(esplayer_),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+}
+
+INSTANTIATE_TEST_CASE_P(ESPlusplayer, EsBasicTest,
+                        ::testing::ValuesIn(es_tc::tc_list));
diff --git a/ut/src/esplusplayer/ut_display.cpp b/ut/src/esplusplayer/ut_display.cpp
new file mode 100755 (executable)
index 0000000..351b09b
--- /dev/null
@@ -0,0 +1,216 @@
+
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <stdio.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <future>
+#include <map>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "gmock/gmock.h"
+#include "gst/gst.h"
+#include "gtest/gtest.h"
+
+#include "esplusplayer_capi/esplusplayer_capi.h"
+#include "esplusplayer_capi/esplusplayer_internal.h"
+#include "ut/include/appwindow.h"
+#include "ut/include/esplusplayer/eseventlistener.hpp"
+#include "ut/include/esplusplayer/esreader.hpp"
+//#include "ut/include/esplusplayer/tclist.h"
+#include "ut/include/streamreader.hpp"
+
+using namespace plusplayer;
+namespace es_tc_diaplay {
+  static const std::string es_h264_aac = "es_h264_aac/";
+  static const std::string es_hevc_ac3 = "es_hevc_ac3/";
+  static const std::string es_vp9_opus = "es_vp9_opus/";
+  std::vector<std::string> tc_list = {
+    es_h264_aac,
+    //es_hevc_ac3,
+    es_vp9_opus,
+  };
+}
+
+class EsDisplayTest : public ::testing::TestWithParam<std::string> {
+ public:
+  EsDisplayTest() { std::cout << "EsDisplayTest()" << std::endl; }
+  ~EsDisplayTest() { std::cout << "~EsDisplayTest()" << std::endl; }
+
+  static void SetUpTestCase() {
+    gst_init_check(nullptr, nullptr, nullptr);
+    window_ = new Environment();
+    ESPacketDownloader::Init();
+    std::cout << "SetUpTestCase()" << std::endl;
+  }
+  static void TearDownTestCase() {
+    if (window_) {
+      delete window_;
+      window_ = nullptr;
+    }
+    std::cout << "TearDownTestCase()" << std::endl;
+  }
+
+  virtual void SetUp() override {
+    uri_ = GetParam();
+    std::cout << "uri_: " << uri_ << std::endl;
+    video_reader_ =
+        new EsStreamReader(uri_ + "video/", ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+    audio_reader_ =
+        new EsStreamReader(uri_ + "audio/", ESPLUSPLAYER_STREAM_TYPE_AUDIO);
+    esplayer_ = esplusplayer_create();
+    ASSERT_NE(nullptr, esplayer_);
+    callback_ =
+        new EsPlayerEventCallback(esplayer_, video_reader_, audio_reader_);
+    callback_->SetCallback();
+
+    std::cout << "SetUp()" << std::endl;
+  }
+
+  virtual void TearDown() override {
+    if (nullptr != esplayer_) {
+      ASSERT_EQ(esplusplayer_stop(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+      ASSERT_EQ(esplusplayer_close(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+    }
+    delete callback_;
+    delete video_reader_;
+    delete audio_reader_;
+
+    std::cout << "TearDown()" << std::endl;
+  }
+
+ public:
+  std::string uri_;
+  EsStreamReader* video_reader_;
+  EsStreamReader* audio_reader_;
+  esplusplayer_handle esplayer_;
+  EsPlayerEventCallback* callback_;
+  static Environment* window_;
+};
+Environment* EsDisplayTest::window_ = nullptr;
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_display_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_ecore_display_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_ecore_display(
+                esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                window_->EcoreWindow(), 0, 0, 1920, 1080),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_surface_display_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  unsigned int surfaceid = 1;
+  ASSERT_EQ(esplusplayer_set_surface_display(esplayer_,
+                                             ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                                             surfaceid, 0, 0, 1920, 1080),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_display_mode_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_display_mode(esplayer_,
+                                             ESPLUSPLAYER_DISPLAY_MODE_FULL_SCREEN),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_display_roi_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_display_mode(esplayer_,
+                                             ESPLUSPLAYER_DISPLAY_MODE_DST_ROI),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_display_roi(esplayer_,0,0,600,500),ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_display_visible_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_display_visible(esplayer_,false),ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_video_roi_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_video_roi(esplayer_,0,0,0.5,0.5),ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_set_display_rotation_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(esplusplayer_set_display_rotation(esplayer_,ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_90),ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+TEST_P(EsDisplayTest, vdapi_display_esplusplayer_get_display_rotation_p_1) {
+  ASSERT_EQ(esplusplayer_open(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_EQ(
+      esplusplayer_set_display(esplayer_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                               window_->Window()),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_display_rotation_type rotation_set = ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_90;
+  esplusplayer_display_rotation_type rotation_get = ESPLUSPLAYER_DISPLAY_ROTATION_TYPE_NONE;
+  ASSERT_EQ(esplusplayer_set_display_rotation(esplayer_,rotation_set),ESPLUSPLAYER_ERROR_TYPE_NONE);
+  ASSERT_TRUE(video_reader_->SetStreamInfo(esplayer_));
+  ASSERT_TRUE(audio_reader_->SetStreamInfo(esplayer_));
+  ASSERT_EQ(esplusplayer_prepare_async(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_get_display_rotation(esplayer_,&rotation_get);
+  ASSERT_EQ(rotation_set,rotation_get);
+  callback_->WaitForPrepareDone();
+  ASSERT_EQ(esplusplayer_start(esplayer_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+INSTANTIATE_TEST_CASE_P(ESPlusplayer, EsDisplayTest,
+                        ::testing::ValuesIn(es_tc_diaplay::tc_list));
diff --git a/ut/src/esplusplayer/ut_setstream.cpp b/ut/src/esplusplayer/ut_setstream.cpp
new file mode 100755 (executable)
index 0000000..4a87e7d
--- /dev/null
@@ -0,0 +1,51 @@
+#include "gmock/gmock.h"\r
+#include "gtest/gtest.h"\r
+\r
+#include <chrono>\r
+#include <thread>\r
+\r
+#include "esplusplayer_capi/esplusplayer_capi.h"\r
+\r
+class EsVideoSetStreamTest : public ::testing::Test {};\r
+\r
+TEST_F(EsVideoSetStreamTest, MJPEG) {\r
+  esplusplayer_video_stream_info vstream_info;\r
+  vstream_info.codec_data = nullptr;\r
+  vstream_info.codec_data_length = 0;\r
+  vstream_info.mime_type = ESPLUSPLAYER_VIDEO_MIME_TYPE_MJPEG;\r
+  vstream_info.width = 1920;\r
+  vstream_info.height = 1080;\r
+  vstream_info.max_width = 1920;\r
+  vstream_info.max_height = 1080;\r
+  vstream_info.framerate_num = 30;\r
+  vstream_info.framerate_den = 1;\r
+\r
+  auto* handle = esplusplayer_create();\r
+  esplusplayer_open(handle);\r
+  esplusplayer_set_video_stream_info(handle, &vstream_info);\r
+  esplusplayer_prepare_async(handle);\r
+  std::this_thread::sleep_for(std::chrono::seconds(2));\r
+  esplusplayer_close(handle);\r
+  esplusplayer_destroy(handle);\r
+}\r
+\r
+TEST_F(EsVideoSetStreamTest, UHD_MJPEG) {\r
+  esplusplayer_video_stream_info vstream_info;\r
+  vstream_info.codec_data = nullptr;\r
+  vstream_info.codec_data_length = 0;\r
+  vstream_info.mime_type = ESPLUSPLAYER_VIDEO_MIME_TYPE_MJPEG;\r
+  vstream_info.width = 3840;\r
+  vstream_info.height = 2160;\r
+  vstream_info.max_width = 3840;\r
+  vstream_info.max_height = 2160;\r
+  vstream_info.framerate_num = 30;\r
+  vstream_info.framerate_den = 1;\r
+\r
+  auto* handle = esplusplayer_create();\r
+  esplusplayer_open(handle);\r
+  esplusplayer_set_video_stream_info(handle, &vstream_info);\r
+  esplusplayer_prepare_async(handle);\r
+  std::this_thread::sleep_for(std::chrono::seconds(2));\r
+  esplusplayer_close(handle);\r
+  esplusplayer_destroy(handle);\r
+}
\ No newline at end of file
diff --git a/ut/src/mixer/constant.cpp b/ut/src/mixer/constant.cpp
new file mode 100755 (executable)
index 0000000..4b86443
--- /dev/null
@@ -0,0 +1,51 @@
+#include "mixer/constant.h"
+
+namespace plusplayer_ut {
+
+VideoPlaneManipulableInfo GetVideoPlaneManipulableInfo(
+    BufferHandleType handle, const PlaneComponent& comp,
+    const std::uint32_t& linesize, const Geometry& geom) {
+  VideoPlaneManipulableInfo ret;
+  ret.handle = handle;
+  ret.component = comp;
+  ret.linesize = linesize;
+  ret.rect = geom;
+  return ret;
+}
+
+Geometry GetGeometry(const int& x, const int& y, const int& w, const int& h) {
+  Geometry geom;
+  geom.x = x;
+  geom.y = y;
+  geom.w = w;
+  geom.h = h;
+  return geom;
+}
+
+CropArea GetCropArea(const double& x, const double& y, const double& w,
+                     const double& h) {
+  CropArea croparea;
+  croparea.scale_x = x;
+  croparea.scale_y = y;
+  croparea.scale_w = w;
+  croparea.scale_h = h;
+  return croparea;
+}
+
+Mixer::ResolutionInfo GetResolutionInfo(int width, int height, int fnum,
+                                        int fden) {
+  Mixer::ResolutionInfo rinfo;
+  rinfo.width = width;
+  rinfo.height = height;
+  rinfo.framerate_num = fnum;
+  rinfo.framerate_den = fden;
+  return rinfo;
+}
+
+static std::uint32_t _kDefaultBuffer = 0;
+BufferDefaultType kDefaultBuffer =
+    reinterpret_cast<BufferDefaultType>(&_kDefaultBuffer);
+
+BufferUnionHandleType kDefaultMappedHandle = {.u32 = kDefaultBufferHandle};
+
+}  // namespace plusplayer_ut
\ No newline at end of file
diff --git a/ut/src/mixer/matcher.cpp b/ut/src/mixer/matcher.cpp
new file mode 100755 (executable)
index 0000000..83f503c
--- /dev/null
@@ -0,0 +1,10 @@
+#include "mixer/matcher.h"
+
+namespace plusplayer_ut {
+
+Matcher<const VideoPlaneManipulableInfo&> IsSameVideoPlaneManipulableInfo(
+    const VideoPlaneManipulableInfo& comparer) {
+  return MakeMatcher(new IsSameVideoPlaneManipulableInfoMatcher(comparer));
+}
+
+}  // namespace plusplayer_ut
\ No newline at end of file
diff --git a/ut/src/mixer/ut_espp_mixerscenario.cpp b/ut/src/mixer/ut_espp_mixerscenario.cpp
new file mode 100755 (executable)
index 0000000..9121b83
--- /dev/null
@@ -0,0 +1,597 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include <gtest/gtest.h>
+
+#include <iostream>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer_capi/mixer_capi.h"
+#include "ut/include/plusplayer/utility.h"
+#include "ut/include/streamreader.hpp"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+using namespace utils;
+using namespace std;
+
+using utils::Utility;
+std::string es_uri_1 = "youtube/";
+std::string es_uri_2 = "bunny/";
+std::string es_vp8_uri = "es_vp8_vorbis/";
+
+//max playing duration : 10 sec => see EsStreamReader::ReadNextPacket()
+constexpr int kPlayingTime = 2;  // (sec)
+
+//------------------------------------------------------------
+class MixerEsppScenarioTestF : public ::testing::Test {
+ public:
+  explicit MixerEsppScenarioTestF(void)
+      : util_(Utility::Instance()),
+        mixer_(nullptr),
+        player1_(nullptr),
+        player2_(nullptr),
+        player3_(nullptr),
+        player4_(nullptr){};
+  ~MixerEsppScenarioTestF(void){};
+
+  static void SetUpTestCase() {
+    ESPacketDownloader::Init();
+    std::cout << "SetUpTestCase()" << std::endl;
+  }
+
+  static void TearDownTestCase() {}
+
+  virtual void SetUp(void) override {
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+    mixer_ = mixer_create();
+    mixer_set_display(mixer_, MIXER_DISPLAY_TYPE_OVERLAY, util_.GetWindow());
+#if 1
+    roi1_.x = 20;
+    roi1_.y = 20;
+    roi1_.w = 720;
+    roi1_.h = 480;
+
+    roi2_.x = 1000;
+    roi2_.y = 20;
+    roi2_.w = 720;
+    roi2_.h = 480;
+
+    roi3_.x = 1000;
+    roi3_.y = 520;
+    roi3_.w = 720;
+    roi3_.h = 480;
+
+    roi4_.x = 20;
+    roi4_.y = 520;
+    roi4_.w = 720;
+    roi4_.h = 480;
+#else
+    roi1_.x = 20;
+    roi1_.y = 20;
+    roi1_.w = 1180;
+    roi1_.h = 720;
+
+    roi2_.x = 1220;
+    roi2_.y = 20;
+    roi2_.w = 640;
+    roi2_.h = 480;
+
+    roi3_.x = 1220;
+    roi3_.y = 520;
+    roi3_.w = 640;
+    roi3_.h = 480;
+#endif
+  }
+
+  virtual void TearDown(void) override {
+    util_.DestroyESPP(player1_);
+    util_.DestroyESPP(player2_);
+    util_.DestroyESPP(player3_);
+    util_.DestroyESPP(player4_);       
+    mixer_destroy(mixer_);
+    player1_ = nullptr;
+    player2_ = nullptr;
+    player3_ = nullptr;
+    player4_ = nullptr;        
+    mixer_ = nullptr;
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+  }
+
+ public:
+  Utility& util_;
+  mixer_handle mixer_;
+  esplusplayer_handle player1_;
+  esplusplayer_handle player2_;
+  esplusplayer_handle player3_;
+  esplusplayer_handle player4_;  
+  Geometry roi1_;
+  Geometry roi2_;
+  Geometry roi3_;
+  Geometry roi4_;
+};
+
+#if 1  // normal mixer test
+TEST_F(MixerEsppScenarioTestF, Basic) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+  player3_ = util_.GetOpenedMixESPP(mixer_, roi3_);
+  ASSERT_NE(player3_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player1_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player3_, es_uri_1));
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, DetachAttach) {
+  player1_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetStartedMixESPP(es_uri_2, mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  player3_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi3_);
+  ASSERT_NE(player3_, nullptr);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, DetachAttach1) {
+  player1_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  player3_ = util_.GetStartedMixESPP(es_uri_2, mixer_, roi1_);
+  ASSERT_NE(player3_, nullptr);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, SetROI) {
+  player1_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetStartedMixESPP(es_uri_2, mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_set_display_roi(player1_, roi2_.x, roi2_.y, roi2_.w,
+                                         roi2_.h),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_display_roi(player2_, roi1_.x, roi1_.y, roi1_.w,
+                                         roi1_.h),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_commit(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, SetROI1) {
+  player1_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetStartedMixESPP(es_uri_2, mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_set_display_roi(player1_, roi2_.x, roi2_.y, roi2_.w,
+                                         roi2_.h),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_display_roi(player2_, roi3_.x, roi3_.y, roi3_.w,
+                                         roi3_.h),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_commit(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, CheckMaxMixedPlayer) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+  player3_ = util_.GetOpenedMixESPP(mixer_, roi3_);
+  ASSERT_NE(player3_, nullptr);
+  esplusplayer_handle player4 = util_.GetOpenedMixESPP(mixer_, roi3_);
+  ASSERT_NE(player4, nullptr);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player3_, es_uri_1));
+
+  EXPECT_FALSE(util_.PrepareESPP(player4, es_uri_1));
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  util_.DestroyESPP(player4);
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, SetAudioFocus) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player1_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_2));
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player2_), MIXER_ERROR_TYPE_NONE);
+  util_.FeedingEsPacket(player2_, ESPLUSPLAYER_STREAM_TYPE_AUDIO, es_uri_2);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, MultiAudioTest) {
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  player3_ = util_.GetOpenedMixESPP(mixer_, roi3_);
+  ASSERT_NE(player3_, nullptr);
+
+  EXPECT_EQ(esplusplayer_set_audio_codec_type(player2_,
+                                              ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_audio_codec_type(player3_,
+                                              ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_2));
+  EXPECT_TRUE(util_.PrepareESPP(player3_, es_uri_1));
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, MultiAudioTest2) {
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  player3_ = util_.GetOpenedMixESPP(mixer_, roi3_);
+  ASSERT_NE(player3_, nullptr);
+
+  EXPECT_EQ(esplusplayer_set_alternative_video_resource(player2_, 1),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_video_codec_type(player3_,
+                                              ESPLUSPLAYER_VIDEO_CODEC_TYPE_SW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_audio_codec_type(player2_,
+                                              ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_audio_codec_type(player3_,
+                                              ESPLUSPLAYER_AUDIO_CODEC_TYPE_SW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_2));
+  EXPECT_TRUE(util_.PrepareESPP(player3_, es_uri_1));
+
+  /* audio hw decoder + mmaudiosink */
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  /* audio sw decoder + pulsesink */
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  /* audio sw decoder + pulsesink */
+  EXPECT_EQ(esplusplayer_start(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_deactivate(player1_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_deactivate(player3_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  /* audio hw decoder + mmaudiosink */
+  EXPECT_EQ(esplusplayer_set_audio_codec_type(player3_,
+                                              ESPLUSPLAYER_AUDIO_CODEC_TYPE_HW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_activate(player3_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  util_.FeedingEsPacket(player3_, ESPLUSPLAYER_STREAM_TYPE_AUDIO, es_uri_1);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_deactivate(player2_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_deactivate(player3_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  /* audio sw decoder + alsasink */
+  EXPECT_EQ(esplusplayer_activate(player2_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  util_.FeedingEsPacket(player2_, ESPLUSPLAYER_STREAM_TYPE_AUDIO, es_uri_2);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, SetAudioFocus1) {
+  player1_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetStartedMixESPP(es_uri_2, mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, SetAudioFocus2) {
+  player1_ = util_.GetStartedMixESPP(es_uri_1, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, nullptr),
+            MIXER_ERROR_TYPE_INVALID_OPERATION);
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, MixerNPlayer) {
+  mixer_set_display_mode(mixer_, MIXER_DISPLAY_MODE_DST_ROI);
+  mixer_set_display_roi(mixer_, roi2_.x, roi2_.y, roi2_.w, roi2_.h);
+  mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DISABLE);
+  mixer_disable_audio_focus_setting(mixer_);
+  mixer_set_alternative_video_scaler(mixer_);
+
+  player1_ = util_.GetOpenedESPP(roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  Geometry roi3;
+  roi3.x = 0;
+  roi3.y = 0;
+  roi3.w = roi2_.w;
+  roi3.h = roi2_.h;
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi3);
+  ASSERT_NE(player2_, nullptr);
+  esplusplayer_set_alternative_video_resource(player2_, 1);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1, utils::EsType::kBoth));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_2, utils::EsType::kVideo));
+
+  esplusplayer_start(player1_);
+  esplusplayer_start(player2_);
+
+  mixer_start(mixer_);
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_EQ(esplusplayer_deactivate(player1_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_deactivate(player2_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(esplusplayer_set_display(player1_, ESPLUSPLAYER_DISPLAY_TYPE_MIXER,
+                                     mixer_),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_display(
+                player2_, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY, util_.GetWindow()),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  esplusplayer_set_alternative_video_resource(player1_, 1);
+  EXPECT_EQ(esplusplayer_activate(player1_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_set_display_roi(player1_, roi3.x, roi3.y, roi3.w, roi3.h);
+  mixer_commit(mixer_);
+  util_.FeedingEsPacket(player1_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, es_uri_1);
+
+  esplusplayer_set_alternative_video_resource(player2_, 0);
+  EXPECT_EQ(esplusplayer_activate(player2_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_set_display_mode(player2_, ESPLUSPLAYER_DISPLAY_MODE_DST_ROI);
+  esplusplayer_set_display_roi(player2_, roi1_.x, roi1_.y, roi1_.w, roi1_.h);
+  util_.FeedingEsPacket(player2_, ESPLUSPLAYER_STREAM_TYPE_VIDEO, es_uri_2);
+  
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  esplusplayer_stop(player1_);
+  esplusplayer_stop(player2_);
+  mixer_stop(mixer_);
+}
+
+TEST_F(MixerEsppScenarioTestF, NDecH264PlayerX2) {
+  mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_NDECODER);
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player1_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_1));
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, NDecH264PlayerX4) {
+  mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_NDECODER);
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+  player3_ = util_.GetOpenedMixESPP(mixer_, roi3_);
+  ASSERT_NE(player3_, nullptr);
+  player4_ = util_.GetOpenedMixESPP(mixer_, roi4_);
+  ASSERT_NE(player4_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player1_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player3_, es_uri_1));
+  EXPECT_TRUE(util_.PrepareESPP(player4_, es_uri_1));  
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player4_), ESPLUSPLAYER_ERROR_TYPE_NONE);  
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player4_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, NDecVp8PlayerX2) {
+  mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_NDECODER);
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player1_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_vp8_uri));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_vp8_uri));
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(MixerEsppScenarioTestF, NDecVp8PlayerX4) {
+  mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_NDECODER);
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixESPP(mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+  player3_ = util_.GetOpenedMixESPP(mixer_, roi3_);
+  ASSERT_NE(player3_, nullptr);
+  player4_ = util_.GetOpenedMixESPP(mixer_, roi4_);
+  ASSERT_NE(player4_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player1_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_TRUE(util_.PrepareESPP(player1_, es_vp8_uri));
+  EXPECT_TRUE(util_.PrepareESPP(player2_, es_vp8_uri));
+  EXPECT_TRUE(util_.PrepareESPP(player3_, es_vp8_uri));
+  EXPECT_TRUE(util_.PrepareESPP(player4_, es_vp8_uri));  
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player4_), ESPLUSPLAYER_ERROR_TYPE_NONE);  
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player3_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player4_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+#endif
diff --git a/ut/src/mixer/ut_mixedframe.cpp b/ut/src/mixer/ut_mixedframe.cpp
new file mode 100755 (executable)
index 0000000..eb32864
--- /dev/null
@@ -0,0 +1,355 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <memory>
+
+#include "mixer/constant.h"
+#include "mixer/matcher.h"
+#include "mixer/mixedframe.h"
+#include "mixer/mock/fakebuffer.h"
+#include "mixer/mock/mock_bufferobject.h"
+#include "mixer/mock/mock_memallocator.h"
+#include "mixer/mock/mock_phyaddraccessor.h"
+#include "mixer/mock/mock_vpmanipulator.h"
+#include "mixer/mock/movable.h"
+#include "mixer/mock/moveobj_wrapper.h"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::AtLeast;
+using ::testing::ByRef;
+using ::testing::DoAll;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::Invoke;
+using ::testing::NotNull;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SizeIs;
+
+/********************************************************************************************
+ * [DEFAULT CLASS] DefaultMixedFrameTestOption
+ */
+
+class DefaultMixedFrameTestOption {
+ public:
+  explicit DefaultMixedFrameTestOption() = default;
+  virtual ~DefaultMixedFrameTestOption() = default;
+
+ protected:
+  virtual void Init_() {
+    ON_CALL(GetMemoryAllocator_(), Allocate(_))
+        .WillByDefault(DoAll(
+            SaveArg<0>(&allocated_size_), CreateFakeBuffer(fakebuffer_),
+            Invoke(
+                this,
+                &DefaultMixedFrameTestOption::DelegateDefaultForBufferObject_),
+            Return(RelaseBufferObject_())));
+  }
+
+ protected:
+  MockMemoryAllocator& GetMemoryAllocator_() { return memalloc_; }
+  MockAccessibleBufferObject& GetBufferObject_() { return bufferobj_.Get(); }
+  MockAccessibleBufferObject* RelaseBufferObject_() {
+    return bufferobj_.Move();
+  }
+  MockPhyAddrAccessor& GetReadablePhyAddrAccessor_() {
+    return r_phyaddraccessor_.Get();
+  }
+  MockPhyAddrAccessor& GetWritablePhyAddrAccessor_() {
+    return w_phyaddraccessor_.Get();
+  }
+  MockAccessibleBufferObject::PhyAddrAccessorPtr
+  MoveReadablePhyAddrAccessor_() {
+    return MockAccessibleBufferObject::PhyAddrAccessorPtr(
+        r_phyaddraccessor_.Move());
+  }
+  MockAccessibleBufferObject::PhyAddrAccessorPtr
+  MoveWritablePhyAddrAccessor_() {
+    return MockAccessibleBufferObject::PhyAddrAccessorPtr(
+        w_phyaddraccessor_.Move());
+  }
+
+ private:
+  virtual void DelegateDefaultForBufferObject_(const std::uint32_t size) {
+    ON_CALL(GetBufferObject_(), GetReadableAddress_())
+        .WillByDefault(
+            Return(Movable(MockAccessibleBufferObject::PhyAddrAccessorPtr(
+                MoveReadablePhyAddrAccessor_()))));
+    ON_CALL(GetBufferObject_(), GetWritableAddress_())
+        .WillByDefault(
+            Return(Movable(MockAccessibleBufferObject::PhyAddrAccessorPtr(
+                MoveWritablePhyAddrAccessor_()))));
+    ON_CALL(GetBufferObject_(), GetBufferHandle())
+        .WillByDefault(Return(kDefaultBufferHandle));
+    ON_CALL(GetBufferObject_(), Export())
+        .WillByDefault(Return(kDefaultBufferKey));
+    ON_CALL(GetBufferObject_(), GetSize())
+        .WillByDefault(Return(allocated_size_));
+
+    ON_CALL(GetReadablePhyAddrAccessor_(), GetAddress())
+        .WillByDefault(Return(fakebuffer_->ptr.get()));
+    ON_CALL(GetWritablePhyAddrAccessor_(), GetAddress())
+        .WillByDefault(Return(fakebuffer_->ptr.get()));
+  }
+
+ private:
+  std::uint32_t allocated_size_;
+  FakeBufferPtr fakebuffer_;
+
+  MoveObjectWrapper<MockPhyAddrAccessor> r_phyaddraccessor_{
+      new MockPhyAddrAccessor()};
+  MoveObjectWrapper<MockPhyAddrAccessor> w_phyaddraccessor_{
+      new MockPhyAddrAccessor()};
+  MoveObjectWrapper<MockAccessibleBufferObject> bufferobj_{
+      new MockAccessibleBufferObject()};
+  MockMemoryAllocator memalloc_;
+};
+
+/********************************************************************************************
+ * InvalidMixedFrameTest
+ */
+
+class InvalidMixedFrameTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    mixed_frame_ = MixedFrame::Create(nullptr, kInvalidWidth, kInvalidHeight);
+    ASSERT_FALSE(mixed_frame_->IsValid());
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  MixedFramePtr& GetMixedFrame() { return mixed_frame_; }
+  const MockVideoPlaneManipulator& GetVideoPlaneManipulator_() const {
+    return vieoplane_manip_;
+  }
+
+ private:
+  MixedFramePtr mixed_frame_;
+  MockVideoPlaneManipulator vieoplane_manip_;
+};
+
+TEST_F(InvalidMixedFrameTest, GetVideoPlaneManipInfo) {
+  EXPECT_EQ(0, GetMixedFrame()->GetVideoPlaneManipInfo().size());
+}
+
+TEST_F(InvalidMixedFrameTest, GetSize) {
+  EXPECT_EQ(0, GetMixedFrame()->GetSize());
+}
+
+TEST_F(InvalidMixedFrameTest, Render) {
+  EXPECT_FALSE(GetMixedFrame()->Render(
+      &GetVideoPlaneManipulator_(),
+      {kYComponentSrcVMInfo, kUVComponentSrcVMInfo},
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+TEST_F(InvalidMixedFrameTest, Export) {
+  BufferKeyType key;
+  EXPECT_FALSE(GetMixedFrame()->Export(key));
+}
+
+/********************************************************************************************
+ * MixedFrameConstructionTest
+ */
+class MixedFrameConstructionTest : public ::testing::Test,
+                                   public DefaultMixedFrameTestOption {
+ public:
+  using MockBufferObjectPtr = std::unique_ptr<MockBufferObject>;
+  virtual ~MixedFrameConstructionTest() {}
+
+  virtual void SetUp() override { Init_(); }
+  virtual void TearDown() override {}
+};
+
+TEST_F(MixedFrameConstructionTest, IsValid_WithInvalidAllocator) {
+  EXPECT_FALSE(
+      MixedFrame::Create(nullptr, kDefaultWidth, kDefaultHeight)->IsValid());
+}
+
+TEST_F(MixedFrameConstructionTest, IsValid_WithInvalidResolution) {
+  EXPECT_FALSE(
+      MixedFrame::Create(&GetMemoryAllocator_(), kInvalidWidth, kInvalidHeight)
+          ->IsValid());
+}
+
+TEST_F(MixedFrameConstructionTest, IsValid_WithAllocateNullPtr) {
+  EXPECT_CALL(GetMemoryAllocator_(), Allocate(kExpectedDefaultByteSize))
+      .WillOnce(Return(nullptr));
+
+  EXPECT_FALSE(
+      MixedFrame::Create(&GetMemoryAllocator_(), kDefaultWidth, kDefaultHeight)
+          ->IsValid());
+}
+
+TEST_F(MixedFrameConstructionTest, IsValid_WithZeroSizeAllocated) {
+  EXPECT_CALL(GetMemoryAllocator_(), Allocate(kExpectedDefaultByteSize))
+      .Times(1);
+  EXPECT_CALL(GetBufferObject_(), GetSize()).WillOnce(Return(0));
+
+  EXPECT_FALSE(
+      MixedFrame::Create(&GetMemoryAllocator_(), kDefaultWidth, kDefaultHeight)
+          ->IsValid());
+}
+
+TEST_F(MixedFrameConstructionTest, IsValid_WithReturnWritableNullPtr) {
+  EXPECT_CALL(GetMemoryAllocator_(), Allocate(kExpectedDefaultByteSize))
+      .Times(1);
+  EXPECT_CALL(GetBufferObject_(), GetSize()).Times(1);
+  EXPECT_CALL(GetBufferObject_(), GetWritableAddress_())
+      .WillOnce(Return(Movable(AccessibleBuffer::PhyAddrAccessorPtr(nullptr))));
+
+  EXPECT_TRUE(
+      MixedFrame::Create(&GetMemoryAllocator_(), kDefaultWidth, kDefaultHeight)
+          ->IsValid());
+}
+
+TEST_F(MixedFrameConstructionTest, IsValid) {
+  EXPECT_CALL(GetMemoryAllocator_(), Allocate(kExpectedDefaultByteSize))
+      .Times(1);
+  EXPECT_CALL(GetBufferObject_(), GetSize()).Times(1);
+  EXPECT_CALL(GetBufferObject_(), GetWritableAddress_()).Times(1);
+  EXPECT_CALL(GetWritablePhyAddrAccessor_(), GetAddress()).Times(2);
+
+  EXPECT_TRUE(
+      MixedFrame::Create(&GetMemoryAllocator_(), kDefaultWidth, kDefaultHeight)
+          ->IsValid());
+}
+
+/********************************************************************************************
+ * MixedFrameTest
+ */
+
+class MixedFrameTest : public ::testing::Test,
+                       public DefaultMixedFrameTestOption {
+ public:
+  explicit MixedFrameTest() = default;
+  virtual ~MixedFrameTest() = default;
+
+  virtual void SetUp() override {
+    Init_();
+
+    ON_CALL(GetVideoPlaneManipulator_(), Do(_, _)).WillByDefault(Return(true));
+
+    EXPECT_CALL(GetMemoryAllocator_(), Allocate(_)).Times(1);
+
+    EXPECT_CALL(GetBufferObject_(), GetSize()).Times(AtLeast(1));
+    EXPECT_CALL(GetBufferObject_(), GetWritableAddress_()).Times(AtLeast(1));
+
+    EXPECT_CALL(GetWritablePhyAddrAccessor_(), GetAddress()).Times(2);
+
+    mixed_frame_ = MixedFrame::Create(&GetMemoryAllocator_(), kDefaultWidth,
+                                      kDefaultHeight);
+    ASSERT_TRUE(mixed_frame_->IsValid());
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  MockVideoPlaneManipulator& GetVideoPlaneManipulator_() {
+    return vieoplane_manip_;
+  }
+  MixedFramePtr& GetMixedFrame() { return mixed_frame_; }
+
+ private:
+  MixedFramePtr mixed_frame_;
+  MockVideoPlaneManipulator vieoplane_manip_;
+};
+
+TEST_F(MixedFrameTest, GetVideoPlaneManipInfo) {
+  EXPECT_CALL(GetBufferObject_(), GetBufferHandle());
+  EXPECT_THAT(
+      GetMixedFrame()->GetVideoPlaneManipInfo(),
+      AllOf(SizeIs(2),
+            ElementsAre(
+                IsSameVideoPlaneManipulableInfo(kYComponentDestVMInfo),
+                IsSameVideoPlaneManipulableInfo(kUVComponentDestVMInfo))));
+}
+
+TEST_F(MixedFrameTest, GetWidth) {
+  EXPECT_EQ(kDefaultWidth, GetMixedFrame()->GetWidth());
+}
+
+TEST_F(MixedFrameTest, GetHeight) {
+  EXPECT_EQ(kDefaultHeight, GetMixedFrame()->GetHeight());
+}
+
+TEST_F(MixedFrameTest, GetSize) {
+  EXPECT_EQ(kExpectedDefaultByteSize, GetMixedFrame()->GetSize());
+}
+
+TEST_F(MixedFrameTest, Render) {
+  ::testing::Sequence s1;
+  EXPECT_CALL(GetBufferObject_(), GetBufferHandle()).Times(2);
+
+  EXPECT_CALL(GetVideoPlaneManipulator_(),
+              Do(IsSameVideoPlaneManipulableInfo(kYComponentSrcVMInfo),
+                 IsSameVideoPlaneManipulableInfo(kCroppedYComponentDestVMInfo)))
+      .InSequence(s1);
+  EXPECT_CALL(
+      GetVideoPlaneManipulator_(),
+      Do(IsSameVideoPlaneManipulableInfo(kUVComponentSrcVMInfo),
+         IsSameVideoPlaneManipulableInfo(kCroppedUVComponentDestVMInfo)))
+      .InSequence(s1);
+
+  EXPECT_TRUE(GetMixedFrame()->Render(
+      &GetVideoPlaneManipulator_(),
+      {kYComponentSrcVMInfo, kUVComponentSrcVMInfo},
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+TEST_F(MixedFrameTest, Render_WithNullOperator) {
+  EXPECT_FALSE(GetMixedFrame()->Render(
+      nullptr, {kYComponentSrcVMInfo, kUVComponentSrcVMInfo},
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+TEST_F(MixedFrameTest, Render_WithFirstOpFailed) {
+  EXPECT_CALL(GetBufferObject_(), GetBufferHandle()).Times(2);
+
+  EXPECT_CALL(GetVideoPlaneManipulator_(),
+              Do(Field(&VideoPlaneManipulableInfo::component,
+                       PlaneComponent::kYComponent),
+                 _))
+      .WillOnce(Return(false));
+  EXPECT_CALL(GetVideoPlaneManipulator_(),
+              Do(Field(&VideoPlaneManipulableInfo::component,
+                       PlaneComponent::kUVComponent),
+                 _))
+      .Times(1);
+
+  EXPECT_FALSE(GetMixedFrame()->Render(
+      &GetVideoPlaneManipulator_(),
+      {kYComponentSrcVMInfo, kUVComponentSrcVMInfo},
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+TEST_F(MixedFrameTest, Render_WithSecondOpFailed) {
+  EXPECT_CALL(GetBufferObject_(), GetBufferHandle()).Times(2);
+
+  EXPECT_CALL(GetVideoPlaneManipulator_(),
+              Do(Field(&VideoPlaneManipulableInfo::component,
+                       PlaneComponent::kYComponent),
+                 _))
+      .Times(1);
+  EXPECT_CALL(GetVideoPlaneManipulator_(),
+              Do(Field(&VideoPlaneManipulableInfo::component,
+                       PlaneComponent::kUVComponent),
+                 _))
+      .WillOnce(Return(false));
+
+  EXPECT_FALSE(GetMixedFrame()->Render(
+      &GetVideoPlaneManipulator_(),
+      {kYComponentSrcVMInfo, kUVComponentSrcVMInfo},
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+TEST_F(MixedFrameTest, Export) {
+  EXPECT_CALL(GetBufferObject_(), Export());
+  BufferKeyType key;
+  EXPECT_TRUE(GetMixedFrame()->Export(key));
+  EXPECT_EQ(kDefaultBufferKey, key);
+}
\ No newline at end of file
diff --git a/ut/src/mixer/ut_mixer.cpp b/ut/src/mixer/ut_mixer.cpp
new file mode 100755 (executable)
index 0000000..9dbf976
--- /dev/null
@@ -0,0 +1,257 @@
+
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include <gtest/gtest.h>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/mixer.h"
+#include "mixer/mixer_eventlistener.h"
+#include "mixer/mixerticket.h"
+#include "mixer/mixerticket_eventlistener.h"
+#include "ut/include/appwindow.h"
+#include "ut/include/plusplayer/utility.h"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+using namespace utils;
+
+class MixerMockPlayer {
+ public:
+  MixerMockPlayer() { listener_ = new MyTicketListener(this); }
+  MixerMockPlayer(int x, int y, int w, int h) {
+    listener_ = new MyTicketListener(this);
+    display_info_.geometry.x = x;
+    display_info_.geometry.y = y;
+    display_info_.geometry.w = w;
+    display_info_.geometry.h = h;
+  }
+  ~MixerMockPlayer() { delete listener_; }
+
+  class MyTicketListener : public MixerTicketEventListener {
+   public:
+    explicit MyTicketListener(MixerMockPlayer* handler) : handler_(handler){};
+    bool OnAudioFocusChanged(bool active) {
+      LOG_INFO("My OnAudioFocusChanged [%d] player [%p]", active, handler_);
+      return true;
+    }
+
+    bool OnUpdateDisplayInfo(const DisplayInfo& cur_info,
+                             DisplayInfo* new_info) {
+      *new_info = handler_->display_info_;
+      LOG_INFO("OnUpdateDisplayInfo x[%d] y[%d]",
+               handler_->display_info_.geometry.x,
+               handler_->display_info_.geometry.y);
+      return true;
+    }
+    MixerMockPlayer* handler_ = nullptr;
+  };
+
+ public:
+  MixerTicketEventListener* listener_ = nullptr;
+  DisplayInfo display_info_;
+};
+
+class MixerMockListener : public MixerEventListener {
+ public:
+  MixerMockListener() {}
+  ~MixerMockListener() {}
+  void OnError() {
+    LOG_INFO(" listener [%p]", this);
+  }
+  void OnResourceConflicted() {
+    LOG_INFO("MyOnResourceConflicted listener[%p]", this);
+  }
+};
+
+TEST(MixerTest, MixerCreate) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  ASSERT_NE(mixer, nullptr);
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerTicketCreate) {
+  MixerMockPlayer p1;
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ASSERT_NE(ticket, nullptr);
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerDisableAutoRscAlloc_1) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  EXPECT_TRUE(mixer->SetRscAllocMode(RscAllocMode::kDisable));
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerDisableAutoRscAlloc_2) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockPlayer p1;
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_FALSE(mixer->SetRscAllocMode(RscAllocMode::kDisable));
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerDisableAudioFocusSetting_1) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  EXPECT_TRUE(mixer->DisableAudioFocusSetting());
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerDisableAudioFocusSetting_2) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockPlayer p1;
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_FALSE(mixer->DisableAudioFocusSetting());
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerSetAudioFocus_1) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockPlayer p1;
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_TRUE(mixer->SetAudioFocus(&p1));
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerSetAudioFocus_2) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockPlayer p1, p2;
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  MixerTicket* ticket2 = mixer->CreateTicket(&p2);
+
+  ticket->RegisterListener(p1.listener_);
+  ticket2->RegisterListener(p2.listener_);
+
+  EXPECT_TRUE(mixer->SetAudioFocus(&p2));
+
+  delete ticket;
+  delete ticket2;
+
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerSetAudioFocus_3) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+       mixer->DisableAudioFocusSetting();
+  MixerMockPlayer p1;
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_FALSE(mixer->SetAudioFocus(&p1));
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerSetDisplay) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  EXPECT_TRUE(mixer->SetDisplay(DisplayType::kOverlay,
+                                Utility::Instance().GetWindow()));
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerCommit) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockPlayer p1(1, 1, 1, 1);
+  MixerMockPlayer p2(2, 2, 2, 2);
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  MixerTicket* ticket2 = mixer->CreateTicket(&p2);
+
+  ticket->RegisterListener(p1.listener_);
+  ticket2->RegisterListener(p2.listener_);
+
+  EXPECT_TRUE(mixer->Commit());
+
+  delete ticket;
+  delete ticket2;
+
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerSetDisplayRoi) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockPlayer p1;
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+
+  ticket->RegisterListener(p1.listener_);
+  Geometry geometry;
+  geometry.x = 11;
+  geometry.y = 11;
+  geometry.w = 22;
+  geometry.h = 22;
+  EXPECT_TRUE(mixer->SetDisplayRoi(geometry));
+
+  delete ticket;
+
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerSetDisplayMode) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockPlayer p1;
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_TRUE(mixer->SetDisplayMode(DisplayMode::kDstRoi));
+
+  delete ticket;
+
+  mixer.reset();
+}
+
+TEST(MixerTest, MixerRegisterListener) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerMockListener* listener = new MixerMockListener;
+  EXPECT_TRUE(mixer->RegisterListener(listener));
+  mixer.reset();
+  delete listener;
+}
+
+TEST(MixerTest, MixerStart) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  EXPECT_TRUE(mixer->SetDisplay(DisplayType::kOverlay,
+                                Utility::Instance().GetWindow()));
+  Geometry geometry;
+  geometry.x = 0;
+  geometry.y = 0;
+  geometry.w = 1920;
+  geometry.h = 1080;
+  EXPECT_TRUE(mixer->SetDisplayRoi(geometry));
+  MixerMockListener* listener = new MixerMockListener;
+  EXPECT_TRUE(mixer->RegisterListener(listener));
+  EXPECT_TRUE(mixer->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  EXPECT_TRUE(mixer->Stop());
+  mixer.reset();
+  delete listener;
+}
+
+TEST(MixerTest, MixerSetAlternativeVideoScaler) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+       EXPECT_TRUE(mixer->SetAlternativeVideoScaler());
+  EXPECT_TRUE(mixer->SetDisplay(DisplayType::kOverlay,
+                                Utility::Instance().GetWindow()));
+  Geometry geometry;
+  geometry.x = 0;
+  geometry.y = 0;
+  geometry.w = 1920;
+  geometry.h = 1080;
+  EXPECT_TRUE(mixer->SetDisplayRoi(geometry));
+  MixerMockListener* listener = new MixerMockListener;
+  EXPECT_TRUE(mixer->RegisterListener(listener));
+  EXPECT_TRUE(mixer->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  EXPECT_TRUE(mixer->Stop());
+  mixer.reset();
+  delete listener;
+}
\ No newline at end of file
diff --git a/ut/src/mixer/ut_mixer_capi.cpp b/ut/src/mixer/ut_mixer_capi.cpp
new file mode 100755 (executable)
index 0000000..663a36a
--- /dev/null
@@ -0,0 +1,227 @@
+
+
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include <gtest/gtest.h>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer_capi/mixer_capi.h"
+#include "ut/include/appwindow.h"
+#include "ut/include/plusplayer/utility.h"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+using namespace utils;
+
+class CMixerMockPlayer {
+ public:
+  CMixerMockPlayer() { listener_ = new MyTicketListener(this); }
+  CMixerMockPlayer(int x, int y, int w, int h) {
+    listener_ = new MyTicketListener(this);
+    display_info_.geometry.x = x;
+    display_info_.geometry.y = y;
+    display_info_.geometry.w = w;
+    display_info_.geometry.h = h;
+  }
+  ~CMixerMockPlayer() { delete listener_; }
+
+  class MyTicketListener : public MixerTicketEventListener {
+   public:
+    explicit MyTicketListener(CMixerMockPlayer* handler) : handler_(handler){};
+    bool OnAudioFocusChanged(bool active) {
+      LOG_INFO("My OnAudioFocusChanged [%d] player [%p]", active, handler_);
+      return true;
+    }
+
+    bool OnUpdateDisplayInfo(const DisplayInfo& cur_info,
+                             DisplayInfo* new_info) {
+      *new_info = handler_->display_info_;
+      LOG_INFO("OnUpdateDisplayInfo x[%d] y[%d]",
+               handler_->display_info_.geometry.x,
+               handler_->display_info_.geometry.y);
+      return true;
+    }
+    CMixerMockPlayer* handler_ = nullptr;
+  };
+
+ public:
+  MixerTicketEventListener* listener_ = nullptr;
+  DisplayInfo display_info_;
+};
+
+TEST(CMixerTest, vdapi_mixer_create_p_1) {
+  mixer_handle mixer = mixer_create();
+  ASSERT_NE(mixer, nullptr);
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_create_ticket_p_1) {
+  CMixerMockPlayer p1;
+  mixer_handle mixer = mixer_create();
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+  ASSERT_NE(ticket, nullptr);
+  delete ticket;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_rsc_alloc_mode_p_1) {
+  mixer_handle mixer = mixer_create();
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_NONE);
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_rsc_alloc_mode_n_1) {
+  mixer_handle mixer = mixer_create();
+  CMixerMockPlayer p1;
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_INVALID_OPERATION);
+  delete ticket;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_disable_audio_focus_setting_p_1) {
+  mixer_handle mixer = mixer_create();
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer), MIXER_ERROR_TYPE_NONE);
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_disable_audio_focus_setting_n_1) {
+  mixer_handle mixer = mixer_create();
+  CMixerMockPlayer p1;
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer),
+            MIXER_ERROR_TYPE_INVALID_OPERATION);
+  delete ticket;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_audio_focus_p_1) {
+  mixer_handle mixer = mixer_create();
+  CMixerMockPlayer p1;
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_EQ(mixer_set_audio_focus(mixer, &p1), MIXER_ERROR_TYPE_NONE);
+  delete ticket;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_audio_focus_p_2) {
+  mixer_handle mixer = mixer_create();
+  CMixerMockPlayer p1, p2;
+
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+  MixerTicket* ticket2 = (MixerTicket*)mixer_create_ticket(mixer, &p2);
+
+  ticket->RegisterListener(p1.listener_);
+  ticket2->RegisterListener(p2.listener_);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer, &p2), MIXER_ERROR_TYPE_NONE);
+
+  delete ticket;
+  delete ticket2;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_audio_focus_n_2) {
+  mixer_handle mixer = mixer_create();
+  mixer_disable_audio_focus_setting(mixer);
+  CMixerMockPlayer p1;
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_EQ(mixer_set_audio_focus(mixer, &p1),
+            MIXER_ERROR_TYPE_INVALID_OPERATION);
+  delete ticket;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_display_p_1) {
+  mixer_handle mixer = mixer_create();
+  EXPECT_EQ(mixer_set_display(mixer, MIXER_DISPLAY_TYPE_OVERLAY,
+                              Utility::Instance().GetWindow()),
+            MIXER_ERROR_TYPE_NONE);
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_commit_p_1) {
+  mixer_handle mixer = mixer_create();
+  CMixerMockPlayer p1(1, 1, 1, 1);
+  CMixerMockPlayer p2(2, 2, 2, 2);
+
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+  MixerTicket* ticket2 = (MixerTicket*)mixer_create_ticket(mixer, &p2);
+
+  ticket->RegisterListener(p1.listener_);
+  ticket2->RegisterListener(p2.listener_);
+
+  EXPECT_EQ(mixer_commit(mixer), MIXER_ERROR_TYPE_NONE);
+
+  delete ticket;
+  delete ticket2;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_display_roi_p_1) {
+  mixer_handle mixer = mixer_create();
+  CMixerMockPlayer p1;
+
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_EQ(mixer_set_display_roi(mixer, 11, 11, 22, 22),
+            MIXER_ERROR_TYPE_NONE);
+
+  delete ticket;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_display_mode_p_1) {
+  mixer_handle mixer = mixer_create();
+  CMixerMockPlayer p1;
+
+  MixerTicket* ticket = (MixerTicket*)mixer_create_ticket(mixer, &p1);
+
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_EQ(mixer_set_display_mode(mixer, MIXER_DISPLAY_MODE_DST_ROI),
+            MIXER_ERROR_TYPE_NONE);
+
+  delete ticket;
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_start_p_1) {
+  mixer_handle mixer = mixer_create();
+  mixer_set_display(mixer, MIXER_DISPLAY_TYPE_OVERLAY,
+                    Utility::Instance().GetWindow());
+  mixer_set_display_roi(mixer, 0, 0, 1920, 1080);
+  EXPECT_EQ(mixer_start(mixer), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  EXPECT_EQ(mixer_stop(mixer), MIXER_ERROR_TYPE_NONE);
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_alternative_video_scaler_p_1) {
+  mixer_handle mixer = mixer_create();
+  EXPECT_EQ(mixer_set_alternative_video_scaler(mixer), MIXER_ERROR_TYPE_NONE);
+  mixer_set_display(mixer, MIXER_DISPLAY_TYPE_OVERLAY,
+                    Utility::Instance().GetWindow());
+  mixer_set_display_roi(mixer, 0, 0, 1920, 1080);
+
+  EXPECT_EQ(mixer_start(mixer), MIXER_ERROR_TYPE_NONE);
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  EXPECT_EQ(mixer_stop(mixer), MIXER_ERROR_TYPE_NONE);
+  mixer_destroy(mixer);
+}
+
+TEST(CMixerTest, vdapi_mixer_set_on_resource_conflict_cb_p_1) {
+  mixer_handle mixer = mixer_create();
+  EXPECT_EQ(mixer_set_resource_conflicted_cb(mixer, nullptr, nullptr),
+            MIXER_ERROR_TYPE_NONE);
+  mixer_destroy(mixer);
+}
+
diff --git a/ut/src/mixer/ut_mixer_espp_capi.cpp b/ut/src/mixer/ut_mixer_espp_capi.cpp
new file mode 100755 (executable)
index 0000000..244b025
--- /dev/null
@@ -0,0 +1,351 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include <gtest/gtest.h>
+
+#include "esplusplayer_capi/esplusplayer_capi.h"
+#include "mixer_capi/mixer_capi.h"
+#include "ut/include/plusplayer/utility.h"
+#include "ut/include/streamreader.hpp"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+using namespace utils;
+using namespace std;
+
+using utils::Utility;
+std::string uri_1 = "youtube/";
+std::string uri_2 = "bunny/";
+
+// max playing duration : 10 sec => see EsStreamReader::ReadNextPacket()
+constexpr int kEsPlayingTime = 1;  // (sec)
+
+class CMixerEsppTestF : public ::testing::Test {
+ public:
+  explicit CMixerEsppTestF(void)
+      : util_(Utility::Instance()),
+        mixer_(nullptr),
+        player1_(nullptr),
+        player2_(nullptr),
+        player3_(nullptr),
+        player4_(nullptr){};
+  ~CMixerEsppTestF(void){};
+
+  static void SetUpTestCase() {
+    ESPacketDownloader::Init();
+    std::cout << "SetUpTestCase()" << std::endl;
+  }
+
+  static void TearDownTestCase() {}
+
+  virtual void SetUp(void) override {
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+    mixer_ = mixer_create();
+    mixer_set_display(mixer_, MIXER_DISPLAY_TYPE_OVERLAY, util_.GetWindow());
+
+    roi1_.x = 20;
+    roi1_.y = 20;
+    roi1_.w = 960;
+    roi1_.h = 540;
+
+    roi2_.x = 1000;
+    roi2_.y = 20;
+    roi2_.w = 720;
+    roi2_.h = 480;
+
+    roi3_.x = 20;
+    roi3_.y = 520;
+    roi3_.w = 720;
+    roi3_.h = 480;
+
+    roi4_.x = 1000;
+    roi4_.y = 520;
+    roi4_.w = 720;
+    roi4_.h = 480;
+  }
+
+  virtual void TearDown(void) override {
+    util_.DestroyESPP(player1_);
+    util_.DestroyESPP(player2_);
+    util_.DestroyESPP(player3_);
+    util_.DestroyESPP(player4_);
+    mixer_destroy(mixer_);
+    player1_ = nullptr;
+    player2_ = nullptr;
+    player3_ = nullptr;
+    player4_ = nullptr;
+    mixer_ = nullptr;
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+  }
+
+ public:
+  Utility& util_;
+  mixer_handle mixer_;
+  esplusplayer_handle player1_;
+  esplusplayer_handle player2_;
+  esplusplayer_handle player3_;
+  esplusplayer_handle player4_;
+  Geometry roi1_;
+  Geometry roi2_;
+  Geometry roi3_;
+  Geometry roi4_;
+};
+
+TEST(CMixerEsppTest, vdapi_mixer_create_destroy_p_1) {
+  mixer_handle mixer = mixer_create();
+  ASSERT_NE(mixer, nullptr);
+  EXPECT_EQ(mixer_destroy(mixer), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_start_stop_p_1) {
+  player1_ = util_.GetPreparedMixESPP(uri_2, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetPreparedMixESPP(uri_2, mixer_, roi2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_EQ(esplusplayer_start(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_start(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(mixer_start(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kEsPlayingTime));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player2_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_get_max_allowed_number_of_player_p_1) {
+  int max_num = mixer_get_max_allowed_number_of_player(mixer_);
+  constexpr int MAX_NUM = 3;
+  EXPECT_EQ(MAX_NUM, max_num);
+}
+
+TEST(CMixerEsppTest, vdapi_mixer_set_display_p_1) {
+  mixer_handle mixer = mixer_create();
+  ASSERT_NE(mixer, nullptr);
+  Utility& util = Utility::Instance();
+  EXPECT_EQ(
+      mixer_set_display(mixer, MIXER_DISPLAY_TYPE_OVERLAY, util.GetWindow()),
+      MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_destroy(mixer), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_display_mode_p_1) {
+  EXPECT_EQ(mixer_set_display_mode(mixer_, MIXER_DISPLAY_MODE_DST_ROI),
+            MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_display_roi_p_1) {
+  EXPECT_EQ(mixer_set_display_mode(mixer_, MIXER_DISPLAY_MODE_DST_ROI),
+            MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_set_display_roi(mixer_, 0, 0, 1920, 1080),
+            MIXER_ERROR_TYPE_NONE);
+  
+  player1_ = util_.GetStartedMixESPP(uri_2, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  mixer_start(mixer_);
+  std::this_thread::sleep_for(std::chrono::seconds(kEsPlayingTime));
+  
+  EXPECT_EQ(mixer_set_display_roi(mixer_, roi2_.x, roi2_.y, roi2_.w, roi2_.h),
+            MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kEsPlayingTime));
+
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_rsc_alloc_mode_p_1) {
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_NONE);
+  mixer_stop(mixer_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_rsc_alloc_mode_n_1) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_INVALID_OPERATION);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_set_video_codec_type_p_1) {
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_NONE);
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_set_video_codec_type(
+                player1_, ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW_N_DECODING),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_set_video_codec_type_p_2) {
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_NONE);
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_set_video_codec_type(player1_,
+                                              ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_set_video_codec_type_n_1) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_set_video_codec_type(
+                player1_, ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW_N_DECODING),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_set_video_codec_type_n_2) {
+  player1_ = util_.GetOpenedESPP(roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_set_video_codec_type(
+                player1_, ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW_N_DECODING),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_set_video_codec_type_n_3) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_set_video_codec_type(player1_,
+                                              ESPLUSPLAYER_VIDEO_CODEC_TYPE_HW),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_esplusplayer_set_alternative_video_resource_p_1) {
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DISABLE),
+            MIXER_ERROR_TYPE_NONE);
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_set_alternative_video_resource(player1_, 0),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_set_alternative_video_resource_n_1) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_set_alternative_video_resource(player1_, 0),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_set_alternative_video_resource_n_2) {
+  EXPECT_EQ(mixer_set_rsc_alloc_mode(mixer_, MIXER_RSC_ALLOC_MODE_DEFAULT),
+            MIXER_ERROR_TYPE_NONE);
+  player1_ = util_.GetPreparedMixESPP(uri_2, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  EXPECT_EQ(esplusplayer_deactivate(player1_, ESPLUSPLAYER_STREAM_TYPE_VIDEO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_alternative_video_resource(player1_, 0),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_disable_audio_focus_setting_p_1) {
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_disable_audio_focus_setting_p_2) {
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer_), MIXER_ERROR_TYPE_NONE);
+  player1_ = util_.GetPreparedMixESPP(uri_2, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  mixer_start(mixer_);
+
+  EXPECT_EQ(esplusplayer_deactivate(player1_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            MIXER_ERROR_TYPE_NONE);
+
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_disable_audio_focus_setting_n_1) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer_),
+            MIXER_ERROR_TYPE_INVALID_OPERATION);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_deactivate_p_1) {
+  EXPECT_EQ(mixer_disable_audio_focus_setting(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  player1_ = util_.GetPreparedMixESPP(uri_2, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_deactivate(player1_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_esplusplayer_deactivate_n_1) {
+  player1_ = util_.GetPreparedMixESPP(uri_2, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_EQ(esplusplayer_deactivate(player1_, ESPLUSPLAYER_STREAM_TYPE_AUDIO),
+            ESPLUSPLAYER_ERROR_TYPE_INVALID_OPERATION);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_alternative_video_scaler_p_1) {
+  EXPECT_EQ(mixer_set_alternative_video_scaler(mixer_),
+            MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_audio_focus_p_1) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+
+  EXPECT_EQ(mixer_set_audio_focus(mixer_, player1_), MIXER_ERROR_TYPE_NONE);
+
+  EXPECT_EQ(esplusplayer_close(player1_), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(mixer_stop(mixer_), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_commit_p_1) {
+  player1_ = util_.GetStartedMixESPP(uri_2, mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);
+  mixer_start(mixer_);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kEsPlayingTime));
+
+  esplusplayer_set_display_roi(player1_, roi3_.x, roi3_.y, roi3_.w, roi3_.h);
+  EXPECT_EQ(mixer_commit(mixer_), MIXER_ERROR_TYPE_NONE);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kEsPlayingTime));
+
+  mixer_stop(mixer_);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_resolution_p_1) {
+  EXPECT_EQ(mixer_set_resolution(mixer_, 1920, 1080, 30, 1), MIXER_ERROR_TYPE_NONE);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_create_ticket_p_1) {
+  player1_ = util_.GetOpenedMixESPP(mixer_, roi1_);
+  ASSERT_NE(player1_, nullptr);        
+  void* ticket = mixer_create_ticket(mixer_, player1_);
+  ASSERT_NE(ticket, nullptr);
+  esplusplayer_close(player1_);
+}
+
+TEST_F(CMixerEsppTestF, vdapi_mixer_set_resource_conflicted_cb_p_1) {
+  EXPECT_EQ(mixer_set_resource_conflicted_cb(mixer_, nullptr, nullptr),
+            MIXER_ERROR_TYPE_NONE);
+}
+
diff --git a/ut/src/mixer/ut_mixerscenario.cpp b/ut/src/mixer/ut_mixerscenario.cpp
new file mode 100755 (executable)
index 0000000..9be8e0f
--- /dev/null
@@ -0,0 +1,628 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include <gtest/gtest.h>
+
+#include <iostream>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/mixer.h"
+#include "mixer/mixer_eventlistener.h"
+#include "mixer/mixerticket.h"
+#include "mixer/mixerticket_eventlistener.h"
+#include "ut/include/plusplayer/utility.h"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+using namespace utils;
+using namespace std;
+
+using utils::Utility;
+std::string dashuri =
+    "";
+std::string httpuri = "";
+std::string hlsuri = "";
+std::string fhd1 =
+    "";
+std::string fhd2 =
+    "";
+std::string fhd3 =
+    "";
+constexpr int kPlayingTime = 5;  // sec
+
+//------------------------------------------------------------
+class MixerScenarioTestF : public ::testing::Test {
+ public:
+  explicit MixerScenarioTestF(void)
+      : util_(Utility::Instance()),
+        mixer_(nullptr),
+        player1_(nullptr),
+        player2_(nullptr),
+        player3_(nullptr){};
+  ~MixerScenarioTestF(void){};
+
+  virtual void SetUp(void) override {
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+    mixer_ = Mixer::Create();
+    mixer_->SetDisplay(DisplayType::kOverlay, util_.GetWindow());
+#if 1
+    geometry1_.x = 20;
+    geometry1_.y = 20;
+    geometry1_.w = 960;
+    geometry1_.h = 540;
+
+    geometry2_.x = 1000;
+    geometry2_.y = 20;
+    geometry2_.w = 720;
+    geometry2_.h = 480;
+
+    geometry3_.x = 20;
+    geometry3_.y = 520;
+    geometry3_.w = 720;
+    geometry3_.h = 480;
+
+    geometry4_.x = 1000;
+    geometry4_.y = 520;
+    geometry4_.w = 720;
+    geometry4_.h = 480;
+#else
+    geometry1_.x = 20;
+    geometry1_.y = 20;
+    geometry1_.w = 1180;
+    geometry1_.h = 720;
+
+    geometry2_.x = 1220;
+    geometry2_.y = 20;
+    geometry2_.w = 640;
+    geometry2_.h = 480;
+
+    geometry3_.x = 1220;
+    geometry3_.y = 520;
+    geometry3_.w = 640;
+    geometry3_.h = 480;
+#endif
+  }
+
+  virtual void TearDown(void) override {
+    util_.DestroyPlayer(player1_);
+    util_.DestroyPlayer(player2_);
+    util_.DestroyPlayer(player3_);
+    mixer_.reset();
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+  }
+
+ public:
+  Utility& util_;
+  std::unique_ptr<Mixer> mixer_;
+  PlusPlayer::Ptr player1_;
+  PlusPlayer::Ptr player2_;
+  PlusPlayer::Ptr player3_;
+  PlusPlayer::Ptr player4_;
+  Geometry geometry1_;
+  Geometry geometry2_;
+  Geometry geometry3_;
+  Geometry geometry4_;
+};
+
+#if 0  // prepare async test
+TEST(MixerScenarioTest, OnePlayer) {
+  AppWindow appwin(0, 0, 1920, 1080);
+  // create player1
+  auto player1 = plusplayer::PlusPlayer::Create();
+
+  shared_ptr<FakeUserData> user_data = std::make_shared<FakeUserData>();
+  shared_ptr<PlusPlayerMockEventListener> mock_eventlistener =
+      std::make_shared<PlusPlayerMockEventListener>();
+  shared_ptr<PlusPlayerFakeEventListener> fake_eventlistener =
+      std::make_shared<PlusPlayerFakeEventListener>();
+  mock_eventlistener->Bind(
+      std::dynamic_pointer_cast<EventListener>(fake_eventlistener));
+
+  ASSERT_NE(player1, nullptr);
+  EXPECT_TRUE(player1->Open(hlsuri.c_str()));
+  player1->RegisterListener(mock_eventlistener.get(), (void*)user_data.get());
+  // set mixer mode
+  EXPECT_TRUE(
+      player1->SetDisplay(DisplayType::kOverlay, appwin.GetWindow().obj));
+  Geometry geometry1;
+  geometry1.x = 0;
+  geometry1.y = 0;
+  geometry1.w = 1920;
+  geometry1.h = 1080;
+  EXPECT_TRUE(player1->SetDisplayMode(DisplayMode::kDstRoi));
+  EXPECT_TRUE(player1->SetDisplayRoi(geometry1));
+  EXPECT_TRUE(player1->PrepareAsync());
+  ASSERT_EQ(
+      user_data->onPrepareDone
+          .WaitForChange(PrepareStatus::kSuccess, DEFAULT_TIMEOUT_FOR_PREPARING)
+          .get(),
+      WatcherStatus::kSuccess);
+  EXPECT_TRUE(player1->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+  EXPECT_TRUE(player1->Stop());
+  EXPECT_TRUE(player1->Close());
+  player1.reset();
+}
+
+TEST(MixerScenarioTest, Basic) {
+  shared_ptr<FakeUserData> user_data1 = std::make_shared<FakeUserData>();
+  shared_ptr<PlusPlayerMockEventListener> mock_eventlistener1 =
+      std::make_shared<PlusPlayerMockEventListener>();
+  shared_ptr<PlusPlayerFakeEventListener> fake_eventlistener1 =
+      std::make_shared<PlusPlayerFakeEventListener>();
+  mock_eventlistener1->Bind(
+      std::dynamic_pointer_cast<EventListener>(fake_eventlistener1));
+
+  shared_ptr<FakeUserData> user_data2 = std::make_shared<FakeUserData>();
+  shared_ptr<PlusPlayerMockEventListener> mock_eventlistener2 =
+      std::make_shared<PlusPlayerMockEventListener>();
+  shared_ptr<PlusPlayerFakeEventListener> fake_eventlistener2 =
+      std::make_shared<PlusPlayerFakeEventListener>();
+  mock_eventlistener2->Bind(
+      std::dynamic_pointer_cast<EventListener>(fake_eventlistener2));
+
+  shared_ptr<FakeUserData> user_data3 = std::make_shared<FakeUserData>();
+  shared_ptr<PlusPlayerMockEventListener> mock_eventlistener3 =
+      std::make_shared<PlusPlayerMockEventListener>();
+  shared_ptr<PlusPlayerFakeEventListener> fake_eventlistener3 =
+      std::make_shared<PlusPlayerFakeEventListener>();
+  mock_eventlistener3->Bind(
+      std::dynamic_pointer_cast<EventListener>(fake_eventlistener3));
+
+  AppWindow appwin(0, 0, 1920, 1080);
+
+  // create mixer
+  auto mixer = Mixer::Create();
+  ASSERT_NE(mixer, nullptr);
+  EXPECT_TRUE(mixer->SetDisplay(DisplayType::kOverlay, appwin.GetWindow().obj));
+
+  // create player1
+  auto player1 = plusplayer::PlusPlayer::Create();
+  ASSERT_NE(player1, nullptr);
+  EXPECT_TRUE(player1->Open(hlsuri.c_str()));
+  player1->RegisterListener(mock_eventlistener1.get(), (void*)user_data1.get());
+  // set mixer mode
+  EXPECT_TRUE(player1->SetDisplay(DisplayType::kMixer, mixer.get()));
+  Geometry geometry1;
+  geometry1.x = 20;
+  geometry1.y = 20;
+  geometry1.w = 1180;
+  geometry1.h = 720;
+  EXPECT_TRUE(player1->SetDisplayRoi(geometry1));
+  // set audio focus
+  EXPECT_TRUE(mixer->SetAudioFocus(player1.get()));
+  EXPECT_TRUE(player1->PrepareAsync());
+
+  // create player2
+  auto player2 = plusplayer::PlusPlayer::Create();
+  EXPECT_NE(player2, nullptr);
+  EXPECT_TRUE(player2->Open(hlsuri.c_str()));
+  player2->RegisterListener(mock_eventlistener2.get(), (void*)user_data2.get());
+  // set mixer mode
+  EXPECT_TRUE(player2->SetDisplay(DisplayType::kMixer, mixer.get()));
+  Geometry geometry2;
+  geometry2.x = 1220;
+  geometry2.y = 20;
+  geometry2.w = 640;
+  geometry2.h = 480;
+  EXPECT_TRUE(player2->SetDisplayRoi(geometry2));
+  EXPECT_TRUE(player2->PrepareAsync());
+
+  // create player3
+  auto player3 = plusplayer::PlusPlayer::Create();
+  EXPECT_NE(player3, nullptr);
+  EXPECT_TRUE(player3->Open(hlsuri.c_str()));
+  player3->RegisterListener(mock_eventlistener3.get(), (void*)user_data3.get());
+  // set mixer mode
+  EXPECT_TRUE(player3->SetDisplay(DisplayType::kMixer, mixer.get()));
+  Geometry geometry3;
+  geometry3.x = 1220;
+  geometry3.y = 520;
+  geometry3.w = 640;
+  geometry3.h = 480;
+  EXPECT_TRUE(player3->SetDisplayRoi(geometry3));
+  EXPECT_TRUE(player3->PrepareAsync());
+
+  ASSERT_EQ(
+      user_data1->onPrepareDone
+          .WaitForChange(PrepareStatus::kSuccess, DEFAULT_TIMEOUT_FOR_PREPARING)
+          .get(),
+      WatcherStatus::kSuccess);
+  
+  ASSERT_EQ(
+      user_data2->onPrepareDone
+          .WaitForChange(PrepareStatus::kSuccess, DEFAULT_TIMEOUT_FOR_PREPARING)
+          .get(),
+      WatcherStatus::kSuccess);
+
+  ASSERT_EQ(
+      user_data3->onPrepareDone
+          .WaitForChange(PrepareStatus::kSuccess, DEFAULT_TIMEOUT_FOR_PREPARING)
+          .get(),
+      WatcherStatus::kSuccess);
+
+  EXPECT_TRUE(player1->Start());
+  EXPECT_TRUE(player2->Start());
+  EXPECT_TRUE(player3->Start());
+
+  EXPECT_TRUE(mixer->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer->Stop());
+  EXPECT_TRUE(player1->Stop());
+  EXPECT_TRUE(player2->Stop());
+  EXPECT_TRUE(player3->Stop());
+
+  EXPECT_TRUE(player1->Close());
+  EXPECT_TRUE(player2->Close());
+  EXPECT_TRUE(player3->Close());
+
+  player1.reset();
+  player2.reset();
+  player3.reset();
+  mixer.reset();
+}
+#endif
+#if 0  // memory check TC
+class MixerScenarioMemTestF : public ::testing::Test {
+ public:
+  explicit MixerScenarioMemTestF(void) : util_(Utility::Instance()){};
+  ~MixerScenarioMemTestF(void){};
+
+  virtual void SetUp(void) override {
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+    geometry1_.x = 20;
+    geometry1_.y = 20;
+    geometry1_.w = 960;
+    geometry1_.h = 540;
+
+    geometry2_.x = 1000;
+    geometry2_.y = 20;
+    geometry2_.w = 720;
+    geometry2_.h = 480;
+
+    geometry3_.x = 1000;
+    geometry3_.y = 520;
+    geometry3_.w = 720;
+    geometry3_.h = 480;
+  }
+
+  virtual void TearDown(void) override {
+    LOG_ERROR("%s", util_.GetCurrentTestName());
+  }
+
+ public:
+  Utility& util_;
+  Geometry geometry1_;
+  Geometry geometry2_;
+  Geometry geometry3_;
+};
+
+TEST(MixerScenarioMemTestF, RealNothing) {
+  std::this_thread::sleep_for(std::chrono::seconds(20));
+}
+
+TEST_F(MixerScenarioMemTestF, OnlyWindow) {
+  std::this_thread::sleep_for(std::chrono::seconds(20));
+}
+
+TEST_F(MixerScenarioMemTestF, OnePlayer) {
+  // create player1
+  auto player1_ = util_.GetOpenedPlusPlayer(hlsuri);
+  ASSERT_NE(player1_, nullptr);
+  EXPECT_TRUE(player1_->Prepare());
+  EXPECT_TRUE(player1_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(40));
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player1_->Close());
+  player1_.reset();
+}
+
+TEST_F(MixerScenarioMemTestF, MixerThreePlayer) {
+  auto mixer_ = Mixer::Create();
+  mixer_->SetDisplay(DisplayType::kOverlay, util_.GetWindow());
+  auto player1_ =
+      util_.GetOpenedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+  auto player2_ =
+      util_.GetOpenedMixPlusPlayer(hlsuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+  auto player3_ =
+      util_.GetOpenedMixPlusPlayer(hlsuri, mixer_.get(), geometry3_);
+  ASSERT_NE(player3_, nullptr);
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player1_.get()));
+
+  EXPECT_TRUE(player1_->Prepare());
+  EXPECT_TRUE(player2_->Prepare());
+  EXPECT_TRUE(player3_->Prepare());
+
+  EXPECT_TRUE(player1_->Start());
+  EXPECT_TRUE(player2_->Start());
+  EXPECT_TRUE(player3_->Start());
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(40));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+  EXPECT_TRUE(player3_->Stop());
+
+  EXPECT_TRUE(player1_->Close());
+  EXPECT_TRUE(player2_->Close());
+  EXPECT_TRUE(player3_->Close());
+
+  player1_.reset();
+  player2_.reset();
+  player3_.reset();
+
+  mixer_.reset();
+}
+
+TEST_F(MixerScenarioMemTestF, MixerOnePlayer) {
+  auto mixer_ = Mixer::Create();
+  mixer_->SetDisplay(DisplayType::kOverlay, util_.GetWindow());
+  auto player1_ =
+      util_.GetOpenedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player1_.get()));
+
+  EXPECT_TRUE(player1_->Prepare());
+
+  EXPECT_TRUE(player1_->Start());
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(40));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player1_->Stop());
+
+  EXPECT_TRUE(player1_->Close());
+
+  player1_.reset();
+  mixer_.reset();
+}
+#endif
+
+#if 1  // normal mixer test
+TEST_F(MixerScenarioTestF, Basic) {
+  player1_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player1_.get()));
+
+  EXPECT_TRUE(player1_->Prepare());
+  EXPECT_TRUE(player2_->Prepare());
+
+  EXPECT_TRUE(player1_->Start());
+  EXPECT_TRUE(player2_->Start());
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, SinglePlay) {
+  player1_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player1_.get()));
+
+  EXPECT_TRUE(player1_->Prepare());
+
+  EXPECT_TRUE(player1_->Start());
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player1_->Stop());
+}
+
+#if 0 // n-decoding test ut : need to call n-decoding mode set api of player
+TEST_F(MixerScenarioTestF, MaxPlay) {
+  player1_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+  player3_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player3_, nullptr);
+  player4_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player4_, nullptr);
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player1_.get()));
+
+  EXPECT_TRUE(player1_->Prepare());
+  EXPECT_TRUE(player2_->Prepare());
+  EXPECT_TRUE(player3_->Prepare());
+  EXPECT_TRUE(player4_->Prepare());
+
+  EXPECT_TRUE(player1_->Start());
+  EXPECT_TRUE(player2_->Start());
+  EXPECT_TRUE(player3_->Start());
+  EXPECT_TRUE(player4_->Start());
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+  EXPECT_TRUE(player3_->Stop());
+  EXPECT_TRUE(player4_->Stop());
+}
+#endif
+
+TEST_F(MixerScenarioTestF, DetachAttach) {
+  player1_ = util_.GetStartedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetStartedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+  EXPECT_TRUE(player1_->Stop());
+
+  player3_ = util_.GetStartedMixPlusPlayer(dashuri, mixer_.get(), geometry3_);
+  ASSERT_NE(player3_, nullptr);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+  EXPECT_TRUE(player3_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, DetachAttach1) {
+  player1_ = util_.GetStartedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetStartedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+  EXPECT_TRUE(player1_->Stop());
+
+  player3_ = util_.GetStartedMixPlusPlayer(dashuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player3_, nullptr);
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+  EXPECT_TRUE(player3_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, SetROI) {
+  player1_ = util_.GetStartedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetStartedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(player1_->SetDisplayRoi(geometry2_));
+  EXPECT_TRUE(player2_->SetDisplayRoi(geometry1_));
+  EXPECT_TRUE(mixer_->Commit());
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, SetROI1) {
+  player1_ = util_.GetStartedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetStartedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->Start());
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(player1_->SetDisplayRoi(geometry2_));
+  EXPECT_TRUE(player2_->SetDisplayRoi(geometry3_));
+  EXPECT_TRUE(mixer_->Commit());
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->Stop());
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, CheckMaxMixedPlayer) {
+  player1_ = util_.GetOpenedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+  player2_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+  player3_ = util_.GetOpenedMixPlusPlayer(dashuri, mixer_.get(), geometry3_);
+  ASSERT_NE(player3_, nullptr);
+  auto player4 =
+      util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry3_);
+  ASSERT_NE(player4, nullptr);
+
+  EXPECT_TRUE(player1_->Prepare());
+  EXPECT_TRUE(player2_->Prepare());
+  EXPECT_TRUE(player3_->Prepare());
+
+  EXPECT_FALSE(player4->Prepare());
+
+  EXPECT_TRUE(player4->Close());
+  EXPECT_TRUE(mixer_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, SetAudioFocus) {
+  player1_ = util_.GetOpenedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetOpenedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player1_.get()));
+
+  EXPECT_TRUE(player1_->Prepare());
+  EXPECT_TRUE(player2_->Prepare());
+
+  EXPECT_TRUE(player1_->Start());
+  EXPECT_TRUE(player2_->Start());
+
+  EXPECT_TRUE(mixer_->Start());
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player2_.get()));
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(mixer_->SetAudioFocus(player1_.get()));
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+  EXPECT_TRUE(mixer_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, SetAudioFocus1) {
+  player1_ = util_.GetStartedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+
+  player2_ = util_.GetStartedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->Start());
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+  EXPECT_TRUE(mixer_->Stop());
+}
+
+TEST_F(MixerScenarioTestF, SetAudioFocus2) {
+  player1_ = util_.GetStartedMixPlusPlayer(hlsuri, mixer_.get(), geometry1_);
+  ASSERT_NE(player1_, nullptr);
+
+  EXPECT_FALSE(mixer_->SetAudioFocus(nullptr));
+  player2_ = util_.GetStartedMixPlusPlayer(httpuri, mixer_.get(), geometry2_);
+  ASSERT_NE(player2_, nullptr);
+
+  EXPECT_TRUE(mixer_->Start());
+
+  std::this_thread::sleep_for(std::chrono::seconds(kPlayingTime));
+
+  EXPECT_TRUE(player1_->Stop());
+  EXPECT_TRUE(player2_->Stop());
+  EXPECT_TRUE(mixer_->Stop());
+}
+#endif
\ No newline at end of file
diff --git a/ut/src/mixer/ut_mixerticket.cpp b/ut/src/mixer/ut_mixerticket.cpp
new file mode 100755 (executable)
index 0000000..440135d
--- /dev/null
@@ -0,0 +1,231 @@
+//
+// @ Copyright [2020] <S/W Platform, Visual Display, Samsung Electronics>
+//
+#include <gtest/gtest.h>
+
+#include "core/utils/plusplayer_log.h"
+#include "mixer/mixer.h"
+#include "mixer/mixer_eventlistener.h"
+#include "mixer/mixerticket.h"
+#include "mixer/mixerticket_eventlistener.h"
+#include "ut/include/appwindow.h"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+
+class MixerTicketMockPlayer {
+ public:
+  MixerTicketMockPlayer() { listener_ = new MyTicketListener(this); }
+  MixerTicketMockPlayer(int x, int y, int w, int h) {
+    listener_ = new MyTicketListener(this);
+    display_info_.geometry.x = x;
+    display_info_.geometry.y = y;
+    display_info_.geometry.w = w;
+    display_info_.geometry.h = h;
+  }
+  ~MixerTicketMockPlayer() { delete listener_; }
+
+  class MyTicketListener : public MixerTicketEventListener {
+   public:
+    explicit MyTicketListener(MixerTicketMockPlayer* handler)
+        : handler_(handler){};
+    bool OnAudioFocusChanged(bool active) {
+      LOG_INFO("My OnAudioFocusChanged [%d] player [%p]", active, handler_);
+      return true;
+    }
+
+    bool OnUpdateDisplayInfo(const DisplayInfo& cur_info,
+                             DisplayInfo* new_info) {
+      *new_info = handler_->display_info_;
+      LOG_INFO("OnUpdateDisplayInfo x[%d] y[%d]",
+               handler_->display_info_.geometry.x,
+               handler_->display_info_.geometry.y);
+      return true;
+    }
+    MixerTicketMockPlayer* handler_ = nullptr;
+  };
+
+ public:
+  MixerTicketEventListener* listener_ = nullptr;
+  DisplayInfo display_info_;
+};
+
+class MyMixerListener : public MixerEventListener {
+ public:
+  MyMixerListener() {}
+  ~MyMixerListener() {}
+  void OnError() {
+    LOG_INFO(" listener [%p]", this);
+  }
+  void OnResourceConflicted() {
+    LOG_INFO("MyOnResourceConflicted listener[%p]", this);
+  }
+};
+
+TEST(MixerticketTest, MixerTicketRenderBasic) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1, p2;
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  MixerTicket* ticket2 = mixer->CreateTicket(&p2);
+  // EXPECT_TRUE(ticket->Render());
+  // EXPECT_TRUE(ticket2->Render());
+  delete ticket;
+  delete ticket2;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTicketRegisterListener) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  EXPECT_TRUE(ticket->RegisterListener(p1.listener_));
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTicketPrepare) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+  EXPECT_TRUE(ticket->Prepare());
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketGetAvailableResourceType_1) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+
+  ticket->RegisterListener(p1.listener_);
+  ResourceType type;
+  EXPECT_TRUE(
+      ticket->GetAvailableResourceType(ResourceCategory::kVideoDecoder, &type));
+
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketGetAvailableResourceType_2) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+
+  mixer->SetRscAllocMode(RscAllocMode::kDisable);
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+
+  ticket->RegisterListener(p1.listener_);
+  ResourceType type;
+  EXPECT_FALSE(
+      ticket->GetAvailableResourceType(ResourceCategory::kVideoDecoder, &type));
+
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketAlloc) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+
+  ticket->RegisterListener(p1.listener_);
+  ResourceType type;
+  EXPECT_TRUE(
+      ticket->GetAvailableResourceType(ResourceCategory::kVideoDecoder, &type));
+  EXPECT_TRUE(ticket->Alloc(ResourceCategory::kVideoDecoder, type));
+
+  EXPECT_TRUE(
+      ticket->GetAvailableResourceType(ResourceCategory::kVideoDecoder, &type));
+  EXPECT_TRUE(ticket->Alloc(ResourceCategory::kVideoDecoder, type));
+
+  EXPECT_TRUE(
+      ticket->GetAvailableResourceType(ResourceCategory::kVideoDecoder, &type));
+  EXPECT_TRUE(ticket->Alloc(ResourceCategory::kVideoDecoder, type));
+
+  EXPECT_FALSE(
+      ticket->GetAvailableResourceType(ResourceCategory::kVideoDecoder, &type));
+  EXPECT_FALSE(ticket->Alloc(ResourceCategory::kVideoDecoder, type));
+
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketDeallocResource) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1, p2, p3;
+
+  MixerTicket* ticket1 = mixer->CreateTicket(&p1);
+
+  ResourceType type;
+  EXPECT_TRUE(ticket1->GetAvailableResourceType(ResourceCategory::kVideoDecoder,
+                                                &type));
+  EXPECT_TRUE(ticket1->Alloc(ResourceCategory::kVideoDecoder, type));
+
+  delete ticket1;
+
+  MixerTicket* ticket2 = mixer->CreateTicket(&p2);
+  EXPECT_TRUE(ticket2->GetAvailableResourceType(ResourceCategory::kVideoDecoder,
+                                                &type));
+  EXPECT_TRUE(ticket2->Alloc(ResourceCategory::kVideoDecoder, type));
+
+  MixerTicket* ticket3 = mixer->CreateTicket(&p3);
+  EXPECT_TRUE(ticket3->GetAvailableResourceType(ResourceCategory::kVideoDecoder,
+                                                &type));
+  EXPECT_TRUE(ticket3->Alloc(ResourceCategory::kVideoDecoder, type));
+
+  delete ticket2;
+  delete ticket3;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketIsAudioFocusHandler_1) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+
+  mixer->DisableAudioFocusSetting();
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+
+  EXPECT_FALSE(ticket->IsAudioFocusHandler());
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketIsAudioFocusHandler_2) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+
+  EXPECT_TRUE(ticket->IsAudioFocusHandler());
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketIsRscAllocHandler_1) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+
+  mixer->SetRscAllocMode(RscAllocMode::kDisable);
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+
+  EXPECT_FALSE(ticket->IsRscAllocHandler());
+  delete ticket;
+  mixer.reset();
+}
+
+TEST(MixerticketTest, MixerTiecketIsRscAllocHandler_2) {
+  std::unique_ptr<Mixer> mixer = Mixer::Create();
+  MixerTicketMockPlayer p1;
+
+  MixerTicket* ticket = mixer->CreateTicket(&p1);
+  ticket->RegisterListener(p1.listener_);
+
+  EXPECT_TRUE(ticket->IsRscAllocHandler());
+  delete ticket;
+  mixer.reset();
+}
\ No newline at end of file
diff --git a/ut/src/mixer/ut_renderer.cpp b/ut/src/mixer/ut_renderer.cpp
new file mode 100755 (executable)
index 0000000..95cd291
--- /dev/null
@@ -0,0 +1,361 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "mixer/constant.h"
+#include "mixer/matcher.h"
+#include "mixer/mock/mock_memallocator.h"
+#include "mixer/mock/mock_renderableobj.h"
+#include "mixer/mock/mock_renderableobj_factory.h"
+#include "mixer/mock/mock_renderer_evtlistener.h"
+#include "mixer/mock/mock_vpcollection.h"
+#include "mixer/mock/mock_vpmanipulator.h"
+#include "mixer/mock/mock_vpscaler.h"
+#include "mixer/renderer.h"
+
+using namespace plusplayer;
+using namespace plusplayer_ut;
+
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::AtLeast;
+using ::testing::DoAll;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::Return;
+using ::testing::ReturnPointee;
+using ::testing::SetArgReferee;
+using ::testing::SizeIs;
+
+/********************************************************************************************
+ * InvalidRendererTest
+ */
+class InvalidRendererTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    ON_CALL(GetRenderableObjectFactory(), CreateRenderableObject(_, _))
+        .WillByDefault(Return(nullptr));
+
+    EXPECT_CALL(GetRenderableObjectFactory(),
+                CreateRenderableObject(kInvalidWidth, kInvalidHeight));
+
+    renderer_ = std::unique_ptr<Renderer>(new Renderer(
+        GetRenderableObjectFactory(),
+        GetResolutionInfo(kInvalidWidth, kInvalidHeight, kInvalidFramerateNum,
+                          kInvalidFramerateDen),
+        nullptr));
+
+    ASSERT_FALSE(renderer_->IsValid());
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  Renderer& GetRenderer() { return *renderer_; }
+
+  const MockRenderableObjectFactory& GetRenderableObjectFactory() const {
+    return mock_mixed_frame_factory_;
+  }
+  const MockVideoPlaneScaler& GetVideoPlaneScaler() const {
+    return mock_vpscaler_;
+  }
+  const MockVideoPlaneCollection* GetVideoPlaneCollection() const {
+    return &videoplanecollection_;
+  }
+
+ private:
+  std::unique_ptr<Renderer> renderer_;
+  MockRenderableObjectFactory mock_mixed_frame_factory_;
+  MockVideoPlaneScaler mock_vpscaler_;
+  MockVideoPlaneCollection videoplanecollection_;
+};
+
+TEST_F(InvalidRendererTest, Start) { EXPECT_FALSE(GetRenderer().Start()); }
+
+TEST_F(InvalidRendererTest, Stop) { EXPECT_FALSE(GetRenderer().Stop()); }
+
+TEST_F(InvalidRendererTest, ChangeRenderingSpeed) {
+  EXPECT_FALSE(
+      GetRenderer().ChangeRenderingSpeed(kFastFramerateNum, kFastFramerateDen));
+}
+
+TEST_F(InvalidRendererTest, Render) {
+  EXPECT_FALSE(GetRenderer().Render(
+      &GetVideoPlaneScaler(), GetVideoPlaneCollection(),
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+/********************************************************************************************
+ * RendererConstructionTest
+ */
+class RendererConstructionTest : public ::testing::Test {
+ public:
+  explicit RendererConstructionTest() {}
+  virtual ~RendererConstructionTest() {}
+  virtual void SetUp() override {
+    mock_mixed_frame_ = new MockRenderableObject();
+
+    ON_CALL(GetRenderableObject(), IsValid()).WillByDefault(Return(true));
+
+    ON_CALL(GetRenderableObjectFactory(), CreateRenderableObject(_, _))
+        .WillByDefault(Return(mock_mixed_frame_));
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  MockRenderableObject& GetRenderableObject() { return *mock_mixed_frame_; }
+  const MockRenderableObjectFactory& GetRenderableObjectFactory() const {
+    return mock_mixed_frame_factory_;
+  }
+  MockRendererEventListener* GetListener() { return nullptr; }
+
+ private:
+  MockRenderableObject* mock_mixed_frame_;
+  MockRenderableObjectFactory mock_mixed_frame_factory_;
+};
+
+TEST_F(RendererConstructionTest, IsValid) {
+  EXPECT_CALL(GetRenderableObject(), IsValid()).Times(AtLeast(1));
+  EXPECT_CALL(GetRenderableObjectFactory(),
+              CreateRenderableObject(kDefaultWidth, kDefaultHeight))
+      .Times(1);
+
+  Renderer renderer(
+      GetRenderableObjectFactory(),
+      GetResolutionInfo(kDefaultWidth, kDefaultHeight, kDefaultFramerateNum,
+                        kDefaultFramerateDen),
+      GetListener());
+
+  EXPECT_TRUE(renderer.IsValid());
+}
+
+TEST_F(RendererConstructionTest, IsValid_WithReturnNullMixedFrame) {
+  // FIXME(bayle.park): memleak will occur by mock_mixed_frame_
+  EXPECT_CALL(GetRenderableObjectFactory(),
+              CreateRenderableObject(kDefaultWidth, kDefaultHeight))
+      .WillOnce(Return(nullptr));
+
+  Renderer renderer(
+      GetRenderableObjectFactory(),
+      GetResolutionInfo(kDefaultWidth, kDefaultHeight, kDefaultFramerateNum,
+                        kDefaultFramerateDen),
+      GetListener());
+
+  EXPECT_FALSE(renderer.IsValid());
+}
+
+TEST_F(RendererConstructionTest, IsValid_WithInvalidMixedFrame) {
+  EXPECT_CALL(GetRenderableObject(), IsValid()).WillRepeatedly(Return(false));
+  EXPECT_CALL(GetRenderableObjectFactory(),
+              CreateRenderableObject(kDefaultWidth, kDefaultHeight))
+      .Times(1);
+
+  Renderer renderer(
+      GetRenderableObjectFactory(),
+      GetResolutionInfo(kDefaultWidth, kDefaultHeight, kDefaultFramerateNum,
+                        kDefaultFramerateDen),
+      GetListener());
+
+  EXPECT_FALSE(renderer.IsValid());
+}
+
+/********************************************************************************************
+ * RendererTest
+ */
+class RendererTest : public ::testing::Test {
+ public:
+  explicit RendererTest() {}
+  virtual ~RendererTest() {}
+  virtual void SetUp() override {
+    mock_mixed_frame_ = new MockRenderableObject();
+
+    ON_CALL(GetRenderableObject(), GetVideoPlaneManipInfo())
+        .WillByDefault(Return(std::vector<VideoPlaneManipulableInfo>(
+            {kYComponentDestVMInfo, kUVComponentDestVMInfo})));
+    ON_CALL(GetRenderableObject(), IsValid()).WillByDefault(Return(true));
+    ON_CALL(GetRenderableObject(), GetWidth())
+        .WillByDefault(Return(kDefaultWidth));
+    ON_CALL(GetRenderableObject(), GetHeight())
+        .WillByDefault(Return(kDefaultHeight));
+    ON_CALL(GetRenderableObject(), GetSize())
+        .WillByDefault(Return(kExpectedDefaultByteSize));
+    ON_CALL(GetRenderableObject(), Render(_, _, _)).WillByDefault(Return(true));
+    ON_CALL(GetRenderableObject(), Export(_))
+        .WillByDefault(
+            DoAll(SetArgReferee<0>(kDefaultBufferKey), Return(true)));
+
+    ON_CALL(*GetVideoPlaneCollection(), GetVideoPlaneManipInfo())
+        .WillByDefault(Return(std::vector<VideoPlaneManipulableInfo>(
+            {kYComponentDestVMInfo, kUVComponentDestVMInfo})));
+
+    ON_CALL(GetRenderableObjectFactory(), CreateRenderableObject(_, _))
+        .WillByDefault(Return(mock_mixed_frame_));
+
+    ON_CALL(GetVideoPlaneScaler(), GetScaleManipulator())
+        .WillByDefault(Return(&GetScaler()));
+
+    ON_CALL(GetScaler(), Do(_, _)).WillByDefault(Return(true));
+
+    ON_CALL(*GetListener(), OnRenderingRelease(_)).WillByDefault(Return(true));
+
+    EXPECT_CALL(GetRenderableObjectFactory(),
+                CreateRenderableObject(kDefaultWidth, kDefaultHeight));
+
+    renderer_ = std::unique_ptr<Renderer>(new Renderer(
+        GetRenderableObjectFactory(),
+        GetResolutionInfo(kDefaultWidth, kDefaultHeight, kDefaultFramerateNum,
+                          kDefaultFramerateDen),
+        GetListener()));
+
+    EXPECT_CALL(GetRenderableObject(), IsValid());
+    ASSERT_TRUE(renderer_->IsValid());
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  Renderer& GetRenderer() { return *renderer_; }
+
+  MockRenderableObject& GetRenderableObject() { return *mock_mixed_frame_; }
+  const MockVideoPlaneScaler& GetVideoPlaneScaler() const {
+    return mock_vpscaler_;
+  }
+  const MockVideoPlaneManipulator& GetScaler() const { return scaler_; }
+  const MockRenderableObjectFactory& GetRenderableObjectFactory() const {
+    return mock_mixed_frame_factory_;
+  }
+  MockRendererEventListener* GetListener() { return &listener_; }
+  const MockVideoPlaneCollection* GetVideoPlaneCollection() const {
+    return &videoplanecollection_;
+  }
+
+ private:
+  std::unique_ptr<Renderer> renderer_;
+  MockVideoPlaneScaler mock_vpscaler_;
+  MockVideoPlaneManipulator scaler_;
+  MockRenderableObject* mock_mixed_frame_;
+  MockRenderableObjectFactory mock_mixed_frame_factory_;
+  MockRendererEventListener listener_;
+  MockVideoPlaneCollection videoplanecollection_;
+};
+
+TEST_F(RendererTest, Start) {
+  EXPECT_CALL(GetRenderableObject(), IsValid()).Times(AtLeast(1));
+
+  EXPECT_TRUE(GetRenderer().Start());
+}
+
+TEST_F(RendererTest, Start_WithTwiceCall) {
+  EXPECT_CALL(GetRenderableObject(), IsValid()).Times(AtLeast(1));
+
+  EXPECT_TRUE(GetRenderer().Start());
+  EXPECT_FALSE(GetRenderer().Start());
+}
+
+TEST_F(RendererTest, Stop) {
+  EXPECT_CALL(GetRenderableObject(), IsValid()).Times(AtLeast(1));
+
+  EXPECT_FALSE(GetRenderer().Stop());
+}
+
+TEST_F(RendererTest, Stop_AfterStart) {
+  EXPECT_CALL(GetRenderableObject(), IsValid()).Times(AtLeast(1));
+
+  EXPECT_TRUE(GetRenderer().Start());
+  EXPECT_TRUE(GetRenderer().Stop());
+}
+
+TEST_F(RendererTest, ChangeResolution) {
+  auto* new_frame = new MockRenderableObject();
+  EXPECT_CALL(*new_frame, IsValid()).WillOnce(Return(true));
+  EXPECT_CALL(GetRenderableObjectFactory(),
+              CreateRenderableObject(kSmallWidth, kSmallHeight))
+      .WillOnce(Return(new_frame));
+
+  EXPECT_TRUE(GetRenderer().ChangeResolution(GetRenderableObjectFactory(),
+                                             kSmallWidth, kSmallHeight));
+}
+
+TEST_F(RendererTest, ChangeResolution_WithInvalidResolution) {
+  EXPECT_FALSE(GetRenderer().ChangeResolution(GetRenderableObjectFactory(),
+                                              kInvalidWidth, kInvalidHeight));
+  EXPECT_FALSE(GetRenderer().ChangeResolution(GetRenderableObjectFactory(),
+                                              kSmallWidth, kInvalidHeight));
+  EXPECT_FALSE(GetRenderer().ChangeResolution(GetRenderableObjectFactory(),
+                                              kInvalidWidth, kSmallHeight));
+}
+
+TEST_F(RendererTest, ChangeResolution_WithSameResolution) {
+  EXPECT_FALSE(GetRenderer().ChangeResolution(GetRenderableObjectFactory(),
+                                              kDefaultWidth, kDefaultHeight));
+}
+
+TEST_F(RendererTest, ChangeResolution_WithReturnNullFrame) {
+  EXPECT_CALL(GetRenderableObjectFactory(),
+              CreateRenderableObject(kSmallWidth, kSmallHeight))
+      .WillOnce(Return(nullptr));
+
+  EXPECT_FALSE(GetRenderer().ChangeResolution(GetRenderableObjectFactory(),
+                                              kSmallWidth, kSmallHeight));
+}
+
+TEST_F(RendererTest, ChangeResolution_WithInvalidNewFrame) {
+  auto* new_frame = new MockRenderableObject();
+  EXPECT_CALL(*new_frame, IsValid()).WillOnce(Return(false));
+  EXPECT_CALL(GetRenderableObjectFactory(),
+              CreateRenderableObject(kSmallWidth, kSmallHeight))
+      .WillOnce(Return(new_frame));
+
+  EXPECT_FALSE(GetRenderer().ChangeResolution(GetRenderableObjectFactory(),
+                                              kSmallWidth, kSmallHeight));
+}
+
+TEST_F(RendererTest, ChangeRenderingSpeed) {
+  EXPECT_CALL(GetRenderableObject(), IsValid()).Times(AtLeast(1));
+
+  EXPECT_TRUE(
+      GetRenderer().ChangeRenderingSpeed(kFastFramerateNum, kFastFramerateDen));
+}
+
+TEST_F(RendererTest, ChangeRenderingSpeed_WithInvalidFramerate) {
+  EXPECT_FALSE(GetRenderer().ChangeRenderingSpeed(kInvalidFramerateNum,
+                                                  kInvalidFramerateDen));
+  EXPECT_FALSE(GetRenderer().ChangeRenderingSpeed(kFastFramerateNum,
+                                                  kInvalidFramerateDen));
+  EXPECT_FALSE(GetRenderer().ChangeRenderingSpeed(kInvalidFramerateNum,
+                                                  kFastFramerateDen));
+}
+
+TEST_F(RendererTest, Render) {
+  EXPECT_CALL(
+      GetRenderableObject(),
+      Render(
+          Eq(&GetScaler()),
+          AllOf(SizeIs(2),
+                ElementsAre(
+                    IsSameVideoPlaneManipulableInfo(kYComponentDestVMInfo),
+                    IsSameVideoPlaneManipulableInfo(kUVComponentDestVMInfo))),
+          AllOf(Field(&Geometry::x, Eq(kDefaultX)),
+                Field(&Geometry::y, Eq(kDefaultY)),
+                Field(&Geometry::w, Eq(kDefaultW)),
+                Field(&Geometry::h, Eq(kDefaultH)))))
+      .Times(1);
+  EXPECT_CALL(*GetVideoPlaneCollection(), GetVideoPlaneManipInfo()).Times(1);
+  EXPECT_CALL(GetRenderableObject(), IsValid()).Times(AtLeast(1));
+  EXPECT_CALL(GetVideoPlaneScaler(), GetScaleManipulator()).Times(1);
+
+  EXPECT_TRUE(GetRenderer().Render(
+      &GetVideoPlaneScaler(), GetVideoPlaneCollection(),
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+TEST_F(RendererTest, Render_WithNullCollection) {
+  EXPECT_FALSE(GetRenderer().Render(
+      &GetVideoPlaneScaler(), nullptr,
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
+
+TEST_F(RendererTest, Render_WithNullScaler) {
+  EXPECT_CALL(GetRenderableObject(), Render(_, _, _)).Times(0);
+
+  EXPECT_FALSE(GetRenderer().Render(
+      nullptr, GetVideoPlaneCollection(),
+      GetGeometry(kDefaultX, kDefaultY, kDefaultW, kDefaultH)));
+}
\ No newline at end of file
diff --git a/ut/src/mixer/ut_tizenbuffermgr.cpp b/ut/src/mixer/ut_tizenbuffermgr.cpp
new file mode 100755 (executable)
index 0000000..2236a39
--- /dev/null
@@ -0,0 +1,183 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "mixer/constant.h"
+#include "mixer/mock/mock_bufferobject.h"
+#include "mixer/tizen/tizenbuffermgr.h"
+
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::Field;
+using ::testing::NotNull;
+using ::testing::Return;
+
+namespace {
+using namespace plusplayer;
+struct MockTBM {
+ public:
+  class Fake {
+   public:
+    MOCK_METHOD3(BoAlloc, BufferDefaultType(tbm_bufmgr, int, int));
+    MOCK_METHOD1(BoUnRef, void(BufferDefaultType));
+    MOCK_METHOD2(BoImport, BufferDefaultType(tbm_bufmgr, BufferKeyType));
+    MOCK_METHOD2(GACopy, int(tbm_bufmgr, GraphicsGABltRopInfo*));
+    MOCK_METHOD2(GAScale, int(tbm_bufmgr, GraphicsGAScaleInfo*));
+    MOCK_METHOD2(GAFill, int(tbm_bufmgr, GraphicsGAFillRectInfo*));
+  };
+
+  static Fake* instance;
+
+  static void BoUnRef(BufferDefaultType bo) { instance->BoUnRef(bo); }
+
+  static BufferDefaultType BoAlloc(tbm_bufmgr bufmgr, int size, int flag) {
+    return instance->BoAlloc(bufmgr, size, flag);
+  }
+  static BufferDefaultType BoImport(tbm_bufmgr bufmgr, BufferKeyType key) {
+    return instance->BoImport(bufmgr, key);
+  }
+
+  static int GAScale(tbm_bufmgr bufmgr, GraphicsGAScaleInfo* info) {
+    return instance->GAScale(bufmgr, info);
+  }
+
+  static int GACopy(tbm_bufmgr bufmgr, GraphicsGABltRopInfo* info) {
+    return instance->GACopy(bufmgr, info);
+  }
+
+  static int GAFill(tbm_bufmgr bufmgr, GraphicsGAFillRectInfo* info) {
+    return instance->GAFill(bufmgr, info);
+  }
+};
+
+MockTBM::Fake* MockTBM::instance = nullptr;
+}  // namespace
+
+namespace plusplayer_ut {
+
+using TizenBufferManager = BufferManagerWithType<MockTBM>;
+
+class TizenBufferManagerTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    MockTBM::instance = &GetTBM();
+
+    ON_CALL(GetTBM(), BoAlloc(_, _, _)).WillByDefault(Return(kDefaultBuffer));
+    ON_CALL(GetTBM(), BoImport(_, _)).WillByDefault(Return(kDefaultBuffer));
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  MockTBM::Fake& GetTBM() { return fake_tbm_; }
+  TizenBufferManager& GetBufferManager() { return bufmgr_; }
+
+ private:
+  MockTBM::Fake fake_tbm_;
+  TizenBufferManager bufmgr_;
+};
+
+TEST_F(TizenBufferManagerTest, IsValid) {
+  EXPECT_TRUE(GetBufferManager().IsValid());
+}
+
+TEST_F(TizenBufferManagerTest, Allocate) {
+  EXPECT_CALL(GetTBM(), BoAlloc(NotNull(), kExpectedDefaultByteSize,
+                                TBM_BO_SCANOUT | (1 << 17)));
+  EXPECT_CALL(GetTBM(), BoUnRef(NotNull()));
+
+  auto* bufferobj = GetBufferManager().Allocate(kExpectedDefaultByteSize);
+  EXPECT_NE(nullptr, bufferobj);
+  if (bufferobj) delete bufferobj;
+}
+
+TEST_F(TizenBufferManagerTest, Allocate_WithNullBO) {
+  EXPECT_CALL(GetTBM(), BoAlloc(NotNull(), kExpectedDefaultByteSize,
+                                TBM_BO_SCANOUT | (1 << 17)))
+      .WillOnce(Return(nullptr));
+
+  EXPECT_EQ(nullptr, GetBufferManager().Allocate(kExpectedDefaultByteSize));
+}
+
+TEST_F(TizenBufferManagerTest, Allocate_WithInvalidBufferSize) {
+  EXPECT_EQ(nullptr, GetBufferManager().Allocate(kInvalidBufferSize));
+}
+
+TEST_F(TizenBufferManagerTest, Import) {
+  EXPECT_CALL(GetTBM(), BoImport(NotNull(), _));
+  EXPECT_CALL(GetTBM(), BoUnRef(NotNull()));
+
+  EXPECT_NE(nullptr, GetBufferManager().Import(kDefaultBufferHandle));
+}
+
+TEST_F(TizenBufferManagerTest, Import_WithNullBO) {
+  EXPECT_CALL(GetTBM(), BoImport(NotNull(), _)).WillOnce(Return(nullptr));
+
+  EXPECT_EQ(nullptr, GetBufferManager().Import(kDefaultBufferHandle));
+}
+
+TEST_F(TizenBufferManagerTest, GetScaleManipulator) {
+  EXPECT_NE(nullptr, GetBufferManager().GetScaleManipulator());
+}
+
+class TizenBufferManagerScalerTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    MockTBM::instance = &GetTBM();
+    ON_CALL(GetTBM(), GAScale(_, _)).WillByDefault(Return(true));
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  MockTBM::Fake& GetTBM() { return fake_tbm_; }
+  const VideoPlaneManipulator& GetScaler() {
+    return *bufmgr_.GetScaleManipulator();
+  }
+
+ private:
+  MockTBM::Fake fake_tbm_;
+  TizenBufferManager bufmgr_;
+};
+
+TEST_F(TizenBufferManagerScalerTest, Do) {
+  EXPECT_CALL(
+      GetTBM(),
+      GAScale(
+          NotNull(),
+          AllOf(
+              Field(&GraphicsGAScaleInfo::ga_mode, GRAPHICS_GA_SCALE_MODE),
+              Field(&GraphicsGAScaleInfo::rop_mode, GRAPHICS_GA_ROP_COPY),
+              Field(&GraphicsGAScaleInfo::ga_op_type, GRAPHICS_GA_SCALE),
+              Field(&GraphicsGAScaleInfo::pre_alphamode, 0),
+              Field(&GraphicsGAScaleInfo::ca_value, 0),
+              Field(&GraphicsGAScaleInfo::rop_on_off, 0),
+              Field(&GraphicsGAScaleInfo::src_handle,
+                    kYComponentSrcVMInfo.handle),
+              Field(&GraphicsGAScaleInfo::src_hbytesize,
+                    kYComponentSrcVMInfo.linesize),
+              Field(
+                  &GraphicsGAScaleInfo::src_rect,
+                  AllOf(
+                      Field(&GraphicsRectInfo::x, kYComponentSrcVMInfo.rect.x),
+                      Field(&GraphicsRectInfo::y, kYComponentSrcVMInfo.rect.y),
+                      Field(&GraphicsRectInfo::w, kYComponentSrcVMInfo.rect.w),
+                      Field(&GraphicsRectInfo::h,
+                            kYComponentSrcVMInfo.rect.h))),
+              Field(&GraphicsGAScaleInfo::dst_handle,
+                    kYComponentDestVMInfo.handle),
+              Field(&GraphicsGAScaleInfo::dst_hbytesize,
+                    kYComponentDestVMInfo.linesize),
+              Field(
+                  &GraphicsGAScaleInfo::dst_rect,
+                  AllOf(
+                      Field(&GraphicsRectInfo::x, kYComponentDestVMInfo.rect.x),
+                      Field(&GraphicsRectInfo::y, kYComponentDestVMInfo.rect.y),
+                      Field(&GraphicsRectInfo::w, kYComponentDestVMInfo.rect.w),
+                      Field(&GraphicsRectInfo::h,
+                            kYComponentDestVMInfo.rect.h))))));
+
+  EXPECT_TRUE(GetScaler().Do(kYComponentSrcVMInfo, kYComponentDestVMInfo));
+}
+
+TEST_F(TizenBufferManagerScalerTest, Do_WithDifferentComponent) {
+  EXPECT_FALSE(GetScaler().Do(kYComponentSrcVMInfo, kUVComponentDestVMInfo));
+}
+}  // namespace  plusplayer_ut
diff --git a/ut/src/mixer/ut_tizenbufferobj.cpp b/ut/src/mixer/ut_tizenbufferobj.cpp
new file mode 100755 (executable)
index 0000000..5eb1cd9
--- /dev/null
@@ -0,0 +1,129 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <iostream>
+
+#include "mixer/constant.h"
+#include "mixer/tizen/tizenbufferobj.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace {
+using namespace plusplayer;
+
+struct MockTBM {
+ public:
+  class Fake {
+   public:
+    MOCK_METHOD1(BoRef, BufferDefaultType(BufferDefaultType));
+    MOCK_METHOD1(BoUnRef, void(BufferDefaultType));
+    MOCK_METHOD1(BoSize, int(BufferDefaultType));
+    MOCK_METHOD2(BoGetHandle, BufferUnionHandleType(BufferDefaultType, int));
+    MOCK_METHOD1(BoExport, BufferKeyType(BufferDefaultType));
+  };
+
+  static Fake* instance;
+
+  static BufferDefaultType BoRef(BufferDefaultType bo) {
+    return instance->BoRef(bo);
+  }
+
+  static void BoUnRef(BufferDefaultType bo) { instance->BoUnRef(bo); }
+
+  static int BoSize(BufferDefaultType bo) { return instance->BoSize(bo); }
+
+  static BufferUnionHandleType BoGetHandle(BufferDefaultType bo, int device) {
+    return instance->BoGetHandle(bo, device);
+  }
+  static BufferKeyType BoExport(BufferDefaultType bo) {
+    return instance->BoExport(bo);
+  }
+};
+
+MockTBM::Fake* MockTBM::instance = nullptr;
+}  // namespace
+
+namespace plusplayer_ut {
+
+using TizenBufferObject = BufferObjectWithType<MockTBM>;
+
+class InvalidBufferObjectWithTypeTest : public ::testing::Test {
+ public:
+  explicit InvalidBufferObjectWithTypeTest() : bufferobj_(nullptr) {}
+  virtual ~InvalidBufferObjectWithTypeTest() = default;
+  virtual void SetUp() override {}
+  virtual void TearDown() override {}
+
+ protected:
+  TizenBufferObject& GetBufferObject() { return bufferobj_; }
+
+ private:
+  TizenBufferObject bufferobj_;
+};
+
+TEST_F(InvalidBufferObjectWithTypeTest, IsValid) {
+  EXPECT_FALSE(GetBufferObject().IsValid());
+}
+
+TEST_F(InvalidBufferObjectWithTypeTest, GetBufferHandle) {
+  EXPECT_EQ(plusplayer::kInvalidBufferHandle,
+            GetBufferObject().GetBufferHandle());
+}
+
+TEST_F(InvalidBufferObjectWithTypeTest, Export) {
+  EXPECT_EQ(plusplayer::kInvalidBufferKey, GetBufferObject().Export());
+}
+
+TEST_F(InvalidBufferObjectWithTypeTest, GetSize) {
+  EXPECT_EQ(plusplayer::kInvalidBufferSize, GetBufferObject().GetSize());
+}
+
+class BufferObjectWithTypeTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    MockTBM::instance = &GetTBM();
+
+    ON_CALL(GetTBM(), BoRef(_)).WillByDefault(Return(kDefaultBuffer));
+    ON_CALL(GetTBM(), BoSize(_))
+        .WillByDefault(Return(kExpectedDefaultByteSize));
+    ON_CALL(GetTBM(), BoGetHandle(_, _))
+        .WillByDefault(Return(kDefaultMappedHandle));
+    ON_CALL(GetTBM(), BoExport(_)).WillByDefault(Return(kDefaultBufferKey));
+
+    EXPECT_CALL(GetTBM(), BoRef(_)).Times(1);
+    EXPECT_CALL(GetTBM(), BoUnRef(_)).Times(1);
+
+    bufferobj_ = std::unique_ptr<TizenBufferObject>(
+        new TizenBufferObject(kDefaultBuffer));
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  MockTBM::Fake& GetTBM() { return fake_tbm_; }
+  TizenBufferObject& GetBufferObject() { return *bufferobj_; }
+
+ private:
+  MockTBM::Fake fake_tbm_;
+  std::unique_ptr<TizenBufferObject> bufferobj_;
+};
+
+TEST_F(BufferObjectWithTypeTest, IsValid) {
+  EXPECT_TRUE(GetBufferObject().IsValid());
+}
+
+TEST_F(BufferObjectWithTypeTest, GetBufferHandle) {
+  EXPECT_CALL(GetTBM(), BoGetHandle(_, _)).Times(1);
+  EXPECT_EQ(kDefaultBufferHandle, GetBufferObject().GetBufferHandle());
+}
+
+TEST_F(BufferObjectWithTypeTest, Export) {
+  EXPECT_CALL(GetTBM(), BoExport(_)).Times(1);
+  EXPECT_EQ(kDefaultBufferKey, GetBufferObject().Export());
+}
+
+TEST_F(BufferObjectWithTypeTest, GetSize) {
+  EXPECT_CALL(GetTBM(), BoSize(_)).Times(1);
+  EXPECT_EQ(kExpectedDefaultByteSize, GetBufferObject().GetSize());
+}
+}  // namespace plusplayer_ut
\ No newline at end of file
diff --git a/ut/src/mixer/ut_videoplane.cpp b/ut/src/mixer/ut_videoplane.cpp
new file mode 100755 (executable)
index 0000000..ea22fab
--- /dev/null
@@ -0,0 +1,212 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#include "mixer/constant.h"
+#include "mixer/matcher.h"
+#include "mixer/mock/mock_bufferobject.h"
+#include "mixer/mock/movable.h"
+#include "mixer/mock/moveobj_wrapper.h"
+#include "mixer/videoplane.h"
+
+using ::testing::AllOf;
+using ::testing::AnyNumber;
+using ::testing::Field;
+using ::testing::Return;
+
+namespace plusplayer_ut {
+
+template <typename PlaneType>
+class DefaultVideoPlaneOptionWithBufferObject {
+ public:
+  using BufferObjectPtr = typename PlaneType::BufferObjectPtr;
+  virtual ~DefaultVideoPlaneOptionWithBufferObject() = default;
+
+ protected:
+  virtual void Init_() {
+    ON_CALL(GetBufferObject(), GetBufferHandle())
+        .WillByDefault(Return(kDefaultBufferHandle));
+    ON_CALL(GetBufferObject(), Export())
+        .WillByDefault(Return(kDefaultBufferKey));
+    ON_CALL(GetBufferObject(), GetSize())
+        .WillByDefault(Return(kDefaultWidth * kDefaultHeight));
+
+    EXPECT_CALL(GetBufferObject(), GetBufferHandle()).Times(AnyNumber());
+    EXPECT_CALL(GetBufferObject(), GetSize()).Times(AnyNumber());
+
+    ASSERT_TRUE(y_plane_->IsValid());
+  }
+
+ protected:
+  PlaneType& GetPlane() { return *y_plane_.get(); }
+  MockBufferObject& GetBufferObject() { return bufferobj_.Get(); }
+  MockBufferObject* MoveBufferObject() { return bufferobj_.Move(); }
+
+ private:
+  MoveObjectWrapper<MockBufferObject> bufferobj_{new MockBufferObject()};
+  std::unique_ptr<PlaneType> y_plane_{new PlaneType(
+      BufferObjectPtr(MoveBufferObject()), kDefaultWidth, kDefaultHeight)};
+};
+
+class YComponentVideoPlaneTest
+    : public ::testing::Test,
+      public DefaultVideoPlaneOptionWithBufferObject<YComponentVideoPlane> {
+ public:
+  virtual void SetUp() override { Init_(); }
+  virtual void TearDown() override {}
+};
+
+TEST_F(YComponentVideoPlaneTest, GetVideoPlaneManipulableInfo) {
+  EXPECT_THAT(
+      GetPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(Field(&VideoPlaneManipulableInfo::component,
+                  PlaneComponent::kYComponent),
+            Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+            Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+            Field(&VideoPlaneManipulableInfo::rect,
+                  IsSameGeometry(
+                      GetGeometry(0, 0, kDefaultWidth, kDefaultHeight)))));
+}
+
+TEST_F(YComponentVideoPlaneTest, GetVideoPlaneManipulableInfo_AfterCrop) {
+  GetPlane().SetCropArea(GetCropArea(0.1, 0.1, 0.9, 0.9));
+
+  EXPECT_THAT(
+      GetPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(Field(&VideoPlaneManipulableInfo::component,
+                  PlaneComponent::kYComponent),
+            Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+            Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+            Field(&VideoPlaneManipulableInfo::rect,
+                  IsSameGeometry(GetGeometry(
+                      kDefaultWidth * 0.1, kDefaultHeight * 0.1,
+                      kDefaultWidth * 0.9, kDefaultHeight * 0.9)))));
+}
+
+class UVComponentVideoPlaneTest
+    : public ::testing::Test,
+      public DefaultVideoPlaneOptionWithBufferObject<UVComponentVideoPlane> {
+ public:
+  virtual void SetUp() override {
+    Init_();
+    ON_CALL(GetBufferObject(), GetSize())
+        .WillByDefault(Return(kDefaultWidth * kDefaultHeight / 2));
+  }
+  virtual void TearDown() override {}
+};
+
+TEST_F(UVComponentVideoPlaneTest, GetVideoPlaneManipulableInfo) {
+  EXPECT_THAT(
+      GetPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(Field(&VideoPlaneManipulableInfo::component,
+                  PlaneComponent::kUVComponent),
+            Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+            Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+            Field(&VideoPlaneManipulableInfo::rect,
+                  IsSameGeometry(GetGeometry(0, 0, kDefaultWidth / 2,
+                                             kDefaultHeight / 2)))));
+}
+
+TEST_F(UVComponentVideoPlaneTest, GetVideoPlaneManipulableInfo_AfterCrop) {
+  GetPlane().SetCropArea(GetCropArea(0.1, 0.1, 0.9, 0.9));
+
+  EXPECT_THAT(
+      GetPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(Field(&VideoPlaneManipulableInfo::component,
+                  PlaneComponent::kUVComponent),
+            Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+            Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+            Field(&VideoPlaneManipulableInfo::rect,
+                  IsSameGeometry(GetGeometry(
+                      kDefaultWidth / 2 * 0.1, kDefaultHeight / 2 * 0.1,
+                      kDefaultWidth / 2 * 0.9, kDefaultHeight / 2 * 0.9)))));
+}
+
+class YUVComponentVideoPlaneTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    ON_CALL(GetBufferObject(), GetBufferHandle())
+        .WillByDefault(Return(kDefaultBufferHandle));
+    ON_CALL(GetBufferObject(), Export())
+        .WillByDefault(Return(kDefaultBufferKey));
+    ON_CALL(GetBufferObject(), GetSize())
+        .WillByDefault(Return(kDefaultWidth * kDefaultHeight * 1.5));
+
+    EXPECT_CALL(GetBufferObject(), GetBufferHandle()).Times(AnyNumber());
+    EXPECT_CALL(GetBufferObject(), GetSize()).Times(AnyNumber());
+
+    ASSERT_TRUE(GetYPlane().IsValid());
+    ASSERT_TRUE(GetUVPlane().IsValid());
+  }
+  virtual void TearDown() override {}
+
+ protected:
+  YComponentVideoPlaneWithSharedMemory& GetYPlane() { return *y_plane_.get(); }
+  UVComponentVideoPlaneWithSharedMemory& GetUVPlane() {
+    return *uv_plane_.get();
+  }
+  MockBufferObject& GetBufferObject() {
+    return dynamic_cast<MockBufferObject&>(*bufferobj_.get());
+  }
+
+ private:
+  std::shared_ptr<BufferObject> bufferobj_{new MockBufferObject()};
+  std::unique_ptr<YComponentVideoPlaneWithSharedMemory> y_plane_{
+      new YComponentVideoPlaneWithSharedMemory(bufferobj_, kDefaultWidth,
+                                               kDefaultHeight)};
+  std::unique_ptr<UVComponentVideoPlaneWithSharedMemory> uv_plane_{
+      new UVComponentVideoPlaneWithSharedMemory(bufferobj_, kDefaultWidth,
+                                                kDefaultHeight)};
+};
+
+TEST_F(YUVComponentVideoPlaneTest, GetVideoPlaneManipulableInfo) {
+  EXPECT_THAT(
+      GetYPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(Field(&VideoPlaneManipulableInfo::component,
+                  PlaneComponent::kYComponent),
+            Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+            Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+            Field(&VideoPlaneManipulableInfo::rect,
+                  IsSameGeometry(
+                      GetGeometry(0, 0, kDefaultWidth, kDefaultHeight)))));
+  EXPECT_THAT(
+      GetUVPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(
+          Field(&VideoPlaneManipulableInfo::component,
+                PlaneComponent::kUVComponent),
+          Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+          Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+          Field(&VideoPlaneManipulableInfo::rect,
+                IsSameGeometry(GetGeometry(0, kDefaultHeight, kDefaultWidth / 2,
+                                           kDefaultHeight / 2)))));
+}
+
+TEST_F(YUVComponentVideoPlaneTest, GetVideoPlaneManipulableInfo_AfterCrop) {
+  GetYPlane().SetCropArea(GetCropArea(0.1, 0.1, 0.9, 0.9));
+  GetUVPlane().SetCropArea(GetCropArea(0.1, 0.1, 0.9, 0.9));
+
+  EXPECT_THAT(
+      GetYPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(Field(&VideoPlaneManipulableInfo::component,
+                  PlaneComponent::kYComponent),
+            Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+            Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+            Field(&VideoPlaneManipulableInfo::rect,
+                  IsSameGeometry(GetGeometry(
+                      kDefaultWidth * 0.1, kDefaultHeight * 0.1,
+                      kDefaultWidth * 0.9, kDefaultHeight * 0.9)))));
+  EXPECT_THAT(
+      GetUVPlane().GetVideoPlaneManipulableInfo(),
+      AllOf(Field(&VideoPlaneManipulableInfo::component,
+                  PlaneComponent::kUVComponent),
+            Field(&VideoPlaneManipulableInfo::handle, kDefaultBufferHandle),
+            Field(&VideoPlaneManipulableInfo::linesize, kDefaultWidth),
+            Field(&VideoPlaneManipulableInfo::rect,
+                  IsSameGeometry(GetGeometry(
+                      kDefaultWidth / 2 * 0.1,
+                      kDefaultHeight / 2 * 0.1 + kDefaultHeight,
+                      kDefaultWidth / 2 * 0.9, kDefaultHeight / 2 * 0.9)))));
+}
+
+}  // namespace plusplayer_ut
\ No newline at end of file
diff --git a/ut/src/plusplayer/imagesimilarity.cpp b/ut/src/plusplayer/imagesimilarity.cpp
new file mode 100755 (executable)
index 0000000..7cf4ff8
--- /dev/null
@@ -0,0 +1,123 @@
+
+#include <unistd.h>
+#include <iostream> // for standard I/O
+#include <string>   // for strings
+#include <iomanip>  // for controlling float print precision
+#include <sstream>  // string to number conversion
+
+#include <opencv2/core/core.hpp>        // Basic OpenCV structures (cv::Mat, Scalar)
+#include <opencv2/imgproc/imgproc.hpp>  // Gaussian Blur
+#include <opencv2/highgui/highgui.hpp>  // OpenCV window I/O
+
+#include "ut/include/plusplayer/imagesimilarity.h"
+
+using namespace std;
+using namespace cv;
+
+
+double getPSNR(const Mat& I1, const Mat& I2)
+{
+    Mat s1;
+    absdiff(I1, I2, s1);       // |I1 - I2|
+    s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bits
+    s1 = s1.mul(s1);           // |I1 - I2|^2
+
+    Scalar s = sum(s1);        // sum elements per channel
+
+    double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
+
+    if( sse <= 1e-10) { // for small values return zero
+        return 0;
+    }
+       else {
+        double mse  = sse / (double)(I1.channels() * I1.total());
+        double psnr = 10.0 * log10((255 * 255) / mse);
+        return psnr;
+    }
+}
+
+Scalar getMSSIM( const Mat& i1, const Mat& i2)
+{
+    const double C1 = 6.5025, C2 = 58.5225;
+    
+    int d = CV_32F;
+
+    Mat I1, I2;
+    i1.convertTo(I1, d);            // cannot calculate on one byte large values
+    i2.convertTo(I2, d);
+
+    Mat I2_2   = I2.mul(I2);        // I2^2
+    Mat I1_2   = I1.mul(I1);        // I1^2
+    Mat I1_I2  = I1.mul(I2);        // I1 * I2
+
+
+    Mat mu1, mu2;                   // PRELIMINARY COMPUTING
+    GaussianBlur(I1, mu1, Size(11, 11), 1.5);
+    GaussianBlur(I2, mu2, Size(11, 11), 1.5);
+
+    Mat mu1_2   =   mu1.mul(mu1);
+    Mat mu2_2   =   mu2.mul(mu2);
+    Mat mu1_mu2 =   mu1.mul(mu2);
+
+    Mat sigma1_2, sigma2_2, sigma12;
+
+    GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
+    sigma1_2 -= mu1_2;
+
+    GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
+    sigma2_2 -= mu2_2;
+
+    GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
+    sigma12 -= mu1_mu2;
+
+    ///////////////////////////////// FORMULA ////////////////////////////////
+    Mat t1, t2, t3;
+
+    t1 = 2 * mu1_mu2 + C1;
+    t2 = 2 * sigma12 + C2;
+    t3 = t1.mul(t2);                 // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
+
+    t1 = mu1_2 + mu2_2 + C1;
+    t2 = sigma1_2 + sigma2_2 + C2;
+    t1 = t1.mul(t2);                 // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
+
+    Mat ssim_map;
+    divide(t3, t1, ssim_map);        // ssim_map =  t3./t1;
+
+    Scalar mssim = mean(ssim_map);   // mssim = average of ssim map
+    return mssim;
+}
+
+double ImageSimilarity::CompareImagesWithPSNR(char *reference_image, char *comparison_image)
+{
+       const string sourceReference(reference_image);
+       const string sourceCompareWith(comparison_image);
+
+       Mat frameReference = imread(sourceReference);
+       Mat frameUnderTest = imread(sourceCompareWith);
+
+    if (frameReference.cols != frameUnderTest.cols || frameReference.rows != frameUnderTest.rows) {
+        return -1;
+    }
+
+    double PSNR_Value = getPSNR(frameReference,frameUnderTest);
+       return PSNR_Value;
+}
+
+double ImageSimilarity::CompareImagesWithMSSIM(char *reference_image, char *comparison_image)
+{
+       const string sourceReference(reference_image);
+       const string sourceCompareWith(comparison_image);
+       
+       Mat frameReference = frameReference = imread(sourceReference);
+       Mat frameUnderTest = frameUnderTest = imread(sourceCompareWith);
+
+       if (frameReference.cols != frameUnderTest.cols || frameReference.rows != frameUnderTest.rows) {
+        return -1;
+    }
+       
+    Scalar mssimV = getMSSIM(frameReference, frameUnderTest);
+
+       double normalized_mean_SSIM = (mssimV.val[2] + mssimV.val[1] + mssimV.val[0])*100/3;
+       return normalized_mean_SSIM;
+}
\ No newline at end of file
diff --git a/ut/src/plusplayer/utility.cpp b/ut/src/plusplayer/utility.cpp
new file mode 100755 (executable)
index 0000000..ee9fd01
--- /dev/null
@@ -0,0 +1,491 @@
+#include <Ecore.h>
+#include <Elementary.h>
+#include <gtest/gtest.h>
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <memory>
+
+//#include "ut/include/plusplayer/tclist.h"
+#include "ut/include/plusplayer/utility.h"
+#include "ut/include/esplusplayer/eseventlistener.hpp"
+#include "ut/include/esplusplayer/esreader.hpp"
+
+#include <math.h>
+#include <fstream>
+#include <jconfig.h>
+#include <jpeglib.h>
+#include "ivideocapture.hpp"
+#include "capi-video-capture.h"
+#include "iaudio-control.hpp"
+#include "diagnosis-audio-control.hpp"
+
+
+using namespace plusplayer;
+//using namespace tc;
+using UserData = void*;
+
+namespace utils {
+using util_ptr = std::unique_ptr<Utility>;
+static util_ptr ptr = nullptr;
+
+Utility& Utility::Instance() {
+  if (ptr.get() == nullptr) ptr.reset(new Utility());
+  return *(ptr.get());
+}
+
+void Utility::Kill() { ptr.reset(); }
+
+void Utility::ThreadSleep(long ms) {
+  std::this_thread::sleep_for(std::chrono::milliseconds(ms));
+}
+
+Utility::Utility() {
+  appwindow_.reset(new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+  audioControl = IAudioControl::getInstance();
+  audioDiagnoser = DiagnosisAudioControl::getInstance();
+}
+
+Utility::~Utility() {}
+
+const char* Utility::GetCurrentTestName(void) {
+  return ::testing::UnitTest::GetInstance()->current_test_info()->name();
+}
+
+#ifndef IS_AUDIO_PRODUCT
+
+#if 0
+plusplayer::PlusPlayer::Ptr Utility::GetOpenedMixPlusPlayer(std::string& uri,
+                                                            Mixer* mixer,
+                                                            Geometry& roi) {
+  auto player = plusplayer::PlusPlayer::Create();
+  EXPECT_TRUE(player->Open(uri.c_str()));
+  EXPECT_TRUE(player->SetDisplay(DisplayType::kMixer, mixer));
+  EXPECT_TRUE(player->SetDisplayRoi(roi));
+  return player;
+}
+
+plusplayer::PlusPlayer::Ptr Utility::GetPreparedMixPlusPlayer(std::string& uri,
+                                                              Mixer* mixer,
+                                                              Geometry& roi) {
+  auto player = this->GetOpenedMixPlusPlayer(uri, mixer, roi);
+  EXPECT_TRUE(player->Prepare());
+  return player;
+}
+
+plusplayer::PlusPlayer::Ptr Utility::GetStartedMixPlusPlayer(std::string& uri,
+                                                             Mixer* mixer,
+                                                             Geometry& roi) {
+  auto player = this->GetPreparedMixPlusPlayer(uri, mixer, roi);
+  EXPECT_TRUE(player->Start());
+  return player;
+}
+#endif
+
+esplusplayer_handle Utility::GetOpenedMixESPP(mixer_handle mixer,
+                                              Geometry& roi) {
+  esplusplayer_handle player = esplusplayer_create();
+  EXPECT_EQ(esplusplayer_open(player), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(
+      esplusplayer_set_display(player, ESPLUSPLAYER_DISPLAY_TYPE_MIXER, mixer),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_display_roi(player, roi.x, roi.y, roi.w, roi.h),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  return player;
+}
+
+esplusplayer_handle Utility::GetPreparedMixESPP(std::string& uri,
+                                                mixer_handle mixer,
+                                                Geometry& roi) {
+  esplusplayer_handle player = this->GetOpenedMixESPP(mixer, roi);
+
+  if (!PrepareESPP(player, uri)) return nullptr;
+  return player;
+}
+
+esplusplayer_handle Utility::GetStartedMixESPP(std::string& uri,
+                                               mixer_handle mixer,
+                                               Geometry& roi) {
+  esplusplayer_handle player = this->GetPreparedMixESPP(uri, mixer, roi);
+
+  if (esplusplayer_start(player) == ESPLUSPLAYER_ERROR_TYPE_NONE)
+    return player;
+  else
+    printf("esplusplayer_start failed\n");
+  return nullptr;
+}
+#endif
+
+esplusplayer_handle Utility::GetOpenedESPP(Geometry& roi) {
+  esplusplayer_handle player = esplusplayer_create();
+  EXPECT_EQ(esplusplayer_open(player), ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_display(player, ESPLUSPLAYER_DISPLAY_TYPE_OVERLAY,
+                                     this->GetWindow()),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(
+      esplusplayer_set_display_mode(player, ESPLUSPLAYER_DISPLAY_MODE_DST_ROI),
+      ESPLUSPLAYER_ERROR_TYPE_NONE);
+  EXPECT_EQ(esplusplayer_set_display_roi(player, roi.x, roi.y, roi.w, roi.h),
+            ESPLUSPLAYER_ERROR_TYPE_NONE);
+  return player;
+}
+
+esplusplayer_handle Utility::GetPreparedESPP(std::string& uri, Geometry& roi) {
+  esplusplayer_handle player = this->GetOpenedESPP(roi);
+
+  if (!PrepareESPP(player, uri)) return nullptr;
+  return player;
+}
+
+esplusplayer_handle Utility::GetStartedESPP(std::string& uri, Geometry& roi) {
+  esplusplayer_handle player = this->GetPreparedESPP(uri, roi);
+
+  if (esplusplayer_start(player) == ESPLUSPLAYER_ERROR_TYPE_NONE)
+    return player;
+  else
+    printf("esplusplayer_start failed\n");
+  return nullptr;
+}
+
+bool Utility::PrepareESPP(esplusplayer_handle player, std::string& uri,
+                          EsType type) {
+  if (!player) return false;
+
+  EsStreamReader* video_reader = nullptr;
+  EsStreamReader* audio_reader = nullptr;
+
+  if (static_cast<int>(type) & EsType::kVideo) {
+    video_reader =
+        new EsStreamReader(uri + "video_00/", ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+    EXPECT_TRUE(video_reader->SetStreamInfo(player));
+  }
+  if (static_cast<int>(type) & EsType::kAudio) {
+    audio_reader =
+        new EsStreamReader(uri + "audio_00/", ESPLUSPLAYER_STREAM_TYPE_AUDIO);
+    EXPECT_TRUE(audio_reader->SetStreamInfo(player));
+  }
+  EsPlayerEventCallback* callback =
+      new EsPlayerEventCallback(player, video_reader, audio_reader);
+  callback->SetCallback();
+
+  bool ret = false;
+  if (esplusplayer_prepare_async(player) != ESPLUSPLAYER_ERROR_TYPE_NONE)
+    printf("esplusplayer_prepare_async failed\n");
+  else
+    ret = callback->WaitForPrepareDone();
+
+  delete callback;
+  if (video_reader != nullptr) delete video_reader;
+  if (audio_reader != nullptr) delete audio_reader;
+  printf("PrepareESPP done\n");
+  return ret;
+}
+
+void Utility::FeedingEsPacket(esplusplayer_handle player,
+                              const esplusplayer_stream_type type,
+                              const std::string& uri) {
+  EsStreamReader* reader;
+  auto feeding_task_fn = [this, &player, &reader]() {
+    esplusplayer_es_packet pkt;
+    while (true) {
+      memset(&pkt, 0, sizeof(esplusplayer_es_packet));
+      if (!reader->ReadNextPacket(pkt)) break;
+      esplusplayer_submit_packet(player, &pkt);
+      delete []pkt.buffer;
+    }
+  };
+  if (type == ESPLUSPLAYER_STREAM_TYPE_VIDEO) {
+    reader =
+        new EsStreamReader(uri + "video_00/", ESPLUSPLAYER_STREAM_TYPE_VIDEO);
+  } else {
+    reader =
+        new EsStreamReader(uri + "audio_00/", ESPLUSPLAYER_STREAM_TYPE_AUDIO);
+  }
+  auto feeding_task = std::thread(feeding_task_fn);
+  if (feeding_task.joinable()) feeding_task.join();
+}
+
+void Utility::DestroyESPP(esplusplayer_handle player) {
+  if (!player) return;
+  esplusplayer_destroy(player);
+  player = nullptr;
+}
+
+evas_h Utility::GetWindow() const { return appwindow_->GetWindow().obj; }
+
+unsigned int Gcd(unsigned int u, unsigned int v) {
+  int shift = 0;
+
+  /* GCD(0,v) == v; GCD(u,0) == u, GCD(0,0) == 0 */
+
+  if (u == 0) {
+    return v;
+  }
+  if (v == 0) {
+    return u;
+  }
+
+  /* Let shift := lg K, where K is the greatest power of 2
+    dividing both u and v. */
+  for (shift = 0; ((u | v) & 1) == 0; ++shift) {
+    u >>= 1;
+    v >>= 1;
+  }
+
+  while ((u & 1) == 0) {
+    u >>= 1;
+  }
+
+  /* From here on, u is always odd. */
+  do {
+    /* remove all factors of 2 in v -- they are not common */
+    /*  note: v is not zero, so while will terminate */
+    while ((v & 1) == 0) {
+      v >>= 1;
+      /* Loop X */
+    }
+    /* Now u and v are both odd. Swap if necessary so u <= v,
+     then set v = v - u (which is even). For bignums, the
+     swapping is just pointer movement, and the subtraction
+     can be done in-place. */
+    if (u > v) {
+      unsigned int t = v;
+      v = u;
+      u = t;
+    }           // Swap u and v.
+    v = v - u;  // Here v >= u.
+  } while (v != 0);
+
+  /* restore common factors of 2 */
+  return u << shift;
+}
+
+void ResizeCopy(unsigned int m_width, unsigned int m_height,
+                unsigned int m_rwidth, unsigned int m_rheight,
+                char* c_ptr, char* y_ptr, unsigned char* dest,
+                unsigned int color_format) {
+  unsigned int omit = 1;
+  unsigned int x = 0;
+  unsigned int y = 0;
+  unsigned char resize = 1;
+
+  if (m_width == m_rwidth) {
+    resize = 0;
+  } else {
+    omit = Gcd(m_width, m_rwidth);
+    omit = m_width / omit;
+  }
+  printf("m_width %u, m_rwidth %u, omit %u\n", m_width, m_rwidth, omit);
+
+  // long int inc = 3 * m_rwidth * m_rheight;
+  long int inc = 0;
+
+  for (y = 0; y < m_height; y++) {
+    if ((y + 1) % omit || !resize) {
+      for (x = 0; x < m_width; x += sizeof(unsigned int)) {
+
+        unsigned int Yplain =
+            *((unsigned int*)((void*)(y_ptr + y * m_width + x)));
+        unsigned int Cplain =
+            *((unsigned int*)((void*)(c_ptr + y * m_width + x)));
+
+        switch (color_format) {
+          case SECVIDEO_CAPTURE_COLOR_YUV444:  // 444
+            break;
+          case SECVIDEO_CAPTURE_COLOR_YUV422:  // 422
+            Cplain = *((unsigned int*)((void*)(c_ptr + y * m_width + x)));
+            break;
+          case SECVIDEO_CAPTURE_COLOR_YUV420:  // 420
+            Cplain = *((unsigned int*)((void*)(c_ptr + (y / 2) * m_width + x)));
+            break;
+          default:
+            break;
+        }
+        if ((x + 4) % omit || !resize) {
+          dest[inc++] = (Yplain) & 0xFF;
+          dest[inc++] = Cplain & 0xFF;
+          dest[inc++] = (Cplain >> 8) & 0xFF;
+        }
+        if ((x + 3) % omit || !resize) {
+          dest[inc++] = (Yplain >> 8) & 0xFF;
+          dest[inc++] = (Cplain) & 0xFF;
+          dest[inc++] = (Cplain >> 8) & 0xFF;
+        }
+
+        if ((x + 2) % omit || !resize) {
+          dest[inc++] = (Yplain >> 16) & 0xFF;
+          dest[inc++] = (Cplain >> 16) & 0xFF;
+          dest[inc++] = (Cplain >> 24) & 0xFF;
+        }
+
+        if ((x + 1) % omit || !resize) {
+          dest[inc++] = (Yplain >> 24) & 0xFF;
+          dest[inc++] = (Cplain >> 16) & 0xFF;
+          dest[inc++] = (Cplain >> 24) & 0xFF;
+        }
+      }
+    }
+  }
+}
+
+int Utility::CaptureYUV(int capture_width, int capture_height,
+                        char* ybuff, char* cbuff, int ysize,
+                        int csize, std::string result_file_path) {
+  // screen capture
+  IVideoCapture* VCObjptr = IVideoCapture::getInstance();
+
+  IVideoCapture::InputParams input_params;
+  
+  input_params.capture_w = capture_width;
+  input_params.capture_h = capture_height;
+
+  IVideoCapture::OutputParams output_params;
+  output_params.p_y_addr = ybuff;
+  output_params.p_c_addr = cbuff;
+  output_params.size_y = ysize;
+  output_params.size_c = csize;
+
+  sleep(1);
+
+  VCObjptr->getVideoPostYUV(input_params, output_params);
+
+  // write
+  FILE* fexpect = NULL;
+
+  while (output_params.p_y_addr) {
+    fexpect = fopen(result_file_path.c_str(), "wb");
+    if (fexpect == NULL) {
+      LOGE("can't open the file");
+      break;
+    }
+    fwrite(output_params.p_y_addr, 1, ysize, fexpect);
+    fclose(fexpect);
+    fexpect = NULL;
+    output_params.p_y_addr = NULL;
+  }
+
+  return 0;
+}
+///TODO:: Modify the API to return the pointer instead of writing it as an image file.
+int Utility::CaptureJPG(const int capture_width, const int capture_height,
+                        char* ybuff, char* cbuff, const int ysize,
+                        const int csize, std::string img_file_path) {
+  IVideoCapture* VCObjptr = IVideoCapture::getInstance();
+  int output_color_format = 0;
+
+  IVideoCapture::InputParams input_params;
+  input_params.capture_w = capture_width;
+  input_params.capture_h = capture_height;
+
+  IVideoCapture::OutputParams output_params;
+  output_params.p_y_addr = ybuff;
+  output_params.p_c_addr = cbuff;
+  output_params.size_y = ysize;
+  output_params.size_c = csize;
+
+  sleep(1);
+
+  VCObjptr->getVideoPostYUV(input_params, output_params);
+  output_color_format = static_cast<int>(output_params.color_format);
+
+  sleep(1);
+
+  unsigned char* rawImage;
+  rawImage = (unsigned char*)malloc(sizeof(unsigned char) * 3 * capture_width *
+                                    capture_height);
+
+  ResizeCopy(capture_width, capture_height, capture_width, capture_height,
+             cbuff, ybuff, rawImage, output_color_format);
+
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  FILE* outfile = NULL; /* target file */
+
+  JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+  int row_stride;          /* physical row width in image buffer */
+
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_compress(&cinfo);
+
+  outfile = fopen(img_file_path.c_str(), "wb");
+  if (outfile == NULL) {
+    LOGE("can't open the file");
+    if (rawImage != NULL) free(rawImage);
+    return -1;
+  }
+  jpeg_stdio_dest(&cinfo, outfile);
+
+  cinfo.image_width = capture_width;
+  cinfo.image_height = capture_height;
+  cinfo.input_components = 3; /* # of color components per pixel */
+  cinfo.in_color_space = JCS_YCbCr;
+  jpeg_set_defaults(&cinfo);
+  jpeg_set_quality(&cinfo, 70, TRUE);
+  jpeg_start_compress(&cinfo, TRUE);
+
+  row_stride = capture_width * 3; /* JSAMPLEs per row in image_buffer */
+
+  while (cinfo.next_scanline < cinfo.image_height) {
+    row_pointer[0] = &((rawImage)[cinfo.next_scanline * row_stride]);
+    (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
+  }
+
+  jpeg_finish_compress(&cinfo);
+  jpeg_destroy_compress(&cinfo);
+  if (rawImage != NULL) free(rawImage);
+
+  if (outfile == NULL) {
+    LOGE("Fail to open file");
+    return -1;
+  } else {
+    fclose(outfile);
+  }
+  return 0;
+}
+
+int Utility::CheckYUV(int x, int y) {
+
+  /* screen capture */
+  IVideoCapture* VCObjptr = IVideoCapture::getInstance();
+
+  int CAPTURE_WIDTH = 640;
+  int CAPTURE_HEIGHT = 360;
+  int CAPTURE_BUF_SIZE = CAPTURE_WIDTH * CAPTURE_HEIGHT;
+  char ybuff[CAPTURE_BUF_SIZE] = {0};
+  char cbuff[CAPTURE_BUF_SIZE] = {0};
+  
+  IVideoCapture::InputParams input_params;
+  input_params.capture_w = 640;
+  input_params.capture_h = 360;
+
+  IVideoCapture::OutputParams output_params;
+  output_params.p_y_addr = ybuff;
+  output_params.p_c_addr = cbuff;
+  output_params.size_y = CAPTURE_BUF_SIZE;
+  output_params.size_c = CAPTURE_BUF_SIZE;
+
+  sleep(1);
+
+  VCObjptr->getVideoPostYUV(input_params, output_params);
+
+  /* check YUV value. As the capture size (640 x 360) is mapped with the full screen (1920 x 1080), the position should be resized. */
+  int new_X = x / 3;
+  int new_Y = y / 3;
+  int position = CAPTURE_WIDTH * (new_Y - 1) + new_X;
+  
+  LOGE("Y value : %d", (int)ybuff[position]);
+  return (int)ybuff[position];
+}
+
+bool Utility::IsAudioDisconnected() {
+  TZTVAudioSource src = AUDIO_SOURCE_MAX;
+  EXPECT_EQ(audioControl->getMainOutSourceSelect(&src), 0);
+  return (src != AUDIO_MULTIMEDIA_DEC0);
+}
+
+bool Utility::IsAudioMute() {
+  long audioMute = 0;
+  EXPECT_EQ(audioDiagnoser->Diagnosis_GetBoolean(0, "main out mute", &audioMute), 0);
+  return (audioMute != 0);
+}
+}  // namespace utils
diff --git a/ut/src/ut_espacket.cpp b/ut/src/ut_espacket.cpp
new file mode 100755 (executable)
index 0000000..b5e5f33
--- /dev/null
@@ -0,0 +1,104 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#include "plusplayer/espacket.h"
+
+namespace pp = plusplayer;
+
+namespace {
+void MakeDummyMatroskaColor(pp::MatroskaColor& color_info) {
+  color_info.matrix_coefficients = 1;
+  color_info.bits_per_channel = 1;
+  color_info.chroma_subsampling_horizontal = 1;
+  color_info.chroma_subsampling_vertical = 1;
+  color_info.cb_subsampling_horizontal = 1;
+  color_info.cb_subsampling_vertical = 1;
+  color_info.chroma_siting_horizontal = 1;
+  color_info.chroma_siting_vertical = 1;
+  color_info.range = 1;
+  color_info.transfer_characteristics = 1;
+  color_info.primaries = 1;
+  color_info.max_cll = 1;
+  color_info.max_fall = 1;
+  color_info.metadata.primary_r_chromaticity_x = 0.5;
+  color_info.metadata.primary_r_chromaticity_y = 0.5;
+  color_info.metadata.primary_g_chromaticity_x = 0.5;
+  color_info.metadata.primary_g_chromaticity_y = 0.5;
+  color_info.metadata.primary_b_chromaticity_x = 0.5;
+  color_info.metadata.primary_b_chromaticity_y = 0.5;
+  color_info.metadata.white_point_chromaticity_x = 0.5;
+  color_info.metadata.white_point_chromaticity_y = 0.5;
+  color_info.metadata.luminance_max = 0.5;
+  color_info.metadata.luminance_min = 0.5;
+}
+bool IsSameMatroskaColor(const pp::MatroskaColor& color_info1,
+                         const pp::MatroskaColor& color_info2) {
+  return color_info1.matrix_coefficients == color_info2.matrix_coefficients &&
+         color_info1.bits_per_channel == color_info2.bits_per_channel &&
+         color_info1.chroma_subsampling_horizontal ==
+             color_info2.chroma_subsampling_horizontal &&
+         color_info1.chroma_subsampling_vertical ==
+             color_info2.chroma_subsampling_vertical &&
+         color_info1.cb_subsampling_horizontal ==
+             color_info2.cb_subsampling_horizontal &&
+         color_info1.cb_subsampling_vertical ==
+             color_info2.cb_subsampling_vertical &&
+         color_info1.chroma_siting_horizontal ==
+             color_info2.chroma_siting_horizontal &&
+         color_info1.chroma_siting_vertical ==
+             color_info2.chroma_siting_vertical &&
+         color_info1.range == color_info2.range &&
+         color_info1.transfer_characteristics ==
+             color_info2.transfer_characteristics &&
+         color_info1.primaries == color_info2.primaries &&
+         color_info1.max_cll == color_info2.max_cll &&
+         color_info1.max_fall == color_info2.max_fall &&
+         color_info1.metadata.primary_r_chromaticity_x ==
+             color_info2.metadata.primary_r_chromaticity_x &&
+         color_info1.metadata.primary_r_chromaticity_y ==
+             color_info2.metadata.primary_r_chromaticity_y &&
+         color_info1.metadata.primary_g_chromaticity_x ==
+             color_info2.metadata.primary_g_chromaticity_x &&
+         color_info1.metadata.primary_g_chromaticity_y ==
+             color_info2.metadata.primary_g_chromaticity_y &&
+         color_info1.metadata.primary_b_chromaticity_x ==
+             color_info2.metadata.primary_b_chromaticity_x &&
+         color_info1.metadata.primary_b_chromaticity_y ==
+             color_info2.metadata.primary_b_chromaticity_y &&
+         color_info1.metadata.white_point_chromaticity_x ==
+             color_info2.metadata.white_point_chromaticity_x &&
+         color_info1.metadata.white_point_chromaticity_y ==
+             color_info2.metadata.white_point_chromaticity_y &&
+         color_info1.metadata.luminance_max ==
+             color_info2.metadata.luminance_max &&
+         color_info1.metadata.luminance_min ==
+             color_info2.metadata.luminance_min;
+}
+}  // namespace
+
+TEST(EsPacket, DISABLED_MatroskaColor_EmptyData) {
+  auto espacket = pp::EsPacket::Create();
+  ASSERT_FALSE(espacket->HasMatroskaColorInfo());
+}
+
+TEST(EsPacket, DISABLED_MatroskaColor_HasData) {
+  auto espacket = pp::EsPacket::Create();
+  pp::MatroskaColor dummy_color_info;
+  ::MakeDummyMatroskaColor(dummy_color_info);
+  espacket->SetMatroskaColorInfo(dummy_color_info);
+  ASSERT_TRUE(espacket->HasMatroskaColorInfo());
+}
+
+TEST(EsPacket, DISABLED_MatroskaColor_GetData) {
+  auto espacket = pp::EsPacket::Create();
+  pp::MatroskaColor dummy_color_info;
+  ::MakeDummyMatroskaColor(dummy_color_info);
+  espacket->SetMatroskaColorInfo(dummy_color_info);
+  ASSERT_TRUE(espacket->HasMatroskaColorInfo());
+  auto saved_data = espacket->GetMatroskaColorInfo();
+  ASSERT_TRUE(::IsSameMatroskaColor(saved_data, dummy_color_info));
+}
diff --git a/ut/src/ut_esplayer.cpp b/ut/src/ut_esplayer.cpp
new file mode 100755 (executable)
index 0000000..f68cba0
--- /dev/null
@@ -0,0 +1,510 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "plusplayer/esplusplayer.h"
+#include "ut/include/streamreader.hpp"
+
+namespace es {
+namespace utils {
+pp::EsPacketPtr MakeEsPacketFromPacket(const es::PacketPtr &pkt,
+                                       pp::StreamType type) {
+  pp::EsPacketPtr buffer = nullptr;
+  if (pkt == nullptr) {
+    buffer = es::Packet::MakeEosPacket(type);
+  } else {
+    buffer = pkt->MakeEsPacket(type);
+  }
+  return std::move(buffer);
+}
+void MakeDummyMatroskaColor(pp::MatroskaColor &color_info) {
+  color_info.matrix_coefficients = 1;
+  color_info.bits_per_channel = 2;
+  color_info.chroma_subsampling_horizontal = 3;
+  color_info.chroma_subsampling_vertical = 4;
+  color_info.cb_subsampling_horizontal = 3;
+  color_info.cb_subsampling_vertical = 4;
+  color_info.chroma_siting_horizontal = 3;
+  color_info.chroma_siting_vertical = 4;
+  color_info.range = 1;
+  color_info.transfer_characteristics = 1;
+  color_info.primaries = 1;
+  color_info.max_cll = 1;
+  color_info.max_fall = 1;
+  color_info.metadata.primary_r_chromaticity_x = 0.1;
+  color_info.metadata.primary_r_chromaticity_y = 0.2;
+  color_info.metadata.primary_g_chromaticity_x = 0.3;
+  color_info.metadata.primary_g_chromaticity_y = 0.4;
+  color_info.metadata.primary_b_chromaticity_x = 0.5;
+  color_info.metadata.primary_b_chromaticity_y = 0.6;
+  color_info.metadata.white_point_chromaticity_x = 0.7;
+  color_info.metadata.white_point_chromaticity_y = 0.8;
+  color_info.metadata.luminance_max = 0.9;
+  color_info.metadata.luminance_min = 1.0;
+}
+}  // namespace utils
+}  // namespace es
+
+class EsPlayerMockEventListener : public pp::EsEventListener {
+ public:
+  MOCK_METHOD2_T(OnError, void(const pp::ErrorType, UserData userdata));
+  MOCK_METHOD1_T(OnResourceConflicted, void(UserData userdata));
+  MOCK_METHOD1_T(OnSeekDone, void(UserData userdata));
+  MOCK_METHOD1_T(OnEos, void(UserData userdata));
+  MOCK_METHOD2_T(OnPrepareDone, void(bool, UserData userdata));
+  MOCK_METHOD5_T(OnBufferStatus,
+                 void(const pp::StreamType &, const pp::BufferStatus &,
+                      const uint64_t, const uint64_t, UserData userdata));
+  MOCK_METHOD2_T(OnReadyToPrepare,
+                 void(const pp::StreamType &, UserData userdata));
+  MOCK_METHOD3_T(OnReadyToSeek, void(const pp::StreamType &, const uint64_t,
+                                     UserData userdata));
+
+  void Bind(std::shared_ptr<pp::EsEventListener> &&eventlistener) {
+    using ::testing::_;
+    using ::testing::Invoke;
+    eventlistener_ = eventlistener;
+    ON_CALL(*this, OnError(_, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &pp::EsEventListener::OnError));
+    ON_CALL(*this, OnResourceConflicted(_))
+        .WillByDefault(Invoke(eventlistener_.get(),
+                              &pp::EsEventListener::OnResourceConflicted));
+    ON_CALL(*this, OnSeekDone(_))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &pp::EsEventListener::OnSeekDone));
+    ON_CALL(*this, OnEos(_))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &pp::EsEventListener::OnEos));
+    ON_CALL(*this, OnPrepareDone(_, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &pp::EsEventListener::OnPrepareDone));
+    ON_CALL(*this, OnBufferStatus(_, _, _, _, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &pp::EsEventListener::OnBufferStatus));
+    ON_CALL(*this, OnReadyToPrepare(_, _))
+        .WillByDefault(Invoke(eventlistener_.get(),
+                              &pp::EsEventListener::OnReadyToPrepare));
+    ON_CALL(*this, OnReadyToSeek(_, _, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &pp::EsEventListener::OnReadyToSeek));
+  }
+
+ private:
+  std::shared_ptr<pp::EsEventListener> eventlistener_;
+};
+
+class EsPlayerTest : public ::testing::Test {
+ protected:
+  static void SetUpTestCase() {
+    env_ = new Environment();
+    ESPacketDownloader::Init();
+  }
+
+  static void TearDownTestCase() {
+    if (env_) {
+      delete env_;
+      env_ = nullptr;
+    }
+  }
+
+  void SetUp() override {
+    gst_init_check(nullptr, nullptr, nullptr);
+    submit_stopped_ = false;
+    player_ = GetCreatePlayer();
+
+    mock_eventlistener_ = std::make_shared<EsPlayerMockEventListener>();
+    fake_eventlistener_ = std::make_shared<EsPlayerFakeEventListener>(this);
+    mock_eventlistener_->Bind(
+        std::dynamic_pointer_cast<pp::EsEventListener>(fake_eventlistener_));
+
+    player_->RegisterListener(mock_eventlistener_.get(), nullptr);
+
+    v_streamreader_ = es::StreamReader<pp::TrackType>::Create(
+        "/welcome_movie/video_00/", pp::kTrackTypeVideo);
+    a_streamreader_ = es::StreamReader<pp::TrackType>::Create(
+        "/welcome_movie/audio_00/", pp::kTrackTypeAudio);
+  }
+
+  void TearDown() override {
+    ClosePlayer();
+    if (video_task_.valid()) {
+      video_task_.wait();
+    }
+    if (audio_task_.valid()) {
+      audio_task_.wait();
+    }
+    mock_eventlistener_.reset();
+    fake_eventlistener_.reset();
+    v_streamreader_.reset();
+    a_streamreader_.reset();
+    is_tzdata_ = false;
+    has_matroska_color_info = false;
+    submit_stopped_ = false;
+  }
+
+  pp::EsPlusPlayer::Ptr GetCreatePlayer() {
+    auto esplayer = pp::EsPlusPlayer::Create();
+    esplayer->Open();
+    esplayer->SetDisplay(pp::DisplayType::kOverlay, env_->Window());
+    return std::move(esplayer);
+  }
+
+  void ClosePlayer() {
+    if (player_) {
+      player_->Close();
+      player_.reset();
+    }
+  }
+
+  pp::VideoStreamPtr GetVideoStream(const pp::Track &track) {
+    auto video_stream = pp::VideoStream::Create();
+    video_stream->SetMimeType(pp::VideoMimeType::kHEVC);
+    video_stream->SetMaxWidth(track.maxwidth);
+    video_stream->SetMaxHeight(track.maxheight);
+    video_stream->SetWidth(track.width);
+    video_stream->SetHeight(track.height);
+    video_stream->SetFramerate(track.framerate_num, track.framerate_den);
+    video_stream->SetCodecData(track.codec_data, track.codec_data_len);
+    return std::move(video_stream);
+  }
+
+  void SetVideoStream() {
+    auto videoinfo =
+        v_streamreader_
+            ->GetMediaInfo<es::VideoInfo<pp::Track, pp::TrackType>>();
+    auto videoextradata = v_streamreader_->GetExtraData();
+    auto videotrack = videoinfo.GetTrack();
+    videotrack.codec_data = videoextradata->data;
+    videotrack.codec_data_len = videoextradata->size;
+
+    auto video_stream = GetVideoStream(videotrack);
+    ASSERT_TRUE(player_->SetStream(video_stream));
+  }
+
+  pp::AudioStreamPtr GetAudioStream(const pp::Track &track) {
+    auto audio_stream = pp::AudioStream::Create();
+    if (!track.mimetype.compare("audio/mpeg"))
+      audio_stream->SetMimeType(pp::AudioMimeType::kAAC);
+    else
+      audio_stream->SetMimeType(pp::AudioMimeType::kAC3);
+    audio_stream->SetSamplerate(track.sample_rate);
+    audio_stream->SetChannels(track.channels);
+    return std::move(audio_stream);
+  }
+
+  void SetAudioStream() {
+    auto audioinfo =
+        a_streamreader_
+            ->GetMediaInfo<es::AudioInfo<pp::Track, pp::TrackType>>();
+    auto audiotrack = audioinfo.GetTrack();
+
+    auto audio_stream = GetAudioStream(audiotrack);
+    ASSERT_TRUE(player_->SetStream(audio_stream));
+  }
+
+  void SetMatroskaColorInfo() { has_matroska_color_info = true; }
+
+  void SetTrustZoneData() {
+    ASSERT_TRUE(player_->SetSubmitDataType(pp::SubmitDataType::kTrustZoneData));
+    is_tzdata_ = true;
+  }
+
+ private:
+  class EsPlayerFakeEventListener : public pp::EsEventListener {
+   public:
+    explicit EsPlayerFakeEventListener(EsPlayerTest *handler)
+        : handler_(handler) {
+      assert(handler);
+    }
+
+    void OnError(const pp::ErrorType &err_code, UserData userdata) override {
+      std::cout << "OnError" << std::endl;
+    }
+    void OnResourceConflicted(UserData userdata) override {
+      std::cout << "OnResourceConflicted" << std::endl;
+    }
+    void OnSeekDone(UserData userdata) override {
+      std::cout << "OnSeekDone" << std::endl;
+    }
+    void OnEos(UserData userdata) override {
+      std::unique_lock<std::mutex> lk(eos_m_);
+      std::cout << "OnEos" << std::endl;
+      eos_ = true;
+      lk.unlock();
+      eos_cv_.notify_all();
+      ASSERT_TRUE(handler_->player_->Stop());
+    }
+    void OnPrepareDone(bool ret, UserData userdata) override {
+      std::cout << "OnPrepareDone" << std::endl;
+      ASSERT_TRUE(handler_->player_->Start());
+    }
+    void OnBufferStatus(const pp::StreamType &type,
+                        const pp::BufferStatus &status,
+                        const uint64_t byte_size, const uint64_t time_size,
+                        UserData userdata) override {
+      auto buffer_status =
+          status == pp::BufferStatus::kUnderrun ? "underrun" : "overrun";
+      std::cout << "OnBufferStatus " << buffer_status << std::endl;
+    }
+    void OnReadyToPrepare(const pp::StreamType &type,
+                          UserData userdata) override {
+      std::cout << "OnReadyToPrepare" << std::endl;
+
+      auto a_streaming_task_fn = [this](
+          es::StreamReader<pp::TrackType>::Ptr &streamreader, bool is_tzdata) {
+        while (true) {
+          auto pkt = streamreader->ReadNextPacket();
+          auto buffer = es::utils::MakeEsPacketFromPacket(
+              pkt, static_cast<pp::StreamType>(streamreader->GetTrackType()));
+          if (is_tzdata)
+            SubmitTzEsPacket(buffer);
+          else
+            SubmitEsPacket(buffer);
+          if (pkt == nullptr) break;
+        }
+      };
+      auto v_streaming_task_fn = [this](
+          es::StreamReader<pp::TrackType>::Ptr &streamreader, bool is_tzdata,
+          bool has_color_info) {
+        while (true) {
+          auto pkt = streamreader->ReadNextPacket();
+          auto buffer = es::utils::MakeEsPacketFromPacket(
+              pkt, static_cast<pp::StreamType>(streamreader->GetTrackType()));
+          if (has_color_info && buffer->GetPts() == 0) {
+            pp::MatroskaColor color_info;
+            es::utils::MakeDummyMatroskaColor(color_info);
+            buffer->SetMatroskaColorInfo(color_info);
+          }
+          if (is_tzdata)
+            SubmitTzEsPacket(buffer);
+          else
+            SubmitEsPacket(buffer);
+          if (pkt == nullptr) break;
+        }
+      };
+      if (type == pp::StreamType::kVideo) {
+        handler_->video_task_ =
+            std::async(std::launch::async, v_streaming_task_fn,
+                       std::ref(handler_->v_streamreader_),
+                       handler_->is_tzdata_, handler_->has_matroska_color_info);
+      } else if (type == pp::StreamType::kAudio) {
+        handler_->audio_task_ = std::async(
+            std::launch::async, a_streaming_task_fn,
+            std::ref(handler_->a_streamreader_), handler_->is_tzdata_);
+      }
+    }
+    void OnReadyToSeek(const pp::StreamType &type, const uint64_t offset,
+                       UserData userdata) override {
+      std::cout << "OnReadyToSeek" << std::endl;
+    }
+
+    void WaitForEos() {
+      std::unique_lock<std::mutex> lk(eos_m_);
+      eos_cv_.wait_for(lk, std::chrono::minutes(1),
+                       [this]() -> bool { return eos_; });
+      eos_ = false;
+      lk.unlock();
+    }
+
+    void SubmitEsPacket(const pp::EsPacketPtr &packet) {
+      using PacketSubmitStatus = pp::PacketSubmitStatus;
+      PacketSubmitStatus status = PacketSubmitStatus::kNotPrepared;
+      while (status != PacketSubmitStatus::kSuccess) {
+        if (handler_->submit_stopped_ == true) break;
+        status = handler_->player_->SubmitPacket(packet);
+        std::this_thread::sleep_for(std::chrono::milliseconds(5));
+      }
+    }
+
+    void SubmitTzEsPacket(const pp::EsPacketPtr &packet) {
+      using PacketSubmitStatus = pp::PacketSubmitStatus;
+      PacketSubmitStatus status = PacketSubmitStatus::kNotPrepared;
+      while (status != PacketSubmitStatus::kSuccess) {
+        if (handler_->submit_stopped_ == true) break;
+        status = handler_->player_->SubmitTrustZonePacket(packet);
+        std::this_thread::sleep_for(std::chrono::milliseconds(5));
+      }
+    }
+
+   private:
+    bool eos_ = false;
+    std::mutex eos_m_;
+    std::condition_variable eos_cv_;
+    EsPlayerTest *handler_{nullptr};
+  };
+
+ public:
+  static Environment *env_;
+  std::atomic<bool> submit_stopped_;
+  std::shared_ptr<pp::EsPlusPlayer> player_;
+  std::shared_ptr<EsPlayerMockEventListener> mock_eventlistener_;
+  std::shared_ptr<EsPlayerFakeEventListener> fake_eventlistener_;
+  es::StreamReader<pp::TrackType>::Ptr v_streamreader_;
+  es::StreamReader<pp::TrackType>::Ptr a_streamreader_;
+  std::future<void> video_task_;
+  std::future<void> audio_task_;
+  bool has_matroska_color_info = false;
+  bool is_tzdata_ = false;
+};
+
+Environment *EsPlayerTest::env_ = nullptr;
+
+TEST_F(EsPlayerTest, Play) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  EXPECT_CALL(*mock_eventlistener_, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener_, OnPrepareDone(true, _));
+  EXPECT_CALL(*mock_eventlistener_, OnEos(_)).Times(1);
+
+  SetVideoStream();
+  SetAudioStream();
+
+  ASSERT_TRUE(player_->PrepareAsync());
+
+  fake_eventlistener_->WaitForEos();
+}
+
+TEST_F(EsPlayerTest, PlayWithDrm) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  EXPECT_CALL(*mock_eventlistener_, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener_, OnPrepareDone(true, _));
+  EXPECT_CALL(*mock_eventlistener_, OnEos(_)).Times(1);
+
+  SetVideoStream();
+  SetAudioStream();
+  SetTrustZoneData();
+
+  ASSERT_TRUE(player_->PrepareAsync());
+
+  fake_eventlistener_->WaitForEos();
+}
+
+TEST_F(EsPlayerTest, PlayWithMatroskaColor) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  EXPECT_CALL(*mock_eventlistener_, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener_, OnPrepareDone(true, _));
+
+  SetVideoStream();
+  SetAudioStream();
+
+  SetMatroskaColorInfo();
+
+  ASSERT_TRUE(player_->PrepareAsync());
+
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+
+  ASSERT_TRUE(player_->Stop());
+  submit_stopped_ = true;
+}
+
+TEST_F(EsPlayerTest, PlayWithDrmAndMatroskaColor) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  EXPECT_CALL(*mock_eventlistener_, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener_, OnPrepareDone(true, _));
+
+  SetVideoStream();
+  SetAudioStream();
+
+  SetMatroskaColorInfo();
+  SetTrustZoneData();
+
+  ASSERT_TRUE(player_->PrepareAsync());
+
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+
+  ASSERT_TRUE(player_->Stop());
+  submit_stopped_ = true;
+}
+
+TEST_F(EsPlayerTest, Get_Adaptive_Info) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  SetVideoStream();
+  SetAudioStream();
+
+  EXPECT_CALL(*mock_eventlistener_, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener_, OnPrepareDone(true, _));
+
+  ASSERT_TRUE(player_->PrepareAsync());
+
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+
+  uint64_t *pvalue = new uint64_t;
+  ASSERT_TRUE(player_->GetAdaptiveInfo(
+      (void *)pvalue, pp::PlayerAdaptiveInfo::kVideoDroppedFrames));
+  std::cout << "Dropped frames: " << *pvalue << std::endl;
+
+  ASSERT_TRUE(player_->Stop());
+  submit_stopped_ = true;
+}
+
+TEST_F(EsPlayerTest, SetGetVolume) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  SetVideoStream();
+  SetAudioStream();
+
+  EXPECT_CALL(*mock_eventlistener_, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener_, OnPrepareDone(true, _));
+
+  const int kVolume = 80;
+  ASSERT_TRUE(player_->SetVolume(kVolume));
+
+  ASSERT_TRUE(player_->PrepareAsync());
+
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  int volume = 0;
+  ASSERT_TRUE(player_->GetVolume(&volume));
+  std::cout << "volume: " << volume << std::endl;
+  ASSERT_EQ(volume, kVolume);
+
+  ASSERT_TRUE(player_->Stop());
+  submit_stopped_ = true;
+}
+
+TEST_F(EsPlayerTest, VideoActivateDeactivate) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  SetVideoStream();
+  SetAudioStream();
+
+  EXPECT_CALL(*mock_eventlistener_, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener_, OnPrepareDone(true, _));
+
+  const int kVolume = 80;
+  ASSERT_TRUE(player_->SetVolume(kVolume));
+
+  ASSERT_TRUE(player_->PrepareAsync());
+
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  EXPECT_TRUE(player_->Deactivate(pp::StreamType::kVideo));
+  // SetVideoStream();
+  EXPECT_TRUE(player_->Activate(pp::StreamType::kVideo));
+  std::this_thread::sleep_for(std::chrono::seconds(15));
+
+  ASSERT_TRUE(player_->Stop());
+  submit_stopped_ = true;
+}
diff --git a/ut/src/ut_esplayer2.cpp b/ut/src/ut_esplayer2.cpp
new file mode 100755 (executable)
index 0000000..54c414f
--- /dev/null
@@ -0,0 +1,775 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <stdio.h>
+
+#include <map>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gst/gst.h"
+#include "gtest/gtest.h"
+
+#include "core/decoderinputbuffer.h"
+#include "core/decoderinputbuffer_listener.h"
+#include "core/track_util.h"
+#include "core/utils/plusplayer_log.h"
+#include "esplayer/esplayer.h"
+#include "plusplayer/esplusplayer.h"
+#include "tracksource/tracksource.h"
+#include "ut/include/appwindow.h"
+
+using namespace plusplayer;
+
+static constexpr int kMaxSizeOfQueue = 3;
+static constexpr int kTrackTypes[] = {kTrackTypeAudio, kTrackTypeVideo,
+                                      kTrackTypeSubtitle};
+
+class Feeder2 : public DecoderInputBufferListener {
+ public:
+  Feeder2() noexcept {}
+  ~Feeder2() {
+    LOG_ENTER;
+    std::lock_guard<std::mutex> lock(state_m_);
+    if (state_ != State::kActivated) {
+      LOG_INFO("Already stopped. just destroy feeder");
+      return;
+    }
+    stop_ = true;
+    for (auto type : kTrackTypes) {
+      feed_buf_[type].buffer_cv.notify_one();
+      if (feed_buf_[type].task.valid()) feed_buf_[type].task.wait();
+    }
+    state_ = State::kNone;
+    player_ = nullptr;
+    LOG_LEAVE;
+    return;
+  }
+
+  void OnRecv(DecoderInputBufferPtr inbuffer) {
+#if 1  // Convert Raw Buffer
+    StreamType type = static_cast<StreamType>(inbuffer->GetType());
+    GstBuffer *gstbuffer = static_cast<GstBuffer *>(inbuffer->Release());
+    uint64_t pts = GST_BUFFER_PTS(gstbuffer) / 1000000;
+    uint64_t duration = GST_BUFFER_DURATION(gstbuffer) / 1000000;
+    GstMapInfo info;
+
+    gst_buffer_map(gstbuffer, &info, GST_MAP_READ);
+    // LOG_INFO("type [%d] pts [%lld] duration [%lld] size [%d]", type, pts,
+    // duration, info.size);
+
+    std::shared_ptr<char> data(new char[info.size],
+                               std::default_delete<char[]>());
+    for (gsize i = 0; i < info.size; i++) {
+      data.get()[i] = info.data[i];
+    }
+    auto inputbuffer = EsPacket::Create(type, data, info.size, pts, duration);
+    gst_buffer_unmap(gstbuffer, &info);
+
+    Push_(std::move(inputbuffer));
+#else
+    Push_(std::move(inbuffer));
+#endif
+  }
+
+  bool Start(plusplayer::EsPlusPlayer *player) {
+    LOG_ENTER;
+    assert(player);
+    std::lock_guard<std::mutex> lock(state_m_);
+    if (state_ == State::kActivated) {
+      LOG_INFO("do nothing, task already activated, call stop if you need");
+      return false;
+    }
+    player_ = player;
+    stop_ = false;
+    for (auto type : kTrackTypes) {
+      feed_buf_[type].type = static_cast<TrackType>(type);
+      feed_buf_[type].task = std::async(std::launch::async, &Feeder2::Task_,
+                                        this, &feed_buf_[type]);
+      feed_buf_[type].activated = true;
+    }
+    state_ = State::kActivated;
+    LOG_LEAVE;
+    return true;
+  }
+
+  bool Stop() {
+    LOG_ENTER;
+    std::lock_guard<std::mutex> lock(state_m_);
+    if (state_ != State::kActivated) {
+      LOG_INFO("Already stopped. just destroy feeder");
+      return true;
+    }
+    stop_ = true;
+    for (auto type : kTrackTypes) {
+      feed_buf_[type].buffer_cv.notify_one();
+      if (feed_buf_[type].task.valid()) feed_buf_[type].task.wait();
+    }
+    state_ = State::kNone;
+    player_ = nullptr;
+    LOG_LEAVE;
+    return true;
+  }
+
+  bool SetEos() {
+    LOG_ENTER;
+    for (auto type : kTrackTypes) {
+      auto inbuffer = EsPacket::CreateEos(static_cast<StreamType>(type));
+      Push_(std::move(inbuffer));
+    }
+    LOG_LEAVE;
+    return true;
+  }
+
+  bool Flush(TrackType type) {
+    LOG_ENTER;
+    if (type >= kTrackTypeMax) {
+      return false;
+    }
+    std::lock_guard<std::mutex> lock(feed_buf_[type].buffer_m);
+    feed_buf_[type].buffer_cv.notify_all();
+    // bool ret =
+    // decoderinputbuffer_util::FlushQueue(feed_buf_[type].inbufferqueue);
+    bool ret = true;
+    while (!feed_buf_[type].inbufferqueue.empty()) {
+      feed_buf_[type].inbufferqueue.pop();
+    }
+    LOG_LEAVE;
+    return ret;
+  }
+
+ private:
+  bool Push_(EsPacketPtr inbuffer) {
+    TrackType type = static_cast<TrackType>(inbuffer->GetType());
+
+    if (type >= kTrackTypeMax) {
+      LOG_INFO("invalid type , failed to push");
+      return false;
+    }
+    if (stop_) {
+      // LOG_INFO("stopped, failed to push");
+      return false;
+    }
+    {
+      std::unique_lock<std::mutex> lock(feed_buf_[type].buffer_m);
+      if (feed_buf_[type].activated) {
+        feed_buf_[type].inbufferqueue.push(std::move(inbuffer));
+        feed_buf_[type].buffer_cv.notify_one();
+      }
+      if (feed_buf_[type].inbufferqueue.size() > kMaxSizeOfQueue) {
+        feed_buf_[type].buffer_cv.wait(lock);
+      }
+    }
+    return true;
+  }
+
+ private:
+  struct FeedBuffer {
+    bool activated = false;
+    TrackType type = kTrackTypeMax;
+    std::mutex buffer_m;
+    std::condition_variable buffer_cv;
+    std::queue<EsPacketPtr> inbufferqueue;
+    std::future<void> task;
+  };
+
+  void Task_(FeedBuffer *feed_buf) {
+    LOG_INFO("ENTER , TASK type[%d]", feed_buf->type);
+    if (!feed_buf) {
+      assert(0 && "feed_buf is null, can't create feeder task");
+      return;
+    }
+    LOG_INFO("FeederTask is Created , TaskID type[%d]", feed_buf->type);
+    while (!stop_) {
+      std::unique_lock<std::mutex> lock(feed_buf->buffer_m);
+      if (feed_buf->inbufferqueue.empty()) {
+        feed_buf->buffer_cv.wait(lock);
+      } else {
+        if (player_->SubmitPacket(feed_buf->inbufferqueue.front()) !=
+            PacketSubmitStatus::kSuccess) {
+          lock.unlock();
+          std::this_thread::sleep_for(std::chrono::milliseconds(5));
+        } else {
+          feed_buf->inbufferqueue.pop();
+          lock.unlock();
+          feed_buf->buffer_cv.notify_one();
+        }
+      }
+    }
+    std::lock_guard<std::mutex> lock(feed_buf->buffer_m);
+    feed_buf->activated = false;
+    // decoderinputbuffer_util::FlushQueue(feed_buf->inbufferqueue);
+    while (!feed_buf->inbufferqueue.empty()) {
+      feed_buf->inbufferqueue.pop();
+    }
+    LOG_INFO("LEAVE , TASK TYPE[%d]", feed_buf->type);
+  }
+
+  enum class State {
+    kNone,
+    kActivated,
+  };
+
+ private:
+  plusplayer::EsPlusPlayer *player_ = nullptr;
+  State state_ = State::kNone;
+  bool stop_ = false;
+  std::mutex state_m_;
+  FeedBuffer feed_buf_[kTrackTypeMax];
+};
+
+class EsPlayerMockEventListener1 : public EsEventListener {
+ public:
+  MOCK_METHOD2_T(OnError, void(const ErrorType, UserData userdata));
+  MOCK_METHOD1_T(OnResourceConflicted, void(UserData userdata));
+  MOCK_METHOD1_T(OnSeekDone, void(UserData userdata));
+  MOCK_METHOD1_T(OnEos, void(UserData userdata));
+  MOCK_METHOD2_T(OnPrepareDone, void(bool, UserData userdata));
+  MOCK_METHOD5_T(OnBufferStatus,
+                 void(const StreamType &, const BufferStatus &, const uint64_t,
+                      const uint64_t, UserData userdata));
+  MOCK_METHOD2_T(OnReadyToPrepare, void(const StreamType &, UserData userdata));
+  MOCK_METHOD3_T(OnReadyToSeek,
+                 void(const StreamType &, const uint64_t, UserData userdata));
+
+  void Bind(std::shared_ptr<EsEventListener> &&eventlistener) {
+    using ::testing::_;
+    using ::testing::Invoke;
+    eventlistener_ = eventlistener;
+    ON_CALL(*this, OnError(_, _))
+        .WillByDefault(Invoke(eventlistener_.get(), &EsEventListener::OnError));
+    ON_CALL(*this, OnResourceConflicted(_))
+        .WillByDefault(Invoke(eventlistener_.get(),
+                              &EsEventListener::OnResourceConflicted));
+    ON_CALL(*this, OnSeekDone(_))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &EsEventListener::OnSeekDone));
+    ON_CALL(*this, OnEos(_))
+        .WillByDefault(Invoke(eventlistener_.get(), &EsEventListener::OnEos));
+    ON_CALL(*this, OnPrepareDone(_, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &EsEventListener::OnPrepareDone));
+    ON_CALL(*this, OnBufferStatus(_, _, _, _, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &EsEventListener::OnBufferStatus));
+    ON_CALL(*this, OnReadyToPrepare(_, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &EsEventListener::OnReadyToPrepare));
+    ON_CALL(*this, OnReadyToSeek(_, _, _))
+        .WillByDefault(
+            Invoke(eventlistener_.get(), &EsEventListener::OnReadyToSeek));
+  }
+
+ private:
+  std::shared_ptr<EsEventListener> eventlistener_;
+};
+
+class EsPlayerFakeEventListener1 : public EsEventListener {
+ public:
+  EsPlayerFakeEventListener1()
+      : eos_(false), ready_audio_data_(false), ready_video_data_(false) {}
+
+  void OnError(const ErrorType &err_code, UserData userdata) override {
+    std::cout << "OnError" << std::endl;
+  }
+  void OnResourceConflicted(UserData userdata) override {
+    std::cout << "OnResourceConflicted" << std::endl;
+  }
+  void OnSeekDone(UserData userdata) override {
+    std::cout << "OnSeekDone" << std::endl;
+  }
+  void OnEos(UserData userdata) override {
+    std::unique_lock<std::mutex> lk(eos_m_);
+    std::cout << "OnEos" << std::endl;
+    eos_ = true;
+    lk.unlock();
+    eos_cv_.notify_all();
+  }
+  void OnPrepareDone(bool ret, UserData userdata) override {
+    std::cout << "OnPrepareDone" << std::endl;
+  }
+  void OnBufferStatus(const StreamType &type, const BufferStatus &status,
+                      const uint64_t byte_size, const uint64_t time_size,
+                      UserData userdata) override {
+    auto buffer_status =
+        status == BufferStatus::kUnderrun ? "underrun" : "overrun";
+    std::cout << "OnBufferStatus " << buffer_status << std::endl;
+  }
+  void OnReadyToPrepare(const StreamType &type, UserData userdata) override {
+    std::cout << "OnReadyToPrepare" << std::endl;
+    std::unique_lock<std::mutex> lk(data_m_);
+    if (type == StreamType::kAudio)
+      ready_audio_data_ = true;
+    else if (type == StreamType::kVideo)
+      ready_video_data_ = true;
+    lk.unlock();
+    data_cv_.notify_all();
+  }
+  void OnReadyToSeek(const StreamType &type, const uint64_t offset,
+                     UserData userdata) override {
+    std::cout << "OnReadyToSeek" << std::endl;
+    std::unique_lock<std::mutex> lk(data_m_);
+    if (type == StreamType::kAudio)
+      ready_audio_data_ = true;
+    else if (type == StreamType::kVideo)
+      ready_video_data_ = true;
+    lk.unlock();
+    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_;
+    });
+    ready_audio_data_ = false;
+    ready_video_data_ = false;
+    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_; });
+    eos_ = false;
+    std::cout << "WaitForEos stop" << std::endl;
+    lk.unlock();
+  }
+
+ private:
+  bool eos_;
+  std::mutex eos_m_;
+  std::condition_variable eos_cv_;
+  bool ready_audio_data_;
+  bool ready_video_data_;
+  std::mutex data_m_;
+  std::condition_variable data_cv_;
+};
+
+class EsPlayerTest2 : public ::testing::Test {
+ public:
+  EsPlayerTest2() {}
+
+  void SetUp() override {
+    gst_init_check(nullptr, nullptr, nullptr);
+    std::string url(
+        "http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/"
+        "bipbop_16x9_variant.m3u8");
+    TypeFinder typefinder(url);
+    StreamingProperty property;
+    if (!typefinder.Probe()) {
+      return;
+    }
+    tracksource_ = TrackSource::CreateCompositor();
+    tracksource_->AddSource(&typefinder, property);
+    if (!tracksource_->Prepare()) {
+      LOG_ERROR("tracksource prepare was failed");
+      return;
+    }
+    feeder_.reset(new Feeder2());
+    tracksource_->RegisterListener(feeder_.get());
+  }
+
+  void TearDown() override {
+    feeder_.reset();
+    tracksource_.reset();
+  }
+
+  std::shared_ptr<Feeder2> GetFeeder2() { return feeder_; }
+  std::shared_ptr<TrackSource> GetTrackSource() { return tracksource_; }
+
+ private:
+  std::shared_ptr<Feeder2> feeder_;
+  std::shared_ptr<TrackSource> tracksource_;
+};
+
+VideoStreamPtr GetVideoStream() {
+  auto video_stream = VideoStream::Create();
+  video_stream->SetMimeType(VideoMimeType::kH264);
+  video_stream->SetWidth(640);
+  video_stream->SetHeight(352);
+  video_stream->SetFramerate(30, 1);
+  return std::move(video_stream);
+}
+
+AudioStreamPtr GetAudioStream() {
+  auto audio_stream = AudioStream::Create();
+  audio_stream->SetMimeType(AudioMimeType::kAAC);
+  audio_stream->SetSamplerate(44100);
+  audio_stream->SetChannels(2);
+  return std::move(audio_stream);
+}
+
+AudioStreamPtr GetAudioStream2() {
+  auto audio_stream = AudioStream::Create();
+  audio_stream->SetMimeType(AudioMimeType::kAAC);
+  audio_stream->SetSamplerate(22050);
+  audio_stream->SetChannels(2);
+  return std::move(audio_stream);
+}
+
+TEST_F(EsPlayerTest2, Play) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  auto mock_eventlistener = std::make_shared<EsPlayerMockEventListener1>();
+  auto fake_eventlistener = std::make_shared<EsPlayerFakeEventListener1>();
+  mock_eventlistener->Bind(
+      std::dynamic_pointer_cast<EsEventListener>(fake_eventlistener));
+
+  auto feeder = GetFeeder2();
+  auto tracksource = GetTrackSource();
+
+  auto esplayer = EsPlusPlayer::Create();
+  esplayer->Open();
+
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow(
+      new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+  assert(appwindow.get());
+#if ECORE_WAYLAND_DISPLAY_TEST
+  esplayer->SetDisplay(DisplayType::kOverlay, appwindow->GetEcoreWL2Window(), 0,
+                       0, 1920, 1080);
+#else
+  Evas_Object *obj = appwindow->GetWindow().obj;
+  esplayer->SetDisplay(plusplayer::DisplayType::kOverlay, obj);
+#endif
+
+  esplayer->RegisterListener(mock_eventlistener.get(), nullptr);
+  EXPECT_CALL(*mock_eventlistener, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener, OnPrepareDone(true, _));
+
+  auto feeding_task_fn = [this, &esplayer]() {
+    auto feeder = GetFeeder2();
+    auto tracksource = GetTrackSource();
+    // Feeder must be started before TrackSource::Start to prevent loss of
+    // packets.
+    feeder->Start(esplayer.get());
+    tracksource->Start();
+
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+  };
+
+  esplayer->SetStream(GetVideoStream());
+  esplayer->SetStream(GetAudioStream());
+  esplayer->PrepareAsync();
+
+  fake_eventlistener->WaitAllStreamData();
+  auto feeding_task = std::thread(feeding_task_fn);
+
+  esplayer->Start();
+
+  feeding_task.join();
+
+  esplayer->Stop();
+  esplayer->Close();
+
+  feeder->Stop();
+  tracksource->Stop();
+}
+
+TEST_F(EsPlayerTest2, Seek) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  auto mock_eventlistener = std::make_shared<EsPlayerMockEventListener1>();
+  auto fake_eventlistener = std::make_shared<EsPlayerFakeEventListener1>();
+  mock_eventlistener->Bind(
+      std::dynamic_pointer_cast<EsEventListener>(fake_eventlistener));
+
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow(
+      new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+  assert(appwindow.get());
+  Evas_Object *obj = appwindow->GetWindow().obj;
+
+  auto feeder = GetFeeder2();
+  auto tracksource = GetTrackSource();
+  auto esplayer = EsPlusPlayer::Create();
+
+  esplayer->Open();
+
+  esplayer->RegisterListener(mock_eventlistener.get(), nullptr);
+  EXPECT_CALL(*mock_eventlistener, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener, OnPrepareDone(true, _));
+
+  auto feeding_task_fn = [this, &esplayer]() {
+    auto feeder = GetFeeder2();
+    auto tracksource = GetTrackSource();
+    // Feeder must be started before TrackSource::Start to prevent loss of
+    // packets.
+    feeder->Start(esplayer.get());
+    tracksource->Start();
+
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+  };
+
+  esplayer->SetDisplay(plusplayer::DisplayType::kOverlay, obj);
+  esplayer->SetStream(GetVideoStream());
+  esplayer->SetStream(GetAudioStream());
+  esplayer->PrepareAsync();
+
+  fake_eventlistener->WaitAllStreamData();
+  auto feeding_task = std::thread(feeding_task_fn);
+
+  esplayer->Start();
+
+  feeding_task.join();
+
+  feeder->Stop();
+  tracksource->Pause();
+  tracksource->Seek(5000);
+
+  EXPECT_CALL(*mock_eventlistener, OnReadyToSeek(_, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener, OnSeekDone(_));
+
+  esplayer->Seek(5000);
+
+  fake_eventlistener->WaitAllStreamData();
+  auto seek_feeding_task = std::thread(feeding_task_fn);
+
+  seek_feeding_task.join();
+
+  esplayer->Stop();
+  esplayer->Close();
+  feeder->Stop();
+  tracksource->Stop();
+}
+
+TEST_F(EsPlayerTest2, DISABLED_SetPlaybackRate) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  auto mock_eventlistener = std::make_shared<EsPlayerMockEventListener1>();
+  auto fake_eventlistener = std::make_shared<EsPlayerFakeEventListener1>();
+  mock_eventlistener->Bind(
+      std::dynamic_pointer_cast<EsEventListener>(fake_eventlistener));
+
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow(
+      new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+  assert(appwindow.get());
+  Evas_Object *obj = appwindow->GetWindow().obj;
+
+  auto feeder = GetFeeder2();
+  auto tracksource = GetTrackSource();
+  auto esplayer = EsPlusPlayer::Create();
+
+  esplayer->Open();
+
+  esplayer->RegisterListener(mock_eventlistener.get(), nullptr);
+  EXPECT_CALL(*mock_eventlistener, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener, OnPrepareDone(true, _));
+
+  auto feeding_task_fn = [this, &esplayer]() {
+    auto feeder = GetFeeder2();
+    auto tracksource = GetTrackSource();
+    // Feeder must be started before TrackSource::Start to prevent loss of
+    // packets.
+    feeder->Start(esplayer.get());
+    tracksource->Start();
+
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+  };
+
+  esplayer->SetDisplay(plusplayer::DisplayType::kOverlay, obj);
+  esplayer->SetStream(GetVideoStream());
+  esplayer->SetStream(GetAudioStream());
+  esplayer->PrepareAsync();
+
+  fake_eventlistener->WaitAllStreamData();
+  auto feeding_task = std::thread(feeding_task_fn);
+
+  esplayer->Start();
+
+  feeding_task.join();
+
+  feeder->Stop();
+  tracksource->Pause();
+
+  double playback_rate = 1.5;
+  uint64_t time_millisecond = 0;
+  esplayer->GetPlayingTime(&time_millisecond);
+
+  esplayer->SetPlaybackRate(playback_rate, true);
+  tracksource->Seek(time_millisecond, playback_rate);
+
+  auto seek_feeding_task = std::thread(feeding_task_fn);
+  seek_feeding_task.join();
+
+  esplayer->Stop();
+  esplayer->Close();
+  feeder->Stop();
+  tracksource->Stop();
+}
+
+TEST_F(EsPlayerTest2, A_DeactivateActivate) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  auto mock_eventlistener = std::make_shared<EsPlayerMockEventListener1>();
+  auto fake_eventlistener = std::make_shared<EsPlayerFakeEventListener1>();
+  mock_eventlistener->Bind(
+      std::dynamic_pointer_cast<EsEventListener>(fake_eventlistener));
+
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow(
+      new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+  assert(appwindow.get());
+  Evas_Object *obj = appwindow->GetWindow().obj;
+
+  auto feeder = GetFeeder2();
+  auto tracksource = GetTrackSource();
+  auto esplayer = EsPlusPlayer::Create();
+
+  esplayer->Open();
+
+  esplayer->RegisterListener(mock_eventlistener.get(), nullptr);
+  EXPECT_CALL(*mock_eventlistener, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener, OnPrepareDone(true, _));
+
+  auto feeding_task_fn = [this, &esplayer]() {
+    auto feeder = GetFeeder2();
+    auto tracksource = GetTrackSource();
+    // Feeder must be started before TrackSource::Start to prevent loss of
+    // packets.
+    feeder->Start(esplayer.get());
+    tracksource->Start();
+  };
+  uint64_t cur_pos_msec = 0;
+  esplayer->SetDisplay(plusplayer::DisplayType::kOverlay, obj);
+  tracksource->SelectTrack(kTrackTypeAudio, 0, 0);
+  esplayer->SetStream(GetVideoStream());
+  esplayer->SetStream(GetAudioStream());
+  esplayer->PrepareAsync();
+
+  fake_eventlistener->WaitAllStreamData();
+  auto feeding_task = std::thread(feeding_task_fn);
+
+  esplayer->Start();
+  feeding_task.join();
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+
+  auto track_list = tracksource->GetTrackInfo();
+  Track activated_track;
+  track_util::GetActiveTrack(track_list, kTrackTypeAudio, &activated_track);
+  if (activated_track.index == 0) {
+    printf("the index[%d] is already activated", 0);
+  }
+  esplayer->Deactivate(static_cast<plusplayer::StreamType>(kTrackTypeAudio));
+  esplayer->GetPlayingTime(&cur_pos_msec);
+
+  feeder->Flush(kTrackTypeAudio);
+  feeder->Stop();
+  tracksource->Pause();
+  tracksource->SelectTrack(kTrackTypeAudio, 1, cur_pos_msec);
+  tracksource->Seek(cur_pos_msec);
+  printf("activate tracktype : %d  index : %d  playingtime : %llu ms ",
+         static_cast<int>(kTrackTypeAudio), 0, cur_pos_msec);
+  track_list = tracksource->GetTrackInfo();
+  if (!track_util::GetActiveTrack(track_list, kTrackTypeAudio,
+                                  &activated_track)) {
+    LOG_ERROR("Can not find active track with [%d] index", 1);
+    return;
+  }
+  esplayer->SetStream(GetAudioStream2());
+  esplayer->Activate(static_cast<plusplayer::StreamType>(kTrackTypeAudio));
+  esplayer->Seek(cur_pos_msec);
+  fake_eventlistener->WaitAllStreamData();
+  auto new_feeding_task = std::thread(feeding_task_fn);
+
+  new_feeding_task.join();
+  std::this_thread::sleep_for(std::chrono::seconds(3));
+  esplayer->Stop();
+  esplayer->Close();
+  feeder->Stop();
+  tracksource->Stop();
+}
+
+TEST_F(EsPlayerTest2, VideoPeekSeek) {
+  using ::testing::_;
+  using ::testing::AtLeast;
+
+  auto mock_eventlistener = std::make_shared<EsPlayerMockEventListener1>();
+  auto fake_eventlistener = std::make_shared<EsPlayerFakeEventListener1>();
+  mock_eventlistener->Bind(
+      std::dynamic_pointer_cast<EsEventListener>(fake_eventlistener));
+
+  std::unique_ptr<plusplayer_ut::AppWindow> appwindow(
+      new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+  assert(appwindow.get());
+  Evas_Object *obj = appwindow->GetWindow().obj;
+
+  auto feeder = GetFeeder2();
+  auto tracksource = GetTrackSource();
+  auto esplayer = EsPlusPlayer::Create();
+
+  esplayer->Open();
+
+  esplayer->RegisterListener(mock_eventlistener.get(), nullptr);
+  EXPECT_CALL(*mock_eventlistener, OnReadyToPrepare(_, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener, OnPrepareDone(true, _));
+
+  auto feeding_task_fn = [this, &esplayer]() {
+    auto feeder = GetFeeder2();
+    auto tracksource = GetTrackSource();
+    // Feeder must be started before TrackSource::Start to prevent loss of
+    // packets.
+    feeder->Start(esplayer.get());
+    tracksource->Start();
+  };
+
+  esplayer->SetDisplay(plusplayer::DisplayType::kOverlay, obj);
+  esplayer->SetStream(GetVideoStream());
+  esplayer->SetStream(GetAudioStream());
+  esplayer->SetVideoFramePeekMode();
+  esplayer->PrepareAsync();
+
+  fake_eventlistener->WaitAllStreamData();
+  auto feeding_task = std::thread(feeding_task_fn);
+
+  esplayer->Start();
+
+  std::this_thread::sleep_for(std::chrono::seconds(10));
+
+  feeding_task.join();
+
+  feeder->Stop();
+  tracksource->Pause();
+  tracksource->Seek(0);
+
+  EXPECT_CALL(*mock_eventlistener, OnReadyToSeek(_, _, _)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_eventlistener, OnSeekDone(_));
+
+  esplayer->Pause();
+  esplayer->Seek(0);
+  fake_eventlistener->WaitAllStreamData();
+  auto seek_feeding_task = std::thread(feeding_task_fn);
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout <<" Render Video and wait 5 sec ~"<< std::endl;
+  esplayer->RenderVideoFrame();
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  std::cout <<" Resume ~"<< std::endl;
+  esplayer->Resume();
+  std::this_thread::sleep_for(std::chrono::seconds(5));
+  seek_feeding_task.join();
+
+  esplayer->Stop();
+  esplayer->Close();
+  feeder->Stop();
+  tracksource->Stop();
+}
\ No newline at end of file
diff --git a/ut/src/ut_esplayer_trackrenderer.cpp b/ut/src/ut_esplayer_trackrenderer.cpp
new file mode 100755 (executable)
index 0000000..6c91b2c
--- /dev/null
@@ -0,0 +1,266 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <memory>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#include "trackrenderer/trackrenderer.h"
+#include "ut/include/streamreader.hpp"
+
+namespace es {
+
+namespace utils {
+pp::trackrenderer::DecoderInputBufferPtr MakeBufferFromPacket(
+    const es::PacketPtr &pkt, pp::trackrenderer::TrackType type) {
+  pp::trackrenderer::DecoderInputBufferPtr buffer = nullptr;
+  if (pkt == nullptr) {
+    buffer = es::Packet::MakeEosBuffer(type);
+  } else {
+    buffer = pkt->MakeDecoderInputBuffer(type);
+  }
+  return std::move(buffer);
+}
+void SubmitDecoderInputBuffer(const pp::trackrenderer::TrackRenderer::Ptr &trackrenderer,
+                              const pp::trackrenderer::DecoderInputBufferPtr &buffer) {
+  using SubmitStatus = pp::trackrenderer::SubmitStatus;
+  SubmitStatus status = SubmitStatus::kNotPrepared;
+  while (status == SubmitStatus::kNotPrepared ||
+         status == SubmitStatus::kFull || status == SubmitStatus::kHold) {
+    trackrenderer->SubmitPacket(buffer, &status);
+  }
+}
+}  // namespace utils
+}  // namespace es
+
+class TrackRendererMockEventListener : public pp::trackrenderer::TrackRenderer::EventListener {
+ public:
+  MOCK_METHOD1_T(OnError, void(const pp::trackrenderer::ErrorType));
+  MOCK_METHOD0_T(OnResourceConflicted, void());
+  MOCK_METHOD0_T(OnSeekDone, void());
+  MOCK_METHOD0_T(OnEos, void());
+  MOCK_METHOD4_T(OnDrmInitData, void(int *, unsigned int, unsigned char *,
+                                     pp::trackrenderer::TrackType));
+  MOCK_METHOD2_T(OnBufferStatus, void(const pp::trackrenderer::TrackType &,
+                                      const pp::trackrenderer::BufferStatus &));
+  MOCK_METHOD2_T(OnSeekData,
+                 void(const pp::trackrenderer::TrackType &, const uint64_t));
+
+  void Bind(std::shared_ptr<pp::trackrenderer::TrackRenderer::EventListener>
+                &&eventlistener) {
+    using ::testing::_;
+    using ::testing::Invoke;
+    eventlistener_ = eventlistener;
+    ON_CALL(*this, OnError(_))
+        .WillByDefault(
+            Invoke(eventlistener_.get(),
+                   &pp::trackrenderer::TrackRenderer::EventListener::OnError));
+    ON_CALL(*this, OnResourceConflicted())
+        .WillByDefault(Invoke(eventlistener_.get(),
+                              &pp::trackrenderer::TrackRenderer::EventListener::
+                                  OnResourceConflicted));
+    ON_CALL(*this, OnSeekDone())
+        .WillByDefault(Invoke(
+            eventlistener_.get(),
+            &pp::trackrenderer::TrackRenderer::EventListener::OnSeekDone));
+    ON_CALL(*this, OnEos())
+        .WillByDefault(
+            Invoke(eventlistener_.get(),
+                   &pp::trackrenderer::TrackRenderer::EventListener::OnEos));
+    ON_CALL(*this, OnDrmInitData(_, _, _, _))
+        .WillByDefault(Invoke(
+            eventlistener_.get(),
+            &pp::trackrenderer::TrackRenderer::EventListener::OnDrmInitData));
+    ON_CALL(*this, OnBufferStatus(_, _))
+        .WillByDefault(Invoke(
+            eventlistener_.get(),
+            &pp::trackrenderer::TrackRenderer::EventListener::OnBufferStatus));
+    ON_CALL(*this, OnSeekData(_, _))
+        .WillByDefault(Invoke(
+            eventlistener_.get(),
+            &pp::trackrenderer::TrackRenderer::EventListener::OnSeekData));
+  }
+
+ private:
+  std::shared_ptr<pp::trackrenderer::TrackRenderer::EventListener>
+      eventlistener_;
+};
+
+class EsPlayerTrackRendererTest : public ::testing::Test {
+ protected:
+  static void SetUpTestCase() {
+    env_ = new Environment();
+    ESPacketDownloader::Init();
+  }
+  static void TearDownTestCase() {
+    if (env_) {
+      delete env_;
+      env_ = nullptr;
+    }
+  }
+
+  void SetUp() override { gst_init_check(nullptr, nullptr, nullptr); }
+  void TearDown() override {}
+
+ public:
+  static Environment *env_;
+};
+
+Environment *EsPlayerTrackRendererTest::env_ = nullptr;
+
+TEST_F(EsPlayerTrackRendererTest, DISABLED_DefaultPlaybackOnPushMode) {
+  class TrackRendererFakeEventListener
+      : public pp::trackrenderer::TrackRenderer::EventListener {};
+  TrackRendererFakeEventListener eventlistener;
+
+  auto v_streamreader = es::StreamReader<pp::trackrenderer::TrackType>::Create(
+      "/welcome_movie/video_00/", pp::trackrenderer::kTrackTypeVideo);
+  auto videoinfo = v_streamreader->GetMediaInfo<
+      es::VideoInfo<pp::trackrenderer::Track, pp::trackrenderer::TrackType>>();
+  auto videoextradata = v_streamreader->GetExtraData();
+  auto videotrack = videoinfo.GetTrack();
+  videotrack.codec_data = videoextradata->data;
+  videotrack.codec_data_len = videoextradata->size;
+
+  auto a_streamreader = es::StreamReader<pp::trackrenderer::TrackType>::Create(
+      "/welcome_movie/audio_01/", pp::trackrenderer::kTrackTypeAudio);
+  auto audioinfo = a_streamreader->GetMediaInfo<
+      es::AudioInfo<pp::trackrenderer::Track, pp::trackrenderer::TrackType>>();
+  auto audiotrack = audioinfo.GetTrack();
+
+  auto trackrenderer = pp::trackrenderer::TrackRenderer::Create();
+  ASSERT_TRUE(
+      trackrenderer->SetDisplay(pp::trackrenderer::DisplayType::kOverlay, env_->Window()));
+  trackrenderer->RegisterListener(&eventlistener);
+
+  auto tracks = {videotrack, audiotrack};
+  ASSERT_TRUE(trackrenderer->SetTrack(tracks));
+
+  auto streaming_task_fn = [&trackrenderer](es::StreamReader<pp::trackrenderer::TrackType>::Ptr &streamreader) {
+    while (true) {
+      auto pkt = streamreader->ReadNextPacket();
+      auto buffer =
+          es::utils::MakeBufferFromPacket(pkt, streamreader->GetTrackType());
+      es::utils::SubmitDecoderInputBuffer(trackrenderer, buffer);
+      if (pkt == nullptr) break;
+    }
+  };
+
+  auto video_task = std::thread(streaming_task_fn, std::ref(v_streamreader));
+  auto audio_task = std::thread(streaming_task_fn, std::ref(a_streamreader));
+
+  ASSERT_TRUE(trackrenderer->Prepare());
+  ASSERT_TRUE(trackrenderer->Start());
+
+  video_task.join();
+  audio_task.join();
+
+  ASSERT_TRUE(trackrenderer->Stop());
+}
+
+TEST_F(EsPlayerTrackRendererTest, DISABLED_Reuse) {
+  class TrackRendererFakeEventListener
+      : public pp::trackrenderer::TrackRenderer::EventListener {};
+  TrackRendererFakeEventListener eventlistener;
+  auto trackrenderer = pp::trackrenderer::TrackRenderer::Create();
+  trackrenderer->RegisterListener(&eventlistener);  // only once
+
+  auto streaming_task_fn =
+      [&trackrenderer](
+          es::StreamReader<pp::trackrenderer::TrackType>::Ptr &streamreader) {
+        while (true) {
+          auto pkt = streamreader->ReadNextPacket();
+          auto buffer = es::utils::MakeBufferFromPacket(
+              pkt, streamreader->GetTrackType());
+          es::utils::SubmitDecoderInputBuffer(trackrenderer, buffer);
+          if (pkt == nullptr) break;
+        }
+      };
+
+  // first playback
+  {
+    auto v_streamreader =
+        es::StreamReader<pp::trackrenderer::TrackType>::Create(
+            "/welcome_movie/video_00/", pp::trackrenderer::kTrackTypeVideo);
+    auto videoinfo = v_streamreader->GetMediaInfo<es::VideoInfo<
+        pp::trackrenderer::Track, pp::trackrenderer::TrackType>>();
+    auto videoextradata = v_streamreader->GetExtraData();
+    auto videotrack = videoinfo.GetTrack();
+    videotrack.codec_data = videoextradata->data;
+    videotrack.codec_data_len = videoextradata->size;
+
+    auto a_streamreader =
+        es::StreamReader<pp::trackrenderer::TrackType>::Create(
+            "/welcome_movie/audio_01/", pp::trackrenderer::kTrackTypeAudio);
+    auto audioinfo = a_streamreader->GetMediaInfo<es::AudioInfo<
+        pp::trackrenderer::Track, pp::trackrenderer::TrackType>>();
+    auto audiotrack = audioinfo.GetTrack();
+
+    auto tracks = {videotrack, audiotrack};
+    ASSERT_TRUE(trackrenderer->SetTrack(tracks));
+
+    ASSERT_TRUE(trackrenderer->SetDisplay(
+        pp::trackrenderer::DisplayType::kOverlay, env_->Window()));
+
+    auto video_task = std::thread(streaming_task_fn, std::ref(v_streamreader));
+    auto audio_task = std::thread(streaming_task_fn, std::ref(a_streamreader));
+
+    ASSERT_TRUE(trackrenderer->Prepare());
+    ASSERT_TRUE(trackrenderer->Start());
+
+    ASSERT_TRUE(trackrenderer->SetAudioMute(true));
+    ASSERT_TRUE(
+        trackrenderer->SetDisplayMode(pp::trackrenderer::DisplayMode::kDstRoi));
+    pp::trackrenderer::Geometry roi;
+    roi.x = 100;
+    roi.y = 100;
+    roi.w = 640;
+    roi.h = 480;
+    ASSERT_TRUE(trackrenderer->SetDisplayRoi(roi));
+
+    video_task.join();
+    audio_task.join();
+
+    ASSERT_TRUE(trackrenderer->Stop());
+  }
+
+  // reuse
+  {
+    auto v_streamreader =
+        es::StreamReader<pp::trackrenderer::TrackType>::Create(
+            "/welcome_movie/video_00/", pp::trackrenderer::kTrackTypeVideo);
+    auto videoinfo = v_streamreader->GetMediaInfo<es::VideoInfo<
+        pp::trackrenderer::Track, pp::trackrenderer::TrackType>>();
+    auto videoextradata = v_streamreader->GetExtraData();
+    auto videotrack = videoinfo.GetTrack();
+    videotrack.codec_data = videoextradata->data;
+    videotrack.codec_data_len = videoextradata->size;
+
+    auto a_streamreader =
+        es::StreamReader<pp::trackrenderer::TrackType>::Create(
+            "/welcome_movie/audio_01/", pp::trackrenderer::kTrackTypeAudio);
+    auto audioinfo = a_streamreader->GetMediaInfo<es::AudioInfo<
+        pp::trackrenderer::Track, pp::trackrenderer::TrackType>>();
+    auto audiotrack = audioinfo.GetTrack();
+
+    auto tracks = {videotrack, audiotrack};
+    ASSERT_TRUE(trackrenderer->SetTrack(tracks));
+
+    ASSERT_TRUE(trackrenderer->SetDisplay(
+        pp::trackrenderer::DisplayType::kOverlay, env_->Window()));
+
+    auto video_task = std::thread(streaming_task_fn, std::ref(v_streamreader));
+    auto audio_task = std::thread(streaming_task_fn, std::ref(a_streamreader));
+
+    ASSERT_TRUE(trackrenderer->Prepare());
+    ASSERT_TRUE(trackrenderer->Start());
+
+    video_task.join();
+    audio_task.join();
+
+    ASSERT_TRUE(trackrenderer->Stop());
+  }
+}
diff --git a/ut/src/ut_main.cpp b/ut/src/ut_main.cpp
new file mode 100755 (executable)
index 0000000..a852b81
--- /dev/null
@@ -0,0 +1,18 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+int main(int argc, char *argv[]) {
+  
+  ::testing::InitGoogleTest(&argc, argv);
+  ::testing::InitGoogleMock(&argc, argv);
+
+  auto ret = -1;
+  ret = RUN_ALL_TESTS();
+
+  
+  return ret;
+}
diff --git a/ut/src/ut_miscellaneous.cpp b/ut/src/ut_miscellaneous.cpp
new file mode 100755 (executable)
index 0000000..b2eeae3
--- /dev/null
@@ -0,0 +1,133 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include <iostream>
+
+#include <boost/any.hpp>
+#include <boost/scope_exit.hpp> // to test "BoostScopeExit"
+
+#include "gtest/gtest.h"
+
+#include "core/utils/scope_exit.h"          // to test "ScopeExit"
+#include "trackrenderer/core/pipeline.hpp"  // to test "UnlinkElements"
+
+using namespace plusplayer;
+
+TEST(MiscTest, DISABLED_BoostScopeExit) {
+  std::string input;
+  std::cout << "input string:" << std::endl;
+  std::getline(std::cin , input);
+
+  if(input == "exit_now") {
+    std::cout << "early return" << std::endl;
+    return;
+  }
+
+  BOOST_SCOPE_EXIT(&input) {
+    input = "string updated";
+    std::cout << "Boost Scopt Exit : string(" << input << ")" << std::endl;
+  } BOOST_SCOPE_EXIT_END
+
+  if(input == "1") {
+    std::cout << "input is 1" << std::endl;
+    return;
+  } else {
+    std::cout << "input is not 1" << std::endl;
+  }
+}
+
+enum class TestState {
+  kNone,
+  kGood,
+  kBad
+};
+
+static void ControlDropRate(TestState* state) {
+  std::cout << __FUNCTION__ << std::endl;
+  *state = TestState::kGood;
+  return;
+}
+
+TEST(MiscTest, DISABLED_BoostScopeExit2) {
+  TestState state = TestState::kNone;
+  BOOST_SCOPE_EXIT(&state) {
+    std::cout << static_cast<int>(state) << std::endl;
+    ASSERT_EQ(state , TestState::kGood);
+  } BOOST_SCOPE_EXIT_END
+  return ControlDropRate(&state);
+}
+
+TEST(MiscTest, DISABLED_BoostScopeExitSequence) {
+  std::string input1{"1st scopt exit requested"};
+  BOOST_SCOPE_EXIT(&input1) {
+    std::cout << input1 << std::endl;
+  } BOOST_SCOPE_EXIT_END
+
+  std::string input2{"2nd scopt exit requested"};
+  BOOST_SCOPE_EXIT(&input2) {
+    std::cout << input2 << std::endl;
+  } BOOST_SCOPE_EXIT_END
+
+  std::string input3{"3rd scopt exit requested"};
+  BOOST_SCOPE_EXIT(&input3) {
+    std::cout << input3 << std::endl;
+  } BOOST_SCOPE_EXIT_END
+}
+
+// TODO(js4716.chun) : don't use this yet...use boost_scope_exit
+TEST(MiscTest, DISABLED_ScopeExit) {
+  std::string input;
+  std::cout << "input string:" << std::endl;
+  std::getline(std::cin, input);
+
+  if (input == "exit_now") {
+    std::cout << "early return" << std::endl;
+    return;
+  }
+
+  auto x = utils::ScopeExit([&input]() {
+    std::cout << "lambda in" << std::endl;
+    input = "string updated";
+    std::cout << "Scopt Exit : string(" << input << ")" << std::endl;
+  });
+
+  if (input == "1") {
+    std::cout << "input is 1 (" << input << ")" << std::endl;
+    return;
+  } else {
+    std::cout << "input is not 1 (" << input << ")" << std::endl;
+  }
+}
+
+TEST(MiscTest, DISABLED_BoostAnyCast) {
+  const float test1 = 3.14;
+  std::cout << "test1: [" << test1 << "]" << std::endl;
+
+  //
+  // Failed Cases
+  //
+  boost::any value1 = 3.14;
+  const float* casted_val1 = boost::any_cast<float>(&value1);
+  if(!casted_val1) { // if casting failed
+    std::cout << "casted_val1: casting failed" << std::endl;
+  } else {
+    std::cout << "casted_val1: [" << *casted_val1 << "]" << std::endl;
+  }
+  try {
+    const float casted_val2 =
+        boost::any_cast<float>(value1);  // Exception thrown.
+    std::cout << "casted_val2: [" << casted_val2 << "]" << std::endl;
+  } catch(...) {
+    std::cout << "casted_val2: casting failed" << std::endl;
+  }
+
+  //
+  // Success Cases
+  //
+  boost::any value2 = float{3.14};
+  const float casted_val3 = boost::any_cast<float>(value2);  // Success
+  std::cout << "casted_val3: [" << casted_val3 << "]" << std::endl;
+  const float* casted_val4 = boost::any_cast<float>(&value2);  // Success
+  std::cout << "casted_val4: [" << *casted_val4 << "]" << std::endl;
+}
diff --git a/ut/src/ut_streamreader.cpp b/ut/src/ut_streamreader.cpp
new file mode 100755 (executable)
index 0000000..b61156c
--- /dev/null
@@ -0,0 +1,130 @@
+//
+// @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#include "ut/include/streamreader.hpp"
+#include "plusplayer/track.h"
+
+class StreamReaderTest : public ::testing::Test {
+ protected:
+  static void SetUpTestCase() { ESPacketDownloader::Init(); }
+  static void TearDownTestCase() {}
+
+  void SetUp() override {}
+  void TearDown() override {}
+
+ public:
+  static Environment *env_;
+};
+
+TEST_F(StreamReaderTest, DISABLED_Create) {
+  ASSERT_NO_THROW({
+    es::StreamReader<pp::TrackType>::Create("/welcome_movie/video_00/",
+                                            pp::kTrackTypeVideo);
+    es::StreamReader<pp::TrackType>::Create("/welcome_movie/audio_00/",
+                                            pp::kTrackTypeAudio);
+  });
+}
+
+TEST_F(StreamReaderTest, DISABLED_ThrowOnCreate) {
+  ASSERT_ANY_THROW({
+    es::StreamReader<pp::TrackType>::Create("foo/bar/", pp::kTrackTypeVideo);
+  });
+}
+
+TEST_F(StreamReaderTest, DISABLED_GetVideoExtraData) {
+  auto v_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/video_00/", pp::kTrackTypeVideo);
+  ASSERT_NO_THROW({ v_streamreader->GetExtraData(); });
+}
+
+TEST_F(StreamReaderTest, DISABLED_GetAudioExtraData) {
+  auto a_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/audio_00/", pp::kTrackTypeAudio);
+  ASSERT_NO_THROW({ a_streamreader->GetExtraData(); });
+}
+
+TEST_F(StreamReaderTest, DISABLED_GetPtsFromFirstVideoPacket) {
+  auto v_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/video_00/", pp::kTrackTypeVideo);
+  auto firstpkt = v_streamreader->ReadNextPacket();
+  ASSERT_EQ(1, firstpkt->pts);
+}
+
+TEST_F(StreamReaderTest, DISABLED_GetPtsFromTwoVideoPacket) {
+  auto v_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/video_00/", pp::kTrackTypeVideo);
+  auto firstpkt = v_streamreader->ReadNextPacket();
+  ASSERT_EQ(1, firstpkt->pts);
+
+  auto secondpkt = v_streamreader->ReadNextPacket();
+  ASSERT_EQ(16666668, secondpkt->pts);
+}
+
+TEST_F(StreamReaderTest, DISABLED_GetPtsFromFirstAudioPacket) {
+  auto a_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/audio_00/", pp::kTrackTypeAudio);
+  auto firstpkt = a_streamreader->ReadNextPacket();
+  ASSERT_EQ(1, firstpkt->pts);
+}
+
+TEST_F(StreamReaderTest, DISABLED_GetPtsFromTwoAudioPacket) {
+  auto a_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/audio_00/", pp::kTrackTypeAudio);
+  auto firstpkt = a_streamreader->ReadNextPacket();
+  ASSERT_EQ(1, firstpkt->pts);
+
+  auto secondpkt = a_streamreader->ReadNextPacket();
+  ASSERT_EQ(21333334, secondpkt->pts);
+}
+
+TEST_F(StreamReaderTest, DISABLED_CheckVideoEOF) {
+  auto v_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/video_00/", pp::kTrackTypeVideo);
+  es::PacketPtr pkt = nullptr;
+  while (1) {
+    pkt = v_streamreader->ReadNextPacket();
+    if (pkt == nullptr) break;
+    ASSERT_NE(nullptr, pkt);
+  }
+  ASSERT_EQ(nullptr, pkt);
+}
+
+TEST_F(StreamReaderTest, DISABLED_CheckAudioEOF) {
+  auto a_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/audio_00/", pp::kTrackTypeAudio);
+  es::PacketPtr pkt = nullptr;
+  while (1) {
+    pkt = a_streamreader->ReadNextPacket();
+    if (pkt == nullptr) break;
+    ASSERT_NE(nullptr, pkt);
+  }
+  ASSERT_EQ(nullptr, pkt);
+}
+
+TEST_F(StreamReaderTest, DISABLED_CheckVideoInfo) {
+  auto v_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/video_00/", pp::kTrackTypeVideo);
+  auto videoinfo =
+      v_streamreader->GetMediaInfo<es::VideoInfo<pp::Track, pp::TrackType>>();
+  ASSERT_EQ("video/x-h265", videoinfo.mimetype);
+  ASSERT_EQ(3840, videoinfo.width);
+  ASSERT_EQ(2160, videoinfo.height);
+  ASSERT_EQ(3840, videoinfo.maxwidth);
+  ASSERT_EQ(2160, videoinfo.maxheight);
+  ASSERT_EQ(60, videoinfo.framerate_num);
+  ASSERT_EQ(1, videoinfo.framerate_den);
+}
+
+TEST_F(StreamReaderTest, DISABLED_CheckAudioInfo) {
+  auto a_streamreader = es::StreamReader<pp::TrackType>::Create(
+      "/welcome_movie/audio_00/", pp::kTrackTypeAudio);
+  auto audioinfo = a_streamreader->GetMediaInfo<
+      es::AudioInfo<pp::Track, pp::TrackType>>();
+  ASSERT_EQ("audio/mpeg", audioinfo.mimetype);
+  ASSERT_EQ(48000, audioinfo.samplerate);
+  ASSERT_EQ(2, audioinfo.channels);
+}
diff --git a/ut/src/ut_trackrendereradapter.cpp b/ut/src/ut_trackrendereradapter.cpp
new file mode 100755 (executable)
index 0000000..12f76ce
--- /dev/null
@@ -0,0 +1,410 @@
+//
+// @ Copyright [2017] <S/W Platform, Visual Display, Samsung Electronics>
+//
+
+#include "gst/gst.h"
+#include "gtest/gtest.h"
+
+#include "Ecore.h"
+#include "Elementary.h"
+#include "glib-object.h"
+
+#include "core/track_util.h"
+#include "core/trackrendereradapter.h"
+#include "core/trackrendereradapter_utils.h"
+#include "plusplayer/track.h"
+#include "trackrenderer/core/decoderinputbuffer.h"
+#include "trackrenderer/core/track_util.h"
+#include "trackrenderer/trackrenderer_capi_utils.h"
+#include "trackrenderer_capi/iniproperty.h"
+#include "trackrenderer_capi/track.h"
+#include "trackrenderer_capi/trackrenderer_capi.h"
+#include "ut/include/appwindow.h"
+
+using namespace plusplayer;
+
+class TrackRendererAdapterTest : public ::testing::Test {
+ public:
+  TrackRendererAdapterTest() {}
+  void SetUp() override {
+    // basic , clean stream
+    std::string url = "";
+    trackrenderer_adapter_ = TrackRendererAdapter::Create();
+    ASSERT_TRUE(trackrenderer_adapter_.get());
+  }
+  std::shared_ptr<TrackRendererAdapter> GetAdapter() {
+    return trackrenderer_adapter_;
+  }
+  std::shared_ptr<plusplayer_ut::AppWindow> GetAppWindow() {
+    return appwindow_;
+  }
+
+ private:
+  std::shared_ptr<TrackRendererAdapter> trackrenderer_adapter_;
+  std::shared_ptr<plusplayer_ut::AppWindow> appwindow_;
+};
+constexpr int kTrackRendererMaxStreamNumber = 3;
+
+Track SetVideoInfo_(std::string mimetype, TrackType type,
+                    const char* codec_data, int w, int h, int framerate_num,
+                    int framerate_den, bool activate) {
+  Track trackinfo;
+  trackinfo.mimetype = mimetype;
+  trackinfo.type = type;
+  trackinfo.codec_data = std::make_shared<char>(*codec_data);
+  trackinfo.width = w;
+  trackinfo.height = h;
+  trackinfo.framerate_num = framerate_num;
+  trackinfo.framerate_den = framerate_den;
+  trackinfo.active = activate;
+  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(TrackRendererAdapterTest, DISABLED_Start) {
+  // auto adapter = GetAdapter();
+  // ASSERT_TRUE(adapter->Start());
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_Stop) {
+  // auto adapter = GetAdapter();
+  // ASSERT_TRUE(adapter->Stop());
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_Prepare) {
+  // auto adapter = GetAdapter();
+  // ASSERT_TRUE(adapter->Prepare());
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_Pause) {
+  // auto adapter = GetAdapter();
+  // ASSERT_TRUE(adapter->Pause());
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_Resume) {
+  // auto adapter = GetAdapter();
+  // ASSERT_TRUE(adapter->Resume());
+}
+
+std::vector<Track> MakeTrackInfo() {
+  std::vector<Track> trackvector;
+  const char* ffmpeg = "ffmpeg";
+  Track trackvideoinfo =
+      SetVideoInfo_("video/x-h264", TrackType::kTrackTypeVideo, ffmpeg, 640,
+                    352, 30, 1, true);
+  Track trackaudioinfo = SetAudioInfo_("audio/mpeg", 44100, 0, 2, 4);
+  trackvector.push_back(trackvideoinfo);
+  trackvector.push_back(trackaudioinfo);
+  return trackvector;
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetTrack) {
+  auto adapter = GetAdapter();
+  std::vector<Track> input_vector = MakeTrackInfo();
+  int size = input_vector.size();
+  if (size <= 0 || size > kTrackRendererMaxStreamNumber) return;
+
+  TrackRendererTrack trackrenderer_tracks[size];
+  int index = 0;
+  for (const auto& track : input_vector) {
+    adapter_utils::MakeTrackRendererTrack(&trackrenderer_tracks[index], track);
+    index++;
+  }
+  // ASSERT
+  //
+
+  auto output_vector =
+      trackrenderer::capi_utils::MakeTrack(trackrenderer_tracks, size);
+
+  plusplayer::track_util::ShowTrackInfo(input_vector);
+  plusplayer::trackrenderer::track_util::ShowTrackInfo(output_vector);
+
+  index = 0;
+  for (const auto& input : input_vector) {
+    auto output = output_vector.at(index);
+    ASSERT_EQ(input.index, output.index);
+    ASSERT_EQ(input.id, output.id);
+    ASSERT_EQ(input.mimetype, output.mimetype);
+    ASSERT_EQ(input.streamtype, output.streamtype);
+    ASSERT_EQ(input.type, output.type);
+    ASSERT_EQ(input.codec_data_len, output.codec_data_len);
+    ASSERT_EQ(0, memcmp(input.codec_data.get(), output.codec_data.get(),
+                        output.codec_data_len));
+    ASSERT_EQ(input.width, output.width);
+    ASSERT_EQ(input.height, output.height);
+    ASSERT_EQ(input.maxwidth, output.maxwidth);
+    ASSERT_EQ(input.maxheight, output.maxheight);
+    ASSERT_EQ(input.framerate_num, output.framerate_num);
+    ASSERT_EQ(input.framerate_den, output.framerate_den);
+    ASSERT_EQ(input.sample_rate, output.sample_rate);
+    ASSERT_EQ(input.sample_format, output.sample_format);
+    ASSERT_EQ(input.channels, output.channels);
+    ASSERT_EQ(input.version, output.version);
+    ASSERT_EQ(input.layer, output.layer);
+    ASSERT_EQ(input.bits_per_sample, output.bits_per_sample);
+    ASSERT_EQ(input.block_align, output.block_align);
+    ASSERT_EQ(input.bitrate, output.bitrate);
+    ASSERT_EQ(input.endianness, output.endianness);
+    ASSERT_EQ(input.is_signed, output.is_signed);
+    ASSERT_EQ(input.active, output.active);
+    ASSERT_EQ(input.use_swdecoder, output.use_swdecoder);
+    ASSERT_EQ(input.language_code, output.language_code);
+    ASSERT_EQ(input.subtitle_format, output.subtitle_format);
+    index++;
+  }
+  ASSERT_TRUE(adapter->SetTrack(input_vector));
+}
+
+std::map<std::string, bool> MakeIniProperties() {
+  std::map<std::string, bool> properties;
+  std::string key = "use_new_hls_mpegts_demuxer";
+  properties[key] = true;
+  key = "use_new_dash_tiny_demuxer";
+  properties[key] = true;
+  key = "use_new_http_demuxer";
+  properties[key] = true;
+  key = "generate_dot";
+  properties[key] = true;
+  return properties;
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetIniProperty) {
+  std::map<std::string, bool> input = MakeIniProperties();
+  const int size = input.size();
+  if (size <= 0) return;
+
+  TrackRendererIniProperty trackrenderer_iniproperty[size];
+  int index = 0;
+  for (const auto& pair : input) {
+    trackrenderer_iniproperty[index].key = pair.first.c_str();
+    trackrenderer_iniproperty[index].value = pair.second;
+    index++;
+  }
+
+  std::map<std::string, bool> output =
+      trackrenderer::capi_utils::MakeIniProperty(trackrenderer_iniproperty, size);
+  ASSERT_EQ(input, output);
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_Seek) {
+  // auto adapter = GetAdapter();
+  // uint64_t time_millisecond = 30;
+  // double playback_rate = 2.5;
+  // ASSERT_TRUE(adapter->Seek(time_millisecond, playback_rate));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_GetPlayingTime) {
+  // auto adapter = GetAdapter();
+  // uint64_t time_millisecond = 0;
+  // ASSERT_TRUE(adapter->GetPlayingTime(&time_millisecond));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_Deactivate) {
+  // auto adapter = GetAdapter();
+  // TrackType input = TrackType::kTrackTypeVideo;
+  // TrackRendererTrackType type =
+  // adapter_utils::ConvertToTrackRendererTrackType(input); TrackType output =
+  // plusplayer::trackrenderer::capi_utils::ConvertToTrackType(type); ASSERT_EQ(input,
+  // output); ASSERT_TRUE(adapter->Deactivate(input));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_Activate) {
+  const char* ffmpeg = "ffmpeg";
+  Track input = SetVideoInfo_("video/x-h264", TrackType::kTrackTypeVideo,
+                              ffmpeg, 640, 352, 30, 1, true);
+  TrackRendererTrack trackrenderer_track;
+
+  adapter_utils::MakeTrackRendererTrack(&trackrenderer_track, input);
+  auto output_vector = trackrenderer::capi_utils::MakeTrack(&trackrenderer_track, 1);
+
+  auto output = output_vector.front();
+
+  ASSERT_EQ(input.index, output.index);
+  ASSERT_EQ(input.id, output.id);
+  ASSERT_EQ(input.mimetype, output.mimetype);
+  ASSERT_EQ(input.streamtype, output.streamtype);
+  ASSERT_EQ(input.type, output.type);
+  ASSERT_EQ(input.codec_data_len, output.codec_data_len);
+  ASSERT_EQ(0, memcmp(input.codec_data.get(), output.codec_data.get(),
+                      output.codec_data_len));
+  ASSERT_EQ(input.width, output.width);
+  ASSERT_EQ(input.height, output.height);
+  ASSERT_EQ(input.maxwidth, output.maxwidth);
+  ASSERT_EQ(input.maxheight, output.maxheight);
+  ASSERT_EQ(input.framerate_num, output.framerate_num);
+  ASSERT_EQ(input.framerate_den, output.framerate_den);
+  ASSERT_EQ(input.sample_rate, output.sample_rate);
+  ASSERT_EQ(input.sample_format, output.sample_format);
+  ASSERT_EQ(input.channels, output.channels);
+  ASSERT_EQ(input.version, output.version);
+  ASSERT_EQ(input.layer, output.layer);
+  ASSERT_EQ(input.bits_per_sample, output.bits_per_sample);
+  ASSERT_EQ(input.block_align, output.block_align);
+  ASSERT_EQ(input.bitrate, output.bitrate);
+  ASSERT_EQ(input.endianness, output.endianness);
+  ASSERT_EQ(input.is_signed, output.is_signed);
+  ASSERT_EQ(input.active, output.active);
+  ASSERT_EQ(input.use_swdecoder, output.use_swdecoder);
+  ASSERT_EQ(input.language_code, output.language_code);
+  ASSERT_EQ(input.subtitle_format, output.subtitle_format);
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SubmitPacket) {
+  auto input = DecoderInputBuffer::Create(
+      static_cast<TrackType>(kTrackTypeVideo), kInvalidTrackIndex, nullptr);
+
+  TrackRendererDecoderInputBuffer trackrenderer_decoderinputbuffer{
+      adapter_utils::ConvertToTrackRendererTrackType(input->GetType()),
+      input->GetIndex(), const_cast<GstBuffer*>(input->Get())};
+
+  auto output = trackrenderer::DecoderInputBuffer::Create(
+      trackrenderer::capi_utils::ConvertToTrackType(
+          trackrenderer_decoderinputbuffer.type),
+      trackrenderer_decoderinputbuffer.index,
+      trackrenderer_decoderinputbuffer.buffer);
+
+  ASSERT_EQ((*input).GetType(), (*output).GetType());
+  ASSERT_EQ((*input).GetIndex(), (*output).GetIndex());
+  ASSERT_EQ((*input).Get(), (*output).Get());
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetDrm) {
+  const drm::Property input;
+  TrackRendererDrmProperty trackrenderer_drm_property;
+
+  adapter_utils::MakeTrackRendererDrmProperty(&trackrenderer_drm_property,
+                                              input);
+
+  trackrenderer::drm::Property output;
+  trackrenderer::capi_utils::MakeDrmProperty(&output, trackrenderer_drm_property);
+  ASSERT_EQ(input.type, output.type);
+  ASSERT_EQ(input.handle, output.handle);
+  ASSERT_EQ(input.external_decryption, output.external_decryption);
+  ASSERT_EQ(input.license_acquired_cb, output.license_acquired_cb);
+  ASSERT_EQ(input.license_acquired_userdata, output.license_acquired_userdata);
+}
+TEST_F(TrackRendererAdapterTest, DISABLED_SetMatroskaColorInfo) {}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_DrmLicenseAcquiredDone) {
+  TrackType input = TrackType::kTrackTypeAudio;
+  auto type =
+      adapter_utils::ConvertToTrackRendererTrackType(
+          input);
+
+  trackrenderer::TrackType output = trackrenderer::capi_utils::ConvertToTrackType(type);
+  ASSERT_EQ(input, output);
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetDisplayMode) {
+  auto adapter = GetAdapter();
+  const DisplayMode input = DisplayMode::kOriginSize;
+  TrackRendererDisplayMode mode =
+      adapter_utils::ConvertToTrackRendererDisplayMode(input);
+  trackrenderer::DisplayMode output = trackrenderer::capi_utils::ConvertToDisplayMode(mode);
+
+  ASSERT_EQ(input, output);
+  ASSERT_TRUE(adapter->SetDisplayMode(input));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetDisplay2) {
+  auto adapter = GetAdapter();
+  auto appwindow = GetAppWindow();
+  appwindow.reset(new plusplayer_ut::AppWindow(0, 0, 1920, 1080));
+
+  const DisplayType input = DisplayType::kOverlay;
+
+  TrackRendererDisplayType type =
+      adapter_utils::ConvertToTrackRendererDisplayType(input);
+  trackrenderer::DisplayType output = trackrenderer::capi_utils::ConvertToDisplayType(type);
+
+  ASSERT_EQ(input, output);
+  ASSERT_TRUE(adapter->SetDisplay(input, appwindow->GetWindow().obj));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetDisplay3) {}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetDisplayRoi) {
+  auto adapter = GetAdapter();
+  Geometry input;
+  input.x = 1;
+  input.y = 1;
+  input.w = 1;
+  input.h = 1;
+  TrackRendererGeometry geometry = {0, 0, 1920, 1080};
+  adapter_utils::MakeTrackRendererGeometry(&geometry, input);
+
+  trackrenderer::Geometry output;
+  trackrenderer::capi_utils::MakeGeometry(&output, geometry);
+  ASSERT_EQ(input.x, output.x);
+  ASSERT_EQ(input.y, output.y);
+  ASSERT_EQ(input.w, output.w);
+  ASSERT_EQ(input.h, output.h);
+  ASSERT_TRUE(adapter->SetDisplayRoi(input));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetDisplayVisible) {
+  auto adapter = GetAdapter();
+  bool is_visible = false;
+  ASSERT_TRUE(adapter->SetDisplayVisible(is_visible));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetAudioMute) {
+  // auto adapter = GetAdapter();
+  // bool is_mute = false;
+  // ASSERT_TRUE(adapter->SetAudioMute(is_mute));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SetVideoStillMode) {
+  StillMode input = StillMode::kOn;
+  TrackRendererStillMode still_mode =
+      adapter_utils::ConvertToTrackRendererStillMode(input);
+
+  trackrenderer::StillMode output = trackrenderer::capi_utils::ConvertToStillMode(still_mode);
+  ASSERT_EQ(input, output); // TODO(js4716.chun) : wrong condition. fix it
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_ErrorCb) {
+  trackrenderer::ErrorType input = ErrorType::kInvalidOperation;
+  TrackRendererErrorType error_type =
+      trackrenderer::capi_utils::ConvertToTrackRendererErrorType(input);
+  ErrorType output = adapter_utils::ConvertToErrorType(error_type);
+  ASSERT_EQ(input, output);  // TODO(js4716.chun) : wrong condition. fix it
+}
+
+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));
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_SubtitleDataCb) {
+  SubtitleType input_type = SubtitleType::kPicture;
+  TrackRendererSubtitleType type =
+      trackrenderer::capi_utils::ConvertToTrackRendererSubtitleType(input_type);
+  SubtitleType output_type = adapter_utils::ConvertToSubtitleType(type);
+  ASSERT_EQ(input_type, output_type);
+}
+
+TEST_F(TrackRendererAdapterTest, DISABLED_DrmInitDataCb) {
+  TrackRendererTrackType input = kTrackRendererTrackTypeSubtitle;
+  auto type = trackrenderer::capi_utils::ConvertToTrackType(input);
+  TrackRendererTrackType output =
+      trackrenderer::capi_utils::ConvertToTrackRendererTrackType(type);
+  ASSERT_EQ(input, output);
+}
+/*
+TEST_F(TrackRendererAdapterTest, DISABLED_GetDisplay){}
+TEST_F(TrackRendererAdapterTest, DISABLED_RegisterListener){}
+TEST_F(TrackRendererAdapterTest, DISABLED_ClosedCaptionDataCb_){}
+*/